--- /dev/null
+/** @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