2 SSDT Pcie Table Generator.
4 Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 - PCI Firmware Specification - Revision 3.0
10 - ACPI 6.4 specification:
11 - s6.2.13 "_PRT (PCI Routing Table)"
12 - s6.1.1 "_ADR (Address)"
14 - Arm Base Boot Requirements v1.0
15 - Arm Base System Architecture v1.0
18 #include <Library/AcpiLib.h>
19 #include <Library/BaseLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Protocol/AcpiTable.h>
25 // Module specific include files.
26 #include <AcpiTableGenerator.h>
27 #include <ConfigurationManagerObject.h>
28 #include <ConfigurationManagerHelper.h>
29 #include <Library/AcpiHelperLib.h>
30 #include <Library/TableHelperLib.h>
31 #include <Library/AmlLib/AmlLib.h>
32 #include <Library/SsdtPcieSupportLib.h>
33 #include <Protocol/ConfigurationManagerProtocol.h>
35 #include "SsdtPcieGenerator.h"
37 #define PCI_MAX_DEVICE_COUNT_PER_BUS 32
38 #define PCI_MAX_FUNCTION_COUNT_PER_DEVICE 8
40 /** ARM standard SSDT Pcie Table Generator.
43 The following Configuration Manager Object(s) are required by
46 - EArmObjPciConfigSpaceInfo
47 - EArmObjPciAddressMapInfo
48 - EArmObjPciInterruptMapInfo
51 /** This macro expands to a function that retrieves the cross-CM-object-
52 reference information from the Configuration Manager.
60 /** This macro expands to a function that retrieves the Pci
61 Configuration Space Information from the Configuration Manager.
65 EArmObjPciConfigSpaceInfo
,
66 CM_ARM_PCI_CONFIG_SPACE_INFO
69 /** This macro expands to a function that retrieves the Pci
70 Address Mapping Information from the Configuration Manager.
74 EArmObjPciAddressMapInfo
,
75 CM_ARM_PCI_ADDRESS_MAP_INFO
78 /** This macro expands to a function that retrieves the Pci
79 Interrupt Mapping Information from the Configuration Manager.
83 EArmObjPciInterruptMapInfo
,
84 CM_ARM_PCI_INTERRUPT_MAP_INFO
87 /** Initialize the MappingTable.
89 @param [in] MappingTable The mapping table structure.
90 @param [in] Count Number of entries to allocate in the
93 @retval EFI_SUCCESS Success.
94 @retval EFI_INVALID_PARAMETER Invalid parameter.
95 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
100 MappingTableInitialize (
101 IN MAPPING_TABLE
*MappingTable
,
107 if ((MappingTable
== NULL
) ||
111 return EFI_INVALID_PARAMETER
;
114 Table
= AllocateZeroPool (sizeof (*Table
) * Count
);
117 return EFI_OUT_OF_RESOURCES
;
120 MappingTable
->Table
= Table
;
121 MappingTable
->LastIndex
= 0;
122 MappingTable
->MaxIndex
= Count
;
127 /** Free the MappingTable.
129 @param [in, out] MappingTable The mapping table structure.
135 IN OUT MAPPING_TABLE
*MappingTable
138 ASSERT (MappingTable
!= NULL
);
139 ASSERT (MappingTable
->Table
!= NULL
);
141 if (MappingTable
->Table
!= NULL
) {
142 FreePool (MappingTable
->Table
);
146 /** Add a new entry to the MappingTable and return its index.
148 If an entry with [Integer] is already available in the table,
149 return its index without adding a new entry.
151 @param [in] MappingTable The mapping table structure.
152 @param [in] Integer New Integer entry to add.
154 @retval The index of the Integer entry in the MappingTable.
160 IN MAPPING_TABLE
*MappingTable
,
168 ASSERT (MappingTable
!= NULL
);
169 ASSERT (MappingTable
->Table
!= NULL
);
171 Table
= MappingTable
->Table
;
172 LastIndex
= MappingTable
->LastIndex
;
174 // Search if there is already an entry with this Integer.
175 for (Index
= 0; Index
< LastIndex
; Index
++) {
176 if (Table
[Index
] == Integer
) {
181 ASSERT (LastIndex
< MappingTable
->MaxIndex
);
183 // If no, create a new entry.
184 Table
[LastIndex
] = Integer
;
186 return MappingTable
->LastIndex
++;
189 /** Generate required Pci device information.
192 Name (_UID, <Uid>) // Uid of the Pci device
193 Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge
194 Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge
195 Name (_SEG, <Pci segment group>) // PCI Segment Group number
196 Name (_BBN, <Bus number>) // PCI Base Bus Number
197 Name (_CCA, 1) // Initially mark the PCI coherent
199 @param [in] PciInfo Pci device information.
200 @param [in] Uid Unique Id of the Pci device.
201 @param [in, out] PciNode Pci node to amend.
203 @retval EFI_SUCCESS Success.
204 @retval EFI_INVALID_PARAMETER Invalid parameter.
205 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
210 GeneratePciDeviceInfo (
211 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
213 IN OUT AML_OBJECT_NODE_HANDLE PciNode
219 ASSERT (PciInfo
!= NULL
);
220 ASSERT (PciNode
!= NULL
);
222 // ASL: Name (_UID, <Uid>)
223 Status
= AmlCodeGenNameInteger ("_UID", Uid
, PciNode
, NULL
);
224 if (EFI_ERROR (Status
)) {
229 // ASL: Name (_HID, EISAID ("PNP0A08"))
230 Status
= AmlGetEisaIdFromString ("PNP0A08", &EisaId
);
231 if (EFI_ERROR (Status
)) {
236 Status
= AmlCodeGenNameInteger ("_HID", EisaId
, PciNode
, NULL
);
237 if (EFI_ERROR (Status
)) {
242 // ASL: Name (_CID, EISAID ("PNP0A03"))
243 Status
= AmlGetEisaIdFromString ("PNP0A03", &EisaId
);
244 if (EFI_ERROR (Status
)) {
249 Status
= AmlCodeGenNameInteger ("_CID", EisaId
, PciNode
, NULL
);
250 if (EFI_ERROR (Status
)) {
255 // ASL: Name (_SEG, <Pci segment group>)
256 Status
= AmlCodeGenNameInteger (
258 PciInfo
->PciSegmentGroupNumber
,
262 if (EFI_ERROR (Status
)) {
267 // ASL: Name (_BBN, <Bus number>)
268 Status
= AmlCodeGenNameInteger (
270 PciInfo
->StartBusNumber
,
274 if (EFI_ERROR (Status
)) {
279 // ASL: Name (_CCA, 1)
280 // Must be aligned with the IORT CCA property in
281 // "Table 14 Memory access properties"
282 Status
= AmlCodeGenNameInteger ("_CCA", 1, PciNode
, NULL
);
283 ASSERT_EFI_ERROR (Status
);
287 /** Generate a _PRT object (Pci Routing Table) for the Pci device.
289 Cf. ACPI 6.4 specification, s6.2.13 "_PRT (PCI Routing Table)"
291 The first model (defining a _CRS object) is used. This is necessary because
292 PCI legacy interrupts are active low and GICv2 SPI interrupts are active
294 Even though PCI interrupts cannot be re-routed, only the first model allows
295 to specify the activation state (low/high).
297 @param [in] Generator The SSDT Pci generator.
298 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
300 @param [in] PciInfo Pci device information.
301 @param [in] Uid Unique Id of the Pci device.
302 @param [in, out] PciNode Pci node to amend.
304 @retval EFI_SUCCESS The function completed successfully.
305 @retval EFI_INVALID_PARAMETER Invalid parameter.
306 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
312 IN ACPI_PCI_GENERATOR
*Generator
,
313 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
314 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
316 IN OUT AML_OBJECT_NODE_HANDLE PciNode
321 AML_OBJECT_NODE_HANDLE PrtNode
;
322 CM_ARM_OBJ_REF
*RefInfo
;
324 CM_ARM_PCI_INTERRUPT_MAP_INFO
*IrqMapInfo
;
326 ASSERT (Generator
!= NULL
);
327 ASSERT (CfgMgrProtocol
!= NULL
);
328 ASSERT (PciInfo
!= NULL
);
329 ASSERT (PciNode
!= NULL
);
333 // Get the array of CM_ARM_OBJ_REF referencing the
334 // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
335 Status
= GetEArmObjCmRef (
337 PciInfo
->InterruptMapToken
,
341 if (EFI_ERROR (Status
)) {
346 // Initialized DeviceTable.
347 Status
= MappingTableInitialize (&Generator
->DeviceTable
, RefCount
);
348 if (EFI_ERROR (Status
)) {
353 // ASL: Name (_PRT, Package () {})
354 Status
= AmlCodeGenNamePackage ("_PRT", NULL
, &PrtNode
);
355 if (EFI_ERROR (Status
)) {
360 for (Index
= 0; Index
< RefCount
; Index
++) {
361 // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
362 Status
= GetEArmObjPciInterruptMapInfo (
364 RefInfo
[Index
].ReferenceToken
,
368 if (EFI_ERROR (Status
)) {
373 // Check that the interrupts flags are SPIs, level high.
374 // Cf. Arm BSA v1.0, sE.6 "Legacy interrupts"
376 (IrqMapInfo
->IntcInterrupt
.Interrupt
>= 32) &&
377 (IrqMapInfo
->IntcInterrupt
.Interrupt
< 1020) &&
378 ((IrqMapInfo
->IntcInterrupt
.Flags
& 0xB) != 0))
380 Status
= EFI_INVALID_PARAMETER
;
381 ASSERT_EFI_ERROR (Status
);
385 // Add the device to the DeviceTable.
386 MappingTableAdd (&Generator
->DeviceTable
, IrqMapInfo
->PciDevice
);
390 Name (_PRT, Package () {
396 ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
397 High word-Device #, Low word-Function #. (for example, device 3,
398 function 2 is 0x00030002). To refer to all the functions on a device #,
399 use a function number of FFFF).
401 Status
= AmlAddPrtEntry (
402 (IrqMapInfo
->PciDevice
<< 16) | 0xFFFF,
403 IrqMapInfo
->PciInterrupt
,
405 IrqMapInfo
->IntcInterrupt
.Interrupt
,
408 if (EFI_ERROR (Status
)) {
414 // Attach the _PRT entry.
415 Status
= AmlAttachNode (PciNode
, PrtNode
);
416 if (EFI_ERROR (Status
)) {
417 ASSERT_EFI_ERROR (Status
);
423 // Generate the Pci slots once all the device have been added.
424 Status
= GeneratePciSlots (PciInfo
, &Generator
->DeviceTable
, Uid
, PciNode
);
425 if (EFI_ERROR (Status
)) {
431 MappingTableFree (&Generator
->DeviceTable
);
433 if (PrtNode
!= NULL
) {
434 AmlDeleteTree (PrtNode
);
440 /** Generate a _CRS method for the Pci device.
442 @param [in] Generator The SSDT Pci generator.
443 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
445 @param [in] PciInfo Pci device information.
446 @param [in, out] PciNode Pci node to amend.
448 @retval EFI_SUCCESS The function completed successfully.
449 @retval EFI_INVALID_PARAMETER Invalid parameter.
450 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
456 IN ACPI_PCI_GENERATOR
*Generator
,
457 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
458 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
459 IN OUT AML_OBJECT_NODE_HANDLE PciNode
465 CM_ARM_OBJ_REF
*RefInfo
;
467 CM_ARM_PCI_ADDRESS_MAP_INFO
*AddrMapInfo
;
468 AML_OBJECT_NODE_HANDLE CrsNode
;
471 ASSERT (Generator
!= NULL
);
472 ASSERT (CfgMgrProtocol
!= NULL
);
473 ASSERT (PciInfo
!= NULL
);
474 ASSERT (PciNode
!= NULL
);
476 // ASL: Name (_CRS, ResourceTemplate () {})
477 Status
= AmlCodeGenNameResourceTemplate ("_CRS", PciNode
, &CrsNode
);
478 if (EFI_ERROR (Status
)) {
484 // WordBusNumber ( // Bus numbers assigned to this root
485 // ResourceProducer, MinFixed, MaxFixed, PosDecode,
486 // 0, // AddressGranularity
487 // <Start>, // AddressMinimum - Minimum Bus Number
488 // <End>, // AddressMaximum - Maximum Bus Number
489 // 0, // AddressTranslation - Set to 0
490 // <End> - <Start> + 1 // RangeLength - Number of Busses
492 Status
= AmlCodeGenRdWordBusNumber (
498 PciInfo
->StartBusNumber
,
499 PciInfo
->EndBusNumber
,
501 PciInfo
->EndBusNumber
- PciInfo
->StartBusNumber
+ 1,
507 if (EFI_ERROR (Status
)) {
512 // Get the array of CM_ARM_OBJ_REF referencing the
513 // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
514 Status
= GetEArmObjCmRef (
516 PciInfo
->AddressMapToken
,
520 if (EFI_ERROR (Status
)) {
525 for (Index
= 0; Index
< RefCount
; Index
++) {
526 // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
527 Status
= GetEArmObjPciAddressMapInfo (
529 RefInfo
[Index
].ReferenceToken
,
533 if (EFI_ERROR (Status
)) {
538 Translation
= (AddrMapInfo
->CpuAddress
!= AddrMapInfo
->PciAddress
);
539 if (AddrMapInfo
->CpuAddress
>= AddrMapInfo
->PciAddress
) {
545 switch (AddrMapInfo
->SpaceCode
) {
547 Status
= AmlCodeGenRdDWordIo (
554 AddrMapInfo
->PciAddress
,
555 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
556 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
557 AddrMapInfo
->AddressSize
,
568 Status
= AmlCodeGenRdDWordMemory (
576 AddrMapInfo
->PciAddress
,
577 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
578 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
579 AddrMapInfo
->AddressSize
,
590 Status
= AmlCodeGenRdQWordMemory (
598 AddrMapInfo
->PciAddress
,
599 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
600 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
601 AddrMapInfo
->AddressSize
,
612 Status
= EFI_INVALID_PARAMETER
;
615 if (EFI_ERROR (Status
)) {
624 /** Generate a RES0 device node to reserve PNP motherboard resources
625 for a given PCI node.
627 @param [in] PciNode Parent PCI node handle of the generated
629 @param [out] CrsNode CRS node of the AML tree to populate.
631 @retval EFI_SUCCESS The function completed successfully.
632 @retval EFI_INVALID_PARAMETER Invalid input parameter.
633 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
638 GenerateMotherboardDevice (
639 IN AML_OBJECT_NODE_HANDLE PciNode
,
640 OUT AML_OBJECT_NODE_HANDLE
*CrsNode
645 AML_OBJECT_NODE_HANDLE ResNode
;
647 if (CrsNode
== NULL
) {
649 return EFI_INVALID_PARAMETER
;
652 // ASL: Device (RES0) {}
653 Status
= AmlCodeGenDevice ("RES0", PciNode
, &ResNode
);
654 if (EFI_ERROR (Status
)) {
659 // ASL: Name (_HID, EISAID ("PNP0C02"))
660 Status
= AmlGetEisaIdFromString ("PNP0C02", &EisaId
); /* PNP Motherboard Resources */
661 if (EFI_ERROR (Status
)) {
666 Status
= AmlCodeGenNameInteger ("_HID", EisaId
, ResNode
, NULL
);
667 if (EFI_ERROR (Status
)) {
672 // ASL: Name (_CRS, ResourceTemplate () {})
673 Status
= AmlCodeGenNameResourceTemplate ("_CRS", ResNode
, CrsNode
);
674 if (EFI_ERROR (Status
)) {
682 /** Reserves ECAM space for PCI config space
684 @param [in] Generator The SSDT Pci generator.
685 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
687 @param [in] PciInfo Pci device information.
688 @param [in, out] PciNode RootNode of the AML tree to populate.
690 @retval EFI_SUCCESS The function completed successfully.
691 @retval EFI_INVALID_PARAMETER Invalid parameter.
692 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
698 IN ACPI_PCI_GENERATOR
*Generator
,
699 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
700 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
701 IN OUT AML_OBJECT_NODE_HANDLE PciNode
705 AML_OBJECT_NODE_HANDLE CrsNode
;
706 UINT64 AddressMinimum
;
707 UINT64 AddressMaximum
;
709 Status
= GenerateMotherboardDevice (PciNode
, &CrsNode
);
710 if (EFI_ERROR (Status
)) {
715 AddressMinimum
= PciInfo
->BaseAddress
+ (PciInfo
->StartBusNumber
*
716 PCI_MAX_DEVICE_COUNT_PER_BUS
* PCI_MAX_FUNCTION_COUNT_PER_DEVICE
* SIZE_4KB
);
717 AddressMaximum
= PciInfo
->BaseAddress
+ ((PciInfo
->EndBusNumber
+ 1) *
718 PCI_MAX_DEVICE_COUNT_PER_BUS
* PCI_MAX_FUNCTION_COUNT_PER_DEVICE
* SIZE_4KB
) - 1;
720 Status
= AmlCodeGenRdQWordMemory (
725 FALSE
, // non-cacheable
731 AddressMaximum
- AddressMinimum
+ 1,
740 if (EFI_ERROR (Status
)) {
748 /** Generate a Pci device.
750 @param [in] Generator The SSDT Pci generator.
751 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
753 @param [in] PciInfo Pci device information.
754 @param [in] Uid Unique Id of the Pci device.
755 @param [in, out] RootNode RootNode of the AML tree to populate.
757 @retval EFI_SUCCESS The function completed successfully.
758 @retval EFI_INVALID_PARAMETER Invalid parameter.
759 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
765 IN ACPI_PCI_GENERATOR
*Generator
,
766 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
767 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
769 IN OUT AML_ROOT_NODE_HANDLE
*RootNode
774 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
775 AML_OBJECT_NODE_HANDLE ScopeNode
;
776 AML_OBJECT_NODE_HANDLE PciNode
;
778 ASSERT (Generator
!= NULL
);
779 ASSERT (CfgMgrProtocol
!= NULL
);
780 ASSERT (PciInfo
!= NULL
);
781 ASSERT (RootNode
!= NULL
);
785 // ASL: Scope (\_SB) {}
786 Status
= AmlCodeGenScope (SB_SCOPE
, RootNode
, &ScopeNode
);
787 if (EFI_ERROR (Status
)) {
792 // Write the name of the PCI device.
793 CopyMem (AslName
, "PCIx", AML_NAME_SEG_SIZE
+ 1);
794 AslName
[AML_NAME_SEG_SIZE
- 1] = AsciiFromHex (Uid
& 0xF);
796 AslName
[AML_NAME_SEG_SIZE
- 2] = AsciiFromHex ((Uid
>> 4) & 0xF);
799 // ASL: Device (PCIx) {}
800 Status
= AmlCodeGenDevice (AslName
, ScopeNode
, &PciNode
);
801 if (EFI_ERROR (Status
)) {
806 // Populate the PCIx node with some Id values.
807 Status
= GeneratePciDeviceInfo (PciInfo
, Uid
, PciNode
);
808 if (EFI_ERROR (Status
)) {
813 // Generate the Pci Routing Table (_PRT).
814 if (PciInfo
->InterruptMapToken
!= CM_NULL_TOKEN
) {
815 Status
= GeneratePrt (
822 if (EFI_ERROR (Status
)) {
828 // Generate the _CRS method.
829 Status
= GeneratePciCrs (Generator
, CfgMgrProtocol
, PciInfo
, PciNode
);
830 if (EFI_ERROR (Status
)) {
835 // Add the PNP Motherboard Resources Device to reserve ECAM space
836 Status
= ReserveEcamSpace (Generator
, CfgMgrProtocol
, PciInfo
, PciNode
);
837 if (EFI_ERROR (Status
)) {
842 // Add the template _OSC method.
843 Status
= AddOscMethod (PciInfo
, PciNode
);
844 ASSERT_EFI_ERROR (Status
);
849 /** Build an Ssdt table describing a Pci device.
851 @param [in] Generator The SSDT Pci generator.
852 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
854 @param [in] AcpiTableInfo Pointer to the ACPI table information.
855 @param [in] PciInfo Pci device information.
856 @param [in] Uid Unique Id of the Pci device.
857 @param [out] Table If success, contains the created SSDT table.
859 @retval EFI_SUCCESS The function completed successfully.
860 @retval EFI_INVALID_PARAMETER Invalid parameter.
861 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
867 IN ACPI_PCI_GENERATOR
*Generator
,
868 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
869 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
870 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
872 OUT EFI_ACPI_DESCRIPTION_HEADER
**Table
877 AML_ROOT_NODE_HANDLE RootNode
;
879 ASSERT (Generator
!= NULL
);
880 ASSERT (CfgMgrProtocol
!= NULL
);
881 ASSERT (PciInfo
!= NULL
);
882 ASSERT (Table
!= NULL
);
884 // Create a new Ssdt table.
885 Status
= AddSsdtAcpiHeader (
891 if (EFI_ERROR (Status
)) {
896 Status
= GeneratePciDevice (
903 if (EFI_ERROR (Status
)) {
908 // Serialize the tree.
909 Status
= AmlSerializeDefinitionBlock (
913 if (EFI_ERROR (Status
)) {
916 "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
924 Status1
= AmlDeleteTree (RootNode
);
925 if (EFI_ERROR (Status1
)) {
928 "ERROR: SSDT-PCI: Failed to cleanup AML tree."
932 // If Status was success but we failed to delete the AML Tree
933 // return Status1 else return the original error code, i.e. Status.
934 if (!EFI_ERROR (Status
)) {
942 /** Construct SSDT tables describing Pci root complexes.
944 This function invokes the Configuration Manager protocol interface
945 to get the required hardware information for generating the ACPI
948 If this function allocates any resources then they must be freed
949 in the FreeXXXXTableResourcesEx function.
951 @param [in] This Pointer to the ACPI table generator.
952 @param [in] AcpiTableInfo Pointer to the ACPI table information.
953 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
955 @param [out] Table Pointer to a list of generated ACPI table(s).
956 @param [out] TableCount Number of generated ACPI table(s).
958 @retval EFI_SUCCESS Table generated successfully.
959 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
960 Manager is less than the Object size for
961 the requested object.
962 @retval EFI_INVALID_PARAMETER A parameter is invalid.
963 @retval EFI_NOT_FOUND Could not find information.
964 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
965 @retval EFI_UNSUPPORTED Unsupported configuration.
970 BuildSsdtPciTableEx (
971 IN CONST ACPI_TABLE_GENERATOR
*This
,
972 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
973 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
974 OUT EFI_ACPI_DESCRIPTION_HEADER
***Table
,
975 OUT UINTN
*CONST TableCount
979 CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
;
982 EFI_ACPI_DESCRIPTION_HEADER
**TableList
;
983 ACPI_PCI_GENERATOR
*Generator
;
986 ASSERT (This
!= NULL
);
987 ASSERT (AcpiTableInfo
!= NULL
);
988 ASSERT (CfgMgrProtocol
!= NULL
);
989 ASSERT (Table
!= NULL
);
990 ASSERT (TableCount
!= NULL
);
991 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
992 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
995 Generator
= (ACPI_PCI_GENERATOR
*)This
;
997 Status
= GetEArmObjPciConfigSpaceInfo (
1003 if (EFI_ERROR (Status
)) {
1008 if (PciCount
> MAX_PCI_ROOT_COMPLEXES_SUPPORTED
) {
1011 "ERROR: SSDT-PCI: Too many Pci root complexes: %d."
1012 " Maximum Pci root complexes supported = %d.\n",
1014 MAX_PCI_ROOT_COMPLEXES_SUPPORTED
1016 return EFI_INVALID_PARAMETER
;
1019 // Allocate a table to store pointers to the SSDT tables.
1020 TableList
= (EFI_ACPI_DESCRIPTION_HEADER
**)
1022 (sizeof (EFI_ACPI_DESCRIPTION_HEADER
*) * PciCount
)
1024 if (TableList
== NULL
) {
1025 Status
= EFI_OUT_OF_RESOURCES
;
1028 "ERROR: SSDT-PCI: Failed to allocate memory for Table List."
1035 // Setup the table list early so that appropriate cleanup
1036 // can be done in case of failure.
1039 for (Index
= 0; Index
< PciCount
; Index
++) {
1040 if (PcdGetBool (PcdPciUseSegmentAsUid
)) {
1041 Uid
= PciInfo
[Index
].PciSegmentGroupNumber
;
1042 if (Uid
> MAX_PCI_ROOT_COMPLEXES_SUPPORTED
) {
1045 "ERROR: SSDT-PCI: Pci root complexes segment number: %d."
1046 " Greater than maximum number of Pci root complexes supported = %d.\n",
1048 MAX_PCI_ROOT_COMPLEXES_SUPPORTED
1050 return EFI_INVALID_PARAMETER
;
1056 // Build a SSDT table describing the Pci devices.
1057 Status
= BuildSsdtPciTable (
1065 if (EFI_ERROR (Status
)) {
1068 "ERROR: SSDT-PCI: Failed to build associated SSDT table."
1079 // Note: Table list and Table count have been setup. The
1080 // error handler does nothing here as the framework will invoke
1081 // FreeSsdtPciTableEx () even on failure.
1085 /** Free any resources allocated for constructing the tables.
1087 @param [in] This Pointer to the ACPI table generator.
1088 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1089 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1091 @param [in, out] Table Pointer to an array of pointers
1093 @param [in] TableCount Number of ACPI table(s).
1095 @retval EFI_SUCCESS The resources were freed successfully.
1096 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1101 FreeSsdtPciTableEx (
1102 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1103 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1104 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1105 IN OUT EFI_ACPI_DESCRIPTION_HEADER
***CONST Table
,
1106 IN CONST UINTN TableCount
1109 EFI_ACPI_DESCRIPTION_HEADER
**TableList
;
1112 ASSERT (This
!= NULL
);
1113 ASSERT (AcpiTableInfo
!= NULL
);
1114 ASSERT (CfgMgrProtocol
!= NULL
);
1115 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1116 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1118 if ((Table
== NULL
) ||
1122 DEBUG ((DEBUG_ERROR
, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
1123 return EFI_INVALID_PARAMETER
;
1127 for (Index
= 0; Index
< TableCount
; Index
++) {
1128 if ((TableList
[Index
] != NULL
) &&
1129 (TableList
[Index
]->Signature
==
1130 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
))
1132 FreePool (TableList
[Index
]);
1136 "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
1139 return EFI_INVALID_PARAMETER
;
1143 // Free the table list.
1149 /** This macro defines the SSDT Pci Table Generator revision.
1151 #define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
1153 /** The interface for the SSDT Pci Table Generator.
1156 ACPI_PCI_GENERATOR SsdtPcieGenerator
= {
1157 // ACPI table generator header
1160 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress
),
1161 // Generator Description
1162 L
"ACPI.STD.SSDT.PCI.GENERATOR",
1163 // ACPI Table Signature
1164 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
,
1165 // ACPI Table Revision - Unused
1167 // Minimum ACPI Table Revision - Unused
1170 TABLE_GENERATOR_CREATOR_ID_ARM
,
1172 SSDT_PCI_GENERATOR_REVISION
,
1173 // Build table function. Use the extended version instead.
1175 // Free table function. Use the extended version instead.
1177 // Extended Build table function.
1178 BuildSsdtPciTableEx
,
1179 // Extended free function.
1183 // Private fields are defined from here.
1196 /** Register the Generator with the ACPI Table Factory.
1198 @param [in] ImageHandle The handle to the image.
1199 @param [in] SystemTable Pointer to the System Table.
1201 @retval EFI_SUCCESS The Generator is registered.
1202 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1203 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1204 is already registered.
1208 AcpiSsdtPcieLibConstructor (
1209 IN EFI_HANDLE ImageHandle
,
1210 IN EFI_SYSTEM_TABLE
*SystemTable
1215 Status
= RegisterAcpiTableGenerator (&SsdtPcieGenerator
.Header
);
1218 "SSDT-PCI: Register Generator. Status = %r\n",
1221 ASSERT_EFI_ERROR (Status
);
1225 /** Deregister the Generator from the ACPI Table Factory.
1227 @param [in] ImageHandle The handle to the image.
1228 @param [in] SystemTable Pointer to the System Table.
1230 @retval EFI_SUCCESS The Generator is deregistered.
1231 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1232 @retval EFI_NOT_FOUND The Generator is not registered.
1236 AcpiSsdtPcieLibDestructor (
1237 IN EFI_HANDLE ImageHandle
,
1238 IN EFI_SYSTEM_TABLE
*SystemTable
1243 Status
= DeregisterAcpiTableGenerator (&SsdtPcieGenerator
.Header
);
1246 "SSDT-PCI: Deregister Generator. Status = %r\n",
1249 ASSERT_EFI_ERROR (Status
);