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, out] PciNode Pci node to amend.
303 @retval EFI_SUCCESS The function completed successfully.
304 @retval EFI_INVALID_PARAMETER Invalid parameter.
305 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
311 IN ACPI_PCI_GENERATOR
*Generator
,
312 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
313 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
314 IN OUT AML_OBJECT_NODE_HANDLE PciNode
319 AML_OBJECT_NODE_HANDLE PrtNode
;
320 CM_ARM_OBJ_REF
*RefInfo
;
322 CM_ARM_PCI_INTERRUPT_MAP_INFO
*IrqMapInfo
;
324 ASSERT (Generator
!= NULL
);
325 ASSERT (CfgMgrProtocol
!= NULL
);
326 ASSERT (PciInfo
!= NULL
);
327 ASSERT (PciNode
!= NULL
);
331 // Get the array of CM_ARM_OBJ_REF referencing the
332 // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
333 Status
= GetEArmObjCmRef (
335 PciInfo
->InterruptMapToken
,
339 if (EFI_ERROR (Status
)) {
344 // Initialized DeviceTable.
345 Status
= MappingTableInitialize (&Generator
->DeviceTable
, RefCount
);
346 if (EFI_ERROR (Status
)) {
351 // ASL: Name (_PRT, Package () {})
352 Status
= AmlCodeGenNamePackage ("_PRT", NULL
, &PrtNode
);
353 if (EFI_ERROR (Status
)) {
358 for (Index
= 0; Index
< RefCount
; Index
++) {
359 // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
360 Status
= GetEArmObjPciInterruptMapInfo (
362 RefInfo
[Index
].ReferenceToken
,
366 if (EFI_ERROR (Status
)) {
371 // Check that the interrupts flags are SPIs, level high.
372 // Cf. Arm BSA v1.0, sE.6 "Legacy interrupts"
374 (IrqMapInfo
->IntcInterrupt
.Interrupt
>= 32) &&
375 (IrqMapInfo
->IntcInterrupt
.Interrupt
< 1020) &&
376 ((IrqMapInfo
->IntcInterrupt
.Flags
& 0xB) != 0))
378 Status
= EFI_INVALID_PARAMETER
;
379 ASSERT_EFI_ERROR (Status
);
383 // Add the device to the DeviceTable.
384 MappingTableAdd (&Generator
->DeviceTable
, IrqMapInfo
->PciDevice
);
388 Name (_PRT, Package () {
394 ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
395 High word-Device #, Low word-Function #. (for example, device 3,
396 function 2 is 0x00030002). To refer to all the functions on a device #,
397 use a function number of FFFF).
399 Status
= AmlAddPrtEntry (
400 (IrqMapInfo
->PciDevice
<< 16) | 0xFFFF,
401 IrqMapInfo
->PciInterrupt
,
403 IrqMapInfo
->IntcInterrupt
.Interrupt
,
406 if (EFI_ERROR (Status
)) {
412 // Attach the _PRT entry.
413 Status
= AmlAttachNode (PciNode
, PrtNode
);
414 if (EFI_ERROR (Status
)) {
415 ASSERT_EFI_ERROR (Status
);
421 // Generate the Pci slots once all the device have been added.
422 Status
= GeneratePciSlots (PciInfo
, &Generator
->DeviceTable
, PciNode
);
423 if (EFI_ERROR (Status
)) {
429 MappingTableFree (&Generator
->DeviceTable
);
431 if (PrtNode
!= NULL
) {
432 AmlDeleteTree (PrtNode
);
438 /** Generate a _CRS method for the Pci device.
440 @param [in] Generator The SSDT Pci generator.
441 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
443 @param [in] PciInfo Pci device information.
444 @param [in, out] PciNode Pci node to amend.
446 @retval EFI_SUCCESS The function completed successfully.
447 @retval EFI_INVALID_PARAMETER Invalid parameter.
448 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
454 IN ACPI_PCI_GENERATOR
*Generator
,
455 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
456 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
457 IN OUT AML_OBJECT_NODE_HANDLE PciNode
463 CM_ARM_OBJ_REF
*RefInfo
;
465 CM_ARM_PCI_ADDRESS_MAP_INFO
*AddrMapInfo
;
466 AML_OBJECT_NODE_HANDLE CrsNode
;
469 ASSERT (Generator
!= NULL
);
470 ASSERT (CfgMgrProtocol
!= NULL
);
471 ASSERT (PciInfo
!= NULL
);
472 ASSERT (PciNode
!= NULL
);
474 // ASL: Name (_CRS, ResourceTemplate () {})
475 Status
= AmlCodeGenNameResourceTemplate ("_CRS", PciNode
, &CrsNode
);
476 if (EFI_ERROR (Status
)) {
482 // WordBusNumber ( // Bus numbers assigned to this root
483 // ResourceProducer, MinFixed, MaxFixed, PosDecode,
484 // 0, // AddressGranularity
485 // <Start>, // AddressMinimum - Minimum Bus Number
486 // <End>, // AddressMaximum - Maximum Bus Number
487 // 0, // AddressTranslation - Set to 0
488 // <End> - <Start> + 1 // RangeLength - Number of Busses
490 Status
= AmlCodeGenRdWordBusNumber (
496 PciInfo
->StartBusNumber
,
497 PciInfo
->EndBusNumber
,
499 PciInfo
->EndBusNumber
- PciInfo
->StartBusNumber
+ 1,
505 if (EFI_ERROR (Status
)) {
510 // Get the array of CM_ARM_OBJ_REF referencing the
511 // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
512 Status
= GetEArmObjCmRef (
514 PciInfo
->AddressMapToken
,
518 if (EFI_ERROR (Status
)) {
523 for (Index
= 0; Index
< RefCount
; Index
++) {
524 // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
525 Status
= GetEArmObjPciAddressMapInfo (
527 RefInfo
[Index
].ReferenceToken
,
531 if (EFI_ERROR (Status
)) {
536 Translation
= (AddrMapInfo
->CpuAddress
!= AddrMapInfo
->PciAddress
);
537 if (AddrMapInfo
->CpuAddress
>= AddrMapInfo
->PciAddress
) {
543 switch (AddrMapInfo
->SpaceCode
) {
545 Status
= AmlCodeGenRdDWordIo (
552 AddrMapInfo
->PciAddress
,
553 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
554 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
555 AddrMapInfo
->AddressSize
,
566 Status
= AmlCodeGenRdDWordMemory (
574 AddrMapInfo
->PciAddress
,
575 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
576 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
577 AddrMapInfo
->AddressSize
,
588 Status
= AmlCodeGenRdQWordMemory (
596 AddrMapInfo
->PciAddress
,
597 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
598 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
599 AddrMapInfo
->AddressSize
,
610 Status
= EFI_INVALID_PARAMETER
;
613 if (EFI_ERROR (Status
)) {
622 /** Generate a RES0 device node to reserve PNP motherboard resources
623 for a given PCI node.
625 @param [in] PciNode Parent PCI node handle of the generated
627 @param [out] CrsNode CRS node of the AML tree to populate.
629 @retval EFI_SUCCESS The function completed successfully.
630 @retval EFI_INVALID_PARAMETER Invalid input parameter.
631 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
636 GenerateMotherboardDevice (
637 IN AML_OBJECT_NODE_HANDLE PciNode
,
638 OUT AML_OBJECT_NODE_HANDLE
*CrsNode
643 AML_OBJECT_NODE_HANDLE ResNode
;
645 if (CrsNode
== NULL
) {
647 return EFI_INVALID_PARAMETER
;
650 // ASL: Device (RES0) {}
651 Status
= AmlCodeGenDevice ("RES0", PciNode
, &ResNode
);
652 if (EFI_ERROR (Status
)) {
657 // ASL: Name (_HID, EISAID ("PNP0C02"))
658 Status
= AmlGetEisaIdFromString ("PNP0C02", &EisaId
); /* PNP Motherboard Resources */
659 if (EFI_ERROR (Status
)) {
664 Status
= AmlCodeGenNameInteger ("_HID", EisaId
, ResNode
, NULL
);
665 if (EFI_ERROR (Status
)) {
670 // ASL: Name (_CRS, ResourceTemplate () {})
671 Status
= AmlCodeGenNameResourceTemplate ("_CRS", ResNode
, CrsNode
);
672 if (EFI_ERROR (Status
)) {
680 /** Reserves ECAM space for PCI config space
682 @param [in] Generator The SSDT Pci generator.
683 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
685 @param [in] PciInfo Pci device information.
686 @param [in, out] PciNode RootNode of the AML tree to populate.
688 @retval EFI_SUCCESS The function completed successfully.
689 @retval EFI_INVALID_PARAMETER Invalid parameter.
690 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
696 IN ACPI_PCI_GENERATOR
*Generator
,
697 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
698 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
699 IN OUT AML_OBJECT_NODE_HANDLE PciNode
703 AML_OBJECT_NODE_HANDLE CrsNode
;
704 UINT64 AddressMinimum
;
705 UINT64 AddressMaximum
;
707 Status
= GenerateMotherboardDevice (PciNode
, &CrsNode
);
708 if (EFI_ERROR (Status
)) {
713 AddressMinimum
= PciInfo
->BaseAddress
+ (PciInfo
->StartBusNumber
*
714 PCI_MAX_DEVICE_COUNT_PER_BUS
* PCI_MAX_FUNCTION_COUNT_PER_DEVICE
* SIZE_4KB
);
715 AddressMaximum
= PciInfo
->BaseAddress
+ ((PciInfo
->EndBusNumber
+ 1) *
716 PCI_MAX_DEVICE_COUNT_PER_BUS
* PCI_MAX_FUNCTION_COUNT_PER_DEVICE
* SIZE_4KB
) - 1;
718 Status
= AmlCodeGenRdQWordMemory (
723 FALSE
, // non-cacheable
729 AddressMaximum
- AddressMinimum
+ 1,
738 if (EFI_ERROR (Status
)) {
746 /** Generate a Pci device.
748 @param [in] Generator The SSDT Pci generator.
749 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
751 @param [in] PciInfo Pci device information.
752 @param [in] Uid Unique Id of the Pci device.
753 @param [in, out] RootNode RootNode of the AML tree to populate.
755 @retval EFI_SUCCESS The function completed successfully.
756 @retval EFI_INVALID_PARAMETER Invalid parameter.
757 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
763 IN ACPI_PCI_GENERATOR
*Generator
,
764 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
765 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
767 IN OUT AML_ROOT_NODE_HANDLE
*RootNode
772 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
773 AML_OBJECT_NODE_HANDLE ScopeNode
;
774 AML_OBJECT_NODE_HANDLE PciNode
;
776 ASSERT (Generator
!= NULL
);
777 ASSERT (CfgMgrProtocol
!= NULL
);
778 ASSERT (PciInfo
!= NULL
);
779 ASSERT (RootNode
!= NULL
);
783 // ASL: Scope (\_SB) {}
784 Status
= AmlCodeGenScope (SB_SCOPE
, RootNode
, &ScopeNode
);
785 if (EFI_ERROR (Status
)) {
790 // Write the name of the PCI device.
791 CopyMem (AslName
, "PCIx", AML_NAME_SEG_SIZE
+ 1);
792 AslName
[AML_NAME_SEG_SIZE
- 1] = AsciiFromHex (Uid
& 0xF);
794 AslName
[AML_NAME_SEG_SIZE
- 2] = AsciiFromHex ((Uid
>> 4) & 0xF);
797 // ASL: Device (PCIx) {}
798 Status
= AmlCodeGenDevice (AslName
, ScopeNode
, &PciNode
);
799 if (EFI_ERROR (Status
)) {
804 // Populate the PCIx node with some Id values.
805 Status
= GeneratePciDeviceInfo (PciInfo
, Uid
, PciNode
);
806 if (EFI_ERROR (Status
)) {
811 // Generate the Pci Routing Table (_PRT).
812 if (PciInfo
->InterruptMapToken
!= CM_NULL_TOKEN
) {
813 Status
= GeneratePrt (
819 if (EFI_ERROR (Status
)) {
825 // Generate the _CRS method.
826 Status
= GeneratePciCrs (Generator
, CfgMgrProtocol
, PciInfo
, PciNode
);
827 if (EFI_ERROR (Status
)) {
832 // Add the PNP Motherboard Resources Device to reserve ECAM space
833 Status
= ReserveEcamSpace (Generator
, CfgMgrProtocol
, PciInfo
, PciNode
);
834 if (EFI_ERROR (Status
)) {
839 // Add the template _OSC method.
840 Status
= AddOscMethod (PciInfo
, PciNode
);
841 ASSERT_EFI_ERROR (Status
);
846 /** Build an Ssdt table describing a Pci device.
848 @param [in] Generator The SSDT Pci generator.
849 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
851 @param [in] AcpiTableInfo Pointer to the ACPI table information.
852 @param [in] PciInfo Pci device information.
853 @param [in] Uid Unique Id of the Pci device.
854 @param [out] Table If success, contains the created SSDT table.
856 @retval EFI_SUCCESS The function completed successfully.
857 @retval EFI_INVALID_PARAMETER Invalid parameter.
858 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
864 IN ACPI_PCI_GENERATOR
*Generator
,
865 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
866 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
867 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
869 OUT EFI_ACPI_DESCRIPTION_HEADER
**Table
874 AML_ROOT_NODE_HANDLE RootNode
;
876 ASSERT (Generator
!= NULL
);
877 ASSERT (CfgMgrProtocol
!= NULL
);
878 ASSERT (PciInfo
!= NULL
);
879 ASSERT (Table
!= NULL
);
881 // Create a new Ssdt table.
882 Status
= AddSsdtAcpiHeader (
888 if (EFI_ERROR (Status
)) {
893 Status
= GeneratePciDevice (
900 if (EFI_ERROR (Status
)) {
905 // Serialize the tree.
906 Status
= AmlSerializeDefinitionBlock (
910 if (EFI_ERROR (Status
)) {
913 "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
921 Status1
= AmlDeleteTree (RootNode
);
922 if (EFI_ERROR (Status1
)) {
925 "ERROR: SSDT-PCI: Failed to cleanup AML tree."
929 // If Status was success but we failed to delete the AML Tree
930 // return Status1 else return the original error code, i.e. Status.
931 if (!EFI_ERROR (Status
)) {
939 /** Construct SSDT tables describing Pci root complexes.
941 This function invokes the Configuration Manager protocol interface
942 to get the required hardware information for generating the ACPI
945 If this function allocates any resources then they must be freed
946 in the FreeXXXXTableResourcesEx function.
948 @param [in] This Pointer to the ACPI table generator.
949 @param [in] AcpiTableInfo Pointer to the ACPI table information.
950 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
952 @param [out] Table Pointer to a list of generated ACPI table(s).
953 @param [out] TableCount Number of generated ACPI table(s).
955 @retval EFI_SUCCESS Table generated successfully.
956 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
957 Manager is less than the Object size for
958 the requested object.
959 @retval EFI_INVALID_PARAMETER A parameter is invalid.
960 @retval EFI_NOT_FOUND Could not find information.
961 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
962 @retval EFI_UNSUPPORTED Unsupported configuration.
967 BuildSsdtPciTableEx (
968 IN CONST ACPI_TABLE_GENERATOR
*This
,
969 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
970 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
971 OUT EFI_ACPI_DESCRIPTION_HEADER
***Table
,
972 OUT UINTN
*CONST TableCount
976 CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
;
979 EFI_ACPI_DESCRIPTION_HEADER
**TableList
;
980 ACPI_PCI_GENERATOR
*Generator
;
982 ASSERT (This
!= NULL
);
983 ASSERT (AcpiTableInfo
!= NULL
);
984 ASSERT (CfgMgrProtocol
!= NULL
);
985 ASSERT (Table
!= NULL
);
986 ASSERT (TableCount
!= NULL
);
987 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
988 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
991 Generator
= (ACPI_PCI_GENERATOR
*)This
;
993 Status
= GetEArmObjPciConfigSpaceInfo (
999 if (EFI_ERROR (Status
)) {
1004 if (PciCount
> MAX_PCI_ROOT_COMPLEXES_SUPPORTED
) {
1007 "ERROR: SSDT-PCI: Too many Pci root complexes: %d."
1008 " Maximum Pci root complexes supported = %d.\n",
1010 MAX_PCI_ROOT_COMPLEXES_SUPPORTED
1012 return EFI_INVALID_PARAMETER
;
1015 // Allocate a table to store pointers to the SSDT tables.
1016 TableList
= (EFI_ACPI_DESCRIPTION_HEADER
**)
1018 (sizeof (EFI_ACPI_DESCRIPTION_HEADER
*) * PciCount
)
1020 if (TableList
== NULL
) {
1021 Status
= EFI_OUT_OF_RESOURCES
;
1024 "ERROR: SSDT-PCI: Failed to allocate memory for Table List."
1031 // Setup the table list early so that appropriate cleanup
1032 // can be done in case of failure.
1035 for (Index
= 0; Index
< PciCount
; Index
++) {
1036 // Build a SSDT table describing the Pci devices.
1037 Status
= BuildSsdtPciTable (
1045 if (EFI_ERROR (Status
)) {
1048 "ERROR: SSDT-PCI: Failed to build associated SSDT table."
1059 // Note: Table list and Table count have been setup. The
1060 // error handler does nothing here as the framework will invoke
1061 // FreeSsdtPciTableEx () even on failure.
1065 /** Free any resources allocated for constructing the tables.
1067 @param [in] This Pointer to the ACPI table generator.
1068 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1069 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1071 @param [in, out] Table Pointer to an array of pointers
1073 @param [in] TableCount Number of ACPI table(s).
1075 @retval EFI_SUCCESS The resources were freed successfully.
1076 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1081 FreeSsdtPciTableEx (
1082 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1083 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1084 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1085 IN OUT EFI_ACPI_DESCRIPTION_HEADER
***CONST Table
,
1086 IN CONST UINTN TableCount
1089 EFI_ACPI_DESCRIPTION_HEADER
**TableList
;
1092 ASSERT (This
!= NULL
);
1093 ASSERT (AcpiTableInfo
!= NULL
);
1094 ASSERT (CfgMgrProtocol
!= NULL
);
1095 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1096 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1098 if ((Table
== NULL
) ||
1102 DEBUG ((DEBUG_ERROR
, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
1103 return EFI_INVALID_PARAMETER
;
1107 for (Index
= 0; Index
< TableCount
; Index
++) {
1108 if ((TableList
[Index
] != NULL
) &&
1109 (TableList
[Index
]->Signature
==
1110 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
))
1112 FreePool (TableList
[Index
]);
1116 "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
1119 return EFI_INVALID_PARAMETER
;
1123 // Free the table list.
1129 /** This macro defines the SSDT Pci Table Generator revision.
1131 #define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
1133 /** The interface for the SSDT Pci Table Generator.
1136 ACPI_PCI_GENERATOR SsdtPcieGenerator
= {
1137 // ACPI table generator header
1140 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress
),
1141 // Generator Description
1142 L
"ACPI.STD.SSDT.PCI.GENERATOR",
1143 // ACPI Table Signature
1144 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
,
1145 // ACPI Table Revision - Unused
1147 // Minimum ACPI Table Revision - Unused
1150 TABLE_GENERATOR_CREATOR_ID_ARM
,
1152 SSDT_PCI_GENERATOR_REVISION
,
1153 // Build table function. Use the extended version instead.
1155 // Free table function. Use the extended version instead.
1157 // Extended Build table function.
1158 BuildSsdtPciTableEx
,
1159 // Extended free function.
1163 // Private fields are defined from here.
1176 /** Register the Generator with the ACPI Table Factory.
1178 @param [in] ImageHandle The handle to the image.
1179 @param [in] SystemTable Pointer to the System Table.
1181 @retval EFI_SUCCESS The Generator is registered.
1182 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1183 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1184 is already registered.
1188 AcpiSsdtPcieLibConstructor (
1189 IN EFI_HANDLE ImageHandle
,
1190 IN EFI_SYSTEM_TABLE
*SystemTable
1195 Status
= RegisterAcpiTableGenerator (&SsdtPcieGenerator
.Header
);
1198 "SSDT-PCI: Register Generator. Status = %r\n",
1201 ASSERT_EFI_ERROR (Status
);
1205 /** Deregister the Generator from the ACPI Table Factory.
1207 @param [in] ImageHandle The handle to the image.
1208 @param [in] SystemTable Pointer to the System Table.
1210 @retval EFI_SUCCESS The Generator is deregistered.
1211 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1212 @retval EFI_NOT_FOUND The Generator is not registered.
1216 AcpiSsdtPcieLibDestructor (
1217 IN EFI_HANDLE ImageHandle
,
1218 IN EFI_SYSTEM_TABLE
*SystemTable
1223 Status
= DeregisterAcpiTableGenerator (&SsdtPcieGenerator
.Header
);
1226 "SSDT-PCI: Deregister Generator. Status = %r\n",
1229 ASSERT_EFI_ERROR (Status
);