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