]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
MdePkg: IORT header update for IORT Rev E.d spec
[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
4c55f639 769 ItsGroupNode->Node.Identifier = 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
4c55f639 875 NcNode->Node.Identifier = 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
4c55f639 1008 RcNode->Node.Identifier = 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
4c55f639 1021 RcNode->PasidCapabilities = EFI_ACPI_RESERVED_WORD;\r
731c67e1 1022 RcNode->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;\r
dfaffc69 1023\r
65c4f3f2
SM
1024 if (NodeList->IdMappingCount > 0) {\r
1025 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
1026 Status = EFI_INVALID_PARAMETER;\r
1027 DEBUG ((\r
1028 DEBUG_ERROR,\r
1029 "ERROR: IORT: Invalid Id Mapping token,"\r
1030 " Token = 0x%x, Status =%r\n",\r
1031 NodeList->IdMappingToken,\r
1032 Status\r
1033 ));\r
1034 return Status;\r
1035 }\r
1036\r
dfaffc69 1037 // Ids for Root Complex\r
731c67e1
MK
1038 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)RcNode +\r
1039 RcNode->Node.IdReference);\r
dfaffc69
SM
1040 Status = AddIdMappingArray (\r
1041 This,\r
1042 CfgMgrProtocol,\r
1043 IdMapArray,\r
1044 NodeList->IdMappingCount,\r
1045 NodeList->IdMappingToken\r
1046 );\r
1047 if (EFI_ERROR (Status)) {\r
1048 DEBUG ((\r
1049 DEBUG_ERROR,\r
1050 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
1051 Status\r
1052 ));\r
1053 return Status;\r
1054 }\r
1055 }\r
1056\r
1057 // Next Root Complex Node\r
731c67e1
MK
1058 RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *)((UINT8 *)RcNode +\r
1059 RcNode->Node.Length);\r
dfaffc69
SM
1060 NodeList++;\r
1061 } // Root Complex Node\r
1062\r
1063 return EFI_SUCCESS;\r
1064}\r
1065\r
1066/** Update the SMMU Interrupt Array.\r
1067\r
1068 This function retrieves the InterruptArray object referenced by the\r
1069 InterruptToken and updates the SMMU InterruptArray.\r
1070\r
1071 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1072 Protocol Interface.\r
1073 @param [in, out] InterruptArray Pointer to an array of Interrupts.\r
1074 @param [in] InterruptCount Number of entries in the InterruptArray.\r
1075 @param [in] InterruptToken Reference Token for retrieving the SMMU\r
1076 InterruptArray object.\r
1077\r
1078 @retval EFI_SUCCESS Table generated successfully.\r
1079 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1080 @retval EFI_NOT_FOUND The required object was not found.\r
1081**/\r
1082STATIC\r
1083EFI_STATUS\r
e3f8605a 1084AddSmmuInterruptArray (\r
731c67e1
MK
1085 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1086 IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *InterruptArray,\r
dfaffc69
SM
1087 IN UINT32 InterruptCount,\r
1088 IN CONST CM_OBJECT_TOKEN InterruptToken\r
1089 )\r
1090{\r
731c67e1
MK
1091 EFI_STATUS Status;\r
1092 CM_ARM_SMMU_INTERRUPT *SmmuInterrupt;\r
1093 UINT32 SmmuInterruptCount;\r
dfaffc69
SM
1094\r
1095 ASSERT (InterruptArray != NULL);\r
1096\r
1097 // Get the SMMU Interrupt Array\r
1098 Status = GetEArmObjSmmuInterruptArray (\r
1099 CfgMgrProtocol,\r
1100 InterruptToken,\r
1101 &SmmuInterrupt,\r
1102 &SmmuInterruptCount\r
1103 );\r
1104 if (EFI_ERROR (Status)) {\r
1105 DEBUG ((\r
1106 DEBUG_ERROR,\r
1107 "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",\r
1108 Status\r
1109 ));\r
1110 return Status;\r
1111 }\r
1112\r
1113 if (SmmuInterruptCount < InterruptCount) {\r
1114 DEBUG ((\r
1115 DEBUG_ERROR,\r
1116 "ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"\r
1117 ));\r
1118 return EFI_NOT_FOUND;\r
1119 }\r
1120\r
1121 // Populate the Id Mapping array\r
1122 while (InterruptCount-- != 0) {\r
731c67e1 1123 InterruptArray->Interrupt = SmmuInterrupt->Interrupt;\r
dfaffc69
SM
1124 InterruptArray->InterruptFlags = SmmuInterrupt->Flags;\r
1125 InterruptArray++;\r
1126 SmmuInterrupt++;\r
1127 } // Id Mapping array\r
1128\r
1129 return EFI_SUCCESS;\r
1130}\r
1131\r
1132/** Update the SMMU v1/v2 Node Information.\r
1133\r
1134 @param [in] This Pointer to the table Generator.\r
1135 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1136 Protocol Interface.\r
1137 @param [in] Iort Pointer to IORT table structure.\r
1138 @param [in] NodesStartOffset Offset for the start of the SMMU v1/v2\r
1139 Nodes.\r
1140 @param [in] NodeList Pointer to an array of SMMU v1/v2 Node\r
1141 Objects.\r
1142 @param [in] NodeCount Number of SMMU v1/v2 Node Objects.\r
1143\r
1144 @retval EFI_SUCCESS Table generated successfully.\r
1145 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1146 @retval EFI_NOT_FOUND The required object was not found.\r
1147**/\r
1148STATIC\r
1149EFI_STATUS\r
1150AddSmmuV1V2Nodes (\r
731c67e1
MK
1151 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1152 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1153 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 1154 IN CONST UINT32 NodesStartOffset,\r
731c67e1 1155 IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *NodeList,\r
dfaffc69
SM
1156 IN UINT32 NodeCount\r
1157 )\r
1158{\r
731c67e1
MK
1159 EFI_STATUS Status;\r
1160 EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *SmmuNode;\r
1161 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;\r
dfaffc69 1162\r
731c67e1
MK
1163 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *ContextInterruptArray;\r
1164 EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *PmuInterruptArray;\r
1165 UINT64 NodeLength;\r
238f903e 1166 UINT32 Offset;\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
4c55f639 1190 SmmuNode->Node.Identifier = 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
238f903e 1209 Offset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);\r
dfaffc69 1210 // Context Interrupt\r
238f903e
SM
1211 SmmuNode->NumContextInterrupts = NodeList->ContextInterruptCount;\r
1212 if (NodeList->ContextInterruptCount != 0) {\r
1213 SmmuNode->ContextInterruptArrayRef = Offset;\r
1214 ContextInterruptArray =\r
1215 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode + Offset);\r
1216 Offset += (NodeList->ContextInterruptCount *\r
1217 sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));\r
1218 }\r
dfaffc69
SM
1219\r
1220 // PMU Interrupt\r
238f903e
SM
1221 SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;\r
1222 if (NodeList->PmuInterruptCount != 0) {\r
1223 SmmuNode->PmuInterruptArrayRef = Offset;\r
1224 PmuInterruptArray =\r
1225 (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode + Offset);\r
1226 }\r
dfaffc69 1227\r
731c67e1
MK
1228 SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt;\r
1229 SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags;\r
1230 SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt;\r
dfaffc69
SM
1231 SmmuNode->SMMU_NSgCfgIrptFlags = NodeList->SMMU_NSgCfgIrptFlags;\r
1232\r
238f903e
SM
1233 if (NodeList->ContextInterruptCount != 0) {\r
1234 if (NodeList->ContextInterruptToken == CM_NULL_TOKEN) {\r
1235 Status = EFI_INVALID_PARAMETER;\r
1236 DEBUG ((\r
1237 DEBUG_ERROR,\r
1238 "ERROR: IORT: Invalid Context Interrupt token,"\r
1239 " Token = 0x%x, Status =%r\n",\r
1240 NodeList->ContextInterruptToken,\r
1241 Status\r
1242 ));\r
1243 return Status;\r
1244 }\r
1245\r
1246 // Add Context Interrupt Array\r
1247 Status = AddSmmuInterruptArray (\r
1248 CfgMgrProtocol,\r
1249 ContextInterruptArray,\r
1250 SmmuNode->NumContextInterrupts,\r
1251 NodeList->ContextInterruptToken\r
1252 );\r
1253 if (EFI_ERROR (Status)) {\r
1254 DEBUG ((\r
1255 DEBUG_ERROR,\r
1256 "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",\r
1257 Status\r
1258 ));\r
1259 return Status;\r
1260 }\r
dfaffc69
SM
1261 }\r
1262\r
1263 // Add PMU Interrupt Array\r
238f903e
SM
1264 if (SmmuNode->NumPmuInterrupts != 0) {\r
1265 if (NodeList->PmuInterruptToken == CM_NULL_TOKEN) {\r
1266 Status = EFI_INVALID_PARAMETER;\r
1267 DEBUG ((\r
1268 DEBUG_ERROR,\r
1269 "ERROR: IORT: Invalid PMU Interrupt token,"\r
1270 " Token = 0x%x, Status =%r\n",\r
1271 NodeList->PmuInterruptToken,\r
1272 Status\r
1273 ));\r
1274 return Status;\r
1275 }\r
1276\r
e3f8605a 1277 Status = AddSmmuInterruptArray (\r
dfaffc69
SM
1278 CfgMgrProtocol,\r
1279 PmuInterruptArray,\r
1280 SmmuNode->NumPmuInterrupts,\r
1281 NodeList->PmuInterruptToken\r
1282 );\r
1283 if (EFI_ERROR (Status)) {\r
1284 DEBUG ((\r
1285 DEBUG_ERROR,\r
1286 "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",\r
1287 Status\r
1288 ));\r
1289 return Status;\r
1290 }\r
1291 }\r
1292\r
65c4f3f2
SM
1293 if (NodeList->IdMappingCount > 0) {\r
1294 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
1295 Status = EFI_INVALID_PARAMETER;\r
1296 DEBUG ((\r
1297 DEBUG_ERROR,\r
1298 "ERROR: IORT: Invalid Id Mapping token,"\r
1299 " Token = 0x%x, Status =%r\n",\r
1300 NodeList->IdMappingToken,\r
1301 Status\r
1302 ));\r
1303 return Status;\r
1304 }\r
1305\r
dfaffc69 1306 // Ids for SMMU v1/v2 Node\r
731c67e1
MK
1307 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)SmmuNode +\r
1308 SmmuNode->Node.IdReference);\r
dfaffc69
SM
1309 Status = AddIdMappingArray (\r
1310 This,\r
1311 CfgMgrProtocol,\r
1312 IdMapArray,\r
1313 NodeList->IdMappingCount,\r
1314 NodeList->IdMappingToken\r
1315 );\r
1316 if (EFI_ERROR (Status)) {\r
1317 DEBUG ((\r
1318 DEBUG_ERROR,\r
1319 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
1320 Status\r
1321 ));\r
1322 return Status;\r
1323 }\r
1324 }\r
731c67e1 1325\r
dfaffc69 1326 // Next SMMU v1/v2 Node\r
731c67e1
MK
1327 SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *)((UINT8 *)SmmuNode +\r
1328 SmmuNode->Node.Length);\r
dfaffc69
SM
1329 NodeList++;\r
1330 } // SMMU v1/v2 Node\r
1331\r
1332 return EFI_SUCCESS;\r
1333}\r
1334\r
1335/** Update the SMMUv3 Node Information.\r
1336\r
1337 This function updates the SMMUv3 node information in the IORT table.\r
1338\r
1339 @param [in] This Pointer to the table Generator.\r
1340 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1341 Protocol Interface.\r
1342 @param [in] Iort Pointer to IORT table structure.\r
1343 @param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.\r
1344 @param [in] NodeList Pointer to an array of SMMUv3 Node Objects.\r
1345 @param [in] NodeCount Number of SMMUv3 Node Objects.\r
1346\r
1347 @retval EFI_SUCCESS Table generated successfully.\r
1348 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1349 @retval EFI_NOT_FOUND The required object was not found.\r
1350**/\r
1351STATIC\r
1352EFI_STATUS\r
1353AddSmmuV3Nodes (\r
731c67e1
MK
1354 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1355 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1356 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 1357 IN CONST UINT32 NodesStartOffset,\r
731c67e1 1358 IN CONST CM_ARM_SMMUV3_NODE *NodeList,\r
dfaffc69
SM
1359 IN UINT32 NodeCount\r
1360 )\r
1361{\r
731c67e1
MK
1362 EFI_STATUS Status;\r
1363 EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *SmmuV3Node;\r
1364 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;\r
1365 UINT64 NodeLength;\r
dfaffc69
SM
1366\r
1367 ASSERT (Iort != NULL);\r
1368\r
731c67e1
MK
1369 SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)Iort +\r
1370 NodesStartOffset);\r
dfaffc69
SM
1371\r
1372 while (NodeCount-- != 0) {\r
8b2ac43b
SM
1373 NodeLength = GetSmmuV3NodeSize (NodeList);\r
1374 if (NodeLength > MAX_UINT16) {\r
1375 Status = EFI_INVALID_PARAMETER;\r
1376 DEBUG ((\r
1377 DEBUG_ERROR,\r
1378 "ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n",\r
1379 NodeLength,\r
1380 Status\r
1381 ));\r
1382 return Status;\r
1383 }\r
1384\r
dfaffc69 1385 // Populate the node header\r
731c67e1
MK
1386 SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;\r
1387 SmmuV3Node->Node.Length = (UINT16)NodeLength;\r
1388 SmmuV3Node->Node.Revision = 2;\r
4c55f639 1389 SmmuV3Node->Node.Identifier = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69 1390 SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount;\r
f5cea604
SM
1391 SmmuV3Node->Node.IdReference = (NodeList->IdMappingCount == 0) ?\r
1392 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);\r
dfaffc69
SM
1393\r
1394 // SMMUv3 specific data\r
731c67e1
MK
1395 SmmuV3Node->Base = NodeList->BaseAddress;\r
1396 SmmuV3Node->Flags = NodeList->Flags;\r
1397 SmmuV3Node->Reserved = EFI_ACPI_RESERVED_WORD;\r
dfaffc69 1398 SmmuV3Node->VatosAddress = NodeList->VatosAddress;\r
731c67e1
MK
1399 SmmuV3Node->Model = NodeList->Model;\r
1400 SmmuV3Node->Event = NodeList->EventInterrupt;\r
1401 SmmuV3Node->Pri = NodeList->PriInterrupt;\r
1402 SmmuV3Node->Gerr = NodeList->GerrInterrupt;\r
1403 SmmuV3Node->Sync = NodeList->SyncInterrupt;\r
dfaffc69
SM
1404\r
1405 if ((SmmuV3Node->Flags & EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN) != 0) {\r
1406 // The Proximity Domain Valid flag is set to 1\r
1407 SmmuV3Node->ProximityDomain = NodeList->ProximityDomain;\r
1408 } else {\r
1409 SmmuV3Node->ProximityDomain = 0;\r
1410 }\r
1411\r
1412 if ((SmmuV3Node->Event != 0) && (SmmuV3Node->Pri != 0) &&\r
731c67e1
MK
1413 (SmmuV3Node->Gerr != 0) && (SmmuV3Node->Sync != 0))\r
1414 {\r
dfaffc69
SM
1415 // If all the SMMU control interrupts are GSIV based,\r
1416 // the DeviceID mapping index field is ignored.\r
1417 SmmuV3Node->DeviceIdMappingIndex = 0;\r
1418 } else {\r
1419 SmmuV3Node->DeviceIdMappingIndex = NodeList->DeviceIdMappingIndex;\r
1420 }\r
1421\r
65c4f3f2
SM
1422 if (NodeList->IdMappingCount > 0) {\r
1423 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
1424 Status = EFI_INVALID_PARAMETER;\r
1425 DEBUG ((\r
1426 DEBUG_ERROR,\r
1427 "ERROR: IORT: Invalid Id Mapping token,"\r
1428 " Token = 0x%x, Status =%r\n",\r
1429 NodeList->IdMappingToken,\r
1430 Status\r
1431 ));\r
1432 return Status;\r
1433 }\r
1434\r
dfaffc69 1435 // Ids for SMMUv3 node\r
731c67e1
MK
1436 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)SmmuV3Node +\r
1437 SmmuV3Node->Node.IdReference);\r
dfaffc69
SM
1438 Status = AddIdMappingArray (\r
1439 This,\r
1440 CfgMgrProtocol,\r
1441 IdMapArray,\r
1442 NodeList->IdMappingCount,\r
1443 NodeList->IdMappingToken\r
1444 );\r
1445 if (EFI_ERROR (Status)) {\r
1446 DEBUG ((\r
1447 DEBUG_ERROR,\r
1448 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
1449 Status\r
1450 ));\r
1451 return Status;\r
1452 }\r
1453 }\r
1454\r
1455 // Next SMMUv3 Node\r
731c67e1
MK
1456 SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)SmmuV3Node +\r
1457 SmmuV3Node->Node.Length);\r
dfaffc69
SM
1458 NodeList++;\r
1459 } // SMMUv3 Node\r
1460\r
1461 return EFI_SUCCESS;\r
1462}\r
1463\r
1464/** Update the PMCG Node Information.\r
1465\r
1466 This function updates the PMCG node information in the IORT table.\r
1467\r
1468 @param [in] This Pointer to the table Generator.\r
1469 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1470 Protocol Interface.\r
1471 @param [in] Iort Pointer to IORT table structure.\r
1472 @param [in] NodesStartOffset Offset for the start of the PMCG Nodes.\r
1473 @param [in] NodeList Pointer to an array of PMCG Node Objects.\r
1474 @param [in] NodeCount Number of PMCG Node Objects.\r
1475\r
1476 @retval EFI_SUCCESS Table generated successfully.\r
1477 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1478 @retval EFI_NOT_FOUND The required object was not found.\r
1479**/\r
1480STATIC\r
1481EFI_STATUS\r
1482AddPmcgNodes (\r
731c67e1
MK
1483 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1484 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1485 IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,\r
dfaffc69 1486 IN CONST UINT32 NodesStartOffset,\r
731c67e1 1487 IN CONST CM_ARM_PMCG_NODE *NodeList,\r
dfaffc69
SM
1488 IN UINT32 NodeCount\r
1489 )\r
1490{\r
731c67e1
MK
1491 EFI_STATUS Status;\r
1492 EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *PmcgNode;\r
1493 EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;\r
1494 ACPI_IORT_GENERATOR *Generator;\r
1495 UINT64 NodeLength;\r
dfaffc69
SM
1496\r
1497 ASSERT (Iort != NULL);\r
1498\r
731c67e1
MK
1499 Generator = (ACPI_IORT_GENERATOR *)This;\r
1500 PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)Iort +\r
1501 NodesStartOffset);\r
dfaffc69
SM
1502\r
1503 while (NodeCount-- != 0) {\r
8b2ac43b
SM
1504 NodeLength = GetPmcgNodeSize (NodeList);\r
1505 if (NodeLength > MAX_UINT16) {\r
1506 Status = EFI_INVALID_PARAMETER;\r
1507 DEBUG ((\r
1508 DEBUG_ERROR,\r
1509 "ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n",\r
1510 NodeLength,\r
1511 Status\r
1512 ));\r
1513 return Status;\r
1514 }\r
1515\r
dfaffc69 1516 // Populate the node header\r
731c67e1
MK
1517 PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;\r
1518 PmcgNode->Node.Length = (UINT16)NodeLength;\r
1519 PmcgNode->Node.Revision = 1;\r
4c55f639 1520 PmcgNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69 1521 PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount;\r
f5cea604
SM
1522 PmcgNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?\r
1523 0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);\r
dfaffc69
SM
1524\r
1525 // PMCG specific data\r
731c67e1 1526 PmcgNode->Base = NodeList->BaseAddress;\r
dfaffc69 1527 PmcgNode->OverflowInterruptGsiv = NodeList->OverflowInterrupt;\r
731c67e1 1528 PmcgNode->Page1Base = NodeList->Page1BaseAddress;\r
dfaffc69
SM
1529\r
1530 Status = GetNodeOffsetReferencedByToken (\r
731c67e1
MK
1531 Generator->NodeIndexer,\r
1532 Generator->IortNodeCount,\r
1533 NodeList->ReferenceToken,\r
1534 &PmcgNode->NodeReference\r
1535 );\r
dfaffc69
SM
1536 if (EFI_ERROR (Status)) {\r
1537 DEBUG ((\r
1538 DEBUG_ERROR,\r
1539 "ERROR: IORT: Failed to get Output Reference for PMCG Node."\r
1540 "Reference Token = %p"\r
1541 " Status = %r\n",\r
1542 NodeList->ReferenceToken,\r
1543 Status\r
1544 ));\r
1545 return Status;\r
1546 }\r
1547\r
65c4f3f2
SM
1548 if (NodeList->IdMappingCount > 0) {\r
1549 if (NodeList->IdMappingToken == CM_NULL_TOKEN) {\r
1550 Status = EFI_INVALID_PARAMETER;\r
1551 DEBUG ((\r
1552 DEBUG_ERROR,\r
1553 "ERROR: IORT: Invalid Id Mapping token,"\r
1554 " Token = 0x%x, Status =%r\n",\r
1555 NodeList->IdMappingToken,\r
1556 Status\r
1557 ));\r
1558 return Status;\r
1559 }\r
1560\r
dfaffc69 1561 // Ids for PMCG node\r
731c67e1
MK
1562 IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)PmcgNode +\r
1563 PmcgNode->Node.IdReference);\r
dfaffc69
SM
1564\r
1565 Status = AddIdMappingArray (\r
731c67e1
MK
1566 This,\r
1567 CfgMgrProtocol,\r
1568 IdMapArray,\r
1569 NodeList->IdMappingCount,\r
1570 NodeList->IdMappingToken\r
1571 );\r
dfaffc69
SM
1572 if (EFI_ERROR (Status)) {\r
1573 DEBUG ((\r
1574 DEBUG_ERROR,\r
1575 "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",\r
1576 Status\r
1577 ));\r
1578 return Status;\r
1579 }\r
1580 }\r
1581\r
1582 // Next PMCG Node\r
731c67e1
MK
1583 PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)PmcgNode +\r
1584 PmcgNode->Node.Length);\r
dfaffc69
SM
1585 NodeList++;\r
1586 } // PMCG Node\r
1587\r
1588 return EFI_SUCCESS;\r
1589}\r
1590\r
1591/** Construct the IORT ACPI table.\r
1592\r
1593 This function invokes the Configuration Manager protocol interface\r
1594 to get the required hardware information for generating the ACPI\r
1595 table.\r
1596\r
1597 If this function allocates any resources then they must be freed\r
1598 in the FreeXXXXTableResources function.\r
1599\r
1600 @param [in] This Pointer to the table generator.\r
1601 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
1602 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
1603 Protocol Interface.\r
1604 @param [out] Table Pointer to the constructed ACPI Table.\r
1605\r
1606 @retval EFI_SUCCESS Table generated successfully.\r
1607 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
1608 @retval EFI_NOT_FOUND The required object was not found.\r
1609 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
1610 Manager is less than the Object size for the\r
1611 requested object.\r
1612**/\r
1613STATIC\r
1614EFI_STATUS\r
1615EFIAPI\r
1616BuildIortTable (\r
731c67e1
MK
1617 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
1618 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,\r
1619 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
1620 OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table\r
dfaffc69
SM
1621 )\r
1622{\r
731c67e1
MK
1623 EFI_STATUS Status;\r
1624\r
1625 UINT64 TableSize;\r
1626 UINT64 NodeSize;\r
1627\r
1628 UINT32 IortNodeCount;\r
1629 UINT32 ItsGroupNodeCount;\r
1630 UINT32 NamedComponentNodeCount;\r
1631 UINT32 RootComplexNodeCount;\r
1632 UINT32 SmmuV1V2NodeCount;\r
1633 UINT32 SmmuV3NodeCount;\r
1634 UINT32 PmcgNodeCount;\r
1635\r
1636 UINT32 ItsGroupOffset;\r
1637 UINT32 NamedComponentOffset;\r
1638 UINT32 RootComplexOffset;\r
1639 UINT32 SmmuV1V2Offset;\r
1640 UINT32 SmmuV3Offset;\r
1641 UINT32 PmcgOffset;\r
1642\r
1643 CM_ARM_ITS_GROUP_NODE *ItsGroupNodeList;\r
1644 CM_ARM_NAMED_COMPONENT_NODE *NamedComponentNodeList;\r
1645 CM_ARM_ROOT_COMPLEX_NODE *RootComplexNodeList;\r
1646 CM_ARM_SMMUV1_SMMUV2_NODE *SmmuV1V2NodeList;\r
1647 CM_ARM_SMMUV3_NODE *SmmuV3NodeList;\r
1648 CM_ARM_PMCG_NODE *PmcgNodeList;\r
1649\r
1650 EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort;\r
1651 IORT_NODE_INDEXER *NodeIndexer;\r
1652 ACPI_IORT_GENERATOR *Generator;\r
dfaffc69
SM
1653\r
1654 ASSERT (This != NULL);\r
1655 ASSERT (AcpiTableInfo != NULL);\r
1656 ASSERT (CfgMgrProtocol != NULL);\r
1657 ASSERT (Table != NULL);\r
1658 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
1659 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
1660\r
1661 if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
731c67e1
MK
1662 (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision))\r
1663 {\r
dfaffc69
SM
1664 DEBUG ((\r
1665 DEBUG_ERROR,\r
1666 "ERROR: IORT: Requested table revision = %d, is not supported."\r
1667 "Supported table revision: Minimum = %d, Maximum = %d\n",\r
1668 AcpiTableInfo->AcpiTableRevision,\r
1669 This->MinAcpiTableRevision,\r
1670 This->AcpiTableRevision\r
1671 ));\r
1672 return EFI_INVALID_PARAMETER;\r
1673 }\r
1674\r
731c67e1
MK
1675 Generator = (ACPI_IORT_GENERATOR *)This;\r
1676 *Table = NULL;\r
dfaffc69
SM
1677\r
1678 // Get the ITS group node info\r
1679 Status = GetEArmObjItsGroup (\r
1680 CfgMgrProtocol,\r
1681 CM_NULL_TOKEN,\r
1682 &ItsGroupNodeList,\r
1683 &ItsGroupNodeCount\r
1684 );\r
1685 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1686 DEBUG ((\r
1687 DEBUG_ERROR,\r
1688 "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",\r
1689 Status\r
1690 ));\r
1691 goto error_handler;\r
1692 }\r
1693\r
1694 // Add the ITS group node count\r
1695 IortNodeCount = ItsGroupNodeCount;\r
1696\r
1697 // Get the Named component node info\r
1698 Status = GetEArmObjNamedComponent (\r
1699 CfgMgrProtocol,\r
1700 CM_NULL_TOKEN,\r
1701 &NamedComponentNodeList,\r
1702 &NamedComponentNodeCount\r
1703 );\r
1704 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1705 DEBUG ((\r
1706 DEBUG_ERROR,\r
1707 "ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",\r
1708 Status\r
1709 ));\r
1710 goto error_handler;\r
1711 }\r
1712\r
1713 // Add the Named Component group count\r
1714 IortNodeCount += NamedComponentNodeCount;\r
1715\r
1716 // Get the Root complex node info\r
1717 Status = GetEArmObjRootComplex (\r
1718 CfgMgrProtocol,\r
1719 CM_NULL_TOKEN,\r
1720 &RootComplexNodeList,\r
1721 &RootComplexNodeCount\r
1722 );\r
1723 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1724 DEBUG ((\r
1725 DEBUG_ERROR,\r
1726 "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",\r
1727 Status\r
1728 ));\r
1729 goto error_handler;\r
1730 }\r
1731\r
1732 // Add the Root Complex node count\r
1733 IortNodeCount += RootComplexNodeCount;\r
1734\r
1735 // Get the SMMU v1/v2 node info\r
1736 Status = GetEArmObjSmmuV1SmmuV2 (\r
1737 CfgMgrProtocol,\r
1738 CM_NULL_TOKEN,\r
1739 &SmmuV1V2NodeList,\r
1740 &SmmuV1V2NodeCount\r
1741 );\r
1742 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1743 DEBUG ((\r
1744 DEBUG_ERROR,\r
1745 "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",\r
1746 Status\r
1747 ));\r
1748 goto error_handler;\r
1749 }\r
1750\r
1751 // Add the SMMU v1/v2 node count\r
1752 IortNodeCount += SmmuV1V2NodeCount;\r
1753\r
1754 // Get the SMMUv3 node info\r
1755 Status = GetEArmObjSmmuV3 (\r
1756 CfgMgrProtocol,\r
1757 CM_NULL_TOKEN,\r
1758 &SmmuV3NodeList,\r
1759 &SmmuV3NodeCount\r
1760 );\r
1761 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1762 DEBUG ((\r
1763 DEBUG_ERROR,\r
1764 "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",\r
1765 Status\r
1766 ));\r
1767 goto error_handler;\r
1768 }\r
1769\r
1770 // Add the SMMUv3 node count\r
1771 IortNodeCount += SmmuV3NodeCount;\r
1772\r
1773 // Get the PMCG node info\r
1774 Status = GetEArmObjPmcg (\r
1775 CfgMgrProtocol,\r
1776 CM_NULL_TOKEN,\r
1777 &PmcgNodeList,\r
1778 &PmcgNodeCount\r
1779 );\r
1780 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
1781 DEBUG ((\r
1782 DEBUG_ERROR,\r
1783 "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",\r
1784 Status\r
1785 ));\r
1786 goto error_handler;\r
1787 }\r
1788\r
1789 // Add the PMCG node count\r
1790 IortNodeCount += PmcgNodeCount;\r
1791\r
1792 // Allocate Node Indexer array\r
731c67e1
MK
1793 NodeIndexer = (IORT_NODE_INDEXER *)AllocateZeroPool (\r
1794 (sizeof (IORT_NODE_INDEXER) *\r
1795 IortNodeCount)\r
1796 );\r
dfaffc69
SM
1797 if (NodeIndexer == NULL) {\r
1798 Status = EFI_OUT_OF_RESOURCES;\r
1799 DEBUG ((\r
1800 DEBUG_ERROR,\r
1801 "ERROR: IORT: Failed to allocate memory for Node Indexer" \\r
1802 " Status = %r\n",\r
1803 Status\r
1804 ));\r
1805 goto error_handler;\r
1806 }\r
1807\r
1808 DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));\r
1809 Generator->IortNodeCount = IortNodeCount;\r
731c67e1 1810 Generator->NodeIndexer = NodeIndexer;\r
dfaffc69
SM
1811\r
1812 // Calculate the size of the IORT table\r
1813 TableSize = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);\r
1814\r
1815 // ITS Group Nodes\r
1816 if (ItsGroupNodeCount > 0) {\r
8b2ac43b 1817 ItsGroupOffset = (UINT32)TableSize;\r
dfaffc69 1818 // Size of ITS Group node list.\r
8b2ac43b
SM
1819 NodeSize = GetSizeofItsGroupNodes (\r
1820 ItsGroupOffset,\r
1821 ItsGroupNodeList,\r
1822 ItsGroupNodeCount,\r
1823 &NodeIndexer\r
1824 );\r
1825 if (NodeSize > MAX_UINT32) {\r
1826 Status = EFI_INVALID_PARAMETER;\r
1827 DEBUG ((\r
1828 DEBUG_ERROR,\r
1829 "ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n",\r
1830 Status\r
1831 ));\r
1832 goto error_handler;\r
1833 }\r
731c67e1 1834\r
8b2ac43b 1835 TableSize += NodeSize;\r
48179539
SM
1836\r
1837 DEBUG ((\r
1838 DEBUG_INFO,\r
1839 " ItsGroupNodeCount = %d\n" \\r
1840 " ItsGroupOffset = %d\n",\r
1841 ItsGroupNodeCount,\r
1842 ItsGroupOffset\r
1843 ));\r
dfaffc69
SM
1844 }\r
1845\r
1846 // Named Component Nodes\r
1847 if (NamedComponentNodeCount > 0) {\r
8b2ac43b 1848 NamedComponentOffset = (UINT32)TableSize;\r
dfaffc69 1849 // Size of Named Component node list.\r
8b2ac43b
SM
1850 NodeSize = GetSizeofNamedComponentNodes (\r
1851 NamedComponentOffset,\r
1852 NamedComponentNodeList,\r
1853 NamedComponentNodeCount,\r
1854 &NodeIndexer\r
1855 );\r
1856 if (NodeSize > MAX_UINT32) {\r
1857 Status = EFI_INVALID_PARAMETER;\r
1858 DEBUG ((\r
1859 DEBUG_ERROR,\r
1860 "ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n",\r
1861 Status\r
1862 ));\r
1863 goto error_handler;\r
1864 }\r
731c67e1 1865\r
8b2ac43b 1866 TableSize += NodeSize;\r
48179539
SM
1867\r
1868 DEBUG ((\r
1869 DEBUG_INFO,\r
1870 " NamedComponentNodeCount = %d\n" \\r
1871 " NamedComponentOffset = %d\n",\r
1872 NamedComponentNodeCount,\r
1873 NamedComponentOffset\r
1874 ));\r
dfaffc69
SM
1875 }\r
1876\r
1877 // Root Complex Nodes\r
1878 if (RootComplexNodeCount > 0) {\r
8b2ac43b 1879 RootComplexOffset = (UINT32)TableSize;\r
dfaffc69 1880 // Size of Root Complex node list.\r
8b2ac43b
SM
1881 NodeSize = GetSizeofRootComplexNodes (\r
1882 RootComplexOffset,\r
1883 RootComplexNodeList,\r
1884 RootComplexNodeCount,\r
1885 &NodeIndexer\r
1886 );\r
1887 if (NodeSize > MAX_UINT32) {\r
1888 Status = EFI_INVALID_PARAMETER;\r
1889 DEBUG ((\r
1890 DEBUG_ERROR,\r
1891 "ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n",\r
1892 Status\r
1893 ));\r
1894 goto error_handler;\r
1895 }\r
731c67e1 1896\r
8b2ac43b 1897 TableSize += NodeSize;\r
48179539
SM
1898\r
1899 DEBUG ((\r
1900 DEBUG_INFO,\r
1901 " RootComplexNodeCount = %d\n" \\r
1902 " RootComplexOffset = %d\n",\r
1903 RootComplexNodeCount,\r
1904 RootComplexOffset\r
1905 ));\r
dfaffc69
SM
1906 }\r
1907\r
1908 // SMMUv1/SMMUv2 Nodes\r
1909 if (SmmuV1V2NodeCount > 0) {\r
8b2ac43b 1910 SmmuV1V2Offset = (UINT32)TableSize;\r
dfaffc69 1911 // Size of SMMUv1/SMMUv2 node list.\r
8b2ac43b
SM
1912 NodeSize = GetSizeofSmmuV1V2Nodes (\r
1913 SmmuV1V2Offset,\r
1914 SmmuV1V2NodeList,\r
1915 SmmuV1V2NodeCount,\r
1916 &NodeIndexer\r
1917 );\r
1918 if (NodeSize > MAX_UINT32) {\r
1919 Status = EFI_INVALID_PARAMETER;\r
1920 DEBUG ((\r
1921 DEBUG_ERROR,\r
1922 "ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n",\r
1923 Status\r
1924 ));\r
1925 goto error_handler;\r
1926 }\r
731c67e1 1927\r
8b2ac43b 1928 TableSize += NodeSize;\r
48179539
SM
1929\r
1930 DEBUG ((\r
1931 DEBUG_INFO,\r
1932 " SmmuV1V2NodeCount = %d\n" \\r
1933 " SmmuV1V2Offset = %d\n",\r
1934 SmmuV1V2NodeCount,\r
1935 SmmuV1V2Offset\r
1936 ));\r
dfaffc69
SM
1937 }\r
1938\r
1939 // SMMUv3 Nodes\r
1940 if (SmmuV3NodeCount > 0) {\r
8b2ac43b 1941 SmmuV3Offset = (UINT32)TableSize;\r
dfaffc69 1942 // Size of SMMUv3 node list.\r
8b2ac43b
SM
1943 NodeSize = GetSizeofSmmuV3Nodes (\r
1944 SmmuV3Offset,\r
1945 SmmuV3NodeList,\r
1946 SmmuV3NodeCount,\r
1947 &NodeIndexer\r
1948 );\r
1949 if (NodeSize > MAX_UINT32) {\r
1950 Status = EFI_INVALID_PARAMETER;\r
1951 DEBUG ((\r
1952 DEBUG_ERROR,\r
1953 "ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n",\r
1954 Status\r
1955 ));\r
1956 goto error_handler;\r
1957 }\r
731c67e1 1958\r
8b2ac43b 1959 TableSize += NodeSize;\r
48179539
SM
1960\r
1961 DEBUG ((\r
1962 DEBUG_INFO,\r
1963 " SmmuV3NodeCount = %d\n" \\r
1964 " SmmuV3Offset = %d\n",\r
1965 SmmuV3NodeCount,\r
1966 SmmuV3Offset\r
1967 ));\r
dfaffc69
SM
1968 }\r
1969\r
1970 // PMCG Nodes\r
1971 if (PmcgNodeCount > 0) {\r
8b2ac43b 1972 PmcgOffset = (UINT32)TableSize;\r
dfaffc69 1973 // Size of PMCG node list.\r
8b2ac43b
SM
1974 NodeSize = GetSizeofPmcgNodes (\r
1975 PmcgOffset,\r
1976 PmcgNodeList,\r
1977 PmcgNodeCount,\r
1978 &NodeIndexer\r
1979 );\r
1980 if (NodeSize > MAX_UINT32) {\r
1981 Status = EFI_INVALID_PARAMETER;\r
1982 DEBUG ((\r
1983 DEBUG_ERROR,\r
1984 "ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n",\r
1985 Status\r
1986 ));\r
1987 goto error_handler;\r
1988 }\r
731c67e1 1989\r
8b2ac43b 1990 TableSize += NodeSize;\r
48179539
SM
1991\r
1992 DEBUG ((\r
1993 DEBUG_INFO,\r
1994 " PmcgNodeCount = %d\n" \\r
1995 " PmcgOffset = %d\n",\r
1996 PmcgNodeCount,\r
1997 PmcgOffset\r
1998 ));\r
dfaffc69
SM
1999 }\r
2000\r
2001 DEBUG ((\r
2002 DEBUG_INFO,\r
2003 "INFO: IORT:\n" \\r
2004 " IortNodeCount = %d\n" \\r
8b2ac43b 2005 " TableSize = 0x%lx\n",\r
dfaffc69
SM
2006 IortNodeCount,\r
2007 TableSize\r
2008 ));\r
2009\r
8b2ac43b
SM
2010 if (TableSize > MAX_UINT32) {\r
2011 Status = EFI_INVALID_PARAMETER;\r
2012 DEBUG ((\r
2013 DEBUG_ERROR,\r
2014 "ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \\r
2015 " Status = %r\n",\r
2016 TableSize,\r
2017 Status\r
2018 ));\r
2019 goto error_handler;\r
2020 }\r
2021\r
dfaffc69 2022 // Allocate the Buffer for IORT table\r
731c67e1 2023 *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);\r
dfaffc69
SM
2024 if (*Table == NULL) {\r
2025 Status = EFI_OUT_OF_RESOURCES;\r
2026 DEBUG ((\r
2027 DEBUG_ERROR,\r
2028 "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \\r
2029 " Status = %r\n",\r
2030 TableSize,\r
2031 Status\r
2032 ));\r
2033 goto error_handler;\r
2034 }\r
2035\r
731c67e1 2036 Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE *)*Table;\r
dfaffc69
SM
2037\r
2038 DEBUG ((\r
2039 DEBUG_INFO,\r
8b2ac43b 2040 "IORT: Iort = 0x%p TableSize = 0x%lx\n",\r
dfaffc69
SM
2041 Iort,\r
2042 TableSize\r
2043 ));\r
2044\r
2045 Status = AddAcpiHeader (\r
2046 CfgMgrProtocol,\r
2047 This,\r
2048 &Iort->Header,\r
e12bdeb1 2049 AcpiTableInfo,\r
8b2ac43b 2050 (UINT32)TableSize\r
dfaffc69
SM
2051 );\r
2052 if (EFI_ERROR (Status)) {\r
2053 DEBUG ((\r
2054 DEBUG_ERROR,\r
2055 "ERROR: IORT: Failed to add ACPI header. Status = %r\n",\r
2056 Status\r
2057 ));\r
2058 goto error_handler;\r
2059 }\r
2060\r
2061 // Update IORT table\r
731c67e1 2062 Iort->NumNodes = IortNodeCount;\r
dfaffc69 2063 Iort->NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);\r
731c67e1 2064 Iort->Reserved = EFI_ACPI_RESERVED_DWORD;\r
dfaffc69
SM
2065\r
2066 if (ItsGroupNodeCount > 0) {\r
2067 Status = AddItsGroupNodes (\r
2068 This,\r
2069 CfgMgrProtocol,\r
2070 Iort,\r
2071 ItsGroupOffset,\r
2072 ItsGroupNodeList,\r
2073 ItsGroupNodeCount\r
2074 );\r
2075 if (EFI_ERROR (Status)) {\r
2076 DEBUG ((\r
2077 DEBUG_ERROR,\r
2078 "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",\r
2079 Status\r
2080 ));\r
2081 goto error_handler;\r
2082 }\r
2083 }\r
2084\r
2085 if (NamedComponentNodeCount > 0) {\r
2086 Status = AddNamedComponentNodes (\r
2087 This,\r
2088 CfgMgrProtocol,\r
2089 Iort,\r
2090 NamedComponentOffset,\r
2091 NamedComponentNodeList,\r
2092 NamedComponentNodeCount\r
2093 );\r
2094 if (EFI_ERROR (Status)) {\r
2095 DEBUG ((\r
2096 DEBUG_ERROR,\r
2097 "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",\r
2098 Status\r
2099 ));\r
2100 goto error_handler;\r
2101 }\r
2102 }\r
2103\r
2104 if (RootComplexNodeCount > 0) {\r
2105 Status = AddRootComplexNodes (\r
2106 This,\r
2107 CfgMgrProtocol,\r
2108 Iort,\r
2109 RootComplexOffset,\r
2110 RootComplexNodeList,\r
2111 RootComplexNodeCount\r
2112 );\r
2113 if (EFI_ERROR (Status)) {\r
2114 DEBUG ((\r
2115 DEBUG_ERROR,\r
2116 "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",\r
2117 Status\r
2118 ));\r
2119 goto error_handler;\r
2120 }\r
2121 }\r
2122\r
2123 if (SmmuV1V2NodeCount > 0) {\r
2124 Status = AddSmmuV1V2Nodes (\r
2125 This,\r
2126 CfgMgrProtocol,\r
2127 Iort,\r
2128 SmmuV1V2Offset,\r
2129 SmmuV1V2NodeList,\r
2130 SmmuV1V2NodeCount\r
2131 );\r
2132 if (EFI_ERROR (Status)) {\r
2133 DEBUG ((\r
2134 DEBUG_ERROR,\r
2135 "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",\r
2136 Status\r
2137 ));\r
2138 goto error_handler;\r
2139 }\r
2140 }\r
2141\r
2142 if (SmmuV3NodeCount > 0) {\r
2143 Status = AddSmmuV3Nodes (\r
2144 This,\r
2145 CfgMgrProtocol,\r
2146 Iort,\r
2147 SmmuV3Offset,\r
2148 SmmuV3NodeList,\r
2149 SmmuV3NodeCount\r
2150 );\r
2151 if (EFI_ERROR (Status)) {\r
2152 DEBUG ((\r
2153 DEBUG_ERROR,\r
2154 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",\r
2155 Status\r
2156 ));\r
2157 goto error_handler;\r
2158 }\r
2159 }\r
2160\r
2161 if (PmcgNodeCount > 0) {\r
2162 Status = AddPmcgNodes (\r
2163 This,\r
2164 CfgMgrProtocol,\r
2165 Iort,\r
2166 PmcgOffset,\r
2167 PmcgNodeList,\r
2168 PmcgNodeCount\r
2169 );\r
2170 if (EFI_ERROR (Status)) {\r
2171 DEBUG ((\r
2172 DEBUG_ERROR,\r
2173 "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",\r
2174 Status\r
2175 ));\r
2176 goto error_handler;\r
2177 }\r
2178 }\r
2179\r
2180 return EFI_SUCCESS;\r
2181\r
2182error_handler:\r
2183 if (Generator->NodeIndexer != NULL) {\r
2184 FreePool (Generator->NodeIndexer);\r
2185 Generator->NodeIndexer = NULL;\r
2186 }\r
2187\r
2188 if (*Table != NULL) {\r
2189 FreePool (*Table);\r
2190 *Table = NULL;\r
2191 }\r
731c67e1 2192\r
dfaffc69
SM
2193 return Status;\r
2194}\r
2195\r
2196/** Free any resources allocated for constructing the IORT\r
2197\r
2198 @param [in] This Pointer to the table generator.\r
2199 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
2200 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
2201 Protocol Interface.\r
2202 @param [in, out] Table Pointer to the ACPI Table.\r
2203\r
2204 @retval EFI_SUCCESS The resources were freed successfully.\r
2205 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
2206**/\r
2207STATIC\r
2208EFI_STATUS\r
2209FreeIortTableResources (\r
731c67e1
MK
2210 IN CONST ACPI_TABLE_GENERATOR *CONST This,\r
2211 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,\r
2212 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,\r
2213 IN OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table\r
dfaffc69
SM
2214 )\r
2215{\r
731c67e1
MK
2216 ACPI_IORT_GENERATOR *Generator;\r
2217\r
dfaffc69
SM
2218 ASSERT (This != NULL);\r
2219 ASSERT (AcpiTableInfo != NULL);\r
2220 ASSERT (CfgMgrProtocol != NULL);\r
2221 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
2222 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
2223\r
731c67e1 2224 Generator = (ACPI_IORT_GENERATOR *)This;\r
dfaffc69
SM
2225\r
2226 // Free any memory allocated by the generator\r
2227 if (Generator->NodeIndexer != NULL) {\r
2228 FreePool (Generator->NodeIndexer);\r
2229 Generator->NodeIndexer = NULL;\r
2230 }\r
2231\r
2232 if ((Table == NULL) || (*Table == NULL)) {\r
2233 DEBUG ((DEBUG_ERROR, "ERROR: IORT: Invalid Table Pointer\n"));\r
2234 ASSERT ((Table != NULL) && (*Table != NULL));\r
2235 return EFI_INVALID_PARAMETER;\r
2236 }\r
2237\r
2238 FreePool (*Table);\r
2239 *Table = NULL;\r
2240 return EFI_SUCCESS;\r
2241}\r
2242\r
2243/** The IORT Table Generator revision.\r
2244*/\r
731c67e1 2245#define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
dfaffc69
SM
2246\r
2247/** The interface for the MADT Table Generator.\r
2248*/\r
2249STATIC\r
731c67e1 2250ACPI_IORT_GENERATOR IortGenerator = {\r
dfaffc69
SM
2251 // ACPI table generator header\r
2252 {\r
2253 // Generator ID\r
2254 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort),\r
2255 // Generator Description\r
2256 L"ACPI.STD.IORT.GENERATOR",\r
2257 // ACPI Table Signature\r
2258 EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE,\r
2259 // ACPI Table Revision supported by this Generator\r
4c55f639 2260 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00,\r
dfaffc69 2261 // Minimum supported ACPI Table Revision\r
4c55f639 2262 EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00,\r
dfaffc69
SM
2263 // Creator ID\r
2264 TABLE_GENERATOR_CREATOR_ID_ARM,\r
2265 // Creator Revision\r
2266 IORT_GENERATOR_REVISION,\r
2267 // Build Table function\r
2268 BuildIortTable,\r
2269 // Free Resource function\r
2270 FreeIortTableResources,\r
2271 // Extended build function not needed\r
2272 NULL,\r
2273 // Extended build function not implemented by the generator.\r
2274 // Hence extended free resource function is not required.\r
2275 NULL\r
2276 },\r
2277\r
2278 // IORT Generator private data\r
2279\r
2280 // Iort Node count\r
2281 0,\r
2282 // Pointer to Iort node indexer\r
2283 NULL\r
2284};\r
2285\r
2286/** Register the Generator with the ACPI Table Factory.\r
2287\r
2288 @param [in] ImageHandle The handle to the image.\r
2289 @param [in] SystemTable Pointer to the System Table.\r
2290\r
2291 @retval EFI_SUCCESS The Generator is registered.\r
2292 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
2293 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
2294 is already registered.\r
2295**/\r
2296EFI_STATUS\r
2297EFIAPI\r
2298AcpiIortLibConstructor (\r
731c67e1
MK
2299 IN EFI_HANDLE ImageHandle,\r
2300 IN EFI_SYSTEM_TABLE *SystemTable\r
dfaffc69
SM
2301 )\r
2302{\r
2303 EFI_STATUS Status;\r
731c67e1 2304\r
dfaffc69
SM
2305 Status = RegisterAcpiTableGenerator (&IortGenerator.Header);\r
2306 DEBUG ((DEBUG_INFO, "IORT: Register Generator. Status = %r\n", Status));\r
2307 ASSERT_EFI_ERROR (Status);\r
2308 return Status;\r
2309}\r
2310\r
2311/** Deregister the Generator from the ACPI Table Factory.\r
2312\r
2313 @param [in] ImageHandle The handle to the image.\r
2314 @param [in] SystemTable Pointer to the System Table.\r
2315\r
2316 @retval EFI_SUCCESS The Generator is deregistered.\r
2317 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
2318 @retval EFI_NOT_FOUND The Generator is not registered.\r
2319**/\r
2320EFI_STATUS\r
2321EFIAPI\r
2322AcpiIortLibDestructor (\r
731c67e1
MK
2323 IN EFI_HANDLE ImageHandle,\r
2324 IN EFI_SYSTEM_TABLE *SystemTable\r
dfaffc69
SM
2325 )\r
2326{\r
2327 EFI_STATUS Status;\r
731c67e1 2328\r
dfaffc69
SM
2329 Status = DeregisterAcpiTableGenerator (&IortGenerator.Header);\r
2330 DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status));\r
2331 ASSERT_EFI_ERROR (Status);\r
2332 return Status;\r
2333}\r