]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/PciHostBridgeDxe/PciHostBridge.c
BaseTools/Ecc: Fix a bug to report fake issue
[mirror_edk2.git] / OvmfPkg / PciHostBridgeDxe / PciHostBridge.c
index 7ca0b6e19b1a6aaecffacd025922aa1c5023d753..efef2ed79efc2963d3be8b0e09e71dec9f2e009e 100644 (file)
@@ -15,6 +15,8 @@
 \r
 **/\r
 \r
+#include <Library/QemuFwCfgLib.h>\r
+\r
 #include "PciHostBridge.h"\r
 \r
 STATIC\r
@@ -43,20 +45,11 @@ EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = {
   }\r
 };\r
 \r
-//\r
-// Hard code: Root Bridge's resource aperture\r
-//\r
-\r
-PCI_ROOT_BRIDGE_RESOURCE_APERTURE  mResAperture[1] = {\r
-  {0, 0xff, 0x80000000, 0xffffffff, 0, 0xffff}\r
-};\r
-\r
 EFI_HANDLE mDriverImageHandle;\r
 \r
 PCI_HOST_BRIDGE_INSTANCE mPciHostBridgeInstanceTemplate = {\r
   PCI_HOST_BRIDGE_SIGNATURE,  // Signature\r
   NULL,                       // HostBridgeHandle\r
-  0,                          // RootBridgeNumber\r
   {NULL, NULL},               // Head\r
   FALSE,                      // ResourceSubiteed\r
   TRUE,                       // CanRestarted\r
@@ -81,8 +74,15 @@ PCI_HOST_BRIDGE_INSTANCE mPciHostBridgeInstanceTemplate = {
 \r
   param[in]  RootBusNumber     The bus number of the root bus (root bridge) to\r
                                create.\r
-                               RootBusNumber is expected to fall into the valid\r
-                               offset range of mResAperture.\r
+\r
+  param[in]  MaxSubBusNumber   The inclusive maximum bus number that can be\r
+                               assigned to any subordinate bus found behind any\r
+                               PCI bridge hanging off this root bus.\r
+\r
+                               The caller is repsonsible for ensuring that\r
+                               RootBusNumber <= MaxSubBusNumber. If\r
+                               RootBusNumber equals MaxSubBusNumber, then the\r
+                               root bus has no room for subordinate buses.\r
 \r
   param[in]  HostBridgeHandle  The EFI_HANDLE corresponding to the host bridge\r
                                that is the parent of the root bridge to create.\r
@@ -109,12 +109,16 @@ STATIC
 EFI_STATUS\r
 InitRootBridge (\r
   IN  UINT8                    RootBusNumber,\r
+  IN  UINT8                    MaxSubBusNumber,\r
   IN  EFI_HANDLE               HostBridgeHandle,\r
   OUT PCI_ROOT_BRIDGE_INSTANCE **RootBus\r
   )\r
 {\r
-  PCI_ROOT_BRIDGE_INSTANCE *PrivateData;\r
-  EFI_STATUS               Status;\r
+  PCI_ROOT_BRIDGE_INSTANCE          *PrivateData;\r
+  PCI_ROOT_BRIDGE_RESOURCE_APERTURE ResAperture;\r
+  EFI_STATUS                        Status;\r
+\r
+  ASSERT (RootBusNumber <= MaxSubBusNumber);\r
 \r
   PrivateData = AllocateZeroPool (sizeof *PrivateData);\r
   if (PrivateData == NULL) {\r
@@ -127,13 +131,18 @@ InitRootBridge (
     sizeof mRootBridgeDevicePathTemplate);\r
   PrivateData->DevicePath.AcpiDevicePath.UID = RootBusNumber;\r
 \r
+  ResAperture.BusBase  = RootBusNumber;\r
+  ResAperture.BusLimit = MaxSubBusNumber;\r
+  ResAperture.MemBase  = BASE_2GB;\r
+  ResAperture.MemLimit = BASE_4GB - 1;\r
+  ResAperture.IoBase   = 0;\r
+  ResAperture.IoLimit  = MAX_UINT16;\r
   //\r
   // The function call below allocates no resources and performs no actions\r
   // that have to be rolled back on later failure. It always succeeds.\r
   //\r
   Status = RootBridgeConstructor (&PrivateData->Io, HostBridgeHandle,\r
-             EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM,\r
-             &mResAperture[RootBusNumber]);\r
+             EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM, &ResAperture);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   Status = gBS->InstallMultipleProtocolInterfaces (&PrivateData->Handle,\r
@@ -144,6 +153,9 @@ InitRootBridge (
     goto FreePrivateData;\r
   }\r
 \r
+  DEBUG ((EFI_D_INFO,\r
+    "%a: installed root bus %d, with room for %d subordinate bus(es)\n",\r
+    __FUNCTION__, RootBusNumber, MaxSubBusNumber - RootBusNumber));\r
   *RootBus = PrivateData;\r
   return EFI_SUCCESS;\r
 \r
@@ -153,6 +165,32 @@ FreePrivateData:
 }\r
 \r
 \r
+/**\r
+  Uninitialize and free a root bridge set up with InitRootBridge().\r
+\r
+  On return, the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance and the device path\r
+  will have been released, freeing RootBus->Handle as well.\r
+\r
+  param[in] RootBus  The private PCI_ROOT_BRIDGE_INSTANCE that has been created\r
+                     with InitRootBridge(), and should be released.\r
+**/\r
+STATIC\r
+VOID\r
+UninitRootBridge (\r
+  IN PCI_ROOT_BRIDGE_INSTANCE *RootBus\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (RootBus->Handle,\r
+                  &gEfiDevicePathProtocolGuid,      &RootBus->DevicePath,\r
+                  &gEfiPciRootBridgeIoProtocolGuid, &RootBus->Io,\r
+                  NULL);\r
+  ASSERT_EFI_ERROR (Status);\r
+  FreePool (RootBus);\r
+}\r
+\r
+\r
 /**\r
   Entry point of this driver\r
 \r
@@ -171,9 +209,14 @@ InitializePciHostBridge (
   )\r
 {\r
   EFI_STATUS                  Status;\r
+  FIRMWARE_CONFIG_ITEM        FwCfgItem;\r
+  UINTN                       FwCfgSize;\r
+  UINT64                      ExtraRootBridgesLeft;\r
+  UINTN                       LastRootBridgeNumber;\r
   UINTN                       RootBridgeNumber;\r
   PCI_HOST_BRIDGE_INSTANCE    *HostBridge;\r
   PCI_ROOT_BRIDGE_INSTANCE    *RootBus;\r
+  EFI_STATUS                  UninstallStatus;\r
 \r
   mDriverImageHandle = ImageHandle;\r
 \r
@@ -186,7 +229,6 @@ InitializePciHostBridge (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  HostBridge->RootBridgeNumber = 1;\r
   InitializeListHead (&HostBridge->Head);\r
 \r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
@@ -196,25 +238,96 @@ InitializePciHostBridge (
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    FreePool (HostBridge);\r
-    return EFI_DEVICE_ERROR;\r
+    goto FreeHostBridge;\r
   }\r
 \r
-  for (RootBridgeNumber = 0;\r
-       RootBridgeNumber < HostBridge->RootBridgeNumber;\r
+  //\r
+  // QEMU provides the number of extra root buses, shortening the exhaustive\r
+  // search below. If there is no hint, the feature is missing.\r
+  //\r
+  Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize);\r
+  if (EFI_ERROR (Status) || FwCfgSize != sizeof ExtraRootBridgesLeft) {\r
+    ExtraRootBridgesLeft = 0;\r
+  } else {\r
+    QemuFwCfgSelectItem (FwCfgItem);\r
+    QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridgesLeft);\r
+    DEBUG ((EFI_D_INFO, "%a: %Lu extra root buses reported by QEMU\n",\r
+      __FUNCTION__, ExtraRootBridgesLeft));\r
+  }\r
+\r
+  //\r
+  // The "main" root bus is always there.\r
+  //\r
+  LastRootBridgeNumber = 0;\r
+\r
+  //\r
+  // Scan all other root buses. If function 0 of any device on a bus returns a\r
+  // VendorId register value different from all-bits-one, then that bus is\r
+  // alive.\r
+  //\r
+  for (RootBridgeNumber = 1;\r
+       RootBridgeNumber < 256 && ExtraRootBridgesLeft > 0;\r
        ++RootBridgeNumber) {\r
-    Status = InitRootBridge (\r
-               (UINT8)RootBridgeNumber,\r
-               HostBridge->HostBridgeHandle,\r
-               &RootBus\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
+    UINTN Device;\r
+\r
+    for (Device = 0; Device <= MAX_PCI_DEVICE_NUMBER; ++Device) {\r
+      if (PciRead16 (PCI_LIB_ADDRESS (RootBridgeNumber, Device, 0,\r
+                       PCI_VENDOR_ID_OFFSET)) != MAX_UINT16) {\r
+        break;\r
+      }\r
+    }\r
+    if (Device <= MAX_PCI_DEVICE_NUMBER) {\r
+      //\r
+      // Found the next root bus. We can now install the *previous* one,\r
+      // because now we know how big a bus number range *that* one has, for any\r
+      // subordinate buses that might exist behind PCI bridges hanging off it.\r
+      //\r
+      Status = InitRootBridge ((UINT8)LastRootBridgeNumber,\r
+                 (UINT8)(RootBridgeNumber - 1), HostBridge->HostBridgeHandle,\r
+                 &RootBus);\r
+      if (EFI_ERROR (Status)) {\r
+        goto RollbackProtocols;\r
+      }\r
+      InsertTailList (&HostBridge->Head, &RootBus->Link);\r
+      LastRootBridgeNumber = RootBridgeNumber;\r
+      --ExtraRootBridgesLeft;\r
     }\r
-    InsertTailList (&HostBridge->Head, &RootBus->Link);\r
   }\r
 \r
+  //\r
+  // Install the last root bus (which might be the only, ie. main, root bus, if\r
+  // we've found no extra root buses).\r
+  //\r
+  Status = InitRootBridge ((UINT8)LastRootBridgeNumber, 255,\r
+             HostBridge->HostBridgeHandle, &RootBus);\r
+  if (EFI_ERROR (Status)) {\r
+    goto RollbackProtocols;\r
+  }\r
+  InsertTailList (&HostBridge->Head, &RootBus->Link);\r
+\r
   return EFI_SUCCESS;\r
+\r
+RollbackProtocols:\r
+  while (!IsListEmpty (&HostBridge->Head)) {\r
+    LIST_ENTRY *Entry;\r
+\r
+    Entry = GetFirstNode (&HostBridge->Head);\r
+    RemoveEntryList (Entry);\r
+    RootBus = DRIVER_INSTANCE_FROM_LIST_ENTRY (Entry);\r
+    UninitRootBridge (RootBus);\r
+  }\r
+  UninstallStatus = gBS->UninstallMultipleProtocolInterfaces (\r
+                           HostBridge->HostBridgeHandle,\r
+                           &gEfiPciHostBridgeResourceAllocationProtocolGuid,\r
+                           &HostBridge->ResAlloc,\r
+                           NULL\r
+                           );\r
+  ASSERT_EFI_ERROR (UninstallStatus);\r
+\r
+FreeHostBridge:\r
+  FreePool (HostBridge);\r
+\r
+  return Status;\r
 }\r
 \r
 \r