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