From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from EUR02-HE1-obe.outbound.protection.outlook.com (EUR02-HE1-obe.outbound.protection.outlook.com [40.107.1.50]) by mx.groups.io with SMTP id smtpd.web08.10185.1633605083377322474 for ; Thu, 07 Oct 2021 04:11:25 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@armh.onmicrosoft.com header.s=selector2-armh-onmicrosoft-com header.b=1M7+DzXa; spf=pass (domain: arm.com, ip: 40.107.1.50, mailfrom: sami.mujawar@arm.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=NGJqVpZd4KY2xJ7hlxePgBgzkkn2JDhJujt9N8N9AYg=; b=1M7+DzXaa1/YvkoKovpEeB0noNX+DyFxNMDgMeeLXbZUxuWCnpinfD4g1i7JF8ydYUfr5fGQZrf8fGcrQq7lRGGboBy2ru/MRMDRyNxy6pO/4CywRvOy6sghT9+SZu+ackQIZPEVRPLmwbw+tOWEHVHmH9clgvQNlNwfeaBdabQ= Received: from DB7PR02CA0025.eurprd02.prod.outlook.com (2603:10a6:10:52::38) by DB7PR08MB3660.eurprd08.prod.outlook.com (2603:10a6:10:46::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4587.19; Thu, 7 Oct 2021 11:11:17 +0000 Received: from DB5EUR03FT004.eop-EUR03.prod.protection.outlook.com (2603:10a6:10:52:cafe::4a) by DB7PR02CA0025.outlook.office365.com (2603:10a6:10:52::38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4587.18 via Frontend Transport; Thu, 7 Oct 2021 11:11:17 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; edk2.groups.io; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;edk2.groups.io; dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by DB5EUR03FT004.mail.protection.outlook.com (10.152.20.128) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4587.18 via Frontend Transport; Thu, 7 Oct 2021 11:11:17 +0000 Received: ("Tessian outbound 16951d3c485e:v103"); Thu, 07 Oct 2021 11:11:17 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 9cd65467389c6107 X-CR-MTA-TID: 64aa7808 Received: from 5c6d917c08c0.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id D607DB97-5836-464F-A612-D86930212F57.1; Thu, 07 Oct 2021 11:11:08 +0000 Received: from EUR01-HE1-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 5c6d917c08c0.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Thu, 07 Oct 2021 11:11:08 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=fmDUZ+XR+68tnoO9VvmjkHSMGbsrFU2il8xZPUuj0Cvq9X8gQptnyOkP9weblzUxp5IWaROrD96w1/eJ6+rSm3kXi/23UL/ygFWVhodr3F5bxbxX3RVDG8pPjX2OZm2CUFtVHarwfOypjbtZiN2bmt/YgpC3OhdAgTWeqMDuizumbHDI5Bgg7yS3AhtszENGLHaDdhPd5j/U4dSQsey3QwBcYcuh35RwCfaUzal7qbJaEUM46AVgNDNisUbmlqTQECmBlNBlEA2s0bz7awZ1E0huLwLgkNqpz0jcXOSJchXCpr+Cr3U1mp/7/QMiaZ2XD7icvW/2iXsXq7WiLYaBIw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=NGJqVpZd4KY2xJ7hlxePgBgzkkn2JDhJujt9N8N9AYg=; b=B0TSId4xHLLGD1KUTpS3/mcMkChlVnhJ45oso9UC8Rz+Jxlq/s/zv5jS/ixaa1eg8i3kGjUBNcB0QrP3AVdO3a6I9YGUU3amWqpxxzALwr4jRRfwJEMczazWmSkvy4xC9XREYXbZzpA+5rcVaFMxSYnixaEtRaKboVEYaugblUbjYRgzuPggNiJ6Xq2l8xE8ujpGki4pomVumLU5LgkCRznv3SDdk2PUlyeTW+ZMkAVRG6pwpO+YyW1hVwzCsvCM/nw78EyIJgw1JSLR1zcJOFb0oadfzbIA9LA+0Ll21tDseRrc783kDcXxuYPrXJK5hH+pblkXOhTZh09YPAxQmg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=NGJqVpZd4KY2xJ7hlxePgBgzkkn2JDhJujt9N8N9AYg=; b=1M7+DzXaa1/YvkoKovpEeB0noNX+DyFxNMDgMeeLXbZUxuWCnpinfD4g1i7JF8ydYUfr5fGQZrf8fGcrQq7lRGGboBy2ru/MRMDRyNxy6pO/4CywRvOy6sghT9+SZu+ackQIZPEVRPLmwbw+tOWEHVHmH9clgvQNlNwfeaBdabQ= Authentication-Results-Original: arm.com; dkim=none (message not signed) header.d=none;arm.com; dmarc=none action=none header.from=arm.com; Received: from AS8PR08MB6806.eurprd08.prod.outlook.com (2603:10a6:20b:39b::12) by AM6PR08MB4852.eurprd08.prod.outlook.com (2603:10a6:20b:cc::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4566.22; Thu, 7 Oct 2021 11:11:03 +0000 Received: from AS8PR08MB6806.eurprd08.prod.outlook.com ([fe80::54b5:239d:9896:ee65]) by AS8PR08MB6806.eurprd08.prod.outlook.com ([fe80::54b5:239d:9896:ee65%4]) with mapi id 15.20.4566.023; Thu, 7 Oct 2021 11:11:03 +0000 Subject: Re: [PATCH v1 7/7] DynamicTablesPkg: SSDT Pci express generator To: Pierre.Gondois@arm.com, devel@edk2.groups.io, Alexei Fedorov Cc: Akanksha Jain , Alexandru Elisei , nd References: <20210623115834.907-1-Pierre.Gondois@arm.com> <20210623115834.907-8-Pierre.Gondois@arm.com> From: "Sami Mujawar" Message-ID: Date: Thu, 7 Oct 2021 12:11:07 +0100 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.0.1 In-Reply-To: <20210623115834.907-8-Pierre.Gondois@arm.com> X-ClientProxiedBy: LNXP265CA0046.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:5c::34) To AS8PR08MB6806.eurprd08.prod.outlook.com (2603:10a6:20b:39b::12) MIME-Version: 1.0 Received: from [10.1.196.43] (217.140.106.52) by LNXP265CA0046.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:5c::34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4587.18 via Frontend Transport; Thu, 7 Oct 2021 11:11:02 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 654a1cd7-f9cb-482d-e02b-08d989832f68 X-MS-TrafficTypeDiagnostic: AM6PR08MB4852:|DB7PR08MB3660: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: x-checkrecipientrouted: true NoDisclaimer: true X-MS-Oob-TLC-OOBClassifiers: OLM:4714;OLM:4714; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: zp87cRs2zebCTEed4YOuZMwjE7+jW0TzescOvVpY39eVeNs/F+VpZdNtL633NYZvLs39iSnvpNZCV8Kc2+9yHR66wAAQEKiylK98VBIm/Eqdyh8nYwB5xMIEMJUJieyFmdAfqLWeCJW4sZ2UO1GWMETvQpMh0A/UwYtxDgi3INQl0iVggwLthdnt2U1LbywSPg6pL+dO8nDF4GZl/4QSvgZ1s8pA31z5UQjtJyjRgoNDaRmre3xT6G74lmv12UFsqANkIbZ+3MZs6VC6562/iD1entAXuIEtBPY9Y7Dnz21dlPjBF0AR1/Et+9uXSJ9gLG3aSVXkOCzcXIrjj3S6VaaFSs+swMS+DFereSvFPE9Zc87Aa5qeYQqIi3H3nH3GaIbAuZcFbiIErOWvYZENc4kdIB89ggXWd2cYw04N+1Tm9jZJC1LmE5BBrMIwZXgZtg0l6z5A+sXRO7ctaU2kKBDXjtyUjjKTJ8ikvrIqd+h9J2G9XAS/gm6x9Rh4bvkQFW4pVn1UtUBdSU6Bi1MRsant+RAStkPukHdO0NML+DiVnhMOySxjrd2JfihEE2NGqiYT7dk/kUStZqN4eKXgKPiCEhcH8RYlAUfp114rSjokhJDZ11o5kO/TtbXkYaGO7k1aOo26+YtTJ0SmokoWGKl4yaQpCnQuZ+nu3iln++8QAFRU7AfTrKR4CjWhUoQJicKMIQfGTXW1DRNAxwXSr28esqM30giK4Oqd7UFz8P0W+9O+P/9FbU3hBwqB5pPAfJpNQ6r7Mf7od6kqvbnKqw== X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:AS8PR08MB6806.eurprd08.prod.outlook.com;PTR:;CAT:NONE;SFS:(4636009)(366004)(956004)(2616005)(33964004)(508600001)(66946007)(31686004)(83380400001)(38100700002)(86362001)(66556008)(31696002)(38350700002)(66476007)(8936002)(2906002)(6486002)(30864003)(36756003)(8676002)(52116002)(37006003)(5660300002)(186003)(44832011)(4326008)(6636002)(26005)(54906003)(6862004)(53546011)(16576012)(316002)(43740500002)(45980500001)(579004)(559001);DIR:OUT;SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM6PR08MB4852 Original-Authentication-Results: arm.com; dkim=none (message not signed) header.d=none;arm.com; dmarc=none action=none header.from=arm.com; Return-Path: Sami.Mujawar@arm.com X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: DB5EUR03FT004.eop-EUR03.prod.protection.outlook.com X-MS-Office365-Filtering-Correlation-Id-Prvs: 99a64b9c-09ce-4bab-01fb-08d98983267d X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: J/xmiaYDrV/hiAqq8LFHZmgEHuhqKK0SIgNvW9r79KRXQldPZQIikpnVi8C315P3n8C1hlTOf+6OCZdbGFLOCy2OBlb0vYyZlAS1XNXoOsTYwe4nbS7ZseeEOWyG+GOpXWKP7qYojvcDsXpC8nsatwSytIPfDFfuXXUQ2H5DNvJl8DwzUdJAbHFiSsR2+zHbk1x3wuRRo5xVmdaeAKS/8TvhI3S2gpvlECUuK4XdI8IaVaQnYZ1mB5246hb4beF+4pPGx5mYZlvFdc4gGWPUWxdiu/WaLJpQm6Tia3Rsbjmjv8DuMHO2ojNgOVD/5sZZUc/LaFx/Iu5hQfhCA2Xh7aLJWzTqz5uA4nQLdoOo5jqWHsTS9bND1bB31jT5pLEa3KSSJP3PVASLSYniA/cEbGBtKEERoeFFBumoHqaftNg6YvRf9F2ngVjmvhROquzCDpTyqWrL2xeUd/gn2u1SI+UGEUomXWrN9+mtlHK29CksdKQliSHTj2HuhQ/8Vjzi5Zr+7uD5PvwUSJ5rpWwBurX3xscjV/U3Y+nfGyW9kr53xn9/4ocVJFP8HUn2+0Fi6E3+DgF3xXSYHoSpNut9aDyA74Mdu+NjBG21O8Oi9/hkfiYwbCsXE4vfm7tAqtjbTB55M+yI51bFb/Ay3SsDRtTzvj57j+L5w1ZMg+tEcBbBHLIUsvMcDEyhBoxOJlB2XkkYxsyudNYpVfQoKYUiB9q0MXUAdHK5F7akS2UJ5As= X-Forefront-Antispam-Report: CIP:63.35.35.123;CTRY:IE;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:64aa7808-outbound-1.mta.getcheckrecipient.com;PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com;CAT:NONE;SFS:(4636009)(46966006)(36840700001)(6862004)(356005)(8676002)(5660300002)(956004)(36756003)(336012)(82310400003)(2616005)(37006003)(44832011)(83380400001)(54906003)(16576012)(81166007)(508600001)(36860700001)(47076005)(6636002)(316002)(8936002)(26005)(33964004)(70206006)(6486002)(2906002)(31686004)(186003)(86362001)(30864003)(53546011)(70586007)(31696002)(4326008)(43740500002)(559001)(579004);DIR:OUT;SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 07 Oct 2021 11:11:17.8679 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 654a1cd7-f9cb-482d-e02b-08d989832f68 X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d;Ip=[63.35.35.123];Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: DB5EUR03FT004.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB7PR08MB3660 Content-Type: multipart/alternative; boundary="------------B0C14A3A16AC527C409570D3" Content-Language: en-GB --------------B0C14A3A16AC527C409570D3 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Hi Pierre, Thank you for this patch. I have some feedback marked inline as [SAMI]. Regards, Sami Muajwar On 23/06/2021 12:58 PM, Pierre.Gondois@arm.com wrote: > From: Pierre Gondois > > This generator allows to generate a SSDT table describing > a Pci express Bus. It uses the following CmObj: > - EArmObjCmRef > - EArmObjPciConfigSpaceInfo > - EArmObjPciAddressMapInfo > - EArmObjPciInterruptMapInfo > > Signed-off-by: Pierre Gondois > --- > DynamicTablesPkg/DynamicTables.dsc.inc | 2 + > DynamicTablesPkg/Include/AcpiTableGenerator.h | 5 + > .../AcpiSsdtPcieLibArm/SsdtPcieGenerator.c | 1417 +++++++++++++++++ > .../AcpiSsdtPcieLibArm/SsdtPcieGenerator.h | 134 ++ > .../Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf | 32 + > .../SsdtPcieOscTemplate.asl | 80 + > 6 files changed, 1670 insertions(+) > create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c > create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h > create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf > create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl > > diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc > index 292215c39456..60bcf4b199e8 100644 > --- a/DynamicTablesPkg/DynamicTables.dsc.inc > +++ b/DynamicTablesPkg/DynamicTables.dsc.inc > @@ -39,6 +39,7 @@ [Components.common] > > # AML Codegen > DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf > + DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf > > # > # Dynamic Table Factory Dxe > @@ -62,6 +63,7 @@ [Components.common] > > # AML Codegen > NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf > + NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf > } > > # > diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h > index 45c808ba740d..58ec941f2a35 100644 > --- a/DynamicTablesPkg/Include/AcpiTableGenerator.h > +++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h > @@ -67,6 +67,10 @@ The Dynamic Tables Framework implements the following ACPI table generators: > The SSDT Cpu-Topology generator collates the cpu and LPI > information from the Configuration Manager and generates a > SSDT table describing the CPU hierarchy. > + - SSDT Pci-Express: > + The SSDT Pci Express generator collates the Pci Express > + information from the Configuration Manager and generates a > + SSDT table describing a Pci Express bus. > */ > > /** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID. > @@ -93,6 +97,7 @@ typedef enum StdAcpiTableId { > EStdAcpiTableIdSsdtSerialPort, ///< SSDT Serial-Port Generator > EStdAcpiTableIdSsdtCmn600, ///< SSDT Cmn-600 Generator > EStdAcpiTableIdSsdtCpuTopology, ///< SSDT Cpu Topology > + EStdAcpiTableIdSsdtPciExpress, ///< SSDT Pci Express Generator > EStdAcpiTableIdMax > } ESTD_ACPI_TABLE_ID; > > diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c > new file mode 100644 > index 000000000000..478bc60ef6f3 > --- /dev/null > +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c > @@ -0,0 +1,1417 @@ > +/** @file > + SSDT Pcie Table Generator. > + > + Copyright (c) 2021, Arm Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Reference(s): > + - PCI Firmware Specification - Revision 3.0 > + - ACPI 6.4 specification: > + - s6.2.13 "_PRT (PCI Routing Table)" > + - s6.1.1 "_ADR (Address)" > + - linux kernel code > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +// Module specific include files. > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "SsdtPcieGenerator.h" > + > +/** ARM standard SSDT Pcie Table Generator. > + > +Requirements: > + The following Configuration Manager Object(s) are required by > + this Generator: > + - EArmObjCmRef > + - EArmObjPciConfigSpaceInfo > + - EArmObjPciAddressMapInfo > + - EArmObjPciInterruptMapInfo > +*/ > + > +/** This macro expands to a function that retrieves the cross-CM-object- > + reference information from the Configuration Manager. > +*/ > +GET_OBJECT_LIST ( > + EObjNameSpaceArm, > + EArmObjCmRef, > + CM_ARM_OBJ_REF > + ); > + > +/** This macro expands to a function that retrieves the Pci > + Configuration Space Information from the Configuration Manager. > +*/ > +GET_OBJECT_LIST ( > + EObjNameSpaceArm, > + EArmObjPciConfigSpaceInfo, > + CM_ARM_PCI_CONFIG_SPACE_INFO > + ); > + > +/** This macro expands to a function that retrieves the Pci > + Address Mapping Information from the Configuration Manager. > +*/ > +GET_OBJECT_LIST ( > + EObjNameSpaceArm, > + EArmObjPciAddressMapInfo, > + CM_ARM_PCI_ADDRESS_MAP_INFO > + ); > + > +/** This macro expands to a function that retrieves the Pci > + Interrupt Mapping Information from the Configuration Manager. > +*/ > +GET_OBJECT_LIST ( > + EObjNameSpaceArm, > + EArmObjPciInterruptMapInfo, > + CM_ARM_PCI_INTERRUPT_MAP_INFO > + ); > + > +/** Initialize the MappingTable. > + > + @param [in] MappingTable The mapping table structure. > + @param [in] Count Number of entries to allocate in the > + MappingTable. > + > + @retval EFI_SUCCESS Success. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +MappingTableInitialize ( > + IN MAPPING_TABLE * MappingTable, > + IN UINT32 Count > + ) > +{ > + UINT32 * Table; > + > + if ((MappingTable == NULL) || > + (Count == 0)) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; > + } > + > + Table = AllocateZeroPool (sizeof (*Table) * Count); > + if (Table == NULL) { > + ASSERT (0); > + return EFI_OUT_OF_RESOURCES; > + } > + > + MappingTable->Table = Table; > + MappingTable->LastIndex = 0; > + MappingTable->MaxIndex = Count; > + > + return EFI_SUCCESS; > +} > + > +/** Free the MappingTable. > + > + @param [in, out] MappingTable The mapping table structure. > +**/ > +STATIC > +VOID > +EFIAPI > +MappingTableFree ( > + IN OUT MAPPING_TABLE * MappingTable > + ) > +{ > + ASSERT (MappingTable != NULL); > + ASSERT (MappingTable->Table != NULL); > + > + if (MappingTable->Table != NULL) { > + FreePool (MappingTable->Table); > + } > +} > + > +/** Add a new entry to the MappingTable and return its index. > + > + If an entry with [Integer] is already available in the table, > + return its index without adding a new entry. > + > + @param [in] MappingTable The mapping table structure. > + @param [in] Integer New Integer entry to add. > + > + @retval The index of the Integer entry in the MappingTable. > +**/ > +STATIC > +UINT32 > +EFIAPI > +MappingTableAdd ( > + IN MAPPING_TABLE * MappingTable, > + IN UINT32 Integer > + ) > +{ > + UINT32 * Table; > + UINT32 Index; > + UINT32 LastIndex; > + > + ASSERT (MappingTable != NULL); > + ASSERT (MappingTable->Table != NULL); > + > + Table = MappingTable->Table; > + LastIndex = MappingTable->LastIndex; > + > + // Search if there is already an entry with this Integer. > + for (Index = 0; Index < LastIndex; Index++) { > + if (Table[Index] == Integer) { > + return Index; > + } > + } > + > + ASSERT (LastIndex < MAX_PCI_LEGACY_INTERRUPT); [SAMI] Since the mapping table is used for PCI devices as well. What happens if the number of devices are more than MAX_PCI_LEGACY_INTERRUPT (which is 4)? > + ASSERT (LastIndex < MappingTable->MaxIndex); > + > + // If no, create a new entry. > + Table[LastIndex] = Integer; > + > + return MappingTable->LastIndex++; > +} > + > +/** Generate required Pci device information. > + > + ASL code: > + Name (_UID, [Uid]) // Uid of the Pci device > + Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge > + Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge > + Name (_SEG, [Pci segment group]) // PCI Segment Group number > + Name (_BBN, [Bus number]) // PCI Base Bus Number > + Name (_CCA, 1) // Initially mark the PCI coherent > + > + @param [in] PciInfo Pci device information. > + @param [in] Uid Unique Id of the Pci device. > + @param [in, out] PciNode Pci node to amend. > + > + @retval EFI_SUCCESS Success. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +GeneratePciDeviceInfo ( > + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo, > + IN UINT32 Uid, > + IN OUT AML_OBJECT_NODE_HANDLE PciNode > + ) > +{ > + EFI_STATUS Status; > + UINT32 EisaId; > + > + ASSERT (PciInfo != NULL); > + ASSERT (PciNode != NULL); > + > + // ASL: Name (_UID, [Uid]) > + Status = AmlCodeGenNameInteger ("_UID", Uid, PciNode, NULL); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: Name (_HID, EISAID ("PNP0A08")) > + Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + Status = AmlCodeGenNameInteger ("_HID", EisaId, PciNode, NULL); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: Name (_CID, EISAID ("PNP0A03")) > + Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + Status = AmlCodeGenNameInteger ("_CID", EisaId, PciNode, NULL); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: Name (_SEG, [Pci segment group]) [SAMI] I think the comment above should be changed to // ASL: Name (_SEG, ) as the 'Pci segment group' is not an optional value. Sam e comment for the 'Bus number' below. > + Status = AmlCodeGenNameInteger ( > + "_SEG", > + PciInfo->PciSegmentGroupNumber, > + PciNode, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: Name (_BBN, [Bus number]) > + Status = AmlCodeGenNameInteger ( > + "_BBN", > + PciInfo->StartBusNumber, > + PciNode, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: Name (_CCA, 1) > + // Must be aligned with the IORT CCA property in > + // "Table 14 Memory access properties" > + Status = AmlCodeGenNameInteger ("_CCA", 1, PciNode, NULL); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + } > + return Status; > +} > + > +/** Generate a Link device. > + > + The Link device is added at the beginning of the ASL Pci device definition. > + > + Each Link device represents a Pci legacy interrupt (INTA-...-INTD). > + > + ASL code: > + Device ([Link Name]) { > + Name (_UID, [Uid]]) > + Name (_HID, EISAID ("PNP0C0F")) > + Name (_PRS, ResourceTemplate () { > + Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { [Irq]] } > + }) > + Method (_CRS, 0) { Return (_PRS) } > + Method (_SRS, 1) { } > + Method (_DIS) { } > + } > + > + The list of objects to define is available at: > + PCI Firmware Specification - Revision 3.3, > + s3.5. "Device State at Firmware/Operating System Handoff" > + > + @param [in] Irq Interrupt controller interrupt. > + @param [in] IrqFlags Interrupt flags. > + @param [in] LinkIndex Legacy Pci interrupt index. > + Must be between 0-INTA and 3-INTD. > + @param [in, out] PciNode Pci node to amend. > + > + @retval EFI_SUCCESS Success. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +GenerateLinkDevice ( > + IN UINT32 Irq, > + IN UINT32 IrqFlags, > + IN UINT32 LinkIndex, > + IN OUT AML_OBJECT_NODE_HANDLE PciNode > + ) > +{ > + EFI_STATUS Status; > + CHAR8 AslName[AML_NAME_SEG_SIZE + 1]; > + AML_OBJECT_NODE_HANDLE LinkNode; > + AML_OBJECT_NODE_HANDLE CrsNode; > + UINT32 EisaId; > + > + ASSERT (LinkIndex < 4); > + ASSERT (PciNode != NULL); > + > + CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1); > + AslName[AML_NAME_SEG_SIZE - 1] = 'A' + LinkIndex; > + > + // ASL: Device (LNKx) {} > + Status = AmlCodeGenDevice (AslName, NULL, &LinkNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // The LNKx devices must be defined before being referenced. > + // Thus add it to the head of the Pci list of variable arguments. > + Status = AmlAttachNode (PciNode, LinkNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + // Failed to add. > + AmlDeleteTree ((AML_NODE_HANDLE)LinkNode); > + return Status; > + } > + > + // ASL: Name (_UID, [Uid]) > + Status = AmlCodeGenNameInteger ("_UID", LinkIndex, LinkNode, NULL); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: Name (_HID, EISAID ("PNP0C0F")) > + Status = AmlGetEisaIdFromString ("PNP0C0F", &EisaId); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + Status = AmlCodeGenNameInteger ("_HID", EisaId, LinkNode, NULL); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: > + // Name (_PRS, ResourceTemplate () { > + // Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { [Irq] } > + // }) > + Status = AmlCodeGenNameResourceTemplate ("_PRS", LinkNode, &CrsNode); [SAMI] The Arm BBR specification, version 1.0, section 8.5.2 Device methods and objects, states: "Note: The _PRS (Possible Resource Settings) and _SRS (Set Resource Settings) are not supported." Can you revisit this function again to see what needs to be done, please? > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + Status = AmlCodeGenRdInterrupt ( > + FALSE, > + (IrqFlags & BIT0) != 0, > + (IrqFlags & BIT1) != 0, > + FALSE, > + &Irq, > + 1, > + CrsNode, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: > + // Method (_CRS, 0) { > + // Return (_PRS) > + // } > + Status = AmlCodeGenMethodRetNameString ( > + "_CRS", > + "_PRS", > + 0, > + FALSE, > + 0, > + LinkNode, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: Method (_SRS, 1) {} > + // Not possible to set interrupts. > + Status = AmlCodeGenMethodRetNameString ( > + "_SRS", > + NULL, > + 1, > + FALSE, > + 0, > + LinkNode, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL:Method (_DIS, 1) {} > + // Not possible to disable interrupts. > + Status = AmlCodeGenMethodRetNameString ( > + "_DIS", > + NULL, > + 0, > + FALSE, > + 0, > + LinkNode, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // _STA: > + // ACPI 6.4, s6.3.7 "_STA (Device Status)": > + // If a device object describes a device that is not on an enumerable bus > + // and the device object does not have an _STA object, then OSPM assumes > + // that the device is present, enabled, shown in the UI, and functioning. > + > + // _MAT: > + // Not supported. Mainly used for processors. > + > + return Status; > +} > + > +/** Generate Pci slots devices. > + > + PCI Firmware Specification - Revision 3.3, > + s4.8 "Generic ACPI PCI Slot Description" requests to describe the PCI slot > + used. It should be possible to enumerate them, but this is additional > + information. > + > + @param [in] MappingTable The mapping table structure. > + @param [in, out] PciNode Pci node to amend. > + > + @retval EFI_SUCCESS Success. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +GeneratePciSlots ( > + IN CONST MAPPING_TABLE * MappingTable, > + IN OUT AML_OBJECT_NODE_HANDLE PciNode > + ) > +{ > + EFI_STATUS Status; > + UINT32 Index; > + UINT32 LastIndex; > + UINT32 DeviceId; > + CHAR8 AslName[AML_NAME_SEG_SIZE + 1]; > + AML_OBJECT_NODE_HANDLE DeviceNode; > + > + ASSERT (MappingTable != NULL); > + ASSERT (PciNode != NULL); > + > + // Generic device name is "Dxx". > + CopyMem (AslName, "Dxx_", AML_NAME_SEG_SIZE + 1); > + > + LastIndex = MappingTable->LastIndex; > + > + // There are at most 32 devices on a Pci bus. > + ASSERT (LastIndex < 32); [SAMI] Return an error if devices are more than 32. > + > + for (Index = 0; Index < LastIndex; Index++) { > + DeviceId = MappingTable->Table[Index]; > + AslName[AML_NAME_SEG_SIZE - 3] = AsciiFromHex (DeviceId & 0xF); > + AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((DeviceId >> 4) & 0xF); > + > + // ASL: > + // Device (Dxx) { > + // Name (_ADR, [address value]) > + // } > + Status = AmlCodeGenDevice (AslName, PciNode, &DeviceNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + /* ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings" > + High word-Device #, Low word-Function #. (for example, device 3, > + function 2 is 0x00030002). To refer to all the functions on a device #, > + use a function number of FFFF). > + */ > + Status = AmlCodeGenNameInteger ( > + "_ADR", > + (DeviceId << 16) | 0xFFFF, > + DeviceNode, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // _SUN object is not generated as we don't know which slot will be used. > + } > + > + return Status; > +} > + > +/** Generate a _PRT object (Pci Routing Table) for the Pci device. > + > + Cf. ACPI 6.4 specification, s6.2.13 "_PRT (PCI Routing Table)" > + > + @param [in] Generator The SSDT Pci generator. > + @param [in] CfgMgrProtocol Pointer to the Configuration Manager > + Protocol interface. > + @param [in] PciInfo Pci device information. > + @param [in, out] PciNode Pci node to amend. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +GeneratePrt ( > + IN ACPI_PCI_GENERATOR * Generator, > + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, > + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo, > + IN OUT AML_OBJECT_NODE_HANDLE PciNode > + ) > +{ > + EFI_STATUS Status; > + INT32 Index; > + UINT32 IrqTableIndex; > + AML_OBJECT_NODE_HANDLE PrtNode; > + CHAR8 AslName[AML_NAME_SEG_SIZE + 1]; > + CM_ARM_OBJ_REF * RefInfo; > + UINT32 RefCount; > + CM_ARM_PCI_INTERRUPT_MAP_INFO * IrqMapInfo; > + UINT32 IrqFlags; > + UINT32 PrevIrqFlags; > + > + ASSERT (Generator != NULL); > + ASSERT (CfgMgrProtocol != NULL); > + ASSERT (PciInfo != NULL); > + ASSERT (PciNode != NULL); > + > + // Get the array of CM_ARM_OBJ_REF referencing the > + // CM_ARM_PCI_INTERRUPT_MAP_INFO objects. > + Status = GetEArmObjCmRef ( > + CfgMgrProtocol, > + PciInfo->InterruptMapToken, > + &RefInfo, > + &RefCount > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + [SAMI] What happens if more than 4 CM_ARM_PCI_INTERRUPT_MAP_INFO objects are returned? > + // Initialized IrqTable. > + Status = MappingTableInitialize (&Generator->IrqTable, RefCount); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // Initialized DeviceTable. > + Status = MappingTableInitialize (&Generator->DeviceTable, RefCount); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + goto exit_handler; > + } > + > + // ASL: Name (_PRT, Package () {}) > + Status = AmlCodeGenNamePackage ("_PRT", PciNode, &PrtNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + goto exit_handler; > + } > + > + CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1); > + > + for (Index = 0; Index < RefCount; Index++) { > + // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one. > + Status = GetEArmObjPciInterruptMapInfo ( > + CfgMgrProtocol, > + RefInfo[Index].ReferenceToken, > + &IrqMapInfo, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + goto exit_handler; > + } > + > + // Add the interrupt in the IrqTable and get the link name. > + IrqTableIndex = MappingTableAdd ( > + &Generator->IrqTable, > + IrqMapInfo->IntcInterrupt.Interrupt > + ); > + AslName[AML_NAME_SEG_SIZE - 1] = 'A' + IrqTableIndex; > + > + // Check that the interrupts flags are identical for all interrupts. > + PrevIrqFlags = IrqFlags; > + IrqFlags = IrqMapInfo->IntcInterrupt.Flags; > + if ((Index > 0) && (PrevIrqFlags != IrqFlags)) { > + ASSERT (0); > + return EFI_INVALID_PARAMETER; [SAMI] Go to the exit_handler to free the MappingTable memory. > + } > + > + // Add the device to the DeviceTable. > + MappingTableAdd (&Generator->DeviceTable, IrqMapInfo->PciDevice); > + > + /* Add a _PRT entry. > + ASL > + Name (_PRT, Package () { > + [OldPrtEntries], > + [NewPrtEntry] > + }) > + > + Address is set as: > + ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings" > + High word-Device #, Low word-Function #. (for example, device 3, > + function 2 is 0x00030002). To refer to all the functions on a device #, > + use a function number of FFFF). > + */ > + Status = AmlAddPrtEntry ( > + (IrqMapInfo->PciDevice << 16) | 0xFFFF, > + IrqMapInfo->PciInterrupt, > + AslName, > + 0, > + PrtNode > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + goto exit_handler; > + } > + } // for > + > + // Generate the LNKx devices now that we know all the interrupts used. > + // To look nicer, do it in reverse order since LNKx are added to the head. > + for (Index = Generator->IrqTable.LastIndex - 1; Index >= 0; Index--) { > + Status = GenerateLinkDevice ( > + Generator->IrqTable.Table[Index], > + IrqFlags, > + Index, > + PciNode > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + goto exit_handler; > + } > + } // for > + > + // Generate the Pci slots once all the device have been added. > + Status = GeneratePciSlots (&Generator->DeviceTable, PciNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + goto exit_handler; > + } > + > +exit_handler: > + MappingTableFree (&Generator->IrqTable); > + MappingTableFree (&Generator->DeviceTable); [SAMI] I think you need to split the exit handler. if initialisation of DeviceTable fails it should not be freed. > + > + return Status; > +} > + > +/** Generate a _CRS method for the Pci device. > + > + @param [in] Generator The SSDT Pci generator. > + @param [in] CfgMgrProtocol Pointer to the Configuration Manager > + Protocol interface. > + @param [in] PciInfo Pci device information. > + @param [in, out] PciNode Pci node to amend. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +GeneratePciCrs ( > + IN ACPI_PCI_GENERATOR * Generator, > + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, > + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo, > + IN OUT AML_OBJECT_NODE_HANDLE PciNode > + ) > +{ > + EFI_STATUS Status; > + BOOLEAN Translation; > + UINT32 Index; > + CM_ARM_OBJ_REF * RefInfo; > + UINT32 RefCount; > + CM_ARM_PCI_ADDRESS_MAP_INFO * AddrMapInfo; > + AML_OBJECT_NODE_HANDLE CrsNode; > + > + ASSERT (Generator != NULL); > + ASSERT (CfgMgrProtocol != NULL); > + ASSERT (PciInfo != NULL); > + ASSERT (PciNode != NULL); > + > + // ASL: Name (_CRS, ResourceTemplate () {}) > + Status = AmlCodeGenNameResourceTemplate ("_CRS", PciNode, &CrsNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // ASL: > + // WordBusNumber ( // Bus numbers assigned to this root > + // ResourceProducer, MinFixed, MaxFixed, PosDecode, > + // 0, // AddressGranularity > + // [Start], // AddressMinimum - Minimum Bus Number > + // [End], // AddressMaximum - Maximum Bus Number > + // 0, // AddressTranslation - Set to 0 > + // [End] - [Start] + 1 // RangeLength - Number of Busses > + // ) > + Status = AmlCodeGenRdWordBusNumber ( > + FALSE, TRUE, TRUE, TRUE, [SAMI] Please put parameters on individual lines. Same comment for other functions calls below. > + 0, > + PciInfo->StartBusNumber, > + PciInfo->EndBusNumber, > + 0, > + PciInfo->EndBusNumber - PciInfo->StartBusNumber + 1, > + 0, > + NULL, > + CrsNode, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // Get the array of CM_ARM_OBJ_REF referencing the > + // CM_ARM_PCI_ADDRESS_MAP_INFO objects. > + Status = GetEArmObjCmRef ( > + CfgMgrProtocol, > + PciInfo->AddressMapToken, > + &RefInfo, > + &RefCount > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + for (Index = 0; Index < RefCount; Index++) { > + // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one. > + Status = GetEArmObjPciAddressMapInfo ( > + CfgMgrProtocol, > + RefInfo[Index].ReferenceToken, > + &AddrMapInfo, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + Translation = (AddrMapInfo->CpuAddress != AddrMapInfo->PciAddress); > + > + switch (AddrMapInfo->SpaceCode) { > + case PCI_SS_IO: > + Status = AmlCodeGenRdDWordIo ( > + FALSE, TRUE, TRUE, TRUE, 3, > + 0, > + AddrMapInfo->PciAddress, > + AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1, > + Translation ? AddrMapInfo->CpuAddress : 0, > + AddrMapInfo->AddressSize, > + 0, NULL, > + TRUE, > + FALSE, > + CrsNode, > + NULL > + ); > + break; > + > + case PCI_SS_M32: > + Status = AmlCodeGenRdDWordMemory ( > + FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, > + 0, > + AddrMapInfo->PciAddress, > + AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1, > + Translation ? AddrMapInfo->CpuAddress : 0, > + AddrMapInfo->AddressSize, > + 0, NULL, > + 0, > + TRUE, > + CrsNode, > + NULL > + ); > + break; > + > + case PCI_SS_M64: > + Status = AmlCodeGenRdQWordMemory ( > + FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, > + 0, > + AddrMapInfo->PciAddress, > + AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1, > + Translation ? AddrMapInfo->CpuAddress : 0, > + AddrMapInfo->AddressSize, > + 0, NULL, > + 0, > + TRUE, > + CrsNode, > + NULL > + ); > + break; > + > + default: > + Status = EFI_INVALID_PARAMETER; > + } // switch > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + } // for > + return Status; > +} > + > +/** Add an _OSC template method to the PciNode. > + > + The _OSC method is provided as an AML blob. The blob is > + parsed and attached at the end of the PciNode list of variable elements. > + > + @param [in, out] PciNode Pci node to amend. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +AddOscMethod ( > + IN OUT AML_OBJECT_NODE_HANDLE PciNode > + ) > +{ > + EFI_STATUS Status; > + EFI_STATUS Status1; > + EFI_ACPI_DESCRIPTION_HEADER * SsdtPcieOscTemplate; > + AML_ROOT_NODE_HANDLE RootNode; > + AML_OBJECT_NODE_HANDLE OscNode; > + > + ASSERT (PciNode != NULL); > + > + // Parse the Ssdt Pci Osc Template. > + SsdtPcieOscTemplate = (EFI_ACPI_DESCRIPTION_HEADER*) > + ssdtpcieosctemplate_aml_code; > + > + RootNode = NULL; > + Status = AmlParseDefinitionBlock ( > + SsdtPcieOscTemplate, [SAMI] Align code here. > + &RootNode [SAMI] Can we change the name from RootNode to OscTemplateRoot here, please? > + ); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template." > + " Status = %r\n", > + Status > + )); > + return Status; > + } > + > + Status = AmlFindNode (RootNode, "\\_OSC", &OscNode); > + if (EFI_ERROR (Status)) { > + goto error_handler; > + } > + > + Status = AmlDetachNode (OscNode); > + if (EFI_ERROR (Status)) { > + goto error_handler; > + } > + > + Status = AmlAttachNode (PciNode, OscNode); > + if (EFI_ERROR (Status)) { [SAMI] If attach fails you would need to free the OscNode branch since it is no longer in the OscTemplateRoot. > + goto error_handler; > + } > + > +error_handler: > + // Cleanup > + Status1 = AmlDeleteTree (RootNode); > + if (EFI_ERROR (Status1)) { > + DEBUG (( > + DEBUG_ERROR, > + "ERROR: SSDT-PCI-OSC: Failed to cleanup AML tree." > + " Status = %r\n", > + Status1 > + )); > + // If Status was success but we failed to delete the AML Tree > + // return Status1 else return the original error code, i.e. Status. > + if (!EFI_ERROR (Status)) { > + return Status1; > + } > + } > + > + return Status; > +} > + > +/** Generate a Pci device. > + > + @param [in] Generator The SSDT Pci generator. > + @param [in] CfgMgrProtocol Pointer to the Configuration Manager > + Protocol interface. > + @param [in] PciInfo Pci device information. > + @param [in] Uid Unique Id of the Pci device. > + @param [in, out] RootNode RootNode of the AML tree to populate. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +GeneratePciDevice ( > + IN ACPI_PCI_GENERATOR * Generator, > + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, > + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo, > + IN UINT32 Uid, > + IN OUT AML_ROOT_NODE_HANDLE * RootNode > + ) > +{ > + EFI_STATUS Status; > + > + CHAR8 AslName[AML_NAME_SEG_SIZE + 1]; > + AML_OBJECT_NODE_HANDLE ScopeNode; > + AML_OBJECT_NODE_HANDLE PciNode; > + > + ASSERT (Generator != NULL); > + ASSERT (CfgMgrProtocol != NULL); > + ASSERT (PciInfo != NULL); > + ASSERT (RootNode != NULL); > + > + PciNode = NULL; > + > + // ASL: Scope (\_SB) {} > + Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // Write the name of the PCI device. > + CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1); > + AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (Uid); > + > + // ASL: Device (PCIx) {} > + Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // Populate the PCIx node with some Id values. > + Status = GeneratePciDeviceInfo (PciInfo, Uid, PciNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // Generate the Pci Routing Table (_PRT). > + if (PciInfo->InterruptMapToken != CM_NULL_TOKEN) { > + Status = GeneratePrt ( > + Generator, > + CfgMgrProtocol, > + PciInfo, > + PciNode > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + } > + > + // Generate the _CRS method. > + Status = GeneratePciCrs (Generator, CfgMgrProtocol, PciInfo, PciNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + // Add the template _OSC method. > + Status = AddOscMethod (PciNode); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + } > + > + return Status; > +} > + > +/** Build an Ssdt table describing a Pci device. > + > + @param [in] Generator The SSDT Pci generator. > + @param [in] CfgMgrProtocol Pointer to the Configuration Manager > + Protocol interface. > + @param [in] PciInfo Pci device information. > + @param [in] Uid Unique Id of the Pci device. > + @param [out] Table If success, contains the created SSDT table. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +BuildSsdtPciTable ( > + IN ACPI_PCI_GENERATOR * Generator, > + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, > + IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo, > + IN UINT32 Uid, > + OUT EFI_ACPI_DESCRIPTION_HEADER ** Table > + ) > +{ > + EFI_STATUS Status; > + EFI_STATUS Status1; > + AML_ROOT_NODE_HANDLE RootNode; > + CHAR8 OemTableId[9]; > + > + ASSERT (Generator != NULL); > + ASSERT (CfgMgrProtocol != NULL); > + ASSERT (PciInfo != NULL); > + ASSERT (Table != NULL); > + > + CopyMem (OemTableId, "SSDTPCIx", sizeof (OemTableId) + 1); > + OemTableId[7] = AsciiFromHex(Uid); > + > + // Create a new Ssdt table. > + Status = AmlCodeGenDefinitionBlock ( > + "SSDT", > + "ARMLTD", > + OemTableId, > + 1, > + &RootNode > + ); [SAMI] The OemID, OemTableId and OemRevision should be picked fromCM_STD_OBJ_CONFIGURATION_MANAGER_INFO andCM_STD_OBJ_ACPI_TABLE_INFOwhich is described in the confiuration manager. > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + Status = GeneratePciDevice ( > + Generator, > + CfgMgrProtocol, > + PciInfo, > + Uid, > + RootNode > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + goto exit_handler; > + } > + > + // Serialize the tree. > + Status = AmlSerializeDefinitionBlock ( > + RootNode, > + Table > + ); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data." > + " Status = %r\n", > + Status > + )); > + } > + > +exit_handler: > + // Cleanup > + Status1 = AmlDeleteTree (RootNode); > + if (EFI_ERROR (Status1)) { > + DEBUG (( > + DEBUG_ERROR, > + "ERROR: SSDT-PCI: Failed to cleanup AML tree." > + " Status = %r\n", > + Status1 > + )); > + // If Status was success but we failed to delete the AML Tree > + // return Status1 else return the original error code, i.e. Status. > + if (!EFI_ERROR (Status)) { > + return Status1; > + } > + } > + > + return Status; > +} > + > +/** Construct SSDT tables describing Pci root complexes. > + > + This function invokes the Configuration Manager protocol interface > + to get the required hardware information for generating the ACPI > + table. > + > + If this function allocates any resources then they must be freed > + in the FreeXXXXTableResourcesEx function. > + > + @param [in] This Pointer to the ACPI table generator. > + @param [in] AcpiTableInfo Pointer to the ACPI table information. > + @param [in] CfgMgrProtocol Pointer to the Configuration Manager > + Protocol interface. > + @param [out] Table Pointer to a list of generated ACPI table(s). > + @param [out] TableCount Number of generated ACPI table(s). > + > + @retval EFI_SUCCESS Table generated successfully. > + @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration > + Manager is less than the Object size for > + the requested object. > + @retval EFI_INVALID_PARAMETER A parameter is invalid. > + @retval EFI_NOT_FOUND Could not find information. > + @retval EFI_OUT_OF_RESOURCES Could not allocate memory. > + @retval EFI_UNSUPPORTED Unsupported configuration. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +BuildSsdtPciTableEx ( > + IN CONST ACPI_TABLE_GENERATOR * This, > + IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo, > + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, > + OUT EFI_ACPI_DESCRIPTION_HEADER *** Table, > + OUT UINTN * CONST TableCount > + ) > +{ > + EFI_STATUS Status; > + CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo; > + UINT32 PciCount; > + UINTN Index; > + EFI_ACPI_DESCRIPTION_HEADER ** TableList; > + ACPI_PCI_GENERATOR * Generator; > + > + ASSERT (This != NULL); > + ASSERT (AcpiTableInfo != NULL); > + ASSERT (CfgMgrProtocol != NULL); > + ASSERT (Table != NULL); > + ASSERT (TableCount != NULL); > + ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID); > + ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature); > + > + *TableCount = 0; > + Generator = (ACPI_PCI_GENERATOR*)This; > + > + Status = GetEArmObjPciConfigSpaceInfo ( > + CfgMgrProtocol, > + CM_NULL_TOKEN, > + &PciInfo, > + &PciCount > + ); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return Status; > + } > + > + if (PciCount > MAX_PCI_ROOT_COMPLEXES_SUPPORTED) { > + DEBUG (( > + DEBUG_ERROR, > + "ERROR: SSDT-PCI: Too many Pci root complexes: %d." > + " Maximum Pci root complexes supported = %d.\n", > + PciCount, > + MAX_PCI_ROOT_COMPLEXES_SUPPORTED > + )); > + return EFI_INVALID_PARAMETER; > + } > + > + // Allocate a table to store pointers to the SSDT tables. > + TableList = (EFI_ACPI_DESCRIPTION_HEADER**) > + AllocateZeroPool ( > + (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * PciCount) > + ); > + if (TableList == NULL) { > + Status = EFI_OUT_OF_RESOURCES; > + DEBUG (( > + DEBUG_ERROR, > + "ERROR: SSDT-PCI: Failed to allocate memory for Table List." > + " Status = %r\n", > + Status > + )); > + return Status; > + } > + > + // Setup the table list early so that appropriate cleanup > + // can be done in case of failure. > + *Table = TableList; > + > + for (Index = 0; Index < PciCount; Index++) { > + // Build a SSDT table describing the Pci devices. > + Status = BuildSsdtPciTable ( > + Generator, > + CfgMgrProtocol, > + &PciInfo[Index], > + Index, > + &TableList[Index] > + ); > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "ERROR: SSDT-PCI: Failed to build associated SSDT table." > + " Status = %r\n", > + Status > + )); > + goto error_handler; > + } > + > + *TableCount += 1; > + } // for > + > +error_handler: > + // Note: Table list and Table count have been setup. The > + // error handler does nothing here as the framework will invoke > + // FreeSsdtPciTableEx () even on failure. > + return Status; > +} > + > +/** Free any resources allocated for constructing the tables. > + > + @param [in] This Pointer to the ACPI table generator. > + @param [in] AcpiTableInfo Pointer to the ACPI Table Info. > + @param [in] CfgMgrProtocol Pointer to the Configuration Manager > + Protocol Interface. > + @param [in, out] Table Pointer to an array of pointers > + to ACPI Table(s). > + @param [in] TableCount Number of ACPI table(s). > + > + @retval EFI_SUCCESS The resources were freed successfully. > + @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid. > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +FreeSsdtPciTableEx ( > + IN CONST ACPI_TABLE_GENERATOR * CONST This, > + IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo, > + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, > + IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table, > + IN CONST UINTN TableCount > + ) > +{ > + EFI_ACPI_DESCRIPTION_HEADER ** TableList; > + UINTN Index; > + > + ASSERT (This != NULL); > + ASSERT (AcpiTableInfo != NULL); > + ASSERT (CfgMgrProtocol != NULL); > + ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID); > + ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature); > + > + if ((Table == NULL) || > + (*Table == NULL) || > + (TableCount == 0)) { > + DEBUG ((DEBUG_ERROR, "ERROR: SSDT-PCI: Invalid Table Pointer\n")); > + return EFI_INVALID_PARAMETER; > + } > + > + TableList = *Table; > + for (Index = 0; Index < TableCount; Index++) { > + if ((TableList[Index] != NULL) && > + (TableList[Index]->Signature == > + EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) { > + FreePool (TableList[Index]); > + } else { > + DEBUG (( > + DEBUG_ERROR, > + "ERROR: SSDT-PCI: Could not free SSDT table at index %d.", > + Index > + )); > + return EFI_INVALID_PARAMETER; > + } > + } //for > + > + // Free the table list. > + FreePool (*Table); > + > + return EFI_SUCCESS; > +} > + > +/** This macro defines the SSDT Pci Table Generator revision. > +*/ > +#define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0) > + > +/** The interface for the SSDT Pci Table Generator. > +*/ > +STATIC > +ACPI_PCI_GENERATOR SsdtPcieGenerator = { > + // ACPI table generator header > + { > + // Generator ID > + CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress), > + // Generator Description > + L"ACPI.STD.SSDT.PCI.GENERATOR", > + // ACPI Table Signature > + EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, > + // ACPI Table Revision - Unused > + 0, > + // Minimum ACPI Table Revision - Unused > + 0, > + // Creator ID > + TABLE_GENERATOR_CREATOR_ID_ARM, > + // Creator Revision > + SSDT_PCI_GENERATOR_REVISION, > + // Build table function. Use the extended version instead. > + NULL, > + // Free table function. Use the extended version instead. > + NULL, > + // Extended Build table function. > + BuildSsdtPciTableEx, > + // Extended free function. > + FreeSsdtPciTableEx > + }, > + > + // Private fields are defined from here. > + > + // IrqTable > + { > + // Table > + NULL, > + // LastIndex > + 0, > + // MaxIndex > + 0 > + }, > + // DeviceTable > + { > + // Table > + NULL, > + // LastIndex > + 0, > + // MaxIndex > + 0 > + }, > +}; > + > +/** Register the Generator with the ACPI Table Factory. > + > + @param [in] ImageHandle The handle to the image. > + @param [in] SystemTable Pointer to the System Table. > + > + @retval EFI_SUCCESS The Generator is registered. > + @retval EFI_INVALID_PARAMETER A parameter is invalid. > + @retval EFI_ALREADY_STARTED The Generator for the Table ID > + is already registered. > +**/ > +EFI_STATUS > +EFIAPI > +AcpiSsdtPcieLibConstructor ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE * SystemTable > + ) > +{ > + EFI_STATUS Status; > + Status = RegisterAcpiTableGenerator (&SsdtPcieGenerator.Header); > + DEBUG (( > + DEBUG_INFO, > + "SSDT-PCI: Register Generator. Status = %r\n", > + Status > + )); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > + > +/** Deregister the Generator from the ACPI Table Factory. > + > + @param [in] ImageHandle The handle to the image. > + @param [in] SystemTable Pointer to the System Table. > + > + @retval EFI_SUCCESS The Generator is deregistered. > + @retval EFI_INVALID_PARAMETER A parameter is invalid. > + @retval EFI_NOT_FOUND The Generator is not registered. > +**/ > +EFI_STATUS > +EFIAPI > +AcpiSsdtPcieLibDestructor ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE * SystemTable > + ) > +{ > + EFI_STATUS Status; > + Status = DeregisterAcpiTableGenerator (&SsdtPcieGenerator.Header); > + DEBUG (( > + DEBUG_INFO, > + "SSDT-PCI: Deregister Generator. Status = %r\n", > + Status > + )); > + ASSERT_EFI_ERROR (Status); > + return Status; > +} > diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h > new file mode 100644 > index 000000000000..2b7f40447d87 > --- /dev/null > +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h > @@ -0,0 +1,134 @@ > +/** @file > + SSDT Pcie Table Generator. > + > + Copyright (c) 2021, Arm Limited. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Reference(s): > + - PCI Firmware Specification - Revision 3.0 > + - ACPI 6.4 specification: > + - s6.2.13 "_PRT (PCI Routing Table)" > + - s6.1.1 "_ADR (Address)" > + - linux kernel code > +**/ > + > +#ifndef SSDT_PCIE_GENERATOR_H_ > +#define SSDT_PCIE_GENERATOR_H_ > + > +/** Pci address attributes. > +*/ > +#define PCI_SS_CONFIG 0 > +#define PCI_SS_IO 1 > +#define PCI_SS_M32 2 > +#define PCI_SS_M64 3 [SAMI] Please add description of SS in the glossary section in the file header. > + > +/** Maximum Pci root complexes supported by this generator. > + > + Note: This is not a hard limitation and can be extended if needed. > + Corresponding changes would be needed to support the Name and > + UID fields describing the Pci root complexes. > +*/ > +#define MAX_PCI_ROOT_COMPLEXES_SUPPORTED 16 > + > +/** Maximum number of Pci legacy interrupts. > + > + Currently 4 for INTA-INTB-INTC-INTD. > +*/ > +#define MAX_PCI_LEGACY_INTERRUPT 4 > + > +// _SB scope of the AML namespace. > +#define SB_SCOPE "\\_SB_" > + > +/** C array containing the compiled AML template. > + This symbol is defined in the auto generated C file > + containing the AML bytecode array. > +*/ > +extern CHAR8 ssdtpcieosctemplate_aml_code[]; > + > +#pragma pack(1) > + > +/** Structure used to map integer to an index. > +*/ > +typedef struct MappingTable { > + /// Mapping table. > + /// Contains the Index <-> integer mapping > + UINT32 * Table; > + > + /// Last used index of the Table. > + /// Bound by MaxIndex. > + UINT32 LastIndex; > + > + /// Number of entries in the Table. > + UINT32 MaxIndex; > +} MAPPING_TABLE; > + > +/** A structure holding the Pcie generator and additional private data. > +*/ > +typedef struct AcpiPcieGenerator { > + /// ACPI Table generator header > + ACPI_TABLE_GENERATOR Header; > + > + // Private fields are defined from here. > + > + /** A structure used to handle the Address and Interrupt Map referencing. > + > + A CM_ARM_PCI_CONFIG_SPACE_INFO structure references two CM_ARM_OBJ_REF: > + - one for the address mapping, referencing > + CM_ARM_PCI_ADDRESS_MAP_INFO structures. > + - one for the address mapping, referencing [SAMI] I believe this should be 'second for interrupt mapping' > + CM_ARM_PCI_INTERRUPT_MAP_INFO structures. > + > + Example (for the interrupt mapping): > + (Pci0) > + CM_ARM_PCI_CONFIG_SPACE_INFO > + | > + v > + (List of references to address mappings) > + CM_ARM_OBJ_REF > + | > + +---------------------------------------- > + | | > + v v > + (A first interrupt mapping) (A second interrupt mapping) > + CM_ARM_PCI_INTERRUPT_MAP_INFO[0] CM_ARM_PCI_INTERRUPT_MAP_INFO[1] [SAMI] Please correct the above diagram. > + > + The CM_ARM_PCI_INTERRUPT_MAP_INFO objects cannot be handled individually. > + Device's Pci legacy interrupts that are mapped to the same CPU interrupt > + are grouped under a Link device. > + For instance, the following mapping: > + - [INTA of device 0] mapped on [GIC irq 168] > + - [INTB of device 1] mapped on [GIC irq 168] > + will be represented in an SSDT table as: > + - [INTA of device 0] mapped on [Link device A] > + - [INTB of device 1] mapped on [Link device A] > + - [Link device A] mapped on [GIC irq 168] > + > + Counting the number of Cpu interrupts used and grouping them in Link > + devices is done through this IRQ_TABLE. > + > + ASL code: > + Scope (_SB) { > + Device (LNKA) { > + [...] > + Name (_PRS, ResourceTemplate () { > + Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { 168 } > + }) > + } > + > + Device (PCI0) { > + Name (_PRT, Package () { > + Package (0x0FFFF, 0, LNKA, 0) // INTA of device 0 <-> LNKA > + Package (0x1FFFF, 1, LNKA, 0) // INTB of device 1 <-> LNKA > + }) > + } > + } > + */ > + MAPPING_TABLE IrqTable; > + > + /// Table to map: Index <-> Pci device > + MAPPING_TABLE DeviceTable; > +} ACPI_PCI_GENERATOR; > + > +#pragma pack() > + > +#endif // SSDT_PCIE_GENERATOR_H_ > diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf > new file mode 100644 > index 000000000000..283b5648017c > --- /dev/null > +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf > @@ -0,0 +1,32 @@ > +## @file > +# Ssdt Serial Port Table Generator > +# > +# Copyright (c) 2021, Arm Limited. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +## > + > +[Defines] > + INF_VERSION = 0x0001001B > + BASE_NAME = SsdtPcieLibArm > + FILE_GUID = E431D7FD-26BF-4E3D-9064-5B13B0439057 > + VERSION_STRING = 1.0 > + MODULE_TYPE = DXE_DRIVER > + LIBRARY_CLASS = NULL|DXE_DRIVER > + CONSTRUCTOR = AcpiSsdtPcieLibConstructor > + DESTRUCTOR = AcpiSsdtPcieLibDestructor > + > +[Sources] > + SsdtPcieGenerator.c > + SsdtPcieGenerator.h > + SsdtPcieOscTemplate.asl > + > +[Packages] > + DynamicTablesPkg/DynamicTablesPkg.dec > + EmbeddedPkg/EmbeddedPkg.dec > + MdePkg/MdePkg.dec > + > +[LibraryClasses] > + AcpiHelperLib > + AmlLib > + BaseLib > diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl > new file mode 100644 > index 000000000000..feaf56b53384 > --- /dev/null > +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl > @@ -0,0 +1,80 @@ > +/** @file > + SSDT Pci Osc (Operating System Capabilities) > + > + Copyright (c) 2021, Arm Limited. All rights reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + @par Reference(s): > + - PCI Firmware Specification - Revision 3.3 > + - ACPI 6.4 specification: > + - s6.2.13 "_PRT (PCI Routing Table)" > + - s6.1.1 "_ADR (Address)" > + - linux kernel code > +**/ > + > +DefinitionBlock ("SsdtPciOsc.aml", "SSDT", 2, "ARMLTD", "PCI-OSC", 1) { > + > + // This table is just a template and is never installed as a table. > + // Pci devices are dynamically created at runtime as: > + // ASL: > + // Device (PCIx) { > + // ... > + // } > + // and the _OSC method available below is appended to the PCIx device as: > + // ASL: > + // Device (PCIx) { > + // ... > + // Method (_OSC, 4 { > + // ... > + // }) > + // } > + Method (_OSC, 4) { > + // > + // OS Control Handoff > + // > + Name (SUPP, Zero) // PCI _OSC Support Field value > + Name (CTRL, Zero) // PCI _OSC Control Field value > + > + // Create DWord-addressable fields from the Capabilities Buffer > + CreateDWordField (Arg3, 0, CDW1) > + CreateDWordField (Arg3, 4, CDW2) > + CreateDWordField (Arg3, 8, CDW3) > + > + // Check for proper UUID > + If (LEqual (Arg0,ToUUID ("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) { > + > + // Save Capabilities DWord2 & 3 > + Store (CDW2, SUPP) > + Store (CDW3, CTRL) > + > + // Only allow native hot plug control if OS supports: > + // * ASPM > + // * Clock PM > + // * MSI/MSI-X > + If (LNotEqual (And (SUPP, 0x16), 0x16)) { > + And (CTRL, 0x1E, CTRL) // Mask bit 0 (and undefined bits) > + } > + > + // Always allow native PME, AER (no dependencies) > + > + // Never allow SHPC (no SHPC controller in this system) > + And (CTRL, 0x1D, CTRL) > + > + If (LNotEqual (Arg1, One)) { // Unknown revision > + Or (CDW1, 0x08, CDW1) > + } > + > + If (LNotEqual (CDW3, CTRL)) { // Capabilities bits were masked > + Or (CDW1, 0x10, CDW1) > + } > + > + // Update DWORD3 in the buffer > + Store (CTRL,CDW3) > + Return (Arg3) > + } Else { > + Or (CDW1, 4, CDW1) // Unrecognized UUID > + Return (Arg3) > + } // If > + } // _OSC > +} --------------B0C14A3A16AC527C409570D3 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: 8bit

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 from CM_STD_OBJ_CONFIGURATION_MANAGER_INFO and CM_STD_OBJ_ACPI_TABLE_INFO which 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
+}

--------------B0C14A3A16AC527C409570D3--