From 9a28033753ca9e86593e15050c7ae02fbc03f9ae Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 8 Oct 2015 10:15:10 -0500 Subject: [PATCH] PCI: generic: Allow multiple hosts with different map_bus() methods The generic driver kept a global struct pci_ops ("gen_pci_ops") which it patched with the .map_bus() method appropriate for the bus device. This is a problem when we have two different types of bus devices: the .map_bus() method for the last device probed clobbers the method for previous devices. The result is that only the last bus device probed has the correct .map_bus(), and the others fail. Move the struct pci_ops into the bus-specific structure and initialize a pointer to it when the bus device is probed. Signed-off-by: David Daney Signed-off-by: Bjorn Helgaas Reviewed-by: Arnd Bergmann Acked-by: Will Deacon --- drivers/pci/host/pci-host-generic.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 224303d2b401..2533e8da136d 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c @@ -27,7 +27,7 @@ struct gen_pci_cfg_bus_ops { u32 bus_shift; - void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int); + struct pci_ops ops; }; struct gen_pci_cfg_windows { @@ -35,7 +35,7 @@ struct gen_pci_cfg_windows { struct resource *bus_range; void __iomem **win; - const struct gen_pci_cfg_bus_ops *ops; + struct gen_pci_cfg_bus_ops *ops; }; /* @@ -65,7 +65,11 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus, static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = { .bus_shift = 16, - .map_bus = gen_pci_map_cfg_bus_cam, + .ops = { + .map_bus = gen_pci_map_cfg_bus_cam, + .read = pci_generic_config_read, + .write = pci_generic_config_write, + } }; static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, @@ -80,12 +84,11 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = { .bus_shift = 20, - .map_bus = gen_pci_map_cfg_bus_ecam, -}; - -static struct pci_ops gen_pci_ops = { - .read = pci_generic_config_read, - .write = pci_generic_config_write, + .ops = { + .map_bus = gen_pci_map_cfg_bus_ecam, + .read = pci_generic_config_read, + .write = pci_generic_config_write, + } }; static const struct of_device_id gen_pci_of_match[] = { @@ -227,8 +230,7 @@ static int gen_pci_probe(struct platform_device *pdev) of_pci_check_probe_only(); of_id = of_match_node(gen_pci_of_match, np); - pci->cfg.ops = of_id->data; - gen_pci_ops.map_bus = pci->cfg.ops->map_bus; + pci->cfg.ops = (struct gen_pci_cfg_bus_ops *)of_id->data; pci->host.dev.parent = dev; INIT_LIST_HEAD(&pci->host.windows); INIT_LIST_HEAD(&pci->resources); @@ -249,7 +251,8 @@ static int gen_pci_probe(struct platform_device *pdev) if (!pci_has_flag(PCI_PROBE_ONLY)) pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); - bus = pci_scan_root_bus(dev, 0, &gen_pci_ops, pci, &pci->resources); + bus = pci_scan_root_bus(dev, 0, + &pci->cfg.ops->ops, pci, &pci->resources); if (!bus) { dev_err(dev, "Scanning rootbus failed"); return -ENODEV;