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