]> git.proxmox.com Git - mirror_edk2.git/blobdiff - DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
DynamicTablesPkg: AcpiSsdtPcieLibArm: Allow use of segment number as UID
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiSsdtPcieLibArm / SsdtPcieGenerator.c
index 3e22587d4a2544fec36ee7e219360c68761d1d63..85098752c614f6556ee768fd79a11ea316c0b5d4 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   SSDT Pcie Table Generator.\r
 \r
-  Copyright (c) 2021, Arm Limited. All rights reserved.<BR>\r
+  Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR>\r
 \r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
@@ -12,6 +12,7 @@
    - s6.1.1 "_ADR (Address)"\r
   - linux kernel code\r
   - Arm Base Boot Requirements v1.0\r
+  - Arm Base System Architecture v1.0\r
 **/\r
 \r
 #include <Library/AcpiLib.h>\r
 #include <Library/AcpiHelperLib.h>\r
 #include <Library/TableHelperLib.h>\r
 #include <Library/AmlLib/AmlLib.h>\r
+#include <Library/SsdtPcieSupportLib.h>\r
 #include <Protocol/ConfigurationManagerProtocol.h>\r
 \r
 #include "SsdtPcieGenerator.h"\r
 \r
+#define PCI_MAX_DEVICE_COUNT_PER_BUS       32\r
+#define PCI_MAX_FUNCTION_COUNT_PER_DEVICE  8\r
+\r
 /** ARM standard SSDT Pcie Table Generator.\r
 \r
 Requirements:\r
@@ -279,251 +284,6 @@ GeneratePciDeviceInfo (
   return Status;\r
 }\r
 \r
-/** Generate a Link device.\r
-\r
-  The Link device is added at the beginning of the ASL Pci device definition.\r
-\r
-  Each Link device represents a Pci legacy interrupt (INTA-...-INTD).\r
-\r
-  ASL code:\r
-  Device (<Link Name>) {\r
-    Name (_UID, <Uid>])\r
-    Name (_HID, EISAID ("PNP0C0F"))\r
-    Name (CRS0, ResourceTemplate () {\r
-      Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { <Irq>] }\r
-      })\r
-    Method (_CRS, 0) {\r
-      Return CRS0\r
-      })\r
-    Method (_DIS) { }\r
-  }\r
-\r
-  The list of objects to define is available at:\r
-  PCI Firmware Specification - Revision 3.3,\r
-  s3.5. "Device State at Firmware/Operating System Handoff"\r
-\r
-  The _PRS and _SRS are not supported, cf Arm Base Boot Requirements v1.0:\r
-  "The _PRS (Possible Resource Settings) and _SRS (Set Resource Settings)\r
-  are not supported."\r
-\r
-  @param [in]       Irq         Interrupt controller interrupt.\r
-  @param [in]       IrqFlags    Interrupt flags.\r
-  @param [in]       LinkIndex   Legacy Pci interrupt index.\r
-                                Must be between 0-INTA and 3-INTD.\r
-  @param [in, out]  PciNode     Pci node to amend.\r
-\r
-  @retval EFI_SUCCESS            Success.\r
-  @retval EFI_INVALID_PARAMETER  Invalid parameter.\r
-  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-GenerateLinkDevice (\r
-  IN      UINT32                  Irq,\r
-  IN      UINT32                  IrqFlags,\r
-  IN      UINT32                  LinkIndex,\r
-  IN  OUT AML_OBJECT_NODE_HANDLE  PciNode\r
-  )\r
-{\r
-  EFI_STATUS              Status;\r
-  CHAR8                   AslName[AML_NAME_SEG_SIZE + 1];\r
-  AML_OBJECT_NODE_HANDLE  LinkNode;\r
-  AML_OBJECT_NODE_HANDLE  CrsNode;\r
-  UINT32                  EisaId;\r
-\r
-  ASSERT (LinkIndex < 4);\r
-  ASSERT (PciNode != NULL);\r
-\r
-  CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1);\r
-  AslName[AML_NAME_SEG_SIZE - 1] = 'A' + LinkIndex;\r
-\r
-  // ASL: Device (LNKx) {}\r
-  Status = AmlCodeGenDevice (AslName, NULL, &LinkNode);\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
-  Status = AmlAttachNode (PciNode, LinkNode);\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    // Failed to add.\r
-    AmlDeleteTree ((AML_NODE_HANDLE)LinkNode);\r
-    return Status;\r
-  }\r
-\r
-  // ASL: Name (_UID, <Uid>)\r
-  Status = AmlCodeGenNameInteger ("_UID", LinkIndex, LinkNode, NULL);\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
-  // ASL: Name (_HID, EISAID ("PNP0C0F"))\r
-  Status = AmlGetEisaIdFromString ("PNP0C0F", &EisaId);\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
-  Status = AmlCodeGenNameInteger ("_HID", EisaId, LinkNode, NULL);\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
-  // ASL:\r
-  // Name (CRS0, ResourceTemplate () {\r
-  //   Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { <Irq> }\r
-  // })\r
-  Status = AmlCodeGenNameResourceTemplate ("CRS0", LinkNode, &CrsNode);\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
-  Status = AmlCodeGenRdInterrupt (\r
-             FALSE,\r
-             (IrqFlags & BIT0) != 0,\r
-             (IrqFlags & BIT1) != 0,\r
-             FALSE,\r
-             &Irq,\r
-             1,\r
-             CrsNode,\r
-             NULL\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
-  // ASL:\r
-  // Method (_CRS, 0) {\r
-  //   Return (CRS0)\r
-  // }\r
-  Status = AmlCodeGenMethodRetNameString (\r
-             "_CRS",\r
-             "CRS0",\r
-             0,\r
-             FALSE,\r
-             0,\r
-             LinkNode,\r
-             NULL\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
-  // ASL:Method (_DIS, 1) {}\r
-  // Not possible to disable interrupts.\r
-  Status = AmlCodeGenMethodRetNameString (\r
-             "_DIS",\r
-             NULL,\r
-             0,\r
-             FALSE,\r
-             0,\r
-             LinkNode,\r
-             NULL\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
-  // _STA:\r
-  // ACPI 6.4, s6.3.7 "_STA (Device Status)":\r
-  // If a device object describes a device that is not on an enumerable bus\r
-  // and the device object does not have an _STA object, then OSPM assumes\r
-  // that the device is present, enabled, shown in the UI, and functioning.\r
-\r
-  // _MAT:\r
-  // Not supported. Mainly used for processors.\r
-\r
-  return Status;\r
-}\r
-\r
-/** Generate Pci slots devices.\r
-\r
-  PCI Firmware Specification - Revision 3.3,\r
-  s4.8 "Generic ACPI PCI Slot Description" requests to describe the PCI slot\r
-  used. It should be possible to enumerate them, but this is additional\r
-  information.\r
-\r
-  @param [in]  MappingTable  The mapping table structure.\r
-  @param [in, out]  PciNode     Pci node to amend.\r
-\r
-  @retval EFI_SUCCESS            Success.\r
-  @retval EFI_INVALID_PARAMETER  Invalid parameter.\r
-  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-GeneratePciSlots (\r
-  IN      CONST MAPPING_TABLE           *MappingTable,\r
-  IN  OUT       AML_OBJECT_NODE_HANDLE  PciNode\r
-  )\r
-{\r
-  EFI_STATUS              Status;\r
-  UINT32                  Index;\r
-  UINT32                  LastIndex;\r
-  UINT32                  DeviceId;\r
-  CHAR8                   AslName[AML_NAME_SEG_SIZE + 1];\r
-  AML_OBJECT_NODE_HANDLE  DeviceNode;\r
-\r
-  ASSERT (MappingTable != NULL);\r
-  ASSERT (PciNode != NULL);\r
-\r
-  // Generic device name is "Dxx".\r
-  CopyMem (AslName, "Dxx_", AML_NAME_SEG_SIZE + 1);\r
-\r
-  LastIndex = MappingTable->LastIndex;\r
-\r
-  // There are at most 32 devices on a Pci bus.\r
-  if (LastIndex >= 32) {\r
-    ASSERT (0);\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  for (Index = 0; Index < LastIndex; Index++) {\r
-    DeviceId                       = MappingTable->Table[Index];\r
-    AslName[AML_NAME_SEG_SIZE - 3] = AsciiFromHex (DeviceId & 0xF);\r
-    AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((DeviceId >> 4) & 0xF);\r
-\r
-    // ASL:\r
-    // Device (Dxx) {\r
-    //   Name (_ADR, <address value>)\r
-    // }\r
-    Status = AmlCodeGenDevice (AslName, PciNode, &DeviceNode);\r
-    if (EFI_ERROR (Status)) {\r
-      ASSERT (0);\r
-      return Status;\r
-    }\r
-\r
-    /* ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"\r
-       High word-Device #, Low word-Function #. (for example, device 3,\r
-       function 2 is 0x00030002). To refer to all the functions on a device #,\r
-       use a function number of FFFF).\r
-    */\r
-    Status = AmlCodeGenNameInteger (\r
-               "_ADR",\r
-               (DeviceId << 16) | 0xFFFF,\r
-               DeviceNode,\r
-               NULL\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      ASSERT (0);\r
-      return Status;\r
-    }\r
-\r
-    // _SUN object is not generated as we don't know which slot will be used.\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
 /** Generate a _PRT object (Pci Routing Table) for the Pci device.\r
 \r
   Cf. ACPI 6.4 specification, s6.2.13 "_PRT (PCI Routing Table)"\r
@@ -538,6 +298,7 @@ GeneratePciSlots (
   @param [in]       CfgMgrProtocol  Pointer to the Configuration Manager\r
                                     Protocol interface.\r
   @param [in]       PciInfo         Pci device information.\r
+  @param [in]       Uid             Unique Id of the Pci device.\r
   @param [in, out]  PciNode         Pci node to amend.\r
 \r
   @retval EFI_SUCCESS             The function completed successfully.\r
@@ -551,19 +312,16 @@ GeneratePrt (
   IN            ACPI_PCI_GENERATOR                            *Generator,\r
   IN      CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  *CONST  CfgMgrProtocol,\r
   IN      CONST CM_ARM_PCI_CONFIG_SPACE_INFO                  *PciInfo,\r
+  IN            UINT32                                        Uid,\r
   IN  OUT       AML_OBJECT_NODE_HANDLE                        PciNode\r
   )\r
 {\r
   EFI_STATUS                     Status;\r
   INT32                          Index;\r
-  UINT32                         IrqTableIndex;\r
   AML_OBJECT_NODE_HANDLE         PrtNode;\r
-  CHAR8                          AslName[AML_NAME_SEG_SIZE + 1];\r
   CM_ARM_OBJ_REF                 *RefInfo;\r
   UINT32                         RefCount;\r
   CM_ARM_PCI_INTERRUPT_MAP_INFO  *IrqMapInfo;\r
-  UINT32                         IrqFlags;\r
-  UINT32                         PrevIrqFlags;\r
 \r
   ASSERT (Generator != NULL);\r
   ASSERT (CfgMgrProtocol != NULL);\r
@@ -585,13 +343,6 @@ GeneratePrt (
     return Status;\r
   }\r
 \r
-  // Initialized IrqTable.\r
-  Status = MappingTableInitialize (&Generator->IrqTable, RefCount);\r
-  if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
-    return Status;\r
-  }\r
-\r
   // Initialized DeviceTable.\r
   Status = MappingTableInitialize (&Generator->DeviceTable, RefCount);\r
   if (EFI_ERROR (Status)) {\r
@@ -606,8 +357,6 @@ GeneratePrt (
     goto exit_handler;\r
   }\r
 \r
-  CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1);\r
-\r
   for (Index = 0; Index < RefCount; Index++) {\r
     // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.\r
     Status = GetEArmObjPciInterruptMapInfo (\r
@@ -621,25 +370,15 @@ GeneratePrt (
       goto exit_handler;\r
     }\r
 \r
-    // Add the interrupt in the IrqTable and get the link name.\r
-    IrqTableIndex = MappingTableAdd (\r
-                      &Generator->IrqTable,\r
-                      IrqMapInfo->IntcInterrupt.Interrupt\r
-                      );\r
-    if (IrqTableIndex >= MAX_PCI_LEGACY_INTERRUPT) {\r
-      ASSERT (0);\r
-      Status = EFI_INVALID_PARAMETER;\r
-      goto exit_handler;\r
-    }\r
-\r
-    AslName[AML_NAME_SEG_SIZE - 1] = 'A' + IrqTableIndex;\r
-\r
-    // Check that the interrupts flags are identical for all interrupts.\r
-    PrevIrqFlags = IrqFlags;\r
-    IrqFlags     = IrqMapInfo->IntcInterrupt.Flags;\r
-    if ((Index > 0) && (PrevIrqFlags != IrqFlags)) {\r
-      ASSERT (0);\r
+    // Check that the interrupts flags are SPIs, level high.\r
+    // Cf. Arm BSA v1.0, sE.6 "Legacy interrupts"\r
+    if ((Index > 0)   &&\r
+        (IrqMapInfo->IntcInterrupt.Interrupt >= 32)   &&\r
+        (IrqMapInfo->IntcInterrupt.Interrupt < 1020)  &&\r
+        ((IrqMapInfo->IntcInterrupt.Flags & 0xB) != 0))\r
+    {\r
       Status = EFI_INVALID_PARAMETER;\r
+      ASSERT_EFI_ERROR (Status);\r
       goto exit_handler;\r
     }\r
 \r
@@ -662,8 +401,8 @@ GeneratePrt (
     Status = AmlAddPrtEntry (\r
                (IrqMapInfo->PciDevice << 16) | 0xFFFF,\r
                IrqMapInfo->PciInterrupt,\r
-               AslName,\r
-               0,\r
+               NULL,\r
+               IrqMapInfo->IntcInterrupt.Interrupt,\r
                PrtNode\r
                );\r
     if (EFI_ERROR (Status)) {\r
@@ -672,31 +411,17 @@ GeneratePrt (
     }\r
   } // for\r
 \r
-  // Generate the LNKx devices now that we know all the interrupts used.\r
-  for (Index = 0; Index < Generator->IrqTable.LastIndex; Index++) {\r
-    Status = GenerateLinkDevice (\r
-               Generator->IrqTable.Table[Index],\r
-               IrqFlags,\r
-               Index,\r
-               PciNode\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      ASSERT (0);\r
-      goto exit_handler;\r
-    }\r
-  } // for\r
-\r
-  // Attach the _PRT entry now, after the LNKx devices.\r
+  // Attach the _PRT entry.\r
   Status = AmlAttachNode (PciNode, PrtNode);\r
   if (EFI_ERROR (Status)) {\r
-    ASSERT (0);\r
+    ASSERT_EFI_ERROR (Status);\r
     goto exit_handler;\r
   }\r
 \r
   PrtNode = NULL;\r
 \r
   // Generate the Pci slots once all the device have been added.\r
-  Status = GeneratePciSlots (&Generator->DeviceTable, PciNode);\r
+  Status = GeneratePciSlots (PciInfo, &Generator->DeviceTable, Uid, PciNode);\r
   if (EFI_ERROR (Status)) {\r
     ASSERT (0);\r
     goto exit_handler;\r
@@ -705,7 +430,6 @@ GeneratePrt (
 exit_handler:\r
   MappingTableFree (&Generator->DeviceTable);\r
 exit_handler0:\r
-  MappingTableFree (&Generator->IrqTable);\r
   if (PrtNode != NULL) {\r
     AmlDeleteTree (PrtNode);\r
   }\r
@@ -742,6 +466,7 @@ GeneratePciCrs (
   UINT32                       RefCount;\r
   CM_ARM_PCI_ADDRESS_MAP_INFO  *AddrMapInfo;\r
   AML_OBJECT_NODE_HANDLE       CrsNode;\r
+  BOOLEAN                      IsPosDecode;\r
 \r
   ASSERT (Generator != NULL);\r
   ASSERT (CfgMgrProtocol != NULL);\r
@@ -811,6 +536,11 @@ GeneratePciCrs (
     }\r
 \r
     Translation = (AddrMapInfo->CpuAddress != AddrMapInfo->PciAddress);\r
+    if (AddrMapInfo->CpuAddress >= AddrMapInfo->PciAddress) {\r
+      IsPosDecode = TRUE;\r
+    } else {\r
+      IsPosDecode = FALSE;\r
+    }\r
 \r
     switch (AddrMapInfo->SpaceCode) {\r
       case PCI_SS_IO:\r
@@ -818,12 +548,12 @@ GeneratePciCrs (
                    FALSE,\r
                    TRUE,\r
                    TRUE,\r
-                   TRUE,\r
+                   IsPosDecode,\r
                    3,\r
                    0,\r
                    AddrMapInfo->PciAddress,\r
                    AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,\r
-                   Translation ? AddrMapInfo->CpuAddress : 0,\r
+                   Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,\r
                    AddrMapInfo->AddressSize,\r
                    0,\r
                    NULL,\r
@@ -837,7 +567,7 @@ GeneratePciCrs (
       case PCI_SS_M32:\r
         Status = AmlCodeGenRdDWordMemory (\r
                    FALSE,\r
-                   TRUE,\r
+                   IsPosDecode,\r
                    TRUE,\r
                    TRUE,\r
                    TRUE,\r
@@ -845,7 +575,7 @@ GeneratePciCrs (
                    0,\r
                    AddrMapInfo->PciAddress,\r
                    AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,\r
-                   Translation ? AddrMapInfo->CpuAddress : 0,\r
+                   Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,\r
                    AddrMapInfo->AddressSize,\r
                    0,\r
                    NULL,\r
@@ -859,7 +589,7 @@ GeneratePciCrs (
       case PCI_SS_M64:\r
         Status = AmlCodeGenRdQWordMemory (\r
                    FALSE,\r
-                   TRUE,\r
+                   IsPosDecode,\r
                    TRUE,\r
                    TRUE,\r
                    TRUE,\r
@@ -867,7 +597,7 @@ GeneratePciCrs (
                    0,\r
                    AddrMapInfo->PciAddress,\r
                    AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,\r
-                   Translation ? AddrMapInfo->CpuAddress : 0,\r
+                   Translation ? AddrMapInfo->CpuAddress - AddrMapInfo->PciAddress : 0,\r
                    AddrMapInfo->AddressSize,\r
                    0,\r
                    NULL,\r
@@ -891,84 +621,125 @@ GeneratePciCrs (
   return Status;\r
 }\r
 \r
-/** Add an _OSC template method to the PciNode.\r
-\r
-  The _OSC method is provided as an AML blob. The blob is\r
-  parsed and attached at the end of the PciNode list of variable elements.\r
+/** Generate a RES0 device node to reserve PNP motherboard resources\r
+  for a given PCI node.\r
 \r
-  @param [in, out]  PciNode     Pci node to amend.\r
+  @param [in]   PciNode       Parent PCI node handle of the generated\r
+                              resource object.\r
+  @param [out]  CrsNode       CRS node of the AML tree to populate.\r
 \r
   @retval EFI_SUCCESS             The function completed successfully.\r
-  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+  @retval EFI_INVALID_PARAMETER   Invalid input parameter.\r
   @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.\r
 **/\r
 STATIC\r
 EFI_STATUS\r
 EFIAPI\r
-AddOscMethod (\r
-  IN  OUT   AML_OBJECT_NODE_HANDLE  PciNode\r
+GenerateMotherboardDevice (\r
+  IN  AML_OBJECT_NODE_HANDLE  PciNode,\r
+  OUT AML_OBJECT_NODE_HANDLE  *CrsNode\r
   )\r
 {\r
-  EFI_STATUS                   Status;\r
-  EFI_STATUS                   Status1;\r
-  EFI_ACPI_DESCRIPTION_HEADER  *SsdtPcieOscTemplate;\r
-  AML_ROOT_NODE_HANDLE         OscTemplateRoot;\r
-  AML_OBJECT_NODE_HANDLE       OscNode;\r
+  EFI_STATUS              Status;\r
+  UINT32                  EisaId;\r
+  AML_OBJECT_NODE_HANDLE  ResNode;\r
 \r
-  ASSERT (PciNode != NULL);\r
+  if (CrsNode == NULL) {\r
+    ASSERT (0);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
-  // Parse the Ssdt Pci Osc Template.\r
-  SsdtPcieOscTemplate = (EFI_ACPI_DESCRIPTION_HEADER *)\r
-                        ssdtpcieosctemplate_aml_code;\r
+  // ASL: Device (RES0) {}\r
+  Status = AmlCodeGenDevice ("RES0", PciNode, &ResNode);\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (0);\r
+    return Status;\r
+  }\r
 \r
-  OscNode         = NULL;\r
-  OscTemplateRoot = NULL;\r
-  Status          = AmlParseDefinitionBlock (\r
-                      SsdtPcieOscTemplate,\r
-                      &OscTemplateRoot\r
-                      );\r
+  // ASL: Name (_HID, EISAID ("PNP0C02"))\r
+  Status = AmlGetEisaIdFromString ("PNP0C02", &EisaId); /* PNP Motherboard Resources */\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((\r
-      DEBUG_ERROR,\r
-      "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template."\r
-      " Status = %r\n",\r
-      Status\r
-      ));\r
+    ASSERT (0);\r
     return Status;\r
   }\r
 \r
-  Status = AmlFindNode (OscTemplateRoot, "\\_OSC", &OscNode);\r
+  Status = AmlCodeGenNameInteger ("_HID", EisaId, ResNode, NULL);\r
   if (EFI_ERROR (Status)) {\r
-    goto error_handler;\r
+    ASSERT (0);\r
+    return Status;\r
   }\r
 \r
-  Status = AmlDetachNode (OscNode);\r
+  // ASL: Name (_CRS, ResourceTemplate () {})\r
+  Status = AmlCodeGenNameResourceTemplate ("_CRS", ResNode, CrsNode);\r
   if (EFI_ERROR (Status)) {\r
-    goto error_handler;\r
+    ASSERT (0);\r
+    return Status;\r
   }\r
 \r
-  Status = AmlAttachNode (PciNode, OscNode);\r
+  return Status;\r
+}\r
+\r
+/** Reserves ECAM space for PCI config space\r
+\r
+  @param [in]       Generator       The SSDT Pci generator.\r
+  @param [in]       CfgMgrProtocol  Pointer to the Configuration Manager\r
+                                    Protocol interface.\r
+  @param [in]       PciInfo         Pci device information.\r
+  @param [in, out]  PciNode         RootNode of the AML tree to populate.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.\r
+  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ReserveEcamSpace (\r
+  IN            ACPI_PCI_GENERATOR                            *Generator,\r
+  IN      CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  *CONST  CfgMgrProtocol,\r
+  IN      CONST CM_ARM_PCI_CONFIG_SPACE_INFO                  *PciInfo,\r
+  IN  OUT       AML_OBJECT_NODE_HANDLE                        PciNode\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  AML_OBJECT_NODE_HANDLE  CrsNode;\r
+  UINT64                  AddressMinimum;\r
+  UINT64                  AddressMaximum;\r
+\r
+  Status = GenerateMotherboardDevice (PciNode, &CrsNode);\r
   if (EFI_ERROR (Status)) {\r
-    // Free the detached node.\r
-    AmlDeleteTree (OscNode);\r
-    goto error_handler;\r
+    ASSERT (0);\r
+    return Status;\r
   }\r
 \r
-error_handler:\r
-  // Cleanup\r
-  Status1 = AmlDeleteTree (OscTemplateRoot);\r
-  if (EFI_ERROR (Status1)) {\r
-    DEBUG ((\r
-      DEBUG_ERROR,\r
-      "ERROR: SSDT-PCI-OSC: Failed to cleanup AML tree."\r
-      " Status = %r\n",\r
-      Status1\r
-      ));\r
-    // If Status was success but we failed to delete the AML Tree\r
-    // return Status1 else return the original error code, i.e. Status.\r
-    if (!EFI_ERROR (Status)) {\r
-      return Status1;\r
-    }\r
+  AddressMinimum = PciInfo->BaseAddress + (PciInfo->StartBusNumber *\r
+                                           PCI_MAX_DEVICE_COUNT_PER_BUS * PCI_MAX_FUNCTION_COUNT_PER_DEVICE * SIZE_4KB);\r
+  AddressMaximum = PciInfo->BaseAddress + ((PciInfo->EndBusNumber + 1) *\r
+                                           PCI_MAX_DEVICE_COUNT_PER_BUS * PCI_MAX_FUNCTION_COUNT_PER_DEVICE * SIZE_4KB) - 1;\r
+\r
+  Status = AmlCodeGenRdQWordMemory (\r
+             FALSE,\r
+             TRUE,\r
+             TRUE,\r
+             TRUE,\r
+             FALSE,  // non-cacheable\r
+             TRUE,\r
+             0,\r
+             AddressMinimum,\r
+             AddressMaximum,\r
+             0,  // no translation\r
+             AddressMaximum - AddressMinimum + 1,\r
+             0,\r
+             NULL,\r
+             0,\r
+             TRUE,\r
+             CrsNode,\r
+             NULL\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (0);\r
+    return Status;\r
   }\r
 \r
   return Status;\r
@@ -1020,7 +791,10 @@ GeneratePciDevice (
 \r
   // Write the name of the PCI device.\r
   CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1);\r
-  AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (Uid);\r
+  AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (Uid & 0xF);\r
+  if (Uid > 0xF) {\r
+    AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((Uid >> 4) & 0xF);\r
+  }\r
 \r
   // ASL: Device (PCIx) {}\r
   Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode);\r
@@ -1042,6 +816,7 @@ GeneratePciDevice (
                Generator,\r
                CfgMgrProtocol,\r
                PciInfo,\r
+               Uid,\r
                PciNode\r
                );\r
     if (EFI_ERROR (Status)) {\r
@@ -1057,9 +832,17 @@ GeneratePciDevice (
     return Status;\r
   }\r
 \r
+  // Add the PNP Motherboard Resources Device to reserve ECAM space\r
+  Status = ReserveEcamSpace (Generator, CfgMgrProtocol, PciInfo, PciNode);\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (0);\r
+    return Status;\r
+  }\r
+\r
   // Add the template _OSC method.\r
-  Status = AddOscMethod (PciNode);\r
+  Status = AddOscMethod (PciInfo, PciNode);\r
   ASSERT_EFI_ERROR (Status);\r
+\r
   return Status;\r
 }\r
 \r
@@ -1198,6 +981,7 @@ BuildSsdtPciTableEx (
   UINTN                         Index;\r
   EFI_ACPI_DESCRIPTION_HEADER   **TableList;\r
   ACPI_PCI_GENERATOR            *Generator;\r
+  UINT32                        Uid;\r
 \r
   ASSERT (This != NULL);\r
   ASSERT (AcpiTableInfo != NULL);\r
@@ -1253,13 +1037,29 @@ BuildSsdtPciTableEx (
   *Table = TableList;\r
 \r
   for (Index = 0; Index < PciCount; Index++) {\r
+    if (PcdGetBool (PcdPciUseSegmentAsUid)) {\r
+      Uid = PciInfo[Index].PciSegmentGroupNumber;\r
+      if (Uid > MAX_PCI_ROOT_COMPLEXES_SUPPORTED) {\r
+        DEBUG ((\r
+          DEBUG_ERROR,\r
+          "ERROR: SSDT-PCI: Pci root complexes segment number: %d."\r
+          " Greater than maximum number of Pci root complexes supported = %d.\n",\r
+          Uid,\r
+          MAX_PCI_ROOT_COMPLEXES_SUPPORTED\r
+          ));\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    } else {\r
+      Uid = Index;\r
+    }\r
+\r
     // Build a SSDT table describing the Pci devices.\r
     Status = BuildSsdtPciTable (\r
                Generator,\r
                CfgMgrProtocol,\r
                AcpiTableInfo,\r
                &PciInfo[Index],\r
-               Index,\r
+               Uid,\r
                &TableList[Index]\r
                );\r
     if (EFI_ERROR (Status)) {\r
@@ -1382,15 +1182,6 @@ ACPI_PCI_GENERATOR  SsdtPcieGenerator = {
 \r
   // Private fields are defined from here.\r
 \r
-  // IrqTable\r
-  {\r
-    // Table\r
-    NULL,\r
-    // LastIndex\r
-    0,\r
-    // MaxIndex\r
-    0\r
-  },\r
   // DeviceTable\r
   {\r
     // Table\r