a84c022
From 1fc02559de87cd88339a83ad05baa9c2b5bd1ac0 Mon Sep 17 00:00:00 2001
a84c022
From: Jayachandran C <jchandra@broadcom.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:09 +0200
a84c022
Subject: [PATCH 01/11] PCI/ECAM: Move ecam.h to linux/include/pci-ecam.h
a84c022
a84c022
This header will be used from arch/arm64 for ACPI PCI implementation
a84c022
so it needs to be moved out of drivers/pci.
a84c022
a84c022
Update users of the header file to use the new name. No functional
a84c022
changes.
a84c022
a84c022
Signed-off-by: Jayachandran C <jchandra@broadcom.com>
a84c022
Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 drivers/pci/ecam.c                  |  3 +-
a84c022
 drivers/pci/ecam.h                  | 67 -------------------------------------
a84c022
 drivers/pci/host/pci-host-common.c  |  3 +-
a84c022
 drivers/pci/host/pci-host-generic.c |  3 +-
a84c022
 drivers/pci/host/pci-thunder-ecam.c |  3 +-
a84c022
 drivers/pci/host/pci-thunder-pem.c  |  3 +-
a84c022
 include/linux/pci-ecam.h            | 67 +++++++++++++++++++++++++++++++++++++
a84c022
 7 files changed, 72 insertions(+), 77 deletions(-)
a84c022
 delete mode 100644 drivers/pci/ecam.h
a84c022
 create mode 100644 include/linux/pci-ecam.h
a84c022
a84c022
diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c
a84c022
index f9832ad..820e26b 100644
a84c022
--- a/drivers/pci/ecam.c
a84c022
+++ b/drivers/pci/ecam.c
a84c022
@@ -19,10 +19,9 @@
a84c022
 #include <linux/kernel.h>
a84c022
 #include <linux/module.h>
a84c022
 #include <linux/pci.h>
a84c022
+#include <linux/pci-ecam.h>
a84c022
 #include <linux/slab.h>
a84c022
 
a84c022
-#include "ecam.h"
a84c022
-
a84c022
 /*
a84c022
  * On 64-bit systems, we do a single ioremap for the whole config space
a84c022
  * since we have enough virtual address range available.  On 32-bit, we
a84c022
diff --git a/drivers/pci/ecam.h b/drivers/pci/ecam.h
a84c022
deleted file mode 100644
a84c022
index 9878beb..0000000
a84c022
--- a/drivers/pci/ecam.h
a84c022
+++ /dev/null
a84c022
@@ -1,67 +0,0 @@
a84c022
-/*
a84c022
- * Copyright 2016 Broadcom
a84c022
- *
a84c022
- * This program is free software; you can redistribute it and/or modify
a84c022
- * it under the terms of the GNU General Public License, version 2, as
a84c022
- * published by the Free Software Foundation (the "GPL").
a84c022
- *
a84c022
- * This program is distributed in the hope that it will be useful, but
a84c022
- * WITHOUT ANY WARRANTY; without even the implied warranty of
a84c022
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
a84c022
- * General Public License version 2 (GPLv2) for more details.
a84c022
- *
a84c022
- * You should have received a copy of the GNU General Public License
a84c022
- * version 2 (GPLv2) along with this source code.
a84c022
- */
a84c022
-#ifndef DRIVERS_PCI_ECAM_H
a84c022
-#define DRIVERS_PCI_ECAM_H
a84c022
-
a84c022
-#include <linux/kernel.h>
a84c022
-#include <linux/platform_device.h>
a84c022
-
a84c022
-/*
a84c022
- * struct to hold pci ops and bus shift of the config window
a84c022
- * for a PCI controller.
a84c022
- */
a84c022
-struct pci_config_window;
a84c022
-struct pci_ecam_ops {
a84c022
-	unsigned int			bus_shift;
a84c022
-	struct pci_ops			pci_ops;
a84c022
-	int				(*init)(struct device *,
a84c022
-						struct pci_config_window *);
a84c022
-};
a84c022
-
a84c022
-/*
a84c022
- * struct to hold the mappings of a config space window. This
a84c022
- * is expected to be used as sysdata for PCI controllers that
a84c022
- * use ECAM.
a84c022
- */
a84c022
-struct pci_config_window {
a84c022
-	struct resource			res;
a84c022
-	struct resource			busr;
a84c022
-	void				*priv;
a84c022
-	struct pci_ecam_ops		*ops;
a84c022
-	union {
a84c022
-		void __iomem		*win;	/* 64-bit single mapping */
a84c022
-		void __iomem		**winp; /* 32-bit per-bus mapping */
a84c022
-	};
a84c022
-};
a84c022
-
a84c022
-/* create and free pci_config_window */
a84c022
-struct pci_config_window *pci_ecam_create(struct device *dev,
a84c022
-		struct resource *cfgres, struct resource *busr,
a84c022
-		struct pci_ecam_ops *ops);
a84c022
-void pci_ecam_free(struct pci_config_window *cfg);
a84c022
-
a84c022
-/* map_bus when ->sysdata is an instance of pci_config_window */
a84c022
-void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
a84c022
-			       int where);
a84c022
-/* default ECAM ops */
a84c022
-extern struct pci_ecam_ops pci_generic_ecam_ops;
a84c022
-
a84c022
-#ifdef CONFIG_PCI_HOST_GENERIC
a84c022
-/* for DT-based PCI controllers that support ECAM */
a84c022
-int pci_host_common_probe(struct platform_device *pdev,
a84c022
-			  struct pci_ecam_ops *ops);
a84c022
-#endif
a84c022
-#endif
a84c022
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
a84c022
index 8cba7ab..c18b9e3 100644
a84c022
--- a/drivers/pci/host/pci-host-common.c
a84c022
+++ b/drivers/pci/host/pci-host-common.c
a84c022
@@ -20,10 +20,9 @@
a84c022
 #include <linux/module.h>
a84c022
 #include <linux/of_address.h>
a84c022
 #include <linux/of_pci.h>
a84c022
+#include <linux/pci-ecam.h>
a84c022
 #include <linux/platform_device.h>
a84c022
 
a84c022
-#include "../ecam.h"
a84c022
-
a84c022
 static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
a84c022
 		       struct list_head *resources, struct resource **bus_range)
a84c022
 {
a84c022
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
a84c022
index 6eaceab..f0ca6de 100644
a84c022
--- a/drivers/pci/host/pci-host-generic.c
a84c022
+++ b/drivers/pci/host/pci-host-generic.c
a84c022
@@ -23,10 +23,9 @@
a84c022
 #include <linux/module.h>
a84c022
 #include <linux/of_address.h>
a84c022
 #include <linux/of_pci.h>
a84c022
+#include <linux/pci-ecam.h>
a84c022
 #include <linux/platform_device.h>
a84c022
 
a84c022
-#include "../ecam.h"
a84c022
-
a84c022
 static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
a84c022
 	.bus_shift	= 16,
a84c022
 	.pci_ops	= {
a84c022
diff --git a/drivers/pci/host/pci-thunder-ecam.c b/drivers/pci/host/pci-thunder-ecam.c
a84c022
index 540d030..a9fc1c9 100644
a84c022
--- a/drivers/pci/host/pci-thunder-ecam.c
a84c022
+++ b/drivers/pci/host/pci-thunder-ecam.c
a84c022
@@ -11,10 +11,9 @@
a84c022
 #include <linux/ioport.h>
a84c022
 #include <linux/of_pci.h>
a84c022
 #include <linux/of.h>
a84c022
+#include <linux/pci-ecam.h>
a84c022
 #include <linux/platform_device.h>
a84c022
 
a84c022
-#include "../ecam.h"
a84c022
-
a84c022
 static void set_val(u32 v, int where, int size, u32 *val)
a84c022
 {
a84c022
 	int shift = (where & 3) * 8;
a84c022
diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
a84c022
index 9b8ab94..5020d3d 100644
a84c022
--- a/drivers/pci/host/pci-thunder-pem.c
a84c022
+++ b/drivers/pci/host/pci-thunder-pem.c
a84c022
@@ -18,10 +18,9 @@
a84c022
 #include <linux/module.h>
a84c022
 #include <linux/of_address.h>
a84c022
 #include <linux/of_pci.h>
a84c022
+#include <linux/pci-ecam.h>
a84c022
 #include <linux/platform_device.h>
a84c022
 
a84c022
-#include "../ecam.h"
a84c022
-
a84c022
 #define PEM_CFG_WR 0x28
a84c022
 #define PEM_CFG_RD 0x30
a84c022
 
a84c022
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
a84c022
new file mode 100644
a84c022
index 0000000..9878beb
a84c022
--- /dev/null
a84c022
+++ b/include/linux/pci-ecam.h
a84c022
@@ -0,0 +1,67 @@
a84c022
+/*
a84c022
+ * Copyright 2016 Broadcom
a84c022
+ *
a84c022
+ * This program is free software; you can redistribute it and/or modify
a84c022
+ * it under the terms of the GNU General Public License, version 2, as
a84c022
+ * published by the Free Software Foundation (the "GPL").
a84c022
+ *
a84c022
+ * This program is distributed in the hope that it will be useful, but
a84c022
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
a84c022
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
a84c022
+ * General Public License version 2 (GPLv2) for more details.
a84c022
+ *
a84c022
+ * You should have received a copy of the GNU General Public License
a84c022
+ * version 2 (GPLv2) along with this source code.
a84c022
+ */
a84c022
+#ifndef DRIVERS_PCI_ECAM_H
a84c022
+#define DRIVERS_PCI_ECAM_H
a84c022
+
a84c022
+#include <linux/kernel.h>
a84c022
+#include <linux/platform_device.h>
a84c022
+
a84c022
+/*
a84c022
+ * struct to hold pci ops and bus shift of the config window
a84c022
+ * for a PCI controller.
a84c022
+ */
a84c022
+struct pci_config_window;
a84c022
+struct pci_ecam_ops {
a84c022
+	unsigned int			bus_shift;
a84c022
+	struct pci_ops			pci_ops;
a84c022
+	int				(*init)(struct device *,
a84c022
+						struct pci_config_window *);
a84c022
+};
a84c022
+
a84c022
+/*
a84c022
+ * struct to hold the mappings of a config space window. This
a84c022
+ * is expected to be used as sysdata for PCI controllers that
a84c022
+ * use ECAM.
a84c022
+ */
a84c022
+struct pci_config_window {
a84c022
+	struct resource			res;
a84c022
+	struct resource			busr;
a84c022
+	void				*priv;
a84c022
+	struct pci_ecam_ops		*ops;
a84c022
+	union {
a84c022
+		void __iomem		*win;	/* 64-bit single mapping */
a84c022
+		void __iomem		**winp; /* 32-bit per-bus mapping */
a84c022
+	};
a84c022
+};
a84c022
+
a84c022
+/* create and free pci_config_window */
a84c022
+struct pci_config_window *pci_ecam_create(struct device *dev,
a84c022
+		struct resource *cfgres, struct resource *busr,
a84c022
+		struct pci_ecam_ops *ops);
a84c022
+void pci_ecam_free(struct pci_config_window *cfg);
a84c022
+
a84c022
+/* map_bus when ->sysdata is an instance of pci_config_window */
a84c022
+void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
a84c022
+			       int where);
a84c022
+/* default ECAM ops */
a84c022
+extern struct pci_ecam_ops pci_generic_ecam_ops;
a84c022
+
a84c022
+#ifdef CONFIG_PCI_HOST_GENERIC
a84c022
+/* for DT-based PCI controllers that support ECAM */
a84c022
+int pci_host_common_probe(struct platform_device *pdev,
a84c022
+			  struct pci_ecam_ops *ops);
a84c022
+#endif
a84c022
+#endif
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From 5eb9996fc097629854f359f9ad3d959fdacb7f8f Mon Sep 17 00:00:00 2001
a84c022
From: Jayachandran C <jchandra@broadcom.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:10 +0200
a84c022
Subject: [PATCH 02/11] PCI/ECAM: Add parent device field to pci_config_window
a84c022
a84c022
Add a parent device field to struct pci_config_window. The parent
a84c022
is not saved now, but will be useful to save it in some cases.
a84c022
Specifically in case of ACPI for ARM64, it can be used to setup
a84c022
ACPI companion and domain.
a84c022
a84c022
Since the parent dev is in struct pci_config_window now, we need
a84c022
not pass it to the init function as a separate argument.
a84c022
a84c022
Signed-off-by: Jayachandran C <jchandra@broadcom.com>
a84c022
Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 drivers/pci/ecam.c                 | 3 ++-
a84c022
 drivers/pci/host/pci-thunder-pem.c | 3 ++-
a84c022
 include/linux/pci-ecam.h           | 4 ++--
a84c022
 3 files changed, 6 insertions(+), 4 deletions(-)
a84c022
a84c022
diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c
a84c022
index 820e26b..66e0d71 100644
a84c022
--- a/drivers/pci/ecam.c
a84c022
+++ b/drivers/pci/ecam.c
a84c022
@@ -51,6 +51,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
a84c022
 	if (!cfg)
a84c022
 		return ERR_PTR(-ENOMEM);
a84c022
 
a84c022
+	cfg->parent = dev;
a84c022
 	cfg->ops = ops;
a84c022
 	cfg->busr.start = busr->start;
a84c022
 	cfg->busr.end = busr->end;
a84c022
@@ -94,7 +95,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
a84c022
 	}
a84c022
 
a84c022
 	if (ops->init) {
a84c022
-		err = ops->init(dev, cfg);
a84c022
+		err = ops->init(cfg);
a84c022
 		if (err)
a84c022
 			goto err_exit;
a84c022
 	}
a84c022
diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
a84c022
index 5020d3d..91f6fc6 100644
a84c022
--- a/drivers/pci/host/pci-thunder-pem.c
a84c022
+++ b/drivers/pci/host/pci-thunder-pem.c
a84c022
@@ -284,8 +284,9 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
a84c022
 	return pci_generic_config_write(bus, devfn, where, size, val);
a84c022
 }
a84c022
 
a84c022
-static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg)
a84c022
+static int thunder_pem_init(struct pci_config_window *cfg)
a84c022
 {
a84c022
+	struct device *dev = cfg->parent;
a84c022
 	resource_size_t bar4_start;
a84c022
 	struct resource *res_pem;
a84c022
 	struct thunder_pem_pci *pem_pci;
a84c022
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
a84c022
index 9878beb..7adad20 100644
a84c022
--- a/include/linux/pci-ecam.h
a84c022
+++ b/include/linux/pci-ecam.h
a84c022
@@ -27,8 +27,7 @@ struct pci_config_window;
a84c022
 struct pci_ecam_ops {
a84c022
 	unsigned int			bus_shift;
a84c022
 	struct pci_ops			pci_ops;
a84c022
-	int				(*init)(struct device *,
a84c022
-						struct pci_config_window *);
a84c022
+	int				(*init)(struct pci_config_window *);
a84c022
 };
a84c022
 
a84c022
 /*
a84c022
@@ -45,6 +44,7 @@ struct pci_config_window {
a84c022
 		void __iomem		*win;	/* 64-bit single mapping */
a84c022
 		void __iomem		**winp; /* 32-bit per-bus mapping */
a84c022
 	};
a84c022
+	struct device			*parent;/* ECAM res was from this dev */
a84c022
 };
a84c022
 
a84c022
 /* create and free pci_config_window */
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From 6ed6c1365df5c9201e9b275e8ed4eaa64ef2ec0d Mon Sep 17 00:00:00 2001
a84c022
From: Sinan Kaya <okaya@codeaurora.org>
a84c022
Date: Fri, 10 Jun 2016 21:55:11 +0200
a84c022
Subject: [PATCH 03/11] PCI: Add new function to unmap IO resources
a84c022
a84c022
We need to release I/O resources so that the same I/O resources
a84c022
can be allocated again in pci_remap_iospace(), like in PCI hotplug removal
a84c022
scenario. Therefore implement new pci_unmap_iospace() call which
a84c022
unmaps I/O space as the symmetry to pci_remap_iospace().
a84c022
a84c022
Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 drivers/pci/pci.c   | 18 ++++++++++++++++++
a84c022
 include/linux/pci.h |  1 +
a84c022
 2 files changed, 19 insertions(+)
a84c022
a84c022
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
a84c022
index c8b4dbd..eb431b5 100644
a84c022
--- a/drivers/pci/pci.c
a84c022
+++ b/drivers/pci/pci.c
a84c022
@@ -25,6 +25,7 @@
a84c022
 #include <linux/device.h>
a84c022
 #include <linux/pm_runtime.h>
a84c022
 #include <linux/pci_hotplug.h>
a84c022
+#include <linux/vmalloc.h>
a84c022
 #include <asm/setup.h>
a84c022
 #include <linux/aer.h>
a84c022
 #include "pci.h"
a84c022
@@ -3165,6 +3166,23 @@ int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
a84c022
 #endif
a84c022
 }
a84c022
 
a84c022
+/**
a84c022
+ *	pci_unmap_iospace - Unmap the memory mapped I/O space
a84c022
+ *	@res: resource to be unmapped
a84c022
+ *
a84c022
+ *	Unmap the CPU virtual address @res from virtual address space.
a84c022
+ *	Only architectures that have memory mapped IO functions defined
a84c022
+ *	(and the PCI_IOBASE value defined) should call this function.
a84c022
+ */
a84c022
+void pci_unmap_iospace(struct resource *res)
a84c022
+{
a84c022
+#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
a84c022
+	unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
a84c022
+
a84c022
+	unmap_kernel_range(vaddr, resource_size(res));
a84c022
+#endif
a84c022
+}
a84c022
+
a84c022
 static void __pci_set_master(struct pci_dev *dev, bool enable)
a84c022
 {
a84c022
 	u16 old_cmd, cmd;
a84c022
diff --git a/include/linux/pci.h b/include/linux/pci.h
a84c022
index b67e4df..12349de 100644
a84c022
--- a/include/linux/pci.h
a84c022
+++ b/include/linux/pci.h
a84c022
@@ -1167,6 +1167,7 @@ int pci_register_io_range(phys_addr_t addr, resource_size_t size);
a84c022
 unsigned long pci_address_to_pio(phys_addr_t addr);
a84c022
 phys_addr_t pci_pio_to_address(unsigned long pio);
a84c022
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
a84c022
+void pci_unmap_iospace(struct resource *res);
a84c022
 
a84c022
 static inline pci_bus_addr_t pci_bus_address(struct pci_dev *pdev, int bar)
a84c022
 {
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From 62f4d54fc2d2882b9ebaa920189574f422e12207 Mon Sep 17 00:00:00 2001
a84c022
From: Jayachandran C <jchandra@broadcom.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:12 +0200
a84c022
Subject: [PATCH 04/11] ACPI/PCI: Support IO resources when parsing PCI host
a84c022
 bridge resources
a84c022
a84c022
Platforms that have memory mapped IO port (such as ARM64) need special
a84c022
handling for PCI I/O resources. For host bridge's resource probing case
a84c022
these resources need to be fixed up with
a84c022
pci_register_io_range()/pci_remap_iospace() etc.
a84c022
a84c022
The same I/O resources need to be released after hotplug
a84c022
removal so that it can be re-added back by the pci_remap_iospace()
a84c022
function during insertion. As a consequence unmap I/O resources
a84c022
with pci_unmap_iospace() when we release host bridge resources.
a84c022
a84c022
Signed-off-by: Jayachandran C <jchandra@broadcom.com>
a84c022
Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
a84c022
[ Tomasz: merged in Sinan's patch to unmap IO resources properly, updated changelog]
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 drivers/acpi/pci_root.c | 39 +++++++++++++++++++++++++++++++++++++++
a84c022
 1 file changed, 39 insertions(+)
a84c022
a84c022
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
a84c022
index ae3fe4e..9a26dd1 100644
a84c022
--- a/drivers/acpi/pci_root.c
a84c022
+++ b/drivers/acpi/pci_root.c
a84c022
@@ -720,6 +720,40 @@ next:
a84c022
 	}
a84c022
 }
a84c022
 
a84c022
+#ifdef PCI_IOBASE
a84c022
+static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
a84c022
+{
a84c022
+	struct resource *res = entry->res;
a84c022
+	resource_size_t cpu_addr = res->start;
a84c022
+	resource_size_t pci_addr = cpu_addr - entry->offset;
a84c022
+	resource_size_t length = resource_size(res);
a84c022
+	unsigned long port;
a84c022
+
a84c022
+	if (pci_register_io_range(cpu_addr, length))
a84c022
+		goto err;
a84c022
+
a84c022
+	port = pci_address_to_pio(cpu_addr);
a84c022
+	if (port == (unsigned long)-1)
a84c022
+		goto err;
a84c022
+
a84c022
+	res->start = port;
a84c022
+	res->end = port + length - 1;
a84c022
+	entry->offset = port - pci_addr;
a84c022
+
a84c022
+	if (pci_remap_iospace(res, cpu_addr) < 0)
a84c022
+		goto err;
a84c022
+
a84c022
+	pr_info("Remapped I/O %pa to %pR\n", &cpu_addr, res);
a84c022
+	return;
a84c022
+err:
a84c022
+	res->flags |= IORESOURCE_DISABLED;
a84c022
+}
a84c022
+#else
a84c022
+static inline void acpi_pci_root_remap_iospace(struct resource_entry *entry)
a84c022
+{
a84c022
+}
a84c022
+#endif
a84c022
+
a84c022
 int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
a84c022
 {
a84c022
 	int ret;
a84c022
@@ -740,6 +774,9 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
a84c022
 			"no IO and memory resources present in _CRS\n");
a84c022
 	else {
a84c022
 		resource_list_for_each_entry_safe(entry, tmp, list) {
a84c022
+			if (entry->res->flags & IORESOURCE_IO)
a84c022
+				acpi_pci_root_remap_iospace(entry);
a84c022
+
a84c022
 			if (entry->res->flags & IORESOURCE_DISABLED)
a84c022
 				resource_list_destroy_entry(entry);
a84c022
 			else
a84c022
@@ -811,6 +848,8 @@ static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
a84c022
 
a84c022
 	resource_list_for_each_entry(entry, &bridge->windows) {
a84c022
 		res = entry->res;
a84c022
+		if (res->flags & IORESOURCE_IO)
a84c022
+			pci_unmap_iospace(res);
a84c022
 		if (res->parent &&
a84c022
 		    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
a84c022
 			release_resource(res);
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From dd4f7822d702cca83baa1de7a5f69344ffb82af9 Mon Sep 17 00:00:00 2001
a84c022
From: Tomasz Nowicki <tn@semihalf.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:13 +0200
a84c022
Subject: [PATCH 05/11] ACPI/PCI: Add generic MCFG table handling
a84c022
a84c022
According to PCI firmware specifications, on systems booting with ACPI,
a84c022
PCI configuration for a host bridge must be set-up through the MCFG table
a84c022
regions for non-hotpluggable bridges and _CBA method for hotpluggable ones.
a84c022
a84c022
Current MCFG table handling code, as implemented for x86, cannot be
a84c022
easily generalized owing to x86 specific quirks handling and related
a84c022
code, which makes it hard to reuse on other architectures.
a84c022
a84c022
In order to implement MCFG PCI configuration handling for new platforms
a84c022
booting with ACPI (eg ARM64) this patch re-implements MCFG handling from
a84c022
scratch in a streamlined fashion and provides (through a generic
a84c022
interface available to all arches):
a84c022
a84c022
- Simplified MCFG table parsing (executed through the pci_mmcfg_late_init()
a84c022
  hook as in current x86)
a84c022
- MCFG regions look-up interface through domain:bus_start:bus_end tuple
a84c022
a84c022
The new MCFG regions handling interface is added to generic ACPI code
a84c022
so that existing architectures (eg x86) can be moved over to it and
a84c022
architectures relying on MCFG for ACPI PCI config space can rely on it
a84c022
without having to resort to arch specific implementations.
a84c022
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Signed-off-by: Jayachandran C <jchandra@broadcom.com>
a84c022
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 drivers/acpi/Kconfig     |  3 ++
a84c022
 drivers/acpi/Makefile    |  1 +
a84c022
 drivers/acpi/pci_mcfg.c  | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
a84c022
 include/linux/pci-acpi.h |  2 ++
a84c022
 include/linux/pci.h      |  2 +-
a84c022
 5 files changed, 99 insertions(+), 1 deletion(-)
a84c022
 create mode 100644 drivers/acpi/pci_mcfg.c
a84c022
a84c022
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
a84c022
index b7e2e77..f98c328 100644
a84c022
--- a/drivers/acpi/Kconfig
a84c022
+++ b/drivers/acpi/Kconfig
a84c022
@@ -217,6 +217,9 @@ config ACPI_PROCESSOR_IDLE
a84c022
 	bool
a84c022
 	select CPU_IDLE
a84c022
 
a84c022
+config ACPI_MCFG
a84c022
+	bool
a84c022
+
a84c022
 config ACPI_CPPC_LIB
a84c022
 	bool
a84c022
 	depends on ACPI_PROCESSOR
a84c022
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
a84c022
index 251ce85..632e81f 100644
a84c022
--- a/drivers/acpi/Makefile
a84c022
+++ b/drivers/acpi/Makefile
a84c022
@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
a84c022
 acpi-y				+= ec.o
a84c022
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
a84c022
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
a84c022
+obj-$(CONFIG_ACPI_MCFG)		+= pci_mcfg.o
a84c022
 acpi-y				+= acpi_lpss.o acpi_apd.o
a84c022
 acpi-y				+= acpi_platform.o
a84c022
 acpi-y				+= acpi_pnp.o
a84c022
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
a84c022
new file mode 100644
a84c022
index 0000000..d3c3e85
a84c022
--- /dev/null
a84c022
+++ b/drivers/acpi/pci_mcfg.c
a84c022
@@ -0,0 +1,92 @@
a84c022
+/*
a84c022
+ * Copyright (C) 2016 Broadcom
a84c022
+ *	Author: Jayachandran C <jchandra@broadcom.com>
a84c022
+ * Copyright (C) 2016 Semihalf
a84c022
+ * 	Author: Tomasz Nowicki <tn@semihalf.com>
a84c022
+ *
a84c022
+ * This program is free software; you can redistribute it and/or modify
a84c022
+ * it under the terms of the GNU General Public License, version 2, as
a84c022
+ * published by the Free Software Foundation (the "GPL").
a84c022
+ *
a84c022
+ * This program is distributed in the hope that it will be useful, but
a84c022
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
a84c022
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
a84c022
+ * General Public License version 2 (GPLv2) for more details.
a84c022
+ *
a84c022
+ * You should have received a copy of the GNU General Public License
a84c022
+ * version 2 (GPLv2) along with this source code.
a84c022
+ */
a84c022
+
a84c022
+#define pr_fmt(fmt) "ACPI: " fmt
a84c022
+
a84c022
+#include <linux/kernel.h>
a84c022
+#include <linux/pci.h>
a84c022
+#include <linux/pci-acpi.h>
a84c022
+
a84c022
+/* Structure to hold entries from the MCFG table */
a84c022
+struct mcfg_entry {
a84c022
+	struct list_head	list;
a84c022
+	phys_addr_t		addr;
a84c022
+	u16			segment;
a84c022
+	u8			bus_start;
a84c022
+	u8			bus_end;
a84c022
+};
a84c022
+
a84c022
+/* List to save mcfg entries */
a84c022
+static LIST_HEAD(pci_mcfg_list);
a84c022
+
a84c022
+phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
a84c022
+{
a84c022
+	struct mcfg_entry *e;
a84c022
+
a84c022
+	/*
a84c022
+	 * We expect exact match, unless MCFG entry end bus covers more than
a84c022
+	 * specified by caller.
a84c022
+	 */
a84c022
+	list_for_each_entry(e, &pci_mcfg_list, list) {
a84c022
+		if (e->segment == seg && e->bus_start == bus_res->start &&
a84c022
+		    e->bus_end >= bus_res->end)
a84c022
+			return e->addr;
a84c022
+	}
a84c022
+
a84c022
+	return 0;
a84c022
+}
a84c022
+
a84c022
+static __init int pci_mcfg_parse(struct acpi_table_header *header)
a84c022
+{
a84c022
+	struct acpi_table_mcfg *mcfg;
a84c022
+	struct acpi_mcfg_allocation *mptr;
a84c022
+	struct mcfg_entry *e, *arr;
a84c022
+	int i, n;
a84c022
+
a84c022
+	if (header->length < sizeof(struct acpi_table_mcfg))
a84c022
+		return -EINVAL;
a84c022
+
a84c022
+	n = (header->length - sizeof(struct acpi_table_mcfg)) /
a84c022
+					sizeof(struct acpi_mcfg_allocation);
a84c022
+	mcfg = (struct acpi_table_mcfg *)header;
a84c022
+	mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
a84c022
+
a84c022
+	arr = kcalloc(n, sizeof(*arr), GFP_KERNEL);
a84c022
+	if (!arr)
a84c022
+		return -ENOMEM;
a84c022
+
a84c022
+	for (i = 0, e = arr; i < n; i++, mptr++, e++) {
a84c022
+		e->segment = mptr->pci_segment;
a84c022
+		e->addr =  mptr->address;
a84c022
+		e->bus_start = mptr->start_bus_number;
a84c022
+		e->bus_end = mptr->end_bus_number;
a84c022
+		list_add(&e->list, &pci_mcfg_list);
a84c022
+	}
a84c022
+
a84c022
+	pr_info("MCFG table detected, %d entries\n", n);
a84c022
+	return 0;
a84c022
+}
a84c022
+
a84c022
+/* Interface called by ACPI - parse and save MCFG table */
a84c022
+void __init pci_mmcfg_late_init(void)
a84c022
+{
a84c022
+	int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
a84c022
+	if (err)
a84c022
+		pr_err("Failed to parse MCFG (%d)\n", err);
a84c022
+}
a84c022
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
a84c022
index 89ab057..7d63a66 100644
a84c022
--- a/include/linux/pci-acpi.h
a84c022
+++ b/include/linux/pci-acpi.h
a84c022
@@ -24,6 +24,8 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
a84c022
 }
a84c022
 extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
a84c022
 
a84c022
+extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res);
a84c022
+
a84c022
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
a84c022
 {
a84c022
 	struct pci_bus *pbus = pdev->bus;
a84c022
diff --git a/include/linux/pci.h b/include/linux/pci.h
a84c022
index 12349de..ce03d65 100644
a84c022
--- a/include/linux/pci.h
a84c022
+++ b/include/linux/pci.h
a84c022
@@ -1723,7 +1723,7 @@ void pcibios_free_irq(struct pci_dev *dev);
a84c022
 extern struct dev_pm_ops pcibios_pm_ops;
a84c022
 #endif
a84c022
 
a84c022
-#ifdef CONFIG_PCI_MMCONFIG
a84c022
+#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG)
a84c022
 void __init pci_mmcfg_early_init(void);
a84c022
 void __init pci_mmcfg_late_init(void);
a84c022
 #else
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From fc1907f9c79f9a0a0c2f4d579896e678915fec48 Mon Sep 17 00:00:00 2001
a84c022
From: Tomasz Nowicki <tn@semihalf.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:14 +0200
a84c022
Subject: [PATCH 06/11] PCI: Refactor generic bus domain assignment
a84c022
a84c022
Change the way PCI bus domain number is assigned and improve function
a84c022
name to reflect what function does. No functional changes.
a84c022
a84c022
Instead of assigning bus domain number inside of pci_bus_assign_domain_nr()
a84c022
simply return domain number and let pci_create_root_bus() do assignment.
a84c022
This way pci_create_root_bus() setups bus structure data in the consistent
a84c022
way. Since pci_bus_assign_domain_nr() now does not assign but retrieves
a84c022
domain number instead, rename it to pci_bus_find_domain_nr().
a84c022
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 drivers/pci/pci.c   | 4 ++--
a84c022
 drivers/pci/probe.c | 4 +++-
a84c022
 include/linux/pci.h | 7 +------
a84c022
 3 files changed, 6 insertions(+), 9 deletions(-)
a84c022
a84c022
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
a84c022
index eb431b5..b9a7833 100644
a84c022
--- a/drivers/pci/pci.c
a84c022
+++ b/drivers/pci/pci.c
a84c022
@@ -4941,7 +4941,7 @@ int pci_get_new_domain_nr(void)
a84c022
 }
a84c022
 
a84c022
 #ifdef CONFIG_PCI_DOMAINS_GENERIC
a84c022
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
a84c022
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
a84c022
 {
a84c022
 	static int use_dt_domains = -1;
a84c022
 	int domain = -1;
a84c022
@@ -4985,7 +4985,7 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
a84c022
 		domain = -1;
a84c022
 	}
a84c022
 
a84c022
-	bus->domain_nr = domain;
a84c022
+	return domain;
a84c022
 }
a84c022
 #endif
a84c022
 #endif
a84c022
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
a84c022
index 8e3ef72..380d46d 100644
a84c022
--- a/drivers/pci/probe.c
a84c022
+++ b/drivers/pci/probe.c
a84c022
@@ -2127,7 +2127,9 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
a84c022
 	b->sysdata = sysdata;
a84c022
 	b->ops = ops;
a84c022
 	b->number = b->busn_res.start = bus;
a84c022
-	pci_bus_assign_domain_nr(b, parent);
a84c022
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
a84c022
+	b->domain_nr = pci_bus_find_domain_nr(b, parent);
a84c022
+#endif
a84c022
 	b2 = pci_find_bus(pci_domain_nr(b), bus);
a84c022
 	if (b2) {
a84c022
 		/* If we already got to this bus through a different bridge, ignore it */
a84c022
diff --git a/include/linux/pci.h b/include/linux/pci.h
a84c022
index ce03d65..48839e8 100644
a84c022
--- a/include/linux/pci.h
a84c022
+++ b/include/linux/pci.h
a84c022
@@ -1390,12 +1390,7 @@ static inline int pci_domain_nr(struct pci_bus *bus)
a84c022
 {
a84c022
 	return bus->domain_nr;
a84c022
 }
a84c022
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
a84c022
-#else
a84c022
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
a84c022
-					struct device *parent)
a84c022
-{
a84c022
-}
a84c022
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent);
a84c022
 #endif
a84c022
 
a84c022
 /* some architectures require additional setup to direct VGA traffic */
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From d6d45ae1d58658111d5e838c41b9ed4729bbb81e Mon Sep 17 00:00:00 2001
a84c022
From: Tomasz Nowicki <tn@semihalf.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:15 +0200
a84c022
Subject: [PATCH 07/11] PCI: Factor DT specific pci_bus_find_domain_nr() code
a84c022
 out
a84c022
a84c022
pci_bus_find_domain_nr() retrieves the host bridge domain number in a DT
a84c022
specific way. Factor our pci_bus_find_domain_nr() in a separate DT
a84c022
function (ie of_pci_bus_find_domain_nr()) so that DT code is self
a84c022
contained, paving the way for retrieving domain number in
a84c022
pci_bus_find_domain_nr() with additional firmware methods (ie ACPI).
a84c022
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 drivers/pci/pci.c | 7 ++++++-
a84c022
 1 file changed, 6 insertions(+), 1 deletion(-)
a84c022
a84c022
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
a84c022
index b9a7833..97f7cd4 100644
a84c022
--- a/drivers/pci/pci.c
a84c022
+++ b/drivers/pci/pci.c
a84c022
@@ -4941,7 +4941,7 @@ int pci_get_new_domain_nr(void)
a84c022
 }
a84c022
 
a84c022
 #ifdef CONFIG_PCI_DOMAINS_GENERIC
a84c022
-int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
a84c022
+static int of_pci_bus_find_domain_nr(struct device *parent)
a84c022
 {
a84c022
 	static int use_dt_domains = -1;
a84c022
 	int domain = -1;
a84c022
@@ -4987,6 +4987,11 @@ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
a84c022
 
a84c022
 	return domain;
a84c022
 }
a84c022
+
a84c022
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
a84c022
+{
a84c022
+	return of_pci_bus_find_domain_nr(parent);
a84c022
+}
a84c022
 #endif
a84c022
 #endif
a84c022
 
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From 92d59511fd365d3c0c31d074b5e96cf48c58f68b Mon Sep 17 00:00:00 2001
a84c022
From: Peter Robinson <pbrobinson@gmail.com>
a84c022
Date: Thu, 30 Jun 2016 16:56:24 +0100
a84c022
Subject: [PATCH 08/11] ARM64/PCI: Add ACPI hook to assign domain number
a84c022
a84c022
PCI core code provides a config option (CONFIG_PCI_DOMAINS_GENERIC)
a84c022
that allows assigning the PCI bus domain number generically by
a84c022
relying on device tree bindings, and falling back to a simple counter
a84c022
when the respective DT properties (ie "linux,pci-domain") are not
a84c022
specified in the host bridge device tree node.
a84c022
a84c022
In a similar way, when a system is booted through ACPI, architectures
a84c022
that are selecting CONFIG_PCI_DOMAINS_GENERIC (ie ARM64) require kernel
a84c022
hooks to retrieve the domain number so that the PCI bus domain number
a84c022
set-up can be handled seamlessly with DT and ACPI in generic core code
a84c022
when CONFIG_PCI_DOMAINS_GENERIC is selected.
a84c022
a84c022
Since currently it is not possible to retrieve a pointer to the PCI
a84c022
host bridge ACPI device backing the host bridge from core PCI code
a84c022
(which would allow retrieving the domain number in an arch agnostic
a84c022
way through the ACPI _SEG method), an arch specific ACPI hook has to
a84c022
be declared and implemented by all arches that rely on
a84c022
CONFIG_PCI_DOMAINS_GENERIC to retrieve the domain number and set it
a84c022
up in core PCI code.
a84c022
a84c022
For the aforementioned reasons, introduce acpi_pci_bus_find_domain_nr()
a84c022
hook to retrieve the domain number on a per-arch basis when the system
a84c022
boots through ACPI. ARM64 dummy implementation of the same is provided
a84c022
in first place in preparation for ARM64 ACPI based PCI host controller
a84c022
driver.
a84c022
a84c022
acpi_pci_bus_find_domain_nr() is called from generic
a84c022
pci_bus_find_domain_nr() as an ACPI option to DT domain assignment.
a84c022
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 arch/arm64/kernel/pci.c | 7 +++++++
a84c022
 drivers/pci/pci.c       | 4 +++-
a84c022
 include/linux/pci.h     | 7 +++++++
a84c022
 3 files changed, 17 insertions(+), 1 deletion(-)
a84c022
a84c022
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
a84c022
index 3c4e308..d5d3d26 100644
a84c022
--- a/arch/arm64/kernel/pci.c
a84c022
+++ b/arch/arm64/kernel/pci.c
a84c022
@@ -17,6 +17,7 @@
a84c022
 #include <linux/mm.h>
a84c022
 #include <linux/of_pci.h>
a84c022
 #include <linux/of_platform.h>
a84c022
+#include <linux/pci.h>
a84c022
 #include <linux/slab.h>
a84c022
 
a84c022
 /*
a84c022
@@ -85,6 +86,12 @@ EXPORT_SYMBOL(pcibus_to_node);
a84c022
 #endif
a84c022
 
a84c022
 #ifdef CONFIG_ACPI
a84c022
+
a84c022
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
a84c022
+{
a84c022
+	return 0;
a84c022
+}
a84c022
+
a84c022
 /* Root bridge scanning */
a84c022
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
a84c022
 {
a84c022
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
a84c022
index 97f7cd4..4834cee 100644
a84c022
--- a/drivers/pci/pci.c
a84c022
+++ b/drivers/pci/pci.c
a84c022
@@ -7,6 +7,7 @@
a84c022
  *	Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
a84c022
  */
a84c022
 
a84c022
+#include <linux/acpi.h>
a84c022
 #include <linux/kernel.h>
a84c022
 #include <linux/delay.h>
a84c022
 #include <linux/init.h>
a84c022
@@ -4990,7 +4991,8 @@ static int of_pci_bus_find_domain_nr(struct device *parent)
a84c022
 
a84c022
 int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
a84c022
 {
a84c022
-	return of_pci_bus_find_domain_nr(parent);
a84c022
+	return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
a84c022
+			       acpi_pci_bus_find_domain_nr(bus);
a84c022
 }
a84c022
 #endif
a84c022
 #endif
a84c022
diff --git a/include/linux/pci.h b/include/linux/pci.h
a84c022
index 48839e8..49ba8af 100644
a84c022
--- a/include/linux/pci.h
a84c022
+++ b/include/linux/pci.h
a84c022
@@ -1390,6 +1390,13 @@ static inline int pci_domain_nr(struct pci_bus *bus)
a84c022
 {
a84c022
 	return bus->domain_nr;
a84c022
 }
a84c022
+/* Arch specific ACPI hook to set-up domain number */
a84c022
+#ifdef CONFIG_ACPI
a84c022
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus);
a84c022
+#else
a84c022
+static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
a84c022
+{ return 0; }
a84c022
+#endif
a84c022
 int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent);
a84c022
 #endif
a84c022
 
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From bb06753d2e163d8100a017f06a6d9dd195d68a76 Mon Sep 17 00:00:00 2001
a84c022
From: Tomasz Nowicki <tn@semihalf.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:17 +0200
a84c022
Subject: [PATCH 09/11] ARM64/PCI: ACPI support for legacy IRQs parsing and
a84c022
 consolidation with DT code
a84c022
a84c022
To enable PCI legacy IRQs on platforms booting with ACPI, arch code
a84c022
should include ACPI specific callbacks that parse and set-up the
a84c022
device IRQ number, equivalent to the DT boot path. Owing to the current
a84c022
ACPI core scan handlers implementation, ACPI PCI legacy IRQs bindings
a84c022
cannot be parsed at device add time, since that would trigger ACPI scan
a84c022
handlers ordering issues depending on how the ACPI tables are defined.
a84c022
a84c022
To solve this problem and consolidate FW PCI legacy IRQs parsing in
a84c022
one single pcibios callback (pending final removal), this patch moves
a84c022
DT PCI IRQ parsing to the pcibios_alloc_irq() callback (called by
a84c022
PCI core code at device probe time) and adds ACPI PCI legacy IRQs
a84c022
parsing to the same callback too, so that FW PCI legacy IRQs parsing
a84c022
is confined in one single arch callback that can be easily removed
a84c022
when code parsing PCI legacy IRQs is consolidated and moved to core
a84c022
PCI code.
a84c022
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Suggested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 arch/arm64/kernel/pci.c | 11 ++++++++---
a84c022
 1 file changed, 8 insertions(+), 3 deletions(-)
a84c022
a84c022
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
a84c022
index d5d3d26..b3b8a2c 100644
a84c022
--- a/arch/arm64/kernel/pci.c
a84c022
+++ b/arch/arm64/kernel/pci.c
a84c022
@@ -51,11 +51,16 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
a84c022
 }
a84c022
 
a84c022
 /*
a84c022
- * Try to assign the IRQ number from DT when adding a new device
a84c022
+ * Try to assign the IRQ number when probing a new device
a84c022
  */
a84c022
-int pcibios_add_device(struct pci_dev *dev)
a84c022
+int pcibios_alloc_irq(struct pci_dev *dev)
a84c022
 {
a84c022
-	dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
a84c022
+	if (acpi_disabled)
a84c022
+		dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
a84c022
+#ifdef CONFIG_ACPI
a84c022
+	else
a84c022
+		return acpi_pci_irq_enable(dev);
a84c022
+#endif
a84c022
 
a84c022
 	return 0;
a84c022
 }
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From b6e298840f532192a589f8ade128dec3fef3a4c6 Mon Sep 17 00:00:00 2001
a84c022
From: Tomasz Nowicki <tn@semihalf.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:18 +0200
a84c022
Subject: [PATCH 10/11] ARM64/PCI: Implement ACPI low-level calls to access
a84c022
 PCI_Config region from AML
a84c022
a84c022
ACPI spec6.1 - chapter: 5.5.2.4 defines OperationRegion (Declare Operation
a84c022
Region). Following the spec: " [...] An Operation Region is a specific
a84c022
region of operation within an address space that is declared as a subset
a84c022
of the entire address space using a starting address (offset) and a length.
a84c022
Control methods must have exclusive access to any address accessed via
a84c022
fields declared in Operation Regions. [...]".
a84c022
a84c022
OperationRegion allows to declare various of operation region address space
a84c022
identifiers including PCI_Config. PCI_Config is meant to access PCI
a84c022
configuration space from the ASL. So every time ASL opcode operates
a84c022
on PCI_Config space region, ASL interpreter dispatches accesses to OS
a84c022
low-level calls - raw_pci_write() and raw_pci_read() for Linux - so-called
a84c022
ACPI RAW accessors.
a84c022
a84c022
In order to support PCI_Config operation region, implement mentioned
a84c022
raw_pci_write() and raw_pci_read() calls so they find associated bus
a84c022
and call read/write ops.
a84c022
a84c022
Waiting for clarification in the ACPI specifications in relation
a84c022
to PCI_Config space handling before PCI bus enumeration is completed,
a84c022
current code does not support PCI_Config region accesses before PCI bus
a84c022
enumeration whilst providing full AML PCI_Config access availability
a84c022
when the PCI bus enumeration is completed by the kernel so that
a84c022
RAW accessors can look-up PCI operations through the struct pci_bus
a84c022
associated with a PCI bus.
a84c022
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Signed-off-by: Jayachandran C <jchandra@broadcom.com>
a84c022
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 arch/arm64/kernel/pci.c | 12 ++++++++++--
a84c022
 1 file changed, 10 insertions(+), 2 deletions(-)
a84c022
a84c022
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
a84c022
index b3b8a2c..328f857 100644
a84c022
--- a/arch/arm64/kernel/pci.c
a84c022
+++ b/arch/arm64/kernel/pci.c
a84c022
@@ -71,13 +71,21 @@ int pcibios_alloc_irq(struct pci_dev *dev)
a84c022
 int raw_pci_read(unsigned int domain, unsigned int bus,
a84c022
 		  unsigned int devfn, int reg, int len, u32 *val)
a84c022
 {
a84c022
-	return -ENXIO;
a84c022
+	struct pci_bus *b = pci_find_bus(domain, bus);
a84c022
+
a84c022
+	if (!b)
a84c022
+		return PCIBIOS_DEVICE_NOT_FOUND;
a84c022
+	return b->ops->read(b, devfn, reg, len, val);
a84c022
 }
a84c022
 
a84c022
 int raw_pci_write(unsigned int domain, unsigned int bus,
a84c022
 		unsigned int devfn, int reg, int len, u32 val)
a84c022
 {
a84c022
-	return -ENXIO;
a84c022
+	struct pci_bus *b = pci_find_bus(domain, bus);
a84c022
+
a84c022
+	if (!b)
a84c022
+		return PCIBIOS_DEVICE_NOT_FOUND;
a84c022
+	return b->ops->write(b, devfn, reg, len, val);
a84c022
 }
a84c022
 
a84c022
 #ifdef CONFIG_NUMA
a84c022
-- 
a84c022
2.7.4
a84c022
a84c022
From 3b8cff3fa89ba3ef6f1cf09a0667aa470b7fad0b Mon Sep 17 00:00:00 2001
a84c022
From: Tomasz Nowicki <tn@semihalf.com>
a84c022
Date: Fri, 10 Jun 2016 21:55:19 +0200
a84c022
Subject: [PATCH 11/11] ARM64/PCI: Support for ACPI based PCI host controller
a84c022
a84c022
Implement pci_acpi_scan_root and other arch-specific call so that ARM64
a84c022
can start using ACPI to setup and enumerate PCI buses.
a84c022
a84c022
Prior to buses enumeration the pci_acpi_scan_root() implementation looks
a84c022
for configuration space start address (obtained through ACPI _CBA method or
a84c022
MCFG interface). If succeed, it uses ECAM library to create new mapping.
a84c022
Then it attaches generic ECAM ops (pci_generic_ecam_ops) which are used
a84c022
for accessing configuration space later on.
a84c022
a84c022
On ARM64, we need to use generic domains (CONFIG_PCI_DOMAINS_GENERIC).
a84c022
In order to achieve that for ACPI case implement
a84c022
acpi_pci_bus_find_domain_nr() body so that it retrieves pci_config_window
a84c022
structure from bus sysdata and eventually gets domain number from
a84c022
acpi_pci_root structure.
a84c022
a84c022
ACPI requires to run acpi_pci_{add|remove}_bus while new PCI bus is created.
a84c022
This allows to do some ACPI-specific additional configuration, like
a84c022
PCI hotplug slot enumeration. In order to fulfill these requirements,
a84c022
we implement arch-specific pcibios_{add|remove}_bus calls
a84c022
and call acpi_pci_{add|remove}_bus from there.
a84c022
a84c022
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
a84c022
Signed-off-by: Jayachandran C <jchandra@broadcom.com>
a84c022
Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
a84c022
---
a84c022
 arch/arm64/Kconfig      |   2 +
a84c022
 arch/arm64/kernel/pci.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++--
a84c022
 2 files changed, 115 insertions(+), 3 deletions(-)
a84c022
a84c022
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
a84c022
index 5a0a691..4806cde 100644
a84c022
--- a/arch/arm64/Kconfig
a84c022
+++ b/arch/arm64/Kconfig
a84c022
@@ -3,6 +3,7 @@ config ARM64
a84c022
 	select ACPI_CCA_REQUIRED if ACPI
a84c022
 	select ACPI_GENERIC_GSI if ACPI
a84c022
 	select ACPI_REDUCED_HARDWARE_ONLY if ACPI
a84c022
+	select ACPI_MCFG if ACPI
a84c022
 	select ARCH_HAS_DEVMEM_IS_ALLOWED
a84c022
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
a84c022
 	select ARCH_HAS_ELF_RANDOMIZE
a84c022
@@ -96,6 +97,7 @@ config ARM64
a84c022
 	select OF_EARLY_FLATTREE
a84c022
 	select OF_NUMA if NUMA && OF
a84c022
 	select OF_RESERVED_MEM
a84c022
+	select PCI_ECAM if ACPI
a84c022
 	select PERF_USE_VMALLOC
a84c022
 	select POWER_RESET
a84c022
 	select POWER_SUPPLY
a84c022
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
a84c022
index 328f857..94cd43c 100644
a84c022
--- a/arch/arm64/kernel/pci.c
a84c022
+++ b/arch/arm64/kernel/pci.c
a84c022
@@ -18,6 +18,8 @@
a84c022
 #include <linux/of_pci.h>
a84c022
 #include <linux/of_platform.h>
a84c022
 #include <linux/pci.h>
a84c022
+#include <linux/pci-acpi.h>
a84c022
+#include <linux/pci-ecam.h>
a84c022
 #include <linux/slab.h>
a84c022
 
a84c022
 /*
a84c022
@@ -100,15 +102,123 @@ EXPORT_SYMBOL(pcibus_to_node);
a84c022
 
a84c022
 #ifdef CONFIG_ACPI
a84c022
 
a84c022
+struct acpi_pci_generic_root_info {
a84c022
+	struct acpi_pci_root_info	common;
a84c022
+	struct pci_config_window	*cfg;	/* config space mapping */
a84c022
+};
a84c022
+
a84c022
 int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
a84c022
 {
a84c022
+	struct pci_config_window *cfg = bus->sysdata;
a84c022
+	struct acpi_device *adev = to_acpi_device(cfg->parent);
a84c022
+	struct acpi_pci_root *root = acpi_driver_data(adev);
a84c022
+
a84c022
+	return root->segment;
a84c022
+}
a84c022
+
a84c022
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
a84c022
+{
a84c022
+	if (!acpi_disabled) {
a84c022
+		struct pci_config_window *cfg = bridge->bus->sysdata;
a84c022
+		struct acpi_device *adev = to_acpi_device(cfg->parent);
a84c022
+		ACPI_COMPANION_SET(&bridge->dev, adev);
a84c022
+	}
a84c022
+
a84c022
 	return 0;
a84c022
 }
a84c022
 
a84c022
-/* Root bridge scanning */
a84c022
+/*
a84c022
+ * Lookup the bus range for the domain in MCFG, and set up config space
a84c022
+ * mapping.
a84c022
+ */
a84c022
+static struct pci_config_window *
a84c022
+pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
a84c022
+{
a84c022
+	struct resource *bus_res = &root->secondary;
a84c022
+	u16 seg = root->segment;
a84c022
+	struct pci_config_window *cfg;
a84c022
+	struct resource cfgres;
a84c022
+	unsigned int bsz;
a84c022
+
a84c022
+	/* Use address from _CBA if present, otherwise lookup MCFG */
a84c022
+	if (!root->mcfg_addr)
a84c022
+		root->mcfg_addr = pci_mcfg_lookup(seg, bus_res);
a84c022
+
a84c022
+	if (!root->mcfg_addr) {
a84c022
+		dev_err(&root->device->dev, "%04x:%pR ECAM region not found\n",
a84c022
+			seg, bus_res);
a84c022
+		return NULL;
a84c022
+	}
a84c022
+
a84c022
+	bsz = 1 << pci_generic_ecam_ops.bus_shift;
a84c022
+	cfgres.start = root->mcfg_addr + bus_res->start * bsz;
a84c022
+	cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1;
a84c022
+	cfgres.flags = IORESOURCE_MEM;
a84c022
+	cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res,
a84c022
+			      &pci_generic_ecam_ops);
a84c022
+	if (IS_ERR(cfg)) {
a84c022
+		dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n",
a84c022
+			seg, bus_res, PTR_ERR(cfg));
a84c022
+		return NULL;
a84c022
+	}
a84c022
+
a84c022
+	return cfg;
a84c022
+}
a84c022
+
a84c022
+/* release_info: free resources allocated by init_info */
a84c022
+static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
a84c022
+{
a84c022
+	struct acpi_pci_generic_root_info *ri;
a84c022
+
a84c022
+	ri = container_of(ci, struct acpi_pci_generic_root_info, common);
a84c022
+	pci_ecam_free(ri->cfg);
a84c022
+	kfree(ri);
a84c022
+}
a84c022
+
a84c022
+static struct acpi_pci_root_ops acpi_pci_root_ops = {
a84c022
+	.release_info = pci_acpi_generic_release_info,
a84c022
+};
a84c022
+
a84c022
+/* Interface called from ACPI code to setup PCI host controller */
a84c022
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
a84c022
 {
a84c022
-	/* TODO: Should be revisited when implementing PCI on ACPI */
a84c022
-	return NULL;
a84c022
+	int node = acpi_get_node(root->device->handle);
a84c022
+	struct acpi_pci_generic_root_info *ri;
a84c022
+	struct pci_bus *bus, *child;
a84c022
+
a84c022
+	ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node);
a84c022
+	if (!ri)
a84c022
+		return NULL;
a84c022
+
a84c022
+	ri->cfg = pci_acpi_setup_ecam_mapping(root);
a84c022
+	if (!ri->cfg) {
a84c022
+		kfree(ri);
a84c022
+		return NULL;
a84c022
+	}
a84c022
+
a84c022
+	acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops;
a84c022
+	bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common,
a84c022
+				   ri->cfg);
a84c022
+	if (!bus)
a84c022
+		return NULL;
a84c022
+
a84c022
+	pci_bus_size_bridges(bus);
a84c022
+	pci_bus_assign_resources(bus);
a84c022
+
a84c022
+	list_for_each_entry(child, &bus->children, node)
a84c022
+		pcie_bus_configure_settings(child);
a84c022
+
a84c022
+	return bus;
a84c022
+}
a84c022
+
a84c022
+void pcibios_add_bus(struct pci_bus *bus)
a84c022
+{
a84c022
+	acpi_pci_add_bus(bus);
a84c022
 }
a84c022
+
a84c022
+void pcibios_remove_bus(struct pci_bus *bus)
a84c022
+{
a84c022
+	acpi_pci_remove_bus(bus);
a84c022
+}
a84c022
+
a84c022
 #endif
a84c022
-- 
a84c022
2.7.4
a84c022