2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
5 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 Create a command transfer TRB to support XHCI command interfaces.
23 @param Xhc The XHCI device.
24 @param CmdTrb The cmd TRB to be executed.
26 @return Created URB or NULL.
32 IN TRB_TEMPLATE
*CmdTrb
37 Urb
= AllocateZeroPool (sizeof (URB
));
42 Urb
->Signature
= XHC_URB_SIG
;
44 Urb
->Ring
= &Xhc
->CmdRing
;
45 XhcPeiSyncTrsRing (Xhc
, Urb
->Ring
);
47 Urb
->TrbStart
= Urb
->Ring
->RingEnqueue
;
48 CopyMem (Urb
->TrbStart
, CmdTrb
, sizeof (TRB_TEMPLATE
));
49 Urb
->TrbStart
->CycleBit
= Urb
->Ring
->RingPCS
& BIT0
;
50 Urb
->TrbEnd
= Urb
->TrbStart
;
56 Execute a XHCI cmd TRB pointed by CmdTrb.
58 @param Xhc The XHCI device.
59 @param CmdTrb The cmd TRB to be executed.
60 @param Timeout Indicates the maximum time, in millisecond, which the
61 transfer is allowed to complete.
62 @param EvtTrb The event TRB corresponding to the cmd TRB.
64 @retval EFI_SUCCESS The transfer was completed successfully.
65 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
66 @retval EFI_TIMEOUT The transfer failed due to timeout.
67 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
73 IN TRB_TEMPLATE
*CmdTrb
,
75 OUT TRB_TEMPLATE
**EvtTrb
82 // Validate the parameters
84 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
85 return EFI_INVALID_PARAMETER
;
88 Status
= EFI_DEVICE_ERROR
;
90 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
91 DEBUG ((EFI_D_ERROR
, "XhcPeiCmdTransfer: HC is halted or has system error\n"));
96 // Create a new URB, then poll the execution status.
98 Urb
= XhcPeiCreateCmdTrb (Xhc
, CmdTrb
);
100 DEBUG ((EFI_D_ERROR
, "XhcPeiCmdTransfer: failed to create URB\n"));
101 Status
= EFI_OUT_OF_RESOURCES
;
105 Status
= XhcPeiExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
106 *EvtTrb
= Urb
->EvtTrb
;
108 if (Urb
->Result
== EFI_USB_NOERROR
) {
109 Status
= EFI_SUCCESS
;
112 XhcPeiFreeUrb (Xhc
, Urb
);
119 Create a new URB for a new transaction.
121 @param Xhc The XHCI device
122 @param BusAddr The logical device address assigned by UsbBus driver
123 @param EpAddr Endpoint addrress
124 @param DevSpeed The device speed
125 @param MaxPacket The max packet length of the endpoint
126 @param Type The transaction type
127 @param Request The standard USB request for control transfer
128 @param Data The user data to transfer
129 @param DataLen The length of data buffer
130 @param Callback The function to call when data is transferred
131 @param Context The context to the callback
133 @return Created URB or NULL
144 IN EFI_USB_DEVICE_REQUEST
*Request
,
147 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
155 Urb
= AllocateZeroPool (sizeof (URB
));
160 Urb
->Signature
= XHC_URB_SIG
;
163 Ep
->BusAddr
= BusAddr
;
164 Ep
->EpAddr
= (UINT8
) (EpAddr
& 0x0F);
165 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
166 Ep
->DevSpeed
= DevSpeed
;
167 Ep
->MaxPacket
= MaxPacket
;
170 Urb
->Request
= Request
;
172 Urb
->DataLen
= DataLen
;
173 Urb
->Callback
= Callback
;
174 Urb
->Context
= Context
;
176 Status
= XhcPeiCreateTransferTrb (Xhc
, Urb
);
177 if (EFI_ERROR (Status
)) {
178 DEBUG ((EFI_D_ERROR
, "XhcPeiCreateUrb: XhcPeiCreateTransferTrb Failed, Status = %r\n", Status
));
187 Free an allocated URB.
189 @param Xhc The XHCI device.
190 @param Urb The URB to free.
199 if ((Xhc
== NULL
) || (Urb
== NULL
)) {
207 Create a transfer TRB.
209 @param Xhc The XHCI device
210 @param Urb The urb used to construct the transfer TRB.
212 @return Created TRB or NULL
216 XhcPeiCreateTransferTrb (
222 TRANSFER_RING
*EPRing
;
231 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
233 return EFI_DEVICE_ERROR
;
236 Urb
->Finished
= FALSE
;
237 Urb
->StartDone
= FALSE
;
238 Urb
->EndDone
= FALSE
;
240 Urb
->Result
= EFI_USB_NOERROR
;
242 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
243 EPRing
= (TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1];
245 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
246 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
247 EPType
= (UINT8
) ((DEVICE_CONTEXT
*)OutputContext
)->EP
[Dci
-1].EPType
;
249 EPType
= (UINT8
) ((DEVICE_CONTEXT_64
*)OutputContext
)->EP
[Dci
-1].EPType
;
252 Urb
->DataPhy
= Urb
->Data
;
257 XhcPeiSyncTrsRing (Xhc
, EPRing
);
258 Urb
->TrbStart
= EPRing
->RingEnqueue
;
260 case ED_CONTROL_BIDIR
:
262 // For control transfer, create SETUP_STAGE_TRB first.
264 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
265 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
266 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
267 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
268 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
269 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
270 TrbStart
->TrbCtrSetup
.Length
= 8;
271 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
272 TrbStart
->TrbCtrSetup
.IOC
= 1;
273 TrbStart
->TrbCtrSetup
.IDT
= 1;
274 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
275 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
276 TrbStart
->TrbCtrSetup
.TRT
= 3;
277 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
278 TrbStart
->TrbCtrSetup
.TRT
= 2;
280 TrbStart
->TrbCtrSetup
.TRT
= 0;
283 // Update the cycle bit
285 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
289 // For control transfer, create DATA_STAGE_TRB.
291 if (Urb
->DataLen
> 0) {
292 XhcPeiSyncTrsRing (Xhc
, EPRing
);
293 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
294 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT (Urb
->DataPhy
);
295 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT (Urb
->DataPhy
);
296 TrbStart
->TrbCtrData
.Length
= (UINT32
) Urb
->DataLen
;
297 TrbStart
->TrbCtrData
.TDSize
= 0;
298 TrbStart
->TrbCtrData
.IntTarget
= 0;
299 TrbStart
->TrbCtrData
.ISP
= 1;
300 TrbStart
->TrbCtrData
.IOC
= 1;
301 TrbStart
->TrbCtrData
.IDT
= 0;
302 TrbStart
->TrbCtrData
.CH
= 0;
303 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
304 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
305 TrbStart
->TrbCtrData
.DIR = 1;
306 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
307 TrbStart
->TrbCtrData
.DIR = 0;
309 TrbStart
->TrbCtrData
.DIR = 0;
312 // Update the cycle bit
314 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
318 // For control transfer, create STATUS_STAGE_TRB.
319 // Get the pointer to next TRB for status stage use
321 XhcPeiSyncTrsRing (Xhc
, EPRing
);
322 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
323 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
324 TrbStart
->TrbCtrStatus
.IOC
= 1;
325 TrbStart
->TrbCtrStatus
.CH
= 0;
326 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
327 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
328 TrbStart
->TrbCtrStatus
.DIR = 0;
329 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
330 TrbStart
->TrbCtrStatus
.DIR = 1;
332 TrbStart
->TrbCtrStatus
.DIR = 0;
335 // Update the cycle bit
337 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
339 // Update the enqueue pointer
341 XhcPeiSyncTrsRing (Xhc
, EPRing
);
343 Urb
->TrbEnd
= (TRB_TEMPLATE
*) (UINTN
) TrbStart
;
352 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
353 while (TotalLen
< Urb
->DataLen
) {
354 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
355 Len
= Urb
->DataLen
- TotalLen
;
359 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
360 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
361 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
362 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
363 TrbStart
->TrbNormal
.TDSize
= 0;
364 TrbStart
->TrbNormal
.IntTarget
= 0;
365 TrbStart
->TrbNormal
.ISP
= 1;
366 TrbStart
->TrbNormal
.IOC
= 1;
367 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
369 // Update the cycle bit
371 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
373 XhcPeiSyncTrsRing (Xhc
, EPRing
);
378 Urb
->TrbNum
= TrbNum
;
379 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
382 case ED_INTERRUPT_OUT
:
383 case ED_INTERRUPT_IN
:
387 TrbStart
= (TRB
*) (UINTN
) EPRing
->RingEnqueue
;
388 while (TotalLen
< Urb
->DataLen
) {
389 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
390 Len
= Urb
->DataLen
- TotalLen
;
394 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
395 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
396 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
397 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
398 TrbStart
->TrbNormal
.TDSize
= 0;
399 TrbStart
->TrbNormal
.IntTarget
= 0;
400 TrbStart
->TrbNormal
.ISP
= 1;
401 TrbStart
->TrbNormal
.IOC
= 1;
402 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
404 // Update the cycle bit
406 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
408 XhcPeiSyncTrsRing (Xhc
, EPRing
);
413 Urb
->TrbNum
= TrbNum
;
414 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
418 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
427 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
428 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
429 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
430 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
431 Stopped to the Running state.
433 @param Xhc The XHCI device.
434 @param Urb The urb which makes the endpoint halted.
436 @retval EFI_SUCCESS The recovery is successful.
437 @retval Others Failed to recovery halted endpoint.
441 XhcPeiRecoverHaltedEndpoint (
450 Status
= EFI_SUCCESS
;
451 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
453 return EFI_DEVICE_ERROR
;
455 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
) (Urb
->Ep
.Direction
));
457 DEBUG ((EFI_D_INFO
, "XhcPeiRecoverHaltedEndpoint: Recovery Halted Slot = %x, Dci = %x\n", SlotId
, Dci
));
460 // 1) Send Reset endpoint command to transit from halt to stop state
462 Status
= XhcPeiResetEndpoint (Xhc
, SlotId
, Dci
);
463 if (EFI_ERROR(Status
)) {
464 DEBUG ((EFI_D_ERROR
, "XhcPeiRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
469 // 2) Set dequeue pointer
471 Status
= XhcPeiSetTrDequeuePointer (Xhc
, SlotId
, Dci
, Urb
);
472 if (EFI_ERROR(Status
)) {
473 DEBUG ((EFI_D_ERROR
, "XhcPeiRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
478 // 3) Ring the doorbell to transit from stop to active
480 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
487 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
488 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
489 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
492 @param Xhc The XHCI device.
493 @param Urb The urb which doesn't get completed in a specified timeout range.
495 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
496 @retval Others Failed to stop the endpoint and dequeue the TDs.
500 XhcPeiDequeueTrbFromEndpoint (
509 Status
= EFI_SUCCESS
;
510 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
512 return EFI_DEVICE_ERROR
;
514 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
) (Urb
->Ep
.Direction
));
516 DEBUG ((EFI_D_INFO
, "XhcPeiDequeueTrbFromEndpoint: Stop Slot = %x, Dci = %x\n", SlotId
, Dci
));
519 // 1) Send Stop endpoint command to stop endpoint.
521 Status
= XhcPeiStopEndpoint (Xhc
, SlotId
, Dci
);
522 if (EFI_ERROR(Status
)) {
523 DEBUG ((EFI_D_ERROR
, "XhcPeiDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
528 // 2) Set dequeue pointer
530 Status
= XhcPeiSetTrDequeuePointer (Xhc
, SlotId
, Dci
, Urb
);
531 if (EFI_ERROR(Status
)) {
532 DEBUG ((EFI_D_ERROR
, "XhcPeiDequeueTrbFromEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
537 // 3) Ring the doorbell to transit from stop to active
539 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
546 Check if the Trb is a transaction of the URB.
548 @param Trb The TRB to be checked
549 @param Urb The transfer ring to be checked.
551 @retval TRUE It is a transaction of the URB.
552 @retval FALSE It is not any transaction of the URB.
556 XhcPeiIsTransferRingTrb (
557 IN TRB_TEMPLATE
*Trb
,
561 TRB_TEMPLATE
*CheckedTrb
;
564 CheckedTrb
= Urb
->Ring
->RingSeg0
;
566 ASSERT (Urb
->Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Urb
->Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
568 for (Index
= 0; Index
< Urb
->Ring
->TrbNumber
; Index
++) {
569 if (Trb
== CheckedTrb
) {
579 Check the URB's execution result and update the URB's
582 @param Xhc The XHCI device.
583 @param Urb The URB to check result.
585 @return Whether the result of URB transfer is finialized.
589 XhcPeiCheckUrbResult (
594 EVT_TRB_TRANSFER
*EvtTrb
;
595 TRB_TEMPLATE
*TRBPtr
;
603 EFI_PHYSICAL_ADDRESS PhyAddr
;
605 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
607 Status
= EFI_SUCCESS
;
615 if (XhcPeiIsHalt (Xhc
) || XhcPeiIsSysError (Xhc
)) {
616 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
621 // Traverse the event ring to find out all new events from the previous check.
623 XhcPeiSyncEventRing (Xhc
, &Xhc
->EventRing
);
624 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
625 Status
= XhcPeiCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**) &EvtTrb
));
626 if (Status
== EFI_NOT_READY
) {
628 // All new events are handled, return directly.
634 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
636 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
641 // Need convert pci device address to host address
643 PhyAddr
= (EFI_PHYSICAL_ADDRESS
) (EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
644 TRBPtr
= (TRB_TEMPLATE
*) (UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*) (UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
647 // Update the status of Urb according to the finished event regardless of whether
648 // the urb is current checked one or in the XHCI's async transfer list.
649 // This way is used to avoid that those completed async transfer events don't get
650 // handled in time and are flushed by newer coming events.
652 if (XhcPeiIsTransferRingTrb (TRBPtr
, Urb
)) {
658 switch (EvtTrb
->Completecode
) {
659 case TRB_COMPLETION_STALL_ERROR
:
660 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
661 CheckedUrb
->Finished
= TRUE
;
662 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
665 case TRB_COMPLETION_BABBLE_ERROR
:
666 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
667 CheckedUrb
->Finished
= TRUE
;
668 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
671 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
672 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
673 CheckedUrb
->Finished
= TRUE
;
674 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb
->Completecode
));
677 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
678 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
679 CheckedUrb
->Finished
= TRUE
;
680 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb
->Completecode
));
683 case TRB_COMPLETION_SHORT_PACKET
:
684 case TRB_COMPLETION_SUCCESS
:
685 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
686 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: short packet happens!\n"));
689 TRBType
= (UINT8
) (TRBPtr
->Type
);
690 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
691 (TRBType
== TRB_TYPE_NORMAL
) ||
692 (TRBType
== TRB_TYPE_ISOCH
)) {
693 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
699 DEBUG ((EFI_D_ERROR
, "XhcPeiCheckUrbResult: Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb
->Completecode
));
700 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
701 CheckedUrb
->Finished
= TRUE
;
706 // Only check first and end Trb event address
708 if (TRBPtr
== CheckedUrb
->TrbStart
) {
709 CheckedUrb
->StartDone
= TRUE
;
712 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
713 CheckedUrb
->EndDone
= TRUE
;
716 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
717 CheckedUrb
->Finished
= TRUE
;
718 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*) EvtTrb
;
725 // Advance event ring to last available entry
727 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
728 // So divide it to two 32-bytes width register access.
730 Low
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
731 High
= XhcPeiReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
732 XhcDequeue
= (UINT64
) (LShiftU64((UINT64
) High
, 32) | Low
);
734 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
736 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
738 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
739 // So divide it to two 32-bytes width register access.
741 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
742 XhcPeiWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
745 return Urb
->Finished
;
749 Execute the transfer by polling the URB. This is a synchronous operation.
751 @param Xhc The XHCI device.
752 @param CmdTransfer The executed URB is for cmd transfer or not.
753 @param Urb The URB to execute.
754 @param Timeout The time to wait before abort, in millisecond.
756 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
757 @return EFI_TIMEOUT The transfer failed due to time out.
758 @return EFI_SUCCESS The transfer finished OK.
764 IN BOOLEAN CmdTransfer
,
780 SlotId
= XhcPeiBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
782 return EFI_DEVICE_ERROR
;
784 Dci
= XhcPeiEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
787 Status
= EFI_SUCCESS
;
788 Loop
= Timeout
* XHC_1_MILLISECOND
;
793 XhcPeiRingDoorBell (Xhc
, SlotId
, Dci
);
795 for (Index
= 0; Index
< Loop
; Index
++) {
796 Finished
= XhcPeiCheckUrbResult (Xhc
, Urb
);
800 MicroSecondDelay (XHC_1_MICROSECOND
);
804 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
805 Status
= EFI_TIMEOUT
;
806 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
807 Status
= EFI_DEVICE_ERROR
;
814 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
816 @param Xhc The XHCI device.
817 @param ParentRouteChart The route string pointed to the parent device if it exists.
818 @param Port The port to be polled.
819 @param PortState The port state.
821 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
822 @retval Others Should not appear.
826 XhcPeiPollPortStatusChange (
828 IN USB_DEV_ROUTE ParentRouteChart
,
830 IN EFI_USB_PORT_STATUS
*PortState
836 USB_DEV_ROUTE RouteChart
;
838 DEBUG ((EFI_D_INFO
, "XhcPeiPollPortStatusChange: PortChangeStatus: %x PortStatus: %x\n", PortState
->PortChangeStatus
, PortState
->PortStatus
));
840 Status
= EFI_SUCCESS
;
842 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
846 if (ParentRouteChart
.Dword
== 0) {
847 RouteChart
.Route
.RouteString
= 0;
848 RouteChart
.Route
.RootPortNum
= Port
+ 1;
849 RouteChart
.Route
.TierNum
= 1;
852 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
854 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
856 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
857 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
860 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
862 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
863 Status
= XhcPeiDisableSlotCmd (Xhc
, SlotId
);
865 Status
= XhcPeiDisableSlotCmd64 (Xhc
, SlotId
);
869 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
870 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
872 // Has a device attached, Identify device speed after port is enabled.
874 Speed
= EFI_USB_SPEED_FULL
;
875 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
876 Speed
= EFI_USB_SPEED_LOW
;
877 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
878 Speed
= EFI_USB_SPEED_HIGH
;
879 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
880 Speed
= EFI_USB_SPEED_SUPER
;
883 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
885 SlotId
= XhcPeiRouteStringToSlotId (Xhc
, RouteChart
);
886 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
887 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
888 Status
= XhcPeiInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
890 Status
= XhcPeiInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
899 Calculate the device context index by endpoint address and direction.
901 @param EpAddr The target endpoint number.
902 @param Direction The direction of the target endpoint.
904 @return The device context index of endpoint.
908 XhcPeiEndpointToDci (
910 IN EFI_USB_DATA_DIRECTION Direction
915 ASSERT (EpAddr
<= 15);
920 Index
= (UINT8
) (2 * EpAddr
);
921 if (Direction
== EfiUsbDataIn
) {
929 Find out the actual device address according to the requested device address from UsbBus.
931 @param Xhc The XHCI device.
932 @param BusDevAddr The requested device address by UsbBus upper driver.
934 @return The actual device address assigned to the device.
938 XhcPeiBusDevAddrToSlotId (
945 for (Index
= 0; Index
< 255; Index
++) {
946 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
947 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
948 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
957 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
961 Find out the slot id according to the device's route string.
963 @param Xhc The XHCI device.
964 @param RouteString The route string described the device location.
966 @return The slot id used by the device.
970 XhcPeiRouteStringToSlotId (
972 IN USB_DEV_ROUTE RouteString
977 for (Index
= 0; Index
< 255; Index
++) {
978 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
979 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
980 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
989 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
993 Ring the door bell to notify XHCI there is a transaction to be executed.
995 @param Xhc The XHCI device.
996 @param SlotId The slot id of the target device.
997 @param Dci The device context index of the target slot or endpoint.
1001 XhcPeiRingDoorBell (
1002 IN PEI_XHC_DEV
*Xhc
,
1008 XhcPeiWriteDoorBellReg (Xhc
, 0, 0);
1010 XhcPeiWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1015 Assign and initialize the device slot for a new device.
1017 @param Xhc The XHCI device.
1018 @param ParentRouteChart The route string pointed to the parent device.
1019 @param ParentPort The port at which the device is located.
1020 @param RouteChart The route string pointed to the device.
1021 @param DeviceSpeed The device speed.
1023 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1024 @retval Others Fail to initialize device slot.
1028 XhcPeiInitializeDeviceSlot (
1029 IN PEI_XHC_DEV
*Xhc
,
1030 IN USB_DEV_ROUTE ParentRouteChart
,
1031 IN UINT16 ParentPort
,
1032 IN USB_DEV_ROUTE RouteChart
,
1033 IN UINT8 DeviceSpeed
1037 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1038 INPUT_CONTEXT
*InputContext
;
1039 DEVICE_CONTEXT
*OutputContext
;
1040 TRANSFER_RING
*EndpointTransferRing
;
1041 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1042 UINT8 DeviceAddress
;
1043 CMD_TRB_ENABLE_SLOT CmdTrb
;
1046 DEVICE_CONTEXT
*ParentDeviceContext
;
1047 EFI_PHYSICAL_ADDRESS PhyAddr
;
1049 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1050 CmdTrb
.CycleBit
= 1;
1051 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1053 Status
= XhcPeiCmdTransfer (
1055 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1056 XHC_GENERIC_TIMEOUT
,
1057 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1059 if (EFI_ERROR (Status
)) {
1060 DEBUG ((EFI_D_ERROR
, "XhcPeiInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
1063 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1064 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1065 SlotId
= (UINT8
) EvtTrb
->SlotId
;
1066 ASSERT (SlotId
!= 0);
1068 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1069 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1070 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1071 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1072 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1075 // 4.3.3 Device Slot Initialization
1076 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1078 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
1079 ASSERT (InputContext
!= NULL
);
1080 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1081 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1083 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1086 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1087 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1088 // Context are affected by the command.
1090 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1093 // 3) Initialize the Input Slot Context data structure
1095 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1096 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1097 InputContext
->Slot
.ContextEntries
= 1;
1098 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1100 if (RouteChart
.Route
.RouteString
!= 0) {
1102 // The device is behind of hub device.
1104 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1105 ASSERT (ParentSlotId
!= 0);
1107 // If the Full/Low device attached to a High Speed Hub, init the TTPortNum and TTHubSlotId field of slot context
1109 ParentDeviceContext
= (DEVICE_CONTEXT
*) Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1110 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1111 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1112 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1114 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1115 // environment from Full/Low speed signaling environment for a device
1117 InputContext
->Slot
.TTPortNum
= ParentPort
;
1118 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1122 // Inherit the TT parameters from parent device.
1124 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1125 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1127 // If the device is a High speed device then down the speed to be the same as its parent Hub
1129 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1130 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1136 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1138 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1139 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1140 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1142 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1144 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1146 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1147 InputContext
->EP
[0].MaxPacketSize
= 512;
1148 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1149 InputContext
->EP
[0].MaxPacketSize
= 64;
1151 InputContext
->EP
[0].MaxPacketSize
= 8;
1154 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1155 // 1KB, and Bulk and Isoch endpoints 3KB.
1157 InputContext
->EP
[0].AverageTRBLength
= 8;
1158 InputContext
->EP
[0].MaxBurstSize
= 0;
1159 InputContext
->EP
[0].Interval
= 0;
1160 InputContext
->EP
[0].MaxPStreams
= 0;
1161 InputContext
->EP
[0].Mult
= 0;
1162 InputContext
->EP
[0].CErr
= 3;
1165 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1167 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1169 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1170 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1172 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1173 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1176 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1178 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
1179 ASSERT (OutputContext
!= NULL
);
1180 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
1181 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
1183 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1185 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1186 // a pointer to the Output Device Context data structure (6.2.1).
1188 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
1190 // Fill DCBAA with PCI device address
1192 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
1195 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1196 // Context data structure described above.
1198 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1199 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1200 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1201 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1202 CmdTrbAddr
.CycleBit
= 1;
1203 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1204 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1205 Status
= XhcPeiCmdTransfer (
1207 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
1208 XHC_GENERIC_TIMEOUT
,
1209 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1211 if (!EFI_ERROR (Status
)) {
1212 DeviceAddress
= (UINT8
) OutputContext
->Slot
.DeviceAddress
;
1213 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Address %d assigned successfully\n", DeviceAddress
));
1214 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1217 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot: Enable Slot, Status = %r\n", Status
));
1222 Assign and initialize the device slot for a new device.
1224 @param Xhc The XHCI device.
1225 @param ParentRouteChart The route string pointed to the parent device.
1226 @param ParentPort The port at which the device is located.
1227 @param RouteChart The route string pointed to the device.
1228 @param DeviceSpeed The device speed.
1230 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1231 @retval Others Fail to initialize device slot.
1235 XhcPeiInitializeDeviceSlot64 (
1236 IN PEI_XHC_DEV
*Xhc
,
1237 IN USB_DEV_ROUTE ParentRouteChart
,
1238 IN UINT16 ParentPort
,
1239 IN USB_DEV_ROUTE RouteChart
,
1240 IN UINT8 DeviceSpeed
1244 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1245 INPUT_CONTEXT_64
*InputContext
;
1246 DEVICE_CONTEXT_64
*OutputContext
;
1247 TRANSFER_RING
*EndpointTransferRing
;
1248 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1249 UINT8 DeviceAddress
;
1250 CMD_TRB_ENABLE_SLOT CmdTrb
;
1253 DEVICE_CONTEXT_64
*ParentDeviceContext
;
1254 EFI_PHYSICAL_ADDRESS PhyAddr
;
1256 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1257 CmdTrb
.CycleBit
= 1;
1258 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1260 Status
= XhcPeiCmdTransfer (
1262 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1263 XHC_GENERIC_TIMEOUT
,
1264 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1266 if (EFI_ERROR (Status
)) {
1267 DEBUG ((EFI_D_ERROR
, "XhcPeiInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
1270 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1271 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1272 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1273 ASSERT (SlotId
!= 0);
1275 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1276 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1277 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1278 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1279 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1282 // 4.3.3 Device Slot Initialization
1283 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1285 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
1286 ASSERT (InputContext
!= NULL
);
1287 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1288 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1290 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1293 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1294 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1295 // Context are affected by the command.
1297 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1300 // 3) Initialize the Input Slot Context data structure
1302 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1303 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1304 InputContext
->Slot
.ContextEntries
= 1;
1305 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1307 if (RouteChart
.Route
.RouteString
!= 0) {
1309 // The device is behind of hub device.
1311 ParentSlotId
= XhcPeiRouteStringToSlotId (Xhc
, ParentRouteChart
);
1312 ASSERT (ParentSlotId
!= 0);
1314 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1316 ParentDeviceContext
= (DEVICE_CONTEXT_64
*) Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1317 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1318 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1319 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1321 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1322 // environment from Full/Low speed signaling environment for a device
1324 InputContext
->Slot
.TTPortNum
= ParentPort
;
1325 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1329 // Inherit the TT parameters from parent device.
1331 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1332 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1334 // If the device is a High speed device then down the speed to be the same as its parent Hub
1336 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1337 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1343 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1345 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1346 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1347 XhcPeiCreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1349 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1351 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1353 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1354 InputContext
->EP
[0].MaxPacketSize
= 512;
1355 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1356 InputContext
->EP
[0].MaxPacketSize
= 64;
1358 InputContext
->EP
[0].MaxPacketSize
= 8;
1361 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1362 // 1KB, and Bulk and Isoch endpoints 3KB.
1364 InputContext
->EP
[0].AverageTRBLength
= 8;
1365 InputContext
->EP
[0].MaxBurstSize
= 0;
1366 InputContext
->EP
[0].Interval
= 0;
1367 InputContext
->EP
[0].MaxPStreams
= 0;
1368 InputContext
->EP
[0].Mult
= 0;
1369 InputContext
->EP
[0].CErr
= 3;
1372 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1374 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1376 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
1377 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1379 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
1380 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1383 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1385 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
1386 ASSERT (OutputContext
!= NULL
);
1387 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
1388 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1390 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1392 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1393 // a pointer to the Output Device Context data structure (6.2.1).
1395 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1397 // Fill DCBAA with PCI device address
1399 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
1402 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1403 // Context data structure described above.
1405 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1406 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1407 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1408 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1409 CmdTrbAddr
.CycleBit
= 1;
1410 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1411 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1412 Status
= XhcPeiCmdTransfer (
1414 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
1415 XHC_GENERIC_TIMEOUT
,
1416 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1418 if (!EFI_ERROR (Status
)) {
1419 DeviceAddress
= (UINT8
) OutputContext
->Slot
.DeviceAddress
;
1420 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Address %d assigned successfully\n", DeviceAddress
));
1421 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1424 DEBUG ((EFI_D_INFO
, "XhcPeiInitializeDeviceSlot64: Enable Slot, Status = %r\n", Status
));
1430 Disable the specified device slot.
1432 @param Xhc The XHCI device.
1433 @param SlotId The slot id to be disabled.
1435 @retval EFI_SUCCESS Successfully disable the device slot.
1439 XhcPeiDisableSlotCmd (
1440 IN PEI_XHC_DEV
*Xhc
,
1445 TRB_TEMPLATE
*EvtTrb
;
1446 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1451 // Disable the device slots occupied by these devices on its downstream ports.
1452 // Entry 0 is reserved.
1454 for (Index
= 0; Index
< 255; Index
++) {
1455 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1456 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1457 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
1461 Status
= XhcPeiDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1463 if (EFI_ERROR (Status
)) {
1464 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd: failed to disable child, ignore error\n"));
1465 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1470 // Construct the disable slot command
1472 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd: Disable device slot %d!\n", SlotId
));
1474 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1475 CmdTrbDisSlot
.CycleBit
= 1;
1476 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1477 CmdTrbDisSlot
.SlotId
= SlotId
;
1478 Status
= XhcPeiCmdTransfer (
1480 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
1481 XHC_GENERIC_TIMEOUT
,
1482 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1484 if (EFI_ERROR (Status
)) {
1485 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
1489 // Free the slot's device context entry
1491 Xhc
->DCBAA
[SlotId
] = 0;
1494 // Free the slot related data structure
1496 for (Index
= 0; Index
< 31; Index
++) {
1497 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1498 RingSeg
= ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1499 if (RingSeg
!= NULL
) {
1500 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1502 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1503 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1507 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1508 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1509 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1513 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1514 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
1517 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1518 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
1521 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1522 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1523 // remove urb from XHCI's asynchronous transfer list.
1525 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1526 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1528 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd: Disable Slot Command, Status = %r\n", Status
));
1533 Disable the specified device slot.
1535 @param Xhc The XHCI device.
1536 @param SlotId The slot id to be disabled.
1538 @retval EFI_SUCCESS Successfully disable the device slot.
1542 XhcPeiDisableSlotCmd64 (
1543 IN PEI_XHC_DEV
*Xhc
,
1548 TRB_TEMPLATE
*EvtTrb
;
1549 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
1554 // Disable the device slots occupied by these devices on its downstream ports.
1555 // Entry 0 is reserved.
1557 for (Index
= 0; Index
< 255; Index
++) {
1558 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
1559 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
1560 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
1564 Status
= XhcPeiDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
1566 if (EFI_ERROR (Status
)) {
1567 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd64: failed to disable child, ignore error\n"));
1568 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
1573 // Construct the disable slot command
1575 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd64: Disable device slot %d!\n", SlotId
));
1577 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
1578 CmdTrbDisSlot
.CycleBit
= 1;
1579 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
1580 CmdTrbDisSlot
.SlotId
= SlotId
;
1581 Status
= XhcPeiCmdTransfer (
1583 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
1584 XHC_GENERIC_TIMEOUT
,
1585 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1587 if (EFI_ERROR (Status
)) {
1588 DEBUG ((EFI_D_ERROR
, "XhcPeiDisableSlotCmd64: Disable Slot Command Failed, Status = %r\n", Status
));
1592 // Free the slot's device context entry
1594 Xhc
->DCBAA
[SlotId
] = 0;
1597 // Free the slot related data structure
1599 for (Index
= 0; Index
< 31; Index
++) {
1600 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
1601 RingSeg
= ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
1602 if (RingSeg
!= NULL
) {
1603 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
1605 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
1606 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
1610 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
1611 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
1612 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
1616 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
1617 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
1620 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
1621 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
1624 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
1625 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
1626 // remove urb from XHCI's asynchronous transfer list.
1628 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
1629 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
1631 DEBUG ((EFI_D_INFO
, "XhcPeiDisableSlotCmd64: Disable Slot Command, Status = %r\n", Status
));
1636 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1638 @param Xhc The XHCI device.
1639 @param SlotId The slot id to be configured.
1640 @param DeviceSpeed The device's speed.
1641 @param ConfigDesc The pointer to the usb device configuration descriptor.
1643 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1647 XhcPeiSetConfigCmd (
1648 IN PEI_XHC_DEV
*Xhc
,
1650 IN UINT8 DeviceSpeed
,
1651 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1655 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1656 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1661 EFI_USB_DATA_DIRECTION Direction
;
1664 EFI_PHYSICAL_ADDRESS PhyAddr
;
1667 TRANSFER_RING
*EndpointTransferRing
;
1668 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1669 INPUT_CONTEXT
*InputContext
;
1670 DEVICE_CONTEXT
*OutputContext
;
1671 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1673 // 4.6.6 Configure Endpoint
1675 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1676 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1677 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1678 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
1680 ASSERT (ConfigDesc
!= NULL
);
1684 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) (ConfigDesc
+ 1);
1685 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1686 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1687 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1690 NumEp
= IfDesc
->NumEndpoints
;
1692 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDesc
+ 1);
1693 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1694 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1695 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1698 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
1699 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1701 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1706 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1707 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1709 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1711 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1713 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1715 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1718 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
1719 case USB_ENDPOINT_BULK
:
1720 if (Direction
== EfiUsbDataIn
) {
1721 InputContext
->EP
[Dci
-1].CErr
= 3;
1722 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
1724 InputContext
->EP
[Dci
-1].CErr
= 3;
1725 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
1728 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1729 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1730 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1731 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1732 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1736 case USB_ENDPOINT_ISO
:
1737 if (Direction
== EfiUsbDataIn
) {
1738 InputContext
->EP
[Dci
-1].CErr
= 0;
1739 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
1741 InputContext
->EP
[Dci
-1].CErr
= 0;
1742 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
1745 // Do not support isochronous transfer now.
1747 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1748 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1750 case USB_ENDPOINT_INTERRUPT
:
1751 if (Direction
== EfiUsbDataIn
) {
1752 InputContext
->EP
[Dci
-1].CErr
= 3;
1753 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
1755 InputContext
->EP
[Dci
-1].CErr
= 3;
1756 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
1758 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1759 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
1761 // Get the bInterval from descriptor and init the interval field of endpoint context
1763 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
1764 Interval
= EpDesc
->Interval
;
1766 // Calculate through the bInterval field of Endpoint descriptor.
1768 ASSERT (Interval
!= 0);
1769 InputContext
->EP
[Dci
-1].Interval
= (UINT32
) HighBitSet32 ((UINT32
) Interval
) + 3;
1770 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1771 Interval
= EpDesc
->Interval
;
1772 ASSERT (Interval
>= 1 && Interval
<= 16);
1774 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1776 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1779 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1780 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1781 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1782 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1786 case USB_ENDPOINT_CONTROL
:
1788 // Do not support control transfer now.
1790 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1792 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd: Unknown EP found, Transfer ring is not allocated.\n"));
1793 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1797 PhyAddr
= UsbHcGetPciAddrForHostAddr (
1799 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
1800 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
1802 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
1803 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
1804 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1805 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1807 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1809 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1812 InputContext
->InputControlContext
.Dword2
|= BIT0
;
1813 InputContext
->Slot
.ContextEntries
= MaxDci
;
1815 // configure endpoint
1817 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
1818 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
1819 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
1820 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
1821 CmdTrbCfgEP
.CycleBit
= 1;
1822 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
1823 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1824 DEBUG ((EFI_D_INFO
, "XhcSetConfigCmd: Configure Endpoint\n"));
1825 Status
= XhcPeiCmdTransfer (
1827 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
1828 XHC_GENERIC_TIMEOUT
,
1829 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1831 if (EFI_ERROR (Status
)) {
1832 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
1838 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
1840 @param Xhc The XHCI device.
1841 @param SlotId The slot id to be configured.
1842 @param DeviceSpeed The device's speed.
1843 @param ConfigDesc The pointer to the usb device configuration descriptor.
1845 @retval EFI_SUCCESS Successfully configure all the device endpoints.
1849 XhcPeiSetConfigCmd64 (
1850 IN PEI_XHC_DEV
*Xhc
,
1852 IN UINT8 DeviceSpeed
,
1853 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
1857 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
1858 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
1863 EFI_USB_DATA_DIRECTION Direction
;
1866 EFI_PHYSICAL_ADDRESS PhyAddr
;
1869 TRANSFER_RING
*EndpointTransferRing
;
1870 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
1871 INPUT_CONTEXT_64
*InputContext
;
1872 DEVICE_CONTEXT_64
*OutputContext
;
1873 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1875 // 4.6.6 Configure Endpoint
1877 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
1878 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
1879 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1880 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
1882 ASSERT (ConfigDesc
!= NULL
);
1886 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) (ConfigDesc
+ 1);
1887 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
1888 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
1889 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
) IfDesc
+ IfDesc
->Length
);
1892 NumEp
= IfDesc
->NumEndpoints
;
1894 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDesc
+ 1);
1895 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
1896 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
1897 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
) EpDesc
+ EpDesc
->Length
);
1900 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
1901 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
1903 Dci
= XhcPeiEndpointToDci (EpAddr
, Direction
);
1909 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
1910 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
1912 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1914 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
1916 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1918 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
1921 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
1922 case USB_ENDPOINT_BULK
:
1923 if (Direction
== EfiUsbDataIn
) {
1924 InputContext
->EP
[Dci
-1].CErr
= 3;
1925 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
1927 InputContext
->EP
[Dci
-1].CErr
= 3;
1928 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
1931 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1932 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1933 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1934 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1935 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1939 case USB_ENDPOINT_ISO
:
1940 if (Direction
== EfiUsbDataIn
) {
1941 InputContext
->EP
[Dci
-1].CErr
= 0;
1942 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
1944 InputContext
->EP
[Dci
-1].CErr
= 0;
1945 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
1948 // Do not support isochronous transfer now.
1950 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
1951 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
1953 case USB_ENDPOINT_INTERRUPT
:
1954 if (Direction
== EfiUsbDataIn
) {
1955 InputContext
->EP
[Dci
-1].CErr
= 3;
1956 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
1958 InputContext
->EP
[Dci
-1].CErr
= 3;
1959 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
1961 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
1962 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
1964 // Get the bInterval from descriptor and init the the interval field of endpoint context
1966 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
1967 Interval
= EpDesc
->Interval
;
1969 // Calculate through the bInterval field of Endpoint descriptor.
1971 ASSERT (Interval
!= 0);
1972 InputContext
->EP
[Dci
-1].Interval
= (UINT32
) HighBitSet32( (UINT32
) Interval
) + 3;
1973 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
1974 Interval
= EpDesc
->Interval
;
1975 ASSERT (Interval
>= 1 && Interval
<= 16);
1977 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
1979 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
1982 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
1983 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1984 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
1985 XhcPeiCreateTransferRing (Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
1989 case USB_ENDPOINT_CONTROL
:
1991 // Do not support control transfer now.
1993 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
1995 DEBUG ((EFI_D_INFO
, "XhcPeiSetConfigCmd64: Unknown EP found, Transfer ring is not allocated.\n"));
1996 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2000 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2002 ((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2003 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2006 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2007 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*) (UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2009 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2010 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2012 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) ((UINTN
)EpDesc
+ EpDesc
->Length
);
2014 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*) ((UINTN
)IfDesc
+ IfDesc
->Length
);
2017 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2018 InputContext
->Slot
.ContextEntries
= MaxDci
;
2020 // configure endpoint
2022 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2023 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2024 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2025 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2026 CmdTrbCfgEP
.CycleBit
= 1;
2027 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2028 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2029 DEBUG ((EFI_D_INFO
, "XhcSetConfigCmd64: Configure Endpoint\n"));
2030 Status
= XhcPeiCmdTransfer (
2032 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2033 XHC_GENERIC_TIMEOUT
,
2034 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2036 if (EFI_ERROR (Status
)) {
2037 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
2045 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2047 @param Xhc The XHCI device.
2048 @param SlotId The slot id to be evaluated.
2049 @param MaxPacketSize The max packet size supported by the device control transfer.
2051 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2055 XhcPeiEvaluateContext (
2056 IN PEI_XHC_DEV
*Xhc
,
2058 IN UINT32 MaxPacketSize
2062 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2063 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2064 INPUT_CONTEXT
*InputContext
;
2065 EFI_PHYSICAL_ADDRESS PhyAddr
;
2067 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2070 // 4.6.7 Evaluate Context
2072 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2073 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2075 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2076 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2078 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2079 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2080 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2081 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2082 CmdTrbEvalu
.CycleBit
= 1;
2083 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2084 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2085 DEBUG ((EFI_D_INFO
, "XhcEvaluateContext: Evaluate context\n"));
2086 Status
= XhcPeiCmdTransfer (
2088 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2089 XHC_GENERIC_TIMEOUT
,
2090 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2092 if (EFI_ERROR (Status
)) {
2093 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
2099 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2101 @param Xhc The XHCI device.
2102 @param SlotId The slot id to be evaluated.
2103 @param MaxPacketSize The max packet size supported by the device control transfer.
2105 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2109 XhcPeiEvaluateContext64 (
2110 IN PEI_XHC_DEV
*Xhc
,
2112 IN UINT32 MaxPacketSize
2116 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2117 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2118 INPUT_CONTEXT_64
*InputContext
;
2119 EFI_PHYSICAL_ADDRESS PhyAddr
;
2121 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2124 // 4.6.7 Evaluate Context
2126 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2127 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2129 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2130 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2132 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2133 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2134 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2135 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2136 CmdTrbEvalu
.CycleBit
= 1;
2137 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2138 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2139 DEBUG ((EFI_D_INFO
, "XhcEvaluateContext64: Evaluate context 64\n"));
2140 Status
= XhcPeiCmdTransfer (
2142 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2143 XHC_GENERIC_TIMEOUT
,
2144 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2146 if (EFI_ERROR (Status
)) {
2147 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
2153 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2155 @param Xhc The XHCI device.
2156 @param SlotId The slot id to be configured.
2157 @param PortNum The total number of downstream port supported by the hub.
2158 @param TTT The TT think time of the hub device.
2159 @param MTT The multi-TT of the hub device.
2161 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2165 XhcPeiConfigHubContext (
2166 IN PEI_XHC_DEV
*Xhc
,
2174 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2175 INPUT_CONTEXT
*InputContext
;
2176 DEVICE_CONTEXT
*OutputContext
;
2177 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2178 EFI_PHYSICAL_ADDRESS PhyAddr
;
2180 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2181 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2182 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2185 // 4.6.7 Evaluate Context
2187 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2189 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2192 // Copy the slot context from OutputContext to Input context
2194 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
2195 InputContext
->Slot
.Hub
= 1;
2196 InputContext
->Slot
.PortNum
= PortNum
;
2197 InputContext
->Slot
.TTT
= TTT
;
2198 InputContext
->Slot
.MTT
= MTT
;
2200 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2201 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2202 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2203 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2204 CmdTrbCfgEP
.CycleBit
= 1;
2205 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2206 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2207 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
2208 Status
= XhcPeiCmdTransfer (
2210 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2211 XHC_GENERIC_TIMEOUT
,
2212 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2214 if (EFI_ERROR (Status
)) {
2215 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
2221 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2223 @param Xhc The XHCI device.
2224 @param SlotId The slot id to be configured.
2225 @param PortNum The total number of downstream port supported by the hub.
2226 @param TTT The TT think time of the hub device.
2227 @param MTT The multi-TT of the hub device.
2229 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2233 XhcPeiConfigHubContext64 (
2234 IN PEI_XHC_DEV
*Xhc
,
2242 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2243 INPUT_CONTEXT_64
*InputContext
;
2244 DEVICE_CONTEXT_64
*OutputContext
;
2245 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2246 EFI_PHYSICAL_ADDRESS PhyAddr
;
2248 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2249 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2250 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2253 // 4.6.7 Evaluate Context
2255 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2257 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2260 // Copy the slot context from OutputContext to Input context
2262 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
2263 InputContext
->Slot
.Hub
= 1;
2264 InputContext
->Slot
.PortNum
= PortNum
;
2265 InputContext
->Slot
.TTT
= TTT
;
2266 InputContext
->Slot
.MTT
= MTT
;
2268 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2269 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2270 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2271 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2272 CmdTrbCfgEP
.CycleBit
= 1;
2273 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2274 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2275 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context 64\n"));
2276 Status
= XhcPeiCmdTransfer (
2278 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2279 XHC_GENERIC_TIMEOUT
,
2280 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2282 if (EFI_ERROR (Status
)) {
2283 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));
2289 Stop endpoint through XHCI's Stop_Endpoint cmd.
2291 @param Xhc The XHCI device.
2292 @param SlotId The slot id of the target device.
2293 @param Dci The device context index of the target slot or endpoint.
2295 @retval EFI_SUCCESS Stop endpoint successfully.
2296 @retval Others Failed to stop endpoint.
2301 XhcPeiStopEndpoint (
2302 IN PEI_XHC_DEV
*Xhc
,
2308 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2309 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
2311 DEBUG ((EFI_D_INFO
, "XhcPeiStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
2314 // Send stop endpoint command to transit Endpoint from running to stop state
2316 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
2317 CmdTrbStopED
.CycleBit
= 1;
2318 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
2319 CmdTrbStopED
.EDID
= Dci
;
2320 CmdTrbStopED
.SlotId
= SlotId
;
2321 Status
= XhcPeiCmdTransfer (
2323 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbStopED
,
2324 XHC_GENERIC_TIMEOUT
,
2325 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2327 if (EFI_ERROR(Status
)) {
2328 DEBUG ((EFI_D_ERROR
, "XhcPeiStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
2335 Reset endpoint through XHCI's Reset_Endpoint cmd.
2337 @param Xhc The XHCI device.
2338 @param SlotId The slot id of the target device.
2339 @param Dci The device context index of the target slot or endpoint.
2341 @retval EFI_SUCCESS Reset endpoint successfully.
2342 @retval Others Failed to reset endpoint.
2347 XhcPeiResetEndpoint (
2348 IN PEI_XHC_DEV
*Xhc
,
2354 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2355 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
2357 DEBUG ((EFI_D_INFO
, "XhcPeiResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
2360 // Send stop endpoint command to transit Endpoint from running to stop state
2362 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
2363 CmdTrbResetED
.CycleBit
= 1;
2364 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
2365 CmdTrbResetED
.EDID
= Dci
;
2366 CmdTrbResetED
.SlotId
= SlotId
;
2367 Status
= XhcPeiCmdTransfer (
2369 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
2370 XHC_GENERIC_TIMEOUT
,
2371 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2373 if (EFI_ERROR(Status
)) {
2374 DEBUG ((EFI_D_ERROR
, "XhcPeiResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
2381 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
2383 @param Xhc The XHCI device.
2384 @param SlotId The slot id of the target device.
2385 @param Dci The device context index of the target slot or endpoint.
2386 @param Urb The dequeue pointer of the transfer ring specified
2387 by the urb to be updated.
2389 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
2390 @retval Others Failed to set transfer ring dequeue pointer.
2395 XhcPeiSetTrDequeuePointer (
2396 IN PEI_XHC_DEV
*Xhc
,
2403 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2404 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
2405 EFI_PHYSICAL_ADDRESS PhyAddr
;
2407 DEBUG ((EFI_D_INFO
, "XhcPeiSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
2410 // Send stop endpoint command to transit Endpoint from running to stop state
2412 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
2413 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
2414 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
2415 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2416 CmdSetTRDeq
.CycleBit
= 1;
2417 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
2418 CmdSetTRDeq
.Endpoint
= Dci
;
2419 CmdSetTRDeq
.SlotId
= SlotId
;
2420 Status
= XhcPeiCmdTransfer (
2422 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
2423 XHC_GENERIC_TIMEOUT
,
2424 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2426 if (EFI_ERROR(Status
)) {
2427 DEBUG ((EFI_D_ERROR
, "XhcPeiSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
2434 Check if there is a new generated event.
2436 @param Xhc The XHCI device.
2437 @param EvtRing The event ring to check.
2438 @param NewEvtTrb The new event TRB found.
2440 @retval EFI_SUCCESS Found a new event TRB at the event ring.
2441 @retval EFI_NOT_READY The event ring has no new event.
2445 XhcPeiCheckNewEvent (
2446 IN PEI_XHC_DEV
*Xhc
,
2447 IN EVENT_RING
*EvtRing
,
2448 OUT TRB_TEMPLATE
**NewEvtTrb
2451 ASSERT (EvtRing
!= NULL
);
2453 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
2455 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
2456 return EFI_NOT_READY
;
2459 EvtRing
->EventRingDequeue
++;
2461 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2463 if ((UINTN
) EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2464 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
2471 Synchronize the specified event ring to update the enqueue and dequeue pointer.
2473 @param Xhc The XHCI device.
2474 @param EvtRing The event ring to sync.
2476 @retval EFI_SUCCESS The event ring is synchronized successfully.
2480 XhcPeiSyncEventRing (
2481 IN PEI_XHC_DEV
*Xhc
,
2482 IN EVENT_RING
*EvtRing
2486 TRB_TEMPLATE
*EvtTrb
;
2488 ASSERT (EvtRing
!= NULL
);
2491 // Calculate the EventRingEnqueue and EventRingCCS.
2492 // Note: only support single Segment
2494 EvtTrb
= EvtRing
->EventRingDequeue
;
2496 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
2497 if (EvtTrb
->CycleBit
!= EvtRing
->EventRingCCS
) {
2503 if ((UINTN
) EvtTrb
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2504 EvtTrb
= EvtRing
->EventRingSeg0
;
2505 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
2509 if (Index
< EvtRing
->TrbNumber
) {
2510 EvtRing
->EventRingEnqueue
= EvtTrb
;
2519 Free XHCI event ring.
2521 @param Xhc The XHCI device.
2522 @param EventRing The event ring to be freed.
2526 XhcPeiFreeEventRing (
2527 IN PEI_XHC_DEV
*Xhc
,
2528 IN EVENT_RING
*EventRing
2531 if(EventRing
->EventRingSeg0
== NULL
) {
2536 // Free EventRing Segment 0
2538 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
2543 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
2547 Create XHCI event ring.
2549 @param Xhc The XHCI device.
2550 @param EventRing The created event ring.
2554 XhcPeiCreateEventRing (
2555 IN PEI_XHC_DEV
*Xhc
,
2556 OUT EVENT_RING
*EventRing
2560 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
2562 EFI_PHYSICAL_ADDRESS ERSTPhy
;
2563 EFI_PHYSICAL_ADDRESS DequeuePhy
;
2565 ASSERT (EventRing
!= NULL
);
2567 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
2568 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2569 ASSERT (Buf
!= NULL
);
2570 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2571 ZeroMem (Buf
, Size
);
2573 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2575 EventRing
->EventRingSeg0
= Buf
;
2576 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
2577 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
2578 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
2581 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
2582 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
2584 EventRing
->EventRingCCS
= 1;
2586 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
2587 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2588 ASSERT (Buf
!= NULL
);
2589 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2590 ZeroMem (Buf
, Size
);
2592 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
2593 EventRing
->ERSTBase
= ERSTBase
;
2594 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
2595 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
2596 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
2598 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
2601 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
2603 XhcPeiWriteRuntimeReg (
2609 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
2611 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2612 // So divide it to two 32-bytes width register access.
2614 XhcPeiWriteRuntimeReg (
2617 XHC_LOW_32BIT ((UINT64
) (UINTN
) DequeuePhy
)
2619 XhcPeiWriteRuntimeReg (
2621 XHC_ERDP_OFFSET
+ 4,
2622 XHC_HIGH_32BIT ((UINT64
) (UINTN
) DequeuePhy
)
2625 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register (5.5.2.3.2)
2627 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2628 // So divide it to two 32-bytes width register access.
2630 XhcPeiWriteRuntimeReg (
2633 XHC_LOW_32BIT ((UINT64
) (UINTN
) ERSTPhy
)
2635 XhcPeiWriteRuntimeReg (
2637 XHC_ERSTBA_OFFSET
+ 4,
2638 XHC_HIGH_32BIT ((UINT64
) (UINTN
) ERSTPhy
)
2641 // Need set IMAN IE bit to enable the ring interrupt
2643 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
2647 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
2649 @param Xhc The XHCI device.
2650 @param TrsRing The transfer ring to sync.
2652 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
2657 IN PEI_XHC_DEV
*Xhc
,
2658 IN TRANSFER_RING
*TrsRing
2662 TRB_TEMPLATE
*TrsTrb
;
2664 ASSERT (TrsRing
!= NULL
);
2666 // Calculate the latest RingEnqueue and RingPCS
2668 TrsTrb
= TrsRing
->RingEnqueue
;
2669 ASSERT (TrsTrb
!= NULL
);
2671 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
2672 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
2676 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
2677 ASSERT (((LINK_TRB
*) TrsTrb
)->TC
!= 0);
2679 // set cycle bit in Link TRB as normal
2681 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
2683 // Toggle PCS maintained by software
2685 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
2686 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
2690 ASSERT (Index
!= TrsRing
->TrbNumber
);
2692 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
2693 TrsRing
->RingEnqueue
= TrsTrb
;
2697 // Clear the Trb context for enqueue, but reserve the PCS bit
2699 TrsTrb
->Parameter1
= 0;
2700 TrsTrb
->Parameter2
= 0;
2704 TrsTrb
->Control
= 0;
2710 Create XHCI transfer ring.
2712 @param Xhc The XHCI Device.
2713 @param TrbNum The number of TRB in the ring.
2714 @param TransferRing The created transfer ring.
2718 XhcPeiCreateTransferRing (
2719 IN PEI_XHC_DEV
*Xhc
,
2721 OUT TRANSFER_RING
*TransferRing
2726 EFI_PHYSICAL_ADDRESS PhyAddr
;
2728 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2729 ASSERT (Buf
!= NULL
);
2730 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
2731 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2733 TransferRing
->RingSeg0
= Buf
;
2734 TransferRing
->TrbNumber
= TrbNum
;
2735 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
2736 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
2737 TransferRing
->RingPCS
= 1;
2739 // 4.9.2 Transfer Ring Management
2740 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
2741 // point to the first TRB in the ring.
2743 EndTrb
= (LINK_TRB
*) ((UINTN
) Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
2744 EndTrb
->Type
= TRB_TYPE_LINK
;
2745 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
2746 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2747 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2749 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
2753 // Set Cycle bit as other TRB PCS init value
2755 EndTrb
->CycleBit
= 0;
2759 Initialize the XHCI host controller for schedule.
2761 @param Xhc The XHCI device to be initialized.
2770 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
2772 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
2773 UINT32 MaxScratchpadBufs
;
2775 EFI_PHYSICAL_ADDRESS ScratchPhy
;
2776 UINT64
*ScratchEntry
;
2777 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
2782 // Initialize memory management.
2784 Xhc
->MemPool
= UsbHcInitMemPool ();
2785 ASSERT (Xhc
->MemPool
!= NULL
);
2788 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
2789 // to enable the device slots that system software is going to use.
2791 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
2792 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
2793 XhcPeiWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, (XhcPeiReadOpReg (Xhc
, XHC_CONFIG_OFFSET
) & ~XHC_CONFIG_MASK
) | Xhc
->MaxSlotsEn
);
2796 // The Device Context Base Address Array entry associated with each allocated Device Slot
2797 // shall contain a 64-bit pointer to the base of the associated Device Context.
2798 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
2799 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
2801 Size
= (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
);
2802 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
2803 ASSERT (Dcbaa
!= NULL
);
2806 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
2807 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
2808 // mode (Run/Stop(R/S) ='1').
2810 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
2811 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
2812 ASSERT (MaxScratchpadBufs
<= 1023);
2813 if (MaxScratchpadBufs
!= 0) {
2815 // Allocate the buffer to record the host address for each entry
2817 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
2818 ASSERT (ScratchEntry
!= NULL
);
2819 Xhc
->ScratchEntry
= ScratchEntry
;
2822 Status
= UsbHcAllocateAlignedPages (
2823 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
2825 (VOID
**) &ScratchBuf
,
2828 ASSERT_EFI_ERROR (Status
);
2830 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
2831 Xhc
->ScratchBuf
= ScratchBuf
;
2834 // Allocate each scratch buffer
2836 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
2837 ScratchEntryPhy
= 0;
2838 Status
= UsbHcAllocateAlignedPages (
2839 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
2841 (VOID
**) &ScratchEntry
[Index
],
2844 ASSERT_EFI_ERROR (Status
);
2845 ZeroMem ((VOID
*) (UINTN
) ScratchEntry
[Index
], Xhc
->PageSize
);
2847 // Fill with the PCI device address
2849 *ScratchBuf
++ = ScratchEntryPhy
;
2852 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
2853 // Device Context Base Address Array points to the Scratchpad Buffer Array.
2855 *(UINT64
*) Dcbaa
= (UINT64
) (UINTN
) ScratchPhy
;
2859 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
2860 // a 64-bit address pointing to where the Device Context Base Address Array is located.
2862 Xhc
->DCBAA
= (UINT64
*) (UINTN
) Dcbaa
;
2864 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2865 // So divide it to two 32-bytes width register access.
2867 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Size
);
2868 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT (DcbaaPhy
));
2869 XhcPeiWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
2871 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:DCBAA=0x%x\n", Xhc
->DCBAA
));
2874 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
2875 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
2876 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
2879 XhcPeiCreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
2881 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
2882 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
2883 // So we set RCS as inverted PCS init value to let Command Ring empty
2885 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
2886 ASSERT ((CmdRingPhy
& 0x3F) == 0);
2887 CmdRingPhy
|= XHC_CRCR_RCS
;
2889 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
2890 // So divide it to two 32-bytes width register access.
2892 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT (CmdRingPhy
));
2893 XhcPeiWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
2895 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:XHC_CRCR=0x%x\n", Xhc
->CmdRing
.RingSeg0
));
2898 // Disable the 'interrupter enable' bit in USB_CMD
2899 // and clear IE & IP bit in all Interrupter X Management Registers.
2901 XhcPeiClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
2902 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
2903 XhcPeiClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
2904 XhcPeiSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
2908 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
2910 XhcPeiCreateEventRing (Xhc
, &Xhc
->EventRing
);
2911 DEBUG ((EFI_D_INFO
, "XhcPeiInitSched:XHC_EVENTRING=0x%x\n", Xhc
->EventRing
.EventRingSeg0
));
2915 Free the resouce allocated at initializing schedule.
2917 @param Xhc The XHCI device.
2926 UINT64
*ScratchEntry
;
2928 if (Xhc
->ScratchBuf
!= NULL
) {
2929 ScratchEntry
= Xhc
->ScratchEntry
;
2930 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
2932 // Free Scratchpad Buffers
2934 UsbHcFreeAlignedPages ((VOID
*) (UINTN
) ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
));
2937 // Free Scratchpad Buffer Array
2939 UsbHcFreeAlignedPages (Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)));
2940 FreePool (Xhc
->ScratchEntry
);
2943 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
2944 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
2945 Xhc
->CmdRing
.RingSeg0
= NULL
;
2948 XhcPeiFreeEventRing (Xhc
,&Xhc
->EventRing
);
2950 if (Xhc
->DCBAA
!= NULL
) {
2951 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof (UINT64
));
2956 // Free memory pool at last
2958 if (Xhc
->MemPool
!= NULL
) {
2959 UsbHcFreeMemPool (Xhc
->MemPool
);
2960 Xhc
->MemPool
= NULL
;