get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/476458/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 476458,
    "url": "http://patchwork.ozlabs.org/api/patches/476458/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-pci/patch/1432644564-24746-6-git-send-email-hanjun.guo@linaro.org/",
    "project": {
        "id": 28,
        "url": "http://patchwork.ozlabs.org/api/projects/28/?format=api",
        "name": "Linux PCI development",
        "link_name": "linux-pci",
        "list_id": "linux-pci.vger.kernel.org",
        "list_email": "linux-pci@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1432644564-24746-6-git-send-email-hanjun.guo@linaro.org>",
    "list_archive_url": null,
    "date": "2015-05-26T12:49:18",
    "name": "[05/11] x86, pci, acpi: Move arch-agnostic MMCONFIG (aka ECAM) and ACPI code out of arch/x86/ directory",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "dfb0ef497dba58dda05d79be4f7145bbe40db1ed",
    "submitter": {
        "id": 47236,
        "url": "http://patchwork.ozlabs.org/api/people/47236/?format=api",
        "name": "Hanjun Guo",
        "email": "hanjun.guo@linaro.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-pci/patch/1432644564-24746-6-git-send-email-hanjun.guo@linaro.org/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/476458/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/476458/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<linux-pci-owner@vger.kernel.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 95DEB140E0F\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 26 May 2015 23:19:41 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1753278AbbEZMx0 (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tTue, 26 May 2015 08:53:26 -0400",
            "from [209.85.220.52] ([209.85.220.52]:33626 \"EHLO\n\tmail-pa0-f52.google.com\" rhost-flags-FAIL-FAIL-OK-FAIL)\n\tby vger.kernel.org with ESMTP id S1753174AbbEZMxZ (ORCPT\n\t<rfc822; linux-pci@vger.kernel.org>); Tue, 26 May 2015 08:53:25 -0400",
            "by padbw4 with SMTP id bw4so92197290pad.0\n\tfor <linux-pci@vger.kernel.org>; Tue, 26 May 2015 05:50:29 -0700 (PDT)",
            "from localhost ([180.150.153.56]) by mx.google.com with ESMTPSA id\n\tb10sm13041657pdo.84.2015.05.26.05.50.28\n\t(version=TLSv1.2 cipher=RC4-SHA bits=128/128);\n\tTue, 26 May 2015 05:50:28 -0700 (PDT)"
        ],
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20130820;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=YI5iXddIu/esqTOwWgUBK0iEDRLtUU9od7BkxqOh228=;\n\tb=mTSfWS7mhYWRtIidslFiSCebXPS8FQyQ+ovEfyxclE9JyKqJzz/IsnosL1V0GpIVW8\n\tg9SBMxHMG+gruUqFreLruIpvPDXaDuakX+nwB5VPbfuZfWVpD0nTNrUmibmA1pgBhGHi\n\tTz9zXD+HVGqW/JBuBFYFNzxAsvRyAO3/RxoseYBd9RlJepAHTXlrKXVQGbCEN8zLxgGt\n\tdTcsZm/qTIagzIjo8zFPetxb6US31/xm8srMBNJkCMnZ9pyrx93URVnt7arRKk0AokvF\n\tK5MLaVcxmRdyPEEha184I3+HOB1bZ0HQYMMYnbeMj/q8x9mx7oNe3PP5kGpetdBf0SkJ\n\t4noQ==",
        "X-Gm-Message-State": "ALoCoQmI0wmXIBYAxneTi+GoivFVhOfulKLAd9gnRDGcqXg0Vw4ZFxWRUi1Y/C5Zll56LDkhU92a",
        "X-Received": "by 10.68.94.37 with SMTP id cz5mr48368669pbb.70.1432644629689;\n\tTue, 26 May 2015 05:50:29 -0700 (PDT)",
        "From": "Hanjun Guo <hanjun.guo@linaro.org>",
        "To": "Bjorn Helgaas <bhelgaas@google.com>, Arnd Bergmann <arnd@arndb.de>,\n\tCatalin Marinas <catalin.marinas@arm.com>,\n\tWill Deacon <will.deacon@arm.com>,\n\t\"Rafael J. Wysocki\" <rjw@rjwysocki.net>",
        "Cc": "Jiang Liu <jiang.liu@linux.intel.com>, Liviu Dudau <Liviu.Dudau@arm.com>,\n\tThomas Gleixner <tglx@linutronix.de>,\n\tYijing Wang <wangyijing@huawei.com>,\n\tLorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>,\n\tTomasz Nowicki <tomasz.nowicki@linaro.org>,\n\tSuravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>,\n\tMark Salter <msalter@redhat.com>, linux-pci@vger.kernel.org,\n\tlinux-arm-kernel@lists.infradead.org, linux-acpi@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org, linaro-acpi@lists.linaro.org,\n\tHanjun Guo <hanjun.guo@linaro.org>",
        "Subject": "[PATCH 05/11] x86, pci,\n\tacpi: Move arch-agnostic MMCONFIG (aka ECAM) and ACPI code out of\n\tarch/x86/ directory",
        "Date": "Tue, 26 May 2015 20:49:18 +0800",
        "Message-Id": "<1432644564-24746-6-git-send-email-hanjun.guo@linaro.org>",
        "X-Mailer": "git-send-email 1.9.1",
        "In-Reply-To": "<1432644564-24746-1-git-send-email-hanjun.guo@linaro.org>",
        "References": "<1432644564-24746-1-git-send-email-hanjun.guo@linaro.org>",
        "Sender": "linux-pci-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<linux-pci.vger.kernel.org>",
        "X-Mailing-List": "linux-pci@vger.kernel.org"
    },
    "content": "From: Tomasz Nowicki <tomasz.nowicki@linaro.org>\n\nECAM standard and MCFG table are architecture independent and it makes\nsense to share common code across all architectures. Both are going to\ncorresponding files - ecam.c and mcfg.c\n\nWhile we are here, rename pci_parse_mcfg to acpi_parse_mcfg.\nWe already have acpi_parse_mcfg prototype which is used nowhere.\nAt the same time, we need pci_parse_mcfg been global so acpi_parse_mcfg\ncan be used perfectly here.\n\nSigned-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>\nSigned-off-by: Hanjun Guo <hanjun.guo@linaro.org>\nTested-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>\n---\n arch/x86/Kconfig               |   3 +\n arch/x86/include/asm/pci_x86.h |  33 ------\n arch/x86/pci/acpi.c            |   1 +\n arch/x86/pci/mmconfig-shared.c | 244 +---------------------------------------\n arch/x86/pci/mmconfig_32.c     |   1 +\n arch/x86/pci/mmconfig_64.c     |   1 +\n arch/x86/pci/numachip.c        |   1 +\n drivers/acpi/Makefile          |   1 +\n drivers/acpi/mcfg.c            |  57 ++++++++++\n drivers/pci/Kconfig            |   7 ++\n drivers/pci/Makefile           |   5 +\n drivers/pci/ecam.c             | 245 +++++++++++++++++++++++++++++++++++++++++\n drivers/xen/pci.c              |   1 +\n include/linux/acpi.h           |   2 +\n include/linux/ecam.h           |  51 +++++++++\n 15 files changed, 381 insertions(+), 272 deletions(-)\n create mode 100644 drivers/acpi/mcfg.c\n create mode 100644 drivers/pci/ecam.c\n create mode 100644 include/linux/ecam.h",
    "diff": "diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig\nindex 226d569..4e3dcb3 100644\n--- a/arch/x86/Kconfig\n+++ b/arch/x86/Kconfig\n@@ -143,6 +143,7 @@ config X86\n \tselect ACPI_LEGACY_TABLES_LOOKUP if ACPI\n \tselect X86_FEATURE_NAMES if PROC_FS\n \tselect SRCU\n+\tselect HAVE_PCI_ECAM\n \n config INSTRUCTION_DECODER\n \tdef_bool y\n@@ -2276,6 +2277,7 @@ config PCI_DIRECT\n \n config PCI_MMCONFIG\n \tdef_bool y\n+\tselect PCI_ECAM\n \tdepends on X86_32 && PCI && (ACPI || SFI) && (PCI_GOMMCONFIG || PCI_GOANY)\n \n config PCI_OLPC\n@@ -2293,6 +2295,7 @@ config PCI_DOMAINS\n \n config PCI_MMCONFIG\n \tbool \"Support mmconfig PCI config space access\"\n+\tselect PCI_ECAM\n \tdepends on X86_64 && PCI && ACPI\n \n config PCI_CNB20LE_QUIRK\ndiff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h\nindex f7f3b6a..2ea44a7 100644\n--- a/arch/x86/include/asm/pci_x86.h\n+++ b/arch/x86/include/asm/pci_x86.h\n@@ -124,41 +124,8 @@ extern int pci_legacy_init(void);\n extern void pcibios_fixup_irqs(void);\n \n /* pci-mmconfig.c */\n-\n-/* \"PCI MMCONFIG %04x [bus %02x-%02x]\" */\n-#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)\n-\n-struct pci_mmcfg_region {\n-\tstruct list_head list;\n-\tstruct resource res;\n-\tu64 address;\n-\tchar __iomem *virt;\n-\tu16 segment;\n-\tu8 start_bus;\n-\tu8 end_bus;\n-\tchar name[PCI_MMCFG_RESOURCE_NAME_LEN];\n-};\n-\n-struct pci_mmcfg_mmio_ops {\n-\tu32 (*read)(int len, void __iomem *addr);\n-\tvoid (*write)(int len, void __iomem *addr, u32 value);\n-};\n-\n-extern int __init pci_mmcfg_arch_init(void);\n-extern void __init pci_mmcfg_arch_free(void);\n-extern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);\n-extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);\n extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,\n \t\t\t       phys_addr_t addr);\n-extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);\n-extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);\n-extern u32 pci_mmio_read(int len, void __iomem *addr);\n-extern void pci_mmio_write(int len, void __iomem *addr, u32 value);\n-extern void pci_mmconfig_register_mmio(struct pci_mmcfg_mmio_ops *ops);\n-\n-extern struct list_head pci_mmcfg_list;\n-\n-#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)\n \n /*\n  * AMD Fam10h CPUs are buggy, and cannot access MMIO config space\ndiff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c\nindex 89bd79b..217508e 100644\n--- a/arch/x86/pci/acpi.c\n+++ b/arch/x86/pci/acpi.c\n@@ -5,6 +5,7 @@\n #include <linux/dmi.h>\n #include <linux/slab.h>\n #include <linux/pci-acpi.h>\n+#include <linux/ecam.h>\n #include <asm/numa.h>\n #include <asm/pci_x86.h>\n \ndiff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c\nindex e770b70..6fa3080 100644\n--- a/arch/x86/pci/mmconfig-shared.c\n+++ b/arch/x86/pci/mmconfig-shared.c\n@@ -18,6 +18,7 @@\n #include <linux/slab.h>\n #include <linux/mutex.h>\n #include <linux/rculist.h>\n+#include <linux/ecam.h>\n #include <asm/e820.h>\n #include <asm/pci_x86.h>\n #include <asm/acpi.h>\n@@ -27,52 +28,6 @@\n /* Indicate if the mmcfg resources have been placed into the resource table. */\n static bool pci_mmcfg_running_state;\n static bool pci_mmcfg_arch_init_failed;\n-static DEFINE_MUTEX(pci_mmcfg_lock);\n-\n-LIST_HEAD(pci_mmcfg_list);\n-\n-static u32\n-pci_mmconfig_generic_read(int len, void __iomem *addr)\n-{\n-\tu32 data = 0;\n-\n-\tswitch (len) {\n-\tcase 1:\n-\t\tdata = readb(addr);\n-\t\tbreak;\n-\tcase 2:\n-\t\tdata = readw(addr);\n-\t\tbreak;\n-\tcase 4:\n-\t\tdata = readl(addr);\n-\t\tbreak;\n-\t}\n-\n-\treturn data;\n-}\n-\n-static void\n-pci_mmconfig_generic_write(int len, void __iomem *addr, u32 value)\n-{\n-\tswitch (len) {\n-\tcase 1:\n-\t\twriteb(value, addr);\n-\t\tbreak;\n-\tcase 2:\n-\t\twritew(value, addr);\n-\t\tbreak;\n-\tcase 4:\n-\t\twritel(value, addr);\n-\t\tbreak;\n-\t}\n-}\n-\n-static struct pci_mmcfg_mmio_ops pci_mmcfg_mmio_default = {\n-\t.read = pci_mmconfig_generic_read,\n-\t.write = pci_mmconfig_generic_write,\n-};\n-\n-static struct pci_mmcfg_mmio_ops *pci_mmcfg_mmio = &pci_mmcfg_mmio_default;\n \n static u32\n pci_mmconfig_amd_read(int len, void __iomem *addr)\n@@ -115,128 +70,6 @@ static struct pci_mmcfg_mmio_ops pci_mmcfg_mmio_amd_fam10h = {\n \t.write = pci_mmconfig_amd_write,\n };\n \n-void\n-pci_mmconfig_register_mmio(struct pci_mmcfg_mmio_ops *ops)\n-{\n-\tpci_mmcfg_mmio = ops;\n-}\n-\n-u32\n-pci_mmio_read(int len, void __iomem *addr)\n-{\n-\tif (!pci_mmcfg_mmio) {\n-\t\tpr_err(\"PCI config space has no accessors !\");\n-\t\treturn 0;\n-\t}\n-\n-\treturn pci_mmcfg_mmio->read(len, addr);\n-}\n-\n-void\n-pci_mmio_write(int len, void __iomem *addr, u32 value)\n-{\n-\tif (!pci_mmcfg_mmio) {\n-\t\tpr_err(\"PCI config space has no accessors !\");\n-\t\treturn;\n-\t}\n-\n-\tpci_mmcfg_mmio->write(len, addr, value);\n-}\n-\n-static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)\n-{\n-\tif (cfg->res.parent)\n-\t\trelease_resource(&cfg->res);\n-\tlist_del(&cfg->list);\n-\tkfree(cfg);\n-}\n-\n-static void __init free_all_mmcfg(void)\n-{\n-\tstruct pci_mmcfg_region *cfg, *tmp;\n-\n-\tpci_mmcfg_arch_free();\n-\tlist_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list)\n-\t\tpci_mmconfig_remove(cfg);\n-}\n-\n-static void list_add_sorted(struct pci_mmcfg_region *new)\n-{\n-\tstruct pci_mmcfg_region *cfg;\n-\n-\t/* keep list sorted by segment and starting bus number */\n-\tlist_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {\n-\t\tif (cfg->segment > new->segment ||\n-\t\t    (cfg->segment == new->segment &&\n-\t\t     cfg->start_bus >= new->start_bus)) {\n-\t\t\tlist_add_tail_rcu(&new->list, &cfg->list);\n-\t\t\treturn;\n-\t\t}\n-\t}\n-\tlist_add_tail_rcu(&new->list, &pci_mmcfg_list);\n-}\n-\n-static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,\n-\t\t\t\t\t\t   int end, u64 addr)\n-{\n-\tstruct pci_mmcfg_region *new;\n-\tstruct resource *res;\n-\n-\tif (addr == 0)\n-\t\treturn NULL;\n-\n-\tnew = kzalloc(sizeof(*new), GFP_KERNEL);\n-\tif (!new)\n-\t\treturn NULL;\n-\n-\tnew->address = addr;\n-\tnew->segment = segment;\n-\tnew->start_bus = start;\n-\tnew->end_bus = end;\n-\n-\tres = &new->res;\n-\tres->start = addr + PCI_MMCFG_BUS_OFFSET(start);\n-\tres->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;\n-\tres->flags = IORESOURCE_MEM | IORESOURCE_BUSY;\n-\tsnprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,\n-\t\t \"PCI MMCONFIG %04x [bus %02x-%02x]\", segment, start, end);\n-\tres->name = new->name;\n-\n-\treturn new;\n-}\n-\n-static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,\n-\t\t\t\t\t\t\tint end, u64 addr)\n-{\n-\tstruct pci_mmcfg_region *new;\n-\n-\tnew = pci_mmconfig_alloc(segment, start, end, addr);\n-\tif (new) {\n-\t\tmutex_lock(&pci_mmcfg_lock);\n-\t\tlist_add_sorted(new);\n-\t\tmutex_unlock(&pci_mmcfg_lock);\n-\n-\t\tpr_info(PREFIX\n-\t\t       \"MMCONFIG for domain %04x [bus %02x-%02x] at %pR \"\n-\t\t       \"(base %#lx)\\n\",\n-\t\t       segment, start, end, &new->res, (unsigned long)addr);\n-\t}\n-\n-\treturn new;\n-}\n-\n-struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)\n-{\n-\tstruct pci_mmcfg_region *cfg;\n-\n-\tlist_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)\n-\t\tif (cfg->segment == segment &&\n-\t\t    cfg->start_bus <= bus && bus <= cfg->end_bus)\n-\t\t\treturn cfg;\n-\n-\treturn NULL;\n-}\n-\n static const char *__init pci_mmcfg_e7520(void)\n {\n \tu32 win;\n@@ -657,8 +490,8 @@ static void __init pci_mmcfg_reject_broken(int early)\n \t}\n }\n \n-static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,\n-\t\t\t\t\tstruct acpi_mcfg_allocation *cfg)\n+int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,\n+\t\t\t\t struct acpi_mcfg_allocation *cfg)\n {\n \tint year;\n \n@@ -680,50 +513,6 @@ static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,\n \treturn -EINVAL;\n }\n \n-static int __init pci_parse_mcfg(struct acpi_table_header *header)\n-{\n-\tstruct acpi_table_mcfg *mcfg;\n-\tstruct acpi_mcfg_allocation *cfg_table, *cfg;\n-\tunsigned long i;\n-\tint entries;\n-\n-\tif (!header)\n-\t\treturn -EINVAL;\n-\n-\tmcfg = (struct acpi_table_mcfg *)header;\n-\n-\t/* how many config structures do we have */\n-\tfree_all_mmcfg();\n-\tentries = 0;\n-\ti = header->length - sizeof(struct acpi_table_mcfg);\n-\twhile (i >= sizeof(struct acpi_mcfg_allocation)) {\n-\t\tentries++;\n-\t\ti -= sizeof(struct acpi_mcfg_allocation);\n-\t}\n-\tif (entries == 0) {\n-\t\tpr_err(PREFIX \"MMCONFIG has no entries\\n\");\n-\t\treturn -ENODEV;\n-\t}\n-\n-\tcfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];\n-\tfor (i = 0; i < entries; i++) {\n-\t\tcfg = &cfg_table[i];\n-\t\tif (acpi_mcfg_check_entry(mcfg, cfg)) {\n-\t\t\tfree_all_mmcfg();\n-\t\t\treturn -ENODEV;\n-\t\t}\n-\n-\t\tif (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,\n-\t\t\t\t   cfg->end_bus_number, cfg->address) == NULL) {\n-\t\t\tpr_warn(PREFIX \"no memory for MCFG entries\\n\");\n-\t\t\tfree_all_mmcfg();\n-\t\t\treturn -ENOMEM;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n #ifdef CONFIG_ACPI_APEI\n extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,\n \t\t\t\t     void *data), void *data);\n@@ -782,7 +571,7 @@ void __init pci_mmcfg_early_init(void)\n \t\tif (pci_mmcfg_check_hostbridge())\n \t\t\tknown_bridge = 1;\n \t\telse\n-\t\t\tacpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);\n+\t\t\tacpi_sfi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);\n \t\t__pci_mmcfg_init(1);\n \n \t\tset_apei_filter();\n@@ -800,7 +589,7 @@ void __init pci_mmcfg_late_init(void)\n \n \t/* MMCONFIG hasn't been enabled yet, try again */\n \tif (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {\n-\t\tacpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);\n+\t\tacpi_sfi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);\n \t\t__pci_mmcfg_init(0);\n \t}\n }\n@@ -916,26 +705,3 @@ error:\n \tkfree(cfg);\n \treturn rc;\n }\n-\n-/* Delete MMCFG information for host bridges */\n-int pci_mmconfig_delete(u16 seg, u8 start, u8 end)\n-{\n-\tstruct pci_mmcfg_region *cfg;\n-\n-\tmutex_lock(&pci_mmcfg_lock);\n-\tlist_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)\n-\t\tif (cfg->segment == seg && cfg->start_bus == start &&\n-\t\t    cfg->end_bus == end) {\n-\t\t\tlist_del_rcu(&cfg->list);\n-\t\t\tsynchronize_rcu();\n-\t\t\tpci_mmcfg_arch_unmap(cfg);\n-\t\t\tif (cfg->res.parent)\n-\t\t\t\trelease_resource(&cfg->res);\n-\t\t\tmutex_unlock(&pci_mmcfg_lock);\n-\t\t\tkfree(cfg);\n-\t\t\treturn 0;\n-\t\t}\n-\tmutex_unlock(&pci_mmcfg_lock);\n-\n-\treturn -ENOENT;\n-}\ndiff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c\nindex 4b3d025..5cf6291 100644\n--- a/arch/x86/pci/mmconfig_32.c\n+++ b/arch/x86/pci/mmconfig_32.c\n@@ -12,6 +12,7 @@\n #include <linux/pci.h>\n #include <linux/init.h>\n #include <linux/rcupdate.h>\n+#include <linux/ecam.h>\n #include <asm/e820.h>\n #include <asm/pci_x86.h>\n \ndiff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c\nindex 032593d..b62ff18 100644\n--- a/arch/x86/pci/mmconfig_64.c\n+++ b/arch/x86/pci/mmconfig_64.c\n@@ -10,6 +10,7 @@\n #include <linux/acpi.h>\n #include <linux/bitmap.h>\n #include <linux/rcupdate.h>\n+#include <linux/ecam.h>\n #include <asm/e820.h>\n #include <asm/pci_x86.h>\n \ndiff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c\nindex 5047e9b..01868b6 100644\n--- a/arch/x86/pci/numachip.c\n+++ b/arch/x86/pci/numachip.c\n@@ -13,6 +13,7 @@\n  *\n  */\n \n+#include <linux/ecam.h>\n #include <linux/pci.h>\n #include <asm/pci_x86.h>\n \ndiff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile\nindex 3e4aec3..576fbb1 100644\n--- a/drivers/acpi/Makefile\n+++ b/drivers/acpi/Makefile\n@@ -68,6 +68,7 @@ obj-$(CONFIG_ACPI_BUTTON)\t+= button.o\n obj-$(CONFIG_ACPI_FAN)\t\t+= fan.o\n obj-$(CONFIG_ACPI_VIDEO)\t+= video.o\n obj-$(CONFIG_ACPI_PCI_SLOT)\t+= pci_slot.o\n+obj-$(CONFIG_PCI_MMCONFIG)\t+= mcfg.o\n obj-$(CONFIG_ACPI_PROCESSOR)\t+= processor.o\n obj-y\t\t\t\t+= container.o\n obj-$(CONFIG_ACPI_THERMAL)\t+= thermal.o\ndiff --git a/drivers/acpi/mcfg.c b/drivers/acpi/mcfg.c\nnew file mode 100644\nindex 0000000..63775af\n--- /dev/null\n+++ b/drivers/acpi/mcfg.c\n@@ -0,0 +1,57 @@\n+/*\n+ * MCFG ACPI table parser.\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ *\n+ */\n+\n+#include <linux/acpi.h>\n+#include <linux/ecam.h>\n+\n+#define\tPREFIX\t\"MCFG: \"\n+\n+int __init acpi_parse_mcfg(struct acpi_table_header *header)\n+{\n+\tstruct acpi_table_mcfg *mcfg;\n+\tstruct acpi_mcfg_allocation *cfg_table, *cfg;\n+\tunsigned long i;\n+\tint entries;\n+\n+\tif (!header)\n+\t\treturn -EINVAL;\n+\n+\tmcfg = (struct acpi_table_mcfg *)header;\n+\n+\t/* how many config structures do we have */\n+\tfree_all_mmcfg();\n+\tentries = 0;\n+\ti = header->length - sizeof(struct acpi_table_mcfg);\n+\twhile (i >= sizeof(struct acpi_mcfg_allocation)) {\n+\t\tentries++;\n+\t\ti -= sizeof(struct acpi_mcfg_allocation);\n+\t}\n+\tif (entries == 0) {\n+\t\tpr_err(PREFIX \"MCFG table has no entries\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tcfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];\n+\tfor (i = 0; i < entries; i++) {\n+\t\tcfg = &cfg_table[i];\n+\t\tif (acpi_mcfg_check_entry(mcfg, cfg)) {\n+\t\t\tfree_all_mmcfg();\n+\t\t\treturn -ENODEV;\n+\t\t}\n+\n+\t\tif (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,\n+\t\t\t\t cfg->end_bus_number, cfg->address) == NULL) {\n+\t\t\tpr_warn(PREFIX \"no memory for MCFG entries\\n\");\n+\t\t\tfree_all_mmcfg();\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig\nindex 7a8f1c5..90a5fb9 100644\n--- a/drivers/pci/Kconfig\n+++ b/drivers/pci/Kconfig\n@@ -22,6 +22,13 @@ config PCI_MSI_IRQ_DOMAIN\n \tdepends on PCI_MSI\n \tselect GENERIC_MSI_IRQ_DOMAIN\n \n+config PCI_ECAM\n+\tbool \"Enhanced Configuration Access Mechanism (ECAM)\"\n+\tdepends on PCI && HAVE_PCI_ECAM\n+\n+config HAVE_PCI_ECAM\n+\tbool\n+\n config PCI_DEBUG\n \tbool \"PCI Debugging\"\n \tdepends on PCI && DEBUG_KERNEL\ndiff --git a/drivers/pci/Makefile b/drivers/pci/Makefile\nindex 73e4af4..ce7b630 100644\n--- a/drivers/pci/Makefile\n+++ b/drivers/pci/Makefile\n@@ -41,6 +41,11 @@ obj-$(CONFIG_SPARC_LEON) += setup-irq.o\n obj-$(CONFIG_M68K) += setup-irq.o\n \n #\n+# Enhanced Configuration Access Mechanism (ECAM)\n+#\n+obj-$(CONFIG_PCI_ECAM)\t+= ecam.o\n+\n+#\n # ACPI Related PCI FW Functions\n # ACPI _DSM provided firmware instance and string name\n #\ndiff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c\nnew file mode 100644\nindex 0000000..c588234\n--- /dev/null\n+++ b/drivers/pci/ecam.c\n@@ -0,0 +1,245 @@\n+/*\n+ * Arch agnostic direct PCI config space access via\n+ * ECAM (Enhanced Configuration Access Mechanism)\n+ *\n+ * Per-architecture code takes care of the mappings, region validation and\n+ * accesses themselves.\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ *\n+ */\n+\n+#include <linux/mutex.h>\n+#include <linux/rculist.h>\n+#include <linux/ecam.h>\n+\n+#include <asm/io.h>\n+\n+#define PREFIX \"PCI: \"\n+\n+static DEFINE_MUTEX(pci_mmcfg_lock);\n+\n+LIST_HEAD(pci_mmcfg_list);\n+\n+static u32\n+pci_mmconfig_generic_read(int len, void __iomem *addr)\n+{\n+\tu32 data = 0;\n+\n+\tswitch (len) {\n+\tcase 1:\n+\t\tdata = readb(addr);\n+\t\tbreak;\n+\tcase 2:\n+\t\tdata = readw(addr);\n+\t\tbreak;\n+\tcase 4:\n+\t\tdata = readl(addr);\n+\t\tbreak;\n+\t}\n+\n+\treturn data;\n+}\n+\n+static void\n+pci_mmconfig_generic_write(int len, void __iomem *addr, u32 value)\n+{\n+\tswitch (len) {\n+\tcase 1:\n+\t\twriteb(value, addr);\n+\t\tbreak;\n+\tcase 2:\n+\t\twritew(value, addr);\n+\t\tbreak;\n+\tcase 4:\n+\t\twritel(value, addr);\n+\t\tbreak;\n+\t}\n+}\n+\n+static struct pci_mmcfg_mmio_ops pci_mmcfg_mmio_default = {\n+\t.read = pci_mmconfig_generic_read,\n+\t.write = pci_mmconfig_generic_write,\n+};\n+\n+static struct pci_mmcfg_mmio_ops *pci_mmcfg_mmio = &pci_mmcfg_mmio_default;\n+\n+void\n+pci_mmconfig_register_mmio(struct pci_mmcfg_mmio_ops *ops)\n+{\n+\tpci_mmcfg_mmio = ops;\n+}\n+\n+u32\n+pci_mmio_read(int len, void __iomem *addr)\n+{\n+\tif (!pci_mmcfg_mmio) {\n+\t\tpr_err(\"PCI config space has no accessors !\");\n+\t\treturn 0;\n+\t}\n+\n+\treturn pci_mmcfg_mmio->read(len, addr);\n+}\n+\n+void\n+pci_mmio_write(int len, void __iomem *addr, u32 value)\n+{\n+\tif (!pci_mmcfg_mmio) {\n+\t\tpr_err(\"PCI config space has no accessors !\");\n+\t\treturn;\n+\t}\n+\n+\tpci_mmcfg_mmio->write(len, addr, value);\n+}\n+\n+static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)\n+{\n+\tif (cfg->res.parent)\n+\t\trelease_resource(&cfg->res);\n+\tlist_del(&cfg->list);\n+\tkfree(cfg);\n+}\n+\n+void __init free_all_mmcfg(void)\n+{\n+\tstruct pci_mmcfg_region *cfg, *tmp;\n+\n+\tpci_mmcfg_arch_free();\n+\tlist_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list)\n+\t\tpci_mmconfig_remove(cfg);\n+}\n+\n+void list_add_sorted(struct pci_mmcfg_region *new)\n+{\n+\tstruct pci_mmcfg_region *cfg;\n+\n+\t/* keep list sorted by segment and starting bus number */\n+\tlist_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {\n+\t\tif (cfg->segment > new->segment ||\n+\t\t    (cfg->segment == new->segment &&\n+\t\t     cfg->start_bus >= new->start_bus)) {\n+\t\t\tlist_add_tail_rcu(&new->list, &cfg->list);\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\tlist_add_tail_rcu(&new->list, &pci_mmcfg_list);\n+}\n+\n+struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,\n+\t\t\t\t\t    int end, u64 addr)\n+{\n+\tstruct pci_mmcfg_region *new;\n+\tstruct resource *res;\n+\n+\tif (addr == 0)\n+\t\treturn NULL;\n+\n+\tnew = kzalloc(sizeof(*new), GFP_KERNEL);\n+\tif (!new)\n+\t\treturn NULL;\n+\n+\tnew->address = addr;\n+\tnew->segment = segment;\n+\tnew->start_bus = start;\n+\tnew->end_bus = end;\n+\n+\tres = &new->res;\n+\tres->start = addr + PCI_MMCFG_BUS_OFFSET(start);\n+\tres->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;\n+\tres->flags = IORESOURCE_MEM | IORESOURCE_BUSY;\n+\tsnprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,\n+\t\t \"PCI MMCONFIG %04x [bus %02x-%02x]\", segment, start, end);\n+\tres->name = new->name;\n+\n+\treturn new;\n+}\n+\n+struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,\n+\t\t\t\t\t  int end, u64 addr)\n+{\n+\tstruct pci_mmcfg_region *new;\n+\n+\tnew = pci_mmconfig_alloc(segment, start, end, addr);\n+\tif (new) {\n+\t\tmutex_lock(&pci_mmcfg_lock);\n+\t\tlist_add_sorted(new);\n+\t\tmutex_unlock(&pci_mmcfg_lock);\n+\n+\t\tpr_info(PREFIX\n+\t\t       \"MMCONFIG for domain %04x [bus %02x-%02x] at %pR \"\n+\t\t       \"(base %#lx)\\n\",\n+\t\t       segment, start, end, &new->res, (unsigned long)addr);\n+\t}\n+\n+\treturn new;\n+}\n+\n+struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)\n+{\n+\tstruct pci_mmcfg_region *cfg;\n+\n+\tlist_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)\n+\t\tif (cfg->segment == segment &&\n+\t\t    cfg->start_bus <= bus && bus <= cfg->end_bus)\n+\t\t\treturn cfg;\n+\n+\treturn NULL;\n+}\n+\n+/* Delete MMCFG information for host bridges */\n+int pci_mmconfig_delete(u16 seg, u8 start, u8 end)\n+{\n+\tstruct pci_mmcfg_region *cfg;\n+\n+\tmutex_lock(&pci_mmcfg_lock);\n+\tlist_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)\n+\t\tif (cfg->segment == seg && cfg->start_bus == start &&\n+\t\t    cfg->end_bus == end) {\n+\t\t\tlist_del_rcu(&cfg->list);\n+\t\t\tsynchronize_rcu();\n+\t\t\tpci_mmcfg_arch_unmap(cfg);\n+\t\t\tif (cfg->res.parent)\n+\t\t\t\trelease_resource(&cfg->res);\n+\t\t\tmutex_unlock(&pci_mmcfg_lock);\n+\t\t\tkfree(cfg);\n+\t\t\treturn 0;\n+\t\t}\n+\tmutex_unlock(&pci_mmcfg_lock);\n+\n+\treturn -ENOENT;\n+}\n+\n+int pci_mmconfig_inject(struct pci_mmcfg_region *cfg)\n+{\n+\tstruct pci_mmcfg_region *cfg_conflict;\n+\tint err = 0;\n+\n+\tmutex_lock(&pci_mmcfg_lock);\n+\tcfg_conflict = pci_mmconfig_lookup(cfg->segment, cfg->start_bus);\n+\tif (cfg_conflict) {\n+\t\tif (cfg_conflict->end_bus < cfg->end_bus)\n+\t\t\tpr_info(FW_INFO \"MMCONFIG for \"\n+\t\t\t\t\"domain %04x [bus %02x-%02x] \"\n+\t\t\t\t\"only partially covers this bridge\\n\",\n+\t\t\t\tcfg_conflict->segment, cfg_conflict->start_bus,\n+\t\t\t\tcfg_conflict->end_bus);\n+\t\terr = -EEXIST;\n+\t\tgoto out;\n+\t}\n+\n+\tif (pci_mmcfg_arch_map(cfg)) {\n+\t\tpr_warn(\"fail to map MMCONFIG %pR.\\n\", &cfg->res);\n+\t\terr = -ENOMEM;\n+\t\tgoto out;\n+\t} else {\n+\t\tlist_add_sorted(cfg);\n+\t\tpr_info(\"MMCONFIG at %pR (base %#lx)\\n\",\n+\t\t\t&cfg->res, (unsigned long)cfg->address);\n+\n+\t}\n+out:\n+\tmutex_unlock(&pci_mmcfg_lock);\n+\treturn err;\n+}\ndiff --git a/drivers/xen/pci.c b/drivers/xen/pci.c\nindex 7494dbe..6785ebb 100644\n--- a/drivers/xen/pci.c\n+++ b/drivers/xen/pci.c\n@@ -20,6 +20,7 @@\n #include <linux/pci.h>\n #include <linux/acpi.h>\n #include <linux/pci-acpi.h>\n+#include <linux/ecam.h>\n #include <xen/xen.h>\n #include <xen/interface/physdev.h>\n #include <xen/interface/xen.h>\ndiff --git a/include/linux/acpi.h b/include/linux/acpi.h\nindex b904af3..5063429 100644\n--- a/include/linux/acpi.h\n+++ b/include/linux/acpi.h\n@@ -144,6 +144,8 @@ int acpi_table_parse_madt(enum acpi_madt_type id,\n \t\t\t  acpi_tbl_entry_handler handler,\n \t\t\t  unsigned int max_entries);\n int acpi_parse_mcfg (struct acpi_table_header *header);\n+int acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,\n+\t\t\t  struct acpi_mcfg_allocation *cfg);\n void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);\n \n /* the following four functions are architecture-dependent */\ndiff --git a/include/linux/ecam.h b/include/linux/ecam.h\nnew file mode 100644\nindex 0000000..2387df5\n--- /dev/null\n+++ b/include/linux/ecam.h\n@@ -0,0 +1,51 @@\n+#ifndef __ECAM_H\n+#define __ECAM_H\n+#ifdef __KERNEL__\n+\n+#include <linux/types.h>\n+#include <linux/acpi.h>\n+\n+/* \"PCI MMCONFIG %04x [bus %02x-%02x]\" */\n+#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)\n+\n+struct pci_mmcfg_region {\n+\tstruct list_head list;\n+\tstruct resource res;\n+\tu64 address;\n+\tchar __iomem *virt;\n+\tu16 segment;\n+\tu8 start_bus;\n+\tu8 end_bus;\n+\tchar name[PCI_MMCFG_RESOURCE_NAME_LEN];\n+};\n+\n+struct pci_mmcfg_mmio_ops {\n+\tu32 (*read)(int len, void __iomem *addr);\n+\tvoid (*write)(int len, void __iomem *addr, u32 value);\n+};\n+\n+struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);\n+struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,\n+\t\t\t\t\t\t   int end, u64 addr);\n+int pci_mmconfig_inject(struct pci_mmcfg_region *cfg);\n+struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,\n+\t\t\t\t\t\t int end, u64 addr);\n+void list_add_sorted(struct pci_mmcfg_region *new);\n+void free_all_mmcfg(void);\n+int pci_mmconfig_delete(u16 seg, u8 start, u8 end);\n+\n+/* Arch specific calls */\n+int pci_mmcfg_arch_init(void);\n+void pci_mmcfg_arch_free(void);\n+int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);\n+void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);\n+extern u32 pci_mmio_read(int len, void __iomem *addr);\n+extern void pci_mmio_write(int len, void __iomem *addr, u32 value);\n+extern void pci_mmconfig_register_mmio(struct pci_mmcfg_mmio_ops *ops);\n+\n+extern struct list_head pci_mmcfg_list;\n+\n+#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)\n+\n+#endif  /* __KERNEL__ */\n+#endif  /* __ECAM_H */\n",
    "prefixes": [
        "05/11"
    ]
}