]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
DynamicTablesPkg: Arm IORT Table Generator
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiIortLibArm / IortGenerator.c
CommitLineData
dfaffc69
SM
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
37Requirements:\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 - EArmObjIdMapping\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
54GET_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
63GET_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
72GET_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
81GET_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
90GET_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
99GET_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
108GET_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
117GET_OBJECT_LIST (\r
118 EObjNameSpaceArm,\r
119 EArmObjIdMapping,\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
126GET_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
138STATIC\r
139UINT32\r
140GetItsGroupNodeSize (\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
168STATIC\r
169UINT32\r
170GetSizeofItsGroupNodes (\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
208STATIC\r
209UINT32\r
210GetNamedComponentNodeSize (\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
241STATIC\r
242UINT32\r
243GetSizeofNamedComponentNodes (\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
282STATIC\r
283UINT32\r
284GetRootComplexNodeSize (\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
313STATIC\r
314UINT32\r
315GetSizeofRootComplexNodes (\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
354STATIC\r
355UINT32\r
356GetSmmuV1V2NodeSize (\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
391STATIC\r
392UINT32\r
393GetSizeofSmmuV1V2Nodes (\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
431STATIC\r
432UINT32\r
433GetSmmuV3NodeSize (\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
462STATIC\r
463UINT32\r
464GetSizeofSmmuV3Nodes (\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
502STATIC\r
503UINT32\r
504GetPmcgNodeSize (\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
533STATIC\r
534UINT32\r
535GetSizeofPmcgNodes (\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
579STATIC\r
580EFI_STATUS\r
581GetNodeOffsetReferencedByToken (\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
636STATIC\r
637EFI_STATUS\r
638AddIdMappingArray (\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 = GetEArmObjIdMapping (\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
727STATIC\r
728EFI_STATUS\r
729AddItsGroupNodes (\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
820STATIC\r
821EFI_STATUS\r
822AddNamedComponentNodes (\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
931STATIC\r
932EFI_STATUS\r
933AddRootComplexNodes (\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
1019STATIC\r
1020EFI_STATUS\r
1021AddSmmuInterrruptArray (\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
1085STATIC\r
1086EFI_STATUS\r
1087AddSmmuV1V2Nodes (\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
1234STATIC\r
1235EFI_STATUS\r
1236AddSmmuV3Nodes (\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
1338STATIC\r
1339EFI_STATUS\r
1340AddPmcgNodes (\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
1446STATIC\r
1447EFI_STATUS\r
1448EFIAPI\r
1449BuildIortTable (\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
1934error_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
1958STATIC\r
1959EFI_STATUS\r
1960FreeIortTableResources (\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
1999STATIC\r
2000ACPI_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
2046EFI_STATUS\r
2047EFIAPI\r
2048AcpiIortLibConstructor (\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
2069EFI_STATUS\r
2070EFIAPI\r
2071AcpiIortLibDestructor (\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