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 @param [in] Generator The SSDT Pci generator.
292 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
294 @param [in] PciInfo Pci device information.
295 @param [in] Uid Unique Id of the Pci device.
296 @param [in, out] PciNode Pci node to amend.
298 @retval EFI_SUCCESS The function completed successfully.
299 @retval EFI_INVALID_PARAMETER Invalid parameter.
300 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
306 IN ACPI_PCI_GENERATOR
*Generator
,
307 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
308 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
310 IN OUT AML_OBJECT_NODE_HANDLE PciNode
315 AML_OBJECT_NODE_HANDLE PrtNode
;
316 CM_ARM_OBJ_REF
*RefInfo
;
318 CM_ARM_PCI_INTERRUPT_MAP_INFO
*IrqMapInfo
;
320 ASSERT (Generator
!= NULL
);
321 ASSERT (CfgMgrProtocol
!= NULL
);
322 ASSERT (PciInfo
!= NULL
);
323 ASSERT (PciNode
!= NULL
);
327 // Get the array of CM_ARM_OBJ_REF referencing the
328 // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
329 Status
= GetEArmObjCmRef (
331 PciInfo
->InterruptMapToken
,
335 if (EFI_ERROR (Status
)) {
340 // Initialized DeviceTable.
341 Status
= MappingTableInitialize (&Generator
->DeviceTable
, RefCount
);
342 if (EFI_ERROR (Status
)) {
347 // ASL: Name (_PRT, Package () {})
348 Status
= AmlCodeGenNamePackage ("_PRT", NULL
, &PrtNode
);
349 if (EFI_ERROR (Status
)) {
354 for (Index
= 0; Index
< RefCount
; Index
++) {
355 // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
356 Status
= GetEArmObjPciInterruptMapInfo (
358 RefInfo
[Index
].ReferenceToken
,
362 if (EFI_ERROR (Status
)) {
367 // Check that the interrupts flags are SPIs, level high.
368 // Cf. Arm BSA v1.0, sE.6 "Legacy interrupts"
370 (IrqMapInfo
->IntcInterrupt
.Interrupt
>= 32) &&
371 (IrqMapInfo
->IntcInterrupt
.Interrupt
< 1020) &&
372 ((IrqMapInfo
->IntcInterrupt
.Flags
& 0xB) != 0))
374 Status
= EFI_INVALID_PARAMETER
;
375 ASSERT_EFI_ERROR (Status
);
379 // Add the device to the DeviceTable.
380 MappingTableAdd (&Generator
->DeviceTable
, IrqMapInfo
->PciDevice
);
384 Name (_PRT, Package () {
390 ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
391 High word-Device #, Low word-Function #. (for example, device 3,
392 function 2 is 0x00030002). To refer to all the functions on a device #,
393 use a function number of FFFF).
395 Use the second model for _PRT object and describe a hardwired interrupt.
397 Status
= AmlAddPrtEntry (
398 (IrqMapInfo
->PciDevice
<< 16) | 0xFFFF,
399 IrqMapInfo
->PciInterrupt
,
401 IrqMapInfo
->IntcInterrupt
.Interrupt
,
404 if (EFI_ERROR (Status
)) {
410 // Attach the _PRT entry.
411 Status
= AmlAttachNode (PciNode
, PrtNode
);
412 if (EFI_ERROR (Status
)) {
413 ASSERT_EFI_ERROR (Status
);
419 // Generate the Pci slots once all the device have been added.
420 Status
= GeneratePciSlots (PciInfo
, &Generator
->DeviceTable
, Uid
, PciNode
);
421 if (EFI_ERROR (Status
)) {
427 MappingTableFree (&Generator
->DeviceTable
);
429 if (PrtNode
!= NULL
) {
430 AmlDeleteTree (PrtNode
);
436 /** Generate a _CRS method for the Pci device.
438 @param [in] Generator The SSDT Pci generator.
439 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
441 @param [in] PciInfo Pci device information.
442 @param [in, out] PciNode Pci node to amend.
444 @retval EFI_SUCCESS The function completed successfully.
445 @retval EFI_INVALID_PARAMETER Invalid parameter.
446 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
452 IN ACPI_PCI_GENERATOR
*Generator
,
453 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
454 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
455 IN OUT AML_OBJECT_NODE_HANDLE PciNode
461 CM_ARM_OBJ_REF
*RefInfo
;
463 CM_ARM_PCI_ADDRESS_MAP_INFO
*AddrMapInfo
;
464 AML_OBJECT_NODE_HANDLE CrsNode
;
467 ASSERT (Generator
!= NULL
);
468 ASSERT (CfgMgrProtocol
!= NULL
);
469 ASSERT (PciInfo
!= NULL
);
470 ASSERT (PciNode
!= NULL
);
472 // ASL: Name (_CRS, ResourceTemplate () {})
473 Status
= AmlCodeGenNameResourceTemplate ("_CRS", PciNode
, &CrsNode
);
474 if (EFI_ERROR (Status
)) {
480 // WordBusNumber ( // Bus numbers assigned to this root
481 // ResourceProducer, MinFixed, MaxFixed, PosDecode,
482 // 0, // AddressGranularity
483 // <Start>, // AddressMinimum - Minimum Bus Number
484 // <End>, // AddressMaximum - Maximum Bus Number
485 // 0, // AddressTranslation - Set to 0
486 // <End> - <Start> + 1 // RangeLength - Number of Busses
488 Status
= AmlCodeGenRdWordBusNumber (
494 PciInfo
->StartBusNumber
,
495 PciInfo
->EndBusNumber
,
497 PciInfo
->EndBusNumber
- PciInfo
->StartBusNumber
+ 1,
503 if (EFI_ERROR (Status
)) {
508 // Get the array of CM_ARM_OBJ_REF referencing the
509 // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
510 Status
= GetEArmObjCmRef (
512 PciInfo
->AddressMapToken
,
516 if (EFI_ERROR (Status
)) {
521 for (Index
= 0; Index
< RefCount
; Index
++) {
522 // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
523 Status
= GetEArmObjPciAddressMapInfo (
525 RefInfo
[Index
].ReferenceToken
,
529 if (EFI_ERROR (Status
)) {
534 Translation
= (AddrMapInfo
->CpuAddress
!= AddrMapInfo
->PciAddress
);
535 if (AddrMapInfo
->CpuAddress
>= AddrMapInfo
->PciAddress
) {
541 switch (AddrMapInfo
->SpaceCode
) {
543 Status
= AmlCodeGenRdDWordIo (
550 AddrMapInfo
->PciAddress
,
551 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
552 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
553 AddrMapInfo
->AddressSize
,
564 Status
= AmlCodeGenRdDWordMemory (
572 AddrMapInfo
->PciAddress
,
573 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
574 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
575 AddrMapInfo
->AddressSize
,
586 Status
= AmlCodeGenRdQWordMemory (
594 AddrMapInfo
->PciAddress
,
595 AddrMapInfo
->PciAddress
+ AddrMapInfo
->AddressSize
- 1,
596 Translation
? AddrMapInfo
->CpuAddress
- AddrMapInfo
->PciAddress
: 0,
597 AddrMapInfo
->AddressSize
,
608 Status
= EFI_INVALID_PARAMETER
;
611 if (EFI_ERROR (Status
)) {
620 /** Generate a RES0 device node to reserve PNP motherboard resources
621 for a given PCI node.
623 @param [in] PciNode Parent PCI node handle of the generated
625 @param [out] CrsNode CRS node of the AML tree to populate.
627 @retval EFI_SUCCESS The function completed successfully.
628 @retval EFI_INVALID_PARAMETER Invalid input parameter.
629 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
634 GenerateMotherboardDevice (
635 IN AML_OBJECT_NODE_HANDLE PciNode
,
636 OUT AML_OBJECT_NODE_HANDLE
*CrsNode
641 AML_OBJECT_NODE_HANDLE ResNode
;
643 if (CrsNode
== NULL
) {
645 return EFI_INVALID_PARAMETER
;
648 // ASL: Device (RES0) {}
649 Status
= AmlCodeGenDevice ("RES0", PciNode
, &ResNode
);
650 if (EFI_ERROR (Status
)) {
655 // ASL: Name (_HID, EISAID ("PNP0C02"))
656 Status
= AmlGetEisaIdFromString ("PNP0C02", &EisaId
); /* PNP Motherboard Resources */
657 if (EFI_ERROR (Status
)) {
662 Status
= AmlCodeGenNameInteger ("_HID", EisaId
, ResNode
, NULL
);
663 if (EFI_ERROR (Status
)) {
668 // ASL: Name (_CRS, ResourceTemplate () {})
669 Status
= AmlCodeGenNameResourceTemplate ("_CRS", ResNode
, CrsNode
);
670 if (EFI_ERROR (Status
)) {
678 /** Reserves ECAM space for PCI config space
680 @param [in] Generator The SSDT Pci generator.
681 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
683 @param [in] PciInfo Pci device information.
684 @param [in, out] PciNode RootNode of the AML tree to populate.
686 @retval EFI_SUCCESS The function completed successfully.
687 @retval EFI_INVALID_PARAMETER Invalid parameter.
688 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
694 IN ACPI_PCI_GENERATOR
*Generator
,
695 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
696 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
697 IN OUT AML_OBJECT_NODE_HANDLE PciNode
701 AML_OBJECT_NODE_HANDLE CrsNode
;
702 UINT64 AddressMinimum
;
703 UINT64 AddressMaximum
;
705 Status
= GenerateMotherboardDevice (PciNode
, &CrsNode
);
706 if (EFI_ERROR (Status
)) {
711 AddressMinimum
= PciInfo
->BaseAddress
+ (PciInfo
->StartBusNumber
*
712 PCI_MAX_DEVICE_COUNT_PER_BUS
* PCI_MAX_FUNCTION_COUNT_PER_DEVICE
* SIZE_4KB
);
713 AddressMaximum
= PciInfo
->BaseAddress
+ ((PciInfo
->EndBusNumber
+ 1) *
714 PCI_MAX_DEVICE_COUNT_PER_BUS
* PCI_MAX_FUNCTION_COUNT_PER_DEVICE
* SIZE_4KB
) - 1;
716 Status
= AmlCodeGenRdQWordMemory (
721 FALSE
, // non-cacheable
727 AddressMaximum
- AddressMinimum
+ 1,
736 if (EFI_ERROR (Status
)) {
744 /** Generate a Pci device.
746 @param [in] Generator The SSDT Pci generator.
747 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
749 @param [in] PciInfo Pci device information.
750 @param [in] Uid Unique Id of the Pci device.
751 @param [in, out] RootNode RootNode of the AML tree to populate.
753 @retval EFI_SUCCESS The function completed successfully.
754 @retval EFI_INVALID_PARAMETER Invalid parameter.
755 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
761 IN ACPI_PCI_GENERATOR
*Generator
,
762 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
763 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
765 IN OUT AML_ROOT_NODE_HANDLE
*RootNode
770 CHAR8 AslName
[AML_NAME_SEG_SIZE
+ 1];
771 AML_OBJECT_NODE_HANDLE ScopeNode
;
772 AML_OBJECT_NODE_HANDLE PciNode
;
774 ASSERT (Generator
!= NULL
);
775 ASSERT (CfgMgrProtocol
!= NULL
);
776 ASSERT (PciInfo
!= NULL
);
777 ASSERT (RootNode
!= NULL
);
781 // ASL: Scope (\_SB) {}
782 Status
= AmlCodeGenScope (SB_SCOPE
, RootNode
, &ScopeNode
);
783 if (EFI_ERROR (Status
)) {
788 // Write the name of the PCI device.
789 CopyMem (AslName
, "PCIx", AML_NAME_SEG_SIZE
+ 1);
790 AslName
[AML_NAME_SEG_SIZE
- 1] = AsciiFromHex (Uid
& 0xF);
792 AslName
[AML_NAME_SEG_SIZE
- 2] = AsciiFromHex ((Uid
>> 4) & 0xF);
795 // ASL: Device (PCIx) {}
796 Status
= AmlCodeGenDevice (AslName
, ScopeNode
, &PciNode
);
797 if (EFI_ERROR (Status
)) {
802 // Populate the PCIx node with some Id values.
803 Status
= GeneratePciDeviceInfo (PciInfo
, Uid
, PciNode
);
804 if (EFI_ERROR (Status
)) {
809 // Generate the Pci Routing Table (_PRT).
810 if (PciInfo
->InterruptMapToken
!= CM_NULL_TOKEN
) {
811 Status
= GeneratePrt (
818 if (EFI_ERROR (Status
)) {
824 // Generate the _CRS method.
825 Status
= GeneratePciCrs (Generator
, CfgMgrProtocol
, PciInfo
, PciNode
);
826 if (EFI_ERROR (Status
)) {
831 // Add the PNP Motherboard Resources Device to reserve ECAM space
832 Status
= ReserveEcamSpace (Generator
, CfgMgrProtocol
, PciInfo
, PciNode
);
833 if (EFI_ERROR (Status
)) {
838 // Add the template _OSC method.
839 Status
= AddOscMethod (PciInfo
, PciNode
);
840 ASSERT_EFI_ERROR (Status
);
845 /** Build an Ssdt table describing a Pci device.
847 @param [in] Generator The SSDT Pci generator.
848 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
850 @param [in] AcpiTableInfo Pointer to the ACPI table information.
851 @param [in] PciInfo Pci device information.
852 @param [in] Uid Unique Id of the Pci device.
853 @param [out] Table If success, contains the created SSDT table.
855 @retval EFI_SUCCESS The function completed successfully.
856 @retval EFI_INVALID_PARAMETER Invalid parameter.
857 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
863 IN ACPI_PCI_GENERATOR
*Generator
,
864 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
865 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
866 IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
,
868 OUT EFI_ACPI_DESCRIPTION_HEADER
**Table
873 AML_ROOT_NODE_HANDLE RootNode
;
875 ASSERT (Generator
!= NULL
);
876 ASSERT (CfgMgrProtocol
!= NULL
);
877 ASSERT (PciInfo
!= NULL
);
878 ASSERT (Table
!= NULL
);
880 // Create a new Ssdt table.
881 Status
= AddSsdtAcpiHeader (
887 if (EFI_ERROR (Status
)) {
892 Status
= GeneratePciDevice (
899 if (EFI_ERROR (Status
)) {
904 // Serialize the tree.
905 Status
= AmlSerializeDefinitionBlock (
909 if (EFI_ERROR (Status
)) {
912 "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
920 Status1
= AmlDeleteTree (RootNode
);
921 if (EFI_ERROR (Status1
)) {
924 "ERROR: SSDT-PCI: Failed to cleanup AML tree."
928 // If Status was success but we failed to delete the AML Tree
929 // return Status1 else return the original error code, i.e. Status.
930 if (!EFI_ERROR (Status
)) {
938 /** Construct SSDT tables describing Pci root complexes.
940 This function invokes the Configuration Manager protocol interface
941 to get the required hardware information for generating the ACPI
944 If this function allocates any resources then they must be freed
945 in the FreeXXXXTableResourcesEx function.
947 @param [in] This Pointer to the ACPI table generator.
948 @param [in] AcpiTableInfo Pointer to the ACPI table information.
949 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
951 @param [out] Table Pointer to a list of generated ACPI table(s).
952 @param [out] TableCount Number of generated ACPI table(s).
954 @retval EFI_SUCCESS Table generated successfully.
955 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
956 Manager is less than the Object size for
957 the requested object.
958 @retval EFI_INVALID_PARAMETER A parameter is invalid.
959 @retval EFI_NOT_FOUND Could not find information.
960 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
961 @retval EFI_UNSUPPORTED Unsupported configuration.
966 BuildSsdtPciTableEx (
967 IN CONST ACPI_TABLE_GENERATOR
*This
,
968 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
969 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
970 OUT EFI_ACPI_DESCRIPTION_HEADER
***Table
,
971 OUT UINTN
*CONST TableCount
975 CM_ARM_PCI_CONFIG_SPACE_INFO
*PciInfo
;
978 EFI_ACPI_DESCRIPTION_HEADER
**TableList
;
979 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 if (PcdGetBool (PcdPciUseSegmentAsUid
)) {
1037 Uid
= PciInfo
[Index
].PciSegmentGroupNumber
;
1038 if (Uid
> MAX_PCI_ROOT_COMPLEXES_SUPPORTED
) {
1041 "ERROR: SSDT-PCI: Pci root complexes segment number: %d."
1042 " Greater than maximum number of Pci root complexes supported = %d.\n",
1044 MAX_PCI_ROOT_COMPLEXES_SUPPORTED
1046 return EFI_INVALID_PARAMETER
;
1052 // Build a SSDT table describing the Pci devices.
1053 Status
= BuildSsdtPciTable (
1061 if (EFI_ERROR (Status
)) {
1064 "ERROR: SSDT-PCI: Failed to build associated SSDT table."
1075 // Note: Table list and Table count have been setup. The
1076 // error handler does nothing here as the framework will invoke
1077 // FreeSsdtPciTableEx () even on failure.
1081 /** Free any resources allocated for constructing the tables.
1083 @param [in] This Pointer to the ACPI table generator.
1084 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
1085 @param [in] CfgMgrProtocol Pointer to the Configuration Manager
1087 @param [in, out] Table Pointer to an array of pointers
1089 @param [in] TableCount Number of ACPI table(s).
1091 @retval EFI_SUCCESS The resources were freed successfully.
1092 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
1097 FreeSsdtPciTableEx (
1098 IN CONST ACPI_TABLE_GENERATOR
*CONST This
,
1099 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO
*CONST AcpiTableInfo
,
1100 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL
*CONST CfgMgrProtocol
,
1101 IN OUT EFI_ACPI_DESCRIPTION_HEADER
***CONST Table
,
1102 IN CONST UINTN TableCount
1105 EFI_ACPI_DESCRIPTION_HEADER
**TableList
;
1108 ASSERT (This
!= NULL
);
1109 ASSERT (AcpiTableInfo
!= NULL
);
1110 ASSERT (CfgMgrProtocol
!= NULL
);
1111 ASSERT (AcpiTableInfo
->TableGeneratorId
== This
->GeneratorID
);
1112 ASSERT (AcpiTableInfo
->AcpiTableSignature
== This
->AcpiTableSignature
);
1114 if ((Table
== NULL
) ||
1118 DEBUG ((DEBUG_ERROR
, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
1119 return EFI_INVALID_PARAMETER
;
1123 for (Index
= 0; Index
< TableCount
; Index
++) {
1124 if ((TableList
[Index
] != NULL
) &&
1125 (TableList
[Index
]->Signature
==
1126 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
))
1128 FreePool (TableList
[Index
]);
1132 "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
1135 return EFI_INVALID_PARAMETER
;
1139 // Free the table list.
1145 /** This macro defines the SSDT Pci Table Generator revision.
1147 #define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
1149 /** The interface for the SSDT Pci Table Generator.
1152 ACPI_PCI_GENERATOR SsdtPcieGenerator
= {
1153 // ACPI table generator header
1156 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress
),
1157 // Generator Description
1158 L
"ACPI.STD.SSDT.PCI.GENERATOR",
1159 // ACPI Table Signature
1160 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
,
1161 // ACPI Table Revision - Unused
1163 // Minimum ACPI Table Revision - Unused
1166 TABLE_GENERATOR_CREATOR_ID_ARM
,
1168 SSDT_PCI_GENERATOR_REVISION
,
1169 // Build table function. Use the extended version instead.
1171 // Free table function. Use the extended version instead.
1173 // Extended Build table function.
1174 BuildSsdtPciTableEx
,
1175 // Extended free function.
1179 // Private fields are defined from here.
1192 /** Register the Generator with the ACPI Table Factory.
1194 @param [in] ImageHandle The handle to the image.
1195 @param [in] SystemTable Pointer to the System Table.
1197 @retval EFI_SUCCESS The Generator is registered.
1198 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1199 @retval EFI_ALREADY_STARTED The Generator for the Table ID
1200 is already registered.
1204 AcpiSsdtPcieLibConstructor (
1205 IN EFI_HANDLE ImageHandle
,
1206 IN EFI_SYSTEM_TABLE
*SystemTable
1211 Status
= RegisterAcpiTableGenerator (&SsdtPcieGenerator
.Header
);
1214 "SSDT-PCI: Register Generator. Status = %r\n",
1217 ASSERT_EFI_ERROR (Status
);
1221 /** Deregister the Generator from the ACPI Table Factory.
1223 @param [in] ImageHandle The handle to the image.
1224 @param [in] SystemTable Pointer to the System Table.
1226 @retval EFI_SUCCESS The Generator is deregistered.
1227 @retval EFI_INVALID_PARAMETER A parameter is invalid.
1228 @retval EFI_NOT_FOUND The Generator is not registered.
1232 AcpiSsdtPcieLibDestructor (
1233 IN EFI_HANDLE ImageHandle
,
1234 IN EFI_SYSTEM_TABLE
*SystemTable
1239 Status
= DeregisterAcpiTableGenerator (&SsdtPcieGenerator
.Header
);
1242 "SSDT-PCI: Deregister Generator. Status = %r\n",
1245 ASSERT_EFI_ERROR (Status
);