[edk2-platforms][PATCH v5 18/30] JadePkg: Add ACPI tables to support PCIe


Nhi Pham
 

From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Add IORT and MCFG tables to let the OS discover the PCIe resources. This
driver also fixup the DSDT table to adapt with the difference between 1P
and 2P system.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com>
Acked-by: Leif Lindholm <leif@nuviainc.com>
---
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf | 4 +
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatform.h | 12 +
Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h | 60 ++++
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiDsdt.c | 90 +++++
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiIort.c | 349 ++++++++++++++++++++
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiMcfg.c | 151 +++++++++
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c | 10 +
7 files changed, 676 insertions(+)

diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
index 72e78fb4e31e..415f795d2a54 100644
--- a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -18,7 +18,9 @@ [Sources.common]
AcpiApei.c
AcpiApei.h
AcpiDsdt.c
+ AcpiIort.c
AcpiMadt.c
+ AcpiMcfg.c
AcpiNfit.c
AcpiPcct.c
AcpiPlatform.h
@@ -43,6 +45,7 @@ [LibraryClasses]
BaseLib
DebugLib
FlashLib
+ HobLib
MailboxInterfaceLib
SystemFirmwareInterfaceLib
TimerLib
@@ -66,6 +69,7 @@ [Guids]
gEfiAcpiTableGuid
gEfiEventReadyToBootGuid
gPlatformInfoHobGuid
+ gRootComplexInfoHobGuid

[Protocols]
gEfiAcpiTableProtocolGuid ## ALWAYS_CONSUMED
diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatform.h b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatform.h
index b5035067a47b..170aeff24d59 100644
--- a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatform.h
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatform.h
@@ -71,4 +71,16 @@ AcpiInstallSratTable (
VOID
);

+EFI_STATUS
+EFIAPI
+AcpiInstallMcfg (
+ VOID
+ );
+
+EFI_STATUS
+EFIAPI
+AcpiInstallIort (
+ VOID
+ );
+
#endif /* ACPI_PLATFORM_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h b/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h
index 132c0d6d6cac..d45688f88401 100644
--- a/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Platform/Ac01.h
@@ -279,4 +279,64 @@
//
#define AC01_PCIE_MMIO32_SIZE_1P_LIST 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x8000000, 0x10000000, 0x10000000, 0x10000000, 0, 0, 0, 0, 0, 0, 0, 0

+//
+// DSDT RCA2 PCIe MMIO32 Attribute
+//
+#define AC01_PCIE_RCA2_QMEM_LIST 0x0000000000000000, 0x0000000060000000, 0x000000006FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+//
+// DSDT RCA3 PCIe MMIO32 Attribute
+//
+#define AC01_PCIE_RCA3_QMEM_LIST 0x0000000000000000, 0x0000000070000000, 0x000000007FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+//
+// DSDT RCB0 PCIe MMIO32 Attribute
+//
+#define AC01_PCIE_RCB0_QMEM_LIST 0x0000000000000000, 0x0000000001000000, 0x000000000FFFFFFF, 0x0000000000000000, 0x000000000F000000
+
+//
+// DSDT RCB1 PCIe MMIO32 Attribute
+//
+#define AC01_PCIE_RCB1_QMEM_LIST 0x0000000000000000, 0x0000000010000000, 0x000000001FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+//
+// DSDT RCB2 PCIe MMIO32 Attribute
+//
+#define AC01_PCIE_RCB2_QMEM_LIST 0x0000000000000000, 0x0000000020000000, 0x000000002FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+//
+// DSDT RCB3 PCIe MMIO32 Attribute
+//
+#define AC01_PCIE_RCB3_QMEM_LIST 0x0000000000000000, 0x0000000030000000, 0x000000003FFFFFFF, 0x0000000000000000, 0x0000000010000000
+
+//
+// TBU PMU IRQ array
+//
+#define AC01_SMMU_TBU_PMU_IRQS_LIST 224, 230, 236, 242, 160, 170, 180, 190, 544, 550, 556, 562, 480, 490, 500, 510
+
+//
+// TCU PMU IRQ array
+//
+#define AC01_SMMU_TCU_PMU_IRQS_LIST 256, 257, 258, 259, 260, 261, 262, 263, 576, 577, 578, 579, 580, 581, 582, 583
+
+//
+// Max TBU PMU of Root Complex A
+//
+#define AC01_RCA_MAX_TBU_PMU 6
+
+//
+// Max TBU PMU of Root Complex B
+//
+#define AC01_RCB_MAX_TBU_PMU 10
+
+//
+// TBU Base offset of Root Complex A
+//
+#define AC01_RCA_TBU_PMU_OFFSET_LIST 0x40000, 0x60000, 0xA0000, 0xE0000, 0x100000, 0x140000
+
+//
+// TBU Base offset of Root Complex B
+//
+#define AC01_RCB_TBU_PMU_OFFSET_LIST 0x40000, 0x60000, 0xA0000, 0xE0000, 0x120000, 0x160000, 0x180000, 0x1C0000, 0x200000, 0x240000
+
#endif /* PLATFORM_AC01_H_ */
diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiDsdt.c b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiDsdt.c
index 82bfbb90f07f..885ad8fc3511 100644
--- a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiDsdt.c
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiDsdt.c
@@ -6,6 +6,7 @@

**/

+#include <Guid/RootComplexInfoHob.h>
#include <Protocol/PciRootBridgeIo.h>
#include <Library/NVParamLib.h>
#include <NVParamDef.h>
@@ -40,6 +41,24 @@ typedef struct {
OP_REGION_DWORD_DATA RegionBase;
OP_REGION_DWORD_DATA RegionLen;
} AML_OP_REGION;
+
+typedef struct {
+ UINT64 AddressGranularity;
+ UINT64 AddressMin;
+ UINT64 AddressMax;
+ UINT64 AddressTranslation;
+ UINT64 RangeLength;
+} QWORD_MEMORY;
+
+STATIC QWORD_MEMORY mQMemList[] = {
+ { AC01_PCIE_RCA2_QMEM_LIST },
+ { AC01_PCIE_RCA3_QMEM_LIST },
+ { AC01_PCIE_RCB0_QMEM_LIST },
+ { AC01_PCIE_RCB1_QMEM_LIST },
+ { AC01_PCIE_RCB2_QMEM_LIST },
+ { AC01_PCIE_RCB3_QMEM_LIST }
+};
+
#pragma pack()

EFI_STATUS
@@ -543,6 +562,76 @@ AcpiPatchPcieAerFwFirst (
return Status;
}

+VOID
+AcpiPatchPcieMmio32 (
+ EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
+ EFI_ACPI_HANDLE TableHandle
+ )
+{
+ AC01_ROOT_COMPLEX *RootComplexList;
+ CHAR8 *NextDescriptor, *Buffer;
+ CHAR8 NodePath[256];
+ EFI_ACPI_DATA_TYPE DataType;
+ EFI_ACPI_HANDLE ObjectHandle;
+ EFI_STATUS Status;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ UINTN DataSize;
+ UINTN Idx;
+ VOID *Hob;
+
+ Hob = GetFirstGuidHob (&gRootComplexInfoHobGuid);
+ if (Hob == NULL) {
+ return;
+ }
+
+ RootComplexList = (AC01_ROOT_COMPLEX *)GET_GUID_HOB_DATA (Hob);
+
+ for (Idx = 0; Idx < AC01_PCIE_MAX_ROOT_COMPLEX; Idx++) {
+ if (!RootComplexList[Idx].Active) {
+ //
+ // Patch for disabled Root Complex
+ //
+ AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X._STA", Idx);
+ UpdateStatusMethodObject (AcpiSdtProtocol, TableHandle, NodePath, 0x0);
+ continue;
+ }
+
+ if (!IsSlaveSocketActive () && Idx <= SOCKET0_LAST_RC) {
+ //
+ // Patch MMIO32 resource in 1P system
+ //
+ AsciiSPrint (NodePath, sizeof (NodePath), "\\_SB.PCI%X.RBUF", Idx);
+ Status = AcpiSdtProtocol->FindPath (TableHandle, NodePath, &ObjectHandle);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = AcpiSdtProtocol->GetOption (ObjectHandle, 2, &DataType, (VOID *)&Buffer, &DataSize);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (DataType != EFI_ACPI_DATA_TYPE_CHILD) {
+ AcpiSdtProtocol->Close (ObjectHandle);
+ continue;
+ }
+
+ NextDescriptor = Buffer + 5; // Point to first address space descriptor
+ while ((NextDescriptor - Buffer) < DataSize) {
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)NextDescriptor;
+ if (Descriptor->Desc == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR
+ && Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ CopyMem (&Descriptor->AddrSpaceGranularity, &mQMemList[Idx - 2], sizeof (QWORD_MEMORY));
+ break;
+ }
+ NextDescriptor += (Descriptor->Len + sizeof (ACPI_LARGE_RESOURCE_HEADER));
+ }
+
+ AcpiSdtProtocol->Close (ObjectHandle);
+ }
+ }
+}
+
EFI_STATUS
AcpiPatchDsdtTable (
VOID
@@ -593,6 +682,7 @@ AcpiPatchDsdtTable (
AcpiPatchNvdimm (AcpiSdtProtocol, TableHandle);
AcpiPatchPcieNuma (AcpiSdtProtocol, TableHandle);
AcpiPatchPcieAerFwFirst (AcpiSdtProtocol, TableHandle);
+ AcpiPatchPcieMmio32 (AcpiSdtProtocol, TableHandle);

AcpiSdtProtocol->Close (TableHandle);
AcpiUpdateChecksum ((UINT8 *)Table, Table->Length);
diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiIort.c b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiIort.c
new file mode 100644
index 000000000000..b8f8cfa356af
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiIort.c
@@ -0,0 +1,349 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <AcpiHeader.h>
+#include <Guid/RootComplexInfoHob.h>
+#include <IndustryStandard/Acpi30.h>
+#include <IndustryStandard/IoRemappingTable.h>
+#include <Library/AcpiLib.h>
+#include <Library/AmpereCpuLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Platform/Ac01.h>
+#include <Protocol/AcpiTable.h>
+
+#define __AC01_ID_MAPPING(In, Num, Out, Ref, Flags) \
+ { \
+ In, \
+ Num, \
+ Out, \
+ OFFSET_OF (AC01_IO_REMAPPING_STRUCTURE, Ref), \
+ Flags \
+ }
+
+#define TCU_TO_SMMU_OFFSET 0x2000
+#define PAGE1_TO_PMCG_OFFSET 0x10000
+
+STATIC AC01_ROOT_COMPLEX *mRootComplexList;
+
+STATIC UINT32 mTbuPmuIrqArray[] = { AC01_SMMU_TBU_PMU_IRQS_LIST };
+STATIC UINT32 mTcuPmuIrqArray[] = { AC01_SMMU_TCU_PMU_IRQS_LIST };
+STATIC UINT64 mRcaTbuPmuOffset[] = { AC01_RCA_TBU_PMU_OFFSET_LIST };
+STATIC UINT64 mRcbTbuPmuOffset[] = { AC01_RCB_TBU_PMU_OFFSET_LIST };
+
+#pragma pack(1)
+
+typedef struct {
+ EFI_ACPI_6_0_IO_REMAPPING_NODE Node;
+ UINT64 Base;
+ UINT32 Flags;
+ UINT32 Reserved;
+ UINT64 VatosAddress;
+ UINT32 Model;
+ UINT32 Event;
+ UINT32 Pri;
+ UINT32 Gerr;
+ UINT32 Sync;
+ UINT32 ProximityDomain;
+ UINT32 DeviceIdMapping;
+} EFI_ACPI_6_2_IO_REMAPPING_SMMU3_NODE;
+
+typedef struct {
+ EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE Node;
+ UINT32 ItsIdentifier;
+} AC01_ITS_NODE;
+
+typedef struct {
+ EFI_ACPI_6_0_IO_REMAPPING_RC_NODE Node;
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE RcIdMapping;
+} AC01_RC_NODE;
+
+typedef struct {
+ EFI_ACPI_6_2_IO_REMAPPING_SMMU3_NODE Node;
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE InterruptMsiMapping;
+ EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE InterruptMsiMappingSingle;
+} AC01_SMMU_NODE;
+
+typedef struct {
+ EFI_ACPI_6_0_IO_REMAPPING_TABLE Iort;
+ AC01_ITS_NODE ItsNode[2];
+ AC01_RC_NODE RcNode[2];
+ AC01_SMMU_NODE SmmuNode[2];
+} AC01_IO_REMAPPING_STRUCTURE;
+
+#pragma pack()
+
+EFI_ACPI_6_0_IO_REMAPPING_TABLE mIortHeader = {
+ .Header = __ACPI_HEADER (
+ EFI_ACPI_6_0_IO_REMAPPING_TABLE_SIGNATURE,
+ AC01_IO_REMAPPING_STRUCTURE,
+ EFI_ACPI_IO_REMAPPING_TABLE_REVISION
+ ),
+ .NumNodes = 0, // To be filled
+ .NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE),
+ 0
+};
+
+AC01_ITS_NODE mItsNodeTemplate = {
+ .Node = {
+ {
+ EFI_ACPI_IORT_TYPE_ITS_GROUP,
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) + 4,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ },
+ .NumItsIdentifiers = 1,
+ },
+ .ItsIdentifier = 1,
+};
+
+AC01_RC_NODE mRcNodeTemplate = {
+ {
+ {
+ EFI_ACPI_IORT_TYPE_ROOT_COMPLEX,
+ sizeof (AC01_RC_NODE),
+ 0x1,
+ 0x0,
+ 0x1,
+ OFFSET_OF (AC01_RC_NODE, RcIdMapping),
+ },
+ EFI_ACPI_IORT_MEM_ACCESS_PROP_CCA,
+ 0x0,
+ 0x0,
+ EFI_ACPI_IORT_MEM_ACCESS_FLAGS_CPM |
+ EFI_ACPI_IORT_MEM_ACCESS_FLAGS_DACS,
+ EFI_ACPI_IORT_ROOT_COMPLEX_ATS_UNSUPPORTED,
+ .PciSegmentNumber = 0,
+ .MemoryAddressSize = 64,
+ },
+ __AC01_ID_MAPPING (0x0, 0xffff, 0x0, SmmuNode, 0),
+};
+
+AC01_SMMU_NODE mSmmuNodeTemplate = {
+ {
+ {
+ EFI_ACPI_IORT_TYPE_SMMUv3,
+ sizeof (AC01_SMMU_NODE),
+ 0x2, // Revision
+ 0x0,
+ 0x2, // Mapping Count
+ OFFSET_OF (AC01_SMMU_NODE, InterruptMsiMapping),
+ },
+ .Base = 0,
+ EFI_ACPI_IORT_SMMUv3_FLAG_COHAC_OVERRIDE | EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0x0,
+ 0x0,
+ 0, // Proximity domain - need fill in
+ .DeviceIdMapping = 1,
+ },
+ __AC01_ID_MAPPING (0x0, 0xffff, 0, SmmuNode, 0),
+ __AC01_ID_MAPPING (0x0, 0x1, 0, SmmuNode, 1),
+};
+
+EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE mPmcgNodeTemplate = {
+ {
+ EFI_ACPI_IORT_TYPE_PMCG,
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE),
+ 0x1,
+ 0x0,
+ 0x0,
+ 0x0,
+ },
+ 0, // Page 0 Base. Need to be filled
+ 0, // GSIV. Need to be filled
+ 0, // Node reference. Need to be filled
+ 0, // Page 1 Base. Need to be filled
+};
+
+STATIC
+VOID
+ConstructIort (
+ VOID *IortBuffer,
+ UINT32 RcCount,
+ UINT32 SmmuPmuAgentCount,
+ UINT32 HeaderCount,
+ INT32 *EnabledRCs
+ )
+{
+ AC01_ROOT_COMPLEX *RootComplex;
+ UINT32 Idx, Idx1;
+ UINT32 ItsOffset[AC01_PCIE_MAX_ROOT_COMPLEX];
+ UINT32 SmmuNodeOffset[AC01_PCIE_MAX_ROOT_COMPLEX];
+ UINT64 *TbuPmuOffset;
+ UINTN MaxTbuPmu;
+ VOID *IortIter, *SmmuIter, *PmcgIter;
+
+ IortIter = IortBuffer;
+ mIortHeader.Header.Length = HeaderCount;
+ mIortHeader.NumNodes = (3 * RcCount) + SmmuPmuAgentCount,
+ CopyMem (IortIter, &mIortHeader, sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE));
+
+ IortIter += sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
+ for (Idx = 0; Idx < RcCount; Idx++) {
+ ItsOffset[Idx] = IortIter - IortBuffer;
+ mItsNodeTemplate.ItsIdentifier = EnabledRCs[Idx];
+ CopyMem (IortIter, &mItsNodeTemplate, sizeof (AC01_ITS_NODE));
+ IortIter += sizeof (AC01_ITS_NODE);
+ }
+
+ SmmuIter = IortIter + RcCount * sizeof (AC01_RC_NODE);
+ PmcgIter = SmmuIter + RcCount * sizeof (AC01_SMMU_NODE);
+ for (Idx = 0; Idx < RcCount; Idx++) {
+ SmmuNodeOffset[Idx] = SmmuIter - IortBuffer;
+ RootComplex = &mRootComplexList[EnabledRCs[Idx]];
+ mSmmuNodeTemplate.Node.Base = RootComplex->TcuBase;
+ mSmmuNodeTemplate.InterruptMsiMapping.OutputBase = EnabledRCs[Idx] << 16;
+ mSmmuNodeTemplate.InterruptMsiMapping.OutputReference = ItsOffset[Idx];
+ mSmmuNodeTemplate.InterruptMsiMappingSingle.OutputBase = EnabledRCs[Idx] << 16;
+ mSmmuNodeTemplate.InterruptMsiMappingSingle.OutputReference = ItsOffset[Idx];
+ /* All RCs on master be assigned to node 0, while remote RCs will be assigned to first remote node */
+ mSmmuNodeTemplate.Node.ProximityDomain = 0;
+ if ((RootComplex->TcuBase & SLAVE_SOCKET_BASE_ADDRESS_OFFSET) != 0) {
+ // RootComplex on remote socket
+ switch (CpuGetSubNumaMode ()) {
+ case SUBNUMA_MODE_MONOLITHIC:
+ mSmmuNodeTemplate.Node.ProximityDomain += MONOLITIC_NUM_OF_REGION;
+ break;
+ case SUBNUMA_MODE_HEMISPHERE:
+ mSmmuNodeTemplate.Node.ProximityDomain += HEMISPHERE_NUM_OF_REGION;
+ break;
+ case SUBNUMA_MODE_QUADRANT:
+ mSmmuNodeTemplate.Node.ProximityDomain += QUADRANT_NUM_OF_REGION;
+ break;
+ }
+ }
+ CopyMem (SmmuIter, &mSmmuNodeTemplate, sizeof (AC01_SMMU_NODE));
+ SmmuIter += sizeof (AC01_SMMU_NODE);
+
+ if (SmmuPmuAgentCount == 0) {
+ continue;
+ }
+
+ //
+ // Add TBU PMCG nodes
+ //
+ if (RootComplex->Type == RootComplexTypeA) {
+ MaxTbuPmu = AC01_RCA_MAX_TBU_PMU;
+ TbuPmuOffset = mRcaTbuPmuOffset;
+ } else {
+ MaxTbuPmu = AC01_RCB_MAX_TBU_PMU;
+ TbuPmuOffset = mRcbTbuPmuOffset;
+ }
+
+ for (Idx1 = 0; Idx1 < MaxTbuPmu; Idx1++) {
+ mPmcgNodeTemplate.Base = RootComplex->TcuBase + TCU_TO_SMMU_OFFSET + TbuPmuOffset[Idx1];
+ mPmcgNodeTemplate.Page1Base = mPmcgNodeTemplate.Base + PAGE1_TO_PMCG_OFFSET;
+ mPmcgNodeTemplate.NodeReference = SmmuNodeOffset[Idx];
+ mPmcgNodeTemplate.OverflowInterruptGsiv = mTbuPmuIrqArray[EnabledRCs[Idx]] + Idx1;
+ CopyMem (PmcgIter, &mPmcgNodeTemplate, sizeof (mPmcgNodeTemplate));
+ PmcgIter += sizeof (mPmcgNodeTemplate);
+ }
+
+ //
+ // Add TCU PMCG node
+ //
+ mPmcgNodeTemplate.Base = RootComplex->TcuBase + TCU_TO_SMMU_OFFSET;
+ mPmcgNodeTemplate.Page1Base = mPmcgNodeTemplate.Base + PAGE1_TO_PMCG_OFFSET;
+ mPmcgNodeTemplate.NodeReference = SmmuNodeOffset[Idx];
+ mPmcgNodeTemplate.OverflowInterruptGsiv = mTcuPmuIrqArray[EnabledRCs[Idx]];
+ CopyMem (PmcgIter, &mPmcgNodeTemplate, sizeof (mPmcgNodeTemplate));
+ PmcgIter += sizeof (mPmcgNodeTemplate);
+ }
+
+ for (Idx = 0; Idx < RcCount; Idx++) {
+ mRcNodeTemplate.Node.PciSegmentNumber = mRootComplexList[EnabledRCs[Idx]].Logical;
+ mRcNodeTemplate.RcIdMapping.OutputReference = SmmuNodeOffset[Idx];
+ CopyMem (IortIter, &mRcNodeTemplate, sizeof (AC01_RC_NODE));
+ IortIter += sizeof (AC01_RC_NODE);
+ }
+}
+
+EFI_STATUS
+EFIAPI
+AcpiInstallIort (
+ VOID
+ )
+{
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
+ EFI_STATUS Status;
+ INT32 EnabledRCs[AC01_PCIE_MAX_ROOT_COMPLEX];
+ UINT32 RcCount, SmmuPmuAgentCount, TotalCount;
+ UINT8 Idx;
+ UINTN TableKey;
+ VOID *Hob;
+ VOID *IortBuffer;
+
+ Hob = GetFirstGuidHob (&gRootComplexInfoHobGuid);
+ if (Hob == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ mRootComplexList = (AC01_ROOT_COMPLEX *)GET_GUID_HOB_DATA (Hob);
+
+ for (Idx = 0, RcCount = 0; Idx < AC01_PCIE_MAX_ROOT_COMPLEX; Idx++) {
+ if (mRootComplexList[Idx].Active) {
+ EnabledRCs[RcCount++] = Idx;
+ }
+ }
+ EnabledRCs[RcCount] = -1;
+
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiTableProtocolGuid,
+ NULL,
+ (VOID **)&AcpiTableProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "IORT: Unable to locate ACPI table entry\n"));
+ return Status;
+ }
+
+ SmmuPmuAgentCount = 0;
+ for (Idx = 0; Idx < RcCount; Idx++) {
+ if (mRootComplexList[EnabledRCs[Idx]].Type == RootComplexTypeA) {
+ SmmuPmuAgentCount += AC01_RCA_MAX_TBU_PMU;
+ } else {
+ SmmuPmuAgentCount += AC01_RCB_MAX_TBU_PMU;
+ }
+ // Plus 1 TCU
+ SmmuPmuAgentCount += 1;
+ }
+
+ TotalCount = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE) +
+ RcCount * (sizeof (AC01_ITS_NODE) + sizeof (AC01_RC_NODE) + sizeof (AC01_SMMU_NODE)) +
+ SmmuPmuAgentCount * sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
+
+ IortBuffer = AllocateZeroPool (TotalCount);
+ if (IortBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ConstructIort (IortBuffer, RcCount, SmmuPmuAgentCount, TotalCount, EnabledRCs);
+
+ Status = AcpiTableProtocol->InstallAcpiTable (
+ AcpiTableProtocol,
+ IortBuffer,
+ TotalCount,
+ &TableKey
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "IORT: Unable to install IORT table entry\n"));
+ }
+
+ FreePool (IortBuffer);
+ return Status;
+}
diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiMcfg.c b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiMcfg.c
new file mode 100644
index 000000000000..0b04246f06fa
--- /dev/null
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiMcfg.c
@@ -0,0 +1,151 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <AcpiHeader.h>
+#include <Guid/RootComplexInfoHob.h>
+#include <IndustryStandard/Acpi30.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Platform/Ac01.h>
+#include <Protocol/AcpiTable.h>
+
+// Required to be 1 to match the kernel quirk for ECAM
+#define EFI_ACPI_MCFG_OEM_REVISION 1
+
+STATIC AC01_ROOT_COMPLEX *mRootComplexList;
+
+#pragma pack(1)
+
+typedef struct
+{
+ UINT64 BaseAddress;
+ UINT16 SegGroupNum;
+ UINT8 StartBusNum;
+ UINT8 EndBusNum;
+ UINT32 Reserved2;
+} EFI_MCFG_CONFIG_STRUCTURE;
+
+typedef struct
+{
+ EFI_ACPI_DESCRIPTION_HEADER Header;
+ UINT64 Reserved1;
+} EFI_MCFG_TABLE_CONFIG;
+
+#pragma pack()
+
+EFI_MCFG_TABLE_CONFIG mMcfgHeader = {
+ {
+ EFI_ACPI_6_1_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE,
+ 0, // To be filled
+ 1,
+ 0x00, // Checksum will be updated at runtime
+ EFI_ACPI_OEM_ID,
+ EFI_ACPI_OEM_TABLE_ID,
+ EFI_ACPI_MCFG_OEM_REVISION,
+ EFI_ACPI_CREATOR_ID,
+ EFI_ACPI_CREATOR_REVISION
+ },
+ 0x0000000000000000, // Reserved
+};
+
+EFI_MCFG_CONFIG_STRUCTURE mMcfgNodeTemplate = {
+ .BaseAddress = 0,
+ .SegGroupNum = 0,
+ .StartBusNum = 0,
+ .EndBusNum = 255,
+ .Reserved2 = 0,
+};
+
+STATIC
+VOID
+ConstructMcfg (
+ VOID *McfgBuffer,
+ UINT32 McfgCount,
+ INT32 *EnabledRCs
+ )
+{
+ AC01_ROOT_COMPLEX *RootComplex;
+ UINT32 Idx;
+ VOID *Iter = McfgBuffer;
+
+ mMcfgHeader.Header.Length = McfgCount;
+ CopyMem (Iter, &mMcfgHeader, sizeof (EFI_MCFG_TABLE_CONFIG));
+
+ Iter += sizeof (EFI_MCFG_TABLE_CONFIG);
+ for (Idx = 0; EnabledRCs[Idx] != -1; Idx++) {
+ RootComplex = &mRootComplexList[EnabledRCs[Idx]];
+ mMcfgNodeTemplate.BaseAddress = RootComplex->MmcfgBase;
+ mMcfgNodeTemplate.SegGroupNum = RootComplex->Logical;
+ CopyMem (Iter, &mMcfgNodeTemplate, sizeof (EFI_MCFG_CONFIG_STRUCTURE));
+ Iter += sizeof (EFI_MCFG_CONFIG_STRUCTURE);
+ }
+}
+
+EFI_STATUS
+EFIAPI
+AcpiInstallMcfg (
+ VOID
+ )
+{
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
+ EFI_STATUS Status;
+ INT32 EnabledRCs[AC01_PCIE_MAX_ROOT_COMPLEX];
+ UINT32 RcCount, McfgCount;
+ UINT8 Idx;
+ UINTN TableKey;
+ VOID *Hob;
+ VOID *McfgBuffer;
+
+ Hob = GetFirstGuidHob (&gRootComplexInfoHobGuid);
+ if (Hob == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ mRootComplexList = (AC01_ROOT_COMPLEX *)GET_GUID_HOB_DATA (Hob);
+
+ for (Idx = 0, RcCount = 0; Idx < AC01_PCIE_MAX_ROOT_COMPLEX; Idx++) {
+ if (mRootComplexList[Idx].Active) {
+ EnabledRCs[RcCount++] = Idx;
+ }
+ }
+ EnabledRCs[RcCount] = -1;
+
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiTableProtocolGuid,
+ NULL,
+ (VOID **)&AcpiTableProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MCFG: Unable to locate ACPI table entry\n"));
+ return Status;
+ }
+
+ McfgCount = sizeof (EFI_MCFG_TABLE_CONFIG) + sizeof (EFI_MCFG_CONFIG_STRUCTURE) * RcCount;
+ McfgBuffer = AllocateZeroPool (McfgCount);
+ if (McfgBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ConstructMcfg (McfgBuffer, McfgCount, EnabledRCs);
+
+ Status = AcpiTableProtocol->InstallAcpiTable (
+ AcpiTableProtocol,
+ McfgBuffer,
+ McfgCount,
+ &TableKey
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "MCFG: Unable to install MCFG table entry\n"));
+ }
+ FreePool (McfgBuffer);
+ return Status;
+}
diff --git a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c
index c4022eb056e0..117f3872a84a 100644
--- a/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c
+++ b/Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c
@@ -93,6 +93,16 @@ InstallAcpiOnReadyToBoot (
DEBUG ((DEBUG_INFO, "Installed NFIT table\n"));
}

+ Status = AcpiInstallIort ();
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "Installed IORT table\n"));
+ }
+
+ Status = AcpiInstallMcfg ();
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "Installed MCFG table\n"));
+ }
+
Status = AcpiPopulateBert ();
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "Populate BERT record\n"));
--
2.17.1