]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / EhciSched.c
index b13e4078b0b85c543cc6f5f560bc07a0dbe1f0e0..fea6f47f4c04146e85cae140a9689dde97527403 100644 (file)
@@ -1,7 +1,9 @@
 /** @file\r
 \r
-Copyright (c) 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
+  EHCI transfer scheduling routines.\r
+\r
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
 http://opensource.org/licenses/bsd-license.php\r
@@ -9,31 +11,20 @@ http://opensource.org/licenses/bsd-license.php
 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
-Module Name:\r
-\r
-    EhciSched.c\r
-\r
-Abstract:\r
-\r
-    EHCI transfer scheduling routines\r
-\r
-Revision History\r
-\r
 **/\r
 \r
 #include "Ehci.h"\r
 \r
 \r
 /**\r
-  Create helper QTD/QH for the EHCI device\r
+  Create helper QTD/QH for the EHCI device.\r
 \r
-  @param  Ehc                   The EHCI device\r
+  @param  Ehc                   The EHCI device.\r
 \r
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for helper QTD/QH\r
-  @retval EFI_SUCCESS           Helper QH/QTD are created\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for helper QTD/QH.\r
+  @retval EFI_SUCCESS           Helper QH/QTD are created.\r
 \r
 **/\r
-STATIC\r
 EFI_STATUS\r
 EhcCreateHelpQ (\r
   IN USB2_HC_DEV          *Ehc\r
@@ -43,11 +34,12 @@ EhcCreateHelpQ (
   EHC_QH                  *Qh;\r
   QH_HW                   *QhHw;\r
   EHC_QTD                 *Qtd;\r
+  EFI_PHYSICAL_ADDRESS    PciAddr;\r
 \r
   //\r
   // Create an inactive Qtd to terminate the short packet read.\r
   //\r
-  Qtd = EhcCreateQtd (Ehc, NULL, 0, QTD_PID_INPUT, 0, 64);\r
+  Qtd = EhcCreateQtd (Ehc, NULL, NULL, 0, QTD_PID_INPUT, 0, 64);\r
 \r
   if (Qtd == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
@@ -77,10 +69,12 @@ EhcCreateHelpQ (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  PciAddr           = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));\r
   QhHw              = &Qh->QhHw;\r
-  QhHw->HorizonLink = QH_LINK (QhHw, EHC_TYPE_QH, FALSE);\r
+  QhHw->HorizonLink = QH_LINK (PciAddr + OFFSET_OF(EHC_QH, QhHw), EHC_TYPE_QH, FALSE);\r
   QhHw->Status      = QTD_STAT_HALTED;\r
   QhHw->ReclaimHead = 1;\r
+  Qh->NextQh        = Qh;\r
   Ehc->ReclaimHead  = Qh;\r
 \r
   //\r
@@ -102,14 +96,13 @@ EhcCreateHelpQ (
 }\r
 \r
 \r
-\r
 /**\r
-  Initialize the schedule data structure such as frame list\r
+  Initialize the schedule data structure such as frame list.\r
 \r
-  @param  Ehc                   The EHCI device to init schedule data for\r
+  @param  Ehc                   The EHCI device to init schedule data.\r
 \r
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to init schedule data\r
-  @retval EFI_SUCCESS           The schedule data is initialized\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to init schedule data.\r
+  @retval EFI_SUCCESS           The schedule data is initialized.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -124,8 +117,8 @@ EhcInitSched (
   UINTN                 Pages;\r
   UINTN                 Bytes;\r
   UINTN                 Index;\r
-  UINT32                *Desc;\r
   EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  PciAddr;\r
 \r
   //\r
   // First initialize the periodical schedule data:\r
@@ -166,10 +159,17 @@ EhcInitSched (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  Ehc->PeriodFrameHost  = Buf;\r
-  Ehc->PeriodFrame      = (VOID *) ((UINTN) PhyAddr);\r
+  Ehc->PeriodFrame      = Buf;\r
   Ehc->PeriodFrameMap   = Map;\r
-  Ehc->High32bitAddr    = EHC_HIGH_32BIT (PhyAddr);\r
+\r
+  //\r
+  // Program the FRAMELISTBASE register with the low 32 bit addr\r
+  //\r
+  EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (PhyAddr));\r
+  //\r
+  // Program the CTRLDSSEGMENT register with the high 32 bit addr\r
+  //\r
+  EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, EHC_HIGH_32BIT (PhyAddr));\r
 \r
   //\r
   // Init memory pool management then create the helper\r
@@ -178,48 +178,80 @@ EhcInitSched (
   //\r
   Ehc->MemPool = UsbHcInitMemPool (\r
                    PciIo,\r
-                   EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT),\r
-                   Ehc->High32bitAddr\r
+                   Ehc->Support64BitDma,\r
+                   EHC_HIGH_32BIT (PhyAddr)\r
                    );\r
 \r
   if (Ehc->MemPool == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit1;\r
   }\r
 \r
   Status = EhcCreateHelpQ (Ehc);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    goto ErrorExit;\r
   }\r
 \r
   //\r
   // Initialize the frame list entries then set the registers\r
   //\r
-  Desc = (UINT32 *) Ehc->PeriodFrame;\r
+  Ehc->PeriodFrameHost      = AllocateZeroPool (EHC_FRAME_LEN * sizeof (UINTN));\r
+  if (Ehc->PeriodFrameHost == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
+  }\r
+\r
+  PciAddr  = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));\r
 \r
   for (Index = 0; Index < EHC_FRAME_LEN; Index++) {\r
-    Desc[Index] = QH_LINK (Ehc->PeriodOne, EHC_TYPE_QH, FALSE);\r
+    //\r
+    // Store the pci bus address of the QH in period frame list which will be accessed by pci bus master.\r
+    //\r
+    ((UINT32 *)(Ehc->PeriodFrame))[Index] = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
+    //\r
+    // Store the host address of the QH in period frame list which will be accessed by host.\r
+    //\r
+    ((UINTN *)(Ehc->PeriodFrameHost))[Index] = (UINTN)Ehc->PeriodOne;\r
   }\r
 \r
-  EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (Ehc->PeriodFrame));\r
-\r
   //\r
   // Second initialize the asynchronous schedule:\r
   // Only need to set the AsynListAddr register to\r
   // the reclamation header\r
   //\r
-  EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (Ehc->ReclaimHead));\r
+  PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));\r
+  EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (PciAddr));\r
   return EFI_SUCCESS;\r
-}\r
 \r
+ErrorExit:\r
+  if (Ehc->PeriodOne != NULL) {\r
+    UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));\r
+    Ehc->PeriodOne = NULL;\r
+  }\r
+\r
+  if (Ehc->ReclaimHead != NULL) {\r
+    UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (EHC_QH));\r
+    Ehc->ReclaimHead = NULL;\r
+  }\r
+\r
+  if (Ehc->ShortReadStop != NULL) {\r
+    UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));\r
+    Ehc->ShortReadStop = NULL;\r
+  }\r
+\r
+ErrorExit1:\r
+  PciIo->FreeBuffer (PciIo, Pages, Buf);\r
+  PciIo->Unmap (PciIo, Map);\r
+\r
+  return Status;\r
+}\r
 \r
 \r
 /**\r
   Free the schedule data. It may be partially initialized.\r
 \r
-  @param  Ehc                   The EHCI device\r
-\r
-  @return None\r
+  @param  Ehc                   The EHCI device.\r
 \r
 **/\r
 VOID\r
@@ -261,13 +293,17 @@ EhcFreeSched (
     PciIo->FreeBuffer (\r
              PciIo,\r
              EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE),\r
-             Ehc->PeriodFrameHost\r
+             Ehc->PeriodFrame\r
              );\r
 \r
     Ehc->PeriodFrame = NULL;\r
   }\r
-}\r
 \r
+  if (Ehc->PeriodFrameHost != NULL) {\r
+    FreePool (Ehc->PeriodFrameHost);\r
+    Ehc->PeriodFrameHost = NULL;\r
+  }\r
+}\r
 \r
 \r
 /**\r
@@ -277,10 +313,8 @@ EhcFreeSched (
   management: A reclamation header is always linked to\r
   the AsyncListAddr, the only active QH is appended to it.\r
 \r
-  @param  Ehc                   The EHCI device\r
-  @param  Qh                    The queue head to link\r
-\r
-  @return None\r
+  @param  Ehc                   The EHCI device.\r
+  @param  Qh                    The queue head to link.\r
 \r
 **/\r
 VOID\r
@@ -290,6 +324,7 @@ EhcLinkQhToAsync (
   )\r
 {\r
   EHC_QH                  *Head;\r
+  EFI_PHYSICAL_ADDRESS    PciAddr;\r
 \r
   //\r
   // Append the queue head after the reclaim header, then\r
@@ -301,19 +336,19 @@ EhcLinkQhToAsync (
   Qh->NextQh              = Head->NextQh;\r
   Head->NextQh            = Qh;\r
 \r
-  Qh->QhHw.HorizonLink    = QH_LINK (Head, EHC_TYPE_QH, FALSE);;\r
-  Head->QhHw.HorizonLink  = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+  PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh->NextQh, sizeof (EHC_QH));\r
+  Qh->QhHw.HorizonLink    = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
+  PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));\r
+  Head->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
 }\r
 \r
 \r
 /**\r
   Unlink a queue head from the asynchronous schedule list.\r
-  Need to synchronize with hardware\r
+  Need to synchronize with hardware.\r
 \r
-  @param  Ehc                   The EHCI device\r
-  @param  Qh                    The queue head to unlink\r
-\r
-  @return None\r
+  @param  Ehc                   The EHCI device.\r
+  @param  Qh                    The queue head to unlink.\r
 \r
 **/\r
 VOID\r
@@ -324,6 +359,7 @@ EhcUnlinkQhFromAsync (
 {\r
   EHC_QH                  *Head;\r
   EFI_STATUS              Status;\r
+  EFI_PHYSICAL_ADDRESS    PciAddr;\r
 \r
   ASSERT (Ehc->ReclaimHead->NextQh == Qh);\r
 \r
@@ -337,15 +373,16 @@ EhcUnlinkQhFromAsync (
   Head->NextQh            = Qh->NextQh;\r
   Qh->NextQh              = NULL;\r
 \r
-  Head->QhHw.HorizonLink  = QH_LINK (Head, EHC_TYPE_QH, FALSE);\r
+  PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));\r
+  Head->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
 \r
   //\r
   // Set and wait the door bell to synchronize with the hardware\r
   //\r
-  Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIME);\r
+  Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIMEOUT);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    EHC_ERROR (("EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n"));\r
+    DEBUG ((EFI_D_ERROR, "EhcUnlinkQhFromAsync: Failed to synchronize with doorbell\n"));\r
   }\r
 }\r
 \r
@@ -355,10 +392,8 @@ EhcUnlinkQhFromAsync (
   schedule frame list. This code is very much the same as\r
   that in UHCI.\r
 \r
-  @param  Ehc                   The EHCI device\r
-  @param  Qh                    The queue head to link\r
-\r
-  @return None\r
+  @param  Ehc                   The EHCI device.\r
+  @param  Qh                    The queue head to link.\r
 \r
 **/\r
 VOID\r
@@ -367,20 +402,18 @@ EhcLinkQhToPeriod (
   IN EHC_QH               *Qh\r
   )\r
 {\r
-  UINT32                  *Frames;\r
   UINTN                   Index;\r
   EHC_QH                  *Prev;\r
   EHC_QH                  *Next;\r
-\r
-  Frames = Ehc->PeriodFrame;\r
+  EFI_PHYSICAL_ADDRESS    PciAddr;\r
 \r
   for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {\r
     //\r
     // First QH can't be NULL because we always keep PeriodOne\r
     // heads on the frame list\r
     //\r
-    ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));\r
-    Next  = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);\r
+    ASSERT (!EHC_LINK_TERMINATED (((UINT32*)Ehc->PeriodFrame)[Index]));\r
+    Next  = (EHC_QH*)((UINTN*)Ehc->PeriodFrameHost)[Index];\r
     Prev  = NULL;\r
 \r
     //\r
@@ -428,7 +461,8 @@ EhcLinkQhToPeriod (
       Prev->NextQh            = Qh;\r
 \r
       Qh->QhHw.HorizonLink    = Prev->QhHw.HorizonLink;\r
-      Prev->QhHw.HorizonLink  = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+      PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));\r
+      Prev->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
       break;\r
     }\r
 \r
@@ -439,14 +473,18 @@ EhcLinkQhToPeriod (
     //\r
     if (Qh->NextQh == NULL) {\r
       Qh->NextQh              = Next;\r
-      Qh->QhHw.HorizonLink    = QH_LINK (Next, EHC_TYPE_QH, FALSE);\r
+      PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Next, sizeof (EHC_QH));\r
+      Qh->QhHw.HorizonLink    = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
     }\r
 \r
+    PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));\r
+\r
     if (Prev == NULL) {\r
-      Frames[Index] = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+      ((UINT32*)Ehc->PeriodFrame)[Index]     = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
+      ((UINTN*)Ehc->PeriodFrameHost)[Index]  = (UINTN)Qh;\r
     } else {\r
       Prev->NextQh            = Qh;\r
-      Prev->QhHw.HorizonLink  = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+      Prev->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
     }\r
   }\r
 }\r
@@ -454,12 +492,10 @@ EhcLinkQhToPeriod (
 \r
 /**\r
   Unlink an interrupt queue head from the periodic\r
-  schedule frame list\r
-\r
-  @param  Ehc                   The EHCI device\r
-  @param  Qh                    The queue head to unlink\r
+  schedule frame list.\r
 \r
-  @return None\r
+  @param  Ehc                   The EHCI device.\r
+  @param  Qh                    The queue head to unlink.\r
 \r
 **/\r
 VOID\r
@@ -468,20 +504,17 @@ EhcUnlinkQhFromPeriod (
   IN EHC_QH               *Qh\r
   )\r
 {\r
-  UINT32                  *Frames;\r
   UINTN                   Index;\r
   EHC_QH                  *Prev;\r
   EHC_QH                  *This;\r
 \r
-  Frames = Ehc->PeriodFrame;\r
-\r
   for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {\r
     //\r
     // Frame link can't be NULL because we always keep PeroidOne\r
     // on the frame list\r
     //\r
-    ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));\r
-    This  = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);\r
+    ASSERT (!EHC_LINK_TERMINATED (((UINT32*)Ehc->PeriodFrame)[Index]));\r
+    This  = (EHC_QH*)((UINTN*)Ehc->PeriodFrameHost)[Index];\r
     Prev  = NULL;\r
 \r
     //\r
@@ -505,7 +538,8 @@ EhcUnlinkQhFromPeriod (
       //\r
       // Qh is the first entry in the frame\r
       //\r
-      Frames[Index] = Qh->QhHw.HorizonLink;\r
+      ((UINT32*)Ehc->PeriodFrame)[Index] = Qh->QhHw.HorizonLink;\r
+      ((UINTN*)Ehc->PeriodFrameHost)[Index] = (UINTN)Qh->NextQh;\r
     } else {\r
       Prev->NextQh            = Qh->NextQh;\r
       Prev->QhHw.HorizonLink  = Qh->QhHw.HorizonLink;\r
@@ -514,18 +548,16 @@ EhcUnlinkQhFromPeriod (
 }\r
 \r
 \r
-\r
 /**\r
   Check the URB's execution result and update the URB's\r
   result accordingly.\r
 \r
-  @param  Ehc                   The EHCI device\r
-  @param  Urb                   The URB to check result\r
+  @param  Ehc                   The EHCI device.\r
+  @param  Urb                   The URB to check result.\r
 \r
   @return Whether the result of URB transfer is finialized.\r
 \r
 **/\r
-STATIC\r
 BOOLEAN\r
 EhcCheckUrbResult (\r
   IN  USB2_HC_DEV         *Ehc,\r
@@ -537,6 +569,7 @@ EhcCheckUrbResult (
   QTD_HW                  *QtdHw;\r
   UINT8                   State;\r
   BOOLEAN                 Finished;\r
+  EFI_PHYSICAL_ADDRESS    PciAddr;\r
 \r
   ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));\r
 \r
@@ -598,7 +631,7 @@ EhcCheckUrbResult (
       }\r
 \r
       if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {\r
-        EHC_DUMP_QH ((Urb->Qh, "Short packet read", FALSE));\r
+        EhcDumpQh (Urb->Qh, "Short packet read", FALSE);\r
 \r
         //\r
         // Short packet read condition. If it isn't a setup transfer,\r
@@ -606,14 +639,15 @@ EhcCheckUrbResult (
         // ShortReadStop. If it is a setup transfer, need to check the\r
         // Status Stage of the setup transfer to get the finial result\r
         //\r
-        if (QtdHw->AltNext == QTD_LINK (Ehc->ShortReadStop, FALSE)) {\r
-          EHC_DEBUG (("EhcCheckUrbResult: Short packet read, break\n"));\r
+        PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));\r
+        if (QtdHw->AltNext == QTD_LINK (PciAddr, FALSE)) {\r
+          DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, break\n"));\r
 \r
           Finished = TRUE;\r
           goto ON_EXIT;\r
         }\r
 \r
-        EHC_DEBUG (("EhcCheckUrbResult: Short packet read, continue\n"));\r
+        DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, continue\n"));\r
       }\r
     }\r
   }\r
@@ -637,13 +671,13 @@ ON_EXIT:
 /**\r
   Execute the transfer by polling the URB. This is a synchronous operation.\r
 \r
-  @param  Ehc                   The EHCI device\r
-  @param  Urb                   The URB to execute\r
-  @param  TimeOut               The time to wait before abort, in millisecond.\r
+  @param  Ehc               The EHCI device.\r
+  @param  Urb               The URB to execute.\r
+  @param  TimeOut           The time to wait before abort, in millisecond.\r
 \r
-  @return EFI_DEVICE_ERROR : The transfer failed due to transfer error\r
-  @return EFI_TIMEOUT      : The transfer failed due to time out\r
-  @return EFI_SUCCESS      : The transfer finished OK\r
+  @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.\r
+  @return EFI_TIMEOUT       The transfer failed due to time out.\r
+  @return EFI_SUCCESS       The transfer finished OK.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -657,30 +691,41 @@ EhcExecTransfer (
   UINTN                   Index;\r
   UINTN                   Loop;\r
   BOOLEAN                 Finished;\r
+  BOOLEAN                 InfiniteLoop;\r
+\r
+  Status       = EFI_SUCCESS;\r
+  Loop         = TimeOut * EHC_1_MILLISECOND;\r
+  Finished     = FALSE;\r
+  InfiniteLoop = FALSE;\r
 \r
-  Status    = EFI_SUCCESS;\r
-  Loop      = (TimeOut * EHC_STALL_1_MILLISECOND / EHC_SYNC_POLL_TIME) + 1;\r
-  Finished  = FALSE;\r
+  //\r
+  // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller\r
+  // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR\r
+  // is returned.\r
+  //\r
+  if (TimeOut == 0) {\r
+    InfiniteLoop = TRUE;\r
+  }\r
 \r
-  for (Index = 0; Index < Loop; Index++) {\r
+  for (Index = 0; InfiniteLoop || (Index < Loop); Index++) {\r
     Finished = EhcCheckUrbResult (Ehc, Urb);\r
 \r
     if (Finished) {\r
       break;\r
     }\r
 \r
-    gBS->Stall (EHC_SYNC_POLL_TIME);\r
+    gBS->Stall (EHC_1_MICROSECOND);\r
   }\r
 \r
   if (!Finished) {\r
-    EHC_ERROR (("EhcExecTransfer: transfer not finished in %dms\n", TimeOut));\r
-    EHC_DUMP_QH ((Urb->Qh, NULL, FALSE));\r
+    DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer not finished in %dms\n", (UINT32)TimeOut));\r
+    EhcDumpQh (Urb->Qh, NULL, FALSE);\r
 \r
     Status = EFI_TIMEOUT;\r
 \r
   } else if (Urb->Result != EFI_USB_NOERROR) {\r
-    EHC_ERROR (("EhcExecTransfer: transfer failed with %x\n", Urb->Result));\r
-    EHC_DUMP_QH ((Urb->Qh, NULL, FALSE));\r
+    DEBUG ((EFI_D_ERROR, "EhcExecTransfer: transfer failed with %x\n", Urb->Result));\r
+    EhcDumpQh (Urb->Qh, NULL, FALSE);\r
 \r
     Status = EFI_DEVICE_ERROR;\r
   }\r
@@ -691,15 +736,15 @@ EhcExecTransfer (
 \r
 /**\r
   Delete a single asynchronous interrupt transfer for\r
-  the device and endpoint\r
+  the device and endpoint.\r
 \r
-  @param  Ehc                   The EHCI device\r
-  @param  DevAddr               The address of the target device\r
-  @param  EpNum                 The endpoint of the target\r
-  @param  DataToggle            Return the next data toggle to use\r
+  @param  Ehc                   The EHCI device.\r
+  @param  DevAddr               The address of the target device.\r
+  @param  EpNum                 The endpoint of the target.\r
+  @param  DataToggle            Return the next data toggle to use.\r
 \r
-  @retval EFI_SUCCESS           An asynchronous transfer is removed\r
-  @retval EFI_NOT_FOUND         No transfer for the device is found\r
+  @retval EFI_SUCCESS           An asynchronous transfer is removed.\r
+  @retval EFI_NOT_FOUND         No transfer for the device is found.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -715,7 +760,7 @@ EhciDelAsyncIntTransfer (
   URB                     *Urb;\r
   EFI_USB_DATA_DIRECTION  Direction;\r
 \r
-  Direction = ((EpNum & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
+  Direction = (((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
   EpNum    &= 0x0F;\r
 \r
   EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
@@ -744,11 +789,9 @@ EhciDelAsyncIntTransfer (
 \r
 \r
 /**\r
-  Remove all the asynchronous interrutp transfers\r
+  Remove all the asynchronous interrutp transfers.\r
 \r
-  @param  Ehc                   The EHCI device\r
-\r
-  @return None\r
+  @param  Ehc                   The EHCI device.\r
 \r
 **/\r
 VOID\r
@@ -772,18 +815,70 @@ EhciDelAllAsyncIntTransfers (
 }\r
 \r
 \r
-\r
 /**\r
-  Update the queue head for next round of asynchronous transfer\r
+  Flush data from PCI controller specific address to mapped system\r
+  memory address.\r
 \r
-  @param  Urb                   The URB to update\r
+  @param  Ehc                The EHCI device.\r
+  @param  Urb                The URB to unmap.\r
 \r
-  @return None\r
+  @retval EFI_SUCCESS        Success to flush data to mapped system memory.\r
+  @retval EFI_DEVICE_ERROR   Fail to flush data to mapped system memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcFlushAsyncIntMap (\r
+  IN  USB2_HC_DEV         *Ehc,\r
+  IN  URB                 *Urb\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
+  EFI_PCI_IO_PROTOCOL           *PciIo;\r
+  UINTN                         Len;\r
+  VOID                          *Map;\r
+\r
+  PciIo = Ehc->PciIo;\r
+  Len   = Urb->DataLen;\r
+\r
+  if (Urb->Ep.Direction == EfiUsbDataIn) {\r
+    MapOp = EfiPciIoOperationBusMasterWrite;\r
+  } else {\r
+    MapOp = EfiPciIoOperationBusMasterRead;\r
+  }\r
+\r
+  Status = PciIo->Unmap (PciIo, Urb->DataMap);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Urb->DataMap = NULL;\r
+\r
+  Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
+  if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);\r
+  Urb->DataMap  = Map;\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+\r
+/**\r
+  Update the queue head for next round of asynchronous transfer.\r
+\r
+  @param  Ehc                   The EHCI device.\r
+  @param  Urb                   The URB to update.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 EhcUpdateAsyncRequest (\r
+  IN  USB2_HC_DEV         *Ehc,\r
   IN URB                  *Urb\r
   )\r
 {\r
@@ -793,6 +888,7 @@ EhcUpdateAsyncRequest (
   EHC_QTD                 *Qtd;\r
   QTD_HW                  *QtdHw;\r
   UINTN                   Index;\r
+  EFI_PHYSICAL_ADDRESS    PciAddr;\r
 \r
   Qtd = NULL;\r
 \r
@@ -819,7 +915,12 @@ EhcUpdateAsyncRequest (
       QtdHw->ErrCnt     = QTD_MAX_ERR;\r
       QtdHw->CurPage    = 0;\r
       QtdHw->TotalBytes = (UINT32) Qtd->DataLen;\r
-      QtdHw->Page[0]    = EHC_LOW_32BIT (Qtd->Data);\r
+      //\r
+      // calculate physical address by offset.\r
+      //\r
+      PciAddr = (UINTN)Urb->DataPhy + ((UINTN)Qtd->Data - (UINTN)Urb->Data);\r
+      QtdHw->Page[0]    = EHC_LOW_32BIT (PciAddr);\r
+      QtdHw->PageHigh[0]= EHC_HIGH_32BIT (PciAddr);\r
     }\r
 \r
     //\r
@@ -836,7 +937,7 @@ EhcUpdateAsyncRequest (
     QhHw->Pid         = 0;\r
     QhHw->ErrCnt      = 0;\r
     QhHw->CurPage     = 0;\r
-    QhHw->IOC         = 0;\r
+    QhHw->Ioc         = 0;\r
     QhHw->TotalBytes  = 0;\r
 \r
     for (Index = 0; Index < 5; Index++) {\r
@@ -844,7 +945,8 @@ EhcUpdateAsyncRequest (
       QhHw->PageHigh[Index] = 0;\r
     }\r
 \r
-    QhHw->NextQtd = QTD_LINK (FirstQtd, FALSE);\r
+    PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, FirstQtd, sizeof (EHC_QTD));\r
+    QhHw->NextQtd = QTD_LINK (PciAddr, FALSE);\r
   }\r
 \r
   return ;\r
@@ -852,16 +954,15 @@ EhcUpdateAsyncRequest (
 \r
 \r
 /**\r
-  Interrupt transfer periodic check handler\r
-\r
-  @param  Event                 Interrupt event\r
-  @param  Context               Pointer to USB2_HC_DEV\r
+  Interrupt transfer periodic check handler.\r
 \r
-  @return None\r
+  @param  Event                 Interrupt event.\r
+  @param  Context               Pointer to USB2_HC_DEV.\r
 \r
 **/\r
 VOID\r
-EhcMoniteAsyncRequests (\r
+EFIAPI\r
+EhcMonitorAsyncRequests (\r
   IN EFI_EVENT            Event,\r
   IN VOID                 *Context\r
   )\r
@@ -873,6 +974,7 @@ EhcMoniteAsyncRequests (
   BOOLEAN                 Finished;\r
   UINT8                   *ProcBuf;\r
   URB                     *Urb;\r
+  EFI_STATUS              Status;\r
 \r
   OldTpl  = gBS->RaiseTPL (EHC_TPL);\r
   Ehc     = (USB2_HC_DEV *) Context;\r
@@ -890,6 +992,15 @@ EhcMoniteAsyncRequests (
       continue;\r
     }\r
 \r
+    //\r
+    // Flush any PCI posted write transactions from a PCI host\r
+    // bridge to system memory.\r
+    //\r
+    Status = EhcFlushAsyncIntMap (Ehc, Urb);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "EhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));\r
+    }\r
+\r
     //\r
     // Allocate a buffer then copy the transferred data for user.\r
     // If failed to allocate the buffer, update the URB for next\r
@@ -903,14 +1014,14 @@ EhcMoniteAsyncRequests (
       ProcBuf = AllocatePool (Urb->Completed);\r
 \r
       if (ProcBuf == NULL) {\r
-        EhcUpdateAsyncRequest (Urb);\r
+        EhcUpdateAsyncRequest (Ehc, Urb);\r
         continue;\r
       }\r
 \r
       CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
     }\r
 \r
-    EhcUpdateAsyncRequest (Urb);\r
+    EhcUpdateAsyncRequest (Ehc, Urb);\r
 \r
     //\r
     // Leave error recovery to its related device driver. A\r
@@ -933,7 +1044,7 @@ EhcMoniteAsyncRequests (
     }\r
 \r
     if (ProcBuf != NULL) {\r
-      gBS->FreePool (ProcBuf);\r
+      FreePool (ProcBuf);\r
     }\r
   }\r
 \r