Home | History | Annotate | Download | only in EhciDxe
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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