]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
DynamicTablesPkg: Apply uncrustify changes
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiSsdtCpuTopologyLibArm / SsdtCpuTopologyGenerator.c
1 /** @file
2 SSDT Cpu Topology Table Generator.
3
4 Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 @par Reference(s):
8 - ACPI 6.3 Specification - January 2019 - s8.4 Declaring Processors
9 **/
10
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>
17
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>
26
27 #include "SsdtCpuTopologyGenerator.h"
28
29 /** ARM standard SSDT Cpu Topology Table Generator.
30
31 Requirements:
32 The following Configuration Manager Object(s) are required by
33 this Generator:
34 - EArmObjGicCInfo
35 - EArmObjProcHierarchyInfo (OPTIONAL) along with
36 - EArmObjCmRef (OPTIONAL)
37 - EArmObjLpiInfo (OPTIONAL)
38 */
39
40 /** This macro expands to a function that retrieves the GIC
41 CPU interface Information from the Configuration Manager.
42 */
43 GET_OBJECT_LIST (
44 EObjNameSpaceArm,
45 EArmObjGicCInfo,
46 CM_ARM_GICC_INFO
47 );
48
49 /**
50 This macro expands to a function that retrieves the Processor Hierarchy
51 information from the Configuration Manager.
52 */
53 GET_OBJECT_LIST (
54 EObjNameSpaceArm,
55 EArmObjProcHierarchyInfo,
56 CM_ARM_PROC_HIERARCHY_INFO
57 );
58
59 /**
60 This macro expands to a function that retrieves the cross-CM-object-
61 reference information from the Configuration Manager.
62 */
63 GET_OBJECT_LIST (
64 EObjNameSpaceArm,
65 EArmObjCmRef,
66 CM_ARM_OBJ_REF
67 );
68
69 /**
70 This macro expands to a function that retrieves the Lpi
71 information from the Configuration Manager.
72 */
73 GET_OBJECT_LIST (
74 EObjNameSpaceArm,
75 EArmObjLpiInfo,
76 CM_ARM_LPI_INFO
77 );
78
79 /** Initialize the TokenTable.
80
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).
84
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).
87
88 @param [in] Generator The SSDT Cpu Topology generator.
89 @param [in] Count Number of entries to allocate in the TokenTable.
90
91 @retval EFI_SUCCESS Success.
92 @retval EFI_INVALID_PARAMETER Invalid parameter.
93 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
94 **/
95 STATIC
96 EFI_STATUS
97 EFIAPI
98 TokenTableInitialize (
99 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
100 IN UINT32 Count
101 )
102 {
103 CM_OBJECT_TOKEN *Table;
104
105 if ((Generator == NULL) ||
106 (Count == 0) ||
107 (Count >= MAX_NODE_COUNT))
108 {
109 ASSERT (0);
110 return EFI_INVALID_PARAMETER;
111 }
112
113 Table = AllocateZeroPool (sizeof (CM_OBJECT_TOKEN) * Count);
114 if (Table == NULL) {
115 ASSERT (0);
116 return EFI_OUT_OF_RESOURCES;
117 }
118
119 Generator->TokenTable.Table = Table;
120
121 return EFI_SUCCESS;
122 }
123
124 /** Free the TokenTable.
125
126 @param [in] Generator The SSDT Cpu Topology generator.
127 **/
128 STATIC
129 VOID
130 EFIAPI
131 TokenTableFree (
132 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator
133 )
134 {
135 ASSERT (Generator != NULL);
136 ASSERT (Generator->TokenTable.Table != NULL);
137
138 if (Generator->TokenTable.Table != NULL) {
139 FreePool (Generator->TokenTable.Table);
140 }
141 }
142
143 /** Add a new entry to the TokenTable and return its index.
144
145 If an entry with Token is already available in the table,
146 return its index without adding a new entry.
147
148 @param [in] Generator The SSDT Cpu Topology generator.
149 @param [in] Token New Token entry to add.
150
151 @retval The index of the token entry in the TokenTable.
152 **/
153 STATIC
154 UINT32
155 EFIAPI
156 TokenTableAdd (
157 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
158 IN CM_OBJECT_TOKEN Token
159 )
160 {
161 CM_OBJECT_TOKEN *Table;
162 UINT32 Index;
163 UINT32 LastIndex;
164
165 ASSERT (Generator != NULL);
166 ASSERT (Generator->TokenTable.Table != NULL);
167
168 Table = Generator->TokenTable.Table;
169 LastIndex = Generator->TokenTable.LastIndex;
170
171 // Search if there is already an entry with this Token.
172 for (Index = 0; Index < LastIndex; Index++) {
173 if (Table[Index] == Token) {
174 return Index;
175 }
176 }
177
178 ASSERT (LastIndex < MAX_NODE_COUNT);
179 ASSERT (LastIndex < Generator->ProcNodeCount);
180
181 // If no, create a new entry.
182 Table[LastIndex] = Token;
183
184 return Generator->TokenTable.LastIndex++;
185 }
186
187 /** Write a string 'Xxxx\0' in AslName (5 bytes long),
188 with 'X' being the leading char of the name, and
189 with 'xxx' being Value in hexadecimal.
190
191 As 'xxx' in hexadecimal represents a number on 12 bits,
192 we have Value < (1 << 12).
193
194 @param [in] LeadChar Leading char of the name.
195 @param [in] Value Hex value of the name.
196 Must be lower than (2 << 12).
197 @param [in, out] AslName Pointer to write the 'Xxxx' string to.
198 Must be at least 5 bytes long.
199
200 @retval EFI_SUCCESS Success.
201 @retval EFI_INVALID_PARAMETER Invalid parameter.
202 **/
203 STATIC
204 EFI_STATUS
205 EFIAPI
206 WriteAslName (
207 IN CHAR8 LeadChar,
208 IN UINT32 Value,
209 IN OUT CHAR8 *AslName
210 )
211 {
212 UINT8 Index;
213
214 if ((Value >= MAX_NODE_COUNT) ||
215 (AslName == NULL))
216 {
217 ASSERT (0);
218 return EFI_INVALID_PARAMETER;
219 }
220
221 AslName[0] = LeadChar;
222 AslName[AML_NAME_SEG_SIZE] = '\0';
223
224 for (Index = 0; Index < AML_NAME_SEG_SIZE - 1; Index++) {
225 AslName[AML_NAME_SEG_SIZE - Index - 1] =
226 AsciiFromHex (((Value >> (4 * Index)) & 0xF));
227 }
228
229 return EFI_SUCCESS;
230 }
231
232 /** Create and add an _LPI method to Cpu/Cluster Node.
233
234 For instance, transform an AML node from:
235 Device (C002)
236 {
237 Name (_UID, 2)
238 Name (_HID, "ACPI0007")
239 }
240
241 To:
242 Device (C002)
243 {
244 Name (_UID, 2)
245 Name (_HID, "ACPI0007")
246 Method (_LPI, 0, NotSerialized)
247 {
248 Return (\_SB.L003)
249 }
250 }
251
252 @param [in] Generator The SSDT Cpu Topology generator.
253 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
254 the Cpu.
255 @param [in] Node Node to which the _LPI method is
256 attached. Can represent a Cpu or a
257 Cluster.
258
259 @retval EFI_SUCCESS The function completed successfully.
260 @retval EFI_INVALID_PARAMETER Invalid parameter.
261 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
262 **/
263 STATIC
264 EFI_STATUS
265 EFIAPI
266 CreateAmlLpiMethod (
267 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
268 IN CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeInfo,
269 IN AML_OBJECT_NODE_HANDLE *Node
270 )
271 {
272 EFI_STATUS Status;
273 UINT32 TokenIndex;
274 CHAR8 AslName[SB_SCOPE_PREFIX_SIZE + AML_NAME_SEG_SIZE];
275
276 ASSERT (Generator != NULL);
277 ASSERT (ProcHierarchyNodeInfo != NULL);
278 ASSERT (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN);
279 ASSERT (Node != NULL);
280
281 TokenIndex = TokenTableAdd (Generator, ProcHierarchyNodeInfo->LpiToken);
282
283 CopyMem (AslName, SB_SCOPE_PREFIX, SB_SCOPE_PREFIX_SIZE);
284
285 Status = WriteAslName (
286 'L',
287 TokenIndex,
288 AslName + SB_SCOPE_PREFIX_SIZE - 1
289 );
290 if (EFI_ERROR (Status)) {
291 ASSERT (0);
292 return Status;
293 }
294
295 // ASL:
296 // Method (_LPI, 0) {
297 // Return ([AslName])
298 // }
299 Status = AmlCodeGenMethodRetNameString (
300 "_LPI",
301 AslName,
302 0,
303 FALSE,
304 0,
305 Node,
306 NULL
307 );
308 if (EFI_ERROR (Status)) {
309 ASSERT (0);
310 }
311
312 return Status;
313 }
314
315 /** Generate all the Lpi states under the '_SB' scope.
316
317 This function generates the following ASL code:
318 Scope (\_SB) {
319 Name (L000, Package() {
320 0, // Version
321 0, // Level Index
322 X, // Count
323 Package() {
324 [An Lpi state]
325 },
326 Package() {
327 [Another Lpi state]
328 },
329 } // Name L000
330
331 Name (L001, Package() {
332 ...
333 } // Name L001
334
335 ...
336 } // Scope /_SB
337
338 The Lpi states are fetched from the Configuration Manager.
339 The names of the Lpi states are generated from the TokenTable.
340
341 @param [in] Generator The SSDT Cpu Topology generator.
342 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
343 Protocol Interface.
344 @param [in] ScopeNode Scope node handle ('\_SB' scope).
345
346 @retval EFI_SUCCESS Success.
347 @retval EFI_INVALID_PARAMETER Invalid parameter.
348 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
349 **/
350 STATIC
351 EFI_STATUS
352 EFIAPI
353 GenerateLpiStates (
354 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
355 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
356 IN AML_OBJECT_NODE_HANDLE ScopeNode
357 )
358 {
359 EFI_STATUS Status;
360
361 UINT32 Index;
362 UINT32 LastIndex;
363
364 AML_OBJECT_NODE_HANDLE LpiNode;
365 CM_ARM_OBJ_REF *LpiRefInfo;
366 UINT32 LpiRefInfoCount;
367 UINT32 LpiRefIndex;
368 CM_ARM_LPI_INFO *LpiInfo;
369 CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
370
371 ASSERT (Generator != NULL);
372 ASSERT (Generator->TokenTable.Table != NULL);
373 ASSERT (CfgMgrProtocol != NULL);
374 ASSERT (ScopeNode != NULL);
375
376 LastIndex = Generator->TokenTable.LastIndex;
377
378 // For each entry in the TokenTable, create a name in the AML namespace
379 // under SB_SCOPE, to store the Lpi states associated with the LpiToken.
380 for (Index = 0; Index < LastIndex; Index++) {
381 Status = WriteAslName ('L', Index, AslName);
382 if (EFI_ERROR (Status)) {
383 ASSERT (0);
384 return Status;
385 }
386
387 // We do not support the LevelId field for now, let it to 0.
388 Status = AmlCreateLpiNode (AslName, 1, 0, ScopeNode, &LpiNode);
389 if (EFI_ERROR (Status)) {
390 ASSERT (0);
391 return Status;
392 }
393
394 // Fetch the LPI objects referenced by the token.
395 Status = GetEArmObjCmRef (
396 CfgMgrProtocol,
397 Generator->TokenTable.Table[Index],
398 &LpiRefInfo,
399 &LpiRefInfoCount
400 );
401 if (EFI_ERROR (Status)) {
402 ASSERT (0);
403 return Status;
404 }
405
406 for (LpiRefIndex = 0; LpiRefIndex < LpiRefInfoCount; LpiRefIndex++) {
407 // For each CM_ARM_LPI_INFO referenced by the token, add an Lpi state.
408 Status = GetEArmObjLpiInfo (
409 CfgMgrProtocol,
410 LpiRefInfo[LpiRefIndex].ReferenceToken,
411 &LpiInfo,
412 NULL
413 );
414 if (EFI_ERROR (Status)) {
415 ASSERT (0);
416 return Status;
417 }
418
419 Status = AmlAddLpiState (
420 LpiInfo->MinResidency,
421 LpiInfo->WorstCaseWakeLatency,
422 LpiInfo->Flags,
423 LpiInfo->ArchFlags,
424 LpiInfo->ResCntFreq,
425 LpiInfo->EnableParentState,
426 LpiInfo->IsInteger ?
427 NULL :
428 &LpiInfo->RegisterEntryMethod,
429 LpiInfo->IsInteger ?
430 LpiInfo->IntegerEntryMethod :
431 0,
432 &LpiInfo->ResidencyCounterRegister,
433 &LpiInfo->UsageCounterRegister,
434 LpiInfo->StateName,
435 LpiNode
436 );
437 if (EFI_ERROR (Status)) {
438 ASSERT (0);
439 return Status;
440 }
441 } // for LpiRefIndex
442 } // for Index
443
444 return EFI_SUCCESS;
445 }
446
447 /** Create a Cpu in the AML namespace.
448
449 This generates the following ASL code:
450 Device (C002)
451 {
452 Name (_UID, 2)
453 Name (_HID, "ACPI0007")
454 }
455
456 @param [in] Generator The SSDT Cpu Topology generator.
457 @param [in] ParentNode Parent node to attach the Cpu node to.
458 @param [in] GicCInfo CM_ARM_GICC_INFO object used to create the node.
459 @param [in] CpuIndex Index used to generate the node name.
460 @param [out] CpuNodePtr If not NULL, return the created Cpu node.
461
462 @retval EFI_SUCCESS Success.
463 @retval EFI_INVALID_PARAMETER Invalid parameter.
464 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
465 **/
466 STATIC
467 EFI_STATUS
468 EFIAPI
469 CreateAmlCpu (
470 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
471 IN AML_NODE_HANDLE ParentNode,
472 IN CM_ARM_GICC_INFO *GicCInfo,
473 IN UINT32 CpuIndex,
474 OUT AML_OBJECT_NODE_HANDLE *CpuNodePtr OPTIONAL
475 )
476 {
477 EFI_STATUS Status;
478 AML_OBJECT_NODE_HANDLE CpuNode;
479 CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
480
481 ASSERT (Generator != NULL);
482 ASSERT (ParentNode != NULL);
483 ASSERT (GicCInfo != NULL);
484
485 Status = WriteAslName ('C', CpuIndex, AslName);
486 if (EFI_ERROR (Status)) {
487 ASSERT (0);
488 return Status;
489 }
490
491 Status = AmlCodeGenDevice (AslName, ParentNode, &CpuNode);
492 if (EFI_ERROR (Status)) {
493 ASSERT (0);
494 return Status;
495 }
496
497 Status = AmlCodeGenNameInteger (
498 "_UID",
499 GicCInfo->AcpiProcessorUid,
500 CpuNode,
501 NULL
502 );
503 if (EFI_ERROR (Status)) {
504 ASSERT (0);
505 return Status;
506 }
507
508 Status = AmlCodeGenNameString (
509 "_HID",
510 ACPI_HID_PROCESSOR_DEVICE,
511 CpuNode,
512 NULL
513 );
514 if (EFI_ERROR (Status)) {
515 ASSERT (0);
516 return Status;
517 }
518
519 // If requested, return the handle to the CpuNode.
520 if (CpuNodePtr != NULL) {
521 *CpuNodePtr = CpuNode;
522 }
523
524 return Status;
525 }
526
527 /** Create a Cpu in the AML namespace from a CM_ARM_PROC_HIERARCHY_INFO
528 CM object.
529
530 @param [in] Generator The SSDT Cpu Topology generator.
531 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
532 Protocol Interface.
533 @param [in] ParentNode Parent node to attach the Cpu node to.
534 @param [in] CpuIndex Index used to generate the node name.
535 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
536 the Cpu.
537
538 @retval EFI_SUCCESS Success.
539 @retval EFI_INVALID_PARAMETER Invalid parameter.
540 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
541 **/
542 STATIC
543 EFI_STATUS
544 EFIAPI
545 CreateAmlCpuFromProcHierarchy (
546 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
547 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
548 IN AML_NODE_HANDLE ParentNode,
549 IN UINT32 CpuIndex,
550 IN CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeInfo
551 )
552 {
553 EFI_STATUS Status;
554 CM_ARM_GICC_INFO *GicCInfo;
555 AML_OBJECT_NODE_HANDLE CpuNode;
556
557 ASSERT (Generator != NULL);
558 ASSERT (CfgMgrProtocol != NULL);
559 ASSERT (ParentNode != NULL);
560 ASSERT (ProcHierarchyNodeInfo != NULL);
561 ASSERT (ProcHierarchyNodeInfo->GicCToken != CM_NULL_TOKEN);
562
563 Status = GetEArmObjGicCInfo (
564 CfgMgrProtocol,
565 ProcHierarchyNodeInfo->GicCToken,
566 &GicCInfo,
567 NULL
568 );
569 if (EFI_ERROR (Status)) {
570 ASSERT (0);
571 return Status;
572 }
573
574 Status = CreateAmlCpu (Generator, ParentNode, GicCInfo, CpuIndex, &CpuNode);
575 if (EFI_ERROR (Status)) {
576 ASSERT (0);
577 return Status;
578 }
579
580 // If a set of Lpi states is associated with the
581 // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
582 if (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN) {
583 Status = CreateAmlLpiMethod (Generator, ProcHierarchyNodeInfo, CpuNode);
584 ASSERT_EFI_ERROR (Status);
585 }
586
587 return Status;
588 }
589
590 /** Create a Cluster in the AML namespace.
591
592 Any CM_ARM_PROC_HIERARCHY_INFO object with the following flags is
593 assumed to be a cluster:
594 - EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL
595 - EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID
596 - EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF
597
598 This generates the following ASL code:
599 Device (C002)
600 {
601 Name (_UID, 2)
602 Name (_HID, "ACPI0010")
603 }
604
605 @param [in] Generator The SSDT Cpu Topology generator.
606 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
607 Protocol Interface.
608 @param [in] ParentNode Parent node to attach the Cluster
609 node to.
610 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO object used
611 to create the node.
612 @param [in] ClusterIndex Index used to generate the node name.
613 @param [out] ClusterNodePtr If success, contains the created Cluster
614 node.
615
616 @retval EFI_SUCCESS Success.
617 @retval EFI_INVALID_PARAMETER Invalid parameter.
618 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
619 **/
620 STATIC
621 EFI_STATUS
622 EFIAPI
623 CreateAmlCluster (
624 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
625 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
626 IN AML_NODE_HANDLE ParentNode,
627 IN CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeInfo,
628 IN UINT32 ClusterIndex,
629 OUT AML_OBJECT_NODE_HANDLE *ClusterNodePtr
630 )
631 {
632 EFI_STATUS Status;
633 AML_OBJECT_NODE_HANDLE ClusterNode;
634 CHAR8 AslNameCluster[AML_NAME_SEG_SIZE + 1];
635
636 ASSERT (Generator != NULL);
637 ASSERT (CfgMgrProtocol != NULL);
638 ASSERT (ParentNode != NULL);
639 ASSERT (ProcHierarchyNodeInfo != NULL);
640 ASSERT (ClusterNodePtr != NULL);
641
642 Status = WriteAslName ('C', ClusterIndex, AslNameCluster);
643 if (EFI_ERROR (Status)) {
644 ASSERT (0);
645 return Status;
646 }
647
648 Status = AmlCodeGenDevice (AslNameCluster, ParentNode, &ClusterNode);
649 if (EFI_ERROR (Status)) {
650 ASSERT (0);
651 return Status;
652 }
653
654 // Use the ClusterIndex for the _UID value as there is no AcpiProcessorUid
655 // and EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID is set for non-Cpus.
656 Status = AmlCodeGenNameInteger (
657 "_UID",
658 ClusterIndex,
659 ClusterNode,
660 NULL
661 );
662 if (EFI_ERROR (Status)) {
663 ASSERT (0);
664 return Status;
665 }
666
667 Status = AmlCodeGenNameString (
668 "_HID",
669 ACPI_HID_PROCESSOR_CONTAINER_DEVICE,
670 ClusterNode,
671 NULL
672 );
673 if (EFI_ERROR (Status)) {
674 ASSERT (0);
675 return Status;
676 }
677
678 // If a set of Lpi states are associated with the
679 // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
680 if (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN) {
681 Status = CreateAmlLpiMethod (
682 Generator,
683 ProcHierarchyNodeInfo,
684 ClusterNode
685 );
686 if (EFI_ERROR (Status)) {
687 ASSERT (0);
688 return Status;
689 }
690 }
691
692 *ClusterNodePtr = ClusterNode;
693
694 return Status;
695 }
696
697 /** Create an AML representation of the Cpu topology.
698
699 A cluster is by extension any non-leave device in the cpu topology.
700
701 @param [in] Generator The SSDT Cpu Topology generator.
702 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
703 Protocol Interface.
704 @param [in] NodeToken Token of the CM_ARM_PROC_HIERARCHY_INFO
705 currently handled.
706 Cannot be CM_NULL_TOKEN.
707 @param [in] ParentNode Parent node to attach the created
708 node to.
709
710 @retval EFI_SUCCESS Success.
711 @retval EFI_INVALID_PARAMETER Invalid parameter.
712 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
713 **/
714 STATIC
715 EFI_STATUS
716 EFIAPI
717 CreateAmlCpuTopologyTree (
718 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
719 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
720 IN CM_OBJECT_TOKEN NodeToken,
721 IN AML_NODE_HANDLE ParentNode
722 )
723 {
724 EFI_STATUS Status;
725 UINT32 Index;
726 UINT32 CpuIndex;
727 UINT32 ClusterIndex;
728 AML_OBJECT_NODE_HANDLE ClusterNode;
729
730 ASSERT (Generator != NULL);
731 ASSERT (Generator->ProcNodeList != NULL);
732 ASSERT (Generator->ProcNodeCount != 0);
733 ASSERT (CfgMgrProtocol != NULL);
734 ASSERT (NodeToken != CM_NULL_TOKEN);
735 ASSERT (ParentNode != NULL);
736
737 CpuIndex = 0;
738 ClusterIndex = 0;
739
740 for (Index = 0; Index < Generator->ProcNodeCount; Index++) {
741 // Find the children of the CM_ARM_PROC_HIERARCHY_INFO
742 // currently being handled (i.e. ParentToken == NodeToken).
743 if (Generator->ProcNodeList[Index].ParentToken == NodeToken) {
744 // Only Cpus (leaf nodes in this tree) have a GicCToken.
745 // Create a Cpu node.
746 if (Generator->ProcNodeList[Index].GicCToken != CM_NULL_TOKEN) {
747 if ((Generator->ProcNodeList[Index].Flags & PPTT_PROCESSOR_MASK) !=
748 PPTT_CPU_PROCESSOR_MASK)
749 {
750 DEBUG ((
751 DEBUG_ERROR,
752 "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cpu: 0x%x.\n",
753 Generator->ProcNodeList[Index].Flags
754 ));
755 ASSERT (0);
756 return EFI_INVALID_PARAMETER;
757 }
758
759 Status = CreateAmlCpuFromProcHierarchy (
760 Generator,
761 CfgMgrProtocol,
762 ParentNode,
763 CpuIndex,
764 &Generator->ProcNodeList[Index]
765 );
766 if (EFI_ERROR (Status)) {
767 ASSERT (0);
768 return Status;
769 }
770
771 CpuIndex++;
772 } else {
773 // If this is not a Cpu, then this is a cluster.
774
775 // Acpi processor Id for clusters is not handled.
776 if ((Generator->ProcNodeList[Index].Flags & PPTT_PROCESSOR_MASK) !=
777 PPTT_CLUSTER_PROCESSOR_MASK)
778 {
779 DEBUG ((
780 DEBUG_ERROR,
781 "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cluster: 0x%x.\n",
782 Generator->ProcNodeList[Index].Flags
783 ));
784 ASSERT (0);
785 return EFI_INVALID_PARAMETER;
786 }
787
788 Status = CreateAmlCluster (
789 Generator,
790 CfgMgrProtocol,
791 ParentNode,
792 &Generator->ProcNodeList[Index],
793 ClusterIndex,
794 &ClusterNode
795 );
796 if (EFI_ERROR (Status)) {
797 ASSERT (0);
798 return Status;
799 }
800
801 // Nodes must have a unique name in the ASL namespace.
802 // Reset the Cpu index whenever we create a new Cluster.
803 ClusterIndex++;
804 CpuIndex = 0;
805
806 // Recursively continue creating an AML tree.
807 Status = CreateAmlCpuTopologyTree (
808 Generator,
809 CfgMgrProtocol,
810 Generator->ProcNodeList[Index].Token,
811 ClusterNode
812 );
813 if (EFI_ERROR (Status)) {
814 ASSERT (0);
815 return Status;
816 }
817 }
818 } // if ParentToken == NodeToken
819 } // for
820
821 return EFI_SUCCESS;
822 }
823
824 /** Create the processor hierarchy AML tree from CM_ARM_PROC_HIERARCHY_INFO
825 CM objects.
826
827 @param [in] Generator The SSDT Cpu Topology generator.
828 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
829 Protocol Interface.
830 @param [in] ScopeNode Scope node handle ('\_SB' scope).
831
832 @retval EFI_SUCCESS Success.
833 @retval EFI_INVALID_PARAMETER Invalid parameter.
834 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
835 **/
836 STATIC
837 EFI_STATUS
838 EFIAPI
839 CreateTopologyFromProcHierarchy (
840 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
841 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
842 IN AML_OBJECT_NODE_HANDLE ScopeNode
843 )
844 {
845 EFI_STATUS Status;
846 UINT32 Index;
847 UINT32 TopLevelProcNodeIndex;
848
849 ASSERT (Generator != NULL);
850 ASSERT (Generator->ProcNodeCount != 0);
851 ASSERT (Generator->ProcNodeList != NULL);
852 ASSERT (CfgMgrProtocol != NULL);
853 ASSERT (ScopeNode != NULL);
854
855 TopLevelProcNodeIndex = MAX_UINT32;
856
857 Status = TokenTableInitialize (Generator, Generator->ProcNodeCount);
858 if (EFI_ERROR (Status)) {
859 ASSERT (0);
860 return Status;
861 }
862
863 // It is assumed that there is one unique CM_ARM_PROC_HIERARCHY_INFO
864 // structure with no ParentToken and the EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL
865 // flag set. All other CM_ARM_PROC_HIERARCHY_INFO are non-physical and
866 // have a ParentToken.
867 for (Index = 0; Index < Generator->ProcNodeCount; Index++) {
868 if ((Generator->ProcNodeList[Index].ParentToken == CM_NULL_TOKEN) &&
869 (Generator->ProcNodeList[Index].Flags &
870 EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL))
871 {
872 if (TopLevelProcNodeIndex != MAX_UINT32) {
873 DEBUG ((
874 DEBUG_ERROR,
875 "ERROR: SSDT-CPU-TOPOLOGY: Top level CM_ARM_PROC_HIERARCHY_INFO "
876 "must be unique\n"
877 ));
878 ASSERT (0);
879 goto exit_handler;
880 }
881
882 TopLevelProcNodeIndex = Index;
883 }
884 } // for
885
886 Status = CreateAmlCpuTopologyTree (
887 Generator,
888 CfgMgrProtocol,
889 Generator->ProcNodeList[TopLevelProcNodeIndex].Token,
890 ScopeNode
891 );
892 if (EFI_ERROR (Status)) {
893 ASSERT (0);
894 goto exit_handler;
895 }
896
897 Status = GenerateLpiStates (Generator, CfgMgrProtocol, ScopeNode);
898 if (EFI_ERROR (Status)) {
899 ASSERT (0);
900 goto exit_handler;
901 }
902
903 exit_handler:
904 TokenTableFree (Generator);
905 return Status;
906 }
907
908 /** Create the processor hierarchy AML tree from CM_ARM_GICC_INFO
909 CM objects.
910
911 A cluster is by extension any non-leave device in the cpu topology.
912
913 @param [in] Generator The SSDT Cpu Topology generator.
914 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
915 Protocol Interface.
916 @param [in] ScopeNode Scope node handle ('\_SB' scope).
917
918 @retval EFI_SUCCESS Success.
919 @retval EFI_INVALID_PARAMETER Invalid parameter.
920 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
921 **/
922 STATIC
923 EFI_STATUS
924 EFIAPI
925 CreateTopologyFromGicC (
926 IN ACPI_CPU_TOPOLOGY_GENERATOR *Generator,
927 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
928 IN AML_OBJECT_NODE_HANDLE ScopeNode
929 )
930 {
931 EFI_STATUS Status;
932 CM_ARM_GICC_INFO *GicCInfo;
933 UINT32 GicCInfoCount;
934 UINT32 Index;
935
936 ASSERT (Generator != NULL);
937 ASSERT (CfgMgrProtocol != NULL);
938 ASSERT (ScopeNode != NULL);
939
940 Status = GetEArmObjGicCInfo (
941 CfgMgrProtocol,
942 CM_NULL_TOKEN,
943 &GicCInfo,
944 &GicCInfoCount
945 );
946 if (EFI_ERROR (Status)) {
947 ASSERT (0);
948 return Status;
949 }
950
951 // For each CM_ARM_GICC_INFO object, create an AML node.
952 for (Index = 0; Index < GicCInfoCount; Index++) {
953 Status = CreateAmlCpu (
954 Generator,
955 ScopeNode,
956 &GicCInfo[Index],
957 Index,
958 NULL
959 );
960 if (EFI_ERROR (Status)) {
961 ASSERT (0);
962 break;
963 }
964 } // for
965
966 return Status;
967 }
968
969 /** Construct the SSDT Cpu Topology ACPI table.
970
971 This function invokes the Configuration Manager protocol interface
972 to get the required hardware information for generating the ACPI
973 table.
974
975 If this function allocates any resources then they must be freed
976 in the FreeXXXXTableResources function.
977
978 @param [in] This Pointer to the table generator.
979 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
980 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
981 Protocol Interface.
982 @param [out] Table Pointer to the constructed ACPI Table.
983
984 @retval EFI_SUCCESS Table generated successfully.
985 @retval EFI_INVALID_PARAMETER A parameter is invalid.
986 @retval EFI_NOT_FOUND The required object was not found.
987 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
988 Manager is less than the Object size for the
989 requested object.
990 **/
991 STATIC
992 EFI_STATUS
993 EFIAPI
994 BuildSsdtCpuTopologyTable (
995 IN CONST ACPI_TABLE_GENERATOR *CONST This,
996 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
997 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
998 OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
999 )
1000 {
1001 EFI_STATUS Status;
1002 AML_ROOT_NODE_HANDLE RootNode;
1003 AML_OBJECT_NODE_HANDLE ScopeNode;
1004 CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeList;
1005 UINT32 ProcHierarchyNodeCount;
1006 ACPI_CPU_TOPOLOGY_GENERATOR *Generator;
1007
1008 ASSERT (This != NULL);
1009 ASSERT (AcpiTableInfo != NULL);
1010 ASSERT (CfgMgrProtocol != NULL);
1011 ASSERT (Table != NULL);
1012 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
1013 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
1014
1015 Generator = (ACPI_CPU_TOPOLOGY_GENERATOR *)This;
1016
1017 Status = AddSsdtAcpiHeader (
1018 CfgMgrProtocol,
1019 This,
1020 AcpiTableInfo,
1021 &RootNode
1022 );
1023 if (EFI_ERROR (Status)) {
1024 return Status;
1025 }
1026
1027 Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
1028 if (EFI_ERROR (Status)) {
1029 goto exit_handler;
1030 }
1031
1032 // Get the processor hierarchy info and update the processor topology
1033 // structure count with Processor Hierarchy Nodes (Type 0)
1034 Status = GetEArmObjProcHierarchyInfo (
1035 CfgMgrProtocol,
1036 CM_NULL_TOKEN,
1037 &ProcHierarchyNodeList,
1038 &ProcHierarchyNodeCount
1039 );
1040 if (EFI_ERROR (Status) &&
1041 (Status != EFI_NOT_FOUND))
1042 {
1043 goto exit_handler;
1044 }
1045
1046 if (Status == EFI_NOT_FOUND) {
1047 // If hierarchy information is not found generate a flat topology
1048 // using CM_ARM_GICC_INFO objects.
1049 Status = CreateTopologyFromGicC (
1050 Generator,
1051 CfgMgrProtocol,
1052 ScopeNode
1053 );
1054 if (EFI_ERROR (Status)) {
1055 goto exit_handler;
1056 }
1057 } else {
1058 // Generate the topology from CM_ARM_PROC_HIERARCHY_INFO objects.
1059 Generator->ProcNodeList = ProcHierarchyNodeList;
1060 Generator->ProcNodeCount = ProcHierarchyNodeCount;
1061
1062 Status = CreateTopologyFromProcHierarchy (
1063 Generator,
1064 CfgMgrProtocol,
1065 ScopeNode
1066 );
1067 if (EFI_ERROR (Status)) {
1068 goto exit_handler;
1069 }
1070 }
1071
1072 Status = AmlSerializeDefinitionBlock (
1073 RootNode,
1074 Table
1075 );
1076 if (EFI_ERROR (Status)) {
1077 DEBUG ((
1078 DEBUG_ERROR,
1079 "ERROR: SSDT-CPU-TOPOLOGY: Failed to Serialize SSDT Table Data."
1080 " Status = %r\n",
1081 Status
1082 ));
1083 goto exit_handler;
1084 }
1085
1086 exit_handler:
1087 // Delete the RootNode and its attached children.
1088 return AmlDeleteTree (RootNode);
1089 }
1090
1091 /** Free any resources allocated for constructing the
1092 SSDT Cpu Topology ACPI table.
1093
1094 @param [in] This Pointer to the table generator.
1095 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1096 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1097 Protocol Interface.
1098 @param [in, out] Table Pointer to the ACPI Table.
1099
1100 @retval EFI_SUCCESS The resources were freed successfully.
1101 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1102 **/
1103 STATIC
1104 EFI_STATUS
1105 FreeSsdtCpuTopologyTableResources (
1106 IN CONST ACPI_TABLE_GENERATOR *CONST This,
1107 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
1108 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
1109 IN OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
1110 )
1111 {
1112 ASSERT (This != NULL);
1113 ASSERT (AcpiTableInfo != NULL);
1114 ASSERT (CfgMgrProtocol != NULL);
1115 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
1116 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
1117
1118 if ((Table == NULL) || (*Table == NULL)) {
1119 DEBUG ((DEBUG_ERROR, "ERROR: SSDT-CPU-TOPOLOGY: Invalid Table Pointer\n"));
1120 ASSERT ((Table != NULL) && (*Table != NULL));
1121 return EFI_INVALID_PARAMETER;
1122 }
1123
1124 FreePool (*Table);
1125 *Table = NULL;
1126 return EFI_SUCCESS;
1127 }
1128
1129 /** This macro defines the SSDT Cpu Topology Table Generator revision.
1130 */
1131 #define SSDT_CPU_TOPOLOGY_GENERATOR_REVISION CREATE_REVISION (1, 0)
1132
1133 /** The interface for the SSDT Cpu Topology Table Generator.
1134 */
1135 STATIC
1136 ACPI_CPU_TOPOLOGY_GENERATOR SsdtCpuTopologyGenerator = {
1137 // ACPI table generator header
1138 {
1139 // Generator ID
1140 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCpuTopology),
1141 // Generator Description
1142 L"ACPI.STD.SSDT.CPU.TOPOLOGY.GENERATOR",
1143 // ACPI Table Signature
1144 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
1145 // ACPI Table Revision - Unused
1146 0,
1147 // Minimum ACPI Table Revision - Unused
1148 0,
1149 // Creator ID
1150 TABLE_GENERATOR_CREATOR_ID_ARM,
1151 // Creator Revision
1152 SSDT_CPU_TOPOLOGY_GENERATOR_REVISION,
1153 // Build Table function
1154 BuildSsdtCpuTopologyTable,
1155 // Free Resource function
1156 FreeSsdtCpuTopologyTableResources,
1157 // Extended build function not needed
1158 NULL,
1159 // Extended build function not implemented by the generator.
1160 // Hence extended free resource function is not required.
1161 NULL
1162 },
1163
1164 // Private fields are defined from here.
1165
1166 // TokenTable
1167 {
1168 // Table
1169 NULL,
1170 // LastIndex
1171 0
1172 },
1173 // ProcNodeList
1174 NULL,
1175 // ProcNodeCount
1176 0
1177 };
1178
1179 /** Register the Generator with the ACPI Table Factory.
1180
1181 @param [in] ImageHandle The handle to the image.
1182 @param [in] SystemTable Pointer to the System Table.
1183
1184 @retval EFI_SUCCESS The Generator is registered.
1185 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1186 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1187 is already registered.
1188 **/
1189 EFI_STATUS
1190 EFIAPI
1191 AcpiSsdtCpuTopologyLibConstructor (
1192 IN EFI_HANDLE ImageHandle,
1193 IN EFI_SYSTEM_TABLE *SystemTable
1194 )
1195 {
1196 EFI_STATUS Status;
1197
1198 Status = RegisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
1199 DEBUG ((
1200 DEBUG_INFO,
1201 "SSDT-CPU-TOPOLOGY: Register Generator. Status = %r\n",
1202 Status
1203 ));
1204 ASSERT_EFI_ERROR (Status);
1205
1206 return Status;
1207 }
1208
1209 /** Deregister the Generator from the ACPI Table Factory.
1210
1211 @param [in] ImageHandle The handle to the image.
1212 @param [in] SystemTable Pointer to the System Table.
1213
1214 @retval EFI_SUCCESS The Generator is deregistered.
1215 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1216 @retval EFI_NOT_FOUND The Generator is not registered.
1217 **/
1218 EFI_STATUS
1219 EFIAPI
1220 AcpiSsdtCpuTopologyLibDestructor (
1221 IN EFI_HANDLE ImageHandle,
1222 IN EFI_SYSTEM_TABLE *SystemTable
1223 )
1224 {
1225 EFI_STATUS Status;
1226
1227 Status = DeregisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
1228 DEBUG ((
1229 DEBUG_INFO,
1230 "SSDT-CPU-TOPOLOGY: Deregister Generator. Status = %r\n",
1231 Status
1232 ));
1233 ASSERT_EFI_ERROR (Status);
1234 return Status;
1235 }