From: Pierre Gondois <Pierre.Gondois@arm.com>
This generator allows to generate a SSDT table describing
a Pci express Bus. It uses the following CmObj:
- EArmObjCmRef
- EArmObjPciConfigSpaceInfo
- EArmObjPciAddressMapInfo
- EArmObjPciInterruptMapInfo
Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
DynamicTablesPkg/DynamicTables.dsc.inc | 2 +
DynamicTablesPkg/Include/AcpiTableGenerator.h | 5 +
.../AcpiSsdtPcieLibArm/SsdtPcieGenerator.c | 1417 +++++++++++++++++
.../AcpiSsdtPcieLibArm/SsdtPcieGenerator.h | 134 ++
.../Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf | 32 +
.../SsdtPcieOscTemplate.asl | 80 +
6 files changed, 1670 insertions(+)
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl
diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
index 292215c39456..60bcf4b199e8 100644
--- a/DynamicTablesPkg/DynamicTables.dsc.inc
+++ b/DynamicTablesPkg/DynamicTables.dsc.inc
@@ -39,6 +39,7 @@ [Components.common]
# AML Codegen
DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
+ DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
#
# Dynamic Table Factory Dxe
@@ -62,6 +63,7 @@ [Components.common]
# AML Codegen
NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
+ NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
}
#
diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h
index 45c808ba740d..58ec941f2a35 100644
--- a/DynamicTablesPkg/Include/AcpiTableGenerator.h
+++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
@@ -67,6 +67,10 @@ The Dynamic Tables Framework implements the following ACPI table generators:
The SSDT Cpu-Topology generator collates the cpu and LPI
information from the Configuration Manager and generates a
SSDT table describing the CPU hierarchy.
+ - SSDT Pci-Express:
+ The SSDT Pci Express generator collates the Pci Express
+ information from the Configuration Manager and generates a
+ SSDT table describing a Pci Express bus.
*/
/** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID.
@@ -93,6 +97,7 @@ typedef enum StdAcpiTableId {
EStdAcpiTableIdSsdtSerialPort, ///< SSDT Serial-Port Generator
EStdAcpiTableIdSsdtCmn600, ///< SSDT Cmn-600 Generator
EStdAcpiTableIdSsdtCpuTopology, ///< SSDT Cpu Topology
+ EStdAcpiTableIdSsdtPciExpress, ///< SSDT Pci Express Generator
EStdAcpiTableIdMax
} ESTD_ACPI_TABLE_ID;
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
new file mode 100644
index 000000000000..478bc60ef6f3
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
@@ -0,0 +1,1417 @@
+/** @file
+ SSDT Pcie Table Generator.
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - PCI Firmware Specification - Revision 3.0
+ - ACPI 6.4 specification:
+ - s6.2.13 "_PRT (PCI Routing Table)"
+ - s6.1.1 "_ADR (Address)"
+ - linux kernel code
+**/
+
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/AcpiHelperLib.h>
+#include <Library/AmlLib/AmlLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+#include "SsdtPcieGenerator.h"
+
+/** ARM standard SSDT Pcie Table Generator.
+
+Requirements:
+ The following Configuration Manager Object(s) are required by
+ this Generator:
+ - EArmObjCmRef
+ - EArmObjPciConfigSpaceInfo
+ - EArmObjPciAddressMapInfo
+ - EArmObjPciInterruptMapInfo
+*/
+
+/** This macro expands to a function that retrieves the cross-CM-object-
+ reference information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjCmRef,
+ CM_ARM_OBJ_REF
+ );
+
+/** This macro expands to a function that retrieves the Pci
+ Configuration Space Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPciConfigSpaceInfo,
+ CM_ARM_PCI_CONFIG_SPACE_INFO
+ );
+
+/** This macro expands to a function that retrieves the Pci
+ Address Mapping Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPciAddressMapInfo,
+ CM_ARM_PCI_ADDRESS_MAP_INFO
+ );
+
+/** This macro expands to a function that retrieves the Pci
+ Interrupt Mapping Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPciInterruptMapInfo,
+ CM_ARM_PCI_INTERRUPT_MAP_INFO
+ );
+
+/** Initialize the MappingTable.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in] Count Number of entries to allocate in the
+ MappingTable.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+MappingTableInitialize (
+ IN MAPPING_TABLE * MappingTable,
+ IN UINT32 Count
+ )
+{
+ UINT32 * Table;
+
+ if ((MappingTable == NULL) ||
+ (Count == 0)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Table = AllocateZeroPool (sizeof (*Table) * Count);
+ if (Table == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MappingTable->Table = Table;
+ MappingTable->LastIndex = 0;
+ MappingTable->MaxIndex = Count;
+
+ return EFI_SUCCESS;
+}
+
+/** Free the MappingTable.
+
+ @param [in, out] MappingTable The mapping table structure.
+**/
+STATIC
+VOID
+EFIAPI
+MappingTableFree (
+ IN OUT MAPPING_TABLE * MappingTable
+ )
+{
+ ASSERT (MappingTable != NULL);
+ ASSERT (MappingTable->Table != NULL);
+
+ if (MappingTable->Table != NULL) {
+ FreePool (MappingTable->Table);
+ }
+}
+
+/** Add a new entry to the MappingTable and return its index.
+
+ If an entry with [Integer] is already available in the table,
+ return its index without adding a new entry.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in] Integer New Integer entry to add.
+
+ @retval The index of the Integer entry in the MappingTable.
+**/
+STATIC
+UINT32
+EFIAPI
+MappingTableAdd (
+ IN MAPPING_TABLE * MappingTable,
+ IN UINT32 Integer
+ )
+{
+ UINT32 * Table;
+ UINT32 Index;
+ UINT32 LastIndex;
+
+ ASSERT (MappingTable != NULL);
+ ASSERT (MappingTable->Table != NULL);
+
+ Table = MappingTable->Table;
+ LastIndex = MappingTable->LastIndex;
+
+ // Search if there is already an entry with this Integer.
+ for (Index = 0; Index < LastIndex; Index++) {
+ if (Table[Index] == Integer) {
+ return Index;
+ }
+ }
+
+ ASSERT (LastIndex < MAX_PCI_LEGACY_INTERRUPT);
+ ASSERT (LastIndex < MappingTable->MaxIndex);
+
+ // If no, create a new entry.
+ Table[LastIndex] = Integer;
+
+ return MappingTable->LastIndex++;
+}
+
+/** Generate required Pci device information.
+
+ ASL code:
+ Name (_UID, [Uid]) // Uid of the Pci device
+ Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge
+ Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge
+ Name (_SEG, [Pci segment group]) // PCI Segment Group number
+ Name (_BBN, [Bus number]) // PCI Base Bus Number
+ Name (_CCA, 1) // Initially mark the PCI coherent
+
+ @param [in] PciInfo Pci device information.
+ @param [in] Uid Unique Id of the Pci device.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePciDeviceInfo (
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN UINT32 Uid,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ UINT32 EisaId;
+
+ ASSERT (PciInfo != NULL);
+ ASSERT (PciNode != NULL);
+
+ // ASL: Name (_UID, [Uid])
+ Status = AmlCodeGenNameInteger ("_UID", Uid, PciNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_HID, EISAID ("PNP0A08"))
+ Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlCodeGenNameInteger ("_HID", EisaId, PciNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_CID, EISAID ("PNP0A03"))
+ Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlCodeGenNameInteger ("_CID", EisaId, PciNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_SEG, [Pci segment group])
+ Status = AmlCodeGenNameInteger (
+ "_SEG",
+ PciInfo->PciSegmentGroupNumber,
+ PciNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_BBN, [Bus number])
+ Status = AmlCodeGenNameInteger (
+ "_BBN",
+ PciInfo->StartBusNumber,
+ PciNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_CCA, 1)
+ // Must be aligned with the IORT CCA property in
+ // "Table 14 Memory access properties"
+ Status = AmlCodeGenNameInteger ("_CCA", 1, PciNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+ return Status;
+}
+
+/** Generate a Link device.
+
+ The Link device is added at the beginning of the ASL Pci device definition.
+
+ Each Link device represents a Pci legacy interrupt (INTA-...-INTD).
+
+ ASL code:
+ Device ([Link Name]) {
+ Name (_UID, [Uid]])
+ Name (_HID, EISAID ("PNP0C0F"))
+ Name (_PRS, ResourceTemplate () {
+ Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { [Irq]] }
+ })
+ Method (_CRS, 0) { Return (_PRS) }
+ Method (_SRS, 1) { }
+ Method (_DIS) { }
+ }
+
+ The list of objects to define is available at:
+ PCI Firmware Specification - Revision 3.3,
+ s3.5. "Device State at Firmware/Operating System Handoff"
+
+ @param [in] Irq Interrupt controller interrupt.
+ @param [in] IrqFlags Interrupt flags.
+ @param [in] LinkIndex Legacy Pci interrupt index.
+ Must be between 0-INTA and 3-INTD.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenerateLinkDevice (
+ IN UINT32 Irq,
+ IN UINT32 IrqFlags,
+ IN UINT32 LinkIndex,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
+ AML_OBJECT_NODE_HANDLE LinkNode;
+ AML_OBJECT_NODE_HANDLE CrsNode;
+ UINT32 EisaId;
+
+ ASSERT (LinkIndex < 4);
+ ASSERT (PciNode != NULL);
+
+ CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1);
+ AslName[AML_NAME_SEG_SIZE - 1] = 'A' + LinkIndex;
+
+ // ASL: Device (LNKx) {}
+ Status = AmlCodeGenDevice (AslName, NULL, &LinkNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // The LNKx devices must be defined before being referenced.
+ // Thus add it to the head of the Pci list of variable arguments.
+ Status = AmlAttachNode (PciNode, LinkNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ // Failed to add.
+ AmlDeleteTree ((AML_NODE_HANDLE)LinkNode);
+ return Status;
+ }
+
+ // ASL: Name (_UID, [Uid])
+ Status = AmlCodeGenNameInteger ("_UID", LinkIndex, LinkNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_HID, EISAID ("PNP0C0F"))
+ Status = AmlGetEisaIdFromString ("PNP0C0F", &EisaId);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlCodeGenNameInteger ("_HID", EisaId, LinkNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL:
+ // Name (_PRS, ResourceTemplate () {
+ // Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { [Irq] }
+ // })
+ Status = AmlCodeGenNameResourceTemplate ("_PRS", LinkNode, &CrsNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlCodeGenRdInterrupt (
+ FALSE,
+ (IrqFlags & BIT0) != 0,
+ (IrqFlags & BIT1) != 0,
+ FALSE,
+ &Irq,
+ 1,
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL:
+ // Method (_CRS, 0) {
+ // Return (_PRS)
+ // }
+ Status = AmlCodeGenMethodRetNameString (
+ "_CRS",
+ "_PRS",
+ 0,
+ FALSE,
+ 0,
+ LinkNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Method (_SRS, 1) {}
+ // Not possible to set interrupts.
+ Status = AmlCodeGenMethodRetNameString (
+ "_SRS",
+ NULL,
+ 1,
+ FALSE,
+ 0,
+ LinkNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL:Method (_DIS, 1) {}
+ // Not possible to disable interrupts.
+ Status = AmlCodeGenMethodRetNameString (
+ "_DIS",
+ NULL,
+ 0,
+ FALSE,
+ 0,
+ LinkNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // _STA:
+ // ACPI 6.4, s6.3.7 "_STA (Device Status)":
+ // If a device object describes a device that is not on an enumerable bus
+ // and the device object does not have an _STA object, then OSPM assumes
+ // that the device is present, enabled, shown in the UI, and functioning.
+
+ // _MAT:
+ // Not supported. Mainly used for processors.
+
+ return Status;
+}
+
+/** Generate Pci slots devices.
+
+ PCI Firmware Specification - Revision 3.3,
+ s4.8 "Generic ACPI PCI Slot Description" requests to describe the PCI slot
+ used. It should be possible to enumerate them, but this is additional
+ information.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePciSlots (
+ IN CONST MAPPING_TABLE * MappingTable,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 LastIndex;
+ UINT32 DeviceId;
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
+ AML_OBJECT_NODE_HANDLE DeviceNode;
+
+ ASSERT (MappingTable != NULL);
+ ASSERT (PciNode != NULL);
+
+ // Generic device name is "Dxx".
+ CopyMem (AslName, "Dxx_", AML_NAME_SEG_SIZE + 1);
+
+ LastIndex = MappingTable->LastIndex;
+
+ // There are at most 32 devices on a Pci bus.
+ ASSERT (LastIndex < 32);
+
+ for (Index = 0; Index < LastIndex; Index++) {
+ DeviceId = MappingTable->Table[Index];
+ AslName[AML_NAME_SEG_SIZE - 3] = AsciiFromHex (DeviceId & 0xF);
+ AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((DeviceId >> 4) & 0xF);
+
+ // ASL:
+ // Device (Dxx) {
+ // Name (_ADR, [address value])
+ // }
+ Status = AmlCodeGenDevice (AslName, PciNode, &DeviceNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ /* ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
+ High word-Device #, Low word-Function #. (for example, device 3,
+ function 2 is 0x00030002). To refer to all the functions on a device #,
+ use a function number of FFFF).
+ */
+ Status = AmlCodeGenNameInteger (
+ "_ADR",
+ (DeviceId << 16) | 0xFFFF,
+ DeviceNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // _SUN object is not generated as we don't know which slot will be used.
+ }
+
+ return Status;
+}
+
+/** Generate a _PRT object (Pci Routing Table) for the Pci device.
+
+ Cf. ACPI 6.4 specification, s6.2.13 "_PRT (PCI Routing Table)"
+
+ @param [in] Generator The SSDT Pci generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] PciInfo Pci device information.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePrt (
+ IN ACPI_PCI_GENERATOR * Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ INT32 Index;
+ UINT32 IrqTableIndex;
+ AML_OBJECT_NODE_HANDLE PrtNode;
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
+ CM_ARM_OBJ_REF * RefInfo;
+ UINT32 RefCount;
+ CM_ARM_PCI_INTERRUPT_MAP_INFO * IrqMapInfo;
+ UINT32 IrqFlags;
+ UINT32 PrevIrqFlags;
+
+ ASSERT (Generator != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (PciInfo != NULL);
+ ASSERT (PciNode != NULL);
+
+ // Get the array of CM_ARM_OBJ_REF referencing the
+ // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
+ Status = GetEArmObjCmRef (
+ CfgMgrProtocol,
+ PciInfo->InterruptMapToken,
+ &RefInfo,
+ &RefCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Initialized IrqTable.
+ Status = MappingTableInitialize (&Generator->IrqTable, RefCount);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Initialized DeviceTable.
+ Status = MappingTableInitialize (&Generator->DeviceTable, RefCount);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // ASL: Name (_PRT, Package () {})
+ Status = AmlCodeGenNamePackage ("_PRT", PciNode, &PrtNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1);
+
+ for (Index = 0; Index < RefCount; Index++) {
+ // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
+ Status = GetEArmObjPciInterruptMapInfo (
+ CfgMgrProtocol,
+ RefInfo[Index].ReferenceToken,
+ &IrqMapInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Add the interrupt in the IrqTable and get the link name.
+ IrqTableIndex = MappingTableAdd (
+ &Generator->IrqTable,
+ IrqMapInfo->IntcInterrupt.Interrupt
+ );
+ AslName[AML_NAME_SEG_SIZE - 1] = 'A' + IrqTableIndex;
+
+ // Check that the interrupts flags are identical for all interrupts.
+ PrevIrqFlags = IrqFlags;
+ IrqFlags = IrqMapInfo->IntcInterrupt.Flags;
+ if ((Index > 0) && (PrevIrqFlags != IrqFlags)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Add the device to the DeviceTable.
+ MappingTableAdd (&Generator->DeviceTable, IrqMapInfo->PciDevice);
+
+ /* Add a _PRT entry.
+ ASL
+ Name (_PRT, Package () {
+ [OldPrtEntries],
+ [NewPrtEntry]
+ })
+
+ Address is set as:
+ ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
+ High word-Device #, Low word-Function #. (for example, device 3,
+ function 2 is 0x00030002). To refer to all the functions on a device #,
+ use a function number of FFFF).
+ */
+ Status = AmlAddPrtEntry (
+ (IrqMapInfo->PciDevice << 16) | 0xFFFF,
+ IrqMapInfo->PciInterrupt,
+ AslName,
+ 0,
+ PrtNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+ } // for
+
+ // Generate the LNKx devices now that we know all the interrupts used.
+ // To look nicer, do it in reverse order since LNKx are added to the head.
+ for (Index = Generator->IrqTable.LastIndex - 1; Index >= 0; Index--) {
+ Status = GenerateLinkDevice (
+ Generator->IrqTable.Table[Index],
+ IrqFlags,
+ Index,
+ PciNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+ } // for
+
+ // Generate the Pci slots once all the device have been added.
+ Status = GeneratePciSlots (&Generator->DeviceTable, PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+exit_handler:
+ MappingTableFree (&Generator->IrqTable);
+ MappingTableFree (&Generator->DeviceTable);
+
+ return Status;
+}
+
+/** Generate a _CRS method for the Pci device.
+
+ @param [in] Generator The SSDT Pci generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] PciInfo Pci device information.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePciCrs (
+ IN ACPI_PCI_GENERATOR * Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Translation;
+ UINT32 Index;
+ CM_ARM_OBJ_REF * RefInfo;
+ UINT32 RefCount;
+ CM_ARM_PCI_ADDRESS_MAP_INFO * AddrMapInfo;
+ AML_OBJECT_NODE_HANDLE CrsNode;
+
+ ASSERT (Generator != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (PciInfo != NULL);
+ ASSERT (PciNode != NULL);
+
+ // ASL: Name (_CRS, ResourceTemplate () {})
+ Status = AmlCodeGenNameResourceTemplate ("_CRS", PciNode, &CrsNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL:
+ // WordBusNumber ( // Bus numbers assigned to this root
+ // ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ // 0, // AddressGranularity
+ // [Start], // AddressMinimum - Minimum Bus Number
+ // [End], // AddressMaximum - Maximum Bus Number
+ // 0, // AddressTranslation - Set to 0
+ // [End] - [Start] + 1 // RangeLength - Number of Busses
+ // )
+ Status = AmlCodeGenRdWordBusNumber (
+ FALSE, TRUE, TRUE, TRUE,
+ 0,
+ PciInfo->StartBusNumber,
+ PciInfo->EndBusNumber,
+ 0,
+ PciInfo->EndBusNumber - PciInfo->StartBusNumber + 1,
+ 0,
+ NULL,
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Get the array of CM_ARM_OBJ_REF referencing the
+ // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
+ Status = GetEArmObjCmRef (
+ CfgMgrProtocol,
+ PciInfo->AddressMapToken,
+ &RefInfo,
+ &RefCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ for (Index = 0; Index < RefCount; Index++) {
+ // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
+ Status = GetEArmObjPciAddressMapInfo (
+ CfgMgrProtocol,
+ RefInfo[Index].ReferenceToken,
+ &AddrMapInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Translation = (AddrMapInfo->CpuAddress != AddrMapInfo->PciAddress);
+
+ switch (AddrMapInfo->SpaceCode) {
+ case PCI_SS_IO:
+ Status = AmlCodeGenRdDWordIo (
+ FALSE, TRUE, TRUE, TRUE, 3,
+ 0,
+ AddrMapInfo->PciAddress,
+ AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
+ Translation ? AddrMapInfo->CpuAddress : 0,
+ AddrMapInfo->AddressSize,
+ 0, NULL,
+ TRUE,
+ FALSE,
+ CrsNode,
+ NULL
+ );
+ break;
+
+ case PCI_SS_M32:
+ Status = AmlCodeGenRdDWordMemory (
+ FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ 0,
+ AddrMapInfo->PciAddress,
+ AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
+ Translation ? AddrMapInfo->CpuAddress : 0,
+ AddrMapInfo->AddressSize,
+ 0, NULL,
+ 0,
+ TRUE,
+ CrsNode,
+ NULL
+ );
+ break;
+
+ case PCI_SS_M64:
+ Status = AmlCodeGenRdQWordMemory (
+ FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ 0,
+ AddrMapInfo->PciAddress,
+ AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
+ Translation ? AddrMapInfo->CpuAddress : 0,
+ AddrMapInfo->AddressSize,
+ 0, NULL,
+ 0,
+ TRUE,
+ CrsNode,
+ NULL
+ );
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ } // switch
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } // for
+ return Status;
+}
+
+/** Add an _OSC template method to the PciNode.
+
+ The _OSC method is provided as an AML blob. The blob is
+ parsed and attached at the end of the PciNode list of variable elements.
+
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AddOscMethod (
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ EFI_ACPI_DESCRIPTION_HEADER * SsdtPcieOscTemplate;
+ AML_ROOT_NODE_HANDLE RootNode;
+ AML_OBJECT_NODE_HANDLE OscNode;
+
+ ASSERT (PciNode != NULL);
+
+ // Parse the Ssdt Pci Osc Template.
+ SsdtPcieOscTemplate = (EFI_ACPI_DESCRIPTION_HEADER*)
+ ssdtpcieosctemplate_aml_code;
+
+ RootNode = NULL;
+ Status = AmlParseDefinitionBlock (
+ SsdtPcieOscTemplate,
+ &RootNode
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = AmlFindNode (RootNode, "\\_OSC", &OscNode);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ Status = AmlDetachNode (OscNode);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ Status = AmlAttachNode (PciNode, OscNode);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+error_handler:
+ // Cleanup
+ Status1 = AmlDeleteTree (RootNode);
+ if (EFI_ERROR (Status1)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI-OSC: Failed to cleanup AML tree."
+ " Status = %r\n",
+ Status1
+ ));
+ // If Status was success but we failed to delete the AML Tree
+ // return Status1 else return the original error code, i.e. Status.
+ if (!EFI_ERROR (Status)) {
+ return Status1;
+ }
+ }
+
+ return Status;
+}
+
+/** Generate a Pci device.
+
+ @param [in] Generator The SSDT Pci generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] PciInfo Pci device information.
+ @param [in] Uid Unique Id of the Pci device.
+ @param [in, out] RootNode RootNode of the AML tree to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePciDevice (
+ IN ACPI_PCI_GENERATOR * Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN UINT32 Uid,
+ IN OUT AML_ROOT_NODE_HANDLE * RootNode
+ )
+{
+ EFI_STATUS Status;
+
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
+ AML_OBJECT_NODE_HANDLE ScopeNode;
+ AML_OBJECT_NODE_HANDLE PciNode;
+
+ ASSERT (Generator != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (PciInfo != NULL);
+ ASSERT (RootNode != NULL);
+
+ PciNode = NULL;
+
+ // ASL: Scope (\_SB) {}
+ Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Write the name of the PCI device.
+ CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1);
+ AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (Uid);
+
+ // ASL: Device (PCIx) {}
+ Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Populate the PCIx node with some Id values.
+ Status = GeneratePciDeviceInfo (PciInfo, Uid, PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Generate the Pci Routing Table (_PRT).
+ if (PciInfo->InterruptMapToken != CM_NULL_TOKEN) {
+ Status = GeneratePrt (
+ Generator,
+ CfgMgrProtocol,
+ PciInfo,
+ PciNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ }
+
+ // Generate the _CRS method.
+ Status = GeneratePciCrs (Generator, CfgMgrProtocol, PciInfo, PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the template _OSC method.
+ Status = AddOscMethod (PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+
+ return Status;
+}
+
+/** Build an Ssdt table describing a Pci device.
+
+ @param [in] Generator The SSDT Pci generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] PciInfo Pci device information.
+ @param [in] Uid Unique Id of the Pci device.
+ @param [out] Table If success, contains the created SSDT table.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSsdtPciTable (
+ IN ACPI_PCI_GENERATOR * Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN UINT32 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ AML_ROOT_NODE_HANDLE RootNode;
+ CHAR8 OemTableId[9];
+
+ ASSERT (Generator != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (PciInfo != NULL);
+ ASSERT (Table != NULL);
+
+ CopyMem (OemTableId, "SSDTPCIx", sizeof (OemTableId) + 1);
+ OemTableId[7] = AsciiFromHex(Uid);
+
+ // Create a new Ssdt table.
+ Status = AmlCodeGenDefinitionBlock (
+ "SSDT",
+ "ARMLTD",
+ OemTableId,
+ 1,
+ &RootNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = GeneratePciDevice (
+ Generator,
+ CfgMgrProtocol,
+ PciInfo,
+ Uid,
+ RootNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Serialize the tree.
+ Status = AmlSerializeDefinitionBlock (
+ RootNode,
+ Table
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
+ " Status = %r\n",
+ Status
+ ));
+ }
+
+exit_handler:
+ // Cleanup
+ Status1 = AmlDeleteTree (RootNode);
+ if (EFI_ERROR (Status1)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Failed to cleanup AML tree."
+ " Status = %r\n",
+ Status1
+ ));
+ // If Status was success but we failed to delete the AML Tree
+ // return Status1 else return the original error code, i.e. Status.
+ if (!EFI_ERROR (Status)) {
+ return Status1;
+ }
+ }
+
+ return Status;
+}
+
+/** Construct SSDT tables describing Pci root complexes.
+
+ This function invokes the Configuration Manager protocol interface
+ to get the required hardware information for generating the ACPI
+ table.
+
+ If this function allocates any resources then they must be freed
+ in the FreeXXXXTableResourcesEx function.
+
+ @param [in] This Pointer to the ACPI table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI table information.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [out] Table Pointer to a list of generated ACPI table(s).
+ @param [out] TableCount Number of generated ACPI table(s).
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for
+ the requested object.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+ @retval EFI_UNSUPPORTED Unsupported configuration.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSsdtPciTableEx (
+ IN CONST ACPI_TABLE_GENERATOR * This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,
+ OUT UINTN * CONST TableCount
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo;
+ UINT32 PciCount;
+ UINTN Index;
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+ ACPI_PCI_GENERATOR * Generator;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (TableCount != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ *TableCount = 0;
+ Generator = (ACPI_PCI_GENERATOR*)This;
+
+ Status = GetEArmObjPciConfigSpaceInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PciInfo,
+ &PciCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (PciCount > MAX_PCI_ROOT_COMPLEXES_SUPPORTED) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Too many Pci root complexes: %d."
+ " Maximum Pci root complexes supported = %d.\n",
+ PciCount,
+ MAX_PCI_ROOT_COMPLEXES_SUPPORTED
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Allocate a table to store pointers to the SSDT tables.
+ TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
+ AllocateZeroPool (
+ (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * PciCount)
+ );
+ if (TableList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Failed to allocate memory for Table List."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Setup the table list early so that appropriate cleanup
+ // can be done in case of failure.
+ *Table = TableList;
+
+ for (Index = 0; Index < PciCount; Index++) {
+ // Build a SSDT table describing the Pci devices.
+ Status = BuildSsdtPciTable (
+ Generator,
+ CfgMgrProtocol,
+ &PciInfo[Index],
+ Index,
+ &TableList[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Failed to build associated SSDT table."
+ " Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ *TableCount += 1;
+ } // for
+
+error_handler:
+ // Note: Table list and Table count have been setup. The
+ // error handler does nothing here as the framework will invoke
+ // FreeSsdtPciTableEx () even on failure.
+ return Status;
+}
+
+/** Free any resources allocated for constructing the tables.
+
+ @param [in] This Pointer to the ACPI table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in, out] Table Pointer to an array of pointers
+ to ACPI Table(s).
+ @param [in] TableCount Number of ACPI table(s).
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FreeSsdtPciTableEx (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,
+ IN CONST UINTN TableCount
+ )
+{
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+ UINTN Index;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((Table == NULL) ||
+ (*Table == NULL) ||
+ (TableCount == 0)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TableList = *Table;
+ for (Index = 0; Index < TableCount; Index++) {
+ if ((TableList[Index] != NULL) &&
+ (TableList[Index]->Signature ==
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
+ FreePool (TableList[Index]);
+ } else {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
+ Index
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+ } //for
+
+ // Free the table list.
+ FreePool (*Table);
+
+ return EFI_SUCCESS;
+}
+
+/** This macro defines the SSDT Pci Table Generator revision.
+*/
+#define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the SSDT Pci Table Generator.
+*/
+STATIC
+ACPI_PCI_GENERATOR SsdtPcieGenerator = {
+ // ACPI table generator header
+ {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress),
+ // Generator Description
+ L"ACPI.STD.SSDT.PCI.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+ // ACPI Table Revision - Unused
+ 0,
+ // Minimum ACPI Table Revision - Unused
+ 0,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ SSDT_PCI_GENERATOR_REVISION,
+ // Build table function. Use the extended version instead.
+ NULL,
+ // Free table function. Use the extended version instead.
+ NULL,
+ // Extended Build table function.
+ BuildSsdtPciTableEx,
+ // Extended free function.
+ FreeSsdtPciTableEx
+ },
+
+ // Private fields are defined from here.
+
+ // IrqTable
+ {
+ // Table
+ NULL,
+ // LastIndex
+ 0,
+ // MaxIndex
+ 0
+ },
+ // DeviceTable
+ {
+ // Table
+ NULL,
+ // LastIndex
+ 0,
+ // MaxIndex
+ 0
+ },
+};
+
+/** Register the Generator with the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is registered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID
+ is already registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiSsdtPcieLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = RegisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
+ DEBUG ((
+ DEBUG_INFO,
+ "SSDT-PCI: Register Generator. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/** Deregister the Generator from the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is deregistered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The Generator is not registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiSsdtPcieLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
+ DEBUG ((
+ DEBUG_INFO,
+ "SSDT-PCI: Deregister Generator. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
new file mode 100644
index 000000000000..2b7f40447d87
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
@@ -0,0 +1,134 @@
+/** @file
+ SSDT Pcie Table Generator.
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - PCI Firmware Specification - Revision 3.0
+ - ACPI 6.4 specification:
+ - s6.2.13 "_PRT (PCI Routing Table)"
+ - s6.1.1 "_ADR (Address)"
+ - linux kernel code
+**/
+
+#ifndef SSDT_PCIE_GENERATOR_H_
+#define SSDT_PCIE_GENERATOR_H_
+
+/** Pci address attributes.
+*/
+#define PCI_SS_CONFIG 0
+#define PCI_SS_IO 1
+#define PCI_SS_M32 2
+#define PCI_SS_M64 3
+
+/** Maximum Pci root complexes supported by this generator.
+
+ Note: This is not a hard limitation and can be extended if needed.
+ Corresponding changes would be needed to support the Name and
+ UID fields describing the Pci root complexes.
+*/
+#define MAX_PCI_ROOT_COMPLEXES_SUPPORTED 16
+
+/** Maximum number of Pci legacy interrupts.
+
+ Currently 4 for INTA-INTB-INTC-INTD.
+*/
+#define MAX_PCI_LEGACY_INTERRUPT 4
+
+// _SB scope of the AML namespace.
+#define SB_SCOPE "\\_SB_"
+
+/** C array containing the compiled AML template.
+ This symbol is defined in the auto generated C file
+ containing the AML bytecode array.
+*/
+extern CHAR8 ssdtpcieosctemplate_aml_code[];
+
+#pragma pack(1)
+
+/** Structure used to map integer to an index.
+*/
+typedef struct MappingTable {
+ /// Mapping table.
+ /// Contains the Index <-> integer mapping
+ UINT32 * Table;
+
+ /// Last used index of the Table.
+ /// Bound by MaxIndex.
+ UINT32 LastIndex;
+
+ /// Number of entries in the Table.
+ UINT32 MaxIndex;
+} MAPPING_TABLE;
+
+/** A structure holding the Pcie generator and additional private data.
+*/
+typedef struct AcpiPcieGenerator {
+ /// ACPI Table generator header
+ ACPI_TABLE_GENERATOR Header;
+
+ // Private fields are defined from here.
+
+ /** A structure used to handle the Address and Interrupt Map referencing.
+
+ A CM_ARM_PCI_CONFIG_SPACE_INFO structure references two CM_ARM_OBJ_REF:
+ - one for the address mapping, referencing
+ CM_ARM_PCI_ADDRESS_MAP_INFO structures.
+ - one for the address mapping, referencing
+ CM_ARM_PCI_INTERRUPT_MAP_INFO structures.
+
+ Example (for the interrupt mapping):
+ (Pci0)
+ CM_ARM_PCI_CONFIG_SPACE_INFO
+ |
+ v
+ (List of references to address mappings)
+ CM_ARM_OBJ_REF
+ |
+ +----------------------------------------
+ | |
+ v v
+ (A first interrupt mapping) (A second interrupt mapping)
+ CM_ARM_PCI_INTERRUPT_MAP_INFO[0] CM_ARM_PCI_INTERRUPT_MAP_INFO[1]
+
+ The CM_ARM_PCI_INTERRUPT_MAP_INFO objects cannot be handled individually.
+ Device's Pci legacy interrupts that are mapped to the same CPU interrupt
+ are grouped under a Link device.
+ For instance, the following mapping:
+ - [INTA of device 0] mapped on [GIC irq 168]
+ - [INTB of device 1] mapped on [GIC irq 168]
+ will be represented in an SSDT table as:
+ - [INTA of device 0] mapped on [Link device A]
+ - [INTB of device 1] mapped on [Link device A]
+ - [Link device A] mapped on [GIC irq 168]
+
+ Counting the number of Cpu interrupts used and grouping them in Link
+ devices is done through this IRQ_TABLE.
+
+ ASL code:
+ Scope (_SB) {
+ Device (LNKA) {
+ [...]
+ Name (_PRS, ResourceTemplate () {
+ Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { 168 }
+ })
+ }
+
+ Device (PCI0) {
+ Name (_PRT, Package () {
+ Package (0x0FFFF, 0, LNKA, 0) // INTA of device 0 <-> LNKA
+ Package (0x1FFFF, 1, LNKA, 0) // INTB of device 1 <-> LNKA
+ })
+ }
+ }
+ */
+ MAPPING_TABLE IrqTable;
+
+ /// Table to map: Index <-> Pci device
+ MAPPING_TABLE DeviceTable;
+} ACPI_PCI_GENERATOR;
+
+#pragma pack()
+
+#endif // SSDT_PCIE_GENERATOR_H_
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
new file mode 100644
index 000000000000..283b5648017c
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
@@ -0,0 +1,32 @@
+## @file
+# Ssdt Serial Port Table Generator
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = SsdtPcieLibArm
+ FILE_GUID = E431D7FD-26BF-4E3D-9064-5B13B0439057
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiSsdtPcieLibConstructor
+ DESTRUCTOR = AcpiSsdtPcieLibDestructor
+
+[Sources]
+ SsdtPcieGenerator.c
+ SsdtPcieGenerator.h
+ SsdtPcieOscTemplate.asl
+
+[Packages]
+ DynamicTablesPkg/DynamicTablesPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ AcpiHelperLib
+ AmlLib
+ BaseLib
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl
new file mode 100644
index 000000000000..feaf56b53384
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl
@@ -0,0 +1,80 @@
+/** @file
+ SSDT Pci Osc (Operating System Capabilities)
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - PCI Firmware Specification - Revision 3.3
+ - ACPI 6.4 specification:
+ - s6.2.13 "_PRT (PCI Routing Table)"
+ - s6.1.1 "_ADR (Address)"
+ - linux kernel code
+**/
+
+DefinitionBlock ("SsdtPciOsc.aml", "SSDT", 2, "ARMLTD", "PCI-OSC", 1) {
+
+ // This table is just a template and is never installed as a table.
+ // Pci devices are dynamically created at runtime as:
+ // ASL:
+ // Device (PCIx) {
+ // ...
+ // }
+ // and the _OSC method available below is appended to the PCIx device as:
+ // ASL:
+ // Device (PCIx) {
+ // ...
+ // Method (_OSC, 4 {
+ // ...
+ // })
+ // }
+ Method (_OSC, 4) {
+ //
+ // OS Control Handoff
+ //
+ Name (SUPP, Zero) // PCI _OSC Support Field value
+ Name (CTRL, Zero) // PCI _OSC Control Field value
+
+ // Create DWord-addressable fields from the Capabilities Buffer
+ CreateDWordField (Arg3, 0, CDW1)
+ CreateDWordField (Arg3, 4, CDW2)
+ CreateDWordField (Arg3, 8, CDW3)
+
+ // Check for proper UUID
+ If (LEqual (Arg0,ToUUID ("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) {
+
+ // Save Capabilities DWord2 & 3
+ Store (CDW2, SUPP)
+ Store (CDW3, CTRL)
+
+ // Only allow native hot plug control if OS supports:
+ // * ASPM
+ // * Clock PM
+ // * MSI/MSI-X
+ If (LNotEqual (And (SUPP, 0x16), 0x16)) {
+ And (CTRL, 0x1E, CTRL) // Mask bit 0 (and undefined bits)
+ }
+
+ // Always allow native PME, AER (no dependencies)
+
+ // Never allow SHPC (no SHPC controller in this system)
+ And (CTRL, 0x1D, CTRL)
+
+ If (LNotEqual (Arg1, One)) { // Unknown revision
+ Or (CDW1, 0x08, CDW1)
+ }
+
+ If (LNotEqual (CDW3, CTRL)) { // Capabilities bits were masked
+ Or (CDW1, 0x10, CDW1)
+ }
+
+ // Update DWORD3 in the buffer
+ Store (CTRL,CDW3)
+ Return (Arg3)
+ } Else {
+ Or (CDW1, 4, CDW1) // Unrecognized UUID
+ Return (Arg3)
+ } // If
+ } // _OSC
+}
--
2.17.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#76965): https://edk2.groups.io/g/devel/message/76965
Mute This Topic: https://groups.io/mt/83735882/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Hi Pierre,
Thank you for this patch.
I have some feedback marked inline as [SAMI].
Regards,
Sami Muajwar
On 23/06/2021 12:58 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> This generator allows to generate a SSDT table describing
> a Pci express Bus. It uses the following CmObj:
> - EArmObjCmRef
> - EArmObjPciConfigSpaceInfo
> - EArmObjPciAddressMapInfo
> - EArmObjPciInterruptMapInfo
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
> DynamicTablesPkg/DynamicTables.dsc.inc | 2 +
> DynamicTablesPkg/Include/AcpiTableGenerator.h | 5 +
> .../AcpiSsdtPcieLibArm/SsdtPcieGenerator.c | 1417 +++++++++++++++++
> .../AcpiSsdtPcieLibArm/SsdtPcieGenerator.h | 134 ++
> .../Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf | 32 +
> .../SsdtPcieOscTemplate.asl | 80 +
> 6 files changed, 1670 insertions(+)
> create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
> create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
> create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
> create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl
>
> diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
> index 292215c39456..60bcf4b199e8 100644
> --- a/DynamicTablesPkg/DynamicTables.dsc.inc
> +++ b/DynamicTablesPkg/DynamicTables.dsc.inc
> @@ -39,6 +39,7 @@ [Components.common]
>
> # AML Codegen
> DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
> + DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
>
> #
> # Dynamic Table Factory Dxe
> @@ -62,6 +63,7 @@ [Components.common]
>
> # AML Codegen
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
> + NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
> }
>
> #
> diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h
> index 45c808ba740d..58ec941f2a35 100644
> --- a/DynamicTablesPkg/Include/AcpiTableGenerator.h
> +++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
> @@ -67,6 +67,10 @@ The Dynamic Tables Framework implements the following ACPI table generators:
> The SSDT Cpu-Topology generator collates the cpu and LPI
> information from the Configuration Manager and generates a
> SSDT table describing the CPU hierarchy.
> + - SSDT Pci-Express:
> + The SSDT Pci Express generator collates the Pci Express
> + information from the Configuration Manager and generates a
> + SSDT table describing a Pci Express bus.
> */
>
> /** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID.
> @@ -93,6 +97,7 @@ typedef enum StdAcpiTableId {
> EStdAcpiTableIdSsdtSerialPort, ///< SSDT Serial-Port Generator
> EStdAcpiTableIdSsdtCmn600, ///< SSDT Cmn-600 Generator
> EStdAcpiTableIdSsdtCpuTopology, ///< SSDT Cpu Topology
> + EStdAcpiTableIdSsdtPciExpress, ///< SSDT Pci Express Generator
> EStdAcpiTableIdMax
> } ESTD_ACPI_TABLE_ID;
>
> diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
> new file mode 100644
> index 000000000000..478bc60ef6f3
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
> @@ -0,0 +1,1417 @@
> +/** @file
> + SSDT Pcie Table Generator.
> +
> + Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Reference(s):
> + - PCI Firmware Specification - Revision 3.0
> + - ACPI 6.4 specification:
> + - s6.2.13 "_PRT (PCI Routing Table)"
> + - s6.1.1 "_ADR (Address)"
> + - linux kernel code
> +**/
> +
> +#include <Library/AcpiLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/AcpiHelperLib.h>
> +#include <Library/AmlLib/AmlLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +#include "SsdtPcieGenerator.h"
> +
> +/** ARM standard SSDT Pcie Table Generator.
> +
> +Requirements:
> + The following Configuration Manager Object(s) are required by
> + this Generator:
> + - EArmObjCmRef
> + - EArmObjPciConfigSpaceInfo
> + - EArmObjPciAddressMapInfo
> + - EArmObjPciInterruptMapInfo
> +*/
> +
> +/** This macro expands to a function that retrieves the cross-CM-object-
> + reference information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> + EObjNameSpaceArm,
> + EArmObjCmRef,
> + CM_ARM_OBJ_REF
> + );
> +
> +/** This macro expands to a function that retrieves the Pci
> + Configuration Space Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> + EObjNameSpaceArm,
> + EArmObjPciConfigSpaceInfo,
> + CM_ARM_PCI_CONFIG_SPACE_INFO
> + );
> +
> +/** This macro expands to a function that retrieves the Pci
> + Address Mapping Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> + EObjNameSpaceArm,
> + EArmObjPciAddressMapInfo,
> + CM_ARM_PCI_ADDRESS_MAP_INFO
> + );
> +
> +/** This macro expands to a function that retrieves the Pci
> + Interrupt Mapping Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> + EObjNameSpaceArm,
> + EArmObjPciInterruptMapInfo,
> + CM_ARM_PCI_INTERRUPT_MAP_INFO
> + );
> +
> +/** Initialize the MappingTable.
> +
> + @param [in] MappingTable The mapping table structure.
> + @param [in] Count Number of entries to allocate in the
> + MappingTable.
> +
> + @retval EFI_SUCCESS Success.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +MappingTableInitialize (
> + IN MAPPING_TABLE * MappingTable,
> + IN UINT32 Count
> + )
> +{
> + UINT32 * Table;
> +
> + if ((MappingTable == NULL) ||
> + (Count == 0)) {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Table = AllocateZeroPool (sizeof (*Table) * Count);
> + if (Table == NULL) {
> + ASSERT (0);
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + MappingTable->Table = Table;
> + MappingTable->LastIndex = 0;
> + MappingTable->MaxIndex = Count;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/** Free the MappingTable.
> +
> + @param [in, out] MappingTable The mapping table structure.
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +MappingTableFree (
> + IN OUT MAPPING_TABLE * MappingTable
> + )
> +{
> + ASSERT (MappingTable != NULL);
> + ASSERT (MappingTable->Table != NULL);
> +
> + if (MappingTable->Table != NULL) {
> + FreePool (MappingTable->Table);
> + }
> +}
> +
> +/** Add a new entry to the MappingTable and return its index.
> +
> + If an entry with [Integer] is already available in the table,
> + return its index without adding a new entry.
> +
> + @param [in] MappingTable The mapping table structure.
> + @param [in] Integer New Integer entry to add.
> +
> + @retval The index of the Integer entry in the MappingTable.
> +**/
> +STATIC
> +UINT32
> +EFIAPI
> +MappingTableAdd (
> + IN MAPPING_TABLE * MappingTable,
> + IN UINT32 Integer
> + )
> +{
> + UINT32 * Table;
> + UINT32 Index;
> + UINT32 LastIndex;
> +
> + ASSERT (MappingTable != NULL);
> + ASSERT (MappingTable->Table != NULL);
> +
> + Table = MappingTable->Table;
> + LastIndex = MappingTable->LastIndex;
> +
> + // Search if there is already an entry with this Integer.
> + for (Index = 0; Index < LastIndex; Index++) {
> + if (Table[Index] == Integer) {
> + return Index;
> + }
> + }
> +
> + ASSERT (LastIndex < MAX_PCI_LEGACY_INTERRUPT);
[SAMI] Since the mapping table is used for PCI devices as well. What
happens if the number of devices are more than MAX_PCI_LEGACY_INTERRUPT
(which is 4)?
> + ASSERT (LastIndex < MappingTable->MaxIndex);
> +
> + // If no, create a new entry.
> + Table[LastIndex] = Integer;
> +
> + return MappingTable->LastIndex++;
> +}
> +
> +/** Generate required Pci device information.
> +
> + ASL code:
> + Name (_UID, [Uid]) // Uid of the Pci device
> + Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge
> + Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge
> + Name (_SEG, [Pci segment group]) // PCI Segment Group number
> + Name (_BBN, [Bus number]) // PCI Base Bus Number
> + Name (_CCA, 1) // Initially mark the PCI coherent
> +
> + @param [in] PciInfo Pci device information.
> + @param [in] Uid Unique Id of the Pci device.
> + @param [in, out] PciNode Pci node to amend.
> +
> + @retval EFI_SUCCESS Success.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GeneratePciDeviceInfo (
> + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
> + IN UINT32 Uid,
> + IN OUT AML_OBJECT_NODE_HANDLE PciNode
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 EisaId;
> +
> + ASSERT (PciInfo != NULL);
> + ASSERT (PciNode != NULL);
> +
> + // ASL: Name (_UID, [Uid])
> + Status = AmlCodeGenNameInteger ("_UID", Uid, PciNode, NULL);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL: Name (_HID, EISAID ("PNP0A08"))
> + Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> + Status = AmlCodeGenNameInteger ("_HID", EisaId, PciNode, NULL);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL: Name (_CID, EISAID ("PNP0A03"))
> + Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> + Status = AmlCodeGenNameInteger ("_CID", EisaId, PciNode, NULL);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL: Name (_SEG, [Pci segment group])
[SAMI] I think the comment above should be changed to // ASL: Name
(_SEG, <Pci segment group>) as the 'Pci segment group' is not an
optional value. Sam e comment for the 'Bus number' below.
> + Status = AmlCodeGenNameInteger (
> + "_SEG",
> + PciInfo->PciSegmentGroupNumber,
> + PciNode,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL: Name (_BBN, [Bus number])
> + Status = AmlCodeGenNameInteger (
> + "_BBN",
> + PciInfo->StartBusNumber,
> + PciNode,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL: Name (_CCA, 1)
> + // Must be aligned with the IORT CCA property in
> + // "Table 14 Memory access properties"
> + Status = AmlCodeGenNameInteger ("_CCA", 1, PciNode, NULL);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + }
> + return Status;
> +}
> +
> +/** Generate a Link device.
> +
> + The Link device is added at the beginning of the ASL Pci device definition.
> +
> + Each Link device represents a Pci legacy interrupt (INTA-...-INTD).
> +
> + ASL code:
> + Device ([Link Name]) {
> + Name (_UID, [Uid]])
> + Name (_HID, EISAID ("PNP0C0F"))
> + Name (_PRS, ResourceTemplate () {
> + Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { [Irq]] }
> + })
> + Method (_CRS, 0) { Return (_PRS) }
> + Method (_SRS, 1) { }
> + Method (_DIS) { }
> + }
> +
> + The list of objects to define is available at:
> + PCI Firmware Specification - Revision 3.3,
> + s3.5. "Device State at Firmware/Operating System Handoff"
> +
> + @param [in] Irq Interrupt controller interrupt.
> + @param [in] IrqFlags Interrupt flags.
> + @param [in] LinkIndex Legacy Pci interrupt index.
> + Must be between 0-INTA and 3-INTD.
> + @param [in, out] PciNode Pci node to amend.
> +
> + @retval EFI_SUCCESS Success.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GenerateLinkDevice (
> + IN UINT32 Irq,
> + IN UINT32 IrqFlags,
> + IN UINT32 LinkIndex,
> + IN OUT AML_OBJECT_NODE_HANDLE PciNode
> + )
> +{
> + EFI_STATUS Status;
> + CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
> + AML_OBJECT_NODE_HANDLE LinkNode;
> + AML_OBJECT_NODE_HANDLE CrsNode;
> + UINT32 EisaId;
> +
> + ASSERT (LinkIndex < 4);
> + ASSERT (PciNode != NULL);
> +
> + CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1);
> + AslName[AML_NAME_SEG_SIZE - 1] = 'A' + LinkIndex;
> +
> + // ASL: Device (LNKx) {}
> + Status = AmlCodeGenDevice (AslName, NULL, &LinkNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // The LNKx devices must be defined before being referenced.
> + // Thus add it to the head of the Pci list of variable arguments.
> + Status = AmlAttachNode (PciNode, LinkNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + // Failed to add.
> + AmlDeleteTree ((AML_NODE_HANDLE)LinkNode);
> + return Status;
> + }
> +
> + // ASL: Name (_UID, [Uid])
> + Status = AmlCodeGenNameInteger ("_UID", LinkIndex, LinkNode, NULL);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL: Name (_HID, EISAID ("PNP0C0F"))
> + Status = AmlGetEisaIdFromString ("PNP0C0F", &EisaId);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> + Status = AmlCodeGenNameInteger ("_HID", EisaId, LinkNode, NULL);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL:
> + // Name (_PRS, ResourceTemplate () {
> + // Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { [Irq] }
> + // })
> + Status = AmlCodeGenNameResourceTemplate ("_PRS", LinkNode, &CrsNode);
[SAMI] The Arm BBR specification, version 1.0, section 8.5.2 Device
methods and objects, states: "Note: The _PRS (Possible Resource
Settings) and _SRS (Set Resource Settings) are not supported."
Can you revisit this function again to see what needs to be done, please?
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> + Status = AmlCodeGenRdInterrupt (
> + FALSE,
> + (IrqFlags & BIT0) != 0,
> + (IrqFlags & BIT1) != 0,
> + FALSE,
> + &Irq,
> + 1,
> + CrsNode,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL:
> + // Method (_CRS, 0) {
> + // Return (_PRS)
> + // }
> + Status = AmlCodeGenMethodRetNameString (
> + "_CRS",
> + "_PRS",
> + 0,
> + FALSE,
> + 0,
> + LinkNode,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL: Method (_SRS, 1) {}
> + // Not possible to set interrupts.
> + Status = AmlCodeGenMethodRetNameString (
> + "_SRS",
> + NULL,
> + 1,
> + FALSE,
> + 0,
> + LinkNode,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL:Method (_DIS, 1) {}
> + // Not possible to disable interrupts.
> + Status = AmlCodeGenMethodRetNameString (
> + "_DIS",
> + NULL,
> + 0,
> + FALSE,
> + 0,
> + LinkNode,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // _STA:
> + // ACPI 6.4, s6.3.7 "_STA (Device Status)":
> + // If a device object describes a device that is not on an enumerable bus
> + // and the device object does not have an _STA object, then OSPM assumes
> + // that the device is present, enabled, shown in the UI, and functioning.
> +
> + // _MAT:
> + // Not supported. Mainly used for processors.
> +
> + return Status;
> +}
> +
> +/** Generate Pci slots devices.
> +
> + PCI Firmware Specification - Revision 3.3,
> + s4.8 "Generic ACPI PCI Slot Description" requests to describe the PCI slot
> + used. It should be possible to enumerate them, but this is additional
> + information.
> +
> + @param [in] MappingTable The mapping table structure.
> + @param [in, out] PciNode Pci node to amend.
> +
> + @retval EFI_SUCCESS Success.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GeneratePciSlots (
> + IN CONST MAPPING_TABLE * MappingTable,
> + IN OUT AML_OBJECT_NODE_HANDLE PciNode
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Index;
> + UINT32 LastIndex;
> + UINT32 DeviceId;
> + CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
> + AML_OBJECT_NODE_HANDLE DeviceNode;
> +
> + ASSERT (MappingTable != NULL);
> + ASSERT (PciNode != NULL);
> +
> + // Generic device name is "Dxx".
> + CopyMem (AslName, "Dxx_", AML_NAME_SEG_SIZE + 1);
> +
> + LastIndex = MappingTable->LastIndex;
> +
> + // There are at most 32 devices on a Pci bus.
> + ASSERT (LastIndex < 32);
[SAMI] Return an error if devices are more than 32.
> +
> + for (Index = 0; Index < LastIndex; Index++) {
> + DeviceId = MappingTable->Table[Index];
> + AslName[AML_NAME_SEG_SIZE - 3] = AsciiFromHex (DeviceId & 0xF);
> + AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((DeviceId >> 4) & 0xF);
> +
> + // ASL:
> + // Device (Dxx) {
> + // Name (_ADR, [address value])
> + // }
> + Status = AmlCodeGenDevice (AslName, PciNode, &DeviceNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + /* ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
> + High word-Device #, Low word-Function #. (for example, device 3,
> + function 2 is 0x00030002). To refer to all the functions on a device #,
> + use a function number of FFFF).
> + */
> + Status = AmlCodeGenNameInteger (
> + "_ADR",
> + (DeviceId << 16) | 0xFFFF,
> + DeviceNode,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // _SUN object is not generated as we don't know which slot will be used.
> + }
> +
> + return Status;
> +}
> +
> +/** Generate a _PRT object (Pci Routing Table) for the Pci device.
> +
> + Cf. ACPI 6.4 specification, s6.2.13 "_PRT (PCI Routing Table)"
> +
> + @param [in] Generator The SSDT Pci generator.
> + @param [in] CfgMgrProtocol Pointer to the Configuration Manager
> + Protocol interface.
> + @param [in] PciInfo Pci device information.
> + @param [in, out] PciNode Pci node to amend.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GeneratePrt (
> + IN ACPI_PCI_GENERATOR * Generator,
> + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
> + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
> + IN OUT AML_OBJECT_NODE_HANDLE PciNode
> + )
> +{
> + EFI_STATUS Status;
> + INT32 Index;
> + UINT32 IrqTableIndex;
> + AML_OBJECT_NODE_HANDLE PrtNode;
> + CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
> + CM_ARM_OBJ_REF * RefInfo;
> + UINT32 RefCount;
> + CM_ARM_PCI_INTERRUPT_MAP_INFO * IrqMapInfo;
> + UINT32 IrqFlags;
> + UINT32 PrevIrqFlags;
> +
> + ASSERT (Generator != NULL);
> + ASSERT (CfgMgrProtocol != NULL);
> + ASSERT (PciInfo != NULL);
> + ASSERT (PciNode != NULL);
> +
> + // Get the array of CM_ARM_OBJ_REF referencing the
> + // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
> + Status = GetEArmObjCmRef (
> + CfgMgrProtocol,
> + PciInfo->InterruptMapToken,
> + &RefInfo,
> + &RefCount
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
[SAMI] What happens if more than 4 CM_ARM_PCI_INTERRUPT_MAP_INFO objects
are returned?
> + // Initialized IrqTable.
> + Status = MappingTableInitialize (&Generator->IrqTable, RefCount);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Initialized DeviceTable.
> + Status = MappingTableInitialize (&Generator->DeviceTable, RefCount);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> +
> + // ASL: Name (_PRT, Package () {})
> + Status = AmlCodeGenNamePackage ("_PRT", PciNode, &PrtNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> +
> + CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1);
> +
> + for (Index = 0; Index < RefCount; Index++) {
> + // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
> + Status = GetEArmObjPciInterruptMapInfo (
> + CfgMgrProtocol,
> + RefInfo[Index].ReferenceToken,
> + &IrqMapInfo,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> +
> + // Add the interrupt in the IrqTable and get the link name.
> + IrqTableIndex = MappingTableAdd (
> + &Generator->IrqTable,
> + IrqMapInfo->IntcInterrupt.Interrupt
> + );
> + AslName[AML_NAME_SEG_SIZE - 1] = 'A' + IrqTableIndex;
> +
> + // Check that the interrupts flags are identical for all interrupts.
> + PrevIrqFlags = IrqFlags;
> + IrqFlags = IrqMapInfo->IntcInterrupt.Flags;
> + if ((Index > 0) && (PrevIrqFlags != IrqFlags)) {
> + ASSERT (0);
> + return EFI_INVALID_PARAMETER;
[SAMI] Go to the exit_handler to free the MappingTable memory.
> + }
> +
> + // Add the device to the DeviceTable.
> + MappingTableAdd (&Generator->DeviceTable, IrqMapInfo->PciDevice);
> +
> + /* Add a _PRT entry.
> + ASL
> + Name (_PRT, Package () {
> + [OldPrtEntries],
> + [NewPrtEntry]
> + })
> +
> + Address is set as:
> + ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
> + High word-Device #, Low word-Function #. (for example, device 3,
> + function 2 is 0x00030002). To refer to all the functions on a device #,
> + use a function number of FFFF).
> + */
> + Status = AmlAddPrtEntry (
> + (IrqMapInfo->PciDevice << 16) | 0xFFFF,
> + IrqMapInfo->PciInterrupt,
> + AslName,
> + 0,
> + PrtNode
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> + } // for
> +
> + // Generate the LNKx devices now that we know all the interrupts used.
> + // To look nicer, do it in reverse order since LNKx are added to the head.
> + for (Index = Generator->IrqTable.LastIndex - 1; Index >= 0; Index--) {
> + Status = GenerateLinkDevice (
> + Generator->IrqTable.Table[Index],
> + IrqFlags,
> + Index,
> + PciNode
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> + } // for
> +
> + // Generate the Pci slots once all the device have been added.
> + Status = GeneratePciSlots (&Generator->DeviceTable, PciNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> +
> +exit_handler:
> + MappingTableFree (&Generator->IrqTable);
> + MappingTableFree (&Generator->DeviceTable);
[SAMI] I think you need to split the exit handler. if initialisation of
DeviceTable fails it should not be freed.
> +
> + return Status;
> +}
> +
> +/** Generate a _CRS method for the Pci device.
> +
> + @param [in] Generator The SSDT Pci generator.
> + @param [in] CfgMgrProtocol Pointer to the Configuration Manager
> + Protocol interface.
> + @param [in] PciInfo Pci device information.
> + @param [in, out] PciNode Pci node to amend.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GeneratePciCrs (
> + IN ACPI_PCI_GENERATOR * Generator,
> + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
> + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
> + IN OUT AML_OBJECT_NODE_HANDLE PciNode
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN Translation;
> + UINT32 Index;
> + CM_ARM_OBJ_REF * RefInfo;
> + UINT32 RefCount;
> + CM_ARM_PCI_ADDRESS_MAP_INFO * AddrMapInfo;
> + AML_OBJECT_NODE_HANDLE CrsNode;
> +
> + ASSERT (Generator != NULL);
> + ASSERT (CfgMgrProtocol != NULL);
> + ASSERT (PciInfo != NULL);
> + ASSERT (PciNode != NULL);
> +
> + // ASL: Name (_CRS, ResourceTemplate () {})
> + Status = AmlCodeGenNameResourceTemplate ("_CRS", PciNode, &CrsNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // ASL:
> + // WordBusNumber ( // Bus numbers assigned to this root
> + // ResourceProducer, MinFixed, MaxFixed, PosDecode,
> + // 0, // AddressGranularity
> + // [Start], // AddressMinimum - Minimum Bus Number
> + // [End], // AddressMaximum - Maximum Bus Number
> + // 0, // AddressTranslation - Set to 0
> + // [End] - [Start] + 1 // RangeLength - Number of Busses
> + // )
> + Status = AmlCodeGenRdWordBusNumber (
> + FALSE, TRUE, TRUE, TRUE,
[SAMI] Please put parameters on individual lines. Same comment for other
functions calls below.
> + 0,
> + PciInfo->StartBusNumber,
> + PciInfo->EndBusNumber,
> + 0,
> + PciInfo->EndBusNumber - PciInfo->StartBusNumber + 1,
> + 0,
> + NULL,
> + CrsNode,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Get the array of CM_ARM_OBJ_REF referencing the
> + // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
> + Status = GetEArmObjCmRef (
> + CfgMgrProtocol,
> + PciInfo->AddressMapToken,
> + &RefInfo,
> + &RefCount
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + for (Index = 0; Index < RefCount; Index++) {
> + // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
> + Status = GetEArmObjPciAddressMapInfo (
> + CfgMgrProtocol,
> + RefInfo[Index].ReferenceToken,
> + &AddrMapInfo,
> + NULL
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + Translation = (AddrMapInfo->CpuAddress != AddrMapInfo->PciAddress);
> +
> + switch (AddrMapInfo->SpaceCode) {
> + case PCI_SS_IO:
> + Status = AmlCodeGenRdDWordIo (
> + FALSE, TRUE, TRUE, TRUE, 3,
> + 0,
> + AddrMapInfo->PciAddress,
> + AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
> + Translation ? AddrMapInfo->CpuAddress : 0,
> + AddrMapInfo->AddressSize,
> + 0, NULL,
> + TRUE,
> + FALSE,
> + CrsNode,
> + NULL
> + );
> + break;
> +
> + case PCI_SS_M32:
> + Status = AmlCodeGenRdDWordMemory (
> + FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
> + 0,
> + AddrMapInfo->PciAddress,
> + AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
> + Translation ? AddrMapInfo->CpuAddress : 0,
> + AddrMapInfo->AddressSize,
> + 0, NULL,
> + 0,
> + TRUE,
> + CrsNode,
> + NULL
> + );
> + break;
> +
> + case PCI_SS_M64:
> + Status = AmlCodeGenRdQWordMemory (
> + FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
> + 0,
> + AddrMapInfo->PciAddress,
> + AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
> + Translation ? AddrMapInfo->CpuAddress : 0,
> + AddrMapInfo->AddressSize,
> + 0, NULL,
> + 0,
> + TRUE,
> + CrsNode,
> + NULL
> + );
> + break;
> +
> + default:
> + Status = EFI_INVALID_PARAMETER;
> + } // switch
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> + } // for
> + return Status;
> +}
> +
> +/** Add an _OSC template method to the PciNode.
> +
> + The _OSC method is provided as an AML blob. The blob is
> + parsed and attached at the end of the PciNode list of variable elements.
> +
> + @param [in, out] PciNode Pci node to amend.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +AddOscMethod (
> + IN OUT AML_OBJECT_NODE_HANDLE PciNode
> + )
> +{
> + EFI_STATUS Status;
> + EFI_STATUS Status1;
> + EFI_ACPI_DESCRIPTION_HEADER * SsdtPcieOscTemplate;
> + AML_ROOT_NODE_HANDLE RootNode;
> + AML_OBJECT_NODE_HANDLE OscNode;
> +
> + ASSERT (PciNode != NULL);
> +
> + // Parse the Ssdt Pci Osc Template.
> + SsdtPcieOscTemplate = (EFI_ACPI_DESCRIPTION_HEADER*)
> + ssdtpcieosctemplate_aml_code;
> +
> + RootNode = NULL;
> + Status = AmlParseDefinitionBlock (
> + SsdtPcieOscTemplate,
[SAMI] Align code here.
> + &RootNode
[SAMI] Can we change the name from RootNode to OscTemplateRoot here, please?
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template."
> + " Status = %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + Status = AmlFindNode (RootNode, "\\_OSC", &OscNode);
> + if (EFI_ERROR (Status)) {
> + goto error_handler;
> + }
> +
> + Status = AmlDetachNode (OscNode);
> + if (EFI_ERROR (Status)) {
> + goto error_handler;
> + }
> +
> + Status = AmlAttachNode (PciNode, OscNode);
> + if (EFI_ERROR (Status)) {
[SAMI] If attach fails you would need to free the OscNode branch since
it is no longer in the OscTemplateRoot.
> + goto error_handler;
> + }
> +
> +error_handler:
> + // Cleanup
> + Status1 = AmlDeleteTree (RootNode);
> + if (EFI_ERROR (Status1)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "ERROR: SSDT-PCI-OSC: Failed to cleanup AML tree."
> + " Status = %r\n",
> + Status1
> + ));
> + // If Status was success but we failed to delete the AML Tree
> + // return Status1 else return the original error code, i.e. Status.
> + if (!EFI_ERROR (Status)) {
> + return Status1;
> + }
> + }
> +
> + return Status;
> +}
> +
> +/** Generate a Pci device.
> +
> + @param [in] Generator The SSDT Pci generator.
> + @param [in] CfgMgrProtocol Pointer to the Configuration Manager
> + Protocol interface.
> + @param [in] PciInfo Pci device information.
> + @param [in] Uid Unique Id of the Pci device.
> + @param [in, out] RootNode RootNode of the AML tree to populate.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GeneratePciDevice (
> + IN ACPI_PCI_GENERATOR * Generator,
> + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
> + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
> + IN UINT32 Uid,
> + IN OUT AML_ROOT_NODE_HANDLE * RootNode
> + )
> +{
> + EFI_STATUS Status;
> +
> + CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
> + AML_OBJECT_NODE_HANDLE ScopeNode;
> + AML_OBJECT_NODE_HANDLE PciNode;
> +
> + ASSERT (Generator != NULL);
> + ASSERT (CfgMgrProtocol != NULL);
> + ASSERT (PciInfo != NULL);
> + ASSERT (RootNode != NULL);
> +
> + PciNode = NULL;
> +
> + // ASL: Scope (\_SB) {}
> + Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Write the name of the PCI device.
> + CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1);
> + AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (Uid);
> +
> + // ASL: Device (PCIx) {}
> + Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Populate the PCIx node with some Id values.
> + Status = GeneratePciDeviceInfo (PciInfo, Uid, PciNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Generate the Pci Routing Table (_PRT).
> + if (PciInfo->InterruptMapToken != CM_NULL_TOKEN) {
> + Status = GeneratePrt (
> + Generator,
> + CfgMgrProtocol,
> + PciInfo,
> + PciNode
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> + }
> +
> + // Generate the _CRS method.
> + Status = GeneratePciCrs (Generator, CfgMgrProtocol, PciInfo, PciNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + // Add the template _OSC method.
> + Status = AddOscMethod (PciNode);
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + }
> +
> + return Status;
> +}
> +
> +/** Build an Ssdt table describing a Pci device.
> +
> + @param [in] Generator The SSDT Pci generator.
> + @param [in] CfgMgrProtocol Pointer to the Configuration Manager
> + Protocol interface.
> + @param [in] PciInfo Pci device information.
> + @param [in] Uid Unique Id of the Pci device.
> + @param [out] Table If success, contains the created SSDT table.
> +
> + @retval EFI_SUCCESS The function completed successfully.
> + @retval EFI_INVALID_PARAMETER Invalid parameter.
> + @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildSsdtPciTable (
> + IN ACPI_PCI_GENERATOR * Generator,
> + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
> + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
> + IN UINT32 Uid,
> + OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
> + )
> +{
> + EFI_STATUS Status;
> + EFI_STATUS Status1;
> + AML_ROOT_NODE_HANDLE RootNode;
> + CHAR8 OemTableId[9];
> +
> + ASSERT (Generator != NULL);
> + ASSERT (CfgMgrProtocol != NULL);
> + ASSERT (PciInfo != NULL);
> + ASSERT (Table != NULL);
> +
> + CopyMem (OemTableId, "SSDTPCIx", sizeof (OemTableId) + 1);
> + OemTableId[7] = AsciiFromHex(Uid);
> +
> + // Create a new Ssdt table.
> + Status = AmlCodeGenDefinitionBlock (
> + "SSDT",
> + "ARMLTD",
> + OemTableId,
> + 1,
> + &RootNode
> + );
[SAMI] The OemID, OemTableId and OemRevision should be picked
fromCM_STD_OBJ_CONFIGURATION_MANAGER_INFO
andCM_STD_OBJ_ACPI_TABLE_INFOwhich is described in the confiuration manager.
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + Status = GeneratePciDevice (
> + Generator,
> + CfgMgrProtocol,
> + PciInfo,
> + Uid,
> + RootNode
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + goto exit_handler;
> + }
> +
> + // Serialize the tree.
> + Status = AmlSerializeDefinitionBlock (
> + RootNode,
> + Table
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
> + " Status = %r\n",
> + Status
> + ));
> + }
> +
> +exit_handler:
> + // Cleanup
> + Status1 = AmlDeleteTree (RootNode);
> + if (EFI_ERROR (Status1)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "ERROR: SSDT-PCI: Failed to cleanup AML tree."
> + " Status = %r\n",
> + Status1
> + ));
> + // If Status was success but we failed to delete the AML Tree
> + // return Status1 else return the original error code, i.e. Status.
> + if (!EFI_ERROR (Status)) {
> + return Status1;
> + }
> + }
> +
> + return Status;
> +}
> +
> +/** Construct SSDT tables describing Pci root complexes.
> +
> + This function invokes the Configuration Manager protocol interface
> + to get the required hardware information for generating the ACPI
> + table.
> +
> + If this function allocates any resources then they must be freed
> + in the FreeXXXXTableResourcesEx function.
> +
> + @param [in] This Pointer to the ACPI table generator.
> + @param [in] AcpiTableInfo Pointer to the ACPI table information.
> + @param [in] CfgMgrProtocol Pointer to the Configuration Manager
> + Protocol interface.
> + @param [out] Table Pointer to a list of generated ACPI table(s).
> + @param [out] TableCount Number of generated ACPI table(s).
> +
> + @retval EFI_SUCCESS Table generated successfully.
> + @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
> + Manager is less than the Object size for
> + the requested object.
> + @retval EFI_INVALID_PARAMETER A parameter is invalid.
> + @retval EFI_NOT_FOUND Could not find information.
> + @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
> + @retval EFI_UNSUPPORTED Unsupported configuration.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildSsdtPciTableEx (
> + IN CONST ACPI_TABLE_GENERATOR * This,
> + IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
> + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
> + OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,
> + OUT UINTN * CONST TableCount
> + )
> +{
> + EFI_STATUS Status;
> + CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo;
> + UINT32 PciCount;
> + UINTN Index;
> + EFI_ACPI_DESCRIPTION_HEADER ** TableList;
> + ACPI_PCI_GENERATOR * Generator;
> +
> + ASSERT (This != NULL);
> + ASSERT (AcpiTableInfo != NULL);
> + ASSERT (CfgMgrProtocol != NULL);
> + ASSERT (Table != NULL);
> + ASSERT (TableCount != NULL);
> + ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> + ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> + *TableCount = 0;
> + Generator = (ACPI_PCI_GENERATOR*)This;
> +
> + Status = GetEArmObjPciConfigSpaceInfo (
> + CfgMgrProtocol,
> + CM_NULL_TOKEN,
> + &PciInfo,
> + &PciCount
> + );
> + if (EFI_ERROR (Status)) {
> + ASSERT (0);
> + return Status;
> + }
> +
> + if (PciCount > MAX_PCI_ROOT_COMPLEXES_SUPPORTED) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "ERROR: SSDT-PCI: Too many Pci root complexes: %d."
> + " Maximum Pci root complexes supported = %d.\n",
> + PciCount,
> + MAX_PCI_ROOT_COMPLEXES_SUPPORTED
> + ));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Allocate a table to store pointers to the SSDT tables.
> + TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
> + AllocateZeroPool (
> + (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * PciCount)
> + );
> + if (TableList == NULL) {
> + Status = EFI_OUT_OF_RESOURCES;
> + DEBUG ((
> + DEBUG_ERROR,
> + "ERROR: SSDT-PCI: Failed to allocate memory for Table List."
> + " Status = %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + // Setup the table list early so that appropriate cleanup
> + // can be done in case of failure.
> + *Table = TableList;
> +
> + for (Index = 0; Index < PciCount; Index++) {
> + // Build a SSDT table describing the Pci devices.
> + Status = BuildSsdtPciTable (
> + Generator,
> + CfgMgrProtocol,
> + &PciInfo[Index],
> + Index,
> + &TableList[Index]
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "ERROR: SSDT-PCI: Failed to build associated SSDT table."
> + " Status = %r\n",
> + Status
> + ));
> + goto error_handler;
> + }
> +
> + *TableCount += 1;
> + } // for
> +
> +error_handler:
> + // Note: Table list and Table count have been setup. The
> + // error handler does nothing here as the framework will invoke
> + // FreeSsdtPciTableEx () even on failure.
> + return Status;
> +}
> +
> +/** Free any resources allocated for constructing the tables.
> +
> + @param [in] This Pointer to the ACPI table generator.
> + @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
> + @param [in] CfgMgrProtocol Pointer to the Configuration Manager
> + Protocol Interface.
> + @param [in, out] Table Pointer to an array of pointers
> + to ACPI Table(s).
> + @param [in] TableCount Number of ACPI table(s).
> +
> + @retval EFI_SUCCESS The resources were freed successfully.
> + @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +FreeSsdtPciTableEx (
> + IN CONST ACPI_TABLE_GENERATOR * CONST This,
> + IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
> + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
> + IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,
> + IN CONST UINTN TableCount
> + )
> +{
> + EFI_ACPI_DESCRIPTION_HEADER ** TableList;
> + UINTN Index;
> +
> + ASSERT (This != NULL);
> + ASSERT (AcpiTableInfo != NULL);
> + ASSERT (CfgMgrProtocol != NULL);
> + ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> + ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> + if ((Table == NULL) ||
> + (*Table == NULL) ||
> + (TableCount == 0)) {
> + DEBUG ((DEBUG_ERROR, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + TableList = *Table;
> + for (Index = 0; Index < TableCount; Index++) {
> + if ((TableList[Index] != NULL) &&
> + (TableList[Index]->Signature ==
> + EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
> + FreePool (TableList[Index]);
> + } else {
> + DEBUG ((
> + DEBUG_ERROR,
> + "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
> + Index
> + ));
> + return EFI_INVALID_PARAMETER;
> + }
> + } //for
> +
> + // Free the table list.
> + FreePool (*Table);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/** This macro defines the SSDT Pci Table Generator revision.
> +*/
> +#define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the SSDT Pci Table Generator.
> +*/
> +STATIC
> +ACPI_PCI_GENERATOR SsdtPcieGenerator = {
> + // ACPI table generator header
> + {
> + // Generator ID
> + CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress),
> + // Generator Description
> + L"ACPI.STD.SSDT.PCI.GENERATOR",
> + // ACPI Table Signature
> + EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
> + // ACPI Table Revision - Unused
> + 0,
> + // Minimum ACPI Table Revision - Unused
> + 0,
> + // Creator ID
> + TABLE_GENERATOR_CREATOR_ID_ARM,
> + // Creator Revision
> + SSDT_PCI_GENERATOR_REVISION,
> + // Build table function. Use the extended version instead.
> + NULL,
> + // Free table function. Use the extended version instead.
> + NULL,
> + // Extended Build table function.
> + BuildSsdtPciTableEx,
> + // Extended free function.
> + FreeSsdtPciTableEx
> + },
> +
> + // Private fields are defined from here.
> +
> + // IrqTable
> + {
> + // Table
> + NULL,
> + // LastIndex
> + 0,
> + // MaxIndex
> + 0
> + },
> + // DeviceTable
> + {
> + // Table
> + NULL,
> + // LastIndex
> + 0,
> + // MaxIndex
> + 0
> + },
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> + @param [in] ImageHandle The handle to the image.
> + @param [in] SystemTable Pointer to the System Table.
> +
> + @retval EFI_SUCCESS The Generator is registered.
> + @retval EFI_INVALID_PARAMETER A parameter is invalid.
> + @retval EFI_ALREADY_STARTED The Generator for the Table ID
> + is already registered.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AcpiSsdtPcieLibConstructor (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE * SystemTable
> + )
> +{
> + EFI_STATUS Status;
> + Status = RegisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
> + DEBUG ((
> + DEBUG_INFO,
> + "SSDT-PCI: Register Generator. Status = %r\n",
> + Status
> + ));
> + ASSERT_EFI_ERROR (Status);
> +
> + return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> + @param [in] ImageHandle The handle to the image.
> + @param [in] SystemTable Pointer to the System Table.
> +
> + @retval EFI_SUCCESS The Generator is deregistered.
> + @retval EFI_INVALID_PARAMETER A parameter is invalid.
> + @retval EFI_NOT_FOUND The Generator is not registered.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AcpiSsdtPcieLibDestructor (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE * SystemTable
> + )
> +{
> + EFI_STATUS Status;
> + Status = DeregisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
> + DEBUG ((
> + DEBUG_INFO,
> + "SSDT-PCI: Deregister Generator. Status = %r\n",
> + Status
> + ));
> + ASSERT_EFI_ERROR (Status);
> + return Status;
> +}
> diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
> new file mode 100644
> index 000000000000..2b7f40447d87
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
> @@ -0,0 +1,134 @@
> +/** @file
> + SSDT Pcie Table Generator.
> +
> + Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Reference(s):
> + - PCI Firmware Specification - Revision 3.0
> + - ACPI 6.4 specification:
> + - s6.2.13 "_PRT (PCI Routing Table)"
> + - s6.1.1 "_ADR (Address)"
> + - linux kernel code
> +**/
> +
> +#ifndef SSDT_PCIE_GENERATOR_H_
> +#define SSDT_PCIE_GENERATOR_H_
> +
> +/** Pci address attributes.
> +*/
> +#define PCI_SS_CONFIG 0
> +#define PCI_SS_IO 1
> +#define PCI_SS_M32 2
> +#define PCI_SS_M64 3
[SAMI] Please add description of SS in the glossary section in the file
header.
> +
> +/** Maximum Pci root complexes supported by this generator.
> +
> + Note: This is not a hard limitation and can be extended if needed.
> + Corresponding changes would be needed to support the Name and
> + UID fields describing the Pci root complexes.
> +*/
> +#define MAX_PCI_ROOT_COMPLEXES_SUPPORTED 16
> +
> +/** Maximum number of Pci legacy interrupts.
> +
> + Currently 4 for INTA-INTB-INTC-INTD.
> +*/
> +#define MAX_PCI_LEGACY_INTERRUPT 4
> +
> +// _SB scope of the AML namespace.
> +#define SB_SCOPE "\\_SB_"
> +
> +/** C array containing the compiled AML template.
> + This symbol is defined in the auto generated C file
> + containing the AML bytecode array.
> +*/
> +extern CHAR8 ssdtpcieosctemplate_aml_code[];
> +
> +#pragma pack(1)
> +
> +/** Structure used to map integer to an index.
> +*/
> +typedef struct MappingTable {
> + /// Mapping table.
> + /// Contains the Index <-> integer mapping
> + UINT32 * Table;
> +
> + /// Last used index of the Table.
> + /// Bound by MaxIndex.
> + UINT32 LastIndex;
> +
> + /// Number of entries in the Table.
> + UINT32 MaxIndex;
> +} MAPPING_TABLE;
> +
> +/** A structure holding the Pcie generator and additional private data.
> +*/
> +typedef struct AcpiPcieGenerator {
> + /// ACPI Table generator header
> + ACPI_TABLE_GENERATOR Header;
> +
> + // Private fields are defined from here.
> +
> + /** A structure used to handle the Address and Interrupt Map referencing.
> +
> + A CM_ARM_PCI_CONFIG_SPACE_INFO structure references two CM_ARM_OBJ_REF:
> + - one for the address mapping, referencing
> + CM_ARM_PCI_ADDRESS_MAP_INFO structures.
> + - one for the address mapping, referencing
[SAMI] I believe this should be 'second for interrupt mapping'
> + CM_ARM_PCI_INTERRUPT_MAP_INFO structures.
> +
> + Example (for the interrupt mapping):
> + (Pci0)
> + CM_ARM_PCI_CONFIG_SPACE_INFO
> + |
> + v
> + (List of references to address mappings)
> + CM_ARM_OBJ_REF
> + |
> + +----------------------------------------
> + | |
> + v v
> + (A first interrupt mapping) (A second interrupt mapping)
> + CM_ARM_PCI_INTERRUPT_MAP_INFO[0] CM_ARM_PCI_INTERRUPT_MAP_INFO[1]
[SAMI] Please correct the above diagram.
> +
> + The CM_ARM_PCI_INTERRUPT_MAP_INFO objects cannot be handled individually.
> + Device's Pci legacy interrupts that are mapped to the same CPU interrupt
> + are grouped under a Link device.
> + For instance, the following mapping:
> + - [INTA of device 0] mapped on [GIC irq 168]
> + - [INTB of device 1] mapped on [GIC irq 168]
> + will be represented in an SSDT table as:
> + - [INTA of device 0] mapped on [Link device A]
> + - [INTB of device 1] mapped on [Link device A]
> + - [Link device A] mapped on [GIC irq 168]
> +
> + Counting the number of Cpu interrupts used and grouping them in Link
> + devices is done through this IRQ_TABLE.
> +
> + ASL code:
> + Scope (_SB) {
> + Device (LNKA) {
> + [...]
> + Name (_PRS, ResourceTemplate () {
> + Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { 168 }
> + })
> + }
> +
> + Device (PCI0) {
> + Name (_PRT, Package () {
> + Package (0x0FFFF, 0, LNKA, 0) // INTA of device 0 <-> LNKA
> + Package (0x1FFFF, 1, LNKA, 0) // INTB of device 1 <-> LNKA
> + })
> + }
> + }
> + */
> + MAPPING_TABLE IrqTable;
> +
> + /// Table to map: Index <-> Pci device
> + MAPPING_TABLE DeviceTable;
> +} ACPI_PCI_GENERATOR;
> +
> +#pragma pack()
> +
> +#endif // SSDT_PCIE_GENERATOR_H_
> diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
> new file mode 100644
> index 000000000000..283b5648017c
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
> @@ -0,0 +1,32 @@
> +## @file
> +# Ssdt Serial Port Table Generator
> +#
> +# Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = SsdtPcieLibArm
> + FILE_GUID = E431D7FD-26BF-4E3D-9064-5B13B0439057
> + VERSION_STRING = 1.0
> + MODULE_TYPE = DXE_DRIVER
> + LIBRARY_CLASS = NULL|DXE_DRIVER
> + CONSTRUCTOR = AcpiSsdtPcieLibConstructor
> + DESTRUCTOR = AcpiSsdtPcieLibDestructor
> +
> +[Sources]
> + SsdtPcieGenerator.c
> + SsdtPcieGenerator.h
> + SsdtPcieOscTemplate.asl
> +
> +[Packages]
> + DynamicTablesPkg/DynamicTablesPkg.dec
> + EmbeddedPkg/EmbeddedPkg.dec
> + MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> + AcpiHelperLib
> + AmlLib
> + BaseLib
> diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl
> new file mode 100644
> index 000000000000..feaf56b53384
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl
> @@ -0,0 +1,80 @@
> +/** @file
> + SSDT Pci Osc (Operating System Capabilities)
> +
> + Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + @par Reference(s):
> + - PCI Firmware Specification - Revision 3.3
> + - ACPI 6.4 specification:
> + - s6.2.13 "_PRT (PCI Routing Table)"
> + - s6.1.1 "_ADR (Address)"
> + - linux kernel code
> +**/
> +
> +DefinitionBlock ("SsdtPciOsc.aml", "SSDT", 2, "ARMLTD", "PCI-OSC", 1) {
> +
> + // This table is just a template and is never installed as a table.
> + // Pci devices are dynamically created at runtime as:
> + // ASL:
> + // Device (PCIx) {
> + // ...
> + // }
> + // and the _OSC method available below is appended to the PCIx device as:
> + // ASL:
> + // Device (PCIx) {
> + // ...
> + // Method (_OSC, 4 {
> + // ...
> + // })
> + // }
> + Method (_OSC, 4) {
> + //
> + // OS Control Handoff
> + //
> + Name (SUPP, Zero) // PCI _OSC Support Field value
> + Name (CTRL, Zero) // PCI _OSC Control Field value
> +
> + // Create DWord-addressable fields from the Capabilities Buffer
> + CreateDWordField (Arg3, 0, CDW1)
> + CreateDWordField (Arg3, 4, CDW2)
> + CreateDWordField (Arg3, 8, CDW3)
> +
> + // Check for proper UUID
> + If (LEqual (Arg0,ToUUID ("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) {
> +
> + // Save Capabilities DWord2 & 3
> + Store (CDW2, SUPP)
> + Store (CDW3, CTRL)
> +
> + // Only allow native hot plug control if OS supports:
> + // * ASPM
> + // * Clock PM
> + // * MSI/MSI-X
> + If (LNotEqual (And (SUPP, 0x16), 0x16)) {
> + And (CTRL, 0x1E, CTRL) // Mask bit 0 (and undefined bits)
> + }
> +
> + // Always allow native PME, AER (no dependencies)
> +
> + // Never allow SHPC (no SHPC controller in this system)
> + And (CTRL, 0x1D, CTRL)
> +
> + If (LNotEqual (Arg1, One)) { // Unknown revision
> + Or (CDW1, 0x08, CDW1)
> + }
> +
> + If (LNotEqual (CDW3, CTRL)) { // Capabilities bits were masked
> + Or (CDW1, 0x10, CDW1)
> + }
> +
> + // Update DWORD3 in the buffer
> + Store (CTRL,CDW3)
> + Return (Arg3)
> + } Else {
> + Or (CDW1, 4, CDW1) // Unrecognized UUID
> + Return (Arg3)
> + } // If
> + } // _OSC
> +}
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#81572): https://edk2.groups.io/g/devel/message/81572
Mute This Topic: https://groups.io/mt/83735882/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2026 Red Hat, Inc.