]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/EhciDxe/EhciSched.c
MdeModulePkg/Usb: All h/w related stop operation at DriverBindingStop() should be...
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / EhciSched.c
index 2d8dc024b931c0243797ed5dbadb45dceb091ffd..5594e6699ea648052a2be683dc46dba6d0c3aa68 100644 (file)
@@ -2,8 +2,8 @@
 \r
   EHCI transfer scheduling routines.\r
 \r
-Copyright (c) 2007 - 2009, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2007 - 2013, 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
@@ -74,6 +74,7 @@ EhcCreateHelpQ (
   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
@@ -116,7 +117,6 @@ EhcInitSched (
   UINTN                 Pages;\r
   UINTN                 Bytes;\r
   UINTN                 Index;\r
-  UINT32                *Desc;\r
   EFI_STATUS            Status;\r
   EFI_PHYSICAL_ADDRESS  PciAddr;\r
 \r
@@ -159,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
@@ -172,31 +179,42 @@ EhcInitSched (
   Ehc->MemPool = UsbHcInitMemPool (\r
                    PciIo,\r
                    EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT),\r
-                   Ehc->High32bitAddr\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->PeriodFrameHost;\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
-    PciAddr     = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (EHC_QH));\r
-    Desc[Index] = QH_LINK (PciAddr, 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
@@ -205,6 +223,28 @@ EhcInitSched (
   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
+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
@@ -244,7 +284,7 @@ EhcFreeSched (
     Ehc->MemPool = NULL;\r
   }\r
 \r
-  if (Ehc->PeriodFrameHost != NULL) {\r
+  if (Ehc->PeriodFrame != NULL) {\r
     PciIo = Ehc->PciIo;\r
     ASSERT (PciIo != NULL);\r
 \r
@@ -253,11 +293,15 @@ 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
+  if (Ehc->PeriodFrameHost != NULL) {\r
+    FreePool (Ehc->PeriodFrameHost);\r
     Ehc->PeriodFrameHost = NULL;\r
-    Ehc->PeriodFrame     = NULL;\r
   }\r
 }\r
 \r
@@ -292,9 +336,9 @@ EhcLinkQhToAsync (
   Qh->NextQh              = Head->NextQh;\r
   Head->NextQh            = Qh;\r
 \r
-  PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head, sizeof (EHC_QH));\r
-  Qh->QhHw.HorizonLink    = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);;\r
-  PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));\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
@@ -329,7 +373,7 @@ EhcUnlinkQhFromAsync (
   Head->NextQh            = Qh->NextQh;\r
   Qh->NextQh              = NULL;\r
 \r
-  PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head, sizeof (EHC_QH));\r
+  PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Head->NextQh, sizeof (EHC_QH));\r
   Head->QhHw.HorizonLink  = QH_LINK (PciAddr, EHC_TYPE_QH, FALSE);\r
 \r
   //\r
@@ -358,21 +402,18 @@ EhcLinkQhToPeriod (
   IN EHC_QH               *Qh\r
   )\r
 {\r
-  UINT32                  *Frames;\r
   UINTN                   Index;\r
   EHC_QH                  *Prev;\r
   EHC_QH                  *Next;\r
   EFI_PHYSICAL_ADDRESS    PciAddr;\r
 \r
-  Frames = Ehc->PeriodFrameHost;\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
@@ -439,7 +480,8 @@ EhcLinkQhToPeriod (
     PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Qh, sizeof (EHC_QH));\r
 \r
     if (Prev == NULL) {\r
-      Frames[Index] = QH_LINK (PciAddr, 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 (PciAddr, EHC_TYPE_QH, FALSE);\r
@@ -462,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->PeriodFrameHost;\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
@@ -499,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
@@ -601,13 +641,13 @@ EhcCheckUrbResult (
         //\r
         PciAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));\r
         if (QtdHw->AltNext == QTD_LINK (PciAddr, FALSE)) {\r
-          DEBUG ((EFI_D_INFO, "EhcCheckUrbResult: Short packet read, break\n"));\r
+          DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, break\n"));\r
 \r
           Finished = TRUE;\r
           goto ON_EXIT;\r
         }\r
 \r
-        DEBUG ((EFI_D_INFO, "EhcCheckUrbResult: Short packet read, continue\n"));\r
+        DEBUG ((EFI_D_VERBOSE, "EhcCheckUrbResult: Short packet read, continue\n"));\r
       }\r
     }\r
   }\r
@@ -651,19 +691,30 @@ 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_1_MILLISECOND / EHC_SYNC_POLL_INTERVAL) + 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_INTERVAL);\r
+    gBS->Stall (EHC_1_MICROSECOND);\r
   }\r
 \r
   if (!Finished) {\r
@@ -864,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
@@ -881,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