2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
5 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) Microsoft Corporation.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
15 Delete a single asynchronous interrupt transfer for
16 the device and endpoint.
18 @param Ehc The EHCI device.
19 @param Data Current data not associated with a QTD.
20 @param DataLen The length of the data.
21 @param PktId Packet ID to use in the QTD.
22 @param Toggle Data toggle to use in the QTD.
23 @param MaxPacket Maximu packet length of the endpoint.
25 @retval the pointer to the created QTD or NULL if failed to create one.
30 IN PEI_USB2_HC_DEV
*Ehc
,
46 Qtd
= UsbHcAllocateMem (Ehc
, Ehc
->MemPool
, sizeof (PEI_EHC_QTD
));
52 Qtd
->Signature
= EHC_QTD_SIG
;
56 InitializeListHead (&Qtd
->QtdList
);
59 QtdHw
->NextQtd
= QTD_LINK (NULL
, TRUE
);
60 QtdHw
->AltNext
= QTD_LINK (NULL
, TRUE
);
61 QtdHw
->Status
= QTD_STAT_ACTIVE
;
63 QtdHw
->ErrCnt
= QTD_MAX_ERR
;
65 QtdHw
->TotalBytes
= 0;
66 QtdHw
->DataToggle
= Toggle
;
69 // Fill in the buffer points
74 for (Index
= 0; Index
<= QTD_MAX_BUFFER
; Index
++) {
76 // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
77 // compute the offset and clear Reserved fields. This is already
78 // done in the data point.
80 QtdHw
->Page
[Index
] = EHC_LOW_32BIT (Data
);
81 QtdHw
->PageHigh
[Index
] = EHC_HIGH_32BIT (Data
);
83 ThisBufLen
= QTD_BUF_LEN
- (EHC_LOW_32BIT (Data
) & QTD_BUF_MASK
);
85 if (Len
+ ThisBufLen
>= DataLen
) {
95 // Need to fix the last pointer if the Qtd can't hold all the
96 // user's data to make sure that the length is in the unit of
97 // max packets. If it can hold all the data, there is no such
101 Len
= Len
- Len
% MaxPacket
;
104 QtdHw
->TotalBytes
= (UINT32
)Len
;
112 Initialize the queue head for interrupt transfer,
113 that is, initialize the following three fields:
114 1. SplitXState in the Status field.
115 2. Microframe S-mask.
116 3. Microframe C-mask.
118 @param Ep The queue head's related endpoint.
119 @param QhHw The queue head to initialize.
129 // Because UEFI interface can't utilitize an endpoint with
130 // poll rate faster than 1ms, only need to set one bit in
131 // the queue head. simple. But it may be changed later. If
132 // sub-1ms interrupt is supported, need to update the S-Mask
135 if (Ep
->DevSpeed
== EFI_USB_SPEED_HIGH
) {
136 QhHw
->SMask
= QH_MICROFRAME_0
;
141 // For low/full speed device, the transfer must go through
142 // the split transaction. Need to update three fields
143 // 1. SplitXState in the status
144 // 2. Microframe S-Mask
145 // 3. Microframe C-Mask
146 // UEFI USB doesn't exercise admission control. It simplely
147 // schedule the high speed transactions in microframe 0, and
148 // full/low speed transactions at microframe 1. This also
149 // avoid the use of FSTN.
151 QhHw
->SMask
= QH_MICROFRAME_1
;
152 QhHw
->CMask
= QH_MICROFRAME_3
| QH_MICROFRAME_4
| QH_MICROFRAME_5
;
156 Allocate and initialize a EHCI queue head.
158 @param Ehci The EHCI device.
159 @param Ep The endpoint to create queue head for.
161 @retval the pointer to the created queue head or NULL if failed to create one.
166 IN PEI_USB2_HC_DEV
*Ehci
,
173 Qh
= UsbHcAllocateMem (Ehci
, Ehci
->MemPool
, sizeof (PEI_EHC_QH
));
179 Qh
->Signature
= EHC_QH_SIG
;
181 Qh
->Interval
= Ep
->PollRate
;
183 InitializeListHead (&Qh
->Qtds
);
186 QhHw
->HorizonLink
= QH_LINK (NULL
, 0, TRUE
);
187 QhHw
->DeviceAddr
= Ep
->DevAddr
;
189 QhHw
->EpNum
= Ep
->EpAddr
;
190 QhHw
->EpSpeed
= Ep
->DevSpeed
;
192 QhHw
->ReclaimHead
= 0;
193 QhHw
->MaxPacketLen
= (UINT32
)Ep
->MaxPacket
;
195 QhHw
->NakReload
= QH_NAK_RELOAD
;
196 QhHw
->HubAddr
= Ep
->HubAddr
;
197 QhHw
->PortNum
= Ep
->HubPort
;
198 QhHw
->Multiplier
= 1;
199 QhHw
->DataToggle
= Ep
->Toggle
;
201 if (Ep
->DevSpeed
!= EFI_USB_SPEED_HIGH
) {
202 QhHw
->Status
|= QTD_STAT_DO_SS
;
206 case EHC_CTRL_TRANSFER
:
208 // Special initialization for the control transfer:
209 // 1. Control transfer initialize data toggle from each QTD
210 // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
214 if (Ep
->DevSpeed
!= EFI_USB_SPEED_HIGH
) {
220 case EHC_INT_TRANSFER_ASYNC
:
221 case EHC_INT_TRANSFER_SYNC
:
223 // Special initialization for the interrupt transfer
224 // to set the S-Mask and C-Mask
227 EhcInitIntQh (Ep
, QhHw
);
230 case EHC_BULK_TRANSFER
:
231 if ((Ep
->DevSpeed
== EFI_USB_SPEED_HIGH
) && (Ep
->Direction
== EfiUsbDataOut
)) {
232 QhHw
->Status
|= QTD_STAT_DO_PING
;
242 Convert the poll interval from application to that
243 be used by EHCI interface data structure. Only need
244 to get the max 2^n that is less than interval. UEFI
245 can't support high speed endpoint with a interval less
246 than 8 microframe because interval is specified in
247 the unit of ms (millisecond).
249 @param Interval The interval to convert.
251 @retval The converted interval.
266 // Find the index (1 based) of the highest non-zero bit
270 while (Interval
!= 0) {
275 return (UINTN
)1 << (BitCount
- 1);
281 @param Ehc The EHCI device.
282 @param Qtds The list head of the QTD.
287 IN PEI_USB2_HC_DEV
*Ehc
,
288 IN EFI_LIST_ENTRY
*Qtds
291 EFI_LIST_ENTRY
*Entry
;
292 EFI_LIST_ENTRY
*Next
;
295 BASE_LIST_FOR_EACH_SAFE (Entry
, Next
, Qtds
) {
296 Qtd
= EFI_LIST_CONTAINER (Entry
, PEI_EHC_QTD
, QtdList
);
298 RemoveEntryList (&Qtd
->QtdList
);
299 UsbHcFreeMem (Ehc
, Ehc
->MemPool
, Qtd
, sizeof (PEI_EHC_QTD
));
304 Free an allocated URB. It is possible for it to be partially inited.
306 @param Ehc The EHCI device.
307 @param Urb The URB to free.
312 IN PEI_USB2_HC_DEV
*Ehc
,
316 if (Urb
->RequestPhy
!= NULL
) {
317 IoMmuUnmap (Ehc
->IoMmu
, Urb
->RequestMap
);
320 if (Urb
->DataMap
!= NULL
) {
321 IoMmuUnmap (Ehc
->IoMmu
, Urb
->DataMap
);
324 if (Urb
->Qh
!= NULL
) {
326 // Ensure that this queue head has been unlinked from the
327 // schedule data structures. Free all the associated QTDs
329 EhcFreeQtds (Ehc
, &Urb
->Qh
->Qtds
);
330 UsbHcFreeMem (Ehc
, Ehc
->MemPool
, Urb
->Qh
, sizeof (PEI_EHC_QH
));
335 Create a list of QTDs for the URB.
337 @param Ehc The EHCI device.
338 @param Urb The URB to create QTDs for.
340 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.
341 @retval EFI_SUCCESS The QTDs are allocated for the URB.
346 IN PEI_USB2_HC_DEV
*Ehc
,
353 PEI_EHC_QTD
*StatusQtd
;
354 PEI_EHC_QTD
*NextQtd
;
355 EFI_LIST_ENTRY
*Entry
;
361 ASSERT ((Urb
!= NULL
) && (Urb
->Qh
!= NULL
));
364 // EHCI follows the alternet next QTD pointer if it meets
365 // a short read and the AlterNext pointer is valid. UEFI
366 // EHCI driver should terminate the transfer except the
373 AlterNext
= QTD_LINK (NULL
, TRUE
);
375 if (Ep
->Direction
== EfiUsbDataIn
) {
376 AlterNext
= QTD_LINK (Ehc
->ShortReadStop
, FALSE
);
380 // Build the Setup and status packets for control transfer
382 if (Urb
->Ep
.Type
== EHC_CTRL_TRANSFER
) {
383 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
384 Qtd
= EhcCreateQtd (Ehc
, Urb
->RequestPhy
, Len
, QTD_PID_SETUP
, 0, Ep
->MaxPacket
);
387 return EFI_OUT_OF_RESOURCES
;
390 InsertTailList (&Qh
->Qtds
, &Qtd
->QtdList
);
393 // Create the status packet now. Set the AlterNext to it. So, when
394 // EHCI meets a short control read, it can resume at the status stage.
395 // Use the opposite direction of the data stage, or IN if there is
398 if (Ep
->Direction
== EfiUsbDataIn
) {
399 Pid
= QTD_PID_OUTPUT
;
404 StatusQtd
= EhcCreateQtd (Ehc
, NULL
, 0, Pid
, 1, Ep
->MaxPacket
);
406 if (StatusQtd
== NULL
) {
410 if (Ep
->Direction
== EfiUsbDataIn
) {
411 AlterNext
= QTD_LINK (StatusQtd
, FALSE
);
418 // Build the data packets for all the transfers
420 if (Ep
->Direction
== EfiUsbDataIn
) {
423 Pid
= QTD_PID_OUTPUT
;
429 while (Len
< Urb
->DataLen
) {
432 (UINT8
*)Urb
->DataPhy
+ Len
,
443 Qtd
->QtdHw
.AltNext
= AlterNext
;
444 InsertTailList (&Qh
->Qtds
, &Qtd
->QtdList
);
447 // Switch the Toggle bit if odd number of packets are included in the QTD.
449 if (((Qtd
->DataLen
+ Ep
->MaxPacket
- 1) / Ep
->MaxPacket
) % 2) {
450 Toggle
= (UINT8
)(1 - Toggle
);
457 // Insert the status packet for control transfer
459 if (Ep
->Type
== EHC_CTRL_TRANSFER
) {
460 InsertTailList (&Qh
->Qtds
, &StatusQtd
->QtdList
);
464 // OK, all the QTDs needed are created. Now, fix the NextQtd point
466 BASE_LIST_FOR_EACH (Entry
, &Qh
->Qtds
) {
467 Qtd
= EFI_LIST_CONTAINER (Entry
, PEI_EHC_QTD
, QtdList
);
470 // break if it is the last entry on the list
472 if (Entry
->ForwardLink
== &Qh
->Qtds
) {
476 NextQtd
= EFI_LIST_CONTAINER (Entry
->ForwardLink
, PEI_EHC_QTD
, QtdList
);
477 Qtd
->QtdHw
.NextQtd
= QTD_LINK (NextQtd
, FALSE
);
481 // Link the QTDs to the queue head
483 NextQtd
= EFI_LIST_CONTAINER (Qh
->Qtds
.ForwardLink
, PEI_EHC_QTD
, QtdList
);
484 Qh
->QhHw
.NextQtd
= QTD_LINK (NextQtd
, FALSE
);
488 EhcFreeQtds (Ehc
, &Qh
->Qtds
);
489 return EFI_OUT_OF_RESOURCES
;
493 Create a new URB and its associated QTD.
495 @param Ehc The EHCI device.
496 @param DevAddr The device address.
497 @param EpAddr Endpoint addrress & its direction.
498 @param DevSpeed The device speed.
499 @param Toggle Initial data toggle to use.
500 @param MaxPacket The max packet length of the endpoint.
501 @param Hub The transaction translator to use.
502 @param Type The transaction type.
503 @param Request The standard USB request for control transfer.
504 @param Data The user data to transfer.
505 @param DataLen The length of data buffer.
506 @param Callback The function to call when data is transferred.
507 @param Context The context to the callback.
508 @param Interval The interval for interrupt transfer.
510 @retval the pointer to the created URB or NULL.
515 IN PEI_USB2_HC_DEV
*Ehc
,
521 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Hub
,
523 IN EFI_USB_DEVICE_REQUEST
*Request
,
526 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
532 EFI_PHYSICAL_ADDRESS PhyAddr
;
533 EDKII_IOMMU_OPERATION MapOp
;
542 Urb
->Signature
= EHC_URB_SIG
;
543 InitializeListHead (&Urb
->UrbList
);
546 Ep
->DevAddr
= DevAddr
;
547 Ep
->EpAddr
= (UINT8
)(EpAddr
& 0x0F);
548 Ep
->Direction
= (((EpAddr
& 0x80) != 0) ? EfiUsbDataIn
: EfiUsbDataOut
);
549 Ep
->DevSpeed
= DevSpeed
;
550 Ep
->MaxPacket
= MaxPacket
;
555 if (DevSpeed
!= EFI_USB_SPEED_HIGH
) {
556 ASSERT (Hub
!= NULL
);
558 Ep
->HubAddr
= Hub
->TranslatorHubAddress
;
559 Ep
->HubPort
= Hub
->TranslatorPortNumber
;
564 Ep
->PollRate
= EhcConvertPollRate (Interval
);
566 Urb
->Request
= Request
;
568 Urb
->DataLen
= DataLen
;
569 Urb
->Callback
= Callback
;
570 Urb
->Context
= Context
;
571 Urb
->Qh
= EhcCreateQh (Ehc
, &Urb
->Ep
);
573 if (Urb
->Qh
== NULL
) {
577 Urb
->RequestPhy
= NULL
;
578 Urb
->RequestMap
= NULL
;
583 // Map the request and user data
585 if (Request
!= NULL
) {
586 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
587 MapOp
= EdkiiIoMmuOperationBusMasterRead
;
588 Status
= IoMmuMap (Ehc
->IoMmu
, MapOp
, Request
, &Len
, &PhyAddr
, &Map
);
590 if (EFI_ERROR (Status
) || (Len
!= sizeof (EFI_USB_DEVICE_REQUEST
))) {
594 Urb
->RequestPhy
= (VOID
*)((UINTN
)PhyAddr
);
595 Urb
->RequestMap
= Map
;
601 if (Ep
->Direction
== EfiUsbDataIn
) {
602 MapOp
= EdkiiIoMmuOperationBusMasterWrite
;
604 MapOp
= EdkiiIoMmuOperationBusMasterRead
;
607 Status
= IoMmuMap (Ehc
->IoMmu
, MapOp
, Data
, &Len
, &PhyAddr
, &Map
);
609 if (EFI_ERROR (Status
) || (Len
!= DataLen
)) {
613 Urb
->DataPhy
= (VOID
*)((UINTN
)PhyAddr
);
617 Status
= EhcCreateQtds (Ehc
, Urb
);
619 if (EFI_ERROR (Status
)) {
626 EhcFreeUrb (Ehc
, Urb
);