]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c
DynamicTablesPkg: Apply uncrustify changes
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiPpttLibArm / PpttGenerator.c
CommitLineData
77db1156
KK
1/** @file\r
2 PPTT Table Generator\r
3\r
4 Copyright (c) 2019, ARM Limited. All rights reserved.\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7 @par Reference(s):\r
8 - ACPI 6.3 Specification, January 2019\r
9\r
10 @par Glossary:\r
11 - Cm or CM - Configuration Manager\r
12 - Obj or OBJ - Object\r
13**/\r
14\r
15#include <Library/AcpiLib.h>\r
16#include <Library/BaseLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
19#include <Protocol/AcpiTable.h>\r
20\r
21// Module specific include files.\r
22#include <AcpiTableGenerator.h>\r
23#include <ConfigurationManagerObject.h>\r
24#include <ConfigurationManagerHelper.h>\r
25#include <Library/TableHelperLib.h>\r
26#include <Protocol/ConfigurationManagerProtocol.h>\r
27\r
28#include "PpttGenerator.h"\r
29\r
30/**\r
31 ARM standard PPTT Generator\r
32\r
33 Requirements:\r
34 The following Configuration Manager Object(s) are used by this Generator:\r
35 - EArmObjProcHierarchyInfo (REQUIRED)\r
36 - EArmObjCacheInfo\r
37 - EArmObjProcNodeIdInfo\r
38 - EArmObjCmRef\r
39 - EArmObjGicCInfo (REQUIRED)\r
40*/\r
41\r
42/**\r
43 This macro expands to a function that retrieves the Processor Hierarchy\r
44 information from the Configuration Manager.\r
45*/\r
46GET_OBJECT_LIST (\r
47 EObjNameSpaceArm,\r
48 EArmObjProcHierarchyInfo,\r
49 CM_ARM_PROC_HIERARCHY_INFO\r
50 );\r
51\r
52/**\r
53 This macro expands to a function that retrieves the cache information\r
54 from the Configuration Manager.\r
55*/\r
56GET_OBJECT_LIST (\r
57 EObjNameSpaceArm,\r
58 EArmObjCacheInfo,\r
59 CM_ARM_CACHE_INFO\r
60 );\r
61\r
62/**\r
63 This macro expands to a function that retrieves the ID information for\r
64 Processor Hierarchy Nodes from the Configuration Manager.\r
65*/\r
66GET_OBJECT_LIST (\r
67 EObjNameSpaceArm,\r
68 EArmObjProcNodeIdInfo,\r
69 CM_ARM_PROC_NODE_ID_INFO\r
70 );\r
71\r
72/**\r
73 This macro expands to a function that retrieves the cross-CM-object-\r
74 reference information from the Configuration Manager.\r
75*/\r
76GET_OBJECT_LIST (\r
77 EObjNameSpaceArm,\r
78 EArmObjCmRef,\r
79 CM_ARM_OBJ_REF\r
80 );\r
81\r
82/**\r
83 This macro expands to a function that retrieves the GIC CPU interface\r
84 information from the Configuration Manager.\r
85*/\r
86GET_OBJECT_LIST (\r
87 EObjNameSpaceArm,\r
88 EArmObjGicCInfo,\r
89 CM_ARM_GICC_INFO\r
90 );\r
91\r
92/**\r
93 Returns the size of the PPTT Processor Hierarchy Node (Type 0) given a\r
94 Processor Hierarchy Info CM object.\r
95\r
96 @param [in] Node Pointer to Processor Hierarchy Info CM object which\r
97 represents the Processor Hierarchy Node to be generated.\r
98\r
99 @retval Size of the Processor Hierarchy Node in bytes.\r
100**/\r
101STATIC\r
102UINT32\r
103GetProcHierarchyNodeSize (\r
731c67e1 104 IN CONST CM_ARM_PROC_HIERARCHY_INFO *Node\r
77db1156
KK
105 )\r
106{\r
107 ASSERT (Node != NULL);\r
108\r
109 // <size of Processor Hierarchy Node> + <size of Private Resources array>\r
110 return sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR) +\r
731c67e1 111 (Node->NoOfPrivateResources * sizeof (UINT32));\r
77db1156
KK
112}\r
113\r
114/**\r
115 This macro expands to a function that retrieves the amount of memory required\r
116 to store the Processor Hierarchy Nodes (Type 0) and updates the Node Indexer.\r
117*/\r
118GET_SIZE_OF_PPTT_STRUCTS (\r
119 ProcHierarchyNodes,\r
120 GetProcHierarchyNodeSize (NodesToIndex),\r
121 CM_ARM_PROC_HIERARCHY_INFO\r
122 );\r
123\r
124/**\r
125 This macro expands to a function that retrieves the amount of memory required\r
126 to store the Cache Type Structures (Type 1) and updates the Node Indexer.\r
127*/\r
128GET_SIZE_OF_PPTT_STRUCTS (\r
129 CacheTypeStructs,\r
130 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE),\r
131 CM_ARM_CACHE_INFO\r
132 );\r
133\r
134/** This macro expands to a function that retrieves the amount of memory\r
135 required to store the ID Structures (Type 2) and updates the Node Indexer.\r
136*/\r
137GET_SIZE_OF_PPTT_STRUCTS (\r
138 IdStructs,\r
139 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID),\r
140 CM_ARM_PROC_NODE_ID_INFO\r
141 );\r
142\r
143/**\r
144 Search the Node Indexer and return the indexed PPTT node with the given\r
145 Token.\r
146\r
147 @param [in] NodeIndexer Pointer to the Node Indexer array.\r
148 @param [in] NodeCount Number of elements in Node Indexer.\r
149 @param [in] SearchToken Token used for Node Indexer lookup.\r
150 @param [out] IndexedNodeFound Pointer to the Node Indexer array element\r
151 with the given Token.\r
152\r
153 @retval EFI_SUCCESS Success.\r
154 @retval EFI_NOT_FOUND No element with a matching token was\r
155 found in the Node Indexer array.\r
156**/\r
157STATIC\r
158EFI_STATUS\r
159GetPpttNodeReferencedByToken (\r
731c67e1
MK
160 IN PPTT_NODE_INDEXER *NodeIndexer,\r
161 IN UINT32 NodeCount,\r
162 IN CONST CM_OBJECT_TOKEN SearchToken,\r
163 OUT PPTT_NODE_INDEXER **IndexedNodeFound\r
77db1156
KK
164 )\r
165{\r
166 EFI_STATUS Status;\r
167\r
168 ASSERT (NodeIndexer != NULL);\r
169\r
170 DEBUG ((\r
171 DEBUG_INFO,\r
172 "PPTT: Node Indexer: SearchToken = %p\n",\r
173 SearchToken\r
174 ));\r
175\r
176 while (NodeCount-- != 0) {\r
177 DEBUG ((\r
178 DEBUG_INFO,\r
179 "PPTT: Node Indexer: NodeIndexer->Token = %p. Offset = %d\n",\r
180 NodeIndexer->Token,\r
181 NodeIndexer->Offset\r
182 ));\r
183\r
184 if (NodeIndexer->Token == SearchToken) {\r
185 *IndexedNodeFound = NodeIndexer;\r
731c67e1 186 Status = EFI_SUCCESS;\r
77db1156
KK
187 DEBUG ((\r
188 DEBUG_INFO,\r
189 "PPTT: Node Indexer: Token = %p. Found, Status = %r\n",\r
190 SearchToken,\r
191 Status\r
192 ));\r
193 return Status;\r
194 }\r
731c67e1 195\r
77db1156
KK
196 NodeIndexer++;\r
197 }\r
198\r
199 Status = EFI_NOT_FOUND;\r
200 DEBUG ((\r
201 DEBUG_ERROR,\r
202 "PPTT: Node Indexer: SearchToken = %p. Status = %r\n",\r
203 SearchToken,\r
204 Status\r
205 ));\r
206\r
207 return Status;\r
208}\r
209\r
210/**\r
211 Detect cycles in the processor and cache topology graph represented in\r
212 the PPTT table.\r
213\r
214 @param [in] Generator Pointer to the PPTT Generator.\r
215\r
216 @retval EFI_SUCCESS There are no cyclic references in the graph.\r
217 @retval EFI_INVALID_PARAMETER Processor or cache references form a cycle.\r
218**/\r
219STATIC\r
220EFI_STATUS\r
221DetectCyclesInTopology (\r
731c67e1 222 IN CONST ACPI_PPTT_GENERATOR *CONST Generator\r
77db1156
KK
223 )\r
224{\r
731c67e1
MK
225 EFI_STATUS Status;\r
226 PPTT_NODE_INDEXER *Iterator;\r
227 PPTT_NODE_INDEXER *CycleDetector;\r
228 UINT32 NodesRemaining;\r
77db1156
KK
229\r
230 ASSERT (Generator != NULL);\r
231\r
731c67e1 232 Iterator = Generator->NodeIndexer;\r
77db1156
KK
233 NodesRemaining = Generator->ProcTopologyStructCount;\r
234\r
235 while (NodesRemaining != 0) {\r
236 DEBUG ((\r
237 DEBUG_INFO,\r
238 "INFO: PPTT: Cycle detection for element with index %d\n",\r
239 Generator->ProcTopologyStructCount - NodesRemaining\r
240 ));\r
241\r
242 CycleDetector = Iterator;\r
243\r
244 // Walk the topology tree\r
245 while (CycleDetector->TopologyParent != NULL) {\r
246 DEBUG ((\r
247 DEBUG_INFO,\r
248 "INFO: PPTT: %p -> %p\n",\r
249 CycleDetector->Token,\r
250 CycleDetector->TopologyParent->Token\r
251 ));\r
252\r
253 // Check if we have already visited this node\r
254 if (CycleDetector->CycleDetectionStamp == NodesRemaining) {\r
255 Status = EFI_INVALID_PARAMETER;\r
256 DEBUG ((\r
257 DEBUG_ERROR,\r
258 "ERROR: PPTT: Cycle in processor and cache topology detected for " \\r
259 "a chain of references originating from a node with: Token = %p " \\r
260 "Status = %r\n",\r
261 Iterator->Token,\r
262 Status\r
263 ));\r
264 return Status;\r
265 }\r
266\r
267 // Stamp the visited node\r
268 CycleDetector->CycleDetectionStamp = NodesRemaining;\r
731c67e1 269 CycleDetector = CycleDetector->TopologyParent;\r
77db1156
KK
270 } // Continue topology tree walk\r
271\r
272 Iterator++;\r
273 NodesRemaining--;\r
274 } // Next Node Indexer\r
275\r
276 return EFI_SUCCESS;\r
277}\r
278\r
279/**\r
280 Update the array of private resources for a given Processor Hierarchy Node.\r
281\r
282 @param [in] Generator Pointer to the PPTT Generator.\r
283 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
284 Protocol Interface.\r
285 @param [in] PrivResArray Pointer to the array of private resources.\r
286 @param [in] PrivResCount Number of private resources.\r
287 @param [in] PrivResArrayToken Reference Token for the CM_ARM_OBJ_REF\r
288 array describing node's private resources.\r
289\r
290 @retval EFI_SUCCESS Array updated successfully.\r
291 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
292 @retval EFI_NOT_FOUND A private resource was not found.\r
293**/\r
294STATIC\r
295EFI_STATUS\r
296AddPrivateResources (\r
731c67e1
MK
297 IN CONST ACPI_PPTT_GENERATOR *CONST Generator,\r
298 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
299 IN UINT32 *PrivResArray,\r
77db1156
KK
300 IN UINT32 PrivResCount,\r
301 IN CONST CM_OBJECT_TOKEN PrivResArrayToken\r
302 )\r
303{\r
731c67e1
MK
304 EFI_STATUS Status;\r
305 CM_ARM_OBJ_REF *CmObjRefs;\r
306 UINT32 CmObjRefCount;\r
307 PPTT_NODE_INDEXER *PpttNodeFound;\r
77db1156
KK
308\r
309 ASSERT (\r
310 (Generator != NULL) &&\r
311 (CfgMgrProtocol != NULL) &&\r
312 (PrivResArray != NULL) &&\r
313 (PrivResCount != 0)\r
314 );\r
315\r
316 // Validate input arguments\r
317 if (PrivResArrayToken == CM_NULL_TOKEN) {\r
318 Status = EFI_INVALID_PARAMETER;\r
319 DEBUG ((\r
320 DEBUG_ERROR,\r
321 "ERROR: PPTT: The number of private resources is %d while " \\r
322 "PrivResToken = CM_NULL_TOKEN. Status = %r\n",\r
323 PrivResCount,\r
324 Status\r
325 ));\r
326 return Status;\r
327 }\r
328\r
329 CmObjRefCount = 0;\r
330 // Get the CM Object References\r
331 Status = GetEArmObjCmRef (\r
332 CfgMgrProtocol,\r
333 PrivResArrayToken,\r
334 &CmObjRefs,\r
335 &CmObjRefCount\r
336 );\r
337 if (EFI_ERROR (Status)) {\r
338 DEBUG ((\r
339 DEBUG_ERROR,\r
340 "ERROR: PPTT: Failed to get CM Object References. " \\r
341 "PrivResToken = %p. Status = %r\n",\r
342 PrivResArrayToken,\r
343 Status\r
344 ));\r
345 return Status;\r
346 }\r
347\r
348 if (CmObjRefCount != PrivResCount) {\r
349 Status = EFI_INVALID_PARAMETER;\r
350 DEBUG ((\r
351 DEBUG_ERROR,\r
352 "ERROR: PPTT: The number of CM Object References retrieved and the " \\r
353 "number of private resources don't match. CmObjRefCount = %d. " \\r
354 "PrivResourceCount = %d. PrivResToken = %p. Status = %r\n",\r
355 CmObjRefCount,\r
356 PrivResCount,\r
357 PrivResArrayToken,\r
358 Status\r
359 ));\r
360 return Status;\r
361 }\r
362\r
363 while (PrivResCount-- != 0) {\r
364 if (CmObjRefs->ReferenceToken == CM_NULL_TOKEN) {\r
365 Status = EFI_INVALID_PARAMETER;\r
366 DEBUG ((\r
367 DEBUG_ERROR,\r
368 "ERROR: PPTT: CM_NULL_TOKEN provided as reference token for a " \\r
369 "private resource. Status = %r\n",\r
370 Status\r
371 ));\r
372 return Status;\r
373 }\r
374\r
375 // The Node indexer has the Processor hierarchy nodes at the begining\r
376 // followed by the cache structs and Id structs. Therefore we can\r
377 // skip the Processor hierarchy nodes in the node indexer search.\r
378 Status = GetPpttNodeReferencedByToken (\r
379 Generator->CacheStructIndexedList,\r
380 (Generator->ProcTopologyStructCount -\r
381 Generator->ProcHierarchyNodeCount),\r
382 CmObjRefs->ReferenceToken,\r
383 &PpttNodeFound\r
384 );\r
385 if (EFI_ERROR (Status)) {\r
386 DEBUG ((\r
387 DEBUG_ERROR,\r
388 "ERROR: PPTT: Failed to get a private resource with Token = %p from " \\r
389 "Node Indexer. Status = %r\n",\r
390 CmObjRefs->ReferenceToken,\r
391 Status\r
392 ));\r
393 return Status;\r
394 }\r
395\r
396 // Update the offset of the private resources in the Processor\r
397 // Hierarchy Node structure\r
398 *(PrivResArray++) = PpttNodeFound->Offset;\r
399 CmObjRefs++;\r
400 }\r
401\r
402 return EFI_SUCCESS;\r
403}\r
404\r
405/**\r
406 Function to test if two indexed Processor Hierarchy Info objects map to the\r
407 same GIC CPU Interface Info object.\r
408\r
409 This is a callback function that can be invoked by FindDuplicateValue ().\r
410\r
411 @param [in] Object1 Pointer to the first indexed Processor Hierarchy\r
412 Info object.\r
413 @param [in] Object2 Pointer to the second indexed Processor Hierarchy\r
414 Info object.\r
415 @param [in] Index1 Index of Object1 to be displayed for debugging\r
416 purposes.\r
417 @param [in] Index2 Index of Object2 to be displayed for debugging\r
418 purposes.\r
419\r
420 @retval TRUE Object1 and Object2 have the same GicCToken.\r
421 @retval FALSE Object1 and Object2 have different GicCTokens.\r
422**/\r
423BOOLEAN\r
424EFIAPI\r
425IsGicCTokenEqual (\r
731c67e1
MK
426 IN CONST VOID *Object1,\r
427 IN CONST VOID *Object2,\r
428 IN UINTN Index1,\r
429 IN UINTN Index2\r
77db1156
KK
430 )\r
431{\r
731c67e1
MK
432 PPTT_NODE_INDEXER *IndexedObject1;\r
433 PPTT_NODE_INDEXER *IndexedObject2;\r
434 CM_ARM_PROC_HIERARCHY_INFO *ProcNode1;\r
435 CM_ARM_PROC_HIERARCHY_INFO *ProcNode2;\r
77db1156
KK
436\r
437 ASSERT (\r
438 (Object1 != NULL) &&\r
439 (Object2 != NULL)\r
440 );\r
441\r
731c67e1
MK
442 IndexedObject1 = (PPTT_NODE_INDEXER *)Object1;\r
443 IndexedObject2 = (PPTT_NODE_INDEXER *)Object2;\r
444 ProcNode1 = (CM_ARM_PROC_HIERARCHY_INFO *)IndexedObject1->Object;\r
445 ProcNode2 = (CM_ARM_PROC_HIERARCHY_INFO *)IndexedObject2->Object;\r
77db1156
KK
446\r
447 if (IS_ACPI_PROC_ID_VALID (ProcNode1) &&\r
448 IS_ACPI_PROC_ID_VALID (ProcNode2) &&\r
449 (ProcNode1->GicCToken != CM_NULL_TOKEN) &&\r
450 (ProcNode2->GicCToken != CM_NULL_TOKEN) &&\r
731c67e1
MK
451 (ProcNode1->GicCToken == ProcNode2->GicCToken))\r
452 {\r
77db1156
KK
453 DEBUG ((\r
454 DEBUG_ERROR,\r
455 "ERROR: PPTT: Two Processor Hierarchy Info objects (%d and %d) map to " \\r
456 "the same GICC Info object. ACPI Processor IDs are not unique. " \\r
457 "GicCToken = %p.\n",\r
458 Index1,\r
459 IndexedObject1->Token,\r
460 Index2,\r
461 ProcNode1->GicCToken\r
462 ));\r
463 return TRUE;\r
464 }\r
465\r
466 return FALSE;\r
467}\r
468\r
469/**\r
470 Update the Processor Hierarchy Node (Type 0) information.\r
471\r
472 This function populates the Processor Hierarchy Nodes with information from\r
473 the Configuration Manager and adds this information to the PPTT table.\r
474\r
475 @param [in] Generator Pointer to the PPTT Generator.\r
476 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
477 Protocol Interface.\r
478 @param [in] Pptt Pointer to PPTT table structure.\r
479 @param [in] NodesStartOffset Offset from the start of PPTT table to the\r
480 start of Processor Hierarchy Nodes.\r
481\r
482 @retval EFI_SUCCESS Node updated successfully.\r
483 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
484 @retval EFI_NOT_FOUND The required object was not found.\r
485**/\r
486STATIC\r
487EFI_STATUS\r
488AddProcHierarchyNodes (\r
731c67e1
MK
489 IN CONST ACPI_PPTT_GENERATOR *CONST Generator,\r
490 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
491 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER *Pptt,\r
492 IN CONST UINT32 NodesStartOffset\r
77db1156
KK
493 )\r
494{\r
731c67e1
MK
495 EFI_STATUS Status;\r
496 EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR *ProcStruct;\r
497 UINT32 *PrivateResources;\r
498 BOOLEAN IsGicCTokenDuplicated;\r
77db1156 499\r
731c67e1
MK
500 CM_ARM_GICC_INFO *GicCInfoList;\r
501 UINT32 GicCInfoCount;\r
502 UINT32 UniqueGicCRefCount;\r
77db1156 503\r
731c67e1
MK
504 PPTT_NODE_INDEXER *PpttNodeFound;\r
505 CM_ARM_PROC_HIERARCHY_INFO *ProcInfoNode;\r
77db1156 506\r
731c67e1
MK
507 PPTT_NODE_INDEXER *ProcNodeIterator;\r
508 UINT32 NodeCount;\r
509 UINT32 Length;\r
77db1156
KK
510\r
511 ASSERT (\r
512 (Generator != NULL) &&\r
513 (CfgMgrProtocol != NULL) &&\r
514 (Pptt != NULL)\r
515 );\r
516\r
731c67e1
MK
517 ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR *)((UINT8 *)Pptt +\r
518 NodesStartOffset);\r
77db1156
KK
519\r
520 ProcNodeIterator = Generator->ProcHierarchyNodeIndexedList;\r
731c67e1 521 NodeCount = Generator->ProcHierarchyNodeCount;\r
77db1156
KK
522\r
523 // Check if every GICC Object is referenced by onlu one Proc Node\r
524 IsGicCTokenDuplicated = FindDuplicateValue (\r
525 ProcNodeIterator,\r
526 NodeCount,\r
527 sizeof (PPTT_NODE_INDEXER),\r
528 IsGicCTokenEqual\r
529 );\r
530 // Duplicate GIC CPU Interface Token was found so two PPTT Processor Hierarchy\r
531 // Nodes map to the same MADT GICC structure\r
532 if (IsGicCTokenDuplicated) {\r
533 return EFI_INVALID_PARAMETER;\r
534 }\r
535\r
536 UniqueGicCRefCount = 0;\r
537\r
538 while (NodeCount-- != 0) {\r
731c67e1 539 ProcInfoNode = (CM_ARM_PROC_HIERARCHY_INFO *)ProcNodeIterator->Object;\r
77db1156
KK
540\r
541 // Check if the private resource count is within the size limit\r
542 // imposed on the Processor Hierarchy node by the specification.\r
543 // Note: The length field is 8 bit wide while the number of private\r
544 // resource field is 32 bit wide.\r
96bb6704
SM
545 Length = GetProcHierarchyNodeSize (ProcInfoNode);\r
546 if (Length > MAX_UINT8) {\r
77db1156
KK
547 Status = EFI_INVALID_PARAMETER;\r
548 DEBUG ((\r
549 DEBUG_ERROR,\r
550 "ERROR: PPTT: Too many private resources. Count = %d. " \\r
551 "Maximum supported Processor Node size exceeded. " \\r
552 "Token = %p. Status = %r\n",\r
553 ProcInfoNode->NoOfPrivateResources,\r
554 ProcInfoNode->ParentToken,\r
555 Status\r
556 ));\r
557 return Status;\r
558 }\r
559\r
560 // Populate the node header\r
731c67e1
MK
561 ProcStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_PROCESSOR;\r
562 ProcStruct->Length = (UINT8)Length;\r
77db1156
KK
563 ProcStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
564 ProcStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
565\r
566 // Populate the flags\r
731c67e1
MK
567 ProcStruct->Flags.PhysicalPackage = ProcInfoNode->Flags & BIT0;\r
568 ProcStruct->Flags.AcpiProcessorIdValid = (ProcInfoNode->Flags & BIT1) >> 1;\r
569 ProcStruct->Flags.ProcessorIsAThread = (ProcInfoNode->Flags & BIT2) >> 2;\r
570 ProcStruct->Flags.NodeIsALeaf = (ProcInfoNode->Flags & BIT3) >> 3;\r
77db1156
KK
571 ProcStruct->Flags.IdenticalImplementation =\r
572 (ProcInfoNode->Flags & BIT4) >> 4;\r
573 ProcStruct->Flags.Reserved = 0;\r
574\r
575 // Populate the parent reference\r
576 if (ProcInfoNode->ParentToken == CM_NULL_TOKEN) {\r
577 ProcStruct->Parent = 0;\r
578 } else {\r
579 Status = GetPpttNodeReferencedByToken (\r
580 Generator->ProcHierarchyNodeIndexedList,\r
581 Generator->ProcHierarchyNodeCount,\r
582 ProcInfoNode->ParentToken,\r
583 &PpttNodeFound\r
584 );\r
585 if (EFI_ERROR (Status)) {\r
586 DEBUG ((\r
587 DEBUG_ERROR,\r
588 "ERROR: PPTT: Failed to get parent processor hierarchy node " \\r
589 "reference. Token = %p, Status = %r\n",\r
590 ProcInfoNode->ParentToken,\r
591 ProcInfoNode->Token,\r
592 Status\r
593 ));\r
594 return Status;\r
595 }\r
596\r
597 // Test if the reference is to a 'leaf' node\r
598 if (IS_PROC_NODE_LEAF (\r
731c67e1
MK
599 ((CM_ARM_PROC_HIERARCHY_INFO *)PpttNodeFound->Object)\r
600 ))\r
601 {\r
77db1156
KK
602 Status = EFI_INVALID_PARAMETER;\r
603 DEBUG ((\r
604 DEBUG_ERROR,\r
605 "ERROR: PPTT: Reference to a leaf Processor Hierarchy Node. " \\r
606 "ParentToken = %p. ChildToken = %p. Status = %r\n",\r
607 ProcInfoNode->ParentToken,\r
608 ProcInfoNode->Token,\r
609 Status\r
610 ));\r
611 return Status;\r
612 }\r
613\r
614 // Update Proc Structure with the offset of the parent node\r
615 ProcStruct->Parent = PpttNodeFound->Offset;\r
616\r
617 // Store the reference for the parent node in the Node Indexer\r
618 // so that this can be used later for cycle detection\r
619 ProcNodeIterator->TopologyParent = PpttNodeFound;\r
620 }\r
621\r
622 // Populate ACPI Processor ID\r
623 if (!IS_ACPI_PROC_ID_VALID (ProcInfoNode)) {\r
624 // Default invalid ACPI Processor ID to 0\r
625 ProcStruct->AcpiProcessorId = 0;\r
626 } else if (ProcInfoNode->GicCToken == CM_NULL_TOKEN) {\r
627 Status = EFI_INVALID_PARAMETER;\r
628 DEBUG ((\r
629 DEBUG_ERROR,\r
630 "ERROR: PPTT: The 'ACPI Processor ID valid' flag is set but no GICC " \\r
631 "structure token was provided. GicCToken = %p. RequestorToken = %p. " \\r
632 "Status = %r\n",\r
633 ProcInfoNode->GicCToken,\r
634 ProcInfoNode->Token,\r
635 Status\r
636 ));\r
637 return Status;\r
638 } else {\r
639 Status = GetEArmObjGicCInfo (\r
640 CfgMgrProtocol,\r
641 ProcInfoNode->GicCToken,\r
642 &GicCInfoList,\r
643 &GicCInfoCount\r
644 );\r
645 if (EFI_ERROR (Status)) {\r
646 DEBUG ((\r
647 DEBUG_ERROR,\r
648 "ERROR: PPTT: Failed to get GICC structure. ACPI Processor ID " \\r
649 "can't be populated. GicCToken = %p. RequestorToken = %p. " \\r
650 "Status = %r\n",\r
651 ProcInfoNode->GicCToken,\r
652 ProcInfoNode->Token,\r
653 Status\r
654 ));\r
655 return Status;\r
656 }\r
657\r
658 if (GicCInfoCount != 1) {\r
659 Status = EFI_INVALID_PARAMETER;\r
660 DEBUG ((\r
661 DEBUG_ERROR,\r
662 "ERROR: PPTT: Failed to find a unique GICC structure. " \\r
663 "ACPI Processor ID can't be populated. " \\r
664 "GICC Structure Count = %d. GicCToken = %p. RequestorToken = %p " \\r
665 "Status = %r\n",\r
666 GicCInfoCount,\r
667 ProcInfoNode->GicCToken,\r
668 ProcInfoNode->Token,\r
669 Status\r
670 ));\r
671 return Status;\r
672 }\r
673\r
674 // Update the ACPI Processor Id\r
675 ProcStruct->AcpiProcessorId = GicCInfoList->AcpiProcessorUid;\r
676\r
677 // Increment the reference count for the number of\r
678 // Unique GICC objects that were retrieved.\r
679 UniqueGicCRefCount++;\r
680 }\r
681\r
682 ProcStruct->NumberOfPrivateResources = ProcInfoNode->NoOfPrivateResources;\r
731c67e1
MK
683 PrivateResources = (UINT32 *)((UINT8 *)ProcStruct +\r
684 sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR));\r
77db1156
KK
685\r
686 if (ProcStruct->NumberOfPrivateResources != 0) {\r
687 // Populate the private resources array\r
688 Status = AddPrivateResources (\r
731c67e1
MK
689 Generator,\r
690 CfgMgrProtocol,\r
691 PrivateResources,\r
692 ProcStruct->NumberOfPrivateResources,\r
693 ProcInfoNode->PrivateResourcesArrayToken\r
694 );\r
77db1156
KK
695 if (EFI_ERROR (Status)) {\r
696 DEBUG ((\r
697 DEBUG_ERROR,\r
698 "ERROR: PPTT: Failed to populate the private resources array. " \\r
699 "Status = %r\n",\r
700 Status\r
701 ));\r
702 return Status;\r
703 }\r
704 }\r
705\r
706 // Next Processor Hierarchy Node\r
731c67e1
MK
707 ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR *)((UINT8 *)ProcStruct +\r
708 ProcStruct->Length);\r
77db1156
KK
709 ProcNodeIterator++;\r
710 } // Processor Hierarchy Node\r
711\r
712 // Knowing the total number of GICC references made and that all GICC Token\r
713 // references are unique, we can test if no GICC instances have been left out.\r
714 Status = GetEArmObjGicCInfo (\r
715 CfgMgrProtocol,\r
716 CM_NULL_TOKEN,\r
717 &GicCInfoList,\r
718 &GicCInfoCount\r
719 );\r
720 if (EFI_ERROR (Status)) {\r
721 DEBUG ((\r
722 DEBUG_ERROR,\r
723 "ERROR: PPTT: Failed to get GICC Info. Status = %r\n",\r
724 Status\r
725 ));\r
726 return Status;\r
727 }\r
728\r
729 // MADT - PPTT cross validation\r
730 // This checks that one and only one GICC structure is referenced by a\r
731 // Processor Hierarchy Node in the PPTT.\r
732 // Since we have already checked that the GICC objects referenced by the\r
733 // Proc Nodes are unique, the UniqueGicCRefCount cannot be greater than\r
734 // the total number of GICC objects in the platform.\r
735 if (GicCInfoCount > UniqueGicCRefCount) {\r
736 Status = EFI_INVALID_PARAMETER;\r
737 DEBUG ((\r
738 DEBUG_ERROR,\r
739 "ERROR: PPTT: %d GICC structure(s) exposed by MADT don't have " \\r
740 "a corresponding Processor Hierarchy Node. Status = %r\n",\r
741 GicCInfoCount - UniqueGicCRefCount,\r
742 Status\r
743 ));\r
744 }\r
745\r
746 return Status;\r
747}\r
748\r
749/**\r
750 Update the Cache Type Structure (Type 1) information.\r
751\r
752 This function populates the Cache Type Structures with information from\r
753 the Configuration Manager and adds this information to the PPTT table.\r
754\r
755 @param [in] Generator Pointer to the PPTT Generator.\r
756 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
757 Protocol Interface.\r
758 @param [in] Pptt Pointer to PPTT table structure.\r
759 @param [in] NodesStartOffset Offset from the start of PPTT table to the\r
760 start of Cache Type Structures.\r
761\r
762 @retval EFI_SUCCESS Structures updated successfully.\r
763 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
764 @retval EFI_NOT_FOUND A required object was not found.\r
765**/\r
766STATIC\r
767EFI_STATUS\r
768AddCacheTypeStructures (\r
731c67e1
MK
769 IN CONST ACPI_PPTT_GENERATOR *CONST Generator,\r
770 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
771 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER *Pptt,\r
772 IN CONST UINT32 NodesStartOffset\r
77db1156
KK
773 )\r
774{\r
731c67e1
MK
775 EFI_STATUS Status;\r
776 EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE *CacheStruct;\r
777 PPTT_NODE_INDEXER *PpttNodeFound;\r
778 CM_ARM_CACHE_INFO *CacheInfoNode;\r
779 PPTT_NODE_INDEXER *CacheNodeIterator;\r
780 UINT32 NodeCount;\r
77db1156
KK
781\r
782 ASSERT (\r
783 (Generator != NULL) &&\r
784 (CfgMgrProtocol != NULL) &&\r
785 (Pptt != NULL)\r
786 );\r
787\r
731c67e1
MK
788 CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE *)((UINT8 *)Pptt +\r
789 NodesStartOffset);\r
77db1156
KK
790\r
791 CacheNodeIterator = Generator->CacheStructIndexedList;\r
731c67e1 792 NodeCount = Generator->CacheStructCount;\r
77db1156
KK
793\r
794 while (NodeCount-- != 0) {\r
731c67e1 795 CacheInfoNode = (CM_ARM_CACHE_INFO *)CacheNodeIterator->Object;\r
77db1156
KK
796\r
797 // Populate the node header\r
731c67e1
MK
798 CacheStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_CACHE;\r
799 CacheStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE);\r
77db1156
KK
800 CacheStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
801 CacheStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
802\r
803 // "On Arm-based systems, all cache properties must be provided in the\r
804 // table." (ACPI 6.3, Section 5.2.29.2)\r
731c67e1
MK
805 CacheStruct->Flags.SizePropertyValid = 1;\r
806 CacheStruct->Flags.NumberOfSetsValid = 1;\r
807 CacheStruct->Flags.AssociativityValid = 1;\r
77db1156 808 CacheStruct->Flags.AllocationTypeValid = 1;\r
731c67e1
MK
809 CacheStruct->Flags.CacheTypeValid = 1;\r
810 CacheStruct->Flags.WritePolicyValid = 1;\r
811 CacheStruct->Flags.LineSizeValid = 1;\r
812 CacheStruct->Flags.Reserved = 0;\r
77db1156
KK
813\r
814 // Populate the reference to the next level of cache\r
815 if (CacheInfoNode->NextLevelOfCacheToken == CM_NULL_TOKEN) {\r
816 CacheStruct->NextLevelOfCache = 0;\r
817 } else {\r
818 Status = GetPpttNodeReferencedByToken (\r
819 Generator->CacheStructIndexedList,\r
820 Generator->CacheStructCount,\r
821 CacheInfoNode->NextLevelOfCacheToken,\r
822 &PpttNodeFound\r
823 );\r
824 if (EFI_ERROR (Status)) {\r
825 DEBUG ((\r
826 DEBUG_ERROR,\r
827 "ERROR: PPTT: Failed to get the reference to the Next Level of " \\r
828 "Cache. NextLevelOfCacheToken = %p. RequestorToken = %p. " \\r
829 "Status = %r\n",\r
830 CacheInfoNode->NextLevelOfCacheToken,\r
831 CacheInfoNode->Token,\r
832 Status\r
833 ));\r
834 return Status;\r
835 }\r
836\r
837 // Update Cache Structure with the offset for the next level of cache\r
838 CacheStruct->NextLevelOfCache = PpttNodeFound->Offset;\r
839\r
840 // Store the next level of cache information in the Node Indexer\r
841 // so that this can be used later for cycle detection\r
842 CacheNodeIterator->TopologyParent = PpttNodeFound;\r
843 }\r
844\r
845 CacheStruct->Size = CacheInfoNode->Size;\r
846\r
847 // Validate and populate the 'Number of sets' field\r
848 if (CacheInfoNode->NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) {\r
849 Status = EFI_INVALID_PARAMETER;\r
850 DEBUG ((\r
851 DEBUG_ERROR,\r
852 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum number " \\r
853 "of sets can be %d. NumberOfSets = %d. Status = %r\n",\r
854 PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX,\r
855 CacheInfoNode->NumberOfSets,\r
856 Status\r
857 ));\r
858 return Status;\r
859 }\r
860\r
861 if (CacheInfoNode->NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) {\r
862 DEBUG ((\r
863 DEBUG_INFO,\r
864 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \\r
865 "number of sets can be %d. NumberOfSets = %d\n",\r
866 PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX,\r
867 CacheInfoNode->NumberOfSets\r
868 ));\r
869 }\r
870\r
871 CacheStruct->NumberOfSets = CacheInfoNode->NumberOfSets;\r
872\r
873 // Validate Associativity field based on maximum associativity\r
874 // supported by ACPI Cache type structure.\r
875 if (CacheInfoNode->Associativity > MAX_UINT8) {\r
876 Status = EFI_INVALID_PARAMETER;\r
877 DEBUG ((\r
878 DEBUG_ERROR,\r
879 "ERROR: PPTT: The maximum associativity supported by ACPI " \\r
880 "Cache type structure is %d. Associativity = %d, Status = %r\n",\r
881 MAX_UINT8,\r
882 CacheInfoNode->Associativity,\r
883 Status\r
884 ));\r
885 return Status;\r
886 }\r
887\r
888 // Validate the Associativity field based on the architecture specification\r
889 // The architecture supports much larger associativity values than the\r
890 // current ACPI specification.\r
891 // These checks will be needed in the future when the ACPI specification\r
892 // is extended. Disabling this code for now.\r
731c67e1 893 #if 0\r
77db1156
KK
894 if (CacheInfoNode->Associativity > PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX) {\r
895 Status = EFI_INVALID_PARAMETER;\r
896 DEBUG ((\r
897 DEBUG_ERROR,\r
898 "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum cache " \\r
899 "associativity can be %d. Associativity = %d. Status = %r\n",\r
900 PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX,\r
901 CacheInfoNode->Associativity,\r
902 Status\r
903 ));\r
904 return Status;\r
905 }\r
906\r
907 if (CacheInfoNode->Associativity > PPTT_ARM_CACHE_ASSOCIATIVITY_MAX) {\r
908 DEBUG ((\r
909 DEBUG_INFO,\r
910 "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \\r
911 "cache associativity can be %d. Associativity = %d\n",\r
912 PPTT_ARM_CACHE_ASSOCIATIVITY_MAX,\r
913 CacheInfoNode->Associativity\r
914 ));\r
915 }\r
731c67e1
MK
916\r
917 #endif\r
77db1156
KK
918\r
919 // Note a typecast is needed as the maximum associativity\r
920 // supported by ACPI Cache type structure is MAX_UINT8.\r
921 CacheStruct->Associativity = (UINT8)CacheInfoNode->Associativity;\r
922\r
923 // Populate cache attributes\r
924 CacheStruct->Attributes.AllocationType =\r
925 CacheInfoNode->Attributes & (BIT0 | BIT1);\r
926 CacheStruct->Attributes.CacheType =\r
927 (CacheInfoNode->Attributes & (BIT2 | BIT3)) >> 2;\r
928 CacheStruct->Attributes.WritePolicy =\r
929 (CacheInfoNode->Attributes & BIT4) >> 4;\r
930 CacheStruct->Attributes.Reserved = 0;\r
931\r
932 // Validate and populate cache line size\r
933 if ((CacheInfoNode->LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) ||\r
731c67e1
MK
934 (CacheInfoNode->LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX))\r
935 {\r
77db1156
KK
936 Status = EFI_INVALID_PARAMETER;\r
937 DEBUG ((\r
938 DEBUG_ERROR,\r
939 "ERROR: PPTT: The cache line size must be between %d and %d bytes " \\r
731c67e1 940 "on ARM Platforms. LineSize = %d. Status = %r\n",\r
77db1156
KK
941 PPTT_ARM_CACHE_LINE_SIZE_MIN,\r
942 PPTT_ARM_CACHE_LINE_SIZE_MAX,\r
943 CacheInfoNode->LineSize,\r
944 Status\r
945 ));\r
946 return Status;\r
947 }\r
948\r
949 if ((CacheInfoNode->LineSize & (CacheInfoNode->LineSize - 1)) != 0) {\r
950 Status = EFI_INVALID_PARAMETER;\r
951 DEBUG ((\r
952 DEBUG_ERROR,\r
953 "ERROR: PPTT: The cache line size is not a power of 2. " \\r
731c67e1 954 "LineSize = %d. Status = %r\n",\r
77db1156
KK
955 CacheInfoNode->LineSize,\r
956 Status\r
957 ));\r
958 return Status;\r
959 }\r
960\r
961 CacheStruct->LineSize = CacheInfoNode->LineSize;\r
962\r
963 // Next Cache Type Structure\r
731c67e1
MK
964 CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE *)((UINT8 *)CacheStruct +\r
965 CacheStruct->Length);\r
77db1156
KK
966 CacheNodeIterator++;\r
967 } // Cache Type Structure\r
968\r
969 return EFI_SUCCESS;\r
970}\r
971\r
972/**\r
973 Update the ID Type Structure (Type 2) information.\r
974\r
975 This function populates the ID Type Structures with information from\r
976 the Configuration Manager and and adds this information to the PPTT table.\r
977\r
978 @param [in] Generator Pointer to the PPTT Generator.\r
979 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
980 Protocol Interface.\r
981 @param [in] Pptt Pointer to PPTT table structure.\r
982 @param [in] NodesStartOffset Offset from the start of PPTT table to the\r
983 start of ID Type Structures.\r
984\r
985 @retval EFI_SUCCESS Structures updated successfully.\r
986 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
987 @retval EFI_NOT_FOUND A required object was not found.\r
988**/\r
989STATIC\r
990EFI_STATUS\r
991AddIdTypeStructures (\r
731c67e1
MK
992 IN CONST ACPI_PPTT_GENERATOR *CONST Generator,\r
993 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
994 IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER *Pptt,\r
995 IN CONST UINT32 NodesStartOffset\r
77db1156
KK
996 )\r
997{\r
731c67e1
MK
998 EFI_ACPI_6_3_PPTT_STRUCTURE_ID *IdStruct;\r
999 CM_ARM_PROC_NODE_ID_INFO *ProcIdInfoNode;\r
1000 PPTT_NODE_INDEXER *IdStructIterator;\r
1001 UINT32 NodeCount;\r
77db1156
KK
1002\r
1003 ASSERT (\r
1004 (Generator != NULL) &&\r
1005 (CfgMgrProtocol != NULL) &&\r
1006 (Pptt != NULL)\r
1007 );\r
1008\r
731c67e1 1009 IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID *)((UINT8 *)Pptt + NodesStartOffset);\r
77db1156
KK
1010\r
1011 IdStructIterator = Generator->IdStructIndexedList;\r
731c67e1 1012 NodeCount = Generator->IdStructCount;\r
77db1156 1013 while (NodeCount-- != 0) {\r
731c67e1 1014 ProcIdInfoNode = (CM_ARM_PROC_NODE_ID_INFO *)IdStructIterator->Object;\r
77db1156
KK
1015\r
1016 // Populate the node\r
731c67e1
MK
1017 IdStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_ID;\r
1018 IdStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID);\r
77db1156
KK
1019 IdStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;\r
1020 IdStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;\r
731c67e1
MK
1021 IdStruct->VendorId = ProcIdInfoNode->VendorId;\r
1022 IdStruct->Level1Id = ProcIdInfoNode->Level1Id;\r
1023 IdStruct->Level2Id = ProcIdInfoNode->Level2Id;\r
1024 IdStruct->MajorRev = ProcIdInfoNode->MajorRev;\r
1025 IdStruct->MinorRev = ProcIdInfoNode->MinorRev;\r
1026 IdStruct->SpinRev = ProcIdInfoNode->SpinRev;\r
77db1156
KK
1027\r
1028 // Next ID Type Structure\r
731c67e1
MK
1029 IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID *)((UINT8 *)IdStruct +\r
1030 IdStruct->Length);\r
77db1156
KK
1031 IdStructIterator++;\r
1032 } // ID Type Structure\r
1033\r
1034 return EFI_SUCCESS;\r
1035}\r
1036\r
1037/**\r
1038 Construct the PPTT ACPI table.\r
1039\r
1040 This function invokes the Configuration Manager protocol interface\r
1041 to get the required hardware information for generating the ACPI\r
1042 table.\r
1043\r
1044 If this function allocates any resources then they must be freed\r
1045 in the FreeXXXXTableResources function.\r
1046\r
1047 @param [in] This Pointer to the table generator.\r
1048 @param [in] AcpiTableInfo Pointer to the ACPI table generator to be used.\r
1049 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1050 Protocol Interface.\r
1051 @param [out] Table Pointer to the constructed ACPI Table.\r
1052\r
1053 @retval EFI_SUCCESS Table generated successfully.\r
1054 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1055 @retval EFI_NOT_FOUND The required object was not found.\r
1056 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
1057 Manager is less than the Object size for\r
1058 the requested object.\r
1059**/\r
1060STATIC\r
1061EFI_STATUS\r
1062EFIAPI\r
1063BuildPpttTable (\r
731c67e1
MK
1064 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1065 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,\r
1066 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1067 OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table\r
77db1156
KK
1068 )\r
1069{\r
731c67e1
MK
1070 EFI_STATUS Status;\r
1071 UINT32 TableSize;\r
1072 UINT32 ProcTopologyStructCount;\r
1073 UINT32 ProcHierarchyNodeCount;\r
1074 UINT32 CacheStructCount;\r
1075 UINT32 IdStructCount;\r
77db1156 1076\r
731c67e1
MK
1077 UINT32 ProcHierarchyNodeOffset;\r
1078 UINT32 CacheStructOffset;\r
1079 UINT32 IdStructOffset;\r
77db1156 1080\r
731c67e1
MK
1081 CM_ARM_PROC_HIERARCHY_INFO *ProcHierarchyNodeList;\r
1082 CM_ARM_CACHE_INFO *CacheStructList;\r
1083 CM_ARM_PROC_NODE_ID_INFO *IdStructList;\r
77db1156 1084\r
731c67e1 1085 ACPI_PPTT_GENERATOR *Generator;\r
77db1156
KK
1086\r
1087 // Pointer to the Node Indexer array\r
731c67e1 1088 PPTT_NODE_INDEXER *NodeIndexer;\r
77db1156 1089\r
731c67e1 1090 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER *Pptt;\r
77db1156
KK
1091\r
1092 ASSERT (\r
1093 (This != NULL) &&\r
1094 (AcpiTableInfo != NULL) &&\r
1095 (CfgMgrProtocol != NULL) &&\r
1096 (Table != NULL) &&\r
1097 (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&\r
1098 (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)\r
1099 );\r
1100\r
1101 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
731c67e1
MK
1102 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision))\r
1103 {\r
77db1156
KK
1104 DEBUG ((\r
1105 DEBUG_ERROR,\r
1106 "ERROR: PPTT: Requested table revision = %d is not supported. "\r
1107 "Supported table revisions: Minimum = %d. Maximum = %d\n",\r
1108 AcpiTableInfo->AcpiTableRevision,\r
1109 This->MinAcpiTableRevision,\r
1110 This->AcpiTableRevision\r
1111 ));\r
1112 return EFI_INVALID_PARAMETER;\r
1113 }\r
1114\r
731c67e1
MK
1115 Generator = (ACPI_PPTT_GENERATOR *)This;\r
1116 *Table = NULL;\r
77db1156
KK
1117\r
1118 // Get the processor hierarchy info and update the processor topology\r
1119 // structure count with Processor Hierarchy Nodes (Type 0)\r
1120 Status = GetEArmObjProcHierarchyInfo (\r
1121 CfgMgrProtocol,\r
1122 CM_NULL_TOKEN,\r
1123 &ProcHierarchyNodeList,\r
d39271f1 1124 &ProcHierarchyNodeCount\r
77db1156
KK
1125 );\r
1126 if (EFI_ERROR (Status)) {\r
1127 DEBUG ((\r
1128 DEBUG_ERROR,\r
1129 "ERROR: PPTT: Failed to get processor hierarchy info. Status = %r\n",\r
1130 Status\r
1131 ));\r
1132 goto error_handler;\r
1133 }\r
1134\r
731c67e1 1135 ProcTopologyStructCount = ProcHierarchyNodeCount;\r
d39271f1 1136 Generator->ProcHierarchyNodeCount = ProcHierarchyNodeCount;\r
77db1156
KK
1137\r
1138 // Get the cache info and update the processor topology structure count with\r
1139 // Cache Type Structures (Type 1)\r
1140 Status = GetEArmObjCacheInfo (\r
1141 CfgMgrProtocol,\r
1142 CM_NULL_TOKEN,\r
1143 &CacheStructList,\r
d39271f1 1144 &CacheStructCount\r
77db1156
KK
1145 );\r
1146 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1147 DEBUG ((\r
1148 DEBUG_ERROR,\r
1149 "ERROR: PPTT: Failed to get cache info. Status = %r\n",\r
1150 Status\r
1151 ));\r
1152 goto error_handler;\r
1153 }\r
1154\r
731c67e1 1155 ProcTopologyStructCount += CacheStructCount;\r
d39271f1 1156 Generator->CacheStructCount = CacheStructCount;\r
77db1156
KK
1157\r
1158 // Get the processor hierarchy node ID info and update the processor topology\r
1159 // structure count with ID Structures (Type 2)\r
1160 Status = GetEArmObjProcNodeIdInfo (\r
1161 CfgMgrProtocol,\r
1162 CM_NULL_TOKEN,\r
1163 &IdStructList,\r
d39271f1 1164 &IdStructCount\r
77db1156
KK
1165 );\r
1166 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1167 DEBUG ((\r
1168 DEBUG_ERROR,\r
1169 "ERROR: PPTT: Failed to get processor hierarchy node ID info. " \\r
1170 "Status = %r\n",\r
1171 Status\r
1172 ));\r
1173 goto error_handler;\r
1174 }\r
1175\r
d39271f1
SM
1176 ProcTopologyStructCount += IdStructCount;\r
1177 Generator->IdStructCount = IdStructCount;\r
77db1156
KK
1178\r
1179 // Allocate Node Indexer array\r
731c67e1
MK
1180 NodeIndexer = (PPTT_NODE_INDEXER *)AllocateZeroPool (\r
1181 sizeof (PPTT_NODE_INDEXER) *\r
1182 ProcTopologyStructCount\r
1183 );\r
77db1156
KK
1184 if (NodeIndexer == NULL) {\r
1185 Status = EFI_OUT_OF_RESOURCES;\r
1186 DEBUG ((\r
1187 DEBUG_ERROR,\r
1188 "ERROR: PPTT: Failed to allocate memory for Node Indexer. Status = %r\n ",\r
1189 Status\r
1190 ));\r
1191 goto error_handler;\r
1192 }\r
1193\r
1194 DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));\r
1195 Generator->ProcTopologyStructCount = ProcTopologyStructCount;\r
731c67e1 1196 Generator->NodeIndexer = NodeIndexer;\r
77db1156
KK
1197\r
1198 // Calculate the size of the PPTT table\r
1199 TableSize = sizeof (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER);\r
1200\r
1201 // Include the size of Processor Hierarchy Nodes and index them\r
1202 if (Generator->ProcHierarchyNodeCount != 0) {\r
731c67e1 1203 ProcHierarchyNodeOffset = TableSize;\r
77db1156 1204 Generator->ProcHierarchyNodeIndexedList = NodeIndexer;\r
731c67e1
MK
1205 TableSize += GetSizeofProcHierarchyNodes (\r
1206 ProcHierarchyNodeOffset,\r
1207 ProcHierarchyNodeList,\r
1208 Generator->ProcHierarchyNodeCount,\r
1209 &NodeIndexer\r
1210 );\r
4d23a7ec
SM
1211\r
1212 DEBUG ((\r
1213 DEBUG_INFO,\r
1214 " ProcHierarchyNodeCount = %d\n" \\r
1215 " ProcHierarchyNodeOffset = 0x%x\n" \\r
1216 " ProcHierarchyNodeIndexedList = 0x%p\n",\r
1217 Generator->ProcHierarchyNodeCount,\r
1218 ProcHierarchyNodeOffset,\r
1219 Generator->ProcHierarchyNodeIndexedList\r
1220 ));\r
77db1156
KK
1221 }\r
1222\r
1223 // Include the size of Cache Type Structures and index them\r
1224 if (Generator->CacheStructCount != 0) {\r
731c67e1 1225 CacheStructOffset = TableSize;\r
77db1156 1226 Generator->CacheStructIndexedList = NodeIndexer;\r
731c67e1
MK
1227 TableSize += GetSizeofCacheTypeStructs (\r
1228 CacheStructOffset,\r
1229 CacheStructList,\r
1230 Generator->CacheStructCount,\r
1231 &NodeIndexer\r
1232 );\r
4d23a7ec
SM
1233 DEBUG ((\r
1234 DEBUG_INFO,\r
1235 " CacheStructCount = %d\n" \\r
1236 " CacheStructOffset = 0x%x\n" \\r
1237 " CacheStructIndexedList = 0x%p\n",\r
1238 Generator->CacheStructCount,\r
1239 CacheStructOffset,\r
1240 Generator->CacheStructIndexedList\r
1241 ));\r
77db1156
KK
1242 }\r
1243\r
1244 // Include the size of ID Type Structures and index them\r
1245 if (Generator->IdStructCount != 0) {\r
731c67e1 1246 IdStructOffset = TableSize;\r
77db1156 1247 Generator->IdStructIndexedList = NodeIndexer;\r
731c67e1
MK
1248 TableSize += GetSizeofIdStructs (\r
1249 IdStructOffset,\r
1250 IdStructList,\r
1251 Generator->IdStructCount,\r
1252 &NodeIndexer\r
1253 );\r
4d23a7ec
SM
1254 DEBUG ((\r
1255 DEBUG_INFO,\r
1256 " IdStructCount = %d\n" \\r
1257 " IdStructOffset = 0x%x\n" \\r
1258 " IdStructIndexedList = 0x%p\n",\r
1259 Generator->IdStructCount,\r
1260 IdStructOffset,\r
1261 Generator->IdStructIndexedList\r
1262 ));\r
77db1156
KK
1263 }\r
1264\r
1265 DEBUG ((\r
1266 DEBUG_INFO,\r
1267 "INFO: PPTT:\n" \\r
1268 " ProcTopologyStructCount = %d\n" \\r
1269 " TableSize = %d\n",\r
1270 ProcTopologyStructCount,\r
1271 TableSize\r
1272 ));\r
1273\r
77db1156 1274 // Allocate the Buffer for the PPTT table\r
731c67e1 1275 *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);\r
77db1156
KK
1276 if (*Table == NULL) {\r
1277 Status = EFI_OUT_OF_RESOURCES;\r
1278 DEBUG ((\r
1279 DEBUG_ERROR,\r
1280 "ERROR: PPTT: Failed to allocate memory for PPTT Table. " \\r
1281 "Size = %d. Status = %r\n",\r
1282 TableSize,\r
1283 Status\r
1284 ));\r
1285 goto error_handler;\r
1286 }\r
1287\r
731c67e1 1288 Pptt = (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER *)*Table;\r
77db1156
KK
1289\r
1290 DEBUG ((\r
1291 DEBUG_INFO,\r
1292 "PPTT: Pptt = 0x%p. TableSize = 0x%x\n",\r
1293 Pptt,\r
1294 TableSize\r
1295 ));\r
1296\r
1297 // Add ACPI header\r
1298 Status = AddAcpiHeader (\r
1299 CfgMgrProtocol,\r
1300 This,\r
1301 &Pptt->Header,\r
1302 AcpiTableInfo,\r
1303 TableSize\r
1304 );\r
1305 if (EFI_ERROR (Status)) {\r
1306 DEBUG ((\r
1307 DEBUG_ERROR,\r
1308 "ERROR: PPTT: Failed to add ACPI header. Status = %r\n",\r
1309 Status\r
1310 ));\r
1311 goto error_handler;\r
1312 }\r
1313\r
1314 // Add Processor Hierarchy Nodes (Type 0) to the generated table\r
1315 if (Generator->ProcHierarchyNodeCount != 0) {\r
1316 Status = AddProcHierarchyNodes (\r
1317 Generator,\r
1318 CfgMgrProtocol,\r
1319 Pptt,\r
1320 ProcHierarchyNodeOffset\r
1321 );\r
1322 if (EFI_ERROR (Status)) {\r
1323 DEBUG ((\r
1324 DEBUG_ERROR,\r
1325 "ERROR: PPTT: Failed to add Processor Hierarchy Nodes. Status = %r\n",\r
1326 Status\r
1327 ));\r
1328 goto error_handler;\r
1329 }\r
1330 }\r
1331\r
1332 // Add Cache Type Structures (Type 1) to the generated table\r
1333 if (Generator->CacheStructCount != 0) {\r
1334 Status = AddCacheTypeStructures (\r
1335 Generator,\r
1336 CfgMgrProtocol,\r
1337 Pptt,\r
1338 CacheStructOffset\r
1339 );\r
1340 if (EFI_ERROR (Status)) {\r
1341 DEBUG ((\r
1342 DEBUG_ERROR,\r
1343 "ERROR: PPTT: Failed to add Cache Type Structures. Status = %r\n",\r
1344 Status\r
1345 ));\r
1346 goto error_handler;\r
1347 }\r
1348 }\r
1349\r
1350 // Add ID Type Structures (Type 2) to the generated table\r
1351 if (Generator->IdStructCount != 0) {\r
1352 Status = AddIdTypeStructures (\r
1353 Generator,\r
1354 CfgMgrProtocol,\r
1355 Pptt,\r
1356 IdStructOffset\r
1357 );\r
1358 if (EFI_ERROR (Status)) {\r
1359 DEBUG ((\r
1360 DEBUG_ERROR,\r
1361 "ERROR: PPTT: Failed to add ID Type Structures. Status = %r\n",\r
1362 Status\r
1363 ));\r
1364 goto error_handler;\r
1365 }\r
1366 }\r
1367\r
1368 // Validate CM object cross-references in PPTT\r
1369 Status = DetectCyclesInTopology (Generator);\r
1370 if (EFI_ERROR (Status)) {\r
1371 DEBUG ((\r
1372 DEBUG_ERROR,\r
1373 "ERROR: PPTT: Invalid processor and cache topology. Status = %r\n",\r
1374 Status\r
1375 ));\r
1376 goto error_handler;\r
1377 }\r
1378\r
1379 return Status;\r
1380\r
1381error_handler:\r
1382 if (Generator->NodeIndexer != NULL) {\r
1383 FreePool (Generator->NodeIndexer);\r
1384 Generator->NodeIndexer = NULL;\r
1385 }\r
1386\r
1387 if (*Table != NULL) {\r
1388 FreePool (*Table);\r
1389 *Table = NULL;\r
1390 }\r
1391\r
1392 return Status;\r
1393}\r
1394\r
1395/**\r
1396 Free any resources allocated for constructing the PPTT\r
1397\r
1398 @param [in] This Pointer to the table generator.\r
1399 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
1400 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1401 Protocol Interface.\r
1402 @param [in, out] Table Pointer to the ACPI Table.\r
1403\r
1404 @retval EFI_SUCCESS The resources were freed successfully.\r
1405 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
1406**/\r
1407STATIC\r
1408EFI_STATUS\r
1409FreePpttTableResources (\r
731c67e1
MK
1410 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1411 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,\r
1412 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1413 IN OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table\r
77db1156
KK
1414 )\r
1415{\r
731c67e1 1416 ACPI_PPTT_GENERATOR *Generator;\r
77db1156
KK
1417\r
1418 ASSERT (\r
1419 (This != NULL) &&\r
1420 (AcpiTableInfo != NULL) &&\r
1421 (CfgMgrProtocol != NULL) &&\r
1422 (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&\r
1423 (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)\r
1424 );\r
1425\r
731c67e1 1426 Generator = (ACPI_PPTT_GENERATOR *)This;\r
77db1156
KK
1427\r
1428 // Free any memory allocated by the generator\r
1429 if (Generator->NodeIndexer != NULL) {\r
1430 FreePool (Generator->NodeIndexer);\r
1431 Generator->NodeIndexer = NULL;\r
1432 }\r
1433\r
1434 if ((Table == NULL) || (*Table == NULL)) {\r
1435 DEBUG ((DEBUG_ERROR, "ERROR: PPTT: Invalid Table Pointer\n"));\r
1436 ASSERT (\r
1437 (Table != NULL) &&\r
1438 (*Table != NULL)\r
1439 );\r
1440 return EFI_INVALID_PARAMETER;\r
1441 }\r
1442\r
1443 FreePool (*Table);\r
1444 *Table = NULL;\r
1445 return EFI_SUCCESS;\r
1446}\r
1447\r
1448/** The PPTT Table Generator revision.\r
1449*/\r
731c67e1 1450#define PPTT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
77db1156
KK
1451\r
1452/** The interface for the PPTT Table Generator.\r
1453*/\r
1454STATIC\r
731c67e1 1455ACPI_PPTT_GENERATOR PpttGenerator = {\r
77db1156
KK
1456 // ACPI table generator header\r
1457 {\r
1458 // Generator ID\r
1459 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPptt),\r
1460 // Generator Description\r
1461 L"ACPI.STD.PPTT.GENERATOR",\r
1462 // ACPI Table Signature\r
1463 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE,\r
1464 // ACPI Table Revision supported by this Generator\r
1465 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,\r
1466 // Minimum supported ACPI Table Revision\r
1467 EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,\r
1468 // Creator ID\r
1469 TABLE_GENERATOR_CREATOR_ID_ARM,\r
1470 // Creator Revision\r
1471 PPTT_GENERATOR_REVISION,\r
1472 // Build Table function\r
1473 BuildPpttTable,\r
1474 // Free Resource function\r
1475 FreePpttTableResources,\r
1476 // Extended build function not needed\r
1477 NULL,\r
1478 // Extended build function not implemented by the generator.\r
1479 // Hence extended free resource function is not required.\r
1480 NULL\r
1481 },\r
1482\r
1483 // PPTT Generator private data\r
1484\r
1485 // Processor topology node count\r
1486 0,\r
d39271f1
SM
1487 // Count of Processor Hierarchy Nodes\r
1488 0,\r
1489 // Count of Cache Structures\r
1490 0,\r
1491 // Count of Id Structures\r
1492 0,\r
77db1156
KK
1493 // Pointer to PPTT Node Indexer\r
1494 NULL\r
1495};\r
1496\r
1497/**\r
1498 Register the Generator with the ACPI Table Factory.\r
1499\r
1500 @param [in] ImageHandle The handle to the image.\r
1501 @param [in] SystemTable Pointer to the System Table.\r
1502\r
1503 @retval EFI_SUCCESS The Generator is registered.\r
1504 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1505 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
1506 is already registered.\r
1507**/\r
1508EFI_STATUS\r
1509EFIAPI\r
1510AcpiPpttLibConstructor (\r
731c67e1
MK
1511 IN EFI_HANDLE ImageHandle,\r
1512 IN EFI_SYSTEM_TABLE *SystemTable\r
77db1156
KK
1513 )\r
1514{\r
1515 EFI_STATUS Status;\r
731c67e1 1516\r
77db1156
KK
1517 Status = RegisterAcpiTableGenerator (&PpttGenerator.Header);\r
1518 DEBUG ((DEBUG_INFO, "PPTT: Register Generator. Status = %r\n", Status));\r
1519 ASSERT_EFI_ERROR (Status);\r
1520 return Status;\r
1521}\r
1522\r
1523/**\r
1524 Deregister the Generator from the ACPI Table Factory.\r
1525\r
1526 @param [in] ImageHandle The handle to the image.\r
1527 @param [in] SystemTable Pointer to the System Table.\r
1528\r
1529 @retval EFI_SUCCESS The Generator is deregistered.\r
1530 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1531 @retval EFI_NOT_FOUND The Generator is not registered.\r
1532**/\r
1533EFI_STATUS\r
1534EFIAPI\r
1535AcpiPpttLibDestructor (\r
731c67e1
MK
1536 IN EFI_HANDLE ImageHandle,\r
1537 IN EFI_SYSTEM_TABLE *SystemTable\r
77db1156
KK
1538 )\r
1539{\r
1540 EFI_STATUS Status;\r
731c67e1 1541\r
77db1156
KK
1542 Status = DeregisterAcpiTableGenerator (&PpttGenerator.Header);\r
1543 DEBUG ((DEBUG_INFO, "PPTT: Deregister Generator. Status = %r\n", Status));\r
1544 ASSERT_EFI_ERROR (Status);\r
1545 return Status;\r
1546}\r