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