mirror of https://github.com/acidanthera/audk.git
1410 lines
42 KiB
C
1410 lines
42 KiB
C
/** @file
|
|
SSDT Cpu Topology Table Generator.
|
|
|
|
Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
@par Reference(s):
|
|
- ACPI 6.3 Specification - January 2019 - s8.4 Declaring Processors
|
|
**/
|
|
|
|
#include <Library/AcpiLib.h>
|
|
#include <Library/BaseLib.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/AcpiHelperLib.h>
|
|
#include <Library/TableHelperLib.h>
|
|
#include <Library/AmlLib/AmlLib.h>
|
|
#include <Protocol/ConfigurationManagerProtocol.h>
|
|
|
|
#include "SsdtCpuTopologyGenerator.h"
|
|
|
|
/** ARM standard SSDT Cpu Topology Table Generator.
|
|
|
|
Requirements:
|
|
The following Configuration Manager Object(s) are required by
|
|
this Generator:
|
|
- EArmObjGicCInfo
|
|
- EArmObjProcHierarchyInfo (OPTIONAL) along with
|
|
- EArmObjCmRef (OPTIONAL)
|
|
- EArmObjLpiInfo (OPTIONAL)
|
|
*/
|
|
|
|
/** This macro expands to a function that retrieves the GIC
|
|
CPU interface Information from the Configuration Manager.
|
|
*/
|
|
GET_OBJECT_LIST (
|
|
EObjNameSpaceArm,
|
|
EArmObjGicCInfo,
|
|
CM_ARM_GICC_INFO
|
|
);
|
|
|
|
/**
|
|
This macro expands to a function that retrieves the Processor Hierarchy
|
|
information from the Configuration Manager.
|
|
*/
|
|
GET_OBJECT_LIST (
|
|
EObjNameSpaceArm,
|
|
EArmObjProcHierarchyInfo,
|
|
CM_ARM_PROC_HIERARCHY_INFO
|
|
);
|
|
|
|
/**
|
|
This macro expands to a function that retrieves the cross-CM-object-
|
|
reference information from the Configuration Manager.
|
|
*/
|
|
GET_OBJECT_LIST (
|
|
EObjNameSpaceArm,
|
|
EArmObjCmRef,
|
|
CM_ARM_OBJ_REF
|
|
);
|
|
|
|
/**
|
|
This macro expands to a function that retrieves the Lpi
|
|
information from the Configuration Manager.
|
|
*/
|
|
GET_OBJECT_LIST (
|
|
EObjNameSpaceArm,
|
|
EArmObjLpiInfo,
|
|
CM_ARM_LPI_INFO
|
|
);
|
|
|
|
/**
|
|
This macro expands to a function that retrieves the CPC
|
|
information from the Configuration Manager.
|
|
*/
|
|
GET_OBJECT_LIST (
|
|
EObjNameSpaceArm,
|
|
EArmObjCpcInfo,
|
|
CM_ARM_CPC_INFO
|
|
);
|
|
|
|
/** Initialize the TokenTable.
|
|
|
|
One entry should be allocated for each CM_ARM_PROC_HIERARCHY_INFO
|
|
structure of the platform. The TokenTable allows to have a mapping:
|
|
Index <-> CM_OBJECT_TOKEN (to CM_ARM_LPI_INFO structures).
|
|
|
|
There will always be less sets of Lpi states (CM_ARM_OBJ_REF)
|
|
than the number of cpus/clusters (CM_ARM_PROC_HIERARCHY_INFO).
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] Count Number of entries to allocate in the TokenTable.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
TokenTableInitialize (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN UINT32 Count
|
|
)
|
|
{
|
|
CM_OBJECT_TOKEN *Table;
|
|
|
|
if ((Generator == NULL) ||
|
|
(Count == 0) ||
|
|
(Count >= MAX_NODE_COUNT))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Table = AllocateZeroPool (sizeof (CM_OBJECT_TOKEN) * Count);
|
|
if (Table == NULL) {
|
|
ASSERT (0);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Generator->TokenTable.Table = Table;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Free the TokenTable.
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
TokenTableFree (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator
|
|
)
|
|
{
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (Generator->TokenTable.Table != NULL);
|
|
|
|
if (Generator->TokenTable.Table != NULL) {
|
|
FreePool (Generator->TokenTable.Table);
|
|
}
|
|
}
|
|
|
|
/** Add a new entry to the TokenTable and return its index.
|
|
|
|
If an entry with Token is already available in the table,
|
|
return its index without adding a new entry.
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] Token New Token entry to add.
|
|
|
|
@retval The index of the token entry in the TokenTable.
|
|
**/
|
|
STATIC
|
|
UINT32
|
|
EFIAPI
|
|
TokenTableAdd (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CM_OBJECT_TOKEN Token
|
|
)
|
|
{
|
|
CM_OBJECT_TOKEN *Table;
|
|
UINT32 Index;
|
|
UINT32 LastIndex;
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (Generator->TokenTable.Table != NULL);
|
|
|
|
Table = Generator->TokenTable.Table;
|
|
LastIndex = Generator->TokenTable.LastIndex;
|
|
|
|
// Search if there is already an entry with this Token.
|
|
for (Index = 0; Index < LastIndex; Index++) {
|
|
if (Table[Index] == Token) {
|
|
return Index;
|
|
}
|
|
}
|
|
|
|
ASSERT (LastIndex < MAX_NODE_COUNT);
|
|
ASSERT (LastIndex < Generator->ProcNodeCount);
|
|
|
|
// If no, create a new entry.
|
|
Table[LastIndex] = Token;
|
|
|
|
return Generator->TokenTable.LastIndex++;
|
|
}
|
|
|
|
/** Write a string 'Xxxx\0' in AslName (5 bytes long),
|
|
with 'X' being the leading char of the name, and
|
|
with 'xxx' being Value in hexadecimal.
|
|
|
|
As 'xxx' in hexadecimal represents a number on 12 bits,
|
|
we have Value < (1 << 12).
|
|
|
|
@param [in] LeadChar Leading char of the name.
|
|
@param [in] Value Hex value of the name.
|
|
Must be lower than (2 << 12).
|
|
@param [in, out] AslName Pointer to write the 'Xxxx' string to.
|
|
Must be at least 5 bytes long.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WriteAslName (
|
|
IN CHAR8 LeadChar,
|
|
IN UINT32 Value,
|
|
IN OUT CHAR8 *AslName
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
if ((Value >= MAX_NODE_COUNT) ||
|
|
(AslName == NULL))
|
|
{
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AslName[0] = LeadChar;
|
|
AslName[AML_NAME_SEG_SIZE] = '\0';
|
|
|
|
for (Index = 0; Index < AML_NAME_SEG_SIZE - 1; Index++) {
|
|
AslName[AML_NAME_SEG_SIZE - Index - 1] =
|
|
AsciiFromHex (((Value >> (4 * Index)) & 0xF));
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Create and add an _CPC Node to Cpu Node.
|
|
|
|
For instance, transform an AML node from:
|
|
Device (C002)
|
|
{
|
|
Name (_UID, 2)
|
|
Name (_HID, "ACPI0007")
|
|
}
|
|
|
|
To:
|
|
Device (C002)
|
|
{
|
|
Name (_UID, 2)
|
|
Name (_HID, "ACPI0007")
|
|
Name(_CPC, Package()
|
|
{
|
|
NumEntries, // Integer
|
|
Revision, // Integer
|
|
HighestPerformance, // Integer or Buffer (Resource Descriptor)
|
|
NominalPerformance, // Integer or Buffer (Resource Descriptor)
|
|
LowestNonlinearPerformance, // Integer or Buffer (Resource Descriptor)
|
|
LowestPerformance, // Integer or Buffer (Resource Descriptor)
|
|
GuaranteedPerformanceRegister, // Buffer (Resource Descriptor)
|
|
DesiredPerformanceRegister , // Buffer (Resource Descriptor)
|
|
MinimumPerformanceRegister , // Buffer (Resource Descriptor)
|
|
MaximumPerformanceRegister , // Buffer (Resource Descriptor)
|
|
PerformanceReductionToleranceRegister, // Buffer (Resource Descriptor)
|
|
TimeWindowRegister, // Buffer (Resource Descriptor)
|
|
CounterWraparoundTime, // Integer or Buffer (Resource Descriptor)
|
|
ReferencePerformanceCounterRegister, // Buffer (Resource Descriptor)
|
|
DeliveredPerformanceCounterRegister, // Buffer (Resource Descriptor)
|
|
PerformanceLimitedRegister, // Buffer (Resource Descriptor)
|
|
CPPCEnableRegister // Buffer (Resource Descriptor)
|
|
AutonomousSelectionEnable, // Integer or Buffer (Resource Descriptor)
|
|
AutonomousActivityWindowRegister, // Buffer (Resource Descriptor)
|
|
EnergyPerformancePreferenceRegister, // Buffer (Resource Descriptor)
|
|
ReferencePerformance // Integer or Buffer (Resource Descriptor)
|
|
LowestFrequency, // Integer or Buffer (Resource Descriptor)
|
|
NominalFrequency // Integer or Buffer (Resource Descriptor)
|
|
})
|
|
}
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
@param [in] GicCInfo Pointer to the CM_ARM_GICC_INFO object
|
|
describing the Cpu.
|
|
@param [in] Node CPU Node to which the _CPC node is
|
|
attached.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateAmlCpcNode (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
|
|
IN CM_ARM_GICC_INFO *GicCInfo,
|
|
IN AML_OBJECT_NODE_HANDLE *Node
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CM_ARM_CPC_INFO *CpcInfo;
|
|
|
|
Status = GetEArmObjCpcInfo (
|
|
CfgMgrProtocol,
|
|
GicCInfo->CpcToken,
|
|
&CpcInfo,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlCreateCpcNode (
|
|
CpcInfo,
|
|
Node,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
|
|
/** Create and add an _LPI method to Cpu/Cluster Node.
|
|
|
|
For instance, transform an AML node from:
|
|
Device (C002)
|
|
{
|
|
Name (_UID, 2)
|
|
Name (_HID, "ACPI0007")
|
|
}
|
|
|
|
To:
|
|
Device (C002)
|
|
{
|
|
Name (_UID, 2)
|
|
Name (_HID, "ACPI0007")
|
|
Method (_LPI, 0, NotSerialized)
|
|
{
|
|
Return (\_SB.L003)
|
|
}
|
|
}
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
|
|
the Cpu.
|
|
@param [in] Node Node to which the _LPI method is
|
|
attached. Can represent a Cpu or a
|
|
Cluster.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateAmlLpiMethod (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeInfo,
|
|
IN AML_OBJECT_NODE_HANDLE *Node
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 TokenIndex;
|
|
CHAR8 AslName[SB_SCOPE_PREFIX_SIZE + AML_NAME_SEG_SIZE];
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (ProcHierarchyNodeInfo != NULL);
|
|
ASSERT (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN);
|
|
ASSERT (Node != NULL);
|
|
|
|
TokenIndex = TokenTableAdd (Generator, ProcHierarchyNodeInfo->LpiToken);
|
|
|
|
CopyMem (AslName, SB_SCOPE_PREFIX, SB_SCOPE_PREFIX_SIZE);
|
|
|
|
Status = WriteAslName (
|
|
'L',
|
|
TokenIndex,
|
|
AslName + SB_SCOPE_PREFIX_SIZE - 1
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// ASL:
|
|
// Method (_LPI, 0) {
|
|
// Return ([AslName])
|
|
// }
|
|
Status = AmlCodeGenMethodRetNameString (
|
|
"_LPI",
|
|
AslName,
|
|
0,
|
|
FALSE,
|
|
0,
|
|
Node,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Generate all the Lpi states under the '_SB' scope.
|
|
|
|
This function generates the following ASL code:
|
|
Scope (\_SB) {
|
|
Name (L000, Package() {
|
|
0, // Version
|
|
0, // Level Index
|
|
X, // Count
|
|
Package() {
|
|
[An Lpi state]
|
|
},
|
|
Package() {
|
|
[Another Lpi state]
|
|
},
|
|
} // Name L000
|
|
|
|
Name (L001, Package() {
|
|
...
|
|
} // Name L001
|
|
|
|
...
|
|
} // Scope /_SB
|
|
|
|
The Lpi states are fetched from the Configuration Manager.
|
|
The names of the Lpi states are generated from the TokenTable.
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
@param [in] ScopeNode Scope node handle ('\_SB' scope).
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GenerateLpiStates (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
|
|
IN AML_OBJECT_NODE_HANDLE ScopeNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 Index;
|
|
UINT32 LastIndex;
|
|
|
|
AML_OBJECT_NODE_HANDLE LpiNode;
|
|
CM_ARM_OBJ_REF *LpiRefInfo;
|
|
UINT32 LpiRefInfoCount;
|
|
UINT32 LpiRefIndex;
|
|
CM_ARM_LPI_INFO *LpiInfo;
|
|
CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (Generator->TokenTable.Table != NULL);
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
ASSERT (ScopeNode != NULL);
|
|
|
|
LastIndex = Generator->TokenTable.LastIndex;
|
|
|
|
// For each entry in the TokenTable, create a name in the AML namespace
|
|
// under SB_SCOPE, to store the Lpi states associated with the LpiToken.
|
|
for (Index = 0; Index < LastIndex; Index++) {
|
|
Status = WriteAslName ('L', Index, AslName);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// We do not support the LevelId field for now, let it to 0.
|
|
Status = AmlCreateLpiNode (AslName, 0, 0, ScopeNode, &LpiNode);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Fetch the LPI objects referenced by the token.
|
|
Status = GetEArmObjCmRef (
|
|
CfgMgrProtocol,
|
|
Generator->TokenTable.Table[Index],
|
|
&LpiRefInfo,
|
|
&LpiRefInfoCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
for (LpiRefIndex = 0; LpiRefIndex < LpiRefInfoCount; LpiRefIndex++) {
|
|
// For each CM_ARM_LPI_INFO referenced by the token, add an Lpi state.
|
|
Status = GetEArmObjLpiInfo (
|
|
CfgMgrProtocol,
|
|
LpiRefInfo[LpiRefIndex].ReferenceToken,
|
|
&LpiInfo,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlAddLpiState (
|
|
LpiInfo->MinResidency,
|
|
LpiInfo->WorstCaseWakeLatency,
|
|
LpiInfo->Flags,
|
|
LpiInfo->ArchFlags,
|
|
LpiInfo->ResCntFreq,
|
|
LpiInfo->EnableParentState,
|
|
LpiInfo->IsInteger ?
|
|
NULL :
|
|
&LpiInfo->RegisterEntryMethod,
|
|
LpiInfo->IsInteger ?
|
|
LpiInfo->IntegerEntryMethod :
|
|
0,
|
|
&LpiInfo->ResidencyCounterRegister,
|
|
&LpiInfo->UsageCounterRegister,
|
|
LpiInfo->StateName,
|
|
LpiNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
} // for LpiRefIndex
|
|
} // for Index
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Create a Cpu in the AML namespace.
|
|
|
|
This generates the following ASL code:
|
|
Device (C002)
|
|
{
|
|
Name (_UID, 2)
|
|
Name (_HID, "ACPI0007")
|
|
}
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] ParentNode Parent node to attach the Cpu node to.
|
|
@param [in] GicCInfo CM_ARM_GICC_INFO object used to create the node.
|
|
@param [in] CpuName Value used to generate the node name.
|
|
@param [out] CpuNodePtr If not NULL, return the created Cpu node.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateAmlCpu (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN AML_NODE_HANDLE ParentNode,
|
|
IN CM_ARM_GICC_INFO *GicCInfo,
|
|
IN UINT32 CpuName,
|
|
OUT AML_OBJECT_NODE_HANDLE *CpuNodePtr OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
AML_OBJECT_NODE_HANDLE CpuNode;
|
|
CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (ParentNode != NULL);
|
|
ASSERT (GicCInfo != NULL);
|
|
|
|
Status = WriteAslName ('C', CpuName, AslName);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlCodeGenDevice (AslName, ParentNode, &CpuNode);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlCodeGenNameInteger (
|
|
"_UID",
|
|
GicCInfo->AcpiProcessorUid,
|
|
CpuNode,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlCodeGenNameString (
|
|
"_HID",
|
|
ACPI_HID_PROCESSOR_DEVICE,
|
|
CpuNode,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// If requested, return the handle to the CpuNode.
|
|
if (CpuNodePtr != NULL) {
|
|
*CpuNodePtr = CpuNode;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Create a Cpu in the AML namespace from a CM_ARM_PROC_HIERARCHY_INFO
|
|
CM object.
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
@param [in] ParentNode Parent node to attach the Cpu node to.
|
|
@param [in] CpuName Value used to generate the node name.
|
|
@param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
|
|
the Cpu.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateAmlCpuFromProcHierarchy (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
|
|
IN AML_NODE_HANDLE ParentNode,
|
|
IN UINT32 CpuName,
|
|
IN CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CM_ARM_GICC_INFO *GicCInfo;
|
|
AML_OBJECT_NODE_HANDLE CpuNode;
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
ASSERT (ParentNode != NULL);
|
|
ASSERT (ProcHierarchyNodeInfo != NULL);
|
|
ASSERT (ProcHierarchyNodeInfo->GicCToken != CM_NULL_TOKEN);
|
|
|
|
Status = GetEArmObjGicCInfo (
|
|
CfgMgrProtocol,
|
|
ProcHierarchyNodeInfo->GicCToken,
|
|
&GicCInfo,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = CreateAmlCpu (Generator, ParentNode, GicCInfo, CpuName, &CpuNode);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// If a set of Lpi states is associated with the
|
|
// CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
|
|
if (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN) {
|
|
Status = CreateAmlLpiMethod (Generator, ProcHierarchyNodeInfo, CpuNode);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
// If a CPC info is associated with the
|
|
// GicCinfo, create an _CPC method returning them.
|
|
if (GicCInfo->CpcToken != CM_NULL_TOKEN) {
|
|
Status = CreateAmlCpcNode (Generator, CfgMgrProtocol, GicCInfo, CpuNode);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Create a Processor Container in the AML namespace.
|
|
|
|
Any CM_ARM_PROC_HIERARCHY_INFO object with the following flags is
|
|
assumed to be a processor container:
|
|
- EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL
|
|
- EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID
|
|
- EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF
|
|
|
|
This generates the following ASL code:
|
|
Device (C002)
|
|
{
|
|
Name (_UID, 2)
|
|
Name (_HID, "ACPI0010")
|
|
}
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
@param [in] ParentNode Parent node to attach the processor
|
|
container node to.
|
|
@param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO object used
|
|
to create the node.
|
|
@param [in] ProcContainerIndex Index used to generate the node name.
|
|
@param [out] ProcContainerNodePtr If success, contains the created processor
|
|
container node.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateAmlProcessorContainer (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
|
|
IN AML_NODE_HANDLE ParentNode,
|
|
IN CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeInfo,
|
|
IN UINT16 ProcContainerName,
|
|
IN UINT32 ProcContainerUid,
|
|
OUT AML_OBJECT_NODE_HANDLE *ProcContainerNodePtr
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
AML_OBJECT_NODE_HANDLE ProcContainerNode;
|
|
CHAR8 AslNameProcContainer[AML_NAME_SEG_SIZE + 1];
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
ASSERT (ParentNode != NULL);
|
|
ASSERT (ProcHierarchyNodeInfo != NULL);
|
|
ASSERT (ProcContainerNodePtr != NULL);
|
|
|
|
Status = WriteAslName ('C', ProcContainerName, AslNameProcContainer);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlCodeGenDevice (AslNameProcContainer, ParentNode, &ProcContainerNode);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Use the ProcContainerIndex for the _UID value as there is no AcpiProcessorUid
|
|
// and EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID is set for non-Cpus.
|
|
Status = AmlCodeGenNameInteger (
|
|
"_UID",
|
|
ProcContainerUid,
|
|
ProcContainerNode,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlCodeGenNameString (
|
|
"_HID",
|
|
ACPI_HID_PROCESSOR_CONTAINER_DEVICE,
|
|
ProcContainerNode,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// If a set of Lpi states are associated with the
|
|
// CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
|
|
if (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN) {
|
|
Status = CreateAmlLpiMethod (
|
|
Generator,
|
|
ProcHierarchyNodeInfo,
|
|
ProcContainerNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
*ProcContainerNodePtr = ProcContainerNode;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Check flags and topology of a ProcNode.
|
|
|
|
@param [in] NodeFlags Flags of the ProcNode to check.
|
|
@param [in] IsLeaf The ProcNode is a leaf.
|
|
@param [in] NodeToken NodeToken of the ProcNode.
|
|
@param [in] ParentNodeToken Parent NodeToken of the ProcNode.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CheckProcNode (
|
|
UINT32 NodeFlags,
|
|
BOOLEAN IsLeaf,
|
|
CM_OBJECT_TOKEN NodeToken,
|
|
CM_OBJECT_TOKEN ParentNodeToken
|
|
)
|
|
{
|
|
BOOLEAN InvalidFlags;
|
|
BOOLEAN HasPhysicalPackageBit;
|
|
BOOLEAN IsTopLevelNode;
|
|
|
|
HasPhysicalPackageBit = (NodeFlags & EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL) ==
|
|
EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL;
|
|
IsTopLevelNode = (ParentNodeToken == CM_NULL_TOKEN);
|
|
|
|
// A top-level node is a Physical Package and conversely.
|
|
InvalidFlags = HasPhysicalPackageBit ^ IsTopLevelNode;
|
|
|
|
// Check Leaf specific flags.
|
|
if (IsLeaf) {
|
|
InvalidFlags |= ((NodeFlags & PPTT_LEAF_MASK) != PPTT_LEAF_MASK);
|
|
} else {
|
|
InvalidFlags |= ((NodeFlags & PPTT_LEAF_MASK) != 0);
|
|
}
|
|
|
|
if (InvalidFlags) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for ProcNode: 0x%p.\n",
|
|
(VOID *)NodeToken
|
|
));
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Create an AML representation of the Cpu topology.
|
|
|
|
A processor container is by extension any non-leave device in the cpu topology.
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
@param [in] NodeToken Token of the CM_ARM_PROC_HIERARCHY_INFO
|
|
currently handled.
|
|
@param [in] ParentNode Parent node to attach the created
|
|
node to.
|
|
@param [in,out] ProcContainerIndex Pointer to the current processor container
|
|
index to be used as UID.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateAmlCpuTopologyTree (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
|
|
IN CM_OBJECT_TOKEN NodeToken,
|
|
IN AML_NODE_HANDLE ParentNode,
|
|
IN OUT UINT32 *ProcContainerIndex
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 Index;
|
|
UINT32 CpuIndex;
|
|
UINT32 ProcContainerName;
|
|
AML_OBJECT_NODE_HANDLE ProcContainerNode;
|
|
UINT32 Uid;
|
|
UINT16 Name;
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (Generator->ProcNodeList != NULL);
|
|
ASSERT (Generator->ProcNodeCount != 0);
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
ASSERT (ParentNode != NULL);
|
|
ASSERT (ProcContainerIndex != NULL);
|
|
|
|
CpuIndex = 0;
|
|
ProcContainerName = 0;
|
|
|
|
for (Index = 0; Index < Generator->ProcNodeCount; Index++) {
|
|
// Find the children of the CM_ARM_PROC_HIERARCHY_INFO
|
|
// currently being handled (i.e. ParentToken == NodeToken).
|
|
if (Generator->ProcNodeList[Index].ParentToken == NodeToken) {
|
|
// Only Cpus (leaf nodes in this tree) have a GicCToken.
|
|
// Create a Cpu node.
|
|
if (Generator->ProcNodeList[Index].GicCToken != CM_NULL_TOKEN) {
|
|
Status = CheckProcNode (
|
|
Generator->ProcNodeList[Index].Flags,
|
|
TRUE,
|
|
Generator->ProcNodeList[Index].Token,
|
|
NodeToken
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
if (Generator->ProcNodeList[Index].OverrideNameUidEnabled) {
|
|
Name = Generator->ProcNodeList[Index].OverrideName;
|
|
} else {
|
|
Name = CpuIndex;
|
|
}
|
|
|
|
Status = CreateAmlCpuFromProcHierarchy (
|
|
Generator,
|
|
CfgMgrProtocol,
|
|
ParentNode,
|
|
Name,
|
|
&Generator->ProcNodeList[Index]
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
CpuIndex++;
|
|
} else {
|
|
// If this is not a Cpu, then this is a processor container.
|
|
|
|
Status = CheckProcNode (
|
|
Generator->ProcNodeList[Index].Flags,
|
|
FALSE,
|
|
Generator->ProcNodeList[Index].Token,
|
|
NodeToken
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
if (Generator->ProcNodeList[Index].OverrideNameUidEnabled) {
|
|
Name = Generator->ProcNodeList[Index].OverrideName;
|
|
Uid = Generator->ProcNodeList[Index].OverrideUid;
|
|
} else {
|
|
Name = ProcContainerName;
|
|
Uid = *ProcContainerIndex;
|
|
}
|
|
|
|
Status = CreateAmlProcessorContainer (
|
|
Generator,
|
|
CfgMgrProtocol,
|
|
ParentNode,
|
|
&Generator->ProcNodeList[Index],
|
|
Name,
|
|
Uid,
|
|
&ProcContainerNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Nodes must have a unique name in the ASL namespace.
|
|
// Reset the Cpu index whenever we create a new processor container.
|
|
(*ProcContainerIndex)++;
|
|
CpuIndex = 0;
|
|
|
|
// And reset the cluster name whenever there is a package.
|
|
if (NodeToken == CM_NULL_TOKEN) {
|
|
ProcContainerName = 0;
|
|
} else {
|
|
ProcContainerName++;
|
|
}
|
|
|
|
// Recursively continue creating an AML tree.
|
|
Status = CreateAmlCpuTopologyTree (
|
|
Generator,
|
|
CfgMgrProtocol,
|
|
Generator->ProcNodeList[Index].Token,
|
|
ProcContainerNode,
|
|
ProcContainerIndex
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
} // if ParentToken == NodeToken
|
|
} // for
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Create the processor hierarchy AML tree from CM_ARM_PROC_HIERARCHY_INFO
|
|
CM objects.
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
@param [in] ScopeNode Scope node handle ('\_SB' scope).
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateTopologyFromProcHierarchy (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
|
|
IN AML_OBJECT_NODE_HANDLE ScopeNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 ProcContainerIndex;
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (Generator->ProcNodeCount != 0);
|
|
ASSERT (Generator->ProcNodeList != NULL);
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
ASSERT (ScopeNode != NULL);
|
|
|
|
ProcContainerIndex = 0;
|
|
|
|
Status = TokenTableInitialize (Generator, Generator->ProcNodeCount);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = CreateAmlCpuTopologyTree (
|
|
Generator,
|
|
CfgMgrProtocol,
|
|
CM_NULL_TOKEN,
|
|
ScopeNode,
|
|
&ProcContainerIndex
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
Status = GenerateLpiStates (Generator, CfgMgrProtocol, ScopeNode);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
exit_handler:
|
|
TokenTableFree (Generator);
|
|
return Status;
|
|
}
|
|
|
|
/** Create the processor hierarchy AML tree from CM_ARM_GICC_INFO
|
|
CM objects.
|
|
|
|
A processor container is by extension any non-leave device in the cpu topology.
|
|
|
|
@param [in] Generator The SSDT Cpu Topology generator.
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
@param [in] ScopeNode Scope node handle ('\_SB' scope).
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CreateTopologyFromGicC (
|
|
IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
|
|
IN AML_OBJECT_NODE_HANDLE ScopeNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CM_ARM_GICC_INFO *GicCInfo;
|
|
UINT32 GicCInfoCount;
|
|
UINT32 Index;
|
|
AML_OBJECT_NODE_HANDLE CpuNode;
|
|
|
|
ASSERT (Generator != NULL);
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
ASSERT (ScopeNode != NULL);
|
|
|
|
Status = GetEArmObjGicCInfo (
|
|
CfgMgrProtocol,
|
|
CM_NULL_TOKEN,
|
|
&GicCInfo,
|
|
&GicCInfoCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// For each CM_ARM_GICC_INFO object, create an AML node.
|
|
for (Index = 0; Index < GicCInfoCount; Index++) {
|
|
Status = CreateAmlCpu (
|
|
Generator,
|
|
ScopeNode,
|
|
&GicCInfo[Index],
|
|
Index,
|
|
&CpuNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
break;
|
|
}
|
|
|
|
// If a CPC info is associated with the
|
|
// GicCinfo, create an _CPC method returning them.
|
|
if (GicCInfo->CpcToken != CM_NULL_TOKEN) {
|
|
Status = CreateAmlCpcNode (Generator, CfgMgrProtocol, &GicCInfo[Index], CpuNode);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
break;
|
|
}
|
|
}
|
|
} // for
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Construct the SSDT Cpu Topology ACPI table.
|
|
|
|
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.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BuildSsdtCpuTopologyTable (
|
|
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;
|
|
AML_ROOT_NODE_HANDLE RootNode;
|
|
AML_OBJECT_NODE_HANDLE ScopeNode;
|
|
CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeList;
|
|
UINT32 ProcHierarchyNodeCount;
|
|
ACPI_CPU_TOPOLOGY_GENERATOR *Generator;
|
|
|
|
ASSERT (This != NULL);
|
|
ASSERT (AcpiTableInfo != NULL);
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
ASSERT (Table != NULL);
|
|
ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
|
|
ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
|
|
|
|
Generator = (ACPI_CPU_TOPOLOGY_GENERATOR *)This;
|
|
|
|
Status = AddSsdtAcpiHeader (
|
|
CfgMgrProtocol,
|
|
This,
|
|
AcpiTableInfo,
|
|
&RootNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
|
|
if (EFI_ERROR (Status)) {
|
|
goto exit_handler;
|
|
}
|
|
|
|
// Get the processor hierarchy info and update the processor topology
|
|
// structure count with Processor Hierarchy Nodes (Type 0)
|
|
Status = GetEArmObjProcHierarchyInfo (
|
|
CfgMgrProtocol,
|
|
CM_NULL_TOKEN,
|
|
&ProcHierarchyNodeList,
|
|
&ProcHierarchyNodeCount
|
|
);
|
|
if (EFI_ERROR (Status) &&
|
|
(Status != EFI_NOT_FOUND))
|
|
{
|
|
goto exit_handler;
|
|
}
|
|
|
|
if (Status == EFI_NOT_FOUND) {
|
|
// If hierarchy information is not found generate a flat topology
|
|
// using CM_ARM_GICC_INFO objects.
|
|
Status = CreateTopologyFromGicC (
|
|
Generator,
|
|
CfgMgrProtocol,
|
|
ScopeNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto exit_handler;
|
|
}
|
|
} else {
|
|
// Generate the topology from CM_ARM_PROC_HIERARCHY_INFO objects.
|
|
Generator->ProcNodeList = ProcHierarchyNodeList;
|
|
Generator->ProcNodeCount = ProcHierarchyNodeCount;
|
|
|
|
Status = CreateTopologyFromProcHierarchy (
|
|
Generator,
|
|
CfgMgrProtocol,
|
|
ScopeNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto exit_handler;
|
|
}
|
|
}
|
|
|
|
Status = AmlSerializeDefinitionBlock (
|
|
RootNode,
|
|
Table
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: SSDT-CPU-TOPOLOGY: Failed to Serialize SSDT Table Data."
|
|
" Status = %r\n",
|
|
Status
|
|
));
|
|
goto exit_handler;
|
|
}
|
|
|
|
exit_handler:
|
|
// Delete the RootNode and its attached children.
|
|
return AmlDeleteTree (RootNode);
|
|
}
|
|
|
|
/** Free any resources allocated for constructing the
|
|
SSDT Cpu Topology ACPI table.
|
|
|
|
@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
|
|
FreeSsdtCpuTopologyTableResources (
|
|
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: SSDT-CPU-TOPOLOGY: Invalid Table Pointer\n"));
|
|
ASSERT ((Table != NULL) && (*Table != NULL));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
FreePool (*Table);
|
|
*Table = NULL;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** This macro defines the SSDT Cpu Topology Table Generator revision.
|
|
*/
|
|
#define SSDT_CPU_TOPOLOGY_GENERATOR_REVISION CREATE_REVISION (1, 0)
|
|
|
|
/** The interface for the SSDT Cpu Topology Table Generator.
|
|
*/
|
|
STATIC
|
|
ACPI_CPU_TOPOLOGY_GENERATOR SsdtCpuTopologyGenerator = {
|
|
// ACPI table generator header
|
|
{
|
|
// Generator ID
|
|
CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCpuTopology),
|
|
// Generator Description
|
|
L"ACPI.STD.SSDT.CPU.TOPOLOGY.GENERATOR",
|
|
// ACPI Table Signature
|
|
EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
|
|
// ACPI Table Revision - Unused
|
|
0,
|
|
// Minimum ACPI Table Revision - Unused
|
|
0,
|
|
// Creator ID
|
|
TABLE_GENERATOR_CREATOR_ID_ARM,
|
|
// Creator Revision
|
|
SSDT_CPU_TOPOLOGY_GENERATOR_REVISION,
|
|
// Build Table function
|
|
BuildSsdtCpuTopologyTable,
|
|
// Free Resource function
|
|
FreeSsdtCpuTopologyTableResources,
|
|
// 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.
|
|
|
|
// TokenTable
|
|
{
|
|
// Table
|
|
NULL,
|
|
// LastIndex
|
|
0
|
|
},
|
|
// ProcNodeList
|
|
NULL,
|
|
// ProcNodeCount
|
|
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
|
|
AcpiSsdtCpuTopologyLibConstructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = RegisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"SSDT-CPU-TOPOLOGY: 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
|
|
AcpiSsdtCpuTopologyLibDestructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = DeregisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"SSDT-CPU-TOPOLOGY: Deregister Generator. Status = %r\n",
|
|
Status
|
|
));
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|