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 ((EFI_D_ERROR
, "XhcCmdTransfer: HC is halted\n"));
90 // Create a new URB, then poll the execution status.
92 Urb
= XhcCreateCmdTrb (Xhc
, CmdTrb
);
95 DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_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
->Ep
.Direction
== EfiUsbDataIn
) {
302 TrbStart
->TrbCtrSetup
.TRT
= 3;
303 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
304 TrbStart
->TrbCtrSetup
.TRT
= 2;
306 TrbStart
->TrbCtrSetup
.TRT
= 0;
309 // Update the cycle bit
311 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
315 // For control transfer, create DATA_STAGE_TRB.
317 if (Urb
->DataLen
> 0) {
318 XhcSyncTrsRing (Xhc
, EPRing
);
319 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
320 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT(Urb
->DataPhy
);
321 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT(Urb
->DataPhy
);
322 TrbStart
->TrbCtrData
.Length
= (UINT32
) Urb
->DataLen
;
323 TrbStart
->TrbCtrData
.TDSize
= 0;
324 TrbStart
->TrbCtrData
.IntTarget
= 0;
325 TrbStart
->TrbCtrData
.ISP
= 1;
326 TrbStart
->TrbCtrData
.IOC
= 1;
327 TrbStart
->TrbCtrData
.IDT
= 0;
328 TrbStart
->TrbCtrData
.CH
= 0;
329 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
330 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
331 TrbStart
->TrbCtrData
.DIR = 1;
332 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
333 TrbStart
->TrbCtrData
.DIR = 0;
335 TrbStart
->TrbCtrData
.DIR = 0;
338 // Update the cycle bit
340 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
344 // For control transfer, create STATUS_STAGE_TRB.
345 // Get the pointer to next TRB for status stage use
347 XhcSyncTrsRing (Xhc
, EPRing
);
348 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
349 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
350 TrbStart
->TrbCtrStatus
.IOC
= 1;
351 TrbStart
->TrbCtrStatus
.CH
= 0;
352 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
353 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
354 TrbStart
->TrbCtrStatus
.DIR = 0;
355 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
356 TrbStart
->TrbCtrStatus
.DIR = 1;
358 TrbStart
->TrbCtrStatus
.DIR = 0;
361 // Update the cycle bit
363 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
365 // Update the enqueue pointer
367 XhcSyncTrsRing (Xhc
, EPRing
);
369 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
378 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
379 while (TotalLen
< Urb
->DataLen
) {
380 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
381 Len
= Urb
->DataLen
- TotalLen
;
385 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
386 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
387 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
388 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
389 TrbStart
->TrbNormal
.TDSize
= 0;
390 TrbStart
->TrbNormal
.IntTarget
= 0;
391 TrbStart
->TrbNormal
.ISP
= 1;
392 TrbStart
->TrbNormal
.IOC
= 1;
393 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
395 // Update the cycle bit
397 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
399 XhcSyncTrsRing (Xhc
, EPRing
);
404 Urb
->TrbNum
= TrbNum
;
405 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
408 case ED_INTERRUPT_OUT
:
409 case ED_INTERRUPT_IN
:
413 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
414 while (TotalLen
< Urb
->DataLen
) {
415 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
416 Len
= Urb
->DataLen
- TotalLen
;
420 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
421 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
422 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
423 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
424 TrbStart
->TrbNormal
.TDSize
= 0;
425 TrbStart
->TrbNormal
.IntTarget
= 0;
426 TrbStart
->TrbNormal
.ISP
= 1;
427 TrbStart
->TrbNormal
.IOC
= 1;
428 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
430 // Update the cycle bit
432 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
434 XhcSyncTrsRing (Xhc
, EPRing
);
439 Urb
->TrbNum
= TrbNum
;
440 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
444 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
454 Initialize the XHCI host controller for schedule.
456 @param Xhc The XHCI Instance to be initialized.
461 IN USB_XHCI_INSTANCE
*Xhc
465 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
467 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
469 UINT32 MaxScratchpadBufs
;
471 EFI_PHYSICAL_ADDRESS ScratchPhy
;
472 UINT64
*ScratchEntry
;
473 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
475 UINTN
*ScratchEntryMap
;
479 // Initialize memory management.
481 Xhc
->MemPool
= UsbHcInitMemPool (Xhc
->PciIo
);
482 ASSERT (Xhc
->MemPool
!= NULL
);
485 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
486 // to enable the device slots that system software is going to use.
488 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
489 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
490 XhcWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, Xhc
->MaxSlotsEn
);
493 // The Device Context Base Address Array entry associated with each allocated Device Slot
494 // shall contain a 64-bit pointer to the base of the associated Device Context.
495 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
496 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
498 Entries
= (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
);
499 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Entries
);
500 ASSERT (Dcbaa
!= NULL
);
501 ZeroMem (Dcbaa
, Entries
);
504 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
505 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
506 // mode (Run/Stop(R/S) ='1').
508 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
509 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
510 ASSERT (MaxScratchpadBufs
<= 1023);
511 if (MaxScratchpadBufs
!= 0) {
513 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
515 ScratchEntryMap
= AllocateZeroPool (sizeof (UINTN
) * MaxScratchpadBufs
);
516 ASSERT (ScratchEntryMap
!= NULL
);
517 Xhc
->ScratchEntryMap
= ScratchEntryMap
;
520 // Allocate the buffer to record the host address for each entry
522 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
523 ASSERT (ScratchEntry
!= NULL
);
524 Xhc
->ScratchEntry
= ScratchEntry
;
527 Status
= UsbHcAllocateAlignedPages (
529 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
531 (VOID
**) &ScratchBuf
,
535 ASSERT_EFI_ERROR (Status
);
537 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
538 Xhc
->ScratchBuf
= ScratchBuf
;
541 // Allocate each scratch buffer
543 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
545 Status
= UsbHcAllocateAlignedPages (
547 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
549 (VOID
**) &ScratchEntry
[Index
],
551 (VOID
**) &ScratchEntryMap
[Index
]
553 ASSERT_EFI_ERROR (Status
);
554 ZeroMem ((VOID
*)(UINTN
)ScratchEntry
[Index
], Xhc
->PageSize
);
556 // Fill with the PCI device address
558 *ScratchBuf
++ = ScratchEntryPhy
;
561 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
562 // Device Context Base Address Array points to the Scratchpad Buffer Array.
564 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
) ScratchPhy
;
568 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
569 // a 64-bit address pointing to where the Device Context Base Address Array is located.
571 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
573 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
574 // So divide it to two 32-bytes width register access.
576 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Entries
);
577 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT(DcbaaPhy
));
578 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
580 DEBUG ((EFI_D_INFO
, "XhcInitSched:DCBAA=0x%x\n", (UINT64
)(UINTN
)Xhc
->DCBAA
));
583 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
584 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
585 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
588 CreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
590 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
591 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
592 // So we set RCS as inverted PCS init value to let Command Ring empty
594 CmdRing
= (UINT64
)(UINTN
)Xhc
->CmdRing
.RingSeg0
;
595 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) CmdRing
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
596 ASSERT ((CmdRingPhy
& 0x3F) == 0);
597 CmdRingPhy
|= XHC_CRCR_RCS
;
599 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
600 // So divide it to two 32-bytes width register access.
602 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT(CmdRingPhy
));
603 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
606 // Disable the 'interrupter enable' bit in USB_CMD
607 // and clear IE & IP bit in all Interrupter X Management Registers.
609 XhcClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
610 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
611 XhcClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
612 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
616 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
618 CreateEventRing (Xhc
, &Xhc
->EventRing
);
619 DEBUG ((DEBUG_INFO
, "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",
620 Xhc
->CmdRing
.RingSeg0
, (UINTN
)Xhc
->CmdRing
.RingSeg0
+ sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
,
621 Xhc
->EventRing
.EventRingSeg0
, (UINTN
)Xhc
->EventRing
.EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
626 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
627 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
628 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
629 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
630 Stopped to the Running state.
632 @param Xhc The XHCI Instance.
633 @param Urb The urb which makes the endpoint halted.
635 @retval EFI_SUCCESS The recovery is successful.
636 @retval Others Failed to recovery halted endpoint.
641 XhcRecoverHaltedEndpoint (
642 IN USB_XHCI_INSTANCE
*Xhc
,
650 Status
= EFI_SUCCESS
;
651 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
653 return EFI_DEVICE_ERROR
;
655 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
658 DEBUG ((EFI_D_INFO
, "Recovery Halted Slot = %x,Dci = %x\n", SlotId
, Dci
));
661 // 1) Send Reset endpoint command to transit from halt to stop state
663 Status
= XhcResetEndpoint(Xhc
, SlotId
, Dci
);
664 if (EFI_ERROR(Status
)) {
665 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
670 // 2)Set dequeue pointer
672 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
673 if (EFI_ERROR(Status
)) {
674 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
679 // 3)Ring the doorbell to transit from stop to active
681 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
688 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
689 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
690 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
693 @param Xhc The XHCI Instance.
694 @param Urb The urb which doesn't get completed in a specified timeout range.
696 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
697 @retval EFI_ALREADY_STARTED The Urb is finished so no deque is needed.
698 @retval Others Failed to stop the endpoint and dequeue the TDs.
703 XhcDequeueTrbFromEndpoint (
704 IN USB_XHCI_INSTANCE
*Xhc
,
712 Status
= EFI_SUCCESS
;
713 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
715 return EFI_DEVICE_ERROR
;
717 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
720 DEBUG ((EFI_D_INFO
, "Stop Slot = %x,Dci = %x\n", SlotId
, Dci
));
723 // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint
725 Status
= XhcStopEndpoint(Xhc
, SlotId
, Dci
, Urb
);
726 if (EFI_ERROR(Status
)) {
727 DEBUG ((EFI_D_ERROR
, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
732 // 2)Set dequeue pointer
734 if (Urb
->Finished
&& Urb
->Result
== EFI_USB_NOERROR
) {
736 // Return Already Started to indicate the pending URB is finished.
737 // This fixes BULK data loss when transfer is detected as timeout
738 // but finished just before stopping endpoint.
740 Status
= EFI_ALREADY_STARTED
;
741 DEBUG ((DEBUG_INFO
, "XhcDequeueTrbFromEndpoint: Pending URB is finished: Length Actual/Expect = %d/%d!\n", Urb
->Completed
, Urb
->DataLen
));
743 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
744 if (EFI_ERROR (Status
)) {
745 DEBUG ((DEBUG_ERROR
, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
751 // 3)Ring the doorbell to transit from stop to active
753 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
760 Create XHCI event ring.
762 @param Xhc The XHCI Instance.
763 @param EventRing The created event ring.
768 IN USB_XHCI_INSTANCE
*Xhc
,
769 OUT EVENT_RING
*EventRing
773 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
775 EFI_PHYSICAL_ADDRESS ERSTPhy
;
776 EFI_PHYSICAL_ADDRESS DequeuePhy
;
778 ASSERT (EventRing
!= NULL
);
780 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
781 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
782 ASSERT (Buf
!= NULL
);
783 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
786 EventRing
->EventRingSeg0
= Buf
;
787 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
788 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
789 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
791 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
794 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
795 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
797 EventRing
->EventRingCCS
= 1;
799 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
800 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
801 ASSERT (Buf
!= NULL
);
802 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
805 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
806 EventRing
->ERSTBase
= ERSTBase
;
807 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
808 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
809 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
811 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, ERSTBase
, Size
);
814 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
822 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
824 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
825 // So divide it to two 32-bytes width register access.
830 XHC_LOW_32BIT((UINT64
)(UINTN
)DequeuePhy
)
835 XHC_HIGH_32BIT((UINT64
)(UINTN
)DequeuePhy
)
838 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
840 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
841 // So divide it to two 32-bytes width register access.
846 XHC_LOW_32BIT((UINT64
)(UINTN
)ERSTPhy
)
850 XHC_ERSTBA_OFFSET
+ 4,
851 XHC_HIGH_32BIT((UINT64
)(UINTN
)ERSTPhy
)
854 // Need set IMAN IE bit to enble the ring interrupt
856 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
860 Create XHCI transfer ring.
862 @param Xhc The XHCI Instance.
863 @param TrbNum The number of TRB in the ring.
864 @param TransferRing The created transfer ring.
869 IN USB_XHCI_INSTANCE
*Xhc
,
871 OUT TRANSFER_RING
*TransferRing
876 EFI_PHYSICAL_ADDRESS PhyAddr
;
878 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
879 ASSERT (Buf
!= NULL
);
880 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
881 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
883 TransferRing
->RingSeg0
= Buf
;
884 TransferRing
->TrbNumber
= TrbNum
;
885 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
886 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
887 TransferRing
->RingPCS
= 1;
889 // 4.9.2 Transfer Ring Management
890 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
891 // point to the first TRB in the ring.
893 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
894 EndTrb
->Type
= TRB_TYPE_LINK
;
895 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
896 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
897 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
899 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
903 // Set Cycle bit as other TRB PCS init value
905 EndTrb
->CycleBit
= 0;
909 Free XHCI event ring.
911 @param Xhc The XHCI Instance.
912 @param EventRing The event ring to be freed.
918 IN USB_XHCI_INSTANCE
*Xhc
,
919 IN EVENT_RING
*EventRing
922 if(EventRing
->EventRingSeg0
== NULL
) {
927 // Free EventRing Segment 0
929 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
934 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
939 Free the resouce allocated at initializing schedule.
941 @param Xhc The XHCI Instance.
946 IN USB_XHCI_INSTANCE
*Xhc
950 UINT64
*ScratchEntry
;
952 if (Xhc
->ScratchBuf
!= NULL
) {
953 ScratchEntry
= Xhc
->ScratchEntry
;
954 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
956 // Free Scratchpad Buffers
958 UsbHcFreeAlignedPages (Xhc
->PciIo
, (VOID
*)(UINTN
)ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*) Xhc
->ScratchEntryMap
[Index
]);
961 // Free Scratchpad Buffer Array
963 UsbHcFreeAlignedPages (Xhc
->PciIo
, Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
964 FreePool (Xhc
->ScratchEntryMap
);
965 FreePool (Xhc
->ScratchEntry
);
968 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
969 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
970 Xhc
->CmdRing
.RingSeg0
= NULL
;
973 XhcFreeEventRing (Xhc
,&Xhc
->EventRing
);
975 if (Xhc
->DCBAA
!= NULL
) {
976 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
));
981 // Free memory pool at last
983 if (Xhc
->MemPool
!= NULL
) {
984 UsbHcFreeMemPool (Xhc
->MemPool
);
990 Check if the Trb is a transaction of the URB.
992 @param Xhc The XHCI Instance.
993 @param Trb The TRB to be checked
994 @param Urb The URB to be checked.
996 @retval TRUE It is a transaction of the URB.
997 @retval FALSE It is not any transaction of the URB.
1002 IN USB_XHCI_INSTANCE
*Xhc
,
1003 IN TRB_TEMPLATE
*Trb
,
1008 TRB_TEMPLATE
*CheckedTrb
;
1010 EFI_PHYSICAL_ADDRESS PhyAddr
;
1012 CheckedTrb
= Urb
->TrbStart
;
1013 for (Index
= 0; Index
< Urb
->TrbNum
; Index
++) {
1014 if (Trb
== CheckedTrb
) {
1019 // If the checked TRB is the link TRB at the end of the transfer ring,
1020 // recircle it to the head of the ring.
1022 if (CheckedTrb
->Type
== TRB_TYPE_LINK
) {
1023 LinkTrb
= (LINK_TRB
*) CheckedTrb
;
1024 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(LinkTrb
->PtrLo
| LShiftU64 ((UINT64
) LinkTrb
->PtrHi
, 32));
1025 CheckedTrb
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1026 ASSERT (CheckedTrb
== Urb
->Ring
->RingSeg0
);
1034 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
1036 @param Xhc The XHCI Instance.
1037 @param Trb The TRB to be checked.
1038 @param Urb The pointer to the matched Urb.
1040 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
1041 @retval FALSE The Trb is not matched with any URBs in the async list.
1046 IN USB_XHCI_INSTANCE
*Xhc
,
1047 IN TRB_TEMPLATE
*Trb
,
1055 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1056 CheckedUrb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1057 if (IsTransferRingTrb (Xhc
, Trb
, CheckedUrb
)) {
1068 Check the URB's execution result and update the URB's
1071 @param Xhc The XHCI Instance.
1072 @param Urb The URB to check result.
1074 @return Whether the result of URB transfer is finialized.
1079 IN USB_XHCI_INSTANCE
*Xhc
,
1083 EVT_TRB_TRANSFER
*EvtTrb
;
1084 TRB_TEMPLATE
*TRBPtr
;
1093 EFI_PHYSICAL_ADDRESS PhyAddr
;
1095 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
1097 Status
= EFI_SUCCESS
;
1100 if (Urb
->Finished
) {
1106 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1107 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
1112 // Traverse the event ring to find out all new events from the previous check.
1114 XhcSyncEventRing (Xhc
, &Xhc
->EventRing
);
1115 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
1116 Status
= XhcCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
1117 if (Status
== EFI_NOT_READY
) {
1119 // All new events are handled, return directly.
1125 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1127 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
1132 // Need convert pci device address to host address
1134 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
1135 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1138 // Update the status of URB including the pending URB, the URB that is currently checked,
1139 // and URBs in the XHCI's async interrupt transfer list.
1140 // This way is used to avoid that those completed async transfer events don't get
1141 // handled in time and are flushed by newer coming events.
1143 if (Xhc
->PendingUrb
!= NULL
&& IsTransferRingTrb (Xhc
, TRBPtr
, Xhc
->PendingUrb
)) {
1144 CheckedUrb
= Xhc
->PendingUrb
;
1145 } else if (IsTransferRingTrb (Xhc
, TRBPtr
, Urb
)) {
1147 } else if (IsAsyncIntTrb (Xhc
, TRBPtr
, &AsyncUrb
)) {
1148 CheckedUrb
= AsyncUrb
;
1153 switch (EvtTrb
->Completecode
) {
1154 case TRB_COMPLETION_STALL_ERROR
:
1155 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
1156 CheckedUrb
->Finished
= TRUE
;
1157 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1160 case TRB_COMPLETION_BABBLE_ERROR
:
1161 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
1162 CheckedUrb
->Finished
= TRUE
;
1163 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1166 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
1167 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
1168 CheckedUrb
->Finished
= TRUE
;
1169 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
1172 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
1173 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1174 CheckedUrb
->Finished
= TRUE
;
1175 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1178 case TRB_COMPLETION_STOPPED
:
1179 case TRB_COMPLETION_STOPPED_LENGTH_INVALID
:
1180 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1181 CheckedUrb
->Finished
= TRUE
;
1183 // The pending URB is timeout and force stopped when stopping endpoint.
1184 // Continue the loop to receive the Command Complete Event for stopping endpoint.
1188 case TRB_COMPLETION_SHORT_PACKET
:
1189 case TRB_COMPLETION_SUCCESS
:
1190 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
1191 DEBUG ((EFI_D_VERBOSE
, "XhcCheckUrbResult: short packet happens!\n"));
1194 TRBType
= (UINT8
) (TRBPtr
->Type
);
1195 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
1196 (TRBType
== TRB_TYPE_NORMAL
) ||
1197 (TRBType
== TRB_TYPE_ISOCH
)) {
1198 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
1204 DEBUG ((EFI_D_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
1205 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1206 CheckedUrb
->Finished
= TRUE
;
1211 // Only check first and end Trb event address
1213 if (TRBPtr
== CheckedUrb
->TrbStart
) {
1214 CheckedUrb
->StartDone
= TRUE
;
1217 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
1218 CheckedUrb
->EndDone
= TRUE
;
1221 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
1222 CheckedUrb
->Finished
= TRUE
;
1223 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
1230 // Advance event ring to last available entry
1232 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1233 // So divide it to two 32-bytes width register access.
1235 Low
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
1236 High
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
1237 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
1239 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
1241 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
1243 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1244 // So divide it to two 32-bytes width register access.
1246 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
1247 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
1250 return Urb
->Finished
;
1255 Execute the transfer by polling the URB. This is a synchronous operation.
1257 @param Xhc The XHCI Instance.
1258 @param CmdTransfer The executed URB is for cmd transfer or not.
1259 @param Urb The URB to execute.
1260 @param Timeout The time to wait before abort, in millisecond.
1262 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1263 @return EFI_TIMEOUT The transfer failed due to time out.
1264 @return EFI_SUCCESS The transfer finished OK.
1265 @retval EFI_OUT_OF_RESOURCES Memory for the timer event could not be allocated.
1270 IN USB_XHCI_INSTANCE
*Xhc
,
1271 IN BOOLEAN CmdTransfer
,
1280 EFI_EVENT TimeoutEvent
;
1281 BOOLEAN IndefiniteTimeout
;
1283 Status
= EFI_SUCCESS
;
1285 TimeoutEvent
= NULL
;
1286 IndefiniteTimeout
= FALSE
;
1292 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1294 return EFI_DEVICE_ERROR
;
1296 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1301 IndefiniteTimeout
= TRUE
;
1305 Status
= gBS
->CreateEvent (
1313 if (EFI_ERROR (Status
)) {
1317 Status
= gBS
->SetTimer (TimeoutEvent
,
1319 EFI_TIMER_PERIOD_MILLISECONDS(Timeout
));
1321 if (EFI_ERROR (Status
)) {
1326 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1329 Finished
= XhcCheckUrbResult (Xhc
, Urb
);
1333 gBS
->Stall (XHC_1_MICROSECOND
);
1334 } while (IndefiniteTimeout
|| EFI_ERROR(gBS
->CheckEvent (TimeoutEvent
)));
1337 if (EFI_ERROR(Status
)) {
1338 Urb
->Result
= EFI_USB_ERR_NOTEXECUTE
;
1339 } else if (!Finished
) {
1340 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
1341 Status
= EFI_TIMEOUT
;
1342 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
1343 Status
= EFI_DEVICE_ERROR
;
1346 if (TimeoutEvent
!= NULL
) {
1347 gBS
->CloseEvent (TimeoutEvent
);
1354 Delete a single asynchronous interrupt transfer for
1355 the device and endpoint.
1357 @param Xhc The XHCI Instance.
1358 @param BusAddr The logical device address assigned by UsbBus driver.
1359 @param EpNum The endpoint of the target.
1361 @retval EFI_SUCCESS An asynchronous transfer is removed.
1362 @retval EFI_NOT_FOUND No transfer for the device is found.
1366 XhciDelAsyncIntTransfer (
1367 IN USB_XHCI_INSTANCE
*Xhc
,
1375 EFI_USB_DATA_DIRECTION Direction
;
1378 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1383 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1384 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1385 if ((Urb
->Ep
.BusAddr
== BusAddr
) &&
1386 (Urb
->Ep
.EpAddr
== EpNum
) &&
1387 (Urb
->Ep
.Direction
== Direction
)) {
1389 // Device doesn't finish the IntTransfer until real data comes
1390 // So the TRB should be removed as well.
1392 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1393 if (EFI_ERROR (Status
)) {
1394 DEBUG ((EFI_D_ERROR
, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));
1397 RemoveEntryList (&Urb
->UrbList
);
1398 FreePool (Urb
->Data
);
1399 XhcFreeUrb (Xhc
, Urb
);
1404 return EFI_NOT_FOUND
;
1408 Remove all the asynchronous interrutp transfers.
1410 @param Xhc The XHCI Instance.
1414 XhciDelAllAsyncIntTransfers (
1415 IN USB_XHCI_INSTANCE
*Xhc
1423 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1424 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1427 // Device doesn't finish the IntTransfer until real data comes
1428 // So the TRB should be removed as well.
1430 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1431 if (EFI_ERROR (Status
)) {
1432 DEBUG ((EFI_D_ERROR
, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));
1435 RemoveEntryList (&Urb
->UrbList
);
1436 FreePool (Urb
->Data
);
1437 XhcFreeUrb (Xhc
, Urb
);
1442 Insert a single asynchronous interrupt transfer for
1443 the device and endpoint.
1445 @param Xhc The XHCI Instance
1446 @param BusAddr The logical device address assigned by UsbBus driver
1447 @param EpAddr Endpoint addrress
1448 @param DevSpeed The device speed
1449 @param MaxPacket The max packet length of the endpoint
1450 @param DataLen The length of data buffer
1451 @param Callback The function to call when data is transferred
1452 @param Context The context to the callback
1454 @return Created URB or NULL
1458 XhciInsertAsyncIntTransfer (
1459 IN USB_XHCI_INSTANCE
*Xhc
,
1465 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
1472 Data
= AllocateZeroPool (DataLen
);
1474 DEBUG ((DEBUG_ERROR
, "%a: failed to allocate buffer\n", __FUNCTION__
));
1478 Urb
= XhcCreateUrb (
1484 XHC_INT_TRANSFER_ASYNC
,
1492 DEBUG ((DEBUG_ERROR
, "%a: failed to create URB\n", __FUNCTION__
));
1498 // New asynchronous transfer must inserted to the head.
1499 // Check the comments in XhcMoniteAsyncRequests
1501 InsertHeadList (&Xhc
->AsyncIntTransfers
, &Urb
->UrbList
);
1507 Update the queue head for next round of asynchronous transfer
1509 @param Xhc The XHCI Instance.
1510 @param Urb The URB to update
1514 XhcUpdateAsyncRequest (
1515 IN USB_XHCI_INSTANCE
*Xhc
,
1521 if (Urb
->Result
== EFI_USB_NOERROR
) {
1522 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1523 if (EFI_ERROR (Status
)) {
1526 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1527 if (EFI_ERROR (Status
)) {
1534 Flush data from PCI controller specific address to mapped system
1537 @param Xhc The XHCI device.
1538 @param Urb The URB to unmap.
1540 @retval EFI_SUCCESS Success to flush data to mapped system memory.
1541 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
1545 XhcFlushAsyncIntMap (
1546 IN USB_XHCI_INSTANCE
*Xhc
,
1551 EFI_PHYSICAL_ADDRESS PhyAddr
;
1552 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
1553 EFI_PCI_IO_PROTOCOL
*PciIo
;
1560 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
1561 MapOp
= EfiPciIoOperationBusMasterWrite
;
1563 MapOp
= EfiPciIoOperationBusMasterRead
;
1566 if (Urb
->DataMap
!= NULL
) {
1567 Status
= PciIo
->Unmap (PciIo
, Urb
->DataMap
);
1568 if (EFI_ERROR (Status
)) {
1573 Urb
->DataMap
= NULL
;
1575 Status
= PciIo
->Map (PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
1576 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
1580 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
1585 return EFI_DEVICE_ERROR
;
1589 Interrupt transfer periodic check handler.
1591 @param Event Interrupt event.
1592 @param Context Pointer to USB_XHCI_INSTANCE.
1597 XhcMonitorAsyncRequests (
1602 USB_XHCI_INSTANCE
*Xhc
;
1611 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1613 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1615 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1616 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1619 // Make sure that the device is available before every check.
1621 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1627 // Check the result of URB execution. If it is still
1628 // active, check the next one.
1630 XhcCheckUrbResult (Xhc
, Urb
);
1632 if (!Urb
->Finished
) {
1637 // Flush any PCI posted write transactions from a PCI host
1638 // bridge to system memory.
1640 Status
= XhcFlushAsyncIntMap (Xhc
, Urb
);
1641 if (EFI_ERROR (Status
)) {
1642 DEBUG ((EFI_D_ERROR
, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1646 // Allocate a buffer then copy the transferred data for user.
1647 // If failed to allocate the buffer, update the URB for next
1648 // round of transfer. Ignore the data of this round.
1651 if (Urb
->Result
== EFI_USB_NOERROR
) {
1653 // Make sure the data received from HW is no more than expected.
1655 if (Urb
->Completed
<= Urb
->DataLen
) {
1656 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1659 if (ProcBuf
== NULL
) {
1660 XhcUpdateAsyncRequest (Xhc
, Urb
);
1664 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1668 // Leave error recovery to its related device driver. A
1669 // common case of the error recovery is to re-submit the
1670 // interrupt transfer which is linked to the head of the
1671 // list. This function scans from head to tail. So the
1672 // re-submitted interrupt transfer's callback function
1673 // will not be called again in this round. Don't touch this
1674 // URB after the callback, it may have been removed by the
1677 if (Urb
->Callback
!= NULL
) {
1679 // Restore the old TPL, USB bus maybe connect device in
1680 // his callback. Some drivers may has a lower TPL restriction.
1682 gBS
->RestoreTPL (OldTpl
);
1683 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1684 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1687 if (ProcBuf
!= NULL
) {
1688 gBS
->FreePool (ProcBuf
);
1691 XhcUpdateAsyncRequest (Xhc
, Urb
);
1693 gBS
->RestoreTPL (OldTpl
);
1697 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1699 @param Xhc The XHCI Instance.
1700 @param ParentRouteChart The route string pointed to the parent device if it exists.
1701 @param Port The port to be polled.
1702 @param PortState The port state.
1704 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1705 @retval Others Should not appear.
1710 XhcPollPortStatusChange (
1711 IN USB_XHCI_INSTANCE
*Xhc
,
1712 IN USB_DEV_ROUTE ParentRouteChart
,
1714 IN EFI_USB_PORT_STATUS
*PortState
1720 USB_DEV_ROUTE RouteChart
;
1722 Status
= EFI_SUCCESS
;
1724 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
1728 if (ParentRouteChart
.Dword
== 0) {
1729 RouteChart
.Route
.RouteString
= 0;
1730 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1731 RouteChart
.Route
.TierNum
= 1;
1734 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1736 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1738 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1739 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1742 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1744 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1745 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1747 Status
= XhcDisableSlotCmd64 (Xhc
, SlotId
);
1751 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1752 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1754 // Has a device attached, Identify device speed after port is enabled.
1756 Speed
= EFI_USB_SPEED_FULL
;
1757 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1758 Speed
= EFI_USB_SPEED_LOW
;
1759 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1760 Speed
= EFI_USB_SPEED_HIGH
;
1761 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1762 Speed
= EFI_USB_SPEED_SUPER
;
1765 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1767 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1768 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
1769 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1770 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1772 Status
= XhcInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1782 Calculate the device context index by endpoint address and direction.
1784 @param EpAddr The target endpoint number.
1785 @param Direction The direction of the target endpoint.
1787 @return The device context index of endpoint.
1801 Index
= (UINT8
) (2 * EpAddr
);
1802 if (Direction
== EfiUsbDataIn
) {
1810 Find out the actual device address according to the requested device address from UsbBus.
1812 @param Xhc The XHCI Instance.
1813 @param BusDevAddr The requested device address by UsbBus upper driver.
1815 @return The actual device address assigned to the device.
1820 XhcBusDevAddrToSlotId (
1821 IN USB_XHCI_INSTANCE
*Xhc
,
1827 for (Index
= 0; Index
< 255; Index
++) {
1828 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1829 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1830 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1839 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1843 Find out the slot id according to the device's route string.
1845 @param Xhc The XHCI Instance.
1846 @param RouteString The route string described the device location.
1848 @return The slot id used by the device.
1853 XhcRouteStringToSlotId (
1854 IN USB_XHCI_INSTANCE
*Xhc
,
1855 IN USB_DEV_ROUTE RouteString
1860 for (Index
= 0; Index
< 255; Index
++) {
1861 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1862 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1863 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1872 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1876 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1878 @param Xhc The XHCI Instance.
1879 @param EvtRing The event ring to sync.
1881 @retval EFI_SUCCESS The event ring is synchronized successfully.
1887 IN USB_XHCI_INSTANCE
*Xhc
,
1888 IN EVENT_RING
*EvtRing
1892 TRB_TEMPLATE
*EvtTrb1
;
1894 ASSERT (EvtRing
!= NULL
);
1897 // Calculate the EventRingEnqueue and EventRingCCS.
1898 // Note: only support single Segment
1900 EvtTrb1
= EvtRing
->EventRingDequeue
;
1902 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1903 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
1909 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1910 EvtTrb1
= EvtRing
->EventRingSeg0
;
1911 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
1915 if (Index
< EvtRing
->TrbNumber
) {
1916 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1925 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1927 @param Xhc The XHCI Instance.
1928 @param TrsRing The transfer ring to sync.
1930 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1936 IN USB_XHCI_INSTANCE
*Xhc
,
1937 IN TRANSFER_RING
*TrsRing
1941 TRB_TEMPLATE
*TrsTrb
;
1943 ASSERT (TrsRing
!= NULL
);
1945 // Calculate the latest RingEnqueue and RingPCS
1947 TrsTrb
= TrsRing
->RingEnqueue
;
1948 ASSERT (TrsTrb
!= NULL
);
1950 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1951 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1955 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1956 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1958 // set cycle bit in Link TRB as normal
1960 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1962 // Toggle PCS maintained by software
1964 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1965 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
1969 ASSERT (Index
!= TrsRing
->TrbNumber
);
1971 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1972 TrsRing
->RingEnqueue
= TrsTrb
;
1976 // Clear the Trb context for enqueue, but reserve the PCS bit
1978 TrsTrb
->Parameter1
= 0;
1979 TrsTrb
->Parameter2
= 0;
1983 TrsTrb
->Control
= 0;
1989 Check if there is a new generated event.
1991 @param Xhc The XHCI Instance.
1992 @param EvtRing The event ring to check.
1993 @param NewEvtTrb The new event TRB found.
1995 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1996 @retval EFI_NOT_READY The event ring has no new event.
2002 IN USB_XHCI_INSTANCE
*Xhc
,
2003 IN EVENT_RING
*EvtRing
,
2004 OUT TRB_TEMPLATE
**NewEvtTrb
2007 ASSERT (EvtRing
!= NULL
);
2009 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
2011 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
2012 return EFI_NOT_READY
;
2015 EvtRing
->EventRingDequeue
++;
2017 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
2019 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
2020 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
2027 Ring the door bell to notify XHCI there is a transaction to be executed.
2029 @param Xhc The XHCI Instance.
2030 @param SlotId The slot id of the target device.
2031 @param Dci The device context index of the target slot or endpoint.
2033 @retval EFI_SUCCESS Successfully ring the door bell.
2039 IN USB_XHCI_INSTANCE
*Xhc
,
2045 XhcWriteDoorBellReg (Xhc
, 0, 0);
2047 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
2054 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
2056 @param Xhc The XHCI Instance.
2057 @param Urb The URB to be rung.
2059 @retval EFI_SUCCESS Successfully ring the door bell.
2063 RingIntTransferDoorBell (
2064 IN USB_XHCI_INSTANCE
*Xhc
,
2071 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
2072 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
2073 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
2078 Assign and initialize the device slot for a new device.
2080 @param Xhc The XHCI Instance.
2081 @param ParentRouteChart The route string pointed to the parent device.
2082 @param ParentPort The port at which the device is located.
2083 @param RouteChart The route string pointed to the device.
2084 @param DeviceSpeed The device speed.
2086 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2091 XhcInitializeDeviceSlot (
2092 IN USB_XHCI_INSTANCE
*Xhc
,
2093 IN USB_DEV_ROUTE ParentRouteChart
,
2094 IN UINT16 ParentPort
,
2095 IN USB_DEV_ROUTE RouteChart
,
2096 IN UINT8 DeviceSpeed
2100 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2101 INPUT_CONTEXT
*InputContext
;
2102 DEVICE_CONTEXT
*OutputContext
;
2103 TRANSFER_RING
*EndpointTransferRing
;
2104 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2105 UINT8 DeviceAddress
;
2106 CMD_TRB_ENABLE_SLOT CmdTrb
;
2109 DEVICE_CONTEXT
*ParentDeviceContext
;
2110 EFI_PHYSICAL_ADDRESS PhyAddr
;
2112 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2113 CmdTrb
.CycleBit
= 1;
2114 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2116 Status
= XhcCmdTransfer (
2118 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2119 XHC_GENERIC_TIMEOUT
,
2120 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2122 if (EFI_ERROR (Status
)) {
2123 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
2126 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2127 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2128 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2129 ASSERT (SlotId
!= 0);
2131 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2132 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2133 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2134 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2135 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2138 // 4.3.3 Device Slot Initialization
2139 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2141 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
2142 ASSERT (InputContext
!= NULL
);
2143 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2144 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2146 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2149 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2150 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2151 // Context are affected by the command.
2153 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2156 // 3) Initialize the Input Slot Context data structure
2158 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2159 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2160 InputContext
->Slot
.ContextEntries
= 1;
2161 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2163 if (RouteChart
.Route
.RouteString
) {
2165 // The device is behind of hub device.
2167 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2168 ASSERT (ParentSlotId
!= 0);
2170 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2172 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2173 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2174 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2175 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2177 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2178 // environment from Full/Low speed signaling environment for a device
2180 InputContext
->Slot
.TTPortNum
= ParentPort
;
2181 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2185 // Inherit the TT parameters from parent device.
2187 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2188 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2190 // If the device is a High speed device then down the speed to be the same as its parent Hub
2192 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2193 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2199 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2201 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2202 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2203 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2205 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2207 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2209 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2210 InputContext
->EP
[0].MaxPacketSize
= 512;
2211 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2212 InputContext
->EP
[0].MaxPacketSize
= 64;
2214 InputContext
->EP
[0].MaxPacketSize
= 8;
2217 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2218 // 1KB, and Bulk and Isoch endpoints 3KB.
2220 InputContext
->EP
[0].AverageTRBLength
= 8;
2221 InputContext
->EP
[0].MaxBurstSize
= 0;
2222 InputContext
->EP
[0].Interval
= 0;
2223 InputContext
->EP
[0].MaxPStreams
= 0;
2224 InputContext
->EP
[0].Mult
= 0;
2225 InputContext
->EP
[0].CErr
= 3;
2228 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2230 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2232 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2233 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2235 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2236 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2239 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2241 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
2242 ASSERT (OutputContext
!= NULL
);
2243 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2244 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
2246 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2248 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2249 // a pointer to the Output Device Context data structure (6.2.1).
2251 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
2253 // Fill DCBAA with PCI device address
2255 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2258 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2259 // Context data structure described above.
2261 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2264 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2265 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2266 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2267 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2268 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2269 CmdTrbAddr
.CycleBit
= 1;
2270 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2271 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2272 Status
= XhcCmdTransfer (
2274 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2275 XHC_GENERIC_TIMEOUT
,
2276 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2278 if (!EFI_ERROR (Status
)) {
2279 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
2280 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2281 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2283 DEBUG ((DEBUG_INFO
, " Address %d assigned unsuccessfully\n"));
2284 XhcDisableSlotCmd (Xhc
, SlotId
);
2291 Assign and initialize the device slot for a new device.
2293 @param Xhc The XHCI Instance.
2294 @param ParentRouteChart The route string pointed to the parent device.
2295 @param ParentPort The port at which the device is located.
2296 @param RouteChart The route string pointed to the device.
2297 @param DeviceSpeed The device speed.
2299 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2304 XhcInitializeDeviceSlot64 (
2305 IN USB_XHCI_INSTANCE
*Xhc
,
2306 IN USB_DEV_ROUTE ParentRouteChart
,
2307 IN UINT16 ParentPort
,
2308 IN USB_DEV_ROUTE RouteChart
,
2309 IN UINT8 DeviceSpeed
2313 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2314 INPUT_CONTEXT_64
*InputContext
;
2315 DEVICE_CONTEXT_64
*OutputContext
;
2316 TRANSFER_RING
*EndpointTransferRing
;
2317 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2318 UINT8 DeviceAddress
;
2319 CMD_TRB_ENABLE_SLOT CmdTrb
;
2322 DEVICE_CONTEXT_64
*ParentDeviceContext
;
2323 EFI_PHYSICAL_ADDRESS PhyAddr
;
2325 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2326 CmdTrb
.CycleBit
= 1;
2327 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2329 Status
= XhcCmdTransfer (
2331 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2332 XHC_GENERIC_TIMEOUT
,
2333 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2335 if (EFI_ERROR (Status
)) {
2336 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
2339 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2340 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2341 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2342 ASSERT (SlotId
!= 0);
2344 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2345 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2346 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2347 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2348 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2351 // 4.3.3 Device Slot Initialization
2352 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2354 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
2355 ASSERT (InputContext
!= NULL
);
2356 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2357 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2359 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2362 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2363 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2364 // Context are affected by the command.
2366 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2369 // 3) Initialize the Input Slot Context data structure
2371 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2372 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2373 InputContext
->Slot
.ContextEntries
= 1;
2374 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2376 if (RouteChart
.Route
.RouteString
) {
2378 // The device is behind of hub device.
2380 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2381 ASSERT (ParentSlotId
!= 0);
2383 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2385 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2386 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2387 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2388 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2390 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2391 // environment from Full/Low speed signaling environment for a device
2393 InputContext
->Slot
.TTPortNum
= ParentPort
;
2394 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2398 // Inherit the TT parameters from parent device.
2400 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2401 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2403 // If the device is a High speed device then down the speed to be the same as its parent Hub
2405 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2406 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2412 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2414 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2415 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2416 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2418 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2420 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2422 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2423 InputContext
->EP
[0].MaxPacketSize
= 512;
2424 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2425 InputContext
->EP
[0].MaxPacketSize
= 64;
2427 InputContext
->EP
[0].MaxPacketSize
= 8;
2430 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2431 // 1KB, and Bulk and Isoch endpoints 3KB.
2433 InputContext
->EP
[0].AverageTRBLength
= 8;
2434 InputContext
->EP
[0].MaxBurstSize
= 0;
2435 InputContext
->EP
[0].Interval
= 0;
2436 InputContext
->EP
[0].MaxPStreams
= 0;
2437 InputContext
->EP
[0].Mult
= 0;
2438 InputContext
->EP
[0].CErr
= 3;
2441 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2443 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2445 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2446 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2448 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2449 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2452 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2454 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
2455 ASSERT (OutputContext
!= NULL
);
2456 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2457 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2459 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2461 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2462 // a pointer to the Output Device Context data structure (6.2.1).
2464 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2466 // Fill DCBAA with PCI device address
2468 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2471 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2472 // Context data structure described above.
2474 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2477 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2478 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2479 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2480 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2481 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2482 CmdTrbAddr
.CycleBit
= 1;
2483 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2484 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2485 Status
= XhcCmdTransfer (
2487 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2488 XHC_GENERIC_TIMEOUT
,
2489 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2491 if (!EFI_ERROR (Status
)) {
2492 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT_64
*) OutputContext
)->Slot
.DeviceAddress
;
2493 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2494 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2496 DEBUG ((DEBUG_INFO
, " Address %d assigned unsuccessfully\n"));
2497 XhcDisableSlotCmd64 (Xhc
, SlotId
);
2505 Disable the specified device slot.
2507 @param Xhc The XHCI Instance.
2508 @param SlotId The slot id to be disabled.
2510 @retval EFI_SUCCESS Successfully disable the device slot.
2516 IN USB_XHCI_INSTANCE
*Xhc
,
2521 TRB_TEMPLATE
*EvtTrb
;
2522 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2527 // Disable the device slots occupied by these devices on its downstream ports.
2528 // Entry 0 is reserved.
2530 for (Index
= 0; Index
< 255; Index
++) {
2531 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2532 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2533 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2537 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2539 if (EFI_ERROR (Status
)) {
2540 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2541 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2546 // Construct the disable slot command
2548 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2550 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2551 CmdTrbDisSlot
.CycleBit
= 1;
2552 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2553 CmdTrbDisSlot
.SlotId
= SlotId
;
2554 Status
= XhcCmdTransfer (
2556 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2557 XHC_GENERIC_TIMEOUT
,
2558 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2560 if (EFI_ERROR (Status
)) {
2561 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2565 // Free the slot's device context entry
2567 Xhc
->DCBAA
[SlotId
] = 0;
2570 // Free the slot related data structure
2572 for (Index
= 0; Index
< 31; Index
++) {
2573 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2574 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2575 if (RingSeg
!= NULL
) {
2576 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2578 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2579 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2583 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2584 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2585 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2589 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2590 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2593 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2594 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2597 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2598 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
2601 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2602 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2603 // remove urb from XHCI's asynchronous transfer list.
2605 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2606 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2612 Disable the specified device slot.
2614 @param Xhc The XHCI Instance.
2615 @param SlotId The slot id to be disabled.
2617 @retval EFI_SUCCESS Successfully disable the device slot.
2622 XhcDisableSlotCmd64 (
2623 IN USB_XHCI_INSTANCE
*Xhc
,
2628 TRB_TEMPLATE
*EvtTrb
;
2629 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2634 // Disable the device slots occupied by these devices on its downstream ports.
2635 // Entry 0 is reserved.
2637 for (Index
= 0; Index
< 255; Index
++) {
2638 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2639 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2640 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2644 Status
= XhcDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2646 if (EFI_ERROR (Status
)) {
2647 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2648 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2653 // Construct the disable slot command
2655 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2657 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2658 CmdTrbDisSlot
.CycleBit
= 1;
2659 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2660 CmdTrbDisSlot
.SlotId
= SlotId
;
2661 Status
= XhcCmdTransfer (
2663 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2664 XHC_GENERIC_TIMEOUT
,
2665 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2667 if (EFI_ERROR (Status
)) {
2668 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2672 // Free the slot's device context entry
2674 Xhc
->DCBAA
[SlotId
] = 0;
2677 // Free the slot related data structure
2679 for (Index
= 0; Index
< 31; Index
++) {
2680 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2681 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2682 if (RingSeg
!= NULL
) {
2683 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2685 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2686 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2690 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2691 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2692 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2696 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2697 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2700 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2701 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2704 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2705 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2708 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2709 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2710 // remove urb from XHCI's asynchronous transfer list.
2712 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2713 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2719 Initialize endpoint context in input context.
2721 @param Xhc The XHCI Instance.
2722 @param SlotId The slot id to be configured.
2723 @param DeviceSpeed The device's speed.
2724 @param InputContext The pointer to the input context.
2725 @param IfDesc The pointer to the usb device interface descriptor.
2727 @return The maximum device context index of endpoint.
2732 XhcInitializeEndpointContext (
2733 IN USB_XHCI_INSTANCE
*Xhc
,
2735 IN UINT8 DeviceSpeed
,
2736 IN INPUT_CONTEXT
*InputContext
,
2737 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2740 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2747 EFI_PHYSICAL_ADDRESS PhyAddr
;
2749 TRANSFER_RING
*EndpointTransferRing
;
2753 NumEp
= IfDesc
->NumEndpoints
;
2755 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2756 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2757 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2758 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2761 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2762 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2766 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2767 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2769 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2775 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2776 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2778 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2780 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2782 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2784 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2787 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2788 case USB_ENDPOINT_BULK
:
2789 if (Direction
== EfiUsbDataIn
) {
2790 InputContext
->EP
[Dci
-1].CErr
= 3;
2791 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2793 InputContext
->EP
[Dci
-1].CErr
= 3;
2794 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2797 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2798 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2799 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2800 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2801 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2802 DEBUG ((DEBUG_INFO
, "Endpoint[%x]: Created BULK ring [%p~%p)\n",
2803 EpDesc
->EndpointAddress
,
2804 EndpointTransferRing
->RingSeg0
,
2805 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2810 case USB_ENDPOINT_ISO
:
2811 if (Direction
== EfiUsbDataIn
) {
2812 InputContext
->EP
[Dci
-1].CErr
= 0;
2813 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2815 InputContext
->EP
[Dci
-1].CErr
= 0;
2816 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2819 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2820 // Refer to XHCI 1.1 spec section 6.2.3.6.
2822 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2823 Interval
= EpDesc
->Interval
;
2824 ASSERT (Interval
>= 1 && Interval
<= 16);
2825 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2826 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2827 Interval
= EpDesc
->Interval
;
2828 ASSERT (Interval
>= 1 && Interval
<= 16);
2829 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2833 // Do not support isochronous transfer now.
2835 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2836 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2838 case USB_ENDPOINT_INTERRUPT
:
2839 if (Direction
== EfiUsbDataIn
) {
2840 InputContext
->EP
[Dci
-1].CErr
= 3;
2841 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2843 InputContext
->EP
[Dci
-1].CErr
= 3;
2844 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2846 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2847 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2849 // Get the bInterval from descriptor and init the the interval field of endpoint context
2851 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2852 Interval
= EpDesc
->Interval
;
2854 // Calculate through the bInterval field of Endpoint descriptor.
2856 ASSERT (Interval
!= 0);
2857 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2858 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2859 Interval
= EpDesc
->Interval
;
2860 ASSERT (Interval
>= 1 && Interval
<= 16);
2862 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2864 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2865 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2866 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2867 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2868 InputContext
->EP
[Dci
-1].CErr
= 3;
2871 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2872 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2873 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2874 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2875 DEBUG ((DEBUG_INFO
, "Endpoint[%x]: Created INT ring [%p~%p)\n",
2876 EpDesc
->EndpointAddress
,
2877 EndpointTransferRing
->RingSeg0
,
2878 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2883 case USB_ENDPOINT_CONTROL
:
2885 // Do not support control transfer now.
2887 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2889 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2890 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2894 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2896 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2897 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2899 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2900 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2901 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2902 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2904 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2911 Initialize endpoint context in input context.
2913 @param Xhc The XHCI Instance.
2914 @param SlotId The slot id to be configured.
2915 @param DeviceSpeed The device's speed.
2916 @param InputContext The pointer to the input context.
2917 @param IfDesc The pointer to the usb device interface descriptor.
2919 @return The maximum device context index of endpoint.
2924 XhcInitializeEndpointContext64 (
2925 IN USB_XHCI_INSTANCE
*Xhc
,
2927 IN UINT8 DeviceSpeed
,
2928 IN INPUT_CONTEXT_64
*InputContext
,
2929 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2932 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2939 EFI_PHYSICAL_ADDRESS PhyAddr
;
2941 TRANSFER_RING
*EndpointTransferRing
;
2945 NumEp
= IfDesc
->NumEndpoints
;
2947 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2948 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2949 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2950 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2953 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2954 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2958 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2959 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2961 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2967 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2968 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2970 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2972 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2974 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2976 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2979 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2980 case USB_ENDPOINT_BULK
:
2981 if (Direction
== EfiUsbDataIn
) {
2982 InputContext
->EP
[Dci
-1].CErr
= 3;
2983 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2985 InputContext
->EP
[Dci
-1].CErr
= 3;
2986 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2989 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2990 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2991 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2992 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2993 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2994 DEBUG ((DEBUG_INFO
, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",
2995 EpDesc
->EndpointAddress
,
2996 EndpointTransferRing
->RingSeg0
,
2997 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
3002 case USB_ENDPOINT_ISO
:
3003 if (Direction
== EfiUsbDataIn
) {
3004 InputContext
->EP
[Dci
-1].CErr
= 0;
3005 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
3007 InputContext
->EP
[Dci
-1].CErr
= 0;
3008 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
3011 // Get the bInterval from descriptor and init the the interval field of endpoint context.
3012 // Refer to XHCI 1.1 spec section 6.2.3.6.
3014 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
3015 Interval
= EpDesc
->Interval
;
3016 ASSERT (Interval
>= 1 && Interval
<= 16);
3017 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
3018 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
3019 Interval
= EpDesc
->Interval
;
3020 ASSERT (Interval
>= 1 && Interval
<= 16);
3021 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
3025 // Do not support isochronous transfer now.
3027 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
3028 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3030 case USB_ENDPOINT_INTERRUPT
:
3031 if (Direction
== EfiUsbDataIn
) {
3032 InputContext
->EP
[Dci
-1].CErr
= 3;
3033 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
3035 InputContext
->EP
[Dci
-1].CErr
= 3;
3036 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
3038 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
3039 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
3041 // Get the bInterval from descriptor and init the the interval field of endpoint context
3043 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
3044 Interval
= EpDesc
->Interval
;
3046 // Calculate through the bInterval field of Endpoint descriptor.
3048 ASSERT (Interval
!= 0);
3049 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
3050 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
3051 Interval
= EpDesc
->Interval
;
3052 ASSERT (Interval
>= 1 && Interval
<= 16);
3054 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
3056 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
3057 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
3058 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
3059 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
3060 InputContext
->EP
[Dci
-1].CErr
= 3;
3063 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
3064 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
3065 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
3066 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
3067 DEBUG ((DEBUG_INFO
, "Endpoint64[%x]: Created INT ring [%p~%p)\n",
3068 EpDesc
->EndpointAddress
,
3069 EndpointTransferRing
->RingSeg0
,
3070 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
3075 case USB_ENDPOINT_CONTROL
:
3077 // Do not support control transfer now.
3079 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
3081 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
3082 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3086 PhyAddr
= UsbHcGetPciAddrForHostAddr (
3088 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
3089 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
3091 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
3092 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
3093 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3094 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3096 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3103 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3105 @param Xhc The XHCI Instance.
3106 @param SlotId The slot id to be configured.
3107 @param DeviceSpeed The device's speed.
3108 @param ConfigDesc The pointer to the usb device configuration descriptor.
3110 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3116 IN USB_XHCI_INSTANCE
*Xhc
,
3118 IN UINT8 DeviceSpeed
,
3119 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
3123 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3127 EFI_PHYSICAL_ADDRESS PhyAddr
;
3129 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3130 INPUT_CONTEXT
*InputContext
;
3131 DEVICE_CONTEXT
*OutputContext
;
3132 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3134 // 4.6.6 Configure Endpoint
3136 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3137 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3138 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3139 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3141 ASSERT (ConfigDesc
!= NULL
);
3145 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3146 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3147 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3148 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3151 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3152 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3156 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3161 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3164 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3165 InputContext
->Slot
.ContextEntries
= MaxDci
;
3167 // configure endpoint
3169 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3170 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3171 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3172 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3173 CmdTrbCfgEP
.CycleBit
= 1;
3174 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3175 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3176 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3177 Status
= XhcCmdTransfer (
3179 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3180 XHC_GENERIC_TIMEOUT
,
3181 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3183 if (EFI_ERROR (Status
)) {
3184 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
3186 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3193 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3195 @param Xhc The XHCI Instance.
3196 @param SlotId The slot id to be configured.
3197 @param DeviceSpeed The device's speed.
3198 @param ConfigDesc The pointer to the usb device configuration descriptor.
3200 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3206 IN USB_XHCI_INSTANCE
*Xhc
,
3208 IN UINT8 DeviceSpeed
,
3209 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
3213 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3217 EFI_PHYSICAL_ADDRESS PhyAddr
;
3219 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3220 INPUT_CONTEXT_64
*InputContext
;
3221 DEVICE_CONTEXT_64
*OutputContext
;
3222 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3224 // 4.6.6 Configure Endpoint
3226 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3227 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3228 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3229 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3231 ASSERT (ConfigDesc
!= NULL
);
3235 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3236 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3237 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3238 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3241 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3242 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3246 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3251 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3254 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3255 InputContext
->Slot
.ContextEntries
= MaxDci
;
3257 // configure endpoint
3259 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3260 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3261 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3262 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3263 CmdTrbCfgEP
.CycleBit
= 1;
3264 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3265 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3266 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3267 Status
= XhcCmdTransfer (
3269 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3270 XHC_GENERIC_TIMEOUT
,
3271 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3273 if (EFI_ERROR (Status
)) {
3274 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
3276 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3283 Stop endpoint through XHCI's Stop_Endpoint cmd.
3285 @param Xhc The XHCI Instance.
3286 @param SlotId The slot id to be configured.
3287 @param Dci The device context index of endpoint.
3288 @param PendingUrb The pending URB to check completion status when stopping the end point.
3290 @retval EFI_SUCCESS Stop endpoint successfully.
3291 @retval Others Failed to stop endpoint.
3297 IN USB_XHCI_INSTANCE
*Xhc
,
3300 IN URB
*PendingUrb OPTIONAL
3304 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3305 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
3307 DEBUG ((EFI_D_INFO
, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3310 // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks
3311 // the PendingUrb completion status, because it's possible that the PendingUrb is
3312 // finished just before stopping the end point, but after the looping check.
3314 // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult
3315 // through function parameter, but That will cause every consumer of XhcCmdTransfer,
3316 // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.
3317 // But actually only XhcCheckUrbResult is aware of the PendingUrb.
3318 // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.
3320 ASSERT (Xhc
->PendingUrb
== NULL
);
3321 Xhc
->PendingUrb
= PendingUrb
;
3323 // Reset the URB result from Timeout to NoError.
3324 // The USB result will be:
3325 // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or
3326 // remain NoError when Success/ShortPacket Transfer Event is received.
3328 if (PendingUrb
!= NULL
) {
3329 PendingUrb
->Result
= EFI_USB_NOERROR
;
3333 // Send stop endpoint command to transit Endpoint from running to stop state
3335 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
3336 CmdTrbStopED
.CycleBit
= 1;
3337 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
3338 CmdTrbStopED
.EDID
= Dci
;
3339 CmdTrbStopED
.SlotId
= SlotId
;
3340 Status
= XhcCmdTransfer (
3342 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbStopED
,
3343 XHC_GENERIC_TIMEOUT
,
3344 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3346 if (EFI_ERROR(Status
)) {
3347 DEBUG ((EFI_D_ERROR
, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
3350 Xhc
->PendingUrb
= NULL
;
3356 Reset endpoint through XHCI's Reset_Endpoint cmd.
3358 @param Xhc The XHCI Instance.
3359 @param SlotId The slot id to be configured.
3360 @param Dci The device context index of endpoint.
3362 @retval EFI_SUCCESS Reset endpoint successfully.
3363 @retval Others Failed to reset endpoint.
3369 IN USB_XHCI_INSTANCE
*Xhc
,
3375 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3376 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
3378 DEBUG ((EFI_D_INFO
, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3381 // Send stop endpoint command to transit Endpoint from running to stop state
3383 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
3384 CmdTrbResetED
.CycleBit
= 1;
3385 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
3386 CmdTrbResetED
.EDID
= Dci
;
3387 CmdTrbResetED
.SlotId
= SlotId
;
3388 Status
= XhcCmdTransfer (
3390 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
3391 XHC_GENERIC_TIMEOUT
,
3392 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3394 if (EFI_ERROR(Status
)) {
3395 DEBUG ((EFI_D_ERROR
, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
3402 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3404 @param Xhc The XHCI Instance.
3405 @param SlotId The slot id to be configured.
3406 @param Dci The device context index of endpoint.
3407 @param Urb The dequeue pointer of the transfer ring specified
3408 by the urb to be updated.
3410 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
3411 @retval Others Failed to set transfer ring dequeue pointer.
3416 XhcSetTrDequeuePointer (
3417 IN USB_XHCI_INSTANCE
*Xhc
,
3424 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3425 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
3426 EFI_PHYSICAL_ADDRESS PhyAddr
;
3428 DEBUG ((EFI_D_INFO
, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
3431 // Send stop endpoint command to transit Endpoint from running to stop state
3433 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
3434 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
3435 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
3436 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3437 CmdSetTRDeq
.CycleBit
= 1;
3438 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
3439 CmdSetTRDeq
.Endpoint
= Dci
;
3440 CmdSetTRDeq
.SlotId
= SlotId
;
3441 Status
= XhcCmdTransfer (
3443 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
3444 XHC_GENERIC_TIMEOUT
,
3445 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3447 if (EFI_ERROR(Status
)) {
3448 DEBUG ((EFI_D_ERROR
, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
3455 Set interface through XHCI's Configure_Endpoint cmd.
3457 @param Xhc The XHCI Instance.
3458 @param SlotId The slot id to be configured.
3459 @param DeviceSpeed The device's speed.
3460 @param ConfigDesc The pointer to the usb device configuration descriptor.
3461 @param Request USB device request to send.
3463 @retval EFI_SUCCESS Successfully set interface.
3469 IN USB_XHCI_INSTANCE
*Xhc
,
3471 IN UINT8 DeviceSpeed
,
3472 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3473 IN EFI_USB_DEVICE_REQUEST
*Request
3477 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3478 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3479 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3480 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3487 EFI_PHYSICAL_ADDRESS PhyAddr
;
3490 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3491 INPUT_CONTEXT
*InputContext
;
3492 DEVICE_CONTEXT
*OutputContext
;
3493 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3495 Status
= EFI_SUCCESS
;
3497 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3498 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3500 // XHCI 4.6.6 Configure Endpoint
3501 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3502 // Context and Add Context flags as follows:
3503 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3504 // Context and Add Context flags to '0'.
3506 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3507 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3509 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3510 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3512 ASSERT (ConfigDesc
!= NULL
);
3516 IfDescActive
= NULL
;
3519 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3520 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3521 if ((IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) && (IfDesc
->Length
>= sizeof (USB_INTERFACE_DESCRIPTOR
))) {
3522 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3523 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3525 // Find out the active interface descriptor.
3527 IfDescActive
= IfDesc
;
3528 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3530 // Find out the interface descriptor to set.
3536 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3540 // XHCI 4.6.6 Configure Endpoint
3541 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3542 // Context and Add Context flags as follows:
3543 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3544 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3545 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3546 // the Drop Context flag to '1' and Add Context flag to '0'.
3547 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3548 // and Add Context flags shall be set to '1'.
3550 // Below codes are to cover 2), 3) and 4).
3553 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3554 NumEp
= IfDescActive
->NumEndpoints
;
3555 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3556 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3557 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3558 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3561 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
3562 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3566 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3567 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3569 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3575 // XHCI 4.3.6 - Setting Alternate Interfaces
3576 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3578 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
, NULL
);
3579 if (EFI_ERROR (Status
)) {
3583 // XHCI 4.3.6 - Setting Alternate Interfaces
3584 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3586 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3587 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3588 if (RingSeg
!= NULL
) {
3589 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3591 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3592 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3596 // Set the Drop Context flag to '1'.
3598 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3600 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3604 // XHCI 4.3.6 - Setting Alternate Interfaces
3605 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3606 // Interface setting, to '0'.
3608 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3612 // XHCI 4.3.6 - Setting Alternate Interfaces
3613 // 4) For each endpoint enabled by the Configure Endpoint Command:
3614 // a. Allocate a Transfer Ring.
3615 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3616 // c. Initialize the Endpoint Context data structure.
3618 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3623 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3624 InputContext
->Slot
.ContextEntries
= MaxDci
;
3626 // XHCI 4.3.6 - Setting Alternate Interfaces
3627 // 5) Issue and successfully complete a Configure Endpoint Command.
3629 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3630 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3631 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3632 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3633 CmdTrbCfgEP
.CycleBit
= 1;
3634 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3635 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3636 DEBUG ((EFI_D_INFO
, "SetInterface: Configure Endpoint\n"));
3637 Status
= XhcCmdTransfer (
3639 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3640 XHC_GENERIC_TIMEOUT
,
3641 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3643 if (EFI_ERROR (Status
)) {
3644 DEBUG ((EFI_D_ERROR
, "SetInterface: Config Endpoint Failed, Status = %r\n", Status
));
3647 // Update the active AlternateSetting.
3649 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3657 Set interface through XHCI's Configure_Endpoint cmd.
3659 @param Xhc The XHCI Instance.
3660 @param SlotId The slot id to be configured.
3661 @param DeviceSpeed The device's speed.
3662 @param ConfigDesc The pointer to the usb device configuration descriptor.
3663 @param Request USB device request to send.
3665 @retval EFI_SUCCESS Successfully set interface.
3671 IN USB_XHCI_INSTANCE
*Xhc
,
3673 IN UINT8 DeviceSpeed
,
3674 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3675 IN EFI_USB_DEVICE_REQUEST
*Request
3679 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3680 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3681 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3682 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3689 EFI_PHYSICAL_ADDRESS PhyAddr
;
3692 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3693 INPUT_CONTEXT_64
*InputContext
;
3694 DEVICE_CONTEXT_64
*OutputContext
;
3695 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3697 Status
= EFI_SUCCESS
;
3699 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3700 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3702 // XHCI 4.6.6 Configure Endpoint
3703 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3704 // Context and Add Context flags as follows:
3705 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3706 // Context and Add Context flags to '0'.
3708 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3709 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3711 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3712 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3714 ASSERT (ConfigDesc
!= NULL
);
3718 IfDescActive
= NULL
;
3721 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3722 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3723 if ((IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) && (IfDesc
->Length
>= sizeof (USB_INTERFACE_DESCRIPTOR
))) {
3724 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3725 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3727 // Find out the active interface descriptor.
3729 IfDescActive
= IfDesc
;
3730 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3732 // Find out the interface descriptor to set.
3738 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3742 // XHCI 4.6.6 Configure Endpoint
3743 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3744 // Context and Add Context flags as follows:
3745 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3746 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3747 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3748 // the Drop Context flag to '1' and Add Context flag to '0'.
3749 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3750 // and Add Context flags shall be set to '1'.
3752 // Below codes are to cover 2), 3) and 4).
3755 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3756 NumEp
= IfDescActive
->NumEndpoints
;
3757 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3758 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3759 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3760 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3763 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
3764 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3768 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3769 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3771 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3777 // XHCI 4.3.6 - Setting Alternate Interfaces
3778 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3780 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
, NULL
);
3781 if (EFI_ERROR (Status
)) {
3785 // XHCI 4.3.6 - Setting Alternate Interfaces
3786 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3788 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3789 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3790 if (RingSeg
!= NULL
) {
3791 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3793 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3794 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3798 // Set the Drop Context flag to '1'.
3800 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3802 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3806 // XHCI 4.3.6 - Setting Alternate Interfaces
3807 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3808 // Interface setting, to '0'.
3810 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3814 // XHCI 4.3.6 - Setting Alternate Interfaces
3815 // 4) For each endpoint enabled by the Configure Endpoint Command:
3816 // a. Allocate a Transfer Ring.
3817 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3818 // c. Initialize the Endpoint Context data structure.
3820 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3825 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3826 InputContext
->Slot
.ContextEntries
= MaxDci
;
3828 // XHCI 4.3.6 - Setting Alternate Interfaces
3829 // 5) Issue and successfully complete a Configure Endpoint Command.
3831 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3832 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3833 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3834 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3835 CmdTrbCfgEP
.CycleBit
= 1;
3836 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3837 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3838 DEBUG ((EFI_D_INFO
, "SetInterface64: Configure Endpoint\n"));
3839 Status
= XhcCmdTransfer (
3841 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3842 XHC_GENERIC_TIMEOUT
,
3843 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3845 if (EFI_ERROR (Status
)) {
3846 DEBUG ((EFI_D_ERROR
, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status
));
3849 // Update the active AlternateSetting.
3851 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3859 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3861 @param Xhc The XHCI Instance.
3862 @param SlotId The slot id to be evaluated.
3863 @param MaxPacketSize The max packet size supported by the device control transfer.
3865 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3870 XhcEvaluateContext (
3871 IN USB_XHCI_INSTANCE
*Xhc
,
3873 IN UINT32 MaxPacketSize
3877 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3878 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3879 INPUT_CONTEXT
*InputContext
;
3880 EFI_PHYSICAL_ADDRESS PhyAddr
;
3882 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3885 // 4.6.7 Evaluate Context
3887 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3888 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3890 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3891 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3893 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3894 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3895 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3896 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3897 CmdTrbEvalu
.CycleBit
= 1;
3898 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3899 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3900 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3901 Status
= XhcCmdTransfer (
3903 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3904 XHC_GENERIC_TIMEOUT
,
3905 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3907 if (EFI_ERROR (Status
)) {
3908 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
3914 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3916 @param Xhc The XHCI Instance.
3917 @param SlotId The slot id to be evaluated.
3918 @param MaxPacketSize The max packet size supported by the device control transfer.
3920 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3925 XhcEvaluateContext64 (
3926 IN USB_XHCI_INSTANCE
*Xhc
,
3928 IN UINT32 MaxPacketSize
3932 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3933 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3934 INPUT_CONTEXT_64
*InputContext
;
3935 EFI_PHYSICAL_ADDRESS PhyAddr
;
3937 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3940 // 4.6.7 Evaluate Context
3942 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3943 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3945 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3946 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3948 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3949 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3950 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3951 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3952 CmdTrbEvalu
.CycleBit
= 1;
3953 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3954 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3955 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3956 Status
= XhcCmdTransfer (
3958 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3959 XHC_GENERIC_TIMEOUT
,
3960 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3962 if (EFI_ERROR (Status
)) {
3963 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
3970 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3972 @param Xhc The XHCI Instance.
3973 @param SlotId The slot id to be configured.
3974 @param PortNum The total number of downstream port supported by the hub.
3975 @param TTT The TT think time of the hub device.
3976 @param MTT The multi-TT of the hub device.
3978 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3982 XhcConfigHubContext (
3983 IN USB_XHCI_INSTANCE
*Xhc
,
3991 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3992 INPUT_CONTEXT
*InputContext
;
3993 DEVICE_CONTEXT
*OutputContext
;
3994 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3995 EFI_PHYSICAL_ADDRESS PhyAddr
;
3997 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3998 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3999 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
4002 // 4.6.7 Evaluate Context
4004 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
4006 InputContext
->InputControlContext
.Dword2
|= BIT0
;
4009 // Copy the slot context from OutputContext to Input context
4011 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
4012 InputContext
->Slot
.Hub
= 1;
4013 InputContext
->Slot
.PortNum
= PortNum
;
4014 InputContext
->Slot
.TTT
= TTT
;
4015 InputContext
->Slot
.MTT
= MTT
;
4017 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
4018 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
4019 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
4020 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
4021 CmdTrbCfgEP
.CycleBit
= 1;
4022 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
4023 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
4024 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
4025 Status
= XhcCmdTransfer (
4027 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
4028 XHC_GENERIC_TIMEOUT
,
4029 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
4031 if (EFI_ERROR (Status
)) {
4032 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
4038 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
4040 @param Xhc The XHCI Instance.
4041 @param SlotId The slot id to be configured.
4042 @param PortNum The total number of downstream port supported by the hub.
4043 @param TTT The TT think time of the hub device.
4044 @param MTT The multi-TT of the hub device.
4046 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
4050 XhcConfigHubContext64 (
4051 IN USB_XHCI_INSTANCE
*Xhc
,
4059 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
4060 INPUT_CONTEXT_64
*InputContext
;
4061 DEVICE_CONTEXT_64
*OutputContext
;
4062 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
4063 EFI_PHYSICAL_ADDRESS PhyAddr
;
4065 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
4066 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
4067 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
4070 // 4.6.7 Evaluate Context
4072 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
4074 InputContext
->InputControlContext
.Dword2
|= BIT0
;
4077 // Copy the slot context from OutputContext to Input context
4079 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
4080 InputContext
->Slot
.Hub
= 1;
4081 InputContext
->Slot
.PortNum
= PortNum
;
4082 InputContext
->Slot
.TTT
= TTT
;
4083 InputContext
->Slot
.MTT
= MTT
;
4085 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
4086 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
4087 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
4088 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
4089 CmdTrbCfgEP
.CycleBit
= 1;
4090 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
4091 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
4092 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
4093 Status
= XhcCmdTransfer (
4095 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
4096 XHC_GENERIC_TIMEOUT
,
4097 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
4099 if (EFI_ERROR (Status
)) {
4100 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));