]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
MdeModulePkg/PciHostBridge: Add IOMMU support.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciHostBridgeDxe / PciRootBridgeIo.c
index dbb415ac2d6e12764c33ffa6af4e78bf68ca8c78..068295b7c0b30edb2996401c7e94acb2d724701e 100644 (file)
@@ -17,6 +17,8 @@ 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
 //\r
@@ -59,20 +61,19 @@ UINT8 mOutStride[] = {
   Construct the Pci Root Bridge instance.\r
 \r
   @param Bridge            The root bridge instance.\r
-  @param HostBridgeHandle  Handle to the HostBridge.\r
 \r
   @return The pointer to PCI_ROOT_BRIDGE_INSTANCE just created\r
           or NULL if creation fails.\r
 **/\r
 PCI_ROOT_BRIDGE_INSTANCE *\r
 CreateRootBridge (\r
-  IN PCI_ROOT_BRIDGE       *Bridge,\r
-  IN EFI_HANDLE            HostBridgeHandle\r
+  IN PCI_ROOT_BRIDGE       *Bridge\r
   )\r
 {\r
   PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
   PCI_RESOURCE_TYPE        Index;\r
   CHAR16                   *DevicePathStr;\r
+  PCI_ROOT_BRIDGE_APERTURE *Aperture;\r
 \r
   DevicePathStr = NULL;\r
 \r
@@ -120,32 +121,37 @@ CreateRootBridge (
     }\r
   }\r
 \r
-  if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {\r
-    //\r
-    // If this bit is set, then the PCI Root Bridge does not\r
-    // 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
-      return NULL;\r
+  //\r
+  // Ignore AllocationAttributes when resources were already assigned.\r
+  //\r
+  if (!Bridge->ResourceAssigned) {\r
+    if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {\r
+      //\r
+      // If this bit is set, then the PCI Root Bridge does not\r
+      // 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
+        return NULL;\r
+      }\r
     }\r
-  }\r
 \r
-  if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) == 0) {\r
-    //\r
-    // 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
-      return NULL;\r
+    if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) == 0) {\r
+      //\r
+      // 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
+        return NULL;\r
+      }\r
     }\r
   }\r
 \r
@@ -174,14 +180,43 @@ CreateRootBridge (
   CopyMem (&RootBridge->PMemAbove4G, &Bridge->PMemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE));\r
 \r
   for (Index = TypeIo; Index < TypeMax; Index++) {\r
-    RootBridge->ResAllocNode[Index].Type   = Index;\r
-    RootBridge->ResAllocNode[Index].Base   = 0;\r
-    RootBridge->ResAllocNode[Index].Length = 0;\r
-    RootBridge->ResAllocNode[Index].Status = ResNone;\r
+    switch (Index) {\r
+    case TypeBus:\r
+      Aperture = &RootBridge->Bus;\r
+      break;\r
+    case TypeIo:\r
+      Aperture = &RootBridge->Io;\r
+      break;\r
+    case TypeMem32:\r
+      Aperture = &RootBridge->Mem;\r
+      break;\r
+    case TypeMem64:\r
+      Aperture = &RootBridge->MemAbove4G;\r
+      break;\r
+    case TypePMem32:\r
+      Aperture = &RootBridge->PMem;\r
+      break;\r
+    case TypePMem64:\r
+      Aperture = &RootBridge->PMemAbove4G;\r
+      break;\r
+    default:\r
+      ASSERT (FALSE);\r
+      Aperture = NULL;\r
+      break;\r
+    }\r
+    RootBridge->ResAllocNode[Index].Type     = Index;\r
+    if (Bridge->ResourceAssigned && (Aperture->Limit >= Aperture->Base)) {\r
+      RootBridge->ResAllocNode[Index].Base   = Aperture->Base;\r
+      RootBridge->ResAllocNode[Index].Length = Aperture->Limit - Aperture->Base + 1;\r
+      RootBridge->ResAllocNode[Index].Status = ResAllocated;\r
+    } else {\r
+      RootBridge->ResAllocNode[Index].Base   = 0;\r
+      RootBridge->ResAllocNode[Index].Length = 0;\r
+      RootBridge->ResAllocNode[Index].Status = ResNone;\r
+    }\r
   }\r
 \r
   RootBridge->RootBridgeIo.SegmentNumber  = Bridge->Segment;\r
-  RootBridge->RootBridgeIo.ParentHandle   = HostBridgeHandle;\r
   RootBridge->RootBridgeIo.PollMem        = RootBridgeIoPollMem;\r
   RootBridge->RootBridgeIo.PollIo         = RootBridgeIoPollIo;\r
   RootBridge->RootBridgeIo.Mem.Read       = RootBridgeIoMemRead;\r
@@ -1039,11 +1074,36 @@ RootBridgeIoMap (
 \r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
 \r
+  if (mIoMmuProtocol != NULL) {\r
+    if (!RootBridge->DmaAbove4G) {\r
+      //\r
+      // Clear 64bit support\r
+      //\r
+      if (Operation > EfiPciOperationBusMasterCommonBuffer) {\r
+        Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64);\r
+      }\r
+    }\r
+    Status = mIoMmuProtocol->Map (\r
+                               mIoMmuProtocol,\r
+                               Operation,\r
+                               HostAddress,\r
+                               NumberOfBytes,\r
+                               DeviceAddress,\r
+                               Mapping\r
+                               );\r
+    return Status;\r
+  }\r
+\r
   PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
-  if (!RootBridge->DmaAbove4G && ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {\r
+  if ((!RootBridge->DmaAbove4G ||\r
+       (Operation != EfiPciOperationBusMasterRead64 &&\r
+        Operation != EfiPciOperationBusMasterWrite64 &&\r
+        Operation != EfiPciOperationBusMasterCommonBuffer64)) &&\r
+      ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {\r
+\r
     //\r
-    // If the root bridge can not handle performing DMA above 4GB but\r
-    // any part of the DMA transfer being mapped is above 4GB, then\r
+    // If the root bridge or the device cannot handle performing DMA above\r
+    // 4GB but any part of the DMA transfer being mapped is above 4GB, then\r
     // map the DMA transfer to a buffer below 4GB.\r
     //\r
 \r
@@ -1156,8 +1216,18 @@ RootBridgeIoUnmap (
   MAP_INFO                 *MapInfo;\r
   LIST_ENTRY               *Link;\r
   PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
+  EFI_STATUS                Status;\r
+\r
+  if (mIoMmuProtocol != NULL) {\r
+    Status = mIoMmuProtocol->Unmap (\r
+                               mIoMmuProtocol,\r
+                               Mapping\r
+                               );\r
+    return Status;\r
+  }\r
 \r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+\r
   //\r
   // See if the Map() operation associated with this Unmap() required a mapping\r
   // buffer. If a mapping buffer was not required, then this function simply\r
@@ -1274,8 +1344,27 @@ RootBridgeIoAllocateBuffer (
 \r
   RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
 \r
+  if (mIoMmuProtocol != NULL) {\r
+    if (!RootBridge->DmaAbove4G) {\r
+      //\r
+      // Clear DUAL_ADDRESS_CYCLE\r
+      //\r
+      Attributes &= ~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
+    return Status;\r
+  }\r
+\r
   AllocateType = AllocateAnyPages;\r
-  if (!RootBridge->DmaAbove4G) {\r
+  if (!RootBridge->DmaAbove4G ||\r
+      (Attributes & EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
     //\r
     // Limit allocations to memory below 4GB\r
     //\r
@@ -1317,6 +1406,17 @@ RootBridgeIoFreeBuffer (
   OUT VOID                             *HostAddress\r
   )\r
 {\r
+  EFI_STATUS                Status;\r
+\r
+  if (mIoMmuProtocol != NULL) {\r
+    Status = mIoMmuProtocol->FreeBuffer (\r
+                               mIoMmuProtocol,\r
+                               Pages,\r
+                               HostAddress\r
+                               );\r
+    return Status;\r
+  }\r
+\r
   return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);\r
 }\r
 \r