3 XHCI transfer scheduling routines.
5 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Create a command transfer TRB to support XHCI command interfaces.
21 @param Xhc The XHCI Instance.
22 @param CmdTrb The cmd TRB to be executed.
24 @return Created URB or NULL.
29 IN USB_XHCI_INSTANCE
*Xhc
,
30 IN TRB_TEMPLATE
*CmdTrb
35 Urb
= AllocateZeroPool (sizeof (URB
));
40 Urb
->Signature
= XHC_URB_SIG
;
42 Urb
->Ring
= &Xhc
->CmdRing
;
43 XhcSyncTrsRing (Xhc
, Urb
->Ring
);
45 Urb
->TrbStart
= Urb
->Ring
->RingEnqueue
;
46 CopyMem (Urb
->TrbStart
, CmdTrb
, sizeof (TRB_TEMPLATE
));
47 Urb
->TrbStart
->CycleBit
= Urb
->Ring
->RingPCS
& BIT0
;
48 Urb
->TrbEnd
= Urb
->TrbStart
;
54 Execute a XHCI cmd TRB pointed by CmdTrb.
56 @param Xhc The XHCI Instance.
57 @param CmdTrb The cmd TRB to be executed.
58 @param Timeout Indicates the maximum time, in millisecond, which the
59 transfer is allowed to complete.
60 @param EvtTrb The event TRB corresponding to the cmd TRB.
62 @retval EFI_SUCCESS The transfer was completed successfully.
63 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
64 @retval EFI_TIMEOUT The transfer failed due to timeout.
65 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
71 IN USB_XHCI_INSTANCE
*Xhc
,
72 IN TRB_TEMPLATE
*CmdTrb
,
74 OUT TRB_TEMPLATE
**EvtTrb
81 // Validate the parameters
83 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
84 return EFI_INVALID_PARAMETER
;
87 Status
= EFI_DEVICE_ERROR
;
89 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
90 DEBUG ((EFI_D_ERROR
, "XhcCmdTransfer: HC is halted\n"));
95 // Create a new URB, then poll the execution status.
97 Urb
= XhcCreateCmdTrb (Xhc
, CmdTrb
);
100 DEBUG ((EFI_D_ERROR
, "XhcCmdTransfer: failed to create URB\n"));
101 Status
= EFI_OUT_OF_RESOURCES
;
105 Status
= XhcExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
106 *EvtTrb
= Urb
->EvtTrb
;
108 if (Urb
->Result
== EFI_USB_NOERROR
) {
109 Status
= EFI_SUCCESS
;
112 XhcFreeUrb (Xhc
, Urb
);
119 Create a new URB for a new transaction.
121 @param Xhc The XHCI Instance
122 @param BusAddr The logical device address assigned by UsbBus driver
123 @param EpAddr Endpoint addrress
124 @param DevSpeed The device speed
125 @param MaxPacket The max packet length of the endpoint
126 @param Type The transaction type
127 @param Request The standard USB request for control transfer
128 @param Data The user data to transfer
129 @param DataLen The length of data buffer
130 @param Callback The function to call when data is transferred
131 @param Context The context to the callback
133 @return Created URB or NULL
138 IN USB_XHCI_INSTANCE
*Xhc
,
144 IN EFI_USB_DEVICE_REQUEST
*Request
,
147 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
155 Urb
= AllocateZeroPool (sizeof (URB
));
160 Urb
->Signature
= XHC_URB_SIG
;
161 InitializeListHead (&Urb
->UrbList
);
164 Ep
->BusAddr
= BusAddr
;
165 Ep
->EpAddr
= (UINT8
)(EpAddr
& 0x0F);
166 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
167 Ep
->DevSpeed
= DevSpeed
;
168 Ep
->MaxPacket
= MaxPacket
;
171 Urb
->Request
= Request
;
173 Urb
->DataLen
= DataLen
;
174 Urb
->Callback
= Callback
;
175 Urb
->Context
= Context
;
177 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
178 ASSERT_EFI_ERROR (Status
);
179 if (EFI_ERROR (Status
)) {
180 DEBUG ((EFI_D_ERROR
, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status
));
189 Free an allocated URB.
191 @param Xhc The XHCI device.
192 @param Urb The URB to free.
197 IN USB_XHCI_INSTANCE
*Xhc
,
201 if ((Xhc
== NULL
) || (Urb
== NULL
)) {
205 if (Urb
->DataMap
!= NULL
) {
206 Xhc
->PciIo
->Unmap (Xhc
->PciIo
, Urb
->DataMap
);
213 Create a transfer TRB.
215 @param Xhc The XHCI Instance
216 @param Urb The urb used to construct the transfer TRB.
218 @return Created TRB or NULL
222 XhcCreateTransferTrb (
223 IN USB_XHCI_INSTANCE
*Xhc
,
228 TRANSFER_RING
*EPRing
;
236 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
237 EFI_PHYSICAL_ADDRESS PhyAddr
;
241 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
243 return EFI_DEVICE_ERROR
;
246 Urb
->Finished
= FALSE
;
247 Urb
->StartDone
= FALSE
;
248 Urb
->EndDone
= FALSE
;
250 Urb
->Result
= EFI_USB_NOERROR
;
252 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
254 EPRing
= (TRANSFER_RING
*)(UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1];
256 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
257 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
258 EPType
= (UINT8
) ((DEVICE_CONTEXT
*)OutputContext
)->EP
[Dci
-1].EPType
;
260 EPType
= (UINT8
) ((DEVICE_CONTEXT_64
*)OutputContext
)->EP
[Dci
-1].EPType
;
263 if (Urb
->Data
!= NULL
) {
264 if (((UINT8
) (Urb
->Ep
.Direction
)) == EfiUsbDataIn
) {
265 MapOp
= EfiPciIoOperationBusMasterWrite
;
267 MapOp
= EfiPciIoOperationBusMasterRead
;
271 Status
= Xhc
->PciIo
->Map (Xhc
->PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
273 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
274 DEBUG ((EFI_D_ERROR
, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
275 return EFI_OUT_OF_RESOURCES
;
278 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
285 XhcSyncTrsRing (Xhc
, EPRing
);
286 Urb
->TrbStart
= EPRing
->RingEnqueue
;
288 case ED_CONTROL_BIDIR
:
290 // For control transfer, create SETUP_STAGE_TRB first.
292 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
293 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
294 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
295 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
296 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
297 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
298 TrbStart
->TrbCtrSetup
.Length
= 8;
299 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
300 TrbStart
->TrbCtrSetup
.IOC
= 1;
301 TrbStart
->TrbCtrSetup
.IDT
= 1;
302 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
303 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
304 TrbStart
->TrbCtrSetup
.TRT
= 3;
305 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
306 TrbStart
->TrbCtrSetup
.TRT
= 2;
308 TrbStart
->TrbCtrSetup
.TRT
= 0;
311 // Update the cycle bit
313 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
317 // For control transfer, create DATA_STAGE_TRB.
319 if (Urb
->DataLen
> 0) {
320 XhcSyncTrsRing (Xhc
, EPRing
);
321 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
322 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT(Urb
->DataPhy
);
323 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT(Urb
->DataPhy
);
324 TrbStart
->TrbCtrData
.Length
= (UINT32
) Urb
->DataLen
;
325 TrbStart
->TrbCtrData
.TDSize
= 0;
326 TrbStart
->TrbCtrData
.IntTarget
= 0;
327 TrbStart
->TrbCtrData
.ISP
= 1;
328 TrbStart
->TrbCtrData
.IOC
= 1;
329 TrbStart
->TrbCtrData
.IDT
= 0;
330 TrbStart
->TrbCtrData
.CH
= 0;
331 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
332 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
333 TrbStart
->TrbCtrData
.DIR = 1;
334 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
335 TrbStart
->TrbCtrData
.DIR = 0;
337 TrbStart
->TrbCtrData
.DIR = 0;
340 // Update the cycle bit
342 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
346 // For control transfer, create STATUS_STAGE_TRB.
347 // Get the pointer to next TRB for status stage use
349 XhcSyncTrsRing (Xhc
, EPRing
);
350 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
351 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
352 TrbStart
->TrbCtrStatus
.IOC
= 1;
353 TrbStart
->TrbCtrStatus
.CH
= 0;
354 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
355 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
356 TrbStart
->TrbCtrStatus
.DIR = 0;
357 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
358 TrbStart
->TrbCtrStatus
.DIR = 1;
360 TrbStart
->TrbCtrStatus
.DIR = 0;
363 // Update the cycle bit
365 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
367 // Update the enqueue pointer
369 XhcSyncTrsRing (Xhc
, EPRing
);
371 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
380 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
381 while (TotalLen
< Urb
->DataLen
) {
382 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
383 Len
= Urb
->DataLen
- TotalLen
;
387 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
388 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
389 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
390 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
391 TrbStart
->TrbNormal
.TDSize
= 0;
392 TrbStart
->TrbNormal
.IntTarget
= 0;
393 TrbStart
->TrbNormal
.ISP
= 1;
394 TrbStart
->TrbNormal
.IOC
= 1;
395 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
397 // Update the cycle bit
399 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
401 XhcSyncTrsRing (Xhc
, EPRing
);
406 Urb
->TrbNum
= TrbNum
;
407 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
410 case ED_INTERRUPT_OUT
:
411 case ED_INTERRUPT_IN
:
415 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
416 while (TotalLen
< Urb
->DataLen
) {
417 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
418 Len
= Urb
->DataLen
- TotalLen
;
422 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
423 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
424 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
425 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
426 TrbStart
->TrbNormal
.TDSize
= 0;
427 TrbStart
->TrbNormal
.IntTarget
= 0;
428 TrbStart
->TrbNormal
.ISP
= 1;
429 TrbStart
->TrbNormal
.IOC
= 1;
430 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
432 // Update the cycle bit
434 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
436 XhcSyncTrsRing (Xhc
, EPRing
);
441 Urb
->TrbNum
= TrbNum
;
442 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
446 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
456 Initialize the XHCI host controller for schedule.
458 @param Xhc The XHCI Instance to be initialized.
463 IN USB_XHCI_INSTANCE
*Xhc
467 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
469 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
471 UINT32 MaxScratchpadBufs
;
473 EFI_PHYSICAL_ADDRESS ScratchPhy
;
474 UINT64
*ScratchEntry
;
475 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
477 UINTN
*ScratchEntryMap
;
481 // Initialize memory management.
483 Xhc
->MemPool
= UsbHcInitMemPool (Xhc
->PciIo
);
484 ASSERT (Xhc
->MemPool
!= NULL
);
487 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
488 // to enable the device slots that system software is going to use.
490 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
491 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
492 XhcWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, Xhc
->MaxSlotsEn
);
495 // The Device Context Base Address Array entry associated with each allocated Device Slot
496 // shall contain a 64-bit pointer to the base of the associated Device Context.
497 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
498 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
500 Entries
= (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
);
501 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Entries
);
502 ASSERT (Dcbaa
!= NULL
);
503 ZeroMem (Dcbaa
, Entries
);
506 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
507 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
508 // mode (Run/Stop(R/S) ='1').
510 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
511 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
512 ASSERT (MaxScratchpadBufs
<= 1023);
513 if (MaxScratchpadBufs
!= 0) {
515 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
517 ScratchEntryMap
= AllocateZeroPool (sizeof (UINTN
) * MaxScratchpadBufs
);
518 ASSERT (ScratchEntryMap
!= NULL
);
519 Xhc
->ScratchEntryMap
= ScratchEntryMap
;
522 // Allocate the buffer to record the host address for each entry
524 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
525 ASSERT (ScratchEntry
!= NULL
);
526 Xhc
->ScratchEntry
= ScratchEntry
;
529 Status
= UsbHcAllocateAlignedPages (
531 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
533 (VOID
**) &ScratchBuf
,
537 ASSERT_EFI_ERROR (Status
);
539 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
540 Xhc
->ScratchBuf
= ScratchBuf
;
543 // Allocate each scratch buffer
545 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
547 Status
= UsbHcAllocateAlignedPages (
549 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
551 (VOID
**) &ScratchEntry
[Index
],
553 (VOID
**) &ScratchEntryMap
[Index
]
555 ASSERT_EFI_ERROR (Status
);
556 ZeroMem ((VOID
*)(UINTN
)ScratchEntry
[Index
], Xhc
->PageSize
);
558 // Fill with the PCI device address
560 *ScratchBuf
++ = ScratchEntryPhy
;
563 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
564 // Device Context Base Address Array points to the Scratchpad Buffer Array.
566 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
) ScratchPhy
;
570 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
571 // a 64-bit address pointing to where the Device Context Base Address Array is located.
573 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
575 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
576 // So divide it to two 32-bytes width register access.
578 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Entries
);
579 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT(DcbaaPhy
));
580 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
582 DEBUG ((EFI_D_INFO
, "XhcInitSched:DCBAA=0x%x\n", (UINT64
)(UINTN
)Xhc
->DCBAA
));
585 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
586 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
587 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
590 CreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
592 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
593 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
594 // So we set RCS as inverted PCS init value to let Command Ring empty
596 CmdRing
= (UINT64
)(UINTN
)Xhc
->CmdRing
.RingSeg0
;
597 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) CmdRing
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
598 ASSERT ((CmdRingPhy
& 0x3F) == 0);
599 CmdRingPhy
|= XHC_CRCR_RCS
;
601 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
602 // So divide it to two 32-bytes width register access.
604 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT(CmdRingPhy
));
605 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
608 // Disable the 'interrupter enable' bit in USB_CMD
609 // and clear IE & IP bit in all Interrupter X Management Registers.
611 XhcClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
612 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
613 XhcClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
614 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
618 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
620 CreateEventRing (Xhc
, &Xhc
->EventRing
);
621 DEBUG ((DEBUG_INFO
, "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",
622 Xhc
->CmdRing
.RingSeg0
, (UINTN
)Xhc
->CmdRing
.RingSeg0
+ sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
,
623 Xhc
->EventRing
.EventRingSeg0
, (UINTN
)Xhc
->EventRing
.EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
628 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
629 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
630 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
631 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
632 Stopped to the Running state.
634 @param Xhc The XHCI Instance.
635 @param Urb The urb which makes the endpoint halted.
637 @retval EFI_SUCCESS The recovery is successful.
638 @retval Others Failed to recovery halted endpoint.
643 XhcRecoverHaltedEndpoint (
644 IN USB_XHCI_INSTANCE
*Xhc
,
652 Status
= EFI_SUCCESS
;
653 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
655 return EFI_DEVICE_ERROR
;
657 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
660 DEBUG ((EFI_D_INFO
, "Recovery Halted Slot = %x,Dci = %x\n", SlotId
, Dci
));
663 // 1) Send Reset endpoint command to transit from halt to stop state
665 Status
= XhcResetEndpoint(Xhc
, SlotId
, Dci
);
666 if (EFI_ERROR(Status
)) {
667 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
672 // 2)Set dequeue pointer
674 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
675 if (EFI_ERROR(Status
)) {
676 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
681 // 3)Ring the doorbell to transit from stop to active
683 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
690 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
691 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
692 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
695 @param Xhc The XHCI Instance.
696 @param Urb The urb which doesn't get completed in a specified timeout range.
698 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
699 @retval Others Failed to stop the endpoint and dequeue the TDs.
704 XhcDequeueTrbFromEndpoint (
705 IN USB_XHCI_INSTANCE
*Xhc
,
713 Status
= EFI_SUCCESS
;
714 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
716 return EFI_DEVICE_ERROR
;
718 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
721 DEBUG ((EFI_D_INFO
, "Stop Slot = %x,Dci = %x\n", SlotId
, Dci
));
724 // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint
726 Status
= XhcStopEndpoint(Xhc
, SlotId
, Dci
);
727 if (EFI_ERROR(Status
)) {
728 DEBUG ((EFI_D_ERROR
, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
733 // 2)Set dequeue pointer
735 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
736 if (EFI_ERROR(Status
)) {
737 DEBUG ((EFI_D_ERROR
, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
742 // 3)Ring the doorbell to transit from stop to active
744 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
751 Create XHCI event ring.
753 @param Xhc The XHCI Instance.
754 @param EventRing The created event ring.
759 IN USB_XHCI_INSTANCE
*Xhc
,
760 OUT EVENT_RING
*EventRing
764 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
766 EFI_PHYSICAL_ADDRESS ERSTPhy
;
767 EFI_PHYSICAL_ADDRESS DequeuePhy
;
769 ASSERT (EventRing
!= NULL
);
771 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
772 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
773 ASSERT (Buf
!= NULL
);
774 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
777 EventRing
->EventRingSeg0
= Buf
;
778 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
779 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
780 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
782 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
785 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
786 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
788 EventRing
->EventRingCCS
= 1;
790 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
791 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
792 ASSERT (Buf
!= NULL
);
793 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
796 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
797 EventRing
->ERSTBase
= ERSTBase
;
798 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
799 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
800 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
802 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, ERSTBase
, Size
);
805 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
813 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
815 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
816 // So divide it to two 32-bytes width register access.
821 XHC_LOW_32BIT((UINT64
)(UINTN
)DequeuePhy
)
826 XHC_HIGH_32BIT((UINT64
)(UINTN
)DequeuePhy
)
829 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
831 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
832 // So divide it to two 32-bytes width register access.
837 XHC_LOW_32BIT((UINT64
)(UINTN
)ERSTPhy
)
841 XHC_ERSTBA_OFFSET
+ 4,
842 XHC_HIGH_32BIT((UINT64
)(UINTN
)ERSTPhy
)
845 // Need set IMAN IE bit to enble the ring interrupt
847 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
851 Create XHCI transfer ring.
853 @param Xhc The XHCI Instance.
854 @param TrbNum The number of TRB in the ring.
855 @param TransferRing The created transfer ring.
860 IN USB_XHCI_INSTANCE
*Xhc
,
862 OUT TRANSFER_RING
*TransferRing
867 EFI_PHYSICAL_ADDRESS PhyAddr
;
869 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
870 ASSERT (Buf
!= NULL
);
871 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
872 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
874 TransferRing
->RingSeg0
= Buf
;
875 TransferRing
->TrbNumber
= TrbNum
;
876 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
877 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
878 TransferRing
->RingPCS
= 1;
880 // 4.9.2 Transfer Ring Management
881 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
882 // point to the first TRB in the ring.
884 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
885 EndTrb
->Type
= TRB_TYPE_LINK
;
886 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
887 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
888 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
890 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
894 // Set Cycle bit as other TRB PCS init value
896 EndTrb
->CycleBit
= 0;
900 Free XHCI event ring.
902 @param Xhc The XHCI Instance.
903 @param EventRing The event ring to be freed.
909 IN USB_XHCI_INSTANCE
*Xhc
,
910 IN EVENT_RING
*EventRing
913 if(EventRing
->EventRingSeg0
== NULL
) {
918 // Free EventRing Segment 0
920 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
925 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
930 Free the resouce allocated at initializing schedule.
932 @param Xhc The XHCI Instance.
937 IN USB_XHCI_INSTANCE
*Xhc
941 UINT64
*ScratchEntry
;
943 if (Xhc
->ScratchBuf
!= NULL
) {
944 ScratchEntry
= Xhc
->ScratchEntry
;
945 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
947 // Free Scratchpad Buffers
949 UsbHcFreeAlignedPages (Xhc
->PciIo
, (VOID
*)(UINTN
)ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*) Xhc
->ScratchEntryMap
[Index
]);
952 // Free Scratchpad Buffer Array
954 UsbHcFreeAlignedPages (Xhc
->PciIo
, Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
955 FreePool (Xhc
->ScratchEntryMap
);
956 FreePool (Xhc
->ScratchEntry
);
959 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
960 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
961 Xhc
->CmdRing
.RingSeg0
= NULL
;
964 XhcFreeEventRing (Xhc
,&Xhc
->EventRing
);
966 if (Xhc
->DCBAA
!= NULL
) {
967 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
));
972 // Free memory pool at last
974 if (Xhc
->MemPool
!= NULL
) {
975 UsbHcFreeMemPool (Xhc
->MemPool
);
981 Check if the Trb is a transaction of the URB.
983 @param Trb The TRB to be checked
984 @param Urb The URB to be checked.
986 @retval TRUE It is a transaction of the URB.
987 @retval FALSE It is not any transaction of the URB.
992 IN USB_XHCI_INSTANCE
*Xhc
,
993 IN TRB_TEMPLATE
*Trb
,
998 TRB_TEMPLATE
*CheckedTrb
;
1000 EFI_PHYSICAL_ADDRESS PhyAddr
;
1002 CheckedTrb
= Urb
->TrbStart
;
1003 for (Index
= 0; Index
< Urb
->TrbNum
; Index
++) {
1004 if (Trb
== CheckedTrb
) {
1009 // If the checked TRB is the link TRB at the end of the transfer ring,
1010 // recircle it to the head of the ring.
1012 if (CheckedTrb
->Type
== TRB_TYPE_LINK
) {
1013 LinkTrb
= (LINK_TRB
*) CheckedTrb
;
1014 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(LinkTrb
->PtrLo
| LShiftU64 ((UINT64
) LinkTrb
->PtrHi
, 32));
1015 CheckedTrb
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1016 ASSERT (CheckedTrb
== Urb
->Ring
->RingSeg0
);
1024 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
1026 @param Xhc The XHCI Instance.
1027 @param Trb The TRB to be checked.
1028 @param Urb The pointer to the matched Urb.
1030 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
1031 @retval FALSE The Trb is not matched with any URBs in the async list.
1036 IN USB_XHCI_INSTANCE
*Xhc
,
1037 IN TRB_TEMPLATE
*Trb
,
1045 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1046 CheckedUrb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1047 if (IsTransferRingTrb (Xhc
, Trb
, CheckedUrb
)) {
1058 Check the URB's execution result and update the URB's
1061 @param Xhc The XHCI Instance.
1062 @param Urb The URB to check result.
1064 @return Whether the result of URB transfer is finialized.
1069 IN USB_XHCI_INSTANCE
*Xhc
,
1073 EVT_TRB_TRANSFER
*EvtTrb
;
1074 TRB_TEMPLATE
*TRBPtr
;
1083 EFI_PHYSICAL_ADDRESS PhyAddr
;
1085 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
1087 Status
= EFI_SUCCESS
;
1090 if (Urb
->Finished
) {
1096 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1097 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
1102 // Traverse the event ring to find out all new events from the previous check.
1104 XhcSyncEventRing (Xhc
, &Xhc
->EventRing
);
1105 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
1106 Status
= XhcCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
1107 if (Status
== EFI_NOT_READY
) {
1109 // All new events are handled, return directly.
1115 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1117 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
1122 // Need convert pci device address to host address
1124 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
1125 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1128 // Update the status of Urb according to the finished event regardless of whether
1129 // the urb is current checked one or in the XHCI's async transfer list.
1130 // This way is used to avoid that those completed async transfer events don't get
1131 // handled in time and are flushed by newer coming events.
1133 if (IsTransferRingTrb (Xhc
, TRBPtr
, Urb
)) {
1135 } else if (IsAsyncIntTrb (Xhc
, TRBPtr
, &AsyncUrb
)) {
1136 CheckedUrb
= AsyncUrb
;
1141 switch (EvtTrb
->Completecode
) {
1142 case TRB_COMPLETION_STALL_ERROR
:
1143 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
1144 CheckedUrb
->Finished
= TRUE
;
1145 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1148 case TRB_COMPLETION_BABBLE_ERROR
:
1149 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
1150 CheckedUrb
->Finished
= TRUE
;
1151 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1154 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
1155 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
1156 CheckedUrb
->Finished
= TRUE
;
1157 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
1160 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
1161 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1162 CheckedUrb
->Finished
= TRUE
;
1163 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1166 case TRB_COMPLETION_SHORT_PACKET
:
1167 case TRB_COMPLETION_SUCCESS
:
1168 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
1169 DEBUG ((EFI_D_VERBOSE
, "XhcCheckUrbResult: short packet happens!\n"));
1172 TRBType
= (UINT8
) (TRBPtr
->Type
);
1173 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
1174 (TRBType
== TRB_TYPE_NORMAL
) ||
1175 (TRBType
== TRB_TYPE_ISOCH
)) {
1176 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
1182 DEBUG ((EFI_D_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
1183 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1184 CheckedUrb
->Finished
= TRUE
;
1189 // Only check first and end Trb event address
1191 if (TRBPtr
== CheckedUrb
->TrbStart
) {
1192 CheckedUrb
->StartDone
= TRUE
;
1195 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
1196 CheckedUrb
->EndDone
= TRUE
;
1199 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
1200 CheckedUrb
->Finished
= TRUE
;
1201 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
1208 // Advance event ring to last available entry
1210 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1211 // So divide it to two 32-bytes width register access.
1213 Low
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
1214 High
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
1215 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
1217 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
1219 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
1221 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1222 // So divide it to two 32-bytes width register access.
1224 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
1225 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
1228 return Urb
->Finished
;
1233 Execute the transfer by polling the URB. This is a synchronous operation.
1235 @param Xhc The XHCI Instance.
1236 @param CmdTransfer The executed URB is for cmd transfer or not.
1237 @param Urb The URB to execute.
1238 @param Timeout The time to wait before abort, in millisecond.
1240 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1241 @return EFI_TIMEOUT The transfer failed due to time out.
1242 @return EFI_SUCCESS The transfer finished OK.
1247 IN USB_XHCI_INSTANCE
*Xhc
,
1248 IN BOOLEAN CmdTransfer
,
1264 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1266 return EFI_DEVICE_ERROR
;
1268 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1272 Status
= EFI_SUCCESS
;
1273 Loop
= Timeout
* XHC_1_MILLISECOND
;
1278 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1280 for (Index
= 0; Index
< Loop
; Index
++) {
1281 Finished
= XhcCheckUrbResult (Xhc
, Urb
);
1285 gBS
->Stall (XHC_1_MICROSECOND
);
1288 if (Index
== Loop
) {
1289 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
1290 Status
= EFI_TIMEOUT
;
1291 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
1292 Status
= EFI_DEVICE_ERROR
;
1299 Delete a single asynchronous interrupt transfer for
1300 the device and endpoint.
1302 @param Xhc The XHCI Instance.
1303 @param BusAddr The logical device address assigned by UsbBus driver.
1304 @param EpNum The endpoint of the target.
1306 @retval EFI_SUCCESS An asynchronous transfer is removed.
1307 @retval EFI_NOT_FOUND No transfer for the device is found.
1311 XhciDelAsyncIntTransfer (
1312 IN USB_XHCI_INSTANCE
*Xhc
,
1320 EFI_USB_DATA_DIRECTION Direction
;
1323 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1328 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1329 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1330 if ((Urb
->Ep
.BusAddr
== BusAddr
) &&
1331 (Urb
->Ep
.EpAddr
== EpNum
) &&
1332 (Urb
->Ep
.Direction
== Direction
)) {
1334 // Device doesn't finish the IntTransfer until real data comes
1335 // So the TRB should be removed as well.
1337 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1338 if (EFI_ERROR (Status
)) {
1339 DEBUG ((EFI_D_ERROR
, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));
1342 RemoveEntryList (&Urb
->UrbList
);
1343 FreePool (Urb
->Data
);
1344 XhcFreeUrb (Xhc
, Urb
);
1349 return EFI_NOT_FOUND
;
1353 Remove all the asynchronous interrutp transfers.
1355 @param Xhc The XHCI Instance.
1359 XhciDelAllAsyncIntTransfers (
1360 IN USB_XHCI_INSTANCE
*Xhc
1368 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1369 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1372 // Device doesn't finish the IntTransfer until real data comes
1373 // So the TRB should be removed as well.
1375 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1376 if (EFI_ERROR (Status
)) {
1377 DEBUG ((EFI_D_ERROR
, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));
1380 RemoveEntryList (&Urb
->UrbList
);
1381 FreePool (Urb
->Data
);
1382 XhcFreeUrb (Xhc
, Urb
);
1387 Update the queue head for next round of asynchronous transfer
1389 @param Xhc The XHCI Instance.
1390 @param Urb The URB to update
1394 XhcUpdateAsyncRequest (
1395 IN USB_XHCI_INSTANCE
*Xhc
,
1401 if (Urb
->Result
== EFI_USB_NOERROR
) {
1402 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1403 if (EFI_ERROR (Status
)) {
1406 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1407 if (EFI_ERROR (Status
)) {
1414 Flush data from PCI controller specific address to mapped system
1417 @param Xhc The XHCI device.
1418 @param Urb The URB to unmap.
1420 @retval EFI_SUCCESS Success to flush data to mapped system memory.
1421 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
1425 XhcFlushAsyncIntMap (
1426 IN USB_XHCI_INSTANCE
*Xhc
,
1431 EFI_PHYSICAL_ADDRESS PhyAddr
;
1432 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
1433 EFI_PCI_IO_PROTOCOL
*PciIo
;
1440 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
1441 MapOp
= EfiPciIoOperationBusMasterWrite
;
1443 MapOp
= EfiPciIoOperationBusMasterRead
;
1446 if (Urb
->DataMap
!= NULL
) {
1447 Status
= PciIo
->Unmap (PciIo
, Urb
->DataMap
);
1448 if (EFI_ERROR (Status
)) {
1453 Urb
->DataMap
= NULL
;
1455 Status
= PciIo
->Map (PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
1456 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
1460 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
1465 return EFI_DEVICE_ERROR
;
1469 Interrupt transfer periodic check handler.
1471 @param Event Interrupt event.
1472 @param Context Pointer to USB_XHCI_INSTANCE.
1477 XhcMonitorAsyncRequests (
1482 USB_XHCI_INSTANCE
*Xhc
;
1491 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1493 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1495 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1496 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1499 // Make sure that the device is available before every check.
1501 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1507 // Check the result of URB execution. If it is still
1508 // active, check the next one.
1510 XhcCheckUrbResult (Xhc
, Urb
);
1512 if (!Urb
->Finished
) {
1517 // Flush any PCI posted write transactions from a PCI host
1518 // bridge to system memory.
1520 Status
= XhcFlushAsyncIntMap (Xhc
, Urb
);
1521 if (EFI_ERROR (Status
)) {
1522 DEBUG ((EFI_D_ERROR
, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1526 // Allocate a buffer then copy the transferred data for user.
1527 // If failed to allocate the buffer, update the URB for next
1528 // round of transfer. Ignore the data of this round.
1531 if (Urb
->Result
== EFI_USB_NOERROR
) {
1532 ASSERT (Urb
->Completed
<= Urb
->DataLen
);
1534 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1536 if (ProcBuf
== NULL
) {
1537 XhcUpdateAsyncRequest (Xhc
, Urb
);
1541 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1545 // Leave error recovery to its related device driver. A
1546 // common case of the error recovery is to re-submit the
1547 // interrupt transfer which is linked to the head of the
1548 // list. This function scans from head to tail. So the
1549 // re-submitted interrupt transfer's callback function
1550 // will not be called again in this round. Don't touch this
1551 // URB after the callback, it may have been removed by the
1554 if (Urb
->Callback
!= NULL
) {
1556 // Restore the old TPL, USB bus maybe connect device in
1557 // his callback. Some drivers may has a lower TPL restriction.
1559 gBS
->RestoreTPL (OldTpl
);
1560 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1561 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1564 if (ProcBuf
!= NULL
) {
1565 gBS
->FreePool (ProcBuf
);
1568 XhcUpdateAsyncRequest (Xhc
, Urb
);
1570 gBS
->RestoreTPL (OldTpl
);
1574 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1576 @param Xhc The XHCI Instance.
1577 @param ParentRouteChart The route string pointed to the parent device if it exists.
1578 @param Port The port to be polled.
1579 @param PortState The port state.
1581 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1582 @retval Others Should not appear.
1587 XhcPollPortStatusChange (
1588 IN USB_XHCI_INSTANCE
*Xhc
,
1589 IN USB_DEV_ROUTE ParentRouteChart
,
1591 IN EFI_USB_PORT_STATUS
*PortState
1597 USB_DEV_ROUTE RouteChart
;
1599 Status
= EFI_SUCCESS
;
1601 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
1605 if (ParentRouteChart
.Dword
== 0) {
1606 RouteChart
.Route
.RouteString
= 0;
1607 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1608 RouteChart
.Route
.TierNum
= 1;
1611 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1613 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1615 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1616 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1619 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1621 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1622 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1624 Status
= XhcDisableSlotCmd64 (Xhc
, SlotId
);
1628 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1629 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1631 // Has a device attached, Identify device speed after port is enabled.
1633 Speed
= EFI_USB_SPEED_FULL
;
1634 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1635 Speed
= EFI_USB_SPEED_LOW
;
1636 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1637 Speed
= EFI_USB_SPEED_HIGH
;
1638 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1639 Speed
= EFI_USB_SPEED_SUPER
;
1642 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1644 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1645 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
1646 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1647 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1649 Status
= XhcInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1659 Calculate the device context index by endpoint address and direction.
1661 @param EpAddr The target endpoint number.
1662 @param Direction The direction of the target endpoint.
1664 @return The device context index of endpoint.
1678 Index
= (UINT8
) (2 * EpAddr
);
1679 if (Direction
== EfiUsbDataIn
) {
1687 Find out the actual device address according to the requested device address from UsbBus.
1689 @param Xhc The XHCI Instance.
1690 @param BusDevAddr The requested device address by UsbBus upper driver.
1692 @return The actual device address assigned to the device.
1697 XhcBusDevAddrToSlotId (
1698 IN USB_XHCI_INSTANCE
*Xhc
,
1704 for (Index
= 0; Index
< 255; Index
++) {
1705 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1706 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1707 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1716 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1720 Find out the slot id according to the device's route string.
1722 @param Xhc The XHCI Instance.
1723 @param RouteString The route string described the device location.
1725 @return The slot id used by the device.
1730 XhcRouteStringToSlotId (
1731 IN USB_XHCI_INSTANCE
*Xhc
,
1732 IN USB_DEV_ROUTE RouteString
1737 for (Index
= 0; Index
< 255; Index
++) {
1738 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1739 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1740 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1749 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1753 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1755 @param Xhc The XHCI Instance.
1756 @param EvtRing The event ring to sync.
1758 @retval EFI_SUCCESS The event ring is synchronized successfully.
1764 IN USB_XHCI_INSTANCE
*Xhc
,
1765 IN EVENT_RING
*EvtRing
1769 TRB_TEMPLATE
*EvtTrb1
;
1771 ASSERT (EvtRing
!= NULL
);
1774 // Calculate the EventRingEnqueue and EventRingCCS.
1775 // Note: only support single Segment
1777 EvtTrb1
= EvtRing
->EventRingDequeue
;
1779 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1780 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
1786 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1787 EvtTrb1
= EvtRing
->EventRingSeg0
;
1788 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
1792 if (Index
< EvtRing
->TrbNumber
) {
1793 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1802 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1804 @param Xhc The XHCI Instance.
1805 @param TrsRing The transfer ring to sync.
1807 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1813 IN USB_XHCI_INSTANCE
*Xhc
,
1814 IN TRANSFER_RING
*TrsRing
1818 TRB_TEMPLATE
*TrsTrb
;
1820 ASSERT (TrsRing
!= NULL
);
1822 // Calculate the latest RingEnqueue and RingPCS
1824 TrsTrb
= TrsRing
->RingEnqueue
;
1825 ASSERT (TrsTrb
!= NULL
);
1827 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1828 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1832 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1833 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1835 // set cycle bit in Link TRB as normal
1837 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1839 // Toggle PCS maintained by software
1841 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1842 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
1846 ASSERT (Index
!= TrsRing
->TrbNumber
);
1848 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1849 TrsRing
->RingEnqueue
= TrsTrb
;
1853 // Clear the Trb context for enqueue, but reserve the PCS bit
1855 TrsTrb
->Parameter1
= 0;
1856 TrsTrb
->Parameter2
= 0;
1860 TrsTrb
->Control
= 0;
1866 Check if there is a new generated event.
1868 @param Xhc The XHCI Instance.
1869 @param EvtRing The event ring to check.
1870 @param NewEvtTrb The new event TRB found.
1872 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1873 @retval EFI_NOT_READY The event ring has no new event.
1879 IN USB_XHCI_INSTANCE
*Xhc
,
1880 IN EVENT_RING
*EvtRing
,
1881 OUT TRB_TEMPLATE
**NewEvtTrb
1884 ASSERT (EvtRing
!= NULL
);
1886 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
1888 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
1889 return EFI_NOT_READY
;
1892 EvtRing
->EventRingDequeue
++;
1894 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1896 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1897 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
1904 Ring the door bell to notify XHCI there is a transaction to be executed.
1906 @param Xhc The XHCI Instance.
1907 @param SlotId The slot id of the target device.
1908 @param Dci The device context index of the target slot or endpoint.
1910 @retval EFI_SUCCESS Successfully ring the door bell.
1916 IN USB_XHCI_INSTANCE
*Xhc
,
1922 XhcWriteDoorBellReg (Xhc
, 0, 0);
1924 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1931 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1933 @param Xhc The XHCI Instance.
1934 @param Urb The URB to be rung.
1936 @retval EFI_SUCCESS Successfully ring the door bell.
1940 RingIntTransferDoorBell (
1941 IN USB_XHCI_INSTANCE
*Xhc
,
1948 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1949 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1950 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1955 Assign and initialize the device slot for a new device.
1957 @param Xhc The XHCI Instance.
1958 @param ParentRouteChart The route string pointed to the parent device.
1959 @param ParentPort The port at which the device is located.
1960 @param RouteChart The route string pointed to the device.
1961 @param DeviceSpeed The device speed.
1963 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1968 XhcInitializeDeviceSlot (
1969 IN USB_XHCI_INSTANCE
*Xhc
,
1970 IN USB_DEV_ROUTE ParentRouteChart
,
1971 IN UINT16 ParentPort
,
1972 IN USB_DEV_ROUTE RouteChart
,
1973 IN UINT8 DeviceSpeed
1977 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1978 INPUT_CONTEXT
*InputContext
;
1979 DEVICE_CONTEXT
*OutputContext
;
1980 TRANSFER_RING
*EndpointTransferRing
;
1981 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1982 UINT8 DeviceAddress
;
1983 CMD_TRB_ENABLE_SLOT CmdTrb
;
1986 DEVICE_CONTEXT
*ParentDeviceContext
;
1987 EFI_PHYSICAL_ADDRESS PhyAddr
;
1989 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1990 CmdTrb
.CycleBit
= 1;
1991 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1993 Status
= XhcCmdTransfer (
1995 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1996 XHC_GENERIC_TIMEOUT
,
1997 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1999 if (EFI_ERROR (Status
)) {
2000 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
2003 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2004 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2005 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2006 ASSERT (SlotId
!= 0);
2008 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2009 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2010 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2011 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2012 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2015 // 4.3.3 Device Slot Initialization
2016 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2018 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
2019 ASSERT (InputContext
!= NULL
);
2020 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2021 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2023 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2026 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2027 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2028 // Context are affected by the command.
2030 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2033 // 3) Initialize the Input Slot Context data structure
2035 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2036 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2037 InputContext
->Slot
.ContextEntries
= 1;
2038 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2040 if (RouteChart
.Route
.RouteString
) {
2042 // The device is behind of hub device.
2044 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2045 ASSERT (ParentSlotId
!= 0);
2047 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2049 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2050 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2051 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2052 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2054 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2055 // environment from Full/Low speed signaling environment for a device
2057 InputContext
->Slot
.TTPortNum
= ParentPort
;
2058 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2062 // Inherit the TT parameters from parent device.
2064 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2065 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2067 // If the device is a High speed device then down the speed to be the same as its parent Hub
2069 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2070 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2076 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2078 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2079 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2080 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2082 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2084 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2086 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2087 InputContext
->EP
[0].MaxPacketSize
= 512;
2088 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2089 InputContext
->EP
[0].MaxPacketSize
= 64;
2091 InputContext
->EP
[0].MaxPacketSize
= 8;
2094 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2095 // 1KB, and Bulk and Isoch endpoints 3KB.
2097 InputContext
->EP
[0].AverageTRBLength
= 8;
2098 InputContext
->EP
[0].MaxBurstSize
= 0;
2099 InputContext
->EP
[0].Interval
= 0;
2100 InputContext
->EP
[0].MaxPStreams
= 0;
2101 InputContext
->EP
[0].Mult
= 0;
2102 InputContext
->EP
[0].CErr
= 3;
2105 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2107 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2109 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2110 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2112 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2113 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2116 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2118 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
2119 ASSERT (OutputContext
!= NULL
);
2120 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2121 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
2123 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2125 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2126 // a pointer to the Output Device Context data structure (6.2.1).
2128 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
2130 // Fill DCBAA with PCI device address
2132 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2135 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2136 // Context data structure described above.
2138 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2141 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2142 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2143 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2144 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2145 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2146 CmdTrbAddr
.CycleBit
= 1;
2147 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2148 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2149 Status
= XhcCmdTransfer (
2151 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2152 XHC_GENERIC_TIMEOUT
,
2153 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2155 if (!EFI_ERROR (Status
)) {
2156 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
2157 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2158 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2165 Assign and initialize the device slot for a new device.
2167 @param Xhc The XHCI Instance.
2168 @param ParentRouteChart The route string pointed to the parent device.
2169 @param ParentPort The port at which the device is located.
2170 @param RouteChart The route string pointed to the device.
2171 @param DeviceSpeed The device speed.
2173 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2178 XhcInitializeDeviceSlot64 (
2179 IN USB_XHCI_INSTANCE
*Xhc
,
2180 IN USB_DEV_ROUTE ParentRouteChart
,
2181 IN UINT16 ParentPort
,
2182 IN USB_DEV_ROUTE RouteChart
,
2183 IN UINT8 DeviceSpeed
2187 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2188 INPUT_CONTEXT_64
*InputContext
;
2189 DEVICE_CONTEXT_64
*OutputContext
;
2190 TRANSFER_RING
*EndpointTransferRing
;
2191 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2192 UINT8 DeviceAddress
;
2193 CMD_TRB_ENABLE_SLOT CmdTrb
;
2196 DEVICE_CONTEXT_64
*ParentDeviceContext
;
2197 EFI_PHYSICAL_ADDRESS PhyAddr
;
2199 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2200 CmdTrb
.CycleBit
= 1;
2201 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2203 Status
= XhcCmdTransfer (
2205 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2206 XHC_GENERIC_TIMEOUT
,
2207 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2209 if (EFI_ERROR (Status
)) {
2210 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
2213 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2214 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2215 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2216 ASSERT (SlotId
!= 0);
2218 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2219 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2220 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2221 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2222 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2225 // 4.3.3 Device Slot Initialization
2226 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2228 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
2229 ASSERT (InputContext
!= NULL
);
2230 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2231 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2233 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2236 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2237 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2238 // Context are affected by the command.
2240 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2243 // 3) Initialize the Input Slot Context data structure
2245 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2246 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2247 InputContext
->Slot
.ContextEntries
= 1;
2248 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2250 if (RouteChart
.Route
.RouteString
) {
2252 // The device is behind of hub device.
2254 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2255 ASSERT (ParentSlotId
!= 0);
2257 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2259 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2260 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2261 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2262 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2264 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2265 // environment from Full/Low speed signaling environment for a device
2267 InputContext
->Slot
.TTPortNum
= ParentPort
;
2268 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2272 // Inherit the TT parameters from parent device.
2274 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2275 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2277 // If the device is a High speed device then down the speed to be the same as its parent Hub
2279 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2280 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2286 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2288 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2289 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2290 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2292 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2294 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2296 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2297 InputContext
->EP
[0].MaxPacketSize
= 512;
2298 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2299 InputContext
->EP
[0].MaxPacketSize
= 64;
2301 InputContext
->EP
[0].MaxPacketSize
= 8;
2304 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2305 // 1KB, and Bulk and Isoch endpoints 3KB.
2307 InputContext
->EP
[0].AverageTRBLength
= 8;
2308 InputContext
->EP
[0].MaxBurstSize
= 0;
2309 InputContext
->EP
[0].Interval
= 0;
2310 InputContext
->EP
[0].MaxPStreams
= 0;
2311 InputContext
->EP
[0].Mult
= 0;
2312 InputContext
->EP
[0].CErr
= 3;
2315 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2317 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2319 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2320 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2322 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2323 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2326 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2328 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
2329 ASSERT (OutputContext
!= NULL
);
2330 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2331 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2333 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2335 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2336 // a pointer to the Output Device Context data structure (6.2.1).
2338 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2340 // Fill DCBAA with PCI device address
2342 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2345 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2346 // Context data structure described above.
2348 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2351 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2352 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2353 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2354 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2355 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2356 CmdTrbAddr
.CycleBit
= 1;
2357 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2358 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2359 Status
= XhcCmdTransfer (
2361 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2362 XHC_GENERIC_TIMEOUT
,
2363 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2365 if (!EFI_ERROR (Status
)) {
2366 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT_64
*) OutputContext
)->Slot
.DeviceAddress
;
2367 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2368 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2375 Disable the specified device slot.
2377 @param Xhc The XHCI Instance.
2378 @param SlotId The slot id to be disabled.
2380 @retval EFI_SUCCESS Successfully disable the device slot.
2386 IN USB_XHCI_INSTANCE
*Xhc
,
2391 TRB_TEMPLATE
*EvtTrb
;
2392 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2397 // Disable the device slots occupied by these devices on its downstream ports.
2398 // Entry 0 is reserved.
2400 for (Index
= 0; Index
< 255; Index
++) {
2401 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2402 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2403 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2407 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2409 if (EFI_ERROR (Status
)) {
2410 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2411 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2416 // Construct the disable slot command
2418 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2420 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2421 CmdTrbDisSlot
.CycleBit
= 1;
2422 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2423 CmdTrbDisSlot
.SlotId
= SlotId
;
2424 Status
= XhcCmdTransfer (
2426 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2427 XHC_GENERIC_TIMEOUT
,
2428 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2430 if (EFI_ERROR (Status
)) {
2431 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2435 // Free the slot's device context entry
2437 Xhc
->DCBAA
[SlotId
] = 0;
2440 // Free the slot related data structure
2442 for (Index
= 0; Index
< 31; Index
++) {
2443 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2444 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2445 if (RingSeg
!= NULL
) {
2446 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2448 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2449 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2453 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2454 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2455 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2459 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2460 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2463 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2464 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2467 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2468 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
2471 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2472 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2473 // remove urb from XHCI's asynchronous transfer list.
2475 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2476 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2482 Disable the specified device slot.
2484 @param Xhc The XHCI Instance.
2485 @param SlotId The slot id to be disabled.
2487 @retval EFI_SUCCESS Successfully disable the device slot.
2492 XhcDisableSlotCmd64 (
2493 IN USB_XHCI_INSTANCE
*Xhc
,
2498 TRB_TEMPLATE
*EvtTrb
;
2499 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2504 // Disable the device slots occupied by these devices on its downstream ports.
2505 // Entry 0 is reserved.
2507 for (Index
= 0; Index
< 255; Index
++) {
2508 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2509 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2510 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2514 Status
= XhcDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2516 if (EFI_ERROR (Status
)) {
2517 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2518 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2523 // Construct the disable slot command
2525 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2527 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2528 CmdTrbDisSlot
.CycleBit
= 1;
2529 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2530 CmdTrbDisSlot
.SlotId
= SlotId
;
2531 Status
= XhcCmdTransfer (
2533 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2534 XHC_GENERIC_TIMEOUT
,
2535 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2537 if (EFI_ERROR (Status
)) {
2538 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2542 // Free the slot's device context entry
2544 Xhc
->DCBAA
[SlotId
] = 0;
2547 // Free the slot related data structure
2549 for (Index
= 0; Index
< 31; Index
++) {
2550 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2551 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2552 if (RingSeg
!= NULL
) {
2553 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2555 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2556 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2560 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2561 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2562 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2566 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2567 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2570 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2571 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2574 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2575 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2578 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2579 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2580 // remove urb from XHCI's asynchronous transfer list.
2582 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2583 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2589 Initialize endpoint context in input context.
2591 @param Xhc The XHCI Instance.
2592 @param SlotId The slot id to be configured.
2593 @param DeviceSpeed The device's speed.
2594 @param InputContext The pointer to the input context.
2595 @param IfDesc The pointer to the usb device interface descriptor.
2597 @return The maximum device context index of endpoint.
2602 XhcInitializeEndpointContext (
2603 IN USB_XHCI_INSTANCE
*Xhc
,
2605 IN UINT8 DeviceSpeed
,
2606 IN INPUT_CONTEXT
*InputContext
,
2607 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2610 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2617 EFI_PHYSICAL_ADDRESS PhyAddr
;
2619 TRANSFER_RING
*EndpointTransferRing
;
2623 NumEp
= IfDesc
->NumEndpoints
;
2625 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2626 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2627 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2628 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2631 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2632 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2636 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2637 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2639 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2645 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2646 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2648 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2650 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2652 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2654 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2657 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2658 case USB_ENDPOINT_BULK
:
2659 if (Direction
== EfiUsbDataIn
) {
2660 InputContext
->EP
[Dci
-1].CErr
= 3;
2661 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2663 InputContext
->EP
[Dci
-1].CErr
= 3;
2664 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2667 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2668 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2669 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2670 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2671 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2672 DEBUG ((DEBUG_INFO
, "Endpoint[%x]: Created BULK ring [%p~%p)\n",
2673 EpDesc
->EndpointAddress
,
2674 EndpointTransferRing
->RingSeg0
,
2675 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2680 case USB_ENDPOINT_ISO
:
2681 if (Direction
== EfiUsbDataIn
) {
2682 InputContext
->EP
[Dci
-1].CErr
= 0;
2683 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2685 InputContext
->EP
[Dci
-1].CErr
= 0;
2686 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2689 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2690 // Refer to XHCI 1.1 spec section 6.2.3.6.
2692 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2693 Interval
= EpDesc
->Interval
;
2694 ASSERT (Interval
>= 1 && Interval
<= 16);
2695 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2696 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2697 Interval
= EpDesc
->Interval
;
2698 ASSERT (Interval
>= 1 && Interval
<= 16);
2699 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2703 // Do not support isochronous transfer now.
2705 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2706 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2708 case USB_ENDPOINT_INTERRUPT
:
2709 if (Direction
== EfiUsbDataIn
) {
2710 InputContext
->EP
[Dci
-1].CErr
= 3;
2711 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2713 InputContext
->EP
[Dci
-1].CErr
= 3;
2714 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2716 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2717 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2719 // Get the bInterval from descriptor and init the the interval field of endpoint context
2721 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2722 Interval
= EpDesc
->Interval
;
2724 // Calculate through the bInterval field of Endpoint descriptor.
2726 ASSERT (Interval
!= 0);
2727 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2728 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2729 Interval
= EpDesc
->Interval
;
2730 ASSERT (Interval
>= 1 && Interval
<= 16);
2732 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2734 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2735 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2736 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2737 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2738 InputContext
->EP
[Dci
-1].CErr
= 3;
2741 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2742 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2743 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2744 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2745 DEBUG ((DEBUG_INFO
, "Endpoint[%x]: Created INT ring [%p~%p)\n",
2746 EpDesc
->EndpointAddress
,
2747 EndpointTransferRing
->RingSeg0
,
2748 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2753 case USB_ENDPOINT_CONTROL
:
2755 // Do not support control transfer now.
2757 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2759 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2760 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2764 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2766 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2767 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2769 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2770 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2771 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2772 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2774 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2781 Initialize endpoint context in input context.
2783 @param Xhc The XHCI Instance.
2784 @param SlotId The slot id to be configured.
2785 @param DeviceSpeed The device's speed.
2786 @param InputContext The pointer to the input context.
2787 @param IfDesc The pointer to the usb device interface descriptor.
2789 @return The maximum device context index of endpoint.
2794 XhcInitializeEndpointContext64 (
2795 IN USB_XHCI_INSTANCE
*Xhc
,
2797 IN UINT8 DeviceSpeed
,
2798 IN INPUT_CONTEXT_64
*InputContext
,
2799 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2802 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2809 EFI_PHYSICAL_ADDRESS PhyAddr
;
2811 TRANSFER_RING
*EndpointTransferRing
;
2815 NumEp
= IfDesc
->NumEndpoints
;
2817 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2818 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2819 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2820 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2823 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2824 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2828 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2829 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2831 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2837 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2838 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2840 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2842 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2844 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2846 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2849 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2850 case USB_ENDPOINT_BULK
:
2851 if (Direction
== EfiUsbDataIn
) {
2852 InputContext
->EP
[Dci
-1].CErr
= 3;
2853 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2855 InputContext
->EP
[Dci
-1].CErr
= 3;
2856 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2859 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2860 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2861 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2862 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2863 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2864 DEBUG ((DEBUG_INFO
, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",
2865 EpDesc
->EndpointAddress
,
2866 EndpointTransferRing
->RingSeg0
,
2867 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2872 case USB_ENDPOINT_ISO
:
2873 if (Direction
== EfiUsbDataIn
) {
2874 InputContext
->EP
[Dci
-1].CErr
= 0;
2875 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2877 InputContext
->EP
[Dci
-1].CErr
= 0;
2878 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2881 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2882 // Refer to XHCI 1.1 spec section 6.2.3.6.
2884 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2885 Interval
= EpDesc
->Interval
;
2886 ASSERT (Interval
>= 1 && Interval
<= 16);
2887 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2888 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2889 Interval
= EpDesc
->Interval
;
2890 ASSERT (Interval
>= 1 && Interval
<= 16);
2891 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2895 // Do not support isochronous transfer now.
2897 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2898 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2900 case USB_ENDPOINT_INTERRUPT
:
2901 if (Direction
== EfiUsbDataIn
) {
2902 InputContext
->EP
[Dci
-1].CErr
= 3;
2903 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2905 InputContext
->EP
[Dci
-1].CErr
= 3;
2906 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2908 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2909 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2911 // Get the bInterval from descriptor and init the the interval field of endpoint context
2913 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2914 Interval
= EpDesc
->Interval
;
2916 // Calculate through the bInterval field of Endpoint descriptor.
2918 ASSERT (Interval
!= 0);
2919 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2920 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2921 Interval
= EpDesc
->Interval
;
2922 ASSERT (Interval
>= 1 && Interval
<= 16);
2924 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2926 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2927 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2928 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2929 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2930 InputContext
->EP
[Dci
-1].CErr
= 3;
2933 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2934 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2935 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2936 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2937 DEBUG ((DEBUG_INFO
, "Endpoint64[%x]: Created INT ring [%p~%p)\n",
2938 EpDesc
->EndpointAddress
,
2939 EndpointTransferRing
->RingSeg0
,
2940 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2945 case USB_ENDPOINT_CONTROL
:
2947 // Do not support control transfer now.
2949 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2951 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
2952 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2956 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2958 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2959 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2961 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2962 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2963 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2964 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2966 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2973 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2975 @param Xhc The XHCI Instance.
2976 @param SlotId The slot id to be configured.
2977 @param DeviceSpeed The device's speed.
2978 @param ConfigDesc The pointer to the usb device configuration descriptor.
2980 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2986 IN USB_XHCI_INSTANCE
*Xhc
,
2988 IN UINT8 DeviceSpeed
,
2989 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
2993 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
2997 EFI_PHYSICAL_ADDRESS PhyAddr
;
2999 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3000 INPUT_CONTEXT
*InputContext
;
3001 DEVICE_CONTEXT
*OutputContext
;
3002 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3004 // 4.6.6 Configure Endpoint
3006 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3007 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3008 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3009 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3011 ASSERT (ConfigDesc
!= NULL
);
3015 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3016 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3017 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3018 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3021 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3022 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3026 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3031 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3034 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3035 InputContext
->Slot
.ContextEntries
= MaxDci
;
3037 // configure endpoint
3039 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3040 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3041 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3042 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3043 CmdTrbCfgEP
.CycleBit
= 1;
3044 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3045 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3046 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3047 Status
= XhcCmdTransfer (
3049 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3050 XHC_GENERIC_TIMEOUT
,
3051 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3053 if (EFI_ERROR (Status
)) {
3054 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
3056 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3063 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3065 @param Xhc The XHCI Instance.
3066 @param SlotId The slot id to be configured.
3067 @param DeviceSpeed The device's speed.
3068 @param ConfigDesc The pointer to the usb device configuration descriptor.
3070 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3076 IN USB_XHCI_INSTANCE
*Xhc
,
3078 IN UINT8 DeviceSpeed
,
3079 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
3083 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3087 EFI_PHYSICAL_ADDRESS PhyAddr
;
3089 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3090 INPUT_CONTEXT_64
*InputContext
;
3091 DEVICE_CONTEXT_64
*OutputContext
;
3092 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3094 // 4.6.6 Configure Endpoint
3096 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3097 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3098 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3099 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3101 ASSERT (ConfigDesc
!= NULL
);
3105 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);