summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Robinson <pbrobinson@gmail.com>2016-07-19 09:00:32 +0100
committerPeter Robinson <pbrobinson@gmail.com>2016-07-19 09:00:32 +0100
commita84c0224bb233a4942301a5075f00dcca596f334 (patch)
tree87ec40ecb74c03f4fce6a5ba209fec0d14438f74
parent7a27e68a3112162e825513c4a9e09e45de8fe1bc (diff)
downloadkernel-a84c0224bb233a4942301a5075f00dcca596f334.tar.gz
kernel-a84c0224bb233a4942301a5075f00dcca596f334.tar.xz
kernel-a84c0224bb233a4942301a5075f00dcca596f334.zip
Add aarch64 ACPI pci-e patches headed for 4.8
-rw-r--r--arm64-pcie-acpi.patch1247
-rw-r--r--arm64-pcie-quirks-xgene.patch508
-rw-r--r--kernel.spec6
3 files changed, 1761 insertions, 0 deletions
diff --git a/arm64-pcie-acpi.patch b/arm64-pcie-acpi.patch
new file mode 100644
index 000000000..e9a359db6
--- /dev/null
+++ b/arm64-pcie-acpi.patch
@@ -0,0 +1,1247 @@
+From 1fc02559de87cd88339a83ad05baa9c2b5bd1ac0 Mon Sep 17 00:00:00 2001
+From: Jayachandran C <jchandra@broadcom.com>
+Date: Fri, 10 Jun 2016 21:55:09 +0200
+Subject: [PATCH 01/11] PCI/ECAM: Move ecam.h to linux/include/pci-ecam.h
+
+This header will be used from arch/arm64 for ACPI PCI implementation
+so it needs to be moved out of drivers/pci.
+
+Update users of the header file to use the new name. No functional
+changes.
+
+Signed-off-by: Jayachandran C <jchandra@broadcom.com>
+Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/pci/ecam.c | 3 +-
+ drivers/pci/ecam.h | 67 -------------------------------------
+ drivers/pci/host/pci-host-common.c | 3 +-
+ drivers/pci/host/pci-host-generic.c | 3 +-
+ drivers/pci/host/pci-thunder-ecam.c | 3 +-
+ drivers/pci/host/pci-thunder-pem.c | 3 +-
+ include/linux/pci-ecam.h | 67 +++++++++++++++++++++++++++++++++++++
+ 7 files changed, 72 insertions(+), 77 deletions(-)
+ delete mode 100644 drivers/pci/ecam.h
+ create mode 100644 include/linux/pci-ecam.h
+
+diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c
+index f9832ad..820e26b 100644
+--- a/drivers/pci/ecam.c
++++ b/drivers/pci/ecam.c
+@@ -19,10 +19,9 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
++#include <linux/pci-ecam.h>
+ #include <linux/slab.h>
+
+-#include "ecam.h"
+-
+ /*
+ * On 64-bit systems, we do a single ioremap for the whole config space
+ * since we have enough virtual address range available. On 32-bit, we
+diff --git a/drivers/pci/ecam.h b/drivers/pci/ecam.h
+deleted file mode 100644
+index 9878beb..0000000
+--- a/drivers/pci/ecam.h
++++ /dev/null
+@@ -1,67 +0,0 @@
+-/*
+- * Copyright 2016 Broadcom
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License, version 2, as
+- * published by the Free Software Foundation (the "GPL").
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License version 2 (GPLv2) for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * version 2 (GPLv2) along with this source code.
+- */
+-#ifndef DRIVERS_PCI_ECAM_H
+-#define DRIVERS_PCI_ECAM_H
+-
+-#include <linux/kernel.h>
+-#include <linux/platform_device.h>
+-
+-/*
+- * struct to hold pci ops and bus shift of the config window
+- * for a PCI controller.
+- */
+-struct pci_config_window;
+-struct pci_ecam_ops {
+- unsigned int bus_shift;
+- struct pci_ops pci_ops;
+- int (*init)(struct device *,
+- struct pci_config_window *);
+-};
+-
+-/*
+- * struct to hold the mappings of a config space window. This
+- * is expected to be used as sysdata for PCI controllers that
+- * use ECAM.
+- */
+-struct pci_config_window {
+- struct resource res;
+- struct resource busr;
+- void *priv;
+- struct pci_ecam_ops *ops;
+- union {
+- void __iomem *win; /* 64-bit single mapping */
+- void __iomem **winp; /* 32-bit per-bus mapping */
+- };
+-};
+-
+-/* create and free pci_config_window */
+-struct pci_config_window *pci_ecam_create(struct device *dev,
+- struct resource *cfgres, struct resource *busr,
+- struct pci_ecam_ops *ops);
+-void pci_ecam_free(struct pci_config_window *cfg);
+-
+-/* map_bus when ->sysdata is an instance of pci_config_window */
+-void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
+- int where);
+-/* default ECAM ops */
+-extern struct pci_ecam_ops pci_generic_ecam_ops;
+-
+-#ifdef CONFIG_PCI_HOST_GENERIC
+-/* for DT-based PCI controllers that support ECAM */
+-int pci_host_common_probe(struct platform_device *pdev,
+- struct pci_ecam_ops *ops);
+-#endif
+-#endif
+diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
+index 8cba7ab..c18b9e3 100644
+--- a/drivers/pci/host/pci-host-common.c
++++ b/drivers/pci/host/pci-host-common.c
+@@ -20,10 +20,9 @@
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/of_pci.h>
++#include <linux/pci-ecam.h>
+ #include <linux/platform_device.h>
+
+-#include "../ecam.h"
+-
+ static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
+ struct list_head *resources, struct resource **bus_range)
+ {
+diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
+index 6eaceab..f0ca6de 100644
+--- a/drivers/pci/host/pci-host-generic.c
++++ b/drivers/pci/host/pci-host-generic.c
+@@ -23,10 +23,9 @@
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/of_pci.h>
++#include <linux/pci-ecam.h>
+ #include <linux/platform_device.h>
+
+-#include "../ecam.h"
+-
+ static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
+ .bus_shift = 16,
+ .pci_ops = {
+diff --git a/drivers/pci/host/pci-thunder-ecam.c b/drivers/pci/host/pci-thunder-ecam.c
+index 540d030..a9fc1c9 100644
+--- a/drivers/pci/host/pci-thunder-ecam.c
++++ b/drivers/pci/host/pci-thunder-ecam.c
+@@ -11,10 +11,9 @@
+ #include <linux/ioport.h>
+ #include <linux/of_pci.h>
+ #include <linux/of.h>
++#include <linux/pci-ecam.h>
+ #include <linux/platform_device.h>
+
+-#include "../ecam.h"
+-
+ static void set_val(u32 v, int where, int size, u32 *val)
+ {
+ int shift = (where & 3) * 8;
+diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
+index 9b8ab94..5020d3d 100644
+--- a/drivers/pci/host/pci-thunder-pem.c
++++ b/drivers/pci/host/pci-thunder-pem.c
+@@ -18,10 +18,9 @@
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/of_pci.h>
++#include <linux/pci-ecam.h>
+ #include <linux/platform_device.h>
+
+-#include "../ecam.h"
+-
+ #define PEM_CFG_WR 0x28
+ #define PEM_CFG_RD 0x30
+
+diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
+new file mode 100644
+index 0000000..9878beb
+--- /dev/null
++++ b/include/linux/pci-ecam.h
+@@ -0,0 +1,67 @@
++/*
++ * Copyright 2016 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License, version 2, as
++ * published by the Free Software Foundation (the "GPL").
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License version 2 (GPLv2) for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * version 2 (GPLv2) along with this source code.
++ */
++#ifndef DRIVERS_PCI_ECAM_H
++#define DRIVERS_PCI_ECAM_H
++
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++
++/*
++ * struct to hold pci ops and bus shift of the config window
++ * for a PCI controller.
++ */
++struct pci_config_window;
++struct pci_ecam_ops {
++ unsigned int bus_shift;
++ struct pci_ops pci_ops;
++ int (*init)(struct device *,
++ struct pci_config_window *);
++};
++
++/*
++ * struct to hold the mappings of a config space window. This
++ * is expected to be used as sysdata for PCI controllers that
++ * use ECAM.
++ */
++struct pci_config_window {
++ struct resource res;
++ struct resource busr;
++ void *priv;
++ struct pci_ecam_ops *ops;
++ union {
++ void __iomem *win; /* 64-bit single mapping */
++ void __iomem **winp; /* 32-bit per-bus mapping */
++ };
++};
++
++/* create and free pci_config_window */
++struct pci_config_window *pci_ecam_create(struct device *dev,
++ struct resource *cfgres, struct resource *busr,
++ struct pci_ecam_ops *ops);
++void pci_ecam_free(struct pci_config_window *cfg);
++
++/* map_bus when ->sysdata is an instance of pci_config_window */
++void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
++ int where);
++/* default ECAM ops */
++extern struct pci_ecam_ops pci_generic_ecam_ops;
++
++#ifdef CONFIG_PCI_HOST_GENERIC
++/* for DT-based PCI controllers that support ECAM */
++int pci_host_common_probe(struct platform_device *pdev,
++ struct pci_ecam_ops *ops);
++#endif
++#endif
+--
+2.7.4
+
+From 5eb9996fc097629854f359f9ad3d959fdacb7f8f Mon Sep 17 00:00:00 2001
+From: Jayachandran C <jchandra@broadcom.com>
+Date: Fri, 10 Jun 2016 21:55:10 +0200
+Subject: [PATCH 02/11] PCI/ECAM: Add parent device field to pci_config_window
+
+Add a parent device field to struct pci_config_window. The parent
+is not saved now, but will be useful to save it in some cases.
+Specifically in case of ACPI for ARM64, it can be used to setup
+ACPI companion and domain.
+
+Since the parent dev is in struct pci_config_window now, we need
+not pass it to the init function as a separate argument.
+
+Signed-off-by: Jayachandran C <jchandra@broadcom.com>
+Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/pci/ecam.c | 3 ++-
+ drivers/pci/host/pci-thunder-pem.c | 3 ++-
+ include/linux/pci-ecam.h | 4 ++--
+ 3 files changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c
+index 820e26b..66e0d71 100644
+--- a/drivers/pci/ecam.c
++++ b/drivers/pci/ecam.c
+@@ -51,6 +51,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
+ if (!cfg)
+ return ERR_PTR(-ENOMEM);
+
++ cfg->parent = dev;
+ cfg->ops = ops;
+ cfg->busr.start = busr->start;
+ cfg->busr.end = busr->end;
+@@ -94,7 +95,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
+ }
+
+ if (ops->init) {
+- err = ops->init(dev, cfg);
++ err = ops->init(cfg);
+ if (err)
+ goto err_exit;
+ }
+diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
+index 5020d3d..91f6fc6 100644
+--- a/drivers/pci/host/pci-thunder-pem.c
++++ b/drivers/pci/host/pci-thunder-pem.c
+@@ -284,8 +284,9 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
+ return pci_generic_config_write(bus, devfn, where, size, val);
+ }
+
+-static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg)
++static int thunder_pem_init(struct pci_config_window *cfg)
+ {
++ struct device *dev = cfg->parent;
+ resource_size_t bar4_start;
+ struct resource *res_pem;
+ struct thunder_pem_pci *pem_pci;
+diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
+index 9878beb..7adad20 100644
+--- a/include/linux/pci-ecam.h
++++ b/include/linux/pci-ecam.h
+@@ -27,8 +27,7 @@ struct pci_config_window;
+ struct pci_ecam_ops {
+ unsigned int bus_shift;
+ struct pci_ops pci_ops;
+- int (*init)(struct device *,
+- struct pci_config_window *);
++ int (*init)(struct pci_config_window *);
+ };
+
+ /*
+@@ -45,6 +44,7 @@ struct pci_config_window {
+ void __iomem *win; /* 64-bit single mapping */
+ void __iomem **winp; /* 32-bit per-bus mapping */
+ };
++ struct device *parent;/* ECAM res was from this dev */
+ };
+
+ /* create and free pci_config_window */
+--
+2.7.4
+
+From 6ed6c1365df5c9201e9b275e8ed4eaa64ef2ec0d Mon Sep 17 00:00:00 2001
+From: Sinan Kaya <okaya@codeaurora.org>
+Date: Fri, 10 Jun 2016 21:55:11 +0200
+Subject: [PATCH 03/11] PCI: Add new function to unmap IO resources
+
+We need to release I/O resources so that the same I/O resources
+can be allocated again in pci_remap_iospace(), like in PCI hotplug removal
+scenario. Therefore implement new pci_unmap_iospace() call which
+unmaps I/O space as the symmetry to pci_remap_iospace().
+
+Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/pci/pci.c | 18 ++++++++++++++++++
+ include/linux/pci.h | 1 +
+ 2 files changed, 19 insertions(+)
+
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index c8b4dbd..eb431b5 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -25,6 +25,7 @@
+ #include <linux/device.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/pci_hotplug.h>
++#include <linux/vmalloc.h>
+ #include <asm/setup.h>
+ #include <linux/aer.h>
+ #include "pci.h"
+@@ -3165,6 +3166,23 @@ int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
+ #endif
+ }
+
++/**
++ * pci_unmap_iospace - Unmap the memory mapped I/O space
++ * @res: resource to be unmapped
++ *
++ * Unmap the CPU virtual address @res from virtual address space.
++ * Only architectures that have memory mapped IO functions defined
++ * (and the PCI_IOBASE value defined) should call this function.
++ */
++void pci_unmap_iospace(struct resource *res)
++{
++#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
++ unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
++
++ unmap_kernel_range(vaddr, resource_size(res));
++#endif
++}
++
+ static void __pci_set_master(struct pci_dev *dev, bool enable)
+ {
+ u16 old_cmd, cmd;
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index b67e4df..12349de 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -1167,6 +1167,7 @@ int pci_register_io_range(phys_addr_t addr, resource_size_t size);
+ unsigned long pci_address_to_pio(phys_addr_t addr);
+ phys_addr_t pci_pio_to_address(unsigned long pio);
+ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
++void pci_unmap_iospace(struct resource *res);
+
+ static inline pci_bus_addr_t pci_bus_address(struct pci_dev *pdev, int bar)
+ {
+--
+2.7.4
+
+From 62f4d54fc2d2882b9ebaa920189574f422e12207 Mon Sep 17 00:00:00 2001
+From: Jayachandran C <jchandra@broadcom.com>
+Date: Fri, 10 Jun 2016 21:55:12 +0200
+Subject: [PATCH 04/11] ACPI/PCI: Support IO resources when parsing PCI host
+ bridge resources
+
+Platforms that have memory mapped IO port (such as ARM64) need special
+handling for PCI I/O resources. For host bridge's resource probing case
+these resources need to be fixed up with
+pci_register_io_range()/pci_remap_iospace() etc.
+
+The same I/O resources need to be released after hotplug
+removal so that it can be re-added back by the pci_remap_iospace()
+function during insertion. As a consequence unmap I/O resources
+with pci_unmap_iospace() when we release host bridge resources.
+
+Signed-off-by: Jayachandran C <jchandra@broadcom.com>
+Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
+[ Tomasz: merged in Sinan's patch to unmap IO resources properly, updated changelog]
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/acpi/pci_root.c | 39 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
+index ae3fe4e..9a26dd1 100644
+--- a/drivers/acpi/pci_root.c
++++ b/drivers/acpi/pci_root.c
+@@ -720,6 +720,40 @@ next:
+ }
+ }
+
++#ifdef PCI_IOBASE
++static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
++{
++ struct resource *res = entry->res;
++ resource_size_t cpu_addr = res->start;
++ resource_size_t pci_addr = cpu_addr - entry->offset;
++ resource_size_t length = resource_size(res);
++ unsigned long port;
++
++ if (pci_register_io_range(cpu_addr, length))
++ goto err;
++
++ port = pci_address_to_pio(cpu_addr);
++ if (port == (unsigned long)-1)
++ goto err;
++
++ res->start = port;
++ res->end = port + length - 1;
++ entry->offset = port - pci_addr;
++
++ if (pci_remap_iospace(res, cpu_addr) < 0)
++ goto err;
++
++ pr_info("Remapped I/O %pa to %pR\n", &cpu_addr, res);
++ return;
++err:
++ res->flags |= IORESOURCE_DISABLED;
++}
++#else
++static inline void acpi_pci_root_remap_iospace(struct resource_entry *entry)
++{
++}
++#endif
++
+ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+ {
+ int ret;
+@@ -740,6 +774,9 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
+ "no IO and memory resources present in _CRS\n");
+ else {
+ resource_list_for_each_entry_safe(entry, tmp, list) {
++ if (entry->res->flags & IORESOURCE_IO)
++ acpi_pci_root_remap_iospace(entry);
++
+ if (entry->res->flags & IORESOURCE_DISABLED)
+ resource_list_destroy_entry(entry);
+ else
+@@ -811,6 +848,8 @@ static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
+
+ resource_list_for_each_entry(entry, &bridge->windows) {
+ res = entry->res;
++ if (res->flags & IORESOURCE_IO)
++ pci_unmap_iospace(res);
+ if (res->parent &&
+ (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+ release_resource(res);
+--
+2.7.4
+
+From dd4f7822d702cca83baa1de7a5f69344ffb82af9 Mon Sep 17 00:00:00 2001
+From: Tomasz Nowicki <tn@semihalf.com>
+Date: Fri, 10 Jun 2016 21:55:13 +0200
+Subject: [PATCH 05/11] ACPI/PCI: Add generic MCFG table handling
+
+According to PCI firmware specifications, on systems booting with ACPI,
+PCI configuration for a host bridge must be set-up through the MCFG table
+regions for non-hotpluggable bridges and _CBA method for hotpluggable ones.
+
+Current MCFG table handling code, as implemented for x86, cannot be
+easily generalized owing to x86 specific quirks handling and related
+code, which makes it hard to reuse on other architectures.
+
+In order to implement MCFG PCI configuration handling for new platforms
+booting with ACPI (eg ARM64) this patch re-implements MCFG handling from
+scratch in a streamlined fashion and provides (through a generic
+interface available to all arches):
+
+- Simplified MCFG table parsing (executed through the pci_mmcfg_late_init()
+ hook as in current x86)
+- MCFG regions look-up interface through domain:bus_start:bus_end tuple
+
+The new MCFG regions handling interface is added to generic ACPI code
+so that existing architectures (eg x86) can be moved over to it and
+architectures relying on MCFG for ACPI PCI config space can rely on it
+without having to resort to arch specific implementations.
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Signed-off-by: Jayachandran C <jchandra@broadcom.com>
+Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/acpi/Kconfig | 3 ++
+ drivers/acpi/Makefile | 1 +
+ drivers/acpi/pci_mcfg.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/pci-acpi.h | 2 ++
+ include/linux/pci.h | 2 +-
+ 5 files changed, 99 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/acpi/pci_mcfg.c
+
+diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
+index b7e2e77..f98c328 100644
+--- a/drivers/acpi/Kconfig
++++ b/drivers/acpi/Kconfig
+@@ -217,6 +217,9 @@ config ACPI_PROCESSOR_IDLE
+ bool
+ select CPU_IDLE
+
++config ACPI_MCFG
++ bool
++
+ config ACPI_CPPC_LIB
+ bool
+ depends on ACPI_PROCESSOR
+diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
+index 251ce85..632e81f 100644
+--- a/drivers/acpi/Makefile
++++ b/drivers/acpi/Makefile
+@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
+ acpi-y += ec.o
+ acpi-$(CONFIG_ACPI_DOCK) += dock.o
+ acpi-y += pci_root.o pci_link.o pci_irq.o
++obj-$(CONFIG_ACPI_MCFG) += pci_mcfg.o
+ acpi-y += acpi_lpss.o acpi_apd.o
+ acpi-y += acpi_platform.o
+ acpi-y += acpi_pnp.o
+diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
+new file mode 100644
+index 0000000..d3c3e85
+--- /dev/null
++++ b/drivers/acpi/pci_mcfg.c
+@@ -0,0 +1,92 @@
++/*
++ * Copyright (C) 2016 Broadcom
++ * Author: Jayachandran C <jchandra@broadcom.com>
++ * Copyright (C) 2016 Semihalf
++ * Author: Tomasz Nowicki <tn@semihalf.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License, version 2, as
++ * published by the Free Software Foundation (the "GPL").
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License version 2 (GPLv2) for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * version 2 (GPLv2) along with this source code.
++ */
++
++#define pr_fmt(fmt) "ACPI: " fmt
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/pci-acpi.h>
++
++/* Structure to hold entries from the MCFG table */
++struct mcfg_entry {
++ struct list_head list;
++ phys_addr_t addr;
++ u16 segment;
++ u8 bus_start;
++ u8 bus_end;
++};
++
++/* List to save mcfg entries */
++static LIST_HEAD(pci_mcfg_list);
++
++phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
++{
++ struct mcfg_entry *e;
++
++ /*
++ * We expect exact match, unless MCFG entry end bus covers more than
++ * specified by caller.
++ */
++ list_for_each_entry(e, &pci_mcfg_list, list) {
++ if (e->segment == seg && e->bus_start == bus_res->start &&
++ e->bus_end >= bus_res->end)
++ return e->addr;
++ }
++
++ return 0;
++}
++
++static __init int pci_mcfg_parse(struct acpi_table_header *header)
++{
++ struct acpi_table_mcfg *mcfg;
++ struct acpi_mcfg_allocation *mptr;
++ struct mcfg_entry *e, *arr;
++ int i, n;
++
++ if (header->length < sizeof(struct acpi_table_mcfg))
++ return -EINVAL;
++
++ n = (header->length - sizeof(struct acpi_table_mcfg)) /
++ sizeof(struct acpi_mcfg_allocation);
++ mcfg = (struct acpi_table_mcfg *)header;
++ mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
++
++ arr = kcalloc(n, sizeof(*arr), GFP_KERNEL);
++ if (!arr)
++ return -ENOMEM;
++
++ for (i = 0, e = arr; i < n; i++, mptr++, e++) {
++ e->segment = mptr->pci_segment;
++ e->addr = mptr->address;
++ e->bus_start = mptr->start_bus_number;
++ e->bus_end = mptr->end_bus_number;
++ list_add(&e->list, &pci_mcfg_list);
++ }
++
++ pr_info("MCFG table detected, %d entries\n", n);
++ return 0;
++}
++
++/* Interface called by ACPI - parse and save MCFG table */
++void __init pci_mmcfg_late_init(void)
++{
++ int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
++ if (err)
++ pr_err("Failed to parse MCFG (%d)\n", err);
++}
+diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
+index 89ab057..7d63a66 100644
+--- a/include/linux/pci-acpi.h
++++ b/include/linux/pci-acpi.h
+@@ -24,6 +24,8 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
+ }
+ extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
+
++extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res);
++
+ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
+ {
+ struct pci_bus *pbus = pdev->bus;
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 12349de..ce03d65 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -1723,7 +1723,7 @@ void pcibios_free_irq(struct pci_dev *dev);
+ extern struct dev_pm_ops pcibios_pm_ops;
+ #endif
+
+-#ifdef CONFIG_PCI_MMCONFIG
++#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG)
+ void __init pci_mmcfg_early_init(void);
+ void __init pci_mmcfg_late_init(void);
+ #else
+--
+2.7.4
+
+From fc1907f9c79f9a0a0c2f4d579896e678915fec48 Mon Sep 17 00:00:00 2001
+From: Tomasz Nowicki <tn@semihalf.com>
+Date: Fri, 10 Jun 2016 21:55:14 +0200
+Subject: [PATCH 06/11] PCI: Refactor generic bus domain assignment
+
+Change the way PCI bus domain number is assigned and improve function
+name to reflect what function does. No functional changes.
+
+Instead of assigning bus domain number inside of pci_bus_assign_domain_nr()
+simply return domain number and let pci_create_root_bus() do assignment.
+This way pci_create_root_bus() setups bus structure data in the consistent
+way. Since pci_bus_assign_domain_nr() now does not assign but retrieves
+domain number instead, rename it to pci_bus_find_domain_nr().
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/pci/pci.c | 4 ++--
+ drivers/pci/probe.c | 4 +++-
+ include/linux/pci.h | 7 +------
+ 3 files changed, 6 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index eb431b5..b9a7833 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -4941,7 +4941,7 @@ int pci_get_new_domain_nr(void)
+ }
+
+ #ifdef CONFIG_PCI_DOMAINS_GENERIC
+-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
++int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
+ {
+ static int use_dt_domains = -1;
+ int domain = -1;
+@@ -4985,7 +4985,7 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+ domain = -1;
+ }
+
+- bus->domain_nr = domain;
++ return domain;
+ }
+ #endif
+ #endif
+diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
+index 8e3ef72..380d46d 100644
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -2127,7 +2127,9 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+ b->sysdata = sysdata;
+ b->ops = ops;
+ b->number = b->busn_res.start = bus;
+- pci_bus_assign_domain_nr(b, parent);
++#ifdef CONFIG_PCI_DOMAINS_GENERIC
++ b->domain_nr = pci_bus_find_domain_nr(b, parent);
++#endif
+ b2 = pci_find_bus(pci_domain_nr(b), bus);
+ if (b2) {
+ /* If we already got to this bus through a different bridge, ignore it */
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index ce03d65..48839e8 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -1390,12 +1390,7 @@ static inline int pci_domain_nr(struct pci_bus *bus)
+ {
+ return bus->domain_nr;
+ }
+-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
+-#else
+-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
+- struct device *parent)
+-{
+-}
++int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent);
+ #endif
+
+ /* some architectures require additional setup to direct VGA traffic */
+--
+2.7.4
+
+From d6d45ae1d58658111d5e838c41b9ed4729bbb81e Mon Sep 17 00:00:00 2001
+From: Tomasz Nowicki <tn@semihalf.com>
+Date: Fri, 10 Jun 2016 21:55:15 +0200
+Subject: [PATCH 07/11] PCI: Factor DT specific pci_bus_find_domain_nr() code
+ out
+
+pci_bus_find_domain_nr() retrieves the host bridge domain number in a DT
+specific way. Factor our pci_bus_find_domain_nr() in a separate DT
+function (ie of_pci_bus_find_domain_nr()) so that DT code is self
+contained, paving the way for retrieving domain number in
+pci_bus_find_domain_nr() with additional firmware methods (ie ACPI).
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ drivers/pci/pci.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index b9a7833..97f7cd4 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -4941,7 +4941,7 @@ int pci_get_new_domain_nr(void)
+ }
+
+ #ifdef CONFIG_PCI_DOMAINS_GENERIC
+-int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
++static int of_pci_bus_find_domain_nr(struct device *parent)
+ {
+ static int use_dt_domains = -1;
+ int domain = -1;
+@@ -4987,6 +4987,11 @@ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
+
+ return domain;
+ }
++
++int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
++{
++ return of_pci_bus_find_domain_nr(parent);
++}
+ #endif
+ #endif
+
+--
+2.7.4
+
+From 92d59511fd365d3c0c31d074b5e96cf48c58f68b Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Thu, 30 Jun 2016 16:56:24 +0100
+Subject: [PATCH 08/11] ARM64/PCI: Add ACPI hook to assign domain number
+
+PCI core code provides a config option (CONFIG_PCI_DOMAINS_GENERIC)
+that allows assigning the PCI bus domain number generically by
+relying on device tree bindings, and falling back to a simple counter
+when the respective DT properties (ie "linux,pci-domain") are not
+specified in the host bridge device tree node.
+
+In a similar way, when a system is booted through ACPI, architectures
+that are selecting CONFIG_PCI_DOMAINS_GENERIC (ie ARM64) require kernel
+hooks to retrieve the domain number so that the PCI bus domain number
+set-up can be handled seamlessly with DT and ACPI in generic core code
+when CONFIG_PCI_DOMAINS_GENERIC is selected.
+
+Since currently it is not possible to retrieve a pointer to the PCI
+host bridge ACPI device backing the host bridge from core PCI code
+(which would allow retrieving the domain number in an arch agnostic
+way through the ACPI _SEG method), an arch specific ACPI hook has to
+be declared and implemented by all arches that rely on
+CONFIG_PCI_DOMAINS_GENERIC to retrieve the domain number and set it
+up in core PCI code.
+
+For the aforementioned reasons, introduce acpi_pci_bus_find_domain_nr()
+hook to retrieve the domain number on a per-arch basis when the system
+boots through ACPI. ARM64 dummy implementation of the same is provided
+in first place in preparation for ARM64 ACPI based PCI host controller
+driver.
+
+acpi_pci_bus_find_domain_nr() is called from generic
+pci_bus_find_domain_nr() as an ACPI option to DT domain assignment.
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ arch/arm64/kernel/pci.c | 7 +++++++
+ drivers/pci/pci.c | 4 +++-
+ include/linux/pci.h | 7 +++++++
+ 3 files changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
+index 3c4e308..d5d3d26 100644
+--- a/arch/arm64/kernel/pci.c
++++ b/arch/arm64/kernel/pci.c
+@@ -17,6 +17,7 @@
+ #include <linux/mm.h>
+ #include <linux/of_pci.h>
+ #include <linux/of_platform.h>
++#include <linux/pci.h>
+ #include <linux/slab.h>
+
+ /*
+@@ -85,6 +86,12 @@ EXPORT_SYMBOL(pcibus_to_node);
+ #endif
+
+ #ifdef CONFIG_ACPI
++
++int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
++{
++ return 0;
++}
++
+ /* Root bridge scanning */
+ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+ {
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index 97f7cd4..4834cee 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -7,6 +7,7 @@
+ * Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
+ */
+
++#include <linux/acpi.h>
+ #include <linux/kernel.h>
+ #include <linux/delay.h>
+ #include <linux/init.h>
+@@ -4990,7 +4991,8 @@ static int of_pci_bus_find_domain_nr(struct device *parent)
+
+ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
+ {
+- return of_pci_bus_find_domain_nr(parent);
++ return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
++ acpi_pci_bus_find_domain_nr(bus);
+ }
+ #endif
+ #endif
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 48839e8..49ba8af 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -1390,6 +1390,13 @@ static inline int pci_domain_nr(struct pci_bus *bus)
+ {
+ return bus->domain_nr;
+ }
++/* Arch specific ACPI hook to set-up domain number */
++#ifdef CONFIG_ACPI
++int acpi_pci_bus_find_domain_nr(struct pci_bus *bus);
++#else
++static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
++{ return 0; }
++#endif
+ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent);
+ #endif
+
+--
+2.7.4
+
+From bb06753d2e163d8100a017f06a6d9dd195d68a76 Mon Sep 17 00:00:00 2001
+From: Tomasz Nowicki <tn@semihalf.com>
+Date: Fri, 10 Jun 2016 21:55:17 +0200
+Subject: [PATCH 09/11] ARM64/PCI: ACPI support for legacy IRQs parsing and
+ consolidation with DT code
+
+To enable PCI legacy IRQs on platforms booting with ACPI, arch code
+should include ACPI specific callbacks that parse and set-up the
+device IRQ number, equivalent to the DT boot path. Owing to the current
+ACPI core scan handlers implementation, ACPI PCI legacy IRQs bindings
+cannot be parsed at device add time, since that would trigger ACPI scan
+handlers ordering issues depending on how the ACPI tables are defined.
+
+To solve this problem and consolidate FW PCI legacy IRQs parsing in
+one single pcibios callback (pending final removal), this patch moves
+DT PCI IRQ parsing to the pcibios_alloc_irq() callback (called by
+PCI core code at device probe time) and adds ACPI PCI legacy IRQs
+parsing to the same callback too, so that FW PCI legacy IRQs parsing
+is confined in one single arch callback that can be easily removed
+when code parsing PCI legacy IRQs is consolidated and moved to core
+PCI code.
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Suggested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ arch/arm64/kernel/pci.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
+index d5d3d26..b3b8a2c 100644
+--- a/arch/arm64/kernel/pci.c
++++ b/arch/arm64/kernel/pci.c
+@@ -51,11 +51,16 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
+ }
+
+ /*
+- * Try to assign the IRQ number from DT when adding a new device
++ * Try to assign the IRQ number when probing a new device
+ */
+-int pcibios_add_device(struct pci_dev *dev)
++int pcibios_alloc_irq(struct pci_dev *dev)
+ {
+- dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
++ if (acpi_disabled)
++ dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
++#ifdef CONFIG_ACPI
++ else
++ return acpi_pci_irq_enable(dev);
++#endif
+
+ return 0;
+ }
+--
+2.7.4
+
+From b6e298840f532192a589f8ade128dec3fef3a4c6 Mon Sep 17 00:00:00 2001
+From: Tomasz Nowicki <tn@semihalf.com>
+Date: Fri, 10 Jun 2016 21:55:18 +0200
+Subject: [PATCH 10/11] ARM64/PCI: Implement ACPI low-level calls to access
+ PCI_Config region from AML
+
+ACPI spec6.1 - chapter: 5.5.2.4 defines OperationRegion (Declare Operation
+Region). Following the spec: " [...] An Operation Region is a specific
+region of operation within an address space that is declared as a subset
+of the entire address space using a starting address (offset) and a length.
+Control methods must have exclusive access to any address accessed via
+fields declared in Operation Regions. [...]".
+
+OperationRegion allows to declare various of operation region address space
+identifiers including PCI_Config. PCI_Config is meant to access PCI
+configuration space from the ASL. So every time ASL opcode operates
+on PCI_Config space region, ASL interpreter dispatches accesses to OS
+low-level calls - raw_pci_write() and raw_pci_read() for Linux - so-called
+ACPI RAW accessors.
+
+In order to support PCI_Config operation region, implement mentioned
+raw_pci_write() and raw_pci_read() calls so they find associated bus
+and call read/write ops.
+
+Waiting for clarification in the ACPI specifications in relation
+to PCI_Config space handling before PCI bus enumeration is completed,
+current code does not support PCI_Config region accesses before PCI bus
+enumeration whilst providing full AML PCI_Config access availability
+when the PCI bus enumeration is completed by the kernel so that
+RAW accessors can look-up PCI operations through the struct pci_bus
+associated with a PCI bus.
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Signed-off-by: Jayachandran C <jchandra@broadcom.com>
+Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ arch/arm64/kernel/pci.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
+index b3b8a2c..328f857 100644
+--- a/arch/arm64/kernel/pci.c
++++ b/arch/arm64/kernel/pci.c
+@@ -71,13 +71,21 @@ int pcibios_alloc_irq(struct pci_dev *dev)
+ int raw_pci_read(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *val)
+ {
+- return -ENXIO;
++ struct pci_bus *b = pci_find_bus(domain, bus);
++
++ if (!b)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ return b->ops->read(b, devfn, reg, len, val);
+ }
+
+ int raw_pci_write(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 val)
+ {
+- return -ENXIO;
++ struct pci_bus *b = pci_find_bus(domain, bus);
++
++ if (!b)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ return b->ops->write(b, devfn, reg, len, val);
+ }
+
+ #ifdef CONFIG_NUMA
+--
+2.7.4
+
+From 3b8cff3fa89ba3ef6f1cf09a0667aa470b7fad0b Mon Sep 17 00:00:00 2001
+From: Tomasz Nowicki <tn@semihalf.com>
+Date: Fri, 10 Jun 2016 21:55:19 +0200
+Subject: [PATCH 11/11] ARM64/PCI: Support for ACPI based PCI host controller
+
+Implement pci_acpi_scan_root and other arch-specific call so that ARM64
+can start using ACPI to setup and enumerate PCI buses.
+
+Prior to buses enumeration the pci_acpi_scan_root() implementation looks
+for configuration space start address (obtained through ACPI _CBA method or
+MCFG interface). If succeed, it uses ECAM library to create new mapping.
+Then it attaches generic ECAM ops (pci_generic_ecam_ops) which are used
+for accessing configuration space later on.
+
+On ARM64, we need to use generic domains (CONFIG_PCI_DOMAINS_GENERIC).
+In order to achieve that for ACPI case implement
+acpi_pci_bus_find_domain_nr() body so that it retrieves pci_config_window
+structure from bus sysdata and eventually gets domain number from
+acpi_pci_root structure.
+
+ACPI requires to run acpi_pci_{add|remove}_bus while new PCI bus is created.
+This allows to do some ACPI-specific additional configuration, like
+PCI hotplug slot enumeration. In order to fulfill these requirements,
+we implement arch-specific pcibios_{add|remove}_bus calls
+and call acpi_pci_{add|remove}_bus from there.
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Signed-off-by: Jayachandran C <jchandra@broadcom.com>
+Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+---
+ arch/arm64/Kconfig | 2 +
+ arch/arm64/kernel/pci.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 115 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index 5a0a691..4806cde 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -3,6 +3,7 @@ config ARM64
+ select ACPI_CCA_REQUIRED if ACPI
+ select ACPI_GENERIC_GSI if ACPI
+ select ACPI_REDUCED_HARDWARE_ONLY if ACPI
++ select ACPI_MCFG if ACPI
+ select ARCH_HAS_DEVMEM_IS_ALLOWED
+ select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+ select ARCH_HAS_ELF_RANDOMIZE
+@@ -96,6 +97,7 @@ config ARM64
+ select OF_EARLY_FLATTREE
+ select OF_NUMA if NUMA && OF
+ select OF_RESERVED_MEM
++ select PCI_ECAM if ACPI
+ select PERF_USE_VMALLOC
+ select POWER_RESET
+ select POWER_SUPPLY
+diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
+index 328f857..94cd43c 100644
+--- a/arch/arm64/kernel/pci.c
++++ b/arch/arm64/kernel/pci.c
+@@ -18,6 +18,8 @@
+ #include <linux/of_pci.h>
+ #include <linux/of_platform.h>
+ #include <linux/pci.h>
++#include <linux/pci-acpi.h>
++#include <linux/pci-ecam.h>
+ #include <linux/slab.h>
+
+ /*
+@@ -100,15 +102,123 @@ EXPORT_SYMBOL(pcibus_to_node);
+
+ #ifdef CONFIG_ACPI
+
++struct acpi_pci_generic_root_info {
++ struct acpi_pci_root_info common;
++ struct pci_config_window *cfg; /* config space mapping */
++};
++
+ int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+ {
++ struct pci_config_window *cfg = bus->sysdata;
++ struct acpi_device *adev = to_acpi_device(cfg->parent);
++ struct acpi_pci_root *root = acpi_driver_data(adev);
++
++ return root->segment;
++}
++
++int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
++{
++ if (!acpi_disabled) {
++ struct pci_config_window *cfg = bridge->bus->sysdata;
++ struct acpi_device *adev = to_acpi_device(cfg->parent);
++ ACPI_COMPANION_SET(&bridge->dev, adev);
++ }
++
+ return 0;
+ }
+
+-/* Root bridge scanning */
++/*
++ * Lookup the bus range for the domain in MCFG, and set up config space
++ * mapping.
++ */
++static struct pci_config_window *
++pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
++{
++ struct resource *bus_res = &root->secondary;
++ u16 seg = root->segment;
++ struct pci_config_window *cfg;
++ struct resource cfgres;
++ unsigned int bsz;
++
++ /* Use address from _CBA if present, otherwise lookup MCFG */
++ if (!root->mcfg_addr)
++ root->mcfg_addr = pci_mcfg_lookup(seg, bus_res);
++
++ if (!root->mcfg_addr) {
++ dev_err(&root->device->dev, "%04x:%pR ECAM region not found\n",
++ seg, bus_res);
++ return NULL;
++ }
++
++ bsz = 1 << pci_generic_ecam_ops.bus_shift;
++ cfgres.start = root->mcfg_addr + bus_res->start * bsz;
++ cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1;
++ cfgres.flags = IORESOURCE_MEM;
++ cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res,
++ &pci_generic_ecam_ops);
++ if (IS_ERR(cfg)) {
++ dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n",
++ seg, bus_res, PTR_ERR(cfg));
++ return NULL;
++ }
++
++ return cfg;
++}
++
++/* release_info: free resources allocated by init_info */
++static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
++{
++ struct acpi_pci_generic_root_info *ri;
++
++ ri = container_of(ci, struct acpi_pci_generic_root_info, common);
++ pci_ecam_free(ri->cfg);
++ kfree(ri);
++}
++
++static struct acpi_pci_root_ops acpi_pci_root_ops = {
++ .release_info = pci_acpi_generic_release_info,
++};
++
++/* Interface called from ACPI code to setup PCI host controller */
+ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+ {
+- /* TODO: Should be revisited when implementing PCI on ACPI */
+- return NULL;
++ int node = acpi_get_node(root->device->handle);
++ struct acpi_pci_generic_root_info *ri;
++ struct pci_bus *bus, *child;
++
++ ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node);
++ if (!ri)
++ return NULL;
++
++ ri->cfg = pci_acpi_setup_ecam_mapping(root);
++ if (!ri->cfg) {
++ kfree(ri);
++ return NULL;
++ }
++
++ acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops;
++ bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common,
++ ri->cfg);
++ if (!bus)
++ return NULL;
++
++ pci_bus_size_bridges(bus);
++ pci_bus_assign_resources(bus);
++
++ list_for_each_entry(child, &bus->children, node)
++ pcie_bus_configure_settings(child);
++
++ return bus;
++}
++
++void pcibios_add_bus(struct pci_bus *bus)
++{
++ acpi_pci_add_bus(bus);
+ }
++
++void pcibios_remove_bus(struct pci_bus *bus)
++{
++ acpi_pci_remove_bus(bus);
++}
++
+ #endif
+--
+2.7.4
+
diff --git a/arm64-pcie-quirks-xgene.patch b/arm64-pcie-quirks-xgene.patch
new file mode 100644
index 000000000..8e6805df6
--- /dev/null
+++ b/arm64-pcie-quirks-xgene.patch
@@ -0,0 +1,508 @@
+From 767b70aa55d013f0c7589955f410d488fed5776a Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Tue, 5 Jul 2016 23:49:39 +0100
+Subject: [PATCH 1/4] Some platforms may not be fully compliant with generic
+ set of PCI config accessors. For these cases we implement the way to
+ overwrite accessors set. Algorithm traverses available quirk list, matches
+ against <oem_id, oem_table_id, domain, bus number> tuple and returns
+ corresponding PCI config ops. oem_id and oem_table_id come from MCFG table
+ standard header. All quirks can be defined using DECLARE_ACPI_MCFG_FIXUP()
+ macro and kept self contained. Example:
+
+/* Custom PCI config ops */
+static struct pci_generic_ecam_ops foo_pci_ops = {
+ .bus_shift = 24,
+ .pci_ops = {
+ .map_bus = pci_ecam_map_bus,
+ .read = foo_ecam_config_read,
+ .write = foo_ecam_config_write,
+ }
+};
+
+DECLARE_ACPI_MCFG_FIXUP(&foo_pci_ops, <oem_id_str>, <oem_table_id>, <domain_nr>, <bus_nr>);
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+Signed-off-by: Dongdong Liu <liudongdong3@huawei.com>
+---
+ drivers/acpi/pci_mcfg.c | 41 ++++++++++++++++++++++++++++++++++++---
+ include/asm-generic/vmlinux.lds.h | 7 +++++++
+ include/linux/pci-acpi.h | 20 +++++++++++++++++++
+ 3 files changed, 65 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
+index d3c3e85..deb0077 100644
+--- a/drivers/acpi/pci_mcfg.c
++++ b/drivers/acpi/pci_mcfg.c
+@@ -22,6 +22,10 @@
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
+ #include <linux/pci-acpi.h>
++#include <linux/pci-ecam.h>
++
++/* Root pointer to the mapped MCFG table */
++static struct acpi_table_mcfg *mcfg_table;
+
+ /* Structure to hold entries from the MCFG table */
+ struct mcfg_entry {
+@@ -35,6 +39,38 @@ struct mcfg_entry {
+ /* List to save mcfg entries */
+ static LIST_HEAD(pci_mcfg_list);
+
++extern struct pci_cfg_fixup __start_acpi_mcfg_fixups[];
++extern struct pci_cfg_fixup __end_acpi_mcfg_fixups[];
++
++struct pci_ecam_ops *pci_mcfg_get_ops(struct acpi_pci_root *root)
++{
++ int bus_num = root->secondary.start;
++ int domain = root->segment;
++ struct pci_cfg_fixup *f;
++
++ if (!mcfg_table)
++ return &pci_generic_ecam_ops;
++
++ /*
++ * Match against platform specific quirks and return corresponding
++ * CAM ops.
++ *
++ * First match against PCI topology <domain:bus> then use OEM ID and
++ * OEM revision from MCFG table standard header.
++ */
++ for (f = __start_acpi_mcfg_fixups; f < __end_acpi_mcfg_fixups; f++) {
++ if ((f->domain == domain || f->domain == PCI_MCFG_DOMAIN_ANY) &&
++ (f->bus_num == bus_num || f->bus_num == PCI_MCFG_BUS_ANY) &&
++ (!strncmp(f->oem_id, mcfg_table->header.oem_id,
++ ACPI_OEM_ID_SIZE)) &&
++ (!strncmp(f->oem_table_id, mcfg_table->header.oem_table_id,
++ ACPI_OEM_TABLE_ID_SIZE)))
++ return f->ops;
++ }
++ /* No quirks, use ECAM */
++ return &pci_generic_ecam_ops;
++}
++
+ phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
+ {
+ struct mcfg_entry *e;
+@@ -54,7 +90,6 @@ phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
+
+ static __init int pci_mcfg_parse(struct acpi_table_header *header)
+ {
+- struct acpi_table_mcfg *mcfg;
+ struct acpi_mcfg_allocation *mptr;
+ struct mcfg_entry *e, *arr;
+ int i, n;
+@@ -64,8 +99,8 @@ static __init int pci_mcfg_parse(struct acpi_table_header *header)
+
+ n = (header->length - sizeof(struct acpi_table_mcfg)) /
+ sizeof(struct acpi_mcfg_allocation);
+- mcfg = (struct acpi_table_mcfg *)header;
+- mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
++ mcfg_table = (struct acpi_table_mcfg *)header;
++ mptr = (struct acpi_mcfg_allocation *) &mcfg_table[1];
+
+ arr = kcalloc(n, sizeof(*arr), GFP_KERNEL);
+ if (!arr)
+diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
+index 6a67ab9..43604fc 100644
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -300,6 +300,13 @@
+ VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \
+ } \
+ \
++ /* ACPI MCFG quirks */ \
++ .acpi_fixup : AT(ADDR(.acpi_fixup) - LOAD_OFFSET) { \
++ VMLINUX_SYMBOL(__start_acpi_mcfg_fixups) = .; \
++ *(.acpi_fixup_mcfg) \
++ VMLINUX_SYMBOL(__end_acpi_mcfg_fixups) = .; \
++ } \
++ \
+ /* Built-in firmware blobs */ \
+ .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start_builtin_fw) = .; \
+diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
+index 7d63a66..c8a6559 100644
+--- a/include/linux/pci-acpi.h
++++ b/include/linux/pci-acpi.h
+@@ -25,6 +25,7 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
+ extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
+
+ extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res);
++extern struct pci_ecam_ops *pci_mcfg_get_ops(struct acpi_pci_root *root);
+
+ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
+ {
+@@ -72,6 +73,25 @@ struct acpi_pci_root_ops {
+ int (*prepare_resources)(struct acpi_pci_root_info *info);
+ };
+
++struct pci_cfg_fixup {
++ struct pci_ecam_ops *ops;
++ char *oem_id;
++ char *oem_table_id;
++ int domain;
++ int bus_num;
++};
++
++#define PCI_MCFG_DOMAIN_ANY -1
++#define PCI_MCFG_BUS_ANY -1
++
++/* Designate a routine to fix up buggy MCFG */
++#define DECLARE_ACPI_MCFG_FIXUP(ops, oem_id, oem_table_id, dom, bus) \
++ static const struct pci_cfg_fixup \
++ __mcfg_fixup_##oem_id##oem_table_id##dom##bus \
++ __used __attribute__((__section__(".acpi_fixup_mcfg"), \
++ aligned((sizeof(void *))))) = \
++ { ops, oem_id, oem_table_id, dom, bus };
++
+ extern int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info);
+ extern struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+ struct acpi_pci_root_ops *ops,
+--
+2.7.4
+
+From 4f86a9b006b25dd7336043dab26058ed6fb2802d Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Tue, 5 Jul 2016 23:52:46 +0100
+Subject: [PATCH 2/4] pci_generic_ecam_ops is used by default. Since there are
+ platforms which have non-compliant ECAM space we need to overwrite these
+ accessors prior to PCI buses enumeration. In order to do that we call
+ pci_mcfg_get_ops to retrieve pci_ecam_ops structure so that we can use proper
+ PCI config space accessors and bus_shift.
+
+pci_generic_ecam_ops is still used for platforms free from quirks.
+
+Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
+---
+ arch/arm64/kernel/pci.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
+index 94cd43c..a891bda 100644
+--- a/arch/arm64/kernel/pci.c
++++ b/arch/arm64/kernel/pci.c
+@@ -139,6 +139,7 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
+ struct pci_config_window *cfg;
+ struct resource cfgres;
+ unsigned int bsz;
++ struct pci_ecam_ops *ops;
+
+ /* Use address from _CBA if present, otherwise lookup MCFG */
+ if (!root->mcfg_addr)
+@@ -150,12 +151,12 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
+ return NULL;
+ }
+
+- bsz = 1 << pci_generic_ecam_ops.bus_shift;
++ ops = pci_mcfg_get_ops(root);
++ bsz = 1 << ops->bus_shift;
+ cfgres.start = root->mcfg_addr + bus_res->start * bsz;
+ cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1;
+ cfgres.flags = IORESOURCE_MEM;
+- cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res,
+- &pci_generic_ecam_ops);
++ cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res, ops);
+ if (IS_ERR(cfg)) {
+ dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n",
+ seg, bus_res, PTR_ERR(cfg));
+--
+2.7.4
+
+From cbdbd697bd6d716eb9d1705ee55445432e73eabb Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Tue, 5 Jul 2016 23:53:59 +0100
+Subject: [PATCH 3/4] The ECAM quirk matching criteria per the discussion on
+ https://lkml.org/lkml/2016/6/13/944 includes: OEM ID, OEM Table ID and OEM
+ Revision. So this patch adds OEM Table ID into the check to match platform
+ specific ECAM quirks as well.
+
+This patch also improve strncmp check using strlen and
+min_t to ignore the padding spaces in OEM ID and OEM
+Table ID.
+
+Signed-off-by: Duc Dang <dhdang@apm.com>
+---
+ drivers/acpi/pci_mcfg.c | 7 +++++--
+ include/linux/pci-acpi.h | 7 ++++---
+ 2 files changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
+index deb0077..307ca9a 100644
+--- a/drivers/acpi/pci_mcfg.c
++++ b/drivers/acpi/pci_mcfg.c
+@@ -62,9 +62,12 @@ struct pci_ecam_ops *pci_mcfg_get_ops(struct acpi_pci_root *root)
+ if ((f->domain == domain || f->domain == PCI_MCFG_DOMAIN_ANY) &&
+ (f->bus_num == bus_num || f->bus_num == PCI_MCFG_BUS_ANY) &&
+ (!strncmp(f->oem_id, mcfg_table->header.oem_id,
+- ACPI_OEM_ID_SIZE)) &&
++ min_t(size_t, strlen(f->oem_id),
++ ACPI_OEM_ID_SIZE))) &&
+ (!strncmp(f->oem_table_id, mcfg_table->header.oem_table_id,
+- ACPI_OEM_TABLE_ID_SIZE)))
++ min_t(size_t, strlen(f->oem_table_id),
++ ACPI_OEM_TABLE_ID_SIZE))) &&
++ (f->oem_revision == mcfg_table->header.oem_revision))
+ return f->ops;
+ }
+ /* No quirks, use ECAM */
+diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
+index c8a6559..5148c8d 100644
+--- a/include/linux/pci-acpi.h
++++ b/include/linux/pci-acpi.h
+@@ -77,6 +77,7 @@ struct pci_cfg_fixup {
+ struct pci_ecam_ops *ops;
+ char *oem_id;
+ char *oem_table_id;
++ u32 oem_revision;
+ int domain;
+ int bus_num;
+ };
+@@ -85,12 +86,12 @@ struct pci_cfg_fixup {
+ #define PCI_MCFG_BUS_ANY -1
+
+ /* Designate a routine to fix up buggy MCFG */
+-#define DECLARE_ACPI_MCFG_FIXUP(ops, oem_id, oem_table_id, dom, bus) \
++#define DECLARE_ACPI_MCFG_FIXUP(ops, oem_id, oem_table_id, rev, dom, bus) \
+ static const struct pci_cfg_fixup \
+- __mcfg_fixup_##oem_id##oem_table_id##dom##bus \
++ __mcfg_fixup_##oem_id##oem_table_id##rev##dom##bus \
+ __used __attribute__((__section__(".acpi_fixup_mcfg"), \
+ aligned((sizeof(void *))))) = \
+- { ops, oem_id, oem_table_id, dom, bus };
++ { ops, oem_id, oem_table_id, rev, dom, bus };
+
+ extern int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info);
+ extern struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
+--
+2.7.4
+
+From 78766cf255bc6aafac2f57372a0446f78322da19 Mon Sep 17 00:00:00 2001
+From: Peter Robinson <pbrobinson@gmail.com>
+Date: Tue, 5 Jul 2016 23:55:11 +0100
+Subject: [PATCH 4/4] X-Gene PCIe controller does not fully support ECAM. This
+ patch adds required ECAM fixup to allow X-Gene PCIe controller to be
+ functional in ACPI boot mode.
+
+Signed-off-by: Duc Dang <dhdang@apm.com>
+---
+ drivers/pci/host/Makefile | 2 +-
+ drivers/pci/host/pci-xgene-ecam.c | 194 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 195 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/pci/host/pci-xgene-ecam.c
+
+diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
+index 9c8698e..3480696 100644
+--- a/drivers/pci/host/Makefile
++++ b/drivers/pci/host/Makefile
+@@ -14,7 +14,7 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
+ obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
+ obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
+ obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o
+-obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
++obj-$(CONFIG_PCI_XGENE) += pci-xgene.o pci-xgene-ecam.o
+ obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
+ obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
+ obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
+diff --git a/drivers/pci/host/pci-xgene-ecam.c b/drivers/pci/host/pci-xgene-ecam.c
+new file mode 100644
+index 0000000..1bea63f
+--- /dev/null
++++ b/drivers/pci/host/pci-xgene-ecam.c
+@@ -0,0 +1,194 @@
++/*
++ * APM X-Gene PCIe ECAM fixup driver
++ *
++ * Copyright (c) 2016, Applied Micro Circuits Corporation
++ * Author:
++ * Duc Dang <dhdang@apm.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_pci.h>
++#include <linux/pci-acpi.h>
++#include <linux/platform_device.h>
++#include <linux/pci-ecam.h>
++
++#ifdef CONFIG_ACPI
++#define RTDID 0x160
++#define ROOT_CAP_AND_CTRL 0x5C
++
++/* PCIe IP version */
++#define XGENE_PCIE_IP_VER_UNKN 0
++#define XGENE_PCIE_IP_VER_1 1
++
++#define APM_OEM_ID "APM"
++#define APM_XGENE_OEM_TABLE_ID "XGENE"
++#define APM_XGENE_OEM_REV 0x00000002
++
++struct xgene_pcie_acpi_root {
++ void __iomem *csr_base;
++ u32 version;
++};
++
++static acpi_status xgene_pcie_find_csr_base(struct acpi_resource *acpi_res,
++ void *data)
++{
++ struct xgene_pcie_acpi_root *root = data;
++ struct acpi_resource_fixed_memory32 *fixed32;
++
++ if (acpi_res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
++ fixed32 = &acpi_res->data.fixed_memory32;
++ root->csr_base = ioremap(fixed32->address,
++ fixed32->address_length);
++ return AE_CTRL_TERMINATE;
++ }
++
++ return AE_OK;
++}
++
++static int xgene_pcie_ecam_init(struct pci_config_window *cfg)
++{
++ struct xgene_pcie_acpi_root *xgene_root;
++ struct device *dev = cfg->parent;
++ struct acpi_device *adev = to_acpi_device(dev);
++ acpi_handle handle = acpi_device_handle(adev);
++
++ xgene_root = devm_kzalloc(dev, sizeof(*xgene_root), GFP_KERNEL);
++ if (!xgene_root)
++ return -ENOMEM;
++
++ acpi_walk_resources(handle, METHOD_NAME__CRS,
++ xgene_pcie_find_csr_base, xgene_root);
++
++ if (!xgene_root->csr_base) {
++ kfree(xgene_root);
++ return -ENODEV;
++ }
++
++ xgene_root->version = XGENE_PCIE_IP_VER_1;
++
++ cfg->priv = xgene_root;
++
++ return 0;
++}
++
++/*
++ * For Configuration request, RTDID register is used as Bus Number,
++ * Device Number and Function number of the header fields.
++ */
++static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn)
++{
++ struct pci_config_window *cfg = bus->sysdata;
++ struct xgene_pcie_acpi_root *port = cfg->priv;
++ unsigned int b, d, f;
++ u32 rtdid_val = 0;
++
++ b = bus->number;
++ d = PCI_SLOT(devfn);
++ f = PCI_FUNC(devfn);
++
++ if (!pci_is_root_bus(bus))
++ rtdid_val = (b << 8) | (d << 3) | f;
++
++ writel(rtdid_val, port->csr_base + RTDID);
++ /* read the register back to ensure flush */
++ readl(port->csr_base + RTDID);
++}
++
++/*
++ * X-Gene PCIe port uses BAR0-BAR1 of RC's configuration space as
++ * the translation from PCI bus to native BUS. Entire DDR region
++ * is mapped into PCIe space using these registers, so it can be
++ * reached by DMA from EP devices. The BAR0/1 of bridge should be
++ * hidden during enumeration to avoid the sizing and resource allocation
++ * by PCIe core.
++ */
++static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
++{
++ if (pci_is_root_bus(bus) && ((offset == PCI_BASE_ADDRESS_0) ||
++ (offset == PCI_BASE_ADDRESS_1)))
++ return true;
++
++ return false;
++}
++
++void __iomem *xgene_pcie_ecam_map_bus(struct pci_bus *bus,
++ unsigned int devfn, int where)
++{
++ struct pci_config_window *cfg = bus->sysdata;
++ unsigned int busn = bus->number;
++ void __iomem *base;
++
++ if (busn < cfg->busr.start || busn > cfg->busr.end)
++ return NULL;
++
++ if ((pci_is_root_bus(bus) && devfn != 0) ||
++ xgene_pcie_hide_rc_bars(bus, where))
++ return NULL;
++
++ xgene_pcie_set_rtdid_reg(bus, devfn);
++
++ if (busn > cfg->busr.start)
++ base = cfg->win + (1 << cfg->ops->bus_shift);
++ else
++ base = cfg->win;
++
++ return base + where;
++}
++
++static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 *val)
++{
++ struct pci_config_window *cfg = bus->sysdata;
++ struct xgene_pcie_acpi_root *port = cfg->priv;
++
++ if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) !=
++ PCIBIOS_SUCCESSFUL)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++
++ /*
++ * The v1 controller has a bug in its Configuration Request
++ * Retry Status (CRS) logic: when CRS is enabled and we read the
++ * Vendor and Device ID of a non-existent device, the controller
++ * fabricates return data of 0xFFFF0001 ("device exists but is not
++ * ready") instead of 0xFFFFFFFF ("device does not exist"). This
++ * causes the PCI core to retry the read until it times out.
++ * Avoid this by not claiming to support CRS.
++ */
++ if (pci_is_root_bus(bus) && (port->version == XGENE_PCIE_IP_VER_1) &&
++ ((where & ~0x3) == ROOT_CAP_AND_CTRL))
++ *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
++
++ if (size <= 2)
++ *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ecam_ops xgene_pcie_ecam_ops = {
++ .bus_shift = 16,
++ .init = xgene_pcie_ecam_init,
++ .pci_ops = {
++ .map_bus = xgene_pcie_ecam_map_bus,
++ .read = xgene_pcie_config_read32,
++ .write = pci_generic_config_write,
++ }
++};
++
++DECLARE_ACPI_MCFG_FIXUP(&xgene_pcie_ecam_ops, APM_OEM_ID,
++ APM_XGENE_OEM_TABLE_ID, APM_XGENE_OEM_REV,
++ PCI_MCFG_DOMAIN_ANY, PCI_MCFG_BUS_ANY);
++#endif
+--
+2.7.4
+
diff --git a/kernel.spec b/kernel.spec
index d2eb20644..dfd06654e 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -506,6 +506,9 @@ Patch422: geekbox-v4-device-tree-support.patch
# This has major conflicts and needs to be rebased
# Patch423: Initial-AllWinner-A64-and-PINE64-support.patch
+Patch424: arm64-pcie-acpi.patch
+Patch425: arm64-pcie-quirks-xgene.patch
+
# http://www.spinics.net/lists/linux-tegra/msg26029.html
Patch426: usb-phy-tegra-Add-38.4MHz-clock-table-entry.patch
@@ -2159,6 +2162,9 @@ fi
#
#
%changelog
+* Tue Jul 19 2016 Peter Robinson <pbrobinson@fedoraproject.org>
+- Add aarch64 ACPI pci-e patches headed for 4.8
+
* Mon Jul 18 2016 Laura Abbott <labbott@redhat.com> - 4.7.0-0.rc7.git4.1
- Linux v4.7-rc7-92-g47ef4ad