public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
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 --]

      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