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

Nhi Pham via groups.io nhi=os.amperecomputing.com at groups.io
Wed Nov 17 16:47:15 UTC 2021


From: Vu Nguyen <vunguyen at 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 at os.amperecomputing.com>
Cc: Chuong Tran <chuong at os.amperecomputing.com>
Cc: Phong Vo <phong at os.amperecomputing.com>
Cc: Leif Lindholm <leif at nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney at intel.com>
Cc: Ard Biesheuvel <ardb+tianocore at kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone at intel.com>

Signed-off-by: Nhi Pham <nhi at os.amperecomputing.com>
Acked-by: Leif Lindholm <leif at 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



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#83831): https://edk2.groups.io/g/devel/message/83831
Mute This Topic: https://groups.io/mt/87123897/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list