]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
3f6cef3ba5558990d56e0ee9759ce0b29d041ec9
[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 ASSERT (0);
109 return EFI_INVALID_PARAMETER;
110 }
111
112 Table = AllocateZeroPool (sizeof (CM_OBJECT_TOKEN) * Count);
113 if (Table == NULL) {
114 ASSERT (0);
115 return EFI_OUT_OF_RESOURCES;
116 }
117
118 Generator->TokenTable.Table = Table;
119
120 return EFI_SUCCESS;
121 }
122
123 /** Free the TokenTable.
124
125 @param [in] Generator The SSDT Cpu Topology generator.
126 **/
127 STATIC
128 VOID
129 EFIAPI
130 TokenTableFree (
131 IN ACPI_CPU_TOPOLOGY_GENERATOR * Generator
132 )
133 {
134 ASSERT (Generator != NULL);
135 ASSERT (Generator->TokenTable.Table != NULL);
136
137 if (Generator->TokenTable.Table != NULL) {
138 FreePool (Generator->TokenTable.Table);
139 }
140 }
141
142 /** Add a new entry to the TokenTable and return its index.
143
144 If an entry with Token is already available in the table,
145 return its index without adding a new entry.
146
147 @param [in] Generator The SSDT Cpu Topology generator.
148 @param [in] Token New Token entry to add.
149
150 @retval The index of the token entry in the TokenTable.
151 **/
152 STATIC
153 UINT32
154 EFIAPI
155 TokenTableAdd (
156 IN ACPI_CPU_TOPOLOGY_GENERATOR * Generator,
157 IN CM_OBJECT_TOKEN Token
158 )
159 {
160 CM_OBJECT_TOKEN * Table;
161 UINT32 Index;
162 UINT32 LastIndex;
163
164 ASSERT (Generator != NULL);
165 ASSERT (Generator->TokenTable.Table != NULL);
166
167 Table = Generator->TokenTable.Table;
168 LastIndex = Generator->TokenTable.LastIndex;
169
170 // Search if there is already an entry with this Token.
171 for (Index = 0; Index < LastIndex; Index++) {
172 if (Table[Index] == Token) {
173 return Index;
174 }
175 }
176
177 ASSERT (LastIndex < MAX_NODE_COUNT);
178 ASSERT (LastIndex < Generator->ProcNodeCount);
179
180 // If no, create a new entry.
181 Table[LastIndex] = Token;
182
183 return Generator->TokenTable.LastIndex++;
184 }
185
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.
189
190 As 'xxx' in hexadecimal represents a number on 12 bits,
191 we have Value < (1 << 12).
192
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.
198
199 @retval EFI_SUCCESS Success.
200 @retval EFI_INVALID_PARAMETER Invalid parameter.
201 **/
202 STATIC
203 EFI_STATUS
204 EFIAPI
205 WriteAslName (
206 IN CHAR8 LeadChar,
207 IN UINT32 Value,
208 IN OUT CHAR8 * AslName
209 )
210 {
211 UINT8 Index;
212
213 if ((Value >= MAX_NODE_COUNT) ||
214 (AslName == NULL)) {
215 ASSERT (0);
216 return EFI_INVALID_PARAMETER;
217 }
218
219 AslName[0] = LeadChar;
220 AslName[AML_NAME_SEG_SIZE] = '\0';
221
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));
225 }
226
227 return EFI_SUCCESS;
228 }
229
230 /** Create and add an _LPI method to Cpu/Cluster Node.
231
232 For instance, transform an AML node from:
233 Device (C002)
234 {
235 Name (_UID, 2)
236 Name (_HID, "ACPI0007")
237 }
238
239 To:
240 Device (C002)
241 {
242 Name (_UID, 2)
243 Name (_HID, "ACPI0007")
244 Method (_LPI, 0, NotSerialized)
245 {
246 Return (\_SB.L003)
247 }
248 }
249
250 @param [in] Generator The SSDT Cpu Topology generator.
251 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO describing
252 the Cpu.
253 @param [in] Node Node to which the _LPI method is
254 attached. Can represent a Cpu or a
255 Cluster.
256
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.
260 **/
261 STATIC
262 EFI_STATUS
263 EFIAPI
264 CreateAmlLpiMethod (
265 IN ACPI_CPU_TOPOLOGY_GENERATOR * Generator,
266 IN CM_ARM_PROC_HIERARCHY_INFO * ProcHierarchyNodeInfo,
267 IN AML_OBJECT_NODE_HANDLE * Node
268 )
269 {
270 EFI_STATUS Status;
271 UINT32 TokenIndex;
272 CHAR8 AslName[SB_SCOPE_PREFIX_SIZE + AML_NAME_SEG_SIZE];
273
274 ASSERT (Generator != NULL);
275 ASSERT (ProcHierarchyNodeInfo != NULL);
276 ASSERT (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN);
277 ASSERT (Node != NULL);
278
279 TokenIndex = TokenTableAdd (Generator, ProcHierarchyNodeInfo->LpiToken);
280
281 CopyMem (AslName, SB_SCOPE_PREFIX, SB_SCOPE_PREFIX_SIZE);
282
283 Status = WriteAslName (
284 'L',
285 TokenIndex,
286 AslName + SB_SCOPE_PREFIX_SIZE - 1
287 );
288 if (EFI_ERROR (Status)) {
289 ASSERT (0);
290 return Status;
291 }
292
293 // ASL:
294 // Method (_LPI, 0) {
295 // Return ([AslName])
296 // }
297 Status = AmlCodeGenMethodRetNameString (
298 "_LPI",
299 AslName,
300 0,
301 FALSE,
302 0,
303 Node,
304 NULL
305 );
306 if (EFI_ERROR (Status)) {
307 ASSERT (0);
308 }
309
310 return Status;
311 }
312
313 /** Generate all the Lpi states under the '_SB' scope.
314
315 This function generates the following ASL code:
316 Scope (\_SB) {
317 Name (L000, Package() {
318 0, // Version
319 0, // Level Index
320 X, // Count
321 Package() {
322 [An Lpi state]
323 },
324 Package() {
325 [Another Lpi state]
326 },
327 } // Name L000
328
329 Name (L001, Package() {
330 ...
331 } // Name L001
332
333 ...
334 } // Scope /_SB
335
336 The Lpi states are fetched from the Configuration Manager.
337 The names of the Lpi states are generated from the TokenTable.
338
339 @param [in] Generator The SSDT Cpu Topology generator.
340 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
341 Protocol Interface.
342 @param [in] ScopeNode Scope node handle ('\_SB' scope).
343
344 @retval EFI_SUCCESS Success.
345 @retval EFI_INVALID_PARAMETER Invalid parameter.
346 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
347 **/
348 STATIC
349 EFI_STATUS
350 EFIAPI
351 GenerateLpiStates (
352 IN ACPI_CPU_TOPOLOGY_GENERATOR * Generator,
353 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
354 IN AML_OBJECT_NODE_HANDLE ScopeNode
355 )
356 {
357 EFI_STATUS Status;
358
359 UINT32 Index;
360 UINT32 LastIndex;
361
362 AML_OBJECT_NODE_HANDLE LpiNode;
363 CM_ARM_OBJ_REF * LpiRefInfo;
364 UINT32 LpiRefInfoCount;
365 UINT32 LpiRefIndex;
366 CM_ARM_LPI_INFO * LpiInfo;
367 CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
368
369 ASSERT (Generator != NULL);
370 ASSERT (Generator->TokenTable.Table != NULL);
371 ASSERT (CfgMgrProtocol != NULL);
372 ASSERT (ScopeNode != NULL);
373
374 LastIndex = Generator->TokenTable.LastIndex;
375
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)) {
381 ASSERT (0);
382 return Status;
383 }
384
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)) {
388 ASSERT (0);
389 return Status;
390 }
391
392 // Fetch the LPI objects referenced by the token.
393 Status = GetEArmObjCmRef (
394 CfgMgrProtocol,
395 Generator->TokenTable.Table[Index],
396 &LpiRefInfo,
397 &LpiRefInfoCount
398 );
399 if (EFI_ERROR (Status)) {
400 ASSERT (0);
401 return Status;
402 }
403
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 (
407 CfgMgrProtocol,
408 LpiRefInfo[LpiRefIndex].ReferenceToken,
409 &LpiInfo,
410 NULL
411 );
412 if (EFI_ERROR (Status)) {
413 ASSERT (0);
414 return Status;
415 }
416
417 Status = AmlAddLpiState (
418 LpiInfo->MinResidency,
419 LpiInfo->WorstCaseWakeLatency,
420 LpiInfo->Flags,
421 LpiInfo->ArchFlags,
422 LpiInfo->ResCntFreq,
423 LpiInfo->EnableParentState,
424 LpiInfo->IsInteger ?
425 NULL :
426 &LpiInfo->RegisterEntryMethod,
427 LpiInfo->IsInteger ?
428 LpiInfo->IntegerEntryMethod :
429 0,
430 &LpiInfo->ResidencyCounterRegister,
431 &LpiInfo->UsageCounterRegister,
432 LpiInfo->StateName,
433 LpiNode
434 );
435 if (EFI_ERROR (Status)) {
436 ASSERT (0);
437 return Status;
438 }
439 } // for LpiRefIndex
440 } // for Index
441
442 return EFI_SUCCESS;
443 }
444
445 /** Create a Cpu in the AML namespace.
446
447 This generates the following ASL code:
448 Device (C002)
449 {
450 Name (_UID, 2)
451 Name (_HID, "ACPI0007")
452 }
453
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.
459
460 @retval EFI_SUCCESS Success.
461 @retval EFI_INVALID_PARAMETER Invalid parameter.
462 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
463 **/
464 STATIC
465 EFI_STATUS
466 EFIAPI
467 CreateAmlCpu (
468 IN ACPI_CPU_TOPOLOGY_GENERATOR * Generator,
469 IN AML_NODE_HANDLE ParentNode,
470 IN CM_ARM_GICC_INFO * GicCInfo,
471 IN UINT32 CpuIndex,
472 OUT AML_OBJECT_NODE_HANDLE * CpuNodePtr OPTIONAL
473 )
474 {
475 EFI_STATUS Status;
476 AML_OBJECT_NODE_HANDLE CpuNode;
477 CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
478
479 ASSERT (Generator != NULL);
480 ASSERT (ParentNode != NULL);
481 ASSERT (GicCInfo != NULL);
482
483 Status = WriteAslName ('C', CpuIndex, AslName);
484 if (EFI_ERROR (Status)) {
485 ASSERT (0);
486 return Status;
487 }
488
489 Status = AmlCodeGenDevice (AslName, ParentNode, &CpuNode);
490 if (EFI_ERROR (Status)) {
491 ASSERT (0);
492 return Status;
493 }
494
495 Status = AmlCodeGenNameInteger (
496 "_UID",
497 GicCInfo->AcpiProcessorUid,
498 CpuNode,
499 NULL
500 );
501 if (EFI_ERROR (Status)) {
502 ASSERT (0);
503 return Status;
504 }
505
506 Status = AmlCodeGenNameString (
507 "_HID",
508 ACPI_HID_PROCESSOR_DEVICE,
509 CpuNode,
510 NULL
511 );
512 if (EFI_ERROR (Status)) {
513 ASSERT (0);
514 return Status;
515 }
516
517 // If requested, return the handle to the CpuNode.
518 if (CpuNodePtr != NULL) {
519 *CpuNodePtr = CpuNode;
520 }
521
522 return Status;
523 }
524
525 /** Create a Cpu in the AML namespace from a CM_ARM_PROC_HIERARCHY_INFO
526 CM object.
527
528 @param [in] Generator The SSDT Cpu Topology generator.
529 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
530 Protocol Interface.
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
534 the Cpu.
535
536 @retval EFI_SUCCESS Success.
537 @retval EFI_INVALID_PARAMETER Invalid parameter.
538 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
539 **/
540 STATIC
541 EFI_STATUS
542 EFIAPI
543 CreateAmlCpuFromProcHierarchy (
544 IN ACPI_CPU_TOPOLOGY_GENERATOR * Generator,
545 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
546 IN AML_NODE_HANDLE ParentNode,
547 IN UINT32 CpuIndex,
548 IN CM_ARM_PROC_HIERARCHY_INFO * ProcHierarchyNodeInfo
549 )
550 {
551 EFI_STATUS Status;
552 CM_ARM_GICC_INFO * GicCInfo;
553 AML_OBJECT_NODE_HANDLE CpuNode;
554
555 ASSERT (Generator != NULL);
556 ASSERT (CfgMgrProtocol != NULL);
557 ASSERT (ParentNode != NULL);
558 ASSERT (ProcHierarchyNodeInfo != NULL);
559 ASSERT (ProcHierarchyNodeInfo->GicCToken != CM_NULL_TOKEN);
560
561 Status = GetEArmObjGicCInfo (
562 CfgMgrProtocol,
563 ProcHierarchyNodeInfo->GicCToken,
564 &GicCInfo,
565 NULL
566 );
567 if (EFI_ERROR (Status)) {
568 ASSERT (0);
569 return Status;
570 }
571
572 Status = CreateAmlCpu (Generator, ParentNode, GicCInfo, CpuIndex, &CpuNode);
573 if (EFI_ERROR (Status)) {
574 ASSERT (0);
575 return Status;
576 }
577
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);
583 }
584
585 return Status;
586 }
587
588 /** Create a Cluster in the AML namespace.
589
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
595
596 This generates the following ASL code:
597 Device (C002)
598 {
599 Name (_UID, 2)
600 Name (_HID, "ACPI0010")
601 }
602
603 @param [in] Generator The SSDT Cpu Topology generator.
604 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
605 Protocol Interface.
606 @param [in] ParentNode Parent node to attach the Cluster
607 node to.
608 @param [in] ProcHierarchyNodeInfo CM_ARM_PROC_HIERARCHY_INFO object used
609 to create the node.
610 @param [in] ClusterIndex Index used to generate the node name.
611 @param [out] ClusterNodePtr If success, contains the created Cluster
612 node.
613
614 @retval EFI_SUCCESS Success.
615 @retval EFI_INVALID_PARAMETER Invalid parameter.
616 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
617 **/
618 STATIC
619 EFI_STATUS
620 EFIAPI
621 CreateAmlCluster (
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
628 )
629 {
630 EFI_STATUS Status;
631 AML_OBJECT_NODE_HANDLE ClusterNode;
632 CHAR8 AslNameCluster[AML_NAME_SEG_SIZE + 1];
633
634 ASSERT (Generator != NULL);
635 ASSERT (CfgMgrProtocol != NULL);
636 ASSERT (ParentNode != NULL);
637 ASSERT (ProcHierarchyNodeInfo != NULL);
638 ASSERT (ClusterNodePtr != NULL);
639
640 Status = WriteAslName ('C', ClusterIndex, AslNameCluster);
641 if (EFI_ERROR (Status)) {
642 ASSERT (0);
643 return Status;
644 }
645
646 Status = AmlCodeGenDevice (AslNameCluster, ParentNode, &ClusterNode);
647 if (EFI_ERROR (Status)) {
648 ASSERT (0);
649 return Status;
650 }
651
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 (
655 "_UID",
656 ClusterIndex,
657 ClusterNode,
658 NULL
659 );
660 if (EFI_ERROR (Status)) {
661 ASSERT (0);
662 return Status;
663 }
664
665 Status = AmlCodeGenNameString (
666 "_HID",
667 ACPI_HID_PROCESSOR_CONTAINER_DEVICE,
668 ClusterNode,
669 NULL
670 );
671 if (EFI_ERROR (Status)) {
672 ASSERT (0);
673 return Status;
674 }
675
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 (
680 Generator,
681 ProcHierarchyNodeInfo,
682 ClusterNode
683 );
684 if (EFI_ERROR (Status)) {
685 ASSERT (0);
686 return Status;
687 }
688 }
689
690 *ClusterNodePtr = ClusterNode;
691
692 return Status;
693 }
694
695 /** Create an AML representation of the Cpu topology.
696
697 A cluster is by extension any non-leave device in the cpu topology.
698
699 @param [in] Generator The SSDT Cpu Topology generator.
700 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
701 Protocol Interface.
702 @param [in] NodeToken Token of the CM_ARM_PROC_HIERARCHY_INFO
703 currently handled.
704 Cannot be CM_NULL_TOKEN.
705 @param [in] ParentNode Parent node to attach the created
706 node to.
707
708 @retval EFI_SUCCESS Success.
709 @retval EFI_INVALID_PARAMETER Invalid parameter.
710 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
711 **/
712 STATIC
713 EFI_STATUS
714 EFIAPI
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
720 )
721 {
722 EFI_STATUS Status;
723 UINT32 Index;
724 UINT32 CpuIndex;
725 UINT32 ClusterIndex;
726 AML_OBJECT_NODE_HANDLE ClusterNode;
727
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);
734
735 CpuIndex = 0;
736 ClusterIndex = 0;
737
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) {
742
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) {
748 DEBUG ((
749 DEBUG_ERROR,
750 "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cpu: 0x%x.\n",
751 Generator->ProcNodeList[Index].Flags
752 ));
753 ASSERT (0);
754 return EFI_INVALID_PARAMETER;
755 }
756
757 Status = CreateAmlCpuFromProcHierarchy (
758 Generator,
759 CfgMgrProtocol,
760 ParentNode,
761 CpuIndex,
762 &Generator->ProcNodeList[Index]
763 );
764 if (EFI_ERROR (Status)) {
765 ASSERT (0);
766 return Status;
767 }
768
769 CpuIndex++;
770
771 } else {
772 // If this is not a Cpu, then this is a cluster.
773
774 // Acpi processor Id for clusters is not handled.
775 if ((Generator->ProcNodeList[Index].Flags & PPTT_PROCESSOR_MASK) !=
776 PPTT_CLUSTER_PROCESSOR_MASK) {
777 DEBUG ((
778 DEBUG_ERROR,
779 "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cluster: 0x%x.\n",
780 Generator->ProcNodeList[Index].Flags
781 ));
782 ASSERT (0);
783 return EFI_INVALID_PARAMETER;
784 }
785
786 Status = CreateAmlCluster (
787 Generator,
788 CfgMgrProtocol,
789 ParentNode,
790 &Generator->ProcNodeList[Index],
791 ClusterIndex,
792 &ClusterNode
793 );
794 if (EFI_ERROR (Status)) {
795 ASSERT (0);
796 return Status;
797 }
798
799 // Nodes must have a unique name in the ASL namespace.
800 // Reset the Cpu index whenever we create a new Cluster.
801 ClusterIndex++;
802 CpuIndex = 0;
803
804 // Recursively continue creating an AML tree.
805 Status = CreateAmlCpuTopologyTree (
806 Generator,
807 CfgMgrProtocol,
808 Generator->ProcNodeList[Index].Token,
809 ClusterNode
810 );
811 if (EFI_ERROR (Status)) {
812 ASSERT (0);
813 return Status;
814 }
815 }
816 } // if ParentToken == NodeToken
817 } // for
818
819 return EFI_SUCCESS;
820 }
821
822 /** Create the processor hierarchy AML tree from CM_ARM_PROC_HIERARCHY_INFO
823 CM objects.
824
825 @param [in] Generator The SSDT Cpu Topology generator.
826 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
827 Protocol Interface.
828 @param [in] ScopeNode Scope node handle ('\_SB' scope).
829
830 @retval EFI_SUCCESS Success.
831 @retval EFI_INVALID_PARAMETER Invalid parameter.
832 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
833 **/
834 STATIC
835 EFI_STATUS
836 EFIAPI
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
841 )
842 {
843 EFI_STATUS Status;
844 UINT32 Index;
845 UINT32 TopLevelProcNodeIndex;
846
847 ASSERT (Generator != NULL);
848 ASSERT (Generator->ProcNodeCount != 0);
849 ASSERT (Generator->ProcNodeList != NULL);
850 ASSERT (CfgMgrProtocol != NULL);
851 ASSERT (ScopeNode != NULL);
852
853 TopLevelProcNodeIndex = MAX_UINT32;
854
855 Status = TokenTableInitialize (Generator, Generator->ProcNodeCount);
856 if (EFI_ERROR (Status)) {
857 ASSERT (0);
858 return Status;
859 }
860
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) {
870 DEBUG ((
871 DEBUG_ERROR,
872 "ERROR: SSDT-CPU-TOPOLOGY: Top level CM_ARM_PROC_HIERARCHY_INFO "
873 "must be unique\n"
874 ));
875 ASSERT (0);
876 goto exit_handler;
877 }
878 TopLevelProcNodeIndex = Index;
879 }
880 } // for
881
882 Status = CreateAmlCpuTopologyTree (
883 Generator,
884 CfgMgrProtocol,
885 Generator->ProcNodeList[TopLevelProcNodeIndex].Token,
886 ScopeNode
887 );
888 if (EFI_ERROR (Status)) {
889 ASSERT (0);
890 goto exit_handler;
891 }
892
893 Status = GenerateLpiStates (Generator, CfgMgrProtocol, ScopeNode);
894 if (EFI_ERROR (Status)) {
895 ASSERT (0);
896 goto exit_handler;
897 }
898
899 exit_handler:
900 TokenTableFree (Generator);
901 return Status;
902 }
903
904 /** Create the processor hierarchy AML tree from CM_ARM_GICC_INFO
905 CM objects.
906
907 A cluster is by extension any non-leave device in the cpu topology.
908
909 @param [in] Generator The SSDT Cpu Topology generator.
910 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
911 Protocol Interface.
912 @param [in] ScopeNode Scope node handle ('\_SB' scope).
913
914 @retval EFI_SUCCESS Success.
915 @retval EFI_INVALID_PARAMETER Invalid parameter.
916 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
917 **/
918 STATIC
919 EFI_STATUS
920 EFIAPI
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
925 )
926 {
927 EFI_STATUS Status;
928 CM_ARM_GICC_INFO * GicCInfo;
929 UINT32 GicCInfoCount;
930 UINT32 Index;
931
932 ASSERT (Generator != NULL);
933 ASSERT (CfgMgrProtocol != NULL);
934 ASSERT (ScopeNode != NULL);
935
936 Status = GetEArmObjGicCInfo (
937 CfgMgrProtocol,
938 CM_NULL_TOKEN,
939 &GicCInfo,
940 &GicCInfoCount
941 );
942 if (EFI_ERROR (Status)) {
943 ASSERT (0);
944 return Status;
945 }
946
947 // For each CM_ARM_GICC_INFO object, create an AML node.
948 for (Index = 0; Index < GicCInfoCount; Index++) {
949 Status = CreateAmlCpu (
950 Generator,
951 ScopeNode,
952 &GicCInfo[Index],
953 Index,
954 NULL
955 );
956 if (EFI_ERROR (Status)) {
957 ASSERT (0);
958 break;
959 }
960 } // for
961
962 return Status;
963 }
964
965 /** Construct the SSDT Cpu Topology ACPI table.
966
967 This function invokes the Configuration Manager protocol interface
968 to get the required hardware information for generating the ACPI
969 table.
970
971 If this function allocates any resources then they must be freed
972 in the FreeXXXXTableResources function.
973
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
977 Protocol Interface.
978 @param [out] Table Pointer to the constructed ACPI Table.
979
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
985 requested object.
986 **/
987 STATIC
988 EFI_STATUS
989 EFIAPI
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
995 )
996 {
997 EFI_STATUS Status;
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;
1003
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);
1010
1011 Generator = (ACPI_CPU_TOPOLOGY_GENERATOR*)This;
1012
1013 Status = AddSsdtAcpiHeader (
1014 CfgMgrProtocol,
1015 This,
1016 AcpiTableInfo,
1017 &RootNode
1018 );
1019 if (EFI_ERROR (Status)) {
1020 return Status;
1021 }
1022
1023 Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
1024 if (EFI_ERROR (Status)) {
1025 goto exit_handler;
1026 }
1027
1028 // Get the processor hierarchy info and update the processor topology
1029 // structure count with Processor Hierarchy Nodes (Type 0)
1030 Status = GetEArmObjProcHierarchyInfo (
1031 CfgMgrProtocol,
1032 CM_NULL_TOKEN,
1033 &ProcHierarchyNodeList,
1034 &ProcHierarchyNodeCount
1035 );
1036 if (EFI_ERROR (Status) &&
1037 (Status != EFI_NOT_FOUND)) {
1038 goto exit_handler;
1039 }
1040
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 (
1045 Generator,
1046 CfgMgrProtocol,
1047 ScopeNode
1048 );
1049 if (EFI_ERROR (Status)) {
1050 goto exit_handler;
1051 }
1052 } else {
1053 // Generate the topology from CM_ARM_PROC_HIERARCHY_INFO objects.
1054 Generator->ProcNodeList = ProcHierarchyNodeList;
1055 Generator->ProcNodeCount = ProcHierarchyNodeCount;
1056
1057 Status = CreateTopologyFromProcHierarchy (
1058 Generator,
1059 CfgMgrProtocol,
1060 ScopeNode
1061 );
1062 if (EFI_ERROR (Status)) {
1063 goto exit_handler;
1064 }
1065 }
1066
1067 Status = AmlSerializeDefinitionBlock (
1068 RootNode,
1069 Table
1070 );
1071 if (EFI_ERROR (Status)) {
1072 DEBUG ((
1073 DEBUG_ERROR,
1074 "ERROR: SSDT-CPU-TOPOLOGY: Failed to Serialize SSDT Table Data."
1075 " Status = %r\n",
1076 Status
1077 ));
1078 goto exit_handler;
1079 }
1080
1081 exit_handler:
1082 // Delete the RootNode and its attached children.
1083 return AmlDeleteTree (RootNode);
1084 }
1085
1086 /** Free any resources allocated for constructing the
1087 SSDT Cpu Topology ACPI table.
1088
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
1092 Protocol Interface.
1093 @param [in, out] Table Pointer to the ACPI Table.
1094
1095 @retval EFI_SUCCESS The resources were freed successfully.
1096 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1097 **/
1098 STATIC
1099 EFI_STATUS
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
1105 )
1106 {
1107 ASSERT (This != NULL);
1108 ASSERT (AcpiTableInfo != NULL);
1109 ASSERT (CfgMgrProtocol != NULL);
1110 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
1111 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
1112
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;
1117 }
1118
1119 FreePool (*Table);
1120 *Table = NULL;
1121 return EFI_SUCCESS;
1122 }
1123
1124 /** This macro defines the SSDT Cpu Topology Table Generator revision.
1125 */
1126 #define SSDT_CPU_TOPOLOGY_GENERATOR_REVISION CREATE_REVISION (1, 0)
1127
1128 /** The interface for the SSDT Cpu Topology Table Generator.
1129 */
1130 STATIC
1131 ACPI_CPU_TOPOLOGY_GENERATOR SsdtCpuTopologyGenerator = {
1132 // ACPI table generator header
1133 {
1134 // Generator ID
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
1141 0,
1142 // Minimum ACPI Table Revision - Unused
1143 0,
1144 // Creator ID
1145 TABLE_GENERATOR_CREATOR_ID_ARM,
1146 // Creator Revision
1147 SSDT_CPU_TOPOLOGY_GENERATOR_REVISION,
1148 // Build Table function
1149 BuildSsdtCpuTopologyTable,
1150 // Free Resource function
1151 FreeSsdtCpuTopologyTableResources,
1152 // Extended build function not needed
1153 NULL,
1154 // Extended build function not implemented by the generator.
1155 // Hence extended free resource function is not required.
1156 NULL
1157 },
1158
1159 // Private fields are defined from here.
1160
1161 // TokenTable
1162 {
1163 // Table
1164 NULL,
1165 // LastIndex
1166 0
1167 },
1168 // ProcNodeList
1169 NULL,
1170 // ProcNodeCount
1171 0
1172 };
1173
1174 /** Register the Generator with the ACPI Table Factory.
1175
1176 @param [in] ImageHandle The handle to the image.
1177 @param [in] SystemTable Pointer to the System Table.
1178
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.
1183 **/
1184 EFI_STATUS
1185 EFIAPI
1186 AcpiSsdtCpuTopologyLibConstructor (
1187 IN EFI_HANDLE ImageHandle,
1188 IN EFI_SYSTEM_TABLE * SystemTable
1189 )
1190 {
1191 EFI_STATUS Status;
1192 Status = RegisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
1193 DEBUG ((
1194 DEBUG_INFO,
1195 "SSDT-CPU-TOPOLOGY: Register Generator. Status = %r\n",
1196 Status
1197 ));
1198 ASSERT_EFI_ERROR (Status);
1199
1200 return Status;
1201 }
1202
1203 /** Deregister the Generator from the ACPI Table Factory.
1204
1205 @param [in] ImageHandle The handle to the image.
1206 @param [in] SystemTable Pointer to the System Table.
1207
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.
1211 **/
1212 EFI_STATUS
1213 EFIAPI
1214 AcpiSsdtCpuTopologyLibDestructor (
1215 IN EFI_HANDLE ImageHandle,
1216 IN EFI_SYSTEM_TABLE * SystemTable
1217 )
1218 {
1219 EFI_STATUS Status;
1220 Status = DeregisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
1221 DEBUG ((
1222 DEBUG_INFO,
1223 "SSDT-CPU-TOPOLOGY: Deregister Generator. Status = %r\n",
1224 Status
1225 ));
1226 ASSERT_EFI_ERROR (Status);
1227 return Status;
1228 }