2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
5 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 Create a command transfer TRB to support XHCI command interfaces.
23 @param Xhc The XHCI device.
24 @param CmdTrb The cmd TRB to be executed.
26 @return Created URB or NULL.
32 IN TRB_TEMPLATE
*CmdTrb
37 Urb
= AllocateZeroPool (sizeof (URB
));
42 Urb
->Signature
= XHC_URB_SIG
;
44 Urb
->Ring
= &Xhc
->CmdRing
;
45 XhcPeiSyncTrsRing (Xhc
, Urb
->Ring
);
47 Urb
->TrbStart
= Urb
->Ring
->RingEnqueue
;
48 CopyMem (Urb
->TrbStart
, CmdTrb
, sizeof (TRB_TEMPLATE
));
49 Urb
->TrbStart
->CycleBit
= Urb
->Ring
->RingPCS
& BIT0
;
50 Urb
->TrbEnd
= Urb
->TrbStart
;
56 Execute a XHCI cmd TRB pointed by CmdTrb.
58 @param Xhc The XHCI device.
59 @param CmdTrb The cmd TRB to be executed.
60 @param Timeout Indicates the maximum time, in millisecond, which the
61 transfer is allowed to complete.
62 @param EvtTrb The event TRB corresponding to the cmd TRB.
64 @retval EFI_SUCCESS The transfer was completed successfully.
65 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
66 @retval EFI_TIMEOUT The transfer failed due to timeout.
67 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
73 IN TRB_TEMPLATE
*CmdTrb
,
75 OUT TRB_TEMPLATE
**EvtTrb
82 // Validate the parameters
84 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
85 return EFI_INVALID_PARAMETER
;
88 Status
= EFI_DEVICE_ERROR
;
90 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
91 DEBUG ((EFI_D_ERROR
, "XhcPeiCmdTransfer: HC is halted or has system error\n"));
96 // Create a new URB, then poll the execution status.
98 Urb
= XhcPeiCreateCmdTrb (Xhc
, CmdTrb
);
100 DEBUG ((EFI_D_ERROR
, "XhcPeiCmdTransfer: failed to create URB\n"));
101 Status
= EFI_OUT_OF_RESOURCES
;
105 Status
= XhcPeiExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
106 *EvtTrb
= Urb
->EvtTrb
;
108 if (Urb
->Result
== EFI_USB_NOERROR
) {
109 Status
= EFI_SUCCESS
;
112 XhcPeiFreeUrb (Xhc
, Urb
);
119 Create a new URB for a new transaction.
121 @param Xhc The XHCI device
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
133 @return Created URB or NULL
144 IN EFI_USB_DEVICE_REQUEST
*Request
,
147 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
155 Urb
= AllocateZeroPool (sizeof (URB
));
160 Urb
->Signature
= XHC_URB_SIG
;
163 Ep
->BusAddr
= BusAddr
;
164 Ep
->EpAddr
= (UINT8
) (EpAddr
& 0x0F);
165 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
166 Ep
->DevSpeed
= DevSpeed
;
167 Ep
->MaxPacket
= MaxPacket
;
170 Urb
->Request
= Request
;
172 Urb
->DataLen
= DataLen
;
173 Urb
->Callback
= Callback
;
174 Urb
->Context
= Context
;
176 Status
= XhcPeiCreateTransferTrb (Xhc
, Urb
);
177 if (EFI_ERROR (Status
)) {
178 DEBUG ((EFI_D_ERROR
, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status
));
187 Free an allocated URB.
189 @param Xhc The XHCI device.
190 @param Urb The URB to free.
199 if ((Xhc
== NULL
) || (Urb
== NULL
)) {
207 Create a transfer TRB.
209 @param Xhc The XHCI device
210 @param Urb The urb used to construct the transfer TRB.
212 @return Created TRB or NULL
216 XhcPeiCreateTransferTrb (
222 TRANSFER_RING
*EPRing
;
231 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
233 return EFI_DEVICE_ERROR
;
236 Urb
->Finished
= FALSE
;
237 Urb
->StartDone
= FALSE
;
238 Urb
->EndDone
= FALSE
;
240 Urb
->Result
= EFI_USB_NOERROR
;
242 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
243 EPRing
= (TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1];
245 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
246 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
247 EPType
= (UINT8
) ((DEVICE_CONTEXT
*)OutputContext
)->EP
[Dci
-1].EPType
;
249 EPType
= (UINT8
) ((DEVICE_CONTEXT_64
*)OutputContext
)->EP
[Dci
-1].EPType
;
252 Urb
->DataPhy
= Urb
->Data
;
257 XhcPeiSyncTrsRing (Xhc
, EPRing
);
258 Urb
->TrbStart
= EPRing
->RingEnqueue
;
260 case ED_CONTROL_BIDIR
:
262 // For control transfer, create SETUP_STAGE_TRB first.
264 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
265 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
266 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
267 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
268 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
269 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
270 TrbStart
->TrbCtrSetup
.Length
= 8;
271 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
272 TrbStart
->TrbCtrSetup
.IOC
= 1;
273 TrbStart
->TrbCtrSetup
.IDT
= 1;
274 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
275 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
276 TrbStart
->TrbCtrSetup
.TRT
= 3;
277 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
278 TrbStart
->TrbCtrSetup
.TRT
= 2;
280 TrbStart
->TrbCtrSetup
.TRT
= 0;
283 // Update the cycle bit
285 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
289 // For control transfer, create DATA_STAGE_TRB.
291 if (Urb
->DataLen
> 0) {
292 XhcPeiSyncTrsRing (Xhc
, EPRing
);
293 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
294 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT (Urb
->DataPhy
);
295 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT (Urb
->DataPhy
);
296 TrbStart
->TrbCtrData
.Length
= (UINT32
) Urb
->DataLen
;
297 TrbStart
->TrbCtrData
.TDSize
= 0;
298 TrbStart
->TrbCtrData
.IntTarget
= 0;
299 TrbStart
->TrbCtrData
.ISP
= 1;
300 TrbStart
->TrbCtrData
.IOC
= 1;
301 TrbStart
->TrbCtrData
.IDT
= 0;
302 TrbStart
->TrbCtrData
.CH
= 0;
303 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
304 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
305 TrbStart
->TrbCtrData
.DIR = 1;
306 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
307 TrbStart
->TrbCtrData
.DIR = 0;
309 TrbStart
->TrbCtrData
.DIR = 0;
312 // Update the cycle bit
314 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
318 // For control transfer, create STATUS_STAGE_TRB.
319 // Get the pointer to next TRB for status stage use
321 XhcPeiSyncTrsRing (Xhc
, EPRing
);
322 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
323 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
324 TrbStart
->TrbCtrStatus
.IOC
= 1;
325 TrbStart
->TrbCtrStatus
.CH
= 0;
326 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
327 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
328 TrbStart
->TrbCtrStatus
.DIR = 0;
329 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
330 TrbStart
->TrbCtrStatus
.DIR = 1;
332 TrbStart
->TrbCtrStatus
.DIR = 0;
335 // Update the cycle bit
337 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
339 // Update the enqueue pointer
341 XhcPeiSyncTrsRing (Xhc
, EPRing
);
343 Urb
->TrbEnd
= (TRB_TEMPLATE
*) (UINTN
) TrbStart
;
352 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
353 while (TotalLen
< Urb
->DataLen
) {
354 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
355 Len
= Urb
->DataLen
- TotalLen
;
359 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
360 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
361 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
362 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
363 TrbStart
->TrbNormal
.TDSize
= 0;
364 TrbStart
->TrbNormal
.IntTarget
= 0;
365 TrbStart
->TrbNormal
.ISP
= 1;
366 TrbStart
->TrbNormal
.IOC
= 1;
367 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
369 // Update the cycle bit
371 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
373 XhcPeiSyncTrsRing (Xhc
, EPRing
);
378 Urb
->TrbNum
= TrbNum
;
379 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
382 case ED_INTERRUPT_OUT
:
383 case ED_INTERRUPT_IN
:
387 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
388 while (TotalLen
< Urb
->DataLen
) {
389 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
390 Len
= Urb
->DataLen
- TotalLen
;
394 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
395 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
396 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
397 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
398 TrbStart
->TrbNormal
.TDSize
= 0;
399 TrbStart
->TrbNormal
.IntTarget
= 0;
400 TrbStart
->TrbNormal
.ISP
= 1;
401 TrbStart
->TrbNormal
.IOC
= 1;
402 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
404 // Update the cycle bit
406 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
408 XhcPeiSyncTrsRing (Xhc
, EPRing
);
413 Urb
->TrbNum
= TrbNum
;
414 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
418 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
427 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
428 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
429 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
430 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
431 Stopped to the Running state.
433 @param Xhc The XHCI device.
434 @param Urb The urb which makes the endpoint halted.
436 @retval EFI_SUCCESS The recovery is successful.
437 @retval Others Failed to recovery halted endpoint.
441 XhcPeiRecoverHaltedEndpoint (
447 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
448 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
449 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
452 EFI_PHYSICAL_ADDRESS PhyAddr
;
454 Status
= EFI_SUCCESS
;
455 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
457 return EFI_DEVICE_ERROR
;
459 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
) (Urb
->Ep
.Direction
));
461 DEBUG ((EFI_D_INFO
, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId
, Dci
));
464 // 1) Send Reset endpoint command to transit from halt to stop state
466 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
467 CmdTrbResetED
.CycleBit
= 1;
468 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
469 CmdTrbResetED
.EDID
= Dci
;
470 CmdTrbResetED
.SlotId
= SlotId
;
471 Status
= XhcPeiCmdTransfer (
473 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
475 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
477 if (EFI_ERROR(Status
)) {
478 DEBUG ((EFI_D_ERROR
, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
483 // 2) Set dequeue pointer
485 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
486 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
487 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
488 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
489 CmdSetTRDeq
.CycleBit
= 1;
490 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
491 CmdSetTRDeq
.Endpoint
= Dci
;
492 CmdSetTRDeq
.SlotId
= SlotId
;
493 Status
= XhcPeiCmdTransfer (
495 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
497 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
499 if (EFI_ERROR(Status
)) {
500 DEBUG ((EFI_D_ERROR
, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
505 // 3) Ring the doorbell to transit from stop to active
507 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
514 Check if the Trb is a transaction of the URB.
516 @param Trb The TRB to be checked
517 @param Urb The transfer ring to be checked.
519 @retval TRUE It is a transaction of the URB.
520 @retval FALSE It is not any transaction of the URB.
524 XhcPeiIsTransferRingTrb (
525 IN TRB_TEMPLATE
*Trb
,
529 TRB_TEMPLATE
*CheckedTrb
;
532 CheckedTrb
= Urb
->Ring
->RingSeg0
;
534 ASSERT (Urb
->Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Urb
->Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
536 for (Index
= 0; Index
< Urb
->Ring
->TrbNumber
; Index
++) {
537 if (Trb
== CheckedTrb
) {
547 Check the URB's execution result and update the URB's
550 @param Xhc The XHCI device.
551 @param Urb The URB to check result.
553 @return Whether the result of URB transfer is finialized.
557 XhcPeiCheckUrbResult (
562 EVT_TRB_TRANSFER
*EvtTrb
;
563 TRB_TEMPLATE
*TRBPtr
;
571 EFI_PHYSICAL_ADDRESS PhyAddr
;
573 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
575 Status
= EFI_SUCCESS
;
583 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
584 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
589 // Traverse the event ring to find out all new events from the previous check.
591 XhcPeiSyncEventRing (Xhc
, &Xhc
->EventRing
);
592 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
593 Status
= XhcPeiCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**) &EvtTrb
));
594 if (Status
== EFI_NOT_READY
) {
596 // All new events are handled, return directly.
602 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
604 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
609 // Need convert pci device address to host address
611 PhyAddr
= (EFI_PHYSICAL_ADDRESS
) (EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
612 TRBPtr
= (TRB_TEMPLATE
*) (UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*) (UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
615 // Update the status of Urb according to the finished event regardless of whether
616 // the urb is current checked one or in the XHCI's async transfer list.
617 // This way is used to avoid that those completed async transfer events don't get
618 // handled in time and are flushed by newer coming events.
620 if (XhcPeiIsTransferRingTrb (TRBPtr
, Urb
)) {
626 switch (EvtTrb
->Completecode
) {
627 case TRB_COMPLETION_STALL_ERROR
:
628 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
629 CheckedUrb
->Finished
= TRUE
;
630 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
633 case TRB_COMPLETION_BABBLE_ERROR
:
634 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
635 CheckedUrb
->Finished
= TRUE
;
636 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
639 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
640 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
641 CheckedUrb
->Finished
= TRUE
;
642 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb
->Completecode
));
645 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
646 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
647 CheckedUrb
->Finished
= TRUE
;
648 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
651 case TRB_COMPLETION_SHORT_PACKET
:
652 case TRB_COMPLETION_SUCCESS
:
653 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
654 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: short packet happens!\n"));
657 TRBType
= (UINT8
) (TRBPtr
->Type
);
658 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
659 (TRBType
== TRB_TYPE_NORMAL
) ||
660 (TRBType
== TRB_TYPE_ISOCH
)) {
661 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
667 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb
->Completecode
));
668 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
669 CheckedUrb
->Finished
= TRUE
;
674 // Only check first and end Trb event address
676 if (TRBPtr
== CheckedUrb
->TrbStart
) {
677 CheckedUrb
->StartDone
= TRUE
;
680 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
681 CheckedUrb
->EndDone
= TRUE
;
684 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
685 CheckedUrb
->Finished
= TRUE
;
686 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*) EvtTrb
;
693 // Advance event ring to last available entry
695 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
696 // So divide it to two 32-bytes width register access.
698 Low
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
699 High
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
700 XhcDequeue
= (UINT64
) (LShiftU64((UINT64
) High
, 32) | Low
);
702 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
704 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
706 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
707 // So divide it to two 32-bytes width register access.
709 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
710 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
713 return Urb
->Finished
;
717 Execute the transfer by polling the URB. This is a synchronous operation.
719 @param Xhc The XHCI device.
720 @param CmdTransfer The executed URB is for cmd transfer or not.
721 @param Urb The URB to execute.
722 @param Timeout The time to wait before abort, in millisecond.
724 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
725 @return EFI_TIMEOUT The transfer failed due to time out.
726 @return EFI_SUCCESS The transfer finished OK.
732 IN BOOLEAN CmdTransfer
,
748 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
750 return EFI_DEVICE_ERROR
;
752 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
755 Status
= EFI_SUCCESS
;
756 Loop
= Timeout
* XHC_1_MILLISECOND
;
761 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
763 for (Index
= 0; Index
< Loop
; Index
++) {
764 Finished
= XhcPeiCheckUrbResult (Xhc
, Urb
);
768 MicroSecondDelay (XHC_1_MICROSECOND
);
772 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
773 Status
= EFI_TIMEOUT
;
774 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
775 Status
= EFI_DEVICE_ERROR
;
782 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
784 @param Xhc The XHCI device.
785 @param ParentRouteChart The route string pointed to the parent device if it exists.
786 @param Port The port to be polled.
787 @param PortState The port state.
789 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
790 @retval Others Should not appear.
794 XhcPeiPollPortStatusChange (
796 IN USB_DEV_ROUTE ParentRouteChart
,
798 IN EFI_USB_PORT_STATUS
*PortState
804 USB_DEV_ROUTE RouteChart
;
806 DEBUG ((EFI_D_INFO
, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState
->PortChangeStatus
, PortState
->PortStatus
));
808 Status
= EFI_SUCCESS
;
810 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
814 if (ParentRouteChart
.Dword
== 0) {
815 RouteChart
.Route
.RouteString
= 0;
816 RouteChart
.Route
.RootPortNum
= Port
+ 1;
817 RouteChart
.Route
.TierNum
= 1;
820 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
822 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
824 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
825 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
828 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
830 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
831 Status
= XhcPeiDisableSlotCmd (Xhc
, SlotId
);
833 Status
= XhcPeiDisableSlotCmd64 (Xhc
, SlotId
);
837 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
838 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
840 // Has a device attached, Identify device speed after port is enabled.
842 Speed
= EFI_USB_SPEED_FULL
;
843 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
844 Speed
= EFI_USB_SPEED_LOW
;
845 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
846 Speed
= EFI_USB_SPEED_HIGH
;
847 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
848 Speed
= EFI_USB_SPEED_SUPER
;
851 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
853 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
854 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
855 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
856 Status
= XhcPeiInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
858 Status
= XhcPeiInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
867 Calculate the device context index by endpoint address and direction.
869 @param EpAddr The target endpoint number.
870 @param Direction The direction of the target endpoint.
872 @return The device context index of endpoint.
876 XhcPeiEndpointToDci (
878 IN EFI_USB_DATA_DIRECTION Direction
883 ASSERT (EpAddr
<= 15);
888 Index
= (UINT8
) (2 * EpAddr
);
889 if (Direction
== EfiUsbDataIn
) {
897 Find out the actual device address according to the requested device address from UsbBus.
899 @param Xhc The XHCI device.
900 @param BusDevAddr The requested device address by UsbBus upper driver.
902 @return The actual device address assigned to the device.
906 XhcPeiBusDevAddrToSlotId (
913 for (Index
= 0; Index
< 255; Index
++) {
914 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
915 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
916 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
925 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
929 Find out the slot id according to the device's route string.
931 @param Xhc The XHCI device.
932 @param RouteString The route string described the device location.
934 @return The slot id used by the device.
938 XhcPeiRouteStringToSlotId (
940 IN USB_DEV_ROUTE RouteString
945 for (Index
= 0; Index
< 255; Index
++) {
946 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
947 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
948 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
957 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
961 Ring the door bell to notify XHCI there is a transaction to be executed.
963 @param Xhc The XHCI device.
964 @param SlotId The slot id of the target device.
965 @param Dci The device context index of the target slot or endpoint.
976 XhcPeiWriteDoorBellReg (Xhc
, 0, 0);
978 XhcPeiWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
983 Assign and initialize the device slot for a new device.
985 @param Xhc The XHCI device.
986 @param ParentRouteChart The route string pointed to the parent device.
987 @param ParentPort The port at which the device is located.
988 @param RouteChart The route string pointed to the device.
989 @param DeviceSpeed The device speed.
991 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
992 @retval Others Fail to initialize device slot.
996 XhcPeiInitializeDeviceSlot (
998 IN USB_DEV_ROUTE ParentRouteChart
,
999 IN UINT16 ParentPort
,
1000 IN USB_DEV_ROUTE RouteChart
,
1001 IN UINT8 DeviceSpeed
1005 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1006 INPUT_CONTEXT
*InputContext
;
1007 DEVICE_CONTEXT
*OutputContext
;
1008 TRANSFER_RING
*EndpointTransferRing
;
1009 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1010 UINT8 DeviceAddress
;
1011 CMD_TRB_ENABLE_SLOT CmdTrb
;
1014 DEVICE_CONTEXT
*ParentDeviceContext
;
1015 EFI_PHYSICAL_ADDRESS PhyAddr
;
1017 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1018 CmdTrb
.CycleBit
= 1;
1019 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1021 Status
= XhcPeiCmdTransfer (
1023 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1024 XHC_GENERIC_TIMEOUT
,
1025 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1027 if (EFI_ERROR (Status
)) {
1028 DEBUG ((EFI_D_ERROR
, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
1031 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1032 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1033 SlotId
= (UINT8
) EvtTrb
->SlotId
;
1034 ASSERT (SlotId
!= 0);
1036 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1037 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1038 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1039 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1040 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1043 // 4.3.3 Device Slot Initialization
1044 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1046 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
1047 ASSERT (InputContext
!= NULL
);
1048 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1049 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1051 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1054 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1055 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1056 // Context are affected by the command.
1058 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1061 // 3) Initialize the Input Slot Context data structure
1063 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1064 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1065 InputContext
->Slot
.ContextEntries
= 1;
1066 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1068 if (RouteChart
.Route
.RouteString
!= 0) {
1070 // The device is behind of hub device.
1072 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1073 ASSERT (ParentSlotId
!= 0);
1075 // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
1077 ParentDeviceContext
= (DEVICE_CONTEXT
*) Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1078 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1079 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1080 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1082 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1083 // environment from Full/Low speed signaling environment for a device
1085 InputContext
->Slot
.TTPortNum
= ParentPort
;
1086 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1090 // Inherit the TT parameters from parent device.
1092 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1093 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1095 // If the device is a High speed device then down the speed to be the same as its parent Hub
1097 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1098 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1104 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1106 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1107 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1108 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1110 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1112 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1114 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1115 InputContext
->EP
[0].MaxPacketSize
= 512;
1116 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1117 InputContext
->EP
[0].MaxPacketSize
= 64;
1119 InputContext
->EP
[0].MaxPacketSize
= 8;
1122 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1123 // 1KB, and Bulk and Isoch endpoints 3KB.
1125 InputContext
->EP
[0].AverageTRBLength
= 8;
1126 InputContext
->EP
[0].MaxBurstSize
= 0;
1127 InputContext
->EP
[0].Interval
= 0;
1128 InputContext
->EP
[0].MaxPStreams
= 0;
1129 InputContext
->EP
[0].Mult
= 0;
1130 InputContext
->EP
[0].CErr
= 3;
1133 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1135 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1137 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1138 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1140 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1141 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1144 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1146 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
1147 ASSERT (OutputContext
!= NULL
);
1148 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
1149 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
1151 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1153 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1154 // a pointer to the Output Device Context data structure (6.2.1).
1156 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
1158 // Fill DCBAA with PCI device address
1160 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
1163 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1164 // Context data structure described above.
1166 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1167 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1168 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1169 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1170 CmdTrbAddr
.CycleBit
= 1;
1171 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1172 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1173 Status
= XhcPeiCmdTransfer (
1175 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
1176 XHC_GENERIC_TIMEOUT
,
1177 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1179 if (!EFI_ERROR (Status
)) {
1180 DeviceAddress
= (UINT8
) OutputContext
->Slot
.DeviceAddress
;
1181 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress
));
1182 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1185 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status
));
1190 Assign and initialize the device slot for a new device.
1192 @param Xhc The XHCI device.
1193 @param ParentRouteChart The route string pointed to the parent device.
1194 @param ParentPort The port at which the device is located.
1195 @param RouteChart The route string pointed to the device.
1196 @param DeviceSpeed The device speed.
1198 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1199 @retval Others Fail to initialize device slot.
1203 XhcPeiInitializeDeviceSlot64 (
1204 IN PEI_XHC_DEV
*Xhc
,
1205 IN USB_DEV_ROUTE ParentRouteChart
,
1206 IN UINT16 ParentPort
,
1207 IN USB_DEV_ROUTE RouteChart
,
1208 IN UINT8 DeviceSpeed
1212 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1213 INPUT_CONTEXT_64
*InputContext
;
1214 DEVICE_CONTEXT_64
*OutputContext
;
1215 TRANSFER_RING
*EndpointTransferRing
;
1216 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1217 UINT8 DeviceAddress
;
1218 CMD_TRB_ENABLE_SLOT CmdTrb
;
1221 DEVICE_CONTEXT_64
*ParentDeviceContext
;
1222 EFI_PHYSICAL_ADDRESS PhyAddr
;
1224 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1225 CmdTrb
.CycleBit
= 1;
1226 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1228 Status
= XhcPeiCmdTransfer (
1230 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1231 XHC_GENERIC_TIMEOUT
,
1232 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1234 if (EFI_ERROR (Status
)) {
1235 DEBUG ((EFI_D_ERROR
, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
1238 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1239 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1240 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1241 ASSERT (SlotId
!= 0);
1243 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1244 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1245 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1246 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1247 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1250 // 4.3.3 Device Slot Initialization
1251 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1253 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
1254 ASSERT (InputContext
!= NULL
);
1255 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1256 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1258 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1261 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1262 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1263 // Context are affected by the command.
1265 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1268 // 3) Initialize the Input Slot Context data structure
1270 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1271 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1272 InputContext
->Slot
.ContextEntries
= 1;
1273 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1275 if (RouteChart
.Route
.RouteString
!= 0) {
1277 // The device is behind of hub device.
1279 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1280 ASSERT (ParentSlotId
!= 0);
1282 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1284 ParentDeviceContext
= (DEVICE_CONTEXT_64
*) Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1285 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1286 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1287 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1289 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1290 // environment from Full/Low speed signaling environment for a device
1292 InputContext
->Slot
.TTPortNum
= ParentPort
;
1293 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1297 // Inherit the TT parameters from parent device.
1299 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1300 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1302 // If the device is a High speed device then down the speed to be the same as its parent Hub
1304 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1305 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1311 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1313 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1314 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1315 XhcPeiCreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1317 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1319 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1321 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1322 InputContext
->EP
[0].MaxPacketSize
= 512;
1323 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1324 InputContext
->EP
[0].MaxPacketSize
= 64;
1326 InputContext
->EP
[0].MaxPacketSize
= 8;
1329 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1330 // 1KB, and Bulk and Isoch endpoints 3KB.
1332 InputContext
->EP
[0].AverageTRBLength
= 8;
1333 InputContext
->EP
[0].MaxBurstSize
= 0;
1334 InputContext
->EP
[0].Interval
= 0;
1335 InputContext
->EP
[0].MaxPStreams
= 0;
1336 InputContext
->EP
[0].Mult
= 0;
1337 InputContext
->EP
[0].CErr
= 3;
1340 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1342 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1344 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1345 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1347 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1348 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1351 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1353 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
1354 ASSERT (OutputContext
!= NULL
);
1355 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
1356 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1358 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1360 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1361 // a pointer to the Output Device Context data structure (6.2.1).
1363 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1365 // Fill DCBAA with PCI device address
1367 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
1370 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1371 // Context data structure described above.
1373 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1374 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1375 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1376 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1377 CmdTrbAddr
.CycleBit
= 1;
1378 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1379 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1380 Status
= XhcPeiCmdTransfer (
1382 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
1383 XHC_GENERIC_TIMEOUT
,
1384 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1386 if (!EFI_ERROR (Status
)) {
1387 DeviceAddress
= (UINT8
) OutputContext
->Slot
.DeviceAddress
;
1388 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress
));
1389 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1392 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status
));
1398 Disable the specified device slot.
1400 @param Xhc The XHCI device.
1401 @param SlotId The slot id to be disabled.
1403 @retval EFI_SUCCESS Successfully disable the device slot.
1407 XhcPeiDisableSlotCmd (
1408 IN PEI_XHC_DEV
*Xhc
,
1413 TRB_TEMPLATE
*EvtTrb
;
1414 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1419 // Disable the device slots occupied by these devices on its downstream ports.
1420 // Entry 0 is reserved.
1422 for (Index
= 0; Index
< 255; Index
++) {
1423 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1424 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1425 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
1429 Status
= XhcPeiDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1431 if (EFI_ERROR (Status
)) {
1432 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
1433 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1438 // Construct the disable slot command
1440 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId
));
1442 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1443 CmdTrbDisSlot
.CycleBit
= 1;
1444 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1445 CmdTrbDisSlot
.SlotId
= SlotId
;
1446 Status
= XhcPeiCmdTransfer (
1448 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
1449 XHC_GENERIC_TIMEOUT
,
1450 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1452 if (EFI_ERROR (Status
)) {
1453 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
1457 // Free the slot's device context entry
1459 Xhc
->DCBAA
[SlotId
] = 0;
1462 // Free the slot related data structure
1464 for (Index
= 0; Index
< 31; Index
++) {
1465 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1466 RingSeg
= ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1467 if (RingSeg
!= NULL
) {
1468 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1470 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1471 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1475 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1476 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1477 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1481 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1482 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1485 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1486 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
1489 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1490 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1491 // remove urb from XHCI's asynchronous transfer list.
1493 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1494 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1496 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status
));
1501 Disable the specified device slot.
1503 @param Xhc The XHCI device.
1504 @param SlotId The slot id to be disabled.
1506 @retval EFI_SUCCESS Successfully disable the device slot.
1510 XhcPeiDisableSlotCmd64 (
1511 IN PEI_XHC_DEV
*Xhc
,
1516 TRB_TEMPLATE
*EvtTrb
;
1517 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1522 // Disable the device slots occupied by these devices on its downstream ports.
1523 // Entry 0 is reserved.
1525 for (Index
= 0; Index
< 255; Index
++) {
1526 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1527 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1528 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
1532 Status
= XhcPeiDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1534 if (EFI_ERROR (Status
)) {
1535 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
1536 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1541 // Construct the disable slot command
1543 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId
));
1545 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1546 CmdTrbDisSlot
.CycleBit
= 1;
1547 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1548 CmdTrbDisSlot
.SlotId
= SlotId
;
1549 Status
= XhcPeiCmdTransfer (
1551 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
1552 XHC_GENERIC_TIMEOUT
,
1553 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1555 if (EFI_ERROR (Status
)) {
1556 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status
));
1560 // Free the slot's device context entry
1562 Xhc
->DCBAA
[SlotId
] = 0;
1565 // Free the slot related data structure
1567 for (Index
= 0; Index
< 31; Index
++) {
1568 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1569 RingSeg
= ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1570 if (RingSeg
!= NULL
) {
1571 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1573 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1574 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1578 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1579 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1580 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1584 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1585 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1588 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1589 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1592 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1593 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1594 // remove urb from XHCI's asynchronous transfer list.
1596 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1597 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1599 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status
));
1604 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1606 @param Xhc The XHCI device.
1607 @param SlotId The slot id to be configured.
1608 @param DeviceSpeed The device's speed.
1609 @param ConfigDesc The pointer to the usb device configuration descriptor.
1611 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1615 XhcPeiSetConfigCmd (
1616 IN PEI_XHC_DEV
*Xhc
,
1618 IN UINT8 DeviceSpeed
,
1619 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1623 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1624 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1629 EFI_USB_DATA_DIRECTION Direction
;
1632 EFI_PHYSICAL_ADDRESS PhyAddr
;
1635 TRANSFER_RING
*EndpointTransferRing
;
1636 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1637 INPUT_CONTEXT
*InputContext
;
1638 DEVICE_CONTEXT
*OutputContext
;
1639 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1641 // 4.6.6 Configure Endpoint
1643 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1644 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1645 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1646 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
1648 ASSERT (ConfigDesc
!= NULL
);
1652 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) (ConfigDesc
+ 1);
1653 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1654 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1655 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1658 NumEp
= IfDesc
->NumEndpoints
;
1660 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDesc
+ 1);
1661 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1662 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1663 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1666 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
1667 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1669 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1674 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1675 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1677 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1679 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1681 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1683 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1686 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
1687 case USB_ENDPOINT_BULK
:
1688 if (Direction
== EfiUsbDataIn
) {
1689 InputContext
->EP
[Dci
-1].CErr
= 3;
1690 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
1692 InputContext
->EP
[Dci
-1].CErr
= 3;
1693 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
1696 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1697 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1698 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1699 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1700 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1704 case USB_ENDPOINT_ISO
:
1705 if (Direction
== EfiUsbDataIn
) {
1706 InputContext
->EP
[Dci
-1].CErr
= 0;
1707 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
1709 InputContext
->EP
[Dci
-1].CErr
= 0;
1710 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
1713 // Do not support isochronous transfer now.
1715 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1716 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1718 case USB_ENDPOINT_INTERRUPT
:
1719 if (Direction
== EfiUsbDataIn
) {
1720 InputContext
->EP
[Dci
-1].CErr
= 3;
1721 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
1723 InputContext
->EP
[Dci
-1].CErr
= 3;
1724 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
1726 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1727 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
1729 // Get the bInterval from descriptor and init the interval field of endpoint context
1731 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
1732 Interval
= EpDesc
->Interval
;
1734 // Calculate through the bInterval field of Endpoint descriptor.
1736 ASSERT (Interval
!= 0);
1737 InputContext
->EP
[Dci
-1].Interval
= (UINT32
) HighBitSet32 ((UINT32
) Interval
) + 3;
1738 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1739 Interval
= EpDesc
->Interval
;
1740 ASSERT (Interval
>= 1 && Interval
<= 16);
1742 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1744 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1747 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1748 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1749 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1750 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1754 case USB_ENDPOINT_CONTROL
:
1756 // Do not support control transfer now.
1758 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1760 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
1761 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1765 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1767 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
1768 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1770 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
1771 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
1772 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1773 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1775 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1777 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1780 InputContext
->InputControlContext
.Dword2
|= BIT0
;
1781 InputContext
->Slot
.ContextEntries
= MaxDci
;
1783 // configure endpoint
1785 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
1786 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
1787 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1788 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1789 CmdTrbCfgEP
.CycleBit
= 1;
1790 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
1791 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1792 DEBUG ((EFI_D_INFO
, "XhcSetConfigCmd: Configure Endpoint\n"));
1793 Status
= XhcPeiCmdTransfer (
1795 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
1796 XHC_GENERIC_TIMEOUT
,
1797 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1799 if (EFI_ERROR (Status
)) {
1800 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
1806 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1808 @param Xhc The XHCI device.
1809 @param SlotId The slot id to be configured.
1810 @param DeviceSpeed The device's speed.
1811 @param ConfigDesc The pointer to the usb device configuration descriptor.
1813 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1817 XhcPeiSetConfigCmd64 (
1818 IN PEI_XHC_DEV
*Xhc
,
1820 IN UINT8 DeviceSpeed
,
1821 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1825 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1826 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1831 EFI_USB_DATA_DIRECTION Direction
;
1834 EFI_PHYSICAL_ADDRESS PhyAddr
;
1837 TRANSFER_RING
*EndpointTransferRing
;
1838 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1839 INPUT_CONTEXT_64
*InputContext
;
1840 DEVICE_CONTEXT_64
*OutputContext
;
1841 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1843 // 4.6.6 Configure Endpoint
1845 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1846 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1847 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1848 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
1850 ASSERT (ConfigDesc
!= NULL
);
1854 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) (ConfigDesc
+ 1);
1855 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1856 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1857 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1860 NumEp
= IfDesc
->NumEndpoints
;
1862 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDesc
+ 1);
1863 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1864 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1865 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1868 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
1869 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1871 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1877 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1878 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1880 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1882 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1884 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1886 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1889 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
1890 case USB_ENDPOINT_BULK
:
1891 if (Direction
== EfiUsbDataIn
) {
1892 InputContext
->EP
[Dci
-1].CErr
= 3;
1893 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
1895 InputContext
->EP
[Dci
-1].CErr
= 3;
1896 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
1899 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1900 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1901 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1902 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1903 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1907 case USB_ENDPOINT_ISO
:
1908 if (Direction
== EfiUsbDataIn
) {
1909 InputContext
->EP
[Dci
-1].CErr
= 0;
1910 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
1912 InputContext
->EP
[Dci
-1].CErr
= 0;
1913 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
1916 // Do not support isochronous transfer now.
1918 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1919 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1921 case USB_ENDPOINT_INTERRUPT
:
1922 if (Direction
== EfiUsbDataIn
) {
1923 InputContext
->EP
[Dci
-1].CErr
= 3;
1924 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
1926 InputContext
->EP
[Dci
-1].CErr
= 3;
1927 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
1929 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1930 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
1932 // Get the bInterval from descriptor and init the the interval field of endpoint context
1934 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
1935 Interval
= EpDesc
->Interval
;
1937 // Calculate through the bInterval field of Endpoint descriptor.
1939 ASSERT (Interval
!= 0);
1940 InputContext
->EP
[Dci
-1].Interval
= (UINT32
) HighBitSet32( (UINT32
) Interval
) + 3;
1941 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1942 Interval
= EpDesc
->Interval
;
1943 ASSERT (Interval
>= 1 && Interval
<= 16);
1945 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1947 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1950 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1951 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1952 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1953 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1957 case USB_ENDPOINT_CONTROL
:
1959 // Do not support control transfer now.
1961 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1963 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
1964 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1968 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1970 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
1971 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1974 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
1975 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
1977 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1978 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1980 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
)EpDesc
+ EpDesc
->Length
);
1982 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
)IfDesc
+ IfDesc
->Length
);
1985 InputContext
->InputControlContext
.Dword2
|= BIT0
;
1986 InputContext
->Slot
.ContextEntries
= MaxDci
;
1988 // configure endpoint
1990 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
1991 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
1992 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1993 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1994 CmdTrbCfgEP
.CycleBit
= 1;
1995 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
1996 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1997 DEBUG ((EFI_D_INFO
, "XhcSetConfigCmd64: Configure Endpoint\n"));
1998 Status
= XhcPeiCmdTransfer (
2000 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2001 XHC_GENERIC_TIMEOUT
,
2002 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2004 if (EFI_ERROR (Status
)) {
2005 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
2013 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2015 @param Xhc The XHCI device.
2016 @param SlotId The slot id to be evaluated.
2017 @param MaxPacketSize The max packet size supported by the device control transfer.
2019 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2023 XhcPeiEvaluateContext (
2024 IN PEI_XHC_DEV
*Xhc
,
2026 IN UINT32 MaxPacketSize
2030 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2031 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2032 INPUT_CONTEXT
*InputContext
;
2033 EFI_PHYSICAL_ADDRESS PhyAddr
;
2035 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2038 // 4.6.7 Evaluate Context
2040 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2041 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2043 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2044 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2046 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2047 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2048 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2049 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2050 CmdTrbEvalu
.CycleBit
= 1;
2051 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2052 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2053 DEBUG ((EFI_D_INFO
, "XhcEvaluateContext: Evaluate context\n"));
2054 Status
= XhcPeiCmdTransfer (
2056 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2057 XHC_GENERIC_TIMEOUT
,
2058 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2060 if (EFI_ERROR (Status
)) {
2061 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
2067 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2069 @param Xhc The XHCI device.
2070 @param SlotId The slot id to be evaluated.
2071 @param MaxPacketSize The max packet size supported by the device control transfer.
2073 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2077 XhcPeiEvaluateContext64 (
2078 IN PEI_XHC_DEV
*Xhc
,
2080 IN UINT32 MaxPacketSize
2084 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2085 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2086 INPUT_CONTEXT_64
*InputContext
;
2087 EFI_PHYSICAL_ADDRESS PhyAddr
;
2089 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2092 // 4.6.7 Evaluate Context
2094 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2095 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2097 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2098 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2100 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2101 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2102 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2103 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2104 CmdTrbEvalu
.CycleBit
= 1;
2105 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2106 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2107 DEBUG ((EFI_D_INFO
, "XhcEvaluateContext64: Evaluate context 64\n"));
2108 Status
= XhcPeiCmdTransfer (
2110 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2111 XHC_GENERIC_TIMEOUT
,
2112 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2114 if (EFI_ERROR (Status
)) {
2115 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
2121 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2123 @param Xhc The XHCI device.
2124 @param SlotId The slot id to be configured.
2125 @param PortNum The total number of downstream port supported by the hub.
2126 @param TTT The TT think time of the hub device.
2127 @param MTT The multi-TT of the hub device.
2129 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2133 XhcPeiConfigHubContext (
2134 IN PEI_XHC_DEV
*Xhc
,
2142 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2143 INPUT_CONTEXT
*InputContext
;
2144 DEVICE_CONTEXT
*OutputContext
;
2145 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2146 EFI_PHYSICAL_ADDRESS PhyAddr
;
2148 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2149 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2150 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2153 // 4.6.7 Evaluate Context
2155 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2157 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2160 // Copy the slot context from OutputContext to Input context
2162 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
2163 InputContext
->Slot
.Hub
= 1;
2164 InputContext
->Slot
.PortNum
= PortNum
;
2165 InputContext
->Slot
.TTT
= TTT
;
2166 InputContext
->Slot
.MTT
= MTT
;
2168 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2169 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2170 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2171 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2172 CmdTrbCfgEP
.CycleBit
= 1;
2173 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2174 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2175 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
2176 Status
= XhcPeiCmdTransfer (
2178 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2179 XHC_GENERIC_TIMEOUT
,
2180 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2182 if (EFI_ERROR (Status
)) {
2183 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
2189 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2191 @param Xhc The XHCI device.
2192 @param SlotId The slot id to be configured.
2193 @param PortNum The total number of downstream port supported by the hub.
2194 @param TTT The TT think time of the hub device.
2195 @param MTT The multi-TT of the hub device.
2197 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2201 XhcPeiConfigHubContext64 (
2202 IN PEI_XHC_DEV
*Xhc
,
2210 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2211 INPUT_CONTEXT_64
*InputContext
;
2212 DEVICE_CONTEXT_64
*OutputContext
;
2213 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2214 EFI_PHYSICAL_ADDRESS PhyAddr
;
2216 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2217 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2218 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2221 // 4.6.7 Evaluate Context
2223 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2225 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2228 // Copy the slot context from OutputContext to Input context
2230 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
2231 InputContext
->Slot
.Hub
= 1;
2232 InputContext
->Slot
.PortNum
= PortNum
;
2233 InputContext
->Slot
.TTT
= TTT
;
2234 InputContext
->Slot
.MTT
= MTT
;
2236 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2237 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2238 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2239 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2240 CmdTrbCfgEP
.CycleBit
= 1;
2241 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2242 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2243 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context 64\n"));
2244 Status
= XhcPeiCmdTransfer (
2246 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2247 XHC_GENERIC_TIMEOUT
,
2248 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2250 if (EFI_ERROR (Status
)) {
2251 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));
2257 Check if there is a new generated event.
2259 @param Xhc The XHCI device.
2260 @param EvtRing The event ring to check.
2261 @param NewEvtTrb The new event TRB found.
2263 @retval EFI_SUCCESS Found a new event TRB at the event ring.
2264 @retval EFI_NOT_READY The event ring has no new event.
2268 XhcPeiCheckNewEvent (
2269 IN PEI_XHC_DEV
*Xhc
,
2270 IN EVENT_RING
*EvtRing
,
2271 OUT TRB_TEMPLATE
**NewEvtTrb
2274 ASSERT (EvtRing
!= NULL
);
2276 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
2278 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
2279 return EFI_NOT_READY
;
2282 EvtRing
->EventRingDequeue
++;
2284 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2286 if ((UINTN
) EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2287 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
2294 Synchronize the specified event ring to update the enqueue and dequeue pointer.
2296 @param Xhc The XHCI device.
2297 @param EvtRing The event ring to sync.
2299 @retval EFI_SUCCESS The event ring is synchronized successfully.
2303 XhcPeiSyncEventRing (
2304 IN PEI_XHC_DEV
*Xhc
,
2305 IN EVENT_RING
*EvtRing
2309 TRB_TEMPLATE
*EvtTrb
;
2311 ASSERT (EvtRing
!= NULL
);
2314 // Calculate the EventRingEnqueue and EventRingCCS.
2315 // Note: only support single Segment
2317 EvtTrb
= EvtRing
->EventRingDequeue
;
2319 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
2320 if (EvtTrb
->CycleBit
!= EvtRing
->EventRingCCS
) {
2326 if ((UINTN
) EvtTrb
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2327 EvtTrb
= EvtRing
->EventRingSeg0
;
2328 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
2332 if (Index
< EvtRing
->TrbNumber
) {
2333 EvtRing
->EventRingEnqueue
= EvtTrb
;
2342 Free XHCI event ring.
2344 @param Xhc The XHCI device.
2345 @param EventRing The event ring to be freed.
2349 XhcPeiFreeEventRing (
2350 IN PEI_XHC_DEV
*Xhc
,
2351 IN EVENT_RING
*EventRing
2354 if(EventRing
->EventRingSeg0
== NULL
) {
2359 // Free EventRing Segment 0
2361 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
2366 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
2370 Create XHCI event ring.
2372 @param Xhc The XHCI device.
2373 @param EventRing The created event ring.
2377 XhcPeiCreateEventRing (
2378 IN PEI_XHC_DEV
*Xhc
,
2379 OUT EVENT_RING
*EventRing
2383 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
2385 EFI_PHYSICAL_ADDRESS ERSTPhy
;
2386 EFI_PHYSICAL_ADDRESS DequeuePhy
;
2388 ASSERT (EventRing
!= NULL
);
2390 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
2391 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2392 ASSERT (Buf
!= NULL
);
2393 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2394 ZeroMem (Buf
, Size
);
2396 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2398 EventRing
->EventRingSeg0
= Buf
;
2399 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
2400 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
2401 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
2404 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
2405 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
2407 EventRing
->EventRingCCS
= 1;
2409 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
2410 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2411 ASSERT (Buf
!= NULL
);
2412 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2413 ZeroMem (Buf
, Size
);
2415 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
2416 EventRing
->ERSTBase
= ERSTBase
;
2417 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
2418 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
2419 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
2421 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2424 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
2426 XhcPeiWriteRuntimeReg (
2432 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
2434 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2435 // So divide it to two 32-bytes width register access.
2437 XhcPeiWriteRuntimeReg (
2440 XHC_LOW_32BIT ((UINT64
) (UINTN
) DequeuePhy
)
2442 XhcPeiWriteRuntimeReg (
2444 XHC_ERDP_OFFSET
+ 4,
2445 XHC_HIGH_32BIT ((UINT64
) (UINTN
) DequeuePhy
)
2448 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
2450 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2451 // So divide it to two 32-bytes width register access.
2453 XhcPeiWriteRuntimeReg (
2456 XHC_LOW_32BIT ((UINT64
) (UINTN
) ERSTPhy
)
2458 XhcPeiWriteRuntimeReg (
2460 XHC_ERSTBA_OFFSET
+ 4,
2461 XHC_HIGH_32BIT ((UINT64
) (UINTN
) ERSTPhy
)
2464 // Need set IMAN IE bit to enable the ring interrupt
2466 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
2470 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
2472 @param Xhc The XHCI device.
2473 @param TrsRing The transfer ring to sync.
2475 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
2480 IN PEI_XHC_DEV
*Xhc
,
2481 IN TRANSFER_RING
*TrsRing
2485 TRB_TEMPLATE
*TrsTrb
;
2487 ASSERT (TrsRing
!= NULL
);
2489 // Calculate the latest RingEnqueue and RingPCS
2491 TrsTrb
= TrsRing
->RingEnqueue
;
2492 ASSERT (TrsTrb
!= NULL
);
2494 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
2495 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
2499 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
2500 ASSERT (((LINK_TRB
*) TrsTrb
)->TC
!= 0);
2502 // set cycle bit in Link TRB as normal
2504 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
2506 // Toggle PCS maintained by software
2508 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
2509 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
2513 ASSERT (Index
!= TrsRing
->TrbNumber
);
2515 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
2516 TrsRing
->RingEnqueue
= TrsTrb
;
2520 // Clear the Trb context for enqueue, but reserve the PCS bit
2522 TrsTrb
->Parameter1
= 0;
2523 TrsTrb
->Parameter2
= 0;
2527 TrsTrb
->Control
= 0;
2533 Create XHCI transfer ring.
2535 @param Xhc The XHCI Device.
2536 @param TrbNum The number of TRB in the ring.
2537 @param TransferRing The created transfer ring.
2541 XhcPeiCreateTransferRing (
2542 IN PEI_XHC_DEV
*Xhc
,
2544 OUT TRANSFER_RING
*TransferRing
2549 EFI_PHYSICAL_ADDRESS PhyAddr
;
2551 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2552 ASSERT (Buf
!= NULL
);
2553 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2554 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2556 TransferRing
->RingSeg0
= Buf
;
2557 TransferRing
->TrbNumber
= TrbNum
;
2558 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
2559 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
2560 TransferRing
->RingPCS
= 1;
2562 // 4.9.2 Transfer Ring Management
2563 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
2564 // point to the first TRB in the ring.
2566 EndTrb
= (LINK_TRB
*) ((UINTN
) Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
2567 EndTrb
->Type
= TRB_TYPE_LINK
;
2568 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2569 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2570 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2572 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
2576 // Set Cycle bit as other TRB PCS init value
2578 EndTrb
->CycleBit
= 0;
2582 Initialize the XHCI host controller for schedule.
2584 @param Xhc The XHCI device to be initialized.
2593 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
2595 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
2596 UINT32 MaxScratchpadBufs
;
2598 EFI_PHYSICAL_ADDRESS ScratchPhy
;
2599 UINT64
*ScratchEntry
;
2600 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
2605 // Initialize memory management.
2607 Xhc
->MemPool
= UsbHcInitMemPool ();
2608 ASSERT (Xhc
->MemPool
!= NULL
);
2611 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
2612 // to enable the device slots that system software is going to use.
2614 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
2615 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
2616 XhcPeiWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, (XhcPeiReadOpReg (Xhc
, XHC_CONFIG_OFFSET
) & ~XHC_CONFIG_MASK
) | Xhc
->MaxSlotsEn
);
2619 // The Device Context Base Address Array entry associated with each allocated Device Slot
2620 // shall contain a 64-bit pointer to the base of the associated Device Context.
2621 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
2622 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
2624 Size
= (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
);
2625 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2626 ASSERT (Dcbaa
!= NULL
);
2629 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
2630 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
2631 // mode (Run/Stop(R/S) ='1').
2633 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
2634 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
2635 ASSERT (MaxScratchpadBufs
<= 1023);
2636 if (MaxScratchpadBufs
!= 0) {
2638 // Allocate the buffer to record the host address for each entry
2640 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
2641 ASSERT (ScratchEntry
!= NULL
);
2642 Xhc
->ScratchEntry
= ScratchEntry
;
2645 Status
= UsbHcAllocateAlignedPages (
2646 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
2648 (VOID
**) &ScratchBuf
,
2651 ASSERT_EFI_ERROR (Status
);
2653 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
2654 Xhc
->ScratchBuf
= ScratchBuf
;
2657 // Allocate each scratch buffer
2659 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
2660 ScratchEntryPhy
= 0;
2661 Status
= UsbHcAllocateAlignedPages (
2662 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
2664 (VOID
**) &ScratchEntry
[Index
],
2667 ASSERT_EFI_ERROR (Status
);
2668 ZeroMem ((VOID
*) (UINTN
) ScratchEntry
[Index
], Xhc
->PageSize
);
2670 // Fill with the PCI device address
2672 *ScratchBuf
++ = ScratchEntryPhy
;
2675 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
2676 // Device Context Base Address Array points to the Scratchpad Buffer Array.
2678 *(UINT64
*) Dcbaa
= (UINT64
) (UINTN
) ScratchPhy
;
2682 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
2683 // a 64-bit address pointing to where the Device Context Base Address Array is located.
2685 Xhc
->DCBAA
= (UINT64
*) (UINTN
) Dcbaa
;
2687 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2688 // So divide it to two 32-bytes width register access.
2690 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Size
);
2691 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT (DcbaaPhy
));
2692 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
2694 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc
->DCBAA
));
2697 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
2698 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
2699 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
2702 XhcPeiCreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
2704 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
2705 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
2706 // So we set RCS as inverted PCS init value to let Command Ring empty
2708 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
2709 ASSERT ((CmdRingPhy
& 0x3F) == 0);
2710 CmdRingPhy
|= XHC_CRCR_RCS
;
2712 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2713 // So divide it to two 32-bytes width register access.
2715 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT (CmdRingPhy
));
2716 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
2718 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc
->CmdRing
.RingSeg0
));
2721 // Disable the 'interrupter enable' bit in USB_CMD
2722 // and clear IE & IP bit in all Interrupter X Management Registers.
2724 XhcPeiClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
2725 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
2726 XhcPeiClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
2727 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
2731 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
2733 XhcPeiCreateEventRing (Xhc
, &Xhc
->EventRing
);
2734 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc
->EventRing
.EventRingSeg0
));
2738 Free the resouce allocated at initializing schedule.
2740 @param Xhc The XHCI device.
2749 UINT64
*ScratchEntry
;
2751 if (Xhc
->ScratchBuf
!= NULL
) {
2752 ScratchEntry
= Xhc
->ScratchEntry
;
2753 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
2755 // Free Scratchpad Buffers
2757 UsbHcFreeAlignedPages ((VOID
*) (UINTN
) ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
));
2760 // Free Scratchpad Buffer Array
2762 UsbHcFreeAlignedPages (Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)));
2763 FreePool (Xhc
->ScratchEntry
);
2766 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
2767 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
2768 Xhc
->CmdRing
.RingSeg0
= NULL
;
2771 XhcPeiFreeEventRing (Xhc
,&Xhc
->EventRing
);
2773 if (Xhc
->DCBAA
!= NULL
) {
2774 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
));
2779 // Free memory pool at last
2781 if (Xhc
->MemPool
!= NULL
) {
2782 UsbHcFreeMemPool (Xhc
->MemPool
);
2783 Xhc
->MemPool
= NULL
;