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