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 <Protocol/ConfigurationManagerProtocol.h>
34 #include "SsdtPcieGenerator.h"
36 /** ARM standard SSDT Pcie Table Generator.
39 The following Configuration Manager Object(s) are required by
42 - EArmObjPciConfigSpaceInfo
43 - EArmObjPciAddressMapInfo
44 - EArmObjPciInterruptMapInfo
47 /** This macro expands to a function that retrieves the cross-CM-object-
48 reference information from the Configuration Manager.
56 /** This macro expands to a function that retrieves the Pci
57 Configuration Space Information from the Configuration Manager.
61 EArmObjPciConfigSpaceInfo
,
62 CM_ARM_PCI_CONFIG_SPACE_INFO
65 /** This macro expands to a function that retrieves the Pci
66 Address Mapping Information from the Configuration Manager.
70 EArmObjPciAddressMapInfo
,
71 CM_ARM_PCI_ADDRESS_MAP_INFO
74 /** This macro expands to a function that retrieves the Pci
75 Interrupt Mapping Information from the Configuration Manager.
79 EArmObjPciInterruptMapInfo
,
80 CM_ARM_PCI_INTERRUPT_MAP_INFO
83 /** Initialize the MappingTable.
85 @param [in] MappingTable The mapping table structure.
86 @param [in] Count Number of entries to allocate in the
89 @retval EFI_SUCCESS Success.
90 @retval EFI_INVALID_PARAMETER Invalid parameter.
91 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
96 MappingTableInitialize (
97 IN MAPPING_TABLE
*MappingTable
,
103 if ((MappingTable
== NULL
) ||
107 return EFI_INVALID_PARAMETER
;
110 Table
= AllocateZeroPool (sizeof (*Table
) * Count
);
113 return EFI_OUT_OF_RESOURCES
;
116 MappingTable
->Table
= Table
;
117 MappingTable
->LastIndex
= 0;
118 MappingTable
->MaxIndex
= Count
;
123 /** Free the MappingTable.
125 @param [in, out] MappingTable The mapping table structure.
131 IN OUT MAPPING_TABLE
*MappingTable
134 ASSERT (MappingTable
!= NULL
);
135 ASSERT (MappingTable
->Table
!= NULL
);
137 if (MappingTable
->Table
!= NULL
) {
138 FreePool (MappingTable
->Table
);
142 /** Add a new entry to the MappingTable and return its index.
144 If an entry with [Integer] is already available in the table,
145 return its index without adding a new entry.
147 @param [in] MappingTable The mapping table structure.
148 @param [in] Integer New Integer entry to add.
150 @retval The index of the Integer entry in the MappingTable.
156 IN MAPPING_TABLE
*MappingTable
,
164 ASSERT (MappingTable
!= NULL
);
165 ASSERT (MappingTable
->Table
!= NULL
);
167 Table
= MappingTable
->Table
;
168 LastIndex
= MappingTable
->LastIndex
;
170 // Search if there is already an entry with this Integer.
171 for (Index
= 0; Index
< LastIndex
; Index
++) {
172 if (Table
[Index
] == Integer
) {
177 ASSERT (LastIndex
< MappingTable
->MaxIndex
);
179 // If no, create a new entry.
180 Table
[LastIndex
] = Integer
;
182 return MappingTable
->LastIndex
++;
185 /** Generate required Pci device information.
188 Name (_UID, <Uid>) // Uid of the Pci device
189 Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge
190 Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge
191 Name (_SEG, <Pci segment group>) // PCI Segment Group number
192 Name (_BBN, <Bus number>) // PCI Base Bus Number
193 Name (_CCA, 1) // Initially mark the PCI coherent
195 @param [in] PciInfo Pci device information.
196 @param [in] Uid Unique Id of the Pci device.
197 @param [in, out] PciNode Pci node to amend.
199 @retval EFI_SUCCESS Success.
200 @retval EFI_INVALID_PARAMETER Invalid parameter.
201 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
206 GeneratePciDeviceInfo (
207 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
209 IN OUT AML_OBJECT_NODE_HANDLE PciNode
215 ASSERT (PciInfo
!= NULL
);
216 ASSERT (PciNode
!= NULL
);
218 // ASL: Name (_UID, <Uid>)
219 Status
= AmlCodeGenNameInteger ("_UID", Uid
, PciNode
, NULL
);
220 if (EFI_ERROR (Status
)) {
225 // ASL: Name (_HID, EISAID ("PNP0A08"))
226 Status
= AmlGetEisaIdFromString ("PNP0A08", &EisaId
);
227 if (EFI_ERROR (Status
)) {
232 Status
= AmlCodeGenNameInteger ("_HID", EisaId
, PciNode
, NULL
);
233 if (EFI_ERROR (Status
)) {
238 // ASL: Name (_CID, EISAID ("PNP0A03"))
239 Status
= AmlGetEisaIdFromString ("PNP0A03", &EisaId
);
240 if (EFI_ERROR (Status
)) {
245 Status
= AmlCodeGenNameInteger ("_CID", EisaId
, PciNode
, NULL
);
246 if (EFI_ERROR (Status
)) {
251 // ASL: Name (_SEG, <Pci segment group>)
252 Status
= AmlCodeGenNameInteger (
254 PciInfo
->PciSegmentGroupNumber
,
258 if (EFI_ERROR (Status
)) {
263 // ASL: Name (_BBN, <Bus number>)
264 Status
= AmlCodeGenNameInteger (
266 PciInfo
->StartBusNumber
,
270 if (EFI_ERROR (Status
)) {
275 // ASL: Name (_CCA, 1)
276 // Must be aligned with the IORT CCA property in
277 // "Table 14 Memory access properties"
278 Status
= AmlCodeGenNameInteger ("_CCA", 1, PciNode
, NULL
);
279 ASSERT_EFI_ERROR (Status
);
283 /** Generate Pci slots devices.
285 PCI Firmware Specification - Revision 3.3,
286 s4.8 "Generic ACPI PCI Slot Description" requests to describe the PCI slot
287 used. It should be possible to enumerate them, but this is additional
290 @param [in] MappingTable The mapping table structure.
291 @param [in, out] PciNode Pci node to amend.
293 @retval EFI_SUCCESS Success.
294 @retval EFI_INVALID_PARAMETER Invalid parameter.
295 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
301 IN CONST MAPPING_TABLE
*MappingTable
,
302 IN OUT AML_OBJECT_NODE_HANDLE PciNode
309 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
310 AML_OBJECT_NODE_HANDLE DeviceNode
;
312 ASSERT (MappingTable
!= NULL
);
313 ASSERT (PciNode
!= NULL
);
315 // Generic device name is "Dxx".
316 CopyMem (AslName
, "Dxx_", AML_NAME_SEG_SIZE
+ 1);
318 LastIndex
= MappingTable
->LastIndex
;
320 // There are at most 32 devices on a Pci bus.
321 if (LastIndex
>= 32) {
323 return EFI_INVALID_PARAMETER
;
326 for (Index
= 0; Index
< LastIndex
; Index
++) {
327 DeviceId
= MappingTable
->Table
[Index
];
328 AslName
[AML_NAME_SEG_SIZE
- 3] = AsciiFromHex (DeviceId
& 0xF);
329 AslName
[AML_NAME_SEG_SIZE
- 2] = AsciiFromHex ((DeviceId
>> 4) & 0xF);
333 // Name (_ADR, <address value>)
335 Status
= AmlCodeGenDevice (AslName
, PciNode
, &DeviceNode
);
336 if (EFI_ERROR (Status
)) {
341 /* ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
342 High word-Device #, Low word-Function #. (for example, device 3,
343 function 2 is 0x00030002). To refer to all the functions on a device #,
344 use a function number of FFFF).
346 Status
= AmlCodeGenNameInteger (
348 (DeviceId
<< 16) | 0xFFFF,
352 if (EFI_ERROR (Status
)) {
357 // _SUN object is not generated as we don't know which slot will be used.
363 /** Generate a _PRT object (Pci Routing Table) for the Pci device.
365 Cf. ACPI 6.4 specification, s6.2.13 "_PRT (PCI Routing Table)"
367 The first model (defining a _CRS object) is used. This is necessary because
368 PCI legacy interrupts are active low and GICv2 SPI interrupts are active
370 Even though PCI interrupts cannot be re-routed, only the first model allows
371 to specify the activation state (low/high).
373 @param [in] Generator The SSDT Pci generator.
374 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
376 @param [in] PciInfo Pci device information.
377 @param [in, out] PciNode Pci node to amend.
379 @retval EFI_SUCCESS The function completed successfully.
380 @retval EFI_INVALID_PARAMETER Invalid parameter.
381 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
387 IN ACPI_PCI_GENERATOR
*Generator
,
388 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
389 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
390 IN OUT AML_OBJECT_NODE_HANDLE PciNode
395 AML_OBJECT_NODE_HANDLE PrtNode
;
396 CM_ARM_OBJ_REF
*RefInfo
;
398 CM_ARM_PCI_INTERRUPT_MAP_INFO
*IrqMapInfo
;
400 ASSERT (Generator
!= NULL
);
401 ASSERT (CfgMgrProtocol
!= NULL
);
402 ASSERT (PciInfo
!= NULL
);
403 ASSERT (PciNode
!= NULL
);
407 // Get the array of CM_ARM_OBJ_REF referencing the
408 // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
409 Status
= GetEArmObjCmRef (
411 PciInfo
->InterruptMapToken
,
415 if (EFI_ERROR (Status
)) {
420 // Initialized DeviceTable.
421 Status
= MappingTableInitialize (&Generator
->DeviceTable
, RefCount
);
422 if (EFI_ERROR (Status
)) {
427 // ASL: Name (_PRT, Package () {})
428 Status
= AmlCodeGenNamePackage ("_PRT", NULL
, &PrtNode
);
429 if (EFI_ERROR (Status
)) {
434 for (Index
= 0; Index
< RefCount
; Index
++) {
435 // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
436 Status
= GetEArmObjPciInterruptMapInfo (
438 RefInfo
[Index
].ReferenceToken
,
442 if (EFI_ERROR (Status
)) {
447 // Check that the interrupts flags are SPIs, level high.
448 // Cf. Arm BSA v1.0, sE.6 "Legacy interrupts"
450 (IrqMapInfo
->IntcInterrupt
.Interrupt
>= 32) &&
451 (IrqMapInfo
->IntcInterrupt
.Interrupt
< 1020) &&
452 ((IrqMapInfo
->IntcInterrupt
.Flags
& 0xB) != 0))
454 Status
= EFI_INVALID_PARAMETER
;
455 ASSERT_EFI_ERROR (Status
);
459 // Add the device to the DeviceTable.
460 MappingTableAdd (&Generator
->DeviceTable
, IrqMapInfo
->PciDevice
);
464 Name (_PRT, Package () {
470 ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
471 High word-Device #, Low word-Function #. (for example, device 3,
472 function 2 is 0x00030002). To refer to all the functions on a device #,
473 use a function number of FFFF).
475 Status
= AmlAddPrtEntry (
476 (IrqMapInfo
->PciDevice
<< 16) | 0xFFFF,
477 IrqMapInfo
->PciInterrupt
,
479 IrqMapInfo
->IntcInterrupt
.Interrupt
,
482 if (EFI_ERROR (Status
)) {
488 // Attach the _PRT entry.
489 Status
= AmlAttachNode (PciNode
, PrtNode
);
490 if (EFI_ERROR (Status
)) {
491 ASSERT_EFI_ERROR (Status
);
497 // Generate the Pci slots once all the device have been added.
498 Status
= GeneratePciSlots (&Generator
->DeviceTable
, PciNode
);
499 if (EFI_ERROR (Status
)) {
505 MappingTableFree (&Generator
->DeviceTable
);
507 if (PrtNode
!= NULL
) {
508 AmlDeleteTree (PrtNode
);
514 /** Generate a _CRS method for the Pci device.
516 @param [in] Generator The SSDT Pci generator.
517 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
519 @param [in] PciInfo Pci device information.
520 @param [in, out] PciNode Pci node to amend.
522 @retval EFI_SUCCESS The function completed successfully.
523 @retval EFI_INVALID_PARAMETER Invalid parameter.
524 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
530 IN ACPI_PCI_GENERATOR
*Generator
,
531 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
532 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
533 IN OUT AML_OBJECT_NODE_HANDLE PciNode
539 CM_ARM_OBJ_REF
*RefInfo
;
541 CM_ARM_PCI_ADDRESS_MAP_INFO
*AddrMapInfo
;
542 AML_OBJECT_NODE_HANDLE CrsNode
;
545 ASSERT (Generator
!= NULL
);
546 ASSERT (CfgMgrProtocol
!= NULL
);
547 ASSERT (PciInfo
!= NULL
);
548 ASSERT (PciNode
!= NULL
);
550 // ASL: Name (_CRS, ResourceTemplate () {})
551 Status
= AmlCodeGenNameResourceTemplate ("_CRS", PciNode
, &CrsNode
);
552 if (EFI_ERROR (Status
)) {
558 // WordBusNumber ( // Bus numbers assigned to this root
559 // ResourceProducer, MinFixed, MaxFixed, PosDecode,
560 // 0, // AddressGranularity
561 // <Start>, // AddressMinimum - Minimum Bus Number
562 // <End>, // AddressMaximum - Maximum Bus Number
563 // 0, // AddressTranslation - Set to 0
564 // <End> - <Start> + 1 // RangeLength - Number of Busses
566 Status
= AmlCodeGenRdWordBusNumber (
572 PciInfo
->StartBusNumber
,
573 PciInfo
->EndBusNumber
,
575 PciInfo
->EndBusNumber
- PciInfo
->StartBusNumber
+ 1,
581 if (EFI_ERROR (Status
)) {
586 // Get the array of CM_ARM_OBJ_REF referencing the
587 // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
588 Status
= GetEArmObjCmRef (
590 PciInfo
->AddressMapToken
,
594 if (EFI_ERROR (Status
)) {
599 for (Index
= 0; Index
< RefCount
; Index
++) {
600 // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
601 Status
= GetEArmObjPciAddressMapInfo (
603 RefInfo
[Index
].ReferenceToken
,
607 if (EFI_ERROR (Status
)) {
612 Translation
= (AddrMapInfo
->CpuAddress
!= AddrMapInfo
->PciAddress
);
613 if (AddrMapInfo
->CpuAddress
>= AddrMapInfo
->PciAddress
) {
619 switch (AddrMapInfo
->SpaceCode
) {
621 Status
= AmlCodeGenRdDWordIo (
628 AddrMapInfo
->PciAddress
,
629 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
630 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
631 AddrMapInfo
->AddressSize
,
642 Status
= AmlCodeGenRdDWordMemory (
650 AddrMapInfo
->PciAddress
,
651 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
652 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
653 AddrMapInfo
->AddressSize
,
664 Status
= AmlCodeGenRdQWordMemory (
672 AddrMapInfo
->PciAddress
,
673 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
674 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
675 AddrMapInfo
->AddressSize
,
686 Status
= EFI_INVALID_PARAMETER
;
689 if (EFI_ERROR (Status
)) {
698 /** Add an _OSC template method to the PciNode.
700 The _OSC method is provided as an AML blob. The blob is
701 parsed and attached at the end of the PciNode list of variable elements.
703 @param [in, out] PciNode Pci node to amend.
705 @retval EFI_SUCCESS The function completed successfully.
706 @retval EFI_INVALID_PARAMETER Invalid parameter.
707 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
713 IN OUT AML_OBJECT_NODE_HANDLE PciNode
718 EFI_ACPI_DESCRIPTION_HEADER
*SsdtPcieOscTemplate
;
719 AML_ROOT_NODE_HANDLE OscTemplateRoot
;
720 AML_OBJECT_NODE_HANDLE OscNode
;
722 ASSERT (PciNode
!= NULL
);
724 // Parse the Ssdt Pci Osc Template.
725 SsdtPcieOscTemplate
= (EFI_ACPI_DESCRIPTION_HEADER
*)
726 ssdtpcieosctemplate_aml_code
;
729 OscTemplateRoot
= NULL
;
730 Status
= AmlParseDefinitionBlock (
734 if (EFI_ERROR (Status
)) {
737 "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template."
744 Status
= AmlFindNode (OscTemplateRoot
, "\\_OSC", &OscNode
);
745 if (EFI_ERROR (Status
)) {
749 Status
= AmlDetachNode (OscNode
);
750 if (EFI_ERROR (Status
)) {
754 Status
= AmlAttachNode (PciNode
, OscNode
);
755 if (EFI_ERROR (Status
)) {
756 // Free the detached node.
757 AmlDeleteTree (OscNode
);
763 Status1
= AmlDeleteTree (OscTemplateRoot
);
764 if (EFI_ERROR (Status1
)) {
767 "ERROR: SSDT-PCI-OSC: Failed to cleanup AML tree."
771 // If Status was success but we failed to delete the AML Tree
772 // return Status1 else return the original error code, i.e. Status.
773 if (!EFI_ERROR (Status
)) {
781 /** Generate a Pci device.
783 @param [in] Generator The SSDT Pci generator.
784 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
786 @param [in] PciInfo Pci device information.
787 @param [in] Uid Unique Id of the Pci device.
788 @param [in, out] RootNode RootNode of the AML tree to populate.
790 @retval EFI_SUCCESS The function completed successfully.
791 @retval EFI_INVALID_PARAMETER Invalid parameter.
792 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
798 IN ACPI_PCI_GENERATOR
*Generator
,
799 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
800 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
802 IN OUT AML_ROOT_NODE_HANDLE
*RootNode
807 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
808 AML_OBJECT_NODE_HANDLE ScopeNode
;
809 AML_OBJECT_NODE_HANDLE PciNode
;
811 ASSERT (Generator
!= NULL
);
812 ASSERT (CfgMgrProtocol
!= NULL
);
813 ASSERT (PciInfo
!= NULL
);
814 ASSERT (RootNode
!= NULL
);
818 // ASL: Scope (\_SB) {}
819 Status
= AmlCodeGenScope (SB_SCOPE
, RootNode
, &ScopeNode
);
820 if (EFI_ERROR (Status
)) {
825 // Write the name of the PCI device.
826 CopyMem (AslName
, "PCIx", AML_NAME_SEG_SIZE
+ 1);
827 AslName
[AML_NAME_SEG_SIZE
- 1] = AsciiFromHex (Uid
);
829 // ASL: Device (PCIx) {}
830 Status
= AmlCodeGenDevice (AslName
, ScopeNode
, &PciNode
);
831 if (EFI_ERROR (Status
)) {
836 // Populate the PCIx node with some Id values.
837 Status
= GeneratePciDeviceInfo (PciInfo
, Uid
, PciNode
);
838 if (EFI_ERROR (Status
)) {
843 // Generate the Pci Routing Table (_PRT).
844 if (PciInfo
->InterruptMapToken
!= CM_NULL_TOKEN
) {
845 Status
= GeneratePrt (
851 if (EFI_ERROR (Status
)) {
857 // Generate the _CRS method.
858 Status
= GeneratePciCrs (Generator
, CfgMgrProtocol
, PciInfo
, PciNode
);
859 if (EFI_ERROR (Status
)) {
864 // Add the template _OSC method.
865 Status
= AddOscMethod (PciNode
);
866 ASSERT_EFI_ERROR (Status
);
870 /** Build an Ssdt table describing a Pci device.
872 @param [in] Generator The SSDT Pci generator.
873 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
875 @param [in] AcpiTableInfo Pointer to the ACPI table information.
876 @param [in] PciInfo Pci device information.
877 @param [in] Uid Unique Id of the Pci device.
878 @param [out] Table If success, contains the created SSDT table.
880 @retval EFI_SUCCESS The function completed successfully.
881 @retval EFI_INVALID_PARAMETER Invalid parameter.
882 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
888 IN ACPI_PCI_GENERATOR
*Generator
,
889 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
890 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
891 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
893 OUT EFI_ACPI_DESCRIPTION_HEADER
**Table
898 AML_ROOT_NODE_HANDLE RootNode
;
900 ASSERT (Generator
!= NULL
);
901 ASSERT (CfgMgrProtocol
!= NULL
);
902 ASSERT (PciInfo
!= NULL
);
903 ASSERT (Table
!= NULL
);
905 // Create a new Ssdt table.
906 Status
= AddSsdtAcpiHeader (
912 if (EFI_ERROR (Status
)) {
917 Status
= GeneratePciDevice (
924 if (EFI_ERROR (Status
)) {
929 // Serialize the tree.
930 Status
= AmlSerializeDefinitionBlock (
934 if (EFI_ERROR (Status
)) {
937 "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
945 Status1
= AmlDeleteTree (RootNode
);
946 if (EFI_ERROR (Status1
)) {
949 "ERROR: SSDT-PCI: Failed to cleanup AML tree."
953 // If Status was success but we failed to delete the AML Tree
954 // return Status1 else return the original error code, i.e. Status.
955 if (!EFI_ERROR (Status
)) {
963 /** Construct SSDT tables describing Pci root complexes.
965 This function invokes the Configuration Manager protocol interface
966 to get the required hardware information for generating the ACPI
969 If this function allocates any resources then they must be freed
970 in the FreeXXXXTableResourcesEx function.
972 @param [in] This Pointer to the ACPI table generator.
973 @param [in] AcpiTableInfo Pointer to the ACPI table information.
974 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
976 @param [out] Table Pointer to a list of generated ACPI table(s).
977 @param [out] TableCount Number of generated ACPI table(s).
979 @retval EFI_SUCCESS Table generated successfully.
980 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
981 Manager is less than the Object size for
982 the requested object.
983 @retval EFI_INVALID_PARAMETER A parameter is invalid.
984 @retval EFI_NOT_FOUND Could not find information.
985 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
986 @retval EFI_UNSUPPORTED Unsupported configuration.
991 BuildSsdtPciTableEx (
992 IN CONST ACPI_TABLE_GENERATOR
*This
,
993 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
994 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
995 OUT EFI_ACPI_DESCRIPTION_HEADER
***Table
,
996 OUT UINTN
*CONST TableCount
1000 CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
;
1003 EFI_ACPI_DESCRIPTION_HEADER
**TableList
;
1004 ACPI_PCI_GENERATOR
*Generator
;
1006 ASSERT (This
!= NULL
);
1007 ASSERT (AcpiTableInfo
!= NULL
);
1008 ASSERT (CfgMgrProtocol
!= NULL
);
1009 ASSERT (Table
!= NULL
);
1010 ASSERT (TableCount
!= NULL
);
1011 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1012 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1015 Generator
= (ACPI_PCI_GENERATOR
*)This
;
1017 Status
= GetEArmObjPciConfigSpaceInfo (
1023 if (EFI_ERROR (Status
)) {
1028 if (PciCount
> MAX_PCI_ROOT_COMPLEXES_SUPPORTED
) {
1031 "ERROR: SSDT-PCI: Too many Pci root complexes: %d."
1032 " Maximum Pci root complexes supported = %d.\n",
1034 MAX_PCI_ROOT_COMPLEXES_SUPPORTED
1036 return EFI_INVALID_PARAMETER
;
1039 // Allocate a table to store pointers to the SSDT tables.
1040 TableList
= (EFI_ACPI_DESCRIPTION_HEADER
**)
1042 (sizeof (EFI_ACPI_DESCRIPTION_HEADER
*) * PciCount
)
1044 if (TableList
== NULL
) {
1045 Status
= EFI_OUT_OF_RESOURCES
;
1048 "ERROR: SSDT-PCI: Failed to allocate memory for Table List."
1055 // Setup the table list early so that appropriate cleanup
1056 // can be done in case of failure.
1059 for (Index
= 0; Index
< PciCount
; Index
++) {
1060 // Build a SSDT table describing the Pci devices.
1061 Status
= BuildSsdtPciTable (
1069 if (EFI_ERROR (Status
)) {
1072 "ERROR: SSDT-PCI: Failed to build associated SSDT table."
1083 // Note: Table list and Table count have been setup. The
1084 // error handler does nothing here as the framework will invoke
1085 // FreeSsdtPciTableEx () even on failure.
1089 /** Free any resources allocated for constructing the tables.
1091 @param [in] This Pointer to the ACPI table generator.
1092 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1093 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1095 @param [in, out] Table Pointer to an array of pointers
1097 @param [in] TableCount Number of ACPI table(s).
1099 @retval EFI_SUCCESS The resources were freed successfully.
1100 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1105 FreeSsdtPciTableEx (
1106 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1107 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1108 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1109 IN OUT EFI_ACPI_DESCRIPTION_HEADER
***CONST Table
,
1110 IN CONST UINTN TableCount
1113 EFI_ACPI_DESCRIPTION_HEADER
**TableList
;
1116 ASSERT (This
!= NULL
);
1117 ASSERT (AcpiTableInfo
!= NULL
);
1118 ASSERT (CfgMgrProtocol
!= NULL
);
1119 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1120 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1122 if ((Table
== NULL
) ||
1126 DEBUG ((DEBUG_ERROR
, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
1127 return EFI_INVALID_PARAMETER
;
1131 for (Index
= 0; Index
< TableCount
; Index
++) {
1132 if ((TableList
[Index
] != NULL
) &&
1133 (TableList
[Index
]->Signature
==
1134 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
))
1136 FreePool (TableList
[Index
]);
1140 "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
1143 return EFI_INVALID_PARAMETER
;
1147 // Free the table list.
1153 /** This macro defines the SSDT Pci Table Generator revision.
1155 #define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
1157 /** The interface for the SSDT Pci Table Generator.
1160 ACPI_PCI_GENERATOR SsdtPcieGenerator
= {
1161 // ACPI table generator header
1164 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress
),
1165 // Generator Description
1166 L
"ACPI.STD.SSDT.PCI.GENERATOR",
1167 // ACPI Table Signature
1168 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
,
1169 // ACPI Table Revision - Unused
1171 // Minimum ACPI Table Revision - Unused
1174 TABLE_GENERATOR_CREATOR_ID_ARM
,
1176 SSDT_PCI_GENERATOR_REVISION
,
1177 // Build table function. Use the extended version instead.
1179 // Free table function. Use the extended version instead.
1181 // Extended Build table function.
1182 BuildSsdtPciTableEx
,
1183 // Extended free function.
1187 // Private fields are defined from here.
1200 /** Register the Generator with the ACPI Table Factory.
1202 @param [in] ImageHandle The handle to the image.
1203 @param [in] SystemTable Pointer to the System Table.
1205 @retval EFI_SUCCESS The Generator is registered.
1206 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1207 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1208 is already registered.
1212 AcpiSsdtPcieLibConstructor (
1213 IN EFI_HANDLE ImageHandle
,
1214 IN EFI_SYSTEM_TABLE
*SystemTable
1219 Status
= RegisterAcpiTableGenerator (&SsdtPcieGenerator
.Header
);
1222 "SSDT-PCI: Register Generator. Status = %r\n",
1225 ASSERT_EFI_ERROR (Status
);
1229 /** Deregister the Generator from the ACPI Table Factory.
1231 @param [in] ImageHandle The handle to the image.
1232 @param [in] SystemTable Pointer to the System Table.
1234 @retval EFI_SUCCESS The Generator is deregistered.
1235 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1236 @retval EFI_NOT_FOUND The Generator is not registered.
1240 AcpiSsdtPcieLibDestructor (
1241 IN EFI_HANDLE ImageHandle
,
1242 IN EFI_SYSTEM_TABLE
*SystemTable
1247 Status
= DeregisterAcpiTableGenerator (&SsdtPcieGenerator
.Header
);
1250 "SSDT-PCI: Deregister Generator. Status = %r\n",
1253 ASSERT_EFI_ERROR (Status
);