3 XHCI transfer scheduling routines.
5 Copyright (c) 2011 - 2018, 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
;
266 if ((Urb
->Data
!= NULL
) && (Urb
->DataMap
== NULL
)) {
267 if (((UINT8
) (Urb
->Ep
.Direction
)) == EfiUsbDataIn
) {
268 MapOp
= EfiPciIoOperationBusMasterWrite
;
270 MapOp
= EfiPciIoOperationBusMasterRead
;
274 Status
= Xhc
->PciIo
->Map (Xhc
->PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
276 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
277 DEBUG ((EFI_D_ERROR
, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
278 return EFI_OUT_OF_RESOURCES
;
281 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
288 XhcSyncTrsRing (Xhc
, EPRing
);
289 Urb
->TrbStart
= EPRing
->RingEnqueue
;
291 case ED_CONTROL_BIDIR
:
293 // For control transfer, create SETUP_STAGE_TRB first.
295 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
296 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
297 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
298 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
299 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
300 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
301 TrbStart
->TrbCtrSetup
.Length
= 8;
302 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
303 TrbStart
->TrbCtrSetup
.IOC
= 1;
304 TrbStart
->TrbCtrSetup
.IDT
= 1;
305 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
306 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
307 TrbStart
->TrbCtrSetup
.TRT
= 3;
308 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
309 TrbStart
->TrbCtrSetup
.TRT
= 2;
311 TrbStart
->TrbCtrSetup
.TRT
= 0;
314 // Update the cycle bit
316 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
320 // For control transfer, create DATA_STAGE_TRB.
322 if (Urb
->DataLen
> 0) {
323 XhcSyncTrsRing (Xhc
, EPRing
);
324 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
325 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT(Urb
->DataPhy
);
326 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT(Urb
->DataPhy
);
327 TrbStart
->TrbCtrData
.Length
= (UINT32
) Urb
->DataLen
;
328 TrbStart
->TrbCtrData
.TDSize
= 0;
329 TrbStart
->TrbCtrData
.IntTarget
= 0;
330 TrbStart
->TrbCtrData
.ISP
= 1;
331 TrbStart
->TrbCtrData
.IOC
= 1;
332 TrbStart
->TrbCtrData
.IDT
= 0;
333 TrbStart
->TrbCtrData
.CH
= 0;
334 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
335 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
336 TrbStart
->TrbCtrData
.DIR = 1;
337 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
338 TrbStart
->TrbCtrData
.DIR = 0;
340 TrbStart
->TrbCtrData
.DIR = 0;
343 // Update the cycle bit
345 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
349 // For control transfer, create STATUS_STAGE_TRB.
350 // Get the pointer to next TRB for status stage use
352 XhcSyncTrsRing (Xhc
, EPRing
);
353 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
354 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
355 TrbStart
->TrbCtrStatus
.IOC
= 1;
356 TrbStart
->TrbCtrStatus
.CH
= 0;
357 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
358 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
359 TrbStart
->TrbCtrStatus
.DIR = 0;
360 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
361 TrbStart
->TrbCtrStatus
.DIR = 1;
363 TrbStart
->TrbCtrStatus
.DIR = 0;
366 // Update the cycle bit
368 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
370 // Update the enqueue pointer
372 XhcSyncTrsRing (Xhc
, EPRing
);
374 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
383 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
384 while (TotalLen
< Urb
->DataLen
) {
385 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
386 Len
= Urb
->DataLen
- TotalLen
;
390 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
391 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
392 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
393 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
394 TrbStart
->TrbNormal
.TDSize
= 0;
395 TrbStart
->TrbNormal
.IntTarget
= 0;
396 TrbStart
->TrbNormal
.ISP
= 1;
397 TrbStart
->TrbNormal
.IOC
= 1;
398 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
400 // Update the cycle bit
402 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
404 XhcSyncTrsRing (Xhc
, EPRing
);
409 Urb
->TrbNum
= TrbNum
;
410 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
413 case ED_INTERRUPT_OUT
:
414 case ED_INTERRUPT_IN
:
418 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
419 while (TotalLen
< Urb
->DataLen
) {
420 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
421 Len
= Urb
->DataLen
- TotalLen
;
425 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
426 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
427 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
428 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
429 TrbStart
->TrbNormal
.TDSize
= 0;
430 TrbStart
->TrbNormal
.IntTarget
= 0;
431 TrbStart
->TrbNormal
.ISP
= 1;
432 TrbStart
->TrbNormal
.IOC
= 1;
433 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
435 // Update the cycle bit
437 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
439 XhcSyncTrsRing (Xhc
, EPRing
);
444 Urb
->TrbNum
= TrbNum
;
445 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
449 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
459 Initialize the XHCI host controller for schedule.
461 @param Xhc The XHCI Instance to be initialized.
466 IN USB_XHCI_INSTANCE
*Xhc
470 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
472 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
474 UINT32 MaxScratchpadBufs
;
476 EFI_PHYSICAL_ADDRESS ScratchPhy
;
477 UINT64
*ScratchEntry
;
478 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
480 UINTN
*ScratchEntryMap
;
484 // Initialize memory management.
486 Xhc
->MemPool
= UsbHcInitMemPool (Xhc
->PciIo
);
487 ASSERT (Xhc
->MemPool
!= NULL
);
490 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
491 // to enable the device slots that system software is going to use.
493 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
494 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
495 XhcWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, Xhc
->MaxSlotsEn
);
498 // The Device Context Base Address Array entry associated with each allocated Device Slot
499 // shall contain a 64-bit pointer to the base of the associated Device Context.
500 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
501 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
503 Entries
= (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
);
504 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Entries
);
505 ASSERT (Dcbaa
!= NULL
);
506 ZeroMem (Dcbaa
, Entries
);
509 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
510 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
511 // mode (Run/Stop(R/S) ='1').
513 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
514 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
515 ASSERT (MaxScratchpadBufs
<= 1023);
516 if (MaxScratchpadBufs
!= 0) {
518 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
520 ScratchEntryMap
= AllocateZeroPool (sizeof (UINTN
) * MaxScratchpadBufs
);
521 ASSERT (ScratchEntryMap
!= NULL
);
522 Xhc
->ScratchEntryMap
= ScratchEntryMap
;
525 // Allocate the buffer to record the host address for each entry
527 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
528 ASSERT (ScratchEntry
!= NULL
);
529 Xhc
->ScratchEntry
= ScratchEntry
;
532 Status
= UsbHcAllocateAlignedPages (
534 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
536 (VOID
**) &ScratchBuf
,
540 ASSERT_EFI_ERROR (Status
);
542 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
543 Xhc
->ScratchBuf
= ScratchBuf
;
546 // Allocate each scratch buffer
548 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
550 Status
= UsbHcAllocateAlignedPages (
552 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
554 (VOID
**) &ScratchEntry
[Index
],
556 (VOID
**) &ScratchEntryMap
[Index
]
558 ASSERT_EFI_ERROR (Status
);
559 ZeroMem ((VOID
*)(UINTN
)ScratchEntry
[Index
], Xhc
->PageSize
);
561 // Fill with the PCI device address
563 *ScratchBuf
++ = ScratchEntryPhy
;
566 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
567 // Device Context Base Address Array points to the Scratchpad Buffer Array.
569 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
) ScratchPhy
;
573 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
574 // a 64-bit address pointing to where the Device Context Base Address Array is located.
576 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
578 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
579 // So divide it to two 32-bytes width register access.
581 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Entries
);
582 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT(DcbaaPhy
));
583 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
585 DEBUG ((EFI_D_INFO
, "XhcInitSched:DCBAA=0x%x\n", (UINT64
)(UINTN
)Xhc
->DCBAA
));
588 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
589 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
590 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
593 CreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
595 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
596 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
597 // So we set RCS as inverted PCS init value to let Command Ring empty
599 CmdRing
= (UINT64
)(UINTN
)Xhc
->CmdRing
.RingSeg0
;
600 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) CmdRing
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
601 ASSERT ((CmdRingPhy
& 0x3F) == 0);
602 CmdRingPhy
|= XHC_CRCR_RCS
;
604 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
605 // So divide it to two 32-bytes width register access.
607 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT(CmdRingPhy
));
608 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
611 // Disable the 'interrupter enable' bit in USB_CMD
612 // and clear IE & IP bit in all Interrupter X Management Registers.
614 XhcClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
615 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
616 XhcClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
617 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
621 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
623 CreateEventRing (Xhc
, &Xhc
->EventRing
);
624 DEBUG ((DEBUG_INFO
, "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",
625 Xhc
->CmdRing
.RingSeg0
, (UINTN
)Xhc
->CmdRing
.RingSeg0
+ sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
,
626 Xhc
->EventRing
.EventRingSeg0
, (UINTN
)Xhc
->EventRing
.EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
631 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
632 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
633 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
634 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
635 Stopped to the Running state.
637 @param Xhc The XHCI Instance.
638 @param Urb The urb which makes the endpoint halted.
640 @retval EFI_SUCCESS The recovery is successful.
641 @retval Others Failed to recovery halted endpoint.
646 XhcRecoverHaltedEndpoint (
647 IN USB_XHCI_INSTANCE
*Xhc
,
655 Status
= EFI_SUCCESS
;
656 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
658 return EFI_DEVICE_ERROR
;
660 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
663 DEBUG ((EFI_D_INFO
, "Recovery Halted Slot = %x,Dci = %x\n", SlotId
, Dci
));
666 // 1) Send Reset endpoint command to transit from halt to stop state
668 Status
= XhcResetEndpoint(Xhc
, SlotId
, Dci
);
669 if (EFI_ERROR(Status
)) {
670 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
675 // 2)Set dequeue pointer
677 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
678 if (EFI_ERROR(Status
)) {
679 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
684 // 3)Ring the doorbell to transit from stop to active
686 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
693 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
694 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
695 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
698 @param Xhc The XHCI Instance.
699 @param Urb The urb which doesn't get completed in a specified timeout range.
701 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
702 @retval EFI_ALREADY_STARTED The Urb is finished so no deque is needed.
703 @retval Others Failed to stop the endpoint and dequeue the TDs.
708 XhcDequeueTrbFromEndpoint (
709 IN USB_XHCI_INSTANCE
*Xhc
,
717 Status
= EFI_SUCCESS
;
718 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
720 return EFI_DEVICE_ERROR
;
722 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
725 DEBUG ((EFI_D_INFO
, "Stop Slot = %x,Dci = %x\n", SlotId
, Dci
));
728 // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint
730 Status
= XhcStopEndpoint(Xhc
, SlotId
, Dci
, Urb
);
731 if (EFI_ERROR(Status
)) {
732 DEBUG ((EFI_D_ERROR
, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
737 // 2)Set dequeue pointer
739 if (Urb
->Finished
&& Urb
->Result
== EFI_USB_NOERROR
) {
741 // Return Already Started to indicate the pending URB is finished.
742 // This fixes BULK data loss when transfer is detected as timeout
743 // but finished just before stopping endpoint.
745 Status
= EFI_ALREADY_STARTED
;
746 DEBUG ((DEBUG_INFO
, "XhcDequeueTrbFromEndpoint: Pending URB is finished: Length Actual/Expect = %d/%d!\n", Urb
->Completed
, Urb
->DataLen
));
748 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
749 if (EFI_ERROR (Status
)) {
750 DEBUG ((DEBUG_ERROR
, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
756 // 3)Ring the doorbell to transit from stop to active
758 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
765 Create XHCI event ring.
767 @param Xhc The XHCI Instance.
768 @param EventRing The created event ring.
773 IN USB_XHCI_INSTANCE
*Xhc
,
774 OUT EVENT_RING
*EventRing
778 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
780 EFI_PHYSICAL_ADDRESS ERSTPhy
;
781 EFI_PHYSICAL_ADDRESS DequeuePhy
;
783 ASSERT (EventRing
!= NULL
);
785 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
786 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
787 ASSERT (Buf
!= NULL
);
788 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
791 EventRing
->EventRingSeg0
= Buf
;
792 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
793 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
794 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
796 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
799 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
800 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
802 EventRing
->EventRingCCS
= 1;
804 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
805 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
806 ASSERT (Buf
!= NULL
);
807 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
810 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
811 EventRing
->ERSTBase
= ERSTBase
;
812 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
813 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
814 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
816 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, ERSTBase
, Size
);
819 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
827 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
829 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
830 // So divide it to two 32-bytes width register access.
835 XHC_LOW_32BIT((UINT64
)(UINTN
)DequeuePhy
)
840 XHC_HIGH_32BIT((UINT64
)(UINTN
)DequeuePhy
)
843 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
845 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
846 // So divide it to two 32-bytes width register access.
851 XHC_LOW_32BIT((UINT64
)(UINTN
)ERSTPhy
)
855 XHC_ERSTBA_OFFSET
+ 4,
856 XHC_HIGH_32BIT((UINT64
)(UINTN
)ERSTPhy
)
859 // Need set IMAN IE bit to enble the ring interrupt
861 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
865 Create XHCI transfer ring.
867 @param Xhc The XHCI Instance.
868 @param TrbNum The number of TRB in the ring.
869 @param TransferRing The created transfer ring.
874 IN USB_XHCI_INSTANCE
*Xhc
,
876 OUT TRANSFER_RING
*TransferRing
881 EFI_PHYSICAL_ADDRESS PhyAddr
;
883 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
884 ASSERT (Buf
!= NULL
);
885 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
886 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
888 TransferRing
->RingSeg0
= Buf
;
889 TransferRing
->TrbNumber
= TrbNum
;
890 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
891 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
892 TransferRing
->RingPCS
= 1;
894 // 4.9.2 Transfer Ring Management
895 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
896 // point to the first TRB in the ring.
898 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
899 EndTrb
->Type
= TRB_TYPE_LINK
;
900 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
901 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
902 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
904 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
908 // Set Cycle bit as other TRB PCS init value
910 EndTrb
->CycleBit
= 0;
914 Free XHCI event ring.
916 @param Xhc The XHCI Instance.
917 @param EventRing The event ring to be freed.
923 IN USB_XHCI_INSTANCE
*Xhc
,
924 IN EVENT_RING
*EventRing
927 if(EventRing
->EventRingSeg0
== NULL
) {
932 // Free EventRing Segment 0
934 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
939 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
944 Free the resouce allocated at initializing schedule.
946 @param Xhc The XHCI Instance.
951 IN USB_XHCI_INSTANCE
*Xhc
955 UINT64
*ScratchEntry
;
957 if (Xhc
->ScratchBuf
!= NULL
) {
958 ScratchEntry
= Xhc
->ScratchEntry
;
959 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
961 // Free Scratchpad Buffers
963 UsbHcFreeAlignedPages (Xhc
->PciIo
, (VOID
*)(UINTN
)ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*) Xhc
->ScratchEntryMap
[Index
]);
966 // Free Scratchpad Buffer Array
968 UsbHcFreeAlignedPages (Xhc
->PciIo
, Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
969 FreePool (Xhc
->ScratchEntryMap
);
970 FreePool (Xhc
->ScratchEntry
);
973 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
974 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
975 Xhc
->CmdRing
.RingSeg0
= NULL
;
978 XhcFreeEventRing (Xhc
,&Xhc
->EventRing
);
980 if (Xhc
->DCBAA
!= NULL
) {
981 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
));
986 // Free memory pool at last
988 if (Xhc
->MemPool
!= NULL
) {
989 UsbHcFreeMemPool (Xhc
->MemPool
);
995 Check if the Trb is a transaction of the URB.
997 @param Xhc The XHCI Instance.
998 @param Trb The TRB to be checked
999 @param Urb The URB to be checked.
1001 @retval TRUE It is a transaction of the URB.
1002 @retval FALSE It is not any transaction of the URB.
1007 IN USB_XHCI_INSTANCE
*Xhc
,
1008 IN TRB_TEMPLATE
*Trb
,
1013 TRB_TEMPLATE
*CheckedTrb
;
1015 EFI_PHYSICAL_ADDRESS PhyAddr
;
1017 CheckedTrb
= Urb
->TrbStart
;
1018 for (Index
= 0; Index
< Urb
->TrbNum
; Index
++) {
1019 if (Trb
== CheckedTrb
) {
1024 // If the checked TRB is the link TRB at the end of the transfer ring,
1025 // recircle it to the head of the ring.
1027 if (CheckedTrb
->Type
== TRB_TYPE_LINK
) {
1028 LinkTrb
= (LINK_TRB
*) CheckedTrb
;
1029 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(LinkTrb
->PtrLo
| LShiftU64 ((UINT64
) LinkTrb
->PtrHi
, 32));
1030 CheckedTrb
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1031 ASSERT (CheckedTrb
== Urb
->Ring
->RingSeg0
);
1039 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
1041 @param Xhc The XHCI Instance.
1042 @param Trb The TRB to be checked.
1043 @param Urb The pointer to the matched Urb.
1045 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
1046 @retval FALSE The Trb is not matched with any URBs in the async list.
1051 IN USB_XHCI_INSTANCE
*Xhc
,
1052 IN TRB_TEMPLATE
*Trb
,
1060 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1061 CheckedUrb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1062 if (IsTransferRingTrb (Xhc
, Trb
, CheckedUrb
)) {
1073 Check the URB's execution result and update the URB's
1076 @param Xhc The XHCI Instance.
1077 @param Urb The URB to check result.
1079 @return Whether the result of URB transfer is finialized.
1084 IN USB_XHCI_INSTANCE
*Xhc
,
1088 EVT_TRB_TRANSFER
*EvtTrb
;
1089 TRB_TEMPLATE
*TRBPtr
;
1098 EFI_PHYSICAL_ADDRESS PhyAddr
;
1100 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
1102 Status
= EFI_SUCCESS
;
1105 if (Urb
->Finished
) {
1111 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1112 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
1117 // Traverse the event ring to find out all new events from the previous check.
1119 XhcSyncEventRing (Xhc
, &Xhc
->EventRing
);
1120 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
1121 Status
= XhcCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
1122 if (Status
== EFI_NOT_READY
) {
1124 // All new events are handled, return directly.
1130 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1132 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
1137 // Need convert pci device address to host address
1139 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
1140 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1143 // Update the status of URB including the pending URB, the URB that is currently checked,
1144 // and URBs in the XHCI's async interrupt transfer list.
1145 // This way is used to avoid that those completed async transfer events don't get
1146 // handled in time and are flushed by newer coming events.
1148 if (Xhc
->PendingUrb
!= NULL
&& IsTransferRingTrb (Xhc
, TRBPtr
, Xhc
->PendingUrb
)) {
1149 CheckedUrb
= Xhc
->PendingUrb
;
1150 } else if (IsTransferRingTrb (Xhc
, TRBPtr
, Urb
)) {
1152 } else if (IsAsyncIntTrb (Xhc
, TRBPtr
, &AsyncUrb
)) {
1153 CheckedUrb
= AsyncUrb
;
1158 switch (EvtTrb
->Completecode
) {
1159 case TRB_COMPLETION_STALL_ERROR
:
1160 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
1161 CheckedUrb
->Finished
= TRUE
;
1162 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1165 case TRB_COMPLETION_BABBLE_ERROR
:
1166 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
1167 CheckedUrb
->Finished
= TRUE
;
1168 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1171 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
1172 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
1173 CheckedUrb
->Finished
= TRUE
;
1174 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
1177 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
1178 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1179 CheckedUrb
->Finished
= TRUE
;
1180 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1183 case TRB_COMPLETION_STOPPED
:
1184 case TRB_COMPLETION_STOPPED_LENGTH_INVALID
:
1185 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1186 CheckedUrb
->Finished
= TRUE
;
1188 // The pending URB is timeout and force stopped when stopping endpoint.
1189 // Continue the loop to receive the Command Complete Event for stopping endpoint.
1193 case TRB_COMPLETION_SHORT_PACKET
:
1194 case TRB_COMPLETION_SUCCESS
:
1195 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
1196 DEBUG ((EFI_D_VERBOSE
, "XhcCheckUrbResult: short packet happens!\n"));
1199 TRBType
= (UINT8
) (TRBPtr
->Type
);
1200 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
1201 (TRBType
== TRB_TYPE_NORMAL
) ||
1202 (TRBType
== TRB_TYPE_ISOCH
)) {
1203 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
1209 DEBUG ((EFI_D_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
1210 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1211 CheckedUrb
->Finished
= TRUE
;
1216 // Only check first and end Trb event address
1218 if (TRBPtr
== CheckedUrb
->TrbStart
) {
1219 CheckedUrb
->StartDone
= TRUE
;
1222 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
1223 CheckedUrb
->EndDone
= TRUE
;
1226 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
1227 CheckedUrb
->Finished
= TRUE
;
1228 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
1235 // Advance event ring to last available entry
1237 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1238 // So divide it to two 32-bytes width register access.
1240 Low
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
1241 High
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
1242 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
1244 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
1246 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
1248 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1249 // So divide it to two 32-bytes width register access.
1251 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
1252 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
1255 return Urb
->Finished
;
1260 Execute the transfer by polling the URB. This is a synchronous operation.
1262 @param Xhc The XHCI Instance.
1263 @param CmdTransfer The executed URB is for cmd transfer or not.
1264 @param Urb The URB to execute.
1265 @param Timeout The time to wait before abort, in millisecond.
1267 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1268 @return EFI_TIMEOUT The transfer failed due to time out.
1269 @return EFI_SUCCESS The transfer finished OK.
1274 IN USB_XHCI_INSTANCE
*Xhc
,
1275 IN BOOLEAN CmdTransfer
,
1291 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1293 return EFI_DEVICE_ERROR
;
1295 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1299 Status
= EFI_SUCCESS
;
1300 Loop
= Timeout
* XHC_1_MILLISECOND
;
1305 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1307 for (Index
= 0; Index
< Loop
; Index
++) {
1308 Finished
= XhcCheckUrbResult (Xhc
, Urb
);
1312 gBS
->Stall (XHC_1_MICROSECOND
);
1315 if (Index
== Loop
) {
1316 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
1317 Status
= EFI_TIMEOUT
;
1318 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
1319 Status
= EFI_DEVICE_ERROR
;
1326 Delete a single asynchronous interrupt transfer for
1327 the device and endpoint.
1329 @param Xhc The XHCI Instance.
1330 @param BusAddr The logical device address assigned by UsbBus driver.
1331 @param EpNum The endpoint of the target.
1333 @retval EFI_SUCCESS An asynchronous transfer is removed.
1334 @retval EFI_NOT_FOUND No transfer for the device is found.
1338 XhciDelAsyncIntTransfer (
1339 IN USB_XHCI_INSTANCE
*Xhc
,
1347 EFI_USB_DATA_DIRECTION Direction
;
1350 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1355 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1356 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1357 if ((Urb
->Ep
.BusAddr
== BusAddr
) &&
1358 (Urb
->Ep
.EpAddr
== EpNum
) &&
1359 (Urb
->Ep
.Direction
== Direction
)) {
1361 // Device doesn't finish the IntTransfer until real data comes
1362 // So the TRB should be removed as well.
1364 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1365 if (EFI_ERROR (Status
)) {
1366 DEBUG ((EFI_D_ERROR
, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));
1369 RemoveEntryList (&Urb
->UrbList
);
1370 FreePool (Urb
->Data
);
1371 XhcFreeUrb (Xhc
, Urb
);
1376 return EFI_NOT_FOUND
;
1380 Remove all the asynchronous interrutp transfers.
1382 @param Xhc The XHCI Instance.
1386 XhciDelAllAsyncIntTransfers (
1387 IN USB_XHCI_INSTANCE
*Xhc
1395 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1396 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1399 // Device doesn't finish the IntTransfer until real data comes
1400 // So the TRB should be removed as well.
1402 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1403 if (EFI_ERROR (Status
)) {
1404 DEBUG ((EFI_D_ERROR
, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));
1407 RemoveEntryList (&Urb
->UrbList
);
1408 FreePool (Urb
->Data
);
1409 XhcFreeUrb (Xhc
, Urb
);
1414 Update the queue head for next round of asynchronous transfer
1416 @param Xhc The XHCI Instance.
1417 @param Urb The URB to update
1421 XhcUpdateAsyncRequest (
1422 IN USB_XHCI_INSTANCE
*Xhc
,
1428 if (Urb
->Result
== EFI_USB_NOERROR
) {
1429 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1430 if (EFI_ERROR (Status
)) {
1433 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1434 if (EFI_ERROR (Status
)) {
1441 Flush data from PCI controller specific address to mapped system
1444 @param Xhc The XHCI device.
1445 @param Urb The URB to unmap.
1447 @retval EFI_SUCCESS Success to flush data to mapped system memory.
1448 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
1452 XhcFlushAsyncIntMap (
1453 IN USB_XHCI_INSTANCE
*Xhc
,
1458 EFI_PHYSICAL_ADDRESS PhyAddr
;
1459 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
1460 EFI_PCI_IO_PROTOCOL
*PciIo
;
1467 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
1468 MapOp
= EfiPciIoOperationBusMasterWrite
;
1470 MapOp
= EfiPciIoOperationBusMasterRead
;
1473 if (Urb
->DataMap
!= NULL
) {
1474 Status
= PciIo
->Unmap (PciIo
, Urb
->DataMap
);
1475 if (EFI_ERROR (Status
)) {
1480 Urb
->DataMap
= NULL
;
1482 Status
= PciIo
->Map (PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
1483 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
1487 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
1492 return EFI_DEVICE_ERROR
;
1496 Interrupt transfer periodic check handler.
1498 @param Event Interrupt event.
1499 @param Context Pointer to USB_XHCI_INSTANCE.
1504 XhcMonitorAsyncRequests (
1509 USB_XHCI_INSTANCE
*Xhc
;
1518 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1520 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1522 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1523 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1526 // Make sure that the device is available before every check.
1528 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1534 // Check the result of URB execution. If it is still
1535 // active, check the next one.
1537 XhcCheckUrbResult (Xhc
, Urb
);
1539 if (!Urb
->Finished
) {
1544 // Flush any PCI posted write transactions from a PCI host
1545 // bridge to system memory.
1547 Status
= XhcFlushAsyncIntMap (Xhc
, Urb
);
1548 if (EFI_ERROR (Status
)) {
1549 DEBUG ((EFI_D_ERROR
, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1553 // Allocate a buffer then copy the transferred data for user.
1554 // If failed to allocate the buffer, update the URB for next
1555 // round of transfer. Ignore the data of this round.
1558 if (Urb
->Result
== EFI_USB_NOERROR
) {
1559 ASSERT (Urb
->Completed
<= Urb
->DataLen
);
1561 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1563 if (ProcBuf
== NULL
) {
1564 XhcUpdateAsyncRequest (Xhc
, Urb
);
1568 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1572 // Leave error recovery to its related device driver. A
1573 // common case of the error recovery is to re-submit the
1574 // interrupt transfer which is linked to the head of the
1575 // list. This function scans from head to tail. So the
1576 // re-submitted interrupt transfer's callback function
1577 // will not be called again in this round. Don't touch this
1578 // URB after the callback, it may have been removed by the
1581 if (Urb
->Callback
!= NULL
) {
1583 // Restore the old TPL, USB bus maybe connect device in
1584 // his callback. Some drivers may has a lower TPL restriction.
1586 gBS
->RestoreTPL (OldTpl
);
1587 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1588 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1591 if (ProcBuf
!= NULL
) {
1592 gBS
->FreePool (ProcBuf
);
1595 XhcUpdateAsyncRequest (Xhc
, Urb
);
1597 gBS
->RestoreTPL (OldTpl
);
1601 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1603 @param Xhc The XHCI Instance.
1604 @param ParentRouteChart The route string pointed to the parent device if it exists.
1605 @param Port The port to be polled.
1606 @param PortState The port state.
1608 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1609 @retval Others Should not appear.
1614 XhcPollPortStatusChange (
1615 IN USB_XHCI_INSTANCE
*Xhc
,
1616 IN USB_DEV_ROUTE ParentRouteChart
,
1618 IN EFI_USB_PORT_STATUS
*PortState
1624 USB_DEV_ROUTE RouteChart
;
1626 Status
= EFI_SUCCESS
;
1628 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
1632 if (ParentRouteChart
.Dword
== 0) {
1633 RouteChart
.Route
.RouteString
= 0;
1634 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1635 RouteChart
.Route
.TierNum
= 1;
1638 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1640 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1642 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1643 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1646 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1648 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1649 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1651 Status
= XhcDisableSlotCmd64 (Xhc
, SlotId
);
1655 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1656 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1658 // Has a device attached, Identify device speed after port is enabled.
1660 Speed
= EFI_USB_SPEED_FULL
;
1661 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1662 Speed
= EFI_USB_SPEED_LOW
;
1663 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1664 Speed
= EFI_USB_SPEED_HIGH
;
1665 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1666 Speed
= EFI_USB_SPEED_SUPER
;
1669 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1671 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1672 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
1673 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1674 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1676 Status
= XhcInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1686 Calculate the device context index by endpoint address and direction.
1688 @param EpAddr The target endpoint number.
1689 @param Direction The direction of the target endpoint.
1691 @return The device context index of endpoint.
1705 Index
= (UINT8
) (2 * EpAddr
);
1706 if (Direction
== EfiUsbDataIn
) {
1714 Find out the actual device address according to the requested device address from UsbBus.
1716 @param Xhc The XHCI Instance.
1717 @param BusDevAddr The requested device address by UsbBus upper driver.
1719 @return The actual device address assigned to the device.
1724 XhcBusDevAddrToSlotId (
1725 IN USB_XHCI_INSTANCE
*Xhc
,
1731 for (Index
= 0; Index
< 255; Index
++) {
1732 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1733 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1734 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1743 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1747 Find out the slot id according to the device's route string.
1749 @param Xhc The XHCI Instance.
1750 @param RouteString The route string described the device location.
1752 @return The slot id used by the device.
1757 XhcRouteStringToSlotId (
1758 IN USB_XHCI_INSTANCE
*Xhc
,
1759 IN USB_DEV_ROUTE RouteString
1764 for (Index
= 0; Index
< 255; Index
++) {
1765 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1766 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1767 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1776 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1780 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1782 @param Xhc The XHCI Instance.
1783 @param EvtRing The event ring to sync.
1785 @retval EFI_SUCCESS The event ring is synchronized successfully.
1791 IN USB_XHCI_INSTANCE
*Xhc
,
1792 IN EVENT_RING
*EvtRing
1796 TRB_TEMPLATE
*EvtTrb1
;
1798 ASSERT (EvtRing
!= NULL
);
1801 // Calculate the EventRingEnqueue and EventRingCCS.
1802 // Note: only support single Segment
1804 EvtTrb1
= EvtRing
->EventRingDequeue
;
1806 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1807 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
1813 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1814 EvtTrb1
= EvtRing
->EventRingSeg0
;
1815 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
1819 if (Index
< EvtRing
->TrbNumber
) {
1820 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1829 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1831 @param Xhc The XHCI Instance.
1832 @param TrsRing The transfer ring to sync.
1834 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1840 IN USB_XHCI_INSTANCE
*Xhc
,
1841 IN TRANSFER_RING
*TrsRing
1845 TRB_TEMPLATE
*TrsTrb
;
1847 ASSERT (TrsRing
!= NULL
);
1849 // Calculate the latest RingEnqueue and RingPCS
1851 TrsTrb
= TrsRing
->RingEnqueue
;
1852 ASSERT (TrsTrb
!= NULL
);
1854 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1855 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1859 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1860 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1862 // set cycle bit in Link TRB as normal
1864 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1866 // Toggle PCS maintained by software
1868 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1869 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
1873 ASSERT (Index
!= TrsRing
->TrbNumber
);
1875 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1876 TrsRing
->RingEnqueue
= TrsTrb
;
1880 // Clear the Trb context for enqueue, but reserve the PCS bit
1882 TrsTrb
->Parameter1
= 0;
1883 TrsTrb
->Parameter2
= 0;
1887 TrsTrb
->Control
= 0;
1893 Check if there is a new generated event.
1895 @param Xhc The XHCI Instance.
1896 @param EvtRing The event ring to check.
1897 @param NewEvtTrb The new event TRB found.
1899 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1900 @retval EFI_NOT_READY The event ring has no new event.
1906 IN USB_XHCI_INSTANCE
*Xhc
,
1907 IN EVENT_RING
*EvtRing
,
1908 OUT TRB_TEMPLATE
**NewEvtTrb
1911 ASSERT (EvtRing
!= NULL
);
1913 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
1915 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
1916 return EFI_NOT_READY
;
1919 EvtRing
->EventRingDequeue
++;
1921 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1923 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1924 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
1931 Ring the door bell to notify XHCI there is a transaction to be executed.
1933 @param Xhc The XHCI Instance.
1934 @param SlotId The slot id of the target device.
1935 @param Dci The device context index of the target slot or endpoint.
1937 @retval EFI_SUCCESS Successfully ring the door bell.
1943 IN USB_XHCI_INSTANCE
*Xhc
,
1949 XhcWriteDoorBellReg (Xhc
, 0, 0);
1951 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1958 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1960 @param Xhc The XHCI Instance.
1961 @param Urb The URB to be rung.
1963 @retval EFI_SUCCESS Successfully ring the door bell.
1967 RingIntTransferDoorBell (
1968 IN USB_XHCI_INSTANCE
*Xhc
,
1975 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1976 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1977 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1982 Assign and initialize the device slot for a new device.
1984 @param Xhc The XHCI Instance.
1985 @param ParentRouteChart The route string pointed to the parent device.
1986 @param ParentPort The port at which the device is located.
1987 @param RouteChart The route string pointed to the device.
1988 @param DeviceSpeed The device speed.
1990 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1995 XhcInitializeDeviceSlot (
1996 IN USB_XHCI_INSTANCE
*Xhc
,
1997 IN USB_DEV_ROUTE ParentRouteChart
,
1998 IN UINT16 ParentPort
,
1999 IN USB_DEV_ROUTE RouteChart
,
2000 IN UINT8 DeviceSpeed
2004 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2005 INPUT_CONTEXT
*InputContext
;
2006 DEVICE_CONTEXT
*OutputContext
;
2007 TRANSFER_RING
*EndpointTransferRing
;
2008 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2009 UINT8 DeviceAddress
;
2010 CMD_TRB_ENABLE_SLOT CmdTrb
;
2013 DEVICE_CONTEXT
*ParentDeviceContext
;
2014 EFI_PHYSICAL_ADDRESS PhyAddr
;
2016 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2017 CmdTrb
.CycleBit
= 1;
2018 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2020 Status
= XhcCmdTransfer (
2022 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2023 XHC_GENERIC_TIMEOUT
,
2024 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2026 if (EFI_ERROR (Status
)) {
2027 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
2030 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2031 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2032 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2033 ASSERT (SlotId
!= 0);
2035 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2036 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2037 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2038 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2039 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2042 // 4.3.3 Device Slot Initialization
2043 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2045 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
2046 ASSERT (InputContext
!= NULL
);
2047 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2048 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2050 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2053 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2054 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2055 // Context are affected by the command.
2057 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2060 // 3) Initialize the Input Slot Context data structure
2062 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2063 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2064 InputContext
->Slot
.ContextEntries
= 1;
2065 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2067 if (RouteChart
.Route
.RouteString
) {
2069 // The device is behind of hub device.
2071 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2072 ASSERT (ParentSlotId
!= 0);
2074 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2076 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2077 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2078 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2079 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2081 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2082 // environment from Full/Low speed signaling environment for a device
2084 InputContext
->Slot
.TTPortNum
= ParentPort
;
2085 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2089 // Inherit the TT parameters from parent device.
2091 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2092 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2094 // If the device is a High speed device then down the speed to be the same as its parent Hub
2096 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2097 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2103 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2105 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2106 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2107 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2109 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2111 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2113 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2114 InputContext
->EP
[0].MaxPacketSize
= 512;
2115 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2116 InputContext
->EP
[0].MaxPacketSize
= 64;
2118 InputContext
->EP
[0].MaxPacketSize
= 8;
2121 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2122 // 1KB, and Bulk and Isoch endpoints 3KB.
2124 InputContext
->EP
[0].AverageTRBLength
= 8;
2125 InputContext
->EP
[0].MaxBurstSize
= 0;
2126 InputContext
->EP
[0].Interval
= 0;
2127 InputContext
->EP
[0].MaxPStreams
= 0;
2128 InputContext
->EP
[0].Mult
= 0;
2129 InputContext
->EP
[0].CErr
= 3;
2132 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2134 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2136 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2137 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2139 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2140 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2143 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2145 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
2146 ASSERT (OutputContext
!= NULL
);
2147 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2148 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
2150 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2152 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2153 // a pointer to the Output Device Context data structure (6.2.1).
2155 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
2157 // Fill DCBAA with PCI device address
2159 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2162 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2163 // Context data structure described above.
2165 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2168 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2169 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2170 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2171 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2172 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2173 CmdTrbAddr
.CycleBit
= 1;
2174 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2175 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2176 Status
= XhcCmdTransfer (
2178 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2179 XHC_GENERIC_TIMEOUT
,
2180 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2182 if (!EFI_ERROR (Status
)) {
2183 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
2184 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2185 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2192 Assign and initialize the device slot for a new device.
2194 @param Xhc The XHCI Instance.
2195 @param ParentRouteChart The route string pointed to the parent device.
2196 @param ParentPort The port at which the device is located.
2197 @param RouteChart The route string pointed to the device.
2198 @param DeviceSpeed The device speed.
2200 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2205 XhcInitializeDeviceSlot64 (
2206 IN USB_XHCI_INSTANCE
*Xhc
,
2207 IN USB_DEV_ROUTE ParentRouteChart
,
2208 IN UINT16 ParentPort
,
2209 IN USB_DEV_ROUTE RouteChart
,
2210 IN UINT8 DeviceSpeed
2214 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2215 INPUT_CONTEXT_64
*InputContext
;
2216 DEVICE_CONTEXT_64
*OutputContext
;
2217 TRANSFER_RING
*EndpointTransferRing
;
2218 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2219 UINT8 DeviceAddress
;
2220 CMD_TRB_ENABLE_SLOT CmdTrb
;
2223 DEVICE_CONTEXT_64
*ParentDeviceContext
;
2224 EFI_PHYSICAL_ADDRESS PhyAddr
;
2226 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2227 CmdTrb
.CycleBit
= 1;
2228 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2230 Status
= XhcCmdTransfer (
2232 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2233 XHC_GENERIC_TIMEOUT
,
2234 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2236 if (EFI_ERROR (Status
)) {
2237 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
2240 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2241 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2242 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2243 ASSERT (SlotId
!= 0);
2245 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2246 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2247 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2248 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2249 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2252 // 4.3.3 Device Slot Initialization
2253 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2255 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
2256 ASSERT (InputContext
!= NULL
);
2257 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2258 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2260 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2263 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2264 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2265 // Context are affected by the command.
2267 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2270 // 3) Initialize the Input Slot Context data structure
2272 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2273 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2274 InputContext
->Slot
.ContextEntries
= 1;
2275 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2277 if (RouteChart
.Route
.RouteString
) {
2279 // The device is behind of hub device.
2281 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2282 ASSERT (ParentSlotId
!= 0);
2284 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2286 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2287 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2288 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2289 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2291 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2292 // environment from Full/Low speed signaling environment for a device
2294 InputContext
->Slot
.TTPortNum
= ParentPort
;
2295 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2299 // Inherit the TT parameters from parent device.
2301 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2302 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2304 // If the device is a High speed device then down the speed to be the same as its parent Hub
2306 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2307 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2313 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2315 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2316 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2317 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2319 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2321 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2323 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2324 InputContext
->EP
[0].MaxPacketSize
= 512;
2325 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2326 InputContext
->EP
[0].MaxPacketSize
= 64;
2328 InputContext
->EP
[0].MaxPacketSize
= 8;
2331 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2332 // 1KB, and Bulk and Isoch endpoints 3KB.
2334 InputContext
->EP
[0].AverageTRBLength
= 8;
2335 InputContext
->EP
[0].MaxBurstSize
= 0;
2336 InputContext
->EP
[0].Interval
= 0;
2337 InputContext
->EP
[0].MaxPStreams
= 0;
2338 InputContext
->EP
[0].Mult
= 0;
2339 InputContext
->EP
[0].CErr
= 3;
2342 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2344 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2346 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2347 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2349 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2350 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2353 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2355 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
2356 ASSERT (OutputContext
!= NULL
);
2357 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2358 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2360 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2362 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2363 // a pointer to the Output Device Context data structure (6.2.1).
2365 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2367 // Fill DCBAA with PCI device address
2369 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2372 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2373 // Context data structure described above.
2375 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2378 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2379 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2380 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2381 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2382 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2383 CmdTrbAddr
.CycleBit
= 1;
2384 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2385 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2386 Status
= XhcCmdTransfer (
2388 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2389 XHC_GENERIC_TIMEOUT
,
2390 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2392 if (!EFI_ERROR (Status
)) {
2393 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT_64
*) OutputContext
)->Slot
.DeviceAddress
;
2394 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2395 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2402 Disable the specified device slot.
2404 @param Xhc The XHCI Instance.
2405 @param SlotId The slot id to be disabled.
2407 @retval EFI_SUCCESS Successfully disable the device slot.
2413 IN USB_XHCI_INSTANCE
*Xhc
,
2418 TRB_TEMPLATE
*EvtTrb
;
2419 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2424 // Disable the device slots occupied by these devices on its downstream ports.
2425 // Entry 0 is reserved.
2427 for (Index
= 0; Index
< 255; Index
++) {
2428 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2429 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2430 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2434 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2436 if (EFI_ERROR (Status
)) {
2437 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2438 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2443 // Construct the disable slot command
2445 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2447 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2448 CmdTrbDisSlot
.CycleBit
= 1;
2449 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2450 CmdTrbDisSlot
.SlotId
= SlotId
;
2451 Status
= XhcCmdTransfer (
2453 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2454 XHC_GENERIC_TIMEOUT
,
2455 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2457 if (EFI_ERROR (Status
)) {
2458 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2462 // Free the slot's device context entry
2464 Xhc
->DCBAA
[SlotId
] = 0;
2467 // Free the slot related data structure
2469 for (Index
= 0; Index
< 31; Index
++) {
2470 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2471 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2472 if (RingSeg
!= NULL
) {
2473 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2475 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2476 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2480 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2481 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2482 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2486 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2487 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2490 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2491 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2494 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2495 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
2498 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2499 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2500 // remove urb from XHCI's asynchronous transfer list.
2502 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2503 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2509 Disable the specified device slot.
2511 @param Xhc The XHCI Instance.
2512 @param SlotId The slot id to be disabled.
2514 @retval EFI_SUCCESS Successfully disable the device slot.
2519 XhcDisableSlotCmd64 (
2520 IN USB_XHCI_INSTANCE
*Xhc
,
2525 TRB_TEMPLATE
*EvtTrb
;
2526 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2531 // Disable the device slots occupied by these devices on its downstream ports.
2532 // Entry 0 is reserved.
2534 for (Index
= 0; Index
< 255; Index
++) {
2535 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2536 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2537 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2541 Status
= XhcDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2543 if (EFI_ERROR (Status
)) {
2544 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2545 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2550 // Construct the disable slot command
2552 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2554 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2555 CmdTrbDisSlot
.CycleBit
= 1;
2556 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2557 CmdTrbDisSlot
.SlotId
= SlotId
;
2558 Status
= XhcCmdTransfer (
2560 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2561 XHC_GENERIC_TIMEOUT
,
2562 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2564 if (EFI_ERROR (Status
)) {
2565 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2569 // Free the slot's device context entry
2571 Xhc
->DCBAA
[SlotId
] = 0;
2574 // Free the slot related data structure
2576 for (Index
= 0; Index
< 31; Index
++) {
2577 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2578 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2579 if (RingSeg
!= NULL
) {
2580 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2582 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2583 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2587 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2588 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2589 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2593 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2594 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2597 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2598 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2601 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2602 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2605 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2606 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2607 // remove urb from XHCI's asynchronous transfer list.
2609 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2610 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2616 Initialize endpoint context in input context.
2618 @param Xhc The XHCI Instance.
2619 @param SlotId The slot id to be configured.
2620 @param DeviceSpeed The device's speed.
2621 @param InputContext The pointer to the input context.
2622 @param IfDesc The pointer to the usb device interface descriptor.
2624 @return The maximum device context index of endpoint.
2629 XhcInitializeEndpointContext (
2630 IN USB_XHCI_INSTANCE
*Xhc
,
2632 IN UINT8 DeviceSpeed
,
2633 IN INPUT_CONTEXT
*InputContext
,
2634 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2637 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2644 EFI_PHYSICAL_ADDRESS PhyAddr
;
2646 TRANSFER_RING
*EndpointTransferRing
;
2650 NumEp
= IfDesc
->NumEndpoints
;
2652 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2653 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2654 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2655 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2658 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2659 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2663 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2664 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2666 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2672 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2673 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2675 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2677 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2679 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2681 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2684 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2685 case USB_ENDPOINT_BULK
:
2686 if (Direction
== EfiUsbDataIn
) {
2687 InputContext
->EP
[Dci
-1].CErr
= 3;
2688 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2690 InputContext
->EP
[Dci
-1].CErr
= 3;
2691 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2694 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2695 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2696 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2697 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2698 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2699 DEBUG ((DEBUG_INFO
, "Endpoint[%x]: Created BULK ring [%p~%p)\n",
2700 EpDesc
->EndpointAddress
,
2701 EndpointTransferRing
->RingSeg0
,
2702 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2707 case USB_ENDPOINT_ISO
:
2708 if (Direction
== EfiUsbDataIn
) {
2709 InputContext
->EP
[Dci
-1].CErr
= 0;
2710 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2712 InputContext
->EP
[Dci
-1].CErr
= 0;
2713 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2716 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2717 // Refer to XHCI 1.1 spec section 6.2.3.6.
2719 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2720 Interval
= EpDesc
->Interval
;
2721 ASSERT (Interval
>= 1 && Interval
<= 16);
2722 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2723 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2724 Interval
= EpDesc
->Interval
;
2725 ASSERT (Interval
>= 1 && Interval
<= 16);
2726 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2730 // Do not support isochronous transfer now.
2732 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2733 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2735 case USB_ENDPOINT_INTERRUPT
:
2736 if (Direction
== EfiUsbDataIn
) {
2737 InputContext
->EP
[Dci
-1].CErr
= 3;
2738 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2740 InputContext
->EP
[Dci
-1].CErr
= 3;
2741 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2743 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2744 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2746 // Get the bInterval from descriptor and init the the interval field of endpoint context
2748 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2749 Interval
= EpDesc
->Interval
;
2751 // Calculate through the bInterval field of Endpoint descriptor.
2753 ASSERT (Interval
!= 0);
2754 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2755 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2756 Interval
= EpDesc
->Interval
;
2757 ASSERT (Interval
>= 1 && Interval
<= 16);
2759 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2761 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2762 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2763 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2764 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2765 InputContext
->EP
[Dci
-1].CErr
= 3;
2768 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2769 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2770 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2771 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2772 DEBUG ((DEBUG_INFO
, "Endpoint[%x]: Created INT ring [%p~%p)\n",
2773 EpDesc
->EndpointAddress
,
2774 EndpointTransferRing
->RingSeg0
,
2775 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2780 case USB_ENDPOINT_CONTROL
:
2782 // Do not support control transfer now.
2784 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2786 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2787 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2791 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2793 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2794 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2796 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2797 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2798 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2799 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2801 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2808 Initialize endpoint context in input context.
2810 @param Xhc The XHCI Instance.
2811 @param SlotId The slot id to be configured.
2812 @param DeviceSpeed The device's speed.
2813 @param InputContext The pointer to the input context.
2814 @param IfDesc The pointer to the usb device interface descriptor.
2816 @return The maximum device context index of endpoint.
2821 XhcInitializeEndpointContext64 (
2822 IN USB_XHCI_INSTANCE
*Xhc
,
2824 IN UINT8 DeviceSpeed
,
2825 IN INPUT_CONTEXT_64
*InputContext
,
2826 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2829 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2836 EFI_PHYSICAL_ADDRESS PhyAddr
;
2838 TRANSFER_RING
*EndpointTransferRing
;
2842 NumEp
= IfDesc
->NumEndpoints
;
2844 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2845 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2846 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2847 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2850 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2851 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2855 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2856 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2858 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2864 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2865 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2867 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2869 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2871 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2873 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2876 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2877 case USB_ENDPOINT_BULK
:
2878 if (Direction
== EfiUsbDataIn
) {
2879 InputContext
->EP
[Dci
-1].CErr
= 3;
2880 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2882 InputContext
->EP
[Dci
-1].CErr
= 3;
2883 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2886 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2887 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2888 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2889 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2890 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2891 DEBUG ((DEBUG_INFO
, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",
2892 EpDesc
->EndpointAddress
,
2893 EndpointTransferRing
->RingSeg0
,
2894 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2899 case USB_ENDPOINT_ISO
:
2900 if (Direction
== EfiUsbDataIn
) {
2901 InputContext
->EP
[Dci
-1].CErr
= 0;
2902 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2904 InputContext
->EP
[Dci
-1].CErr
= 0;
2905 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2908 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2909 // Refer to XHCI 1.1 spec section 6.2.3.6.
2911 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2912 Interval
= EpDesc
->Interval
;
2913 ASSERT (Interval
>= 1 && Interval
<= 16);
2914 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2915 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2916 Interval
= EpDesc
->Interval
;
2917 ASSERT (Interval
>= 1 && Interval
<= 16);
2918 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2922 // Do not support isochronous transfer now.
2924 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2925 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2927 case USB_ENDPOINT_INTERRUPT
:
2928 if (Direction
== EfiUsbDataIn
) {
2929 InputContext
->EP
[Dci
-1].CErr
= 3;
2930 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2932 InputContext
->EP
[Dci
-1].CErr
= 3;
2933 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2935 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2936 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2938 // Get the bInterval from descriptor and init the the interval field of endpoint context
2940 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2941 Interval
= EpDesc
->Interval
;
2943 // Calculate through the bInterval field of Endpoint descriptor.
2945 ASSERT (Interval
!= 0);
2946 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2947 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2948 Interval
= EpDesc
->Interval
;
2949 ASSERT (Interval
>= 1 && Interval
<= 16);
2951 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2953 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2954 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2955 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2956 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2957 InputContext
->EP
[Dci
-1].CErr
= 3;
2960 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2961 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2962 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2963 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2964 DEBUG ((DEBUG_INFO
, "Endpoint64[%x]: Created INT ring [%p~%p)\n",
2965 EpDesc
->EndpointAddress
,
2966 EndpointTransferRing
->RingSeg0
,
2967 (UINTN
) EndpointTransferRing
->RingSeg0
+ TR_RING_TRB_NUMBER
* sizeof (TRB_TEMPLATE
)
2972 case USB_ENDPOINT_CONTROL
:
2974 // Do not support control transfer now.
2976 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2978 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
2979 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2983 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2985 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2986 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2988 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2989 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2990 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2991 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2993 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3000 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3002 @param Xhc The XHCI Instance.
3003 @param SlotId The slot id to be configured.
3004 @param DeviceSpeed The device's speed.
3005 @param ConfigDesc The pointer to the usb device configuration descriptor.
3007 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3013 IN USB_XHCI_INSTANCE
*Xhc
,
3015 IN UINT8 DeviceSpeed
,
3016 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
3020 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3024 EFI_PHYSICAL_ADDRESS PhyAddr
;
3026 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3027 INPUT_CONTEXT
*InputContext
;
3028 DEVICE_CONTEXT
*OutputContext
;
3029 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3031 // 4.6.6 Configure Endpoint
3033 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3034 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3035 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3036 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3038 ASSERT (ConfigDesc
!= NULL
);
3042 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3043 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3044 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3045 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3048 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3049 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3053 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3058 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3061 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3062 InputContext
->Slot
.ContextEntries
= MaxDci
;
3064 // configure endpoint
3066 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3067 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3068 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3069 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3070 CmdTrbCfgEP
.CycleBit
= 1;
3071 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3072 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3073 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3074 Status
= XhcCmdTransfer (
3076 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3077 XHC_GENERIC_TIMEOUT
,
3078 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3080 if (EFI_ERROR (Status
)) {
3081 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
3083 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3090 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3092 @param Xhc The XHCI Instance.
3093 @param SlotId The slot id to be configured.
3094 @param DeviceSpeed The device's speed.
3095 @param ConfigDesc The pointer to the usb device configuration descriptor.
3097 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3103 IN USB_XHCI_INSTANCE
*Xhc
,
3105 IN UINT8 DeviceSpeed
,
3106 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
3110 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3114 EFI_PHYSICAL_ADDRESS PhyAddr
;
3116 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3117 INPUT_CONTEXT_64
*InputContext
;
3118 DEVICE_CONTEXT_64
*OutputContext
;
3119 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3121 // 4.6.6 Configure Endpoint
3123 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3124 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3125 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3126 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3128 ASSERT (ConfigDesc
!= NULL
);
3132 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3133 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3134 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3135 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3138 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3139 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3143 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3148 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3151 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3152 InputContext
->Slot
.ContextEntries
= MaxDci
;
3154 // configure endpoint
3156 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3157 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3158 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3159 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3160 CmdTrbCfgEP
.CycleBit
= 1;
3161 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3162 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3163 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3164 Status
= XhcCmdTransfer (
3166 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3167 XHC_GENERIC_TIMEOUT
,
3168 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3170 if (EFI_ERROR (Status
)) {
3171 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
3173 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3180 Stop endpoint through XHCI's Stop_Endpoint cmd.
3182 @param Xhc The XHCI Instance.
3183 @param SlotId The slot id to be configured.
3184 @param Dci The device context index of endpoint.
3185 @param PendingUrb The pending URB to check completion status when stopping the end point.
3187 @retval EFI_SUCCESS Stop endpoint successfully.
3188 @retval Others Failed to stop endpoint.
3194 IN USB_XHCI_INSTANCE
*Xhc
,
3197 IN URB
*PendingUrb OPTIONAL
3201 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3202 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
3204 DEBUG ((EFI_D_INFO
, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3207 // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks
3208 // the PendingUrb completion status, because it's possible that the PendingUrb is
3209 // finished just before stopping the end point, but after the looping check.
3211 // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult
3212 // through function parameter, but That will cause every consumer of XhcCmdTransfer,
3213 // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.
3214 // But actually only XhcCheckUrbResult is aware of the PendingUrb.
3215 // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.
3217 ASSERT (Xhc
->PendingUrb
== NULL
);
3218 Xhc
->PendingUrb
= PendingUrb
;
3220 // Reset the URB result from Timeout to NoError.
3221 // The USB result will be:
3222 // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or
3223 // remain NoError when Success/ShortPacket Transfer Event is received.
3225 if (PendingUrb
!= NULL
) {
3226 PendingUrb
->Result
= EFI_USB_NOERROR
;
3230 // Send stop endpoint command to transit Endpoint from running to stop state
3232 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
3233 CmdTrbStopED
.CycleBit
= 1;
3234 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
3235 CmdTrbStopED
.EDID
= Dci
;
3236 CmdTrbStopED
.SlotId
= SlotId
;
3237 Status
= XhcCmdTransfer (
3239 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbStopED
,
3240 XHC_GENERIC_TIMEOUT
,
3241 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3243 if (EFI_ERROR(Status
)) {
3244 DEBUG ((EFI_D_ERROR
, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
3247 Xhc
->PendingUrb
= NULL
;
3253 Reset endpoint through XHCI's Reset_Endpoint cmd.
3255 @param Xhc The XHCI Instance.
3256 @param SlotId The slot id to be configured.
3257 @param Dci The device context index of endpoint.
3259 @retval EFI_SUCCESS Reset endpoint successfully.
3260 @retval Others Failed to reset endpoint.
3266 IN USB_XHCI_INSTANCE
*Xhc
,
3272 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3273 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
3275 DEBUG ((EFI_D_INFO
, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3278 // Send stop endpoint command to transit Endpoint from running to stop state
3280 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
3281 CmdTrbResetED
.CycleBit
= 1;
3282 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
3283 CmdTrbResetED
.EDID
= Dci
;
3284 CmdTrbResetED
.SlotId
= SlotId
;
3285 Status
= XhcCmdTransfer (
3287 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
3288 XHC_GENERIC_TIMEOUT
,
3289 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3291 if (EFI_ERROR(Status
)) {
3292 DEBUG ((EFI_D_ERROR
, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
3299 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3301 @param Xhc The XHCI Instance.
3302 @param SlotId The slot id to be configured.
3303 @param Dci The device context index of endpoint.
3304 @param Urb The dequeue pointer of the transfer ring specified
3305 by the urb to be updated.
3307 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
3308 @retval Others Failed to set transfer ring dequeue pointer.
3313 XhcSetTrDequeuePointer (
3314 IN USB_XHCI_INSTANCE
*Xhc
,
3321 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3322 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
3323 EFI_PHYSICAL_ADDRESS PhyAddr
;
3325 DEBUG ((EFI_D_INFO
, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
3328 // Send stop endpoint command to transit Endpoint from running to stop state
3330 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
3331 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
3332 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
3333 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3334 CmdSetTRDeq
.CycleBit
= 1;
3335 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
3336 CmdSetTRDeq
.Endpoint
= Dci
;
3337 CmdSetTRDeq
.SlotId
= SlotId
;
3338 Status
= XhcCmdTransfer (
3340 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
3341 XHC_GENERIC_TIMEOUT
,
3342 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3344 if (EFI_ERROR(Status
)) {
3345 DEBUG ((EFI_D_ERROR
, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
3352 Set interface through XHCI's Configure_Endpoint cmd.
3354 @param Xhc The XHCI Instance.
3355 @param SlotId The slot id to be configured.
3356 @param DeviceSpeed The device's speed.
3357 @param ConfigDesc The pointer to the usb device configuration descriptor.
3358 @param Request USB device request to send.
3360 @retval EFI_SUCCESS Successfully set interface.
3366 IN USB_XHCI_INSTANCE
*Xhc
,
3368 IN UINT8 DeviceSpeed
,
3369 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3370 IN EFI_USB_DEVICE_REQUEST
*Request
3374 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3375 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3376 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3377 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3384 EFI_PHYSICAL_ADDRESS PhyAddr
;
3387 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3388 INPUT_CONTEXT
*InputContext
;
3389 DEVICE_CONTEXT
*OutputContext
;
3390 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3392 Status
= EFI_SUCCESS
;
3394 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3395 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3397 // XHCI 4.6.6 Configure Endpoint
3398 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3399 // Context and Add Context flags as follows:
3400 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3401 // Context and Add Context flags to '0'.
3403 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3404 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3406 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3407 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3409 ASSERT (ConfigDesc
!= NULL
);
3413 IfDescActive
= NULL
;
3416 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3417 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3418 if ((IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) && (IfDesc
->Length
>= sizeof (USB_INTERFACE_DESCRIPTOR
))) {
3419 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3420 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3422 // Find out the active interface descriptor.
3424 IfDescActive
= IfDesc
;
3425 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3427 // Find out the interface descriptor to set.
3433 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3437 // XHCI 4.6.6 Configure Endpoint
3438 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3439 // Context and Add Context flags as follows:
3440 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3441 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3442 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3443 // the Drop Context flag to '1' and Add Context flag to '0'.
3444 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3445 // and Add Context flags shall be set to '1'.
3447 // Below codes are to cover 2), 3) and 4).
3450 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3451 NumEp
= IfDescActive
->NumEndpoints
;
3452 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3453 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3454 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3455 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3458 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
3459 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3463 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3464 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3466 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3472 // XHCI 4.3.6 - Setting Alternate Interfaces
3473 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3475 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
, NULL
);
3476 if (EFI_ERROR (Status
)) {
3480 // XHCI 4.3.6 - Setting Alternate Interfaces
3481 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3483 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3484 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3485 if (RingSeg
!= NULL
) {
3486 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3488 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3489 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3493 // Set the Drop Context flag to '1'.
3495 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3497 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3501 // XHCI 4.3.6 - Setting Alternate Interfaces
3502 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3503 // Interface setting, to '0'.
3505 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3509 // XHCI 4.3.6 - Setting Alternate Interfaces
3510 // 4) For each endpoint enabled by the Configure Endpoint Command:
3511 // a. Allocate a Transfer Ring.
3512 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3513 // c. Initialize the Endpoint Context data structure.
3515 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3520 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3521 InputContext
->Slot
.ContextEntries
= MaxDci
;
3523 // XHCI 4.3.6 - Setting Alternate Interfaces
3524 // 5) Issue and successfully complete a Configure Endpoint Command.
3526 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3527 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3528 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3529 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3530 CmdTrbCfgEP
.CycleBit
= 1;
3531 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3532 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3533 DEBUG ((EFI_D_INFO
, "SetInterface: Configure Endpoint\n"));
3534 Status
= XhcCmdTransfer (
3536 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3537 XHC_GENERIC_TIMEOUT
,
3538 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3540 if (EFI_ERROR (Status
)) {
3541 DEBUG ((EFI_D_ERROR
, "SetInterface: Config Endpoint Failed, Status = %r\n", Status
));
3544 // Update the active AlternateSetting.
3546 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3554 Set interface through XHCI's Configure_Endpoint cmd.
3556 @param Xhc The XHCI Instance.
3557 @param SlotId The slot id to be configured.
3558 @param DeviceSpeed The device's speed.
3559 @param ConfigDesc The pointer to the usb device configuration descriptor.
3560 @param Request USB device request to send.
3562 @retval EFI_SUCCESS Successfully set interface.
3568 IN USB_XHCI_INSTANCE
*Xhc
,
3570 IN UINT8 DeviceSpeed
,
3571 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3572 IN EFI_USB_DEVICE_REQUEST
*Request
3576 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3577 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3578 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3579 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3586 EFI_PHYSICAL_ADDRESS PhyAddr
;
3589 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3590 INPUT_CONTEXT_64
*InputContext
;
3591 DEVICE_CONTEXT_64
*OutputContext
;
3592 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3594 Status
= EFI_SUCCESS
;
3596 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3597 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3599 // XHCI 4.6.6 Configure Endpoint
3600 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3601 // Context and Add Context flags as follows:
3602 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3603 // Context and Add Context flags to '0'.
3605 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3606 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3608 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3609 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3611 ASSERT (ConfigDesc
!= NULL
);
3615 IfDescActive
= NULL
;
3618 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3619 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3620 if ((IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) && (IfDesc
->Length
>= sizeof (USB_INTERFACE_DESCRIPTOR
))) {
3621 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3622 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3624 // Find out the active interface descriptor.
3626 IfDescActive
= IfDesc
;
3627 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3629 // Find out the interface descriptor to set.
3635 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3639 // XHCI 4.6.6 Configure Endpoint
3640 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3641 // Context and Add Context flags as follows:
3642 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3643 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3644 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3645 // the Drop Context flag to '1' and Add Context flag to '0'.
3646 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3647 // and Add Context flags shall be set to '1'.
3649 // Below codes are to cover 2), 3) and 4).
3652 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3653 NumEp
= IfDescActive
->NumEndpoints
;
3654 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3655 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3656 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3657 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3660 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
3661 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3665 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3666 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3668 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3674 // XHCI 4.3.6 - Setting Alternate Interfaces
3675 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3677 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
, NULL
);
3678 if (EFI_ERROR (Status
)) {
3682 // XHCI 4.3.6 - Setting Alternate Interfaces
3683 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3685 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3686 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3687 if (RingSeg
!= NULL
) {
3688 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3690 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3691 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3695 // Set the Drop Context flag to '1'.
3697 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3699 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3703 // XHCI 4.3.6 - Setting Alternate Interfaces
3704 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3705 // Interface setting, to '0'.
3707 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3711 // XHCI 4.3.6 - Setting Alternate Interfaces
3712 // 4) For each endpoint enabled by the Configure Endpoint Command:
3713 // a. Allocate a Transfer Ring.
3714 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3715 // c. Initialize the Endpoint Context data structure.
3717 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3722 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3723 InputContext
->Slot
.ContextEntries
= MaxDci
;
3725 // XHCI 4.3.6 - Setting Alternate Interfaces
3726 // 5) Issue and successfully complete a Configure Endpoint Command.
3728 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3729 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3730 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3731 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3732 CmdTrbCfgEP
.CycleBit
= 1;
3733 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3734 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3735 DEBUG ((EFI_D_INFO
, "SetInterface64: Configure Endpoint\n"));
3736 Status
= XhcCmdTransfer (
3738 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3739 XHC_GENERIC_TIMEOUT
,
3740 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3742 if (EFI_ERROR (Status
)) {
3743 DEBUG ((EFI_D_ERROR
, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status
));
3746 // Update the active AlternateSetting.
3748 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3756 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3758 @param Xhc The XHCI Instance.
3759 @param SlotId The slot id to be evaluated.
3760 @param MaxPacketSize The max packet size supported by the device control transfer.
3762 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3767 XhcEvaluateContext (
3768 IN USB_XHCI_INSTANCE
*Xhc
,
3770 IN UINT32 MaxPacketSize
3774 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3775 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3776 INPUT_CONTEXT
*InputContext
;
3777 EFI_PHYSICAL_ADDRESS PhyAddr
;
3779 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3782 // 4.6.7 Evaluate Context
3784 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3785 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3787 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3788 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3790 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3791 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3792 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3793 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3794 CmdTrbEvalu
.CycleBit
= 1;
3795 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3796 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3797 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3798 Status
= XhcCmdTransfer (
3800 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3801 XHC_GENERIC_TIMEOUT
,
3802 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3804 if (EFI_ERROR (Status
)) {
3805 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
3811 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3813 @param Xhc The XHCI Instance.
3814 @param SlotId The slot id to be evaluated.
3815 @param MaxPacketSize The max packet size supported by the device control transfer.
3817 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3822 XhcEvaluateContext64 (
3823 IN USB_XHCI_INSTANCE
*Xhc
,
3825 IN UINT32 MaxPacketSize
3829 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3830 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3831 INPUT_CONTEXT_64
*InputContext
;
3832 EFI_PHYSICAL_ADDRESS PhyAddr
;
3834 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3837 // 4.6.7 Evaluate Context
3839 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3840 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3842 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3843 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3845 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3846 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3847 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3848 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3849 CmdTrbEvalu
.CycleBit
= 1;
3850 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3851 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3852 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3853 Status
= XhcCmdTransfer (
3855 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3856 XHC_GENERIC_TIMEOUT
,
3857 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3859 if (EFI_ERROR (Status
)) {
3860 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
3867 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3869 @param Xhc The XHCI Instance.
3870 @param SlotId The slot id to be configured.
3871 @param PortNum The total number of downstream port supported by the hub.
3872 @param TTT The TT think time of the hub device.
3873 @param MTT The multi-TT of the hub device.
3875 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3879 XhcConfigHubContext (
3880 IN USB_XHCI_INSTANCE
*Xhc
,
3888 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3889 INPUT_CONTEXT
*InputContext
;
3890 DEVICE_CONTEXT
*OutputContext
;
3891 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3892 EFI_PHYSICAL_ADDRESS PhyAddr
;
3894 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3895 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3896 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3899 // 4.6.7 Evaluate Context
3901 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3903 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3906 // Copy the slot context from OutputContext to Input context
3908 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
3909 InputContext
->Slot
.Hub
= 1;
3910 InputContext
->Slot
.PortNum
= PortNum
;
3911 InputContext
->Slot
.TTT
= TTT
;
3912 InputContext
->Slot
.MTT
= MTT
;
3914 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3915 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3916 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3917 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3918 CmdTrbCfgEP
.CycleBit
= 1;
3919 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3920 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3921 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
3922 Status
= XhcCmdTransfer (
3924 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3925 XHC_GENERIC_TIMEOUT
,
3926 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3928 if (EFI_ERROR (Status
)) {
3929 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
3935 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3937 @param Xhc The XHCI Instance.
3938 @param SlotId The slot id to be configured.
3939 @param PortNum The total number of downstream port supported by the hub.
3940 @param TTT The TT think time of the hub device.
3941 @param MTT The multi-TT of the hub device.
3943 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3947 XhcConfigHubContext64 (
3948 IN USB_XHCI_INSTANCE
*Xhc
,
3956 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3957 INPUT_CONTEXT_64
*InputContext
;
3958 DEVICE_CONTEXT_64
*OutputContext
;
3959 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3960 EFI_PHYSICAL_ADDRESS PhyAddr
;
3962 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3963 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3964 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3967 // 4.6.7 Evaluate Context
3969 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3971 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3974 // Copy the slot context from OutputContext to Input context
3976 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
3977 InputContext
->Slot
.Hub
= 1;
3978 InputContext
->Slot
.PortNum
= PortNum
;
3979 InputContext
->Slot
.TTT
= TTT
;
3980 InputContext
->Slot
.MTT
= MTT
;
3982 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3983 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3984 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3985 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3986 CmdTrbCfgEP
.CycleBit
= 1;
3987 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3988 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3989 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
3990 Status
= XhcCmdTransfer (
3992 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3993 XHC_GENERIC_TIMEOUT
,
3994 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3996 if (EFI_ERROR (Status
)) {
3997 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));