diff options
author | David Daney <david.daney@cavium.com> | 2015-10-08 10:15:10 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2015-10-08 10:15:10 -0500 |
commit | 9a28033753ca9e86593e15050c7ae02fbc03f9ae (patch) | |
tree | 9febdc44f45e6669e4579c432503a82063090b5f /drivers/pci/host/pci-host-generic.c | |
parent | 6701212e86398622a05b85d87391646bf0e81bfc (diff) | |
download | linux-stable-9a28033753ca9e86593e15050c7ae02fbc03f9ae.tar.gz linux-stable-9a28033753ca9e86593e15050c7ae02fbc03f9ae.tar.bz2 linux-stable-9a28033753ca9e86593e15050c7ae02fbc03f9ae.zip |
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 <david.daney@cavium.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/pci/host/pci-host-generic.c')
-rw-r--r-- | drivers/pci/host/pci-host-generic.c | 27 |
1 files 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; |