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