[edk2-devel] [PATCH v2 2/2] DynamicTablesPkg: Add SSDT CMN-600 Table generator

Sami Mujawar sami.mujawar at arm.com
Fri Sep 25 13:18:22 UTC 2020


From: Pierre Gondois <pierre.gondois at arm.com>

The Generic ACPI for Arm Components 1.0 Platform Design
Document, s2.6.4 "ASL code examples" provides information
to describe an Arm CoreLink CMN-600 Coherent Mesh Network
using an ASL definition block table.

The SSDT CMN-600 Table Generator uses the Configuration
Manager protocol to obtain the following information about
the CMN-600 device on the platform:
 - the PERIPHBASE address location and address range;
 - the ROOTNODEBASE address location;
 - the number of Debug and Trace Controller (DTC)
   and their respective interrupt number;

The CMN-600 mesh is described using the CM_ARM_CMN_600_INFO
and CM_ARM_EXTENDED_INTERRUPT structures in the Configuration
Manager.

The SSDT CMN-600 Table generator:
 - gets the CMN-600 hardware information
   from the configuration manager.
 - uses the AmlLib interfaces to parse the AML
   template BLOB and construct an AML tree.
 - uses the AmlLib to update:
   - the "_UID" value;
   - the address location and range of the PERIPHBASE;
   - the address location of the ROOTNODEBASE;
   - the number of Debug and Trace Controller (DTC)
     and their respective interrupt number;
 - serializes the AML tree to an output buffer.
   This output buffer contains the fixed-up AML code,
   which is then installed as an ACPI SSDT table.

Signed-off-by: Pierre Gondois <pierre.gondois at arm.com>
Co-authored-by: Sami Mujawar <sami.mujawar at arm.com>
---

Notes:
    v2:
      - Updates corresponding to changes done in Acpi10.h based on  [SAMI]
        review comments for [PATCH v1 1/1].

 DynamicTablesPkg/DynamicTables.dsc.inc                                        |   2 +
 DynamicTablesPkg/DynamicTablesPkg.ci.yaml                                     |   4 +
 DynamicTablesPkg/Include/AcpiTableGenerator.h                                 |   5 +
 DynamicTablesPkg/Include/ArmNameSpaceObjects.h                                |  64 +-
 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c  | 708 ++++++++++++++++++++
 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h  |  51 ++
 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf   |  34 +
 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl |  81 +++
 8 files changed, 943 insertions(+), 6 deletions(-)

diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
index 7fb14d8d1463f7d4502fd3a7708bc94bc336357d..fa33b7ee67e615e236cb13224c859594566df19f 100644
--- a/DynamicTablesPkg/DynamicTables.dsc.inc
+++ b/DynamicTablesPkg/DynamicTables.dsc.inc
@@ -34,6 +34,7 @@ [Components.common]
 
   # AML Fixup
   DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf
+  DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
 
   #
   # Dynamic Table Factory Dxe
@@ -53,6 +54,7 @@ [Components.common]
 
       # AML Fixup
       NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf
+      NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
   }
 
   #
diff --git a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
index c0d09e79fdf7f6003b5bbda45abc82a0caf4e53f..52c8c2ab4aefb21bea0289a4fd02209ae937a221 100644
--- a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
+++ b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
@@ -70,6 +70,7 @@
                                      # in matching files
         "ExtendWords": [
            "ARMHB",                  # ARMHB000
+           "ARMHC",                  # ARMHC600
            "ARMLTD",
            "EISAID",
            "CCIDX",
@@ -81,8 +82,11 @@
            "lgreater",
            "lless",
            "MPIDR",
+           "PERIPHBASE",
            "pytool",
            "Roadmap",
+           "ROOTNODEBASE",
+           "ssdtcmn",
            "ssdtserialporttemplate",
            "SMMUV",
            "standardised",
diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h
index ef5018c312c1abbc205a06b037ffd6063cf02f0a..352331d6dc957b664d31d55b50efcce5b90d8ada 100644
--- a/DynamicTablesPkg/Include/AcpiTableGenerator.h
+++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
@@ -59,6 +59,10 @@ The Dynamic Tables Framework implements the following ACPI table generators:
             The SSDT Serial generator collates the Serial port information
             from the Configuration Manager and patches the SSDT Serial Port
             template to build the SSDT Serial port table.
+  - SSDT CMN-600:
+            The SSDT CMN-600 generator collates the CMN-600 information
+            from the Configuration Manager and patches the SSDT CMN-600
+            template to build the SSDT CMN-600 table.
 */
 
 /** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID.
@@ -83,6 +87,7 @@ typedef enum StdAcpiTableId {
   EStdAcpiTableIdPptt,                          ///< PPTT Generator
   EStdAcpiTableIdSrat,                          ///< SRAT Generator
   EStdAcpiTableIdSsdtSerialPort,                ///< SSDT Serial-Port Generator
+  EStdAcpiTableIdSsdtCmn600,                    ///< SSDT Cmn-600 Generator
   EStdAcpiTableIdMax
 } ESTD_ACPI_TABLE_ID;
 
diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
index b2534a6505d6fb695f0751bbb09d365bd93d092e..f0654866444e5497a010f7e7177199604f5d32b6 100644
--- a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
+++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
@@ -57,6 +57,7 @@ typedef enum ArmObjectID {
   EArmObjDeviceHandlePci,              ///< 33 - Device Handle Pci
   EArmObjGenericInitiatorAffinityInfo, ///< 34 - Generic Initiator Affinity
   EArmObjSerialPortInfo,               ///< 35 - Generic Serial Port Info
+  EArmObjCmn600Info,                   ///< 36 - CMN-600 Info
   EArmObjMax
 } EARM_OBJECT_ID;
 
@@ -653,18 +654,37 @@ typedef struct CmArmIdMapping {
   UINT32    Flags;
 } CM_ARM_ID_MAPPING;
 
-/** A structure that describes the
-    SMMU interrupts for the Platform.
-
-    ID: EArmObjSmmuInterruptArray
+/** A structure that describes the Arm
+    Generic Interrupts.
 */
-typedef struct CmArmSmmuInterrupt {
+typedef struct CmArmGenericInterrupt {
   /// Interrupt number
   UINT32    Interrupt;
 
   /// Flags
   UINT32    Flags;
-} CM_ARM_SMMU_INTERRUPT;
+} CM_ARM_GENERIC_INTERRUPT;
+
+/** A structure that describes the SMMU interrupts for the Platform.
+
+    Interrupt   Interrupt number.
+    Flags       Interrupt flags as defined for SMMU node.
+
+    ID: EArmObjSmmuInterruptArray
+*/
+typedef CM_ARM_GENERIC_INTERRUPT CM_ARM_SMMU_INTERRUPT;
+
+/** A structure that describes the AML Extended Interrupts.
+
+    Interrupt   Interrupt number.
+    Flags       Interrupt flags as defined by the Interrupt
+                Vector Flags (Byte 3) of the Extended Interrupt
+                resource descriptor.
+                See EFI_ACPI_EXTENDED_INTERRUPT_FLAG_xxx in Acpi10.h
+
+    ID: EArmObjExtendedInterruptInfo
+*/
+typedef CM_ARM_GENERIC_INTERRUPT CM_ARM_EXTENDED_INTERRUPT;
 
 /** A structure that describes the Processor Hierarchy Node (Type 0) in PPTT
 
@@ -825,6 +845,38 @@ typedef struct CmArmGenericInitiatorAffinityInfo {
   CM_OBJECT_TOKEN   DeviceHandleToken;
 } CM_ARM_GENERIC_INITIATOR_AFFINITY_INFO;
 
+/** A structure that describes the CMN-600 hardware.
+
+    ID: EArmObjCmn600Info
+*/
+typedef struct CmArmCmn600Info {
+  /// The PERIPHBASE address.
+  /// Corresponds to the Configuration Node Region (CFGR) base address.
+  UINT64                     PeriphBaseAddress;
+
+  /// The PERIPHBASE address length.
+  /// Corresponds to the CFGR base address length.
+  UINT64                     PeriphBaseAddressLength;
+
+  /// The ROOTNODEBASE address.
+  /// Corresponds to the Root node (ROOT) base address.
+  UINT64                     RootNodeBaseAddress;
+
+  /// The Debug and Trace Logic Controller (DTC) count.
+  /// CMN-600 can have maximum 4 DTCs.
+  UINT8                      DtcCount;
+
+  /// DTC Interrupt list.
+  /// The first interrupt resource descriptor pertains to
+  /// DTC[0], the second to DTC[1] and so on.
+  /// DtcCount determines the number of DTC Interrupts that
+  /// are populated. If DTC count is 2 then DtcInterrupt[2]
+  /// and DtcInterrupt[3] are ignored.
+  /// Note: The size of CM_ARM_CMN_600_INFO structure remains
+  /// constant and does not vary with the DTC count.
+  CM_ARM_EXTENDED_INTERRUPT  DtcInterrupt[4];
+} CM_ARM_CMN_600_INFO;
+
 #pragma pack()
 
 #endif // ARM_NAMESPACE_OBJECTS_H_
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c
new file mode 100644
index 0000000000000000000000000000000000000000..97a5c55fa3f60b6885862a76223994ab5c3daa26
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c
@@ -0,0 +1,708 @@
+/** @file
+  SSDT CMN-600 AML Table Generator.
+
+  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Reference(s):
+  - Arm CoreLink CMN-600 Coherent Mesh Network Technical Reference Manual r3p0
+  - Generic ACPI for Arm Components 1.0 Platform Design Document
+**/
+
+#include <IndustryStandard/DebugPort2Table.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/AmlLib/AmlLib.h>
+#include <Library/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+#include "SsdtCmn600Generator.h"
+
+/** C array containing the compiled AML template.
+    This symbol is defined in the auto generated C file
+    containing the AML bytecode array.
+*/
+extern CHAR8  ssdtcmn600template_aml_code[];
+
+/** SSDT CMN-600 Table Generator.
+
+  Requirements:
+  The following Configuration Manager Object(s) are required by
+  this Generator:
+  - EArmObjCmn600Info
+*/
+
+/** This macro expands to a function that retrieves the CMN-600
+    Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+  EObjNameSpaceArm,
+  EArmObjCmn600Info,
+  CM_ARM_CMN_600_INFO
+  );
+
+/** Check the CMN-600 Information.
+
+  @param [in]  Cmn600InfoList           Array of CMN-600 information structure.
+  @param [in]  Cmn600Count              Count of CMN-600 information structure.
+
+  @retval  EFI_SUCCESS            The function completed successfully.
+  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ValidateCmn600Info (
+  IN  CONST CM_ARM_CMN_600_INFO       * Cmn600InfoList,
+  IN  CONST UINT32                      Cmn600Count
+  )
+{
+  UINT32                            Index;
+  UINT32                            DtcIndex;
+  CONST CM_ARM_CMN_600_INFO       * Cmn600Info;
+  CONST CM_ARM_GENERIC_INTERRUPT  * DtcInterrupt;
+
+  if ((Cmn600InfoList == NULL) ||
+      (Cmn600Count == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Validate each Cmn600Info structure.
+  for (Index = 0; Index < Cmn600Count; Index++) {
+    Cmn600Info = &Cmn600InfoList[Index];
+
+    // At least one DTC is required.
+    if ((Cmn600Info->DtcCount == 0) ||
+        (Cmn600Info->DtcCount > MAX_DTC_COUNT)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: Invalid DTC configuration:\n"
+        ));
+      goto error_handler;
+    }
+
+    // Check PERIPHBASE and ROOTNODEBASE address spaces are initialized.
+    if ((Cmn600Info->PeriphBaseAddress == 0)    ||
+        (Cmn600Info->RootNodeBaseAddress == 0)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: Invalid PERIPHBASE or ROOTNODEBASE.\n"
+        ));
+      goto error_handler;
+    }
+
+    // The PERIPHBASE address must be 64MB aligned for a (X < 4) && (Y < 4)
+    // dimension mesh, and 256MB aligned otherwise.
+    // Check it is a least 64MB aligned.
+    if ((Cmn600Info->PeriphBaseAddress &
+        (PERIPHBASE_MIN_ADDRESS_LENGTH - 1)) != 0) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: PERIPHBASE address must be 64MB aligned.\n"
+        ));
+      goto error_handler;
+    }
+
+    // The PERIPHBASE address is at most 64MB for a (X < 4) && (Y < 4)
+    // dimension mesh, and 256MB otherwise. Check it is not more than 256MB.
+    if (Cmn600Info->PeriphBaseAddressLength > PERIPHBASE_MAX_ADDRESS_LENGTH) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: PERIPHBASE address range must be < 256MB.\n"
+        ));
+      goto error_handler;
+    }
+
+    // Check the 16 KB alignment of the ROOTNODEBASE address.
+    if ((Cmn600Info->PeriphBaseAddress &
+        (ROOTNODEBASE_ADDRESS_LENGTH - 1)) != 0) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: Root base address must be 16KB aligned.\n"
+        ));
+      goto error_handler;
+    }
+
+    // The ROOTNODEBASE address space should be included in the PERIPHBASE
+    // address space.
+    if ((Cmn600Info->PeriphBaseAddress > Cmn600Info->RootNodeBaseAddress)  ||
+        ((Cmn600Info->PeriphBaseAddress + Cmn600Info->PeriphBaseAddressLength) <
+         (Cmn600Info->RootNodeBaseAddress + ROOTNODEBASE_ADDRESS_LENGTH))) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600:"
+        " ROOTNODEBASE address space not in PERIPHBASE address space.\n"
+        ));
+      goto error_handler;
+    }
+
+    for (DtcIndex = 0; DtcIndex < Cmn600Info->DtcCount; DtcIndex++) {
+      DtcInterrupt = &Cmn600Info->DtcInterrupt[DtcIndex];
+      if (((DtcInterrupt->Flags &
+            EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK) == 0)) {
+        DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: DTC Interrupt must be consumer.\n"
+        ));
+        goto error_handler;
+      }
+    } // for DTC Interrupt
+
+  } //for Cmn600InfoList
+
+  return EFI_SUCCESS;
+
+error_handler:
+
+  DEBUG ((
+    DEBUG_ERROR,
+    "PeriphBaseAddress = 0x%llx\n"
+    "PeriphBaseAddressLength = 0x%llx\n"
+    "RootNodeBaseAddress = 0x%llx\n"
+    "DtcCount = %u\n",
+    Cmn600Info->PeriphBaseAddress,
+    Cmn600Info->PeriphBaseAddressLength,
+    Cmn600Info->RootNodeBaseAddress,
+    Cmn600Info->DtcCount
+    ));
+
+  DEBUG_CODE (
+    for (DtcIndex = 0; DtcIndex < Cmn600Info->DtcCount; DtcIndex++) {
+      DtcInterrupt = &Cmn600Info->DtcInterrupt[DtcIndex];
+      DEBUG ((
+        DEBUG_ERROR,
+        "  DTC[%d]:\n",
+        DtcIndex
+        ));
+      DEBUG ((
+        DEBUG_ERROR,
+        "    Interrupt = 0x%lx\n",
+        DtcInterrupt->Interrupt
+        ));
+      DEBUG ((
+        DEBUG_ERROR,
+        "    Flags = 0x%lx\n",
+        DtcInterrupt->Flags
+        ));
+    } // for
+  );
+
+  return EFI_INVALID_PARAMETER;
+}
+
+/** Build a SSDT table describing the CMN-600 device.
+
+  The table created by this function must be freed by FreeSsdtCmn600Table.
+
+  @param [in]  Cmn600Info       Pointer to a Cmn600 structure.
+  @param [in]  Name             The Name to give to the Device.
+                                Must be a NULL-terminated ASL NameString
+                                e.g.: "DEV0", "DV15.DEV0", etc.
+  @param [in]  Uid              UID for the CMN600 device.
+  @param [out] Table            If success, pointer to the created SSDT table.
+
+  @retval EFI_SUCCESS            Table generated successfully.
+  @retval EFI_INVALID_PARAMETER  A parameter is invalid.
+  @retval EFI_NOT_FOUND          Could not find information.
+  @retval EFI_OUT_OF_RESOURCES   Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupCmn600Info (
+  IN  CONST CM_ARM_CMN_600_INFO           * Cmn600Info,
+  IN  CONST CHAR8                         * Name,
+  IN  CONST UINT64                          Uid,
+  OUT       EFI_ACPI_DESCRIPTION_HEADER  ** Table
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_STATUS                        Status1;
+  UINT8                             Index;
+  CONST CM_ARM_GENERIC_INTERRUPT  * DtcInt;
+
+  EFI_ACPI_DESCRIPTION_HEADER     * SsdtCmn600Template;
+  AML_ROOT_NODE_HANDLE              RootNodeHandle;
+  AML_OBJECT_NODE_HANDLE            NameOpIdNode;
+  AML_OBJECT_NODE_HANDLE            NameOpCrsNode;
+  AML_DATA_NODE_HANDLE              CmnPeriphBaseRdNode;
+  AML_DATA_NODE_HANDLE              CmnRootNodeBaseRdNode;
+  AML_OBJECT_NODE_HANDLE            DeviceNode;
+
+  // Parse the Ssdt CMN-600 Template.
+  SsdtCmn600Template = (EFI_ACPI_DESCRIPTION_HEADER*)
+                          ssdtcmn600template_aml_code;
+
+  RootNodeHandle = NULL;
+  Status = AmlParseDefinitionBlock (
+             SsdtCmn600Template,
+             &RootNodeHandle
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT-CMN-600: Failed to parse SSDT CMN-600 Template."
+      " Status = %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  // Get the _UID NameOp object defined by the "Name ()" statement,
+  // and update its value.
+  Status = AmlFindNode (
+             RootNodeHandle,
+             "\\_SB_.CMN0._UID",
+             &NameOpIdNode
+             );
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  Status = AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  // Get the _CRS object defined by the "Name ()" statement.
+  Status = AmlFindNode (
+             RootNodeHandle,
+             "\\_SB.CMN0._CRS",
+             &NameOpCrsNode
+             );
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  // Get the first Rd node in the "_CRS" object.
+  // This is the PERIPHBASE node.
+  Status = AmlNameOpCrsGetFirstRdNode (NameOpCrsNode, &CmnPeriphBaseRdNode);
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  if (CmnPeriphBaseRdNode == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto error_handler;
+  }
+
+  // Update the PERIPHBASE base address and length.
+  Status = AmlUpdateRdQWord (
+             CmnPeriphBaseRdNode,
+             Cmn600Info->PeriphBaseAddress,
+             Cmn600Info->PeriphBaseAddressLength
+             );
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  // Get the QWord node corresponding to the ROOTNODEBASE.
+  // It is the second Resource Data element in the BufferNode's
+  // variable list of arguments.
+  Status = AmlNameOpCrsGetNextRdNode (
+             CmnPeriphBaseRdNode,
+             &CmnRootNodeBaseRdNode
+             );
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  if (CmnRootNodeBaseRdNode == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto error_handler;
+  }
+
+  // Update the ROOTNODEBASE base address and length.
+  Status = AmlUpdateRdQWord (
+             CmnRootNodeBaseRdNode,
+             Cmn600Info->RootNodeBaseAddress,
+             ROOTNODEBASE_ADDRESS_LENGTH
+             );
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  // Add the Interrupt node(s).
+  // Generate Resource Data node(s) corresponding to the "Interrupt ()"
+  // ASL function and add it at the last position in the list of
+  // Resource Data nodes.
+  for (Index = 0; Index < Cmn600Info->DtcCount; Index++) {
+    DtcInt = &Cmn600Info->DtcInterrupt[Index];
+    Status = AmlCodeGenCrsAddRdInterrupt (
+               NameOpCrsNode,
+               ((DtcInt->Flags &
+                 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK) != 0),
+               ((DtcInt->Flags &
+                 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_MODE_MASK) != 0),
+               ((DtcInt->Flags &
+                 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_POLARITY_MASK) != 0),
+               ((DtcInt->Flags &
+                 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_SHARABLE_MASK) != 0),
+               (UINT32*)&DtcInt->Interrupt,
+               1
+               );
+    if (EFI_ERROR (Status)) {
+      goto error_handler;
+    }
+  } // for
+
+  // Fixup the CMN600 device name.
+  // This MUST be done at the end, otherwise AML paths won't be valid anymore.
+  // Get the CMN0 variable defined by the "Device ()" statement.
+  Status = AmlFindNode (RootNodeHandle, "\\_SB_.CMN0", &DeviceNode);
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  // Update the CMN600 Device's name.
+  Status = AmlDeviceOpUpdateName (DeviceNode, (CHAR8*)Name);
+  if (EFI_ERROR (Status)) {
+    goto error_handler;
+  }
+
+  // Serialise the definition block
+  Status = AmlSerializeDefinitionBlock (
+             RootNodeHandle,
+             Table
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT-CMN-600: Failed to Serialize SSDT Table Data."
+      " Status = %r\n",
+      Status
+      ));
+  }
+
+error_handler:
+  // Cleanup
+  if (RootNodeHandle != NULL) {
+    Status1 = AmlDeleteTree (RootNodeHandle);
+    if (EFI_ERROR (Status1)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: Failed to cleanup AML tree."
+        " Status = %r\n",
+        Status1
+        ));
+      // If Status was success but we failed to delete the AML Tree
+      // return Status1 else return the original error code, i.e. Status.
+      if (!EFI_ERROR (Status)) {
+        return Status1;
+      }
+    }
+  }
+
+  return Status;
+}
+
+/** Free any resources allocated for constructing the SSDT tables for CMN-600.
+
+  @param [in]      This           Pointer to the ACPI table generator.
+  @param [in]      AcpiTableInfo  Pointer to the ACPI Table Info.
+  @param [in]      CfgMgrProtocol Pointer to the Configuration Manager
+                                  Protocol Interface.
+  @param [in, out] Table          Pointer to an array of pointers
+                                  to ACPI Table(s).
+  @param [in]      TableCount     Number of ACPI table(s).
+
+  @retval EFI_SUCCESS           The resources were freed successfully.
+  @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FreeSsdtCmn600TableResourcesEx (
+  IN      CONST ACPI_TABLE_GENERATOR                   * CONST This,
+  IN      CONST CM_STD_OBJ_ACPI_TABLE_INFO             * CONST AcpiTableInfo,
+  IN      CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL   * CONST CfgMgrProtocol,
+  IN OUT        EFI_ACPI_DESCRIPTION_HEADER          *** CONST Table,
+  IN      CONST UINTN                                          TableCount
+  )
+{
+  EFI_ACPI_DESCRIPTION_HEADER    ** TableList;
+  UINTN                             Index;
+
+  ASSERT (This != NULL);
+  ASSERT (AcpiTableInfo != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+  if ((Table == NULL)   ||
+      (*Table == NULL)  ||
+      (TableCount == 0)) {
+    DEBUG ((DEBUG_ERROR, "ERROR: SSDT-CMN-600: Invalid Table Pointer\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  TableList = *Table;
+
+  for (Index = 0; Index < TableCount; Index++) {
+    if ((TableList[Index] != NULL) &&
+        (TableList[Index]->Signature ==
+         EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
+      FreePool (TableList[Index]);
+    } else {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: Could not free SSDT table at index %d."
+        " Status = %r\n",
+        Index,
+        EFI_INVALID_PARAMETER
+        ));
+      return EFI_INVALID_PARAMETER;
+    }
+  } //for
+
+  // Free the table list.
+  FreePool (*Table);
+  *Table = NULL;
+  return EFI_SUCCESS;
+}
+
+/** Construct SSDT tables for describing CMN-600 meshes.
+
+  This function invokes the Configuration Manager protocol interface
+  to get the required hardware information for generating the ACPI
+  table.
+
+  If this function allocates any resources then they must be freed
+  in the FreeXXXXTableResourcesEx function.
+
+  @param [in]  This            Pointer to the ACPI table generator.
+  @param [in]  AcpiTableInfo   Pointer to the ACPI table information.
+  @param [in]  CfgMgrProtocol  Pointer to the Configuration Manager
+                               Protocol interface.
+  @param [out] Table           Pointer to a list of generated ACPI table(s).
+  @param [out] TableCount      Number of generated ACPI table(s).
+
+  @retval EFI_SUCCESS            Table generated successfully.
+  @retval EFI_BAD_BUFFER_SIZE    The size returned by the Configuration
+                                 Manager is less than the Object size for
+                                 the requested object.
+  @retval EFI_INVALID_PARAMETER  A parameter is invalid.
+  @retval EFI_NOT_FOUND          Could not find information.
+  @retval EFI_OUT_OF_RESOURCES   Could not allocate memory.
+  @retval EFI_UNSUPPORTED        Unsupported configuration.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSsdtCmn600TableEx (
+  IN  CONST ACPI_TABLE_GENERATOR                   *       This,
+  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO             * CONST AcpiTableInfo,
+  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL   * CONST CfgMgrProtocol,
+  OUT       EFI_ACPI_DESCRIPTION_HEADER          ***       Table,
+  OUT       UINTN                                  * CONST TableCount
+  )
+{
+  EFI_STATUS                        Status;
+  UINT64                            Index;
+  CM_ARM_CMN_600_INFO             * Cmn600Info;
+  UINT32                            Cmn600Count;
+  CHAR8                             NewName[5];
+  EFI_ACPI_DESCRIPTION_HEADER    ** TableList;
+
+  ASSERT (This != NULL);
+  ASSERT (AcpiTableInfo != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (Table != NULL);
+  ASSERT (TableCount != NULL);
+  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+  *Table = NULL;
+
+  // Get CMN-600 information.
+  Status = GetEArmObjCmn600Info (
+             CfgMgrProtocol,
+             CM_NULL_TOKEN,
+             &Cmn600Info,
+             &Cmn600Count
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT-CMN-600: Failed to get the CMN-600 information."
+      " Status = %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  if ((Cmn600Count == 0) || (Cmn600Count > MAX_CMN600_DEVICES_SUPPORTED)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT-CMN-600: CMN600 peripheral count = %d."
+      " This must be between 1 to 16.\n",
+      Cmn600Count
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Validate the CMN-600 Info.
+  Status = ValidateCmn600Info (Cmn600Info, Cmn600Count);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT-CMN-600: Invalid CMN600 information. Status = %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  // Allocate a table to store pointers to the SSDT tables.
+  TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
+              AllocateZeroPool (
+                (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * Cmn600Count)
+                );
+  if (TableList == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT-CMN-600: Failed to allocate memory for Table List."
+      " Status = %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  // Setup the table list early so that that appropriate cleanup
+  // can be done in case of failure.
+  *Table = TableList;
+
+  NewName[0] = 'C';
+  NewName[1] = 'M';
+  NewName[2] = 'N';
+  NewName[4] = '\0';
+  for (Index = 0; Index < Cmn600Count; Index++) {
+    NewName[3] = AsciiFromHex ((UINT8)(Index));
+
+    // Build a SSDT table describing the CMN600 device.
+    Status = FixupCmn600Info (
+               &Cmn600Info[Index],
+               NewName,
+               Index,
+               &TableList[Index]
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ERROR: SSDT-CMN-600: Failed to build associated SSDT table."
+        " Status = %r\n",
+        Status
+        ));
+      break;
+    }
+
+    // Increment the table count here so that appropriate clean-up
+    // can be done in case of failure.
+    *TableCount += 1;
+  } // for
+
+  // Note: Table list and CMN600 device count has been setup. The
+  // framework will invoke FreeSsdtCmn600TableResourcesEx() even
+  // on failure, so appropriate clean-up will be done.
+  return Status;
+}
+
+/** This macro defines the Raw Generator revision.
+*/
+#define SSDT_CMN_600_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the Raw Table Generator.
+*/
+STATIC
+CONST
+ACPI_TABLE_GENERATOR SsdtCmn600Generator = {
+  // Generator ID
+  CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCmn600),
+  // Generator Description
+  L"ACPI.STD.SSDT.CMN600.GENERATOR",
+  // ACPI Table Signature
+  EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+  // ACPI Table Revision - Unused
+  0,
+  // Minimum ACPI Table Revision - Unused
+  0,
+  // Creator ID
+  TABLE_GENERATOR_CREATOR_ID_ARM,
+  // Creator Revision
+  SSDT_CMN_600_GENERATOR_REVISION,
+  // Build table function. Use the extended version instead.
+  NULL,
+  // Free table function. Use the extended version instead.
+  NULL,
+  // Build Table function
+  BuildSsdtCmn600TableEx,
+  // Free Resource function
+  FreeSsdtCmn600TableResourcesEx
+};
+
+/** Register the Generator with the ACPI Table Factory.
+
+  @param [in]  ImageHandle  The handle to the image.
+  @param [in]  SystemTable  Pointer to the System Table.
+
+  @retval EFI_SUCCESS           The Generator is registered.
+  @retval EFI_INVALID_PARAMETER A parameter is invalid.
+  @retval EFI_ALREADY_STARTED   The Generator for the Table ID
+                                is already registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiSsdtCmn600LibConstructor (
+  IN  EFI_HANDLE           ImageHandle,
+  IN  EFI_SYSTEM_TABLE  *  SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = RegisterAcpiTableGenerator (&SsdtCmn600Generator);
+  DEBUG ((
+    DEBUG_INFO,
+    "SSDT-CMN-600: Register Generator. Status = %r\n",
+    Status
+    ));
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/** Deregister the Generator from the ACPI Table Factory.
+
+  @param [in]  ImageHandle  The handle to the image.
+  @param [in]  SystemTable  Pointer to the System Table.
+
+  @retval EFI_SUCCESS           The Generator is deregistered.
+  @retval EFI_INVALID_PARAMETER A parameter is invalid.
+  @retval EFI_NOT_FOUND         The Generator is not registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiSsdtCmn600LibDestructor (
+  IN  EFI_HANDLE           ImageHandle,
+  IN  EFI_SYSTEM_TABLE  *  SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = DeregisterAcpiTableGenerator (&SsdtCmn600Generator);
+  DEBUG ((
+    DEBUG_INFO,
+    "SSDT-CMN-600: Deregister Generator. Status = %r\n",
+    Status
+    ));
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab03b72236e78c28a5e36452bb5d7e93e957332d
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h
@@ -0,0 +1,51 @@
+/** @file
+
+  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - Cm or CM   - Configuration Manager
+    - Obj or OBJ - Object
+    - Std or STD - Standard
+
+  @par Reference(s):
+  - Arm CoreLink CMN-600 Coherent Mesh Network Technical Reference Manual r3p0
+  - Generic ACPI for Arm Components 1.0 Platform Design Document
+**/
+
+#ifndef SSDT_CMN600_GENERATOR_H_
+#define SSDT_CMN600_GENERATOR_H_
+
+/** PeriphBase maximum address length is 256MB (0x10000000)
+    for a (X >= 4) || (Y >= 4) dimensions mesh.
+*/
+#define PERIPHBASE_MAX_ADDRESS_LENGTH   SIZE_256MB
+
+/** PeriphBase minimum address length is 64MB (0x04000000)
+    for a (X < 4) && (Y < 4) dimensions mesh.
+*/
+#define PERIPHBASE_MIN_ADDRESS_LENGTH   SIZE_64MB
+
+/** RootNodeBase address length is 16KB (0x00004000).
+*/
+#define ROOTNODEBASE_ADDRESS_LENGTH     SIZE_16KB
+
+/** Maximum number of CMN-600 Debug and Trace Logic Controllers (DTC).
+*/
+#define MAX_DTC_COUNT                   4
+
+/** Starting value for the UID to represent the CMN600 devices.
+*/
+#define CMN600_DEVICE_START_UID         0
+
+/** Maximum CMN-600 devices supported by this generator.
+    This generator supports a maximum of 16 CMN-600 devices.
+    Note: This is not a hard limitation and can be extended if needed.
+          Corresponding changes would be needed to support the Name and
+          UID fields describing the serial port.
+
+*/
+#define MAX_CMN600_DEVICES_SUPPORTED    16
+
+#endif // SSDT_CMN600_GENERATOR_H_
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
new file mode 100644
index 0000000000000000000000000000000000000000..821c0d531b983e19278062a11317bba83fdc141a
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
@@ -0,0 +1,34 @@
+## @file
+# Ssdt CMN-600 Table Generator
+#
+#  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION    = 0x0001001B
+  BASE_NAME      = SsdtCmn600LibArm
+  FILE_GUID      = CEDB450D-8F0E-4ACC-8FB7-F72EC7D216A4
+  VERSION_STRING = 1.0
+  MODULE_TYPE    = DXE_DRIVER
+  LIBRARY_CLASS  = NULL|DXE_DRIVER
+  CONSTRUCTOR    = AcpiSsdtCmn600LibConstructor
+  DESTRUCTOR     = AcpiSsdtCmn600LibDestructor
+
+[Sources]
+  SsdtCmn600Generator.c
+  SsdtCmn600Generator.h
+  SsdtCmn600Template.asl
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  DynamicTablesPkg/DynamicTablesPkg.dec
+
+[LibraryClasses]
+  AmlLib
+  BaseLib
+
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl
new file mode 100644
index 0000000000000000000000000000000000000000..023a89e2ab3d753cb1cdb8c423766294b0ea3fab
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl
@@ -0,0 +1,81 @@
+/** @file
+  SSDT CMN-600 Template
+
+  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Reference(s):
+  - Arm CoreLink CMN-600 Coherent Mesh Network Technical Reference Manual r3p0
+  - Generic ACPI for Arm Components 1.0 Platform Design Document
+
+  @par Glossary:
+    - {template} - Data fixed up using AML Fixup APIs.
+    - {codegen}  - Data generated using AML Codegen APIs.
+**/
+
+DefinitionBlock ("SsdtCmn600.aml", "SSDT", 2, "ARMLTD", "CMN-600", 1) {
+  Scope (_SB) {
+    // CMN-600 device object for a X * Y mesh, where (X >= 4) || (Y >= 4).
+    Device (CMN0) {                        // {template}
+      Name (_HID, "ARMHC600")
+      Name (_UID, 0x0)                     // {template}
+
+      Name (_CRS, ResourceTemplate () {
+        // Descriptor for 256 MB of the CFG region at offset PERIPHBASE.
+        QWordMemory (
+          ResourceConsumer,                // bit 0 of general flags is 0.
+          PosDecode,
+          MinFixed,                        // Range is fixed.
+          MaxFixed,                        // Range is Fixed.
+          NonCacheable,
+          ReadWrite,
+          0x00000000,                      // Granularity
+          0xA0000000,                      // MinAddress         // {template}
+          0xAFFFFFFF,                      // MaxAddress         // {template}
+          0x00000000,                      // Translation
+          0x10000000,                      // RangeLength        // {template}
+          ,                                // ResourceSourceIndex
+          ,                                // ResourceSource
+          CFGR                             // DescriptorName
+        ) // QWordMemory
+
+        // Descriptor for the root node. This is a 16 KB region at offset
+        // ROOTNODEBASE. In this example, ROOTNODEBASE starts at the 16 KB
+        // aligned offset of PERIPHBASE.
+        QWordMemory (
+          ResourceConsumer,                // bit 0 of general flags is 0.
+          PosDecode,
+          MinFixed,                        // Range is fixed.
+          MaxFixed,                        // Range is Fixed.
+          NonCacheable,
+          ReadWrite,
+          0x00000000,                      // Granularity
+          0xA0000000,                      // MinAddress         // {template}
+          0xAFFFFFFF,                      // MaxAddress         // {template}
+          0x00000000,                      // Translation
+          0x10000000,                      // RangeLength        // {template}
+          ,                                // ResourceSourceIndex
+          ,                                // ResourceSource
+          ROOT                             // DescriptorName
+        ) // QWordMemory
+
+        // The Interrupt information is generated using AmlCodegen.
+        // Interrupt on PMU0 overflow, attached to DTC [0], with GSIV = <gsiv0>.
+        //
+        // Interrupt (                                            // {codegen}
+        //  ResourceConsumer,                // ResourceUsage
+        //  Level,                           // EdgeLevel
+        //  ActiveHigh,                      // ActiveLevel
+        //  Exclusive,                       // Shared
+        //  ,                                // ResourceSourceIndex
+        //  ,                                // ResourceSource
+        //                                   // DescriptorName
+        //  ) {
+        //    0xA5                           // <gsiv0 >
+        // } // Interrupt
+
+      }) // Name
+    } // Device
+  } // _SB
+} // DefinitionBlock
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#65627): https://edk2.groups.io/g/devel/message/65627
Mute This Topic: https://groups.io/mt/77079115/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