]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
MdeModulePkg/PciHostBridgeDxe: Add support for address translation
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciHostBridgeDxe / PciHostBridge.c
index 1494848c3e8c5a256a5c6a1242fee7352795d954..8b71363ea4e5018b50c065ff582eb101746f31df 100644 (file)
@@ -32,6 +32,39 @@ EDKII_IOMMU_PROTOCOL        *mIoMmuProtocol;
 EFI_EVENT                   mIoMmuEvent;\r
 VOID                        *mIoMmuRegistration;\r
 \r
+/**\r
+  This routine gets translation offset from a root bridge instance by resource type.\r
+\r
+  @param RootBridge The Root Bridge Instance for the resources.\r
+  @param ResourceType The Resource Type of the translation offset.\r
+\r
+  @retval The Translation Offset of the specified resource.\r
+**/\r
+UINT64\r
+GetTranslationByResourceType (\r
+  IN  PCI_ROOT_BRIDGE_INSTANCE     *RootBridge,\r
+  IN  PCI_RESOURCE_TYPE            ResourceType\r
+  )\r
+{\r
+  switch (ResourceType) {\r
+    case TypeIo:\r
+      return RootBridge->Io.Translation;\r
+    case TypeMem32:\r
+      return RootBridge->Mem.Translation;\r
+    case TypePMem32:\r
+      return RootBridge->PMem.Translation;\r
+    case TypeMem64:\r
+      return RootBridge->MemAbove4G.Translation;\r
+    case TypePMem64:\r
+      return RootBridge->PMemAbove4G.Translation;\r
+    case TypeBus:\r
+      return RootBridge->Bus.Translation;\r
+    default:\r
+      ASSERT (FALSE);\r
+      return 0;\r
+  }\r
+}\r
+\r
 /**\r
   Ensure the compatibility of an IO space descriptor with the IO aperture.\r
 \r
@@ -366,6 +399,7 @@ InitializePciHostBridge (
   UINTN                       MemApertureIndex;\r
   BOOLEAN                     ResourceAssigned;\r
   LIST_ENTRY                  *Link;\r
+  UINT64                      HostAddress;\r
 \r
   RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);\r
   if ((RootBridges == NULL) || (RootBridgeCount == 0)) {\r
@@ -411,8 +445,15 @@ InitializePciHostBridge (
     }\r
 \r
     if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {\r
+      //\r
+      // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+      // For GCD resource manipulation, we need to use host address.\r
+      //\r
+      HostAddress = TO_HOST_ADDRESS (RootBridges[Index].Io.Base,\r
+        RootBridges[Index].Io.Translation);\r
+\r
       Status = AddIoSpace (\r
-                 RootBridges[Index].Io.Base,\r
+                 HostAddress,\r
                  RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1\r
                  );\r
       ASSERT_EFI_ERROR (Status);\r
@@ -422,7 +463,7 @@ InitializePciHostBridge (
                         EfiGcdIoTypeIo,\r
                         0,\r
                         RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,\r
-                        &RootBridges[Index].Io.Base,\r
+                        &HostAddress,\r
                         gImageHandle,\r
                         NULL\r
                         );\r
@@ -443,14 +484,20 @@ InitializePciHostBridge (
 \r
     for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {\r
       if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {\r
+        //\r
+        // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+        // For GCD resource manipulation, we need to use host address.\r
+        //\r
+        HostAddress = TO_HOST_ADDRESS (MemApertures[MemApertureIndex]->Base,\r
+          MemApertures[MemApertureIndex]->Translation);\r
         Status = AddMemoryMappedIoSpace (\r
-                   MemApertures[MemApertureIndex]->Base,\r
+                   HostAddress,\r
                    MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
                    EFI_MEMORY_UC\r
                    );\r
         ASSERT_EFI_ERROR (Status);\r
         Status = gDS->SetMemorySpaceAttributes (\r
-                        MemApertures[MemApertureIndex]->Base,\r
+                        HostAddress,\r
                         MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
                         EFI_MEMORY_UC\r
                         );\r
@@ -463,7 +510,7 @@ InitializePciHostBridge (
                           EfiGcdMemoryTypeMemoryMappedIo,\r
                           0,\r
                           MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
-                          &MemApertures[MemApertureIndex]->Base,\r
+                          &HostAddress,\r
                           gImageHandle,\r
                           NULL\r
                           );\r
@@ -654,6 +701,11 @@ AllocateResource (
   if (BaseAddress < Limit) {\r
     //\r
     // Have to make sure Aligment is handled since we are doing direct address allocation\r
+    // Strictly speaking, alignment requirement should be applied to device\r
+    // address instead of host address which is used in GCD manipulation below,\r
+    // but as we restrict the alignment of Translation to be larger than any BAR\r
+    // alignment in the root bridge, we can simplify the situation and consider\r
+    // the same alignment requirement is also applied to host address.\r
     //\r
     BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));\r
 \r
@@ -721,6 +773,7 @@ NotifyPhase (
   PCI_RESOURCE_TYPE                     Index2;\r
   BOOLEAN                               ResNodeHandled[TypeMax];\r
   UINT64                                MaxAlignment;\r
+  UINT64                                Translation;\r
 \r
   HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
 \r
@@ -822,14 +875,43 @@ NotifyPhase (
           BitsOfAlignment = LowBitSet64 (Alignment + 1);\r
           BaseAddress = MAX_UINT64;\r
 \r
+          //\r
+          // RESTRICTION: To simplify the situation, we require the alignment of\r
+          // Translation must be larger than any BAR alignment in the same root\r
+          // bridge, so that resource allocation alignment can be applied to\r
+          // both device address and host address.\r
+          //\r
+          Translation = GetTranslationByResourceType (RootBridge, Index);\r
+          if ((Translation & Alignment) != 0) {\r
+            DEBUG ((DEBUG_ERROR, "[%a:%d] Translation %lx is not aligned to %lx!\n",\r
+              __FUNCTION__, __LINE__, Translation, Alignment\r
+              ));\r
+            ASSERT ((Translation & Alignment) == 0);\r
+            //\r
+            // This may be caused by too large alignment or too small\r
+            // Translation; pick the 1st possibility and return out of resource,\r
+            // which can also go thru the same process for out of resource\r
+            // outside the loop.\r
+            //\r
+            ReturnStatus = EFI_OUT_OF_RESOURCES;\r
+            continue;\r
+          }\r
+\r
           switch (Index) {\r
           case TypeIo:\r
+            //\r
+            // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+            // For AllocateResource is manipulating GCD resource, we need to use\r
+            // host address here.\r
+            //\r
             BaseAddress = AllocateResource (\r
                             FALSE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (15, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
-                            RootBridge->Io.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
+                              RootBridge->Io.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->Io.Limit,\r
+                              RootBridge->Io.Translation)\r
                             );\r
             break;\r
 \r
@@ -838,8 +920,10 @@ NotifyPhase (
                             TRUE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (63, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
-                            RootBridge->MemAbove4G.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
+                              RootBridge->MemAbove4G.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->MemAbove4G.Limit,\r
+                              RootBridge->MemAbove4G.Translation)\r
                             );\r
             if (BaseAddress != MAX_UINT64) {\r
               break;\r
@@ -853,8 +937,10 @@ NotifyPhase (
                             TRUE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (31, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
-                            RootBridge->Mem.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
+                              RootBridge->Mem.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->Mem.Limit,\r
+                              RootBridge->Mem.Translation)\r
                             );\r
             break;\r
 \r
@@ -863,8 +949,10 @@ NotifyPhase (
                             TRUE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (63, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
-                            RootBridge->PMemAbove4G.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
+                              RootBridge->PMemAbove4G.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->PMemAbove4G.Limit,\r
+                              RootBridge->PMemAbove4G.Translation)\r
                             );\r
             if (BaseAddress != MAX_UINT64) {\r
               break;\r
@@ -877,8 +965,10 @@ NotifyPhase (
                             TRUE,\r
                             RootBridge->ResAllocNode[Index].Length,\r
                             MIN (31, BitsOfAlignment),\r
-                            ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
-                            RootBridge->PMem.Limit\r
+                            TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
+                              RootBridge->PMem.Translation),\r
+                            TO_HOST_ADDRESS (RootBridge->PMem.Limit,\r
+                              RootBridge->PMem.Translation)\r
                             );\r
             break;\r
 \r
@@ -1421,7 +1511,14 @@ GetProposedResources (
           Descriptor->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
           Descriptor->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;\r
           Descriptor->GenFlag               = 0;\r
-          Descriptor->AddrRangeMin          = RootBridge->ResAllocNode[Index].Base;\r
+          //\r
+          // AddrRangeMin in Resource Descriptor here should be device address\r
+          // instead of host address, or else PCI bus driver cannot set correct\r
+          // address into PCI BAR registers.\r
+          // Base in ResAllocNode is a host address, so conversion is needed.\r
+          //\r
+          Descriptor->AddrRangeMin          = TO_DEVICE_ADDRESS (RootBridge->ResAllocNode[Index].Base,\r
+            GetTranslationByResourceType (RootBridge, Index));\r
           Descriptor->AddrRangeMax          = 0;\r
           Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;\r
           Descriptor->AddrLen               = RootBridge->ResAllocNode[Index].Length;\r