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 > > 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 > --- > 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.
> + > + 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 > +#include > +#include > +#include > +#include > +#include > +#include > + > +// Module specific include files. > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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, ) 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.
> + 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.
> +# > +# 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.
> + > + 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 > +}