3 XHCI transfer scheduling routines.
5 Copyright (c) 2011 - 2012, 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
;
50 Urb
->EvtRing
= &Xhc
->EventRing
;
51 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
52 Urb
->EvtTrbStart
= Urb
->EvtRing
->EventRingEnqueue
;
58 Execute a XHCI cmd TRB pointed by CmdTrb.
60 @param Xhc The XHCI Instance.
61 @param CmdTrb The cmd TRB to be executed.
62 @param Timeout Indicates the maximum time, in millisecond, which the
63 transfer is allowed to complete.
64 @param EvtTrb The event TRB corresponding to the cmd TRB.
66 @retval EFI_SUCCESS The transfer was completed successfully.
67 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
68 @retval EFI_TIMEOUT The transfer failed due to timeout.
69 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
75 IN USB_XHCI_INSTANCE
*Xhc
,
76 IN TRB_TEMPLATE
*CmdTrb
,
78 OUT TRB_TEMPLATE
**EvtTrb
85 // Validate the parameters
87 if ((Xhc
== NULL
) || (CmdTrb
== NULL
)) {
88 return EFI_INVALID_PARAMETER
;
91 Status
= EFI_DEVICE_ERROR
;
93 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
94 DEBUG ((EFI_D_ERROR
, "XhcCmdTransfer: HC is halted\n"));
99 // Create a new URB, then poll the execution status.
101 Urb
= XhcCreateCmdTrb (Xhc
, CmdTrb
);
104 DEBUG ((EFI_D_ERROR
, "XhcCmdTransfer: failed to create URB\n"));
105 Status
= EFI_OUT_OF_RESOURCES
;
109 ASSERT (Urb
->EvtRing
== &Xhc
->EventRing
);
111 Status
= XhcExecTransfer (Xhc
, TRUE
, Urb
, Timeout
);
112 *EvtTrb
= Urb
->EvtTrbStart
;
114 if (Urb
->Result
== EFI_USB_NOERROR
) {
115 Status
= EFI_SUCCESS
;
125 Create a new URB for a new transaction.
127 @param Xhc The XHCI Instance
128 @param BusAddr The logical device address assigned by UsbBus driver
129 @param EpAddr Endpoint addrress
130 @param DevSpeed The device speed
131 @param MaxPacket The max packet length of the endpoint
132 @param Type The transaction type
133 @param Request The standard USB request for control transfer
134 @param Data The user data to transfer
135 @param DataLen The length of data buffer
136 @param Callback The function to call when data is transferred
137 @param Context The context to the callback
139 @return Created URB or NULL
144 IN USB_XHCI_INSTANCE
*Xhc
,
150 IN EFI_USB_DEVICE_REQUEST
*Request
,
153 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
161 Urb
= AllocateZeroPool (sizeof (URB
));
166 Urb
->Signature
= XHC_URB_SIG
;
167 InitializeListHead (&Urb
->UrbList
);
170 Ep
->BusAddr
= BusAddr
;
171 Ep
->EpAddr
= (UINT8
)(EpAddr
& 0x0F);
172 Ep
->Direction
= ((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
173 Ep
->DevSpeed
= DevSpeed
;
174 Ep
->MaxPacket
= MaxPacket
;
177 Urb
->Request
= Request
;
179 Urb
->DataLen
= DataLen
;
180 Urb
->Callback
= Callback
;
181 Urb
->Context
= Context
;
183 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
184 ASSERT_EFI_ERROR (Status
);
190 Create a transfer TRB.
192 @param Xhc The XHCI Instance
193 @param Urb The urb used to construct the transfer TRB.
195 @return Created TRB or NULL
199 XhcCreateTransferTrb (
200 IN USB_XHCI_INSTANCE
*Xhc
,
205 TRANSFER_RING
*EPRing
;
214 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
216 return EFI_DEVICE_ERROR
;
219 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
221 EPRing
= (TRANSFER_RING
*)(UINTN
) Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1];
223 OutputContext
= (VOID
*)(UINTN
)Xhc
->DCBAA
[SlotId
];
224 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
225 EPType
= (UINT8
) ((DEVICE_CONTEXT
*)OutputContext
)->EP
[Dci
-1].EPType
;
227 EPType
= (UINT8
) ((DEVICE_CONTEXT_64
*)OutputContext
)->EP
[Dci
-1].EPType
;
233 XhcSyncTrsRing (Xhc
, EPRing
);
234 Urb
->TrbStart
= EPRing
->RingEnqueue
;
236 case ED_CONTROL_BIDIR
:
237 Urb
->EvtRing
= &Xhc
->EventRing
;
238 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
239 Urb
->EvtTrbStart
= Urb
->EvtRing
->EventRingEnqueue
;
241 // For control transfer, create SETUP_STAGE_TRB first.
243 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
244 TrbStart
->TrbCtrSetup
.bmRequestType
= Urb
->Request
->RequestType
;
245 TrbStart
->TrbCtrSetup
.bRequest
= Urb
->Request
->Request
;
246 TrbStart
->TrbCtrSetup
.wValue
= Urb
->Request
->Value
;
247 TrbStart
->TrbCtrSetup
.wIndex
= Urb
->Request
->Index
;
248 TrbStart
->TrbCtrSetup
.wLength
= Urb
->Request
->Length
;
249 TrbStart
->TrbCtrSetup
.Lenth
= 8;
250 TrbStart
->TrbCtrSetup
.IntTarget
= 0;
251 TrbStart
->TrbCtrSetup
.IOC
= 1;
252 TrbStart
->TrbCtrSetup
.IDT
= 1;
253 TrbStart
->TrbCtrSetup
.Type
= TRB_TYPE_SETUP_STAGE
;
254 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
255 TrbStart
->TrbCtrSetup
.TRT
= 3;
256 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
257 TrbStart
->TrbCtrSetup
.TRT
= 2;
259 TrbStart
->TrbCtrSetup
.TRT
= 0;
262 // Update the cycle bit
264 TrbStart
->TrbCtrSetup
.CycleBit
= EPRing
->RingPCS
& BIT0
;
268 // For control transfer, create DATA_STAGE_TRB.
270 if (Urb
->DataLen
> 0) {
271 XhcSyncTrsRing (Xhc
, EPRing
);
272 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
273 TrbStart
->TrbCtrData
.TRBPtrLo
= XHC_LOW_32BIT(Urb
->Data
);
274 TrbStart
->TrbCtrData
.TRBPtrHi
= XHC_HIGH_32BIT(Urb
->Data
);
275 TrbStart
->TrbCtrData
.Lenth
= (UINT32
) Urb
->DataLen
;
276 TrbStart
->TrbCtrData
.TDSize
= 0;
277 TrbStart
->TrbCtrData
.IntTarget
= 0;
278 TrbStart
->TrbCtrData
.ISP
= 1;
279 TrbStart
->TrbCtrData
.IOC
= 1;
280 TrbStart
->TrbCtrData
.IDT
= 0;
281 TrbStart
->TrbCtrData
.CH
= 0;
282 TrbStart
->TrbCtrData
.Type
= TRB_TYPE_DATA_STAGE
;
283 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
284 TrbStart
->TrbCtrData
.DIR = 1;
285 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
286 TrbStart
->TrbCtrData
.DIR = 0;
288 TrbStart
->TrbCtrData
.DIR = 0;
291 // Update the cycle bit
293 TrbStart
->TrbCtrData
.CycleBit
= EPRing
->RingPCS
& BIT0
;
297 // For control transfer, create STATUS_STAGE_TRB.
298 // Get the pointer to next TRB for status stage use
300 XhcSyncTrsRing (Xhc
, EPRing
);
301 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
302 TrbStart
->TrbCtrStatus
.IntTarget
= 0;
303 TrbStart
->TrbCtrStatus
.IOC
= 1;
304 TrbStart
->TrbCtrStatus
.CH
= 0;
305 TrbStart
->TrbCtrStatus
.Type
= TRB_TYPE_STATUS_STAGE
;
306 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
307 TrbStart
->TrbCtrStatus
.DIR = 0;
308 } else if (Urb
->Ep
.Direction
== EfiUsbDataOut
) {
309 TrbStart
->TrbCtrStatus
.DIR = 1;
311 TrbStart
->TrbCtrStatus
.DIR = 0;
314 // Update the cycle bit
316 TrbStart
->TrbCtrStatus
.CycleBit
= EPRing
->RingPCS
& BIT0
;
318 // Update the enqueue pointer
320 XhcSyncTrsRing (Xhc
, EPRing
);
322 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
328 Urb
->EvtRing
= &Xhc
->EventRing
;
329 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
330 Urb
->EvtTrbStart
= Urb
->EvtRing
->EventRingEnqueue
;
335 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
336 while (TotalLen
< Urb
->DataLen
) {
337 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
338 Len
= Urb
->DataLen
- TotalLen
;
342 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
343 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->Data
+ TotalLen
);
344 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->Data
+ TotalLen
);
345 TrbStart
->TrbNormal
.Lenth
= (UINT32
) Len
;
346 TrbStart
->TrbNormal
.TDSize
= 0;
347 TrbStart
->TrbNormal
.IntTarget
= 0;
348 TrbStart
->TrbNormal
.ISP
= 1;
349 TrbStart
->TrbNormal
.IOC
= 1;
350 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
352 // Update the cycle bit
354 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
356 XhcSyncTrsRing (Xhc
, EPRing
);
361 Urb
->TrbNum
= TrbNum
;
362 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
365 case ED_INTERRUPT_OUT
:
366 case ED_INTERRUPT_IN
:
367 Urb
->EvtRing
= &Xhc
->EventRing
;
368 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
369 Urb
->EvtTrbStart
= Urb
->EvtRing
->EventRingEnqueue
;
374 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
375 while (TotalLen
< Urb
->DataLen
) {
376 if ((TotalLen
+ 0x10000) >= Urb
->DataLen
) {
377 Len
= Urb
->DataLen
- TotalLen
;
381 TrbStart
= (TRB
*)(UINTN
)EPRing
->RingEnqueue
;
382 TrbStart
->TrbNormal
.TRBPtrLo
= XHC_LOW_32BIT((UINT8
*) Urb
->Data
+ TotalLen
);
383 TrbStart
->TrbNormal
.TRBPtrHi
= XHC_HIGH_32BIT((UINT8
*) Urb
->Data
+ TotalLen
);
384 TrbStart
->TrbNormal
.Lenth
= (UINT32
) Len
;
385 TrbStart
->TrbNormal
.TDSize
= 0;
386 TrbStart
->TrbNormal
.IntTarget
= 0;
387 TrbStart
->TrbNormal
.ISP
= 1;
388 TrbStart
->TrbNormal
.IOC
= 1;
389 TrbStart
->TrbNormal
.Type
= TRB_TYPE_NORMAL
;
391 // Update the cycle bit
393 TrbStart
->TrbNormal
.CycleBit
= EPRing
->RingPCS
& BIT0
;
395 XhcSyncTrsRing (Xhc
, EPRing
);
400 Urb
->TrbNum
= TrbNum
;
401 Urb
->TrbEnd
= (TRB_TEMPLATE
*)(UINTN
)TrbStart
;
405 DEBUG ((EFI_D_INFO
, "Not supported EPType 0x%x!\n",EPType
));
415 Initialize the XHCI host controller for schedule.
417 @param Xhc The XHCI Instance to be initialized.
422 IN USB_XHCI_INSTANCE
*Xhc
428 UINT32 MaxScratchpadBufs
;
430 UINT64
*ScratchEntryBuf
;
434 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)
435 // to enable the device slots that system software is going to use.
437 Xhc
->MaxSlotsEn
= Xhc
->HcSParams1
.Data
.MaxSlots
;
438 ASSERT (Xhc
->MaxSlotsEn
>= 1 && Xhc
->MaxSlotsEn
<= 255);
439 XhcWriteOpReg (Xhc
, XHC_CONFIG_OFFSET
, Xhc
->MaxSlotsEn
);
442 // The Device Context Base Address Array entry associated with each allocated Device Slot
443 // shall contain a 64-bit pointer to the base of the associated Device Context.
444 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.
445 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
447 Entries
= (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
);
448 Dcbaa
= AllocatePages (EFI_SIZE_TO_PAGES (Entries
));
449 ASSERT (Dcbaa
!= NULL
);
450 ZeroMem (Dcbaa
, Entries
);
453 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.
454 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run
455 // mode (Run/Stop(R/S) ='1').
457 MaxScratchpadBufs
= ((Xhc
->HcSParams2
.Data
.ScratchBufHi
) << 5) | (Xhc
->HcSParams2
.Data
.ScratchBufLo
);
458 Xhc
->MaxScratchpadBufs
= MaxScratchpadBufs
;
459 ASSERT (MaxScratchpadBufs
<= 1023);
460 if (MaxScratchpadBufs
!= 0) {
461 ScratchBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->PageSize
);
462 ASSERT (ScratchBuf
!= NULL
);
463 ZeroMem (ScratchBuf
, MaxScratchpadBufs
* sizeof (UINT64
));
464 Xhc
->ScratchBuf
= ScratchBuf
;
466 for (Index
= 0; Index
< MaxScratchpadBufs
; Index
++) {
467 ScratchEntryBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (Xhc
->PageSize
), Xhc
->PageSize
);
468 ASSERT (ScratchEntryBuf
!= NULL
);
469 ZeroMem (ScratchEntryBuf
, Xhc
->PageSize
);
470 *ScratchBuf
++ = (UINT64
)(UINTN
)ScratchEntryBuf
;
474 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the
475 // Device Context Base Address Array points to the Scratchpad Buffer Array.
477 *(UINT64
*)Dcbaa
= (UINT64
)(UINTN
)Xhc
->ScratchBuf
;
481 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with
482 // a 64-bit address pointing to where the Device Context Base Address Array is located.
484 Xhc
->DCBAA
= (UINT64
*)(UINTN
)Dcbaa
;
486 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
487 // So divide it to two 32-bytes width register access.
489 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
, XHC_LOW_32BIT(Xhc
->DCBAA
));
490 XhcWriteOpReg (Xhc
, XHC_DCBAAP_OFFSET
+ 4, XHC_HIGH_32BIT (Xhc
->DCBAA
));
491 DEBUG ((EFI_D_INFO
, "XhcInitSched:DCBAA=0x%x\n", (UINT64
)(UINTN
)Xhc
->DCBAA
));
494 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register
495 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.
496 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall
499 CreateTransferRing (Xhc
, CMD_RING_TRB_NUMBER
, &Xhc
->CmdRing
);
501 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a
502 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.
503 // So we set RCS as inverted PCS init value to let Command Ring empty
505 CmdRing
= (UINT64
)(UINTN
)Xhc
->CmdRing
.RingSeg0
;
506 ASSERT ((CmdRing
& 0x3F) == 0);
507 CmdRing
|= XHC_CRCR_RCS
;
509 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
510 // So divide it to two 32-bytes width register access.
512 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
, XHC_LOW_32BIT(CmdRing
));
513 XhcWriteOpReg (Xhc
, XHC_CRCR_OFFSET
+ 4, XHC_HIGH_32BIT (CmdRing
));
515 DEBUG ((EFI_D_INFO
, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc
->CmdRing
.RingSeg0
));
518 // Disable the 'interrupter enable' bit in USB_CMD
519 // and clear IE & IP bit in all Interrupter X Management Registers.
521 XhcClearOpRegBit (Xhc
, XHC_USBCMD_OFFSET
, XHC_USBCMD_INTE
);
522 for (Index
= 0; Index
< (UINT16
)(Xhc
->HcSParams1
.Data
.MaxIntrs
); Index
++) {
523 XhcClearRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IE
);
524 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
+ (Index
* 32), XHC_IMAN_IP
);
528 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer
530 CreateEventRing (Xhc
, &Xhc
->EventRing
);
531 DEBUG ((EFI_D_INFO
, "XhcInitSched:XHC_EVENTRING=0x%x\n", Xhc
->EventRing
.EventRingSeg0
));
535 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted
536 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint
537 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is
538 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the
539 Stopped to the Running state.
541 @param Xhc The XHCI Instance.
542 @param Urb The urb which makes the endpoint halted.
544 @retval EFI_SUCCESS The recovery is successful.
545 @retval Others Failed to recovery halted endpoint.
550 XhcRecoverHaltedEndpoint (
551 IN USB_XHCI_INSTANCE
*Xhc
,
556 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
557 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
558 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
562 Status
= EFI_SUCCESS
;
563 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
565 return EFI_DEVICE_ERROR
;
567 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
570 DEBUG ((EFI_D_INFO
, "Recovery Halted Slot = %x,Dci = %x\n", SlotId
, Dci
));
573 // 1) Send Reset endpoint command to transit from halt to stop state
575 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
576 CmdTrbResetED
.CycleBit
= 1;
577 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
578 CmdTrbResetED
.EDID
= Dci
;
579 CmdTrbResetED
.SlotId
= SlotId
;
580 Status
= XhcCmdTransfer (
582 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
584 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
586 ASSERT (!EFI_ERROR(Status
));
589 // 2)Set dequeue pointer
591 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
592 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (Urb
->Ring
->RingEnqueue
) | Urb
->Ring
->RingPCS
;
593 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (Urb
->Ring
->RingEnqueue
);
594 CmdSetTRDeq
.CycleBit
= 1;
595 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
596 CmdSetTRDeq
.Endpoint
= Dci
;
597 CmdSetTRDeq
.SlotId
= SlotId
;
598 Status
= XhcCmdTransfer (
600 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
602 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
604 ASSERT (!EFI_ERROR(Status
));
607 // 3)Ring the doorbell to transit from stop to active
609 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
615 Create XHCI event ring.
617 @param Xhc The XHCI Instance.
618 @param EventRing The created event ring.
623 IN USB_XHCI_INSTANCE
*Xhc
,
624 OUT EVENT_RING
*EventRing
628 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
630 ASSERT (EventRing
!= NULL
);
632 Buf
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
));
633 ASSERT (Buf
!= NULL
);
634 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
635 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
637 EventRing
->EventRingSeg0
= Buf
;
638 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
639 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
640 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
642 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
643 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
645 EventRing
->EventRingCCS
= 1;
647 Buf
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
));
648 ASSERT (Buf
!= NULL
);
649 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
650 ZeroMem (Buf
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
652 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
653 EventRing
->ERSTBase
= ERSTBase
;
654 ERSTBase
->PtrLo
= XHC_LOW_32BIT (EventRing
->EventRingSeg0
);
655 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (EventRing
->EventRingSeg0
);
656 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
659 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
667 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
669 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
670 // So divide it to two 32-bytes width register access.
675 XHC_LOW_32BIT((UINT64
)(UINTN
)EventRing
->EventRingDequeue
)
680 XHC_HIGH_32BIT((UINT64
)(UINTN
)EventRing
->EventRingDequeue
)
683 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
685 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
686 // So divide it to two 32-bytes width register access.
691 XHC_LOW_32BIT((UINT64
)(UINTN
)ERSTBase
)
695 XHC_ERSTBA_OFFSET
+ 4,
696 XHC_HIGH_32BIT((UINT64
)(UINTN
)ERSTBase
)
699 // Need set IMAN IE bit to enble the ring interrupt
701 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
705 Create XHCI transfer ring.
707 @param Xhc The XHCI Instance.
708 @param TrbNum The number of TRB in the ring.
709 @param TransferRing The created transfer ring.
714 IN USB_XHCI_INSTANCE
*Xhc
,
716 OUT TRANSFER_RING
*TransferRing
722 Buf
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * TrbNum
));
723 ASSERT (Buf
!= NULL
);
724 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
725 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
727 TransferRing
->RingSeg0
= Buf
;
728 TransferRing
->TrbNumber
= TrbNum
;
729 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
730 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
731 TransferRing
->RingPCS
= 1;
733 // 4.9.2 Transfer Ring Management
734 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
735 // point to the first TRB in the ring.
737 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
738 EndTrb
->Type
= TRB_TYPE_LINK
;
739 EndTrb
->PtrLo
= XHC_LOW_32BIT (Buf
);
740 EndTrb
->PtrHi
= XHC_HIGH_32BIT (Buf
);
742 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
746 // Set Cycle bit as other TRB PCS init value
748 EndTrb
->CycleBit
= 0;
752 Free XHCI event ring.
754 @param Xhc The XHCI Instance.
755 @param EventRing The event ring to be freed.
761 IN USB_XHCI_INSTANCE
*Xhc
,
762 IN EVENT_RING
*EventRing
766 EVENT_RING_SEG_TABLE_ENTRY
*TablePtr
;
768 EVENT_RING_SEG_TABLE_ENTRY
*EventRingPtr
;
770 if(EventRing
->EventRingSeg0
== NULL
) {
775 // Get the Event Ring Segment Table base address
777 TablePtr
= (EVENT_RING_SEG_TABLE_ENTRY
*)(EventRing
->ERSTBase
);
780 // Get all the TRBs Ring and release
782 for (Index
= 0; Index
< ERST_NUMBER
; Index
++) {
783 EventRingPtr
= TablePtr
+ Index
;
784 RingBuf
= (VOID
*)(UINTN
)(EventRingPtr
->PtrLo
| LShiftU64 ((UINT64
)EventRingPtr
->PtrHi
, 32));
786 if(RingBuf
!= NULL
) {
787 FreePages (RingBuf
, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
));
788 ZeroMem (EventRingPtr
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
));
792 FreePages (TablePtr
, EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
));
797 Free the resouce allocated at initializing schedule.
799 @param Xhc The XHCI Instance.
804 IN USB_XHCI_INSTANCE
*Xhc
810 if (Xhc
->ScratchBuf
!= NULL
) {
811 ScratchBuf
= Xhc
->ScratchBuf
;
812 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
813 FreeAlignedPages ((VOID
*)(UINTN
)*ScratchBuf
++, EFI_SIZE_TO_PAGES (Xhc
->PageSize
));
815 FreeAlignedPages (Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)));
818 if (Xhc
->DCBAA
!= NULL
) {
819 FreePages (Xhc
->DCBAA
, EFI_SIZE_TO_PAGES((Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
)));
823 if (Xhc
->CmdRing
.RingSeg0
!= NULL
){
824 FreePages (Xhc
->CmdRing
.RingSeg0
, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
));
825 Xhc
->CmdRing
.RingSeg0
= NULL
;
828 XhcFreeEventRing (Xhc
,&Xhc
->EventRing
);
832 Check if it is ring TRB.
834 @param Ring The transfer ring
835 @param Trb The TRB to check if it's in the transfer ring
837 @retval TRUE It is in the ring
838 @retval FALSE It is not in the ring
843 IN TRANSFER_RING
*Ring
,
851 Trb1
= Ring
->RingSeg0
;
854 ASSERT (Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
856 for (Index
= 0; Index
< Ring
->TrbNumber
; Index
++) {
868 Check the URB's execution result and update the URB's
871 @param Xhc The XHCI Instance.
872 @param Urb The URB to check result.
874 @return Whether the result of URB transfer is finialized.
879 IN USB_XHCI_INSTANCE
*Xhc
,
885 EVT_TRB_TRANSFER
*EvtTrb
;
886 TRB_TEMPLATE
*TRBPtr
;
891 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
894 Urb
->Result
= EFI_USB_NOERROR
;
895 Status
= EFI_SUCCESS
;
898 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
899 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
900 Status
= EFI_DEVICE_ERROR
;
905 // Restore the EventRingDequeue and poll the transfer event ring from beginning
909 Urb
->EvtRing
->EventRingDequeue
= Urb
->EvtTrbStart
;
910 for (Index
= 0; Index
< Urb
->EvtRing
->TrbNumber
; Index
++) {
911 XhcSyncEventRing (Xhc
, Urb
->EvtRing
);
912 Status
= XhcCheckNewEvent (Xhc
, Urb
->EvtRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
913 if (Status
== EFI_NOT_READY
) {
914 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
919 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
921 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
925 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
926 if (IsTransferRingTrb (Urb
->Ring
, TRBPtr
)) {
927 switch (EvtTrb
->Completecode
) {
928 case TRB_COMPLETION_STALL_ERROR
:
929 Urb
->Result
|= EFI_USB_ERR_STALL
;
930 Status
= EFI_DEVICE_ERROR
;
931 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
935 case TRB_COMPLETION_BABBLE_ERROR
:
936 Urb
->Result
|= EFI_USB_ERR_BABBLE
;
937 Status
= EFI_DEVICE_ERROR
;
938 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
942 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
943 Urb
->Result
|= EFI_USB_ERR_BUFFER
;
944 Status
= EFI_DEVICE_ERROR
;
945 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
949 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
950 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
951 Status
= EFI_DEVICE_ERROR
;
952 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
956 case TRB_COMPLETION_SHORT_PACKET
:
957 case TRB_COMPLETION_SUCCESS
:
958 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
959 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: short packet happens!\n"));
962 TRBType
= (UINT8
) (TRBPtr
->Type
);
963 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
964 (TRBType
== TRB_TYPE_NORMAL
) ||
965 (TRBType
== TRB_TYPE_ISOCH
)) {
966 Urb
->Completed
+= (Urb
->DataLen
- EvtTrb
->Lenth
);
969 Status
= EFI_SUCCESS
;
973 DEBUG ((EFI_D_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
974 Urb
->Result
|= EFI_USB_ERR_TIMEOUT
;
975 Status
= EFI_DEVICE_ERROR
;
981 // Only check first and end Trb event address
983 if (TRBPtr
== Urb
->TrbStart
) {
987 if (TRBPtr
== Urb
->TrbEnd
) {
991 if (StartDone
&& EndDone
) {
1003 Execute the transfer by polling the URB. This is a synchronous operation.
1005 @param Xhc The XHCI Instance.
1006 @param CmdTransfer The executed URB is for cmd transfer or not.
1007 @param Urb The URB to execute.
1008 @param Timeout The time to wait before abort, in millisecond.
1010 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1011 @return EFI_TIMEOUT The transfer failed due to time out.
1012 @return EFI_SUCCESS The transfer finished OK.
1017 IN USB_XHCI_INSTANCE
*Xhc
,
1018 IN BOOLEAN CmdTransfer
,
1033 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1035 return EFI_DEVICE_ERROR
;
1037 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1041 Status
= EFI_SUCCESS
;
1042 Loop
= (Timeout
* XHC_1_MILLISECOND
/ XHC_POLL_DELAY
) + 1;
1047 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1049 for (Index
= 0; Index
< Loop
; Index
++) {
1050 Status
= XhcCheckUrbResult (Xhc
, Urb
);
1051 if ((Status
!= EFI_NOT_READY
)) {
1054 gBS
->Stall (XHC_POLL_DELAY
);
1061 Delete a single asynchronous interrupt transfer for
1062 the device and endpoint.
1064 @param Xhc The XHCI Instance.
1065 @param BusAddr The logical device address assigned by UsbBus driver.
1066 @param EpNum The endpoint of the target.
1068 @retval EFI_SUCCESS An asynchronous transfer is removed.
1069 @retval EFI_NOT_FOUND No transfer for the device is found.
1073 XhciDelAsyncIntTransfer (
1074 IN USB_XHCI_INSTANCE
*Xhc
,
1082 EFI_USB_DATA_DIRECTION Direction
;
1084 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1089 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1090 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1091 if ((Urb
->Ep
.BusAddr
== BusAddr
) &&
1092 (Urb
->Ep
.EpAddr
== EpNum
) &&
1093 (Urb
->Ep
.Direction
== Direction
)) {
1094 RemoveEntryList (&Urb
->UrbList
);
1095 FreePool (Urb
->Data
);
1101 return EFI_NOT_FOUND
;
1105 Remove all the asynchronous interrutp transfers.
1107 @param Xhc The XHCI Instance.
1111 XhciDelAllAsyncIntTransfers (
1112 IN USB_XHCI_INSTANCE
*Xhc
1119 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1120 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1121 RemoveEntryList (&Urb
->UrbList
);
1122 FreePool (Urb
->Data
);
1128 Update the queue head for next round of asynchronous transfer
1130 @param Xhc The XHCI Instance.
1131 @param Urb The URB to update
1135 XhcUpdateAsyncRequest (
1136 IN USB_XHCI_INSTANCE
*Xhc
,
1142 if (Urb
->Result
== EFI_USB_NOERROR
) {
1143 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1144 if (EFI_ERROR (Status
)) {
1147 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1148 if (EFI_ERROR (Status
)) {
1156 Interrupt transfer periodic check handler.
1158 @param Event Interrupt event.
1159 @param Context Pointer to USB_XHCI_INSTANCE.
1164 XhcMonitorAsyncRequests (
1169 USB_XHCI_INSTANCE
*Xhc
;
1178 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1180 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1182 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1183 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1186 // Make sure that the device is available before every check.
1188 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1194 // Check the result of URB execution. If it is still
1195 // active, check the next one.
1197 Status
= XhcCheckUrbResult (Xhc
, Urb
);
1199 if (Status
== EFI_NOT_READY
) {
1204 // Allocate a buffer then copy the transferred data for user.
1205 // If failed to allocate the buffer, update the URB for next
1206 // round of transfer. Ignore the data of this round.
1209 if (Urb
->Result
== EFI_USB_NOERROR
) {
1210 ASSERT (Urb
->Completed
<= Urb
->DataLen
);
1212 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1214 if (ProcBuf
== NULL
) {
1215 XhcUpdateAsyncRequest (Xhc
, Urb
);
1219 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1222 XhcUpdateAsyncRequest (Xhc
, Urb
);
1225 // Leave error recovery to its related device driver. A
1226 // common case of the error recovery is to re-submit the
1227 // interrupt transfer which is linked to the head of the
1228 // list. This function scans from head to tail. So the
1229 // re-submitted interrupt transfer's callback function
1230 // will not be called again in this round. Don't touch this
1231 // URB after the callback, it may have been removed by the
1234 if (Urb
->Callback
!= NULL
) {
1236 // Restore the old TPL, USB bus maybe connect device in
1237 // his callback. Some drivers may has a lower TPL restriction.
1239 gBS
->RestoreTPL (OldTpl
);
1240 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1241 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1244 if (ProcBuf
!= NULL
) {
1245 gBS
->FreePool (ProcBuf
);
1248 gBS
->RestoreTPL (OldTpl
);
1252 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1254 @param Xhc The XHCI Instance.
1255 @param ParentRouteChart The route string pointed to the parent device if it exists.
1256 @param Port The port to be polled.
1257 @param PortState The port state.
1259 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1260 @retval Others Should not appear.
1265 XhcPollPortStatusChange (
1266 IN USB_XHCI_INSTANCE
*Xhc
,
1267 IN USB_DEV_ROUTE ParentRouteChart
,
1269 IN EFI_USB_PORT_STATUS
*PortState
1275 USB_DEV_ROUTE RouteChart
;
1277 Status
= EFI_SUCCESS
;
1279 if (ParentRouteChart
.Dword
== 0) {
1280 RouteChart
.Route
.RouteString
= 0;
1281 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1282 RouteChart
.Route
.TierNum
= 1;
1285 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1287 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1289 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1290 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1293 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1294 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1296 // Has a device attached, Identify device speed after port is enabled.
1298 Speed
= EFI_USB_SPEED_FULL
;
1299 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1300 Speed
= EFI_USB_SPEED_LOW
;
1301 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1302 Speed
= EFI_USB_SPEED_HIGH
;
1303 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1304 Speed
= EFI_USB_SPEED_SUPER
;
1307 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1309 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1311 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1312 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1314 Status
= XhcInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1316 ASSERT_EFI_ERROR (Status
);
1318 } else if ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) == 0) {
1320 // Device is detached. Disable the allocated device slot and release resource.
1322 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1324 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1325 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1327 Status
= XhcDisableSlotCmd64 (Xhc
, SlotId
);
1329 ASSERT_EFI_ERROR (Status
);
1337 Calculate the device context index by endpoint address and direction.
1339 @param EpAddr The target endpoint number.
1340 @param Direction The direction of the target endpoint.
1342 @return The device context index of endpoint.
1356 Index
= (UINT8
) (2 * EpAddr
);
1357 if (Direction
== EfiUsbDataIn
) {
1365 Find out the actual device address according to the requested device address from UsbBus.
1367 @param Xhc The XHCI Instance.
1368 @param BusDevAddr The requested device address by UsbBus upper driver.
1370 @return The actual device address assigned to the device.
1375 XhcBusDevAddrToSlotId (
1376 IN USB_XHCI_INSTANCE
*Xhc
,
1382 for (Index
= 0; Index
< 255; Index
++) {
1383 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1384 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1385 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1394 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1398 Find out the slot id according to the device's route string.
1400 @param Xhc The XHCI Instance.
1401 @param RouteString The route string described the device location.
1403 @return The slot id used by the device.
1408 XhcRouteStringToSlotId (
1409 IN USB_XHCI_INSTANCE
*Xhc
,
1410 IN USB_DEV_ROUTE RouteString
1415 for (Index
= 0; Index
< 255; Index
++) {
1416 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1417 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1418 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1427 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1431 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1433 @param Xhc The XHCI Instance.
1434 @param EvtRing The event ring to sync.
1436 @retval EFI_SUCCESS The event ring is synchronized successfully.
1442 IN USB_XHCI_INSTANCE
*Xhc
,
1443 IN EVENT_RING
*EvtRing
1447 TRB_TEMPLATE
*EvtTrb1
;
1448 TRB_TEMPLATE
*EvtTrb2
;
1453 ASSERT (EvtRing
!= NULL
);
1456 // Calculate the EventRingEnqueue and EventRingCCS.
1457 // Note: only support single Segment
1459 EvtTrb1
= EvtRing
->EventRingSeg0
;
1460 EvtTrb2
= EvtRing
->EventRingSeg0
;
1462 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1463 if (EvtTrb1
->CycleBit
!= EvtTrb2
->CycleBit
) {
1469 if (Index
< EvtRing
->TrbNumber
) {
1470 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1471 EvtRing
->EventRingCCS
= (EvtTrb2
->CycleBit
) ? 1 : 0;
1473 EvtRing
->EventRingEnqueue
= EvtTrb2
;
1474 EvtRing
->EventRingCCS
= (EvtTrb2
->CycleBit
) ? 0 : 1;
1478 // Apply the EventRingDequeue to Xhc
1480 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1481 // So divide it to two 32-bytes width register access.
1483 Low
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
1484 High
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
1485 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
1487 if ((XhcDequeue
& (~0x0F)) != ((UINT64
)(UINTN
)EvtRing
->EventRingDequeue
& (~0x0F))) {
1489 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1490 // So divide it to two 32-bytes width register access.
1492 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (EvtRing
->EventRingDequeue
) | BIT3
);
1493 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (EvtRing
->EventRingDequeue
));
1500 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1502 @param Xhc The XHCI Instance.
1503 @param TrsRing The transfer ring to sync.
1505 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1511 IN USB_XHCI_INSTANCE
*Xhc
,
1512 IN TRANSFER_RING
*TrsRing
1516 TRB_TEMPLATE
*TrsTrb
;
1518 ASSERT (TrsRing
!= NULL
);
1520 // Calculate the latest RingEnqueue and RingPCS
1522 TrsTrb
= TrsRing
->RingEnqueue
;
1523 ASSERT (TrsTrb
!= NULL
);
1525 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1526 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1530 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1531 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1533 // set cycle bit in Link TRB as normal
1535 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1537 // Toggle PCS maintained by software
1539 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1540 TrsTrb
= (TRB_TEMPLATE
*)(UINTN
)((TrsTrb
->Parameter1
| LShiftU64 ((UINT64
)TrsTrb
->Parameter2
, 32)) & ~0x0F);
1544 ASSERT (Index
!= TrsRing
->TrbNumber
);
1546 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1547 TrsRing
->RingEnqueue
= TrsTrb
;
1551 // Clear the Trb context for enqueue, but reserve the PCS bit
1553 TrsTrb
->Parameter1
= 0;
1554 TrsTrb
->Parameter2
= 0;
1558 TrsTrb
->Control
= 0;
1564 Check if there is a new generated event.
1566 @param Xhc The XHCI Instance.
1567 @param EvtRing The event ring to check.
1568 @param NewEvtTrb The new event TRB found.
1570 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1571 @retval EFI_NOT_READY The event ring has no new event.
1577 IN USB_XHCI_INSTANCE
*Xhc
,
1578 IN EVENT_RING
*EvtRing
,
1579 OUT TRB_TEMPLATE
**NewEvtTrb
1583 TRB_TEMPLATE
*EvtTrb
;
1585 ASSERT (EvtRing
!= NULL
);
1587 EvtTrb
= EvtRing
->EventRingDequeue
;
1588 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
1590 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
1591 return EFI_NOT_READY
;
1594 Status
= EFI_SUCCESS
;
1596 if (((EvtTrb
->Status
>> 24) & 0xFF) != TRB_COMPLETION_SUCCESS
) {
1597 Status
= EFI_DEVICE_ERROR
;
1600 EvtRing
->EventRingDequeue
++;
1602 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1604 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1605 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
1612 Ring the door bell to notify XHCI there is a transaction to be executed.
1614 @param Xhc The XHCI Instance.
1615 @param SlotId The slot id of the target device.
1616 @param Dci The device context index of the target slot or endpoint.
1618 @retval EFI_SUCCESS Successfully ring the door bell.
1624 IN USB_XHCI_INSTANCE
*Xhc
,
1630 XhcWriteDoorBellReg (Xhc
, 0, 0);
1632 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1639 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1641 @param Xhc The XHCI Instance.
1642 @param Urb The URB to be rung.
1644 @retval EFI_SUCCESS Successfully ring the door bell.
1648 RingIntTransferDoorBell (
1649 IN USB_XHCI_INSTANCE
*Xhc
,
1656 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1657 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1658 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1663 Assign and initialize the device slot for a new device.
1665 @param Xhc The XHCI Instance.
1666 @param ParentRouteChart The route string pointed to the parent device.
1667 @param ParentPort The port at which the device is located.
1668 @param RouteChart The route string pointed to the device.
1669 @param DeviceSpeed The device speed.
1671 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1676 XhcInitializeDeviceSlot (
1677 IN USB_XHCI_INSTANCE
*Xhc
,
1678 IN USB_DEV_ROUTE ParentRouteChart
,
1679 IN UINT16 ParentPort
,
1680 IN USB_DEV_ROUTE RouteChart
,
1681 IN UINT8 DeviceSpeed
1685 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1686 INPUT_CONTEXT
*InputContext
;
1687 DEVICE_CONTEXT
*OutputContext
;
1688 TRANSFER_RING
*EndpointTransferRing
;
1689 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1690 UINT8 DeviceAddress
;
1691 CMD_TRB_ENABLE_SLOT CmdTrb
;
1694 DEVICE_CONTEXT
*ParentDeviceContext
;
1696 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1697 CmdTrb
.CycleBit
= 1;
1698 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1700 Status
= XhcCmdTransfer (
1702 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1703 XHC_GENERIC_TIMEOUT
,
1704 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1706 ASSERT_EFI_ERROR (Status
);
1707 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1708 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1709 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1710 ASSERT (SlotId
!= 0);
1712 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1713 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1714 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1715 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1716 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1719 // 4.3.3 Device Slot Initialization
1720 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1722 InputContext
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT
)));
1723 ASSERT (InputContext
!= NULL
);
1724 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1725 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1727 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1730 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1731 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1732 // Context are affected by the command.
1734 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1737 // 3) Initialize the Input Slot Context data structure
1739 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1740 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1741 InputContext
->Slot
.ContextEntries
= 1;
1742 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1744 if (RouteChart
.Route
.RouteString
) {
1746 // The device is behind of hub device.
1748 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
1749 ASSERT (ParentSlotId
!= 0);
1751 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1753 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1754 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1755 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1756 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1758 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1759 // environment from Full/Low speed signaling environment for a device
1761 InputContext
->Slot
.TTPortNum
= ParentPort
;
1762 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1766 // Inherit the TT parameters from parent device.
1768 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1769 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1771 // If the device is a High speed device then down the speed to be the same as its parent Hub
1773 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1774 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1780 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1782 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1783 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1784 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1786 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1788 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1790 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1791 InputContext
->EP
[0].MaxPacketSize
= 512;
1792 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1793 InputContext
->EP
[0].MaxPacketSize
= 64;
1795 InputContext
->EP
[0].MaxPacketSize
= 8;
1798 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1799 // 1KB, and Bulk and Isoch endpoints 3KB.
1801 InputContext
->EP
[0].AverageTRBLength
= 8;
1802 InputContext
->EP
[0].MaxBurstSize
= 0;
1803 InputContext
->EP
[0].Interval
= 0;
1804 InputContext
->EP
[0].MaxPStreams
= 0;
1805 InputContext
->EP
[0].Mult
= 0;
1806 InputContext
->EP
[0].CErr
= 3;
1809 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
1811 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
) | BIT0
;
1812 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
);
1815 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
1817 OutputContext
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT
)));
1818 ASSERT (OutputContext
!= NULL
);
1819 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
1820 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
1822 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
1824 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
1825 // a pointer to the Output Device Context data structure (6.2.1).
1827 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) OutputContext
;
1830 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
1831 // Context data structure described above.
1833 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
1834 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (Xhc
->UsbDevContext
[SlotId
].InputContext
);
1835 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (Xhc
->UsbDevContext
[SlotId
].InputContext
);
1836 CmdTrbAddr
.CycleBit
= 1;
1837 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
1838 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
1839 Status
= XhcCmdTransfer (
1841 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
1842 XHC_GENERIC_TIMEOUT
,
1843 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1845 ASSERT (!EFI_ERROR(Status
));
1847 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
1848 DEBUG ((EFI_D_INFO
, " Address %d assigned succeefully\n", DeviceAddress
));
1850 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
1856 Assign and initialize the device slot for a new device.
1858 @param Xhc The XHCI Instance.
1859 @param ParentRouteChart The route string pointed to the parent device.
1860 @param ParentPort The port at which the device is located.
1861 @param RouteChart The route string pointed to the device.
1862 @param DeviceSpeed The device speed.
1864 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1869 XhcInitializeDeviceSlot64 (
1870 IN USB_XHCI_INSTANCE
*Xhc
,
1871 IN USB_DEV_ROUTE ParentRouteChart
,
1872 IN UINT16 ParentPort
,
1873 IN USB_DEV_ROUTE RouteChart
,
1874 IN UINT8 DeviceSpeed
1878 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1879 INPUT_CONTEXT_64
*InputContext
;
1880 DEVICE_CONTEXT_64
*OutputContext
;
1881 TRANSFER_RING
*EndpointTransferRing
;
1882 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1883 UINT8 DeviceAddress
;
1884 CMD_TRB_ENABLE_SLOT CmdTrb
;
1887 DEVICE_CONTEXT_64
*ParentDeviceContext
;
1889 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1890 CmdTrb
.CycleBit
= 1;
1891 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1893 Status
= XhcCmdTransfer (
1895 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1896 XHC_GENERIC_TIMEOUT
,
1897 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1899 ASSERT_EFI_ERROR (Status
);
1900 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1901 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1902 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1903 ASSERT (SlotId
!= 0);
1905 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1906 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1907 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1908 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1909 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1912 // 4.3.3 Device Slot Initialization
1913 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1915 InputContext
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT_64
)));
1916 ASSERT (InputContext
!= NULL
);
1917 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1918 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
1920 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1923 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1924 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1925 // Context are affected by the command.
1927 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1930 // 3) Initialize the Input Slot Context data structure
1932 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1933 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1934 InputContext
->Slot
.ContextEntries
= 1;
1935 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1937 if (RouteChart
.Route
.RouteString
) {
1939 // The device is behind of hub device.
1941 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
1942 ASSERT (ParentSlotId
!= 0);
1944 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1946 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1947 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1948 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1949 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1951 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1952 // environment from Full/Low speed signaling environment for a device
1954 InputContext
->Slot
.TTPortNum
= ParentPort
;
1955 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
1959 // Inherit the TT parameters from parent device.
1961 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
1962 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
1964 // If the device is a High speed device then down the speed to be the same as its parent Hub
1966 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1967 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
1973 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
1975 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
1976 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
1977 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
1979 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
1981 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
1983 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
1984 InputContext
->EP
[0].MaxPacketSize
= 512;
1985 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
1986 InputContext
->EP
[0].MaxPacketSize
= 64;
1988 InputContext
->EP
[0].MaxPacketSize
= 8;
1991 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
1992 // 1KB, and Bulk and Isoch endpoints 3KB.
1994 InputContext
->EP
[0].AverageTRBLength
= 8;
1995 InputContext
->EP
[0].MaxBurstSize
= 0;
1996 InputContext
->EP
[0].Interval
= 0;
1997 InputContext
->EP
[0].MaxPStreams
= 0;
1998 InputContext
->EP
[0].Mult
= 0;
1999 InputContext
->EP
[0].CErr
= 3;
2002 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2004 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
) | BIT0
;
2005 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
);
2008 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2010 OutputContext
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT_64
)));
2011 ASSERT (OutputContext
!= NULL
);
2012 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2013 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2015 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2017 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2018 // a pointer to the Output Device Context data structure (6.2.1).
2020 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) OutputContext
;
2023 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2024 // Context data structure described above.
2026 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2027 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (Xhc
->UsbDevContext
[SlotId
].InputContext
);
2028 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (Xhc
->UsbDevContext
[SlotId
].InputContext
);
2029 CmdTrbAddr
.CycleBit
= 1;
2030 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2031 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2032 Status
= XhcCmdTransfer (
2034 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2035 XHC_GENERIC_TIMEOUT
,
2036 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2038 ASSERT (!EFI_ERROR(Status
));
2040 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT_64
*) OutputContext
)->Slot
.DeviceAddress
;
2041 DEBUG ((EFI_D_INFO
, " Address %d assigned succeefully\n", DeviceAddress
));
2043 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2050 Disable the specified device slot.
2052 @param Xhc The XHCI Instance.
2053 @param SlotId The slot id to be disabled.
2055 @retval EFI_SUCCESS Successfully disable the device slot.
2061 IN USB_XHCI_INSTANCE
*Xhc
,
2066 TRB_TEMPLATE
*EvtTrb
;
2067 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2072 // Disable the device slots occupied by these devices on its downstream ports.
2073 // Entry 0 is reserved.
2075 for (Index
= 0; Index
< 255; Index
++) {
2076 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2077 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2078 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2082 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2084 if (EFI_ERROR (Status
)) {
2085 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2086 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2091 // Construct the disable slot command
2093 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2095 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2096 CmdTrbDisSlot
.CycleBit
= 1;
2097 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2098 CmdTrbDisSlot
.SlotId
= SlotId
;
2099 Status
= XhcCmdTransfer (
2101 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2102 XHC_GENERIC_TIMEOUT
,
2103 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2105 ASSERT_EFI_ERROR(Status
);
2107 // Free the slot's device context entry
2109 Xhc
->DCBAA
[SlotId
] = 0;
2112 // Free the slot related data structure
2114 for (Index
= 0; Index
< 31; Index
++) {
2115 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2116 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2117 if (RingSeg
!= NULL
) {
2118 FreePages (RingSeg
, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
));
2120 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2124 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2125 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2126 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2130 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2131 FreePages (Xhc
->UsbDevContext
[SlotId
].InputContext
, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT
)));
2134 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2135 FreePages (Xhc
->UsbDevContext
[SlotId
].OutputContext
, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT
)));
2138 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2139 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2140 // remove urb from XHCI's asynchronous transfer list.
2142 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2143 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2149 Disable the specified device slot.
2151 @param Xhc The XHCI Instance.
2152 @param SlotId The slot id to be disabled.
2154 @retval EFI_SUCCESS Successfully disable the device slot.
2159 XhcDisableSlotCmd64 (
2160 IN USB_XHCI_INSTANCE
*Xhc
,
2165 TRB_TEMPLATE
*EvtTrb
;
2166 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2171 // Disable the device slots occupied by these devices on its downstream ports.
2172 // Entry 0 is reserved.
2174 for (Index
= 0; Index
< 255; Index
++) {
2175 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2176 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2177 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2181 Status
= XhcDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2183 if (EFI_ERROR (Status
)) {
2184 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2185 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2190 // Construct the disable slot command
2192 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2194 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2195 CmdTrbDisSlot
.CycleBit
= 1;
2196 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2197 CmdTrbDisSlot
.SlotId
= SlotId
;
2198 Status
= XhcCmdTransfer (
2200 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2201 XHC_GENERIC_TIMEOUT
,
2202 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2204 ASSERT_EFI_ERROR(Status
);
2206 // Free the slot's device context entry
2208 Xhc
->DCBAA
[SlotId
] = 0;
2211 // Free the slot related data structure
2213 for (Index
= 0; Index
< 31; Index
++) {
2214 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2215 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2216 if (RingSeg
!= NULL
) {
2217 FreePages (RingSeg
, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
));
2219 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2223 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2224 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2225 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2229 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2230 FreePages (Xhc
->UsbDevContext
[SlotId
].InputContext
, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT_64
)));
2233 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2234 FreePages (Xhc
->UsbDevContext
[SlotId
].OutputContext
, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT_64
)));
2237 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2238 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2239 // remove urb from XHCI's asynchronous transfer list.
2241 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2242 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2249 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2251 @param Xhc The XHCI Instance.
2252 @param SlotId The slot id to be configured.
2253 @param DeviceSpeed The device's speed.
2254 @param ConfigDesc The pointer to the usb device configuration descriptor.
2256 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2262 IN USB_XHCI_INSTANCE
*Xhc
,
2264 IN UINT8 DeviceSpeed
,
2265 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
2270 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
2271 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2282 TRANSFER_RING
*EndpointTransferRing
;
2283 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2284 INPUT_CONTEXT
*InputContext
;
2285 DEVICE_CONTEXT
*OutputContext
;
2286 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2288 // 4.6.6 Configure Endpoint
2290 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2291 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2292 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2293 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
2295 ASSERT (ConfigDesc
!= NULL
);
2299 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
2300 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
2301 while (IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) {
2302 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2305 NumEp
= IfDesc
->NumEndpoints
;
2307 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2308 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2309 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2310 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2313 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2314 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2316 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2322 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2323 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2325 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2327 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2329 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2331 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2334 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2335 case USB_ENDPOINT_BULK
:
2336 if (Direction
== EfiUsbDataIn
) {
2337 InputContext
->EP
[Dci
-1].CErr
= 3;
2338 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2340 InputContext
->EP
[Dci
-1].CErr
= 3;
2341 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2344 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2345 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2346 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2347 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2348 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2352 case USB_ENDPOINT_ISO
:
2353 if (Direction
== EfiUsbDataIn
) {
2354 InputContext
->EP
[Dci
-1].CErr
= 0;
2355 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2357 InputContext
->EP
[Dci
-1].CErr
= 0;
2358 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2361 case USB_ENDPOINT_INTERRUPT
:
2362 if (Direction
== EfiUsbDataIn
) {
2363 InputContext
->EP
[Dci
-1].CErr
= 3;
2364 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2366 InputContext
->EP
[Dci
-1].CErr
= 3;
2367 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2369 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2370 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2372 // Get the bInterval from descriptor and init the the interval field of endpoint context
2374 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2375 Interval
= EpDesc
->Interval
;
2377 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2379 InputContext
->EP
[Dci
-1].Interval
= 6;
2380 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2381 Interval
= EpDesc
->Interval
;
2382 ASSERT (Interval
>= 1 && Interval
<= 16);
2384 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2386 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2387 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2388 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2389 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2390 InputContext
->EP
[Dci
-1].CErr
= 3;
2393 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2394 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2395 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2396 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2400 case USB_ENDPOINT_CONTROL
:
2406 PhyAddr
= XHC_LOW_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
);
2408 PhyAddr
|= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2409 InputContext
->EP
[Dci
-1].PtrLo
= PhyAddr
;
2410 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
);
2412 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2414 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2417 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2418 InputContext
->Slot
.ContextEntries
= MaxDci
;
2420 // configure endpoint
2422 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2423 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2424 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2425 CmdTrbCfgEP
.CycleBit
= 1;
2426 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2427 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2428 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
2429 Status
= XhcCmdTransfer (
2431 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2432 XHC_GENERIC_TIMEOUT
,
2433 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2435 ASSERT_EFI_ERROR(Status
);
2441 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2443 @param Xhc The XHCI Instance.
2444 @param SlotId The slot id to be configured.
2445 @param DeviceSpeed The device's speed.
2446 @param ConfigDesc The pointer to the usb device configuration descriptor.
2448 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2454 IN USB_XHCI_INSTANCE
*Xhc
,
2456 IN UINT8 DeviceSpeed
,
2457 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
2462 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
2463 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2474 TRANSFER_RING
*EndpointTransferRing
;
2475 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2476 INPUT_CONTEXT_64
*InputContext
;
2477 DEVICE_CONTEXT_64
*OutputContext
;
2478 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2480 // 4.6.6 Configure Endpoint
2482 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2483 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2484 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2485 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
2487 ASSERT (ConfigDesc
!= NULL
);
2491 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
2492 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
2493 while (IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) {
2494 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2497 NumEp
= IfDesc
->NumEndpoints
;
2499 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2500 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2501 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2502 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2505 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2506 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2508 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2514 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2515 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2517 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2519 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2521 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2523 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2526 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2527 case USB_ENDPOINT_BULK
:
2528 if (Direction
== EfiUsbDataIn
) {
2529 InputContext
->EP
[Dci
-1].CErr
= 3;
2530 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2532 InputContext
->EP
[Dci
-1].CErr
= 3;
2533 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2536 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2537 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2538 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2539 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2540 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2544 case USB_ENDPOINT_ISO
:
2545 if (Direction
== EfiUsbDataIn
) {
2546 InputContext
->EP
[Dci
-1].CErr
= 0;
2547 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2549 InputContext
->EP
[Dci
-1].CErr
= 0;
2550 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2553 case USB_ENDPOINT_INTERRUPT
:
2554 if (Direction
== EfiUsbDataIn
) {
2555 InputContext
->EP
[Dci
-1].CErr
= 3;
2556 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2558 InputContext
->EP
[Dci
-1].CErr
= 3;
2559 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2561 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2562 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2564 // Get the bInterval from descriptor and init the the interval field of endpoint context
2566 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2567 Interval
= EpDesc
->Interval
;
2569 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
2571 InputContext
->EP
[Dci
-1].Interval
= 6;
2572 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2573 Interval
= EpDesc
->Interval
;
2574 ASSERT (Interval
>= 1 && Interval
<= 16);
2576 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2578 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2579 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2580 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2581 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2582 InputContext
->EP
[Dci
-1].CErr
= 3;
2585 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2586 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2587 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2588 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2592 case USB_ENDPOINT_CONTROL
:
2598 PhyAddr
= XHC_LOW_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
);
2600 PhyAddr
|= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2601 InputContext
->EP
[Dci
-1].PtrLo
= PhyAddr
;
2602 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
);
2604 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2606 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2609 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2610 InputContext
->Slot
.ContextEntries
= MaxDci
;
2612 // configure endpoint
2614 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2615 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2616 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2617 CmdTrbCfgEP
.CycleBit
= 1;
2618 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2619 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2620 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
2621 Status
= XhcCmdTransfer (
2623 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2624 XHC_GENERIC_TIMEOUT
,
2625 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2627 ASSERT_EFI_ERROR(Status
);
2634 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2636 @param Xhc The XHCI Instance.
2637 @param SlotId The slot id to be evaluated.
2638 @param MaxPacketSize The max packet size supported by the device control transfer.
2640 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2645 XhcEvaluateContext (
2646 IN USB_XHCI_INSTANCE
*Xhc
,
2648 IN UINT32 MaxPacketSize
2652 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2653 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2654 INPUT_CONTEXT
*InputContext
;
2656 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2659 // 4.6.7 Evaluate Context
2661 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2662 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2664 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2665 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2667 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2668 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2669 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2670 CmdTrbEvalu
.CycleBit
= 1;
2671 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2672 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2673 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
2674 Status
= XhcCmdTransfer (
2676 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2677 XHC_GENERIC_TIMEOUT
,
2678 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2680 ASSERT (!EFI_ERROR(Status
));
2686 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
2688 @param Xhc The XHCI Instance.
2689 @param SlotId The slot id to be evaluated.
2690 @param MaxPacketSize The max packet size supported by the device control transfer.
2692 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
2697 XhcEvaluateContext64 (
2698 IN USB_XHCI_INSTANCE
*Xhc
,
2700 IN UINT32 MaxPacketSize
2704 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
2705 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2706 INPUT_CONTEXT_64
*InputContext
;
2708 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2711 // 4.6.7 Evaluate Context
2713 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2714 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2716 InputContext
->InputControlContext
.Dword2
|= BIT1
;
2717 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
2719 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
2720 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2721 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2722 CmdTrbEvalu
.CycleBit
= 1;
2723 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
2724 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2725 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
2726 Status
= XhcCmdTransfer (
2728 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
2729 XHC_GENERIC_TIMEOUT
,
2730 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2732 ASSERT (!EFI_ERROR(Status
));
2739 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2741 @param Xhc The XHCI Instance.
2742 @param SlotId The slot id to be configured.
2743 @param PortNum The total number of downstream port supported by the hub.
2744 @param TTT The TT think time of the hub device.
2745 @param MTT The multi-TT of the hub device.
2747 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2751 XhcConfigHubContext (
2752 IN USB_XHCI_INSTANCE
*Xhc
,
2761 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2762 INPUT_CONTEXT
*InputContext
;
2763 DEVICE_CONTEXT
*OutputContext
;
2764 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2766 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2767 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2768 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2771 // 4.6.7 Evaluate Context
2773 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2775 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2778 // Copy the slot context from OutputContext to Input context
2780 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
2781 InputContext
->Slot
.Hub
= 1;
2782 InputContext
->Slot
.PortNum
= PortNum
;
2783 InputContext
->Slot
.TTT
= TTT
;
2784 InputContext
->Slot
.MTT
= MTT
;
2786 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2787 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2788 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2789 CmdTrbCfgEP
.CycleBit
= 1;
2790 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2791 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2792 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
2793 Status
= XhcCmdTransfer (
2795 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2796 XHC_GENERIC_TIMEOUT
,
2797 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2799 ASSERT (!EFI_ERROR(Status
));
2805 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
2807 @param Xhc The XHCI Instance.
2808 @param SlotId The slot id to be configured.
2809 @param PortNum The total number of downstream port supported by the hub.
2810 @param TTT The TT think time of the hub device.
2811 @param MTT The multi-TT of the hub device.
2813 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
2817 XhcConfigHubContext64 (
2818 IN USB_XHCI_INSTANCE
*Xhc
,
2827 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2828 INPUT_CONTEXT_64
*InputContext
;
2829 DEVICE_CONTEXT_64
*OutputContext
;
2830 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2832 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
2833 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2834 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2837 // 4.6.7 Evaluate Context
2839 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2841 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2844 // Copy the slot context from OutputContext to Input context
2846 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
2847 InputContext
->Slot
.Hub
= 1;
2848 InputContext
->Slot
.PortNum
= PortNum
;
2849 InputContext
->Slot
.TTT
= TTT
;
2850 InputContext
->Slot
.MTT
= MTT
;
2852 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2853 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (InputContext
);
2854 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (InputContext
);
2855 CmdTrbCfgEP
.CycleBit
= 1;
2856 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2857 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2858 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
2859 Status
= XhcCmdTransfer (
2861 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2862 XHC_GENERIC_TIMEOUT
,
2863 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2865 ASSERT (!EFI_ERROR(Status
));