public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Jeff Brasen" <jbrasen@nvidia.com>
To: <devel@edk2.groups.io>
Cc: <jian.j.wang@intel.com>, <gaoliming@byosoft.com.cn>,
	<hao.a.wu@intel.com>, <ray.ni@intel.com>,
	Jeff Brasen <jbrasen@nvidia.com>
Subject: [PATCH] MdeModulePkg/PciHostBridge: Add support for driver binding
Date: Thu, 29 Jun 2023 20:53:45 +0000	[thread overview]
Message-ID: <6add8a5bbb40cd1602acc09345496043ac47fc3e.1688071965.git.jbrasen@nvidia.com> (raw)

If the platform does not support any PCIe devices using the library
method allow devices to connect to host bridge via driver binding.

Signed-off-by: Jeff Brasen <jbrasen@nvidia.com>
---
 .../Bus/Pci/PciHostBridgeDxe/PciHostBridge.c  | 649 ++++++++++++++----
 .../Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf |   1 +
 .../Bus/Pci/PciHostBridgeDxe/PciRootBridge.h  |  13 +
 .../Pci/PciHostBridgeDxe/PciRootBridgeIo.c    |  24 +
 MdeModulePkg/MdeModulePkg.dec                 |   4 +
 5 files changed, 562 insertions(+), 129 deletions(-)

diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
index d573e532ba..506c6660ae 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
@@ -422,167 +422,320 @@ IoMmuProtocolCallback (
 }
 
 /**
+  PCI Root Bridge Memory setup.
 
-  Entry point of this driver.
+  @param  RootBridge            Root Bridge instance.
 
-  @param ImageHandle  Image handle of this driver.
-  @param SystemTable  Pointer to standard EFI system table.
-
-  @retval EFI_SUCCESS       Succeed.
-  @retval EFI_DEVICE_ERROR  Fail to install PCI_ROOT_BRIDGE_IO protocol.
+  @retval EFI_SUCCESS           Memory was setup correctly
+  @retval others                Error in setup
 
 **/
 EFI_STATUS
 EFIAPI
-InitializePciHostBridge (
-  IN EFI_HANDLE        ImageHandle,
-  IN EFI_SYSTEM_TABLE  *SystemTable
+PciRootBridgeMemorySetup (
+  IN PCI_ROOT_BRIDGE  *RootBridge
   )
 {
   EFI_STATUS                Status;
-  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
-  PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
-  PCI_ROOT_BRIDGE           *RootBridges;
-  UINTN                     RootBridgeCount;
-  UINTN                     Index;
+  UINT64                    HostAddress;
   PCI_ROOT_BRIDGE_APERTURE  *MemApertures[4];
   UINTN                     MemApertureIndex;
-  BOOLEAN                   ResourceAssigned;
-  LIST_ENTRY                *Link;
-  UINT64                    HostAddress;
 
-  RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);
-  if ((RootBridges == NULL) || (RootBridgeCount == 0)) {
-    return EFI_UNSUPPORTED;
-  }
-
-  Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **)&mCpuIo);
-  ASSERT_EFI_ERROR (Status);
-
-  //
-  // Most systems in the world including complex servers have only one Host Bridge.
-  //
-  HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
-  ASSERT (HostBridge != NULL);
-
-  HostBridge->Signature    = PCI_HOST_BRIDGE_SIGNATURE;
-  HostBridge->CanRestarted = TRUE;
-  InitializeListHead (&HostBridge->RootBridges);
-  ResourceAssigned = FALSE;
-
-  //
-  // Create Root Bridge Device Handle in this Host Bridge
-  //
-  for (Index = 0; Index < RootBridgeCount; Index++) {
+  if (RootBridge->Io.Base <= RootBridge->Io.Limit) {
     //
-    // Create Root Bridge Handle Instance
+    // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
+    // For GCD resource manipulation, we need to use host address.
     //
-    RootBridge = CreateRootBridge (&RootBridges[Index]);
-    ASSERT (RootBridge != NULL);
-    if (RootBridge == NULL) {
-      continue;
+    HostAddress = TO_HOST_ADDRESS (
+                    RootBridge->Io.Base,
+                    RootBridge->Io.Translation
+                    );
+
+    Status = AddIoSpace (
+               HostAddress,
+               RootBridge->Io.Limit - RootBridge->Io.Base + 1
+               );
+    ASSERT_EFI_ERROR (Status);
+    if (EFI_ERROR (Status)) {
+      return Status;
     }
 
-    //
-    // Make sure all root bridges share the same ResourceAssigned value.
-    //
-    if (Index == 0) {
-      ResourceAssigned = RootBridges[Index].ResourceAssigned;
-    } else {
-      ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);
+    if (RootBridge->ResourceAssigned) {
+      Status = gDS->AllocateIoSpace (
+                      EfiGcdAllocateAddress,
+                      EfiGcdIoTypeIo,
+                      0,
+                      RootBridge->Io.Limit - RootBridge->Io.Base + 1,
+                      &HostAddress,
+                      gImageHandle,
+                      NULL
+                      );
+      ASSERT_EFI_ERROR (Status);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
     }
+  }
+
+  //
+  // Add all the Mem/PMem aperture to GCD
+  // Mem/PMem shouldn't overlap with each other
+  // Root bridge which needs to combine MEM and PMEM should only report
+  // the MEM aperture in Mem
+  //
+  MemApertures[0] = &RootBridge->Mem;
+  MemApertures[1] = &RootBridge->MemAbove4G;
+  MemApertures[2] = &RootBridge->PMem;
+  MemApertures[3] = &RootBridge->PMemAbove4G;
 
-    if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {
+  for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {
+    if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {
       //
       // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
       // For GCD resource manipulation, we need to use host address.
       //
       HostAddress = TO_HOST_ADDRESS (
-                      RootBridges[Index].Io.Base,
-                      RootBridges[Index].Io.Translation
+                      MemApertures[MemApertureIndex]->Base,
+                      MemApertures[MemApertureIndex]->Translation
                       );
-
-      Status = AddIoSpace (
+      Status = AddMemoryMappedIoSpace (
                  HostAddress,
-                 RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1
+                 MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
+                 EFI_MEMORY_UC
                  );
       ASSERT_EFI_ERROR (Status);
-      if (ResourceAssigned) {
-        Status = gDS->AllocateIoSpace (
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      Status = gDS->SetMemorySpaceAttributes (
+                      HostAddress,
+                      MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
+                      EFI_MEMORY_UC
+                      );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));
+      }
+
+      if (RootBridge->ResourceAssigned) {
+        Status = gDS->AllocateMemorySpace (
                         EfiGcdAllocateAddress,
-                        EfiGcdIoTypeIo,
+                        EfiGcdMemoryTypeMemoryMappedIo,
                         0,
-                        RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,
+                        MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
                         &HostAddress,
                         gImageHandle,
                         NULL
                         );
         ASSERT_EFI_ERROR (Status);
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
       }
     }
+  }
+
+  return EFI_SUCCESS;
+}
 
+/**
+  PCI Root Bridge Memory free.
+
+  @param  RootBridge            Root Bridge instance.
+
+  @retval EFI_SUCCESS           Memory was setup correctly
+  @retval others                Error in setup
+
+**/
+EFI_STATUS
+EFIAPI
+PciRootBridgeMemoryFree (
+  IN PCI_ROOT_BRIDGE  *RootBridge
+  )
+{
+  EFI_STATUS                Status;
+  UINT64                    HostAddress;
+  PCI_ROOT_BRIDGE_APERTURE  *MemApertures[4];
+  UINTN                     MemApertureIndex;
+
+  if (RootBridge->Io.Base <= RootBridge->Io.Limit) {
     //
-    // Add all the Mem/PMem aperture to GCD
-    // Mem/PMem shouldn't overlap with each other
-    // Root bridge which needs to combine MEM and PMEM should only report
-    // the MEM aperture in Mem
+    // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
+    // For GCD resource manipulation, we need to use host address.
     //
-    MemApertures[0] = &RootBridges[Index].Mem;
-    MemApertures[1] = &RootBridges[Index].MemAbove4G;
-    MemApertures[2] = &RootBridges[Index].PMem;
-    MemApertures[3] = &RootBridges[Index].PMemAbove4G;
-
-    for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {
-      if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {
-        //
-        // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
-        // For GCD resource manipulation, we need to use host address.
-        //
-        HostAddress = TO_HOST_ADDRESS (
-                        MemApertures[MemApertureIndex]->Base,
-                        MemApertures[MemApertureIndex]->Translation
-                        );
-        Status = AddMemoryMappedIoSpace (
-                   HostAddress,
-                   MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
-                   EFI_MEMORY_UC
-                   );
+    HostAddress = TO_HOST_ADDRESS (
+                    RootBridge->Io.Base,
+                    RootBridge->Io.Translation
+                    );
+
+    if (RootBridge->ResourceAssigned) {
+      Status = gDS->FreeIoSpace (HostAddress, RootBridge->Io.Limit - RootBridge->Io.Base + 1);
+      ASSERT_EFI_ERROR (Status);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    }
+  }
+
+  //
+  // Add all the Mem/PMem aperture to GCD
+  // Mem/PMem shouldn't overlap with each other
+  // Root bridge which needs to combine MEM and PMEM should only report
+  // the MEM aperture in Mem
+  //
+  MemApertures[0] = &RootBridge->Mem;
+  MemApertures[1] = &RootBridge->MemAbove4G;
+  MemApertures[2] = &RootBridge->PMem;
+  MemApertures[3] = &RootBridge->PMemAbove4G;
+
+  for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {
+    if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {
+      //
+      // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
+      // For GCD resource manipulation, we need to use host address.
+      //
+      HostAddress = TO_HOST_ADDRESS (
+                      MemApertures[MemApertureIndex]->Base,
+                      MemApertures[MemApertureIndex]->Translation
+                      );
+      if (RootBridge->ResourceAssigned) {
+        Status = gDS->FreeMemorySpace (HostAddress, RootBridge->Io.Limit - RootBridge->Io.Base + 1);
         ASSERT_EFI_ERROR (Status);
-        Status = gDS->SetMemorySpaceAttributes (
-                        HostAddress,
-                        MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
-                        EFI_MEMORY_UC
-                        );
         if (EFI_ERROR (Status)) {
-          DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));
-        }
-
-        if (ResourceAssigned) {
-          Status = gDS->AllocateMemorySpace (
-                          EfiGcdAllocateAddress,
-                          EfiGcdMemoryTypeMemoryMappedIo,
-                          0,
-                          MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
-                          &HostAddress,
-                          gImageHandle,
-                          NULL
-                          );
-          ASSERT_EFI_ERROR (Status);
+          return Status;
         }
       }
     }
+  }
 
-    //
-    // Insert Root Bridge Handle Instance
-    //
-    InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
+  return EFI_SUCCESS;
+}
+
+/**
+  Test to see if this driver supports ControllerHandle. Any ControllerHandle
+  than contains a gEdkiiPciHostBridgeProtocolGuid protocol can be supported.
+
+  @param  This                Protocol instance pointer.
+  @param  Controller          Handle of device to test.
+  @param  RemainingDevicePath Optional parameter use to pick a specific child
+                              device to start.
+
+  @retval EFI_SUCCESS         This driver supports this device.
+  @retval EFI_ALREADY_STARTED This driver is already running on this device.
+  @retval other               This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciHostBrigeDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS       Status;
+  PCI_ROOT_BRIDGE  *PciRootBridge;
+
+  //
+  // Check if Pci Host Bridge protocol is installed by platform
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEdkiiPciHostBridgeProtocolGuid,
+                  (VOID **)&PciRootBridge,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
   }
 
   //
-  // When resources were assigned, it's not needed to expose
-  // PciHostBridgeResourceAllocation protocol.
+  // Close the protocol used to perform the supported test
+  //
+  gBS->CloseProtocol (
+         Controller,
+         &gEdkiiPciHostBridgeProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Start this driver on ControllerHandle and enumerate Pci bus and start
+  all device under PCI bus.
+
+  @param  This                 Protocol instance pointer.
+  @param  Controller           Handle of device to bind driver to.
+  @param  RemainingDevicePath  Optional parameter use to pick a specific child
+                               device to start.
+
+  @retval EFI_SUCCESS          This driver is added to ControllerHandle.
+  @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle.
+  @retval other                This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciHostBrigeDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  PCI_ROOT_BRIDGE           *PciRootBridge;
+  PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
+  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
+  BOOLEAN                   MemorySetupDone;
+
+  MemorySetupDone = FALSE;
+  //
+  // Check if Pci Host Bridge protocol is installed by platform
   //
-  if (!ResourceAssigned) {
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEdkiiPciHostBridgeProtocolGuid,
+                  (VOID **)&PciRootBridge,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  RootBridge = CreateRootBridge (PciRootBridge);
+  ASSERT (RootBridge != NULL);
+  if (RootBridge == NULL) {
+    Status = EFI_DEVICE_ERROR;
+    goto ErrorExit;
+  }
+
+  Status = PciRootBridgeMemorySetup (PciRootBridge);
+  if (EFI_ERROR (Status)) {
+    goto ErrorExit;
+  }
+
+  MemorySetupDone = TRUE;
+
+  if (!PciRootBridge->ResourceAssigned) {
+    // Create host bridge
+    HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
+    ASSERT (HostBridge != NULL);
+    if (HostBridge == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto ErrorExit;
+    }
+
+    HostBridge->Handle       = 0;
+    HostBridge->Signature    = PCI_HOST_BRIDGE_SIGNATURE;
+    HostBridge->CanRestarted = TRUE;
+    InitializeListHead (&HostBridge->RootBridges);
+
     HostBridge->ResAlloc.NotifyPhase          = NotifyPhase;
     HostBridge->ResAlloc.GetNextRootBridge    = GetNextRootBridge;
     HostBridge->ResAlloc.GetAllocAttributes   = GetAttributes;
@@ -599,28 +752,266 @@ InitializePciHostBridge (
                     NULL
                     );
     ASSERT_EFI_ERROR (Status);
-  }
+    if (EFI_ERROR (Status)) {
+      goto ErrorExit;
+    }
 
-  for (Link = GetFirstNode (&HostBridge->RootBridges)
-       ; !IsNull (&HostBridge->RootBridges, Link)
-       ; Link = GetNextNode (&HostBridge->RootBridges, Link)
-       )
-  {
-    RootBridge                            = ROOT_BRIDGE_FROM_LINK (Link);
+    //
+    // Insert Root Bridge Handle Instance
+    //
+    InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
     RootBridge->RootBridgeIo.ParentHandle = HostBridge->Handle;
+  } else {
+    RootBridge->RootBridgeIo.ParentHandle = 0;
+  }
 
-    Status = gBS->InstallMultipleProtocolInterfaces (
-                    &RootBridge->Handle,
-                    &gEfiDevicePathProtocolGuid,
-                    RootBridge->DevicePath,
-                    &gEfiPciRootBridgeIoProtocolGuid,
-                    &RootBridge->RootBridgeIo,
-                    NULL
-                    );
-    ASSERT_EFI_ERROR (Status);
+  RootBridge->Handle = Controller;
+  Status             = gBS->InstallMultipleProtocolInterfaces (
+                              &RootBridge->Handle,
+                              &gEfiPciRootBridgeIoProtocolGuid,
+                              &RootBridge->RootBridgeIo,
+                              NULL
+                              );
+
+ErrorExit:
+  if (EFI_ERROR (Status)) {
+    if (MemorySetupDone) {
+      PciRootBridgeMemoryFree (PciRootBridge);
+    }
+
+    if (RootBridge != NULL) {
+      if (!IsListEmpty (&RootBridge->Link)) {
+        RemoveEntryList (&RootBridge->Link);
+      }
+
+      FreeRootBridge (RootBridge);
+    }
+
+    gBS->CloseProtocol (
+           Controller,
+           &gEdkiiPciHostBridgeProtocolGuid,
+           This->DriverBindingHandle,
+           Controller
+           );
   }
 
-  PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
+  return Status;
+}
+
+/**
+  Stop this driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param  This              Protocol instance pointer.
+  @param  Controller        Handle of device to stop driver on.
+  @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
+                            children is zero stop the entire bus driver.
+  @param  ChildHandleBuffer List of Child Handles to Stop.
+
+  @retval EFI_SUCCESS       This driver is removed ControllerHandle.
+  @retval other             This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+PciHostBrigeDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Controller,
+  IN  UINTN                        NumberOfChildren,
+  IN  EFI_HANDLE                   *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                       Status;
+  PCI_ROOT_BRIDGE                  *PciRootBridge;
+  PCI_ROOT_BRIDGE_INSTANCE         *RootBridge;
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *RootBridgeIo;
+
+  Status = gBS->HandleProtocol (
+                  Controller,
+                  &gEfiPciRootBridgeIoProtocolGuid,
+                  (VOID **)&RootBridgeIo
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  RootBridge = ROOT_BRIDGE_FROM_THIS (RootBridgeIo);
+
+  Status = gBS->HandleProtocol (
+                  Controller,
+                  &gEdkiiPciHostBridgeProtocolGuid,
+                  (VOID **)&PciRootBridge
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  Controller,
+                  &gEfiPciRootBridgeIoProtocolGuid,
+                  (VOID **)&PciRootBridge
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (!IsListEmpty (&RootBridge->Link)) {
+    RemoveEntryList (&RootBridge->Link);
+  }
+
+  PciRootBridgeMemoryFree (PciRootBridge);
+
+  FreeRootBridge (RootBridge);
+  gBS->CloseProtocol (
+         Controller,
+         &gEdkiiPciHostBridgeProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+  return EFI_SUCCESS;
+}
+
+//
+// PCI Bus Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL  gPciHostBrigeDriverBinding = {
+  PciHostBrigeDriverBindingSupported,
+  PciHostBrigeDriverBindingStart,
+  PciHostBrigeDriverBindingStop,
+  0xa,
+  NULL,
+  NULL
+};
+
+/**
+
+  Entry point of this driver.
+
+  @param ImageHandle  Image handle of this driver.
+  @param SystemTable  Pointer to standard EFI system table.
+
+  @retval EFI_SUCCESS       Succeed.
+  @retval EFI_DEVICE_ERROR  Fail to install PCI_ROOT_BRIDGE_IO protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePciHostBridge (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                Status;
+  PCI_HOST_BRIDGE_INSTANCE  *HostBridge;
+  PCI_ROOT_BRIDGE_INSTANCE  *RootBridge;
+  PCI_ROOT_BRIDGE           *RootBridges;
+  UINTN                     RootBridgeCount;
+  UINTN                     Index;
+  BOOLEAN                   ResourceAssigned;
+  LIST_ENTRY                *Link;
+
+  Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **)&mCpuIo);
+  ASSERT_EFI_ERROR (Status);
+
+  RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);
+  if ((RootBridges == NULL) || (RootBridgeCount == 0)) {
+    // Register for binding protocol if library enumeration is not used
+    Status = EfiLibInstallDriverBinding (
+               ImageHandle,
+               SystemTable,
+               &gPciHostBrigeDriverBinding,
+               ImageHandle
+               );
+    ASSERT_EFI_ERROR (Status);
+  } else {
+    //
+    // Most systems in the world including complex servers have only one Host Bridge.
+    //
+    HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
+    ASSERT (HostBridge != NULL);
+
+    HostBridge->Signature    = PCI_HOST_BRIDGE_SIGNATURE;
+    HostBridge->CanRestarted = TRUE;
+    InitializeListHead (&HostBridge->RootBridges);
+    ResourceAssigned = FALSE;
+
+    //
+    // Create Root Bridge Device Handle in this Host Bridge
+    //
+    for (Index = 0; Index < RootBridgeCount; Index++) {
+      //
+      // Create Root Bridge Handle Instance
+      //
+      RootBridge = CreateRootBridge (&RootBridges[Index]);
+      ASSERT (RootBridge != NULL);
+      if (RootBridge == NULL) {
+        continue;
+      }
+
+      //
+      // Make sure all root bridges share the same ResourceAssigned value.
+      //
+      if (Index == 0) {
+        ResourceAssigned = RootBridges[Index].ResourceAssigned;
+      } else {
+        ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);
+      }
+
+      Status = PciRootBridgeMemorySetup (&RootBridges[Index]);
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+
+      //
+      // Insert Root Bridge Handle Instance
+      //
+      InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
+    }
+
+    //
+    // When resources were assigned, it's not needed to expose
+    // PciHostBridgeResourceAllocation protocol.
+    //
+    if (!ResourceAssigned) {
+      HostBridge->ResAlloc.NotifyPhase          = NotifyPhase;
+      HostBridge->ResAlloc.GetNextRootBridge    = GetNextRootBridge;
+      HostBridge->ResAlloc.GetAllocAttributes   = GetAttributes;
+      HostBridge->ResAlloc.StartBusEnumeration  = StartBusEnumeration;
+      HostBridge->ResAlloc.SetBusNumbers        = SetBusNumbers;
+      HostBridge->ResAlloc.SubmitResources      = SubmitResources;
+      HostBridge->ResAlloc.GetProposedResources = GetProposedResources;
+      HostBridge->ResAlloc.PreprocessController = PreprocessController;
+
+      Status = gBS->InstallMultipleProtocolInterfaces (
+                      &HostBridge->Handle,
+                      &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+                      &HostBridge->ResAlloc,
+                      NULL
+                      );
+      ASSERT_EFI_ERROR (Status);
+    }
+
+    for (Link = GetFirstNode (&HostBridge->RootBridges)
+         ; !IsNull (&HostBridge->RootBridges, Link)
+         ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+         )
+    {
+      RootBridge                            = ROOT_BRIDGE_FROM_LINK (Link);
+      RootBridge->RootBridgeIo.ParentHandle = HostBridge->Handle;
+
+      Status = gBS->InstallMultipleProtocolInterfaces (
+                      &RootBridge->Handle,
+                      &gEfiDevicePathProtocolGuid,
+                      RootBridge->DevicePath,
+                      &gEfiPciRootBridgeIoProtocolGuid,
+                      &RootBridge->RootBridgeIo,
+                      NULL
+                      );
+      ASSERT_EFI_ERROR (Status);
+    }
+
+    PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
+  }
 
   if (!EFI_ERROR (Status)) {
     mIoMmuEvent = EfiCreateProtocolNotifyEvent (
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
index 9c24cacc30..ee4740b14f 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
@@ -46,6 +46,7 @@
   gEfiPciRootBridgeIoProtocolGuid                 ## BY_START
   gEfiPciHostBridgeResourceAllocationProtocolGuid ## BY_START
   gEdkiiIoMmuProtocolGuid                         ## SOMETIMES_CONSUMES
+  gEdkiiPciHostBridgeProtocolGuid                 ## SOMETIMES_CONSUMES
 
 [Depex]
   gEfiCpuIo2ProtocolGuid AND
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
index 10a6200719..7923c4677b 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
@@ -93,6 +93,19 @@ CreateRootBridge (
   IN PCI_ROOT_BRIDGE  *Bridge
   );
 
+/**
+  Free the Pci Root Bridge instance.
+
+  @param Bridge            The root bridge instance.
+
+  @return The pointer to PCI_ROOT_BRIDGE_INSTANCE just created
+          or NULL if creation fails.
+**/
+VOID
+FreeRootBridge (
+  IN PCI_ROOT_BRIDGE_INSTANCE  *Bridge
+  );
+
 //
 // Protocol Member Function Prototypes
 //
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
index 157a0ada80..f0eb465a9d 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
@@ -286,6 +286,30 @@ CreateRootBridge (
   return RootBridge;
 }
 
+/**
+  Free the Pci Root Bridge instance.
+
+  @param Bridge            The root bridge instance.
+
+  @return The pointer to PCI_ROOT_BRIDGE_INSTANCE just created
+          or NULL if creation fails.
+**/
+VOID
+FreeRootBridge (
+  IN PCI_ROOT_BRIDGE_INSTANCE  *Bridge
+  )
+{
+  if (Bridge->ConfigBuffer != NULL) {
+    FreePool (Bridge->ConfigBuffer);
+  }
+
+  if (Bridge->DevicePath != NULL) {
+    FreePool (Bridge->DevicePath);
+  }
+
+  FreePool (Bridge);
+}
+
 /**
   Check parameters for IO,MMIO,PCI read/write services of PCI Root Bridge IO.
 
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index d65dae18aa..24700fa797 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -692,6 +692,10 @@
   ## Include/Protocol/VariablePolicy.h
   gEdkiiVariablePolicyProtocolGuid = { 0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } }
 
+  ## Include/Library/PciHostBridgeLib.h
+  # Exposes a PCI_HOST_BRIDGE structure for driver binding usage
+  gEdkiiPciHostBridgeProtocolGuid = { 0xaff2b72d, 0x202e, 0x40e3, { 0x82, 0xd5, 0x9f, 0x6f, 0x61, 0xaf, 0x2a, 0x0b } }
+
 [PcdsFeatureFlag]
   ## Indicates if the platform can support update capsule across a system reset.<BR><BR>
   #   TRUE  - Supports update capsule across a system reset.<BR>
-- 
2.25.1


             reply	other threads:[~2023-06-29 20:54 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-29 20:53 Jeff Brasen [this message]
2023-06-30  2:29 ` [PATCH] MdeModulePkg/PciHostBridge: Add support for driver binding Ni, Ray
2023-06-30  3:21   ` Jeff Brasen
2023-06-30  3:59     ` Ni, Ray
2023-06-30 15:57       ` Jeff Brasen
2023-07-11 21:49         ` Jeff Brasen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6add8a5bbb40cd1602acc09345496043ac47fc3e.1688071965.git.jbrasen@nvidia.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox