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