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