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