]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
bfe1cd89fcafb905092d81216bef01e12428f69b
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
1 /** @file
2
3 XHCI transfer scheduling routines.
4
5 Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "Xhci.h"
17
18 /**
19 Create a command transfer TRB to support XHCI command interfaces.
20
21 @param Xhc The XHCI Instance.
22 @param CmdTrb The cmd TRB to be executed.
23
24 @return Created URB or NULL.
25
26 **/
27 URB*
28 XhcCreateCmdTrb (
29 IN USB_XHCI_INSTANCE *Xhc,
30 IN TRB_TEMPLATE *CmdTrb
31 )
32 {
33 URB *Urb;
34
35 Urb = AllocateZeroPool (sizeof (URB));
36 if (Urb == NULL) {
37 return NULL;
38 }
39
40 Urb->Signature = XHC_URB_SIG;
41
42 Urb->Ring = &Xhc->CmdRing;
43 XhcSyncTrsRing (Xhc, Urb->Ring);
44 Urb->TrbNum = 1;
45 Urb->TrbStart = Urb->Ring->RingEnqueue;
46 CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));
47 Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;
48 Urb->TrbEnd = Urb->TrbStart;
49
50 return Urb;
51 }
52
53 /**
54 Execute a XHCI cmd TRB pointed by CmdTrb.
55
56 @param Xhc The XHCI Instance.
57 @param CmdTrb The cmd TRB to be executed.
58 @param Timeout Indicates the maximum time, in millisecond, which the
59 transfer is allowed to complete.
60 @param EvtTrb The event TRB corresponding to the cmd TRB.
61
62 @retval EFI_SUCCESS The transfer was completed successfully.
63 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
64 @retval EFI_TIMEOUT The transfer failed due to timeout.
65 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
66
67 **/
68 EFI_STATUS
69 EFIAPI
70 XhcCmdTransfer (
71 IN USB_XHCI_INSTANCE *Xhc,
72 IN TRB_TEMPLATE *CmdTrb,
73 IN UINTN Timeout,
74 OUT TRB_TEMPLATE **EvtTrb
75 )
76 {
77 EFI_STATUS Status;
78 URB *Urb;
79
80 //
81 // Validate the parameters
82 //
83 if ((Xhc == NULL) || (CmdTrb == NULL)) {
84 return EFI_INVALID_PARAMETER;
85 }
86
87 Status = EFI_DEVICE_ERROR;
88
89 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
90 DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: HC is halted\n"));
91 goto ON_EXIT;
92 }
93
94 //
95 // Create a new URB, then poll the execution status.
96 //
97 Urb = XhcCreateCmdTrb (Xhc, CmdTrb);
98
99 if (Urb == NULL) {
100 DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: failed to create URB\n"));
101 Status = EFI_OUT_OF_RESOURCES;
102 goto ON_EXIT;
103 }
104
105 Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout);
106 *EvtTrb = Urb->EvtTrb;
107
108 if (Urb->Result == EFI_USB_NOERROR) {
109 Status = EFI_SUCCESS;
110 }
111
112 FreePool (Urb);
113
114 ON_EXIT:
115 return Status;
116 }
117
118 /**
119 Create a new URB for a new transaction.
120
121 @param Xhc The XHCI Instance
122 @param BusAddr The logical device address assigned by UsbBus driver
123 @param EpAddr Endpoint addrress
124 @param DevSpeed The device speed
125 @param MaxPacket The max packet length of the endpoint
126 @param Type The transaction type
127 @param Request The standard USB request for control transfer
128 @param Data The user data to transfer
129 @param DataLen The length of data buffer
130 @param Callback The function to call when data is transferred
131 @param Context The context to the callback
132
133 @return Created URB or NULL
134
135 **/
136 URB*
137 XhcCreateUrb (
138 IN USB_XHCI_INSTANCE *Xhc,
139 IN UINT8 BusAddr,
140 IN UINT8 EpAddr,
141 IN UINT8 DevSpeed,
142 IN UINTN MaxPacket,
143 IN UINTN Type,
144 IN EFI_USB_DEVICE_REQUEST *Request,
145 IN VOID *Data,
146 IN UINTN DataLen,
147 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
148 IN VOID *Context
149 )
150 {
151 USB_ENDPOINT *Ep;
152 EFI_STATUS Status;
153 URB *Urb;
154
155 Urb = AllocateZeroPool (sizeof (URB));
156 if (Urb == NULL) {
157 return NULL;
158 }
159
160 Urb->Signature = XHC_URB_SIG;
161 InitializeListHead (&Urb->UrbList);
162
163 Ep = &Urb->Ep;
164 Ep->BusAddr = BusAddr;
165 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);
166 Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
167 Ep->DevSpeed = DevSpeed;
168 Ep->MaxPacket = MaxPacket;
169 Ep->Type = Type;
170
171 Urb->Request = Request;
172 Urb->Data = Data;
173 Urb->DataLen = DataLen;
174 Urb->Callback = Callback;
175 Urb->Context = Context;
176
177 Status = XhcCreateTransferTrb (Xhc, Urb);
178 ASSERT_EFI_ERROR (Status);
179
180 return Urb;
181 }
182
183 /**
184 Create a transfer TRB.
185
186 @param Xhc The XHCI Instance
187 @param Urb The urb used to construct the transfer TRB.
188
189 @return Created TRB or NULL
190
191 **/
192 EFI_STATUS
193 XhcCreateTransferTrb (
194 IN USB_XHCI_INSTANCE *Xhc,
195 IN URB *Urb
196 )
197 {
198 VOID *OutputContext;
199 TRANSFER_RING *EPRing;
200 UINT8 EPType;
201 UINT8 SlotId;
202 UINT8 Dci;
203 TRB *TrbStart;
204 UINTN TotalLen;
205 UINTN Len;
206 UINTN TrbNum;
207
208 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
209 if (SlotId == 0) {
210 return EFI_DEVICE_ERROR;
211 }
212
213 Urb->Finished = FALSE;
214 Urb->StartDone = FALSE;
215 Urb->EndDone = FALSE;
216 Urb->Completed = 0;
217 Urb->Result = EFI_USB_NOERROR;
218
219 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
220 ASSERT (Dci < 32);
221 EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];
222 Urb->Ring = EPRing;
223 OutputContext = (VOID *)(UINTN)Xhc->DCBAA[SlotId];
224 if (Xhc->HcCParams.Data.Csz == 0) {
225 EPType = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;
226 } else {
227 EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
228 }
229
230 //
231 // Construct the TRB
232 //
233 XhcSyncTrsRing (Xhc, EPRing);
234 Urb->TrbStart = EPRing->RingEnqueue;
235 switch (EPType) {
236 case ED_CONTROL_BIDIR:
237 //
238 // For control transfer, create SETUP_STAGE_TRB first.
239 //
240 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
241 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;
242 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;
243 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;
244 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;
245 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;
246 TrbStart->TrbCtrSetup.Lenth = 8;
247 TrbStart->TrbCtrSetup.IntTarget = 0;
248 TrbStart->TrbCtrSetup.IOC = 1;
249 TrbStart->TrbCtrSetup.IDT = 1;
250 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;
251 if (Urb->Ep.Direction == EfiUsbDataIn) {
252 TrbStart->TrbCtrSetup.TRT = 3;
253 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
254 TrbStart->TrbCtrSetup.TRT = 2;
255 } else {
256 TrbStart->TrbCtrSetup.TRT = 0;
257 }
258 //
259 // Update the cycle bit
260 //
261 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;
262 Urb->TrbNum++;
263
264 //
265 // For control transfer, create DATA_STAGE_TRB.
266 //
267 if (Urb->DataLen > 0) {
268 XhcSyncTrsRing (Xhc, EPRing);
269 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
270 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->Data);
271 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->Data);
272 TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen;
273 TrbStart->TrbCtrData.TDSize = 0;
274 TrbStart->TrbCtrData.IntTarget = 0;
275 TrbStart->TrbCtrData.ISP = 1;
276 TrbStart->TrbCtrData.IOC = 1;
277 TrbStart->TrbCtrData.IDT = 0;
278 TrbStart->TrbCtrData.CH = 0;
279 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;
280 if (Urb->Ep.Direction == EfiUsbDataIn) {
281 TrbStart->TrbCtrData.DIR = 1;
282 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
283 TrbStart->TrbCtrData.DIR = 0;
284 } else {
285 TrbStart->TrbCtrData.DIR = 0;
286 }
287 //
288 // Update the cycle bit
289 //
290 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;
291 Urb->TrbNum++;
292 }
293 //
294 // For control transfer, create STATUS_STAGE_TRB.
295 // Get the pointer to next TRB for status stage use
296 //
297 XhcSyncTrsRing (Xhc, EPRing);
298 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
299 TrbStart->TrbCtrStatus.IntTarget = 0;
300 TrbStart->TrbCtrStatus.IOC = 1;
301 TrbStart->TrbCtrStatus.CH = 0;
302 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;
303 if (Urb->Ep.Direction == EfiUsbDataIn) {
304 TrbStart->TrbCtrStatus.DIR = 0;
305 } else if (Urb->Ep.Direction == EfiUsbDataOut) {
306 TrbStart->TrbCtrStatus.DIR = 1;
307 } else {
308 TrbStart->TrbCtrStatus.DIR = 0;
309 }
310 //
311 // Update the cycle bit
312 //
313 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;
314 //
315 // Update the enqueue pointer
316 //
317 XhcSyncTrsRing (Xhc, EPRing);
318 Urb->TrbNum++;
319 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
320
321 break;
322
323 case ED_BULK_OUT:
324 case ED_BULK_IN:
325 TotalLen = 0;
326 Len = 0;
327 TrbNum = 0;
328 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
329 while (TotalLen < Urb->DataLen) {
330 if ((TotalLen + 0x10000) >= Urb->DataLen) {
331 Len = Urb->DataLen - TotalLen;
332 } else {
333 Len = 0x10000;
334 }
335 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
336 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);
337 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);
338 TrbStart->TrbNormal.Lenth = (UINT32) Len;
339 TrbStart->TrbNormal.TDSize = 0;
340 TrbStart->TrbNormal.IntTarget = 0;
341 TrbStart->TrbNormal.ISP = 1;
342 TrbStart->TrbNormal.IOC = 1;
343 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
344 //
345 // Update the cycle bit
346 //
347 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
348
349 XhcSyncTrsRing (Xhc, EPRing);
350 TrbNum++;
351 TotalLen += Len;
352 }
353
354 Urb->TrbNum = TrbNum;
355 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
356 break;
357
358 case ED_INTERRUPT_OUT:
359 case ED_INTERRUPT_IN:
360 TotalLen = 0;
361 Len = 0;
362 TrbNum = 0;
363 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
364 while (TotalLen < Urb->DataLen) {
365 if ((TotalLen + 0x10000) >= Urb->DataLen) {
366 Len = Urb->DataLen - TotalLen;
367 } else {
368 Len = 0x10000;
369 }
370 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;
371 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);
372 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);
373 TrbStart->TrbNormal.Lenth = (UINT32) Len;
374 TrbStart->TrbNormal.TDSize = 0;
375 TrbStart->TrbNormal.IntTarget = 0;
376 TrbStart->TrbNormal.ISP = 1;
377 TrbStart->TrbNormal.IOC = 1;
378 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;
379 //
380 // Update the cycle bit
381 //
382 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;
383
384 XhcSyncTrsRing (Xhc, EPRing);
385 TrbNum++;
386 TotalLen += Len;
387 }
388
389 Urb->TrbNum = TrbNum;
390 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;
391 break;
392
393 default:
394 DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));
395 ASSERT (FALSE);
396 break;
397 }
398
399 return EFI_SUCCESS;
400 }
401
402
403 /**
404 Initialize the XHCI host controller for schedule.
405
406 @param Xhc The XHCI Instance to be initialized.
407
408 **/
409 VOID
410 XhcInitSched (
411 IN USB_XHCI_INSTANCE *Xhc
412 )
413 {
414 VOID *Dcbaa;
415 UINT64 CmdRing;
416 UINTN Entries;
417 UINT32 MaxScratchpadBufs;
418 UINT64 *ScratchBuf;
419 UINT64 *ScratchEntryBuf;
420 UINT32 Index;
421
422 //
423 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
424 // to enable the device slots that system software is going to use.
425 //
426 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;
427 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);
428 XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);
429
430 //
431 // The Device Context Base Address Array entry associated with each allocated Device Slot
432 // shall contain a 64-bit pointer to the base of the associated Device Context.
433 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
434 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
435 //
436 Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);
437 Dcbaa = AllocatePages (EFI_SIZE_TO_PAGES (Entries));
438 ASSERT (Dcbaa != NULL);
439 ZeroMem (Dcbaa, Entries);
440
441 //
442 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
443 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
444 // mode (Run/Stop(R/S) ='1').
445 //
446 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);
447 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;
448 ASSERT (MaxScratchpadBufs <= 1023);
449 if (MaxScratchpadBufs != 0) {
450 ScratchBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)), Xhc->PageSize);
451 ASSERT (ScratchBuf != NULL);
452 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));
453 Xhc->ScratchBuf = ScratchBuf;
454
455 for (Index = 0; Index < MaxScratchpadBufs; Index++) {
456 ScratchEntryBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (Xhc->PageSize), Xhc->PageSize);
457 ASSERT (ScratchEntryBuf != NULL);
458 ZeroMem (ScratchEntryBuf, Xhc->PageSize);
459 *ScratchBuf++ = (UINT64)(UINTN)ScratchEntryBuf;
460 }
461
462 //
463 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
464 // Device Context Base Address Array points to the Scratchpad Buffer Array.
465 //
466 *(UINT64 *)Dcbaa = (UINT64)(UINTN)Xhc->ScratchBuf;
467 }
468
469 //
470 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
471 // a 64-bit address pointing to where the Device Context Base Address Array is located.
472 //
473 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;
474 //
475 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
476 // So divide it to two 32-bytes width register access.
477 //
478 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT(Xhc->DCBAA));
479 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (Xhc->DCBAA));
480 DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));
481
482 //
483 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
484 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
485 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
486 // always be '0'.
487 //
488 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);
489 //
490 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
491 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
492 // So we set RCS as inverted PCS init value to let Command Ring empty
493 //
494 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;
495 ASSERT ((CmdRing & 0x3F) == 0);
496 CmdRing |= XHC_CRCR_RCS;
497 //
498 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
499 // So divide it to two 32-bytes width register access.
500 //
501 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRing));
502 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRing));
503
504 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));
505
506 //
507 // Disable the 'interrupter enable' bit in USB_CMD
508 // and clear IE & IP bit in all Interrupter X Management Registers.
509 //
510 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);
511 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {
512 XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);
513 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);
514 }
515
516 //
517 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
518 //
519 CreateEventRing (Xhc, &Xhc->EventRing);
520 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));
521 }
522
523 /**
524 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
525 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
526 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
527 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
528 Stopped to the Running state.
529
530 @param Xhc The XHCI Instance.
531 @param Urb The urb which makes the endpoint halted.
532
533 @retval EFI_SUCCESS The recovery is successful.
534 @retval Others Failed to recovery halted endpoint.
535
536 **/
537 EFI_STATUS
538 EFIAPI
539 XhcRecoverHaltedEndpoint (
540 IN USB_XHCI_INSTANCE *Xhc,
541 IN URB *Urb
542 )
543 {
544 EFI_STATUS Status;
545 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
546 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;
547 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;
548 UINT8 Dci;
549 UINT8 SlotId;
550
551 Status = EFI_SUCCESS;
552 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
553 if (SlotId == 0) {
554 return EFI_DEVICE_ERROR;
555 }
556 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
557 ASSERT (Dci < 32);
558
559 DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));
560
561 //
562 // 1) Send Reset endpoint command to transit from halt to stop state
563 //
564 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));
565 CmdTrbResetED.CycleBit = 1;
566 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;
567 CmdTrbResetED.EDID = Dci;
568 CmdTrbResetED.SlotId = SlotId;
569 Status = XhcCmdTransfer (
570 Xhc,
571 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,
572 XHC_GENERIC_TIMEOUT,
573 (TRB_TEMPLATE **) (UINTN) &EvtTrb
574 );
575 ASSERT (!EFI_ERROR(Status));
576
577 //
578 // 2)Set dequeue pointer
579 //
580 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));
581 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (Urb->Ring->RingEnqueue) | Urb->Ring->RingPCS;
582 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (Urb->Ring->RingEnqueue);
583 CmdSetTRDeq.CycleBit = 1;
584 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;
585 CmdSetTRDeq.Endpoint = Dci;
586 CmdSetTRDeq.SlotId = SlotId;
587 Status = XhcCmdTransfer (
588 Xhc,
589 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,
590 XHC_GENERIC_TIMEOUT,
591 (TRB_TEMPLATE **) (UINTN) &EvtTrb
592 );
593 ASSERT (!EFI_ERROR(Status));
594
595 //
596 // 3)Ring the doorbell to transit from stop to active
597 //
598 XhcRingDoorBell (Xhc, SlotId, Dci);
599
600 return Status;
601 }
602
603 /**
604 Create XHCI event ring.
605
606 @param Xhc The XHCI Instance.
607 @param EventRing The created event ring.
608
609 **/
610 VOID
611 CreateEventRing (
612 IN USB_XHCI_INSTANCE *Xhc,
613 OUT EVENT_RING *EventRing
614 )
615 {
616 VOID *Buf;
617 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;
618
619 ASSERT (EventRing != NULL);
620
621 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER));
622 ASSERT (Buf != NULL);
623 ASSERT (((UINTN) Buf & 0x3F) == 0);
624 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
625
626 EventRing->EventRingSeg0 = Buf;
627 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;
628 EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
629 EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;
630 //
631 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
632 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
633 //
634 EventRing->EventRingCCS = 1;
635
636 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER));
637 ASSERT (Buf != NULL);
638 ASSERT (((UINTN) Buf & 0x3F) == 0);
639 ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
640
641 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
642 EventRing->ERSTBase = ERSTBase;
643 ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);
644 ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
645 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
646
647 //
648 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
649 //
650 XhcWriteRuntimeReg (
651 Xhc,
652 XHC_ERSTSZ_OFFSET,
653 ERST_NUMBER
654 );
655 //
656 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
657 //
658 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
659 // So divide it to two 32-bytes width register access.
660 //
661 XhcWriteRuntimeReg (
662 Xhc,
663 XHC_ERDP_OFFSET,
664 XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
665 );
666 XhcWriteRuntimeReg (
667 Xhc,
668 XHC_ERDP_OFFSET + 4,
669 XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
670 );
671 //
672 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
673 //
674 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
675 // So divide it to two 32-bytes width register access.
676 //
677 XhcWriteRuntimeReg (
678 Xhc,
679 XHC_ERSTBA_OFFSET,
680 XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)
681 );
682 XhcWriteRuntimeReg (
683 Xhc,
684 XHC_ERSTBA_OFFSET + 4,
685 XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)
686 );
687 //
688 // Need set IMAN IE bit to enble the ring interrupt
689 //
690 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);
691 }
692
693 /**
694 Create XHCI transfer ring.
695
696 @param Xhc The XHCI Instance.
697 @param TrbNum The number of TRB in the ring.
698 @param TransferRing The created transfer ring.
699
700 **/
701 VOID
702 CreateTransferRing (
703 IN USB_XHCI_INSTANCE *Xhc,
704 IN UINTN TrbNum,
705 OUT TRANSFER_RING *TransferRing
706 )
707 {
708 VOID *Buf;
709 LINK_TRB *EndTrb;
710
711 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TrbNum));
712 ASSERT (Buf != NULL);
713 ASSERT (((UINTN) Buf & 0x3F) == 0);
714 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
715
716 TransferRing->RingSeg0 = Buf;
717 TransferRing->TrbNumber = TrbNum;
718 TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
719 TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;
720 TransferRing->RingPCS = 1;
721 //
722 // 4.9.2 Transfer Ring Management
723 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
724 // point to the first TRB in the ring.
725 //
726 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
727 EndTrb->Type = TRB_TYPE_LINK;
728 EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
729 EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
730 //
731 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
732 //
733 EndTrb->TC = 1;
734 //
735 // Set Cycle bit as other TRB PCS init value
736 //
737 EndTrb->CycleBit = 0;
738 }
739
740 /**
741 Free XHCI event ring.
742
743 @param Xhc The XHCI Instance.
744 @param EventRing The event ring to be freed.
745
746 **/
747 EFI_STATUS
748 EFIAPI
749 XhcFreeEventRing (
750 IN USB_XHCI_INSTANCE *Xhc,
751 IN EVENT_RING *EventRing
752 )
753 {
754 UINT8 Index;
755 EVENT_RING_SEG_TABLE_ENTRY *TablePtr;
756 VOID *RingBuf;
757 EVENT_RING_SEG_TABLE_ENTRY *EventRingPtr;
758
759 if(EventRing->EventRingSeg0 == NULL) {
760 return EFI_SUCCESS;
761 }
762
763 //
764 // Get the Event Ring Segment Table base address
765 //
766 TablePtr = (EVENT_RING_SEG_TABLE_ENTRY *)(EventRing->ERSTBase);
767
768 //
769 // Get all the TRBs Ring and release
770 //
771 for (Index = 0; Index < ERST_NUMBER; Index++) {
772 EventRingPtr = TablePtr + Index;
773 RingBuf = (VOID *)(UINTN)(EventRingPtr->PtrLo | LShiftU64 ((UINT64)EventRingPtr->PtrHi, 32));
774
775 if(RingBuf != NULL) {
776 FreePages (RingBuf, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER));
777 ZeroMem (EventRingPtr, sizeof (EVENT_RING_SEG_TABLE_ENTRY));
778 }
779 }
780
781 FreePages (TablePtr, EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER));
782 return EFI_SUCCESS;
783 }
784
785 /**
786 Free the resouce allocated at initializing schedule.
787
788 @param Xhc The XHCI Instance.
789
790 **/
791 VOID
792 XhcFreeSched (
793 IN USB_XHCI_INSTANCE *Xhc
794 )
795 {
796 UINT32 Index;
797 UINT64 *ScratchBuf;
798
799 if (Xhc->ScratchBuf != NULL) {
800 ScratchBuf = Xhc->ScratchBuf;
801 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {
802 FreeAlignedPages ((VOID*)(UINTN)*ScratchBuf++, EFI_SIZE_TO_PAGES (Xhc->PageSize));
803 }
804 FreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));
805 }
806
807 if (Xhc->DCBAA != NULL) {
808 FreePages (Xhc->DCBAA, EFI_SIZE_TO_PAGES((Xhc->MaxSlotsEn + 1) * sizeof(UINT64)));
809 Xhc->DCBAA = NULL;
810 }
811
812 if (Xhc->CmdRing.RingSeg0 != NULL){
813 FreePages (Xhc->CmdRing.RingSeg0, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER));
814 Xhc->CmdRing.RingSeg0 = NULL;
815 }
816
817 XhcFreeEventRing (Xhc,&Xhc->EventRing);
818 }
819
820 /**
821 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
822
823 @param Xhc The XHCI Instance.
824 @param Trb The TRB to be checked.
825 @param Urb The pointer to the matched Urb.
826
827 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
828 @retval FALSE The Trb is not matched with any URBs in the async list.
829
830 **/
831 BOOLEAN
832 IsAsyncIntTrb (
833 IN USB_XHCI_INSTANCE *Xhc,
834 IN TRB_TEMPLATE *Trb,
835 OUT URB **Urb
836 )
837 {
838 LIST_ENTRY *Entry;
839 LIST_ENTRY *Next;
840 TRB_TEMPLATE *CheckedTrb;
841 URB *CheckedUrb;
842 UINTN Index;
843
844 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
845 CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
846 CheckedTrb = CheckedUrb->TrbStart;
847 for (Index = 0; Index < CheckedUrb->TrbNum; Index++) {
848 if (Trb == CheckedTrb) {
849 *Urb = CheckedUrb;
850 return TRUE;
851 }
852 CheckedTrb++;
853 if ((UINTN)CheckedTrb >= ((UINTN) CheckedUrb->Ring->RingSeg0 + sizeof (TRB_TEMPLATE) * CheckedUrb->Ring->TrbNumber)) {
854 CheckedTrb = (TRB_TEMPLATE*) CheckedUrb->Ring->RingSeg0;
855 }
856 }
857 }
858
859 return FALSE;
860 }
861
862 /**
863 Check if the Trb is a transaction of the URB.
864
865 @param Trb The TRB to be checked
866 @param Urb The transfer ring to be checked.
867
868 @retval TRUE It is a transaction of the URB.
869 @retval FALSE It is not any transaction of the URB.
870
871 **/
872 BOOLEAN
873 IsTransferRingTrb (
874 IN TRB_TEMPLATE *Trb,
875 IN URB *Urb
876 )
877 {
878 TRB_TEMPLATE *CheckedTrb;
879 UINTN Index;
880
881 CheckedTrb = Urb->Ring->RingSeg0;
882
883 ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);
884
885 for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {
886 if (Trb == CheckedTrb) {
887 return TRUE;
888 }
889 CheckedTrb++;
890 }
891
892 return FALSE;
893 }
894
895 /**
896 Check the URB's execution result and update the URB's
897 result accordingly.
898
899 @param Xhc The XHCI Instance.
900 @param Urb The URB to check result.
901
902 @return Whether the result of URB transfer is finialized.
903
904 **/
905 EFI_STATUS
906 XhcCheckUrbResult (
907 IN USB_XHCI_INSTANCE *Xhc,
908 IN URB *Urb
909 )
910 {
911 EVT_TRB_TRANSFER *EvtTrb;
912 TRB_TEMPLATE *TRBPtr;
913 UINTN Index;
914 UINT8 TRBType;
915 EFI_STATUS Status;
916 URB *AsyncUrb;
917 URB *CheckedUrb;
918 UINT64 XhcDequeue;
919 UINT32 High;
920 UINT32 Low;
921
922 ASSERT ((Xhc != NULL) && (Urb != NULL));
923
924 Status = EFI_SUCCESS;
925 AsyncUrb = NULL;
926
927 if (Urb->Finished) {
928 goto EXIT;
929 }
930
931 EvtTrb = NULL;
932
933 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
934 Urb->Result |= EFI_USB_ERR_SYSTEM;
935 Status = EFI_DEVICE_ERROR;
936 goto EXIT;
937 }
938
939 //
940 // Traverse the event ring to find out all new events from the previous check.
941 //
942 XhcSyncEventRing (Xhc, &Xhc->EventRing);
943 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {
944 Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));
945 if (Status == EFI_NOT_READY) {
946 //
947 // All new events are handled, return directly.
948 //
949 goto EXIT;
950 }
951
952 //
953 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
954 //
955 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {
956 continue;
957 }
958
959 TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));
960
961 //
962 // Update the status of Urb according to the finished event regardless of whether
963 // the urb is current checked one or in the XHCI's async transfer list.
964 // This way is used to avoid that those completed async transfer events don't get
965 // handled in time and are flushed by newer coming events.
966 //
967 if (IsTransferRingTrb (TRBPtr, Urb)) {
968 CheckedUrb = Urb;
969 } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {
970 CheckedUrb = AsyncUrb;
971 } else {
972 continue;
973 }
974
975 switch (EvtTrb->Completecode) {
976 case TRB_COMPLETION_STALL_ERROR:
977 CheckedUrb->Result |= EFI_USB_ERR_STALL;
978 CheckedUrb->Finished = TRUE;
979 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
980 break;
981
982 case TRB_COMPLETION_BABBLE_ERROR:
983 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
984 CheckedUrb->Finished = TRUE;
985 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
986 break;
987
988 case TRB_COMPLETION_DATA_BUFFER_ERROR:
989 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
990 CheckedUrb->Finished = TRUE;
991 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
992 break;
993
994 case TRB_COMPLETION_USB_TRANSACTION_ERROR:
995 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
996 CheckedUrb->Finished = TRUE;
997 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
998 break;
999
1000 case TRB_COMPLETION_SHORT_PACKET:
1001 case TRB_COMPLETION_SUCCESS:
1002 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {
1003 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));
1004 }
1005
1006 TRBType = (UINT8) (TRBPtr->Type);
1007 if ((TRBType == TRB_TYPE_DATA_STAGE) ||
1008 (TRBType == TRB_TYPE_NORMAL) ||
1009 (TRBType == TRB_TYPE_ISOCH)) {
1010 CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Lenth);
1011 }
1012
1013 break;
1014
1015 default:
1016 DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
1017 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
1018 CheckedUrb->Finished = TRUE;
1019 break;
1020 }
1021
1022 //
1023 // Only check first and end Trb event address
1024 //
1025 if (TRBPtr == CheckedUrb->TrbStart) {
1026 CheckedUrb->StartDone = TRUE;
1027 }
1028
1029 if (TRBPtr == CheckedUrb->TrbEnd) {
1030 CheckedUrb->EndDone = TRUE;
1031 }
1032
1033 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {
1034 CheckedUrb->Finished = TRUE;
1035 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;
1036 }
1037 }
1038
1039 EXIT:
1040
1041 //
1042 // Advance event ring to last available entry
1043 //
1044 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1045 // So divide it to two 32-bytes width register access.
1046 //
1047 Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);
1048 High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);
1049 XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);
1050
1051 if ((XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)Xhc->EventRing.EventRingDequeue & (~0x0F))) {
1052 //
1053 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1054 // So divide it to two 32-bytes width register access.
1055 //
1056 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (Xhc->EventRing.EventRingDequeue) | BIT3);
1057 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (Xhc->EventRing.EventRingDequeue));
1058 }
1059
1060 return Status;
1061 }
1062
1063
1064 /**
1065 Execute the transfer by polling the URB. This is a synchronous operation.
1066
1067 @param Xhc The XHCI Instance.
1068 @param CmdTransfer The executed URB is for cmd transfer or not.
1069 @param Urb The URB to execute.
1070 @param Timeout The time to wait before abort, in millisecond.
1071
1072 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1073 @return EFI_TIMEOUT The transfer failed due to time out.
1074 @return EFI_SUCCESS The transfer finished OK.
1075
1076 **/
1077 EFI_STATUS
1078 XhcExecTransfer (
1079 IN USB_XHCI_INSTANCE *Xhc,
1080 IN BOOLEAN CmdTransfer,
1081 IN URB *Urb,
1082 IN UINTN Timeout
1083 )
1084 {
1085 EFI_STATUS Status;
1086 UINTN Index;
1087 UINTN Loop;
1088 UINT8 SlotId;
1089 UINT8 Dci;
1090
1091 if (CmdTransfer) {
1092 SlotId = 0;
1093 Dci = 0;
1094 } else {
1095 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1096 if (SlotId == 0) {
1097 return EFI_DEVICE_ERROR;
1098 }
1099 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1100 ASSERT (Dci < 32);
1101 }
1102
1103 Status = EFI_SUCCESS;
1104 Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1;
1105 if (Timeout == 0) {
1106 Loop = 0xFFFFFFFF;
1107 }
1108
1109 XhcRingDoorBell (Xhc, SlotId, Dci);
1110
1111 for (Index = 0; Index < Loop; Index++) {
1112 Status = XhcCheckUrbResult (Xhc, Urb);
1113 if (Urb->Finished) {
1114 break;
1115 }
1116 gBS->Stall (XHC_POLL_DELAY);
1117 }
1118
1119 if (Index == Loop) {
1120 Urb->Result = EFI_USB_ERR_TIMEOUT;
1121 }
1122
1123 return Status;
1124 }
1125
1126 /**
1127 Delete a single asynchronous interrupt transfer for
1128 the device and endpoint.
1129
1130 @param Xhc The XHCI Instance.
1131 @param BusAddr The logical device address assigned by UsbBus driver.
1132 @param EpNum The endpoint of the target.
1133
1134 @retval EFI_SUCCESS An asynchronous transfer is removed.
1135 @retval EFI_NOT_FOUND No transfer for the device is found.
1136
1137 **/
1138 EFI_STATUS
1139 XhciDelAsyncIntTransfer (
1140 IN USB_XHCI_INSTANCE *Xhc,
1141 IN UINT8 BusAddr,
1142 IN UINT8 EpNum
1143 )
1144 {
1145 LIST_ENTRY *Entry;
1146 LIST_ENTRY *Next;
1147 URB *Urb;
1148 EFI_USB_DATA_DIRECTION Direction;
1149
1150 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;
1151 EpNum &= 0x0F;
1152
1153 Urb = NULL;
1154
1155 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1156 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1157 if ((Urb->Ep.BusAddr == BusAddr) &&
1158 (Urb->Ep.EpAddr == EpNum) &&
1159 (Urb->Ep.Direction == Direction)) {
1160 RemoveEntryList (&Urb->UrbList);
1161 FreePool (Urb->Data);
1162 FreePool (Urb);
1163 return EFI_SUCCESS;
1164 }
1165 }
1166
1167 return EFI_NOT_FOUND;
1168 }
1169
1170 /**
1171 Remove all the asynchronous interrutp transfers.
1172
1173 @param Xhc The XHCI Instance.
1174
1175 **/
1176 VOID
1177 XhciDelAllAsyncIntTransfers (
1178 IN USB_XHCI_INSTANCE *Xhc
1179 )
1180 {
1181 LIST_ENTRY *Entry;
1182 LIST_ENTRY *Next;
1183 URB *Urb;
1184
1185 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1186 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1187 RemoveEntryList (&Urb->UrbList);
1188 FreePool (Urb->Data);
1189 FreePool (Urb);
1190 }
1191 }
1192
1193 /**
1194 Update the queue head for next round of asynchronous transfer
1195
1196 @param Xhc The XHCI Instance.
1197 @param Urb The URB to update
1198
1199 **/
1200 VOID
1201 XhcUpdateAsyncRequest (
1202 IN USB_XHCI_INSTANCE *Xhc,
1203 IN URB *Urb
1204 )
1205 {
1206 EFI_STATUS Status;
1207
1208 if (Urb->Result == EFI_USB_NOERROR) {
1209 Status = XhcCreateTransferTrb (Xhc, Urb);
1210 if (EFI_ERROR (Status)) {
1211 return;
1212 }
1213 Status = RingIntTransferDoorBell (Xhc, Urb);
1214 if (EFI_ERROR (Status)) {
1215 return;
1216 }
1217 }
1218 }
1219
1220
1221 /**
1222 Interrupt transfer periodic check handler.
1223
1224 @param Event Interrupt event.
1225 @param Context Pointer to USB_XHCI_INSTANCE.
1226
1227 **/
1228 VOID
1229 EFIAPI
1230 XhcMonitorAsyncRequests (
1231 IN EFI_EVENT Event,
1232 IN VOID *Context
1233 )
1234 {
1235 USB_XHCI_INSTANCE *Xhc;
1236 LIST_ENTRY *Entry;
1237 LIST_ENTRY *Next;
1238 UINT8 *ProcBuf;
1239 URB *Urb;
1240 UINT8 SlotId;
1241 EFI_STATUS Status;
1242 EFI_TPL OldTpl;
1243
1244 OldTpl = gBS->RaiseTPL (XHC_TPL);
1245
1246 Xhc = (USB_XHCI_INSTANCE*) Context;
1247
1248 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {
1249 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1250
1251 //
1252 // Make sure that the device is available before every check.
1253 //
1254 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1255 if (SlotId == 0) {
1256 continue;
1257 }
1258
1259 //
1260 // Check the result of URB execution. If it is still
1261 // active, check the next one.
1262 //
1263 Status = XhcCheckUrbResult (Xhc, Urb);
1264
1265 if (!Urb->Finished) {
1266 continue;
1267 }
1268
1269 //
1270 // Allocate a buffer then copy the transferred data for user.
1271 // If failed to allocate the buffer, update the URB for next
1272 // round of transfer. Ignore the data of this round.
1273 //
1274 ProcBuf = NULL;
1275 if (Urb->Result == EFI_USB_NOERROR) {
1276 ASSERT (Urb->Completed <= Urb->DataLen);
1277
1278 ProcBuf = AllocateZeroPool (Urb->Completed);
1279
1280 if (ProcBuf == NULL) {
1281 XhcUpdateAsyncRequest (Xhc, Urb);
1282 continue;
1283 }
1284
1285 CopyMem (ProcBuf, Urb->Data, Urb->Completed);
1286 }
1287
1288 //
1289 // Leave error recovery to its related device driver. A
1290 // common case of the error recovery is to re-submit the
1291 // interrupt transfer which is linked to the head of the
1292 // list. This function scans from head to tail. So the
1293 // re-submitted interrupt transfer's callback function
1294 // will not be called again in this round. Don't touch this
1295 // URB after the callback, it may have been removed by the
1296 // callback.
1297 //
1298 if (Urb->Callback != NULL) {
1299 //
1300 // Restore the old TPL, USB bus maybe connect device in
1301 // his callback. Some drivers may has a lower TPL restriction.
1302 //
1303 gBS->RestoreTPL (OldTpl);
1304 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
1305 OldTpl = gBS->RaiseTPL (XHC_TPL);
1306 }
1307
1308 if (ProcBuf != NULL) {
1309 gBS->FreePool (ProcBuf);
1310 }
1311
1312 XhcUpdateAsyncRequest (Xhc, Urb);
1313 }
1314 gBS->RestoreTPL (OldTpl);
1315 }
1316
1317 /**
1318 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1319
1320 @param Xhc The XHCI Instance.
1321 @param ParentRouteChart The route string pointed to the parent device if it exists.
1322 @param Port The port to be polled.
1323 @param PortState The port state.
1324
1325 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1326 @retval Others Should not appear.
1327
1328 **/
1329 EFI_STATUS
1330 EFIAPI
1331 XhcPollPortStatusChange (
1332 IN USB_XHCI_INSTANCE *Xhc,
1333 IN USB_DEV_ROUTE ParentRouteChart,
1334 IN UINT8 Port,
1335 IN EFI_USB_PORT_STATUS *PortState
1336 )
1337 {
1338 EFI_STATUS Status;
1339 UINT8 Speed;
1340 UINT8 SlotId;
1341 USB_DEV_ROUTE RouteChart;
1342
1343 Status = EFI_SUCCESS;
1344
1345 if (ParentRouteChart.Dword == 0) {
1346 RouteChart.Route.RouteString = 0;
1347 RouteChart.Route.RootPortNum = Port + 1;
1348 RouteChart.Route.TierNum = 1;
1349 } else {
1350 if(Port < 14) {
1351 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));
1352 } else {
1353 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));
1354 }
1355 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;
1356 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
1357 }
1358
1359 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
1360 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
1361 //
1362 // Has a device attached, Identify device speed after port is enabled.
1363 //
1364 Speed = EFI_USB_SPEED_FULL;
1365 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
1366 Speed = EFI_USB_SPEED_LOW;
1367 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
1368 Speed = EFI_USB_SPEED_HIGH;
1369 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
1370 Speed = EFI_USB_SPEED_SUPER;
1371 }
1372 //
1373 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1374 //
1375 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1376 if (SlotId == 0) {
1377 if (Xhc->HcCParams.Data.Csz == 0) {
1378 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1379 } else {
1380 Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
1381 }
1382 ASSERT_EFI_ERROR (Status);
1383 }
1384 } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {
1385 //
1386 // Device is detached. Disable the allocated device slot and release resource.
1387 //
1388 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
1389 if (SlotId != 0) {
1390 if (Xhc->HcCParams.Data.Csz == 0) {
1391 Status = XhcDisableSlotCmd (Xhc, SlotId);
1392 } else {
1393 Status = XhcDisableSlotCmd64 (Xhc, SlotId);
1394 }
1395 ASSERT_EFI_ERROR (Status);
1396 }
1397 }
1398 return Status;
1399 }
1400
1401
1402 /**
1403 Calculate the device context index by endpoint address and direction.
1404
1405 @param EpAddr The target endpoint number.
1406 @param Direction The direction of the target endpoint.
1407
1408 @return The device context index of endpoint.
1409
1410 **/
1411 UINT8
1412 XhcEndpointToDci (
1413 IN UINT8 EpAddr,
1414 IN UINT8 Direction
1415 )
1416 {
1417 UINT8 Index;
1418
1419 if (EpAddr == 0) {
1420 return 1;
1421 } else {
1422 Index = (UINT8) (2 * EpAddr);
1423 if (Direction == EfiUsbDataIn) {
1424 Index += 1;
1425 }
1426 return Index;
1427 }
1428 }
1429
1430 /**
1431 Find out the actual device address according to the requested device address from UsbBus.
1432
1433 @param Xhc The XHCI Instance.
1434 @param BusDevAddr The requested device address by UsbBus upper driver.
1435
1436 @return The actual device address assigned to the device.
1437
1438 **/
1439 UINT8
1440 EFIAPI
1441 XhcBusDevAddrToSlotId (
1442 IN USB_XHCI_INSTANCE *Xhc,
1443 IN UINT8 BusDevAddr
1444 )
1445 {
1446 UINT8 Index;
1447
1448 for (Index = 0; Index < 255; Index++) {
1449 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1450 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1451 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {
1452 break;
1453 }
1454 }
1455
1456 if (Index == 255) {
1457 return 0;
1458 }
1459
1460 return Xhc->UsbDevContext[Index + 1].SlotId;
1461 }
1462
1463 /**
1464 Find out the slot id according to the device's route string.
1465
1466 @param Xhc The XHCI Instance.
1467 @param RouteString The route string described the device location.
1468
1469 @return The slot id used by the device.
1470
1471 **/
1472 UINT8
1473 EFIAPI
1474 XhcRouteStringToSlotId (
1475 IN USB_XHCI_INSTANCE *Xhc,
1476 IN USB_DEV_ROUTE RouteString
1477 )
1478 {
1479 UINT8 Index;
1480
1481 for (Index = 0; Index < 255; Index++) {
1482 if (Xhc->UsbDevContext[Index + 1].Enabled &&
1483 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&
1484 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {
1485 break;
1486 }
1487 }
1488
1489 if (Index == 255) {
1490 return 0;
1491 }
1492
1493 return Xhc->UsbDevContext[Index + 1].SlotId;
1494 }
1495
1496 /**
1497 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1498
1499 @param Xhc The XHCI Instance.
1500 @param EvtRing The event ring to sync.
1501
1502 @retval EFI_SUCCESS The event ring is synchronized successfully.
1503
1504 **/
1505 EFI_STATUS
1506 EFIAPI
1507 XhcSyncEventRing (
1508 IN USB_XHCI_INSTANCE *Xhc,
1509 IN EVENT_RING *EvtRing
1510 )
1511 {
1512 UINTN Index;
1513 TRB_TEMPLATE *EvtTrb1;
1514
1515 ASSERT (EvtRing != NULL);
1516
1517 //
1518 // Calculate the EventRingEnqueue and EventRingCCS.
1519 // Note: only support single Segment
1520 //
1521 EvtTrb1 = EvtRing->EventRingDequeue;
1522
1523 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {
1524 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {
1525 break;
1526 }
1527
1528 EvtTrb1++;
1529
1530 if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1531 EvtTrb1 = EvtRing->EventRingSeg0;
1532 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;
1533 }
1534 }
1535
1536 if (Index < EvtRing->TrbNumber) {
1537 EvtRing->EventRingEnqueue = EvtTrb1;
1538 } else {
1539 ASSERT (FALSE);
1540 }
1541
1542 return EFI_SUCCESS;
1543 }
1544
1545 /**
1546 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1547
1548 @param Xhc The XHCI Instance.
1549 @param TrsRing The transfer ring to sync.
1550
1551 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1552
1553 **/
1554 EFI_STATUS
1555 EFIAPI
1556 XhcSyncTrsRing (
1557 IN USB_XHCI_INSTANCE *Xhc,
1558 IN TRANSFER_RING *TrsRing
1559 )
1560 {
1561 UINTN Index;
1562 TRB_TEMPLATE *TrsTrb;
1563
1564 ASSERT (TrsRing != NULL);
1565 //
1566 // Calculate the latest RingEnqueue and RingPCS
1567 //
1568 TrsTrb = TrsRing->RingEnqueue;
1569 ASSERT (TrsTrb != NULL);
1570
1571 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {
1572 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {
1573 break;
1574 }
1575 TrsTrb++;
1576 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {
1577 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);
1578 //
1579 // set cycle bit in Link TRB as normal
1580 //
1581 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;
1582 //
1583 // Toggle PCS maintained by software
1584 //
1585 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;
1586 TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | LShiftU64 ((UINT64)TrsTrb->Parameter2, 32)) & ~0x0F);
1587 }
1588 }
1589
1590 ASSERT (Index != TrsRing->TrbNumber);
1591
1592 if (TrsTrb != TrsRing->RingEnqueue) {
1593 TrsRing->RingEnqueue = TrsTrb;
1594 }
1595
1596 //
1597 // Clear the Trb context for enqueue, but reserve the PCS bit
1598 //
1599 TrsTrb->Parameter1 = 0;
1600 TrsTrb->Parameter2 = 0;
1601 TrsTrb->Status = 0;
1602 TrsTrb->RsvdZ1 = 0;
1603 TrsTrb->Type = 0;
1604 TrsTrb->Control = 0;
1605
1606 return EFI_SUCCESS;
1607 }
1608
1609 /**
1610 Check if there is a new generated event.
1611
1612 @param Xhc The XHCI Instance.
1613 @param EvtRing The event ring to check.
1614 @param NewEvtTrb The new event TRB found.
1615
1616 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1617 @retval EFI_NOT_READY The event ring has no new event.
1618
1619 **/
1620 EFI_STATUS
1621 EFIAPI
1622 XhcCheckNewEvent (
1623 IN USB_XHCI_INSTANCE *Xhc,
1624 IN EVENT_RING *EvtRing,
1625 OUT TRB_TEMPLATE **NewEvtTrb
1626 )
1627 {
1628 EFI_STATUS Status;
1629 TRB_TEMPLATE *EvtTrb;
1630
1631 ASSERT (EvtRing != NULL);
1632
1633 EvtTrb = EvtRing->EventRingDequeue;
1634 *NewEvtTrb = EvtRing->EventRingDequeue;
1635
1636 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {
1637 return EFI_NOT_READY;
1638 }
1639
1640 Status = EFI_SUCCESS;
1641
1642 EvtRing->EventRingDequeue++;
1643 //
1644 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1645 //
1646 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {
1647 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;
1648 }
1649
1650 return Status;
1651 }
1652
1653 /**
1654 Ring the door bell to notify XHCI there is a transaction to be executed.
1655
1656 @param Xhc The XHCI Instance.
1657 @param SlotId The slot id of the target device.
1658 @param Dci The device context index of the target slot or endpoint.
1659
1660 @retval EFI_SUCCESS Successfully ring the door bell.
1661
1662 **/
1663 EFI_STATUS
1664 EFIAPI
1665 XhcRingDoorBell (
1666 IN USB_XHCI_INSTANCE *Xhc,
1667 IN UINT8 SlotId,
1668 IN UINT8 Dci
1669 )
1670 {
1671 if (SlotId == 0) {
1672 XhcWriteDoorBellReg (Xhc, 0, 0);
1673 } else {
1674 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);
1675 }
1676
1677 return EFI_SUCCESS;
1678 }
1679
1680 /**
1681 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1682
1683 @param Xhc The XHCI Instance.
1684 @param Urb The URB to be rung.
1685
1686 @retval EFI_SUCCESS Successfully ring the door bell.
1687
1688 **/
1689 EFI_STATUS
1690 RingIntTransferDoorBell (
1691 IN USB_XHCI_INSTANCE *Xhc,
1692 IN URB *Urb
1693 )
1694 {
1695 UINT8 SlotId;
1696 UINT8 Dci;
1697
1698 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
1699 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));
1700 XhcRingDoorBell (Xhc, SlotId, Dci);
1701 return EFI_SUCCESS;
1702 }
1703
1704 /**
1705 Assign and initialize the device slot for a new device.
1706
1707 @param Xhc The XHCI Instance.
1708 @param ParentRouteChart The route string pointed to the parent device.
1709 @param ParentPort The port at which the device is located.
1710 @param RouteChart The route string pointed to the device.
1711 @param DeviceSpeed The device speed.
1712
1713 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1714
1715 **/
1716 EFI_STATUS
1717 EFIAPI
1718 XhcInitializeDeviceSlot (
1719 IN USB_XHCI_INSTANCE *Xhc,
1720 IN USB_DEV_ROUTE ParentRouteChart,
1721 IN UINT16 ParentPort,
1722 IN USB_DEV_ROUTE RouteChart,
1723 IN UINT8 DeviceSpeed
1724 )
1725 {
1726 EFI_STATUS Status;
1727 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
1728 INPUT_CONTEXT *InputContext;
1729 DEVICE_CONTEXT *OutputContext;
1730 TRANSFER_RING *EndpointTransferRing;
1731 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
1732 UINT8 DeviceAddress;
1733 CMD_TRB_ENABLE_SLOT CmdTrb;
1734 UINT8 SlotId;
1735 UINT8 ParentSlotId;
1736 DEVICE_CONTEXT *ParentDeviceContext;
1737
1738 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1739 CmdTrb.CycleBit = 1;
1740 CmdTrb.Type = TRB_TYPE_EN_SLOT;
1741
1742 Status = XhcCmdTransfer (
1743 Xhc,
1744 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1745 XHC_GENERIC_TIMEOUT,
1746 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1747 );
1748 ASSERT_EFI_ERROR (Status);
1749 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1750 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1751 SlotId = (UINT8)EvtTrb->SlotId;
1752 ASSERT (SlotId != 0);
1753
1754 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1755 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
1756 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
1757 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
1758 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1759
1760 //
1761 // 4.3.3 Device Slot Initialization
1762 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1763 //
1764 InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));
1765 ASSERT (InputContext != NULL);
1766 ASSERT (((UINTN) InputContext & 0x3F) == 0);
1767 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
1768
1769 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1770
1771 //
1772 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1773 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1774 // Context are affected by the command.
1775 //
1776 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1777
1778 //
1779 // 3) Initialize the Input Slot Context data structure
1780 //
1781 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
1782 InputContext->Slot.Speed = DeviceSpeed + 1;
1783 InputContext->Slot.ContextEntries = 1;
1784 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1785
1786 if (RouteChart.Route.RouteString) {
1787 //
1788 // The device is behind of hub device.
1789 //
1790 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
1791 ASSERT (ParentSlotId != 0);
1792 //
1793 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1794 //
1795 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
1796 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1797 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1798 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1799 //
1800 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1801 // environment from Full/Low speed signaling environment for a device
1802 //
1803 InputContext->Slot.TTPortNum = ParentPort;
1804 InputContext->Slot.TTHubSlotId = ParentSlotId;
1805 }
1806 } else {
1807 //
1808 // Inherit the TT parameters from parent device.
1809 //
1810 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
1811 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
1812 //
1813 // If the device is a High speed device then down the speed to be the same as its parent Hub
1814 //
1815 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1816 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
1817 }
1818 }
1819 }
1820
1821 //
1822 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1823 //
1824 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
1825 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
1826 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
1827 //
1828 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1829 //
1830 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
1831
1832 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1833 InputContext->EP[0].MaxPacketSize = 512;
1834 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1835 InputContext->EP[0].MaxPacketSize = 64;
1836 } else {
1837 InputContext->EP[0].MaxPacketSize = 8;
1838 }
1839 //
1840 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1841 // 1KB, and Bulk and Isoch endpoints 3KB.
1842 //
1843 InputContext->EP[0].AverageTRBLength = 8;
1844 InputContext->EP[0].MaxBurstSize = 0;
1845 InputContext->EP[0].Interval = 0;
1846 InputContext->EP[0].MaxPStreams = 0;
1847 InputContext->EP[0].Mult = 0;
1848 InputContext->EP[0].CErr = 3;
1849
1850 //
1851 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1852 //
1853 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0;
1854 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0);
1855
1856 //
1857 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1858 //
1859 OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));
1860 ASSERT (OutputContext != NULL);
1861 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
1862 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
1863
1864 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
1865 //
1866 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1867 // a pointer to the Output Device Context data structure (6.2.1).
1868 //
1869 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputContext;
1870
1871 //
1872 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1873 // Context data structure described above.
1874 //
1875 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
1876 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
1877 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
1878 CmdTrbAddr.CycleBit = 1;
1879 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
1880 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
1881 Status = XhcCmdTransfer (
1882 Xhc,
1883 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
1884 XHC_GENERIC_TIMEOUT,
1885 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1886 );
1887 ASSERT (!EFI_ERROR(Status));
1888
1889 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;
1890 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
1891
1892 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
1893
1894 return Status;
1895 }
1896
1897 /**
1898 Assign and initialize the device slot for a new device.
1899
1900 @param Xhc The XHCI Instance.
1901 @param ParentRouteChart The route string pointed to the parent device.
1902 @param ParentPort The port at which the device is located.
1903 @param RouteChart The route string pointed to the device.
1904 @param DeviceSpeed The device speed.
1905
1906 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1907
1908 **/
1909 EFI_STATUS
1910 EFIAPI
1911 XhcInitializeDeviceSlot64 (
1912 IN USB_XHCI_INSTANCE *Xhc,
1913 IN USB_DEV_ROUTE ParentRouteChart,
1914 IN UINT16 ParentPort,
1915 IN USB_DEV_ROUTE RouteChart,
1916 IN UINT8 DeviceSpeed
1917 )
1918 {
1919 EFI_STATUS Status;
1920 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
1921 INPUT_CONTEXT_64 *InputContext;
1922 DEVICE_CONTEXT_64 *OutputContext;
1923 TRANSFER_RING *EndpointTransferRing;
1924 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;
1925 UINT8 DeviceAddress;
1926 CMD_TRB_ENABLE_SLOT CmdTrb;
1927 UINT8 SlotId;
1928 UINT8 ParentSlotId;
1929 DEVICE_CONTEXT_64 *ParentDeviceContext;
1930
1931 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));
1932 CmdTrb.CycleBit = 1;
1933 CmdTrb.Type = TRB_TYPE_EN_SLOT;
1934
1935 Status = XhcCmdTransfer (
1936 Xhc,
1937 (TRB_TEMPLATE *) (UINTN) &CmdTrb,
1938 XHC_GENERIC_TIMEOUT,
1939 (TRB_TEMPLATE **) (UINTN) &EvtTrb
1940 );
1941 ASSERT_EFI_ERROR (Status);
1942 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);
1943 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));
1944 SlotId = (UINT8)EvtTrb->SlotId;
1945 ASSERT (SlotId != 0);
1946
1947 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));
1948 Xhc->UsbDevContext[SlotId].Enabled = TRUE;
1949 Xhc->UsbDevContext[SlotId].SlotId = SlotId;
1950 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;
1951 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;
1952
1953 //
1954 // 4.3.3 Device Slot Initialization
1955 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1956 //
1957 InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT_64)));
1958 ASSERT (InputContext != NULL);
1959 ASSERT (((UINTN) InputContext & 0x3F) == 0);
1960 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
1961
1962 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;
1963
1964 //
1965 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1966 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1967 // Context are affected by the command.
1968 //
1969 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);
1970
1971 //
1972 // 3) Initialize the Input Slot Context data structure
1973 //
1974 InputContext->Slot.RouteString = RouteChart.Route.RouteString;
1975 InputContext->Slot.Speed = DeviceSpeed + 1;
1976 InputContext->Slot.ContextEntries = 1;
1977 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;
1978
1979 if (RouteChart.Route.RouteString) {
1980 //
1981 // The device is behind of hub device.
1982 //
1983 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);
1984 ASSERT (ParentSlotId != 0);
1985 //
1986 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1987 //
1988 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;
1989 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&
1990 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {
1991 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {
1992 //
1993 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1994 // environment from Full/Low speed signaling environment for a device
1995 //
1996 InputContext->Slot.TTPortNum = ParentPort;
1997 InputContext->Slot.TTHubSlotId = ParentSlotId;
1998 }
1999 } else {
2000 //
2001 // Inherit the TT parameters from parent device.
2002 //
2003 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;
2004 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;
2005 //
2006 // If the device is a High speed device then down the speed to be the same as its parent Hub
2007 //
2008 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2009 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;
2010 }
2011 }
2012 }
2013
2014 //
2015 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2016 //
2017 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));
2018 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;
2019 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);
2020 //
2021 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2022 //
2023 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;
2024
2025 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2026 InputContext->EP[0].MaxPacketSize = 512;
2027 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
2028 InputContext->EP[0].MaxPacketSize = 64;
2029 } else {
2030 InputContext->EP[0].MaxPacketSize = 8;
2031 }
2032 //
2033 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2034 // 1KB, and Bulk and Isoch endpoints 3KB.
2035 //
2036 InputContext->EP[0].AverageTRBLength = 8;
2037 InputContext->EP[0].MaxBurstSize = 0;
2038 InputContext->EP[0].Interval = 0;
2039 InputContext->EP[0].MaxPStreams = 0;
2040 InputContext->EP[0].Mult = 0;
2041 InputContext->EP[0].CErr = 3;
2042
2043 //
2044 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2045 //
2046 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0;
2047 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0);
2048
2049 //
2050 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2051 //
2052 OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT_64)));
2053 ASSERT (OutputContext != NULL);
2054 ASSERT (((UINTN) OutputContext & 0x3F) == 0);
2055 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));
2056
2057 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;
2058 //
2059 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2060 // a pointer to the Output Device Context data structure (6.2.1).
2061 //
2062 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputContext;
2063
2064 //
2065 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2066 // Context data structure described above.
2067 //
2068 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));
2069 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
2070 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (Xhc->UsbDevContext[SlotId].InputContext);
2071 CmdTrbAddr.CycleBit = 1;
2072 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;
2073 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2074 Status = XhcCmdTransfer (
2075 Xhc,
2076 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,
2077 XHC_GENERIC_TIMEOUT,
2078 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2079 );
2080 ASSERT (!EFI_ERROR(Status));
2081
2082 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;
2083 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));
2084
2085 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;
2086
2087 return Status;
2088 }
2089
2090
2091 /**
2092 Disable the specified device slot.
2093
2094 @param Xhc The XHCI Instance.
2095 @param SlotId The slot id to be disabled.
2096
2097 @retval EFI_SUCCESS Successfully disable the device slot.
2098
2099 **/
2100 EFI_STATUS
2101 EFIAPI
2102 XhcDisableSlotCmd (
2103 IN USB_XHCI_INSTANCE *Xhc,
2104 IN UINT8 SlotId
2105 )
2106 {
2107 EFI_STATUS Status;
2108 TRB_TEMPLATE *EvtTrb;
2109 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2110 UINT8 Index;
2111 VOID *RingSeg;
2112
2113 //
2114 // Disable the device slots occupied by these devices on its downstream ports.
2115 // Entry 0 is reserved.
2116 //
2117 for (Index = 0; Index < 255; Index++) {
2118 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2119 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2120 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2121 continue;
2122 }
2123
2124 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2125
2126 if (EFI_ERROR (Status)) {
2127 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2128 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2129 }
2130 }
2131
2132 //
2133 // Construct the disable slot command
2134 //
2135 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2136
2137 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2138 CmdTrbDisSlot.CycleBit = 1;
2139 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2140 CmdTrbDisSlot.SlotId = SlotId;
2141 Status = XhcCmdTransfer (
2142 Xhc,
2143 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2144 XHC_GENERIC_TIMEOUT,
2145 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2146 );
2147 ASSERT_EFI_ERROR(Status);
2148 //
2149 // Free the slot's device context entry
2150 //
2151 Xhc->DCBAA[SlotId] = 0;
2152
2153 //
2154 // Free the slot related data structure
2155 //
2156 for (Index = 0; Index < 31; Index++) {
2157 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2158 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2159 if (RingSeg != NULL) {
2160 FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER));
2161 }
2162 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2163 }
2164 }
2165
2166 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2167 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2168 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2169 }
2170 }
2171
2172 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2173 FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));
2174 }
2175
2176 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2177 FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));
2178 }
2179 //
2180 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2181 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2182 // remove urb from XHCI's asynchronous transfer list.
2183 //
2184 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2185 Xhc->UsbDevContext[SlotId].SlotId = 0;
2186
2187 return Status;
2188 }
2189
2190 /**
2191 Disable the specified device slot.
2192
2193 @param Xhc The XHCI Instance.
2194 @param SlotId The slot id to be disabled.
2195
2196 @retval EFI_SUCCESS Successfully disable the device slot.
2197
2198 **/
2199 EFI_STATUS
2200 EFIAPI
2201 XhcDisableSlotCmd64 (
2202 IN USB_XHCI_INSTANCE *Xhc,
2203 IN UINT8 SlotId
2204 )
2205 {
2206 EFI_STATUS Status;
2207 TRB_TEMPLATE *EvtTrb;
2208 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;
2209 UINT8 Index;
2210 VOID *RingSeg;
2211
2212 //
2213 // Disable the device slots occupied by these devices on its downstream ports.
2214 // Entry 0 is reserved.
2215 //
2216 for (Index = 0; Index < 255; Index++) {
2217 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2218 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||
2219 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {
2220 continue;
2221 }
2222
2223 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2224
2225 if (EFI_ERROR (Status)) {
2226 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2227 Xhc->UsbDevContext[Index + 1].SlotId = 0;
2228 }
2229 }
2230
2231 //
2232 // Construct the disable slot command
2233 //
2234 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));
2235
2236 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));
2237 CmdTrbDisSlot.CycleBit = 1;
2238 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;
2239 CmdTrbDisSlot.SlotId = SlotId;
2240 Status = XhcCmdTransfer (
2241 Xhc,
2242 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,
2243 XHC_GENERIC_TIMEOUT,
2244 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2245 );
2246 ASSERT_EFI_ERROR(Status);
2247 //
2248 // Free the slot's device context entry
2249 //
2250 Xhc->DCBAA[SlotId] = 0;
2251
2252 //
2253 // Free the slot related data structure
2254 //
2255 for (Index = 0; Index < 31; Index++) {
2256 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {
2257 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;
2258 if (RingSeg != NULL) {
2259 FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER));
2260 }
2261 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);
2262 }
2263 }
2264
2265 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
2266 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {
2267 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
2268 }
2269 }
2270
2271 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {
2272 FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT_64)));
2273 }
2274
2275 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {
2276 FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT_64)));
2277 }
2278 //
2279 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2280 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2281 // remove urb from XHCI's asynchronous transfer list.
2282 //
2283 Xhc->UsbDevContext[SlotId].Enabled = FALSE;
2284 Xhc->UsbDevContext[SlotId].SlotId = 0;
2285
2286 return Status;
2287 }
2288
2289
2290 /**
2291 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2292
2293 @param Xhc The XHCI Instance.
2294 @param SlotId The slot id to be configured.
2295 @param DeviceSpeed The device's speed.
2296 @param ConfigDesc The pointer to the usb device configuration descriptor.
2297
2298 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2299
2300 **/
2301 EFI_STATUS
2302 EFIAPI
2303 XhcSetConfigCmd (
2304 IN USB_XHCI_INSTANCE *Xhc,
2305 IN UINT8 SlotId,
2306 IN UINT8 DeviceSpeed,
2307 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
2308 )
2309 {
2310 EFI_STATUS Status;
2311
2312 USB_INTERFACE_DESCRIPTOR *IfDesc;
2313 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2314 UINT8 Index;
2315 UINTN NumEp;
2316 UINTN EpIndex;
2317 UINT8 EpAddr;
2318 UINT8 Direction;
2319 UINT8 Dci;
2320 UINT8 MaxDci;
2321 UINT32 PhyAddr;
2322 UINT8 Interval;
2323
2324 TRANSFER_RING *EndpointTransferRing;
2325 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2326 INPUT_CONTEXT *InputContext;
2327 DEVICE_CONTEXT *OutputContext;
2328 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2329 //
2330 // 4.6.6 Configure Endpoint
2331 //
2332 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2333 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2334 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2335 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));
2336
2337 ASSERT (ConfigDesc != NULL);
2338
2339 MaxDci = 0;
2340
2341 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
2342 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
2343 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {
2344 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2345 }
2346
2347 NumEp = IfDesc->NumEndpoints;
2348
2349 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2350 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2351 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2352 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2353 }
2354
2355 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2356 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2357
2358 Dci = XhcEndpointToDci (EpAddr, Direction);
2359 ASSERT (Dci < 32);
2360 if (Dci > MaxDci) {
2361 MaxDci = Dci;
2362 }
2363
2364 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2365 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2366
2367 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2368 //
2369 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2370 //
2371 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2372 } else {
2373 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2374 }
2375
2376 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2377 case USB_ENDPOINT_BULK:
2378 if (Direction == EfiUsbDataIn) {
2379 InputContext->EP[Dci-1].CErr = 3;
2380 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2381 } else {
2382 InputContext->EP[Dci-1].CErr = 3;
2383 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2384 }
2385
2386 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2387 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2388 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2389 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2390 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2391 }
2392
2393 break;
2394 case USB_ENDPOINT_ISO:
2395 if (Direction == EfiUsbDataIn) {
2396 InputContext->EP[Dci-1].CErr = 0;
2397 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2398 } else {
2399 InputContext->EP[Dci-1].CErr = 0;
2400 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2401 }
2402 break;
2403 case USB_ENDPOINT_INTERRUPT:
2404 if (Direction == EfiUsbDataIn) {
2405 InputContext->EP[Dci-1].CErr = 3;
2406 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2407 } else {
2408 InputContext->EP[Dci-1].CErr = 3;
2409 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2410 }
2411 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2412 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2413 //
2414 // Get the bInterval from descriptor and init the the interval field of endpoint context
2415 //
2416 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2417 Interval = EpDesc->Interval;
2418 //
2419 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2420 //
2421 InputContext->EP[Dci-1].Interval = 6;
2422 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2423 Interval = EpDesc->Interval;
2424 ASSERT (Interval >= 1 && Interval <= 16);
2425 //
2426 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2427 //
2428 InputContext->EP[Dci-1].Interval = Interval - 1;
2429 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2430 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2431 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2432 InputContext->EP[Dci-1].CErr = 3;
2433 }
2434
2435 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2436 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2437 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2438 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2439 }
2440 break;
2441
2442 case USB_ENDPOINT_CONTROL:
2443 default:
2444 ASSERT (0);
2445 break;
2446 }
2447
2448 PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2449 PhyAddr &= ~(0x0F);
2450 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2451 InputContext->EP[Dci-1].PtrLo = PhyAddr;
2452 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2453
2454 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2455 }
2456 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2457 }
2458
2459 InputContext->InputControlContext.Dword2 |= BIT0;
2460 InputContext->Slot.ContextEntries = MaxDci;
2461 //
2462 // configure endpoint
2463 //
2464 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2465 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2466 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2467 CmdTrbCfgEP.CycleBit = 1;
2468 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2469 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2470 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
2471 Status = XhcCmdTransfer (
2472 Xhc,
2473 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2474 XHC_GENERIC_TIMEOUT,
2475 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2476 );
2477 ASSERT_EFI_ERROR(Status);
2478
2479 return Status;
2480 }
2481
2482 /**
2483 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2484
2485 @param Xhc The XHCI Instance.
2486 @param SlotId The slot id to be configured.
2487 @param DeviceSpeed The device's speed.
2488 @param ConfigDesc The pointer to the usb device configuration descriptor.
2489
2490 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2491
2492 **/
2493 EFI_STATUS
2494 EFIAPI
2495 XhcSetConfigCmd64 (
2496 IN USB_XHCI_INSTANCE *Xhc,
2497 IN UINT8 SlotId,
2498 IN UINT8 DeviceSpeed,
2499 IN USB_CONFIG_DESCRIPTOR *ConfigDesc
2500 )
2501 {
2502 EFI_STATUS Status;
2503
2504 USB_INTERFACE_DESCRIPTOR *IfDesc;
2505 USB_ENDPOINT_DESCRIPTOR *EpDesc;
2506 UINT8 Index;
2507 UINTN NumEp;
2508 UINTN EpIndex;
2509 UINT8 EpAddr;
2510 UINT8 Direction;
2511 UINT8 Dci;
2512 UINT8 MaxDci;
2513 UINT32 PhyAddr;
2514 UINT8 Interval;
2515
2516 TRANSFER_RING *EndpointTransferRing;
2517 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2518 INPUT_CONTEXT_64 *InputContext;
2519 DEVICE_CONTEXT_64 *OutputContext;
2520 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2521 //
2522 // 4.6.6 Configure Endpoint
2523 //
2524 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2525 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2526 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2527 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));
2528
2529 ASSERT (ConfigDesc != NULL);
2530
2531 MaxDci = 0;
2532
2533 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);
2534 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {
2535 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {
2536 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2537 }
2538
2539 NumEp = IfDesc->NumEndpoints;
2540
2541 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);
2542 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {
2543 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {
2544 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2545 }
2546
2547 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);
2548 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);
2549
2550 Dci = XhcEndpointToDci (EpAddr, Direction);
2551 ASSERT (Dci < 32);
2552 if (Dci > MaxDci) {
2553 MaxDci = Dci;
2554 }
2555
2556 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);
2557 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;
2558
2559 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
2560 //
2561 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2562 //
2563 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2564 } else {
2565 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2566 }
2567
2568 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {
2569 case USB_ENDPOINT_BULK:
2570 if (Direction == EfiUsbDataIn) {
2571 InputContext->EP[Dci-1].CErr = 3;
2572 InputContext->EP[Dci-1].EPType = ED_BULK_IN;
2573 } else {
2574 InputContext->EP[Dci-1].CErr = 3;
2575 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;
2576 }
2577
2578 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2579 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2580 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2581 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2582 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2583 }
2584
2585 break;
2586 case USB_ENDPOINT_ISO:
2587 if (Direction == EfiUsbDataIn) {
2588 InputContext->EP[Dci-1].CErr = 0;
2589 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;
2590 } else {
2591 InputContext->EP[Dci-1].CErr = 0;
2592 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;
2593 }
2594 break;
2595 case USB_ENDPOINT_INTERRUPT:
2596 if (Direction == EfiUsbDataIn) {
2597 InputContext->EP[Dci-1].CErr = 3;
2598 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;
2599 } else {
2600 InputContext->EP[Dci-1].CErr = 3;
2601 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;
2602 }
2603 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2604 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;
2605 //
2606 // Get the bInterval from descriptor and init the the interval field of endpoint context
2607 //
2608 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
2609 Interval = EpDesc->Interval;
2610 //
2611 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2612 //
2613 InputContext->EP[Dci-1].Interval = 6;
2614 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
2615 Interval = EpDesc->Interval;
2616 ASSERT (Interval >= 1 && Interval <= 16);
2617 //
2618 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2619 //
2620 InputContext->EP[Dci-1].Interval = Interval - 1;
2621 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;
2622 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;
2623 InputContext->EP[Dci-1].MaxBurstSize = 0x0;
2624 InputContext->EP[Dci-1].CErr = 3;
2625 }
2626
2627 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {
2628 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));
2629 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;
2630 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);
2631 }
2632 break;
2633
2634 case USB_ENDPOINT_CONTROL:
2635 default:
2636 ASSERT (0);
2637 break;
2638 }
2639
2640 PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2641 PhyAddr &= ~(0x0F);
2642 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;
2643 InputContext->EP[Dci-1].PtrLo = PhyAddr;
2644 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);
2645
2646 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);
2647 }
2648 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);
2649 }
2650
2651 InputContext->InputControlContext.Dword2 |= BIT0;
2652 InputContext->Slot.ContextEntries = MaxDci;
2653 //
2654 // configure endpoint
2655 //
2656 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2657 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2658 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2659 CmdTrbCfgEP.CycleBit = 1;
2660 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2661 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2662 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));
2663 Status = XhcCmdTransfer (
2664 Xhc,
2665 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2666 XHC_GENERIC_TIMEOUT,
2667 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2668 );
2669 ASSERT_EFI_ERROR(Status);
2670
2671 return Status;
2672 }
2673
2674
2675 /**
2676 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2677
2678 @param Xhc The XHCI Instance.
2679 @param SlotId The slot id to be evaluated.
2680 @param MaxPacketSize The max packet size supported by the device control transfer.
2681
2682 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2683
2684 **/
2685 EFI_STATUS
2686 EFIAPI
2687 XhcEvaluateContext (
2688 IN USB_XHCI_INSTANCE *Xhc,
2689 IN UINT8 SlotId,
2690 IN UINT32 MaxPacketSize
2691 )
2692 {
2693 EFI_STATUS Status;
2694 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2695 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2696 INPUT_CONTEXT *InputContext;
2697
2698 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2699
2700 //
2701 // 4.6.7 Evaluate Context
2702 //
2703 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2704 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2705
2706 InputContext->InputControlContext.Dword2 |= BIT1;
2707 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2708
2709 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2710 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (InputContext);
2711 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext);
2712 CmdTrbEvalu.CycleBit = 1;
2713 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
2714 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2715 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
2716 Status = XhcCmdTransfer (
2717 Xhc,
2718 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2719 XHC_GENERIC_TIMEOUT,
2720 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2721 );
2722 ASSERT (!EFI_ERROR(Status));
2723
2724 return Status;
2725 }
2726
2727 /**
2728 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2729
2730 @param Xhc The XHCI Instance.
2731 @param SlotId The slot id to be evaluated.
2732 @param MaxPacketSize The max packet size supported by the device control transfer.
2733
2734 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2735
2736 **/
2737 EFI_STATUS
2738 EFIAPI
2739 XhcEvaluateContext64 (
2740 IN USB_XHCI_INSTANCE *Xhc,
2741 IN UINT8 SlotId,
2742 IN UINT32 MaxPacketSize
2743 )
2744 {
2745 EFI_STATUS Status;
2746 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;
2747 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2748 INPUT_CONTEXT_64 *InputContext;
2749
2750 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2751
2752 //
2753 // 4.6.7 Evaluate Context
2754 //
2755 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2756 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2757
2758 InputContext->InputControlContext.Dword2 |= BIT1;
2759 InputContext->EP[0].MaxPacketSize = MaxPacketSize;
2760
2761 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));
2762 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (InputContext);
2763 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext);
2764 CmdTrbEvalu.CycleBit = 1;
2765 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;
2766 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2767 DEBUG ((EFI_D_INFO, "Evaluate context\n"));
2768 Status = XhcCmdTransfer (
2769 Xhc,
2770 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,
2771 XHC_GENERIC_TIMEOUT,
2772 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2773 );
2774 ASSERT (!EFI_ERROR(Status));
2775
2776 return Status;
2777 }
2778
2779
2780 /**
2781 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2782
2783 @param Xhc The XHCI Instance.
2784 @param SlotId The slot id to be configured.
2785 @param PortNum The total number of downstream port supported by the hub.
2786 @param TTT The TT think time of the hub device.
2787 @param MTT The multi-TT of the hub device.
2788
2789 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2790
2791 **/
2792 EFI_STATUS
2793 XhcConfigHubContext (
2794 IN USB_XHCI_INSTANCE *Xhc,
2795 IN UINT8 SlotId,
2796 IN UINT8 PortNum,
2797 IN UINT8 TTT,
2798 IN UINT8 MTT
2799 )
2800 {
2801 EFI_STATUS Status;
2802
2803 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2804 INPUT_CONTEXT *InputContext;
2805 DEVICE_CONTEXT *OutputContext;
2806 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2807
2808 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2809 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2810 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2811
2812 //
2813 // 4.6.7 Evaluate Context
2814 //
2815 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
2816
2817 InputContext->InputControlContext.Dword2 |= BIT0;
2818
2819 //
2820 // Copy the slot context from OutputContext to Input context
2821 //
2822 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));
2823 InputContext->Slot.Hub = 1;
2824 InputContext->Slot.PortNum = PortNum;
2825 InputContext->Slot.TTT = TTT;
2826 InputContext->Slot.MTT = MTT;
2827
2828 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2829 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2830 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2831 CmdTrbCfgEP.CycleBit = 1;
2832 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2833 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2834 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
2835 Status = XhcCmdTransfer (
2836 Xhc,
2837 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2838 XHC_GENERIC_TIMEOUT,
2839 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2840 );
2841 ASSERT (!EFI_ERROR(Status));
2842
2843 return Status;
2844 }
2845
2846 /**
2847 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2848
2849 @param Xhc The XHCI Instance.
2850 @param SlotId The slot id to be configured.
2851 @param PortNum The total number of downstream port supported by the hub.
2852 @param TTT The TT think time of the hub device.
2853 @param MTT The multi-TT of the hub device.
2854
2855 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2856
2857 **/
2858 EFI_STATUS
2859 XhcConfigHubContext64 (
2860 IN USB_XHCI_INSTANCE *Xhc,
2861 IN UINT8 SlotId,
2862 IN UINT8 PortNum,
2863 IN UINT8 TTT,
2864 IN UINT8 MTT
2865 )
2866 {
2867 EFI_STATUS Status;
2868
2869 EVT_TRB_COMMAND_COMPLETION *EvtTrb;
2870 INPUT_CONTEXT_64 *InputContext;
2871 DEVICE_CONTEXT_64 *OutputContext;
2872 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;
2873
2874 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);
2875 InputContext = Xhc->UsbDevContext[SlotId].InputContext;
2876 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;
2877
2878 //
2879 // 4.6.7 Evaluate Context
2880 //
2881 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
2882
2883 InputContext->InputControlContext.Dword2 |= BIT0;
2884
2885 //
2886 // Copy the slot context from OutputContext to Input context
2887 //
2888 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));
2889 InputContext->Slot.Hub = 1;
2890 InputContext->Slot.PortNum = PortNum;
2891 InputContext->Slot.TTT = TTT;
2892 InputContext->Slot.MTT = MTT;
2893
2894 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));
2895 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);
2896 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);
2897 CmdTrbCfgEP.CycleBit = 1;
2898 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;
2899 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;
2900 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));
2901 Status = XhcCmdTransfer (
2902 Xhc,
2903 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,
2904 XHC_GENERIC_TIMEOUT,
2905 (TRB_TEMPLATE **) (UINTN) &EvtTrb
2906 );
2907 ASSERT (!EFI_ERROR(Status));
2908
2909 return Status;
2910 }
2911
2912