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