]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciPei/EhciUrb.c
IntelFsp2WrapperPkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciPei / EhciUrb.c
1 /** @file
2 PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
4
5 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) Microsoft Corporation.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include "EhcPeim.h"
13
14 /**
15 Delete a single asynchronous interrupt transfer for
16 the device and endpoint.
17
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.
24
25 @retval the pointer to the created QTD or NULL if failed to create one.
26
27 **/
28 PEI_EHC_QTD *
29 EhcCreateQtd (
30 IN PEI_USB2_HC_DEV *Ehc,
31 IN UINT8 *Data,
32 IN UINTN DataLen,
33 IN UINT8 PktId,
34 IN UINT8 Toggle,
35 IN UINTN MaxPacket
36 )
37 {
38 PEI_EHC_QTD *Qtd;
39 QTD_HW *QtdHw;
40 UINTN Index;
41 UINTN Len;
42 UINTN ThisBufLen;
43
44 ASSERT (Ehc != NULL);
45
46 Qtd = UsbHcAllocateMem (Ehc, Ehc->MemPool, sizeof (PEI_EHC_QTD));
47
48 if (Qtd == NULL) {
49 return NULL;
50 }
51
52 Qtd->Signature = EHC_QTD_SIG;
53 Qtd->Data = Data;
54 Qtd->DataLen = 0;
55
56 InitializeListHead (&Qtd->QtdList);
57
58 QtdHw = &Qtd->QtdHw;
59 QtdHw->NextQtd = QTD_LINK (NULL, TRUE);
60 QtdHw->AltNext = QTD_LINK (NULL, TRUE);
61 QtdHw->Status = QTD_STAT_ACTIVE;
62 QtdHw->Pid = PktId;
63 QtdHw->ErrCnt = QTD_MAX_ERR;
64 QtdHw->Ioc = 0;
65 QtdHw->TotalBytes = 0;
66 QtdHw->DataToggle = Toggle;
67
68 //
69 // Fill in the buffer points
70 //
71 if (Data != NULL) {
72 Len = 0;
73
74 for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {
75 //
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.
79 //
80 QtdHw->Page[Index] = EHC_LOW_32BIT (Data);
81 QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (Data);
82
83 ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (Data) & QTD_BUF_MASK);
84
85 if (Len + ThisBufLen >= DataLen) {
86 Len = DataLen;
87 break;
88 }
89
90 Len += ThisBufLen;
91 Data += ThisBufLen;
92 }
93
94 //
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
98 // need.
99 //
100 if (Len < DataLen) {
101 Len = Len - Len % MaxPacket;
102 }
103
104 QtdHw->TotalBytes = (UINT32) Len;
105 Qtd->DataLen = Len;
106 }
107
108 return Qtd;
109 }
110
111 /**
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.
117
118 @param Ep The queue head's related endpoint.
119 @param QhHw The queue head to initialize.
120
121 **/
122 VOID
123 EhcInitIntQh (
124 IN USB_ENDPOINT *Ep,
125 IN QH_HW *QhHw
126 )
127 {
128 //
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
133 // here
134 //
135 if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
136 QhHw->SMask = QH_MICROFRAME_0;
137 return ;
138 }
139
140 //
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.
150 //
151 QhHw->SMask = QH_MICROFRAME_1;
152 QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
153 }
154
155 /**
156 Allocate and initialize a EHCI queue head.
157
158 @param Ehci The EHCI device.
159 @param Ep The endpoint to create queue head for.
160
161 @retval the pointer to the created queue head or NULL if failed to create one.
162
163 **/
164 PEI_EHC_QH *
165 EhcCreateQh (
166 IN PEI_USB2_HC_DEV *Ehci,
167 IN USB_ENDPOINT *Ep
168 )
169 {
170 PEI_EHC_QH *Qh;
171 QH_HW *QhHw;
172
173 Qh = UsbHcAllocateMem (Ehci, Ehci->MemPool, sizeof (PEI_EHC_QH));
174
175 if (Qh == NULL) {
176 return NULL;
177 }
178
179 Qh->Signature = EHC_QH_SIG;
180 Qh->NextQh = NULL;
181 Qh->Interval = Ep->PollRate;
182
183 InitializeListHead (&Qh->Qtds);
184
185 QhHw = &Qh->QhHw;
186 QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);
187 QhHw->DeviceAddr = Ep->DevAddr;
188 QhHw->Inactive = 0;
189 QhHw->EpNum = Ep->EpAddr;
190 QhHw->EpSpeed = Ep->DevSpeed;
191 QhHw->DtCtrl = 0;
192 QhHw->ReclaimHead = 0;
193 QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;
194 QhHw->CtrlEp = 0;
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;
200
201 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
202 QhHw->Status |= QTD_STAT_DO_SS;
203 }
204
205 switch (Ep->Type) {
206 case EHC_CTRL_TRANSFER:
207 //
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.
211 //
212 QhHw->DtCtrl = 1;
213
214 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
215 QhHw->CtrlEp = 1;
216 }
217 break;
218
219 case EHC_INT_TRANSFER_ASYNC:
220 case EHC_INT_TRANSFER_SYNC:
221 //
222 // Special initialization for the interrupt transfer
223 // to set the S-Mask and C-Mask
224 //
225 QhHw->NakReload = 0;
226 EhcInitIntQh (Ep, QhHw);
227 break;
228
229 case EHC_BULK_TRANSFER:
230 if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
231 QhHw->Status |= QTD_STAT_DO_PING;
232 }
233
234 break;
235 }
236
237 return Qh;
238 }
239
240 /**
241 Convert the poll interval from application to that
242 be used by EHCI interface data structure. Only need
243 to get the max 2^n that is less than interval. UEFI
244 can't support high speed endpoint with a interval less
245 than 8 microframe because interval is specified in
246 the unit of ms (millisecond).
247
248 @param Interval The interval to convert.
249
250 @retval The converted interval.
251
252 **/
253 UINTN
254 EhcConvertPollRate (
255 IN UINTN Interval
256 )
257 {
258 UINTN BitCount;
259
260 if (Interval == 0) {
261 return 1;
262 }
263
264 //
265 // Find the index (1 based) of the highest non-zero bit
266 //
267 BitCount = 0;
268
269 while (Interval != 0) {
270 Interval >>= 1;
271 BitCount++;
272 }
273
274 return (UINTN)1 << (BitCount - 1);
275 }
276
277 /**
278 Free a list of QTDs.
279
280 @param Ehc The EHCI device.
281 @param Qtds The list head of the QTD.
282
283 **/
284 VOID
285 EhcFreeQtds (
286 IN PEI_USB2_HC_DEV *Ehc,
287 IN EFI_LIST_ENTRY *Qtds
288 )
289 {
290 EFI_LIST_ENTRY *Entry;
291 EFI_LIST_ENTRY *Next;
292 PEI_EHC_QTD *Qtd;
293
294 BASE_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
295 Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);
296
297 RemoveEntryList (&Qtd->QtdList);
298 UsbHcFreeMem (Ehc, Ehc->MemPool, Qtd, sizeof (PEI_EHC_QTD));
299 }
300 }
301
302 /**
303 Free an allocated URB. It is possible for it to be partially inited.
304
305 @param Ehc The EHCI device.
306 @param Urb The URB to free.
307
308 **/
309 VOID
310 EhcFreeUrb (
311 IN PEI_USB2_HC_DEV *Ehc,
312 IN PEI_URB *Urb
313 )
314 {
315 if (Urb->RequestPhy != NULL) {
316 IoMmuUnmap (Ehc->IoMmu, Urb->RequestMap);
317 }
318
319 if (Urb->DataMap != NULL) {
320 IoMmuUnmap (Ehc->IoMmu, Urb->DataMap);
321 }
322
323 if (Urb->Qh != NULL) {
324 //
325 // Ensure that this queue head has been unlinked from the
326 // schedule data structures. Free all the associated QTDs
327 //
328 EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
329 UsbHcFreeMem (Ehc, Ehc->MemPool, Urb->Qh, sizeof (PEI_EHC_QH));
330 }
331 }
332
333 /**
334 Create a list of QTDs for the URB.
335
336 @param Ehc The EHCI device.
337 @param Urb The URB to create QTDs for.
338
339 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.
340 @retval EFI_SUCCESS The QTDs are allocated for the URB.
341
342 **/
343 EFI_STATUS
344 EhcCreateQtds (
345 IN PEI_USB2_HC_DEV *Ehc,
346 IN PEI_URB *Urb
347 )
348 {
349 USB_ENDPOINT *Ep;
350 PEI_EHC_QH *Qh;
351 PEI_EHC_QTD *Qtd;
352 PEI_EHC_QTD *StatusQtd;
353 PEI_EHC_QTD *NextQtd;
354 EFI_LIST_ENTRY *Entry;
355 UINT32 AlterNext;
356 UINT8 Toggle;
357 UINTN Len;
358 UINT8 Pid;
359
360 ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
361
362 //
363 // EHCI follows the alternet next QTD pointer if it meets
364 // a short read and the AlterNext pointer is valid. UEFI
365 // EHCI driver should terminate the transfer except the
366 // control transfer.
367 //
368 Toggle = 0;
369 Qh = Urb->Qh;
370 Ep = &Urb->Ep;
371 StatusQtd = NULL;
372 AlterNext = QTD_LINK (NULL, TRUE);
373
374 if (Ep->Direction == EfiUsbDataIn) {
375 AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE);
376 }
377
378 //
379 // Build the Setup and status packets for control transfer
380 //
381 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
382 Len = sizeof (EFI_USB_DEVICE_REQUEST);
383 Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
384
385 if (Qtd == NULL) {
386 return EFI_OUT_OF_RESOURCES;
387 }
388
389 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
390
391 //
392 // Create the status packet now. Set the AlterNext to it. So, when
393 // EHCI meets a short control read, it can resume at the status stage.
394 // Use the opposite direction of the data stage, or IN if there is
395 // no data stage.
396 //
397 if (Ep->Direction == EfiUsbDataIn) {
398 Pid = QTD_PID_OUTPUT;
399 } else {
400 Pid = QTD_PID_INPUT;
401 }
402
403 StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket);
404
405 if (StatusQtd == NULL) {
406 goto ON_ERROR;
407 }
408
409 if (Ep->Direction == EfiUsbDataIn) {
410 AlterNext = QTD_LINK (StatusQtd, FALSE);
411 }
412
413 Toggle = 1;
414 }
415
416 //
417 // Build the data packets for all the transfers
418 //
419 if (Ep->Direction == EfiUsbDataIn) {
420 Pid = QTD_PID_INPUT;
421 } else {
422 Pid = QTD_PID_OUTPUT;
423 }
424
425 Qtd = NULL;
426 Len = 0;
427
428 while (Len < Urb->DataLen) {
429 Qtd = EhcCreateQtd (
430 Ehc,
431 (UINT8 *) Urb->DataPhy + Len,
432 Urb->DataLen - Len,
433 Pid,
434 Toggle,
435 Ep->MaxPacket
436 );
437
438 if (Qtd == NULL) {
439 goto ON_ERROR;
440 }
441
442 Qtd->QtdHw.AltNext = AlterNext;
443 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
444
445 //
446 // Switch the Toggle bit if odd number of packets are included in the QTD.
447 //
448 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
449 Toggle = (UINT8) (1 - Toggle);
450 }
451
452 Len += Qtd->DataLen;
453 }
454
455 //
456 // Insert the status packet for control transfer
457 //
458 if (Ep->Type == EHC_CTRL_TRANSFER) {
459 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
460 }
461
462 //
463 // OK, all the QTDs needed are created. Now, fix the NextQtd point
464 //
465 BASE_LIST_FOR_EACH (Entry, &Qh->Qtds) {
466 Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);
467
468 //
469 // break if it is the last entry on the list
470 //
471 if (Entry->ForwardLink == &Qh->Qtds) {
472 break;
473 }
474
475 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, PEI_EHC_QTD, QtdList);
476 Qtd->QtdHw.NextQtd = QTD_LINK (NextQtd, FALSE);
477 }
478
479 //
480 // Link the QTDs to the queue head
481 //
482 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, PEI_EHC_QTD, QtdList);
483 Qh->QhHw.NextQtd = QTD_LINK (NextQtd, FALSE);
484 return EFI_SUCCESS;
485
486 ON_ERROR:
487 EhcFreeQtds (Ehc, &Qh->Qtds);
488 return EFI_OUT_OF_RESOURCES;
489 }
490
491 /**
492 Create a new URB and its associated QTD.
493
494 @param Ehc The EHCI device.
495 @param DevAddr The device address.
496 @param EpAddr Endpoint addrress & its direction.
497 @param DevSpeed The device speed.
498 @param Toggle Initial data toggle to use.
499 @param MaxPacket The max packet length of the endpoint.
500 @param Hub The transaction translator to use.
501 @param Type The transaction type.
502 @param Request The standard USB request for control transfer.
503 @param Data The user data to transfer.
504 @param DataLen The length of data buffer.
505 @param Callback The function to call when data is transferred.
506 @param Context The context to the callback.
507 @param Interval The interval for interrupt transfer.
508
509 @retval the pointer to the created URB or NULL.
510
511 **/
512 PEI_URB *
513 EhcCreateUrb (
514 IN PEI_USB2_HC_DEV *Ehc,
515 IN UINT8 DevAddr,
516 IN UINT8 EpAddr,
517 IN UINT8 DevSpeed,
518 IN UINT8 Toggle,
519 IN UINTN MaxPacket,
520 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
521 IN UINTN Type,
522 IN EFI_USB_DEVICE_REQUEST *Request,
523 IN VOID *Data,
524 IN UINTN DataLen,
525 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
526 IN VOID *Context,
527 IN UINTN Interval
528 )
529 {
530 USB_ENDPOINT *Ep;
531 EFI_PHYSICAL_ADDRESS PhyAddr;
532 EDKII_IOMMU_OPERATION MapOp;
533 EFI_STATUS Status;
534 UINTN Len;
535 PEI_URB *Urb;
536 VOID *Map;
537
538 Map = NULL;
539
540 Urb = Ehc->Urb;
541 Urb->Signature = EHC_URB_SIG;
542 InitializeListHead (&Urb->UrbList);
543
544 Ep = &Urb->Ep;
545 Ep->DevAddr = DevAddr;
546 Ep->EpAddr = (UINT8) (EpAddr & 0x0F);
547 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
548 Ep->DevSpeed = DevSpeed;
549 Ep->MaxPacket = MaxPacket;
550
551 Ep->HubAddr = 0;
552 Ep->HubPort = 0;
553
554 if (DevSpeed != EFI_USB_SPEED_HIGH) {
555 ASSERT (Hub != NULL);
556
557 Ep->HubAddr = Hub->TranslatorHubAddress;
558 Ep->HubPort = Hub->TranslatorPortNumber;
559 }
560
561 Ep->Toggle = Toggle;
562 Ep->Type = Type;
563 Ep->PollRate = EhcConvertPollRate (Interval);
564
565 Urb->Request = Request;
566 Urb->Data = Data;
567 Urb->DataLen = DataLen;
568 Urb->Callback = Callback;
569 Urb->Context = Context;
570 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);
571
572 if (Urb->Qh == NULL) {
573 goto ON_ERROR;
574 }
575
576 Urb->RequestPhy = NULL;
577 Urb->RequestMap = NULL;
578 Urb->DataPhy = NULL;
579 Urb->DataMap = NULL;
580
581 //
582 // Map the request and user data
583 //
584 if (Request != NULL) {
585 Len = sizeof (EFI_USB_DEVICE_REQUEST);
586 MapOp = EdkiiIoMmuOperationBusMasterRead;
587 Status = IoMmuMap (Ehc->IoMmu, MapOp, Request, &Len, &PhyAddr, &Map);
588
589 if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
590 goto ON_ERROR;
591 }
592
593 Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);
594 Urb->RequestMap = Map;
595 }
596
597 if (Data != NULL) {
598 Len = DataLen;
599
600 if (Ep->Direction == EfiUsbDataIn) {
601 MapOp = EdkiiIoMmuOperationBusMasterWrite;
602 } else {
603 MapOp = EdkiiIoMmuOperationBusMasterRead;
604 }
605
606 Status = IoMmuMap (Ehc->IoMmu, MapOp, Data, &Len, &PhyAddr, &Map);
607
608 if (EFI_ERROR (Status) || (Len != DataLen)) {
609 goto ON_ERROR;
610 }
611
612 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
613 Urb->DataMap = Map;
614 }
615
616 Status = EhcCreateQtds (Ehc, Urb);
617
618 if (EFI_ERROR (Status)) {
619 goto ON_ERROR;
620 }
621
622 return Urb;
623
624 ON_ERROR:
625 EhcFreeUrb (Ehc, Urb);
626 return NULL;
627 }