From: "Sami Mujawar" <sami.mujawar@arm.com>
To: Pierre.Gondois@arm.com, devel@edk2.groups.io,
Alexei Fedorov <Alexei.Fedorov@arm.com>
Cc: Akanksha Jain <akanksha.jain2@arm.com>,
Alexandru Elisei <alexandru.elisei@arm.com>, nd <nd@arm.com>
Subject: Re: [PATCH v1 7/7] DynamicTablesPkg: SSDT Pci express generator
Date: Thu, 7 Oct 2021 12:11:07 +0100 [thread overview]
Message-ID: <e38eb324-a69f-9d49-a9c1-c8689715911d@arm.com> (raw)
In-Reply-To: <20210623115834.907-8-Pierre.Gondois@arm.com>
[-- Attachment #1: Type: text/plain, Size: 58069 bytes --]
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
> +}
[-- Attachment #2: Type: text/html, Size: 58684 bytes --]
prev parent reply other threads:[~2021-10-07 11:11 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-23 11:58 [PATCH v1 0/7] Create a SSDT PCIe generator PierreGondois
2021-06-23 11:58 ` [PATCH v1 1/7] DynamicTablesPkg: AML Code generation for memory ranges PierreGondois
2021-10-06 15:14 ` Sami Mujawar
2021-06-23 11:58 ` [PATCH v1 2/7] DynamicTablesPkg: AML Code generation to create a named Package() PierreGondois
2021-10-06 15:15 ` Sami Mujawar
2021-06-23 11:58 ` [PATCH v1 3/7] DynamicTablesPkg: AML Code generation to create a named ResourceTemplate() PierreGondois
2021-10-06 15:16 ` Sami Mujawar
2021-06-23 11:58 ` [PATCH v1 4/7] DynamicTablesPkg: AML Code generation to add _PRT entries PierreGondois
2021-10-06 15:17 ` Sami Mujawar
2021-06-23 11:58 ` [PATCH v1 5/7] DynamicTablesPkg: Add AmlAttachNode() PierreGondois
2021-10-06 15:17 ` Sami Mujawar
2021-06-23 11:58 ` [PATCH v1 6/7] DynamicTablesPkg: Add Pci related objects PierreGondois
2021-10-06 15:18 ` Sami Mujawar
2021-06-23 11:58 ` [PATCH v1 7/7] DynamicTablesPkg: SSDT Pci express generator PierreGondois
2021-10-07 11:11 ` Sami Mujawar [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e38eb324-a69f-9d49-a9c1-c8689715911d@arm.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox