1 /** @file
2 
3   EHCI transfer scheduling routines.
4 
5 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "Ehci.h"
11 
12 
13 /**
14   Create helper QTD/QH for the EHCI device.
15 
16   @param  Ehc                   The EHCI device.
17 
18   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for helper QTD/QH.
19   @retval EFI_SUCCESS           Helper QH/QTD are created.
20 
21 **/
22 EFI_STATUS
EhcCreateHelpQ(IN USB2_HC_DEV * Ehc)23 EhcCreateHelpQ (
24   IN USB2_HC_DEV          *Ehc
25   )
26 {
27   USB_ENDPOINT            Ep;
28   EHC_QH                  *Qh;
29   QH_HW                   *QhHw;
30   EHC_QTD                 *Qtd;
31   EFI_PHYSICAL_ADDRESS    PciAddr;
32 
33   //
34   // Create an inactive Qtd to terminate the short packet read.
35   //
36   Qtd = EhcCreateQtd (Ehc, NULL, NULL, 0, QTD_PID_INPUT, 0, 64);
37 
38   if (Qtd == NULL) {
39     return EFI_OUT_OF_RESOURCES;
40   }
41 
42   Qtd->QtdHw.Status   = QTD_STAT_HALTED;
43   Ehc->ShortReadStop  = Qtd;
44 
45   //
46   // Create a QH to act as the EHC reclamation header.
47   // Set the header to loopback to itself.
48   //
49   Ep.DevAddr    = 0;
50   Ep.EpAddr     = 1;
51   Ep.Direction  = EfiUsbDataIn;
52   Ep.DevSpeed   = EFI_USB_SPEED_HIGH;
53   Ep.MaxPacket  = 64;
54   Ep.HubAddr    = 0;
55   Ep.HubPort    = 0;
56   Ep.Toggle     = 0;
57   Ep.Type       = EHC_BULK_TRANSFER;
58   Ep.PollRate   = 1;
59 
60   Qh            = EhcCreateQh (Ehc, &Ep);
61 
62   if (Qh == NULL) {
63     return EFI_OUT_OF_RESOURCES;
64   }
65 
66   PciAddr           = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));
67   QhHw              = &Qh->QhHw;
68   QhHw->HorizonLink = QH_LINK (PciAddr + OFFSET_OF(EHC_QH, QhHw), EHC_TYPE_QH, FALSE);
69   QhHw->Status      = QTD_STAT_HALTED;
70   QhHw->ReclaimHead = 1;
71   Qh->NextQh        = Qh;
72   Ehc->ReclaimHead  = Qh;
73 
74   //
75   // Create a dummy QH to act as the terminator for periodical schedule
76   //
77   Ep.EpAddr   = 2;
78   Ep.Type     = EHC_INT_TRANSFER_SYNC;
79 
80   Qh          = EhcCreateQh (Ehc, &Ep);
81 
82   if (Qh == NULL) {
83     return EFI_OUT_OF_RESOURCES;
84   }
85 
86   Qh->QhHw.Status = QTD_STAT_HALTED;
87   Ehc->PeriodOne  = Qh;
88 
89   return EFI_SUCCESS;
90 }
91 
92 
93 /**
94   Initialize the schedule data structure such as frame list.
95 
96   @param  Ehc                   The EHCI device to init schedule data.
97 
98   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to init schedule data.
99   @retval EFI_SUCCESS           The schedule data is initialized.
100 
101 **/
102 EFI_STATUS
EhcInitSched(IN USB2_HC_DEV * Ehc)103 EhcInitSched (
104   IN USB2_HC_DEV          *Ehc
105   )
106 {
107   EFI_PCI_IO_PROTOCOL   *PciIo;
108   VOID                  *Buf;
109   EFI_PHYSICAL_ADDRESS  PhyAddr;
110   VOID                  *Map;
111   UINTN                 Pages;
112   UINTN                 Bytes;
113   UINTN                 Index;
114   EFI_STATUS            Status;
115   EFI_PHYSICAL_ADDRESS  PciAddr;
116 
117   //
118   // First initialize the periodical schedule data:
119   // 1. Allocate and map the memory for the frame list
120   // 2. Create the help QTD/QH
121   // 3. Initialize the frame entries
122   // 4. Set the frame list register
123   //
124   PciIo = Ehc->PciIo;
125 
126   Bytes = 4096;
127   Pages = EFI_SIZE_TO_PAGES (Bytes);
128 
129   Status = PciIo->AllocateBuffer (
130                     PciIo,
131                     AllocateAnyPages,
132                     EfiBootServicesData,
133                     Pages,
134                     &Buf,
135                     0
136                     );
137 
138   if (EFI_ERROR (Status)) {
139     return EFI_OUT_OF_RESOURCES;
140   }
141 
142   Status = PciIo->Map (
143                     PciIo,
144                     EfiPciIoOperationBusMasterCommonBuffer,
145                     Buf,
146                     &Bytes,
147                     &PhyAddr,
148                     &Map
149                     );
150 
151   if (EFI_ERROR (Status) || (Bytes != 4096)) {
152     PciIo->FreeBuffer (PciIo, Pages, Buf);
153     return EFI_OUT_OF_RESOURCES;
154   }
155 
156   Ehc->PeriodFrame      = Buf;
157   Ehc->PeriodFrameMap   = Map;
158 
159   //
160   // Program the FRAMELISTBASE register with the low 32 bit addr
161   //
162   EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (PhyAddr));
163   //
164   // Program the CTRLDSSEGMENT register with the high 32 bit addr
165   //
166   EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, EHC_HIGH_32BIT (PhyAddr));
167 
168   //
169   // Init memory pool management then create the helper
170   // QTD/QH. If failed, previously allocated resources
171   // will be freed by EhcFreeSched
172   //
173   Ehc->MemPool = UsbHcInitMemPool (
174                    PciIo,
175                    Ehc->Support64BitDma,
176                    EHC_HIGH_32BIT (PhyAddr)
177                    );
178 
179   if (Ehc->MemPool == NULL) {
180     Status = EFI_OUT_OF_RESOURCES;
181     goto ErrorExit1;
182   }
183 
184   Status = EhcCreateHelpQ (Ehc);
185 
186   if (EFI_ERROR (Status)) {
187     goto ErrorExit;
188   }
189 
190   //
191   // Initialize the frame list entries then set the registers
192   //
193   Ehc->PeriodFrameHost      = AllocateZeroPool (EHC_FRAME_LEN * sizeof (UINTN));
194   if (Ehc->PeriodFrameHost == NULL) {
195     Status = EFI_OUT_OF_RESOURCES;
196     goto ErrorExit;
197   }
198 
199   PciAddr  = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
200 
201   for (Index = 0; Index < EHC_FRAME_LEN; Index++) {
202     //
203     // Store the pci bus address of the QH in period frame list which will be accessed by pci bus master.
204     //
205     ((UINT32 *)(Ehc->PeriodFrame))[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
206     //
207     // Store the host address of the QH in period frame list which will be accessed by host.
208     //
209     ((UINTN *)(Ehc->PeriodFrameHost))[Index] = (UINTN)Ehc->PeriodOne;
210   }
211 
212   //
213   // Second initialize the asynchronous schedule:
214   // Only need to set the AsynListAddr register to
215   // the reclamation header
216   //
217   PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
218   EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (PciAddr));
219   return EFI_SUCCESS;
220 
221 ErrorExit:
222   if (Ehc->PeriodOne != NULL) {
223     UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
224     Ehc->PeriodOne = NULL;
225   }
226 
227   if (Ehc->ReclaimHead != NULL) {
228     UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
229     Ehc->ReclaimHead = NULL;
230   }
231 
232   if (Ehc->ShortReadStop != NULL) {
233     UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
234     Ehc->ShortReadStop = NULL;
235   }
236 
237 ErrorExit1:
238   PciIo->FreeBuffer (PciIo, Pages, Buf);
239   PciIo->Unmap (PciIo, Map);
240 
241   return Status;
242 }
243 
244 
245 /**
246   Free the schedule data. It may be partially initialized.
247 
248   @param  Ehc                   The EHCI device.
249 
250 **/
251 VOID
EhcFreeSched(IN USB2_HC_DEV * Ehc)252 EhcFreeSched (
253   IN USB2_HC_DEV          *Ehc
254   )
255 {
256   EFI_PCI_IO_PROTOCOL     *PciIo;
257 
258   EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0);
259   EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0);
260 
261   if (Ehc->PeriodOne != NULL) {
262     UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));
263     Ehc->PeriodOne = NULL;
264   }
265 
266   if (Ehc->ReclaimHead != NULL) {
267     UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));
268     Ehc->ReclaimHead = NULL;
269   }
270 
271   if (Ehc->ShortReadStop != NULL) {
272     UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
273     Ehc->ShortReadStop = NULL;
274   }
275 
276   if (Ehc->MemPool != NULL) {
277     UsbHcFreeMemPool (Ehc->MemPool);
278     Ehc->MemPool = NULL;
279   }
280 
281   if (Ehc->PeriodFrame != NULL) {
282     PciIo = Ehc->PciIo;
283     ASSERT (PciIo != NULL);
284 
285     PciIo->Unmap (PciIo, Ehc->PeriodFrameMap);
286 
287     PciIo->FreeBuffer (
288              PciIo,
289              EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE),
290              Ehc->PeriodFrame
291              );
292 
293     Ehc->PeriodFrame = NULL;
294   }
295 
296   if (Ehc->PeriodFrameHost != NULL) {
297     FreePool (Ehc->PeriodFrameHost);
298     Ehc->PeriodFrameHost = NULL;
299   }
300 }
301 
302 
303 /**
304   Link the queue head to the asynchronous schedule list.
305   UEFI only supports one CTRL/BULK transfer at a time
306   due to its interfaces. This simplifies the AsynList
307   management: A reclamation header is always linked to
308   the AsyncListAddr, the only active QH is appended to it.
309 
310   @param  Ehc                   The EHCI device.
311   @param  Qh                    The queue head to link.
312 
313 **/
314 VOID
EhcLinkQhToAsync(IN USB2_HC_DEV * Ehc,IN EHC_QH * Qh)315 EhcLinkQhToAsync (
316   IN USB2_HC_DEV          *Ehc,
317   IN EHC_QH               *Qh
318   )
319 {
320   EHC_QH                  *Head;
321   EFI_PHYSICAL_ADDRESS    PciAddr;
322 
323   //
324   // Append the queue head after the reclaim header, then
325   // fix the hardware visiable parts (EHCI R1.0 page 72).
326   // ReclaimHead is always linked to the EHCI's AsynListAddr.
327   //
328   Head                    = Ehc->ReclaimHead;
329 
330   Qh->NextQh              = Head->NextQh;
331   Head->NextQh            = Qh;
332 
333   PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh->NextQh, sizeof (EHC_QH));
334   Qh->QhHw.HorizonLink    = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
335   PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));
336   Head->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
337 }
338 
339 
340 /**
341   Unlink a queue head from the asynchronous schedule list.
342   Need to synchronize with hardware.
343 
344   @param  Ehc                   The EHCI device.
345   @param  Qh                    The queue head to unlink.
346 
347 **/
348 VOID
EhcUnlinkQhFromAsync(IN USB2_HC_DEV * Ehc,IN EHC_QH * Qh)349 EhcUnlinkQhFromAsync (
350   IN USB2_HC_DEV          *Ehc,
351   IN EHC_QH               *Qh
352   )
353 {
354   EHC_QH                  *Head;
355   EFI_STATUS              Status;
356   EFI_PHYSICAL_ADDRESS    PciAddr;
357 
358   ASSERT (Ehc->ReclaimHead->NextQh == Qh);
359 
360   //
361   // Remove the QH from reclamation head, then update the hardware
362   // visiable part: Only need to loopback the ReclaimHead. The Qh
363   // is pointing to ReclaimHead (which is staill in the list).
364   //
365   Head                    = Ehc->ReclaimHead;
366 
367   Head->NextQh            = Qh->NextQh;
368   Qh->NextQh              = NULL;
369 
370   PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));
371   Head->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
372 
373   //
374   // Set and wait the door bell to synchronize with the hardware
375   //
376   Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIMEOUT);
377 
378   if (EFI_ERROR (Status)) {
379     DEBUG ((EFI_D_ERROR, "EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n"));
380   }
381 }
382 
383 
384 /**
385   Link a queue head for interrupt transfer to the periodic
386   schedule frame list. This code is very much the same as
387   that in UHCI.
388 
389   @param  Ehc                   The EHCI device.
390   @param  Qh                    The queue head to link.
391 
392 **/
393 VOID
EhcLinkQhToPeriod(IN USB2_HC_DEV * Ehc,IN EHC_QH * Qh)394 EhcLinkQhToPeriod (
395   IN USB2_HC_DEV          *Ehc,
396   IN EHC_QH               *Qh
397   )
398 {
399   UINTN                   Index;
400   EHC_QH                  *Prev;
401   EHC_QH                  *Next;
402   EFI_PHYSICAL_ADDRESS    PciAddr;
403 
404   for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {
405     //
406     // First QH can't be NULL because we always keep PeriodOne
407     // heads on the frame list
408     //
409     ASSERT (!EHC_LINK_TERMINATED (((UINT32*)Ehc->PeriodFrame)[Index]));
410     Next  = (EHC_QH*)((UINTN*)Ehc->PeriodFrameHost)[Index];
411     Prev  = NULL;
412 
413     //
414     // Now, insert the queue head (Qh) into this frame:
415     // 1. Find a queue head with the same poll interval, just insert
416     //    Qh after this queue head, then we are done.
417     //
418     // 2. Find the position to insert the queue head into:
419     //      Previous head's interval is bigger than Qh's
420     //      Next head's interval is less than Qh's
421     //    Then, insert the Qh between then
422     //
423     while (Next->Interval > Qh->Interval) {
424       Prev  = Next;
425       Next  = Next->NextQh;
426     }
427 
428     ASSERT (Next != NULL);
429 
430     //
431     // The entry may have been linked into the frame by early insertation.
432     // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh
433     // with Qh.Interval == 8 on the frame. If so, we are done with this frame.
434     // It isn't necessary to compare all the QH with the same interval to
435     // Qh. This is because if there is other QH with the same interval, Qh
436     // should has been inserted after that at Frames[0] and at Frames[0] it is
437     // impossible for (Next == Qh)
438     //
439     if (Next == Qh) {
440       continue;
441     }
442 
443     if (Next->Interval == Qh->Interval) {
444       //
445       // If there is a QH with the same interval, it locates at
446       // Frames[0], and we can simply insert it after this QH. We
447       // are all done.
448       //
449       ASSERT ((Index == 0) && (Qh->NextQh == NULL));
450 
451       Prev                    = Next;
452       Next                    = Next->NextQh;
453 
454       Qh->NextQh              = Next;
455       Prev->NextQh            = Qh;
456 
457       Qh->QhHw.HorizonLink    = Prev->QhHw.HorizonLink;
458       PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));
459       Prev->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
460       break;
461     }
462 
463     //
464     // OK, find the right position, insert it in. If Qh's next
465     // link has already been set, it is in position. This is
466     // guarranted by 2^n polling interval.
467     //
468     if (Qh->NextQh == NULL) {
469       Qh->NextQh              = Next;
470       PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Next, sizeof (EHC_QH));
471       Qh->QhHw.HorizonLink    = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
472     }
473 
474     PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));
475 
476     if (Prev == NULL) {
477       ((UINT32*)Ehc->PeriodFrame)[Index]     = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
478       ((UINTN*)Ehc->PeriodFrameHost)[Index]  = (UINTN)Qh;
479     } else {
480       Prev->NextQh            = Qh;
481       Prev->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);
482     }
483   }
484 }
485 
486 
487 /**
488   Unlink an interrupt queue head from the periodic
489   schedule frame list.
490 
491   @param  Ehc                   The EHCI device.
492   @param  Qh                    The queue head to unlink.
493 
494 **/
495 VOID
EhcUnlinkQhFromPeriod(IN USB2_HC_DEV * Ehc,IN EHC_QH * Qh)496 EhcUnlinkQhFromPeriod (
497   IN USB2_HC_DEV          *Ehc,
498   IN EHC_QH               *Qh
499   )
500 {
501   UINTN                   Index;
502   EHC_QH                  *Prev;
503   EHC_QH                  *This;
504 
505   for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {
506     //
507     // Frame link can't be NULL because we always keep PeroidOne
508     // on the frame list
509     //
510     ASSERT (!EHC_LINK_TERMINATED (((UINT32*)Ehc->PeriodFrame)[Index]));
511     This  = (EHC_QH*)((UINTN*)Ehc->PeriodFrameHost)[Index];
512     Prev  = NULL;
513 
514     //
515     // Walk through the frame's QH list to find the
516     // queue head to remove
517     //
518     while ((This != NULL) && (This != Qh)) {
519       Prev  = This;
520       This  = This->NextQh;
521     }
522 
523     //
524     // Qh may have already been unlinked from this frame
525     // by early action. See the comments in EhcLinkQhToPeriod.
526     //
527     if (This == NULL) {
528       continue;
529     }
530 
531     if (Prev == NULL) {
532       //
533       // Qh is the first entry in the frame
534       //
535       ((UINT32*)Ehc->PeriodFrame)[Index] = Qh->QhHw.HorizonLink;
536       ((UINTN*)Ehc->PeriodFrameHost)[Index] = (UINTN)Qh->NextQh;
537     } else {
538       Prev->NextQh            = Qh->NextQh;
539       Prev->QhHw.HorizonLink  = Qh->QhHw.HorizonLink;
540     }
541   }
542 }
543 
544 
545 /**
546   Check the URB's execution result and update the URB's
547   result accordingly.
548 
549   @param  Ehc                   The EHCI device.
550   @param  Urb                   The URB to check result.
551 
552   @return Whether the result of URB transfer is finialized.
553 
554 **/
555 BOOLEAN
EhcCheckUrbResult(IN USB2_HC_DEV * Ehc,IN URB * Urb)556 EhcCheckUrbResult (
557   IN  USB2_HC_DEV         *Ehc,
558   IN  URB                 *Urb
559   )
560 {
561   LIST_ENTRY              *Entry;
562   EHC_QTD                 *Qtd;
563   QTD_HW                  *QtdHw;
564   UINT8                   State;
565   BOOLEAN                 Finished;
566   EFI_PHYSICAL_ADDRESS    PciAddr;
567 
568   ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));
569 
570   Finished        = TRUE;
571   Urb->Completed  = 0;
572 
573   Urb->Result     = EFI_USB_NOERROR;
574 
575   if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
576     Urb->Result |= EFI_USB_ERR_SYSTEM;
577     goto ON_EXIT;
578   }
579 
580   EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
581     Qtd   = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
582     QtdHw = &Qtd->QtdHw;
583     State = (UINT8) QtdHw->Status;
584 
585     if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {
586       //
587       // EHCI will halt the queue head when met some error.
588       // If it is halted, the result of URB is finialized.
589       //
590       if ((State & QTD_STAT_ERR_MASK) == 0) {
591         Urb->Result |= EFI_USB_ERR_STALL;
592       }
593 
594       if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {
595         Urb->Result |= EFI_USB_ERR_BABBLE;
596       }
597 
598       if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {
599         Urb->Result |= EFI_USB_ERR_BUFFER;
600       }
601 
602       if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) {
603         Urb->Result |= EFI_USB_ERR_TIMEOUT;
604       }
605 
606       Finished = TRUE;
607       goto ON_EXIT;
608 
609     } else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {
610       //
611       // The QTD is still active, no need to check furthur.
612       //
613       Urb->Result |= EFI_USB_ERR_NOTEXECUTE;
614 
615       Finished = FALSE;
616       goto ON_EXIT;
617 
618     } else {
619       //
620       // This QTD is finished OK or met short packet read. Update the
621       // transfer length if it isn't a setup.
622       //
623       if (QtdHw->Pid != QTD_PID_SETUP) {
624         Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes;
625       }
626 
627       if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {
628         EhcDumpQh (Urb->Qh, "Short packet read", FALSE);
629 
630         //
631         // Short packet read condition. If it isn't a setup transfer,
632         // no need to check furthur: the queue head will halt at the
633         // ShortReadStop. If it is a setup transfer, need to check the
634         // Status Stage of the setup transfer to get the finial result
635         //
636         PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
637         if (QtdHw->AltNext == QTD_LINK (PciAddr, FALSE)) {
638           DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, break\n"));
639 
640           Finished = TRUE;
641           goto ON_EXIT;
642         }
643 
644         DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, continue\n"));
645       }
646     }
647   }
648 
649 ON_EXIT:
650   //
651   // Return the data toggle set by EHCI hardware, bulk and interrupt
652   // transfer will use this to initialize the next transaction. For
653   // Control transfer, it always start a new data toggle sequence for
654   // new transfer.
655   //
656   // NOTICE: don't move DT update before the loop, otherwise there is
657   // a race condition that DT is wrong.
658   //
659   Urb->DataToggle = (UINT8) Urb->Qh->QhHw.DataToggle;
660 
661   return Finished;
662 }
663 
664 
665 /**
666   Execute the transfer by polling the URB. This is a synchronous operation.
667 
668   @param  Ehc               The EHCI device.
669   @param  Urb               The URB to execute.
670   @param  TimeOut           The time to wait before abort, in millisecond.
671 
672   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
673   @return EFI_TIMEOUT       The transfer failed due to time out.
674   @return EFI_SUCCESS       The transfer finished OK.
675 
676 **/
677 EFI_STATUS
EhcExecTransfer(IN USB2_HC_DEV * Ehc,IN URB * Urb,IN UINTN TimeOut)678 EhcExecTransfer (
679   IN  USB2_HC_DEV         *Ehc,
680   IN  URB                 *Urb,
681   IN  UINTN               TimeOut
682   )
683 {
684   EFI_STATUS              Status;
685   UINTN                   Index;
686   UINTN                   Loop;
687   BOOLEAN                 Finished;
688   BOOLEAN                 InfiniteLoop;
689 
690   Status       = EFI_SUCCESS;
691   Loop         = TimeOut * EHC_1_MILLISECOND;
692   Finished     = FALSE;
693   InfiniteLoop = FALSE;
694 
695   //
696   // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller
697   // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR
698   // is returned.
699   //
700   if (TimeOut == 0) {
701     InfiniteLoop = TRUE;
702   }
703 
704   for (Index = 0; InfiniteLoop || (Index < Loop); Index++) {
705     Finished = EhcCheckUrbResult (Ehc, Urb);
706 
707     if (Finished) {
708       break;
709     }
710 
711     gBS->Stall (EHC_1_MICROSECOND);
712   }
713 
714   if (!Finished) {
715     DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer not finished in %dms\n", (UINT32)TimeOut));
716     EhcDumpQh (Urb->Qh, NULL, FALSE);
717 
718     Status = EFI_TIMEOUT;
719 
720   } else if (Urb->Result != EFI_USB_NOERROR) {
721     DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer failed with %x\n", Urb->Result));
722     EhcDumpQh (Urb->Qh, NULL, FALSE);
723 
724     Status = EFI_DEVICE_ERROR;
725   }
726 
727   return Status;
728 }
729 
730 
731 /**
732   Delete a single asynchronous interrupt transfer for
733   the device and endpoint.
734 
735   @param  Ehc                   The EHCI device.
736   @param  DevAddr               The address of the target device.
737   @param  EpNum                 The endpoint of the target.
738   @param  DataToggle            Return the next data toggle to use.
739 
740   @retval EFI_SUCCESS           An asynchronous transfer is removed.
741   @retval EFI_NOT_FOUND         No transfer for the device is found.
742 
743 **/
744 EFI_STATUS
EhciDelAsyncIntTransfer(IN USB2_HC_DEV * Ehc,IN UINT8 DevAddr,IN UINT8 EpNum,OUT UINT8 * DataToggle)745 EhciDelAsyncIntTransfer (
746   IN  USB2_HC_DEV         *Ehc,
747   IN  UINT8               DevAddr,
748   IN  UINT8               EpNum,
749   OUT UINT8               *DataToggle
750   )
751 {
752   LIST_ENTRY              *Entry;
753   LIST_ENTRY              *Next;
754   URB                     *Urb;
755   EFI_USB_DATA_DIRECTION  Direction;
756 
757   Direction = (((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
758   EpNum    &= 0x0F;
759 
760   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
761     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
762 
763     if ((Urb->Ep.DevAddr == DevAddr) && (Urb->Ep.EpAddr == EpNum) &&
764         (Urb->Ep.Direction == Direction)) {
765       //
766       // Check the URB status to retrieve the next data toggle
767       // from the associated queue head.
768       //
769       EhcCheckUrbResult (Ehc, Urb);
770       *DataToggle = Urb->DataToggle;
771 
772       EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
773       RemoveEntryList (&Urb->UrbList);
774 
775       gBS->FreePool (Urb->Data);
776       EhcFreeUrb (Ehc, Urb);
777       return EFI_SUCCESS;
778     }
779   }
780 
781   return EFI_NOT_FOUND;
782 }
783 
784 
785 /**
786   Remove all the asynchronous interrutp transfers.
787 
788   @param  Ehc                   The EHCI device.
789 
790 **/
791 VOID
EhciDelAllAsyncIntTransfers(IN USB2_HC_DEV * Ehc)792 EhciDelAllAsyncIntTransfers (
793   IN USB2_HC_DEV          *Ehc
794   )
795 {
796   LIST_ENTRY              *Entry;
797   LIST_ENTRY              *Next;
798   URB                     *Urb;
799 
800   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
801     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
802 
803     EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
804     RemoveEntryList (&Urb->UrbList);
805 
806     gBS->FreePool (Urb->Data);
807     EhcFreeUrb (Ehc, Urb);
808   }
809 }
810 
811 /**
812   Insert a single asynchronous interrupt transfer for
813   the device and endpoint.
814 
815   @param  Ehc               The EHCI device.
816   @param  DevAddr           The device address.
817   @param  EpAddr            Endpoint addrress & its direction.
818   @param  DevSpeed          The device speed.
819   @param  Toggle            Initial data toggle to use.
820   @param  MaxPacket         The max packet length of the endpoint.
821   @param  Hub               The transaction translator to use.
822   @param  DataLen           The length of data buffer.
823   @param  Callback          The function to call when data is transferred.
824   @param  Context           The context to the callback.
825   @param  Interval          The interval for interrupt transfer.
826 
827   @return Created URB or NULL.
828 
829 **/
830 URB *
EhciInsertAsyncIntTransfer(IN 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 DataLen,IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,IN VOID * Context,IN UINTN Interval)831 EhciInsertAsyncIntTransfer (
832   IN USB2_HC_DEV                        *Ehc,
833   IN UINT8                              DevAddr,
834   IN UINT8                              EpAddr,
835   IN UINT8                              DevSpeed,
836   IN UINT8                              Toggle,
837   IN UINTN                              MaxPacket,
838   IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
839   IN UINTN                              DataLen,
840   IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,
841   IN VOID                               *Context,
842   IN UINTN                              Interval
843   )
844 {
845   VOID      *Data;
846   URB       *Urb;
847 
848   Data = AllocatePool (DataLen);
849 
850   if (Data == NULL) {
851     DEBUG ((DEBUG_ERROR, "%a: failed to allocate buffer\n", __FUNCTION__));
852     return NULL;
853   }
854 
855   Urb = EhcCreateUrb (
856           Ehc,
857           DevAddr,
858           EpAddr,
859           DevSpeed,
860           Toggle,
861           MaxPacket,
862           Hub,
863           EHC_INT_TRANSFER_ASYNC,
864           NULL,
865           Data,
866           DataLen,
867           Callback,
868           Context,
869           Interval
870           );
871 
872   if (Urb == NULL) {
873     DEBUG ((DEBUG_ERROR, "%a: failed to create URB\n", __FUNCTION__));
874     gBS->FreePool (Data);
875     return NULL;
876   }
877 
878   //
879   // New asynchronous transfer must inserted to the head.
880   // Check the comments in EhcMoniteAsyncRequests
881   //
882   EhcLinkQhToPeriod (Ehc, Urb->Qh);
883   InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);
884 
885   return Urb;
886 }
887 
888 /**
889   Flush data from PCI controller specific address to mapped system
890   memory address.
891 
892   @param  Ehc                The EHCI device.
893   @param  Urb                The URB to unmap.
894 
895   @retval EFI_SUCCESS        Success to flush data to mapped system memory.
896   @retval EFI_DEVICE_ERROR   Fail to flush data to mapped system memory.
897 
898 **/
899 EFI_STATUS
EhcFlushAsyncIntMap(IN USB2_HC_DEV * Ehc,IN URB * Urb)900 EhcFlushAsyncIntMap (
901   IN  USB2_HC_DEV         *Ehc,
902   IN  URB                 *Urb
903   )
904 {
905   EFI_STATUS                    Status;
906   EFI_PHYSICAL_ADDRESS          PhyAddr;
907   EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
908   EFI_PCI_IO_PROTOCOL           *PciIo;
909   UINTN                         Len;
910   VOID                          *Map;
911 
912   PciIo = Ehc->PciIo;
913   Len   = Urb->DataLen;
914 
915   if (Urb->Ep.Direction == EfiUsbDataIn) {
916     MapOp = EfiPciIoOperationBusMasterWrite;
917   } else {
918     MapOp = EfiPciIoOperationBusMasterRead;
919   }
920 
921   Status = PciIo->Unmap (PciIo, Urb->DataMap);
922   if (EFI_ERROR (Status)) {
923     goto ON_ERROR;
924   }
925 
926   Urb->DataMap = NULL;
927 
928   Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);
929   if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
930     goto ON_ERROR;
931   }
932 
933   Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);
934   Urb->DataMap  = Map;
935   return EFI_SUCCESS;
936 
937 ON_ERROR:
938   return EFI_DEVICE_ERROR;
939 }
940 
941 
942 /**
943   Update the queue head for next round of asynchronous transfer.
944 
945   @param  Ehc                   The EHCI device.
946   @param  Urb                   The URB to update.
947 
948 **/
949 VOID
EhcUpdateAsyncRequest(IN USB2_HC_DEV * Ehc,IN URB * Urb)950 EhcUpdateAsyncRequest (
951   IN  USB2_HC_DEV         *Ehc,
952   IN URB                  *Urb
953   )
954 {
955   LIST_ENTRY              *Entry;
956   EHC_QTD                 *FirstQtd;
957   QH_HW                   *QhHw;
958   EHC_QTD                 *Qtd;
959   QTD_HW                  *QtdHw;
960   UINTN                   Index;
961   EFI_PHYSICAL_ADDRESS    PciAddr;
962 
963   Qtd = NULL;
964 
965   if (Urb->Result == EFI_USB_NOERROR) {
966     FirstQtd = NULL;
967 
968     EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {
969       Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
970 
971       if (FirstQtd == NULL) {
972         FirstQtd = Qtd;
973       }
974 
975       //
976       // Update the QTD for next round of transfer. Host control
977       // may change dt/Total Bytes to Transfer/C_Page/Cerr/Status/
978       // Current Offset. These fields need to be updated. DT isn't
979       // used by interrupt transfer. It uses DT in queue head.
980       // Current Offset is in Page[0], only need to reset Page[0]
981       // to initial data buffer.
982       //
983       QtdHw             = &Qtd->QtdHw;
984       QtdHw->Status     = QTD_STAT_ACTIVE;
985       QtdHw->ErrCnt     = QTD_MAX_ERR;
986       QtdHw->CurPage    = 0;
987       QtdHw->TotalBytes = (UINT32) Qtd->DataLen;
988       //
989       // calculate physical address by offset.
990       //
991       PciAddr = (UINTN)Urb->DataPhy + ((UINTN)Qtd->Data - (UINTN)Urb->Data);
992       QtdHw->Page[0]    = EHC_LOW_32BIT (PciAddr);
993       QtdHw->PageHigh[0]= EHC_HIGH_32BIT (PciAddr);
994     }
995 
996     //
997     // Update QH for next round of transfer. Host control only
998     // touch the fields in transfer overlay area. Only need to
999     // zero out the overlay area and set NextQtd to the first
1000     // QTD. DateToggle bit is left untouched.
1001     //
1002     QhHw              = &Urb->Qh->QhHw;
1003     QhHw->CurQtd      = QTD_LINK (0, TRUE);
1004     QhHw->AltQtd      = 0;
1005 
1006     QhHw->Status      = 0;
1007     QhHw->Pid         = 0;
1008     QhHw->ErrCnt      = 0;
1009     QhHw->CurPage     = 0;
1010     QhHw->Ioc         = 0;
1011     QhHw->TotalBytes  = 0;
1012 
1013     for (Index = 0; Index < 5; Index++) {
1014       QhHw->Page[Index]     = 0;
1015       QhHw->PageHigh[Index] = 0;
1016     }
1017 
1018     PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, FirstQtd, sizeof (EHC_QTD));
1019     QhHw->NextQtd = QTD_LINK (PciAddr, FALSE);
1020   }
1021 
1022   return ;
1023 }
1024 
1025 
1026 /**
1027   Interrupt transfer periodic check handler.
1028 
1029   @param  Event                 Interrupt event.
1030   @param  Context               Pointer to USB2_HC_DEV.
1031 
1032 **/
1033 VOID
1034 EFIAPI
EhcMonitorAsyncRequests(IN EFI_EVENT Event,IN VOID * Context)1035 EhcMonitorAsyncRequests (
1036   IN EFI_EVENT            Event,
1037   IN VOID                 *Context
1038   )
1039 {
1040   USB2_HC_DEV             *Ehc;
1041   EFI_TPL                 OldTpl;
1042   LIST_ENTRY              *Entry;
1043   LIST_ENTRY              *Next;
1044   BOOLEAN                 Finished;
1045   UINT8                   *ProcBuf;
1046   URB                     *Urb;
1047   EFI_STATUS              Status;
1048 
1049   OldTpl  = gBS->RaiseTPL (EHC_TPL);
1050   Ehc     = (USB2_HC_DEV *) Context;
1051 
1052   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {
1053     Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);
1054 
1055     //
1056     // Check the result of URB execution. If it is still
1057     // active, check the next one.
1058     //
1059     Finished = EhcCheckUrbResult (Ehc, Urb);
1060 
1061     if (!Finished) {
1062       continue;
1063     }
1064 
1065     //
1066     // Flush any PCI posted write transactions from a PCI host
1067     // bridge to system memory.
1068     //
1069     Status = EhcFlushAsyncIntMap (Ehc, Urb);
1070     if (EFI_ERROR (Status)) {
1071       DEBUG ((EFI_D_ERROR, "EhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));
1072     }
1073 
1074     //
1075     // Allocate a buffer then copy the transferred data for user.
1076     // If failed to allocate the buffer, update the URB for next
1077     // round of transfer. Ignore the data of this round.
1078     //
1079     ProcBuf = NULL;
1080 
1081     if (Urb->Result == EFI_USB_NOERROR) {
1082       //
1083       // Make sure the data received from HW is no more than expected.
1084       //
1085       if (Urb->Completed <= Urb->DataLen) {
1086         ProcBuf = AllocatePool (Urb->Completed);
1087       }
1088 
1089       if (ProcBuf == NULL) {
1090         EhcUpdateAsyncRequest (Ehc, Urb);
1091         continue;
1092       }
1093 
1094       CopyMem (ProcBuf, Urb->Data, Urb->Completed);
1095     }
1096 
1097     EhcUpdateAsyncRequest (Ehc, Urb);
1098 
1099     //
1100     // Leave error recovery to its related device driver. A
1101     // common case of the error recovery is to re-submit the
1102     // interrupt transfer which is linked to the head of the
1103     // list. This function scans from head to tail. So the
1104     // re-submitted interrupt transfer's callback function
1105     // will not be called again in this round. Don't touch this
1106     // URB after the callback, it may have been removed by the
1107     // callback.
1108     //
1109     if (Urb->Callback != NULL) {
1110       //
1111       // Restore the old TPL, USB bus maybe connect device in
1112       // his callback. Some drivers may has a lower TPL restriction.
1113       //
1114       gBS->RestoreTPL (OldTpl);
1115       (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);
1116       OldTpl = gBS->RaiseTPL (EHC_TPL);
1117     }
1118 
1119     if (ProcBuf != NULL) {
1120       FreePool (ProcBuf);
1121     }
1122   }
1123 
1124   gBS->RestoreTPL (OldTpl);
1125 }
1126