summaryrefslogtreecommitdiff
path: root/DynamicTablesPkg/Library/Acpi
diff options
context:
space:
mode:
authorPierre Gondois <pierre.gondois@arm.com>2022-10-10 11:20:55 +0200
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2022-10-31 12:32:32 +0000
commit8405b1480f9a60e14343fa6c006adb546fc6c7a2 (patch)
treed7b73c59df8b14d10212dd376c7e488b93da6963 /DynamicTablesPkg/Library/Acpi
parentdab7bac94c6ca31b9c9ed1da97eba7dade0c54a6 (diff)
downloadedk2-8405b1480f9a60e14343fa6c006adb546fc6c7a2.zip
edk2-8405b1480f9a60e14343fa6c006adb546fc6c7a2.tar.gz
edk2-8405b1480f9a60e14343fa6c006adb546fc6c7a2.tar.bz2
DynamicTablesPkg: Add PCCT Generator
The Platform Communication Channel Table (PCCT) generator collates the relevant information required for generating a PCCT table from configuration manager using the configuration manager protocol. The DynamicTablesManager then install the PCCT table. From ACPI 6.4, s14 PLATFORM COMMUNICATIONS CHANNEL (PCC): The platform communication channel (PCC) is a generic mechanism for OSPM to communicate with an entity in the platform. Signed-off-by: Pierre Gondois <pierre.gondois@arm.com> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
Diffstat (limited to 'DynamicTablesPkg/Library/Acpi')
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/AcpiPcctLibArm.inf30
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/PcctGenerator.c1186
-rw-r--r--DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/PcctGenerator.h43
3 files changed, 1259 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/AcpiPcctLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/AcpiPcctLibArm.inf
new file mode 100644
index 0000000..da54585
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/AcpiPcctLibArm.inf
@@ -0,0 +1,30 @@
+## @file
+# Pcct Table Generator
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = AcpiPcctLibArm
+ FILE_GUID = 38FE945C-D6ED-4CD6-8D20-FCEF3260D15A
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiPcctLibConstructor
+ DESTRUCTOR = AcpiPcctLibDestructor
+
+[Sources]
+ PcctGenerator.c
+ PcctGenerator.h
+
+[Packages]
+ DynamicTablesPkg/DynamicTablesPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/PcctGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/PcctGenerator.c
new file mode 100644
index 0000000..36caf4a
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/PcctGenerator.c
@@ -0,0 +1,1186 @@
+/** @file
+ PCCT Table Generator
+
+ Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.4 Specification - January 2021
+ s14 PLATFORM COMMUNICATIONS CHANNEL (PCC)
+
+**/
+
+#include <Library/AcpiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+#include "PcctGenerator.h"
+
+/** ARM standard PCCT Generator
+
+Requirements:
+ The following Configuration Manager Object(s) are required by
+ this Generator:
+ - EArmObjPccSubspaceType0Info
+ - EArmObjPccSubspaceType1Info
+ - EArmObjPccSubspaceType2Info
+ - EArmObjPccSubspaceType3Info
+ - EArmObjPccSubspaceType4Info
+ - EArmObjPccSubspaceType5Info
+*/
+
+/** This macro expands to a function that retrieves the PCC
+ Subspace of Type 0 Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPccSubspaceType0Info,
+ CM_ARM_PCC_SUBSPACE_TYPE0_INFO
+ );
+
+/** This macro expands to a function that retrieves the PCC
+ Subspace of Type 1 Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPccSubspaceType1Info,
+ CM_ARM_PCC_SUBSPACE_TYPE1_INFO
+ );
+
+/** This macro expands to a function that retrieves the PCC
+ Subspace of Type 2 Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPccSubspaceType2Info,
+ CM_ARM_PCC_SUBSPACE_TYPE2_INFO
+ );
+
+/** This macro expands to a function that retrieves the PCC
+ Subspace of Type 3 Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPccSubspaceType3Info,
+ CM_ARM_PCC_SUBSPACE_TYPE3_INFO
+ );
+
+/** This macro expands to a function that retrieves the PCC
+ Subspace of Type 4 Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPccSubspaceType4Info,
+ CM_ARM_PCC_SUBSPACE_TYPE4_INFO
+ );
+
+/** This macro expands to a function that retrieves the PCC
+ Subspace of Type 5 Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPccSubspaceType5Info,
+ CM_ARM_PCC_SUBSPACE_TYPE5_INFO
+ );
+
+/** The Platform is capable of generating an interrupt
+ to indicate completion of a command.
+
+ Cf: s14.1.1 Platform Communications Channel Global Flags
+ Platform Interrupt flag
+ and s14.1.6 Extended PCC subspaces (types 3 and 4)
+ If a responder subspace is included in the PCCT,
+ then the global Platform Interrupt flag must be set to 1
+
+ Set this variable and populate the PCCT flag accordingly if either:
+ - One of the PCCT Subspace uses interrupts.
+ - A PCC Subspace of type 4 is used.
+*/
+STATIC BOOLEAN mHasPlatformInterrupt;
+
+/** Initialize the MappingTable.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in] Count Number of entries to allocate in the
+ MappingTable.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+MappingTableInitialize (
+ IN MAPPING_TABLE *MappingTable,
+ IN UINT32 Count
+ )
+{
+ VOID **Table;
+
+ if ((MappingTable == NULL) ||
+ (Count == 0))
+ {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Table = AllocateZeroPool (sizeof (*Table) * Count);
+ if (Table == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MappingTable->Table = Table;
+ MappingTable->MaxIndex = Count;
+
+ return EFI_SUCCESS;
+}
+
+/** Free the MappingTable.
+
+ @param [in, out] MappingTable The mapping table structure.
+**/
+STATIC
+VOID
+EFIAPI
+MappingTableFree (
+ IN OUT MAPPING_TABLE *MappingTable
+ )
+{
+ ASSERT (MappingTable != NULL);
+ ASSERT (MappingTable->Table != NULL);
+
+ if (MappingTable->Table != NULL) {
+ FreePool (MappingTable->Table);
+ }
+}
+
+/** Add a new entry for CmArmPccSubspace at Index.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in] CmArmPccSubspace Pointer to a CM_ARM_PCC_SUBSPACE_TYPE[X]_INFO.
+ @param [in] Index Index at which CmArmPccSubspace must be added.
+ This is the Subspace Id.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+MappingTableAdd (
+ IN MAPPING_TABLE *MappingTable,
+ IN VOID *CmArmPccSubspace,
+ IN UINT32 Index
+ )
+{
+ if ((MappingTable == NULL) ||
+ (MappingTable->Table == NULL) ||
+ (CmArmPccSubspace == NULL))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Index >= MappingTable->MaxIndex) ||
+ (MappingTable->Table[Index] != 0))
+ {
+ ASSERT_EFI_ERROR (EFI_BUFFER_TOO_SMALL);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // Just map the Pcc Subspace in the Table.
+ MappingTable->Table[Index] = CmArmPccSubspace;
+ return EFI_SUCCESS;
+}
+
+/** Parse the CmPccArray objects and add them to the MappingTable.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in] CmPccArray Pointer to an array of CM_ARM_PCC_SUBSPACE_TYPE[X]_INFO.
+ @param [in] CmPccCount Count of objects in CmPccArray.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+MapPccSubspaceId (
+ IN MAPPING_TABLE *MappingTable,
+ IN VOID *CmPccArray,
+ IN UINT32 CmPccCount
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *PccBuffer;
+ UINT32 Index;
+ UINT32 CmObjSize;
+ PCC_SUBSPACE_GENERIC_INFO *GenericPcc;
+
+ if (CmPccCount == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((CmPccArray == NULL) || (MappingTable == NULL)) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GenericPcc = (PCC_SUBSPACE_GENERIC_INFO *)CmPccArray;
+
+ switch (GenericPcc->Type) {
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_GENERIC:
+ CmObjSize = sizeof (CM_ARM_PCC_SUBSPACE_TYPE0_INFO);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS:
+ CmObjSize = sizeof (CM_ARM_PCC_SUBSPACE_TYPE1_INFO);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS:
+ CmObjSize = sizeof (CM_ARM_PCC_SUBSPACE_TYPE2_INFO);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC:
+ CmObjSize = sizeof (CM_ARM_PCC_SUBSPACE_TYPE3_INFO);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC:
+ CmObjSize = sizeof (CM_ARM_PCC_SUBSPACE_TYPE4_INFO);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_5_HW_REGISTERS_COMMUNICATIONS:
+ CmObjSize = sizeof (CM_ARM_PCC_SUBSPACE_TYPE5_INFO);
+ break;
+
+ default:
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PccBuffer = (UINT8 *)CmPccArray;
+
+ // Map the Pcc channel to their Subspace Id.
+ for (Index = 0; Index < CmPccCount; Index++) {
+ GenericPcc = (PCC_SUBSPACE_GENERIC_INFO *)PccBuffer;
+
+ Status = MappingTableAdd (
+ MappingTable,
+ PccBuffer,
+ GenericPcc->SubspaceId
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ PccBuffer += CmObjSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Add one PCCT Subspace structure of Type 0 (Generic).
+
+ @param [in] PccCmObj Pointer to a CmObj PCCT Subspace info structure.
+ @param [in] PccAcpi Pointer to the ACPI PCCT Subspace structure to populate.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AddSubspaceStructType0 (
+ IN CM_ARM_PCC_SUBSPACE_TYPE0_INFO *PccCmObj,
+ IN EFI_ACPI_6_4_PCCT_SUBSPACE_GENERIC *PccAcpi
+ )
+{
+ PCC_MAILBOX_REGISTER_INFO *Doorbell;
+ PCC_SUBSPACE_CHANNEL_TIMING_INFO *ChannelTiming;
+
+ if ((PccCmObj == NULL) ||
+ (PccCmObj->Type != EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_GENERIC) ||
+ (PccAcpi == NULL))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Doorbell = &PccCmObj->DoorbellReg;
+ ChannelTiming = &PccCmObj->ChannelTiming;
+
+ PccAcpi->Type = PccCmObj->Type;
+ PccAcpi->Length = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_GENERIC);
+ *(UINT32 *)&PccAcpi->Reserved[0] = EFI_ACPI_RESERVED_DWORD;
+ *(UINT16 *)&PccAcpi->Reserved[4] = EFI_ACPI_RESERVED_WORD;
+ PccAcpi->BaseAddress = PccCmObj->BaseAddress;
+ PccAcpi->AddressLength = PccCmObj->AddressLength;
+
+ CopyMem (
+ &PccAcpi->DoorbellRegister,
+ &Doorbell->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->DoorbellPreserve = Doorbell->PreserveMask;
+ PccAcpi->DoorbellWrite = Doorbell->WriteMask;
+
+ PccAcpi->NominalLatency = ChannelTiming->NominalLatency;
+ PccAcpi->MaximumPeriodicAccessRate = ChannelTiming->MaxPeriodicAccessRate;
+ PccAcpi->MinimumRequestTurnaroundTime = ChannelTiming->MinRequestTurnaroundTime;
+
+ return EFI_SUCCESS;
+}
+
+/** Add one PCCT subspace structure of Type 1 (HW-Reduced).
+
+ @param [in] PccCmObj Pointer to a CmObj PCCT Subspace info structure.
+ @param [in] PccAcpi Pointer to the ACPI PCCT Subspace structure to populate.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AddSubspaceStructType1 (
+ IN CM_ARM_PCC_SUBSPACE_TYPE1_INFO *PccCmObj,
+ IN EFI_ACPI_6_4_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS *PccAcpi
+ )
+{
+ CM_ARM_PCC_SUBSPACE_TYPE0_INFO *GenericPccCmObj;
+ PCC_MAILBOX_REGISTER_INFO *Doorbell;
+ PCC_SUBSPACE_CHANNEL_TIMING_INFO *ChannelTiming;
+
+ GenericPccCmObj = (CM_ARM_PCC_SUBSPACE_TYPE0_INFO *)PccCmObj;
+
+ if ((PccCmObj == NULL) ||
+ (GenericPccCmObj->Type != EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS) ||
+ (PccAcpi == NULL))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Doorbell = &GenericPccCmObj->DoorbellReg;
+ ChannelTiming = &GenericPccCmObj->ChannelTiming;
+
+ PccAcpi->Type = GenericPccCmObj->Type;
+ PccAcpi->Length = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS);
+ PccAcpi->PlatformInterrupt = PccCmObj->PlatIrq.Interrupt;
+ PccAcpi->PlatformInterruptFlags = PccCmObj->PlatIrq.Flags;
+ PccAcpi->Reserved = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->BaseAddress = GenericPccCmObj->BaseAddress;
+ PccAcpi->AddressLength = GenericPccCmObj->AddressLength;
+
+ CopyMem (
+ &PccAcpi->DoorbellRegister,
+ &Doorbell->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->DoorbellPreserve = Doorbell->PreserveMask;
+ PccAcpi->DoorbellWrite = Doorbell->WriteMask;
+
+ PccAcpi->NominalLatency = ChannelTiming->NominalLatency;
+ PccAcpi->MaximumPeriodicAccessRate = ChannelTiming->MaxPeriodicAccessRate;
+ PccAcpi->MinimumRequestTurnaroundTime = ChannelTiming->MinRequestTurnaroundTime;
+
+ if ((PccCmObj->PlatIrq.Interrupt != 0)) {
+ mHasPlatformInterrupt = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Add one PCCT subspace structure of Type 2 (HW-Reduced).
+
+ @param [in] PccCmObj Pointer to a CmObj PCCT Subspace info structure.
+ @param [in] PccAcpi Pointer to the ACPI PCCT Subspace structure to populate.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AddSubspaceStructType2 (
+ IN CM_ARM_PCC_SUBSPACE_TYPE2_INFO *PccCmObj,
+ IN EFI_ACPI_6_4_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS *PccAcpi
+ )
+{
+ CM_ARM_PCC_SUBSPACE_TYPE0_INFO *GenericPccCmObj;
+ PCC_MAILBOX_REGISTER_INFO *Doorbell;
+ PCC_MAILBOX_REGISTER_INFO *PlatIrqAck;
+ PCC_SUBSPACE_CHANNEL_TIMING_INFO *ChannelTiming;
+
+ GenericPccCmObj = (CM_ARM_PCC_SUBSPACE_TYPE0_INFO *)PccCmObj;
+
+ if ((PccCmObj == NULL) ||
+ (GenericPccCmObj->Type != EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS) ||
+ (PccAcpi == NULL))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Doorbell = &GenericPccCmObj->DoorbellReg;
+ PlatIrqAck = &PccCmObj->PlatIrqAckReg;
+ ChannelTiming = &GenericPccCmObj->ChannelTiming;
+
+ PccAcpi->Type = GenericPccCmObj->Type;
+ PccAcpi->Length = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS);
+ PccAcpi->PlatformInterrupt = PccCmObj->PlatIrq.Interrupt;
+ PccAcpi->PlatformInterruptFlags = PccCmObj->PlatIrq.Flags;
+ PccAcpi->BaseAddress = GenericPccCmObj->BaseAddress;
+ PccAcpi->Reserved = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->BaseAddress = GenericPccCmObj->BaseAddress;
+ PccAcpi->AddressLength = GenericPccCmObj->AddressLength;
+
+ CopyMem (
+ &PccAcpi->DoorbellRegister,
+ &Doorbell->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->DoorbellPreserve = Doorbell->PreserveMask;
+ PccAcpi->DoorbellWrite = Doorbell->WriteMask;
+
+ PccAcpi->NominalLatency = ChannelTiming->NominalLatency;
+ PccAcpi->MaximumPeriodicAccessRate = ChannelTiming->MaxPeriodicAccessRate;
+ PccAcpi->MinimumRequestTurnaroundTime = ChannelTiming->MinRequestTurnaroundTime;
+
+ CopyMem (
+ &PccAcpi->PlatformInterruptAckRegister,
+ &PlatIrqAck->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->PlatformInterruptAckPreserve = PlatIrqAck->PreserveMask;
+ PccAcpi->PlatformInterruptAckWrite = PlatIrqAck->WriteMask;
+
+ if ((PccCmObj->PlatIrq.Interrupt != 0)) {
+ mHasPlatformInterrupt = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Add one PCCT subspace structure of Type 3 or 4 (Extended).
+
+ @param [in] PccCmObj Pointer to a CmObj PCCT Subspace info structure.
+ @param [in] PccAcpi Pointer to the ACPI PCCT Subspace structure to populate.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AddSubspaceStructType34 (
+ IN CM_ARM_PCC_SUBSPACE_TYPE3_INFO *PccCmObj,
+ IN EFI_ACPI_6_4_PCCT_SUBSPACE_3_EXTENDED_PCC *PccAcpi
+ )
+{
+ CM_ARM_PCC_SUBSPACE_TYPE0_INFO *GenericPccCmObj;
+ PCC_MAILBOX_REGISTER_INFO *Doorbell;
+ PCC_MAILBOX_REGISTER_INFO *PlatIrqAck;
+ PCC_MAILBOX_REGISTER_INFO *CmdCompleteCheck;
+ PCC_MAILBOX_REGISTER_INFO *CmdCompleteUpdate;
+ PCC_MAILBOX_REGISTER_INFO *ErrorStatus;
+ PCC_SUBSPACE_CHANNEL_TIMING_INFO *ChannelTiming;
+
+ GenericPccCmObj = (CM_ARM_PCC_SUBSPACE_TYPE0_INFO *)PccCmObj;
+
+ if ((PccCmObj == NULL) ||
+ ((GenericPccCmObj->Type != EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC) &&
+ (GenericPccCmObj->Type != EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC)) ||
+ (PccAcpi == NULL))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Doorbell = &GenericPccCmObj->DoorbellReg;
+ PlatIrqAck = &PccCmObj->PlatIrqAckReg;
+ CmdCompleteCheck = &PccCmObj->CmdCompleteCheckReg;
+ CmdCompleteUpdate = &PccCmObj->CmdCompleteUpdateReg;
+ ErrorStatus = &PccCmObj->ErrorStatusReg;
+ ChannelTiming = &GenericPccCmObj->ChannelTiming;
+
+ PccAcpi->Type = GenericPccCmObj->Type;
+ PccAcpi->Length = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_3_EXTENDED_PCC);
+ PccAcpi->PlatformInterrupt = PccCmObj->PlatIrq.Interrupt;
+ PccAcpi->PlatformInterruptFlags = PccCmObj->PlatIrq.Flags;
+ PccAcpi->Reserved = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->BaseAddress = GenericPccCmObj->BaseAddress;
+ PccAcpi->AddressLength = GenericPccCmObj->AddressLength;
+
+ CopyMem (
+ &PccAcpi->DoorbellRegister,
+ &Doorbell->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->DoorbellPreserve = Doorbell->PreserveMask;
+ PccAcpi->DoorbellWrite = Doorbell->WriteMask;
+
+ PccAcpi->NominalLatency = ChannelTiming->NominalLatency;
+ PccAcpi->MaximumPeriodicAccessRate = ChannelTiming->MaxPeriodicAccessRate;
+ PccAcpi->MinimumRequestTurnaroundTime = ChannelTiming->MinRequestTurnaroundTime;
+
+ CopyMem (
+ &PccAcpi->PlatformInterruptAckRegister,
+ &PlatIrqAck->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->PlatformInterruptAckPreserve = PlatIrqAck->PreserveMask;
+ PccAcpi->PlatformInterruptAckSet = PlatIrqAck->WriteMask;
+
+ PccAcpi->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->Reserved1[1] = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->Reserved1[1] = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->Reserved1[3] = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->Reserved1[4] = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->Reserved1[5] = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->Reserved1[6] = EFI_ACPI_RESERVED_BYTE;
+ PccAcpi->Reserved1[7] = EFI_ACPI_RESERVED_BYTE;
+
+ CopyMem (
+ &PccAcpi->CommandCompleteCheckRegister,
+ &CmdCompleteCheck->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->CommandCompleteCheckMask = CmdCompleteCheck->PreserveMask;
+ // No Write mask.
+
+ CopyMem (
+ &PccAcpi->CommandCompleteUpdateRegister,
+ &CmdCompleteUpdate->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->CommandCompleteUpdatePreserve = CmdCompleteUpdate->PreserveMask;
+ PccAcpi->CommandCompleteUpdateSet = CmdCompleteUpdate->WriteMask;
+
+ CopyMem (
+ &PccAcpi->ErrorStatusRegister,
+ &ErrorStatus->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->ErrorStatusMask = ErrorStatus->PreserveMask;
+ // No Write mask.
+
+ if (GenericPccCmObj->Type == EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC) {
+ mHasPlatformInterrupt = TRUE;
+ } else if ((PccCmObj->PlatIrq.Interrupt != 0)) {
+ mHasPlatformInterrupt = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Add one PCCT subspace structure of Type 5 (HW-Registers).
+
+ @param [in] PccCmObj Pointer to a CmObj PCCT Subspace info structure.
+ @param [in] PccAcpi Pointer to the ACPI PCCT Subspace structure to populate.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AddSubspaceStructType5 (
+ IN CM_ARM_PCC_SUBSPACE_TYPE5_INFO *PccCmObj,
+ IN EFI_ACPI_6_4_PCCT_SUBSPACE_5_HW_REGISTERS_COMMUNICATIONS *PccAcpi
+ )
+{
+ CM_ARM_PCC_SUBSPACE_TYPE0_INFO *GenericPccCmObj;
+ PCC_MAILBOX_REGISTER_INFO *Doorbell;
+ PCC_MAILBOX_REGISTER_INFO *CmdCompleteCheck;
+ PCC_MAILBOX_REGISTER_INFO *ErrorStatus;
+ PCC_SUBSPACE_CHANNEL_TIMING_INFO *ChannelTiming;
+
+ GenericPccCmObj = (CM_ARM_PCC_SUBSPACE_TYPE0_INFO *)PccCmObj;
+
+ if ((PccCmObj == NULL) ||
+ (GenericPccCmObj->Type != EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_5_HW_REGISTERS_COMMUNICATIONS) ||
+ (PccAcpi == NULL))
+ {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Doorbell = &GenericPccCmObj->DoorbellReg;
+ CmdCompleteCheck = &PccCmObj->CmdCompleteCheckReg;
+ ErrorStatus = &PccCmObj->ErrorStatusReg;
+ ChannelTiming = &GenericPccCmObj->ChannelTiming;
+
+ PccAcpi->Type = GenericPccCmObj->Type;
+ PccAcpi->Length = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_5_HW_REGISTERS_COMMUNICATIONS);
+ PccAcpi->Version = PccCmObj->Version;
+ PccAcpi->BaseAddress = GenericPccCmObj->BaseAddress;
+ PccAcpi->SharedMemoryRangeLength = GenericPccCmObj->AddressLength;
+
+ CopyMem (
+ &PccAcpi->DoorbellRegister,
+ &Doorbell->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->DoorbellPreserve = Doorbell->PreserveMask;
+ PccAcpi->DoorbellWrite = Doorbell->WriteMask;
+
+ CopyMem (
+ &PccAcpi->CommandCompleteCheckRegister,
+ &CmdCompleteCheck->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->CommandCompleteCheckMask = CmdCompleteCheck->PreserveMask;
+ // No Write mask.
+
+ CopyMem (
+ &PccAcpi->ErrorStatusRegister,
+ &ErrorStatus->Register,
+ sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE)
+ );
+ PccAcpi->ErrorStatusMask = ErrorStatus->PreserveMask;
+ // No Write mask.
+
+ PccAcpi->NominalLatency = ChannelTiming->NominalLatency;
+ // No MaximumPeriodicAccessRate.
+ PccAcpi->MinimumRequestTurnaroundTime = ChannelTiming->MinRequestTurnaroundTime;
+
+ return EFI_SUCCESS;
+}
+
+/** Populate the PCCT table using the MappingTable.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in] Pcc Pointer to an array of Pcc Subpace structures.
+ @param [in] Size Size of the Pcc array.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PopulatePcctTable (
+ IN MAPPING_TABLE *MappingTable,
+ IN VOID *Pcc,
+ IN UINT32 Size
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *PccBuffer;
+ UINT32 CmObjSize;
+ UINT32 Index;
+ UINT32 MaxIndex;
+ VOID **Table;
+ VOID *CurrentPccSubspace;
+
+ ASSERT (MappingTable != NULL);
+ ASSERT (MappingTable->Table != NULL);
+
+ PccBuffer = Pcc;
+ MaxIndex = MappingTable->MaxIndex;
+ Table = MappingTable->Table;
+
+ for (Index = 0; Index < MaxIndex; Index++) {
+ CurrentPccSubspace = Table[Index];
+ if (CurrentPccSubspace == NULL) {
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (((PCC_SUBSPACE_GENERIC_INFO *)CurrentPccSubspace)->Type) {
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_GENERIC:
+ Status = AddSubspaceStructType0 (
+ (CM_ARM_PCC_SUBSPACE_TYPE0_INFO *)CurrentPccSubspace,
+ (EFI_ACPI_6_4_PCCT_SUBSPACE_GENERIC *)PccBuffer
+ );
+
+ CmObjSize = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_GENERIC);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS:
+ Status = AddSubspaceStructType1 (
+ (CM_ARM_PCC_SUBSPACE_TYPE1_INFO *)CurrentPccSubspace,
+ (EFI_ACPI_6_4_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS *)PccBuffer
+ );
+
+ CmObjSize = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS:
+ Status = AddSubspaceStructType2 (
+ (CM_ARM_PCC_SUBSPACE_TYPE2_INFO *)CurrentPccSubspace,
+ (EFI_ACPI_6_4_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS *)PccBuffer
+ );
+
+ CmObjSize = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC:
+ Status = AddSubspaceStructType34 (
+ (CM_ARM_PCC_SUBSPACE_TYPE3_INFO *)CurrentPccSubspace,
+ (EFI_ACPI_6_4_PCCT_SUBSPACE_3_EXTENDED_PCC *)PccBuffer
+ );
+
+ CmObjSize = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_3_EXTENDED_PCC);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC:
+ Status = AddSubspaceStructType34 (
+ (CM_ARM_PCC_SUBSPACE_TYPE4_INFO *)CurrentPccSubspace,
+ (EFI_ACPI_6_4_PCCT_SUBSPACE_4_EXTENDED_PCC *)PccBuffer
+ );
+
+ CmObjSize = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_4_EXTENDED_PCC);
+ break;
+
+ case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_5_HW_REGISTERS_COMMUNICATIONS:
+ Status = AddSubspaceStructType5 (
+ (CM_ARM_PCC_SUBSPACE_TYPE5_INFO *)CurrentPccSubspace,
+ (EFI_ACPI_6_4_PCCT_SUBSPACE_5_HW_REGISTERS_COMMUNICATIONS *)PccBuffer
+ );
+
+ CmObjSize = sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_5_HW_REGISTERS_COMMUNICATIONS);
+ break;
+
+ default:
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ } // switch
+
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ if (Size < CmObjSize) {
+ ASSERT_EFI_ERROR (EFI_BUFFER_TOO_SMALL);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ PccBuffer += CmObjSize;
+ Size -= CmObjSize;
+ } // for
+
+ return EFI_SUCCESS;
+}
+
+/** Construct the PCCT ACPI table.
+
+ Called by the Dynamic Table Manager, 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 FreeXXXXTableResources function.
+
+ @param [in] This Pointer to the table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [out] Table Pointer to the constructed ACPI Table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for the
+ requested object.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildPcctTable (
+ 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,
+ OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
+ )
+{
+ EFI_STATUS Status;
+ ACPI_PCCT_GENERATOR *Generator;
+ UINT32 TableSize;
+ EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER *Pcct;
+ UINT8 *Buffer;
+
+ MAPPING_TABLE *MappingTable;
+ UINT32 MappingTableCount;
+
+ CM_ARM_PCC_SUBSPACE_TYPE0_INFO *PccType0;
+ UINT32 PccType0Count;
+ CM_ARM_PCC_SUBSPACE_TYPE1_INFO *PccType1;
+ UINT32 PccType1Count;
+ CM_ARM_PCC_SUBSPACE_TYPE2_INFO *PccType2;
+ UINT32 PccType2Count;
+ CM_ARM_PCC_SUBSPACE_TYPE3_INFO *PccType3;
+ UINT32 PccType3Count;
+ CM_ARM_PCC_SUBSPACE_TYPE4_INFO *PccType4;
+ UINT32 PccType4Count;
+ CM_ARM_PCC_SUBSPACE_TYPE5_INFO *PccType5;
+ UINT32 PccType5Count;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PCCT: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Generator = (ACPI_PCCT_GENERATOR *)This;
+ MappingTable = &Generator->MappingTable;
+ *Table = NULL;
+
+ // First get all the Pcc Subpace CmObj of type X.
+
+ Status = GetEArmObjPccSubspaceType0Info (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PccType0,
+ &PccType0Count
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = GetEArmObjPccSubspaceType1Info (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PccType1,
+ &PccType1Count
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = GetEArmObjPccSubspaceType2Info (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PccType2,
+ &PccType2Count
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = GetEArmObjPccSubspaceType3Info (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PccType3,
+ &PccType3Count
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = GetEArmObjPccSubspaceType4Info (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PccType4,
+ &PccType4Count
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = GetEArmObjPccSubspaceType5Info (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PccType5,
+ &PccType5Count
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ // Count the number of Pcc Subspaces.
+ MappingTableCount = PccType0Count;
+ MappingTableCount += PccType1Count;
+ MappingTableCount += PccType2Count;
+ MappingTableCount += PccType3Count;
+ MappingTableCount += PccType4Count;
+ MappingTableCount += PccType5Count;
+
+ Status = MappingTableInitialize (MappingTable, MappingTableCount);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ // Map the Subspace Ids for all types.
+
+ Status = MapPccSubspaceId (MappingTable, PccType0, PccType0Count);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = MapPccSubspaceId (MappingTable, PccType1, PccType1Count);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = MapPccSubspaceId (MappingTable, PccType2, PccType2Count);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = MapPccSubspaceId (MappingTable, PccType3, PccType3Count);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = MapPccSubspaceId (MappingTable, PccType4, PccType4Count);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Status = MapPccSubspaceId (MappingTable, PccType5, PccType5Count);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ // Compute the size of the PCCT table.
+ TableSize = sizeof (EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER);
+ TableSize += PccType0Count * sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_GENERIC);
+ TableSize += PccType1Count * sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_1_HW_REDUCED_COMMUNICATIONS);
+ TableSize += PccType2Count * sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_2_HW_REDUCED_COMMUNICATIONS);
+ TableSize += PccType3Count * sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_3_EXTENDED_PCC);
+ TableSize += PccType4Count * sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_4_EXTENDED_PCC);
+ TableSize += PccType5Count * sizeof (EFI_ACPI_6_4_PCCT_SUBSPACE_5_HW_REGISTERS_COMMUNICATIONS);
+
+ // Allocate a Buffer for the PCCT table.
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
+ if (*Table == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Pcct = (EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER *)*Table;
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Pcct->Header,
+ AcpiTableInfo,
+ TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PCCT: Failed to add ACPI header. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ Buffer = (UINT8 *)Pcct;
+ Buffer += sizeof (EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER);
+ TableSize -= sizeof (EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_HEADER);
+
+ // Populate the PCCT table by following the Subspace Id mapping.
+ Status = PopulatePcctTable (MappingTable, Buffer, TableSize);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ goto error_handler;
+ }
+
+ // Setup the Reserved fields once mHasPlatformInterrupt hase been populated.
+ Pcct->Flags = mHasPlatformInterrupt;
+ Pcct->Reserved = EFI_ACPI_RESERVED_QWORD;
+
+ MappingTableFree (MappingTable);
+
+ return Status;
+
+error_handler:
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PCCT: Failed to install table. Status = %r\n",
+ Status
+ ));
+
+ if (*Table != NULL) {
+ FreePool (*Table);
+ *Table = NULL;
+ }
+
+ MappingTableFree (MappingTable);
+
+ return Status;
+}
+
+/** Free any resources allocated for constructing the PCCT.
+
+ @param [in] This Pointer to the 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 the ACPI Table.
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+FreePcctTableResources (
+ 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
+ )
+{
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((Table == NULL) || (*Table == NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: PCCT: Invalid Table Pointer\n"));
+ ASSERT ((Table != NULL) && (*Table != NULL));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (*Table);
+ *Table = NULL;
+ return EFI_SUCCESS;
+}
+
+/** This macro defines the PCCT Table Generator revision.
+*/
+#define PCCT_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the PCCT Table Generator.
+*/
+STATIC
+ACPI_PCCT_GENERATOR PcctGenerator = {
+ // ACPI table generator header
+ {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPcct),
+ // Generator Description
+ L"ACPI.STD.PCCT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_4_PLATFORM_COMMUNICATIONS_CHANNEL_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION,
+ // Minimum ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL_TABLE_REVISION,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ PCCT_GENERATOR_REVISION,
+ // Build Table function
+ BuildPcctTable,
+ // Free Resource function
+ FreePcctTableResources,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended free resource function is not required.
+ NULL
+ },
+
+ // Private fields are defined from here.
+
+ // Mapping Table
+ {
+ // Table
+ NULL,
+ // MaxIndex
+ 0,
+ },
+};
+
+/** 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
+AcpiPcctLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RegisterAcpiTableGenerator (&PcctGenerator.Header);
+ DEBUG ((DEBUG_INFO, "PCCT: 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
+AcpiPcctLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = DeregisterAcpiTableGenerator (&PcctGenerator.Header);
+ DEBUG ((DEBUG_INFO, "PCCT: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/PcctGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/PcctGenerator.h
new file mode 100644
index 0000000..0631a1f
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiPcctLibArm/PcctGenerator.h
@@ -0,0 +1,43 @@
+/** @file
+ PCCT Table Generator
+
+ Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.4 Specification - January 2021
+ s14 PLATFORM COMMUNICATIONS CHANNEL (PCC)
+
+**/
+
+#ifndef PCCT_GENERATOR_H_
+#define PCCT_GENERATOR_H_
+
+#pragma pack(1)
+
+/** Structure used to map a Pcc Subspace to an index.
+*/
+typedef struct MappingTable {
+ /// Mapping table for Subspace Ids.
+ /// Subspace ID/Index <-> CM_ARM_PCC_SUBSPACE_TYPE[X]_INFO pointer
+ VOID **Table;
+
+ /// Number of entries in the Table.
+ UINT32 MaxIndex;
+} MAPPING_TABLE;
+
+/** A structure holding the Pcct generator and additional private data.
+*/
+typedef struct AcpiPcctGenerator {
+ /// ACPI Table generator header
+ ACPI_TABLE_GENERATOR Header;
+
+ // Private fields are defined from here.
+
+ /// Table to map: Subspace ID/Index <-> CM_ARM_PCC_SUBSPACE_TYPE[X]_INFO pointer
+ MAPPING_TABLE MappingTable;
+} ACPI_PCCT_GENERATOR;
+
+#pragma pack()
+
+#endif // PCCT_GENERATOR_H_