]> 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 33cf119814305292d84e18595eacf5cbf378e2d0..efef2ed79efc2963d3be8b0e09e71dec9f2e009e 100644 (file)
 \r
 **/\r
 \r
-#include "PciHostBridge.h"\r
+#include <Library/QemuFwCfgLib.h>\r
 \r
-//\r
-// Hard code: Root Bridge Number within the host bridge\r
-//            Root Bridge's attribute\r
-//            Root Bridge's device path\r
-//            Root Bridge's resource aperture\r
-//\r
-UINTN RootBridgeNumber = 1;\r
-\r
-UINT64 RootBridgeAttribute[1] = {\r
-  EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM\r
-};\r
+#include "PciHostBridge.h"\r
 \r
-EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[1] = {\r
+STATIC\r
+CONST\r
+EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = {\r
   {\r
     {\r
+      ACPI_DEVICE_PATH,\r
+      ACPI_DP,\r
       {\r
-        ACPI_DEVICE_PATH,\r
-        ACPI_DP,\r
-        {\r
-          (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)),\r
-          (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8)\r
-        }\r
-      },\r
-      EISA_PNP_ID(0x0A03),\r
-      0\r
+        (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)),\r
+        (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8)\r
+      }\r
     },\r
+    EISA_PNP_ID(0x0A03), // HID\r
+    0                    // UID\r
+  },\r
 \r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
     {\r
-      END_DEVICE_PATH_TYPE,\r
-      END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
-      {\r
-        END_DEVICE_PATH_LENGTH,\r
-        0\r
-      }\r
+      END_DEVICE_PATH_LENGTH,\r
+      0\r
     }\r
   }\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
@@ -84,6 +69,128 @@ PCI_HOST_BRIDGE_INSTANCE mPciHostBridgeInstanceTemplate = {
 // Implementation\r
 //\r
 \r
+/**\r
+  Allocate and initialize a root bridge.\r
+\r
+  param[in]  RootBusNumber     The bus number of the root bus (root bridge) to\r
+                               create.\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
+                               HostBridgeHandle is expected to have\r
+                               EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL\r
+                               installed on it.\r
+\r
+  param[out] RootBus           The private PCI_ROOT_BRIDGE_INSTANCE that has\r
+                               been created as the result of the function call.\r
+\r
+  @retval EFI_SUCCESS           Initialization successful. A new\r
+                                EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL has been\r
+                                created as the child of HostBridgeHandle. A\r
+                                device path consisting of an ACPI device path\r
+                                node, with UID = RootBusNumber, has been\r
+                                installed on the same new handle.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
+\r
+  @return                       Error codes from\r
+                                gBS->InstallMultipleProtocolInterfaces().\r
+**/\r
+STATIC\r
+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
+  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
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  PrivateData->Signature = PCI_ROOT_BRIDGE_SIGNATURE;\r
+\r
+  CopyMem (&PrivateData->DevicePath, &mRootBridgeDevicePathTemplate,\r
+    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, &ResAperture);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (&PrivateData->Handle,\r
+                  &gEfiDevicePathProtocolGuid,      &PrivateData->DevicePath,\r
+                  &gEfiPciRootBridgeIoProtocolGuid, &PrivateData->Io,\r
+                  NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    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
+FreePrivateData:\r
+  FreePool (PrivateData);\r
+  return Status;\r
+}\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
@@ -102,9 +209,14 @@ InitializePciHostBridge (
   )\r
 {\r
   EFI_STATUS                  Status;\r
-  UINTN                       Loop2;\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    *PrivateData;\r
+  PCI_ROOT_BRIDGE_INSTANCE    *RootBus;\r
+  EFI_STATUS                  UninstallStatus;\r
 \r
   mDriverImageHandle = ImageHandle;\r
 \r
@@ -117,7 +229,6 @@ InitializePciHostBridge (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  HostBridge->RootBridgeNumber = RootBridgeNumber;\r
   InitializeListHead (&HostBridge->Head);\r
 \r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
@@ -127,48 +238,96 @@ InitializePciHostBridge (
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    FreePool (HostBridge);\r
-    return EFI_DEVICE_ERROR;\r
+    goto FreeHostBridge;\r
   }\r
 \r
   //\r
-  // Create Root Bridge Device Handle in this Host Bridge\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
-  for (Loop2 = 0; Loop2 < HostBridge->RootBridgeNumber; Loop2++) {\r
-    PrivateData = AllocateZeroPool (sizeof(PCI_ROOT_BRIDGE_INSTANCE));\r
-    if (PrivateData == NULL) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
+  //\r
+  // The "main" root bus is always there.\r
+  //\r
+  LastRootBridgeNumber = 0;\r
 \r
-    PrivateData->Signature = PCI_ROOT_BRIDGE_SIGNATURE;\r
-    PrivateData->DevicePath =\r
-      (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[Loop2];\r
-\r
-    RootBridgeConstructor (\r
-      &PrivateData->Io,\r
-      HostBridge->HostBridgeHandle,\r
-      RootBridgeAttribute[Loop2],\r
-      &mResAperture[Loop2]\r
-      );\r
-\r
-    Status = gBS->InstallMultipleProtocolInterfaces(\r
-                    &PrivateData->Handle,\r
-                    &gEfiDevicePathProtocolGuid,\r
-                    PrivateData->DevicePath,\r
-                    &gEfiPciRootBridgeIoProtocolGuid,\r
-                    &PrivateData->Io,\r
-                    NULL\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      FreePool(PrivateData);\r
-      return EFI_DEVICE_ERROR;\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
+    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
+  }\r
 \r
-    InsertTailList (&HostBridge->Head, &PrivateData->Link);\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