public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH WIP edk2-platforms 0/3] SbsaQemu: add support for multiple PCI Express buses
@ 2024-04-25 12:02 Marcin Juszkiewicz
  2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 1/3] SbsaQemu: scan for PCIe buses Marcin Juszkiewicz
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Marcin Juszkiewicz @ 2024-04-25 12:02 UTC (permalink / raw)
  To: devel
  Cc: Leif Lindholm, Ard Biesheuvel, Graeme Gregory, Ray Ni,
	Marcin Juszkiewicz

QEMU allows to have NUMA setup where each node has own cpus, memory and
i/o. We already handle cpus and memory. This patchset adds support for
having multiple PCI Express buses.

SbsaQemu assumed that there is only bus 0. First patch does PCIe bus
scan to find all host bridges (bus 0 one and additional 'pxb-pcie'
ones).

Second patch moves description of PCIe from DSDT to SSDT (one per each
PCIe bus). So Operating System will know about all of them.

Third patch moves generation of MCFG table to C. It is preparation to
move PCIe Pcds from being fixed to dynamic ones.

There are some booting issues with assigning resources for cards:

pci 0000:00:03.0: BAR 15: no space for [mem size 0x00200000 64bit pref]
pci 0000:00:03.0: BAR 15: failed to assign [mem size 0x00200000 64bit pref]
pci 0000:00:01.0: BAR 6: no space for [mem size 0x00040000 pref]
pci 0000:00:01.0: BAR 6: failed to assign [mem size 0x00040000 pref]
pci 0000:00:03.0: BAR 13: no space for [io  size 0x1000]
pci 0000:00:03.0: BAR 13: failed to assign [io  size 0x1000]

Boot log (Linux + lspci + ACPI tables dump):
https://people.linaro.org/~marcin.juszkiewicz/sbsa-ref/boot-linux-with-numa-multiple-pcie-buses.txt

I am wondering where I made mistakes in handling PCIe buses.

Thanks go to Leif for pointing me to use of Aml to generate SSDT tables.

Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Graeme Gregory <graeme@xora.org.uk>
Cc: Ray Ni <ray.ni@intel.com>
To: devel@edk2.groups.io

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
Marcin Juszkiewicz (3):
      SbsaQemu: scan for PCIe buses
      SbsaQemu: describe PCIe buses in SSDT tables
      SbsaQemu: generate MCFG table

 Platform/Qemu/SbsaQemu/SbsaQemu.dsc                 |   2 +
 Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf     |   1 -
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf     |  37 +-
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.h      |  23 +
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c       | 170 +++++-
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.c      | 576 ++++++++++++++++++++
 .../SbsaQemuPciHostBridgeLib.c                      | 185 ++++---
 Silicon/Qemu/SbsaQemu/AcpiTables/Dsdt.asl           | 302 ----------
 Silicon/Qemu/SbsaQemu/AcpiTables/Mcfg.aslc          |  43 --
 .../Drivers/SbsaQemuAcpiDxe/SsdtTemplate.asl        |  82 +++
 10 files changed, 982 insertions(+), 439 deletions(-)
---
base-commit: 73cfdc4afff3e641be217b31b985761ef8338412
change-id: 20240425-review-multiple-pcie-0425-54ce3817fd3f

Best regards,
-- 
Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118288): https://edk2.groups.io/g/devel/message/118288
Mute This Topic: https://groups.io/mt/105728624/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [edk2-devel] [PATCH edk2-platforms WIP 1/3] SbsaQemu: scan for PCIe buses
  2024-04-25 12:02 [edk2-devel] [PATCH WIP edk2-platforms 0/3] SbsaQemu: add support for multiple PCI Express buses Marcin Juszkiewicz
@ 2024-04-25 12:02 ` Marcin Juszkiewicz
  2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 2/3] SbsaQemu: describe PCIe buses in SSDT tables Marcin Juszkiewicz
  2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 3/3] SbsaQemu: generate MCFG table Marcin Juszkiewicz
  2 siblings, 0 replies; 4+ messages in thread
From: Marcin Juszkiewicz @ 2024-04-25 12:02 UTC (permalink / raw)
  To: devel
  Cc: Leif Lindholm, Ard Biesheuvel, Graeme Gregory, Ray Ni,
	Marcin Juszkiewicz

SbsaQemu assumes that there is only one PCI Express bus. But there can
be multiple PCIe buses as NUMA systems can get 'pxb-pcie' HostBridge
devices added.

Let scan for all PCIe buses and report them back so EDK2 will be able to
find all expansions.

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
 .../SbsaQemuPciHostBridgeLib.c                      | 185 ++++++++++++--------
 1 file changed, 109 insertions(+), 76 deletions(-)

diff --git a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuPciHostBridgeLib/SbsaQemuPciHostBridgeLib.c b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuPciHostBridgeLib/SbsaQemuPciHostBridgeLib.c
index 9739c7500def..1c4ed1c74e52 100644
--- a/Silicon/Qemu/SbsaQemu/Library/SbsaQemuPciHostBridgeLib/SbsaQemuPciHostBridgeLib.c
+++ b/Silicon/Qemu/SbsaQemu/Library/SbsaQemuPciHostBridgeLib/SbsaQemuPciHostBridgeLib.c
@@ -6,10 +6,14 @@
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
+#include <limits.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/DevicePathLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/PciHostBridgeLib.h>
+#include <Library/PciLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 
 #include <PiDxe.h>
@@ -52,76 +56,49 @@ CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
   L"Mem", L"I/O", L"Bus"
 };
 
-STATIC PCI_ROOT_BRIDGE mRootBridge = {
-  /* UINT32 Segment; Segment number */
-  0,
-
-  /* UINT64 Supports; Supported attributes */
-  EFI_PCI_ATTRIBUTE_ISA_IO_16 | EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO |
-  EFI_PCI_ATTRIBUTE_VGA_IO_16 | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16,
-
-  /* UINT64 Attributes; Initial attributes */
-  EFI_PCI_ATTRIBUTE_ISA_IO_16 | EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO |
-  EFI_PCI_ATTRIBUTE_VGA_IO_16 | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16,
-
-  /* BOOLEAN DmaAbove4G; DMA above 4GB memory */
-  TRUE,
-
-  /* BOOLEAN NoExtendedConfigSpace; When FALSE, the root bridge supports
-     Extended (4096-byte) Configuration Space.  When TRUE, the root bridge
-     supports 256-byte Configuration Space only. */
-  FALSE,
-
-  /* BOOLEAN ResourceAssigned; Resource assignment status of the root bridge.
-     Set to TRUE if Bus/IO/MMIO resources for root bridge have been assigned */
-  FALSE,
-
-  /* UINT64 AllocationAttributes; Allocation attributes. */
-  EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM |
-  EFI_PCI_HOST_BRIDGE_MEM64_DECODE, /* as Mmio64Size > 0 */
-
-  {
-     /* PCI_ROOT_BRIDGE_APERTURE Bus; Bus aperture which can be used by the
-      * root bridge. */
-     FixedPcdGet32 (PcdPciBusMin),
-     FixedPcdGet32 (PcdPciBusMax)
-  },
-
-  /* PCI_ROOT_BRIDGE_APERTURE Io; IO aperture which can be used by the root
-     bridge */
-  {
-     FixedPcdGet64 (PcdPciIoBase),
-     FixedPcdGet64 (PcdPciIoBase) + FixedPcdGet64 (PcdPciIoSize) - 1
-  },
-
-  /* PCI_ROOT_BRIDGE_APERTURE Mem; MMIO aperture below 4GB which can be used by
-     the root bridge
-     (gEfiMdePkgTokenSpaceGuid.PcdPciMmio32Translation as 0x0) */
-  {
-    FixedPcdGet32 (PcdPciMmio32Base),
-    FixedPcdGet32 (PcdPciMmio32Base) + FixedPcdGet32 (PcdPciMmio32Size) - 1,
-  },
-
-  /* PCI_ROOT_BRIDGE_APERTURE MemAbove4G; MMIO aperture above 4GB which can be
-     used by the root bridge.
-     (gEfiMdePkgTokenSpaceGuid.PcdPciMmio64Translation as 0x0) */
-  {
-    FixedPcdGet64 (PcdPciMmio64Base),
-    FixedPcdGet64 (PcdPciMmio64Base) + FixedPcdGet64 (PcdPciMmio64Size) - 1
-  },
-
-  /* PCI_ROOT_BRIDGE_APERTURE PMem; Prefetchable MMIO aperture below 4GB which
-     can be used by the root bridge.
-     In our case, there are no separate ranges for prefetchable and
-     non-prefetchable BARs */
-  { MAX_UINT64, 0 },
-
-  /* PCI_ROOT_BRIDGE_APERTURE PMemAbove4G; Prefetchable MMIO aperture above 4GB
-     which can be used by the root bridge. */
-  { MAX_UINT64, 0 },
-  /* EFI_DEVICE_PATH_PROTOCOL *DevicePath; Device path. */
-  (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath,
-};
+EFI_STATUS
+EFIAPI
+PciHostBridgeUtilityInitRootBridge (
+  IN UINTN             RootBusNumber,
+  OUT PCI_ROOT_BRIDGE  *RootBus
+  )
+{
+  EFI_PCI_ROOT_BRIDGE_DEVICE_PATH  *DevicePath;
+  UINTN                            MaxSubBusNumber = 255;
+
+  DevicePath = AllocateCopyPool (
+                 sizeof mEfiPciRootBridgeDevicePath,
+                 &mEfiPciRootBridgeDevicePath
+                 );
+  if (DevicePath == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: %r\n", __func__, EFI_OUT_OF_RESOURCES));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  DevicePath->AcpiDevicePath.UID = RootBusNumber;
+
+  RootBus->Segment               = 0;
+  RootBus->Supports              = 0;
+  RootBus->Attributes            = 0;
+  RootBus->DmaAbove4G            = TRUE;
+  RootBus->AllocationAttributes  = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | EFI_PCI_HOST_BRIDGE_MEM64_DECODE, /* as Mmio64Size > 0 */
+  RootBus->Bus.Base              = RootBusNumber;
+  RootBus->Bus.Limit             = MaxSubBusNumber;
+  RootBus->Io.Base               = PcdGet64 (PcdPciIoBase);
+  RootBus->Io.Limit              = PcdGet64 (PcdPciIoBase) + PcdGet64 (PcdPciIoSize) - 1;
+  RootBus->Mem.Base              = PcdGet32 (PcdPciMmio32Base);
+  RootBus->Mem.Limit             = PcdGet32 (PcdPciMmio32Base) + PcdGet32 (PcdPciMmio32Size) - 1;
+  RootBus->MemAbove4G.Base       = PcdGet64 (PcdPciMmio64Base);
+  RootBus->MemAbove4G.Limit      = PcdGet64 (PcdPciMmio64Base) + PcdGet64 (PcdPciMmio64Size) - 1;
+  RootBus->PMem.Base             = MAX_UINT64;
+  RootBus->PMem.Limit            = 0;
+  RootBus->PMemAbove4G.Base      = MAX_UINT64;
+  RootBus->PMemAbove4G.Limit     = 0;
+  RootBus->NoExtendedConfigSpace = FALSE;
+  RootBus->DevicePath            = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
+
+  return EFI_SUCCESS;
+}
 
 /**
   Return all the root bridge instances in an array.
@@ -135,11 +112,67 @@ STATIC PCI_ROOT_BRIDGE mRootBridge = {
 PCI_ROOT_BRIDGE *
 EFIAPI
 PciHostBridgeGetRootBridges (
-  UINTN *Count
+  UINTN  *Count
   )
 {
-  *Count = 1;
-  return &mRootBridge;
+  PCI_ROOT_BRIDGE  *Bridges;
+  int              BusId, BusMin = 0, BusMax = 255, Index = 0;
+  int              AvailableBusses[255] = { INT_MAX }; // INT_MAX as "there is no bus"
+
+  *Count = 0;
+
+  //
+  // Scan all root buses. If function 0 of any device on a bus returns a
+  // VendorId register value different from all-bits-one, then that bus is
+  // alive.
+  //
+  for (BusId = BusMin; BusId <= BusMax; ++BusId) {
+    UINTN  Device;
+
+    for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) {
+      if (PciRead16 (
+            PCI_LIB_ADDRESS (
+              BusId,
+              Device,
+              0,
+              PCI_VENDOR_ID_OFFSET
+              )
+            ) != MAX_UINT16)
+      {
+        break;
+      }
+    }
+
+    if (Device <= PCI_MAX_DEVICE) {
+      DEBUG ((DEBUG_ERROR, "%a: found bus: 0x%02x\n", __func__, BusId));
+      AvailableBusses[Index++] = BusId;
+      *Count                  += 1;
+    }
+  }
+
+  //
+  // Allocate the "main" root bridge, and any extra root bridges.
+  //
+  Bridges = AllocateZeroPool (*Count * sizeof *Bridges);
+  if (Bridges == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: %r\n", __func__, EFI_OUT_OF_RESOURCES));
+    return NULL;
+  }
+
+  for (Index = 0; Index < *Count; Index++) {
+    if (AvailableBusses[Index] == INT_MAX) {
+      break;
+    }
+
+    PciHostBridgeUtilityInitRootBridge (AvailableBusses[Index], &Bridges[Index]);
+
+    // limit previous RootBridge bus range
+    if (Index > 0) {
+      Bridges[Index - 1].Bus.Limit = AvailableBusses[Index] - 1;
+    }
+  }
+
+  return Bridges;
 }
 
 /**
@@ -152,11 +185,11 @@ PciHostBridgeGetRootBridges (
 VOID
 EFIAPI
 PciHostBridgeFreeRootBridges (
-  PCI_ROOT_BRIDGE *Bridges,
-  UINTN           Count
+  PCI_ROOT_BRIDGE  *Bridges,
+  UINTN            Count
   )
 {
-  ASSERT (Count == 1);
+  FreePool (Bridges);
 }
 
 /**

-- 
2.44.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118287): https://edk2.groups.io/g/devel/message/118287
Mute This Topic: https://groups.io/mt/105728623/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [edk2-devel] [PATCH edk2-platforms WIP 2/3] SbsaQemu: describe PCIe buses in SSDT tables
  2024-04-25 12:02 [edk2-devel] [PATCH WIP edk2-platforms 0/3] SbsaQemu: add support for multiple PCI Express buses Marcin Juszkiewicz
  2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 1/3] SbsaQemu: scan for PCIe buses Marcin Juszkiewicz
@ 2024-04-25 12:02 ` Marcin Juszkiewicz
  2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 3/3] SbsaQemu: generate MCFG table Marcin Juszkiewicz
  2 siblings, 0 replies; 4+ messages in thread
From: Marcin Juszkiewicz @ 2024-04-25 12:02 UTC (permalink / raw)
  To: devel
  Cc: Leif Lindholm, Ard Biesheuvel, Graeme Gregory, Ray Ni,
	Marcin Juszkiewicz

We can have more than one PCI Express bus. So instead of having static
description in DSDT we create SSDT table for each existing PCIe bus.

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
 Platform/Qemu/SbsaQemu/SbsaQemu.dsc                 |   2 +
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf     |  37 +-
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.h      |  23 +
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c       |  87 ++-
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.c      | 576 ++++++++++++++++++++
 Silicon/Qemu/SbsaQemu/AcpiTables/Dsdt.asl           | 302 ----------
 .../Drivers/SbsaQemuAcpiDxe/SsdtTemplate.asl        |  82 +++
 7 files changed, 790 insertions(+), 319 deletions(-)

diff --git a/Platform/Qemu/SbsaQemu/SbsaQemu.dsc b/Platform/Qemu/SbsaQemu/SbsaQemu.dsc
index e246db8b0a23..b012eaa34147 100644
--- a/Platform/Qemu/SbsaQemu/SbsaQemu.dsc
+++ b/Platform/Qemu/SbsaQemu/SbsaQemu.dsc
@@ -173,6 +173,8 @@ [LibraryClasses.common]
   ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
 
   AcpiLib|EmbeddedPkg/Library/AcpiLib/AcpiLib.inf
+  AcpiHelperLib|DynamicTablesPkg/Library/Common/AcpiHelperLib/AcpiHelperLib.inf
+  AmlLib|DynamicTablesPkg/Library/Common/AmlLib/AmlLib.inf
 
   ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
   ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf
index 727c8e82d16e..6de1073e6ac2 100644
--- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf
+++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.inf
@@ -18,18 +18,25 @@ [Defines]
 
 [Sources]
   SbsaQemuAcpiDxe.c
+  SbsaQemuAcpiDxe.h
+  SbsaQemuAcpiPcie.c
+  SbsaQemuAcpiPcie.h
+  SsdtTemplate.asl
 
 [Packages]
   ArmPkg/ArmPkg.dec
   ArmPlatformPkg/ArmPlatformPkg.dec
   ArmVirtPkg/ArmVirtPkg.dec
+  DynamicTablesPkg/DynamicTablesPkg.dec
   EmbeddedPkg/EmbeddedPkg.dec
   MdeModulePkg/MdeModulePkg.dec
   MdePkg/MdePkg.dec
   Silicon/Qemu/SbsaQemu/SbsaQemu.dec
 
 [LibraryClasses]
+  AcpiHelperLib
   AcpiLib
+  AmlLib
   ArmLib
   BaseMemoryLib
   BaseLib
@@ -37,6 +44,7 @@ [LibraryClasses]
   DxeServicesLib
   HardwareInfoLib
   PcdLib
+  PciLib
   PrintLib
   UefiDriverEntryPoint
   UefiLib
@@ -54,14 +62,39 @@ [Pcd]
   gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdSmmuBase
 
 [Depex]
-  gEfiAcpiTableProtocolGuid                       ## CONSUMES
+  # We want all PCIe buses to be scanned first
+  gEfiPciIoProtocolGuid             ## CONSUMES
 
 [Guids]
   gEdkiiPlatformHasAcpiGuid
 
 [Protocols]
   gEfiAcpiSdtProtocolGuid
-  gEfiAcpiTableProtocolGuid                       ## CONSUMES
+  gEfiAcpiTableProtocolGuid
+  gEfiPciRootBridgeIoProtocolGuid
+
+
+[Pcd]
+  gArmTokenSpaceGuid.PcdPciBusMin
+  gArmTokenSpaceGuid.PcdPciBusMax
+  gArmTokenSpaceGuid.PcdPciIoBase
+  gArmTokenSpaceGuid.PcdPciIoSize
+  gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
+  gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPciIoLimit
+
+  gArmTokenSpaceGuid.PcdPciMmio32Base
+  gArmTokenSpaceGuid.PcdPciMmio32Size
+  gEfiMdePkgTokenSpaceGuid.PcdPciMmio32Translation
+  gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPciMmio32Limit
+
+  gArmTokenSpaceGuid.PcdPciMmio64Base
+  gArmTokenSpaceGuid.PcdPciMmio64Size
+  gEfiMdePkgTokenSpaceGuid.PcdPciMmio64Translation
+  gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPciMmio64Limit
+
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+  gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPciExpressBarSize
+  gArmVirtSbsaQemuPlatformTokenSpaceGuid.PcdPciExpressBarLimit
 
 [FixedPcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId
diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.h b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.h
new file mode 100644
index 000000000000..56cc6f1381da
--- /dev/null
+++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.h
@@ -0,0 +1,23 @@
+/** @file
+*  This file is an ACPI driver for the Qemu SBSA platform.
+*
+*  Copyright (c) 2024, Linaro Ltd. All rights reserved.
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#ifndef SBSAQEMU_ACPI_PCIE_H
+#define SBSAQEMU_ACPI_PCIE_H
+
+#pragma pack(1)
+
+/* AML bytecode generated from SsdtTemplate.asl */
+extern CHAR8  ssdttemplate_aml_code[];
+
+EFI_STATUS
+AddPcieHostBridges (
+  AML_OBJECT_NODE_HANDLE  ScopeNode
+  );
+
+#endif
diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c
index 30239e7dca0d..f3d5dc9e9ba7 100644
--- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c
+++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c
@@ -6,28 +6,27 @@
 *  SPDX-License-Identifier: BSD-2-Clause-Patent
 *
 **/
-#include <IndustryStandard/Acpi.h>
-#include <IndustryStandard/AcpiAml.h>
 #include <IndustryStandard/IoRemappingTable.h>
 #include <IndustryStandard/SbsaQemuAcpi.h>
 #include <IndustryStandard/SbsaQemuPlatformVersion.h>
+
 #include <Library/AcpiLib.h>
+#include <Library/AmlLib/AmlLib.h>
 #include <Library/ArmLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/PcdLib.h>
-#include <Library/PrintLib.h>
 #include <Library/HardwareInfoLib.h>
+#include <Library/PrintLib.h>
 #include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiDriverEntryPoint.h>
-#include <Library/UefiLib.h>
+
 #include <Protocol/AcpiTable.h>
+#include <Protocol/PciRootBridgeIo.h>
+
 #include "SbsaQemuAcpiDxe.h"
+#include "SbsaQemuAcpiPcie.h"
 
 #pragma pack(1)
 
-
 static UINTN GicItsBase;
 
 #pragma pack ()
@@ -36,7 +35,7 @@ static UINTN GicItsBase;
  * A Function to Compute the ACPI Table Checksum
  */
 VOID
-AcpiPlatformChecksum (
+AcpiTableChecksum (
   IN UINT8      *Buffer,
   IN UINTN      Size
   )
@@ -189,7 +188,7 @@ AddIortTable (
   CopyMem (New, &Rc, sizeof (SBSA_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE));
   New += sizeof (SBSA_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);
 
-  AcpiPlatformChecksum ((UINT8*) PageAddress, TableSize);
+  AcpiTableChecksum ((UINT8*) PageAddress, TableSize);
 
   Status = AcpiTable->InstallAcpiTable (
                         AcpiTable,
@@ -314,7 +313,7 @@ AddMadtTable (
     New += sizeof (EFI_ACPI_6_5_GIC_ITS_STRUCTURE);
   }
 
-  AcpiPlatformChecksum ((UINT8*) PageAddress, TableSize);
+  AcpiTableChecksum ((UINT8*) PageAddress, TableSize);
 
   Status = AcpiTable->InstallAcpiTable (
                         AcpiTable,
@@ -467,7 +466,7 @@ AddSsdtTable (
   }
 
   // Perform Checksum
-  AcpiPlatformChecksum ((UINT8*) PageAddress, TableSize);
+  AcpiTableChecksum ((UINT8*) PageAddress, TableSize);
 
   Status = AcpiTable->InstallAcpiTable (
                         AcpiTable,
@@ -572,7 +571,7 @@ AddPpttTable (
   }
 
   // Perform Checksum
-  AcpiPlatformChecksum ((UINT8*) PageAddress, TableSize);
+  AcpiTableChecksum ((UINT8*) PageAddress, TableSize);
 
   Status = AcpiTable->InstallAcpiTable (
                         AcpiTable,
@@ -667,7 +666,7 @@ AddGtdtTable (
   New += sizeof (EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE);
 
   // Perform Checksum
-  AcpiPlatformChecksum ((UINT8*) PageAddress, TableSize);
+  AcpiTableChecksum ((UINT8*) PageAddress, TableSize);
 
   Status = AcpiTable->InstallAcpiTable (
                         AcpiTable,
@@ -752,7 +751,7 @@ AddSratTable (
   }
 
   // Perform Checksum
-  AcpiPlatformChecksum ((UINT8*) PageAddress, TableSize);
+  AcpiTableChecksum ((UINT8*) PageAddress, TableSize);
 
   Status = AcpiTable->InstallAcpiTable (
                         AcpiTable,
@@ -832,6 +831,58 @@ DisableXhciOnOlderPlatVer (
   return Status;
 }
 
+/** Adds the SSDT ACPI table with PCIe nodes.
+
+  @param AcpiTable        The ACPI Table.
+
+  @return EFI_SUCCESS on success, or an error code.
+
+**/
+STATIC
+EFI_STATUS
+AddSsdtPcieTable (
+  IN  EFI_ACPI_TABLE_PROTOCOL  *AcpiTable
+  )
+{
+  EFI_STATUS                   Status;
+  UINTN                        TableHandle;
+  EFI_ACPI_DESCRIPTION_HEADER  *Table;
+  AML_ROOT_NODE_HANDLE         RootNode;
+  AML_OBJECT_NODE_HANDLE       ScopeNode;
+
+  Status = AmlCodeGenDefinitionBlock ("SSDT", "LINARO", "SBSAQEMU", 0x1, &RootNode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT: AmlCodeGenDefinitionBlock failed."
+      " Status = %r\n",
+      Status
+      ));
+  }
+
+  AmlCodeGenScope ("_SB_", RootNode, &ScopeNode);
+
+  AddPcieHostBridges(ScopeNode);
+
+  // Serialize the tree.
+  Status = AmlSerializeDefinitionBlock (
+             RootNode,
+             &Table
+             );
+
+  Status = AcpiTable->InstallAcpiTable (
+                        AcpiTable,
+                        Table,
+                        Table->Length,
+                        &TableHandle
+                        );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to install SSDT table\n"));
+  }
+
+  return EFI_SUCCESS;
+}
+
 
 EFI_STATUS
 EFIAPI
@@ -895,5 +946,11 @@ InitializeSbsaQemuAcpiDxe (
     DEBUG ((DEBUG_ERROR, "Failed to handle XHCI enablement\n"));
   }
 
+  Status = AddSsdtPcieTable (AcpiTable);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to add SSDT table\n"));
+  }
+
+
   return EFI_SUCCESS;
 }
diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.c b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.c
new file mode 100644
index 000000000000..f5595b8a1baa
--- /dev/null
+++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiPcie.c
@@ -0,0 +1,576 @@
+/** @file
+*  This file is an ACPI driver for the Qemu SBSA platform.
+*
+*  Copyright (c) 2024, Linaro Ltd. All rights reserved.
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Library/AcpiHelperLib.h>
+#include <Library/AmlLib/AmlLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/PciRootBridgeIo.h>
+
+#include "SbsaQemuAcpiPcie.h"
+
+#pragma pack(1)
+
+/** Adds the _OSC method to the PCIe node.
+
+  @param PciNode  PCIe device node.
+
+  @return EFI_SUCCESS on success, or an error code.
+
+**/
+STATIC
+EFI_STATUS
+AddOscMethod (
+  IN  OUT   AML_OBJECT_NODE_HANDLE  PciNode
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_ACPI_DESCRIPTION_HEADER  *SsdtPcieOscTemplate;
+  AML_ROOT_NODE_HANDLE         OscTemplateRoot;
+  AML_OBJECT_NODE_HANDLE       OscNode;
+  AML_OBJECT_NODE_HANDLE       ClonedOscNode;
+
+  ASSERT (PciNode != NULL);
+
+  /* Parse the Ssdt Pci Osc Template. */
+  SsdtPcieOscTemplate = (EFI_ACPI_DESCRIPTION_HEADER *)
+                        ssdttemplate_aml_code;
+
+  Status = AmlParseDefinitionBlock (
+             SsdtPcieOscTemplate,
+             &OscTemplateRoot
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template."
+      " Status = %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Status = AmlFindNode (OscTemplateRoot, "\\_OSC", &OscNode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "AmlFindNode: %r\n", Status));
+    return Status;
+  }
+
+  Status = AmlCloneTree (OscNode, &ClonedOscNode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "AmlCloneTree: %r\n", Status));
+    return Status;
+  }
+
+  Status = AmlAttachNode (PciNode, ClonedOscNode);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "AmlAttachNode: %r\n", Status));
+    // Free the cloned node.
+    AmlDeleteTree (ClonedOscNode);
+    return Status;
+  }
+
+  return Status;
+}
+
+/** Creates a PCI Interrupt Link Device.
+
+  @param PciDeviceHandle  PCIe device node.
+  @param Uid              UID of the Link Device.
+  @param LinkName         Name of the Device.
+  @param Irq              IRQ number.
+
+**/
+STATIC
+VOID
+GenPciLinkDevice (
+  AML_OBJECT_NODE_HANDLE  PciDeviceHandle,
+  UINT32                  Uid,
+  CONST CHAR8             *LinkName,
+  UINT32                  Irq
+  )
+{
+  EFI_STATUS              Status;
+  UINT32                  EisaId;
+  AML_OBJECT_NODE_HANDLE  GsiNode;
+
+  AmlCodeGenDevice (LinkName, PciDeviceHandle, &GsiNode);
+
+  Status = AmlGetEisaIdFromString ("PNP0C0F", &EisaId);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return;
+  }
+
+  AmlCodeGenNameInteger ("_HID", EisaId, GsiNode, NULL);
+  AmlCodeGenNameInteger ("_UID", Uid, GsiNode, NULL);
+
+  AML_OBJECT_NODE_HANDLE  Prs;
+
+  AmlCodeGenNameResourceTemplate ("_PRS", GsiNode, &Prs);
+  AmlCodeGenRdInterrupt (FALSE, FALSE, FALSE, FALSE, &Irq, 1, Prs, NULL);
+  AmlCodeGenMethodRetNameString ("_CRS", "_PRS", 0, TRUE, 0, GsiNode, NULL);
+  AmlCodeGenMethodRetNameString ("_SRS", NULL, 1, FALSE, 0, GsiNode, NULL);
+  AmlCodeGenMethodRetNameString ("_DIS", NULL, 0, FALSE, 0, GsiNode, NULL);
+}
+
+/** Creates a _PRT package.
+
+  @param PciDeviceHandle  PCIe device node.
+
+**/
+STATIC
+VOID
+GenPrtEntries (
+  AML_OBJECT_NODE_HANDLE  PciDeviceHandle
+  )
+{
+  AML_OBJECT_NODE_HANDLE  PrtNode;
+
+  AmlCodeGenNamePackage ("_PRT", PciDeviceHandle, &PrtNode);
+
+  AmlAddPrtEntry (0x0000FFFF, 0, "GSI0", 0, PrtNode);
+  AmlAddPrtEntry (0x0000FFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x0000FFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x0000FFFF, 0, "GSI3", 0, PrtNode);
+
+  AmlAddPrtEntry (0x0001FFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x0001FFFF, 0, "GSI2", 1, PrtNode);
+  AmlAddPrtEntry (0x0001FFFF, 0, "GSI3", 2, PrtNode);
+  AmlAddPrtEntry (0x0001FFFF, 0, "GSI0", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0002FFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x0002FFFF, 0, "GSI3", 1, PrtNode);
+  AmlAddPrtEntry (0x0002FFFF, 0, "GSI0", 2, PrtNode);
+  AmlAddPrtEntry (0x0002FFFF, 0, "GSI1", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0003FFFF, 0, "GSI3", 0, PrtNode);
+  AmlAddPrtEntry (0x0003FFFF, 0, "GSI0", 1, PrtNode);
+  AmlAddPrtEntry (0x0003FFFF, 0, "GSI1", 2, PrtNode);
+  AmlAddPrtEntry (0x0003FFFF, 0, "GSI2", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0004FFFF, 0, "GSI0", 0, PrtNode);
+  AmlAddPrtEntry (0x0004FFFF, 0, "GSI1", 1, PrtNode);
+
+  AmlAddPrtEntry (0x0004FFFF, 0, "GSI2", 2, PrtNode);
+  AmlAddPrtEntry (0x0004FFFF, 0, "GSI3", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0005FFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x0005FFFF, 0, "GSI2", 1, PrtNode);
+  AmlAddPrtEntry (0x0005FFFF, 0, "GSI3", 2, PrtNode);
+  AmlAddPrtEntry (0x0005FFFF, 0, "GSI0", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0006FFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x0006FFFF, 0, "GSI3", 1, PrtNode);
+  AmlAddPrtEntry (0x0006FFFF, 0, "GSI0", 2, PrtNode);
+  AmlAddPrtEntry (0x0006FFFF, 0, "GSI1", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0007FFFF, 0, "GSI3", 0, PrtNode);
+  AmlAddPrtEntry (0x0007FFFF, 0, "GSI0", 1, PrtNode);
+  AmlAddPrtEntry (0x0007FFFF, 0, "GSI1", 2, PrtNode);
+  AmlAddPrtEntry (0x0007FFFF, 0, "GSI2", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0008FFFF, 0, "GSI0", 0, PrtNode);
+  AmlAddPrtEntry (0x0008FFFF, 0, "GSI1", 1, PrtNode);
+  AmlAddPrtEntry (0x0008FFFF, 0, "GSI2", 2, PrtNode);
+  AmlAddPrtEntry (0x0008FFFF, 0, "GSI3", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0009FFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x0009FFFF, 0, "GSI2", 1, PrtNode);
+  AmlAddPrtEntry (0x0009FFFF, 0, "GSI3", 2, PrtNode);
+  AmlAddPrtEntry (0x0009FFFF, 0, "GSI0", 3, PrtNode);
+
+  AmlAddPrtEntry (0x000AFFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x000AFFFF, 0, "GSI3", 1, PrtNode);
+  AmlAddPrtEntry (0x000AFFFF, 0, "GSI0", 2, PrtNode);
+  AmlAddPrtEntry (0x000AFFFF, 0, "GSI1", 3, PrtNode);
+
+  AmlAddPrtEntry (0x000BFFFF, 0, "GSI3", 0, PrtNode);
+  AmlAddPrtEntry (0x000BFFFF, 0, "GSI0", 1, PrtNode);
+  AmlAddPrtEntry (0x000BFFFF, 0, "GSI1", 2, PrtNode);
+  AmlAddPrtEntry (0x000BFFFF, 0, "GSI2", 3, PrtNode);
+
+  AmlAddPrtEntry (0x000CFFFF, 0, "GSI0", 0, PrtNode);
+  AmlAddPrtEntry (0x000CFFFF, 0, "GSI1", 1, PrtNode);
+  AmlAddPrtEntry (0x000CFFFF, 0, "GSI2", 2, PrtNode);
+  AmlAddPrtEntry (0x000CFFFF, 0, "GSI3", 3, PrtNode);
+
+  AmlAddPrtEntry (0x000DFFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x000DFFFF, 0, "GSI2", 1, PrtNode);
+  AmlAddPrtEntry (0x000DFFFF, 0, "GSI3", 2, PrtNode);
+  AmlAddPrtEntry (0x000DFFFF, 0, "GSI0", 3, PrtNode);
+
+  AmlAddPrtEntry (0x000EFFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x000EFFFF, 0, "GSI3", 1, PrtNode);
+  AmlAddPrtEntry (0x000EFFFF, 0, "GSI0", 2, PrtNode);
+  AmlAddPrtEntry (0x000EFFFF, 0, "GSI1", 3, PrtNode);
+
+  AmlAddPrtEntry (0x000FFFFF, 0, "GSI3", 0, PrtNode);
+  AmlAddPrtEntry (0x000FFFFF, 0, "GSI0", 1, PrtNode);
+  AmlAddPrtEntry (0x000FFFFF, 0, "GSI1", 2, PrtNode);
+  AmlAddPrtEntry (0x000FFFFF, 0, "GSI2", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0010FFFF, 0, "GSI0", 0, PrtNode);
+  AmlAddPrtEntry (0x0010FFFF, 0, "GSI1", 1, PrtNode);
+  AmlAddPrtEntry (0x0010FFFF, 0, "GSI2", 2, PrtNode);
+  AmlAddPrtEntry (0x0010FFFF, 0, "GSI3", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0011FFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x0011FFFF, 0, "GSI2", 1, PrtNode);
+  AmlAddPrtEntry (0x0011FFFF, 0, "GSI3", 2, PrtNode);
+  AmlAddPrtEntry (0x0011FFFF, 0, "GSI0", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0012FFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x0012FFFF, 0, "GSI3", 1, PrtNode);
+  AmlAddPrtEntry (0x0012FFFF, 0, "GSI0", 2, PrtNode);
+  AmlAddPrtEntry (0x0012FFFF, 0, "GSI1", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0013FFFF, 0, "GSI3", 0, PrtNode);
+  AmlAddPrtEntry (0x0013FFFF, 0, "GSI0", 1, PrtNode);
+  AmlAddPrtEntry (0x0013FFFF, 0, "GSI1", 2, PrtNode);
+  AmlAddPrtEntry (0x0013FFFF, 0, "GSI2", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0014FFFF, 0, "GSI0", 0, PrtNode);
+  AmlAddPrtEntry (0x0014FFFF, 0, "GSI1", 1, PrtNode);
+  AmlAddPrtEntry (0x0014FFFF, 0, "GSI2", 2, PrtNode);
+  AmlAddPrtEntry (0x0014FFFF, 0, "GSI3", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0015FFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x0015FFFF, 0, "GSI2", 1, PrtNode);
+  AmlAddPrtEntry (0x0015FFFF, 0, "GSI3", 2, PrtNode);
+  AmlAddPrtEntry (0x0015FFFF, 0, "GSI0", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0016FFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x0016FFFF, 0, "GSI3", 1, PrtNode);
+  AmlAddPrtEntry (0x0016FFFF, 0, "GSI0", 2, PrtNode);
+  AmlAddPrtEntry (0x0016FFFF, 0, "GSI1", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0017FFFF, 0, "GSI3", 0, PrtNode);
+  AmlAddPrtEntry (0x0017FFFF, 0, "GSI0", 1, PrtNode);
+  AmlAddPrtEntry (0x0017FFFF, 0, "GSI1", 2, PrtNode);
+  AmlAddPrtEntry (0x0017FFFF, 0, "GSI2", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0018FFFF, 0, "GSI0", 0, PrtNode);
+  AmlAddPrtEntry (0x0018FFFF, 0, "GSI1", 1, PrtNode);
+  AmlAddPrtEntry (0x0018FFFF, 0, "GSI2", 2, PrtNode);
+  AmlAddPrtEntry (0x0018FFFF, 0, "GSI3", 3, PrtNode);
+
+  AmlAddPrtEntry (0x0019FFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x0019FFFF, 0, "GSI2", 1, PrtNode);
+  AmlAddPrtEntry (0x0019FFFF, 0, "GSI3", 2, PrtNode);
+  AmlAddPrtEntry (0x0019FFFF, 0, "GSI0", 3, PrtNode);
+
+  AmlAddPrtEntry (0x001AFFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x001AFFFF, 0, "GSI3", 1, PrtNode);
+  AmlAddPrtEntry (0x001AFFFF, 0, "GSI0", 2, PrtNode);
+  AmlAddPrtEntry (0x001AFFFF, 0, "GSI1", 3, PrtNode);
+
+  AmlAddPrtEntry (0x001BFFFF, 0, "GSI3", 0, PrtNode);
+  AmlAddPrtEntry (0x001BFFFF, 0, "GSI0", 1, PrtNode);
+  AmlAddPrtEntry (0x001BFFFF, 0, "GSI1", 2, PrtNode);
+  AmlAddPrtEntry (0x001BFFFF, 0, "GSI2", 3, PrtNode);
+
+  AmlAddPrtEntry (0x001CFFFF, 0, "GSI0", 0, PrtNode);
+  AmlAddPrtEntry (0x001CFFFF, 0, "GSI1", 1, PrtNode);
+  AmlAddPrtEntry (0x001CFFFF, 0, "GSI2", 2, PrtNode);
+  AmlAddPrtEntry (0x001CFFFF, 0, "GSI3", 3, PrtNode);
+
+  AmlAddPrtEntry (0x001DFFFF, 0, "GSI1", 0, PrtNode);
+  AmlAddPrtEntry (0x001DFFFF, 0, "GSI2", 1, PrtNode);
+  AmlAddPrtEntry (0x001DFFFF, 0, "GSI3", 2, PrtNode);
+  AmlAddPrtEntry (0x001DFFFF, 0, "GSI0", 3, PrtNode);
+
+  AmlAddPrtEntry (0x001EFFFF, 0, "GSI2", 0, PrtNode);
+  AmlAddPrtEntry (0x001EFFFF, 0, "GSI3", 1, PrtNode);
+  AmlAddPrtEntry (0x001EFFFF, 0, "GSI0", 2, PrtNode);
+  AmlAddPrtEntry (0x001EFFFF, 0, "GSI1", 3, PrtNode);
+
+  AmlAddPrtEntry (0x001FFFFF, 0, "GSI3", 0, PrtNode);
+  AmlAddPrtEntry (0x001FFFFF, 0, "GSI0", 1, PrtNode);
+  AmlAddPrtEntry (0x001FFFFF, 0, "GSI1", 2, PrtNode);
+  AmlAddPrtEntry (0x001FFFFF, 0, "GSI2", 3, PrtNode);
+}
+
+EFI_STATUS
+PciGetProtocolAndResource (
+  IN  EFI_HANDLE                         Handle,
+  OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL    **IoDev,
+  OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  **Descriptors
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Get inferface from protocol
+  //
+  Status = gBS->HandleProtocol (
+                  Handle,
+                  &gEfiPciRootBridgeIoProtocolGuid,
+                  (VOID **)IoDev
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Call Configuration() to get address space descriptors
+  //
+  Status = (*IoDev)->Configuration (*IoDev, (VOID **)Descriptors);
+  if (Status == EFI_UNSUPPORTED) {
+    *Descriptors = NULL;
+    return EFI_SUCCESS;
+  } else {
+    return Status;
+  }
+}
+
+EFI_STATUS
+AddPcieHostBridges (
+  AML_OBJECT_NODE_HANDLE  ScopeNode
+  )
+{
+  UINTN       HandleBufSize;
+  EFI_HANDLE  *HandleBuf;
+  UINTN       HandleCount;
+  EFI_STATUS  Status;
+  UINTN       Index;
+
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL    *IoDev;
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR  *Descriptors;
+
+  AML_OBJECT_NODE_HANDLE  PciNode;
+  AML_OBJECT_NODE_HANDLE  ResNode;
+  AML_OBJECT_NODE_HANDLE  RbufRt;
+  AML_OBJECT_NODE_HANDLE  ResRt;
+  UINT64                  PcieDeviceStatus;
+  UINT32                  EisaId;
+  CHAR8                   DeviceName[5];
+
+  HandleBufSize = sizeof (EFI_HANDLE);
+  HandleBuf     = (EFI_HANDLE *)AllocateZeroPool (HandleBufSize);
+  if (HandleBuf == NULL) {
+    DEBUG ((DEBUG_ERROR, "Failed to allocate memory\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = gBS->LocateHandle (
+                  ByProtocol,
+                  &gEfiPciRootBridgeIoProtocolGuid,
+                  NULL,
+                  &HandleBufSize,
+                  HandleBuf
+                  );
+
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    HandleBuf = ReallocatePool (sizeof (EFI_HANDLE), HandleBufSize, HandleBuf);
+    if (HandleBuf == NULL) {
+      DEBUG ((DEBUG_ERROR, "Failed to allocate memory\n"));
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    Status = gBS->LocateHandle (
+                    ByProtocol,
+                    &gEfiPciRootBridgeIoProtocolGuid,
+                    NULL,
+                    &HandleBufSize,
+                    HandleBuf
+                    );
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to locate PciRootBridge\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  HandleCount = HandleBufSize / sizeof (EFI_HANDLE);
+
+  for (Index = 0; Index < HandleCount; Index++) {
+    AsciiSPrint (DeviceName, sizeof (DeviceName), "PCI%x", Index);
+    AmlCodeGenDevice (DeviceName, ScopeNode, &PciNode);
+    Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId);
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      return Status;
+    }
+
+    AmlCodeGenNameInteger ("_HID", EisaId, PciNode, NULL);
+    Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId);
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      return Status;
+    }
+
+    AmlCodeGenNameInteger ("_CID", EisaId, PciNode, NULL);
+    AmlCodeGenNameInteger ("_SEG", 0, PciNode, NULL);
+    AmlCodeGenNameInteger ("_CCA", 1, PciNode, NULL);
+    AmlCodeGenNameString ("_UID", DeviceName, PciNode, NULL);
+
+    GenPciLinkDevice (PciNode, 0, "GSI0", 0x23);
+    GenPciLinkDevice (PciNode, 0, "GSI1", 0x24);
+    GenPciLinkDevice (PciNode, 0, "GSI2", 0x25);
+    GenPciLinkDevice (PciNode, 0, "GSI3", 0x26);
+
+    GenPrtEntries (PciNode);
+    AmlCodeGenNameResourceTemplate ("RBUF", PciNode, &RbufRt);
+    AmlCodeGenMethodRetInteger ("_CBA", PcdGet64 (PcdPciExpressBaseAddress), 0, FALSE, 0, PciNode, NULL);
+
+    Status = PciGetProtocolAndResource (
+               HandleBuf[Index],
+               &IoDev,
+               &Descriptors
+               );
+
+    while ((*Descriptors).Desc != ACPI_END_TAG_DESCRIPTOR) {
+      if (((*Descriptors).ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
+          ((*Descriptors).AddrSpaceGranularity == 0x20))
+      {
+        AmlCodeGenRdDWordMemory (
+          FALSE,
+          TRUE,
+          TRUE,
+          TRUE,
+          1,
+          TRUE,
+          0,
+          (*Descriptors).AddrRangeMin,
+          (*Descriptors).AddrRangeMax,
+          0,
+          (*Descriptors).AddrRangeMax - (*Descriptors).AddrRangeMin + 1,
+          0,
+          NULL,
+          0,
+          TRUE,
+          RbufRt,
+          NULL
+          );
+      }
+
+      if (((*Descriptors).ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
+          ((*Descriptors).AddrSpaceGranularity == 0x40))
+      {
+        AmlCodeGenRdQWordMemory (
+          FALSE,
+          TRUE,
+          TRUE,
+          TRUE,
+          TRUE,
+          TRUE,
+          0,
+          (*Descriptors).AddrRangeMin,
+          (*Descriptors).AddrRangeMax,
+          0,
+          (*Descriptors).AddrRangeMax - (*Descriptors).AddrRangeMin + 1,
+          0,
+          NULL,
+          0,
+          TRUE,
+          RbufRt,
+          NULL
+          );
+      }
+
+      if ((*Descriptors).ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
+        AmlCodeGenRdDWordIo (
+          FALSE,
+          TRUE,
+          TRUE,
+          TRUE,
+          3,
+          0,
+          (*Descriptors).AddrRangeMin,
+          (*Descriptors).AddrRangeMax,
+          0,
+          (*Descriptors).AddrRangeMax - (*Descriptors).AddrRangeMin + 1,
+          0,
+          NULL,
+          FALSE,
+          TRUE,
+          RbufRt,
+          NULL
+          );
+      }
+
+      if ((*Descriptors).ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
+        AmlCodeGenNameInteger ("_BBN", (*Descriptors).AddrRangeMin, PciNode, NULL);
+        AmlCodeGenRdWordBusNumber (
+          FALSE,
+          TRUE,
+          TRUE,
+          TRUE,
+          0,
+          (*Descriptors).AddrRangeMin,
+          (*Descriptors).AddrRangeMax,
+          0,
+          (*Descriptors).AddrRangeMax - (*Descriptors).AddrRangeMin + 1,
+          0,
+          NULL,
+          RbufRt,
+          NULL
+          );
+      }
+
+      (Descriptors)++;
+    }
+
+    DEBUG ((DEBUG_INFO, "\n"));
+
+    AmlCodeGenMethodRetNameString ("_CRS", "RBUF", 0, TRUE, 0, PciNode, NULL);
+    PcieDeviceStatus = 0xF; // STATUS_PRESENT | STATUS_ENABLED | STATUS_SHOWN_IN_UI | STATUS_FUNCTIONING;
+    AmlCodeGenMethodRetInteger ("_STA", PcieDeviceStatus, 0, TRUE, 0, PciNode, NULL);
+
+    AmlCodeGenNameInteger ("SUPP", 0, PciNode, NULL);
+    AmlCodeGenNameInteger ("CTRL", 0, PciNode, NULL);
+
+    AddOscMethod (PciNode);
+
+    if (Index == 0) {
+      // first node
+      AmlCodeGenDevice ("RES0", PciNode, &ResNode);
+      Status = AmlGetEisaIdFromString ("PNP0C02", &EisaId);
+      if (EFI_ERROR (Status)) {
+        ASSERT (0);
+        return Status;
+      }
+
+      AmlCodeGenNameInteger ("_HID", EisaId, ResNode, NULL);
+
+      AmlCodeGenNameResourceTemplate ("_CRS", ResNode, &ResRt);
+      AmlCodeGenRdQWordMemory (
+        FALSE,
+        TRUE,
+        TRUE,
+        TRUE,
+        FALSE,
+        TRUE,
+        0,
+        PcdGet64 (PcdPciExpressBaseAddress), // Range Minimum
+        PcdGet64 (PcdPciExpressBarLimit),    // Range Maximum
+        0x0000000000000000,                       // Translation Offset
+        PcdGet64 (PcdPciExpressBarSize),     // Length
+        //   Bridge->Mem.Base,
+        //   Bridge->Mem.Limit,
+        //   FixedPcdGet32 (PcdPciMmio32Translation),
+        //   Bridge->Mem.Limit - Bridge->Mem.Base + 1,
+        0,
+        NULL /* ResourceSource */,
+        0 /* MemoryRangeType */,
+        TRUE /* IsTypeStatic */,
+        ResRt,
+        NULL
+        );
+    }
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Qemu/SbsaQemu/AcpiTables/Dsdt.asl b/Silicon/Qemu/SbsaQemu/AcpiTables/Dsdt.asl
index c134fb66e860..1c8d4fe4f647 100644
--- a/Silicon/Qemu/SbsaQemu/AcpiTables/Dsdt.asl
+++ b/Silicon/Qemu/SbsaQemu/AcpiTables/Dsdt.asl
@@ -181,307 +181,5 @@ DefinitionBlock ("DsdtTable.aml", "DSDT",
             } // USB0_RHUB_HUB1
         } // USB0_RHUB
     } // USB0
-
-    Device (PCI0)
-    {
-      Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge
-      Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge
-      Name (_SEG, Zero) // PCI Segment Group number
-      Name (_BBN, Zero) // PCI Base Bus Number
-      Name (_UID, "PCI0")
-      Name (_CCA, One)    // Initially mark the PCI coherent (for JunoR1)
-
-      Method (_STA) {
-        Return (0xF)
-      }
-
-      Method (_CBA, 0, NotSerialized) {
-          return (FixedPcdGet32 (PcdPciExpressBaseAddress))
-      }
-
-      LINK_DEVICE(0, GSI0, 0x23)
-      LINK_DEVICE(1, GSI1, 0x24)
-      LINK_DEVICE(2, GSI2, 0x25)
-      LINK_DEVICE(3, GSI3, 0x26)
-
-      Name (_PRT, Package ()  // _PRT: PCI Routing Table
-      {
-        PRT_ENTRY(0x0000FFFF, 0, GSI0),
-        PRT_ENTRY(0x0000FFFF, 0, GSI1),
-        PRT_ENTRY(0x0000FFFF, 0, GSI2),
-        PRT_ENTRY(0x0000FFFF, 0, GSI3),
-
-        PRT_ENTRY(0x0001FFFF, 0, GSI1),
-        PRT_ENTRY(0x0001FFFF, 1, GSI2),
-        PRT_ENTRY(0x0001FFFF, 2, GSI3),
-        PRT_ENTRY(0x0001FFFF, 3, GSI0),
-
-        PRT_ENTRY(0x0002FFFF, 0, GSI2),
-        PRT_ENTRY(0x0002FFFF, 1, GSI3),
-        PRT_ENTRY(0x0002FFFF, 2, GSI0),
-        PRT_ENTRY(0x0002FFFF, 3, GSI1),
-
-        PRT_ENTRY(0x0003FFFF, 0, GSI3),
-        PRT_ENTRY(0x0003FFFF, 1, GSI0),
-        PRT_ENTRY(0x0003FFFF, 2, GSI1),
-        PRT_ENTRY(0x0003FFFF, 3, GSI2),
-
-        PRT_ENTRY(0x0004FFFF, 0, GSI0),
-        PRT_ENTRY(0x0004FFFF, 1, GSI1),
-        PRT_ENTRY(0x0004FFFF, 2, GSI2),
-        PRT_ENTRY(0x0004FFFF, 3, GSI3),
-
-        PRT_ENTRY(0x0005FFFF, 0, GSI1),
-        PRT_ENTRY(0x0005FFFF, 1, GSI2),
-        PRT_ENTRY(0x0005FFFF, 2, GSI3),
-        PRT_ENTRY(0x0005FFFF, 3, GSI0),
-
-        PRT_ENTRY(0x0006FFFF, 0, GSI2),
-        PRT_ENTRY(0x0006FFFF, 1, GSI3),
-        PRT_ENTRY(0x0006FFFF, 2, GSI0),
-        PRT_ENTRY(0x0006FFFF, 3, GSI1),
-
-        PRT_ENTRY(0x0007FFFF, 0, GSI3),
-        PRT_ENTRY(0x0007FFFF, 1, GSI0),
-        PRT_ENTRY(0x0007FFFF, 2, GSI1),
-        PRT_ENTRY(0x0007FFFF, 3, GSI2),
-
-        PRT_ENTRY(0x0008FFFF, 0, GSI0),
-        PRT_ENTRY(0x0008FFFF, 1, GSI1),
-        PRT_ENTRY(0x0008FFFF, 2, GSI2),
-        PRT_ENTRY(0x0008FFFF, 3, GSI3),
-
-        PRT_ENTRY(0x0009FFFF, 0, GSI1),
-        PRT_ENTRY(0x0009FFFF, 1, GSI2),
-        PRT_ENTRY(0x0009FFFF, 2, GSI3),
-        PRT_ENTRY(0x0009FFFF, 3, GSI0),
-
-        PRT_ENTRY(0x000AFFFF, 0, GSI2),
-        PRT_ENTRY(0x000AFFFF, 1, GSI3),
-        PRT_ENTRY(0x000AFFFF, 2, GSI0),
-        PRT_ENTRY(0x000AFFFF, 3, GSI1),
-
-        PRT_ENTRY(0x000BFFFF, 0, GSI3),
-        PRT_ENTRY(0x000BFFFF, 1, GSI0),
-        PRT_ENTRY(0x000BFFFF, 2, GSI1),
-        PRT_ENTRY(0x000BFFFF, 3, GSI2),
-
-        PRT_ENTRY(0x000CFFFF, 0, GSI0),
-        PRT_ENTRY(0x000CFFFF, 1, GSI1),
-        PRT_ENTRY(0x000CFFFF, 2, GSI2),
-        PRT_ENTRY(0x000CFFFF, 3, GSI3),
-
-        PRT_ENTRY(0x000DFFFF, 0, GSI1),
-        PRT_ENTRY(0x000DFFFF, 1, GSI2),
-        PRT_ENTRY(0x000DFFFF, 2, GSI3),
-        PRT_ENTRY(0x000DFFFF, 3, GSI0),
-
-        PRT_ENTRY(0x000EFFFF, 0, GSI2),
-        PRT_ENTRY(0x000EFFFF, 1, GSI3),
-        PRT_ENTRY(0x000EFFFF, 2, GSI0),
-        PRT_ENTRY(0x000EFFFF, 3, GSI1),
-
-        PRT_ENTRY(0x000FFFFF, 0, GSI3),
-        PRT_ENTRY(0x000FFFFF, 1, GSI0),
-        PRT_ENTRY(0x000FFFFF, 2, GSI1),
-        PRT_ENTRY(0x000FFFFF, 3, GSI2),
-
-        PRT_ENTRY(0x0010FFFF, 0, GSI0),
-        PRT_ENTRY(0x0010FFFF, 1, GSI1),
-        PRT_ENTRY(0x0010FFFF, 2, GSI2),
-        PRT_ENTRY(0x0010FFFF, 3, GSI3),
-
-        PRT_ENTRY(0x0011FFFF, 0, GSI1),
-        PRT_ENTRY(0x0011FFFF, 1, GSI2),
-        PRT_ENTRY(0x0011FFFF, 2, GSI3),
-        PRT_ENTRY(0x0011FFFF, 3, GSI0),
-
-        PRT_ENTRY(0x0012FFFF, 0, GSI2),
-        PRT_ENTRY(0x0012FFFF, 1, GSI3),
-        PRT_ENTRY(0x0012FFFF, 2, GSI0),
-        PRT_ENTRY(0x0012FFFF, 3, GSI1),
-
-        PRT_ENTRY(0x0013FFFF, 0, GSI3),
-        PRT_ENTRY(0x0013FFFF, 1, GSI0),
-        PRT_ENTRY(0x0013FFFF, 2, GSI1),
-        PRT_ENTRY(0x0013FFFF, 3, GSI2),
-
-        PRT_ENTRY(0x0014FFFF, 0, GSI0),
-        PRT_ENTRY(0x0014FFFF, 1, GSI1),
-        PRT_ENTRY(0x0014FFFF, 2, GSI2),
-        PRT_ENTRY(0x0014FFFF, 3, GSI3),
-
-        PRT_ENTRY(0x0015FFFF, 0, GSI1),
-        PRT_ENTRY(0x0015FFFF, 1, GSI2),
-        PRT_ENTRY(0x0015FFFF, 2, GSI3),
-        PRT_ENTRY(0x0015FFFF, 3, GSI0),
-
-        PRT_ENTRY(0x0016FFFF, 0, GSI2),
-        PRT_ENTRY(0x0016FFFF, 1, GSI3),
-        PRT_ENTRY(0x0016FFFF, 2, GSI0),
-        PRT_ENTRY(0x0016FFFF, 3, GSI1),
-
-        PRT_ENTRY(0x0017FFFF, 0, GSI3),
-        PRT_ENTRY(0x0017FFFF, 1, GSI0),
-        PRT_ENTRY(0x0017FFFF, 2, GSI1),
-        PRT_ENTRY(0x0017FFFF, 3, GSI2),
-
-        PRT_ENTRY(0x0018FFFF, 0, GSI0),
-        PRT_ENTRY(0x0018FFFF, 1, GSI1),
-        PRT_ENTRY(0x0018FFFF, 2, GSI2),
-        PRT_ENTRY(0x0018FFFF, 3, GSI3),
-
-        PRT_ENTRY(0x0019FFFF, 0, GSI1),
-        PRT_ENTRY(0x0019FFFF, 1, GSI2),
-        PRT_ENTRY(0x0019FFFF, 2, GSI3),
-        PRT_ENTRY(0x0019FFFF, 3, GSI0),
-
-        PRT_ENTRY(0x001AFFFF, 0, GSI2),
-        PRT_ENTRY(0x001AFFFF, 1, GSI3),
-        PRT_ENTRY(0x001AFFFF, 2, GSI0),
-        PRT_ENTRY(0x001AFFFF, 3, GSI1),
-
-        PRT_ENTRY(0x001BFFFF, 0, GSI3),
-        PRT_ENTRY(0x001BFFFF, 1, GSI0),
-        PRT_ENTRY(0x001BFFFF, 2, GSI1),
-        PRT_ENTRY(0x001BFFFF, 3, GSI2),
-
-        PRT_ENTRY(0x001CFFFF, 0, GSI0),
-        PRT_ENTRY(0x001CFFFF, 1, GSI1),
-        PRT_ENTRY(0x001CFFFF, 2, GSI2),
-        PRT_ENTRY(0x001CFFFF, 3, GSI3),
-
-        PRT_ENTRY(0x001DFFFF, 0, GSI1),
-        PRT_ENTRY(0x001DFFFF, 1, GSI2),
-        PRT_ENTRY(0x001DFFFF, 2, GSI3),
-        PRT_ENTRY(0x001DFFFF, 3, GSI0),
-
-        PRT_ENTRY(0x001EFFFF, 0, GSI2),
-        PRT_ENTRY(0x001EFFFF, 1, GSI3),
-        PRT_ENTRY(0x001EFFFF, 2, GSI0),
-        PRT_ENTRY(0x001EFFFF, 3, GSI1),
-
-        PRT_ENTRY(0x001FFFFF, 0, GSI3),
-        PRT_ENTRY(0x001FFFFF, 1, GSI0),
-        PRT_ENTRY(0x001FFFFF, 2, GSI1),
-        PRT_ENTRY(0x001FFFFF, 3, GSI2),
-      })
-
-      // Root complex resources
-      Name (_CRS, ResourceTemplate () {
-        WordBusNumber ( // Bus numbers assigned to this root
-        ResourceProducer,
-        MinFixed, MaxFixed, PosDecode,
-        0,   // AddressGranularity
-        FixedPcdGet32 (PcdPciBusMin),   // AddressMinimum - Minimum Bus Number
-        FixedPcdGet32 (PcdPciBusMax),   // AddressMaximum - Maximum Bus Number
-        0,   // AddressTranslation - Set to 0
-        256  // RangeLength - Number of Busses
-        )
-
-        DWordMemory ( // 32-bit BAR Windows
-          ResourceProducer, PosDecode,
-          MinFixed, MaxFixed,
-          Cacheable, ReadWrite,
-          0x00000000,                              // Granularity
-          FixedPcdGet32 (PcdPciMmio32Base),        // Min Base Address
-          FixedPcdGet32 (PcdPciMmio32Limit),       // Max Base Address
-          FixedPcdGet32 (PcdPciMmio32Translation), // Translate
-          FixedPcdGet32 (PcdPciMmio32Size)         // Length
-          )
-
-        QWordMemory ( // 64-bit BAR Windows
-          ResourceProducer, PosDecode,
-          MinFixed, MaxFixed,
-          Cacheable, ReadWrite,
-          0x00000000,                              // Granularity
-          FixedPcdGet64 (PcdPciMmio64Base),        // Min Base Address
-          FixedPcdGet64 (PcdPciMmio64Limit),       // Max Base Address
-          FixedPcdGet64 (PcdPciMmio64Translation), // Translate
-          FixedPcdGet64 (PcdPciMmio64Size)         // Length
-          )
-
-        DWordIo ( // IO window
-          ResourceProducer,
-          MinFixed,
-          MaxFixed,
-          PosDecode,
-          EntireRange,
-          0x00000000,                              // Granularity
-          FixedPcdGet32 (PcdPciIoBase),            // Min Base Address
-          FixedPcdGet32 (PcdPciIoLimit),           // Max Base Address
-          FixedPcdGet32 (PcdPciIoTranslation),     // Translate
-          FixedPcdGet32 (PcdPciIoSize),            // Length
-          ,,,TypeTranslation
-          )
-      }) // Name(_CRS)
-
-      Device (RES0)
-      {
-        Name (_HID, "PNP0C02" /* PNP Motherboard Resources */)  // _HID: Hardware ID
-        Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
-        {
-           QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
-           0x0000000000000000,                       // Granularity
-           FixedPcdGet64 (PcdPciExpressBaseAddress), // Range Minimum
-           FixedPcdGet64 (PcdPciExpressBarLimit),    // Range Maximum
-           0x0000000000000000,                       // Translation Offset
-           FixedPcdGet64 (PcdPciExpressBarSize),     // Length
-           ,, , AddressRangeMemory, TypeStatic)
-        })
-        Method (_STA) {
-          Return (0xF)
-        }
-      }
-
-      // OS Control Handoff
-      Name (SUPP, Zero) // PCI _OSC Support Field value
-      Name (CTRL, Zero) // PCI _OSC Control Field value
-
-      /*
-       * See [1] 6.2.10, [2] 4.5
-       */
-      Method (_OSC,4) {
-        // Check for proper UUID
-        If (Arg0 == ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766")) {
-          // Create DWord-adressable fields from the Capabilities Buffer
-          CreateDWordField (Arg3,0,CDW1)
-          CreateDWordField (Arg3,4,CDW2)
-          CreateDWordField (Arg3,8,CDW3)
-
-          // Save Capabilities DWord2 & 3
-          Store (CDW2,SUPP)
-          Store (CDW3,CTRL)
-
-          // Only allow native hot plug control if OS supports:
-          // * ASPM
-          // * Clock PM
-          // * MSI/MSI-X
-          If ((SUPP & 0x16) != 0x16) {
-            CTRL &= 0x1E // Mask bit 0 (and undefined bits)
-          }
-
-          // Always allow native PME, AER (no dependencies)
-
-          // Never allow SHPC (no SHPC controller in this system)
-          CTRL &= 0x1D
-
-          If (Arg1 != One) {         // Unknown revision
-            CDW1 |= 0x08
-          }
-
-          If (CDW3 != CTRL) {        // Capabilities bits were masked
-            CDW1 |= 0x10
-          }
-
-          // Update DWORD3 in the buffer
-          Store (CTRL,CDW3)
-          Return (Arg3)
-        } Else {
-          CDW1 |= 4 // Unrecognized UUID
-          Return (Arg3)
-        }
-      } // End _OSC
-    }
   } // Scope (_SB)
 }
diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SsdtTemplate.asl b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SsdtTemplate.asl
new file mode 100644
index 000000000000..2fcdb607d173
--- /dev/null
+++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SsdtTemplate.asl
@@ -0,0 +1,82 @@
+/** @file
+*  Differentiated System Description Table Fields (DSDT).
+*
+*  Copyright (c) 2024, Linaro Ltd. All rights reserved.
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <IndustryStandard/Acpi63.h>
+#include <IndustryStandard/SbsaQemuAcpi.h>
+
+#define LINK_DEVICE(Uid, LinkName, Irq)                                        \
+        Device (LinkName) {                                                    \
+            Name (_HID, EISAID("PNP0C0F"))                                     \
+            Name (_UID, Uid)                                                   \
+            Name (_PRS, ResourceTemplate() {                                   \
+                Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { Irq } \
+            })                                                                 \
+            Method (_CRS, 0) { Return (_PRS) }                                 \
+            Method (_SRS, 1) { }                                               \
+            Method (_DIS) { }                                                  \
+        }
+
+#define PRT_ENTRY(Address, Pin, Link)                                          \
+        Package (4) {                                                          \
+            Address, Pin, Link, Zero                                           \
+          }
+
+DefinitionBlock ("Dsdt.aml", "DSDT",
+                 EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION,
+                 "LINARO", "SBSAQEMU", FixedPcdGet32 (PcdAcpiDefaultOemRevision)) {
+      /*
+       * See [1] 6.2.10, [2] 4.5
+       */
+      Name (SUPP, Zero) // PCI _OSC Support Field value
+      Name (CTRL, Zero) // PCI _OSC Control Field value
+      Method (_OSC, 4, Serialized) {
+        //
+        // OS Control Handoff
+        //
+
+        // Check for proper UUID
+        If (Arg0 == ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766")) {
+          // Create DWord-adressable fields from the Capabilities Buffer
+          CreateDWordField (Arg3,0,CDW1)
+          CreateDWordField (Arg3,4,CDW2)
+          CreateDWordField (Arg3,8,CDW3)
+
+          // Save Capabilities DWord2 & 3
+          Store (CDW2,SUPP)
+          Store (CDW3,CTRL)
+
+          // Only allow native hot plug control if OS supports:
+          // * ASPM
+          // * Clock PM
+          // * MSI/MSI-X
+          If ((SUPP & 0x16) != 0x16) {
+            CTRL |= 0x1E // Mask bit 0 (and undefined bits)
+          }
+
+          // Always allow native PME, AER (no dependencies)
+
+          // Never allow SHPC (no SHPC controller in this system)
+          CTRL &= 0x1D
+
+          If (Arg1 != One) {        // Unknown revision
+            CDW1 |= 0x08
+          }
+
+          If (CDW3 != CTRL) {        // Capabilities bits were masked
+            CDW1 |= 0x10
+          }
+
+          // Update DWORD3 in the buffer
+          Store (CTRL,CDW3)
+          Return (Arg3)
+        } Else {
+          CDW1 |= 4 // Unrecognized UUID
+          Return (Arg3)
+        }
+      } // End _OSC
+}

-- 
2.44.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118290): https://edk2.groups.io/g/devel/message/118290
Mute This Topic: https://groups.io/mt/105728626/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [edk2-devel] [PATCH edk2-platforms WIP 3/3] SbsaQemu: generate MCFG table
  2024-04-25 12:02 [edk2-devel] [PATCH WIP edk2-platforms 0/3] SbsaQemu: add support for multiple PCI Express buses Marcin Juszkiewicz
  2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 1/3] SbsaQemu: scan for PCIe buses Marcin Juszkiewicz
  2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 2/3] SbsaQemu: describe PCIe buses in SSDT tables Marcin Juszkiewicz
@ 2024-04-25 12:02 ` Marcin Juszkiewicz
  2 siblings, 0 replies; 4+ messages in thread
From: Marcin Juszkiewicz @ 2024-04-25 12:02 UTC (permalink / raw)
  To: devel
  Cc: Leif Lindholm, Ard Biesheuvel, Graeme Gregory, Ray Ni,
	Marcin Juszkiewicz

We want to have dynaminc PCI Express variables. Which forces us to
generate MCFG from C code.

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
 Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf      |  1 -
 .../Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c        | 83 ++++++++++++++++++++
 Silicon/Qemu/SbsaQemu/AcpiTables/Mcfg.aslc           | 43 ----------
 3 files changed, 83 insertions(+), 44 deletions(-)

diff --git a/Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf b/Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf
index 8d4905362edc..37abf2f4c512 100644
--- a/Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf
+++ b/Silicon/Qemu/SbsaQemu/AcpiTables/AcpiTables.inf
@@ -19,7 +19,6 @@ [Sources]
   Dbg2.aslc
   Dsdt.asl
   Fadt.aslc
-  Mcfg.aslc
   Spcr.aslc
 
 [Packages]
diff --git a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c
index f3d5dc9e9ba7..6c7913eead81 100644
--- a/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c
+++ b/Silicon/Qemu/SbsaQemu/Drivers/SbsaQemuAcpiDxe/SbsaQemuAcpiDxe.c
@@ -7,6 +7,7 @@
 *
 **/
 #include <IndustryStandard/IoRemappingTable.h>
+#include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>
 #include <IndustryStandard/SbsaQemuAcpi.h>
 #include <IndustryStandard/SbsaQemuPlatformVersion.h>
 
@@ -883,6 +884,83 @@ AddSsdtPcieTable (
   return EFI_SUCCESS;
 }
 
+/** Adds the MCFG ACPI table.
+
+  @param AcpiTable        The ACPI Table.
+  @param PcieCfgData      PCIe configuration data.
+  @param NumPcieSegments  Number of PCIe segments.
+
+  @return EFI_SUCCESS on success, or an error code.
+
+**/
+STATIC
+EFI_STATUS
+AddMcfgTable (
+  IN EFI_ACPI_TABLE_PROTOCOL  *AcpiTable
+  )
+{
+  EFI_STATUS            Status;
+  UINTN                 TableHandle;
+  UINT32                TableSize;
+  EFI_PHYSICAL_ADDRESS  PageAddress;
+  UINT8                 *New;
+
+  EFI_ACPI_DESCRIPTION_HEADER  Header =
+    SBSAQEMU_ACPI_HEADER (
+      EFI_ACPI_6_3_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE,
+      EFI_ACPI_DESCRIPTION_HEADER,
+      EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION
+      );
+
+  TableSize = sizeof (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER) +
+              sizeof (EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE);
+
+  Status = gBS->AllocatePages (
+                  AllocateAnyPages,
+                  EfiACPIReclaimMemory,
+                  EFI_SIZE_TO_PAGES (TableSize),
+                  &PageAddress
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to allocate pages for MCFG table\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  New = (UINT8 *)(UINTN)PageAddress;
+  ZeroMem (New, TableSize);
+
+  // Add the  ACPI Description table header
+  CopyMem (New, &Header, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+  ((EFI_ACPI_DESCRIPTION_HEADER *)New)->Length = TableSize;
+  New                                         += sizeof (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER);
+
+  EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE  *CfgPtr;
+
+  CfgPtr = (VOID *)New;
+
+  CfgPtr->BaseAddress           = PcdGet64 (PcdPciExpressBaseAddress);
+  CfgPtr->PciSegmentGroupNumber = 0;
+  CfgPtr->StartBusNumber        = PcdGet32 (PcdPciBusMin);
+  CfgPtr->EndBusNumber          = PcdGet32 (PcdPciBusMax);
+
+  New += sizeof (EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE);
+
+  // Perform Checksum
+  AcpiTableChecksum ((UINT8 *)PageAddress, TableSize);
+
+  Status = AcpiTable->InstallAcpiTable (
+                        AcpiTable,
+                        (EFI_ACPI_COMMON_HEADER *)PageAddress,
+                        TableSize,
+                        &TableHandle
+                        );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to install MCFG table\n"));
+  }
+
+  return Status;
+}
+
 
 EFI_STATUS
 EFIAPI
@@ -951,6 +1029,11 @@ InitializeSbsaQemuAcpiDxe (
     DEBUG ((DEBUG_ERROR, "Failed to add SSDT table\n"));
   }
 
+  Status = AddMcfgTable (AcpiTable);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to add MCFG table\n"));
+  }
+
 
   return EFI_SUCCESS;
 }
diff --git a/Silicon/Qemu/SbsaQemu/AcpiTables/Mcfg.aslc b/Silicon/Qemu/SbsaQemu/AcpiTables/Mcfg.aslc
deleted file mode 100644
index 289f4ad4ea3a..000000000000
--- a/Silicon/Qemu/SbsaQemu/AcpiTables/Mcfg.aslc
+++ /dev/null
@@ -1,43 +0,0 @@
-/** @file
-*  ACPI Memory mapped configuration space base address Description Table (MCFG).
-*
-*  Copyright (c) 2020, Linaro Limited. All rights reserved.
-*
-*  SPDX-License-Identifier: BSD-2-Clause-Patent
-**/
-
-#include <IndustryStandard/Acpi.h>
-#include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>
-#include <IndustryStandard/SbsaQemuAcpi.h>
-
-#pragma pack(push, 1)
-
-typedef struct {
-  EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER Header;
-  EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE Structure[1];
-} EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_DESCRIPTION_TABLE;
-
-EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_DESCRIPTION_TABLE Mcfg = {
-  {
-    SBSAQEMU_ACPI_HEADER (
-      EFI_ACPI_6_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE,
-      EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_DESCRIPTION_TABLE,
-      EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION),
-    EFI_ACPI_RESERVED_QWORD
-  },
-  {
-    {
-      FixedPcdGet32 (PcdPciExpressBaseAddress),
-      0,
-      FixedPcdGet32 (PcdPciBusMin),
-      FixedPcdGet32 (PcdPciBusMax),
-      EFI_ACPI_RESERVED_DWORD
-    }
-  }
-};
-
-#pragma pack(pop)
-
-// Reference the table being generated to prevent the optimizer
-// from removing the data structure from the executable
-VOID* CONST ReferenceAcpiTable = &Mcfg;

-- 
2.44.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118289): https://edk2.groups.io/g/devel/message/118289
Mute This Topic: https://groups.io/mt/105728625/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-04-25 12:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-25 12:02 [edk2-devel] [PATCH WIP edk2-platforms 0/3] SbsaQemu: add support for multiple PCI Express buses Marcin Juszkiewicz
2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 1/3] SbsaQemu: scan for PCIe buses Marcin Juszkiewicz
2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 2/3] SbsaQemu: describe PCIe buses in SSDT tables Marcin Juszkiewicz
2024-04-25 12:02 ` [edk2-devel] [PATCH edk2-platforms WIP 3/3] SbsaQemu: generate MCFG table Marcin Juszkiewicz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox