]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
MdeModulePkg/PciHostBridge: Move declaration of mIoMmu to header file
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciHostBridgeDxe / PciRootBridgeIo.c
index 5764c2f49f9214e884d93cb24b278a4357c3ffbb..4c908fad885190877f0717efc4b730ecd776744b 100644 (file)
@@ -2,7 +2,7 @@
 \r
   PCI Root Bridge Io Protocol code.\r
 \r
-Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 1999 - 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
@@ -17,10 +17,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "PciRootBridge.h"\r
 #include "PciHostResource.h"\r
 \r
-extern EDKII_IOMMU_PROTOCOL        *mIoMmuProtocol;\r
-\r
 #define NO_MAPPING  (VOID *) (UINTN) -1\r
 \r
+#define RESOURCE_VALID(Resource) ((Resource)->Base <= (Resource)->Limit)\r
+\r
 //\r
 // Lookup table for increment values based on transfer widths\r
 //\r
@@ -122,25 +122,25 @@ CreateRootBridge (
   //\r
   // Make sure Mem and MemAbove4G apertures are valid\r
   //\r
-  if (Bridge->Mem.Base <= Bridge->Mem.Limit) {\r
+  if (RESOURCE_VALID (&Bridge->Mem)) {\r
     ASSERT (Bridge->Mem.Limit < SIZE_4GB);\r
     if (Bridge->Mem.Limit >= SIZE_4GB) {\r
       return NULL;\r
     }\r
   }\r
-  if (Bridge->MemAbove4G.Base <= Bridge->MemAbove4G.Limit) {\r
+  if (RESOURCE_VALID (&Bridge->MemAbove4G)) {\r
     ASSERT (Bridge->MemAbove4G.Base >= SIZE_4GB);\r
     if (Bridge->MemAbove4G.Base < SIZE_4GB) {\r
       return NULL;\r
     }\r
   }\r
-  if (Bridge->PMem.Base <= Bridge->PMem.Limit) {\r
+  if (RESOURCE_VALID (&Bridge->PMem)) {\r
     ASSERT (Bridge->PMem.Limit < SIZE_4GB);\r
     if (Bridge->PMem.Limit >= SIZE_4GB) {\r
       return NULL;\r
     }\r
   }\r
-  if (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit) {\r
+  if (RESOURCE_VALID (&Bridge->PMemAbove4G)) {\r
     ASSERT (Bridge->PMemAbove4G.Base >= SIZE_4GB);\r
     if (Bridge->PMemAbove4G.Base < SIZE_4GB) {\r
       return NULL;\r
@@ -157,11 +157,9 @@ CreateRootBridge (
       // support separate windows for Non-prefetchable and Prefetchable\r
       // memory.\r
       //\r
-      ASSERT (Bridge->PMem.Base > Bridge->PMem.Limit);\r
-      ASSERT (Bridge->PMemAbove4G.Base > Bridge->PMemAbove4G.Limit);\r
-      if ((Bridge->PMem.Base <= Bridge->PMem.Limit) ||\r
-          (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit)\r
-          ) {\r
+      ASSERT (!RESOURCE_VALID (&Bridge->PMem));\r
+      ASSERT (!RESOURCE_VALID (&Bridge->PMemAbove4G));\r
+      if (RESOURCE_VALID (&Bridge->PMem) || RESOURCE_VALID (&Bridge->PMemAbove4G)) {\r
         return NULL;\r
       }\r
     }\r
@@ -171,11 +169,9 @@ CreateRootBridge (
       // If this bit is not set, then the PCI Root Bridge does not support\r
       // 64 bit memory windows.\r
       //\r
-      ASSERT (Bridge->MemAbove4G.Base > Bridge->MemAbove4G.Limit);\r
-      ASSERT (Bridge->PMemAbove4G.Base > Bridge->PMemAbove4G.Limit);\r
-      if ((Bridge->MemAbove4G.Base <= Bridge->MemAbove4G.Limit) ||\r
-          (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit)\r
-          ) {\r
+      ASSERT (!RESOURCE_VALID (&Bridge->MemAbove4G));\r
+      ASSERT (!RESOURCE_VALID (&Bridge->PMemAbove4G));\r
+      if (RESOURCE_VALID (&Bridge->MemAbove4G) || RESOURCE_VALID (&Bridge->PMemAbove4G)) {\r
         return NULL;\r
       }\r
     }\r
@@ -301,6 +297,8 @@ CreateRootBridge (
 \r
   @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
 \r
+  @retval EFI_INVALID_PARAMETER  Address or Count is invalid.\r
+\r
   @retval EFI_UNSUPPORTED        The Buffer is not aligned for the given Width.\r
 \r
   @retval EFI_UNSUPPORTED        The address range specified by Address, Width,\r
@@ -321,6 +319,7 @@ RootBridgeIoCheckParameter (
   UINT64                                       Base;\r
   UINT64                                       Limit;\r
   UINT32                                       Size;\r
+  UINT64                                       Length;\r
 \r
   //\r
   // Check to see if Buffer is NULL\r
@@ -337,7 +336,7 @@ RootBridgeIoCheckParameter (
   }\r
 \r
   //\r
-  // For FIFO type, the target address won't increase during the access,\r
+  // For FIFO type, the device address won't increase during the access,\r
   // so treat Count as 1\r
   //\r
   if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {\r
@@ -347,6 +346,13 @@ RootBridgeIoCheckParameter (
   Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
   Size  = 1 << Width;\r
 \r
+  //\r
+  // Make sure (Count * Size) doesn't exceed MAX_UINT64\r
+  //\r
+  if (Count > DivU64x32 (MAX_UINT64, Size)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   //\r
   // Check to see if Address is aligned\r
   //\r
@@ -354,6 +360,14 @@ RootBridgeIoCheckParameter (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
+  //\r
+  // Make sure (Address + Count * Size) doesn't exceed MAX_UINT64\r
+  //\r
+  Length = MultU64x32 (Count, Size);\r
+  if (Address > MAX_UINT64 - Length) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
 \r
   //\r
@@ -372,7 +386,7 @@ RootBridgeIoCheckParameter (
     //\r
     // Allow Legacy IO access\r
     //\r
-    if (Address + MultU64x32 (Count, Size) <= 0x1000) {\r
+    if (Address + Length <= 0x1000) {\r
       if ((RootBridge->Attributes & (\r
            EFI_PCI_ATTRIBUTE_ISA_IO | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_ATTRIBUTE_VGA_IO |\r
            EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |\r
@@ -386,7 +400,7 @@ RootBridgeIoCheckParameter (
     //\r
     // Allow Legacy MMIO access\r
     //\r
-    if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <= 0xC0000) {\r
+    if ((Address >= 0xA0000) && (Address + Length) <= 0xC0000) {\r
       if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) {\r
         return EFI_SUCCESS;\r
       }\r
@@ -395,12 +409,18 @@ RootBridgeIoCheckParameter (
     // By comparing the Address against Limit we know which range to be used\r
     // for checking\r
     //\r
-    if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) {\r
-      Base = RootBridge->Mem.Base;\r
+    if ((Address >= RootBridge->Mem.Base) && (Address + Length <= RootBridge->Mem.Limit + 1)) {\r
+      Base  = RootBridge->Mem.Base;\r
       Limit = RootBridge->Mem.Limit;\r
-    } else {\r
-      Base = RootBridge->MemAbove4G.Base;\r
+    } else if ((Address >= RootBridge->PMem.Base) && (Address + Length <= RootBridge->PMem.Limit + 1)) {\r
+      Base  = RootBridge->PMem.Base;\r
+      Limit = RootBridge->PMem.Limit;\r
+    } else if ((Address >= RootBridge->MemAbove4G.Base) && (Address + Length <= RootBridge->MemAbove4G.Limit + 1)) {\r
+      Base  = RootBridge->MemAbove4G.Base;\r
       Limit = RootBridge->MemAbove4G.Limit;\r
+    } else {\r
+      Base  = RootBridge->PMemAbove4G.Base;\r
+      Limit = RootBridge->PMemAbove4G.Limit;\r
     }\r
   } else {\r
     PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &Address;\r
@@ -427,7 +447,7 @@ RootBridgeIoCheckParameter (
       return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (Address + MultU64x32 (Count, Size) > Limit + 1) {\r
+  if (Address + Length > Limit + 1) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -468,6 +488,85 @@ RootBridgeIoGetMemTranslationByAddress (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Return the result of (Multiplicand * Multiplier / Divisor).\r
+\r
+  @param Multiplicand A 64-bit unsigned value.\r
+  @param Multiplier   A 64-bit unsigned value.\r
+  @param Divisor      A 32-bit unsigned value.\r
+  @param Remainder    A pointer to a 32-bit unsigned value. This parameter is\r
+                      optional and may be NULL.\r
+\r
+  @return Multiplicand * Multiplier / Divisor.\r
+**/\r
+UINT64\r
+MultThenDivU64x64x32 (\r
+  IN      UINT64                    Multiplicand,\r
+  IN      UINT64                    Multiplier,\r
+  IN      UINT32                    Divisor,\r
+  OUT     UINT32                    *Remainder  OPTIONAL\r
+  )\r
+{\r
+  UINT64                            Uint64;\r
+  UINT32                            LocalRemainder;\r
+  UINT32                            Uint32;\r
+  if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) {\r
+    //\r
+    // Make sure Multiplicand is the bigger one.\r
+    //\r
+    if (Multiplicand < Multiplier) {\r
+      Uint64       = Multiplicand;\r
+      Multiplicand = Multiplier;\r
+      Multiplier   = Uint64;\r
+    }\r
+    //\r
+    // Because Multiplicand * Multiplier overflows,\r
+    //   Multiplicand * Multiplier / Divisor\r
+    // = (2 * Multiplicand' + 1) * Multiplier / Divisor\r
+    // = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor\r
+    //\r
+    Uint64 = MultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder);\r
+    Uint64 = LShiftU64 (Uint64, 1);\r
+    Uint32 = 0;\r
+    if ((Multiplicand & 0x1) == 1) {\r
+      Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32);\r
+    }\r
+    return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder);\r
+  } else {\r
+    return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder);\r
+  }\r
+}\r
+\r
+/**\r
+  Return the elapsed tick count from CurrentTick.\r
+\r
+  @param  CurrentTick  On input, the previous tick count.\r
+                       On output, the current tick count.\r
+  @param  StartTick    The value the performance counter starts with when it\r
+                       rolls over.\r
+  @param  EndTick      The value that the performance counter ends with before\r
+                       it rolls over.\r
+\r
+  @return  The elapsed tick count from CurrentTick.\r
+**/\r
+UINT64\r
+GetElapsedTick (\r
+  UINT64  *CurrentTick,\r
+  UINT64  StartTick,\r
+  UINT64  EndTick\r
+  )\r
+{\r
+  UINT64  PreviousTick;\r
+\r
+  PreviousTick = *CurrentTick;\r
+  *CurrentTick = GetPerformanceCounter();\r
+  if (StartTick < EndTick) {\r
+    return *CurrentTick - PreviousTick;\r
+  } else {\r
+    return PreviousTick - *CurrentTick;\r
+  }\r
+}\r
+\r
 /**\r
   Polls an address in memory mapped I/O space until an exit condition is met,\r
   or a timeout occurs.\r
@@ -517,6 +616,11 @@ RootBridgeIoPollMem (
   EFI_STATUS  Status;\r
   UINT64      NumberOfTicks;\r
   UINT32      Remainder;\r
+  UINT64      StartTick;\r
+  UINT64      EndTick;\r
+  UINT64      CurrentTick;\r
+  UINT64      ElapsedTick;\r
+  UINT64      Frequency;\r
 \r
   if (Result == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -542,28 +646,18 @@ RootBridgeIoPollMem (
     return EFI_SUCCESS;\r
 \r
   } else {\r
-\r
-    //\r
-    // Determine the proper # of metronome ticks to wait for polling the\r
-    // location.  The nuber of ticks is Roundup (Delay /\r
-    // mMetronome->TickPeriod)+1\r
-    // The "+1" to account for the possibility of the first tick being short\r
-    // because we started in the middle of a tick.\r
     //\r
-    // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome\r
-    // protocol definition is updated.\r
+    // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)\r
     //\r
-    NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod,\r
-                      &Remainder);\r
-    if (Remainder != 0) {\r
-      NumberOfTicks += 1;\r
+    Frequency     = GetPerformanceCounterProperties (&StartTick, &EndTick);\r
+    NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);\r
+    if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {\r
+      NumberOfTicks++;\r
     }\r
-    NumberOfTicks += 1;\r
-\r
-    while (NumberOfTicks != 0) {\r
-\r
-      mMetronome->WaitForTick (mMetronome, 1);\r
-\r
+    for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()\r
+        ; ElapsedTick <= NumberOfTicks\r
+        ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)\r
+        ) {\r
       Status = This->Mem.Read (This, Width, Address, 1, Result);\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
@@ -572,8 +666,6 @@ RootBridgeIoPollMem (
       if ((*Result & Mask) == Value) {\r
         return EFI_SUCCESS;\r
       }\r
-\r
-      NumberOfTicks -= 1;\r
     }\r
   }\r
   return EFI_TIMEOUT;\r
@@ -626,6 +718,11 @@ RootBridgeIoPollIo (
   EFI_STATUS  Status;\r
   UINT64      NumberOfTicks;\r
   UINT32      Remainder;\r
+  UINT64      StartTick;\r
+  UINT64      EndTick;\r
+  UINT64      CurrentTick;\r
+  UINT64      ElapsedTick;\r
+  UINT64      Frequency;\r
 \r
   //\r
   // No matter what, always do a single poll.\r
@@ -651,25 +748,18 @@ RootBridgeIoPollIo (
     return EFI_SUCCESS;\r
 \r
   } else {\r
-\r
     //\r
-    // Determine the proper # of metronome ticks to wait for polling the\r
-    // location.  The number of ticks is Roundup (Delay /\r
-    // mMetronome->TickPeriod)+1\r
-    // The "+1" to account for the possibility of the first tick being short\r
-    // because we started in the middle of a tick.\r
+    // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)\r
     //\r
-    NumberOfTicks = DivU64x32Remainder (Delay, (UINT32)mMetronome->TickPeriod,\r
-                      &Remainder);\r
-    if (Remainder != 0) {\r
-      NumberOfTicks += 1;\r
+    Frequency     = GetPerformanceCounterProperties (&StartTick, &EndTick);\r
+    NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);\r
+    if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {\r
+      NumberOfTicks++;\r
     }\r
-    NumberOfTicks += 1;\r
-\r
-    while (NumberOfTicks != 0) {\r
-\r
-      mMetronome->WaitForTick (mMetronome, 1);\r
-\r
+    for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()\r
+        ; ElapsedTick <= NumberOfTicks\r
+        ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)\r
+        ) {\r
       Status = This->Io.Read (This, Width, Address, 1, Result);\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
@@ -678,8 +768,6 @@ RootBridgeIoPollIo (
       if ((*Result & Mask) == Value) {\r
         return EFI_SUCCESS;\r
       }\r
-\r
-      NumberOfTicks -= 1;\r
     }\r
   }\r
   return EFI_TIMEOUT;\r
@@ -1179,7 +1267,7 @@ RootBridgeIoMap (
 \r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
 \r
-  if (mIoMmuProtocol != NULL) {\r
+  if (mIoMmu != NULL) {\r
     if (!RootBridge->DmaAbove4G) {\r
       //\r
       // Clear 64bit support\r
@@ -1188,14 +1276,14 @@ RootBridgeIoMap (
         Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64);\r
       }\r
     }\r
-    Status = mIoMmuProtocol->Map (\r
-                               mIoMmuProtocol,\r
-                               (EDKII_IOMMU_OPERATION) Operation,\r
-                               HostAddress,\r
-                               NumberOfBytes,\r
-                               DeviceAddress,\r
-                               Mapping\r
-                               );\r
+    Status = mIoMmu->Map (\r
+                       mIoMmu,\r
+                       (EDKII_IOMMU_OPERATION) Operation,\r
+                       HostAddress,\r
+                       NumberOfBytes,\r
+                       DeviceAddress,\r
+                       Mapping\r
+                       );\r
     return Status;\r
   }\r
 \r
@@ -1323,11 +1411,11 @@ RootBridgeIoUnmap (
   PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
   EFI_STATUS                Status;\r
 \r
-  if (mIoMmuProtocol != NULL) {\r
-    Status = mIoMmuProtocol->Unmap (\r
-                               mIoMmuProtocol,\r
-                               Mapping\r
-                               );\r
+  if (mIoMmu != NULL) {\r
+    Status = mIoMmu->Unmap (\r
+                       mIoMmu,\r
+                       Mapping\r
+                       );\r
     return Status;\r
   }\r
 \r
@@ -1449,21 +1537,21 @@ RootBridgeIoAllocateBuffer (
 \r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
 \r
-  if (mIoMmuProtocol != NULL) {\r
+  if (mIoMmu != NULL) {\r
     if (!RootBridge->DmaAbove4G) {\r
       //\r
       // Clear DUAL_ADDRESS_CYCLE\r
       //\r
       Attributes &= ~((UINT64) EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
     }\r
-    Status = mIoMmuProtocol->AllocateBuffer (\r
-                               mIoMmuProtocol,\r
-                               Type,\r
-                               MemoryType,\r
-                               Pages,\r
-                               HostAddress,\r
-                               Attributes\r
-                               );\r
+    Status = mIoMmu->AllocateBuffer (\r
+                       mIoMmu,\r
+                       Type,\r
+                       MemoryType,\r
+                       Pages,\r
+                       HostAddress,\r
+                       Attributes\r
+                       );\r
     return Status;\r
   }\r
 \r
@@ -1513,12 +1601,12 @@ RootBridgeIoFreeBuffer (
 {\r
   EFI_STATUS                Status;\r
 \r
-  if (mIoMmuProtocol != NULL) {\r
-    Status = mIoMmuProtocol->FreeBuffer (\r
-                               mIoMmuProtocol,\r
-                               Pages,\r
-                               HostAddress\r
-                               );\r
+  if (mIoMmu != NULL) {\r
+    Status = mIoMmu->FreeBuffer (\r
+                       mIoMmu,\r
+                       Pages,\r
+                       HostAddress\r
+                       );\r
     return Status;\r
   }\r
 \r