]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
MdeModulePkg/PciHostBridgeDxe: Add support for address translation
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciHostBridgeDxe / PciRootBridgeIo.c
index dc06c16dc038d2f397547ce8af2d87e492a09750..5764c2f49f9214e884d93cb24b278a4357c3ffbb 100644 (file)
@@ -86,12 +86,38 @@ CreateRootBridge (
           (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"",\r
           (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L""\r
           ));\r
-  DEBUG ((EFI_D_INFO, "           Bus: %lx - %lx\n", Bridge->Bus.Base, Bridge->Bus.Limit));\r
-  DEBUG ((EFI_D_INFO, "            Io: %lx - %lx\n", Bridge->Io.Base, Bridge->Io.Limit));\r
-  DEBUG ((EFI_D_INFO, "           Mem: %lx - %lx\n", Bridge->Mem.Base, Bridge->Mem.Limit));\r
-  DEBUG ((EFI_D_INFO, "    MemAbove4G: %lx - %lx\n", Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit));\r
-  DEBUG ((EFI_D_INFO, "          PMem: %lx - %lx\n", Bridge->PMem.Base, Bridge->PMem.Limit));\r
-  DEBUG ((EFI_D_INFO, "   PMemAbove4G: %lx - %lx\n", Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit));\r
+  DEBUG ((\r
+    EFI_D_INFO, "           Bus: %lx - %lx Translation=%lx\n",\r
+    Bridge->Bus.Base, Bridge->Bus.Limit, Bridge->Bus.Translation\r
+    ));\r
+  //\r
+  // Translation for bus is not supported.\r
+  //\r
+  ASSERT (Bridge->Bus.Translation == 0);\r
+  if (Bridge->Bus.Translation != 0) {\r
+    return NULL;\r
+  }\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO, "            Io: %lx - %lx Translation=%lx\n",\r
+    Bridge->Io.Base, Bridge->Io.Limit, Bridge->Io.Translation\r
+    ));\r
+  DEBUG ((\r
+    DEBUG_INFO, "           Mem: %lx - %lx Translation=%lx\n",\r
+    Bridge->Mem.Base, Bridge->Mem.Limit, Bridge->Mem.Translation\r
+    ));\r
+  DEBUG ((\r
+    DEBUG_INFO, "    MemAbove4G: %lx - %lx Translation=%lx\n",\r
+    Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit, Bridge->MemAbove4G.Translation\r
+    ));\r
+  DEBUG ((\r
+    DEBUG_INFO, "          PMem: %lx - %lx Translation=%lx\n",\r
+    Bridge->PMem.Base, Bridge->PMem.Limit, Bridge->PMem.Translation\r
+    ));\r
+  DEBUG ((\r
+    DEBUG_INFO, "   PMemAbove4G: %lx - %lx Translation=%lx\n",\r
+    Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit, Bridge->PMemAbove4G.Translation\r
+    ));\r
 \r
   //\r
   // Make sure Mem and MemAbove4G apertures are valid\r
@@ -206,7 +232,12 @@ CreateRootBridge (
     }\r
     RootBridge->ResAllocNode[Index].Type     = Index;\r
     if (Bridge->ResourceAssigned && (Aperture->Limit >= Aperture->Base)) {\r
-      RootBridge->ResAllocNode[Index].Base   = Aperture->Base;\r
+      //\r
+      // Base in ResAllocNode is a host address, while Base in Aperture is a\r
+      // device address.\r
+      //\r
+      RootBridge->ResAllocNode[Index].Base   = TO_HOST_ADDRESS (Aperture->Base,\r
+        Aperture->Translation);\r
       RootBridge->ResAllocNode[Index].Length = Aperture->Limit - Aperture->Base + 1;\r
       RootBridge->ResAllocNode[Index].Status = ResAllocated;\r
     } else {\r
@@ -403,6 +434,40 @@ RootBridgeIoCheckParameter (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Use address to match apertures of memory type and then get the corresponding\r
+  translation.\r
+\r
+  @param RootBridge              The root bridge instance.\r
+  @param Address                 The address used to match aperture.\r
+  @param Translation             Pointer containing the output translation.\r
+\r
+  @return EFI_SUCCESS            Get translation successfully.\r
+  @return EFI_INVALID_PARAMETER  No matched memory aperture; the input Address\r
+                                 must be invalid.\r
+**/\r
+EFI_STATUS\r
+RootBridgeIoGetMemTranslationByAddress (\r
+  IN PCI_ROOT_BRIDGE_INSTANCE               *RootBridge,\r
+  IN UINT64                                 Address,\r
+  IN OUT UINT64                             *Translation\r
+  )\r
+{\r
+  if (Address >= RootBridge->Mem.Base && Address <= RootBridge->Mem.Limit) {\r
+    *Translation = RootBridge->Mem.Translation;\r
+  } else if (Address >= RootBridge->PMem.Base && Address <= RootBridge->PMem.Limit) {\r
+    *Translation = RootBridge->PMem.Translation;\r
+  } else if (Address >= RootBridge->MemAbove4G.Base && Address <= RootBridge->MemAbove4G.Limit) {\r
+    *Translation = RootBridge->MemAbove4G.Translation;\r
+  } else if (Address >= RootBridge->PMemAbove4G.Base && Address <= RootBridge->PMemAbove4G.Limit) {\r
+    *Translation = RootBridge->PMemAbove4G.Translation;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\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
@@ -658,13 +723,25 @@ RootBridgeIoMemRead (
   )\r
 {\r
   EFI_STATUS                             Status;\r
+  PCI_ROOT_BRIDGE_INSTANCE               *RootBridge;\r
+  UINT64                                 Translation;\r
 \r
   Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,\r
                                        Count, Buffer);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
+\r
+  RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+  Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Address passed to CpuIo->Mem.Read needs to be a host address instead of\r
+  // device address.\r
+  return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+      TO_HOST_ADDRESS (Address, Translation), Count, Buffer);\r
 }\r
 \r
 /**\r
@@ -705,13 +782,25 @@ RootBridgeIoMemWrite (
   )\r
 {\r
   EFI_STATUS                             Status;\r
+  PCI_ROOT_BRIDGE_INSTANCE               *RootBridge;\r
+  UINT64                                 Translation;\r
 \r
   Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,\r
                                        Count, Buffer);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
+\r
+  RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+  Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  // Address passed to CpuIo->Mem.Write needs to be a host address instead of\r
+  // device address.\r
+  return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+      TO_HOST_ADDRESS (Address, Translation), Count, Buffer);\r
 }\r
 \r
 /**\r
@@ -746,6 +835,8 @@ RootBridgeIoIoRead (
   )\r
 {\r
   EFI_STATUS                                    Status;\r
+  PCI_ROOT_BRIDGE_INSTANCE                      *RootBridge;\r
+\r
   Status = RootBridgeIoCheckParameter (\r
              This, IoOperation, Width,\r
              Address, Count, Buffer\r
@@ -753,7 +844,13 @@ RootBridgeIoIoRead (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
+\r
+  RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+\r
+  // Address passed to CpuIo->Io.Read needs to be a host address instead of\r
+  // device address.\r
+  return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+      TO_HOST_ADDRESS (Address, RootBridge->Io.Translation), Count, Buffer);\r
 }\r
 \r
 /**\r
@@ -788,6 +885,8 @@ RootBridgeIoIoWrite (
   )\r
 {\r
   EFI_STATUS                                    Status;\r
+  PCI_ROOT_BRIDGE_INSTANCE                      *RootBridge;\r
+\r
   Status = RootBridgeIoCheckParameter (\r
              This, IoOperation, Width,\r
              Address, Count, Buffer\r
@@ -795,7 +894,13 @@ RootBridgeIoIoWrite (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
+\r
+  RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+\r
+  // Address passed to CpuIo->Io.Write needs to be a host address instead of\r
+  // device address.\r
+  return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+      TO_HOST_ADDRESS (Address, RootBridge->Io.Translation), Count, Buffer);\r
 }\r
 \r
 /**\r
@@ -1615,9 +1720,17 @@ RootBridgeIoConfiguration (
 \r
     Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
     Descriptor->Len  = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
+    // According to UEFI 2.7, RootBridgeIo->Configuration should return address\r
+    // range in CPU view (host address), and ResAllocNode->Base is already a CPU\r
+    // view address (host address).\r
     Descriptor->AddrRangeMin  = ResAllocNode->Base;\r
     Descriptor->AddrRangeMax  = ResAllocNode->Base + ResAllocNode->Length - 1;\r
     Descriptor->AddrLen       = ResAllocNode->Length;\r
+    Descriptor->AddrTranslationOffset = GetTranslationByResourceType (\r
+      RootBridge,\r
+      ResAllocNode->Type\r
+      );\r
+\r
     switch (ResAllocNode->Type) {\r
 \r
     case TypeIo:\r