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
,
648 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
649 CMD_TRB_RESET_ENDPOINT CmdTrbResetED
;
650 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq
;
653 EFI_PHYSICAL_ADDRESS PhyAddr
;
655 Status
= EFI_SUCCESS
;
656 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
658 return EFI_DEVICE_ERROR
;
660 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
663 DEBUG ((EFI_D_INFO
, "Recovery Halted Slot = %x,Dci = %x\n", SlotId
, Dci
));
666 // 1) Send Reset endpoint command to transit from halt to stop state
668 ZeroMem (&CmdTrbResetED
, sizeof (CmdTrbResetED
));
669 CmdTrbResetED
.CycleBit
= 1;
670 CmdTrbResetED
.Type
= TRB_TYPE_RESET_ENDPOINT
;
671 CmdTrbResetED
.EDID
= Dci
;
672 CmdTrbResetED
.SlotId
= SlotId
;
673 Status
= XhcCmdTransfer (
675 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbResetED
,
677 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
679 if (EFI_ERROR(Status
)) {
680 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status
));
685 // 2)Set dequeue pointer
687 ZeroMem (&CmdSetTRDeq
, sizeof (CmdSetTRDeq
));
688 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Urb
->Ring
->RingEnqueue
, sizeof (CMD_SET_TR_DEQ_POINTER
));
689 CmdSetTRDeq
.PtrLo
= XHC_LOW_32BIT (PhyAddr
) | Urb
->Ring
->RingPCS
;
690 CmdSetTRDeq
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
691 CmdSetTRDeq
.CycleBit
= 1;
692 CmdSetTRDeq
.Type
= TRB_TYPE_SET_TR_DEQUE
;
693 CmdSetTRDeq
.Endpoint
= Dci
;
694 CmdSetTRDeq
.SlotId
= SlotId
;
695 Status
= XhcCmdTransfer (
697 (TRB_TEMPLATE
*) (UINTN
) &CmdSetTRDeq
,
699 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
701 if (EFI_ERROR(Status
)) {
702 DEBUG ((EFI_D_ERROR
, "XhcRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status
));
707 // 3)Ring the doorbell to transit from stop to active
709 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
716 Create XHCI event ring.
718 @param Xhc The XHCI Instance.
719 @param EventRing The created event ring.
724 IN USB_XHCI_INSTANCE
*Xhc
,
725 OUT EVENT_RING
*EventRing
729 EVENT_RING_SEG_TABLE_ENTRY
*ERSTBase
;
731 EFI_PHYSICAL_ADDRESS ERSTPhy
;
732 EFI_PHYSICAL_ADDRESS DequeuePhy
;
734 ASSERT (EventRing
!= NULL
);
736 Size
= sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
;
737 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
738 ASSERT (Buf
!= NULL
);
739 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
742 EventRing
->EventRingSeg0
= Buf
;
743 EventRing
->TrbNumber
= EVENT_RING_TRB_NUMBER
;
744 EventRing
->EventRingDequeue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
745 EventRing
->EventRingEnqueue
= (TRB_TEMPLATE
*) EventRing
->EventRingSeg0
;
747 DequeuePhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, Size
);
750 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
751 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
753 EventRing
->EventRingCCS
= 1;
755 Size
= sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
;
756 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, Size
);
757 ASSERT (Buf
!= NULL
);
758 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
761 ERSTBase
= (EVENT_RING_SEG_TABLE_ENTRY
*) Buf
;
762 EventRing
->ERSTBase
= ERSTBase
;
763 ERSTBase
->PtrLo
= XHC_LOW_32BIT (DequeuePhy
);
764 ERSTBase
->PtrHi
= XHC_HIGH_32BIT (DequeuePhy
);
765 ERSTBase
->RingTrbSize
= EVENT_RING_TRB_NUMBER
;
767 ERSTPhy
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, ERSTBase
, Size
);
770 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)
778 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)
780 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
781 // So divide it to two 32-bytes width register access.
786 XHC_LOW_32BIT((UINT64
)(UINTN
)DequeuePhy
)
791 XHC_HIGH_32BIT((UINT64
)(UINTN
)DequeuePhy
)
794 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)
796 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
797 // So divide it to two 32-bytes width register access.
802 XHC_LOW_32BIT((UINT64
)(UINTN
)ERSTPhy
)
806 XHC_ERSTBA_OFFSET
+ 4,
807 XHC_HIGH_32BIT((UINT64
)(UINTN
)ERSTPhy
)
810 // Need set IMAN IE bit to enble the ring interrupt
812 XhcSetRuntimeRegBit (Xhc
, XHC_IMAN_OFFSET
, XHC_IMAN_IE
);
816 Create XHCI transfer ring.
818 @param Xhc The XHCI Instance.
819 @param TrbNum The number of TRB in the ring.
820 @param TransferRing The created transfer ring.
825 IN USB_XHCI_INSTANCE
*Xhc
,
827 OUT TRANSFER_RING
*TransferRing
832 EFI_PHYSICAL_ADDRESS PhyAddr
;
834 Buf
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (TRB_TEMPLATE
) * TrbNum
);
835 ASSERT (Buf
!= NULL
);
836 ASSERT (((UINTN
) Buf
& 0x3F) == 0);
837 ZeroMem (Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
839 TransferRing
->RingSeg0
= Buf
;
840 TransferRing
->TrbNumber
= TrbNum
;
841 TransferRing
->RingEnqueue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
842 TransferRing
->RingDequeue
= (TRB_TEMPLATE
*) TransferRing
->RingSeg0
;
843 TransferRing
->RingPCS
= 1;
845 // 4.9.2 Transfer Ring Management
846 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
847 // point to the first TRB in the ring.
849 EndTrb
= (LINK_TRB
*) ((UINTN
)Buf
+ sizeof (TRB_TEMPLATE
) * (TrbNum
- 1));
850 EndTrb
->Type
= TRB_TYPE_LINK
;
851 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Buf
, sizeof (TRB_TEMPLATE
) * TrbNum
);
852 EndTrb
->PtrLo
= XHC_LOW_32BIT (PhyAddr
);
853 EndTrb
->PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
855 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
859 // Set Cycle bit as other TRB PCS init value
861 EndTrb
->CycleBit
= 0;
865 Free XHCI event ring.
867 @param Xhc The XHCI Instance.
868 @param EventRing The event ring to be freed.
874 IN USB_XHCI_INSTANCE
*Xhc
,
875 IN EVENT_RING
*EventRing
878 if(EventRing
->EventRingSeg0
== NULL
) {
883 // Free EventRing Segment 0
885 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->EventRingSeg0
, sizeof (TRB_TEMPLATE
) * EVENT_RING_TRB_NUMBER
);
890 UsbHcFreeMem (Xhc
->MemPool
, EventRing
->ERSTBase
, sizeof (EVENT_RING_SEG_TABLE_ENTRY
) * ERST_NUMBER
);
895 Free the resouce allocated at initializing schedule.
897 @param Xhc The XHCI Instance.
902 IN USB_XHCI_INSTANCE
*Xhc
906 UINT64
*ScratchEntry
;
908 if (Xhc
->ScratchBuf
!= NULL
) {
909 ScratchEntry
= Xhc
->ScratchEntry
;
910 for (Index
= 0; Index
< Xhc
->MaxScratchpadBufs
; Index
++) {
912 // Free Scratchpad Buffers
914 UsbHcFreeAlignedPages (Xhc
->PciIo
, (VOID
*)(UINTN
)ScratchEntry
[Index
], EFI_SIZE_TO_PAGES (Xhc
->PageSize
), (VOID
*) Xhc
->ScratchEntryMap
[Index
]);
917 // Free Scratchpad Buffer Array
919 UsbHcFreeAlignedPages (Xhc
->PciIo
, Xhc
->ScratchBuf
, EFI_SIZE_TO_PAGES (Xhc
->MaxScratchpadBufs
* sizeof (UINT64
)), Xhc
->ScratchMap
);
920 FreePool (Xhc
->ScratchEntryMap
);
921 FreePool (Xhc
->ScratchEntry
);
924 if (Xhc
->CmdRing
.RingSeg0
!= NULL
) {
925 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->CmdRing
.RingSeg0
, sizeof (TRB_TEMPLATE
) * CMD_RING_TRB_NUMBER
);
926 Xhc
->CmdRing
.RingSeg0
= NULL
;
929 XhcFreeEventRing (Xhc
,&Xhc
->EventRing
);
931 if (Xhc
->DCBAA
!= NULL
) {
932 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->DCBAA
, (Xhc
->MaxSlotsEn
+ 1) * sizeof(UINT64
));
937 // Free memory pool at last
939 if (Xhc
->MemPool
!= NULL
) {
940 UsbHcFreeMemPool (Xhc
->MemPool
);
946 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.
948 @param Xhc The XHCI Instance.
949 @param Trb The TRB to be checked.
950 @param Urb The pointer to the matched Urb.
952 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.
953 @retval FALSE The Trb is not matched with any URBs in the async list.
958 IN USB_XHCI_INSTANCE
*Xhc
,
959 IN TRB_TEMPLATE
*Trb
,
965 TRB_TEMPLATE
*CheckedTrb
;
969 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
970 CheckedUrb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
971 CheckedTrb
= CheckedUrb
->TrbStart
;
972 for (Index
= 0; Index
< CheckedUrb
->TrbNum
; Index
++) {
973 if (Trb
== CheckedTrb
) {
978 if ((UINTN
)CheckedTrb
>= ((UINTN
) CheckedUrb
->Ring
->RingSeg0
+ sizeof (TRB_TEMPLATE
) * CheckedUrb
->Ring
->TrbNumber
)) {
979 CheckedTrb
= (TRB_TEMPLATE
*) CheckedUrb
->Ring
->RingSeg0
;
988 Check if the Trb is a transaction of the URB.
990 @param Trb The TRB to be checked
991 @param Urb The transfer ring to be checked.
993 @retval TRUE It is a transaction of the URB.
994 @retval FALSE It is not any transaction of the URB.
999 IN TRB_TEMPLATE
*Trb
,
1003 TRB_TEMPLATE
*CheckedTrb
;
1006 CheckedTrb
= Urb
->Ring
->RingSeg0
;
1008 ASSERT (Urb
->Ring
->TrbNumber
== CMD_RING_TRB_NUMBER
|| Urb
->Ring
->TrbNumber
== TR_RING_TRB_NUMBER
);
1010 for (Index
= 0; Index
< Urb
->Ring
->TrbNumber
; Index
++) {
1011 if (Trb
== CheckedTrb
) {
1021 Check the URB's execution result and update the URB's
1024 @param Xhc The XHCI Instance.
1025 @param Urb The URB to check result.
1027 @return Whether the result of URB transfer is finialized.
1032 IN USB_XHCI_INSTANCE
*Xhc
,
1036 EVT_TRB_TRANSFER
*EvtTrb
;
1037 TRB_TEMPLATE
*TRBPtr
;
1046 EFI_PHYSICAL_ADDRESS PhyAddr
;
1048 ASSERT ((Xhc
!= NULL
) && (Urb
!= NULL
));
1050 Status
= EFI_SUCCESS
;
1053 if (Urb
->Finished
) {
1059 if (XhcIsHalt (Xhc
) || XhcIsSysError (Xhc
)) {
1060 Urb
->Result
|= EFI_USB_ERR_SYSTEM
;
1065 // Traverse the event ring to find out all new events from the previous check.
1067 XhcSyncEventRing (Xhc
, &Xhc
->EventRing
);
1068 for (Index
= 0; Index
< Xhc
->EventRing
.TrbNumber
; Index
++) {
1069 Status
= XhcCheckNewEvent (Xhc
, &Xhc
->EventRing
, ((TRB_TEMPLATE
**)&EvtTrb
));
1070 if (Status
== EFI_NOT_READY
) {
1072 // All new events are handled, return directly.
1078 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.
1080 if ((EvtTrb
->Type
!= TRB_TYPE_COMMAND_COMPLT_EVENT
) && (EvtTrb
->Type
!= TRB_TYPE_TRANS_EVENT
)) {
1085 // Need convert pci device address to host address
1087 PhyAddr
= (EFI_PHYSICAL_ADDRESS
)(EvtTrb
->TRBPtrLo
| LShiftU64 ((UINT64
) EvtTrb
->TRBPtrHi
, 32));
1088 TRBPtr
= (TRB_TEMPLATE
*)(UINTN
) UsbHcGetHostAddrForPciAddr (Xhc
->MemPool
, (VOID
*)(UINTN
) PhyAddr
, sizeof (TRB_TEMPLATE
));
1091 // Update the status of Urb according to the finished event regardless of whether
1092 // the urb is current checked one or in the XHCI's async transfer list.
1093 // This way is used to avoid that those completed async transfer events don't get
1094 // handled in time and are flushed by newer coming events.
1096 if (IsTransferRingTrb (TRBPtr
, Urb
)) {
1098 } else if (IsAsyncIntTrb (Xhc
, TRBPtr
, &AsyncUrb
)) {
1099 CheckedUrb
= AsyncUrb
;
1104 switch (EvtTrb
->Completecode
) {
1105 case TRB_COMPLETION_STALL_ERROR
:
1106 CheckedUrb
->Result
|= EFI_USB_ERR_STALL
;
1107 CheckedUrb
->Finished
= TRUE
;
1108 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1111 case TRB_COMPLETION_BABBLE_ERROR
:
1112 CheckedUrb
->Result
|= EFI_USB_ERR_BABBLE
;
1113 CheckedUrb
->Finished
= TRUE
;
1114 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1117 case TRB_COMPLETION_DATA_BUFFER_ERROR
:
1118 CheckedUrb
->Result
|= EFI_USB_ERR_BUFFER
;
1119 CheckedUrb
->Finished
= TRUE
;
1120 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb
->Completecode
));
1123 case TRB_COMPLETION_USB_TRANSACTION_ERROR
:
1124 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1125 CheckedUrb
->Finished
= TRUE
;
1126 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb
->Completecode
));
1129 case TRB_COMPLETION_SHORT_PACKET
:
1130 case TRB_COMPLETION_SUCCESS
:
1131 if (EvtTrb
->Completecode
== TRB_COMPLETION_SHORT_PACKET
) {
1132 DEBUG ((EFI_D_ERROR
, "XhcCheckUrbResult: short packet happens!\n"));
1135 TRBType
= (UINT8
) (TRBPtr
->Type
);
1136 if ((TRBType
== TRB_TYPE_DATA_STAGE
) ||
1137 (TRBType
== TRB_TYPE_NORMAL
) ||
1138 (TRBType
== TRB_TYPE_ISOCH
)) {
1139 CheckedUrb
->Completed
+= (((TRANSFER_TRB_NORMAL
*)TRBPtr
)->Length
- EvtTrb
->Length
);
1145 DEBUG ((EFI_D_ERROR
, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb
->Completecode
));
1146 CheckedUrb
->Result
|= EFI_USB_ERR_TIMEOUT
;
1147 CheckedUrb
->Finished
= TRUE
;
1152 // Only check first and end Trb event address
1154 if (TRBPtr
== CheckedUrb
->TrbStart
) {
1155 CheckedUrb
->StartDone
= TRUE
;
1158 if (TRBPtr
== CheckedUrb
->TrbEnd
) {
1159 CheckedUrb
->EndDone
= TRUE
;
1162 if (CheckedUrb
->StartDone
&& CheckedUrb
->EndDone
) {
1163 CheckedUrb
->Finished
= TRUE
;
1164 CheckedUrb
->EvtTrb
= (TRB_TEMPLATE
*)EvtTrb
;
1171 // Advance event ring to last available entry
1173 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1174 // So divide it to two 32-bytes width register access.
1176 Low
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
);
1177 High
= XhcReadRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4);
1178 XhcDequeue
= (UINT64
)(LShiftU64((UINT64
)High
, 32) | Low
);
1180 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->EventRing
.EventRingDequeue
, sizeof (TRB_TEMPLATE
));
1182 if ((XhcDequeue
& (~0x0F)) != (PhyAddr
& (~0x0F))) {
1184 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,
1185 // So divide it to two 32-bytes width register access.
1187 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
, XHC_LOW_32BIT (PhyAddr
) | BIT3
);
1188 XhcWriteRuntimeReg (Xhc
, XHC_ERDP_OFFSET
+ 4, XHC_HIGH_32BIT (PhyAddr
));
1191 return Urb
->Finished
;
1196 Execute the transfer by polling the URB. This is a synchronous operation.
1198 @param Xhc The XHCI Instance.
1199 @param CmdTransfer The executed URB is for cmd transfer or not.
1200 @param Urb The URB to execute.
1201 @param Timeout The time to wait before abort, in millisecond.
1203 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
1204 @return EFI_TIMEOUT The transfer failed due to time out.
1205 @return EFI_SUCCESS The transfer finished OK.
1210 IN USB_XHCI_INSTANCE
*Xhc
,
1211 IN BOOLEAN CmdTransfer
,
1227 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1229 return EFI_DEVICE_ERROR
;
1231 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1235 Status
= EFI_SUCCESS
;
1236 Loop
= Timeout
* XHC_1_MILLISECOND
;
1241 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1243 for (Index
= 0; Index
< Loop
; Index
++) {
1244 Finished
= XhcCheckUrbResult (Xhc
, Urb
);
1248 gBS
->Stall (XHC_1_MICROSECOND
);
1251 if (Index
== Loop
) {
1252 Urb
->Result
= EFI_USB_ERR_TIMEOUT
;
1253 Status
= EFI_TIMEOUT
;
1254 } else if (Urb
->Result
!= EFI_USB_NOERROR
) {
1255 Status
= EFI_DEVICE_ERROR
;
1262 Delete a single asynchronous interrupt transfer for
1263 the device and endpoint.
1265 @param Xhc The XHCI Instance.
1266 @param BusAddr The logical device address assigned by UsbBus driver.
1267 @param EpNum The endpoint of the target.
1269 @retval EFI_SUCCESS An asynchronous transfer is removed.
1270 @retval EFI_NOT_FOUND No transfer for the device is found.
1274 XhciDelAsyncIntTransfer (
1275 IN USB_XHCI_INSTANCE
*Xhc
,
1283 EFI_USB_DATA_DIRECTION Direction
;
1285 Direction
= ((EpNum
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
;
1290 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1291 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1292 if ((Urb
->Ep
.BusAddr
== BusAddr
) &&
1293 (Urb
->Ep
.EpAddr
== EpNum
) &&
1294 (Urb
->Ep
.Direction
== Direction
)) {
1295 RemoveEntryList (&Urb
->UrbList
);
1296 FreePool (Urb
->Data
);
1297 XhcFreeUrb (Xhc
, Urb
);
1302 return EFI_NOT_FOUND
;
1306 Remove all the asynchronous interrutp transfers.
1308 @param Xhc The XHCI Instance.
1312 XhciDelAllAsyncIntTransfers (
1313 IN USB_XHCI_INSTANCE
*Xhc
1320 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1321 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1322 RemoveEntryList (&Urb
->UrbList
);
1323 FreePool (Urb
->Data
);
1324 XhcFreeUrb (Xhc
, Urb
);
1329 Update the queue head for next round of asynchronous transfer
1331 @param Xhc The XHCI Instance.
1332 @param Urb The URB to update
1336 XhcUpdateAsyncRequest (
1337 IN USB_XHCI_INSTANCE
*Xhc
,
1343 if (Urb
->Result
== EFI_USB_NOERROR
) {
1344 Status
= XhcCreateTransferTrb (Xhc
, Urb
);
1345 if (EFI_ERROR (Status
)) {
1348 Status
= RingIntTransferDoorBell (Xhc
, Urb
);
1349 if (EFI_ERROR (Status
)) {
1356 Flush data from PCI controller specific address to mapped system
1359 @param Xhc The XHCI device.
1360 @param Urb The URB to unmap.
1362 @retval EFI_SUCCESS Success to flush data to mapped system memory.
1363 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.
1367 XhcFlushAsyncIntMap (
1368 IN USB_XHCI_INSTANCE
*Xhc
,
1373 EFI_PHYSICAL_ADDRESS PhyAddr
;
1374 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
1375 EFI_PCI_IO_PROTOCOL
*PciIo
;
1382 if (Urb
->Ep
.Direction
== EfiUsbDataIn
) {
1383 MapOp
= EfiPciIoOperationBusMasterWrite
;
1385 MapOp
= EfiPciIoOperationBusMasterRead
;
1388 if (Urb
->DataMap
!= NULL
) {
1389 Status
= PciIo
->Unmap (PciIo
, Urb
->DataMap
);
1390 if (EFI_ERROR (Status
)) {
1395 Urb
->DataMap
= NULL
;
1397 Status
= PciIo
->Map (PciIo
, MapOp
, Urb
->Data
, &Len
, &PhyAddr
, &Map
);
1398 if (EFI_ERROR (Status
) || (Len
!= Urb
->DataLen
)) {
1402 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
1407 return EFI_DEVICE_ERROR
;
1411 Interrupt transfer periodic check handler.
1413 @param Event Interrupt event.
1414 @param Context Pointer to USB_XHCI_INSTANCE.
1419 XhcMonitorAsyncRequests (
1424 USB_XHCI_INSTANCE
*Xhc
;
1433 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1435 Xhc
= (USB_XHCI_INSTANCE
*) Context
;
1437 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, &Xhc
->AsyncIntTransfers
) {
1438 Urb
= EFI_LIST_CONTAINER (Entry
, URB
, UrbList
);
1441 // Make sure that the device is available before every check.
1443 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1449 // Check the result of URB execution. If it is still
1450 // active, check the next one.
1452 XhcCheckUrbResult (Xhc
, Urb
);
1454 if (!Urb
->Finished
) {
1459 // Flush any PCI posted write transactions from a PCI host
1460 // bridge to system memory.
1462 Status
= XhcFlushAsyncIntMap (Xhc
, Urb
);
1463 if (EFI_ERROR (Status
)) {
1464 DEBUG ((EFI_D_ERROR
, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1468 // Allocate a buffer then copy the transferred data for user.
1469 // If failed to allocate the buffer, update the URB for next
1470 // round of transfer. Ignore the data of this round.
1473 if (Urb
->Result
== EFI_USB_NOERROR
) {
1474 ASSERT (Urb
->Completed
<= Urb
->DataLen
);
1476 ProcBuf
= AllocateZeroPool (Urb
->Completed
);
1478 if (ProcBuf
== NULL
) {
1479 XhcUpdateAsyncRequest (Xhc
, Urb
);
1483 CopyMem (ProcBuf
, Urb
->Data
, Urb
->Completed
);
1487 // Leave error recovery to its related device driver. A
1488 // common case of the error recovery is to re-submit the
1489 // interrupt transfer which is linked to the head of the
1490 // list. This function scans from head to tail. So the
1491 // re-submitted interrupt transfer's callback function
1492 // will not be called again in this round. Don't touch this
1493 // URB after the callback, it may have been removed by the
1496 if (Urb
->Callback
!= NULL
) {
1498 // Restore the old TPL, USB bus maybe connect device in
1499 // his callback. Some drivers may has a lower TPL restriction.
1501 gBS
->RestoreTPL (OldTpl
);
1502 (Urb
->Callback
) (ProcBuf
, Urb
->Completed
, Urb
->Context
, Urb
->Result
);
1503 OldTpl
= gBS
->RaiseTPL (XHC_TPL
);
1506 if (ProcBuf
!= NULL
) {
1507 gBS
->FreePool (ProcBuf
);
1510 XhcUpdateAsyncRequest (Xhc
, Urb
);
1512 gBS
->RestoreTPL (OldTpl
);
1516 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.
1518 @param Xhc The XHCI Instance.
1519 @param ParentRouteChart The route string pointed to the parent device if it exists.
1520 @param Port The port to be polled.
1521 @param PortState The port state.
1523 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.
1524 @retval Others Should not appear.
1529 XhcPollPortStatusChange (
1530 IN USB_XHCI_INSTANCE
*Xhc
,
1531 IN USB_DEV_ROUTE ParentRouteChart
,
1533 IN EFI_USB_PORT_STATUS
*PortState
1539 USB_DEV_ROUTE RouteChart
;
1541 Status
= EFI_SUCCESS
;
1543 if ((PortState
->PortChangeStatus
& (USB_PORT_STAT_C_CONNECTION
| USB_PORT_STAT_C_ENABLE
| USB_PORT_STAT_C_OVERCURRENT
| USB_PORT_STAT_C_RESET
)) == 0) {
1547 if (ParentRouteChart
.Dword
== 0) {
1548 RouteChart
.Route
.RouteString
= 0;
1549 RouteChart
.Route
.RootPortNum
= Port
+ 1;
1550 RouteChart
.Route
.TierNum
= 1;
1553 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (Port
<< (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1555 RouteChart
.Route
.RouteString
= ParentRouteChart
.Route
.RouteString
| (15 << (4 * (ParentRouteChart
.Route
.TierNum
- 1)));
1557 RouteChart
.Route
.RootPortNum
= ParentRouteChart
.Route
.RootPortNum
;
1558 RouteChart
.Route
.TierNum
= ParentRouteChart
.Route
.TierNum
+ 1;
1561 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1563 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1564 Status
= XhcDisableSlotCmd (Xhc
, SlotId
);
1566 Status
= XhcDisableSlotCmd64 (Xhc
, SlotId
);
1570 if (((PortState
->PortStatus
& USB_PORT_STAT_ENABLE
) != 0) &&
1571 ((PortState
->PortStatus
& USB_PORT_STAT_CONNECTION
) != 0)) {
1573 // Has a device attached, Identify device speed after port is enabled.
1575 Speed
= EFI_USB_SPEED_FULL
;
1576 if ((PortState
->PortStatus
& USB_PORT_STAT_LOW_SPEED
) != 0) {
1577 Speed
= EFI_USB_SPEED_LOW
;
1578 } else if ((PortState
->PortStatus
& USB_PORT_STAT_HIGH_SPEED
) != 0) {
1579 Speed
= EFI_USB_SPEED_HIGH
;
1580 } else if ((PortState
->PortStatus
& USB_PORT_STAT_SUPER_SPEED
) != 0) {
1581 Speed
= EFI_USB_SPEED_SUPER
;
1584 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
1586 SlotId
= XhcRouteStringToSlotId (Xhc
, RouteChart
);
1587 if ((SlotId
== 0) && ((PortState
->PortChangeStatus
& USB_PORT_STAT_C_RESET
) != 0)) {
1588 if (Xhc
->HcCParams
.Data
.Csz
== 0) {
1589 Status
= XhcInitializeDeviceSlot (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1591 Status
= XhcInitializeDeviceSlot64 (Xhc
, ParentRouteChart
, Port
, RouteChart
, Speed
);
1601 Calculate the device context index by endpoint address and direction.
1603 @param EpAddr The target endpoint number.
1604 @param Direction The direction of the target endpoint.
1606 @return The device context index of endpoint.
1620 Index
= (UINT8
) (2 * EpAddr
);
1621 if (Direction
== EfiUsbDataIn
) {
1629 Find out the actual device address according to the requested device address from UsbBus.
1631 @param Xhc The XHCI Instance.
1632 @param BusDevAddr The requested device address by UsbBus upper driver.
1634 @return The actual device address assigned to the device.
1639 XhcBusDevAddrToSlotId (
1640 IN USB_XHCI_INSTANCE
*Xhc
,
1646 for (Index
= 0; Index
< 255; Index
++) {
1647 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1648 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1649 (Xhc
->UsbDevContext
[Index
+ 1].BusDevAddr
== BusDevAddr
)) {
1658 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1662 Find out the slot id according to the device's route string.
1664 @param Xhc The XHCI Instance.
1665 @param RouteString The route string described the device location.
1667 @return The slot id used by the device.
1672 XhcRouteStringToSlotId (
1673 IN USB_XHCI_INSTANCE
*Xhc
,
1674 IN USB_DEV_ROUTE RouteString
1679 for (Index
= 0; Index
< 255; Index
++) {
1680 if (Xhc
->UsbDevContext
[Index
+ 1].Enabled
&&
1681 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
!= 0) &&
1682 (Xhc
->UsbDevContext
[Index
+ 1].RouteString
.Dword
== RouteString
.Dword
)) {
1691 return Xhc
->UsbDevContext
[Index
+ 1].SlotId
;
1695 Synchronize the specified event ring to update the enqueue and dequeue pointer.
1697 @param Xhc The XHCI Instance.
1698 @param EvtRing The event ring to sync.
1700 @retval EFI_SUCCESS The event ring is synchronized successfully.
1706 IN USB_XHCI_INSTANCE
*Xhc
,
1707 IN EVENT_RING
*EvtRing
1711 TRB_TEMPLATE
*EvtTrb1
;
1713 ASSERT (EvtRing
!= NULL
);
1716 // Calculate the EventRingEnqueue and EventRingCCS.
1717 // Note: only support single Segment
1719 EvtTrb1
= EvtRing
->EventRingDequeue
;
1721 for (Index
= 0; Index
< EvtRing
->TrbNumber
; Index
++) {
1722 if (EvtTrb1
->CycleBit
!= EvtRing
->EventRingCCS
) {
1728 if ((UINTN
)EvtTrb1
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1729 EvtTrb1
= EvtRing
->EventRingSeg0
;
1730 EvtRing
->EventRingCCS
= (EvtRing
->EventRingCCS
) ? 0 : 1;
1734 if (Index
< EvtRing
->TrbNumber
) {
1735 EvtRing
->EventRingEnqueue
= EvtTrb1
;
1744 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.
1746 @param Xhc The XHCI Instance.
1747 @param TrsRing The transfer ring to sync.
1749 @retval EFI_SUCCESS The transfer ring is synchronized successfully.
1755 IN USB_XHCI_INSTANCE
*Xhc
,
1756 IN TRANSFER_RING
*TrsRing
1760 TRB_TEMPLATE
*TrsTrb
;
1762 ASSERT (TrsRing
!= NULL
);
1764 // Calculate the latest RingEnqueue and RingPCS
1766 TrsTrb
= TrsRing
->RingEnqueue
;
1767 ASSERT (TrsTrb
!= NULL
);
1769 for (Index
= 0; Index
< TrsRing
->TrbNumber
; Index
++) {
1770 if (TrsTrb
->CycleBit
!= (TrsRing
->RingPCS
& BIT0
)) {
1774 if ((UINT8
) TrsTrb
->Type
== TRB_TYPE_LINK
) {
1775 ASSERT (((LINK_TRB
*)TrsTrb
)->TC
!= 0);
1777 // set cycle bit in Link TRB as normal
1779 ((LINK_TRB
*)TrsTrb
)->CycleBit
= TrsRing
->RingPCS
& BIT0
;
1781 // Toggle PCS maintained by software
1783 TrsRing
->RingPCS
= (TrsRing
->RingPCS
& BIT0
) ? 0 : 1;
1784 TrsTrb
= (TRB_TEMPLATE
*) TrsRing
->RingSeg0
; // Use host address
1788 ASSERT (Index
!= TrsRing
->TrbNumber
);
1790 if (TrsTrb
!= TrsRing
->RingEnqueue
) {
1791 TrsRing
->RingEnqueue
= TrsTrb
;
1795 // Clear the Trb context for enqueue, but reserve the PCS bit
1797 TrsTrb
->Parameter1
= 0;
1798 TrsTrb
->Parameter2
= 0;
1802 TrsTrb
->Control
= 0;
1808 Check if there is a new generated event.
1810 @param Xhc The XHCI Instance.
1811 @param EvtRing The event ring to check.
1812 @param NewEvtTrb The new event TRB found.
1814 @retval EFI_SUCCESS Found a new event TRB at the event ring.
1815 @retval EFI_NOT_READY The event ring has no new event.
1821 IN USB_XHCI_INSTANCE
*Xhc
,
1822 IN EVENT_RING
*EvtRing
,
1823 OUT TRB_TEMPLATE
**NewEvtTrb
1826 ASSERT (EvtRing
!= NULL
);
1828 *NewEvtTrb
= EvtRing
->EventRingDequeue
;
1830 if (EvtRing
->EventRingDequeue
== EvtRing
->EventRingEnqueue
) {
1831 return EFI_NOT_READY
;
1834 EvtRing
->EventRingDequeue
++;
1836 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.
1838 if ((UINTN
)EvtRing
->EventRingDequeue
>= ((UINTN
) EvtRing
->EventRingSeg0
+ sizeof (TRB_TEMPLATE
) * EvtRing
->TrbNumber
)) {
1839 EvtRing
->EventRingDequeue
= EvtRing
->EventRingSeg0
;
1846 Ring the door bell to notify XHCI there is a transaction to be executed.
1848 @param Xhc The XHCI Instance.
1849 @param SlotId The slot id of the target device.
1850 @param Dci The device context index of the target slot or endpoint.
1852 @retval EFI_SUCCESS Successfully ring the door bell.
1858 IN USB_XHCI_INSTANCE
*Xhc
,
1864 XhcWriteDoorBellReg (Xhc
, 0, 0);
1866 XhcWriteDoorBellReg (Xhc
, SlotId
* sizeof (UINT32
), Dci
);
1873 Ring the door bell to notify XHCI there is a transaction to be executed through URB.
1875 @param Xhc The XHCI Instance.
1876 @param Urb The URB to be rung.
1878 @retval EFI_SUCCESS Successfully ring the door bell.
1882 RingIntTransferDoorBell (
1883 IN USB_XHCI_INSTANCE
*Xhc
,
1890 SlotId
= XhcBusDevAddrToSlotId (Xhc
, Urb
->Ep
.BusAddr
);
1891 Dci
= XhcEndpointToDci (Urb
->Ep
.EpAddr
, (UINT8
)(Urb
->Ep
.Direction
));
1892 XhcRingDoorBell (Xhc
, SlotId
, Dci
);
1897 Assign and initialize the device slot for a new device.
1899 @param Xhc The XHCI Instance.
1900 @param ParentRouteChart The route string pointed to the parent device.
1901 @param ParentPort The port at which the device is located.
1902 @param RouteChart The route string pointed to the device.
1903 @param DeviceSpeed The device speed.
1905 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
1910 XhcInitializeDeviceSlot (
1911 IN USB_XHCI_INSTANCE
*Xhc
,
1912 IN USB_DEV_ROUTE ParentRouteChart
,
1913 IN UINT16 ParentPort
,
1914 IN USB_DEV_ROUTE RouteChart
,
1915 IN UINT8 DeviceSpeed
1919 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
1920 INPUT_CONTEXT
*InputContext
;
1921 DEVICE_CONTEXT
*OutputContext
;
1922 TRANSFER_RING
*EndpointTransferRing
;
1923 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
1924 UINT8 DeviceAddress
;
1925 CMD_TRB_ENABLE_SLOT CmdTrb
;
1928 DEVICE_CONTEXT
*ParentDeviceContext
;
1929 EFI_PHYSICAL_ADDRESS PhyAddr
;
1931 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
1932 CmdTrb
.CycleBit
= 1;
1933 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
1935 Status
= XhcCmdTransfer (
1937 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
1938 XHC_GENERIC_TIMEOUT
,
1939 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
1941 if (EFI_ERROR (Status
)) {
1942 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status
));
1945 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
1946 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
1947 SlotId
= (UINT8
)EvtTrb
->SlotId
;
1948 ASSERT (SlotId
!= 0);
1950 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
1951 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
1952 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
1953 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
1954 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
1957 // 4.3.3 Device Slot Initialization
1958 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
1960 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT
));
1961 ASSERT (InputContext
!= NULL
);
1962 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
1963 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
1965 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
1968 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
1969 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
1970 // Context are affected by the command.
1972 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
1975 // 3) Initialize the Input Slot Context data structure
1977 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
1978 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
1979 InputContext
->Slot
.ContextEntries
= 1;
1980 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
1982 if (RouteChart
.Route
.RouteString
) {
1984 // The device is behind of hub device.
1986 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
1987 ASSERT (ParentSlotId
!= 0);
1989 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
1991 ParentDeviceContext
= (DEVICE_CONTEXT
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
1992 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
1993 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
1994 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
1996 // Full/Low device attached to High speed hub port that isolates the high speed signaling
1997 // environment from Full/Low speed signaling environment for a device
1999 InputContext
->Slot
.TTPortNum
= ParentPort
;
2000 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2004 // Inherit the TT parameters from parent device.
2006 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2007 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2009 // If the device is a High speed device then down the speed to be the same as its parent Hub
2011 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2012 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2018 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2020 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2021 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2022 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2024 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2026 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2028 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2029 InputContext
->EP
[0].MaxPacketSize
= 512;
2030 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2031 InputContext
->EP
[0].MaxPacketSize
= 64;
2033 InputContext
->EP
[0].MaxPacketSize
= 8;
2036 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2037 // 1KB, and Bulk and Isoch endpoints 3KB.
2039 InputContext
->EP
[0].AverageTRBLength
= 8;
2040 InputContext
->EP
[0].MaxBurstSize
= 0;
2041 InputContext
->EP
[0].Interval
= 0;
2042 InputContext
->EP
[0].MaxPStreams
= 0;
2043 InputContext
->EP
[0].Mult
= 0;
2044 InputContext
->EP
[0].CErr
= 3;
2047 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2049 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2051 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2052 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2054 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2055 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2058 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2060 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT
));
2061 ASSERT (OutputContext
!= NULL
);
2062 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2063 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT
));
2065 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2067 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2068 // a pointer to the Output Device Context data structure (6.2.1).
2070 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT
));
2072 // Fill DCBAA with PCI device address
2074 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2077 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2078 // Context data structure described above.
2080 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2081 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2082 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2083 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2084 CmdTrbAddr
.CycleBit
= 1;
2085 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2086 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2087 Status
= XhcCmdTransfer (
2089 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2090 XHC_GENERIC_TIMEOUT
,
2091 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2093 if (!EFI_ERROR (Status
)) {
2094 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT
*) OutputContext
)->Slot
.DeviceAddress
;
2095 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2096 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2103 Assign and initialize the device slot for a new device.
2105 @param Xhc The XHCI Instance.
2106 @param ParentRouteChart The route string pointed to the parent device.
2107 @param ParentPort The port at which the device is located.
2108 @param RouteChart The route string pointed to the device.
2109 @param DeviceSpeed The device speed.
2111 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.
2116 XhcInitializeDeviceSlot64 (
2117 IN USB_XHCI_INSTANCE
*Xhc
,
2118 IN USB_DEV_ROUTE ParentRouteChart
,
2119 IN UINT16 ParentPort
,
2120 IN USB_DEV_ROUTE RouteChart
,
2121 IN UINT8 DeviceSpeed
2125 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2126 INPUT_CONTEXT_64
*InputContext
;
2127 DEVICE_CONTEXT_64
*OutputContext
;
2128 TRANSFER_RING
*EndpointTransferRing
;
2129 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr
;
2130 UINT8 DeviceAddress
;
2131 CMD_TRB_ENABLE_SLOT CmdTrb
;
2134 DEVICE_CONTEXT_64
*ParentDeviceContext
;
2135 EFI_PHYSICAL_ADDRESS PhyAddr
;
2137 ZeroMem (&CmdTrb
, sizeof (CMD_TRB_ENABLE_SLOT
));
2138 CmdTrb
.CycleBit
= 1;
2139 CmdTrb
.Type
= TRB_TYPE_EN_SLOT
;
2141 Status
= XhcCmdTransfer (
2143 (TRB_TEMPLATE
*) (UINTN
) &CmdTrb
,
2144 XHC_GENERIC_TIMEOUT
,
2145 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2147 if (EFI_ERROR (Status
)) {
2148 DEBUG ((EFI_D_ERROR
, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status
));
2151 ASSERT (EvtTrb
->SlotId
<= Xhc
->MaxSlotsEn
);
2152 DEBUG ((EFI_D_INFO
, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb
->SlotId
));
2153 SlotId
= (UINT8
)EvtTrb
->SlotId
;
2154 ASSERT (SlotId
!= 0);
2156 ZeroMem (&Xhc
->UsbDevContext
[SlotId
], sizeof (USB_DEV_CONTEXT
));
2157 Xhc
->UsbDevContext
[SlotId
].Enabled
= TRUE
;
2158 Xhc
->UsbDevContext
[SlotId
].SlotId
= SlotId
;
2159 Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
= RouteChart
.Dword
;
2160 Xhc
->UsbDevContext
[SlotId
].ParentRouteString
.Dword
= ParentRouteChart
.Dword
;
2163 // 4.3.3 Device Slot Initialization
2164 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
2166 InputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (INPUT_CONTEXT_64
));
2167 ASSERT (InputContext
!= NULL
);
2168 ASSERT (((UINTN
) InputContext
& 0x3F) == 0);
2169 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2171 Xhc
->UsbDevContext
[SlotId
].InputContext
= (VOID
*) InputContext
;
2174 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1
2175 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input
2176 // Context are affected by the command.
2178 InputContext
->InputControlContext
.Dword2
|= (BIT0
| BIT1
);
2181 // 3) Initialize the Input Slot Context data structure
2183 InputContext
->Slot
.RouteString
= RouteChart
.Route
.RouteString
;
2184 InputContext
->Slot
.Speed
= DeviceSpeed
+ 1;
2185 InputContext
->Slot
.ContextEntries
= 1;
2186 InputContext
->Slot
.RootHubPortNum
= RouteChart
.Route
.RootPortNum
;
2188 if (RouteChart
.Route
.RouteString
) {
2190 // The device is behind of hub device.
2192 ParentSlotId
= XhcRouteStringToSlotId(Xhc
, ParentRouteChart
);
2193 ASSERT (ParentSlotId
!= 0);
2195 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context
2197 ParentDeviceContext
= (DEVICE_CONTEXT_64
*)Xhc
->UsbDevContext
[ParentSlotId
].OutputContext
;
2198 if ((ParentDeviceContext
->Slot
.TTPortNum
== 0) &&
2199 (ParentDeviceContext
->Slot
.TTHubSlotId
== 0)) {
2200 if ((ParentDeviceContext
->Slot
.Speed
== (EFI_USB_SPEED_HIGH
+ 1)) && (DeviceSpeed
< EFI_USB_SPEED_HIGH
)) {
2202 // Full/Low device attached to High speed hub port that isolates the high speed signaling
2203 // environment from Full/Low speed signaling environment for a device
2205 InputContext
->Slot
.TTPortNum
= ParentPort
;
2206 InputContext
->Slot
.TTHubSlotId
= ParentSlotId
;
2210 // Inherit the TT parameters from parent device.
2212 InputContext
->Slot
.TTPortNum
= ParentDeviceContext
->Slot
.TTPortNum
;
2213 InputContext
->Slot
.TTHubSlotId
= ParentDeviceContext
->Slot
.TTHubSlotId
;
2215 // If the device is a High speed device then down the speed to be the same as its parent Hub
2217 if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2218 InputContext
->Slot
.Speed
= ParentDeviceContext
->Slot
.Speed
;
2224 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.
2226 EndpointTransferRing
= AllocateZeroPool (sizeof (TRANSFER_RING
));
2227 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0] = EndpointTransferRing
;
2228 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0]);
2230 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).
2232 InputContext
->EP
[0].EPType
= ED_CONTROL_BIDIR
;
2234 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2235 InputContext
->EP
[0].MaxPacketSize
= 512;
2236 } else if (DeviceSpeed
== EFI_USB_SPEED_HIGH
) {
2237 InputContext
->EP
[0].MaxPacketSize
= 64;
2239 InputContext
->EP
[0].MaxPacketSize
= 8;
2242 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints
2243 // 1KB, and Bulk and Isoch endpoints 3KB.
2245 InputContext
->EP
[0].AverageTRBLength
= 8;
2246 InputContext
->EP
[0].MaxBurstSize
= 0;
2247 InputContext
->EP
[0].Interval
= 0;
2248 InputContext
->EP
[0].MaxPStreams
= 0;
2249 InputContext
->EP
[0].Mult
= 0;
2250 InputContext
->EP
[0].CErr
= 3;
2253 // Init the DCS(dequeue cycle state) as the transfer ring's CCS
2255 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2257 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[0])->RingSeg0
,
2258 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2260 InputContext
->EP
[0].PtrLo
= XHC_LOW_32BIT (PhyAddr
) | BIT0
;
2261 InputContext
->EP
[0].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2264 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
2266 OutputContext
= UsbHcAllocateMem (Xhc
->MemPool
, sizeof (DEVICE_CONTEXT_64
));
2267 ASSERT (OutputContext
!= NULL
);
2268 ASSERT (((UINTN
) OutputContext
& 0x3F) == 0);
2269 ZeroMem (OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2271 Xhc
->UsbDevContext
[SlotId
].OutputContext
= OutputContext
;
2273 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with
2274 // a pointer to the Output Device Context data structure (6.2.1).
2276 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2278 // Fill DCBAA with PCI device address
2280 Xhc
->DCBAA
[SlotId
] = (UINT64
) (UINTN
) PhyAddr
;
2283 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input
2284 // Context data structure described above.
2286 ZeroMem (&CmdTrbAddr
, sizeof (CmdTrbAddr
));
2287 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2288 CmdTrbAddr
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2289 CmdTrbAddr
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2290 CmdTrbAddr
.CycleBit
= 1;
2291 CmdTrbAddr
.Type
= TRB_TYPE_ADDRESS_DEV
;
2292 CmdTrbAddr
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2293 Status
= XhcCmdTransfer (
2295 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbAddr
,
2296 XHC_GENERIC_TIMEOUT
,
2297 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2299 if (!EFI_ERROR (Status
)) {
2300 DeviceAddress
= (UINT8
) ((DEVICE_CONTEXT_64
*) OutputContext
)->Slot
.DeviceAddress
;
2301 DEBUG ((EFI_D_INFO
, " Address %d assigned successfully\n", DeviceAddress
));
2302 Xhc
->UsbDevContext
[SlotId
].XhciDevAddr
= DeviceAddress
;
2309 Disable the specified device slot.
2311 @param Xhc The XHCI Instance.
2312 @param SlotId The slot id to be disabled.
2314 @retval EFI_SUCCESS Successfully disable the device slot.
2320 IN USB_XHCI_INSTANCE
*Xhc
,
2325 TRB_TEMPLATE
*EvtTrb
;
2326 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2331 // Disable the device slots occupied by these devices on its downstream ports.
2332 // Entry 0 is reserved.
2334 for (Index
= 0; Index
< 255; Index
++) {
2335 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2336 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2337 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2341 Status
= XhcDisableSlotCmd (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2343 if (EFI_ERROR (Status
)) {
2344 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2345 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2350 // Construct the disable slot command
2352 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2354 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2355 CmdTrbDisSlot
.CycleBit
= 1;
2356 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2357 CmdTrbDisSlot
.SlotId
= SlotId
;
2358 Status
= XhcCmdTransfer (
2360 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2361 XHC_GENERIC_TIMEOUT
,
2362 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2364 if (EFI_ERROR (Status
)) {
2365 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2369 // Free the slot's device context entry
2371 Xhc
->DCBAA
[SlotId
] = 0;
2374 // Free the slot related data structure
2376 for (Index
= 0; Index
< 31; Index
++) {
2377 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2378 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2379 if (RingSeg
!= NULL
) {
2380 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2382 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2383 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2387 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2388 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2389 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2393 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2394 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2397 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2398 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT
));
2401 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2402 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT
));
2405 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2406 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2407 // remove urb from XHCI's asynchronous transfer list.
2409 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2410 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2416 Disable the specified device slot.
2418 @param Xhc The XHCI Instance.
2419 @param SlotId The slot id to be disabled.
2421 @retval EFI_SUCCESS Successfully disable the device slot.
2426 XhcDisableSlotCmd64 (
2427 IN USB_XHCI_INSTANCE
*Xhc
,
2432 TRB_TEMPLATE
*EvtTrb
;
2433 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot
;
2438 // Disable the device slots occupied by these devices on its downstream ports.
2439 // Entry 0 is reserved.
2441 for (Index
= 0; Index
< 255; Index
++) {
2442 if (!Xhc
->UsbDevContext
[Index
+ 1].Enabled
||
2443 (Xhc
->UsbDevContext
[Index
+ 1].SlotId
== 0) ||
2444 (Xhc
->UsbDevContext
[Index
+ 1].ParentRouteString
.Dword
!= Xhc
->UsbDevContext
[SlotId
].RouteString
.Dword
)) {
2448 Status
= XhcDisableSlotCmd64 (Xhc
, Xhc
->UsbDevContext
[Index
+ 1].SlotId
);
2450 if (EFI_ERROR (Status
)) {
2451 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));
2452 Xhc
->UsbDevContext
[Index
+ 1].SlotId
= 0;
2457 // Construct the disable slot command
2459 DEBUG ((EFI_D_INFO
, "Disable device slot %d!\n", SlotId
));
2461 ZeroMem (&CmdTrbDisSlot
, sizeof (CmdTrbDisSlot
));
2462 CmdTrbDisSlot
.CycleBit
= 1;
2463 CmdTrbDisSlot
.Type
= TRB_TYPE_DIS_SLOT
;
2464 CmdTrbDisSlot
.SlotId
= SlotId
;
2465 Status
= XhcCmdTransfer (
2467 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbDisSlot
,
2468 XHC_GENERIC_TIMEOUT
,
2469 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2471 if (EFI_ERROR (Status
)) {
2472 DEBUG ((EFI_D_ERROR
, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status
));
2476 // Free the slot's device context entry
2478 Xhc
->DCBAA
[SlotId
] = 0;
2481 // Free the slot related data structure
2483 for (Index
= 0; Index
< 31; Index
++) {
2484 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] != NULL
) {
2485 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
])->RingSeg0
;
2486 if (RingSeg
!= NULL
) {
2487 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
2489 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
]);
2490 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Index
] = NULL
;
2494 for (Index
= 0; Index
< Xhc
->UsbDevContext
[SlotId
].DevDesc
.NumConfigurations
; Index
++) {
2495 if (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
] != NULL
) {
2496 FreePool (Xhc
->UsbDevContext
[SlotId
].ConfDesc
[Index
]);
2500 if (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
!= NULL
) {
2501 FreePool (Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
);
2504 if (Xhc
->UsbDevContext
[SlotId
].InputContext
!= NULL
) {
2505 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].InputContext
, sizeof (INPUT_CONTEXT_64
));
2508 if (Xhc
->UsbDevContext
[SlotId
].OutputContext
!= NULL
) {
2509 UsbHcFreeMem (Xhc
->MemPool
, Xhc
->UsbDevContext
[SlotId
].OutputContext
, sizeof (DEVICE_CONTEXT_64
));
2512 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established
2513 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to
2514 // remove urb from XHCI's asynchronous transfer list.
2516 Xhc
->UsbDevContext
[SlotId
].Enabled
= FALSE
;
2517 Xhc
->UsbDevContext
[SlotId
].SlotId
= 0;
2523 Initialize endpoint context in input context.
2525 @param Xhc The XHCI Instance.
2526 @param SlotId The slot id to be configured.
2527 @param DeviceSpeed The device's speed.
2528 @param InputContext The pointer to the input context.
2529 @param IfDesc The pointer to the usb device interface descriptor.
2531 @return The maximum device context index of endpoint.
2536 XhcInitializeEndpointContext (
2537 IN USB_XHCI_INSTANCE
*Xhc
,
2539 IN UINT8 DeviceSpeed
,
2540 IN INPUT_CONTEXT
*InputContext
,
2541 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2544 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2551 EFI_PHYSICAL_ADDRESS PhyAddr
;
2553 TRANSFER_RING
*EndpointTransferRing
;
2557 NumEp
= IfDesc
->NumEndpoints
;
2559 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2560 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2561 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2562 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2565 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2566 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2568 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2574 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2575 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2577 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2579 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2581 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2583 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2586 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2587 case USB_ENDPOINT_BULK
:
2588 if (Direction
== EfiUsbDataIn
) {
2589 InputContext
->EP
[Dci
-1].CErr
= 3;
2590 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2592 InputContext
->EP
[Dci
-1].CErr
= 3;
2593 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2596 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2597 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2598 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2599 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2600 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2604 case USB_ENDPOINT_ISO
:
2605 if (Direction
== EfiUsbDataIn
) {
2606 InputContext
->EP
[Dci
-1].CErr
= 0;
2607 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2609 InputContext
->EP
[Dci
-1].CErr
= 0;
2610 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2613 // Do not support isochronous transfer now.
2615 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2616 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2618 case USB_ENDPOINT_INTERRUPT
:
2619 if (Direction
== EfiUsbDataIn
) {
2620 InputContext
->EP
[Dci
-1].CErr
= 3;
2621 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2623 InputContext
->EP
[Dci
-1].CErr
= 3;
2624 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2626 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2627 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2629 // Get the bInterval from descriptor and init the the interval field of endpoint context
2631 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2632 Interval
= EpDesc
->Interval
;
2634 // Calculate through the bInterval field of Endpoint descriptor.
2636 ASSERT (Interval
!= 0);
2637 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2638 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2639 Interval
= EpDesc
->Interval
;
2640 ASSERT (Interval
>= 1 && Interval
<= 16);
2642 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2644 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2645 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2646 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2647 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2648 InputContext
->EP
[Dci
-1].CErr
= 3;
2651 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2652 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2653 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2654 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2658 case USB_ENDPOINT_CONTROL
:
2660 // Do not support control transfer now.
2662 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2664 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));
2665 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2669 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2671 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2672 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2674 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2675 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2676 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2677 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2679 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2686 Initialize endpoint context in input context.
2688 @param Xhc The XHCI Instance.
2689 @param SlotId The slot id to be configured.
2690 @param DeviceSpeed The device's speed.
2691 @param InputContext The pointer to the input context.
2692 @param IfDesc The pointer to the usb device interface descriptor.
2694 @return The maximum device context index of endpoint.
2699 XhcInitializeEndpointContext64 (
2700 IN USB_XHCI_INSTANCE
*Xhc
,
2702 IN UINT8 DeviceSpeed
,
2703 IN INPUT_CONTEXT_64
*InputContext
,
2704 IN USB_INTERFACE_DESCRIPTOR
*IfDesc
2707 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
2714 EFI_PHYSICAL_ADDRESS PhyAddr
;
2716 TRANSFER_RING
*EndpointTransferRing
;
2720 NumEp
= IfDesc
->NumEndpoints
;
2722 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)(IfDesc
+ 1);
2723 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
2724 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
2725 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2728 EpAddr
= (UINT8
)(EpDesc
->EndpointAddress
& 0x0F);
2729 Direction
= (UINT8
)((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
2731 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
2737 InputContext
->InputControlContext
.Dword2
|= (BIT0
<< Dci
);
2738 InputContext
->EP
[Dci
-1].MaxPacketSize
= EpDesc
->MaxPacketSize
;
2740 if (DeviceSpeed
== EFI_USB_SPEED_SUPER
) {
2742 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.
2744 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2746 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2749 switch (EpDesc
->Attributes
& USB_ENDPOINT_TYPE_MASK
) {
2750 case USB_ENDPOINT_BULK
:
2751 if (Direction
== EfiUsbDataIn
) {
2752 InputContext
->EP
[Dci
-1].CErr
= 3;
2753 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_IN
;
2755 InputContext
->EP
[Dci
-1].CErr
= 3;
2756 InputContext
->EP
[Dci
-1].EPType
= ED_BULK_OUT
;
2759 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2760 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2761 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2762 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2763 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2767 case USB_ENDPOINT_ISO
:
2768 if (Direction
== EfiUsbDataIn
) {
2769 InputContext
->EP
[Dci
-1].CErr
= 0;
2770 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_IN
;
2772 InputContext
->EP
[Dci
-1].CErr
= 0;
2773 InputContext
->EP
[Dci
-1].EPType
= ED_ISOCH_OUT
;
2776 // Do not support isochronous transfer now.
2778 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));
2779 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2781 case USB_ENDPOINT_INTERRUPT
:
2782 if (Direction
== EfiUsbDataIn
) {
2783 InputContext
->EP
[Dci
-1].CErr
= 3;
2784 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_IN
;
2786 InputContext
->EP
[Dci
-1].CErr
= 3;
2787 InputContext
->EP
[Dci
-1].EPType
= ED_INTERRUPT_OUT
;
2789 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2790 InputContext
->EP
[Dci
-1].MaxESITPayload
= EpDesc
->MaxPacketSize
;
2792 // Get the bInterval from descriptor and init the the interval field of endpoint context
2794 if ((DeviceSpeed
== EFI_USB_SPEED_FULL
) || (DeviceSpeed
== EFI_USB_SPEED_LOW
)) {
2795 Interval
= EpDesc
->Interval
;
2797 // Calculate through the bInterval field of Endpoint descriptor.
2799 ASSERT (Interval
!= 0);
2800 InputContext
->EP
[Dci
-1].Interval
= (UINT32
)HighBitSet32((UINT32
)Interval
) + 3;
2801 } else if ((DeviceSpeed
== EFI_USB_SPEED_HIGH
) || (DeviceSpeed
== EFI_USB_SPEED_SUPER
)) {
2802 Interval
= EpDesc
->Interval
;
2803 ASSERT (Interval
>= 1 && Interval
<= 16);
2805 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61
2807 InputContext
->EP
[Dci
-1].Interval
= Interval
- 1;
2808 InputContext
->EP
[Dci
-1].AverageTRBLength
= 0x1000;
2809 InputContext
->EP
[Dci
-1].MaxESITPayload
= 0x0002;
2810 InputContext
->EP
[Dci
-1].MaxBurstSize
= 0x0;
2811 InputContext
->EP
[Dci
-1].CErr
= 3;
2814 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] == NULL
) {
2815 EndpointTransferRing
= AllocateZeroPool(sizeof (TRANSFER_RING
));
2816 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1] = (VOID
*) EndpointTransferRing
;
2817 CreateTransferRing(Xhc
, TR_RING_TRB_NUMBER
, (TRANSFER_RING
*)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1]);
2821 case USB_ENDPOINT_CONTROL
:
2823 // Do not support control transfer now.
2825 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));
2827 DEBUG ((EFI_D_INFO
, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));
2828 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2832 PhyAddr
= UsbHcGetPciAddrForHostAddr (
2834 ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingSeg0
,
2835 sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
2837 PhyAddr
&= ~((EFI_PHYSICAL_ADDRESS
)0x0F);
2838 PhyAddr
|= (EFI_PHYSICAL_ADDRESS
)((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
-1])->RingPCS
;
2839 InputContext
->EP
[Dci
-1].PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2840 InputContext
->EP
[Dci
-1].PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2842 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
2849 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2851 @param Xhc The XHCI Instance.
2852 @param SlotId The slot id to be configured.
2853 @param DeviceSpeed The device's speed.
2854 @param ConfigDesc The pointer to the usb device configuration descriptor.
2856 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2862 IN USB_XHCI_INSTANCE
*Xhc
,
2864 IN UINT8 DeviceSpeed
,
2865 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
2869 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
2873 EFI_PHYSICAL_ADDRESS PhyAddr
;
2875 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2876 INPUT_CONTEXT
*InputContext
;
2877 DEVICE_CONTEXT
*OutputContext
;
2878 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2880 // 4.6.6 Configure Endpoint
2882 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2883 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2884 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
2885 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
2887 ASSERT (ConfigDesc
!= NULL
);
2891 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
2892 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
2893 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
2894 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2897 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
2902 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2905 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2906 InputContext
->Slot
.ContextEntries
= MaxDci
;
2908 // configure endpoint
2910 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2911 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
2912 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2913 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2914 CmdTrbCfgEP
.CycleBit
= 1;
2915 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
2916 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
2917 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
2918 Status
= XhcCmdTransfer (
2920 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
2921 XHC_GENERIC_TIMEOUT
,
2922 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
2924 if (EFI_ERROR (Status
)) {
2925 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status
));
2927 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
2934 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.
2936 @param Xhc The XHCI Instance.
2937 @param SlotId The slot id to be configured.
2938 @param DeviceSpeed The device's speed.
2939 @param ConfigDesc The pointer to the usb device configuration descriptor.
2941 @retval EFI_SUCCESS Successfully configure all the device endpoints.
2947 IN USB_XHCI_INSTANCE
*Xhc
,
2949 IN UINT8 DeviceSpeed
,
2950 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
2954 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
2958 EFI_PHYSICAL_ADDRESS PhyAddr
;
2960 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
2961 INPUT_CONTEXT_64
*InputContext
;
2962 DEVICE_CONTEXT_64
*OutputContext
;
2963 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
2965 // 4.6.6 Configure Endpoint
2967 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
2968 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
2969 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
2970 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
2972 ASSERT (ConfigDesc
!= NULL
);
2976 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
2977 for (Index
= 0; Index
< ConfigDesc
->NumInterfaces
; Index
++) {
2978 while ((IfDesc
->DescriptorType
!= USB_DESC_TYPE_INTERFACE
) || (IfDesc
->AlternateSetting
!= 0)) {
2979 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2982 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDesc
);
2987 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
2990 InputContext
->InputControlContext
.Dword2
|= BIT0
;
2991 InputContext
->Slot
.ContextEntries
= MaxDci
;
2993 // configure endpoint
2995 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
2996 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
2997 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
2998 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
2999 CmdTrbCfgEP
.CycleBit
= 1;
3000 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3001 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3002 DEBUG ((EFI_D_INFO
, "Configure Endpoint\n"));
3003 Status
= XhcCmdTransfer (
3005 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3006 XHC_GENERIC_TIMEOUT
,
3007 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3009 if (EFI_ERROR (Status
)) {
3010 DEBUG ((EFI_D_ERROR
, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status
));
3012 Xhc
->UsbDevContext
[SlotId
].ActiveConfiguration
= ConfigDesc
->ConfigurationValue
;
3019 Stop endpoint through XHCI's Stop_Endpoint cmd.
3021 @param Xhc The XHCI Instance.
3022 @param SlotId The slot id to be configured.
3023 @param Dci The device context index of endpoint.
3025 @retval EFI_SUCCESS Stop endpoint successfully.
3026 @retval Others Failed to stop endpoint.
3032 IN USB_XHCI_INSTANCE
*Xhc
,
3038 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3039 CMD_TRB_STOP_ENDPOINT CmdTrbStopED
;
3041 DEBUG ((EFI_D_INFO
, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId
, Dci
));
3044 // Send stop endpoint command to transit Endpoint from running to stop state
3046 ZeroMem (&CmdTrbStopED
, sizeof (CmdTrbStopED
));
3047 CmdTrbStopED
.CycleBit
= 1;
3048 CmdTrbStopED
.Type
= TRB_TYPE_STOP_ENDPOINT
;
3049 CmdTrbStopED
.EDID
= Dci
;
3050 CmdTrbStopED
.SlotId
= SlotId
;
3051 Status
= XhcCmdTransfer (
3053 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbStopED
,
3054 XHC_GENERIC_TIMEOUT
,
3055 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3057 if (EFI_ERROR(Status
)) {
3058 DEBUG ((EFI_D_ERROR
, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status
));
3065 Set interface through XHCI's Configure_Endpoint cmd.
3067 @param Xhc The XHCI Instance.
3068 @param SlotId The slot id to be configured.
3069 @param DeviceSpeed The device's speed.
3070 @param ConfigDesc The pointer to the usb device configuration descriptor.
3071 @param Request USB device request to send.
3073 @retval EFI_SUCCESS Successfully set interface.
3079 IN USB_XHCI_INSTANCE
*Xhc
,
3081 IN UINT8 DeviceSpeed
,
3082 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3083 IN EFI_USB_DEVICE_REQUEST
*Request
3087 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3088 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3089 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3090 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3097 EFI_PHYSICAL_ADDRESS PhyAddr
;
3100 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3101 INPUT_CONTEXT
*InputContext
;
3102 DEVICE_CONTEXT
*OutputContext
;
3103 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3105 Status
= EFI_SUCCESS
;
3107 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3108 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3110 // XHCI 4.6.6 Configure Endpoint
3111 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3112 // Context and Add Context flags as follows:
3113 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3114 // Context and Add Context flags to '0'.
3116 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3117 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3119 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3120 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT
));
3122 ASSERT (ConfigDesc
!= NULL
);
3126 IfDescActive
= NULL
;
3129 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3130 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3131 if (IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) {
3132 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3133 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3135 // Find out the active interface descriptor.
3137 IfDescActive
= IfDesc
;
3138 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3140 // Find out the interface descriptor to set.
3146 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3150 // XHCI 4.6.6 Configure Endpoint
3151 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3152 // Context and Add Context flags as follows:
3153 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3154 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3155 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3156 // the Drop Context flag to '1' and Add Context flag to '0'.
3157 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3158 // and Add Context flags shall be set to '1'.
3160 // Below codes are to cover 2), 3) and 4).
3163 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3164 NumEp
= IfDescActive
->NumEndpoints
;
3165 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3166 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3167 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3168 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3171 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3172 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3174 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3180 // XHCI 4.3.6 - Setting Alternate Interfaces
3181 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3183 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
);
3184 if (EFI_ERROR (Status
)) {
3188 // XHCI 4.3.6 - Setting Alternate Interfaces
3189 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3191 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3192 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3193 if (RingSeg
!= NULL
) {
3194 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3196 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3197 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3201 // Set the Drop Context flag to '1'.
3203 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3205 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3209 // XHCI 4.3.6 - Setting Alternate Interfaces
3210 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3211 // Interface setting, to '0'.
3213 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3217 // XHCI 4.3.6 - Setting Alternate Interfaces
3218 // 4) For each endpoint enabled by the Configure Endpoint Command:
3219 // a. Allocate a Transfer Ring.
3220 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3221 // c. Initialize the Endpoint Context data structure.
3223 Dci
= XhcInitializeEndpointContext (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3228 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3229 InputContext
->Slot
.ContextEntries
= MaxDci
;
3231 // XHCI 4.3.6 - Setting Alternate Interfaces
3232 // 5) Issue and successfully complete a Configure Endpoint Command.
3234 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3235 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3236 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3237 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3238 CmdTrbCfgEP
.CycleBit
= 1;
3239 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3240 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3241 DEBUG ((EFI_D_INFO
, "SetInterface: Configure Endpoint\n"));
3242 Status
= XhcCmdTransfer (
3244 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3245 XHC_GENERIC_TIMEOUT
,
3246 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3248 if (EFI_ERROR (Status
)) {
3249 DEBUG ((EFI_D_ERROR
, "SetInterface: Config Endpoint Failed, Status = %r\n", Status
));
3252 // Update the active AlternateSetting.
3254 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3262 Set interface through XHCI's Configure_Endpoint cmd.
3264 @param Xhc The XHCI Instance.
3265 @param SlotId The slot id to be configured.
3266 @param DeviceSpeed The device's speed.
3267 @param ConfigDesc The pointer to the usb device configuration descriptor.
3268 @param Request USB device request to send.
3270 @retval EFI_SUCCESS Successfully set interface.
3276 IN USB_XHCI_INSTANCE
*Xhc
,
3278 IN UINT8 DeviceSpeed
,
3279 IN USB_CONFIG_DESCRIPTOR
*ConfigDesc
,
3280 IN EFI_USB_DEVICE_REQUEST
*Request
3284 USB_INTERFACE_DESCRIPTOR
*IfDescActive
;
3285 USB_INTERFACE_DESCRIPTOR
*IfDescSet
;
3286 USB_INTERFACE_DESCRIPTOR
*IfDesc
;
3287 USB_ENDPOINT_DESCRIPTOR
*EpDesc
;
3294 EFI_PHYSICAL_ADDRESS PhyAddr
;
3297 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3298 INPUT_CONTEXT_64
*InputContext
;
3299 DEVICE_CONTEXT_64
*OutputContext
;
3300 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3302 Status
= EFI_SUCCESS
;
3304 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3305 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3307 // XHCI 4.6.6 Configure Endpoint
3308 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3309 // Context and Add Context flags as follows:
3310 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop
3311 // Context and Add Context flags to '0'.
3313 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.
3314 // So the default Drop Context and Add Context flags can be '0' to cover 1).
3316 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3317 CopyMem (&InputContext
->Slot
, &OutputContext
->Slot
, sizeof (SLOT_CONTEXT_64
));
3319 ASSERT (ConfigDesc
!= NULL
);
3323 IfDescActive
= NULL
;
3326 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)(ConfigDesc
+ 1);
3327 while ((UINTN
) IfDesc
< ((UINTN
) ConfigDesc
+ ConfigDesc
->TotalLength
)) {
3328 if (IfDesc
->DescriptorType
== USB_DESC_TYPE_INTERFACE
) {
3329 if (IfDesc
->InterfaceNumber
== (UINT8
) Request
->Index
) {
3330 if (IfDesc
->AlternateSetting
== Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[IfDesc
->InterfaceNumber
]) {
3332 // Find out the active interface descriptor.
3334 IfDescActive
= IfDesc
;
3335 } else if (IfDesc
->AlternateSetting
== (UINT8
) Request
->Value
) {
3337 // Find out the interface descriptor to set.
3343 IfDesc
= (USB_INTERFACE_DESCRIPTOR
*)((UINTN
)IfDesc
+ IfDesc
->Length
);
3347 // XHCI 4.6.6 Configure Endpoint
3348 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop
3349 // Context and Add Context flags as follows:
3350 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set
3351 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.
3352 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set
3353 // the Drop Context flag to '1' and Add Context flag to '0'.
3354 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context
3355 // and Add Context flags shall be set to '1'.
3357 // Below codes are to cover 2), 3) and 4).
3360 if ((IfDescActive
!= NULL
) && (IfDescSet
!= NULL
)) {
3361 NumEp
= IfDescActive
->NumEndpoints
;
3362 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*) (IfDescActive
+ 1);
3363 for (EpIndex
= 0; EpIndex
< NumEp
; EpIndex
++) {
3364 while (EpDesc
->DescriptorType
!= USB_DESC_TYPE_ENDPOINT
) {
3365 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3368 EpAddr
= (UINT8
) (EpDesc
->EndpointAddress
& 0x0F);
3369 Direction
= (UINT8
) ((EpDesc
->EndpointAddress
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
3371 Dci
= XhcEndpointToDci (EpAddr
, Direction
);
3377 // XHCI 4.3.6 - Setting Alternate Interfaces
3378 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.
3380 Status
= XhcStopEndpoint (Xhc
, SlotId
, Dci
);
3381 if (EFI_ERROR (Status
)) {
3385 // XHCI 4.3.6 - Setting Alternate Interfaces
3386 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.
3388 if (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] != NULL
) {
3389 RingSeg
= ((TRANSFER_RING
*)(UINTN
)Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1])->RingSeg0
;
3390 if (RingSeg
!= NULL
) {
3391 UsbHcFreeMem (Xhc
->MemPool
, RingSeg
, sizeof (TRB_TEMPLATE
) * TR_RING_TRB_NUMBER
);
3393 FreePool (Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1]);
3394 Xhc
->UsbDevContext
[SlotId
].EndpointTransferRing
[Dci
- 1] = NULL
;
3398 // Set the Drop Context flag to '1'.
3400 InputContext
->InputControlContext
.Dword1
|= (BIT0
<< Dci
);
3402 EpDesc
= (USB_ENDPOINT_DESCRIPTOR
*)((UINTN
)EpDesc
+ EpDesc
->Length
);
3406 // XHCI 4.3.6 - Setting Alternate Interfaces
3407 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate
3408 // Interface setting, to '0'.
3410 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.
3414 // XHCI 4.3.6 - Setting Alternate Interfaces
3415 // 4) For each endpoint enabled by the Configure Endpoint Command:
3416 // a. Allocate a Transfer Ring.
3417 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.
3418 // c. Initialize the Endpoint Context data structure.
3420 Dci
= XhcInitializeEndpointContext64 (Xhc
, SlotId
, DeviceSpeed
, InputContext
, IfDescSet
);
3425 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3426 InputContext
->Slot
.ContextEntries
= MaxDci
;
3428 // XHCI 4.3.6 - Setting Alternate Interfaces
3429 // 5) Issue and successfully complete a Configure Endpoint Command.
3431 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3432 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3433 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3434 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3435 CmdTrbCfgEP
.CycleBit
= 1;
3436 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3437 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3438 DEBUG ((EFI_D_INFO
, "SetInterface64: Configure Endpoint\n"));
3439 Status
= XhcCmdTransfer (
3441 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3442 XHC_GENERIC_TIMEOUT
,
3443 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3445 if (EFI_ERROR (Status
)) {
3446 DEBUG ((EFI_D_ERROR
, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status
));
3449 // Update the active AlternateSetting.
3451 Xhc
->UsbDevContext
[SlotId
].ActiveAlternateSetting
[(UINT8
) Request
->Index
] = (UINT8
) Request
->Value
;
3459 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3461 @param Xhc The XHCI Instance.
3462 @param SlotId The slot id to be evaluated.
3463 @param MaxPacketSize The max packet size supported by the device control transfer.
3465 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3470 XhcEvaluateContext (
3471 IN USB_XHCI_INSTANCE
*Xhc
,
3473 IN UINT32 MaxPacketSize
3477 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3478 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3479 INPUT_CONTEXT
*InputContext
;
3480 EFI_PHYSICAL_ADDRESS PhyAddr
;
3482 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3485 // 4.6.7 Evaluate Context
3487 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3488 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3490 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3491 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3493 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3494 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3495 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3496 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3497 CmdTrbEvalu
.CycleBit
= 1;
3498 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3499 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3500 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3501 Status
= XhcCmdTransfer (
3503 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3504 XHC_GENERIC_TIMEOUT
,
3505 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3507 if (EFI_ERROR (Status
)) {
3508 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status
));
3514 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.
3516 @param Xhc The XHCI Instance.
3517 @param SlotId The slot id to be evaluated.
3518 @param MaxPacketSize The max packet size supported by the device control transfer.
3520 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.
3525 XhcEvaluateContext64 (
3526 IN USB_XHCI_INSTANCE
*Xhc
,
3528 IN UINT32 MaxPacketSize
3532 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu
;
3533 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3534 INPUT_CONTEXT_64
*InputContext
;
3535 EFI_PHYSICAL_ADDRESS PhyAddr
;
3537 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3540 // 4.6.7 Evaluate Context
3542 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3543 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3545 InputContext
->InputControlContext
.Dword2
|= BIT1
;
3546 InputContext
->EP
[0].MaxPacketSize
= MaxPacketSize
;
3548 ZeroMem (&CmdTrbEvalu
, sizeof (CmdTrbEvalu
));
3549 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3550 CmdTrbEvalu
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3551 CmdTrbEvalu
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3552 CmdTrbEvalu
.CycleBit
= 1;
3553 CmdTrbEvalu
.Type
= TRB_TYPE_EVALU_CONTXT
;
3554 CmdTrbEvalu
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3555 DEBUG ((EFI_D_INFO
, "Evaluate context\n"));
3556 Status
= XhcCmdTransfer (
3558 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbEvalu
,
3559 XHC_GENERIC_TIMEOUT
,
3560 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3562 if (EFI_ERROR (Status
)) {
3563 DEBUG ((EFI_D_ERROR
, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status
));
3570 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3572 @param Xhc The XHCI Instance.
3573 @param SlotId The slot id to be configured.
3574 @param PortNum The total number of downstream port supported by the hub.
3575 @param TTT The TT think time of the hub device.
3576 @param MTT The multi-TT of the hub device.
3578 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3582 XhcConfigHubContext (
3583 IN USB_XHCI_INSTANCE
*Xhc
,
3591 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3592 INPUT_CONTEXT
*InputContext
;
3593 DEVICE_CONTEXT
*OutputContext
;
3594 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3595 EFI_PHYSICAL_ADDRESS PhyAddr
;
3597 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3598 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3599 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3602 // 4.6.7 Evaluate Context
3604 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT
));
3606 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3609 // Copy the slot context from OutputContext to Input context
3611 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT
));
3612 InputContext
->Slot
.Hub
= 1;
3613 InputContext
->Slot
.PortNum
= PortNum
;
3614 InputContext
->Slot
.TTT
= TTT
;
3615 InputContext
->Slot
.MTT
= MTT
;
3617 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3618 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT
));
3619 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3620 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3621 CmdTrbCfgEP
.CycleBit
= 1;
3622 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3623 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3624 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
3625 Status
= XhcCmdTransfer (
3627 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3628 XHC_GENERIC_TIMEOUT
,
3629 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3631 if (EFI_ERROR (Status
)) {
3632 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status
));
3638 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.
3640 @param Xhc The XHCI Instance.
3641 @param SlotId The slot id to be configured.
3642 @param PortNum The total number of downstream port supported by the hub.
3643 @param TTT The TT think time of the hub device.
3644 @param MTT The multi-TT of the hub device.
3646 @retval EFI_SUCCESS Successfully configure the hub device's slot context.
3650 XhcConfigHubContext64 (
3651 IN USB_XHCI_INSTANCE
*Xhc
,
3659 EVT_TRB_COMMAND_COMPLETION
*EvtTrb
;
3660 INPUT_CONTEXT_64
*InputContext
;
3661 DEVICE_CONTEXT_64
*OutputContext
;
3662 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP
;
3663 EFI_PHYSICAL_ADDRESS PhyAddr
;
3665 ASSERT (Xhc
->UsbDevContext
[SlotId
].SlotId
!= 0);
3666 InputContext
= Xhc
->UsbDevContext
[SlotId
].InputContext
;
3667 OutputContext
= Xhc
->UsbDevContext
[SlotId
].OutputContext
;
3670 // 4.6.7 Evaluate Context
3672 ZeroMem (InputContext
, sizeof (INPUT_CONTEXT_64
));
3674 InputContext
->InputControlContext
.Dword2
|= BIT0
;
3677 // Copy the slot context from OutputContext to Input context
3679 CopyMem(&(InputContext
->Slot
), &(OutputContext
->Slot
), sizeof (SLOT_CONTEXT_64
));
3680 InputContext
->Slot
.Hub
= 1;
3681 InputContext
->Slot
.PortNum
= PortNum
;
3682 InputContext
->Slot
.TTT
= TTT
;
3683 InputContext
->Slot
.MTT
= MTT
;
3685 ZeroMem (&CmdTrbCfgEP
, sizeof (CmdTrbCfgEP
));
3686 PhyAddr
= UsbHcGetPciAddrForHostAddr (Xhc
->MemPool
, InputContext
, sizeof (INPUT_CONTEXT_64
));
3687 CmdTrbCfgEP
.PtrLo
= XHC_LOW_32BIT (PhyAddr
);
3688 CmdTrbCfgEP
.PtrHi
= XHC_HIGH_32BIT (PhyAddr
);
3689 CmdTrbCfgEP
.CycleBit
= 1;
3690 CmdTrbCfgEP
.Type
= TRB_TYPE_CON_ENDPOINT
;
3691 CmdTrbCfgEP
.SlotId
= Xhc
->UsbDevContext
[SlotId
].SlotId
;
3692 DEBUG ((EFI_D_INFO
, "Configure Hub Slot Context\n"));
3693 Status
= XhcCmdTransfer (
3695 (TRB_TEMPLATE
*) (UINTN
) &CmdTrbCfgEP
,
3696 XHC_GENERIC_TIMEOUT
,
3697 (TRB_TEMPLATE
**) (UINTN
) &EvtTrb
3699 if (EFI_ERROR (Status
)) {
3700 DEBUG ((EFI_D_ERROR
, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status
));