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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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
->Ep
.Direction
== EfiUsbDataIn
) {
295 TrbStart
->TrbCtrSetup
.TRT
= 3;
296 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
297 TrbStart
->TrbCtrSetup
.TRT
= 2;
299 TrbStart
->TrbCtrSetup
.TRT
= 0;
302 // Update the cycle bit
304 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
308 // For control transfer, create DATA_STAGE_TRB.
310 if (Urb
->DataLen
> 0) {
311 XhcPeiSyncTrsRing (Xhc
, EPRing
);
312 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
313 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT (Urb
->DataPhy
);
314 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT (Urb
->DataPhy
);
315 TrbStart
->TrbCtrData
.Length
= (UINT32
) Urb
->DataLen
;
316 TrbStart
->TrbCtrData
.TDSize
= 0;
317 TrbStart
->TrbCtrData
.IntTarget
= 0;
318 TrbStart
->TrbCtrData
.ISP
= 1;
319 TrbStart
->TrbCtrData
.IOC
= 1;
320 TrbStart
->TrbCtrData
.IDT
= 0;
321 TrbStart
->TrbCtrData
.CH
= 0;
322 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
323 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
324 TrbStart
->TrbCtrData
.DIR = 1;
325 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
326 TrbStart
->TrbCtrData
.DIR = 0;
328 TrbStart
->TrbCtrData
.DIR = 0;
331 // Update the cycle bit
333 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
337 // For control transfer, create STATUS_STAGE_TRB.
338 // Get the pointer to next TRB for status stage use
340 XhcPeiSyncTrsRing (Xhc
, EPRing
);
341 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
342 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
343 TrbStart
->TrbCtrStatus
.IOC
= 1;
344 TrbStart
->TrbCtrStatus
.CH
= 0;
345 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
346 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
347 TrbStart
->TrbCtrStatus
.DIR = 0;
348 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
349 TrbStart
->TrbCtrStatus
.DIR = 1;
351 TrbStart
->TrbCtrStatus
.DIR = 0;
354 // Update the cycle bit
356 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
358 // Update the enqueue pointer
360 XhcPeiSyncTrsRing (Xhc
, EPRing
);
362 Urb
->TrbEnd
= (TRB_TEMPLATE
*) (UINTN
) TrbStart
;
371 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
372 while (TotalLen
< Urb
->DataLen
) {
373 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
374 Len
= Urb
->DataLen
- TotalLen
;
378 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
379 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
380 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
381 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
382 TrbStart
->TrbNormal
.TDSize
= 0;
383 TrbStart
->TrbNormal
.IntTarget
= 0;
384 TrbStart
->TrbNormal
.ISP
= 1;
385 TrbStart
->TrbNormal
.IOC
= 1;
386 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
388 // Update the cycle bit
390 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
392 XhcPeiSyncTrsRing (Xhc
, EPRing
);
397 Urb
->TrbNum
= TrbNum
;
398 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
401 case ED_INTERRUPT_OUT
:
402 case ED_INTERRUPT_IN
:
406 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
407 while (TotalLen
< Urb
->DataLen
) {
408 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
409 Len
= Urb
->DataLen
- TotalLen
;
413 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
414 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
415 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
416 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
417 TrbStart
->TrbNormal
.TDSize
= 0;
418 TrbStart
->TrbNormal
.IntTarget
= 0;
419 TrbStart
->TrbNormal
.ISP
= 1;
420 TrbStart
->TrbNormal
.IOC
= 1;
421 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
423 // Update the cycle bit
425 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
427 XhcPeiSyncTrsRing (Xhc
, EPRing
);
432 Urb
->TrbNum
= TrbNum
;
433 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
437 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
446 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
447 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
448 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
449 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
450 Stopped to the Running state.
452 @param Xhc The XHCI device.
453 @param Urb The urb which makes the endpoint halted.
455 @retval EFI_SUCCESS The recovery is successful.
456 @retval Others Failed to recovery halted endpoint.
460 XhcPeiRecoverHaltedEndpoint (
469 Status
= EFI_SUCCESS
;
470 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
472 return EFI_DEVICE_ERROR
;
474 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
) (Urb
->Ep
.Direction
));
476 DEBUG ((EFI_D_INFO
, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId
, Dci
));
479 // 1) Send Reset endpoint command to transit from halt to stop state
481 Status
= XhcPeiResetEndpoint (Xhc
, SlotId
, Dci
);
482 if (EFI_ERROR(Status
)) {
483 DEBUG ((EFI_D_ERROR
, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
488 // 2) Set dequeue pointer
490 Status
= XhcPeiSetTrDequeuePointer (Xhc
, SlotId
, Dci
, Urb
);
491 if (EFI_ERROR(Status
)) {
492 DEBUG ((EFI_D_ERROR
, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
497 // 3) Ring the doorbell to transit from stop to active
499 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
506 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
507 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
508 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
511 @param Xhc The XHCI device.
512 @param Urb The urb which doesn't get completed in a specified timeout range.
514 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
515 @retval Others Failed to stop the endpoint and dequeue the TDs.
519 XhcPeiDequeueTrbFromEndpoint (
528 Status
= EFI_SUCCESS
;
529 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
531 return EFI_DEVICE_ERROR
;
533 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
) (Urb
->Ep
.Direction
));
535 DEBUG ((EFI_D_INFO
, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId
, Dci
));
538 // 1) Send Stop endpoint command to stop endpoint.
540 Status
= XhcPeiStopEndpoint (Xhc
, SlotId
, Dci
);
541 if (EFI_ERROR(Status
)) {
542 DEBUG ((EFI_D_ERROR
, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
547 // 2) Set dequeue pointer
549 Status
= XhcPeiSetTrDequeuePointer (Xhc
, SlotId
, Dci
, Urb
);
550 if (EFI_ERROR(Status
)) {
551 DEBUG ((EFI_D_ERROR
, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
556 // 3) Ring the doorbell to transit from stop to active
558 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
565 Check if the Trb is a transaction of the URB.
567 @param Trb The TRB to be checked
568 @param Urb The transfer ring to be checked.
570 @retval TRUE It is a transaction of the URB.
571 @retval FALSE It is not any transaction of the URB.
575 XhcPeiIsTransferRingTrb (
576 IN TRB_TEMPLATE
*Trb
,
580 TRB_TEMPLATE
*CheckedTrb
;
583 CheckedTrb
= Urb
->Ring
->RingSeg0
;
585 ASSERT (Urb
->Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Urb
->Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
587 for (Index
= 0; Index
< Urb
->Ring
->TrbNumber
; Index
++) {
588 if (Trb
== CheckedTrb
) {
598 Check the URB's execution result and update the URB's
601 @param Xhc The XHCI device.
602 @param Urb The URB to check result.
604 @return Whether the result of URB transfer is finialized.
608 XhcPeiCheckUrbResult (
613 EVT_TRB_TRANSFER
*EvtTrb
;
614 TRB_TEMPLATE
*TRBPtr
;
622 EFI_PHYSICAL_ADDRESS PhyAddr
;
624 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
626 Status
= EFI_SUCCESS
;
634 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
635 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
640 // Traverse the event ring to find out all new events from the previous check.
642 XhcPeiSyncEventRing (Xhc
, &Xhc
->EventRing
);
643 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
644 Status
= XhcPeiCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**) &EvtTrb
));
645 if (Status
== EFI_NOT_READY
) {
647 // All new events are handled, return directly.
653 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
655 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
660 // Need convert pci device address to host address
662 PhyAddr
= (EFI_PHYSICAL_ADDRESS
) (EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
663 TRBPtr
= (TRB_TEMPLATE
*) (UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*) (UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
666 // Update the status of Urb according to the finished event regardless of whether
667 // the urb is current checked one or in the XHCI's async transfer list.
668 // This way is used to avoid that those completed async transfer events don't get
669 // handled in time and are flushed by newer coming events.
671 if (XhcPeiIsTransferRingTrb (TRBPtr
, Urb
)) {
677 switch (EvtTrb
->Completecode
) {
678 case TRB_COMPLETION_STALL_ERROR
:
679 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
680 CheckedUrb
->Finished
= TRUE
;
681 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
684 case TRB_COMPLETION_BABBLE_ERROR
:
685 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
686 CheckedUrb
->Finished
= TRUE
;
687 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
690 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
691 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
692 CheckedUrb
->Finished
= TRUE
;
693 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb
->Completecode
));
696 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
697 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
698 CheckedUrb
->Finished
= TRUE
;
699 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
702 case TRB_COMPLETION_SHORT_PACKET
:
703 case TRB_COMPLETION_SUCCESS
:
704 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
705 DEBUG ((EFI_D_VERBOSE
, "XhcPeiCheckUrbResult: short packet happens!\n"));
708 TRBType
= (UINT8
) (TRBPtr
->Type
);
709 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
710 (TRBType
== TRB_TYPE_NORMAL
) ||
711 (TRBType
== TRB_TYPE_ISOCH
)) {
712 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
718 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb
->Completecode
));
719 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
720 CheckedUrb
->Finished
= TRUE
;
725 // Only check first and end Trb event address
727 if (TRBPtr
== CheckedUrb
->TrbStart
) {
728 CheckedUrb
->StartDone
= TRUE
;
731 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
732 CheckedUrb
->EndDone
= TRUE
;
735 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
736 CheckedUrb
->Finished
= TRUE
;
737 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*) EvtTrb
;
744 // Advance event ring to last available entry
746 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
747 // So divide it to two 32-bytes width register access.
749 Low
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
750 High
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
751 XhcDequeue
= (UINT64
) (LShiftU64((UINT64
) High
, 32) | Low
);
753 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
755 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
757 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
758 // So divide it to two 32-bytes width register access.
760 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
761 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
764 return Urb
->Finished
;
768 Execute the transfer by polling the URB. This is a synchronous operation.
770 @param Xhc The XHCI device.
771 @param CmdTransfer The executed URB is for cmd transfer or not.
772 @param Urb The URB to execute.
773 @param Timeout The time to wait before abort, in millisecond.
775 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
776 @return EFI_TIMEOUT The transfer failed due to time out.
777 @return EFI_SUCCESS The transfer finished OK.
783 IN BOOLEAN CmdTransfer
,
799 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
801 return EFI_DEVICE_ERROR
;
803 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
806 Status
= EFI_SUCCESS
;
807 Loop
= Timeout
* XHC_1_MILLISECOND
;
812 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
814 for (Index
= 0; Index
< Loop
; Index
++) {
815 Finished
= XhcPeiCheckUrbResult (Xhc
, Urb
);
819 MicroSecondDelay (XHC_1_MICROSECOND
);
823 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
824 Status
= EFI_TIMEOUT
;
825 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
826 Status
= EFI_DEVICE_ERROR
;
833 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
835 @param Xhc The XHCI device.
836 @param ParentRouteChart The route string pointed to the parent device if it exists.
837 @param Port The port to be polled.
838 @param PortState The port state.
840 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
841 @retval Others Should not appear.
845 XhcPeiPollPortStatusChange (
847 IN USB_DEV_ROUTE ParentRouteChart
,
849 IN EFI_USB_PORT_STATUS
*PortState
855 USB_DEV_ROUTE RouteChart
;
857 DEBUG ((EFI_D_INFO
, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState
->PortChangeStatus
, PortState
->PortStatus
));
859 Status
= EFI_SUCCESS
;
861 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
865 if (ParentRouteChart
.Dword
== 0) {
866 RouteChart
.Route
.RouteString
= 0;
867 RouteChart
.Route
.RootPortNum
= Port
+ 1;
868 RouteChart
.Route
.TierNum
= 1;
871 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
873 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
875 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
876 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
879 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
881 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
882 Status
= XhcPeiDisableSlotCmd (Xhc
, SlotId
);
884 Status
= XhcPeiDisableSlotCmd64 (Xhc
, SlotId
);
888 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
889 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
891 // Has a device attached, Identify device speed after port is enabled.
893 Speed
= EFI_USB_SPEED_FULL
;
894 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
895 Speed
= EFI_USB_SPEED_LOW
;
896 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
897 Speed
= EFI_USB_SPEED_HIGH
;
898 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
899 Speed
= EFI_USB_SPEED_SUPER
;
902 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
904 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
905 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
906 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
907 Status
= XhcPeiInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
909 Status
= XhcPeiInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
918 Calculate the device context index by endpoint address and direction.
920 @param EpAddr The target endpoint number.
921 @param Direction The direction of the target endpoint.
923 @return The device context index of endpoint.
927 XhcPeiEndpointToDci (
929 IN EFI_USB_DATA_DIRECTION Direction
934 ASSERT (EpAddr
<= 15);
939 Index
= (UINT8
) (2 * EpAddr
);
940 if (Direction
== EfiUsbDataIn
) {
948 Find out the actual device address according to the requested device address from UsbBus.
950 @param Xhc The XHCI device.
951 @param BusDevAddr The requested device address by UsbBus upper driver.
953 @return The actual device address assigned to the device.
957 XhcPeiBusDevAddrToSlotId (
964 for (Index
= 0; Index
< 255; Index
++) {
965 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
966 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
967 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
976 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
980 Find out the slot id according to the device's route string.
982 @param Xhc The XHCI device.
983 @param RouteString The route string described the device location.
985 @return The slot id used by the device.
989 XhcPeiRouteStringToSlotId (
991 IN USB_DEV_ROUTE RouteString
996 for (Index
= 0; Index
< 255; Index
++) {
997 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
998 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
999 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1008 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1012 Ring the door bell to notify XHCI there is a transaction to be executed.
1014 @param Xhc The XHCI device.
1015 @param SlotId The slot id of the target device.
1016 @param Dci The device context index of the target slot or endpoint.
1020 XhcPeiRingDoorBell (
1021 IN PEI_XHC_DEV
*Xhc
,
1027 XhcPeiWriteDoorBellReg (Xhc
, 0, 0);
1029 XhcPeiWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1034 Assign and initialize the device slot for a new device.
1036 @param Xhc The XHCI device.
1037 @param ParentRouteChart The route string pointed to the parent device.
1038 @param ParentPort The port at which the device is located.
1039 @param RouteChart The route string pointed to the device.
1040 @param DeviceSpeed The device speed.
1042 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1043 @retval Others Fail to initialize device slot.
1047 XhcPeiInitializeDeviceSlot (
1048 IN PEI_XHC_DEV
*Xhc
,
1049 IN USB_DEV_ROUTE ParentRouteChart
,
1050 IN UINT16 ParentPort
,
1051 IN USB_DEV_ROUTE RouteChart
,
1052 IN UINT8 DeviceSpeed
1056 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1057 INPUT_CONTEXT
*InputContext
;
1058 DEVICE_CONTEXT
*OutputContext
;
1059 TRANSFER_RING
*EndpointTransferRing
;
1060 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1061 UINT8 DeviceAddress
;
1062 CMD_TRB_ENABLE_SLOT CmdTrb
;
1065 DEVICE_CONTEXT
*ParentDeviceContext
;
1066 EFI_PHYSICAL_ADDRESS PhyAddr
;
1068 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1069 CmdTrb
.CycleBit
= 1;
1070 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1072 Status
= XhcPeiCmdTransfer (
1074 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1075 XHC_GENERIC_TIMEOUT
,
1076 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1078 if (EFI_ERROR (Status
)) {
1079 DEBUG ((EFI_D_ERROR
, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
1082 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1083 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1084 SlotId
= (UINT8
) EvtTrb
->SlotId
;
1085 ASSERT (SlotId
!= 0);
1087 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1088 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1089 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1090 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1091 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1094 // 4.3.3 Device Slot Initialization
1095 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1097 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
1098 ASSERT (InputContext
!= NULL
);
1099 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1100 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1102 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1105 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1106 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1107 // Context are affected by the command.
1109 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1112 // 3) Initialize the Input Slot Context data structure
1114 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1115 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1116 InputContext
->Slot
.ContextEntries
= 1;
1117 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1119 if (RouteChart
.Route
.RouteString
!= 0) {
1121 // The device is behind of hub device.
1123 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1124 ASSERT (ParentSlotId
!= 0);
1126 // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
1128 ParentDeviceContext
= (DEVICE_CONTEXT
*) Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1129 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1130 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1131 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1133 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1134 // environment from Full/Low speed signaling environment for a device
1136 InputContext
->Slot
.TTPortNum
= ParentPort
;
1137 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1141 // Inherit the TT parameters from parent device.
1143 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1144 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1146 // If the device is a High speed device then down the speed to be the same as its parent Hub
1148 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1149 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1155 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1157 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1158 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1159 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1161 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1163 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1165 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1166 InputContext
->EP
[0].MaxPacketSize
= 512;
1167 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1168 InputContext
->EP
[0].MaxPacketSize
= 64;
1170 InputContext
->EP
[0].MaxPacketSize
= 8;
1173 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1174 // 1KB, and Bulk and Isoch endpoints 3KB.
1176 InputContext
->EP
[0].AverageTRBLength
= 8;
1177 InputContext
->EP
[0].MaxBurstSize
= 0;
1178 InputContext
->EP
[0].Interval
= 0;
1179 InputContext
->EP
[0].MaxPStreams
= 0;
1180 InputContext
->EP
[0].Mult
= 0;
1181 InputContext
->EP
[0].CErr
= 3;
1184 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1186 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1188 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1189 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1191 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1192 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1195 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1197 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
1198 ASSERT (OutputContext
!= NULL
);
1199 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
1200 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
1202 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1204 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1205 // a pointer to the Output Device Context data structure (6.2.1).
1207 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
1209 // Fill DCBAA with PCI device address
1211 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
1214 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1215 // Context data structure described above.
1217 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1220 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY
);
1221 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1222 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1223 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1224 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1225 CmdTrbAddr
.CycleBit
= 1;
1226 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1227 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1228 Status
= XhcPeiCmdTransfer (
1230 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
1231 XHC_GENERIC_TIMEOUT
,
1232 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1234 if (!EFI_ERROR (Status
)) {
1235 DeviceAddress
= (UINT8
) OutputContext
->Slot
.DeviceAddress
;
1236 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress
));
1237 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1240 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status
));
1245 Assign and initialize the device slot for a new device.
1247 @param Xhc The XHCI device.
1248 @param ParentRouteChart The route string pointed to the parent device.
1249 @param ParentPort The port at which the device is located.
1250 @param RouteChart The route string pointed to the device.
1251 @param DeviceSpeed The device speed.
1253 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1254 @retval Others Fail to initialize device slot.
1258 XhcPeiInitializeDeviceSlot64 (
1259 IN PEI_XHC_DEV
*Xhc
,
1260 IN USB_DEV_ROUTE ParentRouteChart
,
1261 IN UINT16 ParentPort
,
1262 IN USB_DEV_ROUTE RouteChart
,
1263 IN UINT8 DeviceSpeed
1267 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1268 INPUT_CONTEXT_64
*InputContext
;
1269 DEVICE_CONTEXT_64
*OutputContext
;
1270 TRANSFER_RING
*EndpointTransferRing
;
1271 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1272 UINT8 DeviceAddress
;
1273 CMD_TRB_ENABLE_SLOT CmdTrb
;
1276 DEVICE_CONTEXT_64
*ParentDeviceContext
;
1277 EFI_PHYSICAL_ADDRESS PhyAddr
;
1279 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1280 CmdTrb
.CycleBit
= 1;
1281 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1283 Status
= XhcPeiCmdTransfer (
1285 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1286 XHC_GENERIC_TIMEOUT
,
1287 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1289 if (EFI_ERROR (Status
)) {
1290 DEBUG ((EFI_D_ERROR
, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
1293 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1294 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1295 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1296 ASSERT (SlotId
!= 0);
1298 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1299 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1300 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1301 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1302 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1305 // 4.3.3 Device Slot Initialization
1306 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1308 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
1309 ASSERT (InputContext
!= NULL
);
1310 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1311 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1313 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1316 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1317 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1318 // Context are affected by the command.
1320 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1323 // 3) Initialize the Input Slot Context data structure
1325 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1326 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1327 InputContext
->Slot
.ContextEntries
= 1;
1328 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1330 if (RouteChart
.Route
.RouteString
!= 0) {
1332 // The device is behind of hub device.
1334 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1335 ASSERT (ParentSlotId
!= 0);
1337 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1339 ParentDeviceContext
= (DEVICE_CONTEXT_64
*) Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1340 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1341 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1342 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1344 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1345 // environment from Full/Low speed signaling environment for a device
1347 InputContext
->Slot
.TTPortNum
= ParentPort
;
1348 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1352 // Inherit the TT parameters from parent device.
1354 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1355 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1357 // If the device is a High speed device then down the speed to be the same as its parent Hub
1359 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1360 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1366 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1368 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1369 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1370 XhcPeiCreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1372 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1374 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1376 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1377 InputContext
->EP
[0].MaxPacketSize
= 512;
1378 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1379 InputContext
->EP
[0].MaxPacketSize
= 64;
1381 InputContext
->EP
[0].MaxPacketSize
= 8;
1384 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1385 // 1KB, and Bulk and Isoch endpoints 3KB.
1387 InputContext
->EP
[0].AverageTRBLength
= 8;
1388 InputContext
->EP
[0].MaxBurstSize
= 0;
1389 InputContext
->EP
[0].Interval
= 0;
1390 InputContext
->EP
[0].MaxPStreams
= 0;
1391 InputContext
->EP
[0].Mult
= 0;
1392 InputContext
->EP
[0].CErr
= 3;
1395 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1397 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1399 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1400 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1402 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1403 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1406 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1408 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
1409 ASSERT (OutputContext
!= NULL
);
1410 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
1411 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1413 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1415 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1416 // a pointer to the Output Device Context data structure (6.2.1).
1418 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1420 // Fill DCBAA with PCI device address
1422 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
1425 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1426 // Context data structure described above.
1428 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
1431 MicroSecondDelay (XHC_RESET_RECOVERY_DELAY
);
1432 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1433 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1434 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1435 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1436 CmdTrbAddr
.CycleBit
= 1;
1437 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1438 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1439 Status
= XhcPeiCmdTransfer (
1441 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
1442 XHC_GENERIC_TIMEOUT
,
1443 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1445 if (!EFI_ERROR (Status
)) {
1446 DeviceAddress
= (UINT8
) OutputContext
->Slot
.DeviceAddress
;
1447 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress
));
1448 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1451 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status
));
1457 Disable the specified device slot.
1459 @param Xhc The XHCI device.
1460 @param SlotId The slot id to be disabled.
1462 @retval EFI_SUCCESS Successfully disable the device slot.
1466 XhcPeiDisableSlotCmd (
1467 IN PEI_XHC_DEV
*Xhc
,
1472 TRB_TEMPLATE
*EvtTrb
;
1473 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1478 // Disable the device slots occupied by these devices on its downstream ports.
1479 // Entry 0 is reserved.
1481 for (Index
= 0; Index
< 255; Index
++) {
1482 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1483 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1484 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
1488 Status
= XhcPeiDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1490 if (EFI_ERROR (Status
)) {
1491 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
1492 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1497 // Construct the disable slot command
1499 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId
));
1501 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1502 CmdTrbDisSlot
.CycleBit
= 1;
1503 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1504 CmdTrbDisSlot
.SlotId
= SlotId
;
1505 Status
= XhcPeiCmdTransfer (
1507 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
1508 XHC_GENERIC_TIMEOUT
,
1509 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1511 if (EFI_ERROR (Status
)) {
1512 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
1516 // Free the slot's device context entry
1518 Xhc
->DCBAA
[SlotId
] = 0;
1521 // Free the slot related data structure
1523 for (Index
= 0; Index
< 31; Index
++) {
1524 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1525 RingSeg
= ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1526 if (RingSeg
!= NULL
) {
1527 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1529 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1530 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1534 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1535 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1536 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1540 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1541 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1544 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1545 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
1548 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1549 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1550 // remove urb from XHCI's asynchronous transfer list.
1552 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1553 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1555 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status
));
1560 Disable the specified device slot.
1562 @param Xhc The XHCI device.
1563 @param SlotId The slot id to be disabled.
1565 @retval EFI_SUCCESS Successfully disable the device slot.
1569 XhcPeiDisableSlotCmd64 (
1570 IN PEI_XHC_DEV
*Xhc
,
1575 TRB_TEMPLATE
*EvtTrb
;
1576 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1581 // Disable the device slots occupied by these devices on its downstream ports.
1582 // Entry 0 is reserved.
1584 for (Index
= 0; Index
< 255; Index
++) {
1585 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1586 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1587 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
1591 Status
= XhcPeiDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1593 if (EFI_ERROR (Status
)) {
1594 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
1595 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1600 // Construct the disable slot command
1602 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId
));
1604 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1605 CmdTrbDisSlot
.CycleBit
= 1;
1606 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1607 CmdTrbDisSlot
.SlotId
= SlotId
;
1608 Status
= XhcPeiCmdTransfer (
1610 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
1611 XHC_GENERIC_TIMEOUT
,
1612 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1614 if (EFI_ERROR (Status
)) {
1615 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status
));
1619 // Free the slot's device context entry
1621 Xhc
->DCBAA
[SlotId
] = 0;
1624 // Free the slot related data structure
1626 for (Index
= 0; Index
< 31; Index
++) {
1627 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1628 RingSeg
= ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1629 if (RingSeg
!= NULL
) {
1630 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1632 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1633 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1637 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1638 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1639 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1643 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1644 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1647 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1648 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1651 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1652 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1653 // remove urb from XHCI's asynchronous transfer list.
1655 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1656 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1658 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status
));
1663 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1665 @param Xhc The XHCI device.
1666 @param SlotId The slot id to be configured.
1667 @param DeviceSpeed The device's speed.
1668 @param ConfigDesc The pointer to the usb device configuration descriptor.
1670 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1674 XhcPeiSetConfigCmd (
1675 IN PEI_XHC_DEV
*Xhc
,
1677 IN UINT8 DeviceSpeed
,
1678 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1682 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1683 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1688 EFI_USB_DATA_DIRECTION Direction
;
1691 EFI_PHYSICAL_ADDRESS PhyAddr
;
1694 TRANSFER_RING
*EndpointTransferRing
;
1695 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1696 INPUT_CONTEXT
*InputContext
;
1697 DEVICE_CONTEXT
*OutputContext
;
1698 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1700 // 4.6.6 Configure Endpoint
1702 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1703 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1704 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1705 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
1707 ASSERT (ConfigDesc
!= NULL
);
1711 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) (ConfigDesc
+ 1);
1712 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1713 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1714 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1717 NumEp
= IfDesc
->NumEndpoints
;
1719 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDesc
+ 1);
1720 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1721 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1722 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1725 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
1726 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1728 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1733 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1734 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1736 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1738 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1740 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1742 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1745 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
1746 case USB_ENDPOINT_BULK
:
1747 if (Direction
== EfiUsbDataIn
) {
1748 InputContext
->EP
[Dci
-1].CErr
= 3;
1749 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
1751 InputContext
->EP
[Dci
-1].CErr
= 3;
1752 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
1755 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1756 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1757 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1758 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1759 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1763 case USB_ENDPOINT_ISO
:
1764 if (Direction
== EfiUsbDataIn
) {
1765 InputContext
->EP
[Dci
-1].CErr
= 0;
1766 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
1768 InputContext
->EP
[Dci
-1].CErr
= 0;
1769 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
1772 // Get the bInterval from descriptor and init the the interval field of endpoint context.
1773 // Refer to XHCI 1.1 spec section 6.2.3.6.
1775 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
1776 Interval
= EpDesc
->Interval
;
1777 ASSERT (Interval
>= 1 && Interval
<= 16);
1778 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
1779 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1780 Interval
= EpDesc
->Interval
;
1781 ASSERT (Interval
>= 1 && Interval
<= 16);
1782 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1786 // Do not support isochronous transfer now.
1788 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1789 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1791 case USB_ENDPOINT_INTERRUPT
:
1792 if (Direction
== EfiUsbDataIn
) {
1793 InputContext
->EP
[Dci
-1].CErr
= 3;
1794 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
1796 InputContext
->EP
[Dci
-1].CErr
= 3;
1797 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
1799 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1800 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
1802 // Get the bInterval from descriptor and init the interval field of endpoint context
1804 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
1805 Interval
= EpDesc
->Interval
;
1807 // Calculate through the bInterval field of Endpoint descriptor.
1809 ASSERT (Interval
!= 0);
1810 InputContext
->EP
[Dci
-1].Interval
= (UINT32
) HighBitSet32 ((UINT32
) Interval
) + 3;
1811 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1812 Interval
= EpDesc
->Interval
;
1813 ASSERT (Interval
>= 1 && Interval
<= 16);
1815 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1817 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1820 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1821 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1822 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1823 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1827 case USB_ENDPOINT_CONTROL
:
1829 // Do not support control transfer now.
1831 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1833 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
1834 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1838 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1840 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
1841 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1843 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
1844 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
1845 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1846 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1848 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1850 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1853 InputContext
->InputControlContext
.Dword2
|= BIT0
;
1854 InputContext
->Slot
.ContextEntries
= MaxDci
;
1856 // configure endpoint
1858 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
1859 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
1860 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1861 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1862 CmdTrbCfgEP
.CycleBit
= 1;
1863 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
1864 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1865 DEBUG ((EFI_D_INFO
, "XhcSetConfigCmd: Configure Endpoint\n"));
1866 Status
= XhcPeiCmdTransfer (
1868 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
1869 XHC_GENERIC_TIMEOUT
,
1870 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1872 if (EFI_ERROR (Status
)) {
1873 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
1879 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1881 @param Xhc The XHCI device.
1882 @param SlotId The slot id to be configured.
1883 @param DeviceSpeed The device's speed.
1884 @param ConfigDesc The pointer to the usb device configuration descriptor.
1886 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1890 XhcPeiSetConfigCmd64 (
1891 IN PEI_XHC_DEV
*Xhc
,
1893 IN UINT8 DeviceSpeed
,
1894 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1898 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1899 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1904 EFI_USB_DATA_DIRECTION Direction
;
1907 EFI_PHYSICAL_ADDRESS PhyAddr
;
1910 TRANSFER_RING
*EndpointTransferRing
;
1911 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1912 INPUT_CONTEXT_64
*InputContext
;
1913 DEVICE_CONTEXT_64
*OutputContext
;
1914 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1916 // 4.6.6 Configure Endpoint
1918 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1919 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1920 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1921 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
1923 ASSERT (ConfigDesc
!= NULL
);
1927 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) (ConfigDesc
+ 1);
1928 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1929 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1930 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1933 NumEp
= IfDesc
->NumEndpoints
;
1935 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDesc
+ 1);
1936 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1937 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1938 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1941 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
1942 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1944 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1950 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1951 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1953 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1955 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1957 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1959 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1962 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
1963 case USB_ENDPOINT_BULK
:
1964 if (Direction
== EfiUsbDataIn
) {
1965 InputContext
->EP
[Dci
-1].CErr
= 3;
1966 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
1968 InputContext
->EP
[Dci
-1].CErr
= 3;
1969 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
1972 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1973 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1974 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1975 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1976 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1980 case USB_ENDPOINT_ISO
:
1981 if (Direction
== EfiUsbDataIn
) {
1982 InputContext
->EP
[Dci
-1].CErr
= 0;
1983 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
1985 InputContext
->EP
[Dci
-1].CErr
= 0;
1986 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
1989 // Get the bInterval from descriptor and init the the interval field of endpoint context.
1990 // Refer to XHCI 1.1 spec section 6.2.3.6.
1992 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
1993 Interval
= EpDesc
->Interval
;
1994 ASSERT (Interval
>= 1 && Interval
<= 16);
1995 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
1996 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1997 Interval
= EpDesc
->Interval
;
1998 ASSERT (Interval
>= 1 && Interval
<= 16);
1999 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2003 // Do not support isochronous transfer now.
2005 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2006 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2008 case USB_ENDPOINT_INTERRUPT
:
2009 if (Direction
== EfiUsbDataIn
) {
2010 InputContext
->EP
[Dci
-1].CErr
= 3;
2011 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2013 InputContext
->EP
[Dci
-1].CErr
= 3;
2014 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2016 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2017 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2019 // Get the bInterval from descriptor and init the the interval field of endpoint context
2021 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2022 Interval
= EpDesc
->Interval
;
2024 // Calculate through the bInterval field of Endpoint descriptor.
2026 ASSERT (Interval
!= 0);
2027 InputContext
->EP
[Dci
-1].Interval
= (UINT32
) HighBitSet32( (UINT32
) Interval
) + 3;
2028 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2029 Interval
= EpDesc
->Interval
;
2030 ASSERT (Interval
>= 1 && Interval
<= 16);
2032 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2034 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2037 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2038 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2039 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2040 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2044 case USB_ENDPOINT_CONTROL
:
2046 // Do not support control transfer now.
2048 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2050 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
2051 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2055 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2057 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2058 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2061 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2062 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2064 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2065 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2067 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
)EpDesc
+ EpDesc
->Length
);
2069 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
)IfDesc
+ IfDesc
->Length
);
2072 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2073 InputContext
->Slot
.ContextEntries
= MaxDci
;
2075 // configure endpoint
2077 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2078 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2079 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2080 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2081 CmdTrbCfgEP
.CycleBit
= 1;
2082 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2083 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2084 DEBUG ((EFI_D_INFO
, "XhcSetConfigCmd64: Configure Endpoint\n"));
2085 Status
= XhcPeiCmdTransfer (
2087 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2088 XHC_GENERIC_TIMEOUT
,
2089 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2091 if (EFI_ERROR (Status
)) {
2092 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
2100 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2102 @param Xhc The XHCI device.
2103 @param SlotId The slot id to be evaluated.
2104 @param MaxPacketSize The max packet size supported by the device control transfer.
2106 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2110 XhcPeiEvaluateContext (
2111 IN PEI_XHC_DEV
*Xhc
,
2113 IN UINT32 MaxPacketSize
2117 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2118 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2119 INPUT_CONTEXT
*InputContext
;
2120 EFI_PHYSICAL_ADDRESS PhyAddr
;
2122 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2125 // 4.6.7 Evaluate Context
2127 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2128 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2130 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2131 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2133 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2134 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2135 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2136 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2137 CmdTrbEvalu
.CycleBit
= 1;
2138 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2139 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2140 DEBUG ((EFI_D_INFO
, "XhcEvaluateContext: Evaluate context\n"));
2141 Status
= XhcPeiCmdTransfer (
2143 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2144 XHC_GENERIC_TIMEOUT
,
2145 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2147 if (EFI_ERROR (Status
)) {
2148 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
2154 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2156 @param Xhc The XHCI device.
2157 @param SlotId The slot id to be evaluated.
2158 @param MaxPacketSize The max packet size supported by the device control transfer.
2160 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2164 XhcPeiEvaluateContext64 (
2165 IN PEI_XHC_DEV
*Xhc
,
2167 IN UINT32 MaxPacketSize
2171 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2172 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2173 INPUT_CONTEXT_64
*InputContext
;
2174 EFI_PHYSICAL_ADDRESS PhyAddr
;
2176 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2179 // 4.6.7 Evaluate Context
2181 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2182 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2184 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2185 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2187 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2188 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2189 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2190 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2191 CmdTrbEvalu
.CycleBit
= 1;
2192 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2193 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2194 DEBUG ((EFI_D_INFO
, "XhcEvaluateContext64: Evaluate context 64\n"));
2195 Status
= XhcPeiCmdTransfer (
2197 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2198 XHC_GENERIC_TIMEOUT
,
2199 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2201 if (EFI_ERROR (Status
)) {
2202 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
2208 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2210 @param Xhc The XHCI device.
2211 @param SlotId The slot id to be configured.
2212 @param PortNum The total number of downstream port supported by the hub.
2213 @param TTT The TT think time of the hub device.
2214 @param MTT The multi-TT of the hub device.
2216 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2220 XhcPeiConfigHubContext (
2221 IN PEI_XHC_DEV
*Xhc
,
2229 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2230 INPUT_CONTEXT
*InputContext
;
2231 DEVICE_CONTEXT
*OutputContext
;
2232 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2233 EFI_PHYSICAL_ADDRESS PhyAddr
;
2235 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2236 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2237 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2240 // 4.6.7 Evaluate Context
2242 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2244 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2247 // Copy the slot context from OutputContext to Input context
2249 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
2250 InputContext
->Slot
.Hub
= 1;
2251 InputContext
->Slot
.PortNum
= PortNum
;
2252 InputContext
->Slot
.TTT
= TTT
;
2253 InputContext
->Slot
.MTT
= MTT
;
2255 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2256 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2257 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2258 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2259 CmdTrbCfgEP
.CycleBit
= 1;
2260 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2261 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2262 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
2263 Status
= XhcPeiCmdTransfer (
2265 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2266 XHC_GENERIC_TIMEOUT
,
2267 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2269 if (EFI_ERROR (Status
)) {
2270 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
2276 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2278 @param Xhc The XHCI device.
2279 @param SlotId The slot id to be configured.
2280 @param PortNum The total number of downstream port supported by the hub.
2281 @param TTT The TT think time of the hub device.
2282 @param MTT The multi-TT of the hub device.
2284 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2288 XhcPeiConfigHubContext64 (
2289 IN PEI_XHC_DEV
*Xhc
,
2297 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2298 INPUT_CONTEXT_64
*InputContext
;
2299 DEVICE_CONTEXT_64
*OutputContext
;
2300 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2301 EFI_PHYSICAL_ADDRESS PhyAddr
;
2303 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2304 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2305 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2308 // 4.6.7 Evaluate Context
2310 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2312 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2315 // Copy the slot context from OutputContext to Input context
2317 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
2318 InputContext
->Slot
.Hub
= 1;
2319 InputContext
->Slot
.PortNum
= PortNum
;
2320 InputContext
->Slot
.TTT
= TTT
;
2321 InputContext
->Slot
.MTT
= MTT
;
2323 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2324 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2325 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2326 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2327 CmdTrbCfgEP
.CycleBit
= 1;
2328 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2329 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2330 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context 64\n"));
2331 Status
= XhcPeiCmdTransfer (
2333 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2334 XHC_GENERIC_TIMEOUT
,
2335 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2337 if (EFI_ERROR (Status
)) {
2338 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));
2344 Stop endpoint through XHCI's Stop_Endpoint cmd.
2346 @param Xhc The XHCI device.
2347 @param SlotId The slot id of the target device.
2348 @param Dci The device context index of the target slot or endpoint.
2350 @retval EFI_SUCCESS Stop endpoint successfully.
2351 @retval Others Failed to stop endpoint.
2356 XhcPeiStopEndpoint (
2357 IN PEI_XHC_DEV
*Xhc
,
2363 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2364 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
2366 DEBUG ((EFI_D_INFO
, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
2369 // Send stop endpoint command to transit Endpoint from running to stop state
2371 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
2372 CmdTrbStopED
.CycleBit
= 1;
2373 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
2374 CmdTrbStopED
.EDID
= Dci
;
2375 CmdTrbStopED
.SlotId
= SlotId
;
2376 Status
= XhcPeiCmdTransfer (
2378 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbStopED
,
2379 XHC_GENERIC_TIMEOUT
,
2380 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2382 if (EFI_ERROR(Status
)) {
2383 DEBUG ((EFI_D_ERROR
, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
2390 Reset endpoint through XHCI's Reset_Endpoint cmd.
2392 @param Xhc The XHCI device.
2393 @param SlotId The slot id of the target device.
2394 @param Dci The device context index of the target slot or endpoint.
2396 @retval EFI_SUCCESS Reset endpoint successfully.
2397 @retval Others Failed to reset endpoint.
2402 XhcPeiResetEndpoint (
2403 IN PEI_XHC_DEV
*Xhc
,
2409 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2410 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
2412 DEBUG ((EFI_D_INFO
, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
2415 // Send stop endpoint command to transit Endpoint from running to stop state
2417 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
2418 CmdTrbResetED
.CycleBit
= 1;
2419 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
2420 CmdTrbResetED
.EDID
= Dci
;
2421 CmdTrbResetED
.SlotId
= SlotId
;
2422 Status
= XhcPeiCmdTransfer (
2424 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
2425 XHC_GENERIC_TIMEOUT
,
2426 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2428 if (EFI_ERROR(Status
)) {
2429 DEBUG ((EFI_D_ERROR
, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
2436 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
2438 @param Xhc The XHCI device.
2439 @param SlotId The slot id of the target device.
2440 @param Dci The device context index of the target slot or endpoint.
2441 @param Urb The dequeue pointer of the transfer ring specified
2442 by the urb to be updated.
2444 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
2445 @retval Others Failed to set transfer ring dequeue pointer.
2450 XhcPeiSetTrDequeuePointer (
2451 IN PEI_XHC_DEV
*Xhc
,
2458 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2459 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
2460 EFI_PHYSICAL_ADDRESS PhyAddr
;
2462 DEBUG ((EFI_D_INFO
, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
2465 // Send stop endpoint command to transit Endpoint from running to stop state
2467 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
2468 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
2469 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
2470 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2471 CmdSetTRDeq
.CycleBit
= 1;
2472 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
2473 CmdSetTRDeq
.Endpoint
= Dci
;
2474 CmdSetTRDeq
.SlotId
= SlotId
;
2475 Status
= XhcPeiCmdTransfer (
2477 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
2478 XHC_GENERIC_TIMEOUT
,
2479 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2481 if (EFI_ERROR(Status
)) {
2482 DEBUG ((EFI_D_ERROR
, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
2489 Check if there is a new generated event.
2491 @param Xhc The XHCI device.
2492 @param EvtRing The event ring to check.
2493 @param NewEvtTrb The new event TRB found.
2495 @retval EFI_SUCCESS Found a new event TRB at the event ring.
2496 @retval EFI_NOT_READY The event ring has no new event.
2500 XhcPeiCheckNewEvent (
2501 IN PEI_XHC_DEV
*Xhc
,
2502 IN EVENT_RING
*EvtRing
,
2503 OUT TRB_TEMPLATE
**NewEvtTrb
2506 ASSERT (EvtRing
!= NULL
);
2508 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
2510 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
2511 return EFI_NOT_READY
;
2514 EvtRing
->EventRingDequeue
++;
2516 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2518 if ((UINTN
) EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2519 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
2526 Synchronize the specified event ring to update the enqueue and dequeue pointer.
2528 @param Xhc The XHCI device.
2529 @param EvtRing The event ring to sync.
2531 @retval EFI_SUCCESS The event ring is synchronized successfully.
2535 XhcPeiSyncEventRing (
2536 IN PEI_XHC_DEV
*Xhc
,
2537 IN EVENT_RING
*EvtRing
2541 TRB_TEMPLATE
*EvtTrb
;
2543 ASSERT (EvtRing
!= NULL
);
2546 // Calculate the EventRingEnqueue and EventRingCCS.
2547 // Note: only support single Segment
2549 EvtTrb
= EvtRing
->EventRingDequeue
;
2551 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
2552 if (EvtTrb
->CycleBit
!= EvtRing
->EventRingCCS
) {
2558 if ((UINTN
) EvtTrb
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2559 EvtTrb
= EvtRing
->EventRingSeg0
;
2560 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
2564 if (Index
< EvtRing
->TrbNumber
) {
2565 EvtRing
->EventRingEnqueue
= EvtTrb
;
2574 Free XHCI event ring.
2576 @param Xhc The XHCI device.
2577 @param EventRing The event ring to be freed.
2581 XhcPeiFreeEventRing (
2582 IN PEI_XHC_DEV
*Xhc
,
2583 IN EVENT_RING
*EventRing
2586 if(EventRing
->EventRingSeg0
== NULL
) {
2591 // Free EventRing Segment 0
2593 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
2598 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
2602 Create XHCI event ring.
2604 @param Xhc The XHCI device.
2605 @param EventRing The created event ring.
2609 XhcPeiCreateEventRing (
2610 IN PEI_XHC_DEV
*Xhc
,
2611 OUT EVENT_RING
*EventRing
2615 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
2617 EFI_PHYSICAL_ADDRESS ERSTPhy
;
2618 EFI_PHYSICAL_ADDRESS DequeuePhy
;
2620 ASSERT (EventRing
!= NULL
);
2622 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
2623 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2624 ASSERT (Buf
!= NULL
);
2625 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2626 ZeroMem (Buf
, Size
);
2628 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2630 EventRing
->EventRingSeg0
= Buf
;
2631 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
2632 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
2633 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
2636 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
2637 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
2639 EventRing
->EventRingCCS
= 1;
2641 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
2642 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2643 ASSERT (Buf
!= NULL
);
2644 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2645 ZeroMem (Buf
, Size
);
2647 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
2648 EventRing
->ERSTBase
= ERSTBase
;
2649 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
2650 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
2651 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
2653 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2656 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
2658 XhcPeiWriteRuntimeReg (
2664 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
2666 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2667 // So divide it to two 32-bytes width register access.
2669 XhcPeiWriteRuntimeReg (
2672 XHC_LOW_32BIT ((UINT64
) (UINTN
) DequeuePhy
)
2674 XhcPeiWriteRuntimeReg (
2676 XHC_ERDP_OFFSET
+ 4,
2677 XHC_HIGH_32BIT ((UINT64
) (UINTN
) DequeuePhy
)
2680 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
2682 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2683 // So divide it to two 32-bytes width register access.
2685 XhcPeiWriteRuntimeReg (
2688 XHC_LOW_32BIT ((UINT64
) (UINTN
) ERSTPhy
)
2690 XhcPeiWriteRuntimeReg (
2692 XHC_ERSTBA_OFFSET
+ 4,
2693 XHC_HIGH_32BIT ((UINT64
) (UINTN
) ERSTPhy
)
2696 // Need set IMAN IE bit to enable the ring interrupt
2698 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
2702 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
2704 @param Xhc The XHCI device.
2705 @param TrsRing The transfer ring to sync.
2707 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
2712 IN PEI_XHC_DEV
*Xhc
,
2713 IN TRANSFER_RING
*TrsRing
2717 TRB_TEMPLATE
*TrsTrb
;
2719 ASSERT (TrsRing
!= NULL
);
2721 // Calculate the latest RingEnqueue and RingPCS
2723 TrsTrb
= TrsRing
->RingEnqueue
;
2724 ASSERT (TrsTrb
!= NULL
);
2726 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
2727 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
2731 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
2732 ASSERT (((LINK_TRB
*) TrsTrb
)->TC
!= 0);
2734 // set cycle bit in Link TRB as normal
2736 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
2738 // Toggle PCS maintained by software
2740 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
2741 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
2745 ASSERT (Index
!= TrsRing
->TrbNumber
);
2747 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
2748 TrsRing
->RingEnqueue
= TrsTrb
;
2752 // Clear the Trb context for enqueue, but reserve the PCS bit
2754 TrsTrb
->Parameter1
= 0;
2755 TrsTrb
->Parameter2
= 0;
2759 TrsTrb
->Control
= 0;
2765 Create XHCI transfer ring.
2767 @param Xhc The XHCI Device.
2768 @param TrbNum The number of TRB in the ring.
2769 @param TransferRing The created transfer ring.
2773 XhcPeiCreateTransferRing (
2774 IN PEI_XHC_DEV
*Xhc
,
2776 OUT TRANSFER_RING
*TransferRing
2781 EFI_PHYSICAL_ADDRESS PhyAddr
;
2783 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2784 ASSERT (Buf
!= NULL
);
2785 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2786 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2788 TransferRing
->RingSeg0
= Buf
;
2789 TransferRing
->TrbNumber
= TrbNum
;
2790 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
2791 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
2792 TransferRing
->RingPCS
= 1;
2794 // 4.9.2 Transfer Ring Management
2795 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
2796 // point to the first TRB in the ring.
2798 EndTrb
= (LINK_TRB
*) ((UINTN
) Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
2799 EndTrb
->Type
= TRB_TYPE_LINK
;
2800 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2801 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2802 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2804 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
2808 // Set Cycle bit as other TRB PCS init value
2810 EndTrb
->CycleBit
= 0;
2814 Initialize the XHCI host controller for schedule.
2816 @param Xhc The XHCI device to be initialized.
2825 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
2827 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
2828 UINT32 MaxScratchpadBufs
;
2830 EFI_PHYSICAL_ADDRESS ScratchPhy
;
2831 UINT64
*ScratchEntry
;
2832 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
2834 UINTN
*ScratchEntryMap
;
2838 // Initialize memory management.
2840 Xhc
->MemPool
= UsbHcInitMemPool ();
2841 ASSERT (Xhc
->MemPool
!= NULL
);
2844 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
2845 // to enable the device slots that system software is going to use.
2847 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
2848 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
2849 XhcPeiWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, (XhcPeiReadOpReg (Xhc
, XHC_CONFIG_OFFSET
) & ~XHC_CONFIG_MASK
) | Xhc
->MaxSlotsEn
);
2852 // The Device Context Base Address Array entry associated with each allocated Device Slot
2853 // shall contain a 64-bit pointer to the base of the associated Device Context.
2854 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
2855 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
2857 Size
= (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
);
2858 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2859 ASSERT (Dcbaa
!= NULL
);
2862 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
2863 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
2864 // mode (Run/Stop(R/S) ='1').
2866 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
2867 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
2868 ASSERT (MaxScratchpadBufs
<= 1023);
2869 if (MaxScratchpadBufs
!= 0) {
2871 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
2873 ScratchEntryMap
= AllocateZeroPool (sizeof (UINTN
) * MaxScratchpadBufs
);
2874 ASSERT (ScratchEntryMap
!= NULL
);
2875 Xhc
->ScratchEntryMap
= ScratchEntryMap
;
2878 // Allocate the buffer to record the host address for each entry
2880 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
2881 ASSERT (ScratchEntry
!= NULL
);
2882 Xhc
->ScratchEntry
= ScratchEntry
;
2885 Status
= UsbHcAllocateAlignedPages (
2886 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
2888 (VOID
**) &ScratchBuf
,
2892 ASSERT_EFI_ERROR (Status
);
2894 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
2895 Xhc
->ScratchBuf
= ScratchBuf
;
2898 // Allocate each scratch buffer
2900 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
2901 ScratchEntryPhy
= 0;
2902 Status
= UsbHcAllocateAlignedPages (
2903 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
2905 (VOID
**) &ScratchEntry
[Index
],
2907 (VOID
**) &ScratchEntryMap
[Index
]
2909 ASSERT_EFI_ERROR (Status
);
2910 ZeroMem ((VOID
*) (UINTN
) ScratchEntry
[Index
], Xhc
->PageSize
);
2912 // Fill with the PCI device address
2914 *ScratchBuf
++ = ScratchEntryPhy
;
2917 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
2918 // Device Context Base Address Array points to the Scratchpad Buffer Array.
2920 *(UINT64
*) Dcbaa
= (UINT64
) (UINTN
) ScratchPhy
;
2924 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
2925 // a 64-bit address pointing to where the Device Context Base Address Array is located.
2927 Xhc
->DCBAA
= (UINT64
*) (UINTN
) Dcbaa
;
2929 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2930 // So divide it to two 32-bytes width register access.
2932 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Size
);
2933 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT (DcbaaPhy
));
2934 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
2936 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc
->DCBAA
));
2939 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
2940 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
2941 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
2944 XhcPeiCreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
2946 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
2947 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
2948 // So we set RCS as inverted PCS init value to let Command Ring empty
2950 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
2951 ASSERT ((CmdRingPhy
& 0x3F) == 0);
2952 CmdRingPhy
|= XHC_CRCR_RCS
;
2954 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2955 // So divide it to two 32-bytes width register access.
2957 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT (CmdRingPhy
));
2958 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
2960 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc
->CmdRing
.RingSeg0
));
2963 // Disable the 'interrupter enable' bit in USB_CMD
2964 // and clear IE & IP bit in all Interrupter X Management Registers.
2966 XhcPeiClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
2967 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
2968 XhcPeiClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
2969 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
2973 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
2975 XhcPeiCreateEventRing (Xhc
, &Xhc
->EventRing
);
2976 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc
->EventRing
.EventRingSeg0
));
2980 Free the resouce allocated at initializing schedule.
2982 @param Xhc The XHCI device.
2991 UINT64
*ScratchEntry
;
2993 if (Xhc
->ScratchBuf
!= NULL
) {
2994 ScratchEntry
= Xhc
->ScratchEntry
;
2995 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
2997 // Free Scratchpad Buffers
2999 UsbHcFreeAlignedPages ((VOID
*) (UINTN
) ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*) Xhc
->ScratchEntryMap
[Index
]);
3002 // Free Scratchpad Buffer Array
3004 UsbHcFreeAlignedPages (Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
3005 FreePool (Xhc
->ScratchEntryMap
);
3006 FreePool (Xhc
->ScratchEntry
);
3009 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
3010 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
3011 Xhc
->CmdRing
.RingSeg0
= NULL
;
3014 XhcPeiFreeEventRing (Xhc
,&Xhc
->EventRing
);
3016 if (Xhc
->DCBAA
!= NULL
) {
3017 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
));
3022 // Free memory pool at last
3024 if (Xhc
->MemPool
!= NULL
) {
3025 UsbHcFreeMemPool (Xhc
->MemPool
);
3026 Xhc
->MemPool
= NULL
;