2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
5 Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
6 Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
15 Create a command transfer TRB to support XHCI command interfaces.
17 @param Xhc The XHCI device.
18 @param CmdTrb The cmd TRB to be executed.
20 @return Created URB or NULL.
26 IN TRB_TEMPLATE
*CmdTrb
31 Urb
= AllocateZeroPool (sizeof (URB
));
36 Urb
->Signature
= XHC_URB_SIG
;
38 Urb
->Ring
= &Xhc
->CmdRing
;
39 XhcPeiSyncTrsRing (Xhc
, Urb
->Ring
);
41 Urb
->TrbStart
= Urb
->Ring
->RingEnqueue
;
42 CopyMem (Urb
->TrbStart
, CmdTrb
, sizeof (TRB_TEMPLATE
));
43 Urb
->TrbStart
->CycleBit
= Urb
->Ring
->RingPCS
& BIT0
;
44 Urb
->TrbEnd
= Urb
->TrbStart
;
50 Execute a XHCI cmd TRB pointed by CmdTrb.
52 @param Xhc The XHCI device.
53 @param CmdTrb The cmd TRB to be executed.
54 @param Timeout Indicates the maximum time, in millisecond, which the
55 transfer is allowed to complete.
56 @param EvtTrb The event TRB corresponding to the cmd TRB.
58 @retval EFI_SUCCESS The transfer was completed successfully.
59 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
60 @retval EFI_TIMEOUT The transfer failed due to timeout.
61 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
67 IN TRB_TEMPLATE
*CmdTrb
,
69 OUT TRB_TEMPLATE
**EvtTrb
76 // Validate the parameters
78 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
79 return EFI_INVALID_PARAMETER
;
82 Status
= EFI_DEVICE_ERROR
;
84 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
85 DEBUG ((DEBUG_ERROR
, "XhcPeiCmdTransfer: HC is halted or has system error\n"));
90 // Create a new URB, then poll the execution status.
92 Urb
= XhcPeiCreateCmdTrb (Xhc
, CmdTrb
);
94 DEBUG ((DEBUG_ERROR
, "XhcPeiCmdTransfer: failed to create URB\n"));
95 Status
= EFI_OUT_OF_RESOURCES
;
99 Status
= XhcPeiExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
100 *EvtTrb
= Urb
->EvtTrb
;
102 if (Urb
->Result
== EFI_USB_NOERROR
) {
103 Status
= EFI_SUCCESS
;
106 XhcPeiFreeUrb (Xhc
, Urb
);
113 Create a new URB for a new transaction.
115 @param Xhc The XHCI device
116 @param BusAddr The logical device address assigned by UsbBus driver
117 @param EpAddr Endpoint addrress
118 @param DevSpeed The device speed
119 @param MaxPacket The max packet length of the endpoint
120 @param Type The transaction type
121 @param Request The standard USB request for control transfer
122 @param Data The user data to transfer
123 @param DataLen The length of data buffer
124 @param Callback The function to call when data is transferred
125 @param Context The context to the callback
127 @return Created URB or NULL
138 IN EFI_USB_DEVICE_REQUEST
*Request
,
141 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
149 Urb
= AllocateZeroPool (sizeof (URB
));
154 Urb
->Signature
= XHC_URB_SIG
;
157 Ep
->BusAddr
= BusAddr
;
158 Ep
->EpAddr
= (UINT8
)(EpAddr
& 0x0F);
159 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
160 Ep
->DevSpeed
= DevSpeed
;
161 Ep
->MaxPacket
= MaxPacket
;
164 Urb
->Request
= Request
;
166 Urb
->DataLen
= DataLen
;
167 Urb
->Callback
= Callback
;
168 Urb
->Context
= Context
;
170 Status
= XhcPeiCreateTransferTrb (Xhc
, Urb
);
171 if (EFI_ERROR (Status
)) {
172 DEBUG ((DEBUG_ERROR
, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status
));
181 Free an allocated URB.
183 @param Xhc The XHCI device.
184 @param Urb The URB to free.
193 if ((Xhc
== NULL
) || (Urb
== NULL
)) {
197 IoMmuUnmap (Urb
->DataMap
);
203 Create a transfer TRB.
205 @param Xhc The XHCI device
206 @param Urb The urb used to construct the transfer TRB.
208 @return Created TRB or NULL
212 XhcPeiCreateTransferTrb (
218 TRANSFER_RING
*EPRing
;
226 EDKII_IOMMU_OPERATION MapOp
;
227 EFI_PHYSICAL_ADDRESS PhyAddr
;
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
;
255 if ((Urb
->Data
!= NULL
) && (Urb
->DataMap
== NULL
)) {
256 if (((UINT8
)(Urb
->Ep
.Direction
)) == EfiUsbDataIn
) {
257 MapOp
= EdkiiIoMmuOperationBusMasterWrite
;
259 MapOp
= EdkiiIoMmuOperationBusMasterRead
;
263 Status
= IoMmuMap (MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
265 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
266 DEBUG ((DEBUG_ERROR
, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
267 return EFI_OUT_OF_RESOURCES
;
270 Urb
->DataPhy
= (VOID
*)((UINTN
)PhyAddr
);
277 XhcPeiSyncTrsRing (Xhc
, EPRing
);
278 Urb
->TrbStart
= EPRing
->RingEnqueue
;
280 case ED_CONTROL_BIDIR
:
282 // For control transfer, create SETUP_STAGE_TRB first.
284 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
285 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
286 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
287 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
288 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
289 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
290 TrbStart
->TrbCtrSetup
.Length
= 8;
291 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
292 TrbStart
->TrbCtrSetup
.IOC
= 1;
293 TrbStart
->TrbCtrSetup
.IDT
= 1;
294 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
295 if (Urb
->DataLen
> 0) {
296 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
297 TrbStart
->TrbCtrSetup
.TRT
= 3;
298 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
299 TrbStart
->TrbCtrSetup
.TRT
= 2;
301 DEBUG ((DEBUG_ERROR
, "XhcPeiCreateTransferTrb: Direction sholud be IN or OUT when Data exists!\n"));
305 TrbStart
->TrbCtrSetup
.TRT
= 0;
309 // Update the cycle bit
311 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
315 // For control transfer, create DATA_STAGE_TRB.
317 if (Urb
->DataLen
> 0) {
318 XhcPeiSyncTrsRing (Xhc
, EPRing
);
319 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
320 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT (Urb
->DataPhy
);
321 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT (Urb
->DataPhy
);
322 TrbStart
->TrbCtrData
.Length
= (UINT32
)Urb
->DataLen
;
323 TrbStart
->TrbCtrData
.TDSize
= 0;
324 TrbStart
->TrbCtrData
.IntTarget
= 0;
325 TrbStart
->TrbCtrData
.ISP
= 1;
326 TrbStart
->TrbCtrData
.IOC
= 1;
327 TrbStart
->TrbCtrData
.IDT
= 0;
328 TrbStart
->TrbCtrData
.CH
= 0;
329 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
330 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
331 TrbStart
->TrbCtrData
.DIR = 1;
332 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
333 TrbStart
->TrbCtrData
.DIR = 0;
335 TrbStart
->TrbCtrData
.DIR = 0;
339 // Update the cycle bit
341 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
346 // For control transfer, create STATUS_STAGE_TRB.
347 // Get the pointer to next TRB for status stage use
349 XhcPeiSyncTrsRing (Xhc
, EPRing
);
350 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
351 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
352 TrbStart
->TrbCtrStatus
.IOC
= 1;
353 TrbStart
->TrbCtrStatus
.CH
= 0;
354 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
355 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
356 TrbStart
->TrbCtrStatus
.DIR = 0;
357 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
358 TrbStart
->TrbCtrStatus
.DIR = 1;
360 TrbStart
->TrbCtrStatus
.DIR = 0;
364 // Update the cycle bit
366 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
368 // Update the enqueue pointer
370 XhcPeiSyncTrsRing (Xhc
, EPRing
);
372 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
381 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
382 while (TotalLen
< Urb
->DataLen
) {
383 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
384 Len
= Urb
->DataLen
- TotalLen
;
389 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
390 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT ((UINT8
*)Urb
->DataPhy
+ TotalLen
);
391 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT ((UINT8
*)Urb
->DataPhy
+ TotalLen
);
392 TrbStart
->TrbNormal
.Length
= (UINT32
)Len
;
393 TrbStart
->TrbNormal
.TDSize
= 0;
394 TrbStart
->TrbNormal
.IntTarget
= 0;
395 TrbStart
->TrbNormal
.ISP
= 1;
396 TrbStart
->TrbNormal
.IOC
= 1;
397 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
399 // Update the cycle bit
401 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
403 XhcPeiSyncTrsRing (Xhc
, EPRing
);
408 Urb
->TrbNum
= TrbNum
;
409 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
412 case ED_INTERRUPT_OUT
:
413 case ED_INTERRUPT_IN
:
417 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
418 while (TotalLen
< Urb
->DataLen
) {
419 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
420 Len
= Urb
->DataLen
- TotalLen
;
425 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
426 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT ((UINT8
*)Urb
->DataPhy
+ TotalLen
);
427 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT ((UINT8
*)Urb
->DataPhy
+ TotalLen
);
428 TrbStart
->TrbNormal
.Length
= (UINT32
)Len
;
429 TrbStart
->TrbNormal
.TDSize
= 0;
430 TrbStart
->TrbNormal
.IntTarget
= 0;
431 TrbStart
->TrbNormal
.ISP
= 1;
432 TrbStart
->TrbNormal
.IOC
= 1;
433 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
435 // Update the cycle bit
437 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
439 XhcPeiSyncTrsRing (Xhc
, EPRing
);
444 Urb
->TrbNum
= TrbNum
;
445 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
449 DEBUG ((DEBUG_INFO
, "Not supported EPType 0x%x!\n", EPType
));
458 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
459 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
460 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
461 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
462 Stopped to the Running state.
464 @param Xhc The XHCI device.
465 @param Urb The urb which makes the endpoint halted.
467 @retval EFI_SUCCESS The recovery is successful.
468 @retval Others Failed to recovery halted endpoint.
472 XhcPeiRecoverHaltedEndpoint (
481 Status
= EFI_SUCCESS
;
482 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
484 return EFI_DEVICE_ERROR
;
487 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
489 DEBUG ((DEBUG_INFO
, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId
, Dci
));
492 // 1) Send Reset endpoint command to transit from halt to stop state
494 Status
= XhcPeiResetEndpoint (Xhc
, SlotId
, Dci
);
495 if (EFI_ERROR (Status
)) {
496 DEBUG ((DEBUG_ERROR
, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
501 // 2) Set dequeue pointer
503 Status
= XhcPeiSetTrDequeuePointer (Xhc
, SlotId
, Dci
, Urb
);
504 if (EFI_ERROR (Status
)) {
505 DEBUG ((DEBUG_ERROR
, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
510 // 3) Ring the doorbell to transit from stop to active
512 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
519 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
520 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
521 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
524 @param Xhc The XHCI device.
525 @param Urb The urb which doesn't get completed in a specified timeout range.
527 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
528 @retval Others Failed to stop the endpoint and dequeue the TDs.
532 XhcPeiDequeueTrbFromEndpoint (
541 Status
= EFI_SUCCESS
;
542 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
544 return EFI_DEVICE_ERROR
;
547 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
549 DEBUG ((DEBUG_INFO
, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId
, Dci
));
552 // 1) Send Stop endpoint command to stop endpoint.
554 Status
= XhcPeiStopEndpoint (Xhc
, SlotId
, Dci
);
555 if (EFI_ERROR (Status
)) {
556 DEBUG ((DEBUG_ERROR
, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
561 // 2) Set dequeue pointer
563 Status
= XhcPeiSetTrDequeuePointer (Xhc
, SlotId
, Dci
, Urb
);
564 if (EFI_ERROR (Status
)) {
565 DEBUG ((DEBUG_ERROR
, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
570 // 3) Ring the doorbell to transit from stop to active
572 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
579 Check if the Trb is a transaction of the URB.
581 @param Trb The TRB to be checked
582 @param Urb The transfer ring to be checked.
584 @retval TRUE It is a transaction of the URB.
585 @retval FALSE It is not any transaction of the URB.
589 XhcPeiIsTransferRingTrb (
590 IN TRB_TEMPLATE
*Trb
,
594 TRB_TEMPLATE
*CheckedTrb
;
597 CheckedTrb
= Urb
->Ring
->RingSeg0
;
599 ASSERT (Urb
->Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Urb
->Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
601 for (Index
= 0; Index
< Urb
->Ring
->TrbNumber
; Index
++) {
602 if (Trb
== CheckedTrb
) {
613 Check the URB's execution result and update the URB's
616 @param Xhc The XHCI device.
617 @param Urb The URB to check result.
619 @return Whether the result of URB transfer is finialized.
623 XhcPeiCheckUrbResult (
628 EVT_TRB_TRANSFER
*EvtTrb
;
629 TRB_TEMPLATE
*TRBPtr
;
637 EFI_PHYSICAL_ADDRESS PhyAddr
;
639 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
641 Status
= EFI_SUCCESS
;
649 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
650 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
655 // Traverse the event ring to find out all new events from the previous check.
657 XhcPeiSyncEventRing (Xhc
, &Xhc
->EventRing
);
658 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
659 Status
= XhcPeiCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
660 if (Status
== EFI_NOT_READY
) {
662 // All new events are handled, return directly.
668 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
670 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
675 // Need convert pci device address to host address
677 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
)EvtTrb
->TRBPtrHi
, 32));
678 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
)UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
)PhyAddr
, sizeof (TRB_TEMPLATE
));
681 // Update the status of Urb according to the finished event regardless of whether
682 // the urb is current checked one or in the XHCI's async transfer list.
683 // This way is used to avoid that those completed async transfer events don't get
684 // handled in time and are flushed by newer coming events.
686 if (XhcPeiIsTransferRingTrb (TRBPtr
, Urb
)) {
692 switch (EvtTrb
->Completecode
) {
693 case TRB_COMPLETION_STALL_ERROR
:
694 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
695 CheckedUrb
->Finished
= TRUE
;
696 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
699 case TRB_COMPLETION_BABBLE_ERROR
:
700 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
701 CheckedUrb
->Finished
= TRUE
;
702 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
705 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
706 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
707 CheckedUrb
->Finished
= TRUE
;
708 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb
->Completecode
));
711 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
712 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
713 CheckedUrb
->Finished
= TRUE
;
714 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
717 case TRB_COMPLETION_SHORT_PACKET
:
718 case TRB_COMPLETION_SUCCESS
:
719 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
720 DEBUG ((DEBUG_VERBOSE
, "XhcPeiCheckUrbResult: short packet happens!\n"));
723 TRBType
= (UINT8
)(TRBPtr
->Type
);
724 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
725 (TRBType
== TRB_TYPE_NORMAL
) ||
726 (TRBType
== TRB_TYPE_ISOCH
))
728 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
734 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb
->Completecode
));
735 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
736 CheckedUrb
->Finished
= TRUE
;
741 // Only check first and end Trb event address
743 if (TRBPtr
== CheckedUrb
->TrbStart
) {
744 CheckedUrb
->StartDone
= TRUE
;
747 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
748 CheckedUrb
->EndDone
= TRUE
;
751 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
752 CheckedUrb
->Finished
= TRUE
;
753 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
760 // Advance event ring to last available entry
762 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
763 // So divide it to two 32-bytes width register access.
765 Low
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
766 High
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
767 XhcDequeue
= (UINT64
)(LShiftU64 ((UINT64
)High
, 32) | Low
);
769 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
771 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
773 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
774 // So divide it to two 32-bytes width register access.
776 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
777 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
780 return Urb
->Finished
;
784 Execute the transfer by polling the URB. This is a synchronous operation.
786 @param Xhc The XHCI device.
787 @param CmdTransfer The executed URB is for cmd transfer or not.
788 @param Urb The URB to execute.
789 @param Timeout The time to wait before abort, in millisecond.
791 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
792 @return EFI_TIMEOUT The transfer failed due to time out.
793 @return EFI_SUCCESS The transfer finished OK.
799 IN BOOLEAN CmdTransfer
,
815 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
817 return EFI_DEVICE_ERROR
;
820 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
823 Status
= EFI_SUCCESS
;
824 Loop
= Timeout
* XHC_1_MILLISECOND
;
829 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
831 for (Index
= 0; Index
< Loop
; Index
++) {
832 Finished
= XhcPeiCheckUrbResult (Xhc
, Urb
);
837 MicroSecondDelay (XHC_1_MICROSECOND
);
841 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
842 Status
= EFI_TIMEOUT
;
843 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
844 Status
= EFI_DEVICE_ERROR
;
851 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
853 @param Xhc The XHCI device.
854 @param ParentRouteChart The route string pointed to the parent device if it exists.
855 @param Port The port to be polled.
856 @param PortState The port state.
858 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
859 @retval Others Should not appear.
863 XhcPeiPollPortStatusChange (
865 IN USB_DEV_ROUTE ParentRouteChart
,
867 IN EFI_USB_PORT_STATUS
*PortState
873 USB_DEV_ROUTE RouteChart
;
875 DEBUG ((DEBUG_INFO
, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState
->PortChangeStatus
, PortState
->PortStatus
));
877 Status
= EFI_SUCCESS
;
879 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
883 if (ParentRouteChart
.Dword
== 0) {
884 RouteChart
.Route
.RouteString
= 0;
885 RouteChart
.Route
.RootPortNum
= Port
+ 1;
886 RouteChart
.Route
.TierNum
= 1;
889 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
891 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
894 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
895 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
898 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
900 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
901 Status
= XhcPeiDisableSlotCmd (Xhc
, SlotId
);
903 Status
= XhcPeiDisableSlotCmd64 (Xhc
, SlotId
);
907 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
908 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0))
911 // Has a device attached, Identify device speed after port is enabled.
913 Speed
= EFI_USB_SPEED_FULL
;
914 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
915 Speed
= EFI_USB_SPEED_LOW
;
916 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
917 Speed
= EFI_USB_SPEED_HIGH
;
918 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
919 Speed
= EFI_USB_SPEED_SUPER
;
923 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
925 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
926 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
927 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
928 Status
= XhcPeiInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
930 Status
= XhcPeiInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
939 Calculate the device context index by endpoint address and direction.
941 @param EpAddr The target endpoint number.
942 @param Direction The direction of the target endpoint.
944 @return The device context index of endpoint.
948 XhcPeiEndpointToDci (
950 IN EFI_USB_DATA_DIRECTION Direction
955 ASSERT (EpAddr
<= 15);
960 Index
= (UINT8
)(2 * EpAddr
);
961 if (Direction
== EfiUsbDataIn
) {
970 Find out the actual device address according to the requested device address from UsbBus.
972 @param Xhc The XHCI device.
973 @param BusDevAddr The requested device address by UsbBus upper driver.
975 @return The actual device address assigned to the device.
979 XhcPeiBusDevAddrToSlotId (
986 for (Index
= 0; Index
< 255; Index
++) {
987 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
988 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
989 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
))
999 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1003 Find out the slot id according to the device's route string.
1005 @param Xhc The XHCI device.
1006 @param RouteString The route string described the device location.
1008 @return The slot id used by the device.
1012 XhcPeiRouteStringToSlotId (
1013 IN PEI_XHC_DEV
*Xhc
,
1014 IN USB_DEV_ROUTE RouteString
1019 for (Index
= 0; Index
< 255; Index
++) {
1020 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1021 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1022 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
))
1032 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1036 Ring the door bell to notify XHCI there is a transaction to be executed.
1038 @param Xhc The XHCI device.
1039 @param SlotId The slot id of the target device.
1040 @param Dci The device context index of the target slot or endpoint.
1044 XhcPeiRingDoorBell (
1045 IN PEI_XHC_DEV
*Xhc
,
1051 XhcPeiWriteDoorBellReg (Xhc
, 0, 0);
1053 XhcPeiWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1058 Assign and initialize the device slot for a new device.
1060 @param Xhc The XHCI device.
1061 @param ParentRouteChart The route string pointed to the parent device.
1062 @param ParentPort The port at which the device is located.
1063 @param RouteChart The route string pointed to the device.
1064 @param DeviceSpeed The device speed.
1066 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1067 @retval Others Fail to initialize device slot.
1071 XhcPeiInitializeDeviceSlot (
1072 IN PEI_XHC_DEV
*Xhc
,
1073 IN USB_DEV_ROUTE ParentRouteChart
,
1074 IN UINT16 ParentPort
,
1075 IN USB_DEV_ROUTE RouteChart
,
1076 IN UINT8 DeviceSpeed
1080 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1081 INPUT_CONTEXT
*InputContext
;
1082 DEVICE_CONTEXT
*OutputContext
;
1083 TRANSFER_RING
*EndpointTransferRing
;
1084 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1085 UINT8 DeviceAddress
;
1086 CMD_TRB_ENABLE_SLOT CmdTrb
;
1089 DEVICE_CONTEXT
*ParentDeviceContext
;
1090 EFI_PHYSICAL_ADDRESS PhyAddr
;
1092 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1093 CmdTrb
.CycleBit
= 1;
1094 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1096 Status
= XhcPeiCmdTransfer (
1098 (TRB_TEMPLATE
*)(UINTN
)&CmdTrb
,
1099 XHC_GENERIC_TIMEOUT
,
1100 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1102 if (EFI_ERROR (Status
)) {
1103 DEBUG ((DEBUG_ERROR
, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
1107 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1108 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1109 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1110 ASSERT (SlotId
!= 0);
1112 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1113 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1114 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1115 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1116 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1119 // 4.3.3 Device Slot Initialization
1120 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1122 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
1123 ASSERT (InputContext
!= NULL
);
1124 ASSERT (((UINTN
)InputContext
& 0x3F) == 0);
1125 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1127 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*)InputContext
;
1130 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1131 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1132 // Context are affected by the command.
1134 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1137 // 3) Initialize the Input Slot Context data structure
1139 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1140 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1141 InputContext
->Slot
.ContextEntries
= 1;
1142 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1144 if (RouteChart
.Route
.RouteString
!= 0) {
1146 // The device is behind of hub device.
1148 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1149 ASSERT (ParentSlotId
!= 0);
1151 // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
1153 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1154 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1155 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0))
1157 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1159 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1160 // environment from Full/Low speed signaling environment for a device
1162 InputContext
->Slot
.TTPortNum
= ParentPort
;
1163 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1167 // Inherit the TT parameters from parent device.
1169 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1170 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1172 // If the device is a High speed device then down the speed to be the same as its parent Hub
1174 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1175 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1181 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1183 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1184 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1185 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1187 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1189 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1191 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1192 InputContext
->EP
[0].MaxPacketSize
= 512;
1193 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1194 InputContext
->EP
[0].MaxPacketSize
= 64;
1196 InputContext
->EP
[0].MaxPacketSize
= 8;
1200 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1201 // 1KB, and Bulk and Isoch endpoints 3KB.
1203 InputContext
->EP
[0].AverageTRBLength
= 8;
1204 InputContext
->EP
[0].MaxBurstSize
= 0;
1205 InputContext
->EP
[0].Interval
= 0;
1206 InputContext
->EP
[0].MaxPStreams
= 0;
1207 InputContext
->EP
[0].Mult
= 0;
1208 InputContext
->EP
[0].CErr
= 3;
1211 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1213 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1215 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1216 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1218 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1219 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1222 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1224 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
1225 ASSERT (OutputContext
!= NULL
);
1226 ASSERT (((UINTN
)OutputContext
& 0x3F) == 0);
1227 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
1229 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1231 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1232 // a pointer to the Output Device Context data structure (6.2.1).
1234 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
1236 // Fill DCBAA with PCI device address
1238 Xhc
->DCBAA
[SlotId
] = (UINT64
)(UINTN
)PhyAddr
;
1241 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1242 // Context data structure described above.
1244 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1247 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY
);
1248 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1249 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1250 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1251 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1252 CmdTrbAddr
.CycleBit
= 1;
1253 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1254 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1255 Status
= XhcPeiCmdTransfer (
1257 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbAddr
,
1258 XHC_GENERIC_TIMEOUT
,
1259 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1261 if (!EFI_ERROR (Status
)) {
1262 DeviceAddress
= (UINT8
)OutputContext
->Slot
.DeviceAddress
;
1263 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress
));
1264 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1267 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status
));
1272 Assign and initialize the device slot for a new device.
1274 @param Xhc The XHCI device.
1275 @param ParentRouteChart The route string pointed to the parent device.
1276 @param ParentPort The port at which the device is located.
1277 @param RouteChart The route string pointed to the device.
1278 @param DeviceSpeed The device speed.
1280 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1281 @retval Others Fail to initialize device slot.
1285 XhcPeiInitializeDeviceSlot64 (
1286 IN PEI_XHC_DEV
*Xhc
,
1287 IN USB_DEV_ROUTE ParentRouteChart
,
1288 IN UINT16 ParentPort
,
1289 IN USB_DEV_ROUTE RouteChart
,
1290 IN UINT8 DeviceSpeed
1294 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1295 INPUT_CONTEXT_64
*InputContext
;
1296 DEVICE_CONTEXT_64
*OutputContext
;
1297 TRANSFER_RING
*EndpointTransferRing
;
1298 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1299 UINT8 DeviceAddress
;
1300 CMD_TRB_ENABLE_SLOT CmdTrb
;
1303 DEVICE_CONTEXT_64
*ParentDeviceContext
;
1304 EFI_PHYSICAL_ADDRESS PhyAddr
;
1306 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1307 CmdTrb
.CycleBit
= 1;
1308 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1310 Status
= XhcPeiCmdTransfer (
1312 (TRB_TEMPLATE
*)(UINTN
)&CmdTrb
,
1313 XHC_GENERIC_TIMEOUT
,
1314 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1316 if (EFI_ERROR (Status
)) {
1317 DEBUG ((DEBUG_ERROR
, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
1321 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1322 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1323 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1324 ASSERT (SlotId
!= 0);
1326 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1327 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1328 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1329 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1330 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1333 // 4.3.3 Device Slot Initialization
1334 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1336 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
1337 ASSERT (InputContext
!= NULL
);
1338 ASSERT (((UINTN
)InputContext
& 0x3F) == 0);
1339 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1341 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*)InputContext
;
1344 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1345 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1346 // Context are affected by the command.
1348 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1351 // 3) Initialize the Input Slot Context data structure
1353 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1354 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1355 InputContext
->Slot
.ContextEntries
= 1;
1356 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1358 if (RouteChart
.Route
.RouteString
!= 0) {
1360 // The device is behind of hub device.
1362 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1363 ASSERT (ParentSlotId
!= 0);
1365 // if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1367 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1368 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1369 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0))
1371 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1373 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1374 // environment from Full/Low speed signaling environment for a device
1376 InputContext
->Slot
.TTPortNum
= ParentPort
;
1377 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1381 // Inherit the TT parameters from parent device.
1383 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1384 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1386 // If the device is a High speed device then down the speed to be the same as its parent Hub
1388 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1389 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1395 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1397 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1398 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1399 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1401 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1403 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1405 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1406 InputContext
->EP
[0].MaxPacketSize
= 512;
1407 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1408 InputContext
->EP
[0].MaxPacketSize
= 64;
1410 InputContext
->EP
[0].MaxPacketSize
= 8;
1414 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1415 // 1KB, and Bulk and Isoch endpoints 3KB.
1417 InputContext
->EP
[0].AverageTRBLength
= 8;
1418 InputContext
->EP
[0].MaxBurstSize
= 0;
1419 InputContext
->EP
[0].Interval
= 0;
1420 InputContext
->EP
[0].MaxPStreams
= 0;
1421 InputContext
->EP
[0].Mult
= 0;
1422 InputContext
->EP
[0].CErr
= 3;
1425 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1427 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1429 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1430 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1432 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1433 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1436 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1438 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
1439 ASSERT (OutputContext
!= NULL
);
1440 ASSERT (((UINTN
)OutputContext
& 0x3F) == 0);
1441 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1443 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1445 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1446 // a pointer to the Output Device Context data structure (6.2.1).
1448 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1450 // Fill DCBAA with PCI device address
1452 Xhc
->DCBAA
[SlotId
] = (UINT64
)(UINTN
)PhyAddr
;
1455 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1456 // Context data structure described above.
1458 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1461 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY
);
1462 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1463 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1464 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1465 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1466 CmdTrbAddr
.CycleBit
= 1;
1467 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1468 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1469 Status
= XhcPeiCmdTransfer (
1471 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbAddr
,
1472 XHC_GENERIC_TIMEOUT
,
1473 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1475 if (!EFI_ERROR (Status
)) {
1476 DeviceAddress
= (UINT8
)OutputContext
->Slot
.DeviceAddress
;
1477 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress
));
1478 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1481 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status
));
1486 Disable the specified device slot.
1488 @param Xhc The XHCI device.
1489 @param SlotId The slot id to be disabled.
1491 @retval EFI_SUCCESS Successfully disable the device slot.
1495 XhcPeiDisableSlotCmd (
1496 IN PEI_XHC_DEV
*Xhc
,
1501 TRB_TEMPLATE
*EvtTrb
;
1502 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1507 // Disable the device slots occupied by these devices on its downstream ports.
1508 // Entry 0 is reserved.
1510 for (Index
= 0; Index
< 255; Index
++) {
1511 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1512 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1513 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
))
1518 Status
= XhcPeiDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1520 if (EFI_ERROR (Status
)) {
1521 DEBUG ((DEBUG_ERROR
, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
1522 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1527 // Construct the disable slot command
1529 DEBUG ((DEBUG_INFO
, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId
));
1531 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1532 CmdTrbDisSlot
.CycleBit
= 1;
1533 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1534 CmdTrbDisSlot
.SlotId
= SlotId
;
1535 Status
= XhcPeiCmdTransfer (
1537 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbDisSlot
,
1538 XHC_GENERIC_TIMEOUT
,
1539 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1541 if (EFI_ERROR (Status
)) {
1542 DEBUG ((DEBUG_ERROR
, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
1547 // Free the slot's device context entry
1549 Xhc
->DCBAA
[SlotId
] = 0;
1552 // Free the slot related data structure
1554 for (Index
= 0; Index
< 31; Index
++) {
1555 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1556 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1557 if (RingSeg
!= NULL
) {
1558 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1561 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1562 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1566 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1567 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1568 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1572 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1573 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1576 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1577 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
1581 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1582 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1583 // remove urb from XHCI's asynchronous transfer list.
1585 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1586 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1588 DEBUG ((DEBUG_INFO
, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status
));
1593 Disable the specified device slot.
1595 @param Xhc The XHCI device.
1596 @param SlotId The slot id to be disabled.
1598 @retval EFI_SUCCESS Successfully disable the device slot.
1602 XhcPeiDisableSlotCmd64 (
1603 IN PEI_XHC_DEV
*Xhc
,
1608 TRB_TEMPLATE
*EvtTrb
;
1609 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1614 // Disable the device slots occupied by these devices on its downstream ports.
1615 // Entry 0 is reserved.
1617 for (Index
= 0; Index
< 255; Index
++) {
1618 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1619 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1620 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
))
1625 Status
= XhcPeiDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1627 if (EFI_ERROR (Status
)) {
1628 DEBUG ((DEBUG_ERROR
, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
1629 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1634 // Construct the disable slot command
1636 DEBUG ((DEBUG_INFO
, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId
));
1638 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1639 CmdTrbDisSlot
.CycleBit
= 1;
1640 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1641 CmdTrbDisSlot
.SlotId
= SlotId
;
1642 Status
= XhcPeiCmdTransfer (
1644 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbDisSlot
,
1645 XHC_GENERIC_TIMEOUT
,
1646 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1648 if (EFI_ERROR (Status
)) {
1649 DEBUG ((DEBUG_ERROR
, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status
));
1654 // Free the slot's device context entry
1656 Xhc
->DCBAA
[SlotId
] = 0;
1659 // Free the slot related data structure
1661 for (Index
= 0; Index
< 31; Index
++) {
1662 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1663 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1664 if (RingSeg
!= NULL
) {
1665 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1668 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1669 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1673 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1674 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1675 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1679 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1680 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1683 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1684 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1688 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1689 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1690 // remove urb from XHCI's asynchronous transfer list.
1692 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1693 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1695 DEBUG ((DEBUG_INFO
, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status
));
1700 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1702 @param Xhc The XHCI device.
1703 @param SlotId The slot id to be configured.
1704 @param DeviceSpeed The device's speed.
1705 @param ConfigDesc The pointer to the usb device configuration descriptor.
1707 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1711 XhcPeiSetConfigCmd (
1712 IN PEI_XHC_DEV
*Xhc
,
1714 IN UINT8 DeviceSpeed
,
1715 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1719 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1720 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1725 EFI_USB_DATA_DIRECTION Direction
;
1728 EFI_PHYSICAL_ADDRESS PhyAddr
;
1731 TRANSFER_RING
*EndpointTransferRing
;
1732 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1733 INPUT_CONTEXT
*InputContext
;
1734 DEVICE_CONTEXT
*OutputContext
;
1735 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1738 // 4.6.6 Configure Endpoint
1740 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1741 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1742 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1743 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
1745 ASSERT (ConfigDesc
!= NULL
);
1749 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
1750 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1751 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1752 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
1755 NumEp
= IfDesc
->NumEndpoints
;
1756 if ((NumEp
== 0) && (MaxDci
== 0)) {
1760 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
1761 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1762 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1763 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1766 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
1767 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1769 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1774 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1775 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1777 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1779 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1781 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1783 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1786 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
1787 case USB_ENDPOINT_BULK
:
1788 if (Direction
== EfiUsbDataIn
) {
1789 InputContext
->EP
[Dci
-1].CErr
= 3;
1790 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
1792 InputContext
->EP
[Dci
-1].CErr
= 3;
1793 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
1796 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1797 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1798 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1799 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*)EndpointTransferRing
;
1800 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1804 case USB_ENDPOINT_ISO
:
1805 if (Direction
== EfiUsbDataIn
) {
1806 InputContext
->EP
[Dci
-1].CErr
= 0;
1807 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
1809 InputContext
->EP
[Dci
-1].CErr
= 0;
1810 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
1814 // Get the bInterval from descriptor and init the the interval field of endpoint context.
1815 // Refer to XHCI 1.1 spec section 6.2.3.6.
1817 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
1818 Interval
= EpDesc
->Interval
;
1819 ASSERT (Interval
>= 1 && Interval
<= 16);
1820 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
1821 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1822 Interval
= EpDesc
->Interval
;
1823 ASSERT (Interval
>= 1 && Interval
<= 16);
1824 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1828 // Do not support isochronous transfer now.
1830 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1831 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1833 case USB_ENDPOINT_INTERRUPT
:
1834 if (Direction
== EfiUsbDataIn
) {
1835 InputContext
->EP
[Dci
-1].CErr
= 3;
1836 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
1838 InputContext
->EP
[Dci
-1].CErr
= 3;
1839 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
1842 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1843 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
1845 // Get the bInterval from descriptor and init the interval field of endpoint context
1847 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
1848 Interval
= EpDesc
->Interval
;
1850 // Calculate through the bInterval field of Endpoint descriptor.
1852 ASSERT (Interval
!= 0);
1853 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32 ((UINT32
)Interval
) + 3;
1854 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1855 Interval
= EpDesc
->Interval
;
1856 ASSERT (Interval
>= 1 && Interval
<= 16);
1858 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1860 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1863 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1864 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1865 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*)EndpointTransferRing
;
1866 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1871 case USB_ENDPOINT_CONTROL
:
1873 // Do not support control transfer now.
1875 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1877 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
1878 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1882 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1884 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
1885 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1887 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
1888 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
1889 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1890 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1892 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1895 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
1898 InputContext
->InputControlContext
.Dword2
|= BIT0
;
1899 InputContext
->Slot
.ContextEntries
= MaxDci
;
1901 // configure endpoint
1903 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
1904 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
1905 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1906 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1907 CmdTrbCfgEP
.CycleBit
= 1;
1908 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
1909 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1910 DEBUG ((DEBUG_INFO
, "XhcSetConfigCmd: Configure Endpoint\n"));
1911 Status
= XhcPeiCmdTransfer (
1913 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbCfgEP
,
1914 XHC_GENERIC_TIMEOUT
,
1915 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1917 if (EFI_ERROR (Status
)) {
1918 DEBUG ((DEBUG_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
1925 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1927 @param Xhc The XHCI device.
1928 @param SlotId The slot id to be configured.
1929 @param DeviceSpeed The device's speed.
1930 @param ConfigDesc The pointer to the usb device configuration descriptor.
1932 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1936 XhcPeiSetConfigCmd64 (
1937 IN PEI_XHC_DEV
*Xhc
,
1939 IN UINT8 DeviceSpeed
,
1940 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1944 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1945 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1950 EFI_USB_DATA_DIRECTION Direction
;
1953 EFI_PHYSICAL_ADDRESS PhyAddr
;
1956 TRANSFER_RING
*EndpointTransferRing
;
1957 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1958 INPUT_CONTEXT_64
*InputContext
;
1959 DEVICE_CONTEXT_64
*OutputContext
;
1960 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1963 // 4.6.6 Configure Endpoint
1965 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1966 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1967 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1968 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
1970 ASSERT (ConfigDesc
!= NULL
);
1974 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
1975 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1976 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1977 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
1980 NumEp
= IfDesc
->NumEndpoints
;
1981 if ((NumEp
== 0) && (MaxDci
== 0)) {
1985 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
1986 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1987 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1988 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1991 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
1992 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1994 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
2000 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2001 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2003 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2005 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2007 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2009 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2012 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2013 case USB_ENDPOINT_BULK
:
2014 if (Direction
== EfiUsbDataIn
) {
2015 InputContext
->EP
[Dci
-1].CErr
= 3;
2016 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2018 InputContext
->EP
[Dci
-1].CErr
= 3;
2019 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2022 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2023 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2024 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2025 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*)EndpointTransferRing
;
2026 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2030 case USB_ENDPOINT_ISO
:
2031 if (Direction
== EfiUsbDataIn
) {
2032 InputContext
->EP
[Dci
-1].CErr
= 0;
2033 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2035 InputContext
->EP
[Dci
-1].CErr
= 0;
2036 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2040 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2041 // Refer to XHCI 1.1 spec section 6.2.3.6.
2043 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2044 Interval
= EpDesc
->Interval
;
2045 ASSERT (Interval
>= 1 && Interval
<= 16);
2046 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2047 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2048 Interval
= EpDesc
->Interval
;
2049 ASSERT (Interval
>= 1 && Interval
<= 16);
2050 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2054 // Do not support isochronous transfer now.
2056 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2057 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2059 case USB_ENDPOINT_INTERRUPT
:
2060 if (Direction
== EfiUsbDataIn
) {
2061 InputContext
->EP
[Dci
-1].CErr
= 3;
2062 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2064 InputContext
->EP
[Dci
-1].CErr
= 3;
2065 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2068 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2069 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2071 // Get the bInterval from descriptor and init the the interval field of endpoint context
2073 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2074 Interval
= EpDesc
->Interval
;
2076 // Calculate through the bInterval field of Endpoint descriptor.
2078 ASSERT (Interval
!= 0);
2079 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32 ((UINT32
)Interval
) + 3;
2080 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2081 Interval
= EpDesc
->Interval
;
2082 ASSERT (Interval
>= 1 && Interval
<= 16);
2084 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2086 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2089 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2090 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2091 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*)EndpointTransferRing
;
2092 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2097 case USB_ENDPOINT_CONTROL
:
2099 // Do not support control transfer now.
2101 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2103 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
2104 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2108 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2110 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2111 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2114 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2115 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2117 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2118 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2120 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2123 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2126 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2127 InputContext
->Slot
.ContextEntries
= MaxDci
;
2129 // configure endpoint
2131 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2132 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2133 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2134 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2135 CmdTrbCfgEP
.CycleBit
= 1;
2136 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2137 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2138 DEBUG ((DEBUG_INFO
, "XhcSetConfigCmd64: Configure Endpoint\n"));
2139 Status
= XhcPeiCmdTransfer (
2141 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbCfgEP
,
2142 XHC_GENERIC_TIMEOUT
,
2143 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2145 if (EFI_ERROR (Status
)) {
2146 DEBUG ((DEBUG_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
2153 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2155 @param Xhc The XHCI device.
2156 @param SlotId The slot id to be evaluated.
2157 @param MaxPacketSize The max packet size supported by the device control transfer.
2159 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2163 XhcPeiEvaluateContext (
2164 IN PEI_XHC_DEV
*Xhc
,
2166 IN UINT32 MaxPacketSize
2170 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2171 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2172 INPUT_CONTEXT
*InputContext
;
2173 EFI_PHYSICAL_ADDRESS PhyAddr
;
2175 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2178 // 4.6.7 Evaluate Context
2180 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2181 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2183 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2184 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2186 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2187 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2188 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2189 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2190 CmdTrbEvalu
.CycleBit
= 1;
2191 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2192 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2193 DEBUG ((DEBUG_INFO
, "XhcEvaluateContext: Evaluate context\n"));
2194 Status
= XhcPeiCmdTransfer (
2196 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbEvalu
,
2197 XHC_GENERIC_TIMEOUT
,
2198 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2200 if (EFI_ERROR (Status
)) {
2201 DEBUG ((DEBUG_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
2208 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2210 @param Xhc The XHCI device.
2211 @param SlotId The slot id to be evaluated.
2212 @param MaxPacketSize The max packet size supported by the device control transfer.
2214 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2218 XhcPeiEvaluateContext64 (
2219 IN PEI_XHC_DEV
*Xhc
,
2221 IN UINT32 MaxPacketSize
2225 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2226 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2227 INPUT_CONTEXT_64
*InputContext
;
2228 EFI_PHYSICAL_ADDRESS PhyAddr
;
2230 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2233 // 4.6.7 Evaluate Context
2235 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2236 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2238 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2239 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2241 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2242 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2243 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2244 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2245 CmdTrbEvalu
.CycleBit
= 1;
2246 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2247 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2248 DEBUG ((DEBUG_INFO
, "XhcEvaluateContext64: Evaluate context 64\n"));
2249 Status
= XhcPeiCmdTransfer (
2251 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbEvalu
,
2252 XHC_GENERIC_TIMEOUT
,
2253 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2255 if (EFI_ERROR (Status
)) {
2256 DEBUG ((DEBUG_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
2263 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2265 @param Xhc The XHCI device.
2266 @param SlotId The slot id to be configured.
2267 @param PortNum The total number of downstream port supported by the hub.
2268 @param TTT The TT think time of the hub device.
2269 @param MTT The multi-TT of the hub device.
2271 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2275 XhcPeiConfigHubContext (
2276 IN PEI_XHC_DEV
*Xhc
,
2284 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2285 INPUT_CONTEXT
*InputContext
;
2286 DEVICE_CONTEXT
*OutputContext
;
2287 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2288 EFI_PHYSICAL_ADDRESS PhyAddr
;
2290 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2291 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2292 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2295 // 4.6.7 Evaluate Context
2297 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2299 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2302 // Copy the slot context from OutputContext to Input context
2304 CopyMem (&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
2305 InputContext
->Slot
.Hub
= 1;
2306 InputContext
->Slot
.PortNum
= PortNum
;
2307 InputContext
->Slot
.TTT
= TTT
;
2308 InputContext
->Slot
.MTT
= MTT
;
2310 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2311 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2312 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2313 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2314 CmdTrbCfgEP
.CycleBit
= 1;
2315 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2316 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2317 DEBUG ((DEBUG_INFO
, "Configure Hub Slot Context\n"));
2318 Status
= XhcPeiCmdTransfer (
2320 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbCfgEP
,
2321 XHC_GENERIC_TIMEOUT
,
2322 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2324 if (EFI_ERROR (Status
)) {
2325 DEBUG ((DEBUG_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
2332 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2334 @param Xhc The XHCI device.
2335 @param SlotId The slot id to be configured.
2336 @param PortNum The total number of downstream port supported by the hub.
2337 @param TTT The TT think time of the hub device.
2338 @param MTT The multi-TT of the hub device.
2340 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2344 XhcPeiConfigHubContext64 (
2345 IN PEI_XHC_DEV
*Xhc
,
2353 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2354 INPUT_CONTEXT_64
*InputContext
;
2355 DEVICE_CONTEXT_64
*OutputContext
;
2356 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2357 EFI_PHYSICAL_ADDRESS PhyAddr
;
2359 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2360 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2361 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2364 // 4.6.7 Evaluate Context
2366 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2368 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2371 // Copy the slot context from OutputContext to Input context
2373 CopyMem (&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
2374 InputContext
->Slot
.Hub
= 1;
2375 InputContext
->Slot
.PortNum
= PortNum
;
2376 InputContext
->Slot
.TTT
= TTT
;
2377 InputContext
->Slot
.MTT
= MTT
;
2379 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2380 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2381 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2382 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2383 CmdTrbCfgEP
.CycleBit
= 1;
2384 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2385 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2386 DEBUG ((DEBUG_INFO
, "Configure Hub Slot Context 64\n"));
2387 Status
= XhcPeiCmdTransfer (
2389 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbCfgEP
,
2390 XHC_GENERIC_TIMEOUT
,
2391 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2393 if (EFI_ERROR (Status
)) {
2394 DEBUG ((DEBUG_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));
2401 Stop endpoint through XHCI's Stop_Endpoint cmd.
2403 @param Xhc The XHCI device.
2404 @param SlotId The slot id of the target device.
2405 @param Dci The device context index of the target slot or endpoint.
2407 @retval EFI_SUCCESS Stop endpoint successfully.
2408 @retval Others Failed to stop endpoint.
2413 XhcPeiStopEndpoint (
2414 IN PEI_XHC_DEV
*Xhc
,
2420 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2421 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
2423 DEBUG ((DEBUG_INFO
, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
2426 // Send stop endpoint command to transit Endpoint from running to stop state
2428 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
2429 CmdTrbStopED
.CycleBit
= 1;
2430 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
2431 CmdTrbStopED
.EDID
= Dci
;
2432 CmdTrbStopED
.SlotId
= SlotId
;
2433 Status
= XhcPeiCmdTransfer (
2435 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbStopED
,
2436 XHC_GENERIC_TIMEOUT
,
2437 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2439 if (EFI_ERROR (Status
)) {
2440 DEBUG ((DEBUG_ERROR
, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
2447 Reset endpoint through XHCI's Reset_Endpoint cmd.
2449 @param Xhc The XHCI device.
2450 @param SlotId The slot id of the target device.
2451 @param Dci The device context index of the target slot or endpoint.
2453 @retval EFI_SUCCESS Reset endpoint successfully.
2454 @retval Others Failed to reset endpoint.
2459 XhcPeiResetEndpoint (
2460 IN PEI_XHC_DEV
*Xhc
,
2466 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2467 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
2469 DEBUG ((DEBUG_INFO
, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
2472 // Send stop endpoint command to transit Endpoint from running to stop state
2474 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
2475 CmdTrbResetED
.CycleBit
= 1;
2476 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
2477 CmdTrbResetED
.EDID
= Dci
;
2478 CmdTrbResetED
.SlotId
= SlotId
;
2479 Status
= XhcPeiCmdTransfer (
2481 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbResetED
,
2482 XHC_GENERIC_TIMEOUT
,
2483 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2485 if (EFI_ERROR (Status
)) {
2486 DEBUG ((DEBUG_ERROR
, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
2493 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
2495 @param Xhc The XHCI device.
2496 @param SlotId The slot id of the target device.
2497 @param Dci The device context index of the target slot or endpoint.
2498 @param Urb The dequeue pointer of the transfer ring specified
2499 by the urb to be updated.
2501 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
2502 @retval Others Failed to set transfer ring dequeue pointer.
2507 XhcPeiSetTrDequeuePointer (
2508 IN PEI_XHC_DEV
*Xhc
,
2515 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2516 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
2517 EFI_PHYSICAL_ADDRESS PhyAddr
;
2519 DEBUG ((DEBUG_INFO
, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
2522 // Send stop endpoint command to transit Endpoint from running to stop state
2524 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
2525 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
2526 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
2527 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2528 CmdSetTRDeq
.CycleBit
= 1;
2529 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
2530 CmdSetTRDeq
.Endpoint
= Dci
;
2531 CmdSetTRDeq
.SlotId
= SlotId
;
2532 Status
= XhcPeiCmdTransfer (
2534 (TRB_TEMPLATE
*)(UINTN
)&CmdSetTRDeq
,
2535 XHC_GENERIC_TIMEOUT
,
2536 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2538 if (EFI_ERROR (Status
)) {
2539 DEBUG ((DEBUG_ERROR
, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
2546 Check if there is a new generated event.
2548 @param Xhc The XHCI device.
2549 @param EvtRing The event ring to check.
2550 @param NewEvtTrb The new event TRB found.
2552 @retval EFI_SUCCESS Found a new event TRB at the event ring.
2553 @retval EFI_NOT_READY The event ring has no new event.
2557 XhcPeiCheckNewEvent (
2558 IN PEI_XHC_DEV
*Xhc
,
2559 IN EVENT_RING
*EvtRing
,
2560 OUT TRB_TEMPLATE
**NewEvtTrb
2563 ASSERT (EvtRing
!= NULL
);
2565 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
2567 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
2568 return EFI_NOT_READY
;
2571 EvtRing
->EventRingDequeue
++;
2573 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2575 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
)EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2576 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
2583 Synchronize the specified event ring to update the enqueue and dequeue pointer.
2585 @param Xhc The XHCI device.
2586 @param EvtRing The event ring to sync.
2588 @retval EFI_SUCCESS The event ring is synchronized successfully.
2592 XhcPeiSyncEventRing (
2593 IN PEI_XHC_DEV
*Xhc
,
2594 IN EVENT_RING
*EvtRing
2598 TRB_TEMPLATE
*EvtTrb
;
2600 ASSERT (EvtRing
!= NULL
);
2603 // Calculate the EventRingEnqueue and EventRingCCS.
2604 // Note: only support single Segment
2606 EvtTrb
= EvtRing
->EventRingDequeue
;
2608 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
2609 if (EvtTrb
->CycleBit
!= EvtRing
->EventRingCCS
) {
2615 if ((UINTN
)EvtTrb
>= ((UINTN
)EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2616 EvtTrb
= EvtRing
->EventRingSeg0
;
2617 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
2621 if (Index
< EvtRing
->TrbNumber
) {
2622 EvtRing
->EventRingEnqueue
= EvtTrb
;
2631 Free XHCI event ring.
2633 @param Xhc The XHCI device.
2634 @param EventRing The event ring to be freed.
2638 XhcPeiFreeEventRing (
2639 IN PEI_XHC_DEV
*Xhc
,
2640 IN EVENT_RING
*EventRing
2643 if (EventRing
->EventRingSeg0
== NULL
) {
2648 // Free EventRing Segment 0
2650 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
2655 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
2659 Create XHCI event ring.
2661 @param Xhc The XHCI device.
2662 @param EventRing The created event ring.
2666 XhcPeiCreateEventRing (
2667 IN PEI_XHC_DEV
*Xhc
,
2668 OUT EVENT_RING
*EventRing
2672 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
2674 EFI_PHYSICAL_ADDRESS ERSTPhy
;
2675 EFI_PHYSICAL_ADDRESS DequeuePhy
;
2677 ASSERT (EventRing
!= NULL
);
2679 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
2680 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2681 ASSERT (Buf
!= NULL
);
2682 ASSERT (((UINTN
)Buf
& 0x3F) == 0);
2683 ZeroMem (Buf
, Size
);
2685 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2687 EventRing
->EventRingSeg0
= Buf
;
2688 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
2689 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*)EventRing
->EventRingSeg0
;
2690 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*)EventRing
->EventRingSeg0
;
2693 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
2694 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
2696 EventRing
->EventRingCCS
= 1;
2698 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
2699 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2700 ASSERT (Buf
!= NULL
);
2701 ASSERT (((UINTN
)Buf
& 0x3F) == 0);
2702 ZeroMem (Buf
, Size
);
2704 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*)Buf
;
2705 EventRing
->ERSTBase
= ERSTBase
;
2706 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
2707 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
2708 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
2710 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2713 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
2715 XhcPeiWriteRuntimeReg (
2721 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
2723 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2724 // So divide it to two 32-bytes width register access.
2726 XhcPeiWriteRuntimeReg (
2729 XHC_LOW_32BIT ((UINT64
)(UINTN
)DequeuePhy
)
2731 XhcPeiWriteRuntimeReg (
2733 XHC_ERDP_OFFSET
+ 4,
2734 XHC_HIGH_32BIT ((UINT64
)(UINTN
)DequeuePhy
)
2737 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
2739 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2740 // So divide it to two 32-bytes width register access.
2742 XhcPeiWriteRuntimeReg (
2745 XHC_LOW_32BIT ((UINT64
)(UINTN
)ERSTPhy
)
2747 XhcPeiWriteRuntimeReg (
2749 XHC_ERSTBA_OFFSET
+ 4,
2750 XHC_HIGH_32BIT ((UINT64
)(UINTN
)ERSTPhy
)
2753 // Need set IMAN IE bit to enable the ring interrupt
2755 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
2759 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
2761 @param Xhc The XHCI device.
2762 @param TrsRing The transfer ring to sync.
2764 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
2769 IN PEI_XHC_DEV
*Xhc
,
2770 IN TRANSFER_RING
*TrsRing
2774 TRB_TEMPLATE
*TrsTrb
;
2776 ASSERT (TrsRing
!= NULL
);
2778 // Calculate the latest RingEnqueue and RingPCS
2780 TrsTrb
= TrsRing
->RingEnqueue
;
2781 ASSERT (TrsTrb
!= NULL
);
2783 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
2784 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
2789 if ((UINT8
)TrsTrb
->Type
== TRB_TYPE_LINK
) {
2790 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
2792 // set cycle bit in Link TRB as normal
2794 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
2796 // Toggle PCS maintained by software
2798 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
2799 TrsTrb
= (TRB_TEMPLATE
*)TrsRing
->RingSeg0
; // Use host address
2803 ASSERT (Index
!= TrsRing
->TrbNumber
);
2805 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
2806 TrsRing
->RingEnqueue
= TrsTrb
;
2810 // Clear the Trb context for enqueue, but reserve the PCS bit
2812 TrsTrb
->Parameter1
= 0;
2813 TrsTrb
->Parameter2
= 0;
2817 TrsTrb
->Control
= 0;
2823 Create XHCI transfer ring.
2825 @param Xhc The XHCI Device.
2826 @param TrbNum The number of TRB in the ring.
2827 @param TransferRing The created transfer ring.
2831 XhcPeiCreateTransferRing (
2832 IN PEI_XHC_DEV
*Xhc
,
2834 OUT TRANSFER_RING
*TransferRing
2839 EFI_PHYSICAL_ADDRESS PhyAddr
;
2841 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2842 ASSERT (Buf
!= NULL
);
2843 ASSERT (((UINTN
)Buf
& 0x3F) == 0);
2844 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2846 TransferRing
->RingSeg0
= Buf
;
2847 TransferRing
->TrbNumber
= TrbNum
;
2848 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*)TransferRing
->RingSeg0
;
2849 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*)TransferRing
->RingSeg0
;
2850 TransferRing
->RingPCS
= 1;
2852 // 4.9.2 Transfer Ring Management
2853 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
2854 // point to the first TRB in the ring.
2856 EndTrb
= (LINK_TRB
*)((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
2857 EndTrb
->Type
= TRB_TYPE_LINK
;
2858 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2859 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2860 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2862 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
2866 // Set Cycle bit as other TRB PCS init value
2868 EndTrb
->CycleBit
= 0;
2872 Initialize the XHCI host controller for schedule.
2874 @param Xhc The XHCI device to be initialized.
2883 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
2885 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
2886 UINT32 MaxScratchpadBufs
;
2888 EFI_PHYSICAL_ADDRESS ScratchPhy
;
2889 UINT64
*ScratchEntry
;
2890 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
2892 UINTN
*ScratchEntryMap
;
2896 // Initialize memory management.
2898 Xhc
->MemPool
= UsbHcInitMemPool ();
2899 ASSERT (Xhc
->MemPool
!= NULL
);
2902 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
2903 // to enable the device slots that system software is going to use.
2905 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
2906 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
2907 XhcPeiWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, (XhcPeiReadOpReg (Xhc
, XHC_CONFIG_OFFSET
) & ~XHC_CONFIG_MASK
) | Xhc
->MaxSlotsEn
);
2910 // The Device Context Base Address Array entry associated with each allocated Device Slot
2911 // shall contain a 64-bit pointer to the base of the associated Device Context.
2912 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
2913 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
2915 Size
= (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
);
2916 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2917 ASSERT (Dcbaa
!= NULL
);
2920 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
2921 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
2922 // mode (Run/Stop(R/S) ='1').
2924 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
2925 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
2926 ASSERT (MaxScratchpadBufs
<= 1023);
2927 if (MaxScratchpadBufs
!= 0) {
2929 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
2931 ScratchEntryMap
= AllocateZeroPool (sizeof (UINTN
) * MaxScratchpadBufs
);
2932 ASSERT (ScratchEntryMap
!= NULL
);
2933 Xhc
->ScratchEntryMap
= ScratchEntryMap
;
2936 // Allocate the buffer to record the host address for each entry
2938 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
2939 ASSERT (ScratchEntry
!= NULL
);
2940 Xhc
->ScratchEntry
= ScratchEntry
;
2943 Status
= UsbHcAllocateAlignedPages (
2944 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
2946 (VOID
**)&ScratchBuf
,
2950 ASSERT_EFI_ERROR (Status
);
2952 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
2953 Xhc
->ScratchBuf
= ScratchBuf
;
2956 // Allocate each scratch buffer
2958 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
2959 ScratchEntryPhy
= 0;
2960 Status
= UsbHcAllocateAlignedPages (
2961 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
2963 (VOID
**)&ScratchEntry
[Index
],
2965 (VOID
**)&ScratchEntryMap
[Index
]
2967 ASSERT_EFI_ERROR (Status
);
2968 ZeroMem ((VOID
*)(UINTN
)ScratchEntry
[Index
], Xhc
->PageSize
);
2970 // Fill with the PCI device address
2972 *ScratchBuf
++ = ScratchEntryPhy
;
2976 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
2977 // Device Context Base Address Array points to the Scratchpad Buffer Array.
2979 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
)ScratchPhy
;
2983 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
2984 // a 64-bit address pointing to where the Device Context Base Address Array is located.
2986 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
2988 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2989 // So divide it to two 32-bytes width register access.
2991 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Size
);
2992 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT (DcbaaPhy
));
2993 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
2995 DEBUG ((DEBUG_INFO
, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc
->DCBAA
));
2998 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
2999 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
3000 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
3003 XhcPeiCreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
3005 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
3006 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
3007 // So we set RCS as inverted PCS init value to let Command Ring empty
3009 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
3010 ASSERT ((CmdRingPhy
& 0x3F) == 0);
3011 CmdRingPhy
|= XHC_CRCR_RCS
;
3013 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
3014 // So divide it to two 32-bytes width register access.
3016 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT (CmdRingPhy
));
3017 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
3019 DEBUG ((DEBUG_INFO
, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc
->CmdRing
.RingSeg0
));
3022 // Disable the 'interrupter enable' bit in USB_CMD
3023 // and clear IE & IP bit in all Interrupter X Management Registers.
3025 XhcPeiClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
3026 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
3027 XhcPeiClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
3028 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
3032 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
3034 XhcPeiCreateEventRing (Xhc
, &Xhc
->EventRing
);
3035 DEBUG ((DEBUG_INFO
, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc
->EventRing
.EventRingSeg0
));
3039 Free the resouce allocated at initializing schedule.
3041 @param Xhc The XHCI device.
3050 UINT64
*ScratchEntry
;
3052 if (Xhc
->ScratchBuf
!= NULL
) {
3053 ScratchEntry
= Xhc
->ScratchEntry
;
3054 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
3056 // Free Scratchpad Buffers
3058 UsbHcFreeAlignedPages ((VOID
*)(UINTN
)ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*)Xhc
->ScratchEntryMap
[Index
]);
3062 // Free Scratchpad Buffer Array
3064 UsbHcFreeAlignedPages (Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
3065 FreePool (Xhc
->ScratchEntryMap
);
3066 FreePool (Xhc
->ScratchEntry
);
3069 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
3070 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
3071 Xhc
->CmdRing
.RingSeg0
= NULL
;
3074 XhcPeiFreeEventRing (Xhc
, &Xhc
->EventRing
);
3076 if (Xhc
->DCBAA
!= NULL
) {
3077 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
));
3082 // Free memory pool at last
3084 if (Xhc
->MemPool
!= NULL
) {
3085 UsbHcFreeMemPool (Xhc
->MemPool
);
3086 Xhc
->MemPool
= NULL
;