diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index e72587fe477d..ffbc8913cc76 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -342,6 +342,7 @@ PER-CPU MEM devm_free_percpu() PCI + devm_pci_alloc_host_bridge() : managed PCI host bridge allocation devm_pci_remap_cfgspace() : ioremap PCI configuration space devm_pci_remap_cfg_resource() : ioremap PCI configuration space resource pcim_enable_device() : after success, all PCI ops become managed diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h index 2d88af5be45f..233b4b50eff3 100644 --- a/arch/arm/include/asm/mach/pci.h +++ b/arch/arm/include/asm/mach/pci.h @@ -16,6 +16,7 @@ struct pci_sys_data; struct pci_ops; struct pci_bus; +struct pci_host_bridge; struct device; struct hw_pci { @@ -25,7 +26,7 @@ struct hw_pci { unsigned int io_optional:1; void **private_data; int (*setup)(int nr, struct pci_sys_data *); - struct pci_bus *(*scan)(int nr, struct pci_sys_data *); + int (*scan)(int nr, struct pci_host_bridge *); void (*preinit)(void); void (*postinit)(void); u8 (*swizzle)(struct pci_dev *dev, u8 *pin); diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index b259956365a0..56dc1a3a33b4 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -458,10 +458,14 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, int nr, busnr; for (nr = busnr = 0; nr < hw->nr_controllers; nr++) { - sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL); - if (WARN(!sys, "PCI: unable to allocate sys data!")) + struct pci_host_bridge *bridge; + + bridge = pci_alloc_host_bridge(sizeof(struct pci_sys_data)); + if (WARN(!bridge, "PCI: unable to allocate bridge!")) break; + sys = pci_host_bridge_priv(bridge); + sys->busnr = busnr; sys->swizzle = hw->swizzle; sys->map_irq = hw->map_irq; @@ -473,7 +477,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, ret = hw->setup(nr, sys); if (ret > 0) { - struct pci_host_bridge *host_bridge; ret = pcibios_init_resource(nr, sys, hw->io_optional); if (ret) { @@ -481,26 +484,37 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, break; } - if (hw->scan) - sys->bus = hw->scan(nr, sys); - else - sys->bus = pci_scan_root_bus_msi(parent, - sys->busnr, hw->ops, sys, - &sys->resources, hw->msi_ctrl); + bridge->map_irq = pcibios_map_irq; + bridge->swizzle_irq = pcibios_swizzle; - if (WARN(!sys->bus, "PCI: unable to scan bus!")) { - kfree(sys); + if (hw->scan) + ret = hw->scan(nr, bridge); + else { + list_splice_init(&sys->resources, + &bridge->windows); + bridge->dev.parent = parent; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + bridge->ops = hw->ops; + bridge->msi = hw->msi_ctrl; + bridge->align_resource = + hw->align_resource; + + ret = pci_scan_root_bus_bridge(bridge); + } + + if (WARN(ret < 0, "PCI: unable to scan bus!")) { + pci_free_host_bridge(bridge); break; } + sys->bus = bridge->bus; + busnr = sys->bus->busn_res.end + 1; list_add(&sys->node, head); - - host_bridge = pci_find_host_bridge(sys->bus); - host_bridge->align_resource = hw->align_resource; } else { - kfree(sys); + pci_free_host_bridge(bridge); if (ret < 0) break; } @@ -519,8 +533,6 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw) if (hw->postinit) hw->postinit(); - pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); - list_for_each_entry(sys, &head, node) { struct pci_bus *bus = sys->bus; diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c index 91fe97144570..dfb62f3f5dcf 100644 --- a/arch/arm/mach-dove/pcie.c +++ b/arch/arm/mach-dove/pcie.c @@ -152,16 +152,23 @@ static void rc_pci_fixup(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); -static struct pci_bus __init * -dove_pcie_scan_bus(int nr, struct pci_sys_data *sys) +static int __init +dove_pcie_scan_bus(int nr, struct pci_host_bridge *bridge) { + struct pci_sys_data *sys = pci_host_bridge_priv(bridge); + if (nr >= num_pcie_ports) { BUG(); - return NULL; + return -EINVAL; } - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, - &sys->resources); + list_splice_init(&sys->resources, &bridge->windows); + bridge->dev.parent = NULL; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + bridge->ops = &pcie_ops; + + return pci_scan_root_bus_bridge(bridge); } static int __init dove_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c index 204eb4460271..070d92ae1b6f 100644 --- a/arch/arm/mach-iop13xx/pci.c +++ b/arch/arm/mach-iop13xx/pci.c @@ -504,10 +504,10 @@ iop13xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) /* Scan an IOP13XX PCI bus. nr selects which ATU we use. */ -struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys) +int iop13xx_scan_bus(int nr, struct pci_host_bridge *bridge) { - int which_atu; - struct pci_bus *bus = NULL; + int which_atu, ret; + struct pci_sys_data *sys = pci_host_bridge_priv(bridge); switch (init_atu) { case IOP13XX_INIT_ATU_ATUX: @@ -525,9 +525,14 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys) if (!which_atu) { BUG(); - return NULL; + return -ENODEV; } + list_splice_init(&sys->resources, &bridge->windows); + bridge->dev.parent = NULL; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + switch (which_atu) { case IOP13XX_INIT_ATU_ATUX: if (time_after_eq(jiffies + msecs_to_jiffies(1000), @@ -535,18 +540,22 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys) while(time_before(jiffies, atux_trhfa_timeout)) udelay(100); - bus = pci_bus_atux = pci_scan_root_bus(NULL, sys->busnr, - &iop13xx_atux_ops, - sys, &sys->resources); + bridge->ops = &iop13xx_atux_ops; + ret = pci_scan_root_bus_bridge(bridge); + if (!ret) + pci_bus_atux = bridge->bus; break; case IOP13XX_INIT_ATU_ATUE: - bus = pci_bus_atue = pci_scan_root_bus(NULL, sys->busnr, - &iop13xx_atue_ops, - sys, &sys->resources); + bridge->ops = &iop13xx_atue_ops; + ret = pci_scan_root_bus_bridge(bridge); + if (!ret) + pci_bus_atue = bridge->bus; break; + default: + ret = -EINVAL; } - return bus; + return ret; } /* This function is called from iop13xx_pci_init() after assigning valid diff --git a/arch/arm/mach-iop13xx/pci.h b/arch/arm/mach-iop13xx/pci.h index 71b9c57e1fde..8dc343cb887a 100644 --- a/arch/arm/mach-iop13xx/pci.h +++ b/arch/arm/mach-iop13xx/pci.h @@ -11,9 +11,10 @@ extern size_t iop13xx_atue_mem_size; extern size_t iop13xx_atux_mem_size; struct pci_sys_data; +struct pci_host_bridge; struct hw_pci; int iop13xx_pci_setup(int nr, struct pci_sys_data *sys); -struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *); +int iop13xx_scan_bus(int nr, struct pci_host_bridge *bridge); void iop13xx_atu_select(struct hw_pci *plat_pci); void iop13xx_pci_init(void); void iop13xx_map_pci_memory(void); diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c index 81ff4327a962..636d84b40466 100644 --- a/arch/arm/mach-mv78xx0/pcie.c +++ b/arch/arm/mach-mv78xx0/pcie.c @@ -194,16 +194,22 @@ static void rc_pci_fixup(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); -static struct pci_bus __init * -mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys) +static int __init mv78xx0_pcie_scan_bus(int nr, struct pci_host_bridge *bridge) { + struct pci_sys_data *sys = pci_host_bridge_priv(bridge); + if (nr >= num_pcie_ports) { BUG(); - return NULL; + return -EINVAL; } - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, - &sys->resources); + list_splice_init(&sys->resources, &bridge->windows); + bridge->dev.parent = NULL; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + bridge->ops = &pcie_ops; + + return pci_scan_root_bus_bridge(bridge); } static int __init mv78xx0_pcie_map_irq(const struct pci_dev *dev, u8 slot, diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h index efeffc6b4ebb..4c0c7de665c3 100644 --- a/arch/arm/mach-orion5x/common.h +++ b/arch/arm/mach-orion5x/common.h @@ -54,6 +54,7 @@ void orion5x_restart(enum reboot_mode, const char *); * PCIe/PCI functions. */ struct pci_bus; +struct pci_host_bridge; struct pci_sys_data; struct pci_dev; @@ -61,7 +62,7 @@ void orion5x_pcie_id(u32 *dev, u32 *rev); void orion5x_pci_disable(void); void orion5x_pci_set_cardbus_mode(void); int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys); -struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys); +int orion5x_pci_sys_scan_bus(int nr, struct pci_host_bridge *bridge); int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); struct tag; diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index ecb998e7f8dc..76951bfbacf5 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -555,18 +555,27 @@ int __init orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys) return 0; } -struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys) +int __init orion5x_pci_sys_scan_bus(int nr, struct pci_host_bridge *bridge) { - if (nr == 0) - return pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, - &sys->resources); + struct pci_sys_data *sys = pci_host_bridge_priv(bridge); - if (nr == 1 && !orion5x_pci_disabled) - return pci_scan_root_bus(NULL, sys->busnr, &pci_ops, sys, - &sys->resources); + list_splice_init(&sys->resources, &bridge->windows); + bridge->dev.parent = NULL; + bridge->sysdata = sys; + bridge->busnr = sys->busnr; + + if (nr == 0) { + bridge->ops = &pcie_ops; + return pci_scan_root_bus_bridge(bridge); + } + + if (nr == 1 && !orion5x_pci_disabled) { + bridge->ops = &pci_ops; + return pci_scan_root_bus_bridge(bridge); + } BUG(); - return NULL; + return -ENODEV; } int __init orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 4f0e3ebfea4b..efcc351c518f 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -39,20 +39,18 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, return res->start; } +#ifdef CONFIG_ACPI /* * Try to assign the IRQ number when probing a new device */ int pcibios_alloc_irq(struct pci_dev *dev) { - 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 + if (!acpi_disabled) + acpi_pci_irq_enable(dev); return 0; } +#endif /* * raw_pci_read/write - Platform-specific PCI config space access. diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c index c175d9cd0bb5..3a05568f65df 100644 --- a/drivers/of/of_pci_irq.c +++ b/drivers/of/of_pci_irq.c @@ -113,7 +113,8 @@ EXPORT_SYMBOL_GPL(of_irq_parse_pci); * @pin: PCI irq pin number; passed when used as map_irq callback. Unused * * @slot and @pin are unused, but included in the function so that this - * function can be used directly as the map_irq callback to pci_fixup_irqs(). + * function can be used directly as the map_irq callback to + * pci_assign_irq() and struct pci_host_bridge.map_irq pointer */ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) { diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 462c1f5f5546..66a21acad952 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -4,7 +4,8 @@ obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ - irq.o vpd.o setup-bus.o vc.o mmap.o + irq.o vpd.o setup-bus.o vc.o mmap.o setup-irq.o + obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSFS) += slot.o @@ -28,20 +29,6 @@ obj-$(CONFIG_HT_IRQ) += htirq.o obj-$(CONFIG_PCI_ATS) += ats.o obj-$(CONFIG_PCI_IOV) += iov.o -# -# Some architectures use the generic PCI setup functions -# -obj-$(CONFIG_ALPHA) += setup-irq.o -obj-$(CONFIG_ARC) += setup-irq.o -obj-$(CONFIG_ARM) += setup-irq.o -obj-$(CONFIG_ARM64) += setup-irq.o -obj-$(CONFIG_UNICORE32) += setup-irq.o -obj-$(CONFIG_SUPERH) += setup-irq.o -obj-$(CONFIG_MIPS) += setup-irq.o -obj-$(CONFIG_TILE) += setup-irq.o -obj-$(CONFIG_SPARC_LEON) += setup-irq.o -obj-$(CONFIG_M68K) += setup-irq.o - # # ACPI Related PCI FW Functions # ACPI _DSM provided firmware instance and string name diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c index 28ed32ba4f1b..d29c020da082 100644 --- a/drivers/pci/dwc/pcie-designware-host.c +++ b/drivers/pci/dwc/pcie-designware-host.c @@ -280,9 +280,9 @@ int dw_pcie_host_init(struct pcie_port *pp) struct device_node *np = dev->of_node; struct platform_device *pdev = to_platform_device(dev); struct pci_bus *bus, *child; + struct pci_host_bridge *bridge; struct resource *cfg_res; int i, ret; - LIST_HEAD(res); struct resource_entry *win, *tmp; cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); @@ -295,16 +295,21 @@ int dw_pcie_host_init(struct pcie_port *pp) dev_err(dev, "missing *config* reg space\n"); } - ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &pp->io_base); + bridge = pci_alloc_host_bridge(0); + if (!bridge) + return -ENOMEM; + + ret = of_pci_get_host_bridge_resources(np, 0, 0xff, + &bridge->windows, &pp->io_base); if (ret) return ret; - ret = devm_request_pci_bus_resources(dev, &res); + ret = devm_request_pci_bus_resources(dev, &bridge->windows); if (ret) goto error; /* Get the I/O and memory ranges from DT */ - resource_list_for_each_entry_safe(win, tmp, &res) { + resource_list_for_each_entry_safe(win, tmp, &bridge->windows) { switch (resource_type(win->res)) { case IORESOURCE_IO: ret = pci_remap_iospace(win->res, pp->io_base); @@ -400,27 +405,27 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->ops->host_init(pp); pp->root_bus_nr = pp->busn->start; + + bridge->dev.parent = dev; + bridge->sysdata = pp; + bridge->busnr = pp->root_bus_nr; + bridge->ops = &dw_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; if (IS_ENABLED(CONFIG_PCI_MSI)) { - bus = pci_scan_root_bus_msi(dev, pp->root_bus_nr, - &dw_pcie_ops, pp, &res, - &dw_pcie_msi_chip); + bridge->msi = &dw_pcie_msi_chip; dw_pcie_msi_chip.dev = dev; - } else - bus = pci_scan_root_bus(dev, pp->root_bus_nr, &dw_pcie_ops, - pp, &res); - if (!bus) { - ret = -ENOMEM; - goto error; } + ret = pci_scan_root_bus_bridge(bridge); + if (ret) + goto error; + + bus = bridge->bus; + if (pp->ops->scan_bus) pp->ops->scan_bus(pp); -#ifdef CONFIG_ARM - /* support old dtbs that incorrectly describe IRQs */ - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); -#endif - pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); @@ -431,7 +436,7 @@ int dw_pcie_host_init(struct pcie_port *pp) return 0; error: - pci_free_resource_list(&res); + pci_free_host_bridge(bridge); return ret; } diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 37d0bcd31f8a..5fb9b620ac78 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -886,12 +886,14 @@ static int advk_pcie_probe(struct platform_device *pdev) struct advk_pcie *pcie; struct resource *res; struct pci_bus *bus, *child; + struct pci_host_bridge *bridge; int ret, irq; - pcie = devm_kzalloc(dev, sizeof(struct advk_pcie), GFP_KERNEL); - if (!pcie) + bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct advk_pcie)); + if (!bridge) return -ENOMEM; + pcie = pci_host_bridge_priv(bridge); pcie->pdev = pdev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -929,14 +931,21 @@ static int advk_pcie_probe(struct platform_device *pdev) return ret; } - bus = pci_scan_root_bus(dev, 0, &advk_pcie_ops, - pcie, &pcie->resources); - if (!bus) { + list_splice_init(&pcie->resources, &bridge->windows); + bridge->dev.parent = dev; + bridge->sysdata = pcie; + bridge->busnr = 0; + bridge->ops = &advk_pcie_ops; + + ret = pci_scan_root_bus_bridge(bridge); + if (ret < 0) { advk_pcie_remove_msi_irq_domain(pcie); advk_pcie_remove_irq_domain(pcie); - return -ENOMEM; + return ret; } + bus = bridge->bus; + pci_bus_assign_resources(bus); list_for_each_entry(child, &bus->children, node) diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c index d26501c4145a..e938eebcb180 100644 --- a/drivers/pci/host/pci-ftpci100.c +++ b/drivers/pci/host/pci-ftpci100.c @@ -178,12 +178,11 @@ static int faraday_res_to_memcfg(resource_size_t mem_base, return 0; } -static int faraday_pci_read_config(struct pci_bus *bus, unsigned int fn, - int config, int size, u32 *value) +static int faraday_raw_pci_read_config(struct faraday_pci *p, int bus_number, + unsigned int fn, int config, int size, + u32 *value) { - struct faraday_pci *p = bus->sysdata; - - writel(PCI_CONF_BUS(bus->number) | + writel(PCI_CONF_BUS(bus_number) | PCI_CONF_DEVICE(PCI_SLOT(fn)) | PCI_CONF_FUNCTION(PCI_FUNC(fn)) | PCI_CONF_WHERE(config) | @@ -197,24 +196,28 @@ static int faraday_pci_read_config(struct pci_bus *bus, unsigned int fn, else if (size == 2) *value = (*value >> (8 * (config & 3))) & 0xFFFF; + return PCIBIOS_SUCCESSFUL; +} + +static int faraday_pci_read_config(struct pci_bus *bus, unsigned int fn, + int config, int size, u32 *value) +{ + struct faraday_pci *p = bus->sysdata; + dev_dbg(&bus->dev, "[read] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", PCI_SLOT(fn), PCI_FUNC(fn), config, size, *value); - return PCIBIOS_SUCCESSFUL; + return faraday_raw_pci_read_config(p, bus->number, fn, config, size, value); } -static int faraday_pci_write_config(struct pci_bus *bus, unsigned int fn, - int config, int size, u32 value) +static int faraday_raw_pci_write_config(struct faraday_pci *p, int bus_number, + unsigned int fn, int config, int size, + u32 value) { - struct faraday_pci *p = bus->sysdata; int ret = PCIBIOS_SUCCESSFUL; - dev_dbg(&bus->dev, - "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", - PCI_SLOT(fn), PCI_FUNC(fn), config, size, value); - - writel(PCI_CONF_BUS(bus->number) | + writel(PCI_CONF_BUS(bus_number) | PCI_CONF_DEVICE(PCI_SLOT(fn)) | PCI_CONF_FUNCTION(PCI_FUNC(fn)) | PCI_CONF_WHERE(config) | @@ -238,6 +241,19 @@ static int faraday_pci_write_config(struct pci_bus *bus, unsigned int fn, return ret; } +static int faraday_pci_write_config(struct pci_bus *bus, unsigned int fn, + int config, int size, u32 value) +{ + struct faraday_pci *p = bus->sysdata; + + dev_dbg(&bus->dev, + "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", + PCI_SLOT(fn), PCI_FUNC(fn), config, size, value); + + return faraday_raw_pci_write_config(p, bus->number, fn, config, size, + value); +} + static struct pci_ops faraday_pci_ops = { .read = faraday_pci_read_config, .write = faraday_pci_write_config, @@ -248,10 +264,10 @@ static void faraday_pci_ack_irq(struct irq_data *d) struct faraday_pci *p = irq_data_get_irq_chip_data(d); unsigned int reg; - faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); + faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®); reg &= ~(0xF << PCI_CTRL2_INTSTS_SHIFT); reg |= BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTSTS_SHIFT); - faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); + faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg); } static void faraday_pci_mask_irq(struct irq_data *d) @@ -259,10 +275,10 @@ static void faraday_pci_mask_irq(struct irq_data *d) struct faraday_pci *p = irq_data_get_irq_chip_data(d); unsigned int reg; - faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); + faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®); reg &= ~((0xF << PCI_CTRL2_INTSTS_SHIFT) | BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT)); - faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); + faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg); } static void faraday_pci_unmask_irq(struct irq_data *d) @@ -270,10 +286,10 @@ static void faraday_pci_unmask_irq(struct irq_data *d) struct faraday_pci *p = irq_data_get_irq_chip_data(d); unsigned int reg; - faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); + faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®); reg &= ~(0xF << PCI_CTRL2_INTSTS_SHIFT); reg |= BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT); - faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, reg); + faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg); } static void faraday_pci_irq_handler(struct irq_desc *desc) @@ -282,7 +298,7 @@ static void faraday_pci_irq_handler(struct irq_desc *desc) struct irq_chip *irqchip = irq_desc_get_chip(desc); unsigned int irq_stat, reg, i; - faraday_pci_read_config(p->bus, 0, FARADAY_PCI_CTRL2, 4, ®); + faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®); irq_stat = reg >> PCI_CTRL2_INTSTS_SHIFT; chained_irq_enter(irqchip, desc); @@ -403,8 +419,8 @@ static int faraday_pci_parse_map_dma_ranges(struct faraday_pci *p, dev_info(dev, "DMA MEM%d BASE: 0x%016llx -> 0x%016llx config %08x\n", i + 1, range.pci_addr, end, val); if (i <= 2) { - faraday_pci_write_config(p->bus, 0, confreg[i], - 4, val); + faraday_raw_pci_write_config(p, 0, 0, confreg[i], + 4, val); } else { dev_err(dev, "ignore extraneous dma-range %d\n", i); break; @@ -432,7 +448,7 @@ static int faraday_pci_probe(struct platform_device *pdev) u32 val; LIST_HEAD(res); - host = pci_alloc_host_bridge(sizeof(*p)); + host = devm_pci_alloc_host_bridge(dev, sizeof(*p)); if (!host) return -ENOMEM; @@ -440,6 +456,8 @@ static int faraday_pci_probe(struct platform_device *pdev) host->ops = &faraday_pci_ops; host->busnr = 0; host->msi = NULL; + host->map_irq = of_irq_parse_and_map_pci; + host->swizzle_irq = pci_common_swizzle; p = pci_host_bridge_priv(host); host->sysdata = p; p->dev = dev; @@ -496,17 +514,8 @@ static int faraday_pci_probe(struct platform_device *pdev) val |= PCI_COMMAND_MEMORY; val |= PCI_COMMAND_MASTER; writel(val, p->base + PCI_CTRL); - - list_splice_init(&res, &host->windows); - ret = pci_register_host_bridge(host); - if (ret) { - dev_err(dev, "failed to register host: %d\n", ret); - return ret; - } - p->bus = host->bus; - /* Mask and clear all interrupts */ - faraday_pci_write_config(p->bus, 0, FARADAY_PCI_CTRL2 + 2, 2, 0xF000); + faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2 + 2, 2, 0xF000); if (variant->cascaded_irq) { ret = faraday_pci_setup_cascaded_irq(p); if (ret) { @@ -519,8 +528,14 @@ static int faraday_pci_probe(struct platform_device *pdev) if (ret) return ret; - pci_scan_child_bus(p->bus); - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); + list_splice_init(&res, &host->windows); + ret = pci_scan_root_bus_bridge(host); + if (ret) { + dev_err(dev, "failed to scan host: %d\n", ret); + return ret; + } + p->bus = host->bus; + pci_bus_assign_resources(p->bus); pci_bus_add_devices(p->bus); pci_free_resource_list(&res); diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c index e9a53bae1c25..44a47d4f0b8f 100644 --- a/drivers/pci/host/pci-host-common.c +++ b/drivers/pci/host/pci-host-common.c @@ -117,8 +117,14 @@ int pci_host_common_probe(struct platform_device *pdev, struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct pci_bus *bus, *child; + struct pci_host_bridge *bridge; struct pci_config_window *cfg; struct list_head resources; + int ret; + + bridge = devm_pci_alloc_host_bridge(dev, 0); + if (!bridge) + return -ENOMEM; type = of_get_property(np, "device_type", NULL); if (!type || strcmp(type, "pci")) { @@ -138,16 +144,21 @@ int pci_host_common_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, cfg->busr.start, &ops->pci_ops, cfg, - &resources); - if (!bus) { - dev_err(dev, "Scanning rootbus failed"); - return -ENODEV; + list_splice_init(&resources, &bridge->windows); + bridge->dev.parent = dev; + bridge->sysdata = cfg; + bridge->busnr = cfg->busr.start; + bridge->ops = &ops->pci_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; + + ret = pci_scan_root_bus_bridge(bridge); + if (ret < 0) { + dev_err(dev, "Scanning root bridge failed"); + return ret; } -#ifdef CONFIG_ARM - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); -#endif + bus = bridge->bus; /* * We insert PCI resources into the iomem_resource and diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 2618f875a600..0dadb81eca70 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -2238,7 +2238,7 @@ static int tegra_pcie_probe(struct platform_device *pdev) struct pci_bus *child; int err; - host = pci_alloc_host_bridge(sizeof(*pcie)); + host = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); if (!host) return -ENOMEM; @@ -2284,16 +2284,15 @@ static int tegra_pcie_probe(struct platform_device *pdev) host->busnr = pcie->busn.start; host->dev.parent = &pdev->dev; host->ops = &tegra_pcie_ops; + host->map_irq = tegra_pcie_map_irq; + host->swizzle_irq = pci_common_swizzle; - err = pci_register_host_bridge(host); + err = pci_scan_root_bus_bridge(host); if (err < 0) { dev_err(dev, "failed to register host: %d\n", err); goto disable_msi; } - pci_scan_child_bus(host->bus); - - pci_fixup_irqs(pci_common_swizzle, tegra_pcie_map_irq); pci_bus_size_bridges(host->bus); pci_bus_assign_resources(host->bus); diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c index 9281eee2d000..f6fcec6b5578 100644 --- a/drivers/pci/host/pci-versatile.c +++ b/drivers/pci/host/pci-versatile.c @@ -125,8 +125,13 @@ static int versatile_pci_probe(struct platform_device *pdev) u32 val; void __iomem *local_pci_cfg_base; struct pci_bus *bus, *child; + struct pci_host_bridge *bridge; LIST_HEAD(pci_res); + bridge = devm_pci_alloc_host_bridge(&pdev->dev, 0); + if (!bridge) + return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); versatile_pci_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(versatile_pci_base)) @@ -199,11 +204,20 @@ static int versatile_pci_probe(struct platform_device *pdev) pci_add_flags(PCI_ENABLE_PROC_DOMAINS); pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC); - bus = pci_scan_root_bus(&pdev->dev, 0, &pci_versatile_ops, NULL, &pci_res); - if (!bus) - return -ENOMEM; + list_splice_init(&pci_res, &bridge->windows); + bridge->dev.parent = &pdev->dev; + bridge->sysdata = NULL; + bridge->busnr = 0; + bridge->ops = &pci_versatile_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; + + ret = pci_scan_root_bus_bridge(bridge); + if (ret < 0) + return ret; + + bus = bridge->bus; - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); pci_assign_unassigned_bus_resources(bus); list_for_each_entry(child, &bus->children, node) pcie_bus_configure_settings(child); diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index 8cae013e7188..bd897479a215 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -636,13 +636,16 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) struct xgene_pcie_port *port; resource_size_t iobase = 0; struct pci_bus *bus, *child; + struct pci_host_bridge *bridge; int ret; LIST_HEAD(res); - port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); - if (!port) + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port)); + if (!bridge) return -ENOMEM; + port = pci_host_bridge_priv(bridge); + port->node = of_node_get(dn); port->dev = dev; @@ -670,11 +673,19 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) if (ret) goto error; - bus = pci_create_root_bus(dev, 0, &xgene_pcie_ops, port, &res); - if (!bus) { - ret = -ENOMEM; + list_splice_init(&res, &bridge->windows); + bridge->dev.parent = dev; + bridge->sysdata = port; + bridge->busnr = 0; + bridge->ops = &xgene_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; + + ret = pci_scan_root_bus_bridge(bridge); + if (ret < 0) goto error; - } + + bus = bridge->bus; pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c index 75ec5cea26f6..4ea4f8f5dc77 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/host/pcie-altera.c @@ -579,12 +579,14 @@ static int altera_pcie_probe(struct platform_device *pdev) struct altera_pcie *pcie; struct pci_bus *bus; struct pci_bus *child; + struct pci_host_bridge *bridge; int ret; - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); + if (!bridge) return -ENOMEM; + pcie = pci_host_bridge_priv(bridge); pcie->pdev = pdev; ret = altera_pcie_parse_dt(pcie); @@ -613,12 +615,20 @@ static int altera_pcie_probe(struct platform_device *pdev) cra_writel(pcie, P2A_INT_ENA_ALL, P2A_INT_ENABLE); altera_pcie_host_init(pcie); - bus = pci_scan_root_bus(dev, pcie->root_bus_nr, &altera_pcie_ops, - pcie, &pcie->resources); - if (!bus) - return -ENOMEM; + list_splice_init(&pcie->resources, &bridge->windows); + bridge->dev.parent = dev; + bridge->sysdata = pcie; + bridge->busnr = pcie->root_bus_nr; + bridge->ops = &altera_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; + + ret = pci_scan_root_bus_bridge(bridge); + if (ret < 0) + return ret; + + bus = bridge->bus; - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); pci_assign_unassigned_bus_resources(bus); /* Configure PCI Express setting. */ diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/host/pcie-iproc-bcma.c index 384c27e664fe..f03d5e3612e9 100644 --- a/drivers/pci/host/pcie-iproc-bcma.c +++ b/drivers/pci/host/pcie-iproc-bcma.c @@ -45,12 +45,15 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev) struct device *dev = &bdev->dev; struct iproc_pcie *pcie; LIST_HEAD(resources); + struct pci_host_bridge *bridge; int ret; - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); + if (!bridge) return -ENOMEM; + pcie = pci_host_bridge_priv(bridge); + pcie->dev = dev; pcie->type = IPROC_PCIE_PAXB_BCMA; diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index 90d2bdd94e41..22531190bc40 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c @@ -52,12 +52,15 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) struct resource reg; resource_size_t iobase = 0; LIST_HEAD(resources); + struct pci_host_bridge *bridge; int ret; - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); + if (!bridge) return -ENOMEM; + pcie = pci_host_bridge_priv(bridge); + pcie->dev = dev; pcie->type = (enum iproc_pcie_type) of_device_get_match_data(dev); diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 0f39bd2a04cb..c57486348856 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -452,14 +452,13 @@ static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus, * Note access to the configuration registers are protected at the higher layer * by 'pci_lock' in drivers/pci/access.c */ -static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus, +static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie, + int busno, unsigned int devfn, int where) { - struct iproc_pcie *pcie = iproc_data(bus); unsigned slot = PCI_SLOT(devfn); unsigned fn = PCI_FUNC(devfn); - unsigned busno = bus->number; u32 val; u16 offset; @@ -499,6 +498,58 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus, return (pcie->base + offset); } +static void __iomem *iproc_pcie_bus_map_cfg_bus(struct pci_bus *bus, + unsigned int devfn, + int where) +{ + return iproc_pcie_map_cfg_bus(iproc_data(bus), bus->number, devfn, + where); +} + +static int iproc_pci_raw_config_read32(struct iproc_pcie *pcie, + unsigned int devfn, int where, + int size, u32 *val) +{ + void __iomem *addr; + + addr = iproc_pcie_map_cfg_bus(pcie, 0, devfn, where & ~0x3); + if (!addr) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + *val = readl(addr); + + if (size <= 2) + *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); + + return PCIBIOS_SUCCESSFUL; +} + +static int iproc_pci_raw_config_write32(struct iproc_pcie *pcie, + unsigned int devfn, int where, + int size, u32 val) +{ + void __iomem *addr; + u32 mask, tmp; + + addr = iproc_pcie_map_cfg_bus(pcie, 0, devfn, where & ~0x3); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 4) { + writel(val, addr); + return PCIBIOS_SUCCESSFUL; + } + + mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); + tmp = readl(addr) & mask; + tmp |= val << ((where & 0x3) * 8); + writel(tmp, addr); + + return PCIBIOS_SUCCESSFUL; +} + static int iproc_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { @@ -524,7 +575,7 @@ static int iproc_pcie_config_write32(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops iproc_pcie_ops = { - .map_bus = iproc_pcie_map_cfg_bus, + .map_bus = iproc_pcie_bus_map_cfg_bus, .read = iproc_pcie_config_read32, .write = iproc_pcie_config_write32, }; @@ -556,12 +607,11 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie) msleep(100); } -static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) +static int iproc_pcie_check_link(struct iproc_pcie *pcie) { struct device *dev = pcie->dev; - u8 hdr_type; - u32 link_ctrl, class, val; - u16 pos = PCI_EXP_CAP, link_status; + u32 hdr_type, link_ctrl, link_status, class, val; + u16 pos = PCI_EXP_CAP; bool link_is_active = false; /* @@ -578,7 +628,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) } /* make sure we are not in EP mode */ - pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr_type); + iproc_pci_raw_config_read32(pcie, 0, PCI_HEADER_TYPE, 1, &hdr_type); if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) { dev_err(dev, "in EP mode, hdr=%#02x\n", hdr_type); return -EFAULT; @@ -588,13 +638,16 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) #define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c #define PCI_CLASS_BRIDGE_MASK 0xffff00 #define PCI_CLASS_BRIDGE_SHIFT 8 - pci_bus_read_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, &class); + iproc_pci_raw_config_read32(pcie, 0, PCI_BRIDGE_CTRL_REG_OFFSET, + 4, &class); class &= ~PCI_CLASS_BRIDGE_MASK; class |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT); - pci_bus_write_config_dword(bus, 0, PCI_BRIDGE_CTRL_REG_OFFSET, class); + iproc_pci_raw_config_write32(pcie, 0, PCI_BRIDGE_CTRL_REG_OFFSET, + 4, class); /* check link status to see if link is active */ - pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, &link_status); + iproc_pci_raw_config_read32(pcie, 0, pos + PCI_EXP_LNKSTA, + 2, &link_status); if (link_status & PCI_EXP_LNKSTA_NLW) link_is_active = true; @@ -603,20 +656,21 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) #define PCI_TARGET_LINK_SPEED_MASK 0xf #define PCI_TARGET_LINK_SPEED_GEN2 0x2 #define PCI_TARGET_LINK_SPEED_GEN1 0x1 - pci_bus_read_config_dword(bus, 0, - pos + PCI_EXP_LNKCTL2, + iproc_pci_raw_config_read32(pcie, 0, + pos + PCI_EXP_LNKCTL2, 4, &link_ctrl); if ((link_ctrl & PCI_TARGET_LINK_SPEED_MASK) == PCI_TARGET_LINK_SPEED_GEN2) { link_ctrl &= ~PCI_TARGET_LINK_SPEED_MASK; link_ctrl |= PCI_TARGET_LINK_SPEED_GEN1; - pci_bus_write_config_dword(bus, 0, - pos + PCI_EXP_LNKCTL2, - link_ctrl); + iproc_pci_raw_config_write32(pcie, 0, + pos + PCI_EXP_LNKCTL2, + 4, link_ctrl); msleep(100); - pci_bus_read_config_word(bus, 0, pos + PCI_EXP_LNKSTA, - &link_status); + iproc_pci_raw_config_read32(pcie, 0, + pos + PCI_EXP_LNKSTA, + 2, &link_status); if (link_status & PCI_EXP_LNKSTA_NLW) link_is_active = true; } @@ -1205,7 +1259,8 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) struct device *dev; int ret; void *sysdata; - struct pci_bus *bus, *child; + struct pci_bus *child; + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); dev = pcie->dev; @@ -1252,18 +1307,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) sysdata = pcie; #endif - bus = pci_create_root_bus(dev, 0, &iproc_pcie_ops, sysdata, res); - if (!bus) { - dev_err(dev, "unable to create PCI root bus\n"); - ret = -ENOMEM; - goto err_power_off_phy; - } - pcie->root_bus = bus; - - ret = iproc_pcie_check_link(pcie, bus); + ret = iproc_pcie_check_link(pcie); if (ret) { dev_err(dev, "no PCIe EP device detected\n"); - goto err_rm_root_bus; + goto err_power_off_phy; } iproc_pcie_enable(pcie); @@ -1272,23 +1319,31 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) if (iproc_pcie_msi_enable(pcie)) dev_info(dev, "not using iProc MSI\n"); - pci_scan_child_bus(bus); - pci_assign_unassigned_bus_resources(bus); + list_splice_init(res, &host->windows); + host->busnr = 0; + host->dev.parent = dev; + host->ops = &iproc_pcie_ops; + host->sysdata = sysdata; + host->map_irq = pcie->map_irq; + host->swizzle_irq = pci_common_swizzle; - if (pcie->map_irq) - pci_fixup_irqs(pci_common_swizzle, pcie->map_irq); + ret = pci_scan_root_bus_bridge(host); + if (ret < 0) { + dev_err(dev, "failed to scan host: %d\n", ret); + goto err_power_off_phy; + } - list_for_each_entry(child, &bus->children, node) + pci_assign_unassigned_bus_resources(host->bus); + + pcie->root_bus = host->bus; + + list_for_each_entry(child, &host->bus->children, node) pcie_bus_configure_settings(child); - pci_bus_add_devices(bus); + pci_bus_add_devices(host->bus); return 0; -err_rm_root_bus: - pci_stop_root_bus(bus); - pci_remove_root_bus(bus); - err_power_off_phy: phy_power_off(pcie->phy); err_exit_phy: diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index cb07c45c1858..246d485b24c6 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -450,29 +450,33 @@ done: static int rcar_pcie_enable(struct rcar_pcie *pcie) { struct device *dev = pcie->dev; + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); struct pci_bus *bus, *child; - LIST_HEAD(res); + int ret; /* Try setting 5 GT/s link speed */ rcar_pcie_force_speedup(pcie); - rcar_pcie_setup(&res, pcie); + rcar_pcie_setup(&bridge->windows, pcie); pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); + bridge->dev.parent = dev; + bridge->sysdata = pcie; + bridge->busnr = pcie->root_bus_nr; + bridge->ops = &rcar_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; if (IS_ENABLED(CONFIG_PCI_MSI)) - bus = pci_scan_root_bus_msi(dev, pcie->root_bus_nr, - &rcar_pcie_ops, pcie, &res, &pcie->msi.chip); - else - bus = pci_scan_root_bus(dev, pcie->root_bus_nr, - &rcar_pcie_ops, pcie, &res); + bridge->msi = &pcie->msi.chip; - if (!bus) { - dev_err(dev, "Scanning rootbus failed"); - return -ENODEV; + ret = pci_scan_root_bus_bridge(bridge); + if (ret < 0) { + kfree(bridge); + return ret; } - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); + bus = bridge->bus; pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); @@ -1127,11 +1131,14 @@ static int rcar_pcie_probe(struct platform_device *pdev) unsigned int data; int err; int (*hw_init_fn)(struct rcar_pcie *); + struct pci_host_bridge *bridge; - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) + bridge = pci_alloc_host_bridge(sizeof(*pcie)); + if (!bridge) return -ENOMEM; + pcie = pci_host_bridge_priv(bridge); + pcie->dev = dev; INIT_LIST_HEAD(&pcie->resources); @@ -1141,12 +1148,12 @@ static int rcar_pcie_probe(struct platform_device *pdev) err = rcar_pcie_get_resources(pcie); if (err < 0) { dev_err(dev, "failed to request resources: %d\n", err); - return err; + goto err_free_bridge; } err = rcar_pcie_parse_map_dma_ranges(pcie, dev->of_node); if (err) - return err; + goto err_free_bridge; pm_runtime_enable(dev); err = pm_runtime_get_sync(dev); @@ -1183,6 +1190,9 @@ static int rcar_pcie_probe(struct platform_device *pdev) return 0; +err_free_bridge: + pci_free_host_bridge(bridge); + err_pm_put: pm_runtime_put(dev); diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 0e020b6e0943..29332ba06bc1 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1284,6 +1284,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) struct rockchip_pcie *rockchip; struct device *dev = &pdev->dev; struct pci_bus *bus, *child; + struct pci_host_bridge *bridge; struct resource_entry *win; resource_size_t io_base; struct resource *mem; @@ -1295,10 +1296,12 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (!dev->of_node) return -ENODEV; - rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL); - if (!rockchip) + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rockchip)); + if (!bridge) return -ENOMEM; + rockchip = pci_host_bridge_priv(bridge); + platform_set_drvdata(pdev, rockchip); rockchip->dev = dev; @@ -1396,11 +1399,20 @@ static int rockchip_pcie_probe(struct platform_device *pdev) goto err_free_res; } - bus = pci_scan_root_bus(&pdev->dev, 0, &rockchip_pcie_ops, rockchip, &res); - if (!bus) { - err = -ENOMEM; + list_splice_init(&res, &bridge->windows); + bridge->dev.parent = &pdev->dev; + bridge->sysdata = rockchip; + bridge->busnr = 0; + bridge->ops = &rockchip_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; + + err = pci_scan_root_bus_bridge(bridge); + if (!err) goto err_free_res; - } + + bus = bridge->bus; + rockchip->root_bus = bus; pci_bus_size_bridges(bus); diff --git a/drivers/pci/host/pcie-xilinx-nwl.c b/drivers/pci/host/pcie-xilinx-nwl.c index 4b16b26ae909..d1f7e4ca5a5a 100644 --- a/drivers/pci/host/pcie-xilinx-nwl.c +++ b/drivers/pci/host/pcie-xilinx-nwl.c @@ -530,7 +530,7 @@ static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie) return 0; } -static int nwl_pcie_enable_msi(struct nwl_pcie *pcie, struct pci_bus *bus) +static int nwl_pcie_enable_msi(struct nwl_pcie *pcie) { struct device *dev = pcie->dev; struct platform_device *pdev = to_platform_device(dev); @@ -791,13 +791,16 @@ static int nwl_pcie_probe(struct platform_device *pdev) struct nwl_pcie *pcie; struct pci_bus *bus; struct pci_bus *child; + struct pci_host_bridge *bridge; int err; resource_size_t iobase = 0; LIST_HEAD(res); - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) - return -ENOMEM; + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); + if (!bridge) + return -ENODEV; + + pcie = pci_host_bridge_priv(bridge); pcie->dev = dev; pcie->ecam_value = NWL_ECAM_VALUE_DEFAULT; @@ -830,21 +833,28 @@ static int nwl_pcie_probe(struct platform_device *pdev) goto error; } - bus = pci_create_root_bus(dev, pcie->root_busno, - &nwl_pcie_ops, pcie, &res); - if (!bus) { - err = -ENOMEM; - goto error; - } + list_splice_init(&res, &bridge->windows); + bridge->dev.parent = dev; + bridge->sysdata = pcie; + bridge->busnr = pcie->root_busno; + bridge->ops = &nwl_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; if (IS_ENABLED(CONFIG_PCI_MSI)) { - err = nwl_pcie_enable_msi(pcie, bus); + err = nwl_pcie_enable_msi(pcie); if (err < 0) { dev_err(dev, "failed to enable MSI support: %d\n", err); goto error; } } - pci_scan_child_bus(bus); + + err = pci_scan_root_bus_bridge(bridge); + if (err) + goto error; + + bus = bridge->bus; + pci_assign_unassigned_bus_resources(bus); list_for_each_entry(child, &bus->children, node) pcie_bus_configure_settings(child); diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index 2fe2df51f9f8..d09b00579bde 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -633,6 +633,7 @@ static int xilinx_pcie_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct xilinx_pcie_port *port; struct pci_bus *bus, *child; + struct pci_host_bridge *bridge; int err; resource_size_t iobase = 0; LIST_HEAD(res); @@ -640,9 +641,11 @@ static int xilinx_pcie_probe(struct platform_device *pdev) if (!dev->of_node) return -ENODEV; - port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); - if (!port) - return -ENOMEM; + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port)); + if (!bridge) + return -ENODEV; + + port = pci_host_bridge_priv(bridge); port->dev = dev; @@ -671,21 +674,26 @@ static int xilinx_pcie_probe(struct platform_device *pdev) if (err) goto error; - bus = pci_create_root_bus(dev, 0, &xilinx_pcie_ops, port, &res); - if (!bus) { - err = -ENOMEM; - goto error; - } + + list_splice_init(&res, &bridge->windows); + bridge->dev.parent = dev; + bridge->sysdata = port; + bridge->busnr = 0; + bridge->ops = &xilinx_pcie_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; #ifdef CONFIG_PCI_MSI xilinx_pcie_msi_chip.dev = dev; - bus->msi = &xilinx_pcie_msi_chip; + bridge->msi = &xilinx_pcie_msi_chip; #endif - pci_scan_child_bus(bus); + err = pci_scan_root_bus_bridge(bridge); + if (err < 0) + goto error; + + bus = bridge->bus; + pci_assign_unassigned_bus_resources(bus); -#ifndef CONFIG_MICROBLAZE - pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); -#endif list_for_each_entry(child, &bus->children, node) pcie_bus_configure_settings(child); pci_bus_add_devices(bus); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index b399fa31e0a2..50f93a3bc4c0 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -412,6 +412,8 @@ static int pci_device_probe(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_driver *drv = to_pci_driver(dev->driver); + pci_assign_irq(pci_dev); + error = pcibios_alloc_irq(pci_dev); if (error < 0) return error; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 7fedfeb0871d..c31310db0404 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -510,16 +510,18 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent) return b; } -static void pci_release_host_bridge_dev(struct device *dev) +static void devm_pci_release_host_bridge_dev(struct device *dev) { struct pci_host_bridge *bridge = to_pci_host_bridge(dev); if (bridge->release_fn) bridge->release_fn(bridge); +} - pci_free_resource_list(&bridge->windows); - - kfree(bridge); +static void pci_release_host_bridge_dev(struct device *dev) +{ + devm_pci_release_host_bridge_dev(dev); + pci_free_host_bridge(to_pci_host_bridge(dev)); } struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) @@ -531,11 +533,36 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) return NULL; INIT_LIST_HEAD(&bridge->windows); + bridge->dev.release = pci_release_host_bridge_dev; return bridge; } EXPORT_SYMBOL(pci_alloc_host_bridge); +struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev, + size_t priv) +{ + struct pci_host_bridge *bridge; + + bridge = devm_kzalloc(dev, sizeof(*bridge) + priv, GFP_KERNEL); + if (!bridge) + return NULL; + + INIT_LIST_HEAD(&bridge->windows); + bridge->dev.release = devm_pci_release_host_bridge_dev; + + return bridge; +} +EXPORT_SYMBOL(devm_pci_alloc_host_bridge); + +void pci_free_host_bridge(struct pci_host_bridge *bridge) +{ + pci_free_resource_list(&bridge->windows); + + kfree(bridge); +} +EXPORT_SYMBOL(pci_free_host_bridge); + static const unsigned char pcix_bus_speed[] = { PCI_SPEED_UNKNOWN, /* 0 */ PCI_SPEED_66MHz_PCIX, /* 1 */ @@ -719,7 +746,7 @@ static void pci_set_bus_msi_domain(struct pci_bus *bus) dev_set_msi_domain(&bus->dev, d); } -int pci_register_host_bridge(struct pci_host_bridge *bridge) +static int pci_register_host_bridge(struct pci_host_bridge *bridge) { struct device *parent = bridge->dev.parent; struct resource_entry *window, *n; @@ -834,7 +861,6 @@ free: kfree(bus); return err; } -EXPORT_SYMBOL(pci_register_host_bridge); static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) @@ -2333,9 +2359,8 @@ void __weak pcibios_remove_bus(struct pci_bus *bus) { } -static struct pci_bus *pci_create_root_bus_msi(struct device *parent, - int bus, struct pci_ops *ops, void *sysdata, - struct list_head *resources, struct msi_controller *msi) +struct pci_bus *pci_create_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, struct list_head *resources) { int error; struct pci_host_bridge *bridge; @@ -2345,13 +2370,11 @@ static struct pci_bus *pci_create_root_bus_msi(struct device *parent, return NULL; bridge->dev.parent = parent; - bridge->dev.release = pci_release_host_bridge_dev; list_splice_init(resources, &bridge->windows); bridge->sysdata = sysdata; bridge->busnr = bus; bridge->ops = ops; - bridge->msi = msi; error = pci_register_host_bridge(bridge); if (error < 0) @@ -2363,13 +2386,6 @@ err_out: kfree(bridge); return NULL; } - -struct pci_bus *pci_create_root_bus(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, struct list_head *resources) -{ - return pci_create_root_bus_msi(parent, bus, ops, sysdata, resources, - NULL); -} EXPORT_SYMBOL_GPL(pci_create_root_bus); int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) @@ -2435,9 +2451,47 @@ void pci_bus_release_busn_res(struct pci_bus *b) res, ret ? "can not be" : "is"); } -struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, - struct list_head *resources, struct msi_controller *msi) +int pci_scan_root_bus_bridge(struct pci_host_bridge *bridge) +{ + struct resource_entry *window; + bool found = false; + struct pci_bus *b; + int max, bus, ret; + + if (!bridge) + return -EINVAL; + + resource_list_for_each_entry(window, &bridge->windows) + if (window->res->flags & IORESOURCE_BUS) { + found = true; + break; + } + + ret = pci_register_host_bridge(bridge); + if (ret < 0) + return ret; + + b = bridge->bus; + bus = bridge->busnr; + + if (!found) { + dev_info(&b->dev, + "No busn resource found for root bus, will use [bus %02x-ff]\n", + bus); + pci_bus_insert_busn_res(b, bus, 255); + } + + max = pci_scan_child_bus(b); + + if (!found) + pci_bus_update_busn_res_end(b, max); + + return 0; +} +EXPORT_SYMBOL(pci_scan_root_bus_bridge); + +struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, struct list_head *resources) { struct resource_entry *window; bool found = false; @@ -2450,7 +2504,7 @@ struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, break; } - b = pci_create_root_bus_msi(parent, bus, ops, sysdata, resources, msi); + b = pci_create_root_bus(parent, bus, ops, sysdata, resources); if (!b) return NULL; @@ -2468,13 +2522,6 @@ struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, return b; } - -struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, struct list_head *resources) -{ - return pci_scan_root_bus_msi(parent, bus, ops, sysdata, resources, - NULL); -} EXPORT_SYMBOL(pci_scan_root_bus); struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 95c225be49d1..81eda3d93a5d 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -15,6 +15,7 @@ #include #include #include +#include "pci.h" void __weak pcibios_update_irq(struct pci_dev *dev, int irq) { @@ -22,12 +23,17 @@ void __weak pcibios_update_irq(struct pci_dev *dev, int irq) pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } -static void pdev_fixup_irq(struct pci_dev *dev, - u8 (*swizzle)(struct pci_dev *, u8 *), - int (*map_irq)(const struct pci_dev *, u8, u8)) +void pci_assign_irq(struct pci_dev *dev) { - u8 pin, slot; + u8 pin; + u8 slot = -1; int irq = 0; + struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus); + + if (!(hbrg->map_irq)) { + dev_dbg(&dev->dev, "runtime IRQ mapping not provided by arch\n"); + return; + } /* If this device is not on the primary bus, we need to figure out which interrupt pin it will come in on. We know which slot it @@ -40,17 +46,22 @@ static void pdev_fixup_irq(struct pci_dev *dev, if (pin > 4) pin = 1; - if (pin != 0) { + if (pin) { /* Follow the chain of bridges, swizzling as we go. */ - slot = (*swizzle)(dev, &pin); + if (hbrg->swizzle_irq) + slot = (*(hbrg->swizzle_irq))(dev, &pin); - irq = (*map_irq)(dev, slot, pin); + /* + * If a swizzling function is not used map_irq must + * ignore slot + */ + irq = (*(hbrg->map_irq))(dev, slot, pin); if (irq == -1) irq = 0; } dev->irq = irq; - dev_dbg(&dev->dev, "fixup irq: got %d\n", dev->irq); + dev_dbg(&dev->dev, "assign IRQ: got %d\n", dev->irq); /* Always tell the device, so the driver knows what is the real IRQ to use; the device does not use it. */ @@ -60,9 +71,23 @@ static void pdev_fixup_irq(struct pci_dev *dev, void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), int (*map_irq)(const struct pci_dev *, u8, u8)) { + /* + * Implement pci_fixup_irqs() through pci_assign_irq(). + * This code should be remove eventually, it is a wrapper + * around pci_assign_irq() interface to keep current + * pci_fixup_irqs() behaviour unchanged on architecture + * code still relying on its interface. + */ struct pci_dev *dev = NULL; + struct pci_host_bridge *hbrg = NULL; - for_each_pci_dev(dev) - pdev_fixup_irq(dev, swizzle, map_irq); + for_each_pci_dev(dev) { + hbrg = pci_find_host_bridge(dev->bus); + hbrg->swizzle_irq = swizzle; + hbrg->map_irq = map_irq; + pci_assign_irq(dev); + hbrg->swizzle_irq = NULL; + hbrg->map_irq = NULL; + } } EXPORT_SYMBOL_GPL(pci_fixup_irqs); diff --git a/include/linux/pci.h b/include/linux/pci.h index 9a6b4c458d9a..bd68ed11b394 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -445,6 +445,8 @@ struct pci_host_bridge { void *sysdata; int busnr; struct list_head windows; /* resource_entry */ + u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* platform IRQ swizzler */ + int (*map_irq)(const struct pci_dev *, u8, u8); void (*release_fn)(struct pci_host_bridge *); void *release_data; struct msi_controller *msi; @@ -471,7 +473,9 @@ static inline struct pci_host_bridge *pci_host_bridge_from_priv(void *priv) } struct pci_host_bridge *pci_alloc_host_bridge(size_t priv); -int pci_register_host_bridge(struct pci_host_bridge *bridge); +struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev, + size_t priv); +void pci_free_host_bridge(struct pci_host_bridge *bridge); struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus); void pci_set_host_bridge_release(struct pci_host_bridge *bridge, @@ -861,13 +865,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax); int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax); void pci_bus_release_busn_res(struct pci_bus *b); -struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, - struct list_head *resources, - struct msi_controller *msi); struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources); +int pci_scan_root_bus_bridge(struct pci_host_bridge *bridge); struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); void pcie_update_link_speed(struct pci_bus *bus, u16 link_status); @@ -1168,6 +1169,7 @@ void pdev_enable_device(struct pci_dev *); int pci_enable_resources(struct pci_dev *, int mask); void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), int (*)(const struct pci_dev *, u8, u8)); +void pci_assign_irq(struct pci_dev *dev); struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res); #define HAVE_PCI_REQ_REGIONS 2 int __must_check pci_request_regions(struct pci_dev *, const char *);