]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with spec
[mirror_edk2.git] / OvmfPkg / Library / PciHostBridgeUtilityLib / PciHostBridgeUtilityLib.c
index 92e1ea812f886eb329a7ea75ddec0505a2110c31..cad2bd6c9687730c7225d22ced19659b224a1276 100644 (file)
 \r
 #include <IndustryStandard/Acpi10.h>\r
 #include <IndustryStandard/Pci.h>\r
+#include <Library/BaseLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/DevicePathLib.h>\r
+#include <Library/HardwareInfoLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/PciHostBridgeUtilityLib.h>\r
 #include <Library/PciLib.h>\r
 #include <Library/QemuFwCfgLib.h>\r
+#include <Protocol/PciHostBridgeResourceAllocation.h>\r
 \r
 #pragma pack(1)\r
 typedef struct {\r
@@ -189,7 +192,9 @@ PciHostBridgeUtilityUninitRootBridge (
 }\r
 \r
 /**\r
-  Utility function to return all the root bridge instances in an array.\r
+  Utility function to scan PCI root bridges and create instances for those\r
+  that are found not empty. Populate their resources from the default\r
+  provided parameters and return all the root bridge instances in an array.\r
 \r
   @param[out] Count                  The number of root bridge instances.\r
 \r
@@ -217,9 +222,9 @@ PciHostBridgeUtilityUninitRootBridge (
 \r
   @return                            All the root bridge instances in an array.\r
 **/\r
+STATIC\r
 PCI_ROOT_BRIDGE *\r
-EFIAPI\r
-PciHostBridgeUtilityGetRootBridges (\r
+PciHostBridgeUtilityGetRootBridgesBusScan (\r
   OUT UINTN                     *Count,\r
   IN  UINT64                    Attributes,\r
   IN  UINT64                    AllocationAttributes,\r
@@ -243,8 +248,6 @@ PciHostBridgeUtilityGetRootBridges (
   UINTN                 LastRootBridgeNumber;\r
   UINTN                 RootBridgeNumber;\r
 \r
-  *Count = 0;\r
-\r
   if ((BusMin > BusMax) || (BusMax > PCI_MAX_BUS)) {\r
     DEBUG ((\r
       DEBUG_ERROR,\r
@@ -403,6 +406,325 @@ FreeBridges:
   return NULL;\r
 }\r
 \r
+/**\r
+  Utility function to read root bridges information from host-provided fw-cfg\r
+  file and return them in an array.\r
+\r
+  @param[out] Count   The number of root bridge instances.\r
+\r
+  @return             All the root bridge instances in an array parsed from\r
+                      host-provided fw-cfg file (hardware-info).\r
+**/\r
+STATIC\r
+PCI_ROOT_BRIDGE *\r
+PciHostBridgeUtilityGetRootBridgesHostProvided (\r
+  OUT UINTN  *Count\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  FIRMWARE_CONFIG_ITEM      FwCfgItem;\r
+  UINTN                     FwCfgSize;\r
+  PCI_ROOT_BRIDGE           *Bridges;\r
+  UINTN                     Initialized;\r
+  UINTN                     LastRootBridgeNumber;\r
+  UINTN                     RootBridgeNumber;\r
+  UINTN                     PciHostBridgeCount;\r
+  UINT8                     *HardwareInfoBlob;\r
+  LIST_ENTRY                HwInfoList;\r
+  LIST_ENTRY                *HwLink;\r
+  HARDWARE_INFO             *HwInfo;\r
+  UINT64                    Attributes;\r
+  UINT64                    AllocationAttributes;\r
+  BOOLEAN                   DmaAbove4G;\r
+  BOOLEAN                   NoExtendedConfigSpace;\r
+  BOOLEAN                   CombineMemPMem;\r
+  PCI_ROOT_BRIDGE_APERTURE  Io;\r
+  PCI_ROOT_BRIDGE_APERTURE  Mem;\r
+  PCI_ROOT_BRIDGE_APERTURE  MemAbove4G;\r
+  PCI_ROOT_BRIDGE_APERTURE  PMem;\r
+  PCI_ROOT_BRIDGE_APERTURE  PMemAbove4G;\r
+\r
+  //\r
+  // Initialize the Hardware Info list head to start with an empty but valid\r
+  // list head.\r
+  //\r
+  InitializeListHead (&HwInfoList);\r
+  HardwareInfoBlob   =  NULL;\r
+  Initialized        = 0;\r
+  Bridges            = NULL;\r
+  PciHostBridgeCount = 0;\r
+\r
+  //\r
+  // Hypervisor can provide the specifications (resources) for one or more\r
+  // PCI host bridges. Such information comes through fw-cfg as part of\r
+  // the hardware-info file.\r
+  //\r
+  Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  HardwareInfoBlob = AllocatePool (FwCfgSize);\r
+\r
+  if (HardwareInfoBlob == NULL) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: Failed to allocate memory for hardware resources info\n",\r
+      __FUNCTION__\r
+      ));\r
+    return NULL;\r
+  }\r
+\r
+  QemuFwCfgSelectItem (FwCfgItem);\r
+  QemuFwCfgReadBytes (FwCfgSize, HardwareInfoBlob);\r
+\r
+  //\r
+  // Create the list of hardware info devices filtering for PCI host\r
+  // bridges\r
+  //\r
+  Status = CreateHardwareInfoList (\r
+             HardwareInfoBlob,\r
+             FwCfgSize,\r
+             HardwareInfoTypeHostBridge,\r
+             &HwInfoList\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "%a: Failed to create hardware info list to retrieve host "\r
+      "bridges information from fw-cfg\n",\r
+      __FUNCTION__\r
+      ));\r
+\r
+    goto FreeBridges;\r
+  }\r
+\r
+  PciHostBridgeCount = GetHardwareInfoCountByType (\r
+                         &HwInfoList,\r
+                         HardwareInfoTypeHostBridge,\r
+                         sizeof (HOST_BRIDGE_INFO)\r
+                         );\r
+\r
+  if (PciHostBridgeCount == 0) {\r
+    goto FreeBridges;\r
+  }\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "%a: Host provided description for %Lu root bridges\n",\r
+    __FUNCTION__,\r
+    PciHostBridgeCount\r
+    ));\r
+\r
+  //\r
+  // Allocate the root bridges\r
+  //\r
+  Bridges = AllocatePool (((UINTN)PciHostBridgeCount) * sizeof *Bridges);\r
+  if (Bridges == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));\r
+    goto FreeBridges;\r
+  }\r
+\r
+  //\r
+  // If Host Bridges' specification was obtained from fw-cfg, the list\r
+  // contains information to populate all root bridges in the system\r
+  // including resources and attributes.\r
+  //\r
+  HwLink = GetFirstHardwareInfoByType (\r
+             &HwInfoList,\r
+             HardwareInfoTypeHostBridge,\r
+             sizeof (HOST_BRIDGE_INFO)\r
+             );\r
+\r
+  while (!EndOfHardwareInfoList (&HwInfoList, HwLink)) {\r
+    HwInfo = HARDWARE_INFO_FROM_LINK (HwLink);\r
+\r
+    Status = HardwareInfoPciHostBridgeGet (\r
+               HwInfo->Data.PciHostBridge,\r
+               (UINTN)HwInfo->Header.Size,\r
+               &RootBridgeNumber,\r
+               &LastRootBridgeNumber,\r
+               &Attributes,\r
+               &DmaAbove4G,\r
+               &NoExtendedConfigSpace,\r
+               &CombineMemPMem,\r
+               &Io,\r
+               &Mem,\r
+               &MemAbove4G,\r
+               &PMem,\r
+               &PMemAbove4G,\r
+               NULL\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto FreeBridges;\r
+    }\r
+\r
+    if ((RootBridgeNumber > LastRootBridgeNumber) || (LastRootBridgeNumber > PCI_MAX_BUS)) {\r
+      DEBUG ((\r
+        DEBUG_ERROR,\r
+        "%a: invalid bus range with BusMin %Lu and BusMax "\r
+        "%Lu\n",\r
+        __FUNCTION__,\r
+        (UINT64)RootBridgeNumber,\r
+        (UINT64)LastRootBridgeNumber\r
+        ));\r
+      goto FreeBridges;\r
+    }\r
+\r
+    AllocationAttributes = 0;\r
+    if (CombineMemPMem) {\r
+      AllocationAttributes |= EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;\r
+    }\r
+\r
+    if ((MemAbove4G.Limit > MemAbove4G.Base) ||\r
+        (PMemAbove4G.Limit > PMemAbove4G.Base))\r
+    {\r
+      AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;\r
+    }\r
+\r
+    Status = PciHostBridgeUtilityInitRootBridge (\r
+               Attributes,\r
+               Attributes,\r
+               AllocationAttributes,\r
+               DmaAbove4G,\r
+               NoExtendedConfigSpace,\r
+               (UINT8)RootBridgeNumber,\r
+               (UINT8)LastRootBridgeNumber,\r
+               &Io,\r
+               &Mem,\r
+               &MemAbove4G,\r
+               &PMem,\r
+               &PMemAbove4G,\r
+               &Bridges[Initialized]\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto FreeBridges;\r
+    }\r
+\r
+    ++Initialized;\r
+\r
+    HwLink = GetNextHardwareInfoByType (\r
+               &HwInfoList,\r
+               HwLink,\r
+               HardwareInfoTypeHostBridge,\r
+               sizeof (HOST_BRIDGE_INFO)\r
+               );\r
+  }\r
+\r
+  *Count = Initialized;\r
+\r
+  //\r
+  // If resources were allocated for host bridges info, release them\r
+  //\r
+  if (HardwareInfoBlob) {\r
+    FreePool (HardwareInfoBlob);\r
+  }\r
+\r
+  FreeHardwareInfoList (&HwInfoList);\r
+  return Bridges;\r
+\r
+FreeBridges:\r
+  while (Initialized > 0) {\r
+    --Initialized;\r
+    PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);\r
+  }\r
+\r
+  if (Bridges) {\r
+    FreePool (Bridges);\r
+  }\r
+\r
+  if (HardwareInfoBlob) {\r
+    FreePool (HardwareInfoBlob);\r
+  }\r
+\r
+  FreeHardwareInfoList (&HwInfoList);\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Utility function to return all the root bridge instances in an array.\r
+\r
+  @param[out] Count                  The number of root bridge instances.\r
+\r
+  @param[in]  Attributes             Initial attributes.\r
+\r
+  @param[in]  AllocAttributes        Allocation attributes.\r
+\r
+  @param[in]  DmaAbove4G             DMA above 4GB memory.\r
+\r
+  @param[in]  NoExtendedConfigSpace  No Extended Config Space.\r
+\r
+  @param[in]  BusMin                 Minimum Bus number, inclusive.\r
+\r
+  @param[in]  BusMax                 Maximum Bus number, inclusive.\r
+\r
+  @param[in]  Io                     IO aperture.\r
+\r
+  @param[in]  Mem                    MMIO aperture.\r
+\r
+  @param[in]  MemAbove4G             MMIO aperture above 4G.\r
+\r
+  @param[in]  PMem                   Prefetchable MMIO aperture.\r
+\r
+  @param[in]  PMemAbove4G            Prefetchable MMIO aperture above 4G.\r
+\r
+  @return                            All the root bridge instances in an array.\r
+**/\r
+PCI_ROOT_BRIDGE *\r
+EFIAPI\r
+PciHostBridgeUtilityGetRootBridges (\r
+  OUT UINTN                     *Count,\r
+  IN  UINT64                    Attributes,\r
+  IN  UINT64                    AllocationAttributes,\r
+  IN  BOOLEAN                   DmaAbove4G,\r
+  IN  BOOLEAN                   NoExtendedConfigSpace,\r
+  IN  UINTN                     BusMin,\r
+  IN  UINTN                     BusMax,\r
+  IN  PCI_ROOT_BRIDGE_APERTURE  *Io,\r
+  IN  PCI_ROOT_BRIDGE_APERTURE  *Mem,\r
+  IN  PCI_ROOT_BRIDGE_APERTURE  *MemAbove4G,\r
+  IN  PCI_ROOT_BRIDGE_APERTURE  *PMem,\r
+  IN  PCI_ROOT_BRIDGE_APERTURE  *PMemAbove4G\r
+  )\r
+{\r
+  PCI_ROOT_BRIDGE  *Bridges;\r
+\r
+  *Count = 0;\r
+\r
+  //\r
+  // First attempt to get the host provided descriptions of the Root Bridges\r
+  // if available.\r
+  //\r
+  Bridges = PciHostBridgeUtilityGetRootBridgesHostProvided (Count);\r
+\r
+  //\r
+  // If host did not provide Root Bridge information, scan the buses and\r
+  // auto populate them with default resources.\r
+  //\r
+  if (Bridges == NULL) {\r
+    Bridges = PciHostBridgeUtilityGetRootBridgesBusScan (\r
+                Count,\r
+                Attributes,\r
+                AllocationAttributes,\r
+                DmaAbove4G,\r
+                NoExtendedConfigSpace,\r
+                BusMin,\r
+                BusMax,\r
+                Io,\r
+                Mem,\r
+                MemAbove4G,\r
+                PMem,\r
+                PMemAbove4G\r
+                );\r
+  }\r
+\r
+  return Bridges;\r
+}\r
+\r
 /**\r
   Utility function to free root bridge instances array from\r
   PciHostBridgeUtilityGetRootBridges().\r