From: Alexander Graf <agraf@suse.de>
Patch-mainline: No
Subject: [PATCH] arm64: Enable generic PHB driver
References: bnc#911732

ARM64 doesn't enable the generic PHB driver which would work just fine. Enable it in a local patch for now. Discussions on how to do it best upstream are ongoing.

Signed-off-by: Alexander Graf <agraf@suse.de>

Index: linux-3.19-rc2-master/drivers/pci/host/Kconfig
===================================================================
--- linux-3.19-rc2-master.orig/drivers/pci/host/Kconfig
+++ linux-3.19-rc2-master/drivers/pci/host/Kconfig
@@ -53,7 +53,7 @@ config PCI_RCAR_GEN2_PCIE
 
 config PCI_HOST_GENERIC
 	bool "Generic PCI host controller"
-	depends on ARM && OF
+	depends on (ARM || ARM64) && OF
 	help
 	  Say Y here if you want to support a simple generic PCI host
 	  controller, such as the one emulated by kvmtool.
Index: linux-3.19-rc2-master/drivers/pci/host/pci-host-generic.c
===================================================================
--- linux-3.19-rc2-master.orig/drivers/pci/host/pci-host-generic.c
+++ linux-3.19-rc2-master/drivers/pci/host/pci-host-generic.c
@@ -44,12 +44,14 @@ struct gen_pci {
 	struct list_head			resources;
 };
 
+/* fake sysdata for cheating ARCH's pcibios code */
+static char	gen_sysdata[256];
+
 static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
 					     unsigned int devfn,
 					     int where)
 {
-	struct pci_sys_data *sys = bus->sysdata;
-	struct gen_pci *pci = sys->private_data;
+	struct gen_pci *pci = dev_get_drvdata(bus->dev.parent->parent);
 	resource_size_t idx = bus->number - pci->cfg.bus_range->start;
 
 	return pci->cfg.win[idx] + ((devfn << 8) | where);
@@ -64,8 +66,7 @@ static void __iomem *gen_pci_map_cfg_bus
 					      unsigned int devfn,
 					      int where)
 {
-	struct pci_sys_data *sys = bus->sysdata;
-	struct gen_pci *pci = sys->private_data;
+	struct gen_pci *pci = dev_get_drvdata(bus->dev.parent->parent);
 	resource_size_t idx = bus->number - pci->cfg.bus_range->start;
 
 	return pci->cfg.win[idx] + ((devfn << 12) | where);
@@ -80,8 +81,7 @@ static int gen_pci_config_read(struct pc
 				int where, int size, u32 *val)
 {
 	void __iomem *addr;
-	struct pci_sys_data *sys = bus->sysdata;
-	struct gen_pci *pci = sys->private_data;
+	struct gen_pci *pci = dev_get_drvdata(bus->dev.parent->parent);
 
 	addr = pci->cfg.ops->map_bus(bus, devfn, where);
 
@@ -103,8 +103,7 @@ static int gen_pci_config_write(struct p
 				 int where, int size, u32 val)
 {
 	void __iomem *addr;
-	struct pci_sys_data *sys = bus->sysdata;
-	struct gen_pci *pci = sys->private_data;
+	struct gen_pci *pci = dev_get_drvdata(bus->dev.parent->parent);
 
 	addr = pci->cfg.ops->map_bus(bus, devfn, where);
 
@@ -143,60 +142,6 @@ static void gen_pci_release_of_pci_range
 	pci_free_resource_list(&pci->resources);
 }
 
-static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
-{
-	int err, res_valid = 0;
-	struct device *dev = pci->host.dev.parent;
-	struct device_node *np = dev->of_node;
-	resource_size_t iobase;
-	struct pci_host_bridge_window *win;
-
-	err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
-					       &iobase);
-	if (err)
-		return err;
-
-	list_for_each_entry(win, &pci->resources, list) {
-		struct resource *parent, *res = win->res;
-
-		switch (resource_type(res)) {
-		case IORESOURCE_IO:
-			parent = &ioport_resource;
-			err = pci_remap_iospace(res, iobase);
-			if (err) {
-				dev_warn(dev, "error %d: failed to map resource %pR\n",
-					 err, res);
-				continue;
-			}
-			break;
-		case IORESOURCE_MEM:
-			parent = &iomem_resource;
-			res_valid |= !(res->flags & IORESOURCE_PREFETCH);
-			break;
-		case IORESOURCE_BUS:
-			pci->cfg.bus_range = res;
-		default:
-			continue;
-		}
-
-		err = devm_request_resource(dev, parent, res);
-		if (err)
-			goto out_release_res;
-	}
-
-	if (!res_valid) {
-		dev_err(dev, "non-prefetchable memory resource required\n");
-		err = -EINVAL;
-		goto out_release_res;
-	}
-
-	return 0;
-
-out_release_res:
-	gen_pci_release_of_pci_ranges(pci);
-	return err;
-}
-
 static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
 {
 	int err;
@@ -244,11 +189,33 @@ static int gen_pci_parse_map_cfg_windows
 	return 0;
 }
 
-static int gen_pci_setup(int nr, struct pci_sys_data *sys)
+static int gen_pci_map_ranges(struct gen_pci *pci,
+		resource_size_t io_base)
 {
-	struct gen_pci *pci = sys->private_data;
-	list_splice_init(&pci->resources, &sys->resources);
-	return 1;
+	struct list_head *res = &pci->resources;
+	struct pci_host_bridge_window *window;
+	int ret;
+
+	list_for_each_entry(window, res, list) {
+		struct resource *res = window->res;
+		u64 restype = resource_type(res);
+
+		switch (restype) {
+		case IORESOURCE_IO:
+			ret = pci_remap_iospace(res, io_base);
+			if (ret < 0)
+				return ret;
+			break;
+		case IORESOURCE_MEM:
+			break;
+		case IORESOURCE_BUS:
+			pci->cfg.bus_range = res;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+	return 0;
 }
 
 static int gen_pci_probe(struct platform_device *pdev)
@@ -259,14 +226,11 @@ static int gen_pci_probe(struct platform
 	const int *prop;
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
+	resource_size_t iobase = 0;
 	struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
-	struct hw_pci hw = {
-		.nr_controllers	= 1,
-		.private_data	= (void **)&pci,
-		.setup		= gen_pci_setup,
-		.map_irq	= of_irq_parse_and_map_pci,
-		.ops		= &gen_pci_ops,
-	};
+	struct pci_bus *bus;
+	struct pci_dev *pci_dev = NULL;
+	bool probe_only = false;
 
 	if (!pci)
 		return -ENOMEM;
@@ -280,9 +244,9 @@ static int gen_pci_probe(struct platform
 	prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
 	if (prop) {
 		if (*prop)
-			pci_add_flags(PCI_PROBE_ONLY);
+			probe_only = true;
 		else
-			pci_clear_flags(PCI_PROBE_ONLY);
+			probe_only = false;
 	}
 
 	of_id = of_match_node(gen_pci_of_match, np);
@@ -291,20 +255,40 @@ static int gen_pci_probe(struct platform
 	INIT_LIST_HEAD(&pci->host.windows);
 	INIT_LIST_HEAD(&pci->resources);
 
-	/* Parse our PCI ranges and request their resources */
-	err = gen_pci_parse_request_of_pci_ranges(pci);
+	err = of_pci_get_host_bridge_resources(np, 0, 0xff,
+			&pci->resources, &iobase);
 	if (err)
 		return err;
 
+	err = gen_pci_map_ranges(pci, iobase);
+	if (err)
+		goto fail;
+
 	/* Parse and map our Configuration Space windows */
 	err = gen_pci_parse_map_cfg_windows(pci);
-	if (err) {
-		gen_pci_release_of_pci_ranges(pci);
-		return err;
+	if (err)
+		goto fail;
+
+	err = -ENOMEM;
+	platform_set_drvdata(pdev, pci);
+	bus = pci_scan_root_bus(dev, 0, &gen_pci_ops, gen_sysdata,
+				&pci->resources);
+	if (!bus)
+		goto fail;
+
+	for_each_pci_dev(pci_dev)
+		pci_dev->irq = of_irq_parse_and_map_pci(pci_dev, 0, 0);
+
+	if (!probe_only) {
+		pci_bus_size_bridges(bus);
+		pci_bus_assign_resources(bus);
+		pci_bus_add_devices(bus);
 	}
 
-	pci_common_init_dev(dev, &hw);
 	return 0;
+ fail:
+	gen_pci_release_of_pci_ranges(pci);
+	return err;
 }
 
 static struct platform_driver gen_pci_driver = {
