3 XHCI transfer scheduling routines.
5 Copyright (c) 2011 - 2020, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) Microsoft Corporation.<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 Instance.
17 @param CmdTrb The cmd TRB to be executed.
19 @return Created URB or NULL.
24 IN USB_XHCI_INSTANCE
*Xhc
,
25 IN TRB_TEMPLATE
*CmdTrb
30 Urb
= AllocateZeroPool (sizeof (URB
));
35 Urb
->Signature
= XHC_URB_SIG
;
37 Urb
->Ring
= &Xhc
->CmdRing
;
38 XhcSyncTrsRing (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 Instance.
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 USB_XHCI_INSTANCE
*Xhc
,
67 IN TRB_TEMPLATE
*CmdTrb
,
69 OUT TRB_TEMPLATE
**EvtTrb
76 // Validate the parameters
78 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
79 return EFI_INVALID_PARAMETER
;
82 Status
= EFI_DEVICE_ERROR
;
84 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
85 DEBUG ((DEBUG_ERROR
, "XhcCmdTransfer: HC is halted\n"));
90 // Create a new URB, then poll the execution status.
92 Urb
= XhcCreateCmdTrb (Xhc
, CmdTrb
);
95 DEBUG ((DEBUG_ERROR
, "XhcCmdTransfer: failed to create URB\n"));
96 Status
= EFI_OUT_OF_RESOURCES
;
100 Status
= XhcExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
101 *EvtTrb
= Urb
->EvtTrb
;
103 if (Urb
->Result
== EFI_USB_NOERROR
) {
104 Status
= EFI_SUCCESS
;
107 XhcFreeUrb (Xhc
, Urb
);
114 Create a new URB for a new transaction.
116 @param Xhc The XHCI Instance
117 @param BusAddr The logical device address assigned by UsbBus driver
118 @param EpAddr Endpoint addrress
119 @param DevSpeed The device speed
120 @param MaxPacket The max packet length of the endpoint
121 @param Type The transaction type
122 @param Request The standard USB request for control transfer
123 @param Data The user data to transfer
124 @param DataLen The length of data buffer
125 @param Callback The function to call when data is transferred
126 @param Context The context to the callback
128 @return Created URB or NULL
133 IN USB_XHCI_INSTANCE
*Xhc
,
139 IN EFI_USB_DEVICE_REQUEST
*Request
,
142 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
150 Urb
= AllocateZeroPool (sizeof (URB
));
155 Urb
->Signature
= XHC_URB_SIG
;
156 InitializeListHead (&Urb
->UrbList
);
159 Ep
->BusAddr
= BusAddr
;
160 Ep
->EpAddr
= (UINT8
)(EpAddr
& 0x0F);
161 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
162 Ep
->DevSpeed
= DevSpeed
;
163 Ep
->MaxPacket
= MaxPacket
;
166 Urb
->Request
= Request
;
168 Urb
->DataLen
= DataLen
;
169 Urb
->Callback
= Callback
;
170 Urb
->Context
= Context
;
172 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
173 ASSERT_EFI_ERROR (Status
);
174 if (EFI_ERROR (Status
)) {
175 DEBUG ((DEBUG_ERROR
, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status
));
184 Free an allocated URB.
186 @param Xhc The XHCI device.
187 @param Urb The URB to free.
192 IN USB_XHCI_INSTANCE
*Xhc
,
196 if ((Xhc
== NULL
) || (Urb
== NULL
)) {
200 if (Urb
->DataMap
!= NULL
) {
201 Xhc
->PciIo
->Unmap (Xhc
->PciIo
, Urb
->DataMap
);
208 Create a transfer TRB.
210 @param Xhc The XHCI Instance
211 @param Urb The urb used to construct the transfer TRB.
213 @return Created TRB or NULL
217 XhcCreateTransferTrb (
218 IN USB_XHCI_INSTANCE
*Xhc
,
223 TRANSFER_RING
*EPRing
;
231 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
232 EFI_PHYSICAL_ADDRESS PhyAddr
;
236 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
238 return EFI_DEVICE_ERROR
;
241 Urb
->Finished
= FALSE
;
242 Urb
->StartDone
= FALSE
;
243 Urb
->EndDone
= FALSE
;
245 Urb
->Result
= EFI_USB_NOERROR
;
247 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
249 EPRing
= (TRANSFER_RING
*)(UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1];
251 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
252 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
253 EPType
= (UINT8
) ((DEVICE_CONTEXT
*)OutputContext
)->EP
[Dci
-1].EPType
;
255 EPType
= (UINT8
) ((DEVICE_CONTEXT_64
*)OutputContext
)->EP
[Dci
-1].EPType
;
261 if ((Urb
->Data
!= NULL
) && (Urb
->DataMap
== NULL
)) {
262 if (((UINT8
) (Urb
->Ep
.Direction
)) == EfiUsbDataIn
) {
263 MapOp
= EfiPciIoOperationBusMasterWrite
;
265 MapOp
= EfiPciIoOperationBusMasterRead
;
269 Status
= Xhc
->PciIo
->Map (Xhc
->PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
271 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
272 DEBUG ((DEBUG_ERROR
, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
273 return EFI_OUT_OF_RESOURCES
;
276 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
283 XhcSyncTrsRing (Xhc
, EPRing
);
284 Urb
->TrbStart
= EPRing
->RingEnqueue
;
286 case ED_CONTROL_BIDIR
:
288 // For control transfer, create SETUP_STAGE_TRB first.
290 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
291 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
292 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
293 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
294 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
295 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
296 TrbStart
->TrbCtrSetup
.Length
= 8;
297 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
298 TrbStart
->TrbCtrSetup
.IOC
= 1;
299 TrbStart
->TrbCtrSetup
.IDT
= 1;
300 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
301 if (Urb
->DataLen
> 0) {
302 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
303 TrbStart
->TrbCtrSetup
.TRT
= 3;
304 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
305 TrbStart
->TrbCtrSetup
.TRT
= 2;
307 DEBUG ((DEBUG_ERROR
, "XhcCreateTransferTrb: Direction sholud be IN or OUT when Data exists!\n"));
311 TrbStart
->TrbCtrSetup
.TRT
= 0;
314 // Update the cycle bit
316 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
320 // For control transfer, create DATA_STAGE_TRB.
322 if (Urb
->DataLen
> 0) {
323 XhcSyncTrsRing (Xhc
, EPRing
);
324 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
325 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT(Urb
->DataPhy
);
326 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT(Urb
->DataPhy
);
327 TrbStart
->TrbCtrData
.Length
= (UINT32
) Urb
->DataLen
;
328 TrbStart
->TrbCtrData
.TDSize
= 0;
329 TrbStart
->TrbCtrData
.IntTarget
= 0;
330 TrbStart
->TrbCtrData
.ISP
= 1;
331 TrbStart
->TrbCtrData
.IOC
= 1;
332 TrbStart
->TrbCtrData
.IDT
= 0;
333 TrbStart
->TrbCtrData
.CH
= 0;
334 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
335 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
336 TrbStart
->TrbCtrData
.DIR = 1;
337 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
338 TrbStart
->TrbCtrData
.DIR = 0;
340 TrbStart
->TrbCtrData
.DIR = 0;
343 // Update the cycle bit
345 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
349 // For control transfer, create STATUS_STAGE_TRB.
350 // Get the pointer to next TRB for status stage use
352 XhcSyncTrsRing (Xhc
, EPRing
);
353 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
354 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
355 TrbStart
->TrbCtrStatus
.IOC
= 1;
356 TrbStart
->TrbCtrStatus
.CH
= 0;
357 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
358 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
359 TrbStart
->TrbCtrStatus
.DIR = 0;
360 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
361 TrbStart
->TrbCtrStatus
.DIR = 1;
363 TrbStart
->TrbCtrStatus
.DIR = 0;
366 // Update the cycle bit
368 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
370 // Update the enqueue pointer
372 XhcSyncTrsRing (Xhc
, EPRing
);
374 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
383 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
384 while (TotalLen
< Urb
->DataLen
) {
385 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
386 Len
= Urb
->DataLen
- TotalLen
;
390 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
391 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
392 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
393 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
394 TrbStart
->TrbNormal
.TDSize
= 0;
395 TrbStart
->TrbNormal
.IntTarget
= 0;
396 TrbStart
->TrbNormal
.ISP
= 1;
397 TrbStart
->TrbNormal
.IOC
= 1;
398 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
400 // Update the cycle bit
402 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
404 XhcSyncTrsRing (Xhc
, EPRing
);
409 Urb
->TrbNum
= TrbNum
;
410 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
413 case ED_INTERRUPT_OUT
:
414 case ED_INTERRUPT_IN
:
418 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
419 while (TotalLen
< Urb
->DataLen
) {
420 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
421 Len
= Urb
->DataLen
- TotalLen
;
425 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
426 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
427 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
428 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
429 TrbStart
->TrbNormal
.TDSize
= 0;
430 TrbStart
->TrbNormal
.IntTarget
= 0;
431 TrbStart
->TrbNormal
.ISP
= 1;
432 TrbStart
->TrbNormal
.IOC
= 1;
433 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
435 // Update the cycle bit
437 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
439 XhcSyncTrsRing (Xhc
, EPRing
);
444 Urb
->TrbNum
= TrbNum
;
445 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
449 DEBUG ((DEBUG_INFO
, "Not supported EPType 0x%x!\n",EPType
));
459 Initialize the XHCI host controller for schedule.
461 @param Xhc The XHCI Instance to be initialized.
466 IN USB_XHCI_INSTANCE
*Xhc
470 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
472 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
474 UINT32 MaxScratchpadBufs
;
476 EFI_PHYSICAL_ADDRESS ScratchPhy
;
477 UINT64
*ScratchEntry
;
478 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
480 UINTN
*ScratchEntryMap
;
484 // Initialize memory management.
486 Xhc
->MemPool
= UsbHcInitMemPool (Xhc
->PciIo
);
487 ASSERT (Xhc
->MemPool
!= NULL
);
490 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
491 // to enable the device slots that system software is going to use.
493 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
494 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
495 XhcWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, Xhc
->MaxSlotsEn
);
498 // The Device Context Base Address Array entry associated with each allocated Device Slot
499 // shall contain a 64-bit pointer to the base of the associated Device Context.
500 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
501 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
503 Entries
= (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
);
504 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Entries
);
505 ASSERT (Dcbaa
!= NULL
);
506 ZeroMem (Dcbaa
, Entries
);
509 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
510 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
511 // mode (Run/Stop(R/S) ='1').
513 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
514 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
515 ASSERT (MaxScratchpadBufs
<= 1023);
516 if (MaxScratchpadBufs
!= 0) {
518 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
520 ScratchEntryMap
= AllocateZeroPool (sizeof (UINTN
) * MaxScratchpadBufs
);
521 ASSERT (ScratchEntryMap
!= NULL
);
522 Xhc
->ScratchEntryMap
= ScratchEntryMap
;
525 // Allocate the buffer to record the host address for each entry
527 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
528 ASSERT (ScratchEntry
!= NULL
);
529 Xhc
->ScratchEntry
= ScratchEntry
;
532 Status
= UsbHcAllocateAlignedPages (
534 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
536 (VOID
**) &ScratchBuf
,
540 ASSERT_EFI_ERROR (Status
);
542 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
543 Xhc
->ScratchBuf
= ScratchBuf
;
546 // Allocate each scratch buffer
548 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
550 Status
= UsbHcAllocateAlignedPages (
552 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
554 (VOID
**) &ScratchEntry
[Index
],
556 (VOID
**) &ScratchEntryMap
[Index
]
558 ASSERT_EFI_ERROR (Status
);
559 ZeroMem ((VOID
*)(UINTN
)ScratchEntry
[Index
], Xhc
->PageSize
);
561 // Fill with the PCI device address
563 *ScratchBuf
++ = ScratchEntryPhy
;
566 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
567 // Device Context Base Address Array points to the Scratchpad Buffer Array.
569 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
) ScratchPhy
;
573 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
574 // a 64-bit address pointing to where the Device Context Base Address Array is located.
576 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
578 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
579 // So divide it to two 32-bytes width register access.
581 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Entries
);
582 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT(DcbaaPhy
));
583 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
585 DEBUG ((DEBUG_INFO
, "XhcInitSched:DCBAA=0x%x\n", (UINT64
)(UINTN
)Xhc
->DCBAA
));
588 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
589 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
590 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
593 CreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
595 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
596 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
597 // So we set RCS as inverted PCS init value to let Command Ring empty
599 CmdRing
= (UINT64
)(UINTN
)Xhc
->CmdRing
.RingSeg0
;
600 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) CmdRing
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
601 ASSERT ((CmdRingPhy
& 0x3F) == 0);
602 CmdRingPhy
|= XHC_CRCR_RCS
;
604 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
605 // So divide it to two 32-bytes width register access.
607 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT(CmdRingPhy
));
608 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
611 // Disable the 'interrupter enable' bit in USB_CMD
612 // and clear IE & IP bit in all Interrupter X Management Registers.
614 XhcClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
615 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
616 XhcClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
617 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
621 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
623 CreateEventRing (Xhc
, &Xhc
->EventRing
);
624 DEBUG ((DEBUG_INFO
, "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",
625 Xhc
->CmdRing
.RingSeg0
, (UINTN
)Xhc
->CmdRing
.RingSeg0
+ sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
,
626 Xhc
->EventRing
.EventRingSeg0
, (UINTN
)Xhc
->EventRing
.EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
631 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
632 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
633 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
634 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
635 Stopped to the Running state.
637 @param Xhc The XHCI Instance.
638 @param Urb The urb which makes the endpoint halted.
640 @retval EFI_SUCCESS The recovery is successful.
641 @retval Others Failed to recovery halted endpoint.
646 XhcRecoverHaltedEndpoint (
647 IN USB_XHCI_INSTANCE
*Xhc
,
655 Status
= EFI_SUCCESS
;
656 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
658 return EFI_DEVICE_ERROR
;
660 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
663 DEBUG ((DEBUG_INFO
, "Recovery Halted Slot = %x,Dci = %x\n", SlotId
, Dci
));
666 // 1) Send Reset endpoint command to transit from halt to stop state
668 Status
= XhcResetEndpoint(Xhc
, SlotId
, Dci
);
669 if (EFI_ERROR(Status
)) {
670 DEBUG ((DEBUG_ERROR
, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
675 // 2)Set dequeue pointer
677 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
678 if (EFI_ERROR(Status
)) {
679 DEBUG ((DEBUG_ERROR
, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
684 // 3)Ring the doorbell to transit from stop to active
686 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
693 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
694 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
695 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
698 @param Xhc The XHCI Instance.
699 @param Urb The urb which doesn't get completed in a specified timeout range.
701 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
702 @retval EFI_ALREADY_STARTED The Urb is finished so no deque is needed.
703 @retval Others Failed to stop the endpoint and dequeue the TDs.
708 XhcDequeueTrbFromEndpoint (
709 IN USB_XHCI_INSTANCE
*Xhc
,
717 Status
= EFI_SUCCESS
;
718 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
720 return EFI_DEVICE_ERROR
;
722 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
725 DEBUG ((DEBUG_INFO
, "Stop Slot = %x,Dci = %x\n", SlotId
, Dci
));
728 // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint
730 Status
= XhcStopEndpoint(Xhc
, SlotId
, Dci
, Urb
);
731 if (EFI_ERROR(Status
)) {
732 DEBUG ((DEBUG_ERROR
, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
737 // 2)Set dequeue pointer
739 if (Urb
->Finished
&& Urb
->Result
== EFI_USB_NOERROR
) {
741 // Return Already Started to indicate the pending URB is finished.
742 // This fixes BULK data loss when transfer is detected as timeout
743 // but finished just before stopping endpoint.
745 Status
= EFI_ALREADY_STARTED
;
746 DEBUG ((DEBUG_INFO
, "XhcDequeueTrbFromEndpoint: Pending URB is finished: Length Actual/Expect = %d/%d!\n", Urb
->Completed
, Urb
->DataLen
));
748 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
749 if (EFI_ERROR (Status
)) {
750 DEBUG ((DEBUG_ERROR
, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
756 // 3)Ring the doorbell to transit from stop to active
758 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
765 Create XHCI event ring.
767 @param Xhc The XHCI Instance.
768 @param EventRing The created event ring.
773 IN USB_XHCI_INSTANCE
*Xhc
,
774 OUT EVENT_RING
*EventRing
778 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
780 EFI_PHYSICAL_ADDRESS ERSTPhy
;
781 EFI_PHYSICAL_ADDRESS DequeuePhy
;
783 ASSERT (EventRing
!= NULL
);
785 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
786 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
787 ASSERT (Buf
!= NULL
);
788 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
791 EventRing
->EventRingSeg0
= Buf
;
792 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
793 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
794 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
796 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
799 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
800 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
802 EventRing
->EventRingCCS
= 1;
804 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
805 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
806 ASSERT (Buf
!= NULL
);
807 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
810 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
811 EventRing
->ERSTBase
= ERSTBase
;
812 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
813 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
814 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
816 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, ERSTBase
, Size
);
819 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
827 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
829 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
830 // So divide it to two 32-bytes width register access.
835 XHC_LOW_32BIT((UINT64
)(UINTN
)DequeuePhy
)
840 XHC_HIGH_32BIT((UINT64
)(UINTN
)DequeuePhy
)
843 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
845 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
846 // So divide it to two 32-bytes width register access.
851 XHC_LOW_32BIT((UINT64
)(UINTN
)ERSTPhy
)
855 XHC_ERSTBA_OFFSET
+ 4,
856 XHC_HIGH_32BIT((UINT64
)(UINTN
)ERSTPhy
)
859 // Need set IMAN IE bit to enble the ring interrupt
861 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
865 Create XHCI transfer ring.
867 @param Xhc The XHCI Instance.
868 @param TrbNum The number of TRB in the ring.
869 @param TransferRing The created transfer ring.
874 IN USB_XHCI_INSTANCE
*Xhc
,
876 OUT TRANSFER_RING
*TransferRing
881 EFI_PHYSICAL_ADDRESS PhyAddr
;
883 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
884 ASSERT (Buf
!= NULL
);
885 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
886 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
888 TransferRing
->RingSeg0
= Buf
;
889 TransferRing
->TrbNumber
= TrbNum
;
890 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
891 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
892 TransferRing
->RingPCS
= 1;
894 // 4.9.2 Transfer Ring Management
895 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
896 // point to the first TRB in the ring.
898 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
899 EndTrb
->Type
= TRB_TYPE_LINK
;
900 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
901 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
902 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
904 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
908 // Set Cycle bit as other TRB PCS init value
910 EndTrb
->CycleBit
= 0;
914 Free XHCI event ring.
916 @param Xhc The XHCI Instance.
917 @param EventRing The event ring to be freed.
923 IN USB_XHCI_INSTANCE
*Xhc
,
924 IN EVENT_RING
*EventRing
927 if(EventRing
->EventRingSeg0
== NULL
) {
932 // Free EventRing Segment 0
934 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
939 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
944 Free the resouce allocated at initializing schedule.
946 @param Xhc The XHCI Instance.
951 IN USB_XHCI_INSTANCE
*Xhc
955 UINT64
*ScratchEntry
;
957 if (Xhc
->ScratchBuf
!= NULL
) {
958 ScratchEntry
= Xhc
->ScratchEntry
;
959 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
961 // Free Scratchpad Buffers
963 UsbHcFreeAlignedPages (Xhc
->PciIo
, (VOID
*)(UINTN
)ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*) Xhc
->ScratchEntryMap
[Index
]);
966 // Free Scratchpad Buffer Array
968 UsbHcFreeAlignedPages (Xhc
->PciIo
, Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
969 FreePool (Xhc
->ScratchEntryMap
);
970 FreePool (Xhc
->ScratchEntry
);
973 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
974 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
975 Xhc
->CmdRing
.RingSeg0
= NULL
;
978 XhcFreeEventRing (Xhc
,&Xhc
->EventRing
);
980 if (Xhc
->DCBAA
!= NULL
) {
981 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
));
986 // Free memory pool at last
988 if (Xhc
->MemPool
!= NULL
) {
989 UsbHcFreeMemPool (Xhc
->MemPool
);
995 Check if the Trb is a transaction of the URB.
997 @param Xhc The XHCI Instance.
998 @param Trb The TRB to be checked
999 @param Urb The URB to be checked.
1001 @retval TRUE It is a transaction of the URB.
1002 @retval FALSE It is not any transaction of the URB.
1007 IN USB_XHCI_INSTANCE
*Xhc
,
1008 IN TRB_TEMPLATE
*Trb
,
1013 TRB_TEMPLATE
*CheckedTrb
;
1015 EFI_PHYSICAL_ADDRESS PhyAddr
;
1017 CheckedTrb
= Urb
->TrbStart
;
1018 for (Index
= 0; Index
< Urb
->TrbNum
; Index
++) {
1019 if (Trb
== CheckedTrb
) {
1024 // If the checked TRB is the link TRB at the end of the transfer ring,
1025 // recircle it to the head of the ring.
1027 if (CheckedTrb
->Type
== TRB_TYPE_LINK
) {
1028 LinkTrb
= (LINK_TRB
*) CheckedTrb
;
1029 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(LinkTrb
->PtrLo
| LShiftU64 ((UINT64
) LinkTrb
->PtrHi
, 32));
1030 CheckedTrb
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1031 ASSERT (CheckedTrb
== Urb
->Ring
->RingSeg0
);
1039 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
1041 @param Xhc The XHCI Instance.
1042 @param Trb The TRB to be checked.
1043 @param Urb The pointer to the matched Urb.
1045 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
1046 @retval FALSE The Trb is not matched with any URBs in the async list.
1051 IN USB_XHCI_INSTANCE
*Xhc
,
1052 IN TRB_TEMPLATE
*Trb
,
1060 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1061 CheckedUrb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1062 if (IsTransferRingTrb (Xhc
, Trb
, CheckedUrb
)) {
1073 Check the URB's execution result and update the URB's
1076 @param Xhc The XHCI Instance.
1077 @param Urb The URB to check result.
1079 @return Whether the result of URB transfer is finialized.
1084 IN USB_XHCI_INSTANCE
*Xhc
,
1088 EVT_TRB_TRANSFER
*EvtTrb
;
1089 TRB_TEMPLATE
*TRBPtr
;
1098 EFI_PHYSICAL_ADDRESS PhyAddr
;
1100 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
1102 Status
= EFI_SUCCESS
;
1105 if (Urb
->Finished
) {
1111 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1112 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
1117 // Traverse the event ring to find out all new events from the previous check.
1119 XhcSyncEventRing (Xhc
, &Xhc
->EventRing
);
1120 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
1121 Status
= XhcCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
1122 if (Status
== EFI_NOT_READY
) {
1124 // All new events are handled, return directly.
1130 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1132 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
1137 // Need convert pci device address to host address
1139 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
1140 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1143 // Update the status of URB including the pending URB, the URB that is currently checked,
1144 // and URBs in the XHCI's async interrupt transfer list.
1145 // This way is used to avoid that those completed async transfer events don't get
1146 // handled in time and are flushed by newer coming events.
1148 if (Xhc
->PendingUrb
!= NULL
&& IsTransferRingTrb (Xhc
, TRBPtr
, Xhc
->PendingUrb
)) {
1149 CheckedUrb
= Xhc
->PendingUrb
;
1150 } else if (IsTransferRingTrb (Xhc
, TRBPtr
, Urb
)) {
1152 } else if (IsAsyncIntTrb (Xhc
, TRBPtr
, &AsyncUrb
)) {
1153 CheckedUrb
= AsyncUrb
;
1158 switch (EvtTrb
->Completecode
) {
1159 case TRB_COMPLETION_STALL_ERROR
:
1160 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
1161 CheckedUrb
->Finished
= TRUE
;
1162 DEBUG ((DEBUG_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1165 case TRB_COMPLETION_BABBLE_ERROR
:
1166 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
1167 CheckedUrb
->Finished
= TRUE
;
1168 DEBUG ((DEBUG_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1171 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
1172 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
1173 CheckedUrb
->Finished
= TRUE
;
1174 DEBUG ((DEBUG_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
1177 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
1178 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1179 CheckedUrb
->Finished
= TRUE
;
1180 DEBUG ((DEBUG_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1183 case TRB_COMPLETION_STOPPED
:
1184 case TRB_COMPLETION_STOPPED_LENGTH_INVALID
:
1185 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1186 CheckedUrb
->Finished
= TRUE
;
1188 // The pending URB is timeout and force stopped when stopping endpoint.
1189 // Continue the loop to receive the Command Complete Event for stopping endpoint.
1193 case TRB_COMPLETION_SHORT_PACKET
:
1194 case TRB_COMPLETION_SUCCESS
:
1195 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
1196 DEBUG ((DEBUG_VERBOSE
, "XhcCheckUrbResult: short packet happens!\n"));
1199 TRBType
= (UINT8
) (TRBPtr
->Type
);
1200 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
1201 (TRBType
== TRB_TYPE_NORMAL
) ||
1202 (TRBType
== TRB_TYPE_ISOCH
)) {
1203 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
1209 DEBUG ((DEBUG_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
1210 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1211 CheckedUrb
->Finished
= TRUE
;
1216 // Only check first and end Trb event address
1218 if (TRBPtr
== CheckedUrb
->TrbStart
) {
1219 CheckedUrb
->StartDone
= TRUE
;
1222 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
1223 CheckedUrb
->EndDone
= TRUE
;
1226 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
1227 CheckedUrb
->Finished
= TRUE
;
1228 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
1235 // Advance event ring to last available entry
1237 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1238 // So divide it to two 32-bytes width register access.
1240 Low
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
1241 High
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
1242 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
1244 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
1246 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
1248 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1249 // So divide it to two 32-bytes width register access.
1251 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
1252 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
1255 return Urb
->Finished
;
1260 Execute the transfer by polling the URB. This is a synchronous operation.
1262 @param Xhc The XHCI Instance.
1263 @param CmdTransfer The executed URB is for cmd transfer or not.
1264 @param Urb The URB to execute.
1265 @param Timeout The time to wait before abort, in millisecond.
1267 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1268 @return EFI_TIMEOUT The transfer failed due to time out.
1269 @return EFI_SUCCESS The transfer finished OK.
1270 @retval EFI_OUT_OF_RESOURCES Memory for the timer event could not be allocated.
1275 IN USB_XHCI_INSTANCE
*Xhc
,
1276 IN BOOLEAN CmdTransfer
,
1285 EFI_EVENT TimeoutEvent
;
1286 BOOLEAN IndefiniteTimeout
;
1288 Status
= EFI_SUCCESS
;
1290 TimeoutEvent
= NULL
;
1291 IndefiniteTimeout
= FALSE
;
1297 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1299 return EFI_DEVICE_ERROR
;
1301 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1306 IndefiniteTimeout
= TRUE
;
1310 Status
= gBS
->CreateEvent (
1318 if (EFI_ERROR (Status
)) {
1322 Status
= gBS
->SetTimer (TimeoutEvent
,
1324 EFI_TIMER_PERIOD_MILLISECONDS(Timeout
));
1326 if (EFI_ERROR (Status
)) {
1331 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1334 Finished
= XhcCheckUrbResult (Xhc
, Urb
);
1338 gBS
->Stall (XHC_1_MICROSECOND
);
1339 } while (IndefiniteTimeout
|| EFI_ERROR(gBS
->CheckEvent (TimeoutEvent
)));
1342 if (EFI_ERROR(Status
)) {
1343 Urb
->Result
= EFI_USB_ERR_NOTEXECUTE
;
1344 } else if (!Finished
) {
1345 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
1346 Status
= EFI_TIMEOUT
;
1347 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
1348 Status
= EFI_DEVICE_ERROR
;
1351 if (TimeoutEvent
!= NULL
) {
1352 gBS
->CloseEvent (TimeoutEvent
);
1359 Delete a single asynchronous interrupt transfer for
1360 the device and endpoint.
1362 @param Xhc The XHCI Instance.
1363 @param BusAddr The logical device address assigned by UsbBus driver.
1364 @param EpNum The endpoint of the target.
1366 @retval EFI_SUCCESS An asynchronous transfer is removed.
1367 @retval EFI_NOT_FOUND No transfer for the device is found.
1371 XhciDelAsyncIntTransfer (
1372 IN USB_XHCI_INSTANCE
*Xhc
,
1380 EFI_USB_DATA_DIRECTION Direction
;
1383 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1388 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1389 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1390 if ((Urb
->Ep
.BusAddr
== BusAddr
) &&
1391 (Urb
->Ep
.EpAddr
== EpNum
) &&
1392 (Urb
->Ep
.Direction
== Direction
)) {
1394 // Device doesn't finish the IntTransfer until real data comes
1395 // So the TRB should be removed as well.
1397 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1398 if (EFI_ERROR (Status
)) {
1399 DEBUG ((DEBUG_ERROR
, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));
1402 RemoveEntryList (&Urb
->UrbList
);
1403 FreePool (Urb
->Data
);
1404 XhcFreeUrb (Xhc
, Urb
);
1409 return EFI_NOT_FOUND
;
1413 Remove all the asynchronous interrutp transfers.
1415 @param Xhc The XHCI Instance.
1419 XhciDelAllAsyncIntTransfers (
1420 IN USB_XHCI_INSTANCE
*Xhc
1428 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1429 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1432 // Device doesn't finish the IntTransfer until real data comes
1433 // So the TRB should be removed as well.
1435 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1436 if (EFI_ERROR (Status
)) {
1437 DEBUG ((DEBUG_ERROR
, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));
1440 RemoveEntryList (&Urb
->UrbList
);
1441 FreePool (Urb
->Data
);
1442 XhcFreeUrb (Xhc
, Urb
);
1447 Insert a single asynchronous interrupt transfer for
1448 the device and endpoint.
1450 @param Xhc The XHCI Instance
1451 @param BusAddr The logical device address assigned by UsbBus driver
1452 @param EpAddr Endpoint addrress
1453 @param DevSpeed The device speed
1454 @param MaxPacket The max packet length of the endpoint
1455 @param DataLen The length of data buffer
1456 @param Callback The function to call when data is transferred
1457 @param Context The context to the callback
1459 @return Created URB or NULL
1463 XhciInsertAsyncIntTransfer (
1464 IN USB_XHCI_INSTANCE
*Xhc
,
1470 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
1477 Data
= AllocateZeroPool (DataLen
);
1479 DEBUG ((DEBUG_ERROR
, "%a: failed to allocate buffer\n", __FUNCTION__
));
1483 Urb
= XhcCreateUrb (
1489 XHC_INT_TRANSFER_ASYNC
,
1497 DEBUG ((DEBUG_ERROR
, "%a: failed to create URB\n", __FUNCTION__
));
1503 // New asynchronous transfer must inserted to the head.
1504 // Check the comments in XhcMoniteAsyncRequests
1506 InsertHeadList (&Xhc
->AsyncIntTransfers
, &Urb
->UrbList
);
1512 Update the queue head for next round of asynchronous transfer
1514 @param Xhc The XHCI Instance.
1515 @param Urb The URB to update
1519 XhcUpdateAsyncRequest (
1520 IN USB_XHCI_INSTANCE
*Xhc
,
1526 if (Urb
->Result
== EFI_USB_NOERROR
) {
1527 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1528 if (EFI_ERROR (Status
)) {
1531 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1532 if (EFI_ERROR (Status
)) {
1539 Flush data from PCI controller specific address to mapped system
1542 @param Xhc The XHCI device.
1543 @param Urb The URB to unmap.
1545 @retval EFI_SUCCESS Success to flush data to mapped system memory.
1546 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
1550 XhcFlushAsyncIntMap (
1551 IN USB_XHCI_INSTANCE
*Xhc
,
1556 EFI_PHYSICAL_ADDRESS PhyAddr
;
1557 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
1558 EFI_PCI_IO_PROTOCOL
*PciIo
;
1565 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
1566 MapOp
= EfiPciIoOperationBusMasterWrite
;
1568 MapOp
= EfiPciIoOperationBusMasterRead
;
1571 if (Urb
->DataMap
!= NULL
) {
1572 Status
= PciIo
->Unmap (PciIo
, Urb
->DataMap
);
1573 if (EFI_ERROR (Status
)) {
1578 Urb
->DataMap
= NULL
;
1580 Status
= PciIo
->Map (PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
1581 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
1585 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
1590 return EFI_DEVICE_ERROR
;
1594 Interrupt transfer periodic check handler.
1596 @param Event Interrupt event.
1597 @param Context Pointer to USB_XHCI_INSTANCE.
1602 XhcMonitorAsyncRequests (
1607 USB_XHCI_INSTANCE
*Xhc
;
1616 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1618 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1620 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1621 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1624 // Make sure that the device is available before every check.
1626 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1632 // Check the result of URB execution. If it is still
1633 // active, check the next one.
1635 XhcCheckUrbResult (Xhc
, Urb
);
1637 if (!Urb
->Finished
) {
1642 // Flush any PCI posted write transactions from a PCI host
1643 // bridge to system memory.
1645 Status
= XhcFlushAsyncIntMap (Xhc
, Urb
);
1646 if (EFI_ERROR (Status
)) {
1647 DEBUG ((DEBUG_ERROR
, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1651 // Allocate a buffer then copy the transferred data for user.
1652 // If failed to allocate the buffer, update the URB for next
1653 // round of transfer. Ignore the data of this round.
1656 if (Urb
->Result
== EFI_USB_NOERROR
) {
1658 // Make sure the data received from HW is no more than expected.
1660 if (Urb
->Completed
<= Urb
->DataLen
) {
1661 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1664 if (ProcBuf
== NULL
) {
1665 XhcUpdateAsyncRequest (Xhc
, Urb
);
1669 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1673 // Leave error recovery to its related device driver. A
1674 // common case of the error recovery is to re-submit the
1675 // interrupt transfer which is linked to the head of the
1676 // list. This function scans from head to tail. So the
1677 // re-submitted interrupt transfer's callback function
1678 // will not be called again in this round. Don't touch this
1679 // URB after the callback, it may have been removed by the
1682 if (Urb
->Callback
!= NULL
) {
1684 // Restore the old TPL, USB bus maybe connect device in
1685 // his callback. Some drivers may has a lower TPL restriction.
1687 gBS
->RestoreTPL (OldTpl
);
1688 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1689 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1692 if (ProcBuf
!= NULL
) {
1693 gBS
->FreePool (ProcBuf
);
1696 XhcUpdateAsyncRequest (Xhc
, Urb
);
1698 gBS
->RestoreTPL (OldTpl
);
1702 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1704 @param Xhc The XHCI Instance.
1705 @param ParentRouteChart The route string pointed to the parent device if it exists.
1706 @param Port The port to be polled.
1707 @param PortState The port state.
1709 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1710 @retval Others Should not appear.
1715 XhcPollPortStatusChange (
1716 IN USB_XHCI_INSTANCE
*Xhc
,
1717 IN USB_DEV_ROUTE ParentRouteChart
,
1719 IN EFI_USB_PORT_STATUS
*PortState
1726 USB_DEV_ROUTE RouteChart
;
1728 Status
= EFI_SUCCESS
;
1729 Retries
= XHC_INIT_DEVICE_SLOT_RETRIES
;
1731 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
1735 if (ParentRouteChart
.Dword
== 0) {
1736 RouteChart
.Route
.RouteString
= 0;
1737 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1738 RouteChart
.Route
.TierNum
= 1;
1741 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1743 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1745 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1746 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1749 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1751 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1752 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1754 Status
= XhcDisableSlotCmd64 (Xhc
, SlotId
);
1758 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1759 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1761 // Has a device attached, Identify device speed after port is enabled.
1763 Speed
= EFI_USB_SPEED_FULL
;
1764 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1765 Speed
= EFI_USB_SPEED_LOW
;
1766 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1767 Speed
= EFI_USB_SPEED_HIGH
;
1768 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1769 Speed
= EFI_USB_SPEED_SUPER
;
1774 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1776 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1777 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
1778 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1779 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1781 Status
= XhcInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1786 // According to the xHCI specification (section 4.6.5), "a USB Transaction
1787 // Error Completion Code for an Address Device Command may be due to a Stall
1788 // response from a device. Software should issue a Disable Slot Command for
1789 // the Device Slot then an Enable Slot Command to recover from this error."
1790 // Therefore, retry the device slot initialization if it fails due to a
1793 } while ((Status
== EFI_DEVICE_ERROR
) && (Retries
-- != 0));
1801 Calculate the device context index by endpoint address and direction.
1803 @param EpAddr The target endpoint number.
1804 @param Direction The direction of the target endpoint.
1806 @return The device context index of endpoint.
1820 Index
= (UINT8
) (2 * EpAddr
);
1821 if (Direction
== EfiUsbDataIn
) {
1829 Find out the actual device address according to the requested device address from UsbBus.
1831 @param Xhc The XHCI Instance.
1832 @param BusDevAddr The requested device address by UsbBus upper driver.
1834 @return The actual device address assigned to the device.
1839 XhcBusDevAddrToSlotId (
1840 IN USB_XHCI_INSTANCE
*Xhc
,
1846 for (Index
= 0; Index
< 255; Index
++) {
1847 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1848 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1849 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1858 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1862 Find out the slot id according to the device's route string.
1864 @param Xhc The XHCI Instance.
1865 @param RouteString The route string described the device location.
1867 @return The slot id used by the device.
1872 XhcRouteStringToSlotId (
1873 IN USB_XHCI_INSTANCE
*Xhc
,
1874 IN USB_DEV_ROUTE RouteString
1879 for (Index
= 0; Index
< 255; Index
++) {
1880 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1881 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1882 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1891 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1895 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1897 @param Xhc The XHCI Instance.
1898 @param EvtRing The event ring to sync.
1900 @retval EFI_SUCCESS The event ring is synchronized successfully.
1906 IN USB_XHCI_INSTANCE
*Xhc
,
1907 IN EVENT_RING
*EvtRing
1911 TRB_TEMPLATE
*EvtTrb1
;
1913 ASSERT (EvtRing
!= NULL
);
1916 // Calculate the EventRingEnqueue and EventRingCCS.
1917 // Note: only support single Segment
1919 EvtTrb1
= EvtRing
->EventRingDequeue
;
1921 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1922 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
1928 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1929 EvtTrb1
= EvtRing
->EventRingSeg0
;
1930 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
1934 if (Index
< EvtRing
->TrbNumber
) {
1935 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1944 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1946 @param Xhc The XHCI Instance.
1947 @param TrsRing The transfer ring to sync.
1949 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1955 IN USB_XHCI_INSTANCE
*Xhc
,
1956 IN TRANSFER_RING
*TrsRing
1960 TRB_TEMPLATE
*TrsTrb
;
1962 ASSERT (TrsRing
!= NULL
);
1964 // Calculate the latest RingEnqueue and RingPCS
1966 TrsTrb
= TrsRing
->RingEnqueue
;
1967 ASSERT (TrsTrb
!= NULL
);
1969 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1970 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1974 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1975 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1977 // set cycle bit in Link TRB as normal
1979 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1981 // Toggle PCS maintained by software
1983 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1984 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
1988 ASSERT (Index
!= TrsRing
->TrbNumber
);
1990 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1991 TrsRing
->RingEnqueue
= TrsTrb
;
1995 // Clear the Trb context for enqueue, but reserve the PCS bit
1997 TrsTrb
->Parameter1
= 0;
1998 TrsTrb
->Parameter2
= 0;
2002 TrsTrb
->Control
= 0;
2008 Check if there is a new generated event.
2010 @param Xhc The XHCI Instance.
2011 @param EvtRing The event ring to check.
2012 @param NewEvtTrb The new event TRB found.
2014 @retval EFI_SUCCESS Found a new event TRB at the event ring.
2015 @retval EFI_NOT_READY The event ring has no new event.
2021 IN USB_XHCI_INSTANCE
*Xhc
,
2022 IN EVENT_RING
*EvtRing
,
2023 OUT TRB_TEMPLATE
**NewEvtTrb
2026 ASSERT (EvtRing
!= NULL
);
2028 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
2030 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
2031 return EFI_NOT_READY
;
2034 EvtRing
->EventRingDequeue
++;
2036 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2038 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2039 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
2046 Ring the door bell to notify XHCI there is a transaction to be executed.
2048 @param Xhc The XHCI Instance.
2049 @param SlotId The slot id of the target device.
2050 @param Dci The device context index of the target slot or endpoint.
2052 @retval EFI_SUCCESS Successfully ring the door bell.
2058 IN USB_XHCI_INSTANCE
*Xhc
,
2064 XhcWriteDoorBellReg (Xhc
, 0, 0);
2066 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
2073 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
2075 @param Xhc The XHCI Instance.
2076 @param Urb The URB to be rung.
2078 @retval EFI_SUCCESS Successfully ring the door bell.
2082 RingIntTransferDoorBell (
2083 IN USB_XHCI_INSTANCE
*Xhc
,
2090 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
2091 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
2092 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
2097 Assign and initialize the device slot for a new device.
2099 @param Xhc The XHCI Instance.
2100 @param ParentRouteChart The route string pointed to the parent device.
2101 @param ParentPort The port at which the device is located.
2102 @param RouteChart The route string pointed to the device.
2103 @param DeviceSpeed The device speed.
2105 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2110 XhcInitializeDeviceSlot (
2111 IN USB_XHCI_INSTANCE
*Xhc
,
2112 IN USB_DEV_ROUTE ParentRouteChart
,
2113 IN UINT16 ParentPort
,
2114 IN USB_DEV_ROUTE RouteChart
,
2115 IN UINT8 DeviceSpeed
2119 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2120 INPUT_CONTEXT
*InputContext
;
2121 DEVICE_CONTEXT
*OutputContext
;
2122 TRANSFER_RING
*EndpointTransferRing
;
2123 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2124 UINT8 DeviceAddress
;
2125 CMD_TRB_ENABLE_SLOT CmdTrb
;
2128 DEVICE_CONTEXT
*ParentDeviceContext
;
2129 EFI_PHYSICAL_ADDRESS PhyAddr
;
2131 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2132 CmdTrb
.CycleBit
= 1;
2133 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2135 Status
= XhcCmdTransfer (
2137 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2138 XHC_GENERIC_TIMEOUT
,
2139 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2141 if (EFI_ERROR (Status
)) {
2142 DEBUG ((DEBUG_ERROR
, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
2145 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2146 DEBUG ((DEBUG_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2147 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2148 ASSERT (SlotId
!= 0);
2150 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2151 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2152 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2153 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2154 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2157 // 4.3.3 Device Slot Initialization
2158 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2160 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
2161 ASSERT (InputContext
!= NULL
);
2162 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2163 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2165 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2168 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2169 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2170 // Context are affected by the command.
2172 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2175 // 3) Initialize the Input Slot Context data structure
2177 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2178 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2179 InputContext
->Slot
.ContextEntries
= 1;
2180 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2182 if (RouteChart
.Route
.RouteString
) {
2184 // The device is behind of hub device.
2186 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2187 ASSERT (ParentSlotId
!= 0);
2189 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2191 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2192 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2193 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2194 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2196 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2197 // environment from Full/Low speed signaling environment for a device
2199 InputContext
->Slot
.TTPortNum
= ParentPort
;
2200 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2204 // Inherit the TT parameters from parent device.
2206 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2207 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2209 // If the device is a High speed device then down the speed to be the same as its parent Hub
2211 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2212 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2218 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2220 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2221 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2222 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2224 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2226 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2228 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2229 InputContext
->EP
[0].MaxPacketSize
= 512;
2230 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2231 InputContext
->EP
[0].MaxPacketSize
= 64;
2233 InputContext
->EP
[0].MaxPacketSize
= 8;
2236 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2237 // 1KB, and Bulk and Isoch endpoints 3KB.
2239 InputContext
->EP
[0].AverageTRBLength
= 8;
2240 InputContext
->EP
[0].MaxBurstSize
= 0;
2241 InputContext
->EP
[0].Interval
= 0;
2242 InputContext
->EP
[0].MaxPStreams
= 0;
2243 InputContext
->EP
[0].Mult
= 0;
2244 InputContext
->EP
[0].CErr
= 3;
2247 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2249 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2251 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2252 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2254 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2255 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2258 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2260 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
2261 ASSERT (OutputContext
!= NULL
);
2262 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2263 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
2265 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2267 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2268 // a pointer to the Output Device Context data structure (6.2.1).
2270 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
2272 // Fill DCBAA with PCI device address
2274 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2277 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2278 // Context data structure described above.
2280 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2283 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2284 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2285 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2286 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2287 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2288 CmdTrbAddr
.CycleBit
= 1;
2289 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2290 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2291 Status
= XhcCmdTransfer (
2293 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2294 XHC_GENERIC_TIMEOUT
,
2295 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2297 if (!EFI_ERROR (Status
)) {
2298 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
2299 DEBUG ((DEBUG_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2300 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2302 DEBUG ((DEBUG_ERROR
, " Slot %d address not assigned successfully. Status = %r\n", SlotId
, Status
));
2303 XhcDisableSlotCmd (Xhc
, SlotId
);
2310 Assign and initialize the device slot for a new device.
2312 @param Xhc The XHCI Instance.
2313 @param ParentRouteChart The route string pointed to the parent device.
2314 @param ParentPort The port at which the device is located.
2315 @param RouteChart The route string pointed to the device.
2316 @param DeviceSpeed The device speed.
2318 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2323 XhcInitializeDeviceSlot64 (
2324 IN USB_XHCI_INSTANCE
*Xhc
,
2325 IN USB_DEV_ROUTE ParentRouteChart
,
2326 IN UINT16 ParentPort
,
2327 IN USB_DEV_ROUTE RouteChart
,
2328 IN UINT8 DeviceSpeed
2332 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2333 INPUT_CONTEXT_64
*InputContext
;
2334 DEVICE_CONTEXT_64
*OutputContext
;
2335 TRANSFER_RING
*EndpointTransferRing
;
2336 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2337 UINT8 DeviceAddress
;
2338 CMD_TRB_ENABLE_SLOT CmdTrb
;
2341 DEVICE_CONTEXT_64
*ParentDeviceContext
;
2342 EFI_PHYSICAL_ADDRESS PhyAddr
;
2344 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2345 CmdTrb
.CycleBit
= 1;
2346 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2348 Status
= XhcCmdTransfer (
2350 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2351 XHC_GENERIC_TIMEOUT
,
2352 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2354 if (EFI_ERROR (Status
)) {
2355 DEBUG ((DEBUG_ERROR
, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
2358 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2359 DEBUG ((DEBUG_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2360 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2361 ASSERT (SlotId
!= 0);
2363 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2364 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2365 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2366 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2367 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2370 // 4.3.3 Device Slot Initialization
2371 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2373 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
2374 ASSERT (InputContext
!= NULL
);
2375 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2376 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2378 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2381 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2382 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2383 // Context are affected by the command.
2385 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2388 // 3) Initialize the Input Slot Context data structure
2390 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2391 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2392 InputContext
->Slot
.ContextEntries
= 1;
2393 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2395 if (RouteChart
.Route
.RouteString
) {
2397 // The device is behind of hub device.
2399 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2400 ASSERT (ParentSlotId
!= 0);
2402 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2404 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2405 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2406 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2407 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2409 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2410 // environment from Full/Low speed signaling environment for a device
2412 InputContext
->Slot
.TTPortNum
= ParentPort
;
2413 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2417 // Inherit the TT parameters from parent device.
2419 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2420 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2422 // If the device is a High speed device then down the speed to be the same as its parent Hub
2424 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2425 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2431 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2433 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2434 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2435 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2437 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2439 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2441 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2442 InputContext
->EP
[0].MaxPacketSize
= 512;
2443 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2444 InputContext
->EP
[0].MaxPacketSize
= 64;
2446 InputContext
->EP
[0].MaxPacketSize
= 8;
2449 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2450 // 1KB, and Bulk and Isoch endpoints 3KB.
2452 InputContext
->EP
[0].AverageTRBLength
= 8;
2453 InputContext
->EP
[0].MaxBurstSize
= 0;
2454 InputContext
->EP
[0].Interval
= 0;
2455 InputContext
->EP
[0].MaxPStreams
= 0;
2456 InputContext
->EP
[0].Mult
= 0;
2457 InputContext
->EP
[0].CErr
= 3;
2460 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2462 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2464 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2465 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2467 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2468 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2471 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2473 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
2474 ASSERT (OutputContext
!= NULL
);
2475 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2476 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2478 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2480 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2481 // a pointer to the Output Device Context data structure (6.2.1).
2483 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2485 // Fill DCBAA with PCI device address
2487 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2490 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2491 // Context data structure described above.
2493 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2496 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2497 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2498 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2499 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2500 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2501 CmdTrbAddr
.CycleBit
= 1;
2502 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2503 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2504 Status
= XhcCmdTransfer (
2506 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2507 XHC_GENERIC_TIMEOUT
,
2508 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2510 if (!EFI_ERROR (Status
)) {
2511 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT_64
*) OutputContext
)->Slot
.DeviceAddress
;
2512 DEBUG ((DEBUG_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2513 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2515 DEBUG ((DEBUG_ERROR
, " Slot %d address not assigned successfully. Status = %r\n", SlotId
, Status
));
2516 XhcDisableSlotCmd64 (Xhc
, SlotId
);
2524 Disable the specified device slot.
2526 @param Xhc The XHCI Instance.
2527 @param SlotId The slot id to be disabled.
2529 @retval EFI_SUCCESS Successfully disable the device slot.
2535 IN USB_XHCI_INSTANCE
*Xhc
,
2540 TRB_TEMPLATE
*EvtTrb
;
2541 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2546 // Disable the device slots occupied by these devices on its downstream ports.
2547 // Entry 0 is reserved.
2549 for (Index
= 0; Index
< 255; Index
++) {
2550 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2551 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2552 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2556 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2558 if (EFI_ERROR (Status
)) {
2559 DEBUG ((DEBUG_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2560 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2565 // Construct the disable slot command
2567 DEBUG ((DEBUG_INFO
, "Disable device slot %d!\n", SlotId
));
2569 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2570 CmdTrbDisSlot
.CycleBit
= 1;
2571 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2572 CmdTrbDisSlot
.SlotId
= SlotId
;
2573 Status
= XhcCmdTransfer (
2575 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2576 XHC_GENERIC_TIMEOUT
,
2577 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2579 if (EFI_ERROR (Status
)) {
2580 DEBUG ((DEBUG_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2584 // Free the slot's device context entry
2586 Xhc
->DCBAA
[SlotId
] = 0;
2589 // Free the slot related data structure
2591 for (Index
= 0; Index
< 31; Index
++) {
2592 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2593 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2594 if (RingSeg
!= NULL
) {
2595 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2597 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2598 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2602 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2603 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2604 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2608 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2609 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2612 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2613 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2616 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2617 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
2620 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2621 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2622 // remove urb from XHCI's asynchronous transfer list.
2624 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2625 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2631 Disable the specified device slot.
2633 @param Xhc The XHCI Instance.
2634 @param SlotId The slot id to be disabled.
2636 @retval EFI_SUCCESS Successfully disable the device slot.
2641 XhcDisableSlotCmd64 (
2642 IN USB_XHCI_INSTANCE
*Xhc
,
2647 TRB_TEMPLATE
*EvtTrb
;
2648 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2653 // Disable the device slots occupied by these devices on its downstream ports.
2654 // Entry 0 is reserved.
2656 for (Index
= 0; Index
< 255; Index
++) {
2657 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2658 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2659 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2663 Status
= XhcDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2665 if (EFI_ERROR (Status
)) {
2666 DEBUG ((DEBUG_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2667 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2672 // Construct the disable slot command
2674 DEBUG ((DEBUG_INFO
, "Disable device slot %d!\n", SlotId
));
2676 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2677 CmdTrbDisSlot
.CycleBit
= 1;
2678 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2679 CmdTrbDisSlot
.SlotId
= SlotId
;
2680 Status
= XhcCmdTransfer (
2682 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2683 XHC_GENERIC_TIMEOUT
,
2684 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2686 if (EFI_ERROR (Status
)) {
2687 DEBUG ((DEBUG_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2691 // Free the slot's device context entry
2693 Xhc
->DCBAA
[SlotId
] = 0;
2696 // Free the slot related data structure
2698 for (Index
= 0; Index
< 31; Index
++) {
2699 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2700 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2701 if (RingSeg
!= NULL
) {
2702 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2704 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2705 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2709 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2710 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2711 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2715 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2716 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2719 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2720 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2723 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2724 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2727 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2728 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2729 // remove urb from XHCI's asynchronous transfer list.
2731 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2732 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2738 Initialize endpoint context in input context.
2740 @param Xhc The XHCI Instance.
2741 @param SlotId The slot id to be configured.
2742 @param DeviceSpeed The device's speed.
2743 @param InputContext The pointer to the input context.
2744 @param IfDesc The pointer to the usb device interface descriptor.
2746 @return The maximum device context index of endpoint.
2751 XhcInitializeEndpointContext (
2752 IN USB_XHCI_INSTANCE
*Xhc
,
2754 IN UINT8 DeviceSpeed
,
2755 IN INPUT_CONTEXT
*InputContext
,
2756 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2759 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2766 EFI_PHYSICAL_ADDRESS PhyAddr
;
2768 TRANSFER_RING
*EndpointTransferRing
;
2772 NumEp
= IfDesc
->NumEndpoints
;
2774 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2775 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2776 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2777 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2780 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2781 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2785 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2786 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2788 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2794 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2795 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2797 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2799 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2801 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2803 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2806 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2807 case USB_ENDPOINT_BULK
:
2808 if (Direction
== EfiUsbDataIn
) {
2809 InputContext
->EP
[Dci
-1].CErr
= 3;
2810 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2812 InputContext
->EP
[Dci
-1].CErr
= 3;
2813 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2816 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2817 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2818 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2819 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2820 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2821 DEBUG ((DEBUG_INFO
, "Endpoint[%x]: Created BULK ring [%p~%p)\n",
2822 EpDesc
->EndpointAddress
,
2823 EndpointTransferRing
->RingSeg0
,
2824 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2829 case USB_ENDPOINT_ISO
:
2830 if (Direction
== EfiUsbDataIn
) {
2831 InputContext
->EP
[Dci
-1].CErr
= 0;
2832 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2834 InputContext
->EP
[Dci
-1].CErr
= 0;
2835 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2838 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2839 // Refer to XHCI 1.1 spec section 6.2.3.6.
2841 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2842 Interval
= EpDesc
->Interval
;
2843 ASSERT (Interval
>= 1 && Interval
<= 16);
2844 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2845 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2846 Interval
= EpDesc
->Interval
;
2847 ASSERT (Interval
>= 1 && Interval
<= 16);
2848 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2852 // Do not support isochronous transfer now.
2854 DEBUG ((DEBUG_INFO
, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2855 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2857 case USB_ENDPOINT_INTERRUPT
:
2858 if (Direction
== EfiUsbDataIn
) {
2859 InputContext
->EP
[Dci
-1].CErr
= 3;
2860 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2862 InputContext
->EP
[Dci
-1].CErr
= 3;
2863 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2865 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2866 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2868 // Get the bInterval from descriptor and init the the interval field of endpoint context
2870 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2871 Interval
= EpDesc
->Interval
;
2873 // Calculate through the bInterval field of Endpoint descriptor.
2875 ASSERT (Interval
!= 0);
2876 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2877 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2878 Interval
= EpDesc
->Interval
;
2879 ASSERT (Interval
>= 1 && Interval
<= 16);
2881 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2883 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2884 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2885 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2886 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2887 InputContext
->EP
[Dci
-1].CErr
= 3;
2890 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2891 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2892 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2893 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2894 DEBUG ((DEBUG_INFO
, "Endpoint[%x]: Created INT ring [%p~%p)\n",
2895 EpDesc
->EndpointAddress
,
2896 EndpointTransferRing
->RingSeg0
,
2897 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2902 case USB_ENDPOINT_CONTROL
:
2904 // Do not support control transfer now.
2906 DEBUG ((DEBUG_INFO
, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2908 DEBUG ((DEBUG_INFO
, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2909 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2913 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2915 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2916 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2918 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2919 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2920 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2921 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2923 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2930 Initialize endpoint context in input context.
2932 @param Xhc The XHCI Instance.
2933 @param SlotId The slot id to be configured.
2934 @param DeviceSpeed The device's speed.
2935 @param InputContext The pointer to the input context.
2936 @param IfDesc The pointer to the usb device interface descriptor.
2938 @return The maximum device context index of endpoint.
2943 XhcInitializeEndpointContext64 (
2944 IN USB_XHCI_INSTANCE
*Xhc
,
2946 IN UINT8 DeviceSpeed
,
2947 IN INPUT_CONTEXT_64
*InputContext
,
2948 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2951 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2958 EFI_PHYSICAL_ADDRESS PhyAddr
;
2960 TRANSFER_RING
*EndpointTransferRing
;
2964 NumEp
= IfDesc
->NumEndpoints
;
2966 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2967 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2968 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2969 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2972 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2973 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2977 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2978 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2980 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2986 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2987 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2989 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2991 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2993 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2995 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2998 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2999 case USB_ENDPOINT_BULK
:
3000 if (Direction
== EfiUsbDataIn
) {
3001 InputContext
->EP
[Dci
-1].CErr
= 3;
3002 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
3004 InputContext
->EP
[Dci
-1].CErr
= 3;
3005 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
3008 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
3009 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
3010 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
3011 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
3012 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
3013 DEBUG ((DEBUG_INFO
, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",
3014 EpDesc
->EndpointAddress
,
3015 EndpointTransferRing
->RingSeg0
,
3016 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
3021 case USB_ENDPOINT_ISO
:
3022 if (Direction
== EfiUsbDataIn
) {
3023 InputContext
->EP
[Dci
-1].CErr
= 0;
3024 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
3026 InputContext
->EP
[Dci
-1].CErr
= 0;
3027 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
3030 // Get the bInterval from descriptor and init the the interval field of endpoint context.
3031 // Refer to XHCI 1.1 spec section 6.2.3.6.
3033 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
3034 Interval
= EpDesc
->Interval
;
3035 ASSERT (Interval
>= 1 && Interval
<= 16);
3036 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
3037 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
3038 Interval
= EpDesc
->Interval
;
3039 ASSERT (Interval
>= 1 && Interval
<= 16);
3040 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
3044 // Do not support isochronous transfer now.
3046 DEBUG ((DEBUG_INFO
, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
3047 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3049 case USB_ENDPOINT_INTERRUPT
:
3050 if (Direction
== EfiUsbDataIn
) {
3051 InputContext
->EP
[Dci
-1].CErr
= 3;
3052 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
3054 InputContext
->EP
[Dci
-1].CErr
= 3;
3055 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
3057 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
3058 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
3060 // Get the bInterval from descriptor and init the the interval field of endpoint context
3062 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
3063 Interval
= EpDesc
->Interval
;
3065 // Calculate through the bInterval field of Endpoint descriptor.
3067 ASSERT (Interval
!= 0);
3068 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
3069 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
3070 Interval
= EpDesc
->Interval
;
3071 ASSERT (Interval
>= 1 && Interval
<= 16);
3073 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
3075 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
3076 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
3077 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
3078 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
3079 InputContext
->EP
[Dci
-1].CErr
= 3;
3082 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
3083 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
3084 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
3085 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
3086 DEBUG ((DEBUG_INFO
, "Endpoint64[%x]: Created INT ring [%p~%p)\n",
3087 EpDesc
->EndpointAddress
,
3088 EndpointTransferRing
->RingSeg0
,
3089 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
3094 case USB_ENDPOINT_CONTROL
:
3096 // Do not support control transfer now.
3098 DEBUG ((DEBUG_INFO
, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
3100 DEBUG ((DEBUG_INFO
, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
3101 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3105 PhyAddr
= UsbHcGetPciAddrForHostAddr (
3107 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
3108 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
3110 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
3111 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
3112 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3113 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3115 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3122 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3124 @param Xhc The XHCI Instance.
3125 @param SlotId The slot id to be configured.
3126 @param DeviceSpeed The device's speed.
3127 @param ConfigDesc The pointer to the usb device configuration descriptor.
3129 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3135 IN USB_XHCI_INSTANCE
*Xhc
,
3137 IN UINT8 DeviceSpeed
,
3138 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
3142 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3146 EFI_PHYSICAL_ADDRESS PhyAddr
;
3148 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3149 INPUT_CONTEXT
*InputContext
;
3150 DEVICE_CONTEXT
*OutputContext
;
3151 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3153 // 4.6.6 Configure Endpoint
3155 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3156 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3157 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3158 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3160 ASSERT (ConfigDesc
!= NULL
);
3164 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3165 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3166 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3167 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3170 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3171 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3175 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3180 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3183 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3184 InputContext
->Slot
.ContextEntries
= MaxDci
;
3186 // configure endpoint
3188 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3189 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3190 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3191 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3192 CmdTrbCfgEP
.CycleBit
= 1;
3193 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3194 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3195 DEBUG ((DEBUG_INFO
, "Configure Endpoint\n"));
3196 Status
= XhcCmdTransfer (
3198 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3199 XHC_GENERIC_TIMEOUT
,
3200 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3202 if (EFI_ERROR (Status
)) {
3203 DEBUG ((DEBUG_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
3205 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3212 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3214 @param Xhc The XHCI Instance.
3215 @param SlotId The slot id to be configured.
3216 @param DeviceSpeed The device's speed.
3217 @param ConfigDesc The pointer to the usb device configuration descriptor.
3219 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3225 IN USB_XHCI_INSTANCE
*Xhc
,
3227 IN UINT8 DeviceSpeed
,
3228 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
3232 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3236 EFI_PHYSICAL_ADDRESS PhyAddr
;
3238 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3239 INPUT_CONTEXT_64
*InputContext
;
3240 DEVICE_CONTEXT_64
*OutputContext
;
3241 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3243 // 4.6.6 Configure Endpoint
3245 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3246 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3247 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3248 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3250 ASSERT (ConfigDesc
!= NULL
);
3254 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3255 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3256 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3257 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3260 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3261 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3265 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3270 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3273 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3274 InputContext
->Slot
.ContextEntries
= MaxDci
;
3276 // configure endpoint
3278 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3279 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3280 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3281 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3282 CmdTrbCfgEP
.CycleBit
= 1;
3283 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3284 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3285 DEBUG ((DEBUG_INFO
, "Configure Endpoint\n"));
3286 Status
= XhcCmdTransfer (
3288 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3289 XHC_GENERIC_TIMEOUT
,
3290 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3292 if (EFI_ERROR (Status
)) {
3293 DEBUG ((DEBUG_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
3295 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3302 Stop endpoint through XHCI's Stop_Endpoint cmd.
3304 @param Xhc The XHCI Instance.
3305 @param SlotId The slot id to be configured.
3306 @param Dci The device context index of endpoint.
3307 @param PendingUrb The pending URB to check completion status when stopping the end point.
3309 @retval EFI_SUCCESS Stop endpoint successfully.
3310 @retval Others Failed to stop endpoint.
3316 IN USB_XHCI_INSTANCE
*Xhc
,
3319 IN URB
*PendingUrb OPTIONAL
3323 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3324 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
3326 DEBUG ((DEBUG_INFO
, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3329 // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks
3330 // the PendingUrb completion status, because it's possible that the PendingUrb is
3331 // finished just before stopping the end point, but after the looping check.
3333 // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult
3334 // through function parameter, but That will cause every consumer of XhcCmdTransfer,
3335 // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.
3336 // But actually only XhcCheckUrbResult is aware of the PendingUrb.
3337 // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.
3339 ASSERT (Xhc
->PendingUrb
== NULL
);
3340 Xhc
->PendingUrb
= PendingUrb
;
3342 // Reset the URB result from Timeout to NoError.
3343 // The USB result will be:
3344 // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or
3345 // remain NoError when Success/ShortPacket Transfer Event is received.
3347 if (PendingUrb
!= NULL
) {
3348 PendingUrb
->Result
= EFI_USB_NOERROR
;
3352 // Send stop endpoint command to transit Endpoint from running to stop state
3354 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
3355 CmdTrbStopED
.CycleBit
= 1;
3356 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
3357 CmdTrbStopED
.EDID
= Dci
;
3358 CmdTrbStopED
.SlotId
= SlotId
;
3359 Status
= XhcCmdTransfer (
3361 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbStopED
,
3362 XHC_GENERIC_TIMEOUT
,
3363 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3365 if (EFI_ERROR(Status
)) {
3366 DEBUG ((DEBUG_ERROR
, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
3369 Xhc
->PendingUrb
= NULL
;
3375 Reset endpoint through XHCI's Reset_Endpoint cmd.
3377 @param Xhc The XHCI Instance.
3378 @param SlotId The slot id to be configured.
3379 @param Dci The device context index of endpoint.
3381 @retval EFI_SUCCESS Reset endpoint successfully.
3382 @retval Others Failed to reset endpoint.
3388 IN USB_XHCI_INSTANCE
*Xhc
,
3394 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3395 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
3397 DEBUG ((DEBUG_INFO
, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3400 // Send stop endpoint command to transit Endpoint from running to stop state
3402 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
3403 CmdTrbResetED
.CycleBit
= 1;
3404 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
3405 CmdTrbResetED
.EDID
= Dci
;
3406 CmdTrbResetED
.SlotId
= SlotId
;
3407 Status
= XhcCmdTransfer (
3409 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
3410 XHC_GENERIC_TIMEOUT
,
3411 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3413 if (EFI_ERROR(Status
)) {
3414 DEBUG ((DEBUG_ERROR
, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
3421 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3423 @param Xhc The XHCI Instance.
3424 @param SlotId The slot id to be configured.
3425 @param Dci The device context index of endpoint.
3426 @param Urb The dequeue pointer of the transfer ring specified
3427 by the urb to be updated.
3429 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
3430 @retval Others Failed to set transfer ring dequeue pointer.
3435 XhcSetTrDequeuePointer (
3436 IN USB_XHCI_INSTANCE
*Xhc
,
3443 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3444 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
3445 EFI_PHYSICAL_ADDRESS PhyAddr
;
3447 DEBUG ((DEBUG_INFO
, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
3450 // Send stop endpoint command to transit Endpoint from running to stop state
3452 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
3453 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
3454 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
3455 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3456 CmdSetTRDeq
.CycleBit
= 1;
3457 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
3458 CmdSetTRDeq
.Endpoint
= Dci
;
3459 CmdSetTRDeq
.SlotId
= SlotId
;
3460 Status
= XhcCmdTransfer (
3462 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
3463 XHC_GENERIC_TIMEOUT
,
3464 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3466 if (EFI_ERROR(Status
)) {
3467 DEBUG ((DEBUG_ERROR
, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
3474 Set interface through XHCI's Configure_Endpoint cmd.
3476 @param Xhc The XHCI Instance.
3477 @param SlotId The slot id to be configured.
3478 @param DeviceSpeed The device's speed.
3479 @param ConfigDesc The pointer to the usb device configuration descriptor.
3480 @param Request USB device request to send.
3482 @retval EFI_SUCCESS Successfully set interface.
3488 IN USB_XHCI_INSTANCE
*Xhc
,
3490 IN UINT8 DeviceSpeed
,
3491 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3492 IN EFI_USB_DEVICE_REQUEST
*Request
3496 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3497 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3498 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3499 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3506 EFI_PHYSICAL_ADDRESS PhyAddr
;
3509 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3510 INPUT_CONTEXT
*InputContext
;
3511 DEVICE_CONTEXT
*OutputContext
;
3512 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3514 Status
= EFI_SUCCESS
;
3516 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3517 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3519 // XHCI 4.6.6 Configure Endpoint
3520 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3521 // Context and Add Context flags as follows:
3522 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3523 // Context and Add Context flags to '0'.
3525 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3526 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3528 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3529 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3531 ASSERT (ConfigDesc
!= NULL
);
3535 IfDescActive
= NULL
;
3538 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3539 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3540 if ((IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) && (IfDesc
->Length
>= sizeof (USB_INTERFACE_DESCRIPTOR
))) {
3541 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3542 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3544 // Find out the active interface descriptor.
3546 IfDescActive
= IfDesc
;
3547 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3549 // Find out the interface descriptor to set.
3555 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3559 // XHCI 4.6.6 Configure Endpoint
3560 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3561 // Context and Add Context flags as follows:
3562 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3563 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3564 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3565 // the Drop Context flag to '1' and Add Context flag to '0'.
3566 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3567 // and Add Context flags shall be set to '1'.
3569 // Below codes are to cover 2), 3) and 4).
3572 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3573 NumEp
= IfDescActive
->NumEndpoints
;
3574 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3575 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3576 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3577 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3580 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
3581 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3585 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3586 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3588 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3594 // XHCI 4.3.6 - Setting Alternate Interfaces
3595 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3597 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
, NULL
);
3598 if (EFI_ERROR (Status
)) {
3602 // XHCI 4.3.6 - Setting Alternate Interfaces
3603 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3605 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3606 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3607 if (RingSeg
!= NULL
) {
3608 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3610 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3611 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3615 // Set the Drop Context flag to '1'.
3617 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3619 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3623 // XHCI 4.3.6 - Setting Alternate Interfaces
3624 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3625 // Interface setting, to '0'.
3627 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3631 // XHCI 4.3.6 - Setting Alternate Interfaces
3632 // 4) For each endpoint enabled by the Configure Endpoint Command:
3633 // a. Allocate a Transfer Ring.
3634 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3635 // c. Initialize the Endpoint Context data structure.
3637 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3642 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3643 InputContext
->Slot
.ContextEntries
= MaxDci
;
3645 // XHCI 4.3.6 - Setting Alternate Interfaces
3646 // 5) Issue and successfully complete a Configure Endpoint Command.
3648 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3649 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3650 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3651 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3652 CmdTrbCfgEP
.CycleBit
= 1;
3653 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3654 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3655 DEBUG ((DEBUG_INFO
, "SetInterface: Configure Endpoint\n"));
3656 Status
= XhcCmdTransfer (
3658 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3659 XHC_GENERIC_TIMEOUT
,
3660 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3662 if (EFI_ERROR (Status
)) {
3663 DEBUG ((DEBUG_ERROR
, "SetInterface: Config Endpoint Failed, Status = %r\n", Status
));
3666 // Update the active AlternateSetting.
3668 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3676 Set interface through XHCI's Configure_Endpoint cmd.
3678 @param Xhc The XHCI Instance.
3679 @param SlotId The slot id to be configured.
3680 @param DeviceSpeed The device's speed.
3681 @param ConfigDesc The pointer to the usb device configuration descriptor.
3682 @param Request USB device request to send.
3684 @retval EFI_SUCCESS Successfully set interface.
3690 IN USB_XHCI_INSTANCE
*Xhc
,
3692 IN UINT8 DeviceSpeed
,
3693 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3694 IN EFI_USB_DEVICE_REQUEST
*Request
3698 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3699 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3700 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3701 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3708 EFI_PHYSICAL_ADDRESS PhyAddr
;
3711 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3712 INPUT_CONTEXT_64
*InputContext
;
3713 DEVICE_CONTEXT_64
*OutputContext
;
3714 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3716 Status
= EFI_SUCCESS
;
3718 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3719 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3721 // XHCI 4.6.6 Configure Endpoint
3722 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3723 // Context and Add Context flags as follows:
3724 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3725 // Context and Add Context flags to '0'.
3727 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3728 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3730 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3731 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3733 ASSERT (ConfigDesc
!= NULL
);
3737 IfDescActive
= NULL
;
3740 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3741 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3742 if ((IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) && (IfDesc
->Length
>= sizeof (USB_INTERFACE_DESCRIPTOR
))) {
3743 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3744 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3746 // Find out the active interface descriptor.
3748 IfDescActive
= IfDesc
;
3749 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3751 // Find out the interface descriptor to set.
3757 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3761 // XHCI 4.6.6 Configure Endpoint
3762 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3763 // Context and Add Context flags as follows:
3764 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3765 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3766 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3767 // the Drop Context flag to '1' and Add Context flag to '0'.
3768 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3769 // and Add Context flags shall be set to '1'.
3771 // Below codes are to cover 2), 3) and 4).
3774 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3775 NumEp
= IfDescActive
->NumEndpoints
;
3776 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3777 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3778 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3779 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3782 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
3783 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3787 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3788 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3790 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3796 // XHCI 4.3.6 - Setting Alternate Interfaces
3797 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3799 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
, NULL
);
3800 if (EFI_ERROR (Status
)) {
3804 // XHCI 4.3.6 - Setting Alternate Interfaces
3805 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3807 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3808 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3809 if (RingSeg
!= NULL
) {
3810 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3812 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3813 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3817 // Set the Drop Context flag to '1'.
3819 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3821 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3825 // XHCI 4.3.6 - Setting Alternate Interfaces
3826 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3827 // Interface setting, to '0'.
3829 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3833 // XHCI 4.3.6 - Setting Alternate Interfaces
3834 // 4) For each endpoint enabled by the Configure Endpoint Command:
3835 // a. Allocate a Transfer Ring.
3836 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3837 // c. Initialize the Endpoint Context data structure.
3839 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3844 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3845 InputContext
->Slot
.ContextEntries
= MaxDci
;
3847 // XHCI 4.3.6 - Setting Alternate Interfaces
3848 // 5) Issue and successfully complete a Configure Endpoint Command.
3850 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3851 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3852 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3853 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3854 CmdTrbCfgEP
.CycleBit
= 1;
3855 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3856 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3857 DEBUG ((DEBUG_INFO
, "SetInterface64: Configure Endpoint\n"));
3858 Status
= XhcCmdTransfer (
3860 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3861 XHC_GENERIC_TIMEOUT
,
3862 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3864 if (EFI_ERROR (Status
)) {
3865 DEBUG ((DEBUG_ERROR
, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status
));
3868 // Update the active AlternateSetting.
3870 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3878 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3880 @param Xhc The XHCI Instance.
3881 @param SlotId The slot id to be evaluated.
3882 @param MaxPacketSize The max packet size supported by the device control transfer.
3884 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3889 XhcEvaluateContext (
3890 IN USB_XHCI_INSTANCE
*Xhc
,
3892 IN UINT32 MaxPacketSize
3896 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3897 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3898 INPUT_CONTEXT
*InputContext
;
3899 EFI_PHYSICAL_ADDRESS PhyAddr
;
3901 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3904 // 4.6.7 Evaluate Context
3906 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3907 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3909 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3910 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3912 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3913 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3914 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3915 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3916 CmdTrbEvalu
.CycleBit
= 1;
3917 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3918 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3919 DEBUG ((DEBUG_INFO
, "Evaluate context\n"));
3920 Status
= XhcCmdTransfer (
3922 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3923 XHC_GENERIC_TIMEOUT
,
3924 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3926 if (EFI_ERROR (Status
)) {
3927 DEBUG ((DEBUG_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
3933 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3935 @param Xhc The XHCI Instance.
3936 @param SlotId The slot id to be evaluated.
3937 @param MaxPacketSize The max packet size supported by the device control transfer.
3939 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3944 XhcEvaluateContext64 (
3945 IN USB_XHCI_INSTANCE
*Xhc
,
3947 IN UINT32 MaxPacketSize
3951 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3952 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3953 INPUT_CONTEXT_64
*InputContext
;
3954 EFI_PHYSICAL_ADDRESS PhyAddr
;
3956 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3959 // 4.6.7 Evaluate Context
3961 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3962 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3964 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3965 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3967 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3968 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3969 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3970 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3971 CmdTrbEvalu
.CycleBit
= 1;
3972 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3973 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3974 DEBUG ((DEBUG_INFO
, "Evaluate context\n"));
3975 Status
= XhcCmdTransfer (
3977 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3978 XHC_GENERIC_TIMEOUT
,
3979 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3981 if (EFI_ERROR (Status
)) {
3982 DEBUG ((DEBUG_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
3989 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3991 @param Xhc The XHCI Instance.
3992 @param SlotId The slot id to be configured.
3993 @param PortNum The total number of downstream port supported by the hub.
3994 @param TTT The TT think time of the hub device.
3995 @param MTT The multi-TT of the hub device.
3997 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
4001 XhcConfigHubContext (
4002 IN USB_XHCI_INSTANCE
*Xhc
,
4010 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
4011 INPUT_CONTEXT
*InputContext
;
4012 DEVICE_CONTEXT
*OutputContext
;
4013 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
4014 EFI_PHYSICAL_ADDRESS PhyAddr
;
4016 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
4017 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
4018 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
4021 // 4.6.7 Evaluate Context
4023 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
4025 InputContext
->InputControlContext
.Dword2
|= BIT0
;
4028 // Copy the slot context from OutputContext to Input context
4030 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
4031 InputContext
->Slot
.Hub
= 1;
4032 InputContext
->Slot
.PortNum
= PortNum
;
4033 InputContext
->Slot
.TTT
= TTT
;
4034 InputContext
->Slot
.MTT
= MTT
;
4036 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
4037 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
4038 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
4039 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
4040 CmdTrbCfgEP
.CycleBit
= 1;
4041 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
4042 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
4043 DEBUG ((DEBUG_INFO
, "Configure Hub Slot Context\n"));
4044 Status
= XhcCmdTransfer (
4046 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
4047 XHC_GENERIC_TIMEOUT
,
4048 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
4050 if (EFI_ERROR (Status
)) {
4051 DEBUG ((DEBUG_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
4057 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
4059 @param Xhc The XHCI Instance.
4060 @param SlotId The slot id to be configured.
4061 @param PortNum The total number of downstream port supported by the hub.
4062 @param TTT The TT think time of the hub device.
4063 @param MTT The multi-TT of the hub device.
4065 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
4069 XhcConfigHubContext64 (
4070 IN USB_XHCI_INSTANCE
*Xhc
,
4078 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
4079 INPUT_CONTEXT_64
*InputContext
;
4080 DEVICE_CONTEXT_64
*OutputContext
;
4081 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
4082 EFI_PHYSICAL_ADDRESS PhyAddr
;
4084 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
4085 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
4086 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
4089 // 4.6.7 Evaluate Context
4091 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
4093 InputContext
->InputControlContext
.Dword2
|= BIT0
;
4096 // Copy the slot context from OutputContext to Input context
4098 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
4099 InputContext
->Slot
.Hub
= 1;
4100 InputContext
->Slot
.PortNum
= PortNum
;
4101 InputContext
->Slot
.TTT
= TTT
;
4102 InputContext
->Slot
.MTT
= MTT
;
4104 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
4105 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
4106 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
4107 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
4108 CmdTrbCfgEP
.CycleBit
= 1;
4109 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
4110 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
4111 DEBUG ((DEBUG_INFO
, "Configure Hub Slot Context\n"));
4112 Status
= XhcCmdTransfer (
4114 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
4115 XHC_GENERIC_TIMEOUT
,
4116 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
4118 if (EFI_ERROR (Status
)) {
4119 DEBUG ((DEBUG_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));