3 XHCI transfer scheduling routines.
5 Copyright (c) 2011, 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
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.
19 Create a command transfer TRB to support XHCI command interfaces.
21 @param Xhc The XHCI Instance.
22 @param CmdTrb The cmd TRB to be executed.
24 @return Created URB or NULL.
29 IN USB_XHCI_INSTANCE
*Xhc
,
30 IN TRB_TEMPLATE
*CmdTrb
35 Urb
= AllocateZeroPool (sizeof (URB
));
40 Urb
->Signature
= XHC_URB_SIG
;
42 Urb
->Ring
= &Xhc
->CmdRing
;
43 XhcSyncTrsRing (Xhc
, Urb
->Ring
);
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
;
50 Urb
->EvtRing
= &Xhc
->CmdEventRing
;
51 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
52 Urb
->EvtTrbStart
= Urb
->EvtRing
->EventRingEnqueue
;
58 Execute a XHCI cmd TRB pointed by CmdTrb.
60 @param Xhc The XHCI Instance.
61 @param CmdTrb The cmd TRB to be executed.
62 @param Timeout Indicates the maximum time, in millisecond, which the
63 transfer is allowed to complete.
64 @param EvtTrb The event TRB corresponding to the cmd TRB.
66 @retval EFI_SUCCESS The transfer was completed successfully.
67 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
68 @retval EFI_TIMEOUT The transfer failed due to timeout.
69 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
75 IN USB_XHCI_INSTANCE
*Xhc
,
76 IN TRB_TEMPLATE
*CmdTrb
,
78 OUT TRB_TEMPLATE
**EvtTrb
85 // Validate the parameters
87 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
88 return EFI_INVALID_PARAMETER
;
91 Status
= EFI_DEVICE_ERROR
;
93 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
94 DEBUG ((EFI_D_ERROR
, "XhcCmdTransfer: HC is halted\n"));
99 // Create a new URB, then poll the execution status.
101 Urb
= XhcCreateCmdTrb (Xhc
, CmdTrb
);
104 DEBUG ((EFI_D_ERROR
, "XhcCmdTransfer: failed to create URB\n"));
105 Status
= EFI_OUT_OF_RESOURCES
;
109 ASSERT (Urb
->EvtRing
== &Xhc
->CmdEventRing
);
111 Status
= XhcExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
112 *EvtTrb
= Urb
->EvtTrbStart
;
114 if (Urb
->Result
== EFI_USB_NOERROR
) {
115 Status
= EFI_SUCCESS
;
125 Create a new URB for a new transaction.
127 @param Xhc The XHCI Instance
128 @param DevAddr The device address
129 @param EpAddr Endpoint addrress
130 @param DevSpeed The device speed
131 @param MaxPacket The max packet length of the endpoint
132 @param Type The transaction type
133 @param Request The standard USB request for control transfer
134 @param Data The user data to transfer
135 @param DataLen The length of data buffer
136 @param Callback The function to call when data is transferred
137 @param Context The context to the callback
139 @return Created URB or NULL
144 IN USB_XHCI_INSTANCE
*Xhc
,
150 IN EFI_USB_DEVICE_REQUEST
*Request
,
153 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
161 Urb
= AllocateZeroPool (sizeof (URB
));
166 Urb
->Signature
= XHC_URB_SIG
;
167 InitializeListHead (&Urb
->UrbList
);
170 Ep
->DevAddr
= DevAddr
;
171 Ep
->EpAddr
= (UINT8
)(EpAddr
& 0x0F);
172 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
173 Ep
->DevSpeed
= DevSpeed
;
174 Ep
->MaxPacket
= MaxPacket
;
177 Urb
->Request
= Request
;
179 Urb
->DataLen
= DataLen
;
180 Urb
->Callback
= Callback
;
181 Urb
->Context
= Context
;
183 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
184 ASSERT_EFI_ERROR (Status
);
190 Create a transfer TRB.
192 @param Xhc The XHCI Instance
193 @param Urb The urb used to construct the transfer TRB.
195 @return Created TRB or NULL
199 XhcCreateTransferTrb (
200 IN USB_XHCI_INSTANCE
*Xhc
,
204 DEVICE_CONTEXT
*OutputContext
;
205 TRANSFER_RING
*EPRing
;
214 SlotId
= XhcDevAddrToSlotId(Xhc
, Urb
->Ep
.DevAddr
);
215 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
217 EPRing
= (TRANSFER_RING
*)(UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1];
219 OutputContext
= (DEVICE_CONTEXT
*)(UINTN
) Xhc
->DCBAA
[SlotId
];
220 EPType
= (UINT8
) OutputContext
->EP
[Dci
-1].EPType
;
225 XhcSyncTrsRing (Xhc
, EPRing
);
226 Urb
->TrbStart
= EPRing
->RingEnqueue
;
228 case ED_CONTROL_BIDIR
:
229 Urb
->EvtRing
= &Xhc
->CtrlTrEventRing
;
230 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
231 Urb
->EvtTrbStart
= Urb
->EvtRing
->EventRingEnqueue
;
233 // For control transfer, create SETUP_STAGE_TRB first.
235 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
236 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
237 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
238 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
239 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
240 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
241 TrbStart
->TrbCtrSetup
.Lenth
= 8;
242 TrbStart
->TrbCtrSetup
.IntTarget
= Urb
->EvtRing
->EventInterrupter
;
243 TrbStart
->TrbCtrSetup
.IOC
= 1;
244 TrbStart
->TrbCtrSetup
.IDT
= 1;
245 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
246 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
247 TrbStart
->TrbCtrSetup
.TRT
= 3;
248 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
249 TrbStart
->TrbCtrSetup
.TRT
= 2;
251 TrbStart
->TrbCtrSetup
.TRT
= 0;
254 // Update the cycle bit
256 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
260 // For control transfer, create DATA_STAGE_TRB.
262 if (Urb
->DataLen
> 0) {
263 XhcSyncTrsRing (Xhc
, EPRing
);
264 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
265 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT(Urb
->Data
);
266 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT(Urb
->Data
);
267 TrbStart
->TrbCtrData
.Lenth
= (UINT32
) Urb
->DataLen
;
268 TrbStart
->TrbCtrData
.TDSize
= 0;
269 TrbStart
->TrbCtrData
.IntTarget
= Urb
->EvtRing
->EventInterrupter
;
270 TrbStart
->TrbCtrData
.ISP
= 1;
271 TrbStart
->TrbCtrData
.IOC
= 1;
272 TrbStart
->TrbCtrData
.IDT
= 0;
273 TrbStart
->TrbCtrData
.CH
= 0;
274 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
275 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
276 TrbStart
->TrbCtrData
.DIR = 1;
277 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
278 TrbStart
->TrbCtrData
.DIR = 0;
280 TrbStart
->TrbCtrData
.DIR = 0;
283 // Update the cycle bit
285 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
289 // For control transfer, create STATUS_STAGE_TRB.
290 // Get the pointer to next TRB for status stage use
292 XhcSyncTrsRing (Xhc
, EPRing
);
293 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
294 TrbStart
->TrbCtrStatus
.IntTarget
= Urb
->EvtRing
->EventInterrupter
;
295 TrbStart
->TrbCtrStatus
.IOC
= 1;
296 TrbStart
->TrbCtrStatus
.CH
= 0;
297 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
298 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
299 TrbStart
->TrbCtrStatus
.DIR = 0;
300 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
301 TrbStart
->TrbCtrStatus
.DIR = 1;
303 TrbStart
->TrbCtrStatus
.DIR = 0;
306 // Update the cycle bit
308 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
310 // Update the enqueue pointer
312 XhcSyncTrsRing (Xhc
, EPRing
);
314 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
320 Urb
->EvtRing
= &Xhc
->BulkTrEventRing
;
321 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
322 Urb
->EvtTrbStart
= Urb
->EvtRing
->EventRingEnqueue
;
327 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
328 while (TotalLen
< Urb
->DataLen
) {
329 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
330 Len
= Urb
->DataLen
- TotalLen
;
334 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
335 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->Data
+ TotalLen
);
336 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->Data
+ TotalLen
);
337 TrbStart
->TrbNormal
.Lenth
= (UINT32
) Len
;
338 TrbStart
->TrbNormal
.TDSize
= 0;
339 TrbStart
->TrbNormal
.IntTarget
= Urb
->EvtRing
->EventInterrupter
;
340 TrbStart
->TrbNormal
.ISP
= 1;
341 TrbStart
->TrbNormal
.IOC
= 1;
342 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
344 // Update the cycle bit
346 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
348 XhcSyncTrsRing (Xhc
, EPRing
);
353 Urb
->TrbNum
= TrbNum
;
354 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
357 case ED_INTERRUPT_OUT
:
358 case ED_INTERRUPT_IN
:
359 if (Urb
->Ep
.Type
== XHC_INT_TRANSFER_ASYNC
) {
360 Urb
->EvtRing
= &Xhc
->AsynIntTrEventRing
;
361 } else if(Urb
->Ep
.Type
== XHC_INT_TRANSFER_SYNC
){
362 Urb
->EvtRing
= &Xhc
->IntTrEventRing
;
364 DEBUG ((EFI_D_ERROR
, "EP Interrupt type error!\n"));
367 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
368 Urb
->EvtTrbStart
= Urb
->EvtRing
->EventRingEnqueue
;
373 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
374 while (TotalLen
< Urb
->DataLen
) {
375 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
376 Len
= Urb
->DataLen
- TotalLen
;
380 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
381 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->Data
+ TotalLen
);
382 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->Data
+ TotalLen
);
383 TrbStart
->TrbNormal
.Lenth
= (UINT32
) Len
;
384 TrbStart
->TrbNormal
.TDSize
= 0;
385 TrbStart
->TrbNormal
.IntTarget
= Urb
->EvtRing
->EventInterrupter
;
386 TrbStart
->TrbNormal
.ISP
= 1;
387 TrbStart
->TrbNormal
.IOC
= 1;
388 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
390 // Update the cycle bit
392 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
394 XhcSyncTrsRing (Xhc
, EPRing
);
399 Urb
->TrbNum
= TrbNum
;
400 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
404 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
414 Initialize the XHCI host controller for schedule.
416 @param Xhc The XHCI Instance to be initialized.
421 IN USB_XHCI_INSTANCE
*Xhc
427 UINT32 MaxScratchpadBufs
;
429 UINT64
*ScratchEntryBuf
;
433 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
434 // to enable the device slots that system software is going to use.
436 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
437 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
438 XhcWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, Xhc
->MaxSlotsEn
);
441 // The Device Context Base Address Array entry associated with each allocated Device Slot
442 // shall contain a 64-bit pointer to the base of the associated Device Context.
443 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
444 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
446 Entries
= (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
);
447 Dcbaa
= AllocatePages (EFI_SIZE_TO_PAGES (Entries
));
448 ASSERT (Dcbaa
!= NULL
);
449 ZeroMem (Dcbaa
, Entries
);
452 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
453 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
454 // mode (Run/Stop(R/S) ='1').
456 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
457 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
458 ASSERT (MaxScratchpadBufs
<= 1023);
459 if (MaxScratchpadBufs
!= 0) {
460 ScratchBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->PageSize
);
461 ASSERT (ScratchBuf
!= NULL
);
462 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
463 Xhc
->ScratchBuf
= ScratchBuf
;
465 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
466 ScratchEntryBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (Xhc
->PageSize
), Xhc
->PageSize
);
467 ASSERT (ScratchEntryBuf
!= NULL
);
468 ZeroMem (ScratchEntryBuf
, Xhc
->PageSize
);
469 *ScratchBuf
++ = (UINT64
)(UINTN
)ScratchEntryBuf
;
473 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
474 // Device Context Base Address Array points to the Scratchpad Buffer Array.
476 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
)Xhc
->ScratchBuf
;
480 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
481 // a 64-bit address pointing to where the Device Context Base Address Array is located.
483 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
484 XhcWriteOpReg64 (Xhc
, XHC_DCBAAP_OFFSET
, (UINT64
)(UINTN
)Xhc
->DCBAA
);
485 DEBUG ((EFI_D_INFO
, "XhcInitSched:DCBAA=0x%x\n", (UINT64
)(UINTN
)Xhc
->DCBAA
));
488 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
489 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
490 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
493 CreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
495 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
496 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
497 // So we set RCS as inverted PCS init value to let Command Ring empty
499 CmdRing
= (UINT64
)(UINTN
)Xhc
->CmdRing
.RingSeg0
;
500 ASSERT ((CmdRing
& 0x3F) == 0);
501 CmdRing
|= XHC_CRCR_RCS
;
502 XhcWriteOpReg64 (Xhc
, XHC_CRCR_OFFSET
, CmdRing
);
504 DEBUG ((EFI_D_INFO
, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc
->CmdRing
.RingSeg0
));
507 // Disable the 'interrupter enable' bit in USB_CMD
508 // and clear IE & IP bit in all Interrupter X Management Registers.
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
);
517 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
519 CreateEventRing (Xhc
, CMD_INTER
, &Xhc
->CmdEventRing
);
520 CreateEventRing (Xhc
, CTRL_INTER
, &Xhc
->CtrlTrEventRing
);
521 CreateEventRing (Xhc
, BULK_INTER
, &Xhc
->BulkTrEventRing
);
522 CreateEventRing (Xhc
, INT_INTER
, &Xhc
->IntTrEventRing
);
523 CreateEventRing (Xhc
, INT_INTER_ASYNC
, &Xhc
->AsynIntTrEventRing
);
527 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
528 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
529 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
530 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
531 Stopped to the Running state.
533 @param Xhc The XHCI Instance.
534 @param Urb The urb which makes the endpoint halted.
536 @retval EFI_SUCCESS The recovery is successful.
537 @retval Others Failed to recovery halted endpoint.
542 XhcRecoverHaltedEndpoint (
543 IN USB_XHCI_INSTANCE
*Xhc
,
548 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
549 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
550 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
554 Status
= EFI_SUCCESS
;
555 SlotId
= XhcDevAddrToSlotId(Xhc
, Urb
->Ep
.DevAddr
);
556 Dci
= XhcEndpointToDci(Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
558 DEBUG ((EFI_D_INFO
, "Recovery Halted Slot = %x,Dci = %x\n", SlotId
, Dci
));
561 // 1) Send Reset endpoint command to transit from halt to stop state
563 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
564 CmdTrbResetED
.CycleBit
= 1;
565 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
566 CmdTrbResetED
.EDID
= Dci
;
567 CmdTrbResetED
.SlotId
= SlotId
;
568 Status
= XhcCmdTransfer (
570 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
572 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
574 ASSERT (!EFI_ERROR(Status
));
577 // 2)Set dequeue pointer
579 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
580 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (Urb
->Ring
->RingEnqueue
) | Urb
->Ring
->RingPCS
;
581 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (Urb
->Ring
->RingEnqueue
);
582 CmdSetTRDeq
.CycleBit
= 1;
583 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
584 CmdSetTRDeq
.Endpoint
= Dci
;
585 CmdSetTRDeq
.SlotId
= SlotId
;
586 Status
= XhcCmdTransfer (
588 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
590 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
592 ASSERT (!EFI_ERROR(Status
));
595 // 3)Ring the doorbell to transit from stop to active
597 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
603 Create XHCI event ring.
605 @param Xhc The XHCI Instance.
606 @param EventInterrupter The interrupter of event.
607 @param EventRing The created event ring.
612 IN USB_XHCI_INSTANCE
*Xhc
,
613 IN UINT8 EventInterrupter
,
614 OUT EVENT_RING
*EventRing
618 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
620 ASSERT (EventRing
!= NULL
);
622 Buf
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
));
623 ASSERT (Buf
!= NULL
);
624 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
625 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
627 EventRing
->EventRingSeg0
= Buf
;
628 EventRing
->EventInterrupter
= EventInterrupter
;
629 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
630 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
631 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
633 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
634 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
636 EventRing
->EventRingCCS
= 1;
638 Buf
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
));
639 ASSERT (Buf
!= NULL
);
640 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
641 ZeroMem (Buf
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
643 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
644 EventRing
->ERSTBase
= ERSTBase
;
645 ERSTBase
->PtrLo
= XHC_LOW_32BIT (EventRing
->EventRingSeg0
);
646 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (EventRing
->EventRingSeg0
);
647 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
650 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
654 XHC_ERSTSZ_OFFSET
+ (32 * EventRing
->EventInterrupter
),
658 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
660 XhcWriteRuntimeReg64 (
662 XHC_ERDP_OFFSET
+ (32 * EventRing
->EventInterrupter
),
663 (UINT64
)(UINTN
)EventRing
->EventRingDequeue
666 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
668 XhcWriteRuntimeReg64 (
670 XHC_ERSTBA_OFFSET
+ (32 * EventRing
->EventInterrupter
),
671 (UINT64
)(UINTN
)ERSTBase
674 // Need set IMAN IE bit to enble the ring interrupt
676 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (32 * EventRing
->EventInterrupter
), XHC_IMAN_IE
);
680 Create XHCI transfer ring.
682 @param Xhc The XHCI Instance.
683 @param TrbNum The number of TRB in the ring.
684 @param TransferRing The created transfer ring.
689 IN USB_XHCI_INSTANCE
*Xhc
,
691 OUT TRANSFER_RING
*TransferRing
697 Buf
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * TrbNum
));
698 ASSERT (Buf
!= NULL
);
699 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
700 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
702 TransferRing
->RingSeg0
= Buf
;
703 TransferRing
->TrbNumber
= TrbNum
;
704 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
705 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
706 TransferRing
->RingPCS
= 1;
708 // 4.9.2 Transfer Ring Management
709 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
710 // point to the first TRB in the ring.
712 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
713 EndTrb
->Type
= TRB_TYPE_LINK
;
714 EndTrb
->PtrLo
= XHC_LOW_32BIT (Buf
);
715 EndTrb
->PtrHi
= XHC_HIGH_32BIT (Buf
);
717 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
721 // Set Cycle bit as other TRB PCS init value
723 EndTrb
->CycleBit
= 0;
727 Free XHCI event ring.
729 @param Xhc The XHCI Instance.
730 @param EventRing The event ring to be freed.
736 IN USB_XHCI_INSTANCE
*Xhc
,
737 IN EVENT_RING
*EventRing
741 EVENT_RING_SEG_TABLE_ENTRY
*TablePtr
;
743 EVENT_RING_SEG_TABLE_ENTRY
*EventRingPtr
;
745 if(EventRing
->EventRingSeg0
== NULL
) {
750 // Get the Event Ring Segment Table base address
752 TablePtr
= (EVENT_RING_SEG_TABLE_ENTRY
*)(EventRing
->ERSTBase
);
755 // Get all the TRBs Ring and release
757 for (Index
= 0; Index
< ERST_NUMBER
; Index
++) {
758 EventRingPtr
= TablePtr
+ Index
;
759 RingBuf
= (VOID
*)(UINTN
)(EventRingPtr
->PtrLo
| ((UINT64
)EventRingPtr
->PtrHi
<< 32));
761 if(RingBuf
!= NULL
) {
762 FreePages (RingBuf
, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
));
763 ZeroMem (EventRingPtr
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
));
767 FreePages (TablePtr
, EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
));
772 Free the resouce allocated at initializing schedule.
774 @param Xhc The XHCI Instance.
779 IN USB_XHCI_INSTANCE
*Xhc
785 if (Xhc
->ScratchBuf
!= NULL
) {
786 ScratchBuf
= Xhc
->ScratchBuf
;
787 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
788 FreeAlignedPages ((VOID
*)(UINTN
)*ScratchBuf
++, EFI_SIZE_TO_PAGES (Xhc
->PageSize
));
790 FreeAlignedPages (Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)));
793 if (Xhc
->DCBAA
!= NULL
) {
794 FreePages (Xhc
->DCBAA
, EFI_SIZE_TO_PAGES((Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
)));
798 if (Xhc
->CmdRing
.RingSeg0
!= NULL
){
799 FreePages (Xhc
->CmdRing
.RingSeg0
, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
));
800 Xhc
->CmdRing
.RingSeg0
= NULL
;
803 XhcFreeEventRing (Xhc
,&Xhc
->CmdEventRing
);
804 XhcFreeEventRing (Xhc
,&Xhc
->CtrlTrEventRing
);
805 XhcFreeEventRing (Xhc
,&Xhc
->BulkTrEventRing
);
806 XhcFreeEventRing (Xhc
,&Xhc
->AsynIntTrEventRing
);
807 XhcFreeEventRing (Xhc
,&Xhc
->IntTrEventRing
);
811 Check if it is ring TRB.
813 @param Ring The transfer ring
814 @param Trb The TRB to check if it's in the transfer ring
816 @retval TRUE It is in the ring
817 @retval FALSE It is not in the ring
822 IN TRANSFER_RING
*Ring
,
830 Trb1
= Ring
->RingSeg0
;
833 ASSERT (Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
835 for (Index
= 0; Index
< Ring
->TrbNumber
; Index
++) {
847 Check the URB's execution result and update the URB's
850 @param Xhc The XHCI Instance.
851 @param Urb The URB to check result.
853 @return Whether the result of URB transfer is finialized.
858 IN USB_XHCI_INSTANCE
*Xhc
,
864 EVT_TRB_TRANSFER
*EvtTrb
;
865 TRB_TEMPLATE
*TRBPtr
;
870 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
873 Urb
->Result
= EFI_USB_NOERROR
;
874 Status
= EFI_SUCCESS
;
877 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
878 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
879 Status
= EFI_DEVICE_ERROR
;
884 // Restore the EventRingDequeue and poll the transfer event ring from beginning
888 Urb
->EvtRing
->EventRingDequeue
= Urb
->EvtTrbStart
;
889 for (Index
= 0; Index
< Urb
->EvtRing
->TrbNumber
; Index
++) {
890 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
891 Status
= XhcCheckNewEvent (Xhc
, Urb
->EvtRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
892 if (Status
== EFI_NOT_READY
) {
893 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
897 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
)(EvtTrb
->TRBPtrLo
| (UINT64
) EvtTrb
->TRBPtrHi
<< 32);
899 switch (EvtTrb
->Completecode
) {
900 case TRB_COMPLETION_STALL_ERROR
:
901 Urb
->Result
|= EFI_USB_ERR_STALL
;
902 Status
= EFI_DEVICE_ERROR
;
903 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
907 case TRB_COMPLETION_BABBLE_ERROR
:
908 Urb
->Result
|= EFI_USB_ERR_BABBLE
;
909 Status
= EFI_DEVICE_ERROR
;
910 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
914 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
915 Urb
->Result
|= EFI_USB_ERR_BUFFER
;
916 Status
= EFI_DEVICE_ERROR
;
917 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
921 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
922 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
923 Status
= EFI_DEVICE_ERROR
;
924 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
928 case TRB_COMPLETION_SHORT_PACKET
:
929 case TRB_COMPLETION_SUCCESS
:
930 if (IsTransferRingTrb (Urb
->Ring
, TRBPtr
)) {
931 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
932 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: short packet happens!\n"));
934 TRBType
= (UINT8
) (TRBPtr
->Type
);
935 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
936 (TRBType
== TRB_TYPE_NORMAL
) ||
937 (TRBType
== TRB_TYPE_ISOCH
)) {
938 Urb
->Completed
+= (Urb
->DataLen
- EvtTrb
->Lenth
);
941 Status
= EFI_SUCCESS
;
945 DEBUG ((EFI_D_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
946 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
947 Status
= EFI_DEVICE_ERROR
;
953 // Only check first and end Trb event address
955 if (TRBPtr
== Urb
->TrbStart
) {
959 if (TRBPtr
== Urb
->TrbEnd
) {
963 if (StartDone
&& EndDone
) {
974 Execute the transfer by polling the URB. This is a synchronous operation.
976 @param Xhc The XHCI Instance.
977 @param CmdTransfer The executed URB is for cmd transfer or not.
978 @param Urb The URB to execute.
979 @param Timeout The time to wait before abort, in millisecond.
981 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
982 @return EFI_TIMEOUT The transfer failed due to time out.
983 @return EFI_SUCCESS The transfer finished OK.
988 IN USB_XHCI_INSTANCE
*Xhc
,
989 IN BOOLEAN CmdTransfer
,
1004 SlotId
= XhcDevAddrToSlotId(Xhc
, Urb
->Ep
.DevAddr
);
1005 Dci
= XhcEndpointToDci(Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1008 Status
= EFI_SUCCESS
;
1009 Loop
= (Timeout
* XHC_1_MILLISECOND
/ XHC_POLL_DELAY
) + 1;
1014 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1016 for (Index
= 0; Index
< Loop
; Index
++) {
1017 Status
= XhcCheckUrbResult (Xhc
, Urb
);
1018 if ((Status
!= EFI_NOT_READY
)) {
1021 gBS
->Stall (XHC_POLL_DELAY
);
1028 Delete a single asynchronous interrupt transfer for
1029 the device and endpoint.
1031 @param Xhc The XHCI Instance.
1032 @param DevAddr The address of the target device.
1033 @param EpNum The endpoint of the target.
1035 @retval EFI_SUCCESS An asynchronous transfer is removed.
1036 @retval EFI_NOT_FOUND No transfer for the device is found.
1040 XhciDelAsyncIntTransfer (
1041 IN USB_XHCI_INSTANCE
*Xhc
,
1049 EFI_USB_DATA_DIRECTION Direction
;
1051 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1056 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1057 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1058 if ((Urb
->Ep
.DevAddr
== DevAddr
) &&
1059 (Urb
->Ep
.EpAddr
== EpNum
) &&
1060 (Urb
->Ep
.Direction
== Direction
)) {
1061 RemoveEntryList (&Urb
->UrbList
);
1062 FreePool (Urb
->Data
);
1068 return EFI_NOT_FOUND
;
1072 Remove all the asynchronous interrutp transfers.
1074 @param Xhc The XHCI Instance.
1078 XhciDelAllAsyncIntTransfers (
1079 IN USB_XHCI_INSTANCE
*Xhc
1086 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1087 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1088 RemoveEntryList (&Urb
->UrbList
);
1089 FreePool (Urb
->Data
);
1095 Update the queue head for next round of asynchronous transfer
1097 @param Xhc The XHCI Instance.
1098 @param Urb The URB to update
1102 XhcUpdateAsyncRequest (
1103 IN USB_XHCI_INSTANCE
*Xhc
,
1109 if (Urb
->Result
== EFI_USB_NOERROR
) {
1110 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1111 ASSERT_EFI_ERROR (Status
);
1112 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1113 ASSERT_EFI_ERROR (Status
);
1119 Interrupt transfer periodic check handler.
1121 @param Event Interrupt event.
1122 @param Context Pointer to USB_XHCI_INSTANCE.
1127 XhcMonitorAsyncRequests (
1132 USB_XHCI_INSTANCE
*Xhc
;
1141 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1143 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1145 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1146 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1149 // Make sure that the device is available before every check.
1151 SlotId
= XhcDevAddrToSlotId(Xhc
, Urb
->Ep
.DevAddr
);
1157 // Check the result of URB execution. If it is still
1158 // active, check the next one.
1160 Status
= XhcCheckUrbResult (Xhc
, Urb
);
1162 if (Status
== EFI_NOT_READY
) {
1167 // Allocate a buffer then copy the transferred data for user.
1168 // If failed to allocate the buffer, update the URB for next
1169 // round of transfer. Ignore the data of this round.
1172 if (Urb
->Result
== EFI_USB_NOERROR
) {
1173 ASSERT (Urb
->Completed
<= Urb
->DataLen
);
1175 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1177 if (ProcBuf
== NULL
) {
1178 XhcUpdateAsyncRequest (Xhc
, Urb
);
1182 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1185 XhcUpdateAsyncRequest (Xhc
, Urb
);
1188 // Leave error recovery to its related device driver. A
1189 // common case of the error recovery is to re-submit the
1190 // interrupt transfer which is linked to the head of the
1191 // list. This function scans from head to tail. So the
1192 // re-submitted interrupt transfer's callback function
1193 // will not be called again in this round. Don't touch this
1194 // URB after the callback, it may have been removed by the
1197 if (Urb
->Callback
!= NULL
) {
1199 // Restore the old TPL, USB bus maybe connect device in
1200 // his callback. Some drivers may has a lower TPL restriction.
1202 gBS
->RestoreTPL (OldTpl
);
1203 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1204 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1207 if (ProcBuf
!= NULL
) {
1208 gBS
->FreePool (ProcBuf
);
1211 gBS
->RestoreTPL (OldTpl
);
1215 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1217 @param Xhc The XHCI Instance.
1218 @param ParentRouteChart The route string pointed to the parent device if it exists.
1219 @param Port The port to be polled.
1220 @param PortState The port state.
1222 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1223 @retval Others Should not appear.
1228 XhcPollPortStatusChange (
1229 IN USB_XHCI_INSTANCE
*Xhc
,
1230 IN USB_DEV_ROUTE ParentRouteChart
,
1232 IN EFI_USB_PORT_STATUS
*PortState
1238 USB_DEV_ROUTE RouteChart
;
1240 Status
= EFI_SUCCESS
;
1242 if (ParentRouteChart
.Dword
== 0) {
1243 RouteChart
.Route
.RouteString
= 0;
1244 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1245 RouteChart
.Route
.TierNum
= 1;
1248 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1250 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1252 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1253 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1256 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1257 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1259 // Has a device attached, Identify device speed after port is enabled.
1261 Speed
= EFI_USB_SPEED_FULL
;
1262 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1263 Speed
= EFI_USB_SPEED_LOW
;
1264 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1265 Speed
= EFI_USB_SPEED_HIGH
;
1266 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1267 Speed
= EFI_USB_SPEED_SUPER
;
1270 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1272 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1274 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1275 ASSERT_EFI_ERROR (Status
);
1277 } else if ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) == 0) {
1279 // Device is detached. Disable the allocated device slot and release resource.
1281 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1283 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1284 ASSERT_EFI_ERROR (Status
);
1292 Calculate the device context index by endpoint address and direction.
1294 @param EpAddr The target endpoint number.
1295 @param Direction The direction of the target endpoint.
1297 @return The device context index of endpoint.
1311 Index
= (UINT8
) (2 * EpAddr
);
1312 if (Direction
== EfiUsbDataIn
) {
1320 Find out the slot id according to device address assigned by XHCI's Address_Device cmd.
1322 @param Xhc The XHCI Instance.
1323 @param DevAddr The device address of the target device.
1325 @return The slot id used by the device.
1329 XhcDevAddrToSlotId (
1330 IN USB_XHCI_INSTANCE
*Xhc
,
1336 for (Index
= 0; Index
< 255; Index
++) {
1337 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1338 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1339 (Xhc
->UsbDevContext
[Index
+ 1].XhciDevAddr
== DevAddr
)) {
1348 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1352 Find out the actual device address according to the requested device address from UsbBus.
1354 @param Xhc The XHCI Instance.
1355 @param BusDevAddr The requested device address by UsbBus upper driver.
1357 @return The actual device address assigned to the device.
1362 XhcBusDevAddrToSlotId (
1363 IN USB_XHCI_INSTANCE
*Xhc
,
1369 for (Index
= 0; Index
< 255; Index
++) {
1370 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1371 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1372 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1381 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1385 Find out the slot id according to the device's route string.
1387 @param Xhc The XHCI Instance.
1388 @param RouteString The route string described the device location.
1390 @return The slot id used by the device.
1395 XhcRouteStringToSlotId (
1396 IN USB_XHCI_INSTANCE
*Xhc
,
1397 IN USB_DEV_ROUTE RouteString
1402 for (Index
= 0; Index
< 255; Index
++) {
1403 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1404 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1405 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1414 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1418 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1420 @param Xhc The XHCI Instance.
1421 @param EvtRing The event ring to sync.
1423 @retval EFI_SUCCESS The event ring is synchronized successfully.
1429 IN USB_XHCI_INSTANCE
*Xhc
,
1430 IN EVENT_RING
*EvtRing
1434 TRB_TEMPLATE
*EvtTrb1
;
1435 TRB_TEMPLATE
*EvtTrb2
;
1436 TRB_TEMPLATE
*XhcDequeue
;
1438 ASSERT (EvtRing
!= NULL
);
1441 // Calculate the EventRingEnqueue and EventRingCCS.
1442 // Note: only support single Segment
1444 EvtTrb1
= EvtRing
->EventRingSeg0
;
1445 EvtTrb2
= EvtRing
->EventRingSeg0
;
1447 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1448 if (EvtTrb1
->CycleBit
!= EvtTrb2
->CycleBit
) {
1454 if (Index
< EvtRing
->TrbNumber
) {
1455 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1456 EvtRing
->EventRingCCS
= (EvtTrb2
->CycleBit
) ? 1 : 0;
1458 EvtRing
->EventRingEnqueue
= EvtTrb2
;
1459 EvtRing
->EventRingCCS
= (EvtTrb2
->CycleBit
) ? 0 : 1;
1463 // Apply the EventRingDequeue to Xhc
1465 XhcDequeue
= (TRB_TEMPLATE
*)(UINTN
) XhcReadRuntimeReg64 (
1467 XHC_ERDP_OFFSET
+ (32 * EvtRing
->EventInterrupter
)
1470 if (((UINT64
)(UINTN
)XhcDequeue
& (~0x0F)) != ((UINT64
)(UINTN
)EvtRing
->EventRingDequeue
& (~0x0F))) {
1471 XhcWriteRuntimeReg64 (
1473 XHC_ERDP_OFFSET
+ (32 * EvtRing
->EventInterrupter
),
1474 (UINT64
)(UINTN
)EvtRing
->EventRingDequeue
| BIT3
1482 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1484 @param Xhc The XHCI Instance.
1485 @param TrsRing The transfer ring to sync.
1487 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1493 IN USB_XHCI_INSTANCE
*Xhc
,
1494 IN TRANSFER_RING
*TrsRing
1498 TRB_TEMPLATE
*TrsTrb
;
1500 ASSERT (TrsRing
!= NULL
);
1502 // Calculate the latest RingEnqueue and RingPCS
1504 TrsTrb
= TrsRing
->RingEnqueue
;
1505 ASSERT (TrsTrb
!= NULL
);
1507 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1508 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1512 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1513 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1515 // set cycle bit in Link TRB as normal
1517 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1519 // Toggle PCS maintained by software
1521 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1522 TrsTrb
= (TRB_TEMPLATE
*)(UINTN
)((TrsTrb
->Parameter1
| ((UINT64
)TrsTrb
->Parameter2
<< 32)) & ~0x0F);
1526 ASSERT (Index
!= TrsRing
->TrbNumber
);
1528 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1529 TrsRing
->RingEnqueue
= TrsTrb
;
1533 // Clear the Trb context for enqueue, but reserve the PCS bit
1535 TrsTrb
->Parameter1
= 0;
1536 TrsTrb
->Parameter2
= 0;
1540 TrsTrb
->Control
= 0;
1546 Check if there is a new generated event.
1548 @param Xhc The XHCI Instance.
1549 @param EvtRing The event ring to check.
1550 @param NewEvtTrb The new event TRB found.
1552 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1553 @retval EFI_NOT_READY The event ring has no new event.
1559 IN USB_XHCI_INSTANCE
*Xhc
,
1560 IN EVENT_RING
*EvtRing
,
1561 OUT TRB_TEMPLATE
**NewEvtTrb
1565 TRB_TEMPLATE
*EvtTrb
;
1567 ASSERT (EvtRing
!= NULL
);
1569 EvtTrb
= EvtRing
->EventRingDequeue
;
1570 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
1572 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
1573 return EFI_NOT_READY
;
1576 Status
= EFI_SUCCESS
;
1578 if (((EvtTrb
->Status
>> 24) & 0xFF) != TRB_COMPLETION_SUCCESS
) {
1579 Status
= EFI_DEVICE_ERROR
;
1582 EvtRing
->EventRingDequeue
++;
1584 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1586 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1587 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
1594 Ring the door bell to notify XHCI there is a transaction to be executed.
1596 @param Xhc The XHCI Instance.
1597 @param SlotId The slot id of the target device.
1598 @param Dci The device context index of the target slot or endpoint.
1600 @retval EFI_SUCCESS Successfully ring the door bell.
1606 IN USB_XHCI_INSTANCE
*Xhc
,
1612 XhcWriteDoorBellReg (Xhc
, 0, 0);
1614 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1621 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1623 @param Xhc The XHCI Instance.
1624 @param Urb The URB to be rung.
1626 @retval EFI_SUCCESS Successfully ring the door bell.
1630 RingIntTransferDoorBell (
1631 IN USB_XHCI_INSTANCE
*Xhc
,
1638 SlotId
= XhcDevAddrToSlotId(Xhc
, Urb
->Ep
.DevAddr
);
1639 Dci
= XhcEndpointToDci(Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1640 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1645 Assign and initialize the device slot for a new device.
1647 @param Xhc The XHCI Instance.
1648 @param ParentRouteChart The route string pointed to the parent device.
1649 @param ParentPort The port at which the device is located.
1650 @param RouteChart The route string pointed to the device.
1651 @param DeviceSpeed The device speed.
1653 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1658 XhcInitializeDeviceSlot (
1659 IN USB_XHCI_INSTANCE
*Xhc
,
1660 IN USB_DEV_ROUTE ParentRouteChart
,
1661 IN UINT16 ParentPort
,
1662 IN USB_DEV_ROUTE RouteChart
,
1663 IN UINT8 DeviceSpeed
1667 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1668 INPUT_CONTEXT
*InputContext
;
1669 DEVICE_CONTEXT
*OutputContext
;
1670 TRANSFER_RING
*EndpointTransferRing
;
1671 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1672 UINT8 DeviceAddress
;
1673 CMD_TRB_ENABLE_SLOT CmdTrb
;
1676 DEVICE_CONTEXT
*ParentDeviceContext
;
1678 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1679 CmdTrb
.CycleBit
= 1;
1680 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1682 Status
= XhcCmdTransfer (
1684 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1685 XHC_GENERIC_TIMEOUT
,
1686 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1688 ASSERT_EFI_ERROR (Status
);
1689 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1690 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1691 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1692 ASSERT (SlotId
!= 0);
1694 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1695 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1696 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1697 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1698 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1701 // 4.3.3 Device Slot Initialization
1702 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1704 InputContext
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT
)));
1705 ASSERT (InputContext
!= NULL
);
1706 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1707 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1709 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1712 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1713 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1714 // Context are affected by the command.
1716 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1719 // 3) Initialize the Input Slot Context data structure
1721 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1722 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1723 InputContext
->Slot
.ContextEntries
= 1;
1724 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1726 if (RouteChart
.Route
.RouteString
) {
1728 // The device is behind of hub device.
1730 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
1731 ASSERT (ParentSlotId
!= 0);
1733 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1735 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1736 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1737 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1738 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1740 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1741 // environment from Full/Low speed signaling environment for a device
1743 InputContext
->Slot
.TTPortNum
= ParentPort
;
1744 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1748 // Inherit the TT parameters from parent device.
1750 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1751 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1753 // If the device is a High speed device then down the speed to be the same as its parent Hub
1755 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1756 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1762 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1764 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1765 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1766 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1768 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1770 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1772 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1773 InputContext
->EP
[0].MaxPacketSize
= 512;
1774 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1775 InputContext
->EP
[0].MaxPacketSize
= 64;
1777 InputContext
->EP
[0].MaxPacketSize
= 8;
1780 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1781 // 1KB, and Bulk and Isoch endpoints 3KB.
1783 InputContext
->EP
[0].AverageTRBLength
= 8;
1784 InputContext
->EP
[0].MaxBurstSize
= 0;
1785 InputContext
->EP
[0].Interval
= 0;
1786 InputContext
->EP
[0].MaxPStreams
= 0;
1787 InputContext
->EP
[0].Mult
= 0;
1788 InputContext
->EP
[0].CErr
= 3;
1791 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1793 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
) | BIT0
;
1794 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
);
1797 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1799 OutputContext
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT
)));
1800 ASSERT (OutputContext
!= NULL
);
1801 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
1802 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
1804 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1806 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1807 // a pointer to the Output Device Context data structure (6.2.1).
1809 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) OutputContext
;
1812 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1813 // Context data structure described above.
1815 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1816 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (Xhc
->UsbDevContext
[SlotId
].InputContext
);
1817 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (Xhc
->UsbDevContext
[SlotId
].InputContext
);
1818 CmdTrbAddr
.CycleBit
= 1;
1819 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1820 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1821 Status
= XhcCmdTransfer (
1823 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
1824 XHC_GENERIC_TIMEOUT
,
1825 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1827 ASSERT (!EFI_ERROR(Status
));
1829 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
1830 DEBUG ((EFI_D_INFO
, " Address %d assigned succeefully\n", DeviceAddress
));
1832 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1838 Disable the specified device slot.
1840 @param Xhc The XHCI Instance.
1841 @param SlotId The slot id to be disabled.
1843 @retval EFI_SUCCESS Successfully disable the device slot.
1849 IN USB_XHCI_INSTANCE
*Xhc
,
1854 TRB_TEMPLATE
*EvtTrb
;
1855 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1860 // Disable the device slots occupied by these devices on its downstream ports.
1861 // Entry 0 is reserved.
1863 for (Index
= 0; Index
< 255; Index
++) {
1864 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1865 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1866 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
1870 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1872 if (EFI_ERROR (Status
)) {
1873 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
1874 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1879 // Construct the disable slot command
1881 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
1883 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1884 CmdTrbDisSlot
.CycleBit
= 1;
1885 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1886 CmdTrbDisSlot
.SlotId
= SlotId
;
1887 Status
= XhcCmdTransfer (
1889 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
1890 XHC_GENERIC_TIMEOUT
,
1891 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1893 ASSERT_EFI_ERROR(Status
);
1895 // Free the slot's device context entry
1897 Xhc
->DCBAA
[SlotId
] = 0;
1900 // Free the slot related data structure
1902 for (Index
= 0; Index
< 31; Index
++) {
1903 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1904 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1905 if (RingSeg
!= NULL
) {
1906 FreePages (RingSeg
, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
));
1908 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1912 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1913 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1914 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1918 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1919 FreePages (Xhc
->UsbDevContext
[SlotId
].InputContext
, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT
)));
1922 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1923 FreePages (Xhc
->UsbDevContext
[SlotId
].OutputContext
, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT
)));
1926 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1927 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1928 // remove urb from XHCI's asynchronous transfer list.
1930 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1936 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1938 @param Xhc The XHCI Instance.
1939 @param SlotId The slot id to be configured.
1940 @param DeviceSpeed The device's speed.
1941 @param ConfigDesc The pointer to the usb device configuration descriptor.
1943 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1949 IN USB_XHCI_INSTANCE
*Xhc
,
1951 IN UINT8 DeviceSpeed
,
1952 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1957 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1958 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1969 TRANSFER_RING
*EndpointTransferRing
;
1970 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1971 INPUT_CONTEXT
*InputContext
;
1972 DEVICE_CONTEXT
*OutputContext
;
1973 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1975 // 4.6.6 Configure Endpoint
1977 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1978 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1979 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1980 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
1982 ASSERT (ConfigDesc
!= NULL
);
1986 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
1987 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1988 while (IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) {
1989 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
1992 NumEp
= IfDesc
->NumEndpoints
;
1994 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
1995 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1996 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1997 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2000 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2001 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2003 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2009 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2010 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2012 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2014 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2016 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2018 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2021 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2022 case USB_ENDPOINT_BULK
:
2023 if (Direction
== EfiUsbDataIn
) {
2024 InputContext
->EP
[Dci
-1].CErr
= 3;
2025 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2027 InputContext
->EP
[Dci
-1].CErr
= 3;
2028 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2031 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2032 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2033 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2034 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2035 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2039 case USB_ENDPOINT_ISO
:
2040 if (Direction
== EfiUsbDataIn
) {
2041 InputContext
->EP
[Dci
-1].CErr
= 0;
2042 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2044 InputContext
->EP
[Dci
-1].CErr
= 0;
2045 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2048 case USB_ENDPOINT_INTERRUPT
:
2049 if (Direction
== EfiUsbDataIn
) {
2050 InputContext
->EP
[Dci
-1].CErr
= 3;
2051 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2053 InputContext
->EP
[Dci
-1].CErr
= 3;
2054 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2056 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2057 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2059 // Get the bInterval from descriptor and init the the interval field of endpoint context
2061 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2062 Interval
= EpDesc
->Interval
;
2064 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2066 InputContext
->EP
[Dci
-1].Interval
= 6;
2067 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2068 Interval
= EpDesc
->Interval
;
2069 ASSERT (Interval
>= 1 && Interval
<= 16);
2071 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2073 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2074 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2075 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2076 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2077 InputContext
->EP
[Dci
-1].CErr
= 3;
2080 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2081 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2082 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2083 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2087 case USB_ENDPOINT_CONTROL
:
2093 PhyAddr
= XHC_LOW_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
);
2095 PhyAddr
|= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2096 InputContext
->EP
[Dci
-1].PtrLo
= PhyAddr
;
2097 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
);
2099 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2101 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2104 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2105 InputContext
->Slot
.ContextEntries
= MaxDci
;
2107 // configure endpoint
2109 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2110 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2111 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2112 CmdTrbCfgEP
.CycleBit
= 1;
2113 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2114 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2115 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
2116 Status
= XhcCmdTransfer (
2118 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2119 XHC_GENERIC_TIMEOUT
,
2120 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2122 ASSERT_EFI_ERROR(Status
);
2128 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2130 @param Xhc The XHCI Instance.
2131 @param SlotId The slot id to be evaluated.
2132 @param MaxPacketSize The max packet size supported by the device control transfer.
2134 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2139 XhcEvaluateContext (
2140 IN USB_XHCI_INSTANCE
*Xhc
,
2142 IN UINT32 MaxPacketSize
2146 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2147 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2148 INPUT_CONTEXT
*InputContext
;
2150 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2153 // 4.6.7 Evaluate Context
2155 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2156 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2158 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2159 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2161 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2162 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2163 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2164 CmdTrbEvalu
.CycleBit
= 1;
2165 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2166 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2167 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
2168 Status
= XhcCmdTransfer (
2170 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2171 XHC_GENERIC_TIMEOUT
,
2172 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2174 ASSERT (!EFI_ERROR(Status
));
2180 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2182 @param Xhc The XHCI Instance.
2183 @param SlotId The slot id to be configured.
2184 @param PortNum The total number of downstream port supported by the hub.
2185 @param TTT The TT think time of the hub device.
2186 @param MTT The multi-TT of the hub device.
2188 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2192 XhcConfigHubContext (
2193 IN USB_XHCI_INSTANCE
*Xhc
,
2202 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2203 INPUT_CONTEXT
*InputContext
;
2204 DEVICE_CONTEXT
*OutputContext
;
2205 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2207 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2208 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2209 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2212 // 4.6.7 Evaluate Context
2214 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2216 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2219 // Copy the slot context from OutputContext to Input context
2221 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
2222 InputContext
->Slot
.Hub
= 1;
2223 InputContext
->Slot
.PortNum
= PortNum
;
2224 InputContext
->Slot
.TTT
= TTT
;
2225 InputContext
->Slot
.MTT
= MTT
;
2227 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2228 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2229 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2230 CmdTrbCfgEP
.CycleBit
= 1;
2231 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2232 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2233 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
2234 Status
= XhcCmdTransfer (
2236 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2237 XHC_GENERIC_TIMEOUT
,
2238 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2240 ASSERT (!EFI_ERROR(Status
));