mirror of https://github.com/acidanthera/audk.git
1187 lines
38 KiB
C
1187 lines
38 KiB
C
/** @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;
|
|
}
|