3 XHCI transfer scheduling routines.
5 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Create a command transfer TRB to support XHCI command interfaces.
21 @param Xhc The XHCI Instance.
22 @param CmdTrb The cmd TRB to be executed.
24 @return Created URB or NULL.
29 IN USB_XHCI_INSTANCE
*Xhc
,
30 IN TRB_TEMPLATE
*CmdTrb
35 Urb
= AllocateZeroPool (sizeof (URB
));
40 Urb
->Signature
= XHC_URB_SIG
;
42 Urb
->Ring
= &Xhc
->CmdRing
;
43 XhcSyncTrsRing (Xhc
, Urb
->Ring
);
45 Urb
->TrbStart
= Urb
->Ring
->RingEnqueue
;
46 CopyMem (Urb
->TrbStart
, CmdTrb
, sizeof (TRB_TEMPLATE
));
47 Urb
->TrbStart
->CycleBit
= Urb
->Ring
->RingPCS
& BIT0
;
48 Urb
->TrbEnd
= Urb
->TrbStart
;
54 Execute a XHCI cmd TRB pointed by CmdTrb.
56 @param Xhc The XHCI Instance.
57 @param CmdTrb The cmd TRB to be executed.
58 @param Timeout Indicates the maximum time, in millisecond, which the
59 transfer is allowed to complete.
60 @param EvtTrb The event TRB corresponding to the cmd TRB.
62 @retval EFI_SUCCESS The transfer was completed successfully.
63 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
64 @retval EFI_TIMEOUT The transfer failed due to timeout.
65 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
71 IN USB_XHCI_INSTANCE
*Xhc
,
72 IN TRB_TEMPLATE
*CmdTrb
,
74 OUT TRB_TEMPLATE
**EvtTrb
81 // Validate the parameters
83 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
84 return EFI_INVALID_PARAMETER
;
87 Status
= EFI_DEVICE_ERROR
;
89 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
90 DEBUG ((EFI_D_ERROR
, "XhcCmdTransfer: HC is halted\n"));
95 // Create a new URB, then poll the execution status.
97 Urb
= XhcCreateCmdTrb (Xhc
, CmdTrb
);
100 DEBUG ((EFI_D_ERROR
, "XhcCmdTransfer: failed to create URB\n"));
101 Status
= EFI_OUT_OF_RESOURCES
;
105 Status
= XhcExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
106 *EvtTrb
= Urb
->EvtTrb
;
108 if (Urb
->Result
== EFI_USB_NOERROR
) {
109 Status
= EFI_SUCCESS
;
112 XhcFreeUrb (Xhc
, Urb
);
119 Create a new URB for a new transaction.
121 @param Xhc The XHCI Instance
122 @param BusAddr The logical device address assigned by UsbBus driver
123 @param EpAddr Endpoint addrress
124 @param DevSpeed The device speed
125 @param MaxPacket The max packet length of the endpoint
126 @param Type The transaction type
127 @param Request The standard USB request for control transfer
128 @param Data The user data to transfer
129 @param DataLen The length of data buffer
130 @param Callback The function to call when data is transferred
131 @param Context The context to the callback
133 @return Created URB or NULL
138 IN USB_XHCI_INSTANCE
*Xhc
,
144 IN EFI_USB_DEVICE_REQUEST
*Request
,
147 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
155 Urb
= AllocateZeroPool (sizeof (URB
));
160 Urb
->Signature
= XHC_URB_SIG
;
161 InitializeListHead (&Urb
->UrbList
);
164 Ep
->BusAddr
= BusAddr
;
165 Ep
->EpAddr
= (UINT8
)(EpAddr
& 0x0F);
166 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
167 Ep
->DevSpeed
= DevSpeed
;
168 Ep
->MaxPacket
= MaxPacket
;
171 Urb
->Request
= Request
;
173 Urb
->DataLen
= DataLen
;
174 Urb
->Callback
= Callback
;
175 Urb
->Context
= Context
;
177 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
178 ASSERT_EFI_ERROR (Status
);
179 if (EFI_ERROR (Status
)) {
180 DEBUG ((EFI_D_ERROR
, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status
));
189 Free an allocated URB.
191 @param Xhc The XHCI device.
192 @param Urb The URB to free.
197 IN USB_XHCI_INSTANCE
*Xhc
,
201 if ((Xhc
== NULL
) || (Urb
== NULL
)) {
205 if (Urb
->DataMap
!= NULL
) {
206 Xhc
->PciIo
->Unmap (Xhc
->PciIo
, Urb
->DataMap
);
213 Create a transfer TRB.
215 @param Xhc The XHCI Instance
216 @param Urb The urb used to construct the transfer TRB.
218 @return Created TRB or NULL
222 XhcCreateTransferTrb (
223 IN USB_XHCI_INSTANCE
*Xhc
,
228 TRANSFER_RING
*EPRing
;
236 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
237 EFI_PHYSICAL_ADDRESS PhyAddr
;
241 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
243 return EFI_DEVICE_ERROR
;
246 Urb
->Finished
= FALSE
;
247 Urb
->StartDone
= FALSE
;
248 Urb
->EndDone
= FALSE
;
250 Urb
->Result
= EFI_USB_NOERROR
;
252 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
254 EPRing
= (TRANSFER_RING
*)(UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1];
256 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
257 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
258 EPType
= (UINT8
) ((DEVICE_CONTEXT
*)OutputContext
)->EP
[Dci
-1].EPType
;
260 EPType
= (UINT8
) ((DEVICE_CONTEXT_64
*)OutputContext
)->EP
[Dci
-1].EPType
;
263 if (Urb
->Data
!= NULL
) {
264 if (((UINT8
) (Urb
->Ep
.Direction
)) == EfiUsbDataIn
) {
265 MapOp
= EfiPciIoOperationBusMasterWrite
;
267 MapOp
= EfiPciIoOperationBusMasterRead
;
271 Status
= Xhc
->PciIo
->Map (Xhc
->PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
273 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
274 DEBUG ((EFI_D_ERROR
, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
275 return EFI_OUT_OF_RESOURCES
;
278 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
285 XhcSyncTrsRing (Xhc
, EPRing
);
286 Urb
->TrbStart
= EPRing
->RingEnqueue
;
288 case ED_CONTROL_BIDIR
:
290 // For control transfer, create SETUP_STAGE_TRB first.
292 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
293 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
294 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
295 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
296 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
297 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
298 TrbStart
->TrbCtrSetup
.Length
= 8;
299 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
300 TrbStart
->TrbCtrSetup
.IOC
= 1;
301 TrbStart
->TrbCtrSetup
.IDT
= 1;
302 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
303 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
304 TrbStart
->TrbCtrSetup
.TRT
= 3;
305 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
306 TrbStart
->TrbCtrSetup
.TRT
= 2;
308 TrbStart
->TrbCtrSetup
.TRT
= 0;
311 // Update the cycle bit
313 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
317 // For control transfer, create DATA_STAGE_TRB.
319 if (Urb
->DataLen
> 0) {
320 XhcSyncTrsRing (Xhc
, EPRing
);
321 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
322 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT(Urb
->DataPhy
);
323 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT(Urb
->DataPhy
);
324 TrbStart
->TrbCtrData
.Length
= (UINT32
) Urb
->DataLen
;
325 TrbStart
->TrbCtrData
.TDSize
= 0;
326 TrbStart
->TrbCtrData
.IntTarget
= 0;
327 TrbStart
->TrbCtrData
.ISP
= 1;
328 TrbStart
->TrbCtrData
.IOC
= 1;
329 TrbStart
->TrbCtrData
.IDT
= 0;
330 TrbStart
->TrbCtrData
.CH
= 0;
331 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
332 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
333 TrbStart
->TrbCtrData
.DIR = 1;
334 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
335 TrbStart
->TrbCtrData
.DIR = 0;
337 TrbStart
->TrbCtrData
.DIR = 0;
340 // Update the cycle bit
342 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
346 // For control transfer, create STATUS_STAGE_TRB.
347 // Get the pointer to next TRB for status stage use
349 XhcSyncTrsRing (Xhc
, EPRing
);
350 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
351 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
352 TrbStart
->TrbCtrStatus
.IOC
= 1;
353 TrbStart
->TrbCtrStatus
.CH
= 0;
354 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
355 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
356 TrbStart
->TrbCtrStatus
.DIR = 0;
357 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
358 TrbStart
->TrbCtrStatus
.DIR = 1;
360 TrbStart
->TrbCtrStatus
.DIR = 0;
363 // Update the cycle bit
365 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
367 // Update the enqueue pointer
369 XhcSyncTrsRing (Xhc
, EPRing
);
371 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
380 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
381 while (TotalLen
< Urb
->DataLen
) {
382 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
383 Len
= Urb
->DataLen
- TotalLen
;
387 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
388 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
389 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
390 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
391 TrbStart
->TrbNormal
.TDSize
= 0;
392 TrbStart
->TrbNormal
.IntTarget
= 0;
393 TrbStart
->TrbNormal
.ISP
= 1;
394 TrbStart
->TrbNormal
.IOC
= 1;
395 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
397 // Update the cycle bit
399 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
401 XhcSyncTrsRing (Xhc
, EPRing
);
406 Urb
->TrbNum
= TrbNum
;
407 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
410 case ED_INTERRUPT_OUT
:
411 case ED_INTERRUPT_IN
:
415 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
416 while (TotalLen
< Urb
->DataLen
) {
417 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
418 Len
= Urb
->DataLen
- TotalLen
;
422 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
423 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
424 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->DataPhy
+ TotalLen
);
425 TrbStart
->TrbNormal
.Length
= (UINT32
) Len
;
426 TrbStart
->TrbNormal
.TDSize
= 0;
427 TrbStart
->TrbNormal
.IntTarget
= 0;
428 TrbStart
->TrbNormal
.ISP
= 1;
429 TrbStart
->TrbNormal
.IOC
= 1;
430 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
432 // Update the cycle bit
434 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
436 XhcSyncTrsRing (Xhc
, EPRing
);
441 Urb
->TrbNum
= TrbNum
;
442 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
446 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
456 Initialize the XHCI host controller for schedule.
458 @param Xhc The XHCI Instance to be initialized.
463 IN USB_XHCI_INSTANCE
*Xhc
467 EFI_PHYSICAL_ADDRESS DcbaaPhy
;
469 EFI_PHYSICAL_ADDRESS CmdRingPhy
;
471 UINT32 MaxScratchpadBufs
;
473 EFI_PHYSICAL_ADDRESS ScratchPhy
;
474 UINT64
*ScratchEntry
;
475 EFI_PHYSICAL_ADDRESS ScratchEntryPhy
;
477 UINTN
*ScratchEntryMap
;
481 // Initialize memory management.
483 Xhc
->MemPool
= UsbHcInitMemPool (Xhc
->PciIo
);
484 ASSERT (Xhc
->MemPool
!= NULL
);
487 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
488 // to enable the device slots that system software is going to use.
490 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
491 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
492 XhcWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, Xhc
->MaxSlotsEn
);
495 // The Device Context Base Address Array entry associated with each allocated Device Slot
496 // shall contain a 64-bit pointer to the base of the associated Device Context.
497 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
498 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
500 Entries
= (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
);
501 Dcbaa
= UsbHcAllocateMem (Xhc
->MemPool
, Entries
);
502 ASSERT (Dcbaa
!= NULL
);
503 ZeroMem (Dcbaa
, Entries
);
506 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
507 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
508 // mode (Run/Stop(R/S) ='1').
510 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
511 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
512 ASSERT (MaxScratchpadBufs
<= 1023);
513 if (MaxScratchpadBufs
!= 0) {
515 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
517 ScratchEntryMap
= AllocateZeroPool (sizeof (UINTN
) * MaxScratchpadBufs
);
518 ASSERT (ScratchEntryMap
!= NULL
);
519 Xhc
->ScratchEntryMap
= ScratchEntryMap
;
522 // Allocate the buffer to record the host address for each entry
524 ScratchEntry
= AllocateZeroPool (sizeof (UINT64
) * MaxScratchpadBufs
);
525 ASSERT (ScratchEntry
!= NULL
);
526 Xhc
->ScratchEntry
= ScratchEntry
;
529 Status
= UsbHcAllocateAlignedPages (
531 EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)),
533 (VOID
**) &ScratchBuf
,
537 ASSERT_EFI_ERROR (Status
);
539 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
540 Xhc
->ScratchBuf
= ScratchBuf
;
543 // Allocate each scratch buffer
545 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
547 Status
= UsbHcAllocateAlignedPages (
549 EFI_SIZE_TO_PAGES (Xhc
->PageSize
),
551 (VOID
**) &ScratchEntry
[Index
],
553 (VOID
**) &ScratchEntryMap
[Index
]
555 ASSERT_EFI_ERROR (Status
);
556 ZeroMem ((VOID
*)(UINTN
)ScratchEntry
[Index
], Xhc
->PageSize
);
558 // Fill with the PCI device address
560 *ScratchBuf
++ = ScratchEntryPhy
;
563 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
564 // Device Context Base Address Array points to the Scratchpad Buffer Array.
566 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
) ScratchPhy
;
570 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
571 // a 64-bit address pointing to where the Device Context Base Address Array is located.
573 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
575 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
576 // So divide it to two 32-bytes width register access.
578 DcbaaPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Dcbaa
, Entries
);
579 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT(DcbaaPhy
));
580 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (DcbaaPhy
));
582 DEBUG ((EFI_D_INFO
, "XhcInitSched:DCBAA=0x%x\n", (UINT64
)(UINTN
)Xhc
->DCBAA
));
585 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
586 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
587 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
590 CreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
592 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
593 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
594 // So we set RCS as inverted PCS init value to let Command Ring empty
596 CmdRing
= (UINT64
)(UINTN
)Xhc
->CmdRing
.RingSeg0
;
597 CmdRingPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) CmdRing
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
598 ASSERT ((CmdRingPhy
& 0x3F) == 0);
599 CmdRingPhy
|= XHC_CRCR_RCS
;
601 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
602 // So divide it to two 32-bytes width register access.
604 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT(CmdRingPhy
));
605 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRingPhy
));
607 DEBUG ((EFI_D_INFO
, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc
->CmdRing
.RingSeg0
));
610 // Disable the 'interrupter enable' bit in USB_CMD
611 // and clear IE & IP bit in all Interrupter X Management Registers.
613 XhcClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
614 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
615 XhcClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
616 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
620 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
622 CreateEventRing (Xhc
, &Xhc
->EventRing
);
623 DEBUG ((EFI_D_INFO
, "XhcInitSched:XHC_EVENTRING=0x%x\n", Xhc
->EventRing
.EventRingSeg0
));
627 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
628 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
629 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
630 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
631 Stopped to the Running state.
633 @param Xhc The XHCI Instance.
634 @param Urb The urb which makes the endpoint halted.
636 @retval EFI_SUCCESS The recovery is successful.
637 @retval Others Failed to recovery halted endpoint.
642 XhcRecoverHaltedEndpoint (
643 IN USB_XHCI_INSTANCE
*Xhc
,
651 Status
= EFI_SUCCESS
;
652 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
654 return EFI_DEVICE_ERROR
;
656 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
659 DEBUG ((EFI_D_INFO
, "Recovery Halted Slot = %x,Dci = %x\n", SlotId
, Dci
));
662 // 1) Send Reset endpoint command to transit from halt to stop state
664 Status
= XhcResetEndpoint(Xhc
, SlotId
, Dci
);
665 if (EFI_ERROR(Status
)) {
666 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
671 // 2)Set dequeue pointer
673 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
674 if (EFI_ERROR(Status
)) {
675 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
680 // 3)Ring the doorbell to transit from stop to active
682 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
689 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer
690 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to
691 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running
694 @param Xhc The XHCI Instance.
695 @param Urb The urb which doesn't get completed in a specified timeout range.
697 @retval EFI_SUCCESS The dequeuing of the TDs is successful.
698 @retval Others Failed to stop the endpoint and dequeue the TDs.
703 XhcDequeueTrbFromEndpoint (
704 IN USB_XHCI_INSTANCE
*Xhc
,
712 Status
= EFI_SUCCESS
;
713 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
715 return EFI_DEVICE_ERROR
;
717 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
720 DEBUG ((EFI_D_INFO
, "Stop Slot = %x,Dci = %x\n", SlotId
, Dci
));
723 // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint
725 Status
= XhcStopEndpoint(Xhc
, SlotId
, Dci
);
726 if (EFI_ERROR(Status
)) {
727 DEBUG ((EFI_D_ERROR
, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
732 // 2)Set dequeue pointer
734 Status
= XhcSetTrDequeuePointer(Xhc
, SlotId
, Dci
, Urb
);
735 if (EFI_ERROR(Status
)) {
736 DEBUG ((EFI_D_ERROR
, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status
));
741 // 3)Ring the doorbell to transit from stop to active
743 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
750 Create XHCI event ring.
752 @param Xhc The XHCI Instance.
753 @param EventRing The created event ring.
758 IN USB_XHCI_INSTANCE
*Xhc
,
759 OUT EVENT_RING
*EventRing
763 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
765 EFI_PHYSICAL_ADDRESS ERSTPhy
;
766 EFI_PHYSICAL_ADDRESS DequeuePhy
;
768 ASSERT (EventRing
!= NULL
);
770 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
771 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
772 ASSERT (Buf
!= NULL
);
773 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
776 EventRing
->EventRingSeg0
= Buf
;
777 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
778 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
779 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
781 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
784 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
785 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
787 EventRing
->EventRingCCS
= 1;
789 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
790 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
791 ASSERT (Buf
!= NULL
);
792 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
795 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
796 EventRing
->ERSTBase
= ERSTBase
;
797 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
798 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
799 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
801 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, ERSTBase
, Size
);
804 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
812 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
814 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
815 // So divide it to two 32-bytes width register access.
820 XHC_LOW_32BIT((UINT64
)(UINTN
)DequeuePhy
)
825 XHC_HIGH_32BIT((UINT64
)(UINTN
)DequeuePhy
)
828 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
830 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
831 // So divide it to two 32-bytes width register access.
836 XHC_LOW_32BIT((UINT64
)(UINTN
)ERSTPhy
)
840 XHC_ERSTBA_OFFSET
+ 4,
841 XHC_HIGH_32BIT((UINT64
)(UINTN
)ERSTPhy
)
844 // Need set IMAN IE bit to enble the ring interrupt
846 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
850 Create XHCI transfer ring.
852 @param Xhc The XHCI Instance.
853 @param TrbNum The number of TRB in the ring.
854 @param TransferRing The created transfer ring.
859 IN USB_XHCI_INSTANCE
*Xhc
,
861 OUT TRANSFER_RING
*TransferRing
866 EFI_PHYSICAL_ADDRESS PhyAddr
;
868 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
869 ASSERT (Buf
!= NULL
);
870 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
871 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
873 TransferRing
->RingSeg0
= Buf
;
874 TransferRing
->TrbNumber
= TrbNum
;
875 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
876 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
877 TransferRing
->RingPCS
= 1;
879 // 4.9.2 Transfer Ring Management
880 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
881 // point to the first TRB in the ring.
883 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
884 EndTrb
->Type
= TRB_TYPE_LINK
;
885 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
886 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
887 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
889 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
893 // Set Cycle bit as other TRB PCS init value
895 EndTrb
->CycleBit
= 0;
899 Free XHCI event ring.
901 @param Xhc The XHCI Instance.
902 @param EventRing The event ring to be freed.
908 IN USB_XHCI_INSTANCE
*Xhc
,
909 IN EVENT_RING
*EventRing
912 if(EventRing
->EventRingSeg0
== NULL
) {
917 // Free EventRing Segment 0
919 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
924 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
929 Free the resouce allocated at initializing schedule.
931 @param Xhc The XHCI Instance.
936 IN USB_XHCI_INSTANCE
*Xhc
940 UINT64
*ScratchEntry
;
942 if (Xhc
->ScratchBuf
!= NULL
) {
943 ScratchEntry
= Xhc
->ScratchEntry
;
944 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
946 // Free Scratchpad Buffers
948 UsbHcFreeAlignedPages (Xhc
->PciIo
, (VOID
*)(UINTN
)ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*) Xhc
->ScratchEntryMap
[Index
]);
951 // Free Scratchpad Buffer Array
953 UsbHcFreeAlignedPages (Xhc
->PciIo
, Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
954 FreePool (Xhc
->ScratchEntryMap
);
955 FreePool (Xhc
->ScratchEntry
);
958 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
959 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
960 Xhc
->CmdRing
.RingSeg0
= NULL
;
963 XhcFreeEventRing (Xhc
,&Xhc
->EventRing
);
965 if (Xhc
->DCBAA
!= NULL
) {
966 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
));
971 // Free memory pool at last
973 if (Xhc
->MemPool
!= NULL
) {
974 UsbHcFreeMemPool (Xhc
->MemPool
);
980 Check if the Trb is a transaction of the URB.
982 @param Trb The TRB to be checked
983 @param Urb The URB to be checked.
985 @retval TRUE It is a transaction of the URB.
986 @retval FALSE It is not any transaction of the URB.
991 IN USB_XHCI_INSTANCE
*Xhc
,
992 IN TRB_TEMPLATE
*Trb
,
997 TRB_TEMPLATE
*CheckedTrb
;
999 EFI_PHYSICAL_ADDRESS PhyAddr
;
1001 CheckedTrb
= Urb
->TrbStart
;
1002 for (Index
= 0; Index
< Urb
->TrbNum
; Index
++) {
1003 if (Trb
== CheckedTrb
) {
1008 // If the checked TRB is the link TRB at the end of the transfer ring,
1009 // recircle it to the head of the ring.
1011 if (CheckedTrb
->Type
== TRB_TYPE_LINK
) {
1012 LinkTrb
= (LINK_TRB
*) CheckedTrb
;
1013 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(LinkTrb
->PtrLo
| LShiftU64 ((UINT64
) LinkTrb
->PtrHi
, 32));
1014 CheckedTrb
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1015 ASSERT (CheckedTrb
== Urb
->Ring
->RingSeg0
);
1023 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
1025 @param Xhc The XHCI Instance.
1026 @param Trb The TRB to be checked.
1027 @param Urb The pointer to the matched Urb.
1029 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
1030 @retval FALSE The Trb is not matched with any URBs in the async list.
1035 IN USB_XHCI_INSTANCE
*Xhc
,
1036 IN TRB_TEMPLATE
*Trb
,
1044 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1045 CheckedUrb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1046 if (IsTransferRingTrb (Xhc
, Trb
, CheckedUrb
)) {
1057 Check the URB's execution result and update the URB's
1060 @param Xhc The XHCI Instance.
1061 @param Urb The URB to check result.
1063 @return Whether the result of URB transfer is finialized.
1068 IN USB_XHCI_INSTANCE
*Xhc
,
1072 EVT_TRB_TRANSFER
*EvtTrb
;
1073 TRB_TEMPLATE
*TRBPtr
;
1082 EFI_PHYSICAL_ADDRESS PhyAddr
;
1084 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
1086 Status
= EFI_SUCCESS
;
1089 if (Urb
->Finished
) {
1095 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1096 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
1101 // Traverse the event ring to find out all new events from the previous check.
1103 XhcSyncEventRing (Xhc
, &Xhc
->EventRing
);
1104 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
1105 Status
= XhcCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
1106 if (Status
== EFI_NOT_READY
) {
1108 // All new events are handled, return directly.
1114 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1116 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
1121 // Need convert pci device address to host address
1123 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
1124 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1127 // Update the status of Urb according to the finished event regardless of whether
1128 // the urb is current checked one or in the XHCI's async transfer list.
1129 // This way is used to avoid that those completed async transfer events don't get
1130 // handled in time and are flushed by newer coming events.
1132 if (IsTransferRingTrb (Xhc
, TRBPtr
, Urb
)) {
1134 } else if (IsAsyncIntTrb (Xhc
, TRBPtr
, &AsyncUrb
)) {
1135 CheckedUrb
= AsyncUrb
;
1140 switch (EvtTrb
->Completecode
) {
1141 case TRB_COMPLETION_STALL_ERROR
:
1142 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
1143 CheckedUrb
->Finished
= TRUE
;
1144 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1147 case TRB_COMPLETION_BABBLE_ERROR
:
1148 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
1149 CheckedUrb
->Finished
= TRUE
;
1150 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1153 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
1154 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
1155 CheckedUrb
->Finished
= TRUE
;
1156 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
1159 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
1160 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1161 CheckedUrb
->Finished
= TRUE
;
1162 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1165 case TRB_COMPLETION_SHORT_PACKET
:
1166 case TRB_COMPLETION_SUCCESS
:
1167 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
1168 DEBUG ((EFI_D_VERBOSE
, "XhcCheckUrbResult: short packet happens!\n"));
1171 TRBType
= (UINT8
) (TRBPtr
->Type
);
1172 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
1173 (TRBType
== TRB_TYPE_NORMAL
) ||
1174 (TRBType
== TRB_TYPE_ISOCH
)) {
1175 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
1181 DEBUG ((EFI_D_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
1182 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1183 CheckedUrb
->Finished
= TRUE
;
1188 // Only check first and end Trb event address
1190 if (TRBPtr
== CheckedUrb
->TrbStart
) {
1191 CheckedUrb
->StartDone
= TRUE
;
1194 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
1195 CheckedUrb
->EndDone
= TRUE
;
1198 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
1199 CheckedUrb
->Finished
= TRUE
;
1200 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
1207 // Advance event ring to last available entry
1209 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1210 // So divide it to two 32-bytes width register access.
1212 Low
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
1213 High
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
1214 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
1216 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
1218 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
1220 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1221 // So divide it to two 32-bytes width register access.
1223 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
1224 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
1227 return Urb
->Finished
;
1232 Execute the transfer by polling the URB. This is a synchronous operation.
1234 @param Xhc The XHCI Instance.
1235 @param CmdTransfer The executed URB is for cmd transfer or not.
1236 @param Urb The URB to execute.
1237 @param Timeout The time to wait before abort, in millisecond.
1239 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1240 @return EFI_TIMEOUT The transfer failed due to time out.
1241 @return EFI_SUCCESS The transfer finished OK.
1246 IN USB_XHCI_INSTANCE
*Xhc
,
1247 IN BOOLEAN CmdTransfer
,
1263 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1265 return EFI_DEVICE_ERROR
;
1267 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1271 Status
= EFI_SUCCESS
;
1272 Loop
= Timeout
* XHC_1_MILLISECOND
;
1277 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1279 for (Index
= 0; Index
< Loop
; Index
++) {
1280 Finished
= XhcCheckUrbResult (Xhc
, Urb
);
1284 gBS
->Stall (XHC_1_MICROSECOND
);
1287 if (Index
== Loop
) {
1288 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
1289 Status
= EFI_TIMEOUT
;
1290 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
1291 Status
= EFI_DEVICE_ERROR
;
1298 Delete a single asynchronous interrupt transfer for
1299 the device and endpoint.
1301 @param Xhc The XHCI Instance.
1302 @param BusAddr The logical device address assigned by UsbBus driver.
1303 @param EpNum The endpoint of the target.
1305 @retval EFI_SUCCESS An asynchronous transfer is removed.
1306 @retval EFI_NOT_FOUND No transfer for the device is found.
1310 XhciDelAsyncIntTransfer (
1311 IN USB_XHCI_INSTANCE
*Xhc
,
1319 EFI_USB_DATA_DIRECTION Direction
;
1322 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1327 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1328 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1329 if ((Urb
->Ep
.BusAddr
== BusAddr
) &&
1330 (Urb
->Ep
.EpAddr
== EpNum
) &&
1331 (Urb
->Ep
.Direction
== Direction
)) {
1333 // Device doesn't finish the IntTransfer until real data comes
1334 // So the TRB should be removed as well.
1336 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1337 if (EFI_ERROR (Status
)) {
1338 DEBUG ((EFI_D_ERROR
, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));
1341 RemoveEntryList (&Urb
->UrbList
);
1342 FreePool (Urb
->Data
);
1343 XhcFreeUrb (Xhc
, Urb
);
1348 return EFI_NOT_FOUND
;
1352 Remove all the asynchronous interrutp transfers.
1354 @param Xhc The XHCI Instance.
1358 XhciDelAllAsyncIntTransfers (
1359 IN USB_XHCI_INSTANCE
*Xhc
1367 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1368 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1371 // Device doesn't finish the IntTransfer until real data comes
1372 // So the TRB should be removed as well.
1374 Status
= XhcDequeueTrbFromEndpoint (Xhc
, Urb
);
1375 if (EFI_ERROR (Status
)) {
1376 DEBUG ((EFI_D_ERROR
, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));
1379 RemoveEntryList (&Urb
->UrbList
);
1380 FreePool (Urb
->Data
);
1381 XhcFreeUrb (Xhc
, Urb
);
1386 Update the queue head for next round of asynchronous transfer
1388 @param Xhc The XHCI Instance.
1389 @param Urb The URB to update
1393 XhcUpdateAsyncRequest (
1394 IN USB_XHCI_INSTANCE
*Xhc
,
1400 if (Urb
->Result
== EFI_USB_NOERROR
) {
1401 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1402 if (EFI_ERROR (Status
)) {
1405 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1406 if (EFI_ERROR (Status
)) {
1413 Flush data from PCI controller specific address to mapped system
1416 @param Xhc The XHCI device.
1417 @param Urb The URB to unmap.
1419 @retval EFI_SUCCESS Success to flush data to mapped system memory.
1420 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
1424 XhcFlushAsyncIntMap (
1425 IN USB_XHCI_INSTANCE
*Xhc
,
1430 EFI_PHYSICAL_ADDRESS PhyAddr
;
1431 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
1432 EFI_PCI_IO_PROTOCOL
*PciIo
;
1439 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
1440 MapOp
= EfiPciIoOperationBusMasterWrite
;
1442 MapOp
= EfiPciIoOperationBusMasterRead
;
1445 if (Urb
->DataMap
!= NULL
) {
1446 Status
= PciIo
->Unmap (PciIo
, Urb
->DataMap
);
1447 if (EFI_ERROR (Status
)) {
1452 Urb
->DataMap
= NULL
;
1454 Status
= PciIo
->Map (PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
1455 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
1459 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
1464 return EFI_DEVICE_ERROR
;
1468 Interrupt transfer periodic check handler.
1470 @param Event Interrupt event.
1471 @param Context Pointer to USB_XHCI_INSTANCE.
1476 XhcMonitorAsyncRequests (
1481 USB_XHCI_INSTANCE
*Xhc
;
1490 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1492 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1494 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1495 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1498 // Make sure that the device is available before every check.
1500 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1506 // Check the result of URB execution. If it is still
1507 // active, check the next one.
1509 XhcCheckUrbResult (Xhc
, Urb
);
1511 if (!Urb
->Finished
) {
1516 // Flush any PCI posted write transactions from a PCI host
1517 // bridge to system memory.
1519 Status
= XhcFlushAsyncIntMap (Xhc
, Urb
);
1520 if (EFI_ERROR (Status
)) {
1521 DEBUG ((EFI_D_ERROR
, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1525 // Allocate a buffer then copy the transferred data for user.
1526 // If failed to allocate the buffer, update the URB for next
1527 // round of transfer. Ignore the data of this round.
1530 if (Urb
->Result
== EFI_USB_NOERROR
) {
1531 ASSERT (Urb
->Completed
<= Urb
->DataLen
);
1533 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1535 if (ProcBuf
== NULL
) {
1536 XhcUpdateAsyncRequest (Xhc
, Urb
);
1540 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1544 // Leave error recovery to its related device driver. A
1545 // common case of the error recovery is to re-submit the
1546 // interrupt transfer which is linked to the head of the
1547 // list. This function scans from head to tail. So the
1548 // re-submitted interrupt transfer's callback function
1549 // will not be called again in this round. Don't touch this
1550 // URB after the callback, it may have been removed by the
1553 if (Urb
->Callback
!= NULL
) {
1555 // Restore the old TPL, USB bus maybe connect device in
1556 // his callback. Some drivers may has a lower TPL restriction.
1558 gBS
->RestoreTPL (OldTpl
);
1559 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1560 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1563 if (ProcBuf
!= NULL
) {
1564 gBS
->FreePool (ProcBuf
);
1567 XhcUpdateAsyncRequest (Xhc
, Urb
);
1569 gBS
->RestoreTPL (OldTpl
);
1573 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1575 @param Xhc The XHCI Instance.
1576 @param ParentRouteChart The route string pointed to the parent device if it exists.
1577 @param Port The port to be polled.
1578 @param PortState The port state.
1580 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1581 @retval Others Should not appear.
1586 XhcPollPortStatusChange (
1587 IN USB_XHCI_INSTANCE
*Xhc
,
1588 IN USB_DEV_ROUTE ParentRouteChart
,
1590 IN EFI_USB_PORT_STATUS
*PortState
1596 USB_DEV_ROUTE RouteChart
;
1598 Status
= EFI_SUCCESS
;
1600 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
1604 if (ParentRouteChart
.Dword
== 0) {
1605 RouteChart
.Route
.RouteString
= 0;
1606 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1607 RouteChart
.Route
.TierNum
= 1;
1610 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1612 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1614 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1615 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1618 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1620 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1621 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1623 Status
= XhcDisableSlotCmd64 (Xhc
, SlotId
);
1627 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1628 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1630 // Has a device attached, Identify device speed after port is enabled.
1632 Speed
= EFI_USB_SPEED_FULL
;
1633 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1634 Speed
= EFI_USB_SPEED_LOW
;
1635 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1636 Speed
= EFI_USB_SPEED_HIGH
;
1637 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1638 Speed
= EFI_USB_SPEED_SUPER
;
1641 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1643 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1644 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
1645 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1646 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1648 Status
= XhcInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1658 Calculate the device context index by endpoint address and direction.
1660 @param EpAddr The target endpoint number.
1661 @param Direction The direction of the target endpoint.
1663 @return The device context index of endpoint.
1677 Index
= (UINT8
) (2 * EpAddr
);
1678 if (Direction
== EfiUsbDataIn
) {
1686 Find out the actual device address according to the requested device address from UsbBus.
1688 @param Xhc The XHCI Instance.
1689 @param BusDevAddr The requested device address by UsbBus upper driver.
1691 @return The actual device address assigned to the device.
1696 XhcBusDevAddrToSlotId (
1697 IN USB_XHCI_INSTANCE
*Xhc
,
1703 for (Index
= 0; Index
< 255; Index
++) {
1704 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1705 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1706 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1715 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1719 Find out the slot id according to the device's route string.
1721 @param Xhc The XHCI Instance.
1722 @param RouteString The route string described the device location.
1724 @return The slot id used by the device.
1729 XhcRouteStringToSlotId (
1730 IN USB_XHCI_INSTANCE
*Xhc
,
1731 IN USB_DEV_ROUTE RouteString
1736 for (Index
= 0; Index
< 255; Index
++) {
1737 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1738 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1739 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1748 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1752 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1754 @param Xhc The XHCI Instance.
1755 @param EvtRing The event ring to sync.
1757 @retval EFI_SUCCESS The event ring is synchronized successfully.
1763 IN USB_XHCI_INSTANCE
*Xhc
,
1764 IN EVENT_RING
*EvtRing
1768 TRB_TEMPLATE
*EvtTrb1
;
1770 ASSERT (EvtRing
!= NULL
);
1773 // Calculate the EventRingEnqueue and EventRingCCS.
1774 // Note: only support single Segment
1776 EvtTrb1
= EvtRing
->EventRingDequeue
;
1778 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1779 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
1785 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1786 EvtTrb1
= EvtRing
->EventRingSeg0
;
1787 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
1791 if (Index
< EvtRing
->TrbNumber
) {
1792 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1801 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1803 @param Xhc The XHCI Instance.
1804 @param TrsRing The transfer ring to sync.
1806 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1812 IN USB_XHCI_INSTANCE
*Xhc
,
1813 IN TRANSFER_RING
*TrsRing
1817 TRB_TEMPLATE
*TrsTrb
;
1819 ASSERT (TrsRing
!= NULL
);
1821 // Calculate the latest RingEnqueue and RingPCS
1823 TrsTrb
= TrsRing
->RingEnqueue
;
1824 ASSERT (TrsTrb
!= NULL
);
1826 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1827 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1831 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1832 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1834 // set cycle bit in Link TRB as normal
1836 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1838 // Toggle PCS maintained by software
1840 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1841 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
1845 ASSERT (Index
!= TrsRing
->TrbNumber
);
1847 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1848 TrsRing
->RingEnqueue
= TrsTrb
;
1852 // Clear the Trb context for enqueue, but reserve the PCS bit
1854 TrsTrb
->Parameter1
= 0;
1855 TrsTrb
->Parameter2
= 0;
1859 TrsTrb
->Control
= 0;
1865 Check if there is a new generated event.
1867 @param Xhc The XHCI Instance.
1868 @param EvtRing The event ring to check.
1869 @param NewEvtTrb The new event TRB found.
1871 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1872 @retval EFI_NOT_READY The event ring has no new event.
1878 IN USB_XHCI_INSTANCE
*Xhc
,
1879 IN EVENT_RING
*EvtRing
,
1880 OUT TRB_TEMPLATE
**NewEvtTrb
1883 ASSERT (EvtRing
!= NULL
);
1885 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
1887 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
1888 return EFI_NOT_READY
;
1891 EvtRing
->EventRingDequeue
++;
1893 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1895 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1896 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
1903 Ring the door bell to notify XHCI there is a transaction to be executed.
1905 @param Xhc The XHCI Instance.
1906 @param SlotId The slot id of the target device.
1907 @param Dci The device context index of the target slot or endpoint.
1909 @retval EFI_SUCCESS Successfully ring the door bell.
1915 IN USB_XHCI_INSTANCE
*Xhc
,
1921 XhcWriteDoorBellReg (Xhc
, 0, 0);
1923 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1930 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1932 @param Xhc The XHCI Instance.
1933 @param Urb The URB to be rung.
1935 @retval EFI_SUCCESS Successfully ring the door bell.
1939 RingIntTransferDoorBell (
1940 IN USB_XHCI_INSTANCE
*Xhc
,
1947 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1948 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1949 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1954 Assign and initialize the device slot for a new device.
1956 @param Xhc The XHCI Instance.
1957 @param ParentRouteChart The route string pointed to the parent device.
1958 @param ParentPort The port at which the device is located.
1959 @param RouteChart The route string pointed to the device.
1960 @param DeviceSpeed The device speed.
1962 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1967 XhcInitializeDeviceSlot (
1968 IN USB_XHCI_INSTANCE
*Xhc
,
1969 IN USB_DEV_ROUTE ParentRouteChart
,
1970 IN UINT16 ParentPort
,
1971 IN USB_DEV_ROUTE RouteChart
,
1972 IN UINT8 DeviceSpeed
1976 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1977 INPUT_CONTEXT
*InputContext
;
1978 DEVICE_CONTEXT
*OutputContext
;
1979 TRANSFER_RING
*EndpointTransferRing
;
1980 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1981 UINT8 DeviceAddress
;
1982 CMD_TRB_ENABLE_SLOT CmdTrb
;
1985 DEVICE_CONTEXT
*ParentDeviceContext
;
1986 EFI_PHYSICAL_ADDRESS PhyAddr
;
1988 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1989 CmdTrb
.CycleBit
= 1;
1990 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1992 Status
= XhcCmdTransfer (
1994 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1995 XHC_GENERIC_TIMEOUT
,
1996 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1998 if (EFI_ERROR (Status
)) {
1999 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
2002 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2003 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2004 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2005 ASSERT (SlotId
!= 0);
2007 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2008 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2009 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2010 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2011 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2014 // 4.3.3 Device Slot Initialization
2015 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2017 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
2018 ASSERT (InputContext
!= NULL
);
2019 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2020 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2022 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2025 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2026 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2027 // Context are affected by the command.
2029 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2032 // 3) Initialize the Input Slot Context data structure
2034 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2035 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2036 InputContext
->Slot
.ContextEntries
= 1;
2037 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2039 if (RouteChart
.Route
.RouteString
) {
2041 // The device is behind of hub device.
2043 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2044 ASSERT (ParentSlotId
!= 0);
2046 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2048 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2049 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2050 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2051 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2053 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2054 // environment from Full/Low speed signaling environment for a device
2056 InputContext
->Slot
.TTPortNum
= ParentPort
;
2057 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2061 // Inherit the TT parameters from parent device.
2063 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2064 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2066 // If the device is a High speed device then down the speed to be the same as its parent Hub
2068 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2069 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2075 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2077 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2078 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2079 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2081 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2083 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2085 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2086 InputContext
->EP
[0].MaxPacketSize
= 512;
2087 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2088 InputContext
->EP
[0].MaxPacketSize
= 64;
2090 InputContext
->EP
[0].MaxPacketSize
= 8;
2093 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2094 // 1KB, and Bulk and Isoch endpoints 3KB.
2096 InputContext
->EP
[0].AverageTRBLength
= 8;
2097 InputContext
->EP
[0].MaxBurstSize
= 0;
2098 InputContext
->EP
[0].Interval
= 0;
2099 InputContext
->EP
[0].MaxPStreams
= 0;
2100 InputContext
->EP
[0].Mult
= 0;
2101 InputContext
->EP
[0].CErr
= 3;
2104 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2106 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2108 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2109 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2111 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2112 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2115 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2117 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
2118 ASSERT (OutputContext
!= NULL
);
2119 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2120 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
2122 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2124 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2125 // a pointer to the Output Device Context data structure (6.2.1).
2127 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
2129 // Fill DCBAA with PCI device address
2131 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2134 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2135 // Context data structure described above.
2137 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2140 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2141 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2142 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2143 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2144 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2145 CmdTrbAddr
.CycleBit
= 1;
2146 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2147 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2148 Status
= XhcCmdTransfer (
2150 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2151 XHC_GENERIC_TIMEOUT
,
2152 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2154 if (!EFI_ERROR (Status
)) {
2155 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
2156 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2157 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2164 Assign and initialize the device slot for a new device.
2166 @param Xhc The XHCI Instance.
2167 @param ParentRouteChart The route string pointed to the parent device.
2168 @param ParentPort The port at which the device is located.
2169 @param RouteChart The route string pointed to the device.
2170 @param DeviceSpeed The device speed.
2172 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2177 XhcInitializeDeviceSlot64 (
2178 IN USB_XHCI_INSTANCE
*Xhc
,
2179 IN USB_DEV_ROUTE ParentRouteChart
,
2180 IN UINT16 ParentPort
,
2181 IN USB_DEV_ROUTE RouteChart
,
2182 IN UINT8 DeviceSpeed
2186 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2187 INPUT_CONTEXT_64
*InputContext
;
2188 DEVICE_CONTEXT_64
*OutputContext
;
2189 TRANSFER_RING
*EndpointTransferRing
;
2190 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2191 UINT8 DeviceAddress
;
2192 CMD_TRB_ENABLE_SLOT CmdTrb
;
2195 DEVICE_CONTEXT_64
*ParentDeviceContext
;
2196 EFI_PHYSICAL_ADDRESS PhyAddr
;
2198 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2199 CmdTrb
.CycleBit
= 1;
2200 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2202 Status
= XhcCmdTransfer (
2204 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2205 XHC_GENERIC_TIMEOUT
,
2206 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2208 if (EFI_ERROR (Status
)) {
2209 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
2212 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2213 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2214 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2215 ASSERT (SlotId
!= 0);
2217 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2218 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2219 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2220 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2221 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2224 // 4.3.3 Device Slot Initialization
2225 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2227 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
2228 ASSERT (InputContext
!= NULL
);
2229 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2230 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2232 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2235 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2236 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2237 // Context are affected by the command.
2239 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2242 // 3) Initialize the Input Slot Context data structure
2244 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2245 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2246 InputContext
->Slot
.ContextEntries
= 1;
2247 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2249 if (RouteChart
.Route
.RouteString
) {
2251 // The device is behind of hub device.
2253 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2254 ASSERT (ParentSlotId
!= 0);
2256 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2258 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2259 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2260 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2261 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2263 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2264 // environment from Full/Low speed signaling environment for a device
2266 InputContext
->Slot
.TTPortNum
= ParentPort
;
2267 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2271 // Inherit the TT parameters from parent device.
2273 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2274 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2276 // If the device is a High speed device then down the speed to be the same as its parent Hub
2278 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2279 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2285 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2287 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2288 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2289 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2291 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2293 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2295 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2296 InputContext
->EP
[0].MaxPacketSize
= 512;
2297 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2298 InputContext
->EP
[0].MaxPacketSize
= 64;
2300 InputContext
->EP
[0].MaxPacketSize
= 8;
2303 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2304 // 1KB, and Bulk and Isoch endpoints 3KB.
2306 InputContext
->EP
[0].AverageTRBLength
= 8;
2307 InputContext
->EP
[0].MaxBurstSize
= 0;
2308 InputContext
->EP
[0].Interval
= 0;
2309 InputContext
->EP
[0].MaxPStreams
= 0;
2310 InputContext
->EP
[0].Mult
= 0;
2311 InputContext
->EP
[0].CErr
= 3;
2314 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2316 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2318 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2319 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2321 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2322 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2325 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2327 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
2328 ASSERT (OutputContext
!= NULL
);
2329 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2330 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2332 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2334 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2335 // a pointer to the Output Device Context data structure (6.2.1).
2337 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2339 // Fill DCBAA with PCI device address
2341 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2344 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2345 // Context data structure described above.
2347 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request
2350 gBS
->Stall (XHC_RESET_RECOVERY_DELAY
);
2351 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2352 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2353 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2354 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2355 CmdTrbAddr
.CycleBit
= 1;
2356 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2357 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2358 Status
= XhcCmdTransfer (
2360 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2361 XHC_GENERIC_TIMEOUT
,
2362 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2364 if (!EFI_ERROR (Status
)) {
2365 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT_64
*) OutputContext
)->Slot
.DeviceAddress
;
2366 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2367 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2374 Disable the specified device slot.
2376 @param Xhc The XHCI Instance.
2377 @param SlotId The slot id to be disabled.
2379 @retval EFI_SUCCESS Successfully disable the device slot.
2385 IN USB_XHCI_INSTANCE
*Xhc
,
2390 TRB_TEMPLATE
*EvtTrb
;
2391 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2396 // Disable the device slots occupied by these devices on its downstream ports.
2397 // Entry 0 is reserved.
2399 for (Index
= 0; Index
< 255; Index
++) {
2400 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2401 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2402 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2406 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2408 if (EFI_ERROR (Status
)) {
2409 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2410 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2415 // Construct the disable slot command
2417 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2419 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2420 CmdTrbDisSlot
.CycleBit
= 1;
2421 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2422 CmdTrbDisSlot
.SlotId
= SlotId
;
2423 Status
= XhcCmdTransfer (
2425 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2426 XHC_GENERIC_TIMEOUT
,
2427 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2429 if (EFI_ERROR (Status
)) {
2430 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2434 // Free the slot's device context entry
2436 Xhc
->DCBAA
[SlotId
] = 0;
2439 // Free the slot related data structure
2441 for (Index
= 0; Index
< 31; Index
++) {
2442 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2443 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2444 if (RingSeg
!= NULL
) {
2445 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2447 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2448 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2452 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2453 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2454 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2458 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2459 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2462 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2463 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2466 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2467 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
2470 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2471 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2472 // remove urb from XHCI's asynchronous transfer list.
2474 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2475 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2481 Disable the specified device slot.
2483 @param Xhc The XHCI Instance.
2484 @param SlotId The slot id to be disabled.
2486 @retval EFI_SUCCESS Successfully disable the device slot.
2491 XhcDisableSlotCmd64 (
2492 IN USB_XHCI_INSTANCE
*Xhc
,
2497 TRB_TEMPLATE
*EvtTrb
;
2498 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2503 // Disable the device slots occupied by these devices on its downstream ports.
2504 // Entry 0 is reserved.
2506 for (Index
= 0; Index
< 255; Index
++) {
2507 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2508 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2509 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2513 Status
= XhcDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2515 if (EFI_ERROR (Status
)) {
2516 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2517 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2522 // Construct the disable slot command
2524 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2526 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2527 CmdTrbDisSlot
.CycleBit
= 1;
2528 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2529 CmdTrbDisSlot
.SlotId
= SlotId
;
2530 Status
= XhcCmdTransfer (
2532 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2533 XHC_GENERIC_TIMEOUT
,
2534 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2536 if (EFI_ERROR (Status
)) {
2537 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2541 // Free the slot's device context entry
2543 Xhc
->DCBAA
[SlotId
] = 0;
2546 // Free the slot related data structure
2548 for (Index
= 0; Index
< 31; Index
++) {
2549 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2550 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2551 if (RingSeg
!= NULL
) {
2552 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2554 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2555 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2559 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2560 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2561 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2565 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2566 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2569 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2570 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2573 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2574 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2577 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2578 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2579 // remove urb from XHCI's asynchronous transfer list.
2581 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2582 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2588 Initialize endpoint context in input context.
2590 @param Xhc The XHCI Instance.
2591 @param SlotId The slot id to be configured.
2592 @param DeviceSpeed The device's speed.
2593 @param InputContext The pointer to the input context.
2594 @param IfDesc The pointer to the usb device interface descriptor.
2596 @return The maximum device context index of endpoint.
2601 XhcInitializeEndpointContext (
2602 IN USB_XHCI_INSTANCE
*Xhc
,
2604 IN UINT8 DeviceSpeed
,
2605 IN INPUT_CONTEXT
*InputContext
,
2606 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2609 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2616 EFI_PHYSICAL_ADDRESS PhyAddr
;
2618 TRANSFER_RING
*EndpointTransferRing
;
2622 NumEp
= IfDesc
->NumEndpoints
;
2624 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2625 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2626 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2627 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2630 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2631 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2635 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2636 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2638 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2644 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2645 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2647 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2649 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2651 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2653 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2656 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2657 case USB_ENDPOINT_BULK
:
2658 if (Direction
== EfiUsbDataIn
) {
2659 InputContext
->EP
[Dci
-1].CErr
= 3;
2660 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2662 InputContext
->EP
[Dci
-1].CErr
= 3;
2663 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2666 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2667 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2668 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2669 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2670 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2674 case USB_ENDPOINT_ISO
:
2675 if (Direction
== EfiUsbDataIn
) {
2676 InputContext
->EP
[Dci
-1].CErr
= 0;
2677 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2679 InputContext
->EP
[Dci
-1].CErr
= 0;
2680 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2683 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2684 // Refer to XHCI 1.1 spec section 6.2.3.6.
2686 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2687 Interval
= EpDesc
->Interval
;
2688 ASSERT (Interval
>= 1 && Interval
<= 16);
2689 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2690 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2691 Interval
= EpDesc
->Interval
;
2692 ASSERT (Interval
>= 1 && Interval
<= 16);
2693 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2697 // Do not support isochronous transfer now.
2699 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2700 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2702 case USB_ENDPOINT_INTERRUPT
:
2703 if (Direction
== EfiUsbDataIn
) {
2704 InputContext
->EP
[Dci
-1].CErr
= 3;
2705 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2707 InputContext
->EP
[Dci
-1].CErr
= 3;
2708 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2710 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2711 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2713 // Get the bInterval from descriptor and init the the interval field of endpoint context
2715 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2716 Interval
= EpDesc
->Interval
;
2718 // Calculate through the bInterval field of Endpoint descriptor.
2720 ASSERT (Interval
!= 0);
2721 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2722 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2723 Interval
= EpDesc
->Interval
;
2724 ASSERT (Interval
>= 1 && Interval
<= 16);
2726 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2728 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2729 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2730 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2731 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2732 InputContext
->EP
[Dci
-1].CErr
= 3;
2735 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2736 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2737 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2738 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2742 case USB_ENDPOINT_CONTROL
:
2744 // Do not support control transfer now.
2746 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2748 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2749 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2753 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2755 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2756 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2758 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2759 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2760 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2761 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2763 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2770 Initialize endpoint context in input context.
2772 @param Xhc The XHCI Instance.
2773 @param SlotId The slot id to be configured.
2774 @param DeviceSpeed The device's speed.
2775 @param InputContext The pointer to the input context.
2776 @param IfDesc The pointer to the usb device interface descriptor.
2778 @return The maximum device context index of endpoint.
2783 XhcInitializeEndpointContext64 (
2784 IN USB_XHCI_INSTANCE
*Xhc
,
2786 IN UINT8 DeviceSpeed
,
2787 IN INPUT_CONTEXT_64
*InputContext
,
2788 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2791 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2798 EFI_PHYSICAL_ADDRESS PhyAddr
;
2800 TRANSFER_RING
*EndpointTransferRing
;
2804 NumEp
= IfDesc
->NumEndpoints
;
2806 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2807 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2808 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2809 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2812 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
2813 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2817 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2818 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2820 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2826 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2827 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2829 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2831 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2833 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2835 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2838 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2839 case USB_ENDPOINT_BULK
:
2840 if (Direction
== EfiUsbDataIn
) {
2841 InputContext
->EP
[Dci
-1].CErr
= 3;
2842 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2844 InputContext
->EP
[Dci
-1].CErr
= 3;
2845 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2848 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2849 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2850 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2851 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2852 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2856 case USB_ENDPOINT_ISO
:
2857 if (Direction
== EfiUsbDataIn
) {
2858 InputContext
->EP
[Dci
-1].CErr
= 0;
2859 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2861 InputContext
->EP
[Dci
-1].CErr
= 0;
2862 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2865 // Get the bInterval from descriptor and init the the interval field of endpoint context.
2866 // Refer to XHCI 1.1 spec section 6.2.3.6.
2868 if (DeviceSpeed
== EFI_USB_SPEED_FULL
) {
2869 Interval
= EpDesc
->Interval
;
2870 ASSERT (Interval
>= 1 && Interval
<= 16);
2871 InputContext
->EP
[Dci
-1].Interval
= Interval
+ 2;
2872 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2873 Interval
= EpDesc
->Interval
;
2874 ASSERT (Interval
>= 1 && Interval
<= 16);
2875 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2879 // Do not support isochronous transfer now.
2881 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2882 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2884 case USB_ENDPOINT_INTERRUPT
:
2885 if (Direction
== EfiUsbDataIn
) {
2886 InputContext
->EP
[Dci
-1].CErr
= 3;
2887 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2889 InputContext
->EP
[Dci
-1].CErr
= 3;
2890 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2892 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2893 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2895 // Get the bInterval from descriptor and init the the interval field of endpoint context
2897 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2898 Interval
= EpDesc
->Interval
;
2900 // Calculate through the bInterval field of Endpoint descriptor.
2902 ASSERT (Interval
!= 0);
2903 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2904 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2905 Interval
= EpDesc
->Interval
;
2906 ASSERT (Interval
>= 1 && Interval
<= 16);
2908 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2910 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2911 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2912 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2913 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2914 InputContext
->EP
[Dci
-1].CErr
= 3;
2917 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2918 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2919 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2920 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2924 case USB_ENDPOINT_CONTROL
:
2926 // Do not support control transfer now.
2928 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2930 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
2931 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2935 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2937 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2938 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2940 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2941 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2942 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2943 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2945 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2952 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2954 @param Xhc The XHCI Instance.
2955 @param SlotId The slot id to be configured.
2956 @param DeviceSpeed The device's speed.
2957 @param ConfigDesc The pointer to the usb device configuration descriptor.
2959 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2965 IN USB_XHCI_INSTANCE
*Xhc
,
2967 IN UINT8 DeviceSpeed
,
2968 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
2972 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
2976 EFI_PHYSICAL_ADDRESS PhyAddr
;
2978 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2979 INPUT_CONTEXT
*InputContext
;
2980 DEVICE_CONTEXT
*OutputContext
;
2981 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2983 // 4.6.6 Configure Endpoint
2985 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2986 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2987 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2988 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
2990 ASSERT (ConfigDesc
!= NULL
);
2994 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
2995 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
2996 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
2997 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3000 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3001 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3005 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3010 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3013 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3014 InputContext
->Slot
.ContextEntries
= MaxDci
;
3016 // configure endpoint
3018 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3019 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3020 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3021 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3022 CmdTrbCfgEP
.CycleBit
= 1;
3023 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3024 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3025 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3026 Status
= XhcCmdTransfer (
3028 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3029 XHC_GENERIC_TIMEOUT
,
3030 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3032 if (EFI_ERROR (Status
)) {
3033 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
3035 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3042 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
3044 @param Xhc The XHCI Instance.
3045 @param SlotId The slot id to be configured.
3046 @param DeviceSpeed The device's speed.
3047 @param ConfigDesc The pointer to the usb device configuration descriptor.
3049 @retval EFI_SUCCESS Successfully configure all the device endpoints.
3055 IN USB_XHCI_INSTANCE
*Xhc
,
3057 IN UINT8 DeviceSpeed
,
3058 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
3062 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3066 EFI_PHYSICAL_ADDRESS PhyAddr
;
3068 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3069 INPUT_CONTEXT_64
*InputContext
;
3070 DEVICE_CONTEXT_64
*OutputContext
;
3071 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3073 // 4.6.6 Configure Endpoint
3075 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3076 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3077 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3078 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3080 ASSERT (ConfigDesc
!= NULL
);
3084 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3085 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3086 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3087 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3090 if (IfDesc
->Length
< sizeof (USB_INTERFACE_DESCRIPTOR
)) {
3091 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3095 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3100 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3103 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3104 InputContext
->Slot
.ContextEntries
= MaxDci
;
3106 // configure endpoint
3108 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3109 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3110 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3111 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3112 CmdTrbCfgEP
.CycleBit
= 1;
3113 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3114 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3115 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3116 Status
= XhcCmdTransfer (
3118 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3119 XHC_GENERIC_TIMEOUT
,
3120 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3122 if (EFI_ERROR (Status
)) {
3123 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
3125 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3132 Stop endpoint through XHCI's Stop_Endpoint cmd.
3134 @param Xhc The XHCI Instance.
3135 @param SlotId The slot id to be configured.
3136 @param Dci The device context index of endpoint.
3138 @retval EFI_SUCCESS Stop endpoint successfully.
3139 @retval Others Failed to stop endpoint.
3145 IN USB_XHCI_INSTANCE
*Xhc
,
3151 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3152 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
3154 DEBUG ((EFI_D_INFO
, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3157 // Send stop endpoint command to transit Endpoint from running to stop state
3159 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
3160 CmdTrbStopED
.CycleBit
= 1;
3161 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
3162 CmdTrbStopED
.EDID
= Dci
;
3163 CmdTrbStopED
.SlotId
= SlotId
;
3164 Status
= XhcCmdTransfer (
3166 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbStopED
,
3167 XHC_GENERIC_TIMEOUT
,
3168 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3170 if (EFI_ERROR(Status
)) {
3171 DEBUG ((EFI_D_ERROR
, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
3178 Reset endpoint through XHCI's Reset_Endpoint cmd.
3180 @param Xhc The XHCI Instance.
3181 @param SlotId The slot id to be configured.
3182 @param Dci The device context index of endpoint.
3184 @retval EFI_SUCCESS Reset endpoint successfully.
3185 @retval Others Failed to reset endpoint.
3191 IN USB_XHCI_INSTANCE
*Xhc
,
3197 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3198 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
3200 DEBUG ((EFI_D_INFO
, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3203 // Send stop endpoint command to transit Endpoint from running to stop state
3205 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
3206 CmdTrbResetED
.CycleBit
= 1;
3207 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
3208 CmdTrbResetED
.EDID
= Dci
;
3209 CmdTrbResetED
.SlotId
= SlotId
;
3210 Status
= XhcCmdTransfer (
3212 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
3213 XHC_GENERIC_TIMEOUT
,
3214 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3216 if (EFI_ERROR(Status
)) {
3217 DEBUG ((EFI_D_ERROR
, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
3224 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3226 @param Xhc The XHCI Instance.
3227 @param SlotId The slot id to be configured.
3228 @param Dci The device context index of endpoint.
3229 @param Urb The dequeue pointer of the transfer ring specified
3230 by the urb to be updated.
3232 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
3233 @retval Others Failed to set transfer ring dequeue pointer.
3238 XhcSetTrDequeuePointer (
3239 IN USB_XHCI_INSTANCE
*Xhc
,
3246 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3247 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
3248 EFI_PHYSICAL_ADDRESS PhyAddr
;
3250 DEBUG ((EFI_D_INFO
, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
3253 // Send stop endpoint command to transit Endpoint from running to stop state
3255 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
3256 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
3257 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
3258 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3259 CmdSetTRDeq
.CycleBit
= 1;
3260 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
3261 CmdSetTRDeq
.Endpoint
= Dci
;
3262 CmdSetTRDeq
.SlotId
= SlotId
;
3263 Status
= XhcCmdTransfer (
3265 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
3266 XHC_GENERIC_TIMEOUT
,
3267 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3269 if (EFI_ERROR(Status
)) {
3270 DEBUG ((EFI_D_ERROR
, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
3277 Set interface through XHCI's Configure_Endpoint cmd.
3279 @param Xhc The XHCI Instance.
3280 @param SlotId The slot id to be configured.
3281 @param DeviceSpeed The device's speed.
3282 @param ConfigDesc The pointer to the usb device configuration descriptor.
3283 @param Request USB device request to send.
3285 @retval EFI_SUCCESS Successfully set interface.
3291 IN USB_XHCI_INSTANCE
*Xhc
,
3293 IN UINT8 DeviceSpeed
,
3294 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3295 IN EFI_USB_DEVICE_REQUEST
*Request
3299 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3300 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3301 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3302 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3309 EFI_PHYSICAL_ADDRESS PhyAddr
;
3312 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3313 INPUT_CONTEXT
*InputContext
;
3314 DEVICE_CONTEXT
*OutputContext
;
3315 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3317 Status
= EFI_SUCCESS
;
3319 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3320 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3322 // XHCI 4.6.6 Configure Endpoint
3323 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3324 // Context and Add Context flags as follows:
3325 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3326 // Context and Add Context flags to '0'.
3328 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3329 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3331 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3332 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3334 ASSERT (ConfigDesc
!= NULL
);
3338 IfDescActive
= NULL
;
3341 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3342 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3343 if ((IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) && (IfDesc
->Length
>= sizeof (USB_INTERFACE_DESCRIPTOR
))) {
3344 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3345 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3347 // Find out the active interface descriptor.
3349 IfDescActive
= IfDesc
;
3350 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3352 // Find out the interface descriptor to set.
3358 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3362 // XHCI 4.6.6 Configure Endpoint
3363 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3364 // Context and Add Context flags as follows:
3365 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3366 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3367 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3368 // the Drop Context flag to '1' and Add Context flag to '0'.
3369 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3370 // and Add Context flags shall be set to '1'.
3372 // Below codes are to cover 2), 3) and 4).
3375 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3376 NumEp
= IfDescActive
->NumEndpoints
;
3377 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3378 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3379 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3380 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3383 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
3384 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3388 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3389 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3391 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3397 // XHCI 4.3.6 - Setting Alternate Interfaces
3398 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3400 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
);
3401 if (EFI_ERROR (Status
)) {
3405 // XHCI 4.3.6 - Setting Alternate Interfaces
3406 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3408 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3409 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3410 if (RingSeg
!= NULL
) {
3411 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3413 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3414 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3418 // Set the Drop Context flag to '1'.
3420 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3422 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3426 // XHCI 4.3.6 - Setting Alternate Interfaces
3427 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3428 // Interface setting, to '0'.
3430 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3434 // XHCI 4.3.6 - Setting Alternate Interfaces
3435 // 4) For each endpoint enabled by the Configure Endpoint Command:
3436 // a. Allocate a Transfer Ring.
3437 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3438 // c. Initialize the Endpoint Context data structure.
3440 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3445 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3446 InputContext
->Slot
.ContextEntries
= MaxDci
;
3448 // XHCI 4.3.6 - Setting Alternate Interfaces
3449 // 5) Issue and successfully complete a Configure Endpoint Command.
3451 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3452 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3453 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3454 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3455 CmdTrbCfgEP
.CycleBit
= 1;
3456 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3457 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3458 DEBUG ((EFI_D_INFO
, "SetInterface: Configure Endpoint\n"));
3459 Status
= XhcCmdTransfer (
3461 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3462 XHC_GENERIC_TIMEOUT
,
3463 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3465 if (EFI_ERROR (Status
)) {
3466 DEBUG ((EFI_D_ERROR
, "SetInterface: Config Endpoint Failed, Status = %r\n", Status
));
3469 // Update the active AlternateSetting.
3471 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3479 Set interface through XHCI's Configure_Endpoint cmd.
3481 @param Xhc The XHCI Instance.
3482 @param SlotId The slot id to be configured.
3483 @param DeviceSpeed The device's speed.
3484 @param ConfigDesc The pointer to the usb device configuration descriptor.
3485 @param Request USB device request to send.
3487 @retval EFI_SUCCESS Successfully set interface.
3493 IN USB_XHCI_INSTANCE
*Xhc
,
3495 IN UINT8 DeviceSpeed
,
3496 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3497 IN EFI_USB_DEVICE_REQUEST
*Request
3501 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3502 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3503 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3504 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3511 EFI_PHYSICAL_ADDRESS PhyAddr
;
3514 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3515 INPUT_CONTEXT_64
*InputContext
;
3516 DEVICE_CONTEXT_64
*OutputContext
;
3517 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3519 Status
= EFI_SUCCESS
;
3521 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3522 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3524 // XHCI 4.6.6 Configure Endpoint
3525 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3526 // Context and Add Context flags as follows:
3527 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3528 // Context and Add Context flags to '0'.
3530 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3531 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3533 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3534 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3536 ASSERT (ConfigDesc
!= NULL
);
3540 IfDescActive
= NULL
;
3543 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3544 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3545 if ((IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) && (IfDesc
->Length
>= sizeof (USB_INTERFACE_DESCRIPTOR
))) {
3546 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3547 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3549 // Find out the active interface descriptor.
3551 IfDescActive
= IfDesc
;
3552 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3554 // Find out the interface descriptor to set.
3560 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3564 // XHCI 4.6.6 Configure Endpoint
3565 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3566 // Context and Add Context flags as follows:
3567 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3568 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3569 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3570 // the Drop Context flag to '1' and Add Context flag to '0'.
3571 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3572 // and Add Context flags shall be set to '1'.
3574 // Below codes are to cover 2), 3) and 4).
3577 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3578 NumEp
= IfDescActive
->NumEndpoints
;
3579 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3580 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3581 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3582 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3585 if (EpDesc
->Length
< sizeof (USB_ENDPOINT_DESCRIPTOR
)) {
3586 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3590 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3591 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3593 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3599 // XHCI 4.3.6 - Setting Alternate Interfaces
3600 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3602 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
);
3603 if (EFI_ERROR (Status
)) {
3607 // XHCI 4.3.6 - Setting Alternate Interfaces
3608 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3610 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3611 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3612 if (RingSeg
!= NULL
) {
3613 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3615 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3616 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3620 // Set the Drop Context flag to '1'.
3622 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3624 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3628 // XHCI 4.3.6 - Setting Alternate Interfaces
3629 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3630 // Interface setting, to '0'.
3632 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3636 // XHCI 4.3.6 - Setting Alternate Interfaces
3637 // 4) For each endpoint enabled by the Configure Endpoint Command:
3638 // a. Allocate a Transfer Ring.
3639 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3640 // c. Initialize the Endpoint Context data structure.
3642 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3647 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3648 InputContext
->Slot
.ContextEntries
= MaxDci
;
3650 // XHCI 4.3.6 - Setting Alternate Interfaces
3651 // 5) Issue and successfully complete a Configure Endpoint Command.
3653 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3654 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3655 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3656 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3657 CmdTrbCfgEP
.CycleBit
= 1;
3658 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3659 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3660 DEBUG ((EFI_D_INFO
, "SetInterface64: Configure Endpoint\n"));
3661 Status
= XhcCmdTransfer (
3663 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3664 XHC_GENERIC_TIMEOUT
,
3665 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3667 if (EFI_ERROR (Status
)) {
3668 DEBUG ((EFI_D_ERROR
, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status
));
3671 // Update the active AlternateSetting.
3673 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3681 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3683 @param Xhc The XHCI Instance.
3684 @param SlotId The slot id to be evaluated.
3685 @param MaxPacketSize The max packet size supported by the device control transfer.
3687 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3692 XhcEvaluateContext (
3693 IN USB_XHCI_INSTANCE
*Xhc
,
3695 IN UINT32 MaxPacketSize
3699 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3700 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3701 INPUT_CONTEXT
*InputContext
;
3702 EFI_PHYSICAL_ADDRESS PhyAddr
;
3704 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3707 // 4.6.7 Evaluate Context
3709 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3710 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3712 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3713 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3715 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3716 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3717 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3718 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3719 CmdTrbEvalu
.CycleBit
= 1;
3720 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3721 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3722 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3723 Status
= XhcCmdTransfer (
3725 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3726 XHC_GENERIC_TIMEOUT
,
3727 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3729 if (EFI_ERROR (Status
)) {
3730 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
3736 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3738 @param Xhc The XHCI Instance.
3739 @param SlotId The slot id to be evaluated.
3740 @param MaxPacketSize The max packet size supported by the device control transfer.
3742 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3747 XhcEvaluateContext64 (
3748 IN USB_XHCI_INSTANCE
*Xhc
,
3750 IN UINT32 MaxPacketSize
3754 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3755 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3756 INPUT_CONTEXT_64
*InputContext
;
3757 EFI_PHYSICAL_ADDRESS PhyAddr
;
3759 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3762 // 4.6.7 Evaluate Context
3764 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3765 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3767 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3768 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3770 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3771 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3772 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3773 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3774 CmdTrbEvalu
.CycleBit
= 1;
3775 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3776 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3777 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3778 Status
= XhcCmdTransfer (
3780 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3781 XHC_GENERIC_TIMEOUT
,
3782 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3784 if (EFI_ERROR (Status
)) {
3785 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
3792 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3794 @param Xhc The XHCI Instance.
3795 @param SlotId The slot id to be configured.
3796 @param PortNum The total number of downstream port supported by the hub.
3797 @param TTT The TT think time of the hub device.
3798 @param MTT The multi-TT of the hub device.
3800 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3804 XhcConfigHubContext (
3805 IN USB_XHCI_INSTANCE
*Xhc
,
3813 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3814 INPUT_CONTEXT
*InputContext
;
3815 DEVICE_CONTEXT
*OutputContext
;
3816 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3817 EFI_PHYSICAL_ADDRESS PhyAddr
;
3819 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3820 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3821 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3824 // 4.6.7 Evaluate Context
3826 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3828 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3831 // Copy the slot context from OutputContext to Input context
3833 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
3834 InputContext
->Slot
.Hub
= 1;
3835 InputContext
->Slot
.PortNum
= PortNum
;
3836 InputContext
->Slot
.TTT
= TTT
;
3837 InputContext
->Slot
.MTT
= MTT
;
3839 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3840 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3841 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3842 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3843 CmdTrbCfgEP
.CycleBit
= 1;
3844 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3845 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3846 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
3847 Status
= XhcCmdTransfer (
3849 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3850 XHC_GENERIC_TIMEOUT
,
3851 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3853 if (EFI_ERROR (Status
)) {
3854 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
3860 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3862 @param Xhc The XHCI Instance.
3863 @param SlotId The slot id to be configured.
3864 @param PortNum The total number of downstream port supported by the hub.
3865 @param TTT The TT think time of the hub device.
3866 @param MTT The multi-TT of the hub device.
3868 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3872 XhcConfigHubContext64 (
3873 IN USB_XHCI_INSTANCE
*Xhc
,
3881 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3882 INPUT_CONTEXT_64
*InputContext
;
3883 DEVICE_CONTEXT_64
*OutputContext
;
3884 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3885 EFI_PHYSICAL_ADDRESS PhyAddr
;
3887 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3888 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3889 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3892 // 4.6.7 Evaluate Context
3894 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3896 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3899 // Copy the slot context from OutputContext to Input context
3901 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
3902 InputContext
->Slot
.Hub
= 1;
3903 InputContext
->Slot
.PortNum
= PortNum
;
3904 InputContext
->Slot
.TTT
= TTT
;
3905 InputContext
->Slot
.MTT
= MTT
;
3907 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3908 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3909 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3910 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3911 CmdTrbCfgEP
.CycleBit
= 1;
3912 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3913 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3914 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
3915 Status
= XhcCmdTransfer (
3917 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3918 XHC_GENERIC_TIMEOUT
,
3919 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3921 if (EFI_ERROR (Status
)) {
3922 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));