]> git.proxmox.com Git - mirror_edk2.git/commitdiff
DynamicTablesPkg: Add SSDT CMN-600 Table generator
authorPierre Gondois <pierre.gondois@arm.com>
Thu, 6 Aug 2020 13:59:32 +0000 (14:59 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Tue, 3 Nov 2020 09:09:22 +0000 (09:09 +0000)
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@arm.com>
Co-authored-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
DynamicTablesPkg/DynamicTables.dsc.inc
DynamicTablesPkg/DynamicTablesPkg.ci.yaml
DynamicTablesPkg/Include/AcpiTableGenerator.h
DynamicTablesPkg/Include/ArmNameSpaceObjects.h
DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c [new file with mode: 0644]
DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h [new file with mode: 0644]
DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf [new file with mode: 0644]
DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl [new file with mode: 0644]

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