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>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
14 Create a command transfer TRB to support XHCI command interfaces.
16 @param Xhc The XHCI device.
17 @param CmdTrb The cmd TRB to be executed.
19 @return Created URB or NULL.
25 IN TRB_TEMPLATE
*CmdTrb
30 Urb
= AllocateZeroPool (sizeof (URB
));
35 Urb
->Signature
= XHC_URB_SIG
;
37 Urb
->Ring
= &Xhc
->CmdRing
;
38 XhcPeiSyncTrsRing (Xhc
, Urb
->Ring
);
40 Urb
->TrbStart
= Urb
->Ring
->RingEnqueue
;
41 CopyMem (Urb
->TrbStart
, CmdTrb
, sizeof (TRB_TEMPLATE
));
42 Urb
->TrbStart
->CycleBit
= Urb
->Ring
->RingPCS
& BIT0
;
43 Urb
->TrbEnd
= Urb
->TrbStart
;
49 Execute a XHCI cmd TRB pointed by CmdTrb.
51 @param Xhc The XHCI device.
52 @param CmdTrb The cmd TRB to be executed.
53 @param Timeout Indicates the maximum time, in millisecond, which the
54 transfer is allowed to complete.
55 @param EvtTrb The event TRB corresponding to the cmd TRB.
57 @retval EFI_SUCCESS The transfer was completed successfully.
58 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
59 @retval EFI_TIMEOUT The transfer failed due to timeout.
60 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
66 IN TRB_TEMPLATE
*CmdTrb
,
68 OUT TRB_TEMPLATE
**EvtTrb
75 // Validate the parameters
77 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
78 return EFI_INVALID_PARAMETER
;
81 Status
= EFI_DEVICE_ERROR
;
83 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
84 DEBUG ((DEBUG_ERROR
, "XhcPeiCmdTransfer: HC is halted or has system error\n"));
89 // Create a new URB, then poll the execution status.
91 Urb
= XhcPeiCreateCmdTrb (Xhc
, CmdTrb
);
93 DEBUG ((DEBUG_ERROR
, "XhcPeiCmdTransfer: failed to create URB\n"));
94 Status
= EFI_OUT_OF_RESOURCES
;
98 Status
= XhcPeiExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
99 *EvtTrb
= Urb
->EvtTrb
;
101 if (Urb
->Result
== EFI_USB_NOERROR
) {
102 Status
= EFI_SUCCESS
;
105 XhcPeiFreeUrb (Xhc
, Urb
);
112 Create a new URB for a new transaction.
114 @param Xhc The XHCI device
115 @param BusAddr The logical device address assigned by UsbBus driver
116 @param EpAddr Endpoint addrress
117 @param DevSpeed The device speed
118 @param MaxPacket The max packet length of the endpoint
119 @param Type The transaction type
120 @param Request The standard USB request for control transfer
121 @param Data The user data to transfer
122 @param DataLen The length of data buffer
123 @param Callback The function to call when data is transferred
124 @param Context The context to the callback
126 @return Created URB or NULL
137 IN EFI_USB_DEVICE_REQUEST
*Request
,
140 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
148 Urb
= AllocateZeroPool (sizeof (URB
));
153 Urb
->Signature
= XHC_URB_SIG
;
156 Ep
->BusAddr
= BusAddr
;
157 Ep
->EpAddr
= (UINT8
)(EpAddr
& 0x0F);
158 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
159 Ep
->DevSpeed
= DevSpeed
;
160 Ep
->MaxPacket
= MaxPacket
;
163 Urb
->Request
= Request
;
165 Urb
->DataLen
= DataLen
;
166 Urb
->Callback
= Callback
;
167 Urb
->Context
= Context
;
169 Status
= XhcPeiCreateTransferTrb (Xhc
, Urb
);
170 if (EFI_ERROR (Status
)) {
171 DEBUG ((DEBUG_ERROR
, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status
));
180 Free an allocated URB.
182 @param Xhc The XHCI device.
183 @param Urb The URB to free.
192 if ((Xhc
== NULL
) || (Urb
== NULL
)) {
196 IoMmuUnmap (Urb
->DataMap
);
202 Create a transfer TRB.
204 @param Xhc The XHCI device
205 @param Urb The urb used to construct the transfer TRB.
207 @return Created TRB or NULL
211 XhcPeiCreateTransferTrb (
217 TRANSFER_RING
*EPRing
;
225 EDKII_IOMMU_OPERATION MapOp
;
226 EFI_PHYSICAL_ADDRESS PhyAddr
;
230 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
232 return EFI_DEVICE_ERROR
;
235 Urb
->Finished
= FALSE
;
236 Urb
->StartDone
= FALSE
;
237 Urb
->EndDone
= FALSE
;
239 Urb
->Result
= EFI_USB_NOERROR
;
241 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
242 EPRing
= (TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1];
244 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
245 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
246 EPType
= (UINT8
)((DEVICE_CONTEXT
*)OutputContext
)->EP
[Dci
-1].EPType
;
248 EPType
= (UINT8
)((DEVICE_CONTEXT_64
*)OutputContext
)->EP
[Dci
-1].EPType
;
254 if ((Urb
->Data
!= NULL
) && (Urb
->DataMap
== NULL
)) {
255 if (((UINT8
)(Urb
->Ep
.Direction
)) == EfiUsbDataIn
) {
256 MapOp
= EdkiiIoMmuOperationBusMasterWrite
;
258 MapOp
= EdkiiIoMmuOperationBusMasterRead
;
262 Status
= IoMmuMap (MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
264 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
265 DEBUG ((DEBUG_ERROR
, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
266 return EFI_OUT_OF_RESOURCES
;
269 Urb
->DataPhy
= (VOID
*)((UINTN
)PhyAddr
);
276 XhcPeiSyncTrsRing (Xhc
, EPRing
);
277 Urb
->TrbStart
= EPRing
->RingEnqueue
;
279 case ED_CONTROL_BIDIR
:
281 // For control transfer, create SETUP_STAGE_TRB first.
283 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
284 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
285 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
286 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
287 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
288 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
289 TrbStart
->TrbCtrSetup
.Length
= 8;
290 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
291 TrbStart
->TrbCtrSetup
.IOC
= 1;
292 TrbStart
->TrbCtrSetup
.IDT
= 1;
293 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
294 if (Urb
->DataLen
> 0) {
295 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
296 TrbStart
->TrbCtrSetup
.TRT
= 3;
297 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
298 TrbStart
->TrbCtrSetup
.TRT
= 2;
300 DEBUG ((DEBUG_ERROR
, "XhcPeiCreateTransferTrb: Direction sholud be IN or OUT when Data exists!\n"));
304 TrbStart
->TrbCtrSetup
.TRT
= 0;
308 // Update the cycle bit
310 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
314 // For control transfer, create DATA_STAGE_TRB.
316 if (Urb
->DataLen
> 0) {
317 XhcPeiSyncTrsRing (Xhc
, EPRing
);
318 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
319 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT (Urb
->DataPhy
);
320 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT (Urb
->DataPhy
);
321 TrbStart
->TrbCtrData
.Length
= (UINT32
)Urb
->DataLen
;
322 TrbStart
->TrbCtrData
.TDSize
= 0;
323 TrbStart
->TrbCtrData
.IntTarget
= 0;
324 TrbStart
->TrbCtrData
.ISP
= 1;
325 TrbStart
->TrbCtrData
.IOC
= 1;
326 TrbStart
->TrbCtrData
.IDT
= 0;
327 TrbStart
->TrbCtrData
.CH
= 0;
328 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
329 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
330 TrbStart
->TrbCtrData
.DIR = 1;
331 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
332 TrbStart
->TrbCtrData
.DIR = 0;
334 TrbStart
->TrbCtrData
.DIR = 0;
338 // Update the cycle bit
340 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
345 // For control transfer, create STATUS_STAGE_TRB.
346 // Get the pointer to next TRB for status stage use
348 XhcPeiSyncTrsRing (Xhc
, EPRing
);
349 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
350 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
351 TrbStart
->TrbCtrStatus
.IOC
= 1;
352 TrbStart
->TrbCtrStatus
.CH
= 0;
353 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
354 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
355 TrbStart
->TrbCtrStatus
.DIR = 0;
356 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
357 TrbStart
->TrbCtrStatus
.DIR = 1;
359 TrbStart
->TrbCtrStatus
.DIR = 0;
363 // Update the cycle bit
365 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
367 // Update the enqueue pointer
369 XhcPeiSyncTrsRing (Xhc
, EPRing
);
371 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
380 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
381 while (TotalLen
< Urb
->DataLen
) {
382 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
383 Len
= Urb
->DataLen
- TotalLen
;
388 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
389 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT ((UINT8
*)Urb
->DataPhy
+ TotalLen
);
390 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT ((UINT8
*)Urb
->DataPhy
+ TotalLen
);
391 TrbStart
->TrbNormal
.Length
= (UINT32
)Len
;
392 TrbStart
->TrbNormal
.TDSize
= 0;
393 TrbStart
->TrbNormal
.IntTarget
= 0;
394 TrbStart
->TrbNormal
.ISP
= 1;
395 TrbStart
->TrbNormal
.IOC
= 1;
396 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
398 // Update the cycle bit
400 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
402 XhcPeiSyncTrsRing (Xhc
, EPRing
);
407 Urb
->TrbNum
= TrbNum
;
408 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
411 case ED_INTERRUPT_OUT
:
412 case ED_INTERRUPT_IN
:
416 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
417 while (TotalLen
< Urb
->DataLen
) {
418 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
419 Len
= Urb
->DataLen
- TotalLen
;
424 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
425 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT ((UINT8
*)Urb
->DataPhy
+ TotalLen
);
426 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT ((UINT8
*)Urb
->DataPhy
+ TotalLen
);
427 TrbStart
->TrbNormal
.Length
= (UINT32
)Len
;
428 TrbStart
->TrbNormal
.TDSize
= 0;
429 TrbStart
->TrbNormal
.IntTarget
= 0;
430 TrbStart
->TrbNormal
.ISP
= 1;
431 TrbStart
->TrbNormal
.IOC
= 1;
432 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
434 // Update the cycle bit
436 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
438 XhcPeiSyncTrsRing (Xhc
, EPRing
);
443 Urb
->TrbNum
= TrbNum
;
444 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
448 DEBUG ((DEBUG_INFO
, "Not supported EPType 0x%x!\n", EPType
));
457 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
458 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
459 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
460 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
461 Stopped to the Running state.
463 @param Xhc The XHCI device.
464 @param Urb The urb which makes the endpoint halted.
466 @retval EFI_SUCCESS The recovery is successful.
467 @retval Others Failed to recovery halted endpoint.
471 XhcPeiRecoverHaltedEndpoint (
480 Status
= EFI_SUCCESS
;
481 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
483 return EFI_DEVICE_ERROR
;
486 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
488 DEBUG ((DEBUG_INFO
, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId
, Dci
));
491 // 1) Send Reset endpoint command to transit from halt to stop state
493 Status
= XhcPeiResetEndpoint (Xhc
, SlotId
, Dci
);
494 if (EFI_ERROR (Status
)) {
495 DEBUG ((DEBUG_ERROR
, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
500 // 2) Set dequeue pointer
502 Status
= XhcPeiSetTrDequeuePointer (Xhc
, SlotId
, Dci
, Urb
);
503 if (EFI_ERROR (Status
)) {
504 DEBUG ((DEBUG_ERROR
, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
509 // 3) Ring the doorbell to transit from stop to active
511 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
518 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
519 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
520 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
523 @param Xhc The XHCI device.
524 @param Urb The urb which doesn't get completed in a specified timeout range.
526 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
527 @retval Others Failed to stop the endpoint and dequeue the TDs.
531 XhcPeiDequeueTrbFromEndpoint (
540 Status
= EFI_SUCCESS
;
541 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
543 return EFI_DEVICE_ERROR
;
546 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
548 DEBUG ((DEBUG_INFO
, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId
, Dci
));
551 // 1) Send Stop endpoint command to stop endpoint.
553 Status
= XhcPeiStopEndpoint (Xhc
, SlotId
, Dci
);
554 if (EFI_ERROR (Status
)) {
555 DEBUG ((DEBUG_ERROR
, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
560 // 2) Set dequeue pointer
562 Status
= XhcPeiSetTrDequeuePointer (Xhc
, SlotId
, Dci
, Urb
);
563 if (EFI_ERROR (Status
)) {
564 DEBUG ((DEBUG_ERROR
, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
569 // 3) Ring the doorbell to transit from stop to active
571 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
578 Check if the Trb is a transaction of the URB.
580 @param Trb The TRB to be checked
581 @param Urb The transfer ring to be checked.
583 @retval TRUE It is a transaction of the URB.
584 @retval FALSE It is not any transaction of the URB.
588 XhcPeiIsTransferRingTrb (
589 IN TRB_TEMPLATE
*Trb
,
593 TRB_TEMPLATE
*CheckedTrb
;
596 CheckedTrb
= Urb
->Ring
->RingSeg0
;
598 ASSERT (Urb
->Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Urb
->Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
600 for (Index
= 0; Index
< Urb
->Ring
->TrbNumber
; Index
++) {
601 if (Trb
== CheckedTrb
) {
612 Check the URB's execution result and update the URB's
615 @param Xhc The XHCI device.
616 @param Urb The URB to check result.
618 @return Whether the result of URB transfer is finialized.
622 XhcPeiCheckUrbResult (
627 EVT_TRB_TRANSFER
*EvtTrb
;
628 TRB_TEMPLATE
*TRBPtr
;
636 EFI_PHYSICAL_ADDRESS PhyAddr
;
638 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
640 Status
= EFI_SUCCESS
;
648 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
649 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
654 // Traverse the event ring to find out all new events from the previous check.
656 XhcPeiSyncEventRing (Xhc
, &Xhc
->EventRing
);
657 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
658 Status
= XhcPeiCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
659 if (Status
== EFI_NOT_READY
) {
661 // All new events are handled, return directly.
667 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
669 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
674 // Need convert pci device address to host address
676 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
)EvtTrb
->TRBPtrHi
, 32));
677 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
)UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
)PhyAddr
, sizeof (TRB_TEMPLATE
));
680 // Update the status of Urb according to the finished event regardless of whether
681 // the urb is current checked one or in the XHCI's async transfer list.
682 // This way is used to avoid that those completed async transfer events don't get
683 // handled in time and are flushed by newer coming events.
685 if (XhcPeiIsTransferRingTrb (TRBPtr
, Urb
)) {
691 switch (EvtTrb
->Completecode
) {
692 case TRB_COMPLETION_STALL_ERROR
:
693 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
694 CheckedUrb
->Finished
= TRUE
;
695 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
698 case TRB_COMPLETION_BABBLE_ERROR
:
699 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
700 CheckedUrb
->Finished
= TRUE
;
701 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
704 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
705 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
706 CheckedUrb
->Finished
= TRUE
;
707 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb
->Completecode
));
710 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
711 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
712 CheckedUrb
->Finished
= TRUE
;
713 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
716 case TRB_COMPLETION_SHORT_PACKET
:
717 case TRB_COMPLETION_SUCCESS
:
718 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
719 DEBUG ((DEBUG_VERBOSE
, "XhcPeiCheckUrbResult: short packet happens!\n"));
722 TRBType
= (UINT8
)(TRBPtr
->Type
);
723 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
724 (TRBType
== TRB_TYPE_NORMAL
) ||
725 (TRBType
== TRB_TYPE_ISOCH
))
727 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
733 DEBUG ((DEBUG_ERROR
, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb
->Completecode
));
734 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
735 CheckedUrb
->Finished
= TRUE
;
740 // Only check first and end Trb event address
742 if (TRBPtr
== CheckedUrb
->TrbStart
) {
743 CheckedUrb
->StartDone
= TRUE
;
746 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
747 CheckedUrb
->EndDone
= TRUE
;
750 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
751 CheckedUrb
->Finished
= TRUE
;
752 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
759 // Advance event ring to last available entry
761 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
762 // So divide it to two 32-bytes width register access.
764 Low
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
765 High
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
766 XhcDequeue
= (UINT64
)(LShiftU64 ((UINT64
)High
, 32) | Low
);
768 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
770 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
772 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
773 // So divide it to two 32-bytes width register access.
775 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
776 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
779 return Urb
->Finished
;
783 Execute the transfer by polling the URB. This is a synchronous operation.
785 @param Xhc The XHCI device.
786 @param CmdTransfer The executed URB is for cmd transfer or not.
787 @param Urb The URB to execute.
788 @param Timeout The time to wait before abort, in millisecond.
790 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
791 @return EFI_TIMEOUT The transfer failed due to time out.
792 @return EFI_SUCCESS The transfer finished OK.
798 IN BOOLEAN CmdTransfer
,
814 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
816 return EFI_DEVICE_ERROR
;
819 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
822 Status
= EFI_SUCCESS
;
823 Loop
= Timeout
* XHC_1_MILLISECOND
;
828 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
830 for (Index
= 0; Index
< Loop
; Index
++) {
831 Finished
= XhcPeiCheckUrbResult (Xhc
, Urb
);
836 MicroSecondDelay (XHC_1_MICROSECOND
);
840 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
841 Status
= EFI_TIMEOUT
;
842 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
843 Status
= EFI_DEVICE_ERROR
;
850 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
852 @param Xhc The XHCI device.
853 @param ParentRouteChart The route string pointed to the parent device if it exists.
854 @param Port The port to be polled.
855 @param PortState The port state.
857 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
858 @retval Others Should not appear.
862 XhcPeiPollPortStatusChange (
864 IN USB_DEV_ROUTE ParentRouteChart
,
866 IN EFI_USB_PORT_STATUS
*PortState
872 USB_DEV_ROUTE RouteChart
;
874 DEBUG ((DEBUG_INFO
, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState
->PortChangeStatus
, PortState
->PortStatus
));
876 Status
= EFI_SUCCESS
;
878 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
882 if (ParentRouteChart
.Dword
== 0) {
883 RouteChart
.Route
.RouteString
= 0;
884 RouteChart
.Route
.RootPortNum
= Port
+ 1;
885 RouteChart
.Route
.TierNum
= 1;
888 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
890 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
893 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
894 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
897 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
899 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
900 Status
= XhcPeiDisableSlotCmd (Xhc
, SlotId
);
902 Status
= XhcPeiDisableSlotCmd64 (Xhc
, SlotId
);
906 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
907 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0))
910 // Has a device attached, Identify device speed after port is enabled.
912 Speed
= EFI_USB_SPEED_FULL
;
913 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
914 Speed
= EFI_USB_SPEED_LOW
;
915 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
916 Speed
= EFI_USB_SPEED_HIGH
;
917 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
918 Speed
= EFI_USB_SPEED_SUPER
;
922 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
924 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
925 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
926 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
927 Status
= XhcPeiInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
929 Status
= XhcPeiInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
938 Calculate the device context index by endpoint address and direction.
940 @param EpAddr The target endpoint number.
941 @param Direction The direction of the target endpoint.
943 @return The device context index of endpoint.
947 XhcPeiEndpointToDci (
949 IN EFI_USB_DATA_DIRECTION Direction
954 ASSERT (EpAddr
<= 15);
959 Index
= (UINT8
)(2 * EpAddr
);
960 if (Direction
== EfiUsbDataIn
) {
969 Find out the actual device address according to the requested device address from UsbBus.
971 @param Xhc The XHCI device.
972 @param BusDevAddr The requested device address by UsbBus upper driver.
974 @return The actual device address assigned to the device.
978 XhcPeiBusDevAddrToSlotId (
985 for (Index
= 0; Index
< 255; Index
++) {
986 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
987 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
988 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
))
998 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1002 Find out the slot id according to the device's route string.
1004 @param Xhc The XHCI device.
1005 @param RouteString The route string described the device location.
1007 @return The slot id used by the device.
1011 XhcPeiRouteStringToSlotId (
1012 IN PEI_XHC_DEV
*Xhc
,
1013 IN USB_DEV_ROUTE RouteString
1018 for (Index
= 0; Index
< 255; Index
++) {
1019 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1020 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1021 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
))
1031 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1035 Ring the door bell to notify XHCI there is a transaction to be executed.
1037 @param Xhc The XHCI device.
1038 @param SlotId The slot id of the target device.
1039 @param Dci The device context index of the target slot or endpoint.
1043 XhcPeiRingDoorBell (
1044 IN PEI_XHC_DEV
*Xhc
,
1050 XhcPeiWriteDoorBellReg (Xhc
, 0, 0);
1052 XhcPeiWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1057 Assign and initialize the device slot for a new device.
1059 @param Xhc The XHCI device.
1060 @param ParentRouteChart The route string pointed to the parent device.
1061 @param ParentPort The port at which the device is located.
1062 @param RouteChart The route string pointed to the device.
1063 @param DeviceSpeed The device speed.
1065 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1066 @retval Others Fail to initialize device slot.
1070 XhcPeiInitializeDeviceSlot (
1071 IN PEI_XHC_DEV
*Xhc
,
1072 IN USB_DEV_ROUTE ParentRouteChart
,
1073 IN UINT16 ParentPort
,
1074 IN USB_DEV_ROUTE RouteChart
,
1075 IN UINT8 DeviceSpeed
1079 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1080 INPUT_CONTEXT
*InputContext
;
1081 DEVICE_CONTEXT
*OutputContext
;
1082 TRANSFER_RING
*EndpointTransferRing
;
1083 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1084 UINT8 DeviceAddress
;
1085 CMD_TRB_ENABLE_SLOT CmdTrb
;
1088 DEVICE_CONTEXT
*ParentDeviceContext
;
1089 EFI_PHYSICAL_ADDRESS PhyAddr
;
1091 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1092 CmdTrb
.CycleBit
= 1;
1093 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1095 Status
= XhcPeiCmdTransfer (
1097 (TRB_TEMPLATE
*)(UINTN
)&CmdTrb
,
1098 XHC_GENERIC_TIMEOUT
,
1099 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1101 if (EFI_ERROR (Status
)) {
1102 DEBUG ((DEBUG_ERROR
, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
1106 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1107 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1108 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1109 ASSERT (SlotId
!= 0);
1111 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1112 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1113 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1114 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1115 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1118 // 4.3.3 Device Slot Initialization
1119 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1121 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
1122 ASSERT (InputContext
!= NULL
);
1123 ASSERT (((UINTN
)InputContext
& 0x3F) == 0);
1124 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1126 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*)InputContext
;
1129 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1130 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1131 // Context are affected by the command.
1133 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1136 // 3) Initialize the Input Slot Context data structure
1138 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1139 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1140 InputContext
->Slot
.ContextEntries
= 1;
1141 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1143 if (RouteChart
.Route
.RouteString
!= 0) {
1145 // The device is behind of hub device.
1147 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1148 ASSERT (ParentSlotId
!= 0);
1150 // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
1152 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1153 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1154 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0))
1156 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1158 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1159 // environment from Full/Low speed signaling environment for a device
1161 InputContext
->Slot
.TTPortNum
= ParentPort
;
1162 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1166 // Inherit the TT parameters from parent device.
1168 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1169 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1171 // If the device is a High speed device then down the speed to be the same as its parent Hub
1173 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1174 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1180 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1182 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1183 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1184 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1186 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1188 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1190 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1191 InputContext
->EP
[0].MaxPacketSize
= 512;
1192 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1193 InputContext
->EP
[0].MaxPacketSize
= 64;
1195 InputContext
->EP
[0].MaxPacketSize
= 8;
1199 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1200 // 1KB, and Bulk and Isoch endpoints 3KB.
1202 InputContext
->EP
[0].AverageTRBLength
= 8;
1203 InputContext
->EP
[0].MaxBurstSize
= 0;
1204 InputContext
->EP
[0].Interval
= 0;
1205 InputContext
->EP
[0].MaxPStreams
= 0;
1206 InputContext
->EP
[0].Mult
= 0;
1207 InputContext
->EP
[0].CErr
= 3;
1210 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1212 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1214 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1215 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1217 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1218 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1221 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1223 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
1224 ASSERT (OutputContext
!= NULL
);
1225 ASSERT (((UINTN
)OutputContext
& 0x3F) == 0);
1226 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
1228 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1230 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1231 // a pointer to the Output Device Context data structure (6.2.1).
1233 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
1235 // Fill DCBAA with PCI device address
1237 Xhc
->DCBAA
[SlotId
] = (UINT64
)(UINTN
)PhyAddr
;
1240 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1241 // Context data structure described above.
1243 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1246 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY
);
1247 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1248 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1249 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1250 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1251 CmdTrbAddr
.CycleBit
= 1;
1252 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1253 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1254 Status
= XhcPeiCmdTransfer (
1256 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbAddr
,
1257 XHC_GENERIC_TIMEOUT
,
1258 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1260 if (!EFI_ERROR (Status
)) {
1261 DeviceAddress
= (UINT8
)OutputContext
->Slot
.DeviceAddress
;
1262 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress
));
1263 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1266 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status
));
1271 Assign and initialize the device slot for a new device.
1273 @param Xhc The XHCI device.
1274 @param ParentRouteChart The route string pointed to the parent device.
1275 @param ParentPort The port at which the device is located.
1276 @param RouteChart The route string pointed to the device.
1277 @param DeviceSpeed The device speed.
1279 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1280 @retval Others Fail to initialize device slot.
1284 XhcPeiInitializeDeviceSlot64 (
1285 IN PEI_XHC_DEV
*Xhc
,
1286 IN USB_DEV_ROUTE ParentRouteChart
,
1287 IN UINT16 ParentPort
,
1288 IN USB_DEV_ROUTE RouteChart
,
1289 IN UINT8 DeviceSpeed
1293 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1294 INPUT_CONTEXT_64
*InputContext
;
1295 DEVICE_CONTEXT_64
*OutputContext
;
1296 TRANSFER_RING
*EndpointTransferRing
;
1297 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1298 UINT8 DeviceAddress
;
1299 CMD_TRB_ENABLE_SLOT CmdTrb
;
1302 DEVICE_CONTEXT_64
*ParentDeviceContext
;
1303 EFI_PHYSICAL_ADDRESS PhyAddr
;
1305 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1306 CmdTrb
.CycleBit
= 1;
1307 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1309 Status
= XhcPeiCmdTransfer (
1311 (TRB_TEMPLATE
*)(UINTN
)&CmdTrb
,
1312 XHC_GENERIC_TIMEOUT
,
1313 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1315 if (EFI_ERROR (Status
)) {
1316 DEBUG ((DEBUG_ERROR
, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
1320 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1321 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1322 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1323 ASSERT (SlotId
!= 0);
1325 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1326 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1327 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1328 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1329 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1332 // 4.3.3 Device Slot Initialization
1333 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1335 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
1336 ASSERT (InputContext
!= NULL
);
1337 ASSERT (((UINTN
)InputContext
& 0x3F) == 0);
1338 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1340 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*)InputContext
;
1343 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1344 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1345 // Context are affected by the command.
1347 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1350 // 3) Initialize the Input Slot Context data structure
1352 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1353 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1354 InputContext
->Slot
.ContextEntries
= 1;
1355 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1357 if (RouteChart
.Route
.RouteString
!= 0) {
1359 // The device is behind of hub device.
1361 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1362 ASSERT (ParentSlotId
!= 0);
1364 // if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1366 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1367 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1368 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0))
1370 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1372 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1373 // environment from Full/Low speed signaling environment for a device
1375 InputContext
->Slot
.TTPortNum
= ParentPort
;
1376 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1380 // Inherit the TT parameters from parent device.
1382 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1383 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1385 // If the device is a High speed device then down the speed to be the same as its parent Hub
1387 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1388 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1394 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1396 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1397 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1398 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1400 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1402 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1404 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1405 InputContext
->EP
[0].MaxPacketSize
= 512;
1406 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1407 InputContext
->EP
[0].MaxPacketSize
= 64;
1409 InputContext
->EP
[0].MaxPacketSize
= 8;
1413 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1414 // 1KB, and Bulk and Isoch endpoints 3KB.
1416 InputContext
->EP
[0].AverageTRBLength
= 8;
1417 InputContext
->EP
[0].MaxBurstSize
= 0;
1418 InputContext
->EP
[0].Interval
= 0;
1419 InputContext
->EP
[0].MaxPStreams
= 0;
1420 InputContext
->EP
[0].Mult
= 0;
1421 InputContext
->EP
[0].CErr
= 3;
1424 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1426 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1428 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1429 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1431 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1432 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1435 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1437 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
1438 ASSERT (OutputContext
!= NULL
);
1439 ASSERT (((UINTN
)OutputContext
& 0x3F) == 0);
1440 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1442 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1444 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1445 // a pointer to the Output Device Context data structure (6.2.1).
1447 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1449 // Fill DCBAA with PCI device address
1451 Xhc
->DCBAA
[SlotId
] = (UINT64
)(UINTN
)PhyAddr
;
1454 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1455 // Context data structure described above.
1457 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1460 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY
);
1461 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1462 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1463 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1464 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1465 CmdTrbAddr
.CycleBit
= 1;
1466 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1467 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1468 Status
= XhcPeiCmdTransfer (
1470 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbAddr
,
1471 XHC_GENERIC_TIMEOUT
,
1472 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1474 if (!EFI_ERROR (Status
)) {
1475 DeviceAddress
= (UINT8
)OutputContext
->Slot
.DeviceAddress
;
1476 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress
));
1477 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1480 DEBUG ((DEBUG_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status
));
1485 Disable the specified device slot.
1487 @param Xhc The XHCI device.
1488 @param SlotId The slot id to be disabled.
1490 @retval EFI_SUCCESS Successfully disable the device slot.
1494 XhcPeiDisableSlotCmd (
1495 IN PEI_XHC_DEV
*Xhc
,
1500 TRB_TEMPLATE
*EvtTrb
;
1501 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1506 // Disable the device slots occupied by these devices on its downstream ports.
1507 // Entry 0 is reserved.
1509 for (Index
= 0; Index
< 255; Index
++) {
1510 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1511 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1512 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
))
1517 Status
= XhcPeiDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1519 if (EFI_ERROR (Status
)) {
1520 DEBUG ((DEBUG_ERROR
, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
1521 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1526 // Construct the disable slot command
1528 DEBUG ((DEBUG_INFO
, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId
));
1530 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1531 CmdTrbDisSlot
.CycleBit
= 1;
1532 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1533 CmdTrbDisSlot
.SlotId
= SlotId
;
1534 Status
= XhcPeiCmdTransfer (
1536 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbDisSlot
,
1537 XHC_GENERIC_TIMEOUT
,
1538 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1540 if (EFI_ERROR (Status
)) {
1541 DEBUG ((DEBUG_ERROR
, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
1546 // Free the slot's device context entry
1548 Xhc
->DCBAA
[SlotId
] = 0;
1551 // Free the slot related data structure
1553 for (Index
= 0; Index
< 31; Index
++) {
1554 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1555 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1556 if (RingSeg
!= NULL
) {
1557 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1560 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1561 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1565 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1566 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1567 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1571 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1572 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1575 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1576 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
1580 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1581 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1582 // remove urb from XHCI's asynchronous transfer list.
1584 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1585 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1587 DEBUG ((DEBUG_INFO
, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status
));
1592 Disable the specified device slot.
1594 @param Xhc The XHCI device.
1595 @param SlotId The slot id to be disabled.
1597 @retval EFI_SUCCESS Successfully disable the device slot.
1601 XhcPeiDisableSlotCmd64 (
1602 IN PEI_XHC_DEV
*Xhc
,
1607 TRB_TEMPLATE
*EvtTrb
;
1608 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1613 // Disable the device slots occupied by these devices on its downstream ports.
1614 // Entry 0 is reserved.
1616 for (Index
= 0; Index
< 255; Index
++) {
1617 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1618 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1619 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
))
1624 Status
= XhcPeiDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1626 if (EFI_ERROR (Status
)) {
1627 DEBUG ((DEBUG_ERROR
, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
1628 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1633 // Construct the disable slot command
1635 DEBUG ((DEBUG_INFO
, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId
));
1637 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1638 CmdTrbDisSlot
.CycleBit
= 1;
1639 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1640 CmdTrbDisSlot
.SlotId
= SlotId
;
1641 Status
= XhcPeiCmdTransfer (
1643 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbDisSlot
,
1644 XHC_GENERIC_TIMEOUT
,
1645 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1647 if (EFI_ERROR (Status
)) {
1648 DEBUG ((DEBUG_ERROR
, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status
));
1653 // Free the slot's device context entry
1655 Xhc
->DCBAA
[SlotId
] = 0;
1658 // Free the slot related data structure
1660 for (Index
= 0; Index
< 31; Index
++) {
1661 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1662 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1663 if (RingSeg
!= NULL
) {
1664 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1667 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1668 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1672 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1673 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1674 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1678 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1679 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1682 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1683 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1687 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1688 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1689 // remove urb from XHCI's asynchronous transfer list.
1691 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1692 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1694 DEBUG ((DEBUG_INFO
, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status
));
1699 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1701 @param Xhc The XHCI device.
1702 @param SlotId The slot id to be configured.
1703 @param DeviceSpeed The device's speed.
1704 @param ConfigDesc The pointer to the usb device configuration descriptor.
1706 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1710 XhcPeiSetConfigCmd (
1711 IN PEI_XHC_DEV
*Xhc
,
1713 IN UINT8 DeviceSpeed
,
1714 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1718 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1719 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1724 EFI_USB_DATA_DIRECTION Direction
;
1727 EFI_PHYSICAL_ADDRESS PhyAddr
;
1730 TRANSFER_RING
*EndpointTransferRing
;
1731 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1732 INPUT_CONTEXT
*InputContext
;
1733 DEVICE_CONTEXT
*OutputContext
;
1734 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1737 // 4.6.6 Configure Endpoint
1739 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1740 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1741 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1742 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
1744 ASSERT (ConfigDesc
!= NULL
);
1748 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
1749 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1750 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1751 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
1754 NumEp
= IfDesc
->NumEndpoints
;
1756 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
1757 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1758 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1759 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1762 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
1763 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1765 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1770 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1771 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1773 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1775 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1777 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1779 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1782 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
1783 case USB_ENDPOINT_BULK
:
1784 if (Direction
== EfiUsbDataIn
) {
1785 InputContext
->EP
[Dci
-1].CErr
= 3;
1786 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
1788 InputContext
->EP
[Dci
-1].CErr
= 3;
1789 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
1792 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1793 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1794 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1795 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*)EndpointTransferRing
;
1796 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1800 case USB_ENDPOINT_ISO
:
1801 if (Direction
== EfiUsbDataIn
) {
1802 InputContext
->EP
[Dci
-1].CErr
= 0;
1803 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
1805 InputContext
->EP
[Dci
-1].CErr
= 0;
1806 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
1810 // Get the bInterval from descriptor and init the the interval field of endpoint context.
1811 // Refer to XHCI 1.1 spec section 6.2.3.6.
1813 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
1814 Interval
= EpDesc
->Interval
;
1815 ASSERT (Interval
>= 1 && Interval
<= 16);
1816 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
1817 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1818 Interval
= EpDesc
->Interval
;
1819 ASSERT (Interval
>= 1 && Interval
<= 16);
1820 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1824 // Do not support isochronous transfer now.
1826 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1827 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1829 case USB_ENDPOINT_INTERRUPT
:
1830 if (Direction
== EfiUsbDataIn
) {
1831 InputContext
->EP
[Dci
-1].CErr
= 3;
1832 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
1834 InputContext
->EP
[Dci
-1].CErr
= 3;
1835 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
1838 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1839 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
1841 // Get the bInterval from descriptor and init the interval field of endpoint context
1843 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
1844 Interval
= EpDesc
->Interval
;
1846 // Calculate through the bInterval field of Endpoint descriptor.
1848 ASSERT (Interval
!= 0);
1849 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32 ((UINT32
)Interval
) + 3;
1850 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1851 Interval
= EpDesc
->Interval
;
1852 ASSERT (Interval
>= 1 && Interval
<= 16);
1854 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1856 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1859 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1860 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1861 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*)EndpointTransferRing
;
1862 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1867 case USB_ENDPOINT_CONTROL
:
1869 // Do not support control transfer now.
1871 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1873 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
1874 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1878 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1880 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
1881 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1883 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
1884 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
1885 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1886 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1888 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1891 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
1894 InputContext
->InputControlContext
.Dword2
|= BIT0
;
1895 InputContext
->Slot
.ContextEntries
= MaxDci
;
1897 // configure endpoint
1899 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
1900 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
1901 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1902 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1903 CmdTrbCfgEP
.CycleBit
= 1;
1904 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
1905 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1906 DEBUG ((DEBUG_INFO
, "XhcSetConfigCmd: Configure Endpoint\n"));
1907 Status
= XhcPeiCmdTransfer (
1909 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbCfgEP
,
1910 XHC_GENERIC_TIMEOUT
,
1911 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
1913 if (EFI_ERROR (Status
)) {
1914 DEBUG ((DEBUG_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
1921 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1923 @param Xhc The XHCI device.
1924 @param SlotId The slot id to be configured.
1925 @param DeviceSpeed The device's speed.
1926 @param ConfigDesc The pointer to the usb device configuration descriptor.
1928 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1932 XhcPeiSetConfigCmd64 (
1933 IN PEI_XHC_DEV
*Xhc
,
1935 IN UINT8 DeviceSpeed
,
1936 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1940 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1941 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1946 EFI_USB_DATA_DIRECTION Direction
;
1949 EFI_PHYSICAL_ADDRESS PhyAddr
;
1952 TRANSFER_RING
*EndpointTransferRing
;
1953 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1954 INPUT_CONTEXT_64
*InputContext
;
1955 DEVICE_CONTEXT_64
*OutputContext
;
1956 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1959 // 4.6.6 Configure Endpoint
1961 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1962 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1963 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1964 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
1966 ASSERT (ConfigDesc
!= NULL
);
1970 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
1971 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1972 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1973 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
1976 NumEp
= IfDesc
->NumEndpoints
;
1978 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
1979 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1980 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1981 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1984 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
1985 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1987 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1993 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1994 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1996 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1998 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2000 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2002 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2005 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2006 case USB_ENDPOINT_BULK
:
2007 if (Direction
== EfiUsbDataIn
) {
2008 InputContext
->EP
[Dci
-1].CErr
= 3;
2009 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2011 InputContext
->EP
[Dci
-1].CErr
= 3;
2012 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2015 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2016 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2017 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2018 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*)EndpointTransferRing
;
2019 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2023 case USB_ENDPOINT_ISO
:
2024 if (Direction
== EfiUsbDataIn
) {
2025 InputContext
->EP
[Dci
-1].CErr
= 0;
2026 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2028 InputContext
->EP
[Dci
-1].CErr
= 0;
2029 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2033 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2034 // Refer to XHCI 1.1 spec section 6.2.3.6.
2036 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2037 Interval
= EpDesc
->Interval
;
2038 ASSERT (Interval
>= 1 && Interval
<= 16);
2039 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2040 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2041 Interval
= EpDesc
->Interval
;
2042 ASSERT (Interval
>= 1 && Interval
<= 16);
2043 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2047 // Do not support isochronous transfer now.
2049 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2050 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2052 case USB_ENDPOINT_INTERRUPT
:
2053 if (Direction
== EfiUsbDataIn
) {
2054 InputContext
->EP
[Dci
-1].CErr
= 3;
2055 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2057 InputContext
->EP
[Dci
-1].CErr
= 3;
2058 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2061 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2062 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2064 // Get the bInterval from descriptor and init the the interval field of endpoint context
2066 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2067 Interval
= EpDesc
->Interval
;
2069 // Calculate through the bInterval field of Endpoint descriptor.
2071 ASSERT (Interval
!= 0);
2072 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32 ((UINT32
)Interval
) + 3;
2073 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2074 Interval
= EpDesc
->Interval
;
2075 ASSERT (Interval
>= 1 && Interval
<= 16);
2077 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2079 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2082 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2083 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2084 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*)EndpointTransferRing
;
2085 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2090 case USB_ENDPOINT_CONTROL
:
2092 // Do not support control transfer now.
2094 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2096 DEBUG ((DEBUG_INFO
, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
2097 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2101 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2103 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2104 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2107 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2108 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2110 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2111 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2113 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2116 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2119 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2120 InputContext
->Slot
.ContextEntries
= MaxDci
;
2122 // configure endpoint
2124 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2125 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2126 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2127 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2128 CmdTrbCfgEP
.CycleBit
= 1;
2129 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2130 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2131 DEBUG ((DEBUG_INFO
, "XhcSetConfigCmd64: Configure Endpoint\n"));
2132 Status
= XhcPeiCmdTransfer (
2134 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbCfgEP
,
2135 XHC_GENERIC_TIMEOUT
,
2136 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2138 if (EFI_ERROR (Status
)) {
2139 DEBUG ((DEBUG_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
2146 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2148 @param Xhc The XHCI device.
2149 @param SlotId The slot id to be evaluated.
2150 @param MaxPacketSize The max packet size supported by the device control transfer.
2152 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2156 XhcPeiEvaluateContext (
2157 IN PEI_XHC_DEV
*Xhc
,
2159 IN UINT32 MaxPacketSize
2163 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2164 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2165 INPUT_CONTEXT
*InputContext
;
2166 EFI_PHYSICAL_ADDRESS PhyAddr
;
2168 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2171 // 4.6.7 Evaluate Context
2173 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2174 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2176 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2177 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2179 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2180 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2181 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2182 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2183 CmdTrbEvalu
.CycleBit
= 1;
2184 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2185 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2186 DEBUG ((DEBUG_INFO
, "XhcEvaluateContext: Evaluate context\n"));
2187 Status
= XhcPeiCmdTransfer (
2189 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbEvalu
,
2190 XHC_GENERIC_TIMEOUT
,
2191 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2193 if (EFI_ERROR (Status
)) {
2194 DEBUG ((DEBUG_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
2201 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2203 @param Xhc The XHCI device.
2204 @param SlotId The slot id to be evaluated.
2205 @param MaxPacketSize The max packet size supported by the device control transfer.
2207 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2211 XhcPeiEvaluateContext64 (
2212 IN PEI_XHC_DEV
*Xhc
,
2214 IN UINT32 MaxPacketSize
2218 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2219 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2220 INPUT_CONTEXT_64
*InputContext
;
2221 EFI_PHYSICAL_ADDRESS PhyAddr
;
2223 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2226 // 4.6.7 Evaluate Context
2228 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2229 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2231 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2232 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2234 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2235 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2236 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2237 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2238 CmdTrbEvalu
.CycleBit
= 1;
2239 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2240 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2241 DEBUG ((DEBUG_INFO
, "XhcEvaluateContext64: Evaluate context 64\n"));
2242 Status
= XhcPeiCmdTransfer (
2244 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbEvalu
,
2245 XHC_GENERIC_TIMEOUT
,
2246 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2248 if (EFI_ERROR (Status
)) {
2249 DEBUG ((DEBUG_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
2256 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2258 @param Xhc The XHCI device.
2259 @param SlotId The slot id to be configured.
2260 @param PortNum The total number of downstream port supported by the hub.
2261 @param TTT The TT think time of the hub device.
2262 @param MTT The multi-TT of the hub device.
2264 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2268 XhcPeiConfigHubContext (
2269 IN PEI_XHC_DEV
*Xhc
,
2277 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2278 INPUT_CONTEXT
*InputContext
;
2279 DEVICE_CONTEXT
*OutputContext
;
2280 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2281 EFI_PHYSICAL_ADDRESS PhyAddr
;
2283 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2284 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2285 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2288 // 4.6.7 Evaluate Context
2290 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2292 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2295 // Copy the slot context from OutputContext to Input context
2297 CopyMem (&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
2298 InputContext
->Slot
.Hub
= 1;
2299 InputContext
->Slot
.PortNum
= PortNum
;
2300 InputContext
->Slot
.TTT
= TTT
;
2301 InputContext
->Slot
.MTT
= MTT
;
2303 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2304 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2305 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2306 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2307 CmdTrbCfgEP
.CycleBit
= 1;
2308 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2309 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2310 DEBUG ((DEBUG_INFO
, "Configure Hub Slot Context\n"));
2311 Status
= XhcPeiCmdTransfer (
2313 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbCfgEP
,
2314 XHC_GENERIC_TIMEOUT
,
2315 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2317 if (EFI_ERROR (Status
)) {
2318 DEBUG ((DEBUG_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
2325 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2327 @param Xhc The XHCI device.
2328 @param SlotId The slot id to be configured.
2329 @param PortNum The total number of downstream port supported by the hub.
2330 @param TTT The TT think time of the hub device.
2331 @param MTT The multi-TT of the hub device.
2333 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2337 XhcPeiConfigHubContext64 (
2338 IN PEI_XHC_DEV
*Xhc
,
2346 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2347 INPUT_CONTEXT_64
*InputContext
;
2348 DEVICE_CONTEXT_64
*OutputContext
;
2349 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2350 EFI_PHYSICAL_ADDRESS PhyAddr
;
2352 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2353 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2354 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2357 // 4.6.7 Evaluate Context
2359 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2361 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2364 // Copy the slot context from OutputContext to Input context
2366 CopyMem (&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
2367 InputContext
->Slot
.Hub
= 1;
2368 InputContext
->Slot
.PortNum
= PortNum
;
2369 InputContext
->Slot
.TTT
= TTT
;
2370 InputContext
->Slot
.MTT
= MTT
;
2372 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2373 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2374 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2375 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2376 CmdTrbCfgEP
.CycleBit
= 1;
2377 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2378 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2379 DEBUG ((DEBUG_INFO
, "Configure Hub Slot Context 64\n"));
2380 Status
= XhcPeiCmdTransfer (
2382 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbCfgEP
,
2383 XHC_GENERIC_TIMEOUT
,
2384 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2386 if (EFI_ERROR (Status
)) {
2387 DEBUG ((DEBUG_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));
2394 Stop endpoint through XHCI's Stop_Endpoint cmd.
2396 @param Xhc The XHCI device.
2397 @param SlotId The slot id of the target device.
2398 @param Dci The device context index of the target slot or endpoint.
2400 @retval EFI_SUCCESS Stop endpoint successfully.
2401 @retval Others Failed to stop endpoint.
2406 XhcPeiStopEndpoint (
2407 IN PEI_XHC_DEV
*Xhc
,
2413 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2414 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
2416 DEBUG ((DEBUG_INFO
, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
2419 // Send stop endpoint command to transit Endpoint from running to stop state
2421 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
2422 CmdTrbStopED
.CycleBit
= 1;
2423 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
2424 CmdTrbStopED
.EDID
= Dci
;
2425 CmdTrbStopED
.SlotId
= SlotId
;
2426 Status
= XhcPeiCmdTransfer (
2428 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbStopED
,
2429 XHC_GENERIC_TIMEOUT
,
2430 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2432 if (EFI_ERROR (Status
)) {
2433 DEBUG ((DEBUG_ERROR
, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
2440 Reset endpoint through XHCI's Reset_Endpoint cmd.
2442 @param Xhc The XHCI device.
2443 @param SlotId The slot id of the target device.
2444 @param Dci The device context index of the target slot or endpoint.
2446 @retval EFI_SUCCESS Reset endpoint successfully.
2447 @retval Others Failed to reset endpoint.
2452 XhcPeiResetEndpoint (
2453 IN PEI_XHC_DEV
*Xhc
,
2459 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2460 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
2462 DEBUG ((DEBUG_INFO
, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
2465 // Send stop endpoint command to transit Endpoint from running to stop state
2467 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
2468 CmdTrbResetED
.CycleBit
= 1;
2469 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
2470 CmdTrbResetED
.EDID
= Dci
;
2471 CmdTrbResetED
.SlotId
= SlotId
;
2472 Status
= XhcPeiCmdTransfer (
2474 (TRB_TEMPLATE
*)(UINTN
)&CmdTrbResetED
,
2475 XHC_GENERIC_TIMEOUT
,
2476 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2478 if (EFI_ERROR (Status
)) {
2479 DEBUG ((DEBUG_ERROR
, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
2486 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
2488 @param Xhc The XHCI device.
2489 @param SlotId The slot id of the target device.
2490 @param Dci The device context index of the target slot or endpoint.
2491 @param Urb The dequeue pointer of the transfer ring specified
2492 by the urb to be updated.
2494 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
2495 @retval Others Failed to set transfer ring dequeue pointer.
2500 XhcPeiSetTrDequeuePointer (
2501 IN PEI_XHC_DEV
*Xhc
,
2508 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2509 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
2510 EFI_PHYSICAL_ADDRESS PhyAddr
;
2512 DEBUG ((DEBUG_INFO
, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
2515 // Send stop endpoint command to transit Endpoint from running to stop state
2517 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
2518 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
2519 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
2520 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2521 CmdSetTRDeq
.CycleBit
= 1;
2522 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
2523 CmdSetTRDeq
.Endpoint
= Dci
;
2524 CmdSetTRDeq
.SlotId
= SlotId
;
2525 Status
= XhcPeiCmdTransfer (
2527 (TRB_TEMPLATE
*)(UINTN
)&CmdSetTRDeq
,
2528 XHC_GENERIC_TIMEOUT
,
2529 (TRB_TEMPLATE
**)(UINTN
)&EvtTrb
2531 if (EFI_ERROR (Status
)) {
2532 DEBUG ((DEBUG_ERROR
, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
2539 Check if there is a new generated event.
2541 @param Xhc The XHCI device.
2542 @param EvtRing The event ring to check.
2543 @param NewEvtTrb The new event TRB found.
2545 @retval EFI_SUCCESS Found a new event TRB at the event ring.
2546 @retval EFI_NOT_READY The event ring has no new event.
2550 XhcPeiCheckNewEvent (
2551 IN PEI_XHC_DEV
*Xhc
,
2552 IN EVENT_RING
*EvtRing
,
2553 OUT TRB_TEMPLATE
**NewEvtTrb
2556 ASSERT (EvtRing
!= NULL
);
2558 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
2560 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
2561 return EFI_NOT_READY
;
2564 EvtRing
->EventRingDequeue
++;
2566 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2568 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
)EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2569 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
2576 Synchronize the specified event ring to update the enqueue and dequeue pointer.
2578 @param Xhc The XHCI device.
2579 @param EvtRing The event ring to sync.
2581 @retval EFI_SUCCESS The event ring is synchronized successfully.
2585 XhcPeiSyncEventRing (
2586 IN PEI_XHC_DEV
*Xhc
,
2587 IN EVENT_RING
*EvtRing
2591 TRB_TEMPLATE
*EvtTrb
;
2593 ASSERT (EvtRing
!= NULL
);
2596 // Calculate the EventRingEnqueue and EventRingCCS.
2597 // Note: only support single Segment
2599 EvtTrb
= EvtRing
->EventRingDequeue
;
2601 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
2602 if (EvtTrb
->CycleBit
!= EvtRing
->EventRingCCS
) {
2608 if ((UINTN
)EvtTrb
>= ((UINTN
)EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2609 EvtTrb
= EvtRing
->EventRingSeg0
;
2610 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
2614 if (Index
< EvtRing
->TrbNumber
) {
2615 EvtRing
->EventRingEnqueue
= EvtTrb
;
2624 Free XHCI event ring.
2626 @param Xhc The XHCI device.
2627 @param EventRing The event ring to be freed.
2631 XhcPeiFreeEventRing (
2632 IN PEI_XHC_DEV
*Xhc
,
2633 IN EVENT_RING
*EventRing
2636 if (EventRing
->EventRingSeg0
== NULL
) {
2641 // Free EventRing Segment 0
2643 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
2648 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
2652 Create XHCI event ring.
2654 @param Xhc The XHCI device.
2655 @param EventRing The created event ring.
2659 XhcPeiCreateEventRing (
2660 IN PEI_XHC_DEV
*Xhc
,
2661 OUT EVENT_RING
*EventRing
2665 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
2667 EFI_PHYSICAL_ADDRESS ERSTPhy
;
2668 EFI_PHYSICAL_ADDRESS DequeuePhy
;
2670 ASSERT (EventRing
!= NULL
);
2672 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
2673 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2674 ASSERT (Buf
!= NULL
);
2675 ASSERT (((UINTN
)Buf
& 0x3F) == 0);
2676 ZeroMem (Buf
, Size
);
2678 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2680 EventRing
->EventRingSeg0
= Buf
;
2681 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
2682 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*)EventRing
->EventRingSeg0
;
2683 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*)EventRing
->EventRingSeg0
;
2686 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
2687 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
2689 EventRing
->EventRingCCS
= 1;
2691 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
2692 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2693 ASSERT (Buf
!= NULL
);
2694 ASSERT (((UINTN
)Buf
& 0x3F) == 0);
2695 ZeroMem (Buf
, Size
);
2697 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*)Buf
;
2698 EventRing
->ERSTBase
= ERSTBase
;
2699 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
2700 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
2701 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
2703 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2706 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
2708 XhcPeiWriteRuntimeReg (
2714 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
2716 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2717 // So divide it to two 32-bytes width register access.
2719 XhcPeiWriteRuntimeReg (
2722 XHC_LOW_32BIT ((UINT64
)(UINTN
)DequeuePhy
)
2724 XhcPeiWriteRuntimeReg (
2726 XHC_ERDP_OFFSET
+ 4,
2727 XHC_HIGH_32BIT ((UINT64
)(UINTN
)DequeuePhy
)
2730 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
2732 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2733 // So divide it to two 32-bytes width register access.
2735 XhcPeiWriteRuntimeReg (
2738 XHC_LOW_32BIT ((UINT64
)(UINTN
)ERSTPhy
)
2740 XhcPeiWriteRuntimeReg (
2742 XHC_ERSTBA_OFFSET
+ 4,
2743 XHC_HIGH_32BIT ((UINT64
)(UINTN
)ERSTPhy
)
2746 // Need set IMAN IE bit to enable the ring interrupt
2748 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
2752 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
2754 @param Xhc The XHCI device.
2755 @param TrsRing The transfer ring to sync.
2757 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
2762 IN PEI_XHC_DEV
*Xhc
,
2763 IN TRANSFER_RING
*TrsRing
2767 TRB_TEMPLATE
*TrsTrb
;
2769 ASSERT (TrsRing
!= NULL
);
2771 // Calculate the latest RingEnqueue and RingPCS
2773 TrsTrb
= TrsRing
->RingEnqueue
;
2774 ASSERT (TrsTrb
!= NULL
);
2776 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
2777 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
2782 if ((UINT8
)TrsTrb
->Type
== TRB_TYPE_LINK
) {
2783 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
2785 // set cycle bit in Link TRB as normal
2787 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
2789 // Toggle PCS maintained by software
2791 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
2792 TrsTrb
= (TRB_TEMPLATE
*)TrsRing
->RingSeg0
; // Use host address
2796 ASSERT (Index
!= TrsRing
->TrbNumber
);
2798 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
2799 TrsRing
->RingEnqueue
= TrsTrb
;
2803 // Clear the Trb context for enqueue, but reserve the PCS bit
2805 TrsTrb
->Parameter1
= 0;
2806 TrsTrb
->Parameter2
= 0;
2810 TrsTrb
->Control
= 0;
2816 Create XHCI transfer ring.
2818 @param Xhc The XHCI Device.
2819 @param TrbNum The number of TRB in the ring.
2820 @param TransferRing The created transfer ring.
2824 XhcPeiCreateTransferRing (
2825 IN PEI_XHC_DEV
*Xhc
,
2827 OUT TRANSFER_RING
*TransferRing
2832 EFI_PHYSICAL_ADDRESS PhyAddr
;
2834 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2835 ASSERT (Buf
!= NULL
);
2836 ASSERT (((UINTN
)Buf
& 0x3F) == 0);
2837 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2839 TransferRing
->RingSeg0
= Buf
;
2840 TransferRing
->TrbNumber
= TrbNum
;
2841 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*)TransferRing
->RingSeg0
;
2842 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*)TransferRing
->RingSeg0
;
2843 TransferRing
->RingPCS
= 1;
2845 // 4.9.2 Transfer Ring Management
2846 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
2847 // point to the first TRB in the ring.
2849 EndTrb
= (LINK_TRB
*)((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
2850 EndTrb
->Type
= TRB_TYPE_LINK
;
2851 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2852 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2853 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2855 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
2859 // Set Cycle bit as other TRB PCS init value
2861 EndTrb
->CycleBit
= 0;
2865 Initialize the XHCI host controller for schedule.
2867 @param Xhc The XHCI device to be initialized.
2876 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
2878 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
2879 UINT32 MaxScratchpadBufs
;
2881 EFI_PHYSICAL_ADDRESS ScratchPhy
;
2882 UINT64
*ScratchEntry
;
2883 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
2885 UINTN
*ScratchEntryMap
;
2889 // Initialize memory management.
2891 Xhc
->MemPool
= UsbHcInitMemPool ();
2892 ASSERT (Xhc
->MemPool
!= NULL
);
2895 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
2896 // to enable the device slots that system software is going to use.
2898 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
2899 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
2900 XhcPeiWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, (XhcPeiReadOpReg (Xhc
, XHC_CONFIG_OFFSET
) & ~XHC_CONFIG_MASK
) | Xhc
->MaxSlotsEn
);
2903 // The Device Context Base Address Array entry associated with each allocated Device Slot
2904 // shall contain a 64-bit pointer to the base of the associated Device Context.
2905 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
2906 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
2908 Size
= (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
);
2909 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2910 ASSERT (Dcbaa
!= NULL
);
2913 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
2914 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
2915 // mode (Run/Stop(R/S) ='1').
2917 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
2918 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
2919 ASSERT (MaxScratchpadBufs
<= 1023);
2920 if (MaxScratchpadBufs
!= 0) {
2922 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
2924 ScratchEntryMap
= AllocateZeroPool (sizeof (UINTN
) * MaxScratchpadBufs
);
2925 ASSERT (ScratchEntryMap
!= NULL
);
2926 Xhc
->ScratchEntryMap
= ScratchEntryMap
;
2929 // Allocate the buffer to record the host address for each entry
2931 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
2932 ASSERT (ScratchEntry
!= NULL
);
2933 Xhc
->ScratchEntry
= ScratchEntry
;
2936 Status
= UsbHcAllocateAlignedPages (
2937 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
2939 (VOID
**)&ScratchBuf
,
2943 ASSERT_EFI_ERROR (Status
);
2945 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
2946 Xhc
->ScratchBuf
= ScratchBuf
;
2949 // Allocate each scratch buffer
2951 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
2952 ScratchEntryPhy
= 0;
2953 Status
= UsbHcAllocateAlignedPages (
2954 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
2956 (VOID
**)&ScratchEntry
[Index
],
2958 (VOID
**)&ScratchEntryMap
[Index
]
2960 ASSERT_EFI_ERROR (Status
);
2961 ZeroMem ((VOID
*)(UINTN
)ScratchEntry
[Index
], Xhc
->PageSize
);
2963 // Fill with the PCI device address
2965 *ScratchBuf
++ = ScratchEntryPhy
;
2969 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
2970 // Device Context Base Address Array points to the Scratchpad Buffer Array.
2972 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
)ScratchPhy
;
2976 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
2977 // a 64-bit address pointing to where the Device Context Base Address Array is located.
2979 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
2981 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2982 // So divide it to two 32-bytes width register access.
2984 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Size
);
2985 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT (DcbaaPhy
));
2986 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
2988 DEBUG ((DEBUG_INFO
, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc
->DCBAA
));
2991 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
2992 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
2993 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
2996 XhcPeiCreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
2998 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
2999 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
3000 // So we set RCS as inverted PCS init value to let Command Ring empty
3002 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
3003 ASSERT ((CmdRingPhy
& 0x3F) == 0);
3004 CmdRingPhy
|= XHC_CRCR_RCS
;
3006 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
3007 // So divide it to two 32-bytes width register access.
3009 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT (CmdRingPhy
));
3010 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
3012 DEBUG ((DEBUG_INFO
, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc
->CmdRing
.RingSeg0
));
3015 // Disable the 'interrupter enable' bit in USB_CMD
3016 // and clear IE & IP bit in all Interrupter X Management Registers.
3018 XhcPeiClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
3019 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
3020 XhcPeiClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
3021 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
3025 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
3027 XhcPeiCreateEventRing (Xhc
, &Xhc
->EventRing
);
3028 DEBUG ((DEBUG_INFO
, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc
->EventRing
.EventRingSeg0
));
3032 Free the resouce allocated at initializing schedule.
3034 @param Xhc The XHCI device.
3043 UINT64
*ScratchEntry
;
3045 if (Xhc
->ScratchBuf
!= NULL
) {
3046 ScratchEntry
= Xhc
->ScratchEntry
;
3047 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
3049 // Free Scratchpad Buffers
3051 UsbHcFreeAlignedPages ((VOID
*)(UINTN
)ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*)Xhc
->ScratchEntryMap
[Index
]);
3055 // Free Scratchpad Buffer Array
3057 UsbHcFreeAlignedPages (Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
3058 FreePool (Xhc
->ScratchEntryMap
);
3059 FreePool (Xhc
->ScratchEntry
);
3062 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
3063 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
3064 Xhc
->CmdRing
.RingSeg0
= NULL
;
3067 XhcPeiFreeEventRing (Xhc
, &Xhc
->EventRing
);
3069 if (Xhc
->DCBAA
!= NULL
) {
3070 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
));
3075 // Free memory pool at last
3077 if (Xhc
->MemPool
!= NULL
) {
3078 UsbHcFreeMemPool (Xhc
->MemPool
);
3079 Xhc
->MemPool
= NULL
;