]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
DynamicTablesPkg: IORT set reference to Id array only if present
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiIortLibArm / IortGenerator.c
CommitLineData
dfaffc69
SM
1/** @file\r
2 IORT Table Generator\r
3\r
65c4f3f2 4 Copyright (c) 2017 - 2022, Arm Limited. All rights reserved.\r
9cd9bdc6 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
dfaffc69
SM
6\r
7 @par Reference(s):\r
8 - IO Remapping Table, Platform Design Document,\r
9 Document number: ARM DEN 0049D, Issue D, March 2018\r
10\r
11**/\r
12\r
13#include <IndustryStandard/IoRemappingTable.h>\r
14#include <Library/AcpiLib.h>\r
15#include <Library/BaseLib.h>\r
16#include <Library/DebugLib.h>\r
17#include <Library/MemoryAllocationLib.h>\r
18#include <Protocol/AcpiTable.h>\r
19\r
20// Module specific include files.\r
21#include <AcpiTableGenerator.h>\r
22#include <ConfigurationManagerObject.h>\r
23#include <ConfigurationManagerHelper.h>\r
24#include <Library/TableHelperLib.h>\r
25#include <Protocol/ConfigurationManagerProtocol.h>\r
26\r
27#include "IortGenerator.h"\r
28\r
29/** ARM standard IORT Generator\r
30\r
31Requirements:\r
32 The following Configuration Manager Object(s) are required by\r
33 this Generator:\r
34 - EArmObjItsGroup\r
35 - EArmObjNamedComponent\r
36 - EArmObjRootComplex\r
37 - EArmObjSmmuV1SmmuV2\r
38 - EArmObjSmmuV3\r
39 - EArmObjPmcg\r
40 - EArmObjGicItsIdentifierArray\r
98a4a7a9 41 - EArmObjIdMappingArray\r
dfaffc69
SM
42 - EArmObjGicItsIdentifierArray\r
43*/\r
44\r
45/** This macro expands to a function that retrieves the ITS\r
46 Group node information from the Configuration Manager.\r
47*/\r
48GET_OBJECT_LIST (\r
49 EObjNameSpaceArm,\r
50 EArmObjItsGroup,\r
51 CM_ARM_ITS_GROUP_NODE\r
52 );\r
53\r
54/** This macro expands to a function that retrieves the\r
55 Named Component node information from the Configuration Manager.\r
56*/\r
57GET_OBJECT_LIST (\r
58 EObjNameSpaceArm,\r
59 EArmObjNamedComponent,\r
60 CM_ARM_NAMED_COMPONENT_NODE\r
61 );\r
62\r
63/** This macro expands to a function that retrieves the\r
64 Root Complex node information from the Configuration Manager.\r
65*/\r
66GET_OBJECT_LIST (\r
67 EObjNameSpaceArm,\r
68 EArmObjRootComplex,\r
69 CM_ARM_ROOT_COMPLEX_NODE\r
70 );\r
71\r
72/** This macro expands to a function that retrieves the\r
73 SMMU v1/v2 node information from the Configuration Manager.\r
74*/\r
75GET_OBJECT_LIST (\r
76 EObjNameSpaceArm,\r
77 EArmObjSmmuV1SmmuV2,\r
78 CM_ARM_SMMUV1_SMMUV2_NODE\r
79 );\r
80\r
81/** This macro expands to a function that retrieves the\r
82 SMMU v3 node information from the Configuration Manager.\r
83*/\r
84GET_OBJECT_LIST (\r
85 EObjNameSpaceArm,\r
86 EArmObjSmmuV3,\r
87 CM_ARM_SMMUV3_NODE\r
88 );\r
89\r
90/** This macro expands to a function that retrieves the\r
91 PMCG node information from the Configuration Manager.\r
92*/\r
93GET_OBJECT_LIST (\r
94 EObjNameSpaceArm,\r
95 EArmObjPmcg,\r
96 CM_ARM_PMCG_NODE\r
97 );\r
98\r
99/** This macro expands to a function that retrieves the\r
100 ITS Identifier Array information from the Configuration Manager.\r
101*/\r
102GET_OBJECT_LIST (\r
103 EObjNameSpaceArm,\r
104 EArmObjGicItsIdentifierArray,\r
105 CM_ARM_ITS_IDENTIFIER\r
106 );\r
107\r
108/** This macro expands to a function that retrieves the\r
109 Id Mapping Array information from the Configuration Manager.\r
110*/\r
111GET_OBJECT_LIST (\r
112 EObjNameSpaceArm,\r
98a4a7a9 113 EArmObjIdMappingArray,\r
dfaffc69
SM
114 CM_ARM_ID_MAPPING\r
115 );\r
116\r
117/** This macro expands to a function that retrieves the\r
118 SMMU Interrupt Array information from the Configuration Manager.\r
119*/\r
120GET_OBJECT_LIST (\r
121 EObjNameSpaceArm,\r
122 EArmObjSmmuInterruptArray,\r
123 CM_ARM_SMMU_INTERRUPT\r
124 );\r
125\r
126/** Returns the size of the ITS Group node.\r
127\r
128 @param [in] Node Pointer to ITS Group node.\r
129\r
130 @retval Size of the ITS Group Node.\r
131**/\r
132STATIC\r
133UINT32\r
134GetItsGroupNodeSize (\r
731c67e1 135 IN CONST CM_ARM_ITS_GROUP_NODE *Node\r
dfaffc69
SM
136 )\r
137{\r
138 ASSERT (Node != NULL);\r
139\r
140 /* Size of ITS Group Node +\r
141 Size of ITS Identifier array\r
142 */\r
8b2ac43b 143 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) +\r
731c67e1 144 (Node->ItsIdCount * sizeof (UINT32)));\r
dfaffc69
SM
145}\r
146\r
147/** Returns the total size required for the ITS Group nodes and\r
148 updates the Node Indexer.\r
149\r
150 This function calculates the size required for the node group\r
151 and also populates the Node Indexer array with offsets for the\r
152 individual nodes.\r
153\r
154 @param [in] NodeStartOffset Offset from the start of the\r
155 IORT where this node group starts.\r
156 @param [in] NodeList Pointer to ITS Group node list.\r
157 @param [in] NodeCount Count of the ITS Group nodes.\r
158 @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
159\r
160 @retval Total size of the ITS Group Nodes.\r
161**/\r
162STATIC\r
8b2ac43b 163UINT64\r
dfaffc69
SM
164GetSizeofItsGroupNodes (\r
165 IN CONST UINT32 NodeStartOffset,\r
731c67e1 166 IN CONST CM_ARM_ITS_GROUP_NODE *NodeList,\r
dfaffc69 167 IN UINT32 NodeCount,\r
731c67e1 168 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer\r
dfaffc69
SM
169 )\r
170{\r
8b2ac43b 171 UINT64 Size;\r
dfaffc69
SM
172\r
173 ASSERT (NodeList != NULL);\r
174\r
175 Size = 0;\r
176 while (NodeCount-- != 0) {\r
731c67e1
MK
177 (*NodeIndexer)->Token = NodeList->Token;\r
178 (*NodeIndexer)->Object = (VOID *)NodeList;\r
8b2ac43b 179 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);\r
dfaffc69
SM
180 DEBUG ((\r
181 DEBUG_INFO,\r
182 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
183 *NodeIndexer,\r
184 (*NodeIndexer)->Token,\r
185 (*NodeIndexer)->Object,\r
186 (*NodeIndexer)->Offset\r
187 ));\r
188\r
189 Size += GetItsGroupNodeSize (NodeList);\r
190 (*NodeIndexer)++;\r
191 NodeList++;\r
192 }\r
731c67e1 193\r
dfaffc69
SM
194 return Size;\r
195}\r
196\r
197/** Returns the size of the Named Component node.\r
198\r
199 @param [in] Node Pointer to Named Component node.\r
200\r
201 @retval Size of the Named Component node.\r
202**/\r
203STATIC\r
204UINT32\r
205GetNamedComponentNodeSize (\r
731c67e1 206 IN CONST CM_ARM_NAMED_COMPONENT_NODE *Node\r
dfaffc69
SM
207 )\r
208{\r
209 ASSERT (Node != NULL);\r
210\r
211 /* Size of Named Component node +\r
212 Size of ID mapping array +\r
213 Size of ASCII string + 'padding to 32-bit word aligned'.\r
214 */\r
8b2ac43b 215 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +\r
731c67e1
MK
216 (Node->IdMappingCount *\r
217 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +\r
218 ALIGN_VALUE (AsciiStrSize (Node->ObjectName), 4));\r
dfaffc69
SM
219}\r
220\r
221/** Returns the total size required for the Named Component nodes and\r
222 updates the Node Indexer.\r
223\r
224 This function calculates the size required for the node group\r
225 and also populates the Node Indexer array with offsets for the\r
226 individual nodes.\r
227\r
228 @param [in] NodeStartOffset Offset from the start of the\r
229 IORT where this node group starts.\r
230 @param [in] NodeList Pointer to Named Component node list.\r
231 @param [in] NodeCount Count of the Named Component nodes.\r
232 @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
233\r
234 @retval Total size of the Named Component nodes.\r
235**/\r
236STATIC\r
8b2ac43b 237UINT64\r
dfaffc69
SM
238GetSizeofNamedComponentNodes (\r
239 IN CONST UINT32 NodeStartOffset,\r
731c67e1 240 IN CONST CM_ARM_NAMED_COMPONENT_NODE *NodeList,\r
dfaffc69 241 IN UINT32 NodeCount,\r
731c67e1 242 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer\r
dfaffc69
SM
243 )\r
244{\r
8b2ac43b 245 UINT64 Size;\r
dfaffc69
SM
246\r
247 ASSERT (NodeList != NULL);\r
248\r
249 Size = 0;\r
250 while (NodeCount-- != 0) {\r
731c67e1
MK
251 (*NodeIndexer)->Token = NodeList->Token;\r
252 (*NodeIndexer)->Object = (VOID *)NodeList;\r
8b2ac43b 253 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);\r
dfaffc69
SM
254 DEBUG ((\r
255 DEBUG_INFO,\r
256 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
257 *NodeIndexer,\r
258 (*NodeIndexer)->Token,\r
259 (*NodeIndexer)->Object,\r
260 (*NodeIndexer)->Offset\r
261 ));\r
262\r
263 Size += GetNamedComponentNodeSize (NodeList);\r
264 (*NodeIndexer)++;\r
265 NodeList++;\r
266 }\r
267\r
268 return Size;\r
269}\r
270\r
271/** Returns the size of the Root Complex node.\r
272\r
273 @param [in] Node Pointer to Root Complex node.\r
274\r
275 @retval Size of the Root Complex node.\r
276**/\r
277STATIC\r
278UINT32\r
279GetRootComplexNodeSize (\r
731c67e1 280 IN CONST CM_ARM_ROOT_COMPLEX_NODE *Node\r
dfaffc69
SM
281 )\r
282{\r
283 ASSERT (Node != NULL);\r
284\r
285 /* Size of Root Complex node +\r
286 Size of ID mapping array\r
287 */\r
8b2ac43b 288 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE) +\r
731c67e1
MK
289 (Node->IdMappingCount *\r
290 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));\r
dfaffc69
SM
291}\r
292\r
293/** Returns the total size required for the Root Complex nodes and\r
294 updates the Node Indexer.\r
295\r
296 This function calculates the size required for the node group\r
297 and also populates the Node Indexer array with offsets for the\r
298 individual nodes.\r
299\r
300 @param [in] NodeStartOffset Offset from the start of the\r
301 IORT where this node group starts.\r
302 @param [in] NodeList Pointer to Root Complex node list.\r
303 @param [in] NodeCount Count of the Root Complex nodes.\r
304 @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
305\r
306 @retval Total size of the Root Complex nodes.\r
307**/\r
308STATIC\r
8b2ac43b 309UINT64\r
dfaffc69
SM
310GetSizeofRootComplexNodes (\r
311 IN CONST UINT32 NodeStartOffset,\r
731c67e1 312 IN CONST CM_ARM_ROOT_COMPLEX_NODE *NodeList,\r
dfaffc69 313 IN UINT32 NodeCount,\r
731c67e1 314 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer\r
dfaffc69
SM
315 )\r
316{\r
8b2ac43b 317 UINT64 Size;\r
dfaffc69
SM
318\r
319 ASSERT (NodeList != NULL);\r
320\r
321 Size = 0;\r
322 while (NodeCount-- != 0) {\r
731c67e1
MK
323 (*NodeIndexer)->Token = NodeList->Token;\r
324 (*NodeIndexer)->Object = (VOID *)NodeList;\r
8b2ac43b 325 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);\r
dfaffc69
SM
326 DEBUG ((\r
327 DEBUG_INFO,\r
328 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
329 *NodeIndexer,\r
330 (*NodeIndexer)->Token,\r
331 (*NodeIndexer)->Object,\r
332 (*NodeIndexer)->Offset\r
333 ));\r
334\r
335 Size += GetRootComplexNodeSize (NodeList);\r
336 (*NodeIndexer)++;\r
337 NodeList++;\r
338 }\r
339\r
340 return Size;\r
341}\r
342\r
343/** Returns the size of the SMMUv1/SMMUv2 node.\r
344\r
345 @param [in] Node Pointer to SMMUv1/SMMUv2 node list.\r
346\r
347 @retval Size of the SMMUv1/SMMUv2 node.\r
348**/\r
349STATIC\r
350UINT32\r
351GetSmmuV1V2NodeSize (\r
731c67e1 352 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *Node\r
dfaffc69
SM
353 )\r
354{\r
355 ASSERT (Node != NULL);\r
356\r
357 /* Size of SMMU v1/SMMU v2 node +\r
358 Size of ID mapping array +\r
359 Size of context interrupt array +\r
360 Size of PMU interrupt array\r
361 */\r
8b2ac43b 362 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +\r
731c67e1
MK
363 (Node->IdMappingCount *\r
364 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +\r
365 (Node->ContextInterruptCount *\r
366 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +\r
367 (Node->PmuInterruptCount *\r
368 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)));\r
dfaffc69
SM
369}\r
370\r
371/** Returns the total size required for the SMMUv1/SMMUv2 nodes and\r
372 updates the Node Indexer.\r
373\r
374 This function calculates the size required for the node group\r
375 and also populates the Node Indexer array with offsets for the\r
376 individual nodes.\r
377\r
378 @param [in] NodeStartOffset Offset from the start of the\r
379 IORT where this node group starts.\r
380 @param [in] NodeList Pointer to SMMUv1/SMMUv2 node list.\r
381 @param [in] NodeCount Count of the SMMUv1/SMMUv2 nodes.\r
382 @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
383\r
384 @retval Total size of the SMMUv1/SMMUv2 nodes.\r
385**/\r
386STATIC\r
8b2ac43b 387UINT64\r
dfaffc69
SM
388GetSizeofSmmuV1V2Nodes (\r
389 IN CONST UINT32 NodeStartOffset,\r
731c67e1 390 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *NodeList,\r
dfaffc69 391 IN UINT32 NodeCount,\r
731c67e1 392 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer\r
dfaffc69
SM
393 )\r
394{\r
8b2ac43b 395 UINT64 Size;\r
dfaffc69
SM
396\r
397 ASSERT (NodeList != NULL);\r
398\r
399 Size = 0;\r
400 while (NodeCount-- != 0) {\r
731c67e1
MK
401 (*NodeIndexer)->Token = NodeList->Token;\r
402 (*NodeIndexer)->Object = (VOID *)NodeList;\r
8b2ac43b 403 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);\r
dfaffc69
SM
404 DEBUG ((\r
405 DEBUG_INFO,\r
406 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
407 *NodeIndexer,\r
408 (*NodeIndexer)->Token,\r
409 (*NodeIndexer)->Object,\r
410 (*NodeIndexer)->Offset\r
411 ));\r
412\r
413 Size += GetSmmuV1V2NodeSize (NodeList);\r
414 (*NodeIndexer)++;\r
415 NodeList++;\r
416 }\r
731c67e1 417\r
dfaffc69
SM
418 return Size;\r
419}\r
420\r
421/** Returns the size of the SMMUv3 node.\r
422\r
423 @param [in] Node Pointer to SMMUv3 node list.\r
424\r
425 @retval Total size of the SMMUv3 nodes.\r
426**/\r
427STATIC\r
428UINT32\r
429GetSmmuV3NodeSize (\r
731c67e1 430 IN CONST CM_ARM_SMMUV3_NODE *Node\r
dfaffc69
SM
431 )\r
432{\r
433 ASSERT (Node != NULL);\r
434\r
435 /* Size of SMMU v1/SMMU v2 node +\r
436 Size of ID mapping array\r
437 */\r
8b2ac43b 438 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE) +\r
731c67e1
MK
439 (Node->IdMappingCount *\r
440 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));\r
dfaffc69
SM
441}\r
442\r
443/** Returns the total size required for the SMMUv3 nodes and\r
444 updates the Node Indexer.\r
445\r
446 This function calculates the size required for the node group\r
447 and also populates the Node Indexer array with offsets for the\r
448 individual nodes.\r
449\r
450 @param [in] NodeStartOffset Offset from the start of the\r
451 IORT where this node group starts.\r
452 @param [in] NodeList Pointer to SMMUv3 node list.\r
453 @param [in] NodeCount Count of the SMMUv3 nodes.\r
454 @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
455\r
456 @retval Total size of the SMMUv3 nodes.\r
457**/\r
458STATIC\r
8b2ac43b 459UINT64\r
dfaffc69
SM
460GetSizeofSmmuV3Nodes (\r
461 IN CONST UINT32 NodeStartOffset,\r
731c67e1 462 IN CONST CM_ARM_SMMUV3_NODE *NodeList,\r
dfaffc69 463 IN UINT32 NodeCount,\r
731c67e1 464 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer\r
dfaffc69
SM
465 )\r
466{\r
8b2ac43b 467 UINT64 Size;\r
dfaffc69
SM
468\r
469 ASSERT (NodeList != NULL);\r
470\r
471 Size = 0;\r
472 while (NodeCount-- != 0) {\r
731c67e1
MK
473 (*NodeIndexer)->Token = NodeList->Token;\r
474 (*NodeIndexer)->Object = (VOID *)NodeList;\r
8b2ac43b 475 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);\r
dfaffc69
SM
476 DEBUG ((\r
477 DEBUG_INFO,\r
478 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
479 *NodeIndexer,\r
480 (*NodeIndexer)->Token,\r
481 (*NodeIndexer)->Object,\r
482 (*NodeIndexer)->Offset\r
483 ));\r
484\r
485 Size += GetSmmuV3NodeSize (NodeList);\r
486 (*NodeIndexer)++;\r
487 NodeList++;\r
488 }\r
731c67e1 489\r
dfaffc69
SM
490 return Size;\r
491}\r
492\r
493/** Returns the size of the PMCG node.\r
494\r
495 @param [in] Node Pointer to PMCG node.\r
496\r
497 @retval Size of the PMCG node.\r
498**/\r
499STATIC\r
500UINT32\r
501GetPmcgNodeSize (\r
731c67e1 502 IN CONST CM_ARM_PMCG_NODE *Node\r
dfaffc69
SM
503 )\r
504{\r
505 ASSERT (Node != NULL);\r
506\r
507 /* Size of PMCG node +\r
508 Size of ID mapping array\r
509 */\r
8b2ac43b 510 return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE) +\r
731c67e1
MK
511 (Node->IdMappingCount *\r
512 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));\r
dfaffc69
SM
513}\r
514\r
515/** Returns the total size required for the PMCG nodes and\r
516 updates the Node Indexer.\r
517\r
518 This function calculates the size required for the node group\r
519 and also populates the Node Indexer array with offsets for the\r
520 individual nodes.\r
521\r
522 @param [in] NodeStartOffset Offset from the start of the\r
523 IORT where this node group starts.\r
524 @param [in] NodeList Pointer to PMCG node list.\r
525 @param [in] NodeCount Count of the PMCG nodes.\r
526 @param [in, out] NodeIndexer Pointer to the next Node Indexer.\r
527\r
528 @retval Total size of the PMCG nodes.\r
529**/\r
530STATIC\r
8b2ac43b 531UINT64\r
dfaffc69
SM
532GetSizeofPmcgNodes (\r
533 IN CONST UINT32 NodeStartOffset,\r
731c67e1 534 IN CONST CM_ARM_PMCG_NODE *NodeList,\r
dfaffc69 535 IN UINT32 NodeCount,\r
731c67e1 536 IN OUT IORT_NODE_INDEXER **CONST NodeIndexer\r
dfaffc69
SM
537 )\r
538{\r
8b2ac43b 539 UINT64 Size;\r
dfaffc69
SM
540\r
541 ASSERT (NodeList != NULL);\r
542\r
543 Size = 0;\r
544 while (NodeCount-- != 0) {\r
731c67e1
MK
545 (*NodeIndexer)->Token = NodeList->Token;\r
546 (*NodeIndexer)->Object = (VOID *)NodeList;\r
8b2ac43b 547 (*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);\r
dfaffc69
SM
548 DEBUG ((\r
549 DEBUG_INFO,\r
550 "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",\r
551 *NodeIndexer,\r
552 (*NodeIndexer)->Token,\r
553 (*NodeIndexer)->Object,\r
554 (*NodeIndexer)->Offset\r
555 ));\r
556\r
557 Size += GetPmcgNodeSize (NodeList);\r
558 (*NodeIndexer)++;\r
559 NodeList++;\r
560 }\r
731c67e1 561\r
dfaffc69
SM
562 return Size;\r
563}\r
564\r
565/** Returns the offset of the Node referenced by the Token.\r
566\r
567 @param [in] NodeIndexer Pointer to node indexer array.\r
568 @param [in] NodeCount Count of the nodes.\r
569 @param [in] Token Reference token for the node.\r
570 @param [out] NodeOffset Offset of the node from the\r
571 start of the IORT table.\r
572\r
573 @retval EFI_SUCCESS Success.\r
574 @retval EFI_NOT_FOUND No matching token reference\r
575 found in node indexer array.\r
576**/\r
577STATIC\r
578EFI_STATUS\r
579GetNodeOffsetReferencedByToken (\r
731c67e1
MK
580 IN IORT_NODE_INDEXER *NodeIndexer,\r
581 IN UINT32 NodeCount,\r
582 IN CM_OBJECT_TOKEN Token,\r
583 OUT UINT32 *NodeOffset\r
dfaffc69
SM
584 )\r
585{\r
586 DEBUG ((\r
731c67e1
MK
587 DEBUG_INFO,\r
588 "IORT: Node Indexer: Search Token = %p\n",\r
589 Token\r
590 ));\r
dfaffc69
SM
591 while (NodeCount-- != 0) {\r
592 DEBUG ((\r
593 DEBUG_INFO,\r
594 "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",\r
595 NodeIndexer->Token,\r
596 NodeIndexer->Offset\r
597 ));\r
598 if (NodeIndexer->Token == Token) {\r
599 *NodeOffset = NodeIndexer->Offset;\r
600 DEBUG ((\r
601 DEBUG_INFO,\r
602 "IORT: Node Indexer: Token = %p, Found\n",\r
603 Token\r
604 ));\r
605 return EFI_SUCCESS;\r
606 }\r
731c67e1 607\r
dfaffc69
SM
608 NodeIndexer++;\r
609 }\r
731c67e1 610\r
dfaffc69
SM
611 DEBUG ((\r
612 DEBUG_INFO,\r
613 "IORT: Node Indexer: Token = %p, Not Found\n",\r
614 Token\r
615 ));\r
616 return EFI_NOT_FOUND;\r
617}\r
618\r
619/** Update the Id Mapping Array.\r
620\r
621 This function retrieves the Id Mapping Array object referenced by the\r
622 IdMappingToken and updates the IdMapArray.\r
623\r
624 @param [in] This Pointer to the table Generator.\r
625 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
626 Protocol Interface.\r
627 @param [in] IdMapArray Pointer to an array of Id Mappings.\r
628 @param [in] IdCount Number of Id Mappings.\r
629 @param [in] IdMappingToken Reference Token for retrieving the\r
630 Id Mapping Array object.\r
631\r
632 @retval EFI_SUCCESS Table generated successfully.\r
633 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
634 @retval EFI_NOT_FOUND The required object was not found.\r
635**/\r
636STATIC\r
637EFI_STATUS\r
638AddIdMappingArray (\r
731c67e1
MK
639 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
640 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
641 IN EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray,\r
dfaffc69
SM
642 IN UINT32 IdCount,\r
643 IN CONST CM_OBJECT_TOKEN IdMappingToken\r
644 )\r
645{\r
731c67e1
MK
646 EFI_STATUS Status;\r
647 CM_ARM_ID_MAPPING *IdMappings;\r
648 UINT32 IdMappingCount;\r
649 ACPI_IORT_GENERATOR *Generator;\r
dfaffc69
SM
650\r
651 ASSERT (IdMapArray != NULL);\r
652\r
731c67e1 653 Generator = (ACPI_IORT_GENERATOR *)This;\r
dfaffc69
SM
654\r
655 // Get the Id Mapping Array\r
98a4a7a9 656 Status = GetEArmObjIdMappingArray (\r
dfaffc69
SM
657 CfgMgrProtocol,\r
658 IdMappingToken,\r
659 &IdMappings,\r
660 &IdMappingCount\r
661 );\r
662 if (EFI_ERROR (Status)) {\r
663 DEBUG ((\r
664 DEBUG_ERROR,\r
665 "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",\r
666 Status\r
667 ));\r
668 return Status;\r
669 }\r
670\r
671 if (IdMappingCount < IdCount) {\r
672 DEBUG ((\r
673 DEBUG_ERROR,\r
674 "ERROR: IORT: Failed to get the required number of Id Mappings.\n"\r
675 ));\r
676 return EFI_NOT_FOUND;\r
677 }\r
678\r
679 // Populate the Id Mapping array\r
680 while (IdCount-- != 0) {\r
681 Status = GetNodeOffsetReferencedByToken (\r
731c67e1
MK
682 Generator->NodeIndexer,\r
683 Generator->IortNodeCount,\r
684 IdMappings->OutputReferenceToken,\r
685 &IdMapArray->OutputReference\r
686 );\r
dfaffc69
SM
687 if (EFI_ERROR (Status)) {\r
688 DEBUG ((\r
689 DEBUG_ERROR,\r
690 "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."\r
691 "Reference Token = %p"\r
692 " Status = %r\n",\r
693 IdMappings->OutputReferenceToken,\r
694 Status\r
695 ));\r
696 return Status;\r
697 }\r
698\r
731c67e1
MK
699 IdMapArray->InputBase = IdMappings->InputBase;\r
700 IdMapArray->NumIds = IdMappings->NumIds;\r
dfaffc69 701 IdMapArray->OutputBase = IdMappings->OutputBase;\r
731c67e1 702 IdMapArray->Flags = IdMappings->Flags;\r
dfaffc69
SM
703\r
704 IdMapArray++;\r
705 IdMappings++;\r
706 } // Id Mapping array\r
707\r
708 return EFI_SUCCESS;\r
709}\r
710\r
711/** Update the ITS Group Node Information.\r
712\r
713 @param [in] This Pointer to the table Generator.\r
714 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
715 Protocol Interface.\r
716 @param [in] Iort Pointer to IORT table structure.\r
717 @param [in] NodesStartOffset Offset for the start of the ITS Group\r
718 Nodes.\r
719 @param [in] NodeList Pointer to an array of ITS Group Node\r
720 Objects.\r
721 @param [in] NodeCount Number of ITS Group Node Objects.\r
722\r
723 @retval EFI_SUCCESS Table generated successfully.\r
724 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
725 @retval EFI_NOT_FOUND The required object was not found.\r
726**/\r
727STATIC\r
728EFI_STATUS\r
729AddItsGroupNodes (\r
731c67e1
MK
730 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
731 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
732 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 733 IN CONST UINT32 NodesStartOffset,\r
731c67e1 734 IN CONST CM_ARM_ITS_GROUP_NODE *NodeList,\r
dfaffc69
SM
735 IN UINT32 NodeCount\r
736 )\r
737{\r
731c67e1
MK
738 EFI_STATUS Status;\r
739 EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *ItsGroupNode;\r
740 UINT32 *ItsIds;\r
741 CM_ARM_ITS_IDENTIFIER *ItsIdentifier;\r
742 UINT32 ItsIdentifierCount;\r
743 UINT32 IdIndex;\r
744 UINT64 NodeLength;\r
dfaffc69
SM
745\r
746 ASSERT (Iort != NULL);\r
747\r
731c67e1
MK
748 ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *)((UINT8 *)Iort +\r
749 NodesStartOffset);\r
dfaffc69
SM
750\r
751 while (NodeCount-- != 0) {\r
8b2ac43b
SM
752 NodeLength = GetItsGroupNodeSize (NodeList);\r
753 if (NodeLength > MAX_UINT16) {\r
754 Status = EFI_INVALID_PARAMETER;\r
755 DEBUG ((\r
756 DEBUG_ERROR,\r
757 "ERROR: IORT: ITS Id Array Node length 0x%lx > MAX_UINT16."\r
758 " Status = %r\n",\r
759 NodeLength,\r
760 Status\r
761 ));\r
762 return Status;\r
763 }\r
764\r
dfaffc69 765 // Populate the node header\r
731c67e1
MK
766 ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP;\r
767 ItsGroupNode->Node.Length = (UINT16)NodeLength;\r
768 ItsGroupNode->Node.Revision = 0;\r
769 ItsGroupNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69 770 ItsGroupNode->Node.NumIdMappings = 0;\r
731c67e1 771 ItsGroupNode->Node.IdReference = 0;\r
dfaffc69
SM
772\r
773 // IORT specific data\r
774 ItsGroupNode->NumItsIdentifiers = NodeList->ItsIdCount;\r
731c67e1
MK
775 ItsIds = (UINT32 *)((UINT8 *)ItsGroupNode +\r
776 sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE));\r
dfaffc69
SM
777\r
778 Status = GetEArmObjGicItsIdentifierArray (\r
779 CfgMgrProtocol,\r
780 NodeList->ItsIdToken,\r
781 &ItsIdentifier,\r
782 &ItsIdentifierCount\r
783 );\r
784 if (EFI_ERROR (Status)) {\r
785 DEBUG ((\r
786 DEBUG_ERROR,\r
787 "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",\r
788 Status\r
789 ));\r
790 return Status;\r
791 }\r
792\r
793 if (ItsIdentifierCount < ItsGroupNode->NumItsIdentifiers) {\r
794 DEBUG ((\r
795 DEBUG_ERROR,\r
796 "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"\r
797 ));\r
798 return EFI_NOT_FOUND;\r
799 }\r
800\r
801 // Populate the ITS identifier array\r
802 for (IdIndex = 0; IdIndex < ItsGroupNode->NumItsIdentifiers; IdIndex++) {\r
803 ItsIds[IdIndex] = ItsIdentifier[IdIndex].ItsId;\r
804 } // ITS identifier array\r
805\r
806 // Next IORT Group Node\r
731c67e1
MK
807 ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *)((UINT8 *)ItsGroupNode +\r
808 ItsGroupNode->Node.Length);\r
dfaffc69
SM
809 NodeList++;\r
810 } // IORT Group Node\r
811\r
812 return EFI_SUCCESS;\r
813}\r
814\r
815/** Update the Named Component Node Information.\r
816\r
817 This function updates the Named Component node information in the IORT\r
818 table.\r
819\r
820 @param [in] This Pointer to the table Generator.\r
821 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
822 Protocol Interface.\r
823 @param [in] Iort Pointer to IORT table structure.\r
824 @param [in] NodesStartOffset Offset for the start of the Named\r
825 Component Nodes.\r
826 @param [in] NodeList Pointer to an array of Named Component\r
827 Node Objects.\r
828 @param [in] NodeCount Number of Named Component Node Objects.\r
829\r
830 @retval EFI_SUCCESS Table generated successfully.\r
831 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
832 @retval EFI_NOT_FOUND The required object was not found.\r
833**/\r
834STATIC\r
835EFI_STATUS\r
836AddNamedComponentNodes (\r
731c67e1
MK
837 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
838 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
839 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 840 IN CONST UINT32 NodesStartOffset,\r
731c67e1 841 IN CONST CM_ARM_NAMED_COMPONENT_NODE *NodeList,\r
dfaffc69
SM
842 IN UINT32 NodeCount\r
843 )\r
844{\r
731c67e1
MK
845 EFI_STATUS Status;\r
846 EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *NcNode;\r
847 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;\r
848 CHAR8 *ObjectName;\r
849 UINTN ObjectNameLength;\r
850 UINT64 NodeLength;\r
dfaffc69
SM
851\r
852 ASSERT (Iort != NULL);\r
853\r
731c67e1
MK
854 NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *)((UINT8 *)Iort +\r
855 NodesStartOffset);\r
dfaffc69
SM
856\r
857 while (NodeCount-- != 0) {\r
8b2ac43b
SM
858 NodeLength = GetNamedComponentNodeSize (NodeList);\r
859 if (NodeLength > MAX_UINT16) {\r
860 Status = EFI_INVALID_PARAMETER;\r
861 DEBUG ((\r
862 DEBUG_ERROR,\r
863 "ERROR: IORT: Named Component Node length 0x%lx > MAX_UINT16."\r
864 " Status = %r\n",\r
865 NodeLength,\r
866 Status\r
867 ));\r
868 return Status;\r
869 }\r
870\r
dfaffc69 871 // Populate the node header\r
731c67e1
MK
872 NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP;\r
873 NcNode->Node.Length = (UINT16)NodeLength;\r
874 NcNode->Node.Revision = 2;\r
875 NcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69
SM
876 NcNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
877\r
731c67e1 878 ObjectNameLength = AsciiStrLen (NodeList->ObjectName) + 1;\r
f5cea604
SM
879 NcNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?\r
880 0 : ((UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +\r
881 (ALIGN_VALUE (ObjectNameLength, 4))));\r
dfaffc69
SM
882\r
883 // Named Component specific data\r
731c67e1
MK
884 NcNode->Flags = NodeList->Flags;\r
885 NcNode->CacheCoherent = NodeList->CacheCoherent;\r
886 NcNode->AllocationHints = NodeList->AllocationHints;\r
887 NcNode->Reserved = EFI_ACPI_RESERVED_WORD;\r
dfaffc69 888 NcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;\r
731c67e1 889 NcNode->AddressSizeLimit = NodeList->AddressSizeLimit;\r
dfaffc69
SM
890\r
891 // Copy the object name\r
731c67e1
MK
892 ObjectName = (CHAR8 *)((UINT8 *)NcNode +\r
893 sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE));\r
dfaffc69
SM
894 Status = AsciiStrCpyS (\r
895 ObjectName,\r
8b2ac43b 896 ObjectNameLength,\r
dfaffc69
SM
897 NodeList->ObjectName\r
898 );\r
899 if (EFI_ERROR (Status)) {\r
900 DEBUG ((\r
901 DEBUG_ERROR,\r
902 "ERROR: IORT: Failed to copy Object Name. Status = %r\n",\r
903 Status\r
904 ));\r
905 return Status;\r
906 }\r
907\r
65c4f3f2
SM
908 if (NodeList->IdMappingCount > 0) {\r
909 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
910 Status = EFI_INVALID_PARAMETER;\r
911 DEBUG ((\r
912 DEBUG_ERROR,\r
913 "ERROR: IORT: Invalid Id Mapping token,"\r
914 " Token = 0x%x, Status =%r\n",\r
915 NodeList->IdMappingToken,\r
916 Status\r
917 ));\r
918 return Status;\r
919 }\r
920\r
dfaffc69 921 // Ids for Named Component\r
731c67e1
MK
922 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)NcNode +\r
923 NcNode->Node.IdReference);\r
dfaffc69
SM
924\r
925 Status = AddIdMappingArray (\r
926 This,\r
927 CfgMgrProtocol,\r
928 IdMapArray,\r
929 NodeList->IdMappingCount,\r
930 NodeList->IdMappingToken\r
931 );\r
932 if (EFI_ERROR (Status)) {\r
933 DEBUG ((\r
934 DEBUG_ERROR,\r
935 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
936 Status\r
937 ));\r
938 return Status;\r
939 }\r
940 }\r
941\r
942 // Next Named Component Node\r
731c67e1
MK
943 NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *)((UINT8 *)NcNode +\r
944 NcNode->Node.Length);\r
dfaffc69
SM
945 NodeList++;\r
946 } // Named Component Node\r
947\r
948 return EFI_SUCCESS;\r
949}\r
950\r
951/** Update the Root Complex Node Information.\r
952\r
953 This function updates the Root Complex node information in the IORT table.\r
954\r
955 @param [in] This Pointer to the table Generator.\r
956 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
957 Protocol Interface.\r
958 @param [in] Iort Pointer to IORT table structure.\r
959 @param [in] NodesStartOffset Offset for the start of the Root Complex\r
960 Nodes.\r
961 @param [in] NodeList Pointer to an array of Root Complex Node\r
962 Objects.\r
963 @param [in] NodeCount Number of Root Complex Node Objects.\r
964\r
965 @retval EFI_SUCCESS Table generated successfully.\r
966 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
967 @retval EFI_NOT_FOUND The required object was not found.\r
968**/\r
969STATIC\r
970EFI_STATUS\r
971AddRootComplexNodes (\r
731c67e1
MK
972 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
973 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
974 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 975 IN CONST UINT32 NodesStartOffset,\r
731c67e1 976 IN CONST CM_ARM_ROOT_COMPLEX_NODE *NodeList,\r
dfaffc69
SM
977 IN UINT32 NodeCount\r
978 )\r
979{\r
731c67e1
MK
980 EFI_STATUS Status;\r
981 EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *RcNode;\r
982 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;\r
983 UINT64 NodeLength;\r
dfaffc69
SM
984\r
985 ASSERT (Iort != NULL);\r
986\r
731c67e1
MK
987 RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *)((UINT8 *)Iort +\r
988 NodesStartOffset);\r
dfaffc69
SM
989\r
990 while (NodeCount-- != 0) {\r
8b2ac43b
SM
991 NodeLength = GetRootComplexNodeSize (NodeList);\r
992 if (NodeLength > MAX_UINT16) {\r
993 Status = EFI_INVALID_PARAMETER;\r
994 DEBUG ((\r
995 DEBUG_ERROR,\r
996 "ERROR: IORT: Root Complex Node length 0x%lx > MAX_UINT16."\r
997 " Status = %r\n",\r
998 NodeLength,\r
999 Status\r
1000 ));\r
1001 return Status;\r
1002 }\r
1003\r
dfaffc69 1004 // Populate the node header\r
731c67e1
MK
1005 RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX;\r
1006 RcNode->Node.Length = (UINT16)NodeLength;\r
1007 RcNode->Node.Revision = 1;\r
1008 RcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69 1009 RcNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
f5cea604
SM
1010 RcNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?\r
1011 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);\r
dfaffc69
SM
1012\r
1013 // Root Complex specific data\r
731c67e1
MK
1014 RcNode->CacheCoherent = NodeList->CacheCoherent;\r
1015 RcNode->AllocationHints = NodeList->AllocationHints;\r
1016 RcNode->Reserved = EFI_ACPI_RESERVED_WORD;\r
dfaffc69 1017 RcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;\r
731c67e1
MK
1018 RcNode->AtsAttribute = NodeList->AtsAttribute;\r
1019 RcNode->PciSegmentNumber = NodeList->PciSegmentNumber;\r
dfaffc69 1020 RcNode->MemoryAddressSize = NodeList->MemoryAddressSize;\r
731c67e1
MK
1021 RcNode->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;\r
1022 RcNode->Reserved1[1] = EFI_ACPI_RESERVED_BYTE;\r
1023 RcNode->Reserved1[2] = EFI_ACPI_RESERVED_BYTE;\r
dfaffc69 1024\r
65c4f3f2
SM
1025 if (NodeList->IdMappingCount > 0) {\r
1026 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
1027 Status = EFI_INVALID_PARAMETER;\r
1028 DEBUG ((\r
1029 DEBUG_ERROR,\r
1030 "ERROR: IORT: Invalid Id Mapping token,"\r
1031 " Token = 0x%x, Status =%r\n",\r
1032 NodeList->IdMappingToken,\r
1033 Status\r
1034 ));\r
1035 return Status;\r
1036 }\r
1037\r
dfaffc69 1038 // Ids for Root Complex\r
731c67e1
MK
1039 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)RcNode +\r
1040 RcNode->Node.IdReference);\r
dfaffc69
SM
1041 Status = AddIdMappingArray (\r
1042 This,\r
1043 CfgMgrProtocol,\r
1044 IdMapArray,\r
1045 NodeList->IdMappingCount,\r
1046 NodeList->IdMappingToken\r
1047 );\r
1048 if (EFI_ERROR (Status)) {\r
1049 DEBUG ((\r
1050 DEBUG_ERROR,\r
1051 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
1052 Status\r
1053 ));\r
1054 return Status;\r
1055 }\r
1056 }\r
1057\r
1058 // Next Root Complex Node\r
731c67e1
MK
1059 RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *)((UINT8 *)RcNode +\r
1060 RcNode->Node.Length);\r
dfaffc69
SM
1061 NodeList++;\r
1062 } // Root Complex Node\r
1063\r
1064 return EFI_SUCCESS;\r
1065}\r
1066\r
1067/** Update the SMMU Interrupt Array.\r
1068\r
1069 This function retrieves the InterruptArray object referenced by the\r
1070 InterruptToken and updates the SMMU InterruptArray.\r
1071\r
1072 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1073 Protocol Interface.\r
1074 @param [in, out] InterruptArray Pointer to an array of Interrupts.\r
1075 @param [in] InterruptCount Number of entries in the InterruptArray.\r
1076 @param [in] InterruptToken Reference Token for retrieving the SMMU\r
1077 InterruptArray object.\r
1078\r
1079 @retval EFI_SUCCESS Table generated successfully.\r
1080 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1081 @retval EFI_NOT_FOUND The required object was not found.\r
1082**/\r
1083STATIC\r
1084EFI_STATUS\r
e3f8605a 1085AddSmmuInterruptArray (\r
731c67e1
MK
1086 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1087 IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *InterruptArray,\r
dfaffc69
SM
1088 IN UINT32 InterruptCount,\r
1089 IN CONST CM_OBJECT_TOKEN InterruptToken\r
1090 )\r
1091{\r
731c67e1
MK
1092 EFI_STATUS Status;\r
1093 CM_ARM_SMMU_INTERRUPT *SmmuInterrupt;\r
1094 UINT32 SmmuInterruptCount;\r
dfaffc69
SM
1095\r
1096 ASSERT (InterruptArray != NULL);\r
1097\r
1098 // Get the SMMU Interrupt Array\r
1099 Status = GetEArmObjSmmuInterruptArray (\r
1100 CfgMgrProtocol,\r
1101 InterruptToken,\r
1102 &SmmuInterrupt,\r
1103 &SmmuInterruptCount\r
1104 );\r
1105 if (EFI_ERROR (Status)) {\r
1106 DEBUG ((\r
1107 DEBUG_ERROR,\r
1108 "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",\r
1109 Status\r
1110 ));\r
1111 return Status;\r
1112 }\r
1113\r
1114 if (SmmuInterruptCount < InterruptCount) {\r
1115 DEBUG ((\r
1116 DEBUG_ERROR,\r
1117 "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"\r
1118 ));\r
1119 return EFI_NOT_FOUND;\r
1120 }\r
1121\r
1122 // Populate the Id Mapping array\r
1123 while (InterruptCount-- != 0) {\r
731c67e1 1124 InterruptArray->Interrupt = SmmuInterrupt->Interrupt;\r
dfaffc69
SM
1125 InterruptArray->InterruptFlags = SmmuInterrupt->Flags;\r
1126 InterruptArray++;\r
1127 SmmuInterrupt++;\r
1128 } // Id Mapping array\r
1129\r
1130 return EFI_SUCCESS;\r
1131}\r
1132\r
1133/** Update the SMMU v1/v2 Node Information.\r
1134\r
1135 @param [in] This Pointer to the table Generator.\r
1136 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1137 Protocol Interface.\r
1138 @param [in] Iort Pointer to IORT table structure.\r
1139 @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2\r
1140 Nodes.\r
1141 @param [in] NodeList Pointer to an array of SMMU v1/v2 Node\r
1142 Objects.\r
1143 @param [in] NodeCount Number of SMMU v1/v2 Node Objects.\r
1144\r
1145 @retval EFI_SUCCESS Table generated successfully.\r
1146 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1147 @retval EFI_NOT_FOUND The required object was not found.\r
1148**/\r
1149STATIC\r
1150EFI_STATUS\r
1151AddSmmuV1V2Nodes (\r
731c67e1
MK
1152 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1153 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1154 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 1155 IN CONST UINT32 NodesStartOffset,\r
731c67e1 1156 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *NodeList,\r
dfaffc69
SM
1157 IN UINT32 NodeCount\r
1158 )\r
1159{\r
731c67e1
MK
1160 EFI_STATUS Status;\r
1161 EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *SmmuNode;\r
1162 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;\r
dfaffc69 1163\r
731c67e1
MK
1164 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *ContextInterruptArray;\r
1165 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *PmuInterruptArray;\r
1166 UINT64 NodeLength;\r
dfaffc69
SM
1167\r
1168 ASSERT (Iort != NULL);\r
1169\r
731c67e1
MK
1170 SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *)((UINT8 *)Iort +\r
1171 NodesStartOffset);\r
dfaffc69
SM
1172\r
1173 while (NodeCount-- != 0) {\r
8b2ac43b
SM
1174 NodeLength = GetSmmuV1V2NodeSize (NodeList);\r
1175 if (NodeLength > MAX_UINT16) {\r
1176 Status = EFI_INVALID_PARAMETER;\r
1177 DEBUG ((\r
1178 DEBUG_ERROR,\r
1179 "ERROR: IORT: SMMU V1/V2 Node length 0x%lx > MAX_UINT16. Status = %r\n",\r
1180 NodeLength,\r
1181 Status\r
1182 ));\r
1183 return Status;\r
1184 }\r
1185\r
dfaffc69 1186 // Populate the node header\r
731c67e1
MK
1187 SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2;\r
1188 SmmuNode->Node.Length = (UINT16)NodeLength;\r
1189 SmmuNode->Node.Revision = 0;\r
1190 SmmuNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69 1191 SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
f5cea604
SM
1192 SmmuNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?\r
1193 0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +\r
1194 (NodeList->ContextInterruptCount *\r
1195 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +\r
1196 (NodeList->PmuInterruptCount *\r
1197 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)));\r
dfaffc69
SM
1198\r
1199 // SMMU v1/v2 specific data\r
731c67e1
MK
1200 SmmuNode->Base = NodeList->BaseAddress;\r
1201 SmmuNode->Span = NodeList->Span;\r
dfaffc69
SM
1202 SmmuNode->Model = NodeList->Model;\r
1203 SmmuNode->Flags = NodeList->Flags;\r
1204\r
1205 // Reference to Global Interrupt Array\r
1206 SmmuNode->GlobalInterruptArrayRef =\r
1207 OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE, SMMU_NSgIrpt);\r
1208\r
1209 // Context Interrupt\r
731c67e1 1210 SmmuNode->NumContextInterrupts = NodeList->ContextInterruptCount;\r
dfaffc69
SM
1211 SmmuNode->ContextInterruptArrayRef =\r
1212 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);\r
1213 ContextInterruptArray =\r
731c67e1
MK
1214 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode +\r
1215 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE));\r
dfaffc69
SM
1216\r
1217 // PMU Interrupt\r
731c67e1 1218 SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;\r
dfaffc69 1219 SmmuNode->PmuInterruptArrayRef = SmmuNode->ContextInterruptArrayRef +\r
731c67e1
MK
1220 (NodeList->ContextInterruptCount *\r
1221 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));\r
dfaffc69 1222 PmuInterruptArray =\r
731c67e1
MK
1223 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode +\r
1224 SmmuNode->PmuInterruptArrayRef);\r
dfaffc69 1225\r
731c67e1
MK
1226 SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt;\r
1227 SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags;\r
1228 SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt;\r
dfaffc69
SM
1229 SmmuNode->SMMU_NSgCfgIrptFlags = NodeList->SMMU_NSgCfgIrptFlags;\r
1230\r
1231 // Add Context Interrupt Array\r
e3f8605a 1232 Status = AddSmmuInterruptArray (\r
dfaffc69
SM
1233 CfgMgrProtocol,\r
1234 ContextInterruptArray,\r
1235 SmmuNode->NumContextInterrupts,\r
1236 NodeList->ContextInterruptToken\r
1237 );\r
1238 if (EFI_ERROR (Status)) {\r
1239 DEBUG ((\r
1240 DEBUG_ERROR,\r
1241 "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",\r
1242 Status\r
1243 ));\r
1244 return Status;\r
1245 }\r
1246\r
1247 // Add PMU Interrupt Array\r
1248 if ((SmmuNode->NumPmuInterrupts > 0) &&\r
731c67e1
MK
1249 (NodeList->PmuInterruptToken != CM_NULL_TOKEN))\r
1250 {\r
e3f8605a 1251 Status = AddSmmuInterruptArray (\r
dfaffc69
SM
1252 CfgMgrProtocol,\r
1253 PmuInterruptArray,\r
1254 SmmuNode->NumPmuInterrupts,\r
1255 NodeList->PmuInterruptToken\r
1256 );\r
1257 if (EFI_ERROR (Status)) {\r
1258 DEBUG ((\r
1259 DEBUG_ERROR,\r
1260 "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",\r
1261 Status\r
1262 ));\r
1263 return Status;\r
1264 }\r
1265 }\r
1266\r
65c4f3f2
SM
1267 if (NodeList->IdMappingCount > 0) {\r
1268 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
1269 Status = EFI_INVALID_PARAMETER;\r
1270 DEBUG ((\r
1271 DEBUG_ERROR,\r
1272 "ERROR: IORT: Invalid Id Mapping token,"\r
1273 " Token = 0x%x, Status =%r\n",\r
1274 NodeList->IdMappingToken,\r
1275 Status\r
1276 ));\r
1277 return Status;\r
1278 }\r
1279\r
dfaffc69 1280 // Ids for SMMU v1/v2 Node\r
731c67e1
MK
1281 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)SmmuNode +\r
1282 SmmuNode->Node.IdReference);\r
dfaffc69
SM
1283 Status = AddIdMappingArray (\r
1284 This,\r
1285 CfgMgrProtocol,\r
1286 IdMapArray,\r
1287 NodeList->IdMappingCount,\r
1288 NodeList->IdMappingToken\r
1289 );\r
1290 if (EFI_ERROR (Status)) {\r
1291 DEBUG ((\r
1292 DEBUG_ERROR,\r
1293 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
1294 Status\r
1295 ));\r
1296 return Status;\r
1297 }\r
1298 }\r
731c67e1 1299\r
dfaffc69 1300 // Next SMMU v1/v2 Node\r
731c67e1
MK
1301 SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *)((UINT8 *)SmmuNode +\r
1302 SmmuNode->Node.Length);\r
dfaffc69
SM
1303 NodeList++;\r
1304 } // SMMU v1/v2 Node\r
1305\r
1306 return EFI_SUCCESS;\r
1307}\r
1308\r
1309/** Update the SMMUv3 Node Information.\r
1310\r
1311 This function updates the SMMUv3 node information in the IORT table.\r
1312\r
1313 @param [in] This Pointer to the table Generator.\r
1314 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1315 Protocol Interface.\r
1316 @param [in] Iort Pointer to IORT table structure.\r
1317 @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.\r
1318 @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.\r
1319 @param [in] NodeCount Number of SMMUv3 Node Objects.\r
1320\r
1321 @retval EFI_SUCCESS Table generated successfully.\r
1322 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1323 @retval EFI_NOT_FOUND The required object was not found.\r
1324**/\r
1325STATIC\r
1326EFI_STATUS\r
1327AddSmmuV3Nodes (\r
731c67e1
MK
1328 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1329 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1330 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 1331 IN CONST UINT32 NodesStartOffset,\r
731c67e1 1332 IN CONST CM_ARM_SMMUV3_NODE *NodeList,\r
dfaffc69
SM
1333 IN UINT32 NodeCount\r
1334 )\r
1335{\r
731c67e1
MK
1336 EFI_STATUS Status;\r
1337 EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *SmmuV3Node;\r
1338 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;\r
1339 UINT64 NodeLength;\r
dfaffc69
SM
1340\r
1341 ASSERT (Iort != NULL);\r
1342\r
731c67e1
MK
1343 SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)Iort +\r
1344 NodesStartOffset);\r
dfaffc69
SM
1345\r
1346 while (NodeCount-- != 0) {\r
8b2ac43b
SM
1347 NodeLength = GetSmmuV3NodeSize (NodeList);\r
1348 if (NodeLength > MAX_UINT16) {\r
1349 Status = EFI_INVALID_PARAMETER;\r
1350 DEBUG ((\r
1351 DEBUG_ERROR,\r
1352 "ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n",\r
1353 NodeLength,\r
1354 Status\r
1355 ));\r
1356 return Status;\r
1357 }\r
1358\r
dfaffc69 1359 // Populate the node header\r
731c67e1
MK
1360 SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;\r
1361 SmmuV3Node->Node.Length = (UINT16)NodeLength;\r
1362 SmmuV3Node->Node.Revision = 2;\r
1363 SmmuV3Node->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69 1364 SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount;\r
f5cea604
SM
1365 SmmuV3Node->Node.IdReference = (NodeList->IdMappingCount == 0) ?\r
1366 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);\r
dfaffc69
SM
1367\r
1368 // SMMUv3 specific data\r
731c67e1
MK
1369 SmmuV3Node->Base = NodeList->BaseAddress;\r
1370 SmmuV3Node->Flags = NodeList->Flags;\r
1371 SmmuV3Node->Reserved = EFI_ACPI_RESERVED_WORD;\r
dfaffc69 1372 SmmuV3Node->VatosAddress = NodeList->VatosAddress;\r
731c67e1
MK
1373 SmmuV3Node->Model = NodeList->Model;\r
1374 SmmuV3Node->Event = NodeList->EventInterrupt;\r
1375 SmmuV3Node->Pri = NodeList->PriInterrupt;\r
1376 SmmuV3Node->Gerr = NodeList->GerrInterrupt;\r
1377 SmmuV3Node->Sync = NodeList->SyncInterrupt;\r
dfaffc69
SM
1378\r
1379 if ((SmmuV3Node->Flags & EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN) != 0) {\r
1380 // The Proximity Domain Valid flag is set to 1\r
1381 SmmuV3Node->ProximityDomain = NodeList->ProximityDomain;\r
1382 } else {\r
1383 SmmuV3Node->ProximityDomain = 0;\r
1384 }\r
1385\r
1386 if ((SmmuV3Node->Event != 0) && (SmmuV3Node->Pri != 0) &&\r
731c67e1
MK
1387 (SmmuV3Node->Gerr != 0) && (SmmuV3Node->Sync != 0))\r
1388 {\r
dfaffc69
SM
1389 // If all the SMMU control interrupts are GSIV based,\r
1390 // the DeviceID mapping index field is ignored.\r
1391 SmmuV3Node->DeviceIdMappingIndex = 0;\r
1392 } else {\r
1393 SmmuV3Node->DeviceIdMappingIndex = NodeList->DeviceIdMappingIndex;\r
1394 }\r
1395\r
65c4f3f2
SM
1396 if (NodeList->IdMappingCount > 0) {\r
1397 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
1398 Status = EFI_INVALID_PARAMETER;\r
1399 DEBUG ((\r
1400 DEBUG_ERROR,\r
1401 "ERROR: IORT: Invalid Id Mapping token,"\r
1402 " Token = 0x%x, Status =%r\n",\r
1403 NodeList->IdMappingToken,\r
1404 Status\r
1405 ));\r
1406 return Status;\r
1407 }\r
1408\r
dfaffc69 1409 // Ids for SMMUv3 node\r
731c67e1
MK
1410 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)SmmuV3Node +\r
1411 SmmuV3Node->Node.IdReference);\r
dfaffc69
SM
1412 Status = AddIdMappingArray (\r
1413 This,\r
1414 CfgMgrProtocol,\r
1415 IdMapArray,\r
1416 NodeList->IdMappingCount,\r
1417 NodeList->IdMappingToken\r
1418 );\r
1419 if (EFI_ERROR (Status)) {\r
1420 DEBUG ((\r
1421 DEBUG_ERROR,\r
1422 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
1423 Status\r
1424 ));\r
1425 return Status;\r
1426 }\r
1427 }\r
1428\r
1429 // Next SMMUv3 Node\r
731c67e1
MK
1430 SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)SmmuV3Node +\r
1431 SmmuV3Node->Node.Length);\r
dfaffc69
SM
1432 NodeList++;\r
1433 } // SMMUv3 Node\r
1434\r
1435 return EFI_SUCCESS;\r
1436}\r
1437\r
1438/** Update the PMCG Node Information.\r
1439\r
1440 This function updates the PMCG node information in the IORT table.\r
1441\r
1442 @param [in] This Pointer to the table Generator.\r
1443 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1444 Protocol Interface.\r
1445 @param [in] Iort Pointer to IORT table structure.\r
1446 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.\r
1447 @param [in] NodeList Pointer to an array of PMCG Node Objects.\r
1448 @param [in] NodeCount Number of PMCG Node Objects.\r
1449\r
1450 @retval EFI_SUCCESS Table generated successfully.\r
1451 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1452 @retval EFI_NOT_FOUND The required object was not found.\r
1453**/\r
1454STATIC\r
1455EFI_STATUS\r
1456AddPmcgNodes (\r
731c67e1
MK
1457 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1458 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1459 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 1460 IN CONST UINT32 NodesStartOffset,\r
731c67e1 1461 IN CONST CM_ARM_PMCG_NODE *NodeList,\r
dfaffc69
SM
1462 IN UINT32 NodeCount\r
1463 )\r
1464{\r
731c67e1
MK
1465 EFI_STATUS Status;\r
1466 EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *PmcgNode;\r
1467 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;\r
1468 ACPI_IORT_GENERATOR *Generator;\r
1469 UINT64 NodeLength;\r
dfaffc69
SM
1470\r
1471 ASSERT (Iort != NULL);\r
1472\r
731c67e1
MK
1473 Generator = (ACPI_IORT_GENERATOR *)This;\r
1474 PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)Iort +\r
1475 NodesStartOffset);\r
dfaffc69
SM
1476\r
1477 while (NodeCount-- != 0) {\r
8b2ac43b
SM
1478 NodeLength = GetPmcgNodeSize (NodeList);\r
1479 if (NodeLength > MAX_UINT16) {\r
1480 Status = EFI_INVALID_PARAMETER;\r
1481 DEBUG ((\r
1482 DEBUG_ERROR,\r
1483 "ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n",\r
1484 NodeLength,\r
1485 Status\r
1486 ));\r
1487 return Status;\r
1488 }\r
1489\r
dfaffc69 1490 // Populate the node header\r
731c67e1
MK
1491 PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;\r
1492 PmcgNode->Node.Length = (UINT16)NodeLength;\r
1493 PmcgNode->Node.Revision = 1;\r
1494 PmcgNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69 1495 PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
f5cea604
SM
1496 PmcgNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?\r
1497 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);\r
dfaffc69
SM
1498\r
1499 // PMCG specific data\r
731c67e1 1500 PmcgNode->Base = NodeList->BaseAddress;\r
dfaffc69 1501 PmcgNode->OverflowInterruptGsiv = NodeList->OverflowInterrupt;\r
731c67e1 1502 PmcgNode->Page1Base = NodeList->Page1BaseAddress;\r
dfaffc69
SM
1503\r
1504 Status = GetNodeOffsetReferencedByToken (\r
731c67e1
MK
1505 Generator->NodeIndexer,\r
1506 Generator->IortNodeCount,\r
1507 NodeList->ReferenceToken,\r
1508 &PmcgNode->NodeReference\r
1509 );\r
dfaffc69
SM
1510 if (EFI_ERROR (Status)) {\r
1511 DEBUG ((\r
1512 DEBUG_ERROR,\r
1513 "ERROR: IORT: Failed to get Output Reference for PMCG Node."\r
1514 "Reference Token = %p"\r
1515 " Status = %r\n",\r
1516 NodeList->ReferenceToken,\r
1517 Status\r
1518 ));\r
1519 return Status;\r
1520 }\r
1521\r
65c4f3f2
SM
1522 if (NodeList->IdMappingCount > 0) {\r
1523 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
1524 Status = EFI_INVALID_PARAMETER;\r
1525 DEBUG ((\r
1526 DEBUG_ERROR,\r
1527 "ERROR: IORT: Invalid Id Mapping token,"\r
1528 " Token = 0x%x, Status =%r\n",\r
1529 NodeList->IdMappingToken,\r
1530 Status\r
1531 ));\r
1532 return Status;\r
1533 }\r
1534\r
dfaffc69 1535 // Ids for PMCG node\r
731c67e1
MK
1536 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)PmcgNode +\r
1537 PmcgNode->Node.IdReference);\r
dfaffc69
SM
1538\r
1539 Status = AddIdMappingArray (\r
731c67e1
MK
1540 This,\r
1541 CfgMgrProtocol,\r
1542 IdMapArray,\r
1543 NodeList->IdMappingCount,\r
1544 NodeList->IdMappingToken\r
1545 );\r
dfaffc69
SM
1546 if (EFI_ERROR (Status)) {\r
1547 DEBUG ((\r
1548 DEBUG_ERROR,\r
1549 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
1550 Status\r
1551 ));\r
1552 return Status;\r
1553 }\r
1554 }\r
1555\r
1556 // Next PMCG Node\r
731c67e1
MK
1557 PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)PmcgNode +\r
1558 PmcgNode->Node.Length);\r
dfaffc69
SM
1559 NodeList++;\r
1560 } // PMCG Node\r
1561\r
1562 return EFI_SUCCESS;\r
1563}\r
1564\r
1565/** Construct the IORT ACPI table.\r
1566\r
1567 This function invokes the Configuration Manager protocol interface\r
1568 to get the required hardware information for generating the ACPI\r
1569 table.\r
1570\r
1571 If this function allocates any resources then they must be freed\r
1572 in the FreeXXXXTableResources function.\r
1573\r
1574 @param [in] This Pointer to the table generator.\r
1575 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
1576 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1577 Protocol Interface.\r
1578 @param [out] Table Pointer to the constructed ACPI Table.\r
1579\r
1580 @retval EFI_SUCCESS Table generated successfully.\r
1581 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1582 @retval EFI_NOT_FOUND The required object was not found.\r
1583 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
1584 Manager is less than the Object size for the\r
1585 requested object.\r
1586**/\r
1587STATIC\r
1588EFI_STATUS\r
1589EFIAPI\r
1590BuildIortTable (\r
731c67e1
MK
1591 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1592 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,\r
1593 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1594 OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table\r
dfaffc69
SM
1595 )\r
1596{\r
731c67e1
MK
1597 EFI_STATUS Status;\r
1598\r
1599 UINT64 TableSize;\r
1600 UINT64 NodeSize;\r
1601\r
1602 UINT32 IortNodeCount;\r
1603 UINT32 ItsGroupNodeCount;\r
1604 UINT32 NamedComponentNodeCount;\r
1605 UINT32 RootComplexNodeCount;\r
1606 UINT32 SmmuV1V2NodeCount;\r
1607 UINT32 SmmuV3NodeCount;\r
1608 UINT32 PmcgNodeCount;\r
1609\r
1610 UINT32 ItsGroupOffset;\r
1611 UINT32 NamedComponentOffset;\r
1612 UINT32 RootComplexOffset;\r
1613 UINT32 SmmuV1V2Offset;\r
1614 UINT32 SmmuV3Offset;\r
1615 UINT32 PmcgOffset;\r
1616\r
1617 CM_ARM_ITS_GROUP_NODE *ItsGroupNodeList;\r
1618 CM_ARM_NAMED_COMPONENT_NODE *NamedComponentNodeList;\r
1619 CM_ARM_ROOT_COMPLEX_NODE *RootComplexNodeList;\r
1620 CM_ARM_SMMUV1_SMMUV2_NODE *SmmuV1V2NodeList;\r
1621 CM_ARM_SMMUV3_NODE *SmmuV3NodeList;\r
1622 CM_ARM_PMCG_NODE *PmcgNodeList;\r
1623\r
1624 EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort;\r
1625 IORT_NODE_INDEXER *NodeIndexer;\r
1626 ACPI_IORT_GENERATOR *Generator;\r
dfaffc69
SM
1627\r
1628 ASSERT (This != NULL);\r
1629 ASSERT (AcpiTableInfo != NULL);\r
1630 ASSERT (CfgMgrProtocol != NULL);\r
1631 ASSERT (Table != NULL);\r
1632 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
1633 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
1634\r
1635 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
731c67e1
MK
1636 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision))\r
1637 {\r
dfaffc69
SM
1638 DEBUG ((\r
1639 DEBUG_ERROR,\r
1640 "ERROR: IORT: Requested table revision = %d, is not supported."\r
1641 "Supported table revision: Minimum = %d, Maximum = %d\n",\r
1642 AcpiTableInfo->AcpiTableRevision,\r
1643 This->MinAcpiTableRevision,\r
1644 This->AcpiTableRevision\r
1645 ));\r
1646 return EFI_INVALID_PARAMETER;\r
1647 }\r
1648\r
731c67e1
MK
1649 Generator = (ACPI_IORT_GENERATOR *)This;\r
1650 *Table = NULL;\r
dfaffc69
SM
1651\r
1652 // Get the ITS group node info\r
1653 Status = GetEArmObjItsGroup (\r
1654 CfgMgrProtocol,\r
1655 CM_NULL_TOKEN,\r
1656 &ItsGroupNodeList,\r
1657 &ItsGroupNodeCount\r
1658 );\r
1659 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1660 DEBUG ((\r
1661 DEBUG_ERROR,\r
1662 "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",\r
1663 Status\r
1664 ));\r
1665 goto error_handler;\r
1666 }\r
1667\r
1668 // Add the ITS group node count\r
1669 IortNodeCount = ItsGroupNodeCount;\r
1670\r
1671 // Get the Named component node info\r
1672 Status = GetEArmObjNamedComponent (\r
1673 CfgMgrProtocol,\r
1674 CM_NULL_TOKEN,\r
1675 &NamedComponentNodeList,\r
1676 &NamedComponentNodeCount\r
1677 );\r
1678 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1679 DEBUG ((\r
1680 DEBUG_ERROR,\r
1681 "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",\r
1682 Status\r
1683 ));\r
1684 goto error_handler;\r
1685 }\r
1686\r
1687 // Add the Named Component group count\r
1688 IortNodeCount += NamedComponentNodeCount;\r
1689\r
1690 // Get the Root complex node info\r
1691 Status = GetEArmObjRootComplex (\r
1692 CfgMgrProtocol,\r
1693 CM_NULL_TOKEN,\r
1694 &RootComplexNodeList,\r
1695 &RootComplexNodeCount\r
1696 );\r
1697 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1698 DEBUG ((\r
1699 DEBUG_ERROR,\r
1700 "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",\r
1701 Status\r
1702 ));\r
1703 goto error_handler;\r
1704 }\r
1705\r
1706 // Add the Root Complex node count\r
1707 IortNodeCount += RootComplexNodeCount;\r
1708\r
1709 // Get the SMMU v1/v2 node info\r
1710 Status = GetEArmObjSmmuV1SmmuV2 (\r
1711 CfgMgrProtocol,\r
1712 CM_NULL_TOKEN,\r
1713 &SmmuV1V2NodeList,\r
1714 &SmmuV1V2NodeCount\r
1715 );\r
1716 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1717 DEBUG ((\r
1718 DEBUG_ERROR,\r
1719 "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",\r
1720 Status\r
1721 ));\r
1722 goto error_handler;\r
1723 }\r
1724\r
1725 // Add the SMMU v1/v2 node count\r
1726 IortNodeCount += SmmuV1V2NodeCount;\r
1727\r
1728 // Get the SMMUv3 node info\r
1729 Status = GetEArmObjSmmuV3 (\r
1730 CfgMgrProtocol,\r
1731 CM_NULL_TOKEN,\r
1732 &SmmuV3NodeList,\r
1733 &SmmuV3NodeCount\r
1734 );\r
1735 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1736 DEBUG ((\r
1737 DEBUG_ERROR,\r
1738 "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",\r
1739 Status\r
1740 ));\r
1741 goto error_handler;\r
1742 }\r
1743\r
1744 // Add the SMMUv3 node count\r
1745 IortNodeCount += SmmuV3NodeCount;\r
1746\r
1747 // Get the PMCG node info\r
1748 Status = GetEArmObjPmcg (\r
1749 CfgMgrProtocol,\r
1750 CM_NULL_TOKEN,\r
1751 &PmcgNodeList,\r
1752 &PmcgNodeCount\r
1753 );\r
1754 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1755 DEBUG ((\r
1756 DEBUG_ERROR,\r
1757 "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",\r
1758 Status\r
1759 ));\r
1760 goto error_handler;\r
1761 }\r
1762\r
1763 // Add the PMCG node count\r
1764 IortNodeCount += PmcgNodeCount;\r
1765\r
1766 // Allocate Node Indexer array\r
731c67e1
MK
1767 NodeIndexer = (IORT_NODE_INDEXER *)AllocateZeroPool (\r
1768 (sizeof (IORT_NODE_INDEXER) *\r
1769 IortNodeCount)\r
1770 );\r
dfaffc69
SM
1771 if (NodeIndexer == NULL) {\r
1772 Status = EFI_OUT_OF_RESOURCES;\r
1773 DEBUG ((\r
1774 DEBUG_ERROR,\r
1775 "ERROR: IORT: Failed to allocate memory for Node Indexer" \\r
1776 " Status = %r\n",\r
1777 Status\r
1778 ));\r
1779 goto error_handler;\r
1780 }\r
1781\r
1782 DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));\r
1783 Generator->IortNodeCount = IortNodeCount;\r
731c67e1 1784 Generator->NodeIndexer = NodeIndexer;\r
dfaffc69
SM
1785\r
1786 // Calculate the size of the IORT table\r
1787 TableSize = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);\r
1788\r
1789 // ITS Group Nodes\r
1790 if (ItsGroupNodeCount > 0) {\r
8b2ac43b 1791 ItsGroupOffset = (UINT32)TableSize;\r
dfaffc69 1792 // Size of ITS Group node list.\r
8b2ac43b
SM
1793 NodeSize = GetSizeofItsGroupNodes (\r
1794 ItsGroupOffset,\r
1795 ItsGroupNodeList,\r
1796 ItsGroupNodeCount,\r
1797 &NodeIndexer\r
1798 );\r
1799 if (NodeSize > MAX_UINT32) {\r
1800 Status = EFI_INVALID_PARAMETER;\r
1801 DEBUG ((\r
1802 DEBUG_ERROR,\r
1803 "ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n",\r
1804 Status\r
1805 ));\r
1806 goto error_handler;\r
1807 }\r
731c67e1 1808\r
8b2ac43b 1809 TableSize += NodeSize;\r
48179539
SM
1810\r
1811 DEBUG ((\r
1812 DEBUG_INFO,\r
1813 " ItsGroupNodeCount = %d\n" \\r
1814 " ItsGroupOffset = %d\n",\r
1815 ItsGroupNodeCount,\r
1816 ItsGroupOffset\r
1817 ));\r
dfaffc69
SM
1818 }\r
1819\r
1820 // Named Component Nodes\r
1821 if (NamedComponentNodeCount > 0) {\r
8b2ac43b 1822 NamedComponentOffset = (UINT32)TableSize;\r
dfaffc69 1823 // Size of Named Component node list.\r
8b2ac43b
SM
1824 NodeSize = GetSizeofNamedComponentNodes (\r
1825 NamedComponentOffset,\r
1826 NamedComponentNodeList,\r
1827 NamedComponentNodeCount,\r
1828 &NodeIndexer\r
1829 );\r
1830 if (NodeSize > MAX_UINT32) {\r
1831 Status = EFI_INVALID_PARAMETER;\r
1832 DEBUG ((\r
1833 DEBUG_ERROR,\r
1834 "ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n",\r
1835 Status\r
1836 ));\r
1837 goto error_handler;\r
1838 }\r
731c67e1 1839\r
8b2ac43b 1840 TableSize += NodeSize;\r
48179539
SM
1841\r
1842 DEBUG ((\r
1843 DEBUG_INFO,\r
1844 " NamedComponentNodeCount = %d\n" \\r
1845 " NamedComponentOffset = %d\n",\r
1846 NamedComponentNodeCount,\r
1847 NamedComponentOffset\r
1848 ));\r
dfaffc69
SM
1849 }\r
1850\r
1851 // Root Complex Nodes\r
1852 if (RootComplexNodeCount > 0) {\r
8b2ac43b 1853 RootComplexOffset = (UINT32)TableSize;\r
dfaffc69 1854 // Size of Root Complex node list.\r
8b2ac43b
SM
1855 NodeSize = GetSizeofRootComplexNodes (\r
1856 RootComplexOffset,\r
1857 RootComplexNodeList,\r
1858 RootComplexNodeCount,\r
1859 &NodeIndexer\r
1860 );\r
1861 if (NodeSize > MAX_UINT32) {\r
1862 Status = EFI_INVALID_PARAMETER;\r
1863 DEBUG ((\r
1864 DEBUG_ERROR,\r
1865 "ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n",\r
1866 Status\r
1867 ));\r
1868 goto error_handler;\r
1869 }\r
731c67e1 1870\r
8b2ac43b 1871 TableSize += NodeSize;\r
48179539
SM
1872\r
1873 DEBUG ((\r
1874 DEBUG_INFO,\r
1875 " RootComplexNodeCount = %d\n" \\r
1876 " RootComplexOffset = %d\n",\r
1877 RootComplexNodeCount,\r
1878 RootComplexOffset\r
1879 ));\r
dfaffc69
SM
1880 }\r
1881\r
1882 // SMMUv1/SMMUv2 Nodes\r
1883 if (SmmuV1V2NodeCount > 0) {\r
8b2ac43b 1884 SmmuV1V2Offset = (UINT32)TableSize;\r
dfaffc69 1885 // Size of SMMUv1/SMMUv2 node list.\r
8b2ac43b
SM
1886 NodeSize = GetSizeofSmmuV1V2Nodes (\r
1887 SmmuV1V2Offset,\r
1888 SmmuV1V2NodeList,\r
1889 SmmuV1V2NodeCount,\r
1890 &NodeIndexer\r
1891 );\r
1892 if (NodeSize > MAX_UINT32) {\r
1893 Status = EFI_INVALID_PARAMETER;\r
1894 DEBUG ((\r
1895 DEBUG_ERROR,\r
1896 "ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n",\r
1897 Status\r
1898 ));\r
1899 goto error_handler;\r
1900 }\r
731c67e1 1901\r
8b2ac43b 1902 TableSize += NodeSize;\r
48179539
SM
1903\r
1904 DEBUG ((\r
1905 DEBUG_INFO,\r
1906 " SmmuV1V2NodeCount = %d\n" \\r
1907 " SmmuV1V2Offset = %d\n",\r
1908 SmmuV1V2NodeCount,\r
1909 SmmuV1V2Offset\r
1910 ));\r
dfaffc69
SM
1911 }\r
1912\r
1913 // SMMUv3 Nodes\r
1914 if (SmmuV3NodeCount > 0) {\r
8b2ac43b 1915 SmmuV3Offset = (UINT32)TableSize;\r
dfaffc69 1916 // Size of SMMUv3 node list.\r
8b2ac43b
SM
1917 NodeSize = GetSizeofSmmuV3Nodes (\r
1918 SmmuV3Offset,\r
1919 SmmuV3NodeList,\r
1920 SmmuV3NodeCount,\r
1921 &NodeIndexer\r
1922 );\r
1923 if (NodeSize > MAX_UINT32) {\r
1924 Status = EFI_INVALID_PARAMETER;\r
1925 DEBUG ((\r
1926 DEBUG_ERROR,\r
1927 "ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n",\r
1928 Status\r
1929 ));\r
1930 goto error_handler;\r
1931 }\r
731c67e1 1932\r
8b2ac43b 1933 TableSize += NodeSize;\r
48179539
SM
1934\r
1935 DEBUG ((\r
1936 DEBUG_INFO,\r
1937 " SmmuV3NodeCount = %d\n" \\r
1938 " SmmuV3Offset = %d\n",\r
1939 SmmuV3NodeCount,\r
1940 SmmuV3Offset\r
1941 ));\r
dfaffc69
SM
1942 }\r
1943\r
1944 // PMCG Nodes\r
1945 if (PmcgNodeCount > 0) {\r
8b2ac43b 1946 PmcgOffset = (UINT32)TableSize;\r
dfaffc69 1947 // Size of PMCG node list.\r
8b2ac43b
SM
1948 NodeSize = GetSizeofPmcgNodes (\r
1949 PmcgOffset,\r
1950 PmcgNodeList,\r
1951 PmcgNodeCount,\r
1952 &NodeIndexer\r
1953 );\r
1954 if (NodeSize > MAX_UINT32) {\r
1955 Status = EFI_INVALID_PARAMETER;\r
1956 DEBUG ((\r
1957 DEBUG_ERROR,\r
1958 "ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n",\r
1959 Status\r
1960 ));\r
1961 goto error_handler;\r
1962 }\r
731c67e1 1963\r
8b2ac43b 1964 TableSize += NodeSize;\r
48179539
SM
1965\r
1966 DEBUG ((\r
1967 DEBUG_INFO,\r
1968 " PmcgNodeCount = %d\n" \\r
1969 " PmcgOffset = %d\n",\r
1970 PmcgNodeCount,\r
1971 PmcgOffset\r
1972 ));\r
dfaffc69
SM
1973 }\r
1974\r
1975 DEBUG ((\r
1976 DEBUG_INFO,\r
1977 "INFO: IORT:\n" \\r
1978 " IortNodeCount = %d\n" \\r
8b2ac43b 1979 " TableSize = 0x%lx\n",\r
dfaffc69
SM
1980 IortNodeCount,\r
1981 TableSize\r
1982 ));\r
1983\r
8b2ac43b
SM
1984 if (TableSize > MAX_UINT32) {\r
1985 Status = EFI_INVALID_PARAMETER;\r
1986 DEBUG ((\r
1987 DEBUG_ERROR,\r
1988 "ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \\r
1989 " Status = %r\n",\r
1990 TableSize,\r
1991 Status\r
1992 ));\r
1993 goto error_handler;\r
1994 }\r
1995\r
dfaffc69 1996 // Allocate the Buffer for IORT table\r
731c67e1 1997 *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);\r
dfaffc69
SM
1998 if (*Table == NULL) {\r
1999 Status = EFI_OUT_OF_RESOURCES;\r
2000 DEBUG ((\r
2001 DEBUG_ERROR,\r
2002 "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \\r
2003 " Status = %r\n",\r
2004 TableSize,\r
2005 Status\r
2006 ));\r
2007 goto error_handler;\r
2008 }\r
2009\r
731c67e1 2010 Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE *)*Table;\r
dfaffc69
SM
2011\r
2012 DEBUG ((\r
2013 DEBUG_INFO,\r
8b2ac43b 2014 "IORT: Iort = 0x%p TableSize = 0x%lx\n",\r
dfaffc69
SM
2015 Iort,\r
2016 TableSize\r
2017 ));\r
2018\r
2019 Status = AddAcpiHeader (\r
2020 CfgMgrProtocol,\r
2021 This,\r
2022 &Iort->Header,\r
e12bdeb1 2023 AcpiTableInfo,\r
8b2ac43b 2024 (UINT32)TableSize\r
dfaffc69
SM
2025 );\r
2026 if (EFI_ERROR (Status)) {\r
2027 DEBUG ((\r
2028 DEBUG_ERROR,\r
2029 "ERROR: IORT: Failed to add ACPI header. Status = %r\n",\r
2030 Status\r
2031 ));\r
2032 goto error_handler;\r
2033 }\r
2034\r
2035 // Update IORT table\r
731c67e1 2036 Iort->NumNodes = IortNodeCount;\r
dfaffc69 2037 Iort->NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);\r
731c67e1 2038 Iort->Reserved = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69
SM
2039\r
2040 if (ItsGroupNodeCount > 0) {\r
2041 Status = AddItsGroupNodes (\r
2042 This,\r
2043 CfgMgrProtocol,\r
2044 Iort,\r
2045 ItsGroupOffset,\r
2046 ItsGroupNodeList,\r
2047 ItsGroupNodeCount\r
2048 );\r
2049 if (EFI_ERROR (Status)) {\r
2050 DEBUG ((\r
2051 DEBUG_ERROR,\r
2052 "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",\r
2053 Status\r
2054 ));\r
2055 goto error_handler;\r
2056 }\r
2057 }\r
2058\r
2059 if (NamedComponentNodeCount > 0) {\r
2060 Status = AddNamedComponentNodes (\r
2061 This,\r
2062 CfgMgrProtocol,\r
2063 Iort,\r
2064 NamedComponentOffset,\r
2065 NamedComponentNodeList,\r
2066 NamedComponentNodeCount\r
2067 );\r
2068 if (EFI_ERROR (Status)) {\r
2069 DEBUG ((\r
2070 DEBUG_ERROR,\r
2071 "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",\r
2072 Status\r
2073 ));\r
2074 goto error_handler;\r
2075 }\r
2076 }\r
2077\r
2078 if (RootComplexNodeCount > 0) {\r
2079 Status = AddRootComplexNodes (\r
2080 This,\r
2081 CfgMgrProtocol,\r
2082 Iort,\r
2083 RootComplexOffset,\r
2084 RootComplexNodeList,\r
2085 RootComplexNodeCount\r
2086 );\r
2087 if (EFI_ERROR (Status)) {\r
2088 DEBUG ((\r
2089 DEBUG_ERROR,\r
2090 "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",\r
2091 Status\r
2092 ));\r
2093 goto error_handler;\r
2094 }\r
2095 }\r
2096\r
2097 if (SmmuV1V2NodeCount > 0) {\r
2098 Status = AddSmmuV1V2Nodes (\r
2099 This,\r
2100 CfgMgrProtocol,\r
2101 Iort,\r
2102 SmmuV1V2Offset,\r
2103 SmmuV1V2NodeList,\r
2104 SmmuV1V2NodeCount\r
2105 );\r
2106 if (EFI_ERROR (Status)) {\r
2107 DEBUG ((\r
2108 DEBUG_ERROR,\r
2109 "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",\r
2110 Status\r
2111 ));\r
2112 goto error_handler;\r
2113 }\r
2114 }\r
2115\r
2116 if (SmmuV3NodeCount > 0) {\r
2117 Status = AddSmmuV3Nodes (\r
2118 This,\r
2119 CfgMgrProtocol,\r
2120 Iort,\r
2121 SmmuV3Offset,\r
2122 SmmuV3NodeList,\r
2123 SmmuV3NodeCount\r
2124 );\r
2125 if (EFI_ERROR (Status)) {\r
2126 DEBUG ((\r
2127 DEBUG_ERROR,\r
2128 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",\r
2129 Status\r
2130 ));\r
2131 goto error_handler;\r
2132 }\r
2133 }\r
2134\r
2135 if (PmcgNodeCount > 0) {\r
2136 Status = AddPmcgNodes (\r
2137 This,\r
2138 CfgMgrProtocol,\r
2139 Iort,\r
2140 PmcgOffset,\r
2141 PmcgNodeList,\r
2142 PmcgNodeCount\r
2143 );\r
2144 if (EFI_ERROR (Status)) {\r
2145 DEBUG ((\r
2146 DEBUG_ERROR,\r
2147 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",\r
2148 Status\r
2149 ));\r
2150 goto error_handler;\r
2151 }\r
2152 }\r
2153\r
2154 return EFI_SUCCESS;\r
2155\r
2156error_handler:\r
2157 if (Generator->NodeIndexer != NULL) {\r
2158 FreePool (Generator->NodeIndexer);\r
2159 Generator->NodeIndexer = NULL;\r
2160 }\r
2161\r
2162 if (*Table != NULL) {\r
2163 FreePool (*Table);\r
2164 *Table = NULL;\r
2165 }\r
731c67e1 2166\r
dfaffc69
SM
2167 return Status;\r
2168}\r
2169\r
2170/** Free any resources allocated for constructing the IORT\r
2171\r
2172 @param [in] This Pointer to the table generator.\r
2173 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
2174 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
2175 Protocol Interface.\r
2176 @param [in, out] Table Pointer to the ACPI Table.\r
2177\r
2178 @retval EFI_SUCCESS The resources were freed successfully.\r
2179 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
2180**/\r
2181STATIC\r
2182EFI_STATUS\r
2183FreeIortTableResources (\r
731c67e1
MK
2184 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
2185 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,\r
2186 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
2187 IN OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table\r
dfaffc69
SM
2188 )\r
2189{\r
731c67e1
MK
2190 ACPI_IORT_GENERATOR *Generator;\r
2191\r
dfaffc69
SM
2192 ASSERT (This != NULL);\r
2193 ASSERT (AcpiTableInfo != NULL);\r
2194 ASSERT (CfgMgrProtocol != NULL);\r
2195 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
2196 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
2197\r
731c67e1 2198 Generator = (ACPI_IORT_GENERATOR *)This;\r
dfaffc69
SM
2199\r
2200 // Free any memory allocated by the generator\r
2201 if (Generator->NodeIndexer != NULL) {\r
2202 FreePool (Generator->NodeIndexer);\r
2203 Generator->NodeIndexer = NULL;\r
2204 }\r
2205\r
2206 if ((Table == NULL) || (*Table == NULL)) {\r
2207 DEBUG ((DEBUG_ERROR, "ERROR: IORT: Invalid Table Pointer\n"));\r
2208 ASSERT ((Table != NULL) && (*Table != NULL));\r
2209 return EFI_INVALID_PARAMETER;\r
2210 }\r
2211\r
2212 FreePool (*Table);\r
2213 *Table = NULL;\r
2214 return EFI_SUCCESS;\r
2215}\r
2216\r
2217/** The IORT Table Generator revision.\r
2218*/\r
731c67e1 2219#define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
dfaffc69
SM
2220\r
2221/** The interface for the MADT Table Generator.\r
2222*/\r
2223STATIC\r
731c67e1 2224ACPI_IORT_GENERATOR IortGenerator = {\r
dfaffc69
SM
2225 // ACPI table generator header\r
2226 {\r
2227 // Generator ID\r
2228 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort),\r
2229 // Generator Description\r
2230 L"ACPI.STD.IORT.GENERATOR",\r
2231 // ACPI Table Signature\r
2232 EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE,\r
2233 // ACPI Table Revision supported by this Generator\r
2234 EFI_ACPI_IO_REMAPPING_TABLE_REVISION,\r
2235 // Minimum supported ACPI Table Revision\r
2236 EFI_ACPI_IO_REMAPPING_TABLE_REVISION,\r
2237 // Creator ID\r
2238 TABLE_GENERATOR_CREATOR_ID_ARM,\r
2239 // Creator Revision\r
2240 IORT_GENERATOR_REVISION,\r
2241 // Build Table function\r
2242 BuildIortTable,\r
2243 // Free Resource function\r
2244 FreeIortTableResources,\r
2245 // Extended build function not needed\r
2246 NULL,\r
2247 // Extended build function not implemented by the generator.\r
2248 // Hence extended free resource function is not required.\r
2249 NULL\r
2250 },\r
2251\r
2252 // IORT Generator private data\r
2253\r
2254 // Iort Node count\r
2255 0,\r
2256 // Pointer to Iort node indexer\r
2257 NULL\r
2258};\r
2259\r
2260/** Register the Generator with the ACPI Table Factory.\r
2261\r
2262 @param [in] ImageHandle The handle to the image.\r
2263 @param [in] SystemTable Pointer to the System Table.\r
2264\r
2265 @retval EFI_SUCCESS The Generator is registered.\r
2266 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
2267 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
2268 is already registered.\r
2269**/\r
2270EFI_STATUS\r
2271EFIAPI\r
2272AcpiIortLibConstructor (\r
731c67e1
MK
2273 IN EFI_HANDLE ImageHandle,\r
2274 IN EFI_SYSTEM_TABLE *SystemTable\r
dfaffc69
SM
2275 )\r
2276{\r
2277 EFI_STATUS Status;\r
731c67e1 2278\r
dfaffc69
SM
2279 Status = RegisterAcpiTableGenerator (&IortGenerator.Header);\r
2280 DEBUG ((DEBUG_INFO, "IORT: Register Generator. Status = %r\n", Status));\r
2281 ASSERT_EFI_ERROR (Status);\r
2282 return Status;\r
2283}\r
2284\r
2285/** Deregister the Generator from the ACPI Table Factory.\r
2286\r
2287 @param [in] ImageHandle The handle to the image.\r
2288 @param [in] SystemTable Pointer to the System Table.\r
2289\r
2290 @retval EFI_SUCCESS The Generator is deregistered.\r
2291 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
2292 @retval EFI_NOT_FOUND The Generator is not registered.\r
2293**/\r
2294EFI_STATUS\r
2295EFIAPI\r
2296AcpiIortLibDestructor (\r
731c67e1
MK
2297 IN EFI_HANDLE ImageHandle,\r
2298 IN EFI_SYSTEM_TABLE *SystemTable\r
dfaffc69
SM
2299 )\r
2300{\r
2301 EFI_STATUS Status;\r
731c67e1 2302\r
dfaffc69
SM
2303 Status = DeregisterAcpiTableGenerator (&IortGenerator.Header);\r
2304 DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status));\r
2305 ASSERT_EFI_ERROR (Status);\r
2306 return Status;\r
2307}\r