2 SSDT Cpu Topology Table Generator.
4 Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - ACPI 6.3 Specification - January 2019 - s8.4 Declaring Processors
11 #include <Library/AcpiLib.h>
12 #include <Library/BaseLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Protocol/AcpiTable.h>
18 // Module specific include files.
19 #include <AcpiTableGenerator.h>
20 #include <ConfigurationManagerObject.h>
21 #include <ConfigurationManagerHelper.h>
22 #include <Library/AcpiHelperLib.h>
23 #include <Library/TableHelperLib.h>
24 #include <Library/AmlLib/AmlLib.h>
25 #include <Protocol/ConfigurationManagerProtocol.h>
27 #include "SsdtCpuTopologyGenerator.h"
29 /** ARM standard SSDT Cpu Topology Table Generator.
32 The following Configuration Manager Object(s) are required by
35 - EArmObjProcHierarchyInfo (OPTIONAL) along with
36 - EArmObjCmRef (OPTIONAL)
37 - EArmObjLpiInfo (OPTIONAL)
40 /** This macro expands to a function that retrieves the GIC
41 CPU interface Information from the Configuration Manager.
50 This macro expands to a function that retrieves the Processor Hierarchy
51 information from the Configuration Manager.
55 EArmObjProcHierarchyInfo
,
56 CM_ARM_PROC_HIERARCHY_INFO
60 This macro expands to a function that retrieves the cross-CM-object-
61 reference information from the Configuration Manager.
70 This macro expands to a function that retrieves the Lpi
71 information from the Configuration Manager.
79 /** Initialize the TokenTable.
81 One entry should be allocated for each CM_ARM_PROC_HIERARCHY_INFO
82 structure of the platform. The TokenTable allows to have a mapping:
83 Index <-> CM_OBJECT_TOKEN (to CM_ARM_LPI_INFO structures).
85 There will always be less sets of Lpi states (CM_ARM_OBJ_REF)
86 than the number of cpus/clusters (CM_ARM_PROC_HIERARCHY_INFO).
88 @param [in] Generator The SSDT Cpu Topology generator.
89 @param [in] Count Number of entries to allocate in the TokenTable.
91 @retval EFI_SUCCESS Success.
92 @retval EFI_INVALID_PARAMETER Invalid parameter.
93 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
98 TokenTableInitialize (
99 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
103 CM_OBJECT_TOKEN
* Table
;
105 if ((Generator
== NULL
) ||
107 (Count
>= MAX_NODE_COUNT
)) {
109 return EFI_INVALID_PARAMETER
;
112 Table
= AllocateZeroPool (sizeof (CM_OBJECT_TOKEN
) * Count
);
115 return EFI_OUT_OF_RESOURCES
;
118 Generator
->TokenTable
.Table
= Table
;
123 /** Free the TokenTable.
125 @param [in] Generator The SSDT Cpu Topology generator.
131 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
134 ASSERT (Generator
!= NULL
);
135 ASSERT (Generator
->TokenTable
.Table
!= NULL
);
137 if (Generator
->TokenTable
.Table
!= NULL
) {
138 FreePool (Generator
->TokenTable
.Table
);
142 /** Add a new entry to the TokenTable and return its index.
144 If an entry with Token is already available in the table,
145 return its index without adding a new entry.
147 @param [in] Generator The SSDT Cpu Topology generator.
148 @param [in] Token New Token entry to add.
150 @retval The index of the token entry in the TokenTable.
156 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
157 IN CM_OBJECT_TOKEN Token
160 CM_OBJECT_TOKEN
* Table
;
164 ASSERT (Generator
!= NULL
);
165 ASSERT (Generator
->TokenTable
.Table
!= NULL
);
167 Table
= Generator
->TokenTable
.Table
;
168 LastIndex
= Generator
->TokenTable
.LastIndex
;
170 // Search if there is already an entry with this Token.
171 for (Index
= 0; Index
< LastIndex
; Index
++) {
172 if (Table
[Index
] == Token
) {
177 ASSERT (LastIndex
< MAX_NODE_COUNT
);
178 ASSERT (LastIndex
< Generator
->ProcNodeCount
);
180 // If no, create a new entry.
181 Table
[LastIndex
] = Token
;
183 return Generator
->TokenTable
.LastIndex
++;
186 /** Write a string 'Xxxx\0' in AslName (5 bytes long),
187 with 'X' being the leading char of the name, and
188 with 'xxx' being Value in hexadecimal.
190 As 'xxx' in hexadecimal represents a number on 12 bits,
191 we have Value < (1 << 12).
193 @param [in] LeadChar Leading char of the name.
194 @param [in] Value Hex value of the name.
195 Must be lower than (2 << 12).
196 @param [in, out] AslName Pointer to write the 'Xxxx' string to.
197 Must be at least 5 bytes long.
199 @retval EFI_SUCCESS Success.
200 @retval EFI_INVALID_PARAMETER Invalid parameter.
208 IN OUT CHAR8
* AslName
213 if ((Value
>= MAX_NODE_COUNT
) ||
216 return EFI_INVALID_PARAMETER
;
219 AslName
[0] = LeadChar
;
220 AslName
[AML_NAME_SEG_SIZE
] = '\0';
222 for (Index
= 0; Index
< AML_NAME_SEG_SIZE
- 1; Index
++) {
223 AslName
[AML_NAME_SEG_SIZE
- Index
- 1] =
224 AsciiFromHex (((Value
>> (4 * Index
)) & 0xF));
230 /** Create and add an _LPI method to Cpu/Cluster Node.
232 For instance, transform an AML node from:
236 Name (_HID, "ACPI0007")
243 Name (_HID, "ACPI0007")
244 Method (_LPI, 0, NotSerialized)
250 @param [in] Generator The SSDT Cpu Topology generator.
251 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
253 @param [in] Node Node to which the _LPI method is
254 attached. Can represent a Cpu or a
257 @retval EFI_SUCCESS The function completed successfully.
258 @retval EFI_INVALID_PARAMETER Invalid parameter.
259 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
265 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
266 IN CM_ARM_PROC_HIERARCHY_INFO
* ProcHierarchyNodeInfo
,
267 IN AML_OBJECT_NODE_HANDLE
* Node
272 CHAR8 AslName
[SB_SCOPE_PREFIX_SIZE
+ AML_NAME_SEG_SIZE
];
274 ASSERT (Generator
!= NULL
);
275 ASSERT (ProcHierarchyNodeInfo
!= NULL
);
276 ASSERT (ProcHierarchyNodeInfo
->LpiToken
!= CM_NULL_TOKEN
);
277 ASSERT (Node
!= NULL
);
279 TokenIndex
= TokenTableAdd (Generator
, ProcHierarchyNodeInfo
->LpiToken
);
281 CopyMem (AslName
, SB_SCOPE_PREFIX
, SB_SCOPE_PREFIX_SIZE
);
283 Status
= WriteAslName (
286 AslName
+ SB_SCOPE_PREFIX_SIZE
- 1
288 if (EFI_ERROR (Status
)) {
294 // Method (_LPI, 0) {
295 // Return ([AslName])
297 Status
= AmlCodeGenMethodRetNameString (
306 if (EFI_ERROR (Status
)) {
313 /** Generate all the Lpi states under the '_SB' scope.
315 This function generates the following ASL code:
317 Name (L000, Package() {
329 Name (L001, Package() {
336 The Lpi states are fetched from the Configuration Manager.
337 The names of the Lpi states are generated from the TokenTable.
339 @param [in] Generator The SSDT Cpu Topology generator.
340 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
342 @param [in] ScopeNode Scope node handle ('\_SB' scope).
344 @retval EFI_SUCCESS Success.
345 @retval EFI_INVALID_PARAMETER Invalid parameter.
346 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
352 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
353 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
354 IN AML_OBJECT_NODE_HANDLE ScopeNode
362 AML_OBJECT_NODE_HANDLE LpiNode
;
363 CM_ARM_OBJ_REF
* LpiRefInfo
;
364 UINT32 LpiRefInfoCount
;
366 CM_ARM_LPI_INFO
* LpiInfo
;
367 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
369 ASSERT (Generator
!= NULL
);
370 ASSERT (Generator
->TokenTable
.Table
!= NULL
);
371 ASSERT (CfgMgrProtocol
!= NULL
);
372 ASSERT (ScopeNode
!= NULL
);
374 LastIndex
= Generator
->TokenTable
.LastIndex
;
376 // For each entry in the TokenTable, create a name in the AML namespace
377 // under SB_SCOPE, to store the Lpi states associated with the LpiToken.
378 for (Index
= 0; Index
< LastIndex
; Index
++) {
379 Status
= WriteAslName ('L', Index
, AslName
);
380 if (EFI_ERROR (Status
)) {
385 // We do not support the LevelId field for now, let it to 0.
386 Status
= AmlCreateLpiNode (AslName
, 1, 0, ScopeNode
, &LpiNode
);
387 if (EFI_ERROR (Status
)) {
392 // Fetch the LPI objects referenced by the token.
393 Status
= GetEArmObjCmRef (
395 Generator
->TokenTable
.Table
[Index
],
399 if (EFI_ERROR (Status
)) {
404 for (LpiRefIndex
= 0; LpiRefIndex
< LpiRefInfoCount
; LpiRefIndex
++) {
405 // For each CM_ARM_LPI_INFO referenced by the token, add an Lpi state.
406 Status
= GetEArmObjLpiInfo (
408 LpiRefInfo
[LpiRefIndex
].ReferenceToken
,
412 if (EFI_ERROR (Status
)) {
417 Status
= AmlAddLpiState (
418 LpiInfo
->MinResidency
,
419 LpiInfo
->WorstCaseWakeLatency
,
423 LpiInfo
->EnableParentState
,
426 &LpiInfo
->RegisterEntryMethod
,
428 LpiInfo
->IntegerEntryMethod
:
430 &LpiInfo
->ResidencyCounterRegister
,
431 &LpiInfo
->UsageCounterRegister
,
435 if (EFI_ERROR (Status
)) {
445 /** Create a Cpu in the AML namespace.
447 This generates the following ASL code:
451 Name (_HID, "ACPI0007")
454 @param [in] Generator The SSDT Cpu Topology generator.
455 @param [in] ParentNode Parent node to attach the Cpu node to.
456 @param [in] GicCInfo CM_ARM_GICC_INFO object used to create the node.
457 @param [in] CpuIndex Index used to generate the node name.
458 @param [out] CpuNodePtr If not NULL, return the created Cpu node.
460 @retval EFI_SUCCESS Success.
461 @retval EFI_INVALID_PARAMETER Invalid parameter.
462 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
468 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
469 IN AML_NODE_HANDLE ParentNode
,
470 IN CM_ARM_GICC_INFO
* GicCInfo
,
472 OUT AML_OBJECT_NODE_HANDLE
* CpuNodePtr OPTIONAL
476 AML_OBJECT_NODE_HANDLE CpuNode
;
477 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
479 ASSERT (Generator
!= NULL
);
480 ASSERT (ParentNode
!= NULL
);
481 ASSERT (GicCInfo
!= NULL
);
483 Status
= WriteAslName ('C', CpuIndex
, AslName
);
484 if (EFI_ERROR (Status
)) {
489 Status
= AmlCodeGenDevice (AslName
, ParentNode
, &CpuNode
);
490 if (EFI_ERROR (Status
)) {
495 Status
= AmlCodeGenNameInteger (
497 GicCInfo
->AcpiProcessorUid
,
501 if (EFI_ERROR (Status
)) {
506 Status
= AmlCodeGenNameString (
508 ACPI_HID_PROCESSOR_DEVICE
,
512 if (EFI_ERROR (Status
)) {
517 // If requested, return the handle to the CpuNode.
518 if (CpuNodePtr
!= NULL
) {
519 *CpuNodePtr
= CpuNode
;
525 /** Create a Cpu in the AML namespace from a CM_ARM_PROC_HIERARCHY_INFO
528 @param [in] Generator The SSDT Cpu Topology generator.
529 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
531 @param [in] ParentNode Parent node to attach the Cpu node to.
532 @param [in] CpuIndex Index used to generate the node name.
533 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
536 @retval EFI_SUCCESS Success.
537 @retval EFI_INVALID_PARAMETER Invalid parameter.
538 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
543 CreateAmlCpuFromProcHierarchy (
544 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
545 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
546 IN AML_NODE_HANDLE ParentNode
,
548 IN CM_ARM_PROC_HIERARCHY_INFO
* ProcHierarchyNodeInfo
552 CM_ARM_GICC_INFO
* GicCInfo
;
553 AML_OBJECT_NODE_HANDLE CpuNode
;
555 ASSERT (Generator
!= NULL
);
556 ASSERT (CfgMgrProtocol
!= NULL
);
557 ASSERT (ParentNode
!= NULL
);
558 ASSERT (ProcHierarchyNodeInfo
!= NULL
);
559 ASSERT (ProcHierarchyNodeInfo
->GicCToken
!= CM_NULL_TOKEN
);
561 Status
= GetEArmObjGicCInfo (
563 ProcHierarchyNodeInfo
->GicCToken
,
567 if (EFI_ERROR (Status
)) {
572 Status
= CreateAmlCpu (Generator
, ParentNode
, GicCInfo
, CpuIndex
, &CpuNode
);
573 if (EFI_ERROR (Status
)) {
578 // If a set of Lpi states is associated with the
579 // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
580 if (ProcHierarchyNodeInfo
->LpiToken
!= CM_NULL_TOKEN
) {
581 Status
= CreateAmlLpiMethod (Generator
, ProcHierarchyNodeInfo
, CpuNode
);
582 ASSERT_EFI_ERROR (Status
);
588 /** Create a Cluster in the AML namespace.
590 Any CM_ARM_PROC_HIERARCHY_INFO object with the following flags is
591 assumed to be a cluster:
592 - EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL
593 - EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID
594 - EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF
596 This generates the following ASL code:
600 Name (_HID, "ACPI0010")
603 @param [in] Generator The SSDT Cpu Topology generator.
604 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
606 @param [in] ParentNode Parent node to attach the Cluster
608 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO object used
610 @param [in] ClusterIndex Index used to generate the node name.
611 @param [out] ClusterNodePtr If success, contains the created Cluster
614 @retval EFI_SUCCESS Success.
615 @retval EFI_INVALID_PARAMETER Invalid parameter.
616 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
622 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
623 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
624 IN AML_NODE_HANDLE ParentNode
,
625 IN CM_ARM_PROC_HIERARCHY_INFO
* ProcHierarchyNodeInfo
,
626 IN UINT32 ClusterIndex
,
627 OUT AML_OBJECT_NODE_HANDLE
* ClusterNodePtr
631 AML_OBJECT_NODE_HANDLE ClusterNode
;
632 CHAR8 AslNameCluster
[AML_NAME_SEG_SIZE
+ 1];
634 ASSERT (Generator
!= NULL
);
635 ASSERT (CfgMgrProtocol
!= NULL
);
636 ASSERT (ParentNode
!= NULL
);
637 ASSERT (ProcHierarchyNodeInfo
!= NULL
);
638 ASSERT (ClusterNodePtr
!= NULL
);
640 Status
= WriteAslName ('C', ClusterIndex
, AslNameCluster
);
641 if (EFI_ERROR (Status
)) {
646 Status
= AmlCodeGenDevice (AslNameCluster
, ParentNode
, &ClusterNode
);
647 if (EFI_ERROR (Status
)) {
652 // Use the ClusterIndex for the _UID value as there is no AcpiProcessorUid
653 // and EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID is set for non-Cpus.
654 Status
= AmlCodeGenNameInteger (
660 if (EFI_ERROR (Status
)) {
665 Status
= AmlCodeGenNameString (
667 ACPI_HID_PROCESSOR_CONTAINER_DEVICE
,
671 if (EFI_ERROR (Status
)) {
676 // If a set of Lpi states are associated with the
677 // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
678 if (ProcHierarchyNodeInfo
->LpiToken
!= CM_NULL_TOKEN
) {
679 Status
= CreateAmlLpiMethod (
681 ProcHierarchyNodeInfo
,
684 if (EFI_ERROR (Status
)) {
690 *ClusterNodePtr
= ClusterNode
;
695 /** Create an AML representation of the Cpu topology.
697 A cluster is by extension any non-leave device in the cpu topology.
699 @param [in] Generator The SSDT Cpu Topology generator.
700 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
702 @param [in] NodeToken Token of the CM_ARM_PROC_HIERARCHY_INFO
704 Cannot be CM_NULL_TOKEN.
705 @param [in] ParentNode Parent node to attach the created
708 @retval EFI_SUCCESS Success.
709 @retval EFI_INVALID_PARAMETER Invalid parameter.
710 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
715 CreateAmlCpuTopologyTree (
716 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
717 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
718 IN CM_OBJECT_TOKEN NodeToken
,
719 IN AML_NODE_HANDLE ParentNode
726 AML_OBJECT_NODE_HANDLE ClusterNode
;
728 ASSERT (Generator
!= NULL
);
729 ASSERT (Generator
->ProcNodeList
!= NULL
);
730 ASSERT (Generator
->ProcNodeCount
!= 0);
731 ASSERT (CfgMgrProtocol
!= NULL
);
732 ASSERT (NodeToken
!= CM_NULL_TOKEN
);
733 ASSERT (ParentNode
!= NULL
);
738 for (Index
= 0; Index
< Generator
->ProcNodeCount
; Index
++) {
739 // Find the children of the CM_ARM_PROC_HIERARCHY_INFO
740 // currently being handled (i.e. ParentToken == NodeToken).
741 if (Generator
->ProcNodeList
[Index
].ParentToken
== NodeToken
) {
743 // Only Cpus (leaf nodes in this tree) have a GicCToken.
744 // Create a Cpu node.
745 if (Generator
->ProcNodeList
[Index
].GicCToken
!= CM_NULL_TOKEN
) {
746 if ((Generator
->ProcNodeList
[Index
].Flags
& PPTT_PROCESSOR_MASK
) !=
747 PPTT_CPU_PROCESSOR_MASK
) {
750 "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cpu: 0x%x.\n",
751 Generator
->ProcNodeList
[Index
].Flags
754 return EFI_INVALID_PARAMETER
;
757 Status
= CreateAmlCpuFromProcHierarchy (
762 &Generator
->ProcNodeList
[Index
]
764 if (EFI_ERROR (Status
)) {
772 // If this is not a Cpu, then this is a cluster.
774 // Acpi processor Id for clusters is not handled.
775 if ((Generator
->ProcNodeList
[Index
].Flags
& PPTT_PROCESSOR_MASK
) !=
776 PPTT_CLUSTER_PROCESSOR_MASK
) {
779 "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cluster: 0x%x.\n",
780 Generator
->ProcNodeList
[Index
].Flags
783 return EFI_INVALID_PARAMETER
;
786 Status
= CreateAmlCluster (
790 &Generator
->ProcNodeList
[Index
],
794 if (EFI_ERROR (Status
)) {
799 // Nodes must have a unique name in the ASL namespace.
800 // Reset the Cpu index whenever we create a new Cluster.
804 // Recursively continue creating an AML tree.
805 Status
= CreateAmlCpuTopologyTree (
808 Generator
->ProcNodeList
[Index
].Token
,
811 if (EFI_ERROR (Status
)) {
816 } // if ParentToken == NodeToken
822 /** Create the processor hierarchy AML tree from CM_ARM_PROC_HIERARCHY_INFO
825 @param [in] Generator The SSDT Cpu Topology generator.
826 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
828 @param [in] ScopeNode Scope node handle ('\_SB' scope).
830 @retval EFI_SUCCESS Success.
831 @retval EFI_INVALID_PARAMETER Invalid parameter.
832 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
837 CreateTopologyFromProcHierarchy (
838 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
839 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
840 IN AML_OBJECT_NODE_HANDLE ScopeNode
845 UINT32 TopLevelProcNodeIndex
;
847 ASSERT (Generator
!= NULL
);
848 ASSERT (Generator
->ProcNodeCount
!= 0);
849 ASSERT (Generator
->ProcNodeList
!= NULL
);
850 ASSERT (CfgMgrProtocol
!= NULL
);
851 ASSERT (ScopeNode
!= NULL
);
853 TopLevelProcNodeIndex
= MAX_UINT32
;
855 Status
= TokenTableInitialize (Generator
, Generator
->ProcNodeCount
);
856 if (EFI_ERROR (Status
)) {
861 // It is assumed that there is one unique CM_ARM_PROC_HIERARCHY_INFO
862 // structure with no ParentToken and the EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL
863 // flag set. All other CM_ARM_PROC_HIERARCHY_INFO are non-physical and
864 // have a ParentToken.
865 for (Index
= 0; Index
< Generator
->ProcNodeCount
; Index
++) {
866 if ((Generator
->ProcNodeList
[Index
].ParentToken
== CM_NULL_TOKEN
) &&
867 (Generator
->ProcNodeList
[Index
].Flags
&
868 EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL
)) {
869 if (TopLevelProcNodeIndex
!= MAX_UINT32
) {
872 "ERROR: SSDT-CPU-TOPOLOGY: Top level CM_ARM_PROC_HIERARCHY_INFO "
878 TopLevelProcNodeIndex
= Index
;
882 Status
= CreateAmlCpuTopologyTree (
885 Generator
->ProcNodeList
[TopLevelProcNodeIndex
].Token
,
888 if (EFI_ERROR (Status
)) {
893 Status
= GenerateLpiStates (Generator
, CfgMgrProtocol
, ScopeNode
);
894 if (EFI_ERROR (Status
)) {
900 TokenTableFree (Generator
);
904 /** Create the processor hierarchy AML tree from CM_ARM_GICC_INFO
907 A cluster is by extension any non-leave device in the cpu topology.
909 @param [in] Generator The SSDT Cpu Topology generator.
910 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
912 @param [in] ScopeNode Scope node handle ('\_SB' scope).
914 @retval EFI_SUCCESS Success.
915 @retval EFI_INVALID_PARAMETER Invalid parameter.
916 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
921 CreateTopologyFromGicC (
922 IN ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
,
923 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
924 IN AML_OBJECT_NODE_HANDLE ScopeNode
928 CM_ARM_GICC_INFO
* GicCInfo
;
929 UINT32 GicCInfoCount
;
932 ASSERT (Generator
!= NULL
);
933 ASSERT (CfgMgrProtocol
!= NULL
);
934 ASSERT (ScopeNode
!= NULL
);
936 Status
= GetEArmObjGicCInfo (
942 if (EFI_ERROR (Status
)) {
947 // For each CM_ARM_GICC_INFO object, create an AML node.
948 for (Index
= 0; Index
< GicCInfoCount
; Index
++) {
949 Status
= CreateAmlCpu (
956 if (EFI_ERROR (Status
)) {
965 /** Construct the SSDT Cpu Topology ACPI table.
967 This function invokes the Configuration Manager protocol interface
968 to get the required hardware information for generating the ACPI
971 If this function allocates any resources then they must be freed
972 in the FreeXXXXTableResources function.
974 @param [in] This Pointer to the table generator.
975 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
976 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
978 @param [out] Table Pointer to the constructed ACPI Table.
980 @retval EFI_SUCCESS Table generated successfully.
981 @retval EFI_INVALID_PARAMETER A parameter is invalid.
982 @retval EFI_NOT_FOUND The required object was not found.
983 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
984 Manager is less than the Object size for the
990 BuildSsdtCpuTopologyTable (
991 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
992 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
993 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
994 OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
998 AML_ROOT_NODE_HANDLE RootNode
;
999 AML_OBJECT_NODE_HANDLE ScopeNode
;
1000 CM_ARM_PROC_HIERARCHY_INFO
* ProcHierarchyNodeList
;
1001 UINT32 ProcHierarchyNodeCount
;
1002 ACPI_CPU_TOPOLOGY_GENERATOR
* Generator
;
1004 ASSERT (This
!= NULL
);
1005 ASSERT (AcpiTableInfo
!= NULL
);
1006 ASSERT (CfgMgrProtocol
!= NULL
);
1007 ASSERT (Table
!= NULL
);
1008 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1009 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1011 Generator
= (ACPI_CPU_TOPOLOGY_GENERATOR
*)This
;
1013 Status
= AddSsdtAcpiHeader (
1019 if (EFI_ERROR (Status
)) {
1023 Status
= AmlCodeGenScope (SB_SCOPE
, RootNode
, &ScopeNode
);
1024 if (EFI_ERROR (Status
)) {
1028 // Get the processor hierarchy info and update the processor topology
1029 // structure count with Processor Hierarchy Nodes (Type 0)
1030 Status
= GetEArmObjProcHierarchyInfo (
1033 &ProcHierarchyNodeList
,
1034 &ProcHierarchyNodeCount
1036 if (EFI_ERROR (Status
) &&
1037 (Status
!= EFI_NOT_FOUND
)) {
1041 if (Status
== EFI_NOT_FOUND
) {
1042 // If hierarchy information is not found generate a flat topology
1043 // using CM_ARM_GICC_INFO objects.
1044 Status
= CreateTopologyFromGicC (
1049 if (EFI_ERROR (Status
)) {
1053 // Generate the topology from CM_ARM_PROC_HIERARCHY_INFO objects.
1054 Generator
->ProcNodeList
= ProcHierarchyNodeList
;
1055 Generator
->ProcNodeCount
= ProcHierarchyNodeCount
;
1057 Status
= CreateTopologyFromProcHierarchy (
1062 if (EFI_ERROR (Status
)) {
1067 Status
= AmlSerializeDefinitionBlock (
1071 if (EFI_ERROR (Status
)) {
1074 "ERROR: SSDT-CPU-TOPOLOGY: Failed to Serialize SSDT Table Data."
1082 // Delete the RootNode and its attached children.
1083 return AmlDeleteTree (RootNode
);
1086 /** Free any resources allocated for constructing the
1087 SSDT Cpu Topology ACPI table.
1089 @param [in] This Pointer to the table generator.
1090 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1091 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1093 @param [in, out] Table Pointer to the ACPI Table.
1095 @retval EFI_SUCCESS The resources were freed successfully.
1096 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1100 FreeSsdtCpuTopologyTableResources (
1101 IN CONST ACPI_TABLE_GENERATOR
* CONST This
,
1102 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
* CONST AcpiTableInfo
,
1103 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
* CONST CfgMgrProtocol
,
1104 IN OUT EFI_ACPI_DESCRIPTION_HEADER
** CONST Table
1107 ASSERT (This
!= NULL
);
1108 ASSERT (AcpiTableInfo
!= NULL
);
1109 ASSERT (CfgMgrProtocol
!= NULL
);
1110 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1111 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1113 if ((Table
== NULL
) || (*Table
== NULL
)) {
1114 DEBUG ((DEBUG_ERROR
, "ERROR: SSDT-CPU-TOPOLOGY: Invalid Table Pointer\n"));
1115 ASSERT ((Table
!= NULL
) && (*Table
!= NULL
));
1116 return EFI_INVALID_PARAMETER
;
1124 /** This macro defines the SSDT Cpu Topology Table Generator revision.
1126 #define SSDT_CPU_TOPOLOGY_GENERATOR_REVISION CREATE_REVISION (1, 0)
1128 /** The interface for the SSDT Cpu Topology Table Generator.
1131 ACPI_CPU_TOPOLOGY_GENERATOR SsdtCpuTopologyGenerator
= {
1132 // ACPI table generator header
1135 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCpuTopology
),
1136 // Generator Description
1137 L
"ACPI.STD.SSDT.CPU.TOPOLOGY.GENERATOR",
1138 // ACPI Table Signature
1139 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
,
1140 // ACPI Table Revision - Unused
1142 // Minimum ACPI Table Revision - Unused
1145 TABLE_GENERATOR_CREATOR_ID_ARM
,
1147 SSDT_CPU_TOPOLOGY_GENERATOR_REVISION
,
1148 // Build Table function
1149 BuildSsdtCpuTopologyTable
,
1150 // Free Resource function
1151 FreeSsdtCpuTopologyTableResources
,
1152 // Extended build function not needed
1154 // Extended build function not implemented by the generator.
1155 // Hence extended free resource function is not required.
1159 // Private fields are defined from here.
1174 /** Register the Generator with the ACPI Table Factory.
1176 @param [in] ImageHandle The handle to the image.
1177 @param [in] SystemTable Pointer to the System Table.
1179 @retval EFI_SUCCESS The Generator is registered.
1180 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1181 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1182 is already registered.
1186 AcpiSsdtCpuTopologyLibConstructor (
1187 IN EFI_HANDLE ImageHandle
,
1188 IN EFI_SYSTEM_TABLE
* SystemTable
1192 Status
= RegisterAcpiTableGenerator (&SsdtCpuTopologyGenerator
.Header
);
1195 "SSDT-CPU-TOPOLOGY: Register Generator. Status = %r\n",
1198 ASSERT_EFI_ERROR (Status
);
1203 /** Deregister the Generator from the ACPI Table Factory.
1205 @param [in] ImageHandle The handle to the image.
1206 @param [in] SystemTable Pointer to the System Table.
1208 @retval EFI_SUCCESS The Generator is deregistered.
1209 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1210 @retval EFI_NOT_FOUND The Generator is not registered.
1214 AcpiSsdtCpuTopologyLibDestructor (
1215 IN EFI_HANDLE ImageHandle
,
1216 IN EFI_SYSTEM_TABLE
* SystemTable
1220 Status
= DeregisterAcpiTableGenerator (&SsdtCpuTopologyGenerator
.Header
);
1223 "SSDT-CPU-TOPOLOGY: Deregister Generator. Status = %r\n",
1226 ASSERT_EFI_ERROR (Status
);