3 XHCI transfer scheduling routines.
5 Copyright (c) 2011 - 2015, 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 URBs in XHCI's asynchronous transfer list.
982 @param Xhc The XHCI Instance.
983 @param Trb The TRB to be checked.
984 @param Urb The pointer to the matched Urb.
986 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
987 @retval FALSE The Trb is not matched with any URBs in the async list.
992 IN USB_XHCI_INSTANCE
*Xhc
,
993 IN TRB_TEMPLATE
*Trb
,
999 TRB_TEMPLATE
*CheckedTrb
;
1003 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1004 CheckedUrb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1005 CheckedTrb
= CheckedUrb
->TrbStart
;
1006 for (Index
= 0; Index
< CheckedUrb
->TrbNum
; Index
++) {
1007 if (Trb
== CheckedTrb
) {
1012 if ((UINTN
)CheckedTrb
>= ((UINTN
) CheckedUrb
->Ring
->RingSeg0
+ sizeof (TRB_TEMPLATE
) * CheckedUrb
->Ring
->TrbNumber
)) {
1013 CheckedTrb
= (TRB_TEMPLATE
*) CheckedUrb
->Ring
->RingSeg0
;
1022 Check if the Trb is a transaction of the URB.
1024 @param Trb The TRB to be checked
1025 @param Urb The transfer ring to be checked.
1027 @retval TRUE It is a transaction of the URB.
1028 @retval FALSE It is not any transaction of the URB.
1033 IN TRB_TEMPLATE
*Trb
,
1037 TRB_TEMPLATE
*CheckedTrb
;
1040 CheckedTrb
= Urb
->Ring
->RingSeg0
;
1042 ASSERT (Urb
->Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Urb
->Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
1044 for (Index
= 0; Index
< Urb
->Ring
->TrbNumber
; Index
++) {
1045 if (Trb
== CheckedTrb
) {
1055 Check the URB's execution result and update the URB's
1058 @param Xhc The XHCI Instance.
1059 @param Urb The URB to check result.
1061 @return Whether the result of URB transfer is finialized.
1066 IN USB_XHCI_INSTANCE
*Xhc
,
1070 EVT_TRB_TRANSFER
*EvtTrb
;
1071 TRB_TEMPLATE
*TRBPtr
;
1080 EFI_PHYSICAL_ADDRESS PhyAddr
;
1082 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
1084 Status
= EFI_SUCCESS
;
1087 if (Urb
->Finished
) {
1093 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1094 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
1099 // Traverse the event ring to find out all new events from the previous check.
1101 XhcSyncEventRing (Xhc
, &Xhc
->EventRing
);
1102 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
1103 Status
= XhcCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
1104 if (Status
== EFI_NOT_READY
) {
1106 // All new events are handled, return directly.
1112 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1114 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
1119 // Need convert pci device address to host address
1121 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
1122 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1125 // Update the status of Urb according to the finished event regardless of whether
1126 // the urb is current checked one or in the XHCI's async transfer list.
1127 // This way is used to avoid that those completed async transfer events don't get
1128 // handled in time and are flushed by newer coming events.
1130 if (IsTransferRingTrb (TRBPtr
, Urb
)) {
1132 } else if (IsAsyncIntTrb (Xhc
, TRBPtr
, &AsyncUrb
)) {
1133 CheckedUrb
= AsyncUrb
;
1138 switch (EvtTrb
->Completecode
) {
1139 case TRB_COMPLETION_STALL_ERROR
:
1140 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
1141 CheckedUrb
->Finished
= TRUE
;
1142 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1145 case TRB_COMPLETION_BABBLE_ERROR
:
1146 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
1147 CheckedUrb
->Finished
= TRUE
;
1148 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1151 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
1152 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
1153 CheckedUrb
->Finished
= TRUE
;
1154 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
1157 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
1158 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1159 CheckedUrb
->Finished
= TRUE
;
1160 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1163 case TRB_COMPLETION_SHORT_PACKET
:
1164 case TRB_COMPLETION_SUCCESS
:
1165 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
1166 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: short packet happens!\n"));
1169 TRBType
= (UINT8
) (TRBPtr
->Type
);
1170 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
1171 (TRBType
== TRB_TYPE_NORMAL
) ||
1172 (TRBType
== TRB_TYPE_ISOCH
)) {
1173 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
1179 DEBUG ((EFI_D_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
1180 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1181 CheckedUrb
->Finished
= TRUE
;
1186 // Only check first and end Trb event address
1188 if (TRBPtr
== CheckedUrb
->TrbStart
) {
1189 CheckedUrb
->StartDone
= TRUE
;
1192 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
1193 CheckedUrb
->EndDone
= TRUE
;
1196 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
1197 CheckedUrb
->Finished
= TRUE
;
1198 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
1205 // Advance event ring to last available entry
1207 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1208 // So divide it to two 32-bytes width register access.
1210 Low
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
1211 High
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
1212 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
1214 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
1216 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
1218 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1219 // So divide it to two 32-bytes width register access.
1221 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
1222 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
1225 return Urb
->Finished
;
1230 Execute the transfer by polling the URB. This is a synchronous operation.
1232 @param Xhc The XHCI Instance.
1233 @param CmdTransfer The executed URB is for cmd transfer or not.
1234 @param Urb The URB to execute.
1235 @param Timeout The time to wait before abort, in millisecond.
1237 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1238 @return EFI_TIMEOUT The transfer failed due to time out.
1239 @return EFI_SUCCESS The transfer finished OK.
1244 IN USB_XHCI_INSTANCE
*Xhc
,
1245 IN BOOLEAN CmdTransfer
,
1261 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1263 return EFI_DEVICE_ERROR
;
1265 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1269 Status
= EFI_SUCCESS
;
1270 Loop
= Timeout
* XHC_1_MILLISECOND
;
1275 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1277 for (Index
= 0; Index
< Loop
; Index
++) {
1278 Finished
= XhcCheckUrbResult (Xhc
, Urb
);
1282 gBS
->Stall (XHC_1_MICROSECOND
);
1285 if (Index
== Loop
) {
1286 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
1287 Status
= EFI_TIMEOUT
;
1288 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
1289 Status
= EFI_DEVICE_ERROR
;
1296 Delete a single asynchronous interrupt transfer for
1297 the device and endpoint.
1299 @param Xhc The XHCI Instance.
1300 @param BusAddr The logical device address assigned by UsbBus driver.
1301 @param EpNum The endpoint of the target.
1303 @retval EFI_SUCCESS An asynchronous transfer is removed.
1304 @retval EFI_NOT_FOUND No transfer for the device is found.
1308 XhciDelAsyncIntTransfer (
1309 IN USB_XHCI_INSTANCE
*Xhc
,
1317 EFI_USB_DATA_DIRECTION Direction
;
1319 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1324 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1325 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1326 if ((Urb
->Ep
.BusAddr
== BusAddr
) &&
1327 (Urb
->Ep
.EpAddr
== EpNum
) &&
1328 (Urb
->Ep
.Direction
== Direction
)) {
1329 RemoveEntryList (&Urb
->UrbList
);
1330 FreePool (Urb
->Data
);
1331 XhcFreeUrb (Xhc
, Urb
);
1336 return EFI_NOT_FOUND
;
1340 Remove all the asynchronous interrutp transfers.
1342 @param Xhc The XHCI Instance.
1346 XhciDelAllAsyncIntTransfers (
1347 IN USB_XHCI_INSTANCE
*Xhc
1354 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1355 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1356 RemoveEntryList (&Urb
->UrbList
);
1357 FreePool (Urb
->Data
);
1358 XhcFreeUrb (Xhc
, Urb
);
1363 Update the queue head for next round of asynchronous transfer
1365 @param Xhc The XHCI Instance.
1366 @param Urb The URB to update
1370 XhcUpdateAsyncRequest (
1371 IN USB_XHCI_INSTANCE
*Xhc
,
1377 if (Urb
->Result
== EFI_USB_NOERROR
) {
1378 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1379 if (EFI_ERROR (Status
)) {
1382 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1383 if (EFI_ERROR (Status
)) {
1390 Flush data from PCI controller specific address to mapped system
1393 @param Xhc The XHCI device.
1394 @param Urb The URB to unmap.
1396 @retval EFI_SUCCESS Success to flush data to mapped system memory.
1397 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
1401 XhcFlushAsyncIntMap (
1402 IN USB_XHCI_INSTANCE
*Xhc
,
1407 EFI_PHYSICAL_ADDRESS PhyAddr
;
1408 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
1409 EFI_PCI_IO_PROTOCOL
*PciIo
;
1416 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
1417 MapOp
= EfiPciIoOperationBusMasterWrite
;
1419 MapOp
= EfiPciIoOperationBusMasterRead
;
1422 if (Urb
->DataMap
!= NULL
) {
1423 Status
= PciIo
->Unmap (PciIo
, Urb
->DataMap
);
1424 if (EFI_ERROR (Status
)) {
1429 Urb
->DataMap
= NULL
;
1431 Status
= PciIo
->Map (PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
1432 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
1436 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
1441 return EFI_DEVICE_ERROR
;
1445 Interrupt transfer periodic check handler.
1447 @param Event Interrupt event.
1448 @param Context Pointer to USB_XHCI_INSTANCE.
1453 XhcMonitorAsyncRequests (
1458 USB_XHCI_INSTANCE
*Xhc
;
1467 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1469 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1471 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1472 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1475 // Make sure that the device is available before every check.
1477 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1483 // Check the result of URB execution. If it is still
1484 // active, check the next one.
1486 XhcCheckUrbResult (Xhc
, Urb
);
1488 if (!Urb
->Finished
) {
1493 // Flush any PCI posted write transactions from a PCI host
1494 // bridge to system memory.
1496 Status
= XhcFlushAsyncIntMap (Xhc
, Urb
);
1497 if (EFI_ERROR (Status
)) {
1498 DEBUG ((EFI_D_ERROR
, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1502 // Allocate a buffer then copy the transferred data for user.
1503 // If failed to allocate the buffer, update the URB for next
1504 // round of transfer. Ignore the data of this round.
1507 if (Urb
->Result
== EFI_USB_NOERROR
) {
1508 ASSERT (Urb
->Completed
<= Urb
->DataLen
);
1510 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1512 if (ProcBuf
== NULL
) {
1513 XhcUpdateAsyncRequest (Xhc
, Urb
);
1517 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1521 // Leave error recovery to its related device driver. A
1522 // common case of the error recovery is to re-submit the
1523 // interrupt transfer which is linked to the head of the
1524 // list. This function scans from head to tail. So the
1525 // re-submitted interrupt transfer's callback function
1526 // will not be called again in this round. Don't touch this
1527 // URB after the callback, it may have been removed by the
1530 if (Urb
->Callback
!= NULL
) {
1532 // Restore the old TPL, USB bus maybe connect device in
1533 // his callback. Some drivers may has a lower TPL restriction.
1535 gBS
->RestoreTPL (OldTpl
);
1536 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1537 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1540 if (ProcBuf
!= NULL
) {
1541 gBS
->FreePool (ProcBuf
);
1544 XhcUpdateAsyncRequest (Xhc
, Urb
);
1546 gBS
->RestoreTPL (OldTpl
);
1550 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1552 @param Xhc The XHCI Instance.
1553 @param ParentRouteChart The route string pointed to the parent device if it exists.
1554 @param Port The port to be polled.
1555 @param PortState The port state.
1557 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1558 @retval Others Should not appear.
1563 XhcPollPortStatusChange (
1564 IN USB_XHCI_INSTANCE
*Xhc
,
1565 IN USB_DEV_ROUTE ParentRouteChart
,
1567 IN EFI_USB_PORT_STATUS
*PortState
1573 USB_DEV_ROUTE RouteChart
;
1575 Status
= EFI_SUCCESS
;
1577 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
1581 if (ParentRouteChart
.Dword
== 0) {
1582 RouteChart
.Route
.RouteString
= 0;
1583 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1584 RouteChart
.Route
.TierNum
= 1;
1587 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1589 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1591 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1592 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1595 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1597 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1598 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1600 Status
= XhcDisableSlotCmd64 (Xhc
, SlotId
);
1604 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1605 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1607 // Has a device attached, Identify device speed after port is enabled.
1609 Speed
= EFI_USB_SPEED_FULL
;
1610 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1611 Speed
= EFI_USB_SPEED_LOW
;
1612 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1613 Speed
= EFI_USB_SPEED_HIGH
;
1614 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1615 Speed
= EFI_USB_SPEED_SUPER
;
1618 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1620 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1621 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
1622 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1623 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1625 Status
= XhcInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1635 Calculate the device context index by endpoint address and direction.
1637 @param EpAddr The target endpoint number.
1638 @param Direction The direction of the target endpoint.
1640 @return The device context index of endpoint.
1654 Index
= (UINT8
) (2 * EpAddr
);
1655 if (Direction
== EfiUsbDataIn
) {
1663 Find out the actual device address according to the requested device address from UsbBus.
1665 @param Xhc The XHCI Instance.
1666 @param BusDevAddr The requested device address by UsbBus upper driver.
1668 @return The actual device address assigned to the device.
1673 XhcBusDevAddrToSlotId (
1674 IN USB_XHCI_INSTANCE
*Xhc
,
1680 for (Index
= 0; Index
< 255; Index
++) {
1681 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1682 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1683 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1692 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1696 Find out the slot id according to the device's route string.
1698 @param Xhc The XHCI Instance.
1699 @param RouteString The route string described the device location.
1701 @return The slot id used by the device.
1706 XhcRouteStringToSlotId (
1707 IN USB_XHCI_INSTANCE
*Xhc
,
1708 IN USB_DEV_ROUTE RouteString
1713 for (Index
= 0; Index
< 255; Index
++) {
1714 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1715 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1716 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1725 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1729 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1731 @param Xhc The XHCI Instance.
1732 @param EvtRing The event ring to sync.
1734 @retval EFI_SUCCESS The event ring is synchronized successfully.
1740 IN USB_XHCI_INSTANCE
*Xhc
,
1741 IN EVENT_RING
*EvtRing
1745 TRB_TEMPLATE
*EvtTrb1
;
1747 ASSERT (EvtRing
!= NULL
);
1750 // Calculate the EventRingEnqueue and EventRingCCS.
1751 // Note: only support single Segment
1753 EvtTrb1
= EvtRing
->EventRingDequeue
;
1755 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1756 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
1762 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1763 EvtTrb1
= EvtRing
->EventRingSeg0
;
1764 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
1768 if (Index
< EvtRing
->TrbNumber
) {
1769 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1778 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1780 @param Xhc The XHCI Instance.
1781 @param TrsRing The transfer ring to sync.
1783 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1789 IN USB_XHCI_INSTANCE
*Xhc
,
1790 IN TRANSFER_RING
*TrsRing
1794 TRB_TEMPLATE
*TrsTrb
;
1796 ASSERT (TrsRing
!= NULL
);
1798 // Calculate the latest RingEnqueue and RingPCS
1800 TrsTrb
= TrsRing
->RingEnqueue
;
1801 ASSERT (TrsTrb
!= NULL
);
1803 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1804 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1808 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1809 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1811 // set cycle bit in Link TRB as normal
1813 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1815 // Toggle PCS maintained by software
1817 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1818 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
1822 ASSERT (Index
!= TrsRing
->TrbNumber
);
1824 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1825 TrsRing
->RingEnqueue
= TrsTrb
;
1829 // Clear the Trb context for enqueue, but reserve the PCS bit
1831 TrsTrb
->Parameter1
= 0;
1832 TrsTrb
->Parameter2
= 0;
1836 TrsTrb
->Control
= 0;
1842 Check if there is a new generated event.
1844 @param Xhc The XHCI Instance.
1845 @param EvtRing The event ring to check.
1846 @param NewEvtTrb The new event TRB found.
1848 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1849 @retval EFI_NOT_READY The event ring has no new event.
1855 IN USB_XHCI_INSTANCE
*Xhc
,
1856 IN EVENT_RING
*EvtRing
,
1857 OUT TRB_TEMPLATE
**NewEvtTrb
1860 ASSERT (EvtRing
!= NULL
);
1862 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
1864 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
1865 return EFI_NOT_READY
;
1868 EvtRing
->EventRingDequeue
++;
1870 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1872 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1873 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
1880 Ring the door bell to notify XHCI there is a transaction to be executed.
1882 @param Xhc The XHCI Instance.
1883 @param SlotId The slot id of the target device.
1884 @param Dci The device context index of the target slot or endpoint.
1886 @retval EFI_SUCCESS Successfully ring the door bell.
1892 IN USB_XHCI_INSTANCE
*Xhc
,
1898 XhcWriteDoorBellReg (Xhc
, 0, 0);
1900 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1907 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1909 @param Xhc The XHCI Instance.
1910 @param Urb The URB to be rung.
1912 @retval EFI_SUCCESS Successfully ring the door bell.
1916 RingIntTransferDoorBell (
1917 IN USB_XHCI_INSTANCE
*Xhc
,
1924 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1925 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1926 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1931 Assign and initialize the device slot for a new device.
1933 @param Xhc The XHCI Instance.
1934 @param ParentRouteChart The route string pointed to the parent device.
1935 @param ParentPort The port at which the device is located.
1936 @param RouteChart The route string pointed to the device.
1937 @param DeviceSpeed The device speed.
1939 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1944 XhcInitializeDeviceSlot (
1945 IN USB_XHCI_INSTANCE
*Xhc
,
1946 IN USB_DEV_ROUTE ParentRouteChart
,
1947 IN UINT16 ParentPort
,
1948 IN USB_DEV_ROUTE RouteChart
,
1949 IN UINT8 DeviceSpeed
1953 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1954 INPUT_CONTEXT
*InputContext
;
1955 DEVICE_CONTEXT
*OutputContext
;
1956 TRANSFER_RING
*EndpointTransferRing
;
1957 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1958 UINT8 DeviceAddress
;
1959 CMD_TRB_ENABLE_SLOT CmdTrb
;
1962 DEVICE_CONTEXT
*ParentDeviceContext
;
1963 EFI_PHYSICAL_ADDRESS PhyAddr
;
1965 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1966 CmdTrb
.CycleBit
= 1;
1967 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1969 Status
= XhcCmdTransfer (
1971 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1972 XHC_GENERIC_TIMEOUT
,
1973 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1975 if (EFI_ERROR (Status
)) {
1976 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
1979 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1980 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1981 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1982 ASSERT (SlotId
!= 0);
1984 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1985 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1986 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1987 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1988 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1991 // 4.3.3 Device Slot Initialization
1992 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1994 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
1995 ASSERT (InputContext
!= NULL
);
1996 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1997 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1999 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2002 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2003 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2004 // Context are affected by the command.
2006 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2009 // 3) Initialize the Input Slot Context data structure
2011 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2012 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2013 InputContext
->Slot
.ContextEntries
= 1;
2014 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2016 if (RouteChart
.Route
.RouteString
) {
2018 // The device is behind of hub device.
2020 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2021 ASSERT (ParentSlotId
!= 0);
2023 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2025 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2026 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2027 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2028 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2030 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2031 // environment from Full/Low speed signaling environment for a device
2033 InputContext
->Slot
.TTPortNum
= ParentPort
;
2034 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2038 // Inherit the TT parameters from parent device.
2040 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2041 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2043 // If the device is a High speed device then down the speed to be the same as its parent Hub
2045 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2046 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2052 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2054 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2055 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2056 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2058 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2060 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2062 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2063 InputContext
->EP
[0].MaxPacketSize
= 512;
2064 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2065 InputContext
->EP
[0].MaxPacketSize
= 64;
2067 InputContext
->EP
[0].MaxPacketSize
= 8;
2070 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2071 // 1KB, and Bulk and Isoch endpoints 3KB.
2073 InputContext
->EP
[0].AverageTRBLength
= 8;
2074 InputContext
->EP
[0].MaxBurstSize
= 0;
2075 InputContext
->EP
[0].Interval
= 0;
2076 InputContext
->EP
[0].MaxPStreams
= 0;
2077 InputContext
->EP
[0].Mult
= 0;
2078 InputContext
->EP
[0].CErr
= 3;
2081 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2083 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2085 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2086 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2088 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2089 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2092 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2094 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
2095 ASSERT (OutputContext
!= NULL
);
2096 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2097 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
2099 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2101 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2102 // a pointer to the Output Device Context data structure (6.2.1).
2104 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
2106 // Fill DCBAA with PCI device address
2108 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2111 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2112 // Context data structure described above.
2114 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2115 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2116 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2117 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2118 CmdTrbAddr
.CycleBit
= 1;
2119 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2120 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2121 Status
= XhcCmdTransfer (
2123 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2124 XHC_GENERIC_TIMEOUT
,
2125 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2127 if (!EFI_ERROR (Status
)) {
2128 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
2129 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2130 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2137 Assign and initialize the device slot for a new device.
2139 @param Xhc The XHCI Instance.
2140 @param ParentRouteChart The route string pointed to the parent device.
2141 @param ParentPort The port at which the device is located.
2142 @param RouteChart The route string pointed to the device.
2143 @param DeviceSpeed The device speed.
2145 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2150 XhcInitializeDeviceSlot64 (
2151 IN USB_XHCI_INSTANCE
*Xhc
,
2152 IN USB_DEV_ROUTE ParentRouteChart
,
2153 IN UINT16 ParentPort
,
2154 IN USB_DEV_ROUTE RouteChart
,
2155 IN UINT8 DeviceSpeed
2159 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2160 INPUT_CONTEXT_64
*InputContext
;
2161 DEVICE_CONTEXT_64
*OutputContext
;
2162 TRANSFER_RING
*EndpointTransferRing
;
2163 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2164 UINT8 DeviceAddress
;
2165 CMD_TRB_ENABLE_SLOT CmdTrb
;
2168 DEVICE_CONTEXT_64
*ParentDeviceContext
;
2169 EFI_PHYSICAL_ADDRESS PhyAddr
;
2171 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2172 CmdTrb
.CycleBit
= 1;
2173 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2175 Status
= XhcCmdTransfer (
2177 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2178 XHC_GENERIC_TIMEOUT
,
2179 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2181 if (EFI_ERROR (Status
)) {
2182 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
2185 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2186 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2187 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2188 ASSERT (SlotId
!= 0);
2190 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2191 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2192 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2193 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2194 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2197 // 4.3.3 Device Slot Initialization
2198 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2200 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
2201 ASSERT (InputContext
!= NULL
);
2202 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2203 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2205 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2208 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2209 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2210 // Context are affected by the command.
2212 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2215 // 3) Initialize the Input Slot Context data structure
2217 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2218 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2219 InputContext
->Slot
.ContextEntries
= 1;
2220 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2222 if (RouteChart
.Route
.RouteString
) {
2224 // The device is behind of hub device.
2226 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2227 ASSERT (ParentSlotId
!= 0);
2229 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2231 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2232 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2233 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2234 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2236 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2237 // environment from Full/Low speed signaling environment for a device
2239 InputContext
->Slot
.TTPortNum
= ParentPort
;
2240 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2244 // Inherit the TT parameters from parent device.
2246 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2247 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2249 // If the device is a High speed device then down the speed to be the same as its parent Hub
2251 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2252 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2258 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2260 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2261 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2262 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2264 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2266 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2268 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2269 InputContext
->EP
[0].MaxPacketSize
= 512;
2270 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2271 InputContext
->EP
[0].MaxPacketSize
= 64;
2273 InputContext
->EP
[0].MaxPacketSize
= 8;
2276 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2277 // 1KB, and Bulk and Isoch endpoints 3KB.
2279 InputContext
->EP
[0].AverageTRBLength
= 8;
2280 InputContext
->EP
[0].MaxBurstSize
= 0;
2281 InputContext
->EP
[0].Interval
= 0;
2282 InputContext
->EP
[0].MaxPStreams
= 0;
2283 InputContext
->EP
[0].Mult
= 0;
2284 InputContext
->EP
[0].CErr
= 3;
2287 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2289 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2291 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2292 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2294 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2295 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2298 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2300 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
2301 ASSERT (OutputContext
!= NULL
);
2302 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2303 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2305 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2307 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2308 // a pointer to the Output Device Context data structure (6.2.1).
2310 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2312 // Fill DCBAA with PCI device address
2314 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2317 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2318 // Context data structure described above.
2320 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2321 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2322 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2323 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2324 CmdTrbAddr
.CycleBit
= 1;
2325 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2326 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2327 Status
= XhcCmdTransfer (
2329 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2330 XHC_GENERIC_TIMEOUT
,
2331 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2333 if (!EFI_ERROR (Status
)) {
2334 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT_64
*) OutputContext
)->Slot
.DeviceAddress
;
2335 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2336 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2343 Disable the specified device slot.
2345 @param Xhc The XHCI Instance.
2346 @param SlotId The slot id to be disabled.
2348 @retval EFI_SUCCESS Successfully disable the device slot.
2354 IN USB_XHCI_INSTANCE
*Xhc
,
2359 TRB_TEMPLATE
*EvtTrb
;
2360 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2365 // Disable the device slots occupied by these devices on its downstream ports.
2366 // Entry 0 is reserved.
2368 for (Index
= 0; Index
< 255; Index
++) {
2369 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2370 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2371 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2375 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2377 if (EFI_ERROR (Status
)) {
2378 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2379 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2384 // Construct the disable slot command
2386 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2388 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2389 CmdTrbDisSlot
.CycleBit
= 1;
2390 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2391 CmdTrbDisSlot
.SlotId
= SlotId
;
2392 Status
= XhcCmdTransfer (
2394 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2395 XHC_GENERIC_TIMEOUT
,
2396 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2398 if (EFI_ERROR (Status
)) {
2399 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2403 // Free the slot's device context entry
2405 Xhc
->DCBAA
[SlotId
] = 0;
2408 // Free the slot related data structure
2410 for (Index
= 0; Index
< 31; Index
++) {
2411 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2412 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2413 if (RingSeg
!= NULL
) {
2414 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2416 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2417 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2421 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2422 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2423 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2427 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2428 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2431 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2432 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2435 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2436 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
2439 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2440 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2441 // remove urb from XHCI's asynchronous transfer list.
2443 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2444 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2450 Disable the specified device slot.
2452 @param Xhc The XHCI Instance.
2453 @param SlotId The slot id to be disabled.
2455 @retval EFI_SUCCESS Successfully disable the device slot.
2460 XhcDisableSlotCmd64 (
2461 IN USB_XHCI_INSTANCE
*Xhc
,
2466 TRB_TEMPLATE
*EvtTrb
;
2467 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2472 // Disable the device slots occupied by these devices on its downstream ports.
2473 // Entry 0 is reserved.
2475 for (Index
= 0; Index
< 255; Index
++) {
2476 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2477 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2478 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2482 Status
= XhcDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2484 if (EFI_ERROR (Status
)) {
2485 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2486 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2491 // Construct the disable slot command
2493 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2495 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2496 CmdTrbDisSlot
.CycleBit
= 1;
2497 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2498 CmdTrbDisSlot
.SlotId
= SlotId
;
2499 Status
= XhcCmdTransfer (
2501 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2502 XHC_GENERIC_TIMEOUT
,
2503 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2505 if (EFI_ERROR (Status
)) {
2506 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2510 // Free the slot's device context entry
2512 Xhc
->DCBAA
[SlotId
] = 0;
2515 // Free the slot related data structure
2517 for (Index
= 0; Index
< 31; Index
++) {
2518 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2519 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2520 if (RingSeg
!= NULL
) {
2521 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2523 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2524 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2528 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2529 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2530 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2534 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2535 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2538 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2539 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2542 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2543 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2546 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2547 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2548 // remove urb from XHCI's asynchronous transfer list.
2550 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2551 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2557 Initialize endpoint context in input context.
2559 @param Xhc The XHCI Instance.
2560 @param SlotId The slot id to be configured.
2561 @param DeviceSpeed The device's speed.
2562 @param InputContext The pointer to the input context.
2563 @param IfDesc The pointer to the usb device interface descriptor.
2565 @return The maximum device context index of endpoint.
2570 XhcInitializeEndpointContext (
2571 IN USB_XHCI_INSTANCE
*Xhc
,
2573 IN UINT8 DeviceSpeed
,
2574 IN INPUT_CONTEXT
*InputContext
,
2575 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2578 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2585 EFI_PHYSICAL_ADDRESS PhyAddr
;
2587 TRANSFER_RING
*EndpointTransferRing
;
2591 NumEp
= IfDesc
->NumEndpoints
;
2593 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2594 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2595 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2596 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2599 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2600 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2602 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2608 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2609 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2611 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2613 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2615 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2617 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2620 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2621 case USB_ENDPOINT_BULK
:
2622 if (Direction
== EfiUsbDataIn
) {
2623 InputContext
->EP
[Dci
-1].CErr
= 3;
2624 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2626 InputContext
->EP
[Dci
-1].CErr
= 3;
2627 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2630 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2631 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2632 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2633 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2634 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2638 case USB_ENDPOINT_ISO
:
2639 if (Direction
== EfiUsbDataIn
) {
2640 InputContext
->EP
[Dci
-1].CErr
= 0;
2641 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2643 InputContext
->EP
[Dci
-1].CErr
= 0;
2644 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2647 // Do not support isochronous transfer now.
2649 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2650 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2652 case USB_ENDPOINT_INTERRUPT
:
2653 if (Direction
== EfiUsbDataIn
) {
2654 InputContext
->EP
[Dci
-1].CErr
= 3;
2655 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2657 InputContext
->EP
[Dci
-1].CErr
= 3;
2658 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2660 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2661 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2663 // Get the bInterval from descriptor and init the the interval field of endpoint context
2665 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2666 Interval
= EpDesc
->Interval
;
2668 // Calculate through the bInterval field of Endpoint descriptor.
2670 ASSERT (Interval
!= 0);
2671 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2672 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2673 Interval
= EpDesc
->Interval
;
2674 ASSERT (Interval
>= 1 && Interval
<= 16);
2676 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2678 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2679 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2680 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2681 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2682 InputContext
->EP
[Dci
-1].CErr
= 3;
2685 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2686 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2687 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2688 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2692 case USB_ENDPOINT_CONTROL
:
2694 // Do not support control transfer now.
2696 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2698 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2699 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2703 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2705 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2706 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2708 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2709 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2710 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2711 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2713 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2720 Initialize endpoint context in input context.
2722 @param Xhc The XHCI Instance.
2723 @param SlotId The slot id to be configured.
2724 @param DeviceSpeed The device's speed.
2725 @param InputContext The pointer to the input context.
2726 @param IfDesc The pointer to the usb device interface descriptor.
2728 @return The maximum device context index of endpoint.
2733 XhcInitializeEndpointContext64 (
2734 IN USB_XHCI_INSTANCE
*Xhc
,
2736 IN UINT8 DeviceSpeed
,
2737 IN INPUT_CONTEXT_64
*InputContext
,
2738 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2741 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2748 EFI_PHYSICAL_ADDRESS PhyAddr
;
2750 TRANSFER_RING
*EndpointTransferRing
;
2754 NumEp
= IfDesc
->NumEndpoints
;
2756 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2757 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2758 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2759 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2762 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2763 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2765 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2771 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2772 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2774 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2776 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2778 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2780 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2783 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2784 case USB_ENDPOINT_BULK
:
2785 if (Direction
== EfiUsbDataIn
) {
2786 InputContext
->EP
[Dci
-1].CErr
= 3;
2787 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2789 InputContext
->EP
[Dci
-1].CErr
= 3;
2790 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2793 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2794 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2795 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2796 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2797 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2801 case USB_ENDPOINT_ISO
:
2802 if (Direction
== EfiUsbDataIn
) {
2803 InputContext
->EP
[Dci
-1].CErr
= 0;
2804 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2806 InputContext
->EP
[Dci
-1].CErr
= 0;
2807 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2810 // Do not support isochronous transfer now.
2812 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2813 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2815 case USB_ENDPOINT_INTERRUPT
:
2816 if (Direction
== EfiUsbDataIn
) {
2817 InputContext
->EP
[Dci
-1].CErr
= 3;
2818 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2820 InputContext
->EP
[Dci
-1].CErr
= 3;
2821 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2823 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2824 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2826 // Get the bInterval from descriptor and init the the interval field of endpoint context
2828 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2829 Interval
= EpDesc
->Interval
;
2831 // Calculate through the bInterval field of Endpoint descriptor.
2833 ASSERT (Interval
!= 0);
2834 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2835 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2836 Interval
= EpDesc
->Interval
;
2837 ASSERT (Interval
>= 1 && Interval
<= 16);
2839 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2841 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2842 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2843 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2844 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2845 InputContext
->EP
[Dci
-1].CErr
= 3;
2848 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2849 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2850 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2851 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2855 case USB_ENDPOINT_CONTROL
:
2857 // Do not support control transfer now.
2859 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2861 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
2862 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2866 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2868 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2869 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2871 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2872 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2873 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2874 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2876 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2883 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2885 @param Xhc The XHCI Instance.
2886 @param SlotId The slot id to be configured.
2887 @param DeviceSpeed The device's speed.
2888 @param ConfigDesc The pointer to the usb device configuration descriptor.
2890 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2896 IN USB_XHCI_INSTANCE
*Xhc
,
2898 IN UINT8 DeviceSpeed
,
2899 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
2903 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
2907 EFI_PHYSICAL_ADDRESS PhyAddr
;
2909 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2910 INPUT_CONTEXT
*InputContext
;
2911 DEVICE_CONTEXT
*OutputContext
;
2912 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2914 // 4.6.6 Configure Endpoint
2916 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2917 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2918 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2919 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
2921 ASSERT (ConfigDesc
!= NULL
);
2925 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
2926 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
2927 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
2928 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2931 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
2936 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2939 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2940 InputContext
->Slot
.ContextEntries
= MaxDci
;
2942 // configure endpoint
2944 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2945 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2946 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2947 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2948 CmdTrbCfgEP
.CycleBit
= 1;
2949 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2950 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2951 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
2952 Status
= XhcCmdTransfer (
2954 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2955 XHC_GENERIC_TIMEOUT
,
2956 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2958 if (EFI_ERROR (Status
)) {
2959 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
2961 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
2968 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2970 @param Xhc The XHCI Instance.
2971 @param SlotId The slot id to be configured.
2972 @param DeviceSpeed The device's speed.
2973 @param ConfigDesc The pointer to the usb device configuration descriptor.
2975 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2981 IN USB_XHCI_INSTANCE
*Xhc
,
2983 IN UINT8 DeviceSpeed
,
2984 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
2988 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
2992 EFI_PHYSICAL_ADDRESS PhyAddr
;
2994 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2995 INPUT_CONTEXT_64
*InputContext
;
2996 DEVICE_CONTEXT_64
*OutputContext
;
2997 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2999 // 4.6.6 Configure Endpoint
3001 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3002 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3003 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3004 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3006 ASSERT (ConfigDesc
!= NULL
);
3010 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3011 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
3012 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
3013 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3016 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
3021 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3024 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3025 InputContext
->Slot
.ContextEntries
= MaxDci
;
3027 // configure endpoint
3029 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3030 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3031 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3032 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3033 CmdTrbCfgEP
.CycleBit
= 1;
3034 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3035 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3036 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3037 Status
= XhcCmdTransfer (
3039 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3040 XHC_GENERIC_TIMEOUT
,
3041 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3043 if (EFI_ERROR (Status
)) {
3044 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
3046 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3053 Stop endpoint through XHCI's Stop_Endpoint cmd.
3055 @param Xhc The XHCI Instance.
3056 @param SlotId The slot id to be configured.
3057 @param Dci The device context index of endpoint.
3059 @retval EFI_SUCCESS Stop endpoint successfully.
3060 @retval Others Failed to stop endpoint.
3066 IN USB_XHCI_INSTANCE
*Xhc
,
3072 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3073 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
3075 DEBUG ((EFI_D_INFO
, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3078 // Send stop endpoint command to transit Endpoint from running to stop state
3080 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
3081 CmdTrbStopED
.CycleBit
= 1;
3082 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
3083 CmdTrbStopED
.EDID
= Dci
;
3084 CmdTrbStopED
.SlotId
= SlotId
;
3085 Status
= XhcCmdTransfer (
3087 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbStopED
,
3088 XHC_GENERIC_TIMEOUT
,
3089 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3091 if (EFI_ERROR(Status
)) {
3092 DEBUG ((EFI_D_ERROR
, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
3099 Reset endpoint through XHCI's Reset_Endpoint cmd.
3101 @param Xhc The XHCI Instance.
3102 @param SlotId The slot id to be configured.
3103 @param Dci The device context index of endpoint.
3105 @retval EFI_SUCCESS Reset endpoint successfully.
3106 @retval Others Failed to reset endpoint.
3112 IN USB_XHCI_INSTANCE
*Xhc
,
3118 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3119 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
3121 DEBUG ((EFI_D_INFO
, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3124 // Send stop endpoint command to transit Endpoint from running to stop state
3126 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
3127 CmdTrbResetED
.CycleBit
= 1;
3128 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
3129 CmdTrbResetED
.EDID
= Dci
;
3130 CmdTrbResetED
.SlotId
= SlotId
;
3131 Status
= XhcCmdTransfer (
3133 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
3134 XHC_GENERIC_TIMEOUT
,
3135 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3137 if (EFI_ERROR(Status
)) {
3138 DEBUG ((EFI_D_ERROR
, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
3145 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.
3147 @param Xhc The XHCI Instance.
3148 @param SlotId The slot id to be configured.
3149 @param Dci The device context index of endpoint.
3150 @param Urb The dequeue pointer of the transfer ring specified
3151 by the urb to be updated.
3153 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.
3154 @retval Others Failed to set transfer ring dequeue pointer.
3159 XhcSetTrDequeuePointer (
3160 IN USB_XHCI_INSTANCE
*Xhc
,
3167 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3168 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
3169 EFI_PHYSICAL_ADDRESS PhyAddr
;
3171 DEBUG ((EFI_D_INFO
, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId
, Dci
, Urb
));
3174 // Send stop endpoint command to transit Endpoint from running to stop state
3176 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
3177 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
3178 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
3179 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3180 CmdSetTRDeq
.CycleBit
= 1;
3181 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
3182 CmdSetTRDeq
.Endpoint
= Dci
;
3183 CmdSetTRDeq
.SlotId
= SlotId
;
3184 Status
= XhcCmdTransfer (
3186 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
3187 XHC_GENERIC_TIMEOUT
,
3188 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3190 if (EFI_ERROR(Status
)) {
3191 DEBUG ((EFI_D_ERROR
, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status
));
3198 Set interface through XHCI's Configure_Endpoint cmd.
3200 @param Xhc The XHCI Instance.
3201 @param SlotId The slot id to be configured.
3202 @param DeviceSpeed The device's speed.
3203 @param ConfigDesc The pointer to the usb device configuration descriptor.
3204 @param Request USB device request to send.
3206 @retval EFI_SUCCESS Successfully set interface.
3212 IN USB_XHCI_INSTANCE
*Xhc
,
3214 IN UINT8 DeviceSpeed
,
3215 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3216 IN EFI_USB_DEVICE_REQUEST
*Request
3220 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3221 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3222 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3223 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3230 EFI_PHYSICAL_ADDRESS PhyAddr
;
3233 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3234 INPUT_CONTEXT
*InputContext
;
3235 DEVICE_CONTEXT
*OutputContext
;
3236 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3238 Status
= EFI_SUCCESS
;
3240 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3241 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3243 // XHCI 4.6.6 Configure Endpoint
3244 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3245 // Context and Add Context flags as follows:
3246 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3247 // Context and Add Context flags to '0'.
3249 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3250 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3252 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3253 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3255 ASSERT (ConfigDesc
!= NULL
);
3259 IfDescActive
= NULL
;
3262 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3263 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3264 if (IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) {
3265 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3266 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3268 // Find out the active interface descriptor.
3270 IfDescActive
= IfDesc
;
3271 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3273 // Find out the interface descriptor to set.
3279 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3283 // XHCI 4.6.6 Configure Endpoint
3284 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3285 // Context and Add Context flags as follows:
3286 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3287 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3288 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3289 // the Drop Context flag to '1' and Add Context flag to '0'.
3290 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3291 // and Add Context flags shall be set to '1'.
3293 // Below codes are to cover 2), 3) and 4).
3296 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3297 NumEp
= IfDescActive
->NumEndpoints
;
3298 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3299 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3300 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3301 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3304 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3305 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3307 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3313 // XHCI 4.3.6 - Setting Alternate Interfaces
3314 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3316 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
);
3317 if (EFI_ERROR (Status
)) {
3321 // XHCI 4.3.6 - Setting Alternate Interfaces
3322 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3324 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3325 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3326 if (RingSeg
!= NULL
) {
3327 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3329 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3330 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3334 // Set the Drop Context flag to '1'.
3336 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3338 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3342 // XHCI 4.3.6 - Setting Alternate Interfaces
3343 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3344 // Interface setting, to '0'.
3346 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3350 // XHCI 4.3.6 - Setting Alternate Interfaces
3351 // 4) For each endpoint enabled by the Configure Endpoint Command:
3352 // a. Allocate a Transfer Ring.
3353 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3354 // c. Initialize the Endpoint Context data structure.
3356 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3361 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3362 InputContext
->Slot
.ContextEntries
= MaxDci
;
3364 // XHCI 4.3.6 - Setting Alternate Interfaces
3365 // 5) Issue and successfully complete a Configure Endpoint Command.
3367 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3368 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3369 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3370 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3371 CmdTrbCfgEP
.CycleBit
= 1;
3372 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3373 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3374 DEBUG ((EFI_D_INFO
, "SetInterface: Configure Endpoint\n"));
3375 Status
= XhcCmdTransfer (
3377 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3378 XHC_GENERIC_TIMEOUT
,
3379 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3381 if (EFI_ERROR (Status
)) {
3382 DEBUG ((EFI_D_ERROR
, "SetInterface: Config Endpoint Failed, Status = %r\n", Status
));
3385 // Update the active AlternateSetting.
3387 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3395 Set interface through XHCI's Configure_Endpoint cmd.
3397 @param Xhc The XHCI Instance.
3398 @param SlotId The slot id to be configured.
3399 @param DeviceSpeed The device's speed.
3400 @param ConfigDesc The pointer to the usb device configuration descriptor.
3401 @param Request USB device request to send.
3403 @retval EFI_SUCCESS Successfully set interface.
3409 IN USB_XHCI_INSTANCE
*Xhc
,
3411 IN UINT8 DeviceSpeed
,
3412 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3413 IN EFI_USB_DEVICE_REQUEST
*Request
3417 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3418 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3419 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3420 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3427 EFI_PHYSICAL_ADDRESS PhyAddr
;
3430 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3431 INPUT_CONTEXT_64
*InputContext
;
3432 DEVICE_CONTEXT_64
*OutputContext
;
3433 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3435 Status
= EFI_SUCCESS
;
3437 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3438 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3440 // XHCI 4.6.6 Configure Endpoint
3441 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3442 // Context and Add Context flags as follows:
3443 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3444 // Context and Add Context flags to '0'.
3446 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3447 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3449 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3450 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3452 ASSERT (ConfigDesc
!= NULL
);
3456 IfDescActive
= NULL
;
3459 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3460 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3461 if (IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) {
3462 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3463 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3465 // Find out the active interface descriptor.
3467 IfDescActive
= IfDesc
;
3468 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3470 // Find out the interface descriptor to set.
3476 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3480 // XHCI 4.6.6 Configure Endpoint
3481 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3482 // Context and Add Context flags as follows:
3483 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3484 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3485 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3486 // the Drop Context flag to '1' and Add Context flag to '0'.
3487 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3488 // and Add Context flags shall be set to '1'.
3490 // Below codes are to cover 2), 3) and 4).
3493 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3494 NumEp
= IfDescActive
->NumEndpoints
;
3495 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3496 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3497 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3498 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3501 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3502 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3504 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3510 // XHCI 4.3.6 - Setting Alternate Interfaces
3511 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3513 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
);
3514 if (EFI_ERROR (Status
)) {
3518 // XHCI 4.3.6 - Setting Alternate Interfaces
3519 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3521 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3522 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3523 if (RingSeg
!= NULL
) {
3524 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3526 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3527 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3531 // Set the Drop Context flag to '1'.
3533 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3535 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3539 // XHCI 4.3.6 - Setting Alternate Interfaces
3540 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3541 // Interface setting, to '0'.
3543 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3547 // XHCI 4.3.6 - Setting Alternate Interfaces
3548 // 4) For each endpoint enabled by the Configure Endpoint Command:
3549 // a. Allocate a Transfer Ring.
3550 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3551 // c. Initialize the Endpoint Context data structure.
3553 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3558 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3559 InputContext
->Slot
.ContextEntries
= MaxDci
;
3561 // XHCI 4.3.6 - Setting Alternate Interfaces
3562 // 5) Issue and successfully complete a Configure Endpoint Command.
3564 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3565 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3566 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3567 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3568 CmdTrbCfgEP
.CycleBit
= 1;
3569 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3570 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3571 DEBUG ((EFI_D_INFO
, "SetInterface64: Configure Endpoint\n"));
3572 Status
= XhcCmdTransfer (
3574 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3575 XHC_GENERIC_TIMEOUT
,
3576 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3578 if (EFI_ERROR (Status
)) {
3579 DEBUG ((EFI_D_ERROR
, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status
));
3582 // Update the active AlternateSetting.
3584 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3592 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3594 @param Xhc The XHCI Instance.
3595 @param SlotId The slot id to be evaluated.
3596 @param MaxPacketSize The max packet size supported by the device control transfer.
3598 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3603 XhcEvaluateContext (
3604 IN USB_XHCI_INSTANCE
*Xhc
,
3606 IN UINT32 MaxPacketSize
3610 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3611 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3612 INPUT_CONTEXT
*InputContext
;
3613 EFI_PHYSICAL_ADDRESS PhyAddr
;
3615 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3618 // 4.6.7 Evaluate Context
3620 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3621 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3623 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3624 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3626 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3627 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3628 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3629 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3630 CmdTrbEvalu
.CycleBit
= 1;
3631 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3632 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3633 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3634 Status
= XhcCmdTransfer (
3636 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3637 XHC_GENERIC_TIMEOUT
,
3638 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3640 if (EFI_ERROR (Status
)) {
3641 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
3647 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3649 @param Xhc The XHCI Instance.
3650 @param SlotId The slot id to be evaluated.
3651 @param MaxPacketSize The max packet size supported by the device control transfer.
3653 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3658 XhcEvaluateContext64 (
3659 IN USB_XHCI_INSTANCE
*Xhc
,
3661 IN UINT32 MaxPacketSize
3665 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3666 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3667 INPUT_CONTEXT_64
*InputContext
;
3668 EFI_PHYSICAL_ADDRESS PhyAddr
;
3670 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3673 // 4.6.7 Evaluate Context
3675 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3676 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3678 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3679 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3681 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3682 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3683 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3684 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3685 CmdTrbEvalu
.CycleBit
= 1;
3686 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3687 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3688 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3689 Status
= XhcCmdTransfer (
3691 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3692 XHC_GENERIC_TIMEOUT
,
3693 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3695 if (EFI_ERROR (Status
)) {
3696 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
3703 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3705 @param Xhc The XHCI Instance.
3706 @param SlotId The slot id to be configured.
3707 @param PortNum The total number of downstream port supported by the hub.
3708 @param TTT The TT think time of the hub device.
3709 @param MTT The multi-TT of the hub device.
3711 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3715 XhcConfigHubContext (
3716 IN USB_XHCI_INSTANCE
*Xhc
,
3724 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3725 INPUT_CONTEXT
*InputContext
;
3726 DEVICE_CONTEXT
*OutputContext
;
3727 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3728 EFI_PHYSICAL_ADDRESS PhyAddr
;
3730 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3731 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3732 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3735 // 4.6.7 Evaluate Context
3737 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3739 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3742 // Copy the slot context from OutputContext to Input context
3744 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
3745 InputContext
->Slot
.Hub
= 1;
3746 InputContext
->Slot
.PortNum
= PortNum
;
3747 InputContext
->Slot
.TTT
= TTT
;
3748 InputContext
->Slot
.MTT
= MTT
;
3750 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3751 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3752 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3753 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3754 CmdTrbCfgEP
.CycleBit
= 1;
3755 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3756 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3757 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
3758 Status
= XhcCmdTransfer (
3760 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3761 XHC_GENERIC_TIMEOUT
,
3762 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3764 if (EFI_ERROR (Status
)) {
3765 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
3771 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3773 @param Xhc The XHCI Instance.
3774 @param SlotId The slot id to be configured.
3775 @param PortNum The total number of downstream port supported by the hub.
3776 @param TTT The TT think time of the hub device.
3777 @param MTT The multi-TT of the hub device.
3779 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3783 XhcConfigHubContext64 (
3784 IN USB_XHCI_INSTANCE
*Xhc
,
3792 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3793 INPUT_CONTEXT_64
*InputContext
;
3794 DEVICE_CONTEXT_64
*OutputContext
;
3795 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3796 EFI_PHYSICAL_ADDRESS PhyAddr
;
3798 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3799 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3800 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3803 // 4.6.7 Evaluate Context
3805 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3807 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3810 // Copy the slot context from OutputContext to Input context
3812 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
3813 InputContext
->Slot
.Hub
= 1;
3814 InputContext
->Slot
.PortNum
= PortNum
;
3815 InputContext
->Slot
.TTT
= TTT
;
3816 InputContext
->Slot
.MTT
= MTT
;
3818 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3819 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3820 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3821 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3822 CmdTrbCfgEP
.CycleBit
= 1;
3823 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3824 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3825 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
3826 Status
= XhcCmdTransfer (
3828 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3829 XHC_GENERIC_TIMEOUT
,
3830 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3832 if (EFI_ERROR (Status
)) {
3833 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));