diff options
Diffstat (limited to 'drivers/pci')
81 files changed, 4034 insertions, 2139 deletions
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 17d2b07ee67..e04fe2d9df3 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -33,21 +33,14 @@ obj-$(CONFIG_PCI_IOV) += iov.o # # Some architectures use the generic PCI setup functions # -obj-$(CONFIG_X86) += setup-bus.o -obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o -obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o -obj-$(CONFIG_UNICORE32) += setup-bus.o setup-irq.o -obj-$(CONFIG_PARISC) += setup-bus.o -obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o -obj-$(CONFIG_PPC) += setup-bus.o -obj-$(CONFIG_FRV) += setup-bus.o -obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o -obj-$(CONFIG_X86_VISWS) += setup-irq.o -obj-$(CONFIG_MN10300) += setup-bus.o -obj-$(CONFIG_MICROBLAZE) += setup-bus.o -obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o -obj-$(CONFIG_SPARC_LEON) += setup-bus.o setup-irq.o -obj-$(CONFIG_M68K) += setup-bus.o setup-irq.o +obj-$(CONFIG_ALPHA) += setup-irq.o +obj-$(CONFIG_ARM) += 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 diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 7f8b78c0887..d292d7cb341 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -148,7 +148,7 @@ static noinline void pci_wait_cfg(struct pci_dev *dev) int pci_user_read_config_##size \ (struct pci_dev *dev, int pos, type *val) \ { \ - int ret = 0; \ + int ret = PCIBIOS_SUCCESSFUL; \ u32 data = -1; \ if (PCI_##size##_BAD) \ return -EINVAL; \ @@ -159,9 +159,7 @@ int pci_user_read_config_##size \ pos, sizeof(type), &data); \ raw_spin_unlock_irq(&pci_lock); \ *val = (type)data; \ - if (ret > 0) \ - ret = -EINVAL; \ - return ret; \ + return pcibios_err_to_errno(ret); \ } \ EXPORT_SYMBOL_GPL(pci_user_read_config_##size); @@ -170,7 +168,7 @@ EXPORT_SYMBOL_GPL(pci_user_read_config_##size); int pci_user_write_config_##size \ (struct pci_dev *dev, int pos, type val) \ { \ - int ret = -EIO; \ + int ret = PCIBIOS_SUCCESSFUL; \ if (PCI_##size##_BAD) \ return -EINVAL; \ raw_spin_lock_irq(&pci_lock); \ @@ -179,9 +177,7 @@ int pci_user_write_config_##size \ ret = dev->bus->ops->write(dev->bus, dev->devfn, \ pos, sizeof(type), val); \ raw_spin_unlock_irq(&pci_lock); \ - if (ret > 0) \ - ret = -EINVAL; \ - return ret; \ + return pcibios_err_to_errno(ret); \ } \ EXPORT_SYMBOL_GPL(pci_user_write_config_##size); @@ -235,10 +231,7 @@ static int pci_vpd_pci22_wait(struct pci_dev *dev) } if (time_after(jiffies, timeout)) { - dev_printk(KERN_DEBUG, &dev->dev, - "vpd r/w failed. This is likely a firmware " - "bug on this device. Contact the card " - "vendor for a firmware update."); + dev_printk(KERN_DEBUG, &dev->dev, "vpd r/w failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n"); return -ETIMEDOUT; } if (fatal_signal_pending(current)) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 38901665c77..73aef51a28f 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -13,7 +13,6 @@ #include <linux/errno.h> #include <linux/ioport.h> #include <linux/proc_fs.h> -#include <linux/init.h> #include <linux/slab.h> #include "pci.h" @@ -132,7 +131,7 @@ static void pci_clip_resource_to_region(struct pci_bus *bus, static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, resource_size_t size, resource_size_t align, - resource_size_t min, unsigned int type_mask, + resource_size_t min, unsigned long type_mask, resource_size_t (*alignf)(void *, const struct resource *, resource_size_t, @@ -144,7 +143,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, struct resource *r, avail; resource_size_t max; - type_mask |= IORESOURCE_IO | IORESOURCE_MEM; + type_mask |= IORESOURCE_TYPE_BITS; pci_bus_for_each_resource(bus, r, i) { if (!r) @@ -200,7 +199,7 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, */ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t size, resource_size_t align, - resource_size_t min, unsigned int type_mask, + resource_size_t min, unsigned long type_mask, resource_size_t (*alignf)(void *, const struct resource *, resource_size_t, @@ -227,6 +226,7 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, type_mask, alignf, alignf_data, &pci_32_bit); } +EXPORT_SYMBOL(pci_bus_alloc_resource); void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } @@ -236,7 +236,7 @@ void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } * * This adds add sysfs entries and start device drivers */ -int pci_bus_add_device(struct pci_dev *dev) +void pci_bus_add_device(struct pci_dev *dev) { int retval; @@ -253,9 +253,8 @@ int pci_bus_add_device(struct pci_dev *dev) WARN_ON(retval < 0); dev->is_added = 1; - - return 0; } +EXPORT_SYMBOL_GPL(pci_bus_add_device); /** * pci_bus_add_devices - start driver for PCI devices @@ -267,16 +266,12 @@ void pci_bus_add_devices(const struct pci_bus *bus) { struct pci_dev *dev; struct pci_bus *child; - int retval; list_for_each_entry(dev, &bus->devices, bus_list) { /* Skip already-added devices */ if (dev->is_added) continue; - retval = pci_bus_add_device(dev); - if (retval) - dev_err(&dev->dev, "Error adding device (%d)\n", - retval); + pci_bus_add_device(dev); } list_for_each_entry(dev, &bus->devices, bus_list) { @@ -286,6 +281,7 @@ void pci_bus_add_devices(const struct pci_bus *bus) pci_bus_add_devices(child); } } +EXPORT_SYMBOL(pci_bus_add_devices); /** pci_walk_bus - walk devices on/under bus, calling callback. * @top bus whose devices should be walked @@ -351,6 +347,3 @@ void pci_bus_put(struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_put); -EXPORT_SYMBOL(pci_bus_alloc_resource); -EXPORT_SYMBOL_GPL(pci_bus_add_device); -EXPORT_SYMBOL(pci_bus_add_devices); diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c index 47aaf22d814..0e5f3c95af5 100644 --- a/drivers/pci/host-bridge.c +++ b/drivers/pci/host-bridge.c @@ -3,7 +3,6 @@ */ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/pci.h> #include <linux/module.h> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 47d46c6d846..21df477be0c 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -27,10 +27,23 @@ config PCI_TEGRA config PCI_RCAR_GEN2 bool "Renesas R-Car Gen2 Internal PCI controller" - depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST) + depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST) help Say Y here if you want internal PCI support on R-Car Gen2 SoC. There are 3 internal PCI controllers available with a single built-in EHCI/OHCI host controller present on each one. +config PCI_RCAR_GEN2_PCIE + bool "Renesas R-Car PCIe controller" + depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST) + help + Say Y here if you want PCIe controller support on R-Car Gen2 SoCs. + +config PCI_HOST_GENERIC + bool "Generic PCI host controller" + depends on ARM && OF + help + Say Y here if you want to support a simple generic PCI host + controller, such as the one emulated by kvmtool. + endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 13fb3333aa0..611ba4b48c9 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -4,3 +4,5 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o +obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o +obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index 3de6bfbbe8e..c5d0ca38450 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -415,9 +415,7 @@ static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg) { struct pcie_port *pp = arg; - dw_handle_msi_irq(pp); - - return IRQ_HANDLED; + return dw_handle_msi_irq(pp); } static void exynos_pcie_msi_init(struct pcie_port *pp) @@ -511,7 +509,8 @@ static struct pcie_host_ops exynos_pcie_host_ops = { .host_init = exynos_pcie_host_init, }; -static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) +static int __init add_pcie_port(struct pcie_port *pp, + struct platform_device *pdev) { int ret; @@ -546,7 +545,6 @@ static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) pp->root_bus_nr = -1; pp->ops = &exynos_pcie_host_ops; - spin_lock_init(&pp->conf_lock); ret = dw_pcie_host_init(pp); if (ret) { dev_err(&pdev->dev, "failed to initialize host\n"); @@ -568,10 +566,8 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) exynos_pcie = devm_kzalloc(&pdev->dev, sizeof(*exynos_pcie), GFP_KERNEL); - if (!exynos_pcie) { - dev_err(&pdev->dev, "no memory for exynos pcie\n"); + if (!exynos_pcie) return -ENOMEM; - } pp = &exynos_pcie->pp; diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c new file mode 100644 index 00000000000..44fe6aa6a43 --- /dev/null +++ b/drivers/pci/host/pci-host-generic.c @@ -0,0 +1,388 @@ +/* + * Simple, generic PCI host controller driver targetting firmware-initialised + * systems and virtual machines (e.g. the PCI emulation provided by kvmtool). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Copyright (C) 2014 ARM Limited + * + * Author: Will Deacon <will.deacon@arm.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_pci.h> +#include <linux/platform_device.h> + +struct gen_pci_cfg_bus_ops { + u32 bus_shift; + void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int); +}; + +struct gen_pci_cfg_windows { + struct resource res; + struct resource bus_range; + void __iomem **win; + + const struct gen_pci_cfg_bus_ops *ops; +}; + +struct gen_pci { + struct pci_host_bridge host; + struct gen_pci_cfg_windows cfg; + struct list_head resources; +}; + +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; + resource_size_t idx = bus->number - pci->cfg.bus_range.start; + + return pci->cfg.win[idx] + ((devfn << 8) | where); +} + +static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = { + .bus_shift = 16, + .map_bus = gen_pci_map_cfg_bus_cam, +}; + +static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, + unsigned int devfn, + int where) +{ + struct pci_sys_data *sys = bus->sysdata; + struct gen_pci *pci = sys->private_data; + resource_size_t idx = bus->number - pci->cfg.bus_range.start; + + return pci->cfg.win[idx] + ((devfn << 12) | where); +} + +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 int gen_pci_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + void __iomem *addr; + struct pci_sys_data *sys = bus->sysdata; + struct gen_pci *pci = sys->private_data; + + addr = pci->cfg.ops->map_bus(bus, devfn, where); + + switch (size) { + case 1: + *val = readb(addr); + break; + case 2: + *val = readw(addr); + break; + default: + *val = readl(addr); + } + + return PCIBIOS_SUCCESSFUL; +} + +static int gen_pci_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + void __iomem *addr; + struct pci_sys_data *sys = bus->sysdata; + struct gen_pci *pci = sys->private_data; + + addr = pci->cfg.ops->map_bus(bus, devfn, where); + + switch (size) { + case 1: + writeb(val, addr); + break; + case 2: + writew(val, addr); + break; + default: + writel(val, addr); + } + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops gen_pci_ops = { + .read = gen_pci_config_read, + .write = gen_pci_config_write, +}; + +static const struct of_device_id gen_pci_of_match[] = { + { .compatible = "pci-host-cam-generic", + .data = &gen_pci_cfg_cam_bus_ops }, + + { .compatible = "pci-host-ecam-generic", + .data = &gen_pci_cfg_ecam_bus_ops }, + + { }, +}; +MODULE_DEVICE_TABLE(of, gen_pci_of_match); + +static int gen_pci_calc_io_offset(struct device *dev, + struct of_pci_range *range, + struct resource *res, + resource_size_t *offset) +{ + static atomic_t wins = ATOMIC_INIT(0); + int err, idx, max_win; + unsigned int window; + + if (!PAGE_ALIGNED(range->cpu_addr)) + return -EINVAL; + + max_win = (IO_SPACE_LIMIT + 1) / SZ_64K; + idx = atomic_inc_return(&wins); + if (idx > max_win) + return -ENOSPC; + + window = (idx - 1) * SZ_64K; + err = pci_ioremap_io(window, range->cpu_addr); + if (err) + return err; + + of_pci_range_to_resource(range, dev->of_node, res); + res->start = window; + res->end = res->start + range->size - 1; + *offset = window - range->pci_addr; + return 0; +} + +static int gen_pci_calc_mem_offset(struct device *dev, + struct of_pci_range *range, + struct resource *res, + resource_size_t *offset) +{ + of_pci_range_to_resource(range, dev->of_node, res); + *offset = range->cpu_addr - range->pci_addr; + return 0; +} + +static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) +{ + struct pci_host_bridge_window *win; + + list_for_each_entry(win, &pci->resources, list) + release_resource(win->res); + + pci_free_resource_list(&pci->resources); +} + +static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) +{ + struct of_pci_range range; + struct of_pci_range_parser parser; + int err, res_valid = 0; + struct device *dev = pci->host.dev.parent; + struct device_node *np = dev->of_node; + + if (of_pci_range_parser_init(&parser, np)) { + dev_err(dev, "missing \"ranges\" property\n"); + return -EINVAL; + } + + for_each_of_pci_range(&parser, &range) { + struct resource *parent, *res; + resource_size_t offset; + u32 restype = range.flags & IORESOURCE_TYPE_BITS; + + res = devm_kmalloc(dev, sizeof(*res), GFP_KERNEL); + if (!res) { + err = -ENOMEM; + goto out_release_res; + } + + switch (restype) { + case IORESOURCE_IO: + parent = &ioport_resource; + err = gen_pci_calc_io_offset(dev, &range, res, &offset); + break; + case IORESOURCE_MEM: + parent = &iomem_resource; + err = gen_pci_calc_mem_offset(dev, &range, res, &offset); + res_valid |= !(res->flags & IORESOURCE_PREFETCH || err); + break; + default: + err = -EINVAL; + continue; + } + + if (err) { + dev_warn(dev, + "error %d: failed to add resource [type 0x%x, %lld bytes]\n", + err, restype, range.size); + continue; + } + + err = request_resource(parent, res); + if (err) + goto out_release_res; + + pci_add_resource_offset(&pci->resources, res, offset); + } + + 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; + u8 bus_max; + resource_size_t busn; + struct resource *bus_range; + struct device *dev = pci->host.dev.parent; + struct device_node *np = dev->of_node; + + if (of_pci_parse_bus_range(np, &pci->cfg.bus_range)) + pci->cfg.bus_range = (struct resource) { + .name = np->name, + .start = 0, + .end = 0xff, + .flags = IORESOURCE_BUS, + }; + + err = of_address_to_resource(np, 0, &pci->cfg.res); + if (err) { + dev_err(dev, "missing \"reg\" property\n"); + return err; + } + + pci->cfg.win = devm_kcalloc(dev, resource_size(&pci->cfg.bus_range), + sizeof(*pci->cfg.win), GFP_KERNEL); + if (!pci->cfg.win) + return -ENOMEM; + + /* Limit the bus-range to fit within reg */ + bus_max = pci->cfg.bus_range.start + + (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; + pci->cfg.bus_range.end = min_t(resource_size_t, pci->cfg.bus_range.end, + bus_max); + + /* Map our Configuration Space windows */ + if (!devm_request_mem_region(dev, pci->cfg.res.start, + resource_size(&pci->cfg.res), + "Configuration Space")) + return -ENOMEM; + + bus_range = &pci->cfg.bus_range; + for (busn = bus_range->start; busn <= bus_range->end; ++busn) { + u32 idx = busn - bus_range->start; + u32 sz = 1 << pci->cfg.ops->bus_shift; + + pci->cfg.win[idx] = devm_ioremap(dev, + pci->cfg.res.start + busn * sz, + sz); + if (!pci->cfg.win[idx]) + return -ENOMEM; + } + + /* Register bus resource */ + pci_add_resource(&pci->resources, bus_range); + return 0; +} + +static int gen_pci_setup(int nr, struct pci_sys_data *sys) +{ + struct gen_pci *pci = sys->private_data; + list_splice_init(&pci->resources, &sys->resources); + return 1; +} + +static int gen_pci_probe(struct platform_device *pdev) +{ + int err; + const char *type; + const struct of_device_id *of_id; + const int *prop; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + 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, + }; + + if (!pci) + return -ENOMEM; + + type = of_get_property(np, "device_type", NULL); + if (!type || strcmp(type, "pci")) { + dev_err(dev, "invalid \"device_type\" %s\n", type); + return -EINVAL; + } + + prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL); + if (prop) { + if (*prop) + pci_add_flags(PCI_PROBE_ONLY); + else + pci_clear_flags(PCI_PROBE_ONLY); + } + + of_id = of_match_node(gen_pci_of_match, np); + pci->cfg.ops = of_id->data; + pci->host.dev.parent = dev; + 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); + if (err) + return err; + + /* 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; + } + + pci_common_init_dev(dev, &hw); + return 0; +} + +static struct platform_driver gen_pci_driver = { + .driver = { + .name = "pci-host-generic", + .owner = THIS_MODULE, + .of_match_table = gen_pci_of_match, + }, + .probe = gen_pci_probe, +}; +module_platform_driver(gen_pci_driver); + +MODULE_DESCRIPTION("Generic PCI host driver"); +MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index e8663a8c340..a568efaa331 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -25,6 +25,7 @@ #include <linux/resource.h> #include <linux/signal.h> #include <linux/types.h> +#include <linux/interrupt.h> #include "pcie-designware.h" @@ -32,13 +33,9 @@ struct imx6_pcie { int reset_gpio; - int power_on_gpio; - int wake_up_gpio; - int disable_gpio; - struct clk *lvds_gate; - struct clk *sata_ref_100m; - struct clk *pcie_ref_125m; - struct clk *pcie_axi; + struct clk *pcie_bus; + struct clk *pcie_phy; + struct clk *pcie; struct pcie_port pp; struct regmap *iomuxc_gpr; void __iomem *mem_base; @@ -231,36 +228,27 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); int ret; - if (gpio_is_valid(imx6_pcie->power_on_gpio)) - gpio_set_value(imx6_pcie->power_on_gpio, 1); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); - ret = clk_prepare_enable(imx6_pcie->sata_ref_100m); + ret = clk_prepare_enable(imx6_pcie->pcie_phy); if (ret) { - dev_err(pp->dev, "unable to enable sata_ref_100m\n"); - goto err_sata_ref; + dev_err(pp->dev, "unable to enable pcie_phy clock\n"); + goto err_pcie_phy; } - ret = clk_prepare_enable(imx6_pcie->pcie_ref_125m); + ret = clk_prepare_enable(imx6_pcie->pcie_bus); if (ret) { - dev_err(pp->dev, "unable to enable pcie_ref_125m\n"); - goto err_pcie_ref; + dev_err(pp->dev, "unable to enable pcie_bus clock\n"); + goto err_pcie_bus; } - ret = clk_prepare_enable(imx6_pcie->lvds_gate); + ret = clk_prepare_enable(imx6_pcie->pcie); if (ret) { - dev_err(pp->dev, "unable to enable lvds_gate\n"); - goto err_lvds_gate; - } - - ret = clk_prepare_enable(imx6_pcie->pcie_axi); - if (ret) { - dev_err(pp->dev, "unable to enable pcie_axi\n"); - goto err_pcie_axi; + dev_err(pp->dev, "unable to enable pcie clock\n"); + goto err_pcie; } /* allow the clocks to stabilize */ @@ -274,13 +262,11 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) } return 0; -err_pcie_axi: - clk_disable_unprepare(imx6_pcie->lvds_gate); -err_lvds_gate: - clk_disable_unprepare(imx6_pcie->pcie_ref_125m); -err_pcie_ref: - clk_disable_unprepare(imx6_pcie->sata_ref_100m); -err_sata_ref: +err_pcie: + clk_disable_unprepare(imx6_pcie->pcie_bus); +err_pcie_bus: + clk_disable_unprepare(imx6_pcie->pcie_phy); +err_pcie_phy: return ret; } @@ -329,6 +315,13 @@ static int imx6_pcie_wait_for_link(struct pcie_port *pp) return 0; } +static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg) +{ + struct pcie_port *pp = arg; + + return dw_handle_msi_irq(pp); +} + static int imx6_pcie_start_link(struct pcie_port *pp) { struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); @@ -403,6 +396,9 @@ static void imx6_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); imx6_pcie_start_link(pp); + + if (IS_ENABLED(CONFIG_PCI_MSI)) + dw_pcie_msi_init(pp); } static void imx6_pcie_reset_phy(struct pcie_port *pp) @@ -424,20 +420,40 @@ static void imx6_pcie_reset_phy(struct pcie_port *pp) static int imx6_pcie_link_up(struct pcie_port *pp) { - u32 rc, ltssm, rx_valid; + u32 rc, debug_r0, rx_valid; + int count = 5; /* - * Test if the PHY reports that the link is up and also that - * the link training finished. It might happen that the PHY - * reports the link is already up, but the link training bit - * is still set, so make sure to check the training is done - * as well here. + * Test if the PHY reports that the link is up and also that the LTSSM + * training finished. There are three possible states of the link when + * this code is called: + * 1) The link is DOWN (unlikely) + * The link didn't come up yet for some reason. This usually means + * we have a real problem somewhere. Reset the PHY and exit. This + * state calls for inspection of the DEBUG registers. + * 2) The link is UP, but still in LTSSM training + * Wait for the training to finish, which should take a very short + * time. If the training does not finish, we have a problem and we + * need to inspect the DEBUG registers. If the training does finish, + * the link is up and operating correctly. + * 3) The link is UP and no longer in LTSSM training + * The link is up and operating correctly. */ - rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1); - if ((rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) && - !(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING)) - return 1; - + while (1) { + rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1); + if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP)) + break; + if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING)) + return 1; + if (!count--) + break; + dev_dbg(pp->dev, "Link is up, but still in training\n"); + /* + * Wait a little bit, then re-check if the link finished + * the training. + */ + usleep_range(1000, 2000); + } /* * From L0, initiate MAC entry to gen2 if EP/RC supports gen2. * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2). @@ -446,15 +462,16 @@ static int imx6_pcie_link_up(struct pcie_port *pp) * to gen2 is stuck */ pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid); - ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F; + debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0); if (rx_valid & 0x01) return 0; - if (ltssm != 0x0d) + if ((debug_r0 & 0x3f) != 0x0d) return 0; dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n"); + dev_dbg(pp->dev, "debug_r0=%08x debug_r1=%08x\n", debug_r0, rc); imx6_pcie_reset_phy(pp); @@ -466,21 +483,30 @@ static struct pcie_host_ops imx6_pcie_host_ops = { .host_init = imx6_pcie_host_init, }; -static int imx6_add_pcie_port(struct pcie_port *pp, +static int __init imx6_add_pcie_port(struct pcie_port *pp, struct platform_device *pdev) { int ret; - pp->irq = platform_get_irq(pdev, 0); - if (!pp->irq) { - dev_err(&pdev->dev, "failed to get irq\n"); - return -ENODEV; + if (IS_ENABLED(CONFIG_PCI_MSI)) { + pp->msi_irq = platform_get_irq_byname(pdev, "msi"); + if (pp->msi_irq <= 0) { + dev_err(&pdev->dev, "failed to get MSI irq\n"); + return -ENODEV; + } + + ret = devm_request_irq(&pdev->dev, pp->msi_irq, + imx6_pcie_msi_handler, + IRQF_SHARED, "mx6-pcie-msi", pp); + if (ret) { + dev_err(&pdev->dev, "failed to request MSI irq\n"); + return -ENODEV; + } } pp->root_bus_nr = -1; pp->ops = &imx6_pcie_host_ops; - spin_lock_init(&pp->conf_lock); ret = dw_pcie_host_init(pp); if (ret) { dev_err(&pdev->dev, "failed to initialize host\n"); @@ -525,69 +551,26 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) } } - imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0); - if (gpio_is_valid(imx6_pcie->power_on_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, - imx6_pcie->power_on_gpio, - GPIOF_OUT_INIT_LOW, - "PCIe power enable"); - if (ret) { - dev_err(&pdev->dev, "unable to get power-on gpio\n"); - return ret; - } - } - - imx6_pcie->wake_up_gpio = of_get_named_gpio(np, "wake-up-gpio", 0); - if (gpio_is_valid(imx6_pcie->wake_up_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, - imx6_pcie->wake_up_gpio, - GPIOF_IN, - "PCIe wake up"); - if (ret) { - dev_err(&pdev->dev, "unable to get wake-up gpio\n"); - return ret; - } - } - - imx6_pcie->disable_gpio = of_get_named_gpio(np, "disable-gpio", 0); - if (gpio_is_valid(imx6_pcie->disable_gpio)) { - ret = devm_gpio_request_one(&pdev->dev, - imx6_pcie->disable_gpio, - GPIOF_OUT_INIT_HIGH, - "PCIe disable endpoint"); - if (ret) { - dev_err(&pdev->dev, "unable to get disable-ep gpio\n"); - return ret; - } - } - /* Fetch clocks */ - imx6_pcie->lvds_gate = devm_clk_get(&pdev->dev, "lvds_gate"); - if (IS_ERR(imx6_pcie->lvds_gate)) { - dev_err(&pdev->dev, - "lvds_gate clock select missing or invalid\n"); - return PTR_ERR(imx6_pcie->lvds_gate); - } - - imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m"); - if (IS_ERR(imx6_pcie->sata_ref_100m)) { + imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy"); + if (IS_ERR(imx6_pcie->pcie_phy)) { dev_err(&pdev->dev, - "sata_ref_100m clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->sata_ref_100m); + "pcie_phy clock source missing or invalid\n"); + return PTR_ERR(imx6_pcie->pcie_phy); } - imx6_pcie->pcie_ref_125m = devm_clk_get(&pdev->dev, "pcie_ref_125m"); - if (IS_ERR(imx6_pcie->pcie_ref_125m)) { + imx6_pcie->pcie_bus = devm_clk_get(&pdev->dev, "pcie_bus"); + if (IS_ERR(imx6_pcie->pcie_bus)) { dev_err(&pdev->dev, - "pcie_ref_125m clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie_ref_125m); + "pcie_bus clock source missing or invalid\n"); + return PTR_ERR(imx6_pcie->pcie_bus); } - imx6_pcie->pcie_axi = devm_clk_get(&pdev->dev, "pcie_axi"); - if (IS_ERR(imx6_pcie->pcie_axi)) { + imx6_pcie->pcie = devm_clk_get(&pdev->dev, "pcie"); + if (IS_ERR(imx6_pcie->pcie)) { dev_err(&pdev->dev, - "pcie_axi clock source missing or invalid\n"); - return PTR_ERR(imx6_pcie->pcie_axi); + "pcie clock source missing or invalid\n"); + return PTR_ERR(imx6_pcie->pcie); } /* Grab GPR config register range */ diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 13478ecd411..ce23e0f076b 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -60,14 +60,6 @@ #define PCIE_DEBUG_CTRL 0x1a60 #define PCIE_DEBUG_SOFT_RESET BIT(20) -/* - * This product ID is registered by Marvell, and used when the Marvell - * SoC is not the root complex, but an endpoint on the PCIe bus. It is - * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI - * bridge. - */ -#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846 - /* PCI configuration space of a PCI-to-PCI bridge */ struct mvebu_sw_pci_bridge { u16 vendor; @@ -109,7 +101,9 @@ struct mvebu_pcie { struct mvebu_pcie_port *ports; struct msi_chip *msi; struct resource io; + char io_name[30]; struct resource realio; + char mem_name[30]; struct resource mem; struct resource busn; int nports; @@ -119,7 +113,6 @@ struct mvebu_pcie { struct mvebu_pcie_port { char *name; void __iomem *base; - spinlock_t conf_lock; u32 port; u32 lane; int devfn; @@ -299,6 +292,60 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port, return PCIBIOS_SUCCESSFUL; } +/* + * Remove windows, starting from the largest ones to the smallest + * ones. + */ +static void mvebu_pcie_del_windows(struct mvebu_pcie_port *port, + phys_addr_t base, size_t size) +{ + while (size) { + size_t sz = 1 << (fls(size) - 1); + + mvebu_mbus_del_window(base, sz); + base += sz; + size -= sz; + } +} + +/* + * MBus windows can only have a power of two size, but PCI BARs do not + * have this constraint. Therefore, we have to split the PCI BAR into + * areas each having a power of two size. We start from the largest + * one (i.e highest order bit set in the size). + */ +static void mvebu_pcie_add_windows(struct mvebu_pcie_port *port, + unsigned int target, unsigned int attribute, + phys_addr_t base, size_t size, + phys_addr_t remap) +{ + size_t size_mapped = 0; + + while (size) { + size_t sz = 1 << (fls(size) - 1); + int ret; + + ret = mvebu_mbus_add_window_remap_by_id(target, attribute, base, + sz, remap); + if (ret) { + phys_addr_t end = base + sz - 1; + + dev_err(&port->pcie->pdev->dev, + "Could not create MBus window at [mem %pa-%pa]: %d\n", + &base, &end, ret); + mvebu_pcie_del_windows(port, base - size_mapped, + size_mapped); + return; + } + + size -= sz; + size_mapped += sz; + base += sz; + if (remap != MVEBU_MBUS_NO_REMAP) + remap += sz; + } +} + static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) { phys_addr_t iobase; @@ -310,8 +357,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) /* If a window was configured, remove it */ if (port->iowin_base) { - mvebu_mbus_del_window(port->iowin_base, - port->iowin_size); + mvebu_pcie_del_windows(port, port->iowin_base, + port->iowin_size); port->iowin_base = 0; port->iowin_size = 0; } @@ -337,11 +384,11 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) port->iowin_base = port->pcie->io.start + iobase; port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) | (port->bridge.iolimitupper << 16)) - - iobase); + iobase) + 1; - mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, - port->iowin_base, port->iowin_size, - iobase); + mvebu_pcie_add_windows(port, port->io_target, port->io_attr, + port->iowin_base, port->iowin_size, + iobase); } static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) @@ -352,8 +399,8 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) /* If a window was configured, remove it */ if (port->memwin_base) { - mvebu_mbus_del_window(port->memwin_base, - port->memwin_size); + mvebu_pcie_del_windows(port, port->memwin_base, + port->memwin_size); port->memwin_base = 0; port->memwin_size = 0; } @@ -370,10 +417,11 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16); port->memwin_size = (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - - port->memwin_base; + port->memwin_base + 1; - mvebu_mbus_add_window_by_id(port->mem_target, port->mem_attr, - port->memwin_base, port->memwin_size); + mvebu_pcie_add_windows(port, port->mem_target, port->mem_attr, + port->memwin_base, port->memwin_size, + MVEBU_MBUS_NO_REMAP); } /* @@ -388,7 +436,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port) bridge->class = PCI_CLASS_BRIDGE_PCI; bridge->vendor = PCI_VENDOR_ID_MARVELL; - bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID; + bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16; + bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff; bridge->header_type = PCI_HEADER_TYPE_BRIDGE; bridge->cache_line_size = 0x10; @@ -565,9 +614,9 @@ static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys) return sys->private_data; } -static struct mvebu_pcie_port * -mvebu_pcie_find_port(struct mvebu_pcie *pcie, struct pci_bus *bus, - int devfn) +static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie, + struct pci_bus *bus, + int devfn) { int i; @@ -590,7 +639,6 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, { struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); struct mvebu_pcie_port *port; - unsigned long flags; int ret; port = mvebu_pcie_find_port(pcie, bus, devfn); @@ -616,10 +664,8 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, return PCIBIOS_DEVICE_NOT_FOUND; /* Access the real PCIe interface */ - spin_lock_irqsave(&port->conf_lock, flags); ret = mvebu_pcie_hw_wr_conf(port, bus, devfn, where, size, val); - spin_unlock_irqrestore(&port->conf_lock, flags); return ret; } @@ -630,7 +676,6 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, { struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); struct mvebu_pcie_port *port; - unsigned long flags; int ret; port = mvebu_pcie_find_port(pcie, bus, devfn); @@ -662,10 +707,8 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, } /* Access the real PCIe interface */ - spin_lock_irqsave(&port->conf_lock, flags); ret = mvebu_pcie_hw_rd_conf(port, bus, devfn, where, size, val); - spin_unlock_irqrestore(&port->conf_lock, flags); return ret; } @@ -679,10 +722,30 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) { struct mvebu_pcie *pcie = sys_to_pcie(sys); int i; + int domain = 0; + +#ifdef CONFIG_PCI_DOMAINS + domain = sys->domain; +#endif - if (resource_size(&pcie->realio) != 0) + snprintf(pcie->mem_name, sizeof(pcie->mem_name), "PCI MEM %04x", + domain); + pcie->mem.name = pcie->mem_name; + + snprintf(pcie->io_name, sizeof(pcie->io_name), "PCI I/O %04x", domain); + pcie->realio.name = pcie->io_name; + + if (request_resource(&iomem_resource, &pcie->mem)) + return 0; + + if (resource_size(&pcie->realio) != 0) { + if (request_resource(&ioport_resource, &pcie->realio)) { + release_resource(&pcie->mem); + return 0; + } pci_add_resource_offset(&sys->resources, &pcie->realio, sys->io_offset); + } pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); pci_add_resource(&sys->resources, &pcie->busn); @@ -718,24 +781,31 @@ static void mvebu_pcie_add_bus(struct pci_bus *bus) } static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, - const struct resource *res, - resource_size_t start, - resource_size_t size, - resource_size_t align) + const struct resource *res, + resource_size_t start, + resource_size_t size, + resource_size_t align) { if (dev->bus->number != 0) return start; /* * On the PCI-to-PCI bridge side, the I/O windows must have at - * least a 64 KB size and be aligned on their size, and the - * memory windows must have at least a 1 MB size and be - * aligned on their size + * least a 64 KB size and the memory windows must have at + * least a 1 MB size. Moreover, MBus windows need to have a + * base address aligned on their size, and their size must be + * a power of two. This means that if the BAR doesn't have a + * power of two size, several MBus windows will actually be + * created. We need to ensure that the biggest MBus window + * (which will be the first one) is aligned on its size, which + * explains the rounddown_pow_of_two() being done here. */ if (res->flags & IORESOURCE_IO) - return round_up(start, max_t(resource_size_t, SZ_64K, size)); + return round_up(start, max_t(resource_size_t, SZ_64K, + rounddown_pow_of_two(size))); else if (res->flags & IORESOURCE_MEM) - return round_up(start, max_t(resource_size_t, SZ_1M, size)); + return round_up(start, max_t(resource_size_t, SZ_1M, + rounddown_pow_of_two(size))); else return start; } @@ -764,7 +834,8 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie) * found, maps it. */ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev, - struct device_node *np, struct mvebu_pcie_port *port) + struct device_node *np, + struct mvebu_pcie_port *port) { struct resource regs; int ret = 0; @@ -804,7 +875,7 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn, for (i = 0; i < nranges; i++) { u32 flags = of_read_number(range, 1); - u32 slot = of_read_number(range, 2); + u32 slot = of_read_number(range + 1, 1); u64 cpuaddr = of_read_number(range + na, pna); unsigned long rtype; @@ -985,7 +1056,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev) mvebu_pcie_set_local_dev_nr(port, 1); port->dn = child; - spin_lock_init(&port->conf_lock); mvebu_sw_pci_bridge_init(port); i++; } diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c index ceec147baec..3ef854f5a5b 100644 --- a/drivers/pci/host/pci-rcar-gen2.c +++ b/drivers/pci/host/pci-rcar-gen2.c @@ -15,9 +15,11 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_pci.h> #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/sizes.h> #include <linux/slab.h> /* AHB-PCI Bridge PCI communication registers */ @@ -39,9 +41,26 @@ #define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20) #define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24) +#define RCAR_PCI_INT_SIGTABORT (1 << 0) +#define RCAR_PCI_INT_SIGRETABORT (1 << 1) +#define RCAR_PCI_INT_REMABORT (1 << 2) +#define RCAR_PCI_INT_PERR (1 << 3) +#define RCAR_PCI_INT_SIGSERR (1 << 4) +#define RCAR_PCI_INT_RESERR (1 << 5) +#define RCAR_PCI_INT_WIN1ERR (1 << 12) +#define RCAR_PCI_INT_WIN2ERR (1 << 13) #define RCAR_PCI_INT_A (1 << 16) #define RCAR_PCI_INT_B (1 << 17) #define RCAR_PCI_INT_PME (1 << 19) +#define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT | \ + RCAR_PCI_INT_SIGRETABORT | \ + RCAR_PCI_INT_SIGRETABORT | \ + RCAR_PCI_INT_REMABORT | \ + RCAR_PCI_INT_PERR | \ + RCAR_PCI_INT_SIGSERR | \ + RCAR_PCI_INT_RESERR | \ + RCAR_PCI_INT_WIN1ERR | \ + RCAR_PCI_INT_WIN2ERR) #define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30) #define RCAR_AHB_BUS_MMODE_HTRANS (1 << 0) @@ -74,16 +93,15 @@ #define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48) -/* Number of internal PCI controllers */ -#define RCAR_PCI_NR_CONTROLLERS 3 - struct rcar_pci_priv { struct device *dev; void __iomem *reg; struct resource io_res; struct resource mem_res; struct resource *cfg_res; + unsigned busnr; int irq; + unsigned long window_size; }; /* PCI configuration space operations */ @@ -102,6 +120,10 @@ static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn, if (slot > 2) return NULL; + /* bridge logic only has registers to 0x40 */ + if (slot == 0x0 && where >= 0x40) + return NULL; + val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG : RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG; @@ -156,16 +178,61 @@ static int rcar_pci_write_config(struct pci_bus *bus, unsigned int devfn, } /* PCI interrupt mapping */ -static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct pci_sys_data *sys = dev->bus->sysdata; struct rcar_pci_priv *priv = sys->private_data; + int irq; + + irq = of_irq_parse_and_map_pci(dev, slot, pin); + if (!irq) + irq = priv->irq; + + return irq; +} + +#ifdef CONFIG_PCI_DEBUG +/* if debug enabled, then attach an error handler irq to the bridge */ + +static irqreturn_t rcar_pci_err_irq(int irq, void *pw) +{ + struct rcar_pci_priv *priv = pw; + u32 status = ioread32(priv->reg + RCAR_PCI_INT_STATUS_REG); + + if (status & RCAR_PCI_INT_ALLERRORS) { + dev_err(priv->dev, "error irq: status %08x\n", status); + + /* clear the error(s) */ + iowrite32(status & RCAR_PCI_INT_ALLERRORS, + priv->reg + RCAR_PCI_INT_STATUS_REG); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} - return priv->irq; +static void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) +{ + int ret; + u32 val; + + ret = devm_request_irq(priv->dev, priv->irq, rcar_pci_err_irq, + IRQF_SHARED, "error irq", priv); + if (ret) { + dev_err(priv->dev, "cannot claim IRQ for error handling\n"); + return; + } + + val = ioread32(priv->reg + RCAR_PCI_INT_ENABLE_REG); + val |= RCAR_PCI_INT_ALLERRORS; + iowrite32(val, priv->reg + RCAR_PCI_INT_ENABLE_REG); } +#else +static inline void rcar_pci_setup_errirq(struct rcar_pci_priv *priv) { } +#endif /* PCI host controller setup */ -static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) +static int rcar_pci_setup(int nr, struct pci_sys_data *sys) { struct rcar_pci_priv *priv = sys->private_data; void __iomem *reg = priv->reg; @@ -183,10 +250,31 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) iowrite32(val, reg + RCAR_USBCTR_REG); udelay(4); - /* De-assert reset and set PCIAHB window1 size to 1GB */ + /* De-assert reset and reset PCIAHB window1 size */ val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK | RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST); - iowrite32(val | RCAR_USBCTR_PCIAHB_WIN1_1G, reg + RCAR_USBCTR_REG); + + /* Setup PCIAHB window1 size */ + switch (priv->window_size) { + case SZ_2G: + val |= RCAR_USBCTR_PCIAHB_WIN1_2G; + break; + case SZ_1G: + val |= RCAR_USBCTR_PCIAHB_WIN1_1G; + break; + case SZ_512M: + val |= RCAR_USBCTR_PCIAHB_WIN1_512M; + break; + default: + pr_warn("unknown window size %ld - defaulting to 256M\n", + priv->window_size); + priv->window_size = SZ_256M; + /* fall-through */ + case SZ_256M: + val |= RCAR_USBCTR_PCIAHB_WIN1_256M; + break; + } + iowrite32(val, reg + RCAR_USBCTR_REG); /* Configure AHB master and slave modes */ iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG); @@ -197,7 +285,7 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) RCAR_PCI_ARBITER_PCIBP_MODE; iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG); - /* PCI-AHB mapping: 0x40000000-0x80000000 */ + /* PCI-AHB mapping: 0x40000000 base */ iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16, reg + RCAR_PCIAHB_WIN1_CTR_REG); @@ -224,10 +312,15 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys) iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME, reg + RCAR_PCI_INT_ENABLE_REG); + if (priv->irq > 0) + rcar_pci_setup_errirq(priv); + /* Add PCI resources */ pci_add_resource(&sys->resources, &priv->io_res); pci_add_resource(&sys->resources, &priv->mem_res); + /* Setup bus number based on platform device id / of bus-range */ + sys->busnr = priv->busnr; return 1; } @@ -236,48 +329,13 @@ static struct pci_ops rcar_pci_ops = { .write = rcar_pci_write_config, }; -static struct hw_pci rcar_hw_pci __initdata = { - .map_irq = rcar_pci_map_irq, - .ops = &rcar_pci_ops, - .setup = rcar_pci_setup, -}; - -static int rcar_pci_count __initdata; - -static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv) -{ - void **private_data; - int count; - - if (rcar_hw_pci.nr_controllers < rcar_pci_count) - goto add_priv; - - /* (Re)allocate private data pointer array if needed */ - count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS; - private_data = kzalloc(count * sizeof(void *), GFP_KERNEL); - if (!private_data) - return -ENOMEM; - - rcar_pci_count = count; - if (rcar_hw_pci.private_data) { - memcpy(private_data, rcar_hw_pci.private_data, - rcar_hw_pci.nr_controllers * sizeof(void *)); - kfree(rcar_hw_pci.private_data); - } - - rcar_hw_pci.private_data = private_data; - -add_priv: - /* Add private data pointer to the array */ - rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv; - return 0; -} - -static int __init rcar_pci_probe(struct platform_device *pdev) +static int rcar_pci_probe(struct platform_device *pdev) { struct resource *cfg_res, *mem_res; struct rcar_pci_priv *priv; void __iomem *reg; + struct hw_pci hw; + void *hw_private[1]; cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg = devm_ioremap_resource(&pdev->dev, cfg_res); @@ -308,31 +366,60 @@ static int __init rcar_pci_probe(struct platform_device *pdev) priv->reg = reg; priv->dev = &pdev->dev; - return rcar_pci_add_controller(priv); + if (priv->irq < 0) { + dev_err(&pdev->dev, "no valid irq found\n"); + return priv->irq; + } + + priv->window_size = SZ_1G; + + if (pdev->dev.of_node) { + struct resource busnr; + int ret; + + ret = of_pci_parse_bus_range(pdev->dev.of_node, &busnr); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse bus-range\n"); + return ret; + } + + priv->busnr = busnr.start; + if (busnr.end != busnr.start) + dev_warn(&pdev->dev, "only one bus number supported\n"); + } else { + priv->busnr = pdev->id; + } + + hw_private[0] = priv; + memset(&hw, 0, sizeof(hw)); + hw.nr_controllers = ARRAY_SIZE(hw_private); + hw.private_data = hw_private; + hw.map_irq = rcar_pci_map_irq; + hw.ops = &rcar_pci_ops; + hw.setup = rcar_pci_setup; + pci_common_init_dev(&pdev->dev, &hw); + return 0; } +static struct of_device_id rcar_pci_of_match[] = { + { .compatible = "renesas,pci-r8a7790", }, + { .compatible = "renesas,pci-r8a7791", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, rcar_pci_of_match); + static struct platform_driver rcar_pci_driver = { .driver = { .name = "pci-rcar-gen2", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + .of_match_table = rcar_pci_of_match, }, + .probe = rcar_pci_probe, }; -static int __init rcar_pci_init(void) -{ - int retval; - - retval = platform_driver_probe(&rcar_pci_driver, rcar_pci_probe); - if (!retval) - pci_common_init(&rcar_hw_pci); - - /* Private data pointer array is not needed any more */ - kfree(rcar_hw_pci.private_data); - rcar_hw_pci.private_data = NULL; - - return retval; -} - -subsys_initcall(rcar_pci_init); +module_platform_driver(rcar_pci_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI"); diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 330f7e3a32d..083cf37ca04 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -639,10 +639,15 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) { struct tegra_pcie *pcie = sys_to_pcie(pdev->bus->sysdata); + int irq; tegra_cpuidle_pcie_irqs_in_use(); - return pcie->irq; + irq = of_irq_parse_and_map_pci(pdev, slot, pin); + if (!irq) + irq = pcie->irq; + + return irq; } static void tegra_pcie_add_bus(struct pci_bus *bus) diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 17ce88f79d2..1eaf4df3618 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/msi.h> #include <linux/of_address.h> +#include <linux/of_pci.h> #include <linux/pci.h> #include <linux/pci_regs.h> #include <linux/types.h> @@ -155,15 +156,17 @@ static struct irq_chip dw_msi_irq_chip = { }; /* MSI int handler */ -void dw_handle_msi_irq(struct pcie_port *pp) +irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) { unsigned long val; int i, pos, irq; + irqreturn_t ret = IRQ_NONE; for (i = 0; i < MAX_MSI_CTRLS; i++) { dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, (u32 *)&val); if (val) { + ret = IRQ_HANDLED; pos = 0; while ((pos = find_next_bit(&val, 32, pos)) != 32) { irq = irq_find_mapping(pp->irq_domain, @@ -176,6 +179,8 @@ void dw_handle_msi_irq(struct pcie_port *pp) } } } + + return ret; } void dw_pcie_msi_init(struct pcie_port *pp) @@ -294,14 +299,12 @@ no_valid_irq: static void clear_irq(unsigned int irq) { unsigned int pos, nvec; - struct irq_desc *desc; struct msi_desc *msi; struct pcie_port *pp; struct irq_data *data = irq_get_irq_data(irq); /* get the port structure */ - desc = irq_to_desc(irq); - msi = irq_desc_get_msi_desc(desc); + msi = irq_data_get_msi(data); pp = sys_to_pcie(msi->dev->bus->sysdata); if (!pp) { BUG(); @@ -492,7 +495,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp) dw_pci.nr_controllers = 1; dw_pci.private_data = (void **)&pp; - pci_common_init(&dw_pci); + pci_common_init_dev(pp->dev, &dw_pci); pci_assign_unassigned_resources(); #ifdef CONFIG_PCI_DOMAINS dw_pci.domain++; @@ -522,13 +525,13 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE); dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE); dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1, PCIE_ATU_LIMIT); dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); + dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); } static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) @@ -537,7 +540,6 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE); dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE); dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1, @@ -545,6 +547,7 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr), PCIE_ATU_UPPER_TARGET); + dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); } static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) @@ -553,7 +556,6 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE); dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE); dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1, @@ -561,6 +563,7 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr), PCIE_ATU_UPPER_TARGET); + dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); } static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, @@ -640,7 +643,6 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 *val) { struct pcie_port *pp = sys_to_pcie(bus->sysdata); - unsigned long flags; int ret; if (!pp) { @@ -653,13 +655,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, return PCIBIOS_DEVICE_NOT_FOUND; } - spin_lock_irqsave(&pp->conf_lock, flags); if (bus->number != pp->root_bus_nr) ret = dw_pcie_rd_other_conf(pp, bus, devfn, where, size, val); else ret = dw_pcie_rd_own_conf(pp, where, size, val); - spin_unlock_irqrestore(&pp->conf_lock, flags); return ret; } @@ -668,7 +668,6 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 val) { struct pcie_port *pp = sys_to_pcie(bus->sysdata); - unsigned long flags; int ret; if (!pp) { @@ -679,13 +678,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn, if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) return PCIBIOS_DEVICE_NOT_FOUND; - spin_lock_irqsave(&pp->conf_lock, flags); if (bus->number != pp->root_bus_nr) ret = dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val); else ret = dw_pcie_wr_own_conf(pp, where, size, val); - spin_unlock_irqrestore(&pp->conf_lock, flags); return ret; } @@ -725,7 +722,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys) if (pp) { pp->root_bus_nr = sys->busnr; - bus = pci_scan_root_bus(NULL, sys->busnr, &dw_pcie_ops, + bus = pci_scan_root_bus(pp->dev, sys->busnr, &dw_pcie_ops, sys, &sys->resources); } else { bus = NULL; @@ -738,8 +735,13 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys) static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata); + int irq; - return pp->irq; + irq = of_irq_parse_and_map_pci(dev, slot, pin); + if (!irq) + irq = pp->irq; + + return irq; } static void dw_pcie_add_bus(struct pci_bus *bus) @@ -766,7 +768,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) u32 membase; u32 memlimit; - /* set the number of lines as 4 */ + /* set the number of lanes */ dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val); val &= ~PORT_LINK_MODE_MASK; switch (pp->lanes) { @@ -800,7 +802,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) /* setup RC BARs */ dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0); - dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_1); + dw_pcie_writel_rc(pp, 0x00000000, PCI_BASE_ADDRESS_1); /* setup interrupt pins */ dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE, &val); diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index 3063b3594d8..77f592faa7b 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -41,7 +41,6 @@ struct pcie_port { void __iomem *va_cfg1_base; u64 io_base; u64 mem_base; - spinlock_t conf_lock; struct resource cfg; struct resource io; struct resource mem; @@ -68,7 +67,7 @@ struct pcie_host_ops { int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val); -void dw_handle_msi_irq(struct pcie_port *pp); +irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); void dw_pcie_msi_init(struct pcie_port *pp); int dw_pcie_link_up(struct pcie_port *pp); void dw_pcie_setup_rc(struct pcie_port *pp); diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c new file mode 100644 index 00000000000..f7d3de32c9a --- /dev/null +++ b/drivers/pci/host/pcie-rcar.c @@ -0,0 +1,1006 @@ +/* + * PCIe driver for Renesas R-Car SoCs + * Copyright (C) 2014 Renesas Electronics Europe Ltd + * + * Based on: + * arch/sh/drivers/pci/pcie-sh7786.c + * arch/sh/drivers/pci/ops-sh7786.c + * Copyright (C) 2009 - 2011 Paul Mundt + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/msi.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_pci.h> +#include <linux/of_platform.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define DRV_NAME "rcar-pcie" + +#define PCIECAR 0x000010 +#define PCIECCTLR 0x000018 +#define CONFIG_SEND_ENABLE (1 << 31) +#define TYPE0 (0 << 8) +#define TYPE1 (1 << 8) +#define PCIECDR 0x000020 +#define PCIEMSR 0x000028 +#define PCIEINTXR 0x000400 +#define PCIEMSITXR 0x000840 + +/* Transfer control */ +#define PCIETCTLR 0x02000 +#define CFINIT 1 +#define PCIETSTR 0x02004 +#define DATA_LINK_ACTIVE 1 +#define PCIEERRFR 0x02020 +#define UNSUPPORTED_REQUEST (1 << 4) +#define PCIEMSIFR 0x02044 +#define PCIEMSIALR 0x02048 +#define MSIFE 1 +#define PCIEMSIAUR 0x0204c +#define PCIEMSIIER 0x02050 + +/* root port address */ +#define PCIEPRAR(x) (0x02080 + ((x) * 0x4)) + +/* local address reg & mask */ +#define PCIELAR(x) (0x02200 + ((x) * 0x20)) +#define PCIELAMR(x) (0x02208 + ((x) * 0x20)) +#define LAM_PREFETCH (1 << 3) +#define LAM_64BIT (1 << 2) +#define LAR_ENABLE (1 << 1) + +/* PCIe address reg & mask */ +#define PCIEPARL(x) (0x03400 + ((x) * 0x20)) +#define PCIEPARH(x) (0x03404 + ((x) * 0x20)) +#define PCIEPAMR(x) (0x03408 + ((x) * 0x20)) +#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20)) +#define PAR_ENABLE (1 << 31) +#define IO_SPACE (1 << 8) + +/* Configuration */ +#define PCICONF(x) (0x010000 + ((x) * 0x4)) +#define PMCAP(x) (0x010040 + ((x) * 0x4)) +#define EXPCAP(x) (0x010070 + ((x) * 0x4)) +#define VCCAP(x) (0x010100 + ((x) * 0x4)) + +/* link layer */ +#define IDSETR1 0x011004 +#define TLCTLR 0x011048 +#define MACSR 0x011054 +#define MACCTLR 0x011058 +#define SCRAMBLE_DISABLE (1 << 27) + +/* R-Car H1 PHY */ +#define H1_PCIEPHYADRR 0x04000c +#define WRITE_CMD (1 << 16) +#define PHY_ACK (1 << 24) +#define RATE_POS 12 +#define LANE_POS 8 +#define ADR_POS 0 +#define H1_PCIEPHYDOUTR 0x040014 +#define H1_PCIEPHYSR 0x040018 + +#define INT_PCI_MSI_NR 32 + +#define RCONF(x) (PCICONF(0)+(x)) +#define RPMCAP(x) (PMCAP(0)+(x)) +#define REXPCAP(x) (EXPCAP(0)+(x)) +#define RVCCAP(x) (VCCAP(0)+(x)) + +#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24) +#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19) +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16) + +#define PCI_MAX_RESOURCES 4 +#define MAX_NR_INBOUND_MAPS 6 + +struct rcar_msi { + DECLARE_BITMAP(used, INT_PCI_MSI_NR); + struct irq_domain *domain; + struct msi_chip chip; + unsigned long pages; + struct mutex lock; + int irq1; + int irq2; +}; + +static inline struct rcar_msi *to_rcar_msi(struct msi_chip *chip) +{ + return container_of(chip, struct rcar_msi, chip); +} + +/* Structure representing the PCIe interface */ +struct rcar_pcie { + struct device *dev; + void __iomem *base; + struct resource res[PCI_MAX_RESOURCES]; + struct resource busn; + int root_bus_nr; + struct clk *clk; + struct clk *bus_clk; + struct rcar_msi msi; +}; + +static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys) +{ + return sys->private_data; +} + +static void pci_write_reg(struct rcar_pcie *pcie, unsigned long val, + unsigned long reg) +{ + writel(val, pcie->base + reg); +} + +static unsigned long pci_read_reg(struct rcar_pcie *pcie, unsigned long reg) +{ + return readl(pcie->base + reg); +} + +enum { + PCI_ACCESS_READ, + PCI_ACCESS_WRITE, +}; + +static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) +{ + int shift = 8 * (where & 3); + u32 val = pci_read_reg(pcie, where & ~3); + + val &= ~(mask << shift); + val |= data << shift; + pci_write_reg(pcie, val, where & ~3); +} + +static u32 rcar_read_conf(struct rcar_pcie *pcie, int where) +{ + int shift = 8 * (where & 3); + u32 val = pci_read_reg(pcie, where & ~3); + + return val >> shift; +} + +/* Serialization is provided by 'pci_lock' in drivers/pci/access.c */ +static int rcar_pcie_config_access(struct rcar_pcie *pcie, + unsigned char access_type, struct pci_bus *bus, + unsigned int devfn, int where, u32 *data) +{ + int dev, func, reg, index; + + dev = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + reg = where & ~3; + index = reg / 4; + + /* + * While each channel has its own memory-mapped extended config + * space, it's generally only accessible when in endpoint mode. + * When in root complex mode, the controller is unable to target + * itself with either type 0 or type 1 accesses, and indeed, any + * controller initiated target transfer to its own config space + * result in a completer abort. + * + * Each channel effectively only supports a single device, but as + * the same channel <-> device access works for any PCI_SLOT() + * value, we cheat a bit here and bind the controller's config + * space to devfn 0 in order to enable self-enumeration. In this + * case the regular ECAR/ECDR path is sidelined and the mangled + * config access itself is initiated as an internal bus transaction. + */ + if (pci_is_root_bus(bus)) { + if (dev != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (access_type == PCI_ACCESS_READ) { + *data = pci_read_reg(pcie, PCICONF(index)); + } else { + /* Keep an eye out for changes to the root bus number */ + if (pci_is_root_bus(bus) && (reg == PCI_PRIMARY_BUS)) + pcie->root_bus_nr = *data & 0xff; + + pci_write_reg(pcie, *data, PCICONF(index)); + } + + return PCIBIOS_SUCCESSFUL; + } + + if (pcie->root_bus_nr < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Clear errors */ + pci_write_reg(pcie, pci_read_reg(pcie, PCIEERRFR), PCIEERRFR); + + /* Set the PIO address */ + pci_write_reg(pcie, PCIE_CONF_BUS(bus->number) | PCIE_CONF_DEV(dev) | + PCIE_CONF_FUNC(func) | reg, PCIECAR); + + /* Enable the configuration access */ + if (bus->parent->number == pcie->root_bus_nr) + pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE0, PCIECCTLR); + else + pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE1, PCIECCTLR); + + /* Check for errors */ + if (pci_read_reg(pcie, PCIEERRFR) & UNSUPPORTED_REQUEST) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* Check for master and target aborts */ + if (rcar_read_conf(pcie, RCONF(PCI_STATUS)) & + (PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (access_type == PCI_ACCESS_READ) + *data = pci_read_reg(pcie, PCIECDR); + else + pci_write_reg(pcie, *data, PCIECDR); + + /* Disable the configuration access */ + pci_write_reg(pcie, 0, PCIECCTLR); + + return PCIBIOS_SUCCESSFUL; +} + +static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata); + int ret; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ, + bus, devfn, where, val); + if (ret != PCIBIOS_SUCCESSFUL) { + *val = 0xffffffff; + return ret; + } + + if (size == 1) + *val = (*val >> (8 * (where & 3))) & 0xff; + else if (size == 2) + *val = (*val >> (8 * (where & 2))) & 0xffff; + + dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n", + bus->number, devfn, where, size, (unsigned long)*val); + + return ret; +} + +/* Serialization is provided by 'pci_lock' in drivers/pci/access.c */ +static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata); + int shift, ret; + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ, + bus, devfn, where, &data); + if (ret != PCIBIOS_SUCCESSFUL) + return ret; + + dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n", + bus->number, devfn, where, size, (unsigned long)val); + + if (size == 1) { + shift = 8 * (where & 3); + data &= ~(0xff << shift); + data |= ((val & 0xff) << shift); + } else if (size == 2) { + shift = 8 * (where & 2); + data &= ~(0xffff << shift); + data |= ((val & 0xffff) << shift); + } else + data = val; + + ret = rcar_pcie_config_access(pcie, PCI_ACCESS_WRITE, + bus, devfn, where, &data); + + return ret; +} + +static struct pci_ops rcar_pcie_ops = { + .read = rcar_pcie_read_conf, + .write = rcar_pcie_write_conf, +}; + +static void rcar_pcie_setup_window(int win, struct resource *res, + struct rcar_pcie *pcie) +{ + /* Setup PCIe address space mappings for each resource */ + resource_size_t size; + u32 mask; + + pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win)); + + /* + * The PAMR mask is calculated in units of 128Bytes, which + * keeps things pretty simple. + */ + size = resource_size(res); + mask = (roundup_pow_of_two(size) / SZ_128) - 1; + pci_write_reg(pcie, mask << 7, PCIEPAMR(win)); + + pci_write_reg(pcie, upper_32_bits(res->start), PCIEPARH(win)); + pci_write_reg(pcie, lower_32_bits(res->start), PCIEPARL(win)); + + /* First resource is for IO */ + mask = PAR_ENABLE; + if (res->flags & IORESOURCE_IO) + mask |= IO_SPACE; + + pci_write_reg(pcie, mask, PCIEPTCTLR(win)); +} + +static int rcar_pcie_setup(int nr, struct pci_sys_data *sys) +{ + struct rcar_pcie *pcie = sys_to_pcie(sys); + struct resource *res; + int i; + + pcie->root_bus_nr = -1; + + /* Setup PCI resources */ + for (i = 0; i < PCI_MAX_RESOURCES; i++) { + + res = &pcie->res[i]; + if (!res->flags) + continue; + + rcar_pcie_setup_window(i, res, pcie); + + if (res->flags & IORESOURCE_IO) + pci_ioremap_io(nr * SZ_64K, res->start); + else + pci_add_resource(&sys->resources, res); + } + pci_add_resource(&sys->resources, &pcie->busn); + + return 1; +} + +static void rcar_pcie_add_bus(struct pci_bus *bus) +{ + if (IS_ENABLED(CONFIG_PCI_MSI)) { + struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata); + + bus->msi = &pcie->msi.chip; + } +} + +struct hw_pci rcar_pci = { + .setup = rcar_pcie_setup, + .map_irq = of_irq_parse_and_map_pci, + .ops = &rcar_pcie_ops, + .add_bus = rcar_pcie_add_bus, +}; + +static void rcar_pcie_enable(struct rcar_pcie *pcie) +{ + struct platform_device *pdev = to_platform_device(pcie->dev); + + rcar_pci.nr_controllers = 1; + rcar_pci.private_data = (void **)&pcie; + + pci_common_init_dev(&pdev->dev, &rcar_pci); +#ifdef CONFIG_PCI_DOMAINS + rcar_pci.domain++; +#endif +} + +static int phy_wait_for_ack(struct rcar_pcie *pcie) +{ + unsigned int timeout = 100; + + while (timeout--) { + if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK) + return 0; + + udelay(100); + } + + dev_err(pcie->dev, "Access to PCIe phy timed out\n"); + + return -ETIMEDOUT; +} + +static void phy_write_reg(struct rcar_pcie *pcie, + unsigned int rate, unsigned int addr, + unsigned int lane, unsigned int data) +{ + unsigned long phyaddr; + + phyaddr = WRITE_CMD | + ((rate & 1) << RATE_POS) | + ((lane & 0xf) << LANE_POS) | + ((addr & 0xff) << ADR_POS); + + /* Set write data */ + pci_write_reg(pcie, data, H1_PCIEPHYDOUTR); + pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR); + + /* Ignore errors as they will be dealt with if the data link is down */ + phy_wait_for_ack(pcie); + + /* Clear command */ + pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR); + pci_write_reg(pcie, 0, H1_PCIEPHYADRR); + + /* Ignore errors as they will be dealt with if the data link is down */ + phy_wait_for_ack(pcie); +} + +static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie) +{ + unsigned int timeout = 10; + + while (timeout--) { + if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE)) + return 0; + + msleep(5); + } + + return -ETIMEDOUT; +} + +static int rcar_pcie_hw_init(struct rcar_pcie *pcie) +{ + int err; + + /* Begin initialization */ + pci_write_reg(pcie, 0, PCIETCTLR); + + /* Set mode */ + pci_write_reg(pcie, 1, PCIEMSR); + + /* + * Initial header for port config space is type 1, set the device + * class to match. Hardware takes care of propagating the IDSETR + * settings, so there is no need to bother with a quirk. + */ + pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1); + + /* + * Setup Secondary Bus Number & Subordinate Bus Number, even though + * they aren't used, to avoid bridge being detected as broken. + */ + rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1); + rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1); + + /* Initialize default capabilities. */ + rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP); + rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS), + PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4); + rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f, + PCI_HEADER_TYPE_BRIDGE); + + /* Enable data link layer active state reporting */ + rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0, PCI_EXP_LNKCAP_DLLLARC); + + /* Write out the physical slot number = 0 */ + rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0); + + /* Set the completion timer timeout to the maximum 50ms. */ + rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50); + + /* Terminate list of capabilities (Next Capability Offset=0) */ + rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0); + + /* Enable MAC data scrambling. */ + rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0); + + /* Enable MSI */ + if (IS_ENABLED(CONFIG_PCI_MSI)) + pci_write_reg(pcie, 0x101f0000, PCIEMSITXR); + + /* Finish initialization - establish a PCI Express link */ + pci_write_reg(pcie, CFINIT, PCIETCTLR); + + /* This will timeout if we don't have a link. */ + err = rcar_pcie_wait_for_dl(pcie); + if (err) + return err; + + /* Enable INTx interrupts */ + rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8); + + /* Enable slave Bus Mastering */ + rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST); + + wmb(); + + return 0; +} + +static int rcar_pcie_hw_init_h1(struct rcar_pcie *pcie) +{ + unsigned int timeout = 10; + + /* Initialize the phy */ + phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191); + phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180); + phy_write_reg(pcie, 0, 0x43, 0x1, 0x00210188); + phy_write_reg(pcie, 1, 0x43, 0x1, 0x00210188); + phy_write_reg(pcie, 0, 0x44, 0x1, 0x015C0014); + phy_write_reg(pcie, 1, 0x44, 0x1, 0x015C0014); + phy_write_reg(pcie, 1, 0x4C, 0x1, 0x786174A0); + phy_write_reg(pcie, 1, 0x4D, 0x1, 0x048000BB); + phy_write_reg(pcie, 0, 0x51, 0x1, 0x079EC062); + phy_write_reg(pcie, 0, 0x52, 0x1, 0x20000000); + phy_write_reg(pcie, 1, 0x52, 0x1, 0x20000000); + phy_write_reg(pcie, 1, 0x56, 0x1, 0x00003806); + + phy_write_reg(pcie, 0, 0x60, 0x1, 0x004B03A5); + phy_write_reg(pcie, 0, 0x64, 0x1, 0x3F0F1F0F); + phy_write_reg(pcie, 0, 0x66, 0x1, 0x00008000); + + while (timeout--) { + if (pci_read_reg(pcie, H1_PCIEPHYSR)) + return rcar_pcie_hw_init(pcie); + + msleep(5); + } + + return -ETIMEDOUT; +} + +static int rcar_msi_alloc(struct rcar_msi *chip) +{ + int msi; + + mutex_lock(&chip->lock); + + msi = find_first_zero_bit(chip->used, INT_PCI_MSI_NR); + if (msi < INT_PCI_MSI_NR) + set_bit(msi, chip->used); + else + msi = -ENOSPC; + + mutex_unlock(&chip->lock); + + return msi; +} + +static void rcar_msi_free(struct rcar_msi *chip, unsigned long irq) +{ + mutex_lock(&chip->lock); + clear_bit(irq, chip->used); + mutex_unlock(&chip->lock); +} + +static irqreturn_t rcar_pcie_msi_irq(int irq, void *data) +{ + struct rcar_pcie *pcie = data; + struct rcar_msi *msi = &pcie->msi; + unsigned long reg; + + reg = pci_read_reg(pcie, PCIEMSIFR); + + /* MSI & INTx share an interrupt - we only handle MSI here */ + if (!reg) + return IRQ_NONE; + + while (reg) { + unsigned int index = find_first_bit(®, 32); + unsigned int irq; + + /* clear the interrupt */ + pci_write_reg(pcie, 1 << index, PCIEMSIFR); + + irq = irq_find_mapping(msi->domain, index); + if (irq) { + if (test_bit(index, msi->used)) + generic_handle_irq(irq); + else + dev_info(pcie->dev, "unhandled MSI\n"); + } else { + /* Unknown MSI, just clear it */ + dev_dbg(pcie->dev, "unexpected MSI\n"); + } + + /* see if there's any more pending in this vector */ + reg = pci_read_reg(pcie, PCIEMSIFR); + } + + return IRQ_HANDLED; +} + +static int rcar_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, + struct msi_desc *desc) +{ + struct rcar_msi *msi = to_rcar_msi(chip); + struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip); + struct msi_msg msg; + unsigned int irq; + int hwirq; + + hwirq = rcar_msi_alloc(msi); + if (hwirq < 0) + return hwirq; + + irq = irq_create_mapping(msi->domain, hwirq); + if (!irq) { + rcar_msi_free(msi, hwirq); + return -EINVAL; + } + + irq_set_msi_desc(irq, desc); + + msg.address_lo = pci_read_reg(pcie, PCIEMSIALR) & ~MSIFE; + msg.address_hi = pci_read_reg(pcie, PCIEMSIAUR); + msg.data = hwirq; + + write_msi_msg(irq, &msg); + + return 0; +} + +static void rcar_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) +{ + struct rcar_msi *msi = to_rcar_msi(chip); + struct irq_data *d = irq_get_irq_data(irq); + + rcar_msi_free(msi, d->hwirq); +} + +static struct irq_chip rcar_msi_irq_chip = { + .name = "R-Car PCIe MSI", + .irq_enable = unmask_msi_irq, + .irq_disable = mask_msi_irq, + .irq_mask = mask_msi_irq, + .irq_unmask = unmask_msi_irq, +}; + +static int rcar_msi_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &rcar_msi_irq_chip, handle_simple_irq); + irq_set_chip_data(irq, domain->host_data); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static const struct irq_domain_ops msi_domain_ops = { + .map = rcar_msi_map, +}; + +static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) +{ + struct platform_device *pdev = to_platform_device(pcie->dev); + struct rcar_msi *msi = &pcie->msi; + unsigned long base; + int err; + + mutex_init(&msi->lock); + + msi->chip.dev = pcie->dev; + msi->chip.setup_irq = rcar_msi_setup_irq; + msi->chip.teardown_irq = rcar_msi_teardown_irq; + + msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR, + &msi_domain_ops, &msi->chip); + if (!msi->domain) { + dev_err(&pdev->dev, "failed to create IRQ domain\n"); + return -ENOMEM; + } + + /* Two irqs are for MSI, but they are also used for non-MSI irqs */ + err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq, + IRQF_SHARED, rcar_msi_irq_chip.name, pcie); + if (err < 0) { + dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); + goto err; + } + + err = devm_request_irq(&pdev->dev, msi->irq2, rcar_pcie_msi_irq, + IRQF_SHARED, rcar_msi_irq_chip.name, pcie); + if (err < 0) { + dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); + goto err; + } + + /* setup MSI data target */ + msi->pages = __get_free_pages(GFP_KERNEL, 0); + base = virt_to_phys((void *)msi->pages); + + pci_write_reg(pcie, base | MSIFE, PCIEMSIALR); + pci_write_reg(pcie, 0, PCIEMSIAUR); + + /* enable all MSI interrupts */ + pci_write_reg(pcie, 0xffffffff, PCIEMSIIER); + + return 0; + +err: + irq_domain_remove(msi->domain); + return err; +} + +static int rcar_pcie_get_resources(struct platform_device *pdev, + struct rcar_pcie *pcie) +{ + struct resource res; + int err, i; + + err = of_address_to_resource(pdev->dev.of_node, 0, &res); + if (err) + return err; + + pcie->clk = devm_clk_get(&pdev->dev, "pcie"); + if (IS_ERR(pcie->clk)) { + dev_err(pcie->dev, "cannot get platform clock\n"); + return PTR_ERR(pcie->clk); + } + err = clk_prepare_enable(pcie->clk); + if (err) + goto fail_clk; + + pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus"); + if (IS_ERR(pcie->bus_clk)) { + dev_err(pcie->dev, "cannot get pcie bus clock\n"); + err = PTR_ERR(pcie->bus_clk); + goto fail_clk; + } + err = clk_prepare_enable(pcie->bus_clk); + if (err) + goto err_map_reg; + + i = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (i < 0) { + dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n"); + err = -ENOENT; + goto err_map_reg; + } + pcie->msi.irq1 = i; + + i = irq_of_parse_and_map(pdev->dev.of_node, 1); + if (i < 0) { + dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n"); + err = -ENOENT; + goto err_map_reg; + } + pcie->msi.irq2 = i; + + pcie->base = devm_ioremap_resource(&pdev->dev, &res); + if (IS_ERR(pcie->base)) { + err = PTR_ERR(pcie->base); + goto err_map_reg; + } + + return 0; + +err_map_reg: + clk_disable_unprepare(pcie->bus_clk); +fail_clk: + clk_disable_unprepare(pcie->clk); + + return err; +} + +static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie, + struct of_pci_range *range, + int *index) +{ + u64 restype = range->flags; + u64 cpu_addr = range->cpu_addr; + u64 cpu_end = range->cpu_addr + range->size; + u64 pci_addr = range->pci_addr; + u32 flags = LAM_64BIT | LAR_ENABLE; + u64 mask; + u64 size; + int idx = *index; + + if (restype & IORESOURCE_PREFETCH) + flags |= LAM_PREFETCH; + + /* + * If the size of the range is larger than the alignment of the start + * address, we have to use multiple entries to perform the mapping. + */ + if (cpu_addr > 0) { + unsigned long nr_zeros = __ffs64(cpu_addr); + u64 alignment = 1ULL << nr_zeros; + size = min(range->size, alignment); + } else { + size = range->size; + } + /* Hardware supports max 4GiB inbound region */ + size = min(size, 1ULL << 32); + + mask = roundup_pow_of_two(size) - 1; + mask &= ~0xf; + + while (cpu_addr < cpu_end) { + /* + * Set up 64-bit inbound regions as the range parser doesn't + * distinguish between 32 and 64-bit types. + */ + pci_write_reg(pcie, lower_32_bits(pci_addr), PCIEPRAR(idx)); + pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx)); + pci_write_reg(pcie, lower_32_bits(mask) | flags, PCIELAMR(idx)); + + pci_write_reg(pcie, upper_32_bits(pci_addr), PCIEPRAR(idx+1)); + pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx+1)); + pci_write_reg(pcie, 0, PCIELAMR(idx+1)); + + pci_addr += size; + cpu_addr += size; + idx += 2; + + if (idx > MAX_NR_INBOUND_MAPS) { + dev_err(pcie->dev, "Failed to map inbound regions!\n"); + return -EINVAL; + } + } + *index = idx; + + return 0; +} + +static int pci_dma_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node) +{ + const int na = 3, ns = 2; + int rlen; + + parser->node = node; + parser->pna = of_n_addr_cells(node); + parser->np = parser->pna + na + ns; + + parser->range = of_get_property(node, "dma-ranges", &rlen); + if (!parser->range) + return -ENOENT; + + parser->end = parser->range + rlen / sizeof(__be32); + return 0; +} + +static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie, + struct device_node *np) +{ + struct of_pci_range range; + struct of_pci_range_parser parser; + int index = 0; + int err; + + if (pci_dma_range_parser_init(&parser, np)) + return -EINVAL; + + /* Get the dma-ranges from DT */ + for_each_of_pci_range(&parser, &range) { + u64 end = range.cpu_addr + range.size - 1; + dev_dbg(pcie->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", + range.flags, range.cpu_addr, end, range.pci_addr); + + err = rcar_pcie_inbound_ranges(pcie, &range, &index); + if (err) + return err; + } + + return 0; +} + +static const struct of_device_id rcar_pcie_of_match[] = { + { .compatible = "renesas,pcie-r8a7779", .data = rcar_pcie_hw_init_h1 }, + { .compatible = "renesas,pcie-r8a7790", .data = rcar_pcie_hw_init }, + { .compatible = "renesas,pcie-r8a7791", .data = rcar_pcie_hw_init }, + {}, +}; +MODULE_DEVICE_TABLE(of, rcar_pcie_of_match); + +static int rcar_pcie_probe(struct platform_device *pdev) +{ + struct rcar_pcie *pcie; + unsigned int data; + struct of_pci_range range; + struct of_pci_range_parser parser; + const struct of_device_id *of_id; + int err, win = 0; + int (*hw_init_fn)(struct rcar_pcie *); + + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->dev = &pdev->dev; + platform_set_drvdata(pdev, pcie); + + /* Get the bus range */ + if (of_pci_parse_bus_range(pdev->dev.of_node, &pcie->busn)) { + dev_err(&pdev->dev, "failed to parse bus-range property\n"); + return -EINVAL; + } + + if (of_pci_range_parser_init(&parser, pdev->dev.of_node)) { + dev_err(&pdev->dev, "missing ranges property\n"); + return -EINVAL; + } + + err = rcar_pcie_get_resources(pdev, pcie); + if (err < 0) { + dev_err(&pdev->dev, "failed to request resources: %d\n", err); + return err; + } + + for_each_of_pci_range(&parser, &range) { + of_pci_range_to_resource(&range, pdev->dev.of_node, + &pcie->res[win++]); + + if (win > PCI_MAX_RESOURCES) + break; + } + + err = rcar_pcie_parse_map_dma_ranges(pcie, pdev->dev.of_node); + if (err) + return err; + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + err = rcar_pcie_enable_msi(pcie); + if (err < 0) { + dev_err(&pdev->dev, + "failed to enable MSI support: %d\n", + err); + return err; + } + } + + of_id = of_match_device(rcar_pcie_of_match, pcie->dev); + if (!of_id || !of_id->data) + return -EINVAL; + hw_init_fn = of_id->data; + + /* Failure to get a link might just be that no cards are inserted */ + err = hw_init_fn(pcie); + if (err) { + dev_info(&pdev->dev, "PCIe link down\n"); + return 0; + } + + data = pci_read_reg(pcie, MACSR); + dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f); + + rcar_pcie_enable(pcie); + + return 0; +} + +static struct platform_driver rcar_pcie_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = rcar_pcie_of_match, + .suppress_bind_attrs = true, + }, + .probe = rcar_pcie_probe, +}; +module_platform_driver(rcar_pcie_driver); + +MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>"); +MODULE_DESCRIPTION("Renesas R-Car PCIe driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c index 6258dc260d9..c68366cee6b 100644 --- a/drivers/pci/hotplug-pci.c +++ b/drivers/pci/hotplug-pci.c @@ -4,7 +4,7 @@ #include <linux/export.h> #include "pci.h" -int __ref pci_hp_add_bridge(struct pci_dev *dev) +int pci_hp_add_bridge(struct pci_dev *dev) { struct pci_bus *parent = dev->bus; int pass, busnr, start = parent->busn_res.start; diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index b6162be4df4..b0e61bf261a 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -93,7 +93,6 @@ struct acpiphp_slot { struct list_head funcs; /* one slot may have different objects (i.e. for each function) */ struct slot *slot; - struct mutex crit_sect; u8 device; /* pci device# */ u32 flags; /* see below */ @@ -117,20 +116,40 @@ struct acpiphp_func { }; struct acpiphp_context { - acpi_handle handle; + struct acpi_hotplug_context hp; struct acpiphp_func func; struct acpiphp_bridge *bridge; unsigned int refcount; }; +static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_context, hp); +} + static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) { return container_of(func, struct acpiphp_context, func); } +static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) +{ + return func_to_context(func)->hp.self; +} + static inline acpi_handle func_to_handle(struct acpiphp_func *func) { - return func_to_context(func)->handle; + return func_to_acpi_device(func)->handle; +} + +struct acpiphp_root_context { + struct acpi_hotplug_context hp; + struct acpiphp_bridge *root_bridge; +}; + +static inline struct acpiphp_root_context *to_acpiphp_root_context(struct acpi_hotplug_context *hp) +{ + return container_of(hp, struct acpiphp_root_context, hp); } /* @@ -158,7 +177,6 @@ struct acpiphp_attention_info #define FUNC_HAS_STA (0x00000001) #define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_DCK (0x00000004) /* function prototypes */ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 728c31f4c2c..e291efcd02a 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -63,10 +63,6 @@ MODULE_LICENSE("GPL"); MODULE_PARM_DESC(disable, "disable acpiphp driver"); module_param_named(disable, acpiphp_disabled, bool, 0444); -/* export the attention callback registration methods */ -EXPORT_SYMBOL_GPL(acpiphp_register_attention); -EXPORT_SYMBOL_GPL(acpiphp_unregister_attention); - static int enable_slot (struct hotplug_slot *slot); static int disable_slot (struct hotplug_slot *slot); static int set_attention_status (struct hotplug_slot *slot, u8 value); @@ -104,6 +100,7 @@ int acpiphp_register_attention(struct acpiphp_attention_info *info) } return retval; } +EXPORT_SYMBOL_GPL(acpiphp_register_attention); /** @@ -124,6 +121,7 @@ int acpiphp_unregister_attention(struct acpiphp_attention_info *info) } return retval; } +EXPORT_SYMBOL_GPL(acpiphp_unregister_attention); /** diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cd929aed361..602d153c705 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -41,7 +41,6 @@ #define pr_fmt(fmt) "acpiphp_glue: " fmt -#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> @@ -58,71 +57,59 @@ static LIST_HEAD(bridge_list); static DEFINE_MUTEX(bridge_mutex); -static DEFINE_MUTEX(acpiphp_context_lock); -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); +static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type); +static void acpiphp_post_dock_fixup(struct acpi_device *adev); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus); -static void hotplug_event(acpi_handle handle, u32 type, void *data); +static void hotplug_event(u32 type, struct acpiphp_context *context); static void free_bridge(struct kref *kref); -static void acpiphp_context_handler(acpi_handle handle, void *context) -{ - /* Intentionally empty. */ -} - /** * acpiphp_init_context - Create hotplug context and grab a reference to it. - * @handle: ACPI object handle to create the context for. + * @adev: ACPI device object to create the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_init_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) { struct acpiphp_context *context; - acpi_status status; context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return NULL; - context->handle = handle; context->refcount = 1; - status = acpi_attach_data(handle, acpiphp_context_handler, context); - if (ACPI_FAILURE(status)) { - kfree(context); - return NULL; - } + acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_notify, NULL, + acpiphp_post_dock_fixup); return context; } /** * acpiphp_get_context - Get hotplug context and grab a reference to it. - * @handle: ACPI object handle to get the context for. + * @adev: ACPI device object to get the context for. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ -static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) +static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev) { - struct acpiphp_context *context = NULL; - acpi_status status; - void *data; + struct acpiphp_context *context; - status = acpi_get_data(handle, acpiphp_context_handler, &data); - if (ACPI_SUCCESS(status)) { - context = data; - context->refcount++; - } + if (!adev->hp) + return NULL; + + context = to_acpiphp_context(adev->hp); + context->refcount++; return context; } /** * acpiphp_put_context - Drop a reference to ACPI hotplug context. - * @handle: ACPI object handle to put the context for. + * @context: ACPI hotplug context to drop a reference to. * * The context object is removed if there are no more references to it. * - * Call under acpiphp_context_lock. + * Call under acpi_hp_context_lock. */ static void acpiphp_put_context(struct acpiphp_context *context) { @@ -130,7 +117,7 @@ static void acpiphp_put_context(struct acpiphp_context *context) return; WARN_ON(context->bridge); - acpi_detach_data(context->handle, acpiphp_context_handler); + context->hp.self->hp = NULL; kfree(context); } @@ -144,6 +131,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge) kref_put(&bridge->ref, free_bridge); } +static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev) +{ + struct acpiphp_context *context; + + acpi_lock_hp_context(); + context = acpiphp_get_context(adev); + if (!context || context->func.parent->is_going_away) { + acpi_unlock_hp_context(); + return NULL; + } + get_bridge(context->func.parent); + acpiphp_put_context(context); + acpi_unlock_hp_context(); + return context; +} + +static void acpiphp_let_context_go(struct acpiphp_context *context) +{ + put_bridge(context->func.parent); +} + static void free_bridge(struct kref *kref) { struct acpiphp_context *context; @@ -151,7 +159,7 @@ static void free_bridge(struct kref *kref) struct acpiphp_slot *slot, *next; struct acpiphp_func *func, *tmp; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = container_of(kref, struct acpiphp_bridge, ref); @@ -175,31 +183,32 @@ static void free_bridge(struct kref *kref) pci_dev_put(bridge->pci_dev); kfree(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); } -/* - * the _DCK method can do funny things... and sometimes not - * hah-hah funny. +/** + * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices. + * @adev: ACPI device object corresponding to a PCI device. * - * TBD - figure out a way to only call fixups for - * systems that require them. + * TBD - figure out a way to only call fixups for systems that require them. */ -static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) +static void acpiphp_post_dock_fixup(struct acpi_device *adev) { - struct acpiphp_context *context = data; - struct pci_bus *bus = context->func.slot->bus; + struct acpiphp_context *context = acpiphp_grab_context(adev); + struct pci_bus *bus; u32 buses; - if (!bus->self) + if (!context) return; + bus = context->func.slot->bus; + if (!bus->self) + goto out; + /* fixup bad _DCK function that rewrites * secondary bridge on slot */ - pci_read_config_dword(bus->self, - PCI_PRIMARY_BUS, - &buses); + pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses); if (((buses >> 8) & 0xff) != bus->busn_res.start) { buses = (buses & 0xff000000) @@ -208,13 +217,10 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) | ((unsigned int)(bus->busn_res.end) << 16); pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); } -} - -static const struct acpi_dock_ops acpiphp_dock_ops = { - .fixup = post_dock_fixups, - .handler = hotplug_event, -}; + out: + acpiphp_let_context_go(context); +} /* Check whether the PCI device is managed by native PCIe hotplug driver */ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) @@ -245,26 +251,19 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) return true; } -static void acpiphp_dock_init(void *data) -{ - struct acpiphp_context *context = data; - - get_bridge(context->func.parent); -} - -static void acpiphp_dock_release(void *data) -{ - struct acpiphp_context *context = data; - - put_bridge(context->func.parent); -} - -/* callback routine to register each ACPI PCI slot object */ -static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, - void **rv) +/** + * acpiphp_add_context - Add ACPIPHP context to an ACPI device object. + * @handle: ACPI handle of the object to add a context to. + * @lvl: Not used. + * @data: The object's parent ACPIPHP bridge. + * @rv: Not used. + */ +static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, + void **rv) { struct acpiphp_bridge *bridge = data; struct acpiphp_context *context; + struct acpi_device *adev; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; acpi_status status = AE_OK; @@ -274,9 +273,6 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, struct pci_dev *pdev = bridge->pci_dev; u32 val; - if (pdev && device_is_managed_by_native_pciehp(pdev)) - return AE_OK; - status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) @@ -284,31 +280,34 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, "can't evaluate _ADR (%#x)\n", status); return AE_OK; } + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; device = (adr >> 16) & 0xffff; function = adr & 0xffff; - mutex_lock(&acpiphp_context_lock); - context = acpiphp_init_context(handle); + acpi_lock_hp_context(); + context = acpiphp_init_context(adev); if (!context) { - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); acpi_handle_err(handle, "No hotplug context\n"); return AE_NOT_EXIST; } newfunc = &context->func; newfunc->function = function; newfunc->parent = bridge; - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); - if (acpi_has_method(handle, "_EJ0")) + /* + * If this is a dock device, its _EJ0 should be executed by the dock + * notify handler after calling _DCK. + */ + if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; - if (acpi_has_method(handle, "_DCK")) - newfunc->flags |= FUNC_HAS_DCK; - /* search for objects that share the same slot */ list_for_each_entry(slot, &bridge->slots, node) if (slot->device == device) @@ -316,19 +315,26 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); if (!slot) { - status = AE_NO_MEMORY; - goto err; + acpi_lock_hp_context(); + acpiphp_put_context(context); + acpi_unlock_hp_context(); + return AE_NO_MEMORY; } slot->bus = bridge->pci_bus; slot->device = device; INIT_LIST_HEAD(&slot->funcs); - mutex_init(&slot->crit_sect); list_add_tail(&slot->node, &bridge->slots); - /* Register slots for ejectable functions only. */ - if (acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) { + /* + * Expose slots to user space for functions that have _EJ0 or _RMV or + * are located in dock stations. Do not expose them for devices handled + * by the native PCIe hotplug (PCIeHP), becuase that code is supposed to + * expose slots to user space in those cases. + */ + if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev)) + && !(pdev && device_is_managed_by_native_pciehp(pdev))) { unsigned long long sun; int retval; @@ -345,11 +351,9 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, slot->slot = NULL; bridge->nr_slots--; if (retval == -EBUSY) - pr_warn("Slot %llu already registered by another " - "hotplug driver\n", sun); + pr_warn("Slot %llu already registered by another hotplug driver\n", sun); else - pr_warn("acpiphp_register_hotplug_slot failed " - "(err code = 0x%x)\n", retval); + pr_warn("acpiphp_register_hotplug_slot failed (err code = 0x%x)\n", retval); } /* Even if the slot registration fails, we can still use it. */ } @@ -362,52 +366,20 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, &val, 60*1000)) slot->flags |= SLOT_ENABLED; - if (is_dock_device(handle)) { - /* we don't want to call this device's _EJ0 - * because we want the dock notify handler - * to call it after it calls _DCK - */ - newfunc->flags &= ~FUNC_HAS_EJ0; - if (register_hotplug_dock_device(handle, - &acpiphp_dock_ops, context, - acpiphp_dock_init, acpiphp_dock_release)) - pr_debug("failed to register dock device\n"); - } - - /* install notify handler */ - if (!(newfunc->flags & FUNC_HAS_DCK)) { - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event, - context); - if (ACPI_FAILURE(status)) - acpi_handle_err(handle, - "failed to install notify handler\n"); - } - return AE_OK; - - err: - mutex_lock(&acpiphp_context_lock); - acpiphp_put_context(context); - mutex_unlock(&acpiphp_context_lock); - return status; } -static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) +static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) { - struct acpiphp_context *context; struct acpiphp_bridge *bridge = NULL; - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (context) { - bridge = context->bridge; + acpi_lock_hp_context(); + if (adev->hp) { + bridge = to_acpiphp_root_context(adev->hp)->root_bridge; if (bridge) get_bridge(bridge); - - acpiphp_put_context(context); } - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); return bridge; } @@ -415,22 +387,15 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) { struct acpiphp_slot *slot; struct acpiphp_func *func; - acpi_status status; list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(func, &slot->funcs, sibling) { - acpi_handle handle = func_to_handle(func); - - if (is_dock_device(handle)) - unregister_hotplug_dock_device(handle); + struct acpi_device *adev = func_to_acpi_device(func); - if (!(func->flags & FUNC_HAS_DCK)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event); - if (ACPI_FAILURE(status)) - pr_err("failed to remove notify handler\n"); - } + acpi_lock_hp_context(); + adev->hp->notify = NULL; + adev->hp->fixup = NULL; + acpi_unlock_hp_context(); } slot->flags |= SLOT_IS_GOING_AWAY; if (slot->slot) @@ -441,7 +406,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) list_del(&bridge->list); mutex_unlock(&bridge_mutex); + acpi_lock_hp_context(); bridge->is_going_away = true; + acpi_unlock_hp_context(); } /** @@ -450,7 +417,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) */ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) { - struct list_head *tmp; + struct pci_bus *tmp; unsigned char max, n; /* @@ -463,41 +430,14 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) */ max = bus->busn_res.start; - list_for_each(tmp, &bus->children) { - n = pci_bus_max_busnr(pci_bus_b(tmp)); + list_for_each_entry(tmp, &bus->children, node) { + n = pci_bus_max_busnr(tmp); if (n > max) max = n; } return max; } -/** - * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree. - * @handle: ACPI device object handle to start from. - */ -static void acpiphp_bus_trim(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); - if (adev) - acpi_bus_trim(adev); -} - -/** - * acpiphp_bus_add - Scan ACPI namespace subtree. - * @handle: ACPI object handle to start the scan from. - */ -static void acpiphp_bus_add(acpi_handle handle) -{ - struct acpi_device *adev = NULL; - - acpi_bus_scan(handle); - acpi_bus_get_device(handle, &adev); - if (acpi_device_enumerated(adev)) - acpi_device_set_power(adev, ACPI_STATE_D0); -} - static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) { struct acpiphp_func *func; @@ -537,9 +477,13 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot) { struct acpiphp_func *func; - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_add(func_to_handle(func)); + list_for_each_entry(func, &slot->funcs, sibling) { + struct acpi_device *adev = func_to_acpi_device(func); + acpi_bus_scan(adev->handle); + if (acpi_device_enumerated(adev)) + acpi_device_set_power(adev, ACPI_STATE_D0); + } return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0)); } @@ -550,7 +494,7 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot) * This function should be called per *physical slot*, * not per each slot object in ACPI namespace. */ -static void __ref enable_slot(struct acpiphp_slot *slot) +static void enable_slot(struct acpiphp_slot *slot) { struct pci_dev *dev; struct pci_bus *bus = slot->bus; @@ -565,8 +509,7 @@ static void __ref enable_slot(struct acpiphp_slot *slot) if (PCI_SLOT(dev->devfn) != slot->device) continue; - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { + if (pci_is_bridge(dev)) { max = pci_scan_bridge(bus, dev, max, pass); if (pass && dev->subordinate) { check_hotplug_bridge(slot, dev); @@ -604,32 +547,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot) } } -/* return first device in slot, acquiring a reference on it */ -static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot) -{ - struct pci_bus *bus = slot->bus; - struct pci_dev *dev; - struct pci_dev *ret = NULL; - - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) - if (PCI_SLOT(dev->devfn) == slot->device) { - ret = pci_dev_get(dev); - break; - } - up_read(&pci_bus_sem); - - return ret; -} - /** * disable_slot - disable a slot * @slot: ACPI PHP slot */ static void disable_slot(struct acpiphp_slot *slot) { + struct pci_bus *bus = slot->bus; + struct pci_dev *dev, *prev; struct acpiphp_func *func; - struct pci_dev *pdev; /* * enable_slot() enumerates all functions in this device via @@ -637,22 +563,18 @@ static void disable_slot(struct acpiphp_slot *slot) * methods (_EJ0, etc.) or not. Therefore, we remove all functions * here. */ - while ((pdev = dev_in_slot(slot))) { - pci_stop_and_remove_bus_device(pdev); - pci_dev_put(pdev); - } + list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->device) + pci_stop_and_remove_bus_device(dev); list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_trim(func_to_handle(func)); + acpi_bus_trim(func_to_acpi_device(func)); slot->flags &= (~SLOT_ENABLED); } -static bool acpiphp_no_hotplug(acpi_handle handle) +static bool acpiphp_no_hotplug(struct acpi_device *adev) { - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); return adev && adev->flags.no_hotplug; } @@ -661,7 +583,7 @@ static bool slot_no_hotplug(struct acpiphp_slot *slot) struct acpiphp_func *func; list_for_each_entry(func, &slot->funcs, sibling) - if (acpiphp_no_hotplug(func_to_handle(func))) + if (acpiphp_no_hotplug(func_to_acpi_device(func))) return true; return false; @@ -709,40 +631,48 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) return (unsigned int)sta; } +static inline bool device_status_valid(unsigned int sta) +{ + /* + * ACPI spec says that _STA may return bit 0 clear with bit 3 set + * if the device is valid but does not require a device driver to be + * loaded (Section 6.3.7 of ACPI 5.0A). + */ + unsigned int mask = ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_FUNCTIONING; + return (sta & mask) == mask; +} + /** * trim_stale_devices - remove PCI devices that are not responding. * @dev: PCI device to start walking the hierarchy from. */ static void trim_stale_devices(struct pci_dev *dev) { - acpi_handle handle = ACPI_HANDLE(&dev->dev); + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); struct pci_bus *bus = dev->subordinate; bool alive = false; - if (handle) { + if (adev) { acpi_status status; unsigned long long sta; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL) - || acpiphp_no_hotplug(handle); + status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); + alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) + || acpiphp_no_hotplug(adev); } - if (!alive) { - u32 v; + if (!alive) + alive = pci_device_is_present(dev); - /* Check if the device responds. */ - alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0); - } if (!alive) { pci_stop_and_remove_bus_device(dev); - if (handle) - acpiphp_bus_trim(handle); + if (adev) + acpi_bus_trim(adev); } else if (bus) { struct pci_dev *child, *tmp; /* The device is a bridge. so check the bus below it. */ pm_runtime_get_sync(&dev->dev); - list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) + list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) trim_stale_devices(child); pm_runtime_put(&dev->dev); @@ -768,13 +698,12 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) struct pci_bus *bus = slot->bus; struct pci_dev *dev, *tmp; - mutex_lock(&slot->crit_sect); if (slot_no_hotplug(slot)) { ; /* do nothing */ - } else if (get_slot_status(slot) == ACPI_STA_ALL) { + } else if (device_status_valid(get_slot_status(slot))) { /* remove stale devices if any */ - list_for_each_entry_safe(dev, tmp, &bus->devices, - bus_list) + list_for_each_entry_safe_reverse(dev, tmp, + &bus->devices, bus_list) if (PCI_SLOT(dev->devfn) == slot->device) trim_stale_devices(dev); @@ -783,7 +712,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) } else { disable_slot(slot); } - mutex_unlock(&slot->crit_sect); } } @@ -805,7 +733,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) int i; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; - list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { + list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) { for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { struct resource *res = &dev->resource[i]; if ((res->flags & type_mask) && !res->start && @@ -823,186 +751,112 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) * ACPI event handlers */ -void acpiphp_check_host_bridge(acpi_handle handle) +void acpiphp_check_host_bridge(struct acpi_device *adev) { struct acpiphp_bridge *bridge; - bridge = acpiphp_handle_to_bridge(handle); + bridge = acpiphp_dev_to_bridge(adev); if (bridge) { + pci_lock_rescan_remove(); + acpiphp_check_bridge(bridge); + + pci_unlock_rescan_remove(); put_bridge(bridge); } } static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); -static void hotplug_event(acpi_handle handle, u32 type, void *data) +static void hotplug_event(u32 type, struct acpiphp_context *context) { - struct acpiphp_context *context = data; + acpi_handle handle = context->hp.self->handle; struct acpiphp_func *func = &context->func; + struct acpiphp_slot *slot = func->slot; struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - mutex_lock(&acpiphp_context_lock); + acpi_lock_hp_context(); bridge = context->bridge; if (bridge) get_bridge(bridge); - mutex_unlock(&acpiphp_context_lock); + acpi_unlock_hp_context(); - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + pci_lock_rescan_remove(); switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ - pr_debug("%s: Bus check notify on %s\n", __func__, objname); - pr_debug("%s: re-enumerating slots under %s\n", - __func__, objname); - if (bridge) { + acpi_handle_debug(handle, "Bus check in %s()\n", __func__); + if (bridge) acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; - - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - - mutex_lock(&slot->crit_sect); + else if (!(slot->flags & SLOT_IS_GOING_AWAY)) enable_slot(slot); - mutex_unlock(&slot->crit_sect); - } + break; case ACPI_NOTIFY_DEVICE_CHECK: /* device check */ - pr_debug("%s: Device check notify on %s\n", __func__, objname); + acpi_handle_debug(handle, "Device check in %s()\n", __func__); if (bridge) { acpiphp_check_bridge(bridge); - } else { - struct acpiphp_slot *slot = func->slot; - int ret; - - if (slot->flags & SLOT_IS_GOING_AWAY) - break; - + } else if (!(slot->flags & SLOT_IS_GOING_AWAY)) { /* * Check if anything has changed in the slot and rescan * from the parent if that's the case. */ - mutex_lock(&slot->crit_sect); - ret = acpiphp_rescan_slot(slot); - mutex_unlock(&slot->crit_sect); - if (ret) + if (acpiphp_rescan_slot(slot)) acpiphp_check_bridge(func->parent); } break; case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ - pr_debug("%s: Device eject notify on %s\n", __func__, objname); - acpiphp_disable_and_eject_slot(func->slot); + acpi_handle_debug(handle, "Eject request in %s()\n", __func__); + acpiphp_disable_and_eject_slot(slot); break; } + pci_unlock_rescan_remove(); if (bridge) put_bridge(bridge); } -static void hotplug_event_work(void *data, u32 type) +static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type) { - struct acpiphp_context *context = data; - acpi_handle handle = context->handle; - - acpi_scan_lock_acquire(); - pci_lock_rescan_remove(); + struct acpiphp_context *context; - hotplug_event(handle, type, context); + context = acpiphp_grab_context(adev); + if (!context) + return -ENODATA; - pci_unlock_rescan_remove(); - acpi_scan_lock_release(); - acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); - put_bridge(context->func.parent); + hotplug_event(type, context); + acpiphp_let_context_go(context); + return 0; } /** - * handle_hotplug_event - handle ACPI hotplug event - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @data: pointer to acpiphp_context structure + * acpiphp_enumerate_slots - Enumerate PCI slots for a given bus. + * @bus: PCI bus to enumerate the slots for. * - * Handles ACPI event notification on slots. - */ -static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) -{ - struct acpiphp_context *context; - u32 ost_code = ACPI_OST_SC_SUCCESS; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - break; - case ACPI_NOTIFY_EJECT_REQUEST: - ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS; - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - return; - - case ACPI_NOTIFY_FREQUENCY_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a frequency mismatch\n"); - goto out; - - case ACPI_NOTIFY_BUS_MODE_MISMATCH: - acpi_handle_err(handle, "Device cannot be configured due " - "to a bus mode mismatch\n"); - goto out; - - case ACPI_NOTIFY_POWER_FAULT: - acpi_handle_err(handle, "Device has suffered a power fault\n"); - goto out; - - default: - acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type); - ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY; - goto out; - } - - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (context && !WARN_ON(context->handle != handle)) { - get_bridge(context->func.parent); - acpiphp_put_context(context); - acpi_hotplug_execute(hotplug_event_work, context, type); - mutex_unlock(&acpiphp_context_lock); - return; - } - mutex_unlock(&acpiphp_context_lock); - ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - - out: - acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); -} - -/* - * Create hotplug slots for the PCI bus. - * It should always return 0 to avoid skipping following notifiers. + * A "slot" is an object associated with a PCI device number. All functions + * (PCI devices) with the same bus and device number belong to the same slot. */ void acpiphp_enumerate_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; + struct acpi_device *adev; acpi_handle handle; acpi_status status; if (acpiphp_disabled) return; - handle = ACPI_HANDLE(bus->bridge); - if (!handle) + adev = ACPI_COMPANION(bus->bridge); + if (!adev) return; + handle = adev->handle; bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (!bridge) { acpi_handle_err(handle, "No memory for bridge object\n"); @@ -1021,7 +875,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) */ get_device(&bus->dev); - if (!pci_is_root_bus(bridge->pci_bus)) { + acpi_lock_hp_context(); + if (pci_is_root_bus(bridge->pci_bus)) { + struct acpiphp_root_context *root_context; + + root_context = kzalloc(sizeof(*root_context), GFP_KERNEL); + if (!root_context) + goto err; + + root_context->root_bridge = bridge; + acpi_set_hp_context(adev, &root_context->hp, NULL, NULL, NULL); + } else { struct acpiphp_context *context; /* @@ -1030,38 +894,60 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) * parent is going to be handled by pciehp, in which case this * bridge is not interesting to us either. */ - mutex_lock(&acpiphp_context_lock); - context = acpiphp_get_context(handle); - if (!context) { - mutex_unlock(&acpiphp_context_lock); - put_device(&bus->dev); - pci_dev_put(bridge->pci_dev); - kfree(bridge); - return; - } + context = acpiphp_get_context(adev); + if (!context) + goto err; + bridge->context = context; context->bridge = bridge; /* Get a reference to the parent bridge. */ get_bridge(context->func.parent); - mutex_unlock(&acpiphp_context_lock); } + acpi_unlock_hp_context(); - /* must be added to the list prior to calling register_slot */ + /* Must be added to the list prior to calling acpiphp_add_context(). */ mutex_lock(&bridge_mutex); list_add(&bridge->list, &bridge_list); mutex_unlock(&bridge_mutex); /* register all slot objects under this bridge */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - register_slot, NULL, bridge, NULL); + acpiphp_add_context, NULL, bridge, NULL); if (ACPI_FAILURE(status)) { acpi_handle_err(handle, "failed to register slots\n"); cleanup_bridge(bridge); put_bridge(bridge); } + return; + + err: + acpi_unlock_hp_context(); + put_device(&bus->dev); + pci_dev_put(bridge->pci_dev); + kfree(bridge); } -/* Destroy hotplug slots associated with the PCI bus */ +void acpiphp_drop_bridge(struct acpiphp_bridge *bridge) +{ + if (pci_is_root_bus(bridge->pci_bus)) { + struct acpiphp_root_context *root_context; + struct acpi_device *adev; + + acpi_lock_hp_context(); + adev = ACPI_COMPANION(bridge->pci_bus->bridge); + root_context = to_acpiphp_root_context(adev->hp); + adev->hp = NULL; + acpi_unlock_hp_context(); + kfree(root_context); + } + cleanup_bridge(bridge); + put_bridge(bridge); +} + +/** + * acpiphp_remove_slots - Remove slot objects associated with a given bus. + * @bus: PCI bus to remove the slot objects for. + */ void acpiphp_remove_slots(struct pci_bus *bus) { struct acpiphp_bridge *bridge; @@ -1073,8 +959,7 @@ void acpiphp_remove_slots(struct pci_bus *bus) list_for_each_entry(bridge, &bridge_list, list) if (bridge->pci_bus == bus) { mutex_unlock(&bridge_mutex); - cleanup_bridge(bridge); - put_bridge(bridge); + acpiphp_drop_bridge(bridge); return; } @@ -1092,13 +977,10 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); /* configure all functions */ if (!(slot->flags & SLOT_ENABLED)) enable_slot(slot); - mutex_unlock(&slot->crit_sect); - pci_unlock_rescan_remove(); return 0; } @@ -1114,8 +996,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) if (slot->flags & SLOT_IS_GOING_AWAY) return -ENODEV; - mutex_lock(&slot->crit_sect); - /* unconfigure all functions */ disable_slot(slot); @@ -1129,7 +1009,6 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) break; } - mutex_unlock(&slot->crit_sect); return 0; } @@ -1137,9 +1016,15 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) { int ret; + /* + * Acquire acpi_scan_lock to ensure that the execution of _EJ0 in + * acpiphp_disable_and_eject_slot() will be synchronized properly. + */ + acpi_scan_lock_acquire(); pci_lock_rescan_remove(); ret = acpiphp_disable_and_eject_slot(slot); pci_unlock_rescan_remove(); + acpi_scan_lock_release(); return ret; } diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index 1356211431d..6a0ddf75734 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -56,9 +56,9 @@ struct cpci_hp_controller_ops { int (*enable_irq) (void); int (*disable_irq) (void); int (*check_irq) (void *dev_id); - int (*hardware_test) (struct slot* slot, u32 value); - u8 (*get_power) (struct slot* slot); - int (*set_power) (struct slot* slot, int value); + int (*hardware_test) (struct slot *slot, u32 value); + u8 (*get_power) (struct slot *slot); + int (*set_power) (struct slot *slot, int value); }; struct cpci_hp_controller { @@ -89,13 +89,13 @@ int cpci_hp_stop(void); u8 cpci_get_attention_status(struct slot *slot); u8 cpci_get_latch_status(struct slot *slot); u8 cpci_get_adapter_status(struct slot *slot); -u16 cpci_get_hs_csr(struct slot * slot); +u16 cpci_get_hs_csr(struct slot *slot); int cpci_set_attention_status(struct slot *slot, int status); -int cpci_check_and_clear_ins(struct slot * slot); -int cpci_check_ext(struct slot * slot); -int cpci_clear_ext(struct slot * slot); -int cpci_led_on(struct slot * slot); -int cpci_led_off(struct slot * slot); +int cpci_check_and_clear_ins(struct slot *slot); +int cpci_check_ext(struct slot *slot); +int cpci_clear_ext(struct slot *slot); +int cpci_led_on(struct slot *slot); +int cpci_led_off(struct slot *slot); int cpci_configure_slot(struct slot *slot); int cpci_unconfigure_slot(struct slot *slot); diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index 00c81a3cefc..e09cf7827d6 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -65,10 +65,10 @@ static int thread_finished; static int enable_slot(struct hotplug_slot *slot); static int disable_slot(struct hotplug_slot *slot); static int set_attention_status(struct hotplug_slot *slot, u8 value); -static int get_power_status(struct hotplug_slot *slot, u8 * value); -static int get_attention_status(struct hotplug_slot *slot, u8 * value); -static int get_adapter_status(struct hotplug_slot *slot, u8 * value); -static int get_latch_status(struct hotplug_slot *slot, u8 * value); +static int get_power_status(struct hotplug_slot *slot, u8 *value); +static int get_attention_status(struct hotplug_slot *slot, u8 *value); +static int get_adapter_status(struct hotplug_slot *slot, u8 *value); +static int get_latch_status(struct hotplug_slot *slot, u8 *value); static struct hotplug_slot_ops cpci_hotplug_slot_ops = { .enable_slot = enable_slot, @@ -168,7 +168,7 @@ cpci_get_power_status(struct slot *slot) } static int -get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) +get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; @@ -177,7 +177,7 @@ get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) } static int -get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) +get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; @@ -192,14 +192,14 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) } static int -get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) +get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { *value = hotplug_slot->info->adapter_status; return 0; } static int -get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) +get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { *value = hotplug_slot->info->latch_status; return 0; @@ -299,6 +299,7 @@ error_slot: error: return status; } +EXPORT_SYMBOL_GPL(cpci_hp_register_bus); int cpci_hp_unregister_bus(struct pci_bus *bus) @@ -329,6 +330,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus) up_write(&list_rwsem); return status; } +EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); /* This is the interrupt mode interrupt handler */ static irqreturn_t @@ -360,7 +362,7 @@ static int init_slots(int clear_ins) { struct slot *slot; - struct pci_dev* dev; + struct pci_dev *dev; dbg("%s - enter", __func__); down_read(&list_rwsem); @@ -614,6 +616,7 @@ cpci_hp_register_controller(struct cpci_hp_controller *new_controller) controller = new_controller; return status; } +EXPORT_SYMBOL_GPL(cpci_hp_register_controller); static void cleanup_slots(void) @@ -653,6 +656,7 @@ cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) status = -ENODEV; return status; } +EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); int cpci_hp_start(void) @@ -690,6 +694,7 @@ cpci_hp_start(void) dbg("%s - exit", __func__); return 0; } +EXPORT_SYMBOL_GPL(cpci_hp_start); int cpci_hp_stop(void) @@ -704,6 +709,7 @@ cpci_hp_stop(void) cpci_stop_thread(); return 0; } +EXPORT_SYMBOL_GPL(cpci_hp_stop); int __init cpci_hotplug_init(int debug) @@ -721,10 +727,3 @@ cpci_hotplug_exit(void) cpci_hp_stop(); cpci_hp_unregister_controller(controller); } - -EXPORT_SYMBOL_GPL(cpci_hp_register_controller); -EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); -EXPORT_SYMBOL_GPL(cpci_hp_register_bus); -EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); -EXPORT_SYMBOL_GPL(cpci_hp_start); -EXPORT_SYMBOL_GPL(cpci_hp_stop); diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 8c146485176..7d48ecae669 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -46,7 +46,7 @@ extern int cpci_debug; #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) -u8 cpci_get_attention_status(struct slot* slot) +u8 cpci_get_attention_status(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -66,7 +66,7 @@ u8 cpci_get_attention_status(struct slot* slot) return hs_csr & 0x0008 ? 1 : 0; } -int cpci_set_attention_status(struct slot* slot, int status) +int cpci_set_attention_status(struct slot *slot, int status) { int hs_cap; u16 hs_csr; @@ -93,7 +93,7 @@ int cpci_set_attention_status(struct slot* slot, int status) return 1; } -u16 cpci_get_hs_csr(struct slot* slot) +u16 cpci_get_hs_csr(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -111,7 +111,7 @@ u16 cpci_get_hs_csr(struct slot* slot) return hs_csr; } -int cpci_check_and_clear_ins(struct slot* slot) +int cpci_check_and_clear_ins(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -140,7 +140,7 @@ int cpci_check_and_clear_ins(struct slot* slot) return ins; } -int cpci_check_ext(struct slot* slot) +int cpci_check_ext(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -161,7 +161,7 @@ int cpci_check_ext(struct slot* slot) return ext; } -int cpci_clear_ext(struct slot* slot) +int cpci_clear_ext(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -187,7 +187,7 @@ int cpci_clear_ext(struct slot* slot) return 0; } -int cpci_led_on(struct slot* slot) +int cpci_led_on(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -216,7 +216,7 @@ int cpci_led_on(struct slot* slot) return 0; } -int cpci_led_off(struct slot* slot) +int cpci_led_off(struct slot *slot) { int hs_cap; u16 hs_csr; @@ -250,7 +250,7 @@ int cpci_led_off(struct slot* slot) * Device configuration functions */ -int __ref cpci_configure_slot(struct slot *slot) +int cpci_configure_slot(struct slot *slot) { struct pci_dev *dev; struct pci_bus *parent; @@ -289,8 +289,7 @@ int __ref cpci_configure_slot(struct slot *slot) list_for_each_entry(dev, &parent->devices, bus_list) if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn)) continue; - if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + if (pci_is_bridge(dev)) pci_hp_add_bridge(dev); @@ -304,7 +303,7 @@ int __ref cpci_configure_slot(struct slot *slot) return ret; } -int cpci_unconfigure_slot(struct slot* slot) +int cpci_unconfigure_slot(struct slot *slot) { struct pci_dev *dev, *temp; diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c index 7536eef620b..04fcd781140 100644 --- a/drivers/pci/hotplug/cpcihp_generic.c +++ b/drivers/pci/hotplug/cpcihp_generic.c @@ -78,8 +78,8 @@ static struct cpci_hp_controller generic_hpc; static int __init validate_parameters(void) { - char* str; - char* p; + char *str; + char *p; unsigned long tmp; if(!bridge) { @@ -142,8 +142,8 @@ static int query_enum(void) static int __init cpcihp_generic_init(void) { int status; - struct resource* r; - struct pci_dev* dev; + struct resource *r; + struct pci_dev *dev; info(DRIVER_DESC " version: " DRIVER_VERSION); status = validate_parameters(); diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index e8c4a7ccf57..6757b3ef7e1 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -295,7 +295,7 @@ static struct pci_driver zt5550_hc_driver = { static int __init zt5550_init(void) { - struct resource* r; + struct resource *r; int rc; info(DRIVER_DESC " version: " DRIVER_VERSION); diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index 516b87738b6..0450f405807 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -255,7 +255,7 @@ struct pci_func { struct pci_resource *io_head; struct pci_resource *bus_head; struct timer_list *p_task_event; - struct pci_dev* pci_dev; + struct pci_dev *pci_dev; }; struct slot { @@ -278,7 +278,7 @@ struct slot { }; struct pci_resource { - struct pci_resource * next; + struct pci_resource *next; u32 base; u32 length; }; diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 31273e155e6..4aaee746df8 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -94,7 +94,7 @@ static inline int is_slot66mhz(struct slot *slot) * * Returns pointer to the head of the SMBIOS tables (or %NULL). */ -static void __iomem * detect_SMBIOS_pointer(void __iomem *begin, void __iomem *end) +static void __iomem *detect_SMBIOS_pointer(void __iomem *begin, void __iomem *end) { void __iomem *fp; void __iomem *endp; @@ -131,7 +131,7 @@ static void __iomem * detect_SMBIOS_pointer(void __iomem *begin, void __iomem *e * * For unexpected switch opens */ -static int init_SERR(struct controller * ctrl) +static int init_SERR(struct controller *ctrl) { u32 tempdword; u32 number_of_slots; @@ -291,7 +291,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot) kfree(slot); } -static int ctrl_slot_cleanup (struct controller * ctrl) +static int ctrl_slot_cleanup (struct controller *ctrl) { struct slot *old_slot, *next_slot; @@ -706,8 +706,7 @@ static int ctrl_slot_setup(struct controller *ctrl, hotplug_slot_info->adapter_status = get_presence_status(ctrl, slot); - dbg("registering bus %d, dev %d, number %d, " - "ctrl->slot_device_offset %d, slot %d\n", + dbg("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", slot->bus, slot->device, slot->number, ctrl->slot_device_offset, slot_number); @@ -837,8 +836,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bus = pdev->subordinate; if (!bus) { - dev_notice(&pdev->dev, "the device is not a bridge, " - "skipping\n"); + dev_notice(&pdev->dev, "the device is not a bridge, skipping\n"); rc = -ENODEV; goto err_disable_device; } @@ -920,12 +918,12 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bus->max_bus_speed = PCI_SPEED_100MHz_PCIX; break; } - if (bus_cap & 20) { + if (bus_cap & 0x20) { dbg("bus max supports 66MHz PCI-X\n"); bus->max_bus_speed = PCI_SPEED_66MHz_PCIX; break; } - if (bus_cap & 10) { + if (bus_cap & 0x10) { dbg("bus max supports 66MHz PCI\n"); bus->max_bus_speed = PCI_SPEED_66MHz; break; diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 11845b79679..bde47fce324 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -39,9 +39,9 @@ #include <linux/kthread.h> #include "cpqphp.h" -static u32 configure_new_device(struct controller* ctrl, struct pci_func *func, +static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, u8 behind_bridge, struct resource_lists *resources); -static int configure_new_function(struct controller* ctrl, struct pci_func *func, +static int configure_new_function(struct controller *ctrl, struct pci_func *func, u8 behind_bridge, struct resource_lists *resources); static void interrupt_event_handler(struct controller *ctrl); @@ -64,7 +64,7 @@ static void long_delay(int delay) /* FIXME: The following line needs to be somewhere else... */ #define WRONG_BUS_FREQUENCY 0x07 -static u8 handle_switch_change(u8 change, struct controller * ctrl) +static u8 handle_switch_change(u8 change, struct controller *ctrl) { int hp_slot; u8 rc = 0; @@ -138,7 +138,7 @@ static struct slot *cpqhp_find_slot(struct controller *ctrl, u8 device) } -static u8 handle_presence_change(u16 change, struct controller * ctrl) +static u8 handle_presence_change(u16 change, struct controller *ctrl) { int hp_slot; u8 rc = 0; @@ -232,7 +232,7 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl) } -static u8 handle_power_fault(u8 change, struct controller * ctrl) +static u8 handle_power_fault(u8 change, struct controller *ctrl) { int hp_slot; u8 rc = 0; @@ -709,7 +709,8 @@ static struct pci_resource *get_max_resource(struct pci_resource **head, u32 siz temp = temp->next; } - temp->next = max->next; + if (temp) + temp->next = max->next; } max->next = NULL; @@ -996,7 +997,7 @@ struct pci_func *cpqhp_slot_create(u8 busnumber) * * Returns %0 if successful, !0 otherwise. */ -static int slot_remove(struct pci_func * old_slot) +static int slot_remove(struct pci_func *old_slot) { struct pci_func *next; @@ -1108,7 +1109,7 @@ struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index) /* DJZ: I don't think is_bridge will work as is. * FIXME */ -static int is_bridge(struct pci_func * func) +static int is_bridge(struct pci_func *func) { /* Check the header type */ if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) @@ -1624,7 +1625,7 @@ static u32 board_added(struct pci_func *func, struct controller *ctrl) * @replace_flag: whether replacing or adding a new device * @ctrl: target controller */ -static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl) +static u32 remove_board(struct pci_func *func, u32 replace_flag, struct controller *ctrl) { int index; u8 skip = 0; @@ -1741,7 +1742,7 @@ static void pushbutton_helper_thread(unsigned long data) /* this is the main worker thread */ -static int event_thread(void* data) +static int event_thread(void *data) { struct controller *ctrl; @@ -1991,7 +1992,7 @@ int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func) u16 temp_word; u32 tempdword; int rc; - struct slot* p_slot; + struct slot *p_slot; int physical_slot = 0; tempdword = 0; @@ -2087,7 +2088,7 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) u8 replace_flag; u32 rc = 0; unsigned int devfn; - struct slot* p_slot; + struct slot *p_slot; struct pci_bus *pci_bus = ctrl->pci_bus; int physical_slot=0; @@ -2269,8 +2270,8 @@ int cpqhp_hardware_test(struct controller *ctrl, int test_num) * * Returns 0 if success. */ -static u32 configure_new_device(struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources) +static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, + u8 behind_bridge, struct resource_lists *resources) { u8 temp_byte, function, max_functions, stop_it; int rc; diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index 76ba8a1c774..0968a9bcb34 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -34,7 +34,6 @@ #include <linux/workqueue.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> -#include <linux/init.h> #include <asm/uaccess.h> #include "cpqphp.h" #include "cpqphp_nvram.h" @@ -108,7 +107,7 @@ static spinlock_t int15_lock; */ -static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) +static u32 add_byte(u32 **p_buffer, u8 value, u32 *used, u32 *avail) { u8 **tByte; @@ -123,7 +122,7 @@ static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) } -static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail) +static u32 add_dword(u32 **p_buffer, u32 value, u32 *used, u32 *avail) { if ((*used + 4) > *avail) return(1); @@ -268,12 +267,12 @@ static u32 store_HRT (void __iomem *rom_start) ctrl = cpqhp_ctrl_list; /* The revision of this structure */ - rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); + rc = add_byte(&pFill, 1 + ctrl->push_flag, &usedbytes, &available); if (rc) return(rc); /* The number of controllers */ - rc = add_byte( &pFill, 1, &usedbytes, &available); + rc = add_byte(&pFill, 1, &usedbytes, &available); if (rc) return(rc); @@ -283,22 +282,22 @@ static u32 store_HRT (void __iomem *rom_start) numCtrl++; /* The bus number */ - rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); + rc = add_byte(&pFill, ctrl->bus, &usedbytes, &available); if (rc) return(rc); /* The device Number */ - rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); + rc = add_byte(&pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); if (rc) return(rc); /* The function Number */ - rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); + rc = add_byte(&pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); if (rc) return(rc); /* Skip the number of available entries */ - rc = add_dword( &pFill, 0, &usedbytes, &available); + rc = add_dword(&pFill, 0, &usedbytes, &available); if (rc) return(rc); @@ -312,12 +311,12 @@ static u32 store_HRT (void __iomem *rom_start) loop ++; /* base */ - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + rc = add_dword(&pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); /* length */ - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + rc = add_dword(&pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -337,12 +336,12 @@ static u32 store_HRT (void __iomem *rom_start) loop ++; /* base */ - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + rc = add_dword(&pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); /* length */ - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + rc = add_dword(&pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -362,12 +361,12 @@ static u32 store_HRT (void __iomem *rom_start) loop ++; /* base */ - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + rc = add_dword(&pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); /* length */ - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + rc = add_dword(&pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); @@ -387,12 +386,12 @@ static u32 store_HRT (void __iomem *rom_start) loop ++; /* base */ - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + rc = add_dword(&pFill, resNode->base, &usedbytes, &available); if (rc) return(rc); /* length */ - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + rc = add_dword(&pFill, resNode->length, &usedbytes, &available); if (rc) return(rc); diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index a3e3c2002b5..1c8c2f130d3 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -81,7 +81,7 @@ static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iom } -int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) +int cpqhp_configure_device (struct controller *ctrl, struct pci_func *func) { struct pci_bus *child; int num; @@ -121,7 +121,7 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) } -int cpqhp_unconfigure_device(struct pci_func* func) +int cpqhp_unconfigure_device(struct pci_func *func) { int j; @@ -129,7 +129,7 @@ int cpqhp_unconfigure_device(struct pci_func* func) pci_lock_rescan_remove(); for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); + struct pci_dev *temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); if (temp) { pci_dev_put(temp); pci_stop_and_remove_bus_device(temp); @@ -203,7 +203,7 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) } -static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) +static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 *dev_num) { u16 tdevice; u32 work; @@ -280,7 +280,7 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num } -int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) +int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot) { /* plain (bridges allowed) */ return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); @@ -465,7 +465,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) * * returns 0 if success */ -int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) +int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func *new_slot) { long rc; u8 class_code; @@ -549,7 +549,7 @@ int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) * * returns 0 if success */ -int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) +int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func) { u8 cloop; u8 header_type; @@ -686,7 +686,7 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) * * returns 0 if success */ -int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) +int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func *func) { u8 cloop; u8 header_type; @@ -949,7 +949,7 @@ int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) * * returns 0 if success */ -int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) +int cpqhp_configure_board(struct controller *ctrl, struct pci_func *func) { int cloop; u8 header_type; @@ -1027,7 +1027,7 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) * * returns 0 if the board is the same nonzero otherwise */ -int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) +int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func) { u8 cloop; u8 header_type; @@ -1419,7 +1419,7 @@ int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_st * * returns 0 if success */ -int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) +int cpqhp_return_board_resources(struct pci_func *func, struct resource_lists *resources) { int rc = 0; struct pci_resource *node; @@ -1475,7 +1475,7 @@ int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * * * Puts node back in the resource list pointed to by head */ -void cpqhp_destroy_resource_list (struct resource_lists * resources) +void cpqhp_destroy_resource_list (struct resource_lists *resources) { struct pci_resource *res, *tres; @@ -1522,7 +1522,7 @@ void cpqhp_destroy_resource_list (struct resource_lists * resources) * * Puts node back in the resource list pointed to by head */ -void cpqhp_destroy_board_resources (struct pci_func * func) +void cpqhp_destroy_board_resources (struct pci_func *func) { struct pci_resource *res, *tres; diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index 17c1f36315d..4a392c44e3d 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -79,7 +79,7 @@ static int show_ctrl (struct controller *ctrl, char *buf) static int show_dev (struct controller *ctrl, char *buf) { - char * out = buf; + char *out = buf; int index; struct pci_resource *res; struct pci_func *new_slot; diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index cf3ac1e4b09..f7b8684a773 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -74,7 +74,7 @@ static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value) static inline int get_cur_bus_info(struct slot **sl) { int rc = 1; - struct slot * slot_cur = *sl; + struct slot *slot_cur = *sl; debug("options = %x\n", slot_cur->ctrl->options); debug("revision = %x\n", slot_cur->ctrl->revision); @@ -114,8 +114,8 @@ static inline int slot_update(struct slot **sl) static int __init get_max_slots (void) { - struct slot * slot_cur; - struct list_head * tmp; + struct slot *slot_cur; + struct list_head *tmp; u8 slot_count = 0; list_for_each(tmp, &ibmphp_slot_head) { @@ -280,7 +280,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) return rc; } -static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; @@ -311,7 +311,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) return rc; } -static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; @@ -338,7 +338,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) } -static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; @@ -364,7 +364,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) return rc; } -static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; @@ -433,7 +433,7 @@ static int get_max_bus_speed(struct slot *slot) } /* -static int get_max_adapter_speed_1(struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) +static int get_max_adapter_speed_1(struct hotplug_slot *hotplug_slot, u8 *value, u8 flag) { int rc = -ENODEV; struct slot *pslot; @@ -471,7 +471,7 @@ static int get_max_adapter_speed_1(struct hotplug_slot *hotplug_slot, u8 * value return rc; } -static int get_bus_name(struct hotplug_slot *hotplug_slot, char * value) +static int get_bus_name(struct hotplug_slot *hotplug_slot, char *value) { int rc = -ENODEV; struct slot *pslot = NULL; @@ -671,7 +671,7 @@ static struct pci_func *ibm_slot_find(u8 busno, u8 device, u8 function) { struct pci_func *func_cur; struct slot *slot_cur; - struct list_head * tmp; + struct list_head *tmp; list_for_each(tmp, &ibmphp_slot_head) { slot_cur = list_entry(tmp, struct slot, ibm_slot_list); if (slot_cur->func) { @@ -696,8 +696,8 @@ static struct pci_func *ibm_slot_find(u8 busno, u8 device, u8 function) static void free_slots(void) { struct slot *slot_cur; - struct list_head * tmp; - struct list_head * next; + struct list_head *tmp; + struct list_head *next; debug("%s -- enter\n", __func__); @@ -825,10 +825,10 @@ static int ibm_configure_device(struct pci_func *func) /******************************************************* * Returns whether the bus is empty or not *******************************************************/ -static int is_bus_empty(struct slot * slot_cur) +static int is_bus_empty(struct slot *slot_cur) { int rc; - struct slot * tmp_slot; + struct slot *tmp_slot; u8 i = slot_cur->bus_on->slot_min; while (i <= slot_cur->bus_on->slot_max) { @@ -856,7 +856,7 @@ static int is_bus_empty(struct slot * slot_cur) * Parameters: slot * Returns: bus is set (0) or error code ***********************************************************/ -static int set_bus(struct slot * slot_cur) +static int set_bus(struct slot *slot_cur) { int rc; u8 speed; @@ -956,7 +956,7 @@ static int set_bus(struct slot * slot_cur) static int check_limitations(struct slot *slot_cur) { u8 i; - struct slot * tmp_slot; + struct slot *tmp_slot; u8 count = 0; u8 limitation = 0; @@ -1045,8 +1045,7 @@ static int enable_slot(struct hotplug_slot *hs) rc = check_limitations(slot_cur); if (rc) { err("Adding this card exceeds the limitations of this bus.\n"); - err("(i.e., >1 133MHz cards running on same bus, or " - ">2 66 PCI cards running on same bus.\n"); + err("(i.e., >1 133MHz cards running on same bus, or >2 66 PCI cards running on same bus.\n"); err("Try hot-adding into another bus\n"); rc = -EINVAL; goto error_nopower; @@ -1070,12 +1069,10 @@ static int enable_slot(struct hotplug_slot *hs) !(SLOT_PWRGD(slot_cur->status))) err("power fault occurred trying to power up\n"); else if (SLOT_BUS_SPEED(slot_cur->status)) { - err("bus speed mismatch occurred. please check " - "current bus speed and card capability\n"); + err("bus speed mismatch occurred. please check current bus speed and card capability\n"); print_card_capability(slot_cur); } else if (SLOT_BUS_MODE(slot_cur->ext_status)) { - err("bus mode mismatch occurred. please check " - "current bus mode and card capability\n"); + err("bus mode mismatch occurred. please check current bus mode and card capability\n"); print_card_capability(slot_cur); } ibmphp_update_slot_info(slot_cur); @@ -1098,8 +1095,7 @@ static int enable_slot(struct hotplug_slot *hs) goto error_power; } if (SLOT_POWER(slot_cur->status) && (SLOT_BUS_SPEED(slot_cur->status))) { - err("bus speed mismatch occurred. please check current bus " - "speed and card capability\n"); + err("bus speed mismatch occurred. please check current bus speed and card capability\n"); print_card_capability(slot_cur); goto error_power; } diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index bd044158b36..0f65ac55543 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c @@ -563,7 +563,7 @@ static int first_slot_num (u8 slot_num, u8 first_slot, u8 var) return rc; } -static struct opt_rio_lo * find_rxe_num (u8 slot_num) +static struct opt_rio_lo *find_rxe_num (u8 slot_num) { struct opt_rio_lo *opt_lo_ptr; @@ -575,7 +575,7 @@ static struct opt_rio_lo * find_rxe_num (u8 slot_num) return NULL; } -static struct opt_rio * find_chassis_num (u8 slot_num) +static struct opt_rio *find_chassis_num (u8 slot_num) { struct opt_rio *opt_vg_ptr; @@ -593,7 +593,7 @@ static struct opt_rio * find_chassis_num (u8 slot_num) static u8 calculate_first_slot (u8 slot_num) { u8 first_slot = 1; - struct slot * slot_cur; + struct slot *slot_cur; list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) { if (slot_cur->ctrl) { @@ -607,7 +607,7 @@ static u8 calculate_first_slot (u8 slot_num) #define SLOT_NAME_SIZE 30 -static char *create_file_name (struct slot * slot_cur) +static char *create_file_name (struct slot *slot_cur) { struct opt_rio *opt_vg_ptr = NULL; struct opt_rio_lo *opt_lo_ptr = NULL; @@ -1192,7 +1192,7 @@ int ibmphp_register_pci (void) } return rc; } -static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids) +static int ibmphp_probe (struct pci_dev *dev, const struct pci_device_id *ids) { struct controller *ctrl; diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index 5fc7a089f53..a936022956e 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -533,7 +533,7 @@ static u8 hpc_readcmdtoindex (u8 cmd, u8 index) * * Return 0 or error codes *---------------------------------------------------------------------*/ -int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) +int ibmphp_hpc_readslot (struct slot *pslot, u8 cmd, u8 *pstatus) { void __iomem *wpg_bbar = NULL; struct controller *ctlr_ptr; @@ -672,7 +672,7 @@ int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) * * Action: issue a WRITE command to HPC *---------------------------------------------------------------------*/ -int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) +int ibmphp_hpc_writeslot (struct slot *pslot, u8 cmd) { void __iomem *wpg_bbar = NULL; struct controller *ctlr_ptr; @@ -1102,7 +1102,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void) * Value: *---------------------------------------------------------------------*/ static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void __iomem *wpg_bbar, - u8 * pstatus) + u8 *pstatus) { int rc = 0; u8 done = 0; diff --git a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c index 639ea3a75e1..2fd296706ce 100644 --- a/drivers/pci/hotplug/ibmphp_pci.c +++ b/drivers/pci/hotplug/ibmphp_pci.c @@ -47,7 +47,7 @@ static u8 find_sec_number (u8 primary_busno, u8 slotno); * We also assign the same irq numbers for multi function devices. * These are PIC mode, so shouldn't matter n.e.ways (hopefully) */ -static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) +static void assign_alt_irq (struct pci_func *cur_func, u8 class_code) { int j; for (j = 0; j < 4; j++) { @@ -137,8 +137,8 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) "Please choose another device.\n", cur_func->device); return -ENODEV; } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x is not supported for hot plugging. " - "Please choose another device.\n", cur_func->device); + err ("The device %x is not supported for hot plugging. Please choose another device.\n", + cur_func->device); return -ENODEV; } switch (hdr_type) { @@ -179,8 +179,8 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) case PCI_HEADER_TYPE_MULTIBRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " - "Please insert another card.\n", cur_func->device); + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. Please insert another card.\n", + cur_func->device); return -ENODEV; } assign_alt_irq (cur_func, class_code); @@ -247,8 +247,8 @@ int ibmphp_configure_card (struct pci_func *func, u8 slotno) class >>= 8; debug ("class now is %x\n", class); if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " - "Please insert another card.\n", cur_func->device); + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. Please insert another card.\n", + cur_func->device); return -ENODEV; } @@ -1073,7 +1073,7 @@ error: * Input: bridge function * Output: amount of resources needed *****************************************************************************/ -static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) +static struct res_needed *scan_behind_bridge (struct pci_func *func, u8 busno) { int count, len[6]; u16 vendor_id; @@ -1125,13 +1125,11 @@ static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x is VGA compatible and as is not supported for hot plugging. " - "Please choose another device.\n", device); + err ("The device %x is VGA compatible and as is not supported for hot plugging. Please choose another device.\n", device); amount->not_correct = 1; return amount; } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x is not supported for hot plugging. " - "Please choose another device.\n", device); + err ("The device %x is not supported for hot plugging. Please choose another device.\n", device); amount->not_correct = 1; return amount; } @@ -1483,12 +1481,10 @@ static int unconfigure_boot_card (struct slot *slot_cur) debug ("hdr_type %x, class %x\n", hdr_type, class); class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x function %x is VGA compatible and is not supported for hot removing. " - "Please choose another device.\n", device, function); + err ("The device %x function %x is VGA compatible and is not supported for hot removing. Please choose another device.\n", device, function); return -ENODEV; } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x function %x is not supported for hot removing. " - "Please choose another device.\n", device, function); + err ("The device %x function %x is not supported for hot removing. Please choose another device.\n", device, function); return -ENODEV; } @@ -1513,9 +1509,7 @@ static int unconfigure_boot_card (struct slot *slot_cur) case PCI_HEADER_TYPE_BRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This device %x function %x is not PCI-to-PCI bridge, " - "and is not supported for hot-removing. " - "Please try another card.\n", device, function); + err ("This device %x function %x is not PCI-to-PCI bridge, and is not supported for hot-removing. Please try another card.\n", device, function); return -ENODEV; } rc = unconfigure_boot_bridge (busno, device, function); @@ -1529,9 +1523,7 @@ static int unconfigure_boot_card (struct slot *slot_cur) case PCI_HEADER_TYPE_MULTIBRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This device %x function %x is not PCI-to-PCI bridge, " - "and is not supported for hot-removing. " - "Please try another card.\n", device, function); + err ("This device %x function %x is not PCI-to-PCI bridge, and is not supported for hot-removing. Please try another card.\n", device, function); return -ENODEV; } rc = unconfigure_boot_bridge (busno, device, function); diff --git a/drivers/pci/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c index a265acb2d51..f34745abd5b 100644 --- a/drivers/pci/hotplug/ibmphp_res.c +++ b/drivers/pci/hotplug/ibmphp_res.c @@ -46,9 +46,9 @@ static struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); static LIST_HEAD(gbuses); -static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag) +static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc *curr, u8 busno, int flag) { - struct bus_node * newbus; + struct bus_node *newbus; if (!(curr) && !(flag)) { err ("NULL pointer passed\n"); @@ -69,7 +69,7 @@ static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 return newbus; } -static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr) +static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc *curr) { struct resource_node *rs; @@ -93,7 +93,7 @@ static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * cur static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) { - struct bus_node * newbus; + struct bus_node *newbus; struct range_node *newrange; u8 num_ranges = 0; @@ -789,8 +789,7 @@ int ibmphp_remove_resource (struct resource_node *res) bus_cur = find_bus_wprev (res->busno, NULL, 0); if (!bus_cur) { - err ("cannot find corresponding bus of the io resource to remove " - "bailing out...\n"); + err ("cannot find corresponding bus of the io resource to remove bailing out...\n"); return -ENODEV; } @@ -934,9 +933,9 @@ int ibmphp_remove_resource (struct resource_node *res) return 0; } -static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res) +static struct range_node *find_range (struct bus_node *bus_cur, struct resource_node *res) { - struct range_node * range = NULL; + struct range_node *range = NULL; switch (res->type) { case IO: diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index cfa92a984e6..56d8486dc16 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -59,14 +59,12 @@ static bool debug; #define DRIVER_DESC "PCI Hot Plug PCI Core" -////////////////////////////////////////////////////////////////// - static LIST_HEAD(pci_hotplug_slot_list); static DEFINE_MUTEX(pci_hp_mutex); /* Weee, fun with macros... */ -#define GET_STATUS(name,type) \ -static int get_##name (struct hotplug_slot *slot, type *value) \ +#define GET_STATUS(name, type) \ +static int get_##name(struct hotplug_slot *slot, type *value) \ { \ struct hotplug_slot_ops *ops = slot->ops; \ int retval = 0; \ @@ -92,42 +90,41 @@ static ssize_t power_read_file(struct pci_slot *slot, char *buf) retval = get_power_status(slot->hotplug, &value); if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); -exit: - return retval; + return retval; + + return sprintf(buf, "%d\n", value); } static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf, - size_t count) + size_t count) { struct hotplug_slot *slot = pci_slot->hotplug; unsigned long lpower; u8 power; int retval = 0; - lpower = simple_strtoul (buf, NULL, 10); + lpower = simple_strtoul(buf, NULL, 10); power = (u8)(lpower & 0xff); - dbg ("power = %d\n", power); + dbg("power = %d\n", power); if (!try_module_get(slot->ops->owner)) { retval = -ENODEV; goto exit; } switch (power) { - case 0: - if (slot->ops->disable_slot) - retval = slot->ops->disable_slot(slot); - break; - - case 1: - if (slot->ops->enable_slot) - retval = slot->ops->enable_slot(slot); - break; - - default: - err ("Illegal value specified for power\n"); - retval = -EINVAL; + case 0: + if (slot->ops->disable_slot) + retval = slot->ops->disable_slot(slot); + break; + + case 1: + if (slot->ops->enable_slot) + retval = slot->ops->enable_slot(slot); + break; + + default: + err("Illegal value specified for power\n"); + retval = -EINVAL; } module_put(slot->ops->owner); @@ -150,24 +147,22 @@ static ssize_t attention_read_file(struct pci_slot *slot, char *buf) retval = get_attention_status(slot->hotplug, &value); if (retval) - goto exit; - retval = sprintf(buf, "%d\n", value); + return retval; -exit: - return retval; + return sprintf(buf, "%d\n", value); } static ssize_t attention_write_file(struct pci_slot *slot, const char *buf, - size_t count) + size_t count) { struct hotplug_slot_ops *ops = slot->hotplug->ops; unsigned long lattention; u8 attention; int retval = 0; - lattention = simple_strtoul (buf, NULL, 10); + lattention = simple_strtoul(buf, NULL, 10); attention = (u8)(lattention & 0xff); - dbg (" - attention = %d\n", attention); + dbg(" - attention = %d\n", attention); if (!try_module_get(ops->owner)) { retval = -ENODEV; @@ -196,11 +191,9 @@ static ssize_t latch_read_file(struct pci_slot *slot, char *buf) retval = get_latch_status(slot->hotplug, &value); if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); + return retval; -exit: - return retval; + return sprintf(buf, "%d\n", value); } static struct pci_slot_attribute hotplug_slot_attr_latch = { @@ -215,11 +208,9 @@ static ssize_t presence_read_file(struct pci_slot *slot, char *buf) retval = get_adapter_status(slot->hotplug, &value); if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); + return retval; -exit: - return retval; + return sprintf(buf, "%d\n", value); } static struct pci_slot_attribute hotplug_slot_attr_presence = { @@ -228,7 +219,7 @@ static struct pci_slot_attribute hotplug_slot_attr_presence = { }; static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf, - size_t count) + size_t count) { struct hotplug_slot *slot = pci_slot->hotplug; unsigned long ltest; @@ -237,7 +228,7 @@ static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf, ltest = simple_strtoul (buf, NULL, 10); test = (u32)(ltest & 0xffffffff); - dbg ("test = %d\n", test); + dbg("test = %d\n", test); if (!try_module_get(slot->ops->owner)) { retval = -ENODEV; @@ -261,6 +252,7 @@ static struct pci_slot_attribute hotplug_slot_attr_test = { static bool has_power_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; + if ((!slot) || (!slot->ops)) return false; if ((slot->ops->enable_slot) || @@ -273,6 +265,7 @@ static bool has_power_file(struct pci_slot *pci_slot) static bool has_attention_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; + if ((!slot) || (!slot->ops)) return false; if ((slot->ops->set_attention_status) || @@ -284,6 +277,7 @@ static bool has_attention_file(struct pci_slot *pci_slot) static bool has_latch_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; + if ((!slot) || (!slot->ops)) return false; if (slot->ops->get_latch_status) @@ -294,6 +288,7 @@ static bool has_latch_file(struct pci_slot *pci_slot) static bool has_adapter_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; + if ((!slot) || (!slot->ops)) return false; if (slot->ops->get_adapter_status) @@ -304,6 +299,7 @@ static bool has_adapter_file(struct pci_slot *pci_slot) static bool has_test_file(struct pci_slot *pci_slot) { struct hotplug_slot *slot = pci_slot->hotplug; + if ((!slot) || (!slot->ops)) return false; if (slot->ops->hardware_test) @@ -397,13 +393,13 @@ static void fs_remove_slot(struct pci_slot *slot) pci_hp_remove_module_link(slot); } -static struct hotplug_slot *get_slot_from_name (const char *name) +static struct hotplug_slot *get_slot_from_name(const char *name) { struct hotplug_slot *slot; struct list_head *tmp; - list_for_each (tmp, &pci_hotplug_slot_list) { - slot = list_entry (tmp, struct hotplug_slot, slot_list); + list_for_each(tmp, &pci_hotplug_slot_list) { + slot = list_entry(tmp, struct hotplug_slot, slot_list); if (strcmp(hotplug_slot_name(slot), name) == 0) return slot; } @@ -436,8 +432,7 @@ int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, if ((slot->info == NULL) || (slot->ops == NULL)) return -EINVAL; if (slot->release == NULL) { - dbg("Why are you trying to register a hotplug slot " - "without a proper release function?\n"); + dbg("Why are you trying to register a hotplug slot without a proper release function?\n"); return -EINVAL; } @@ -468,6 +463,7 @@ out: mutex_unlock(&pci_hp_mutex); return result; } +EXPORT_SYMBOL_GPL(__pci_hp_register); /** * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem @@ -506,6 +502,7 @@ int pci_hp_deregister(struct hotplug_slot *hotplug) return 0; } +EXPORT_SYMBOL_GPL(pci_hp_deregister); /** * pci_hp_change_slot_info - changes the slot's information structure in the core @@ -527,24 +524,23 @@ int pci_hp_change_slot_info(struct hotplug_slot *hotplug, return 0; } +EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); -static int __init pci_hotplug_init (void) +static int __init pci_hotplug_init(void) { int result; result = cpci_hotplug_init(debug); if (result) { - err ("cpci_hotplug_init with error %d\n", result); - goto err_cpci; + err("cpci_hotplug_init with error %d\n", result); + return result; } - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - -err_cpci: + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); return result; } -static void __exit pci_hotplug_exit (void) +static void __exit pci_hotplug_exit(void) { cpci_hotplug_exit(); } @@ -557,7 +553,3 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -EXPORT_SYMBOL_GPL(__pci_hp_register); -EXPORT_SYMBOL_GPL(pci_hp_deregister); -EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 88b37cad4b3..8e9012dca45 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -76,6 +76,7 @@ struct slot { struct hotplug_slot *hotplug_slot; struct delayed_work work; /* work for button event */ struct mutex lock; + struct mutex hotplug_lock; struct workqueue_struct *wq; }; @@ -109,6 +110,8 @@ struct controller { #define INT_BUTTON_PRESS 7 #define INT_BUTTON_RELEASE 8 #define INT_BUTTON_CANCEL 9 +#define INT_LINK_UP 10 +#define INT_LINK_DOWN 11 #define STATIC_STATE 0 #define BLINKINGON_STATE 1 @@ -124,7 +127,7 @@ struct controller { #define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_HPS) #define EMI(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_EIP) #define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS) -#define PSN(ctrl) ((ctrl)->slot_cap >> 19) +#define PSN(ctrl) (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19) int pciehp_sysfs_enable_slot(struct slot *slot); int pciehp_sysfs_disable_slot(struct slot *slot); @@ -132,6 +135,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot); u8 pciehp_handle_switch_change(struct slot *p_slot); u8 pciehp_handle_presence_change(struct slot *p_slot); u8 pciehp_handle_power_fault(struct slot *p_slot); +void pciehp_handle_linkstate_change(struct slot *p_slot); int pciehp_configure_device(struct slot *p_slot); int pciehp_unconfigure_device(struct slot *p_slot); void pciehp_queue_pushbutton_work(struct work_struct *work); @@ -153,6 +157,7 @@ void pciehp_green_led_on(struct slot *slot); void pciehp_green_led_off(struct slot *slot); void pciehp_green_led_blink(struct slot *slot); int pciehp_check_link_status(struct controller *ctrl); +bool pciehp_check_link_active(struct controller *ctrl); void pciehp_release_ctrl(struct controller *ctrl); int pciehp_reset_slot(struct slot *slot, int probe); diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index eddddd447d0..93cc9266e8c 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c @@ -103,15 +103,16 @@ static int __init dummy_probe(struct pcie_device *dev) } static struct pcie_port_service_driver __initdata dummy_driver = { - .name = "pciehp_dummy", + .name = "pciehp_dummy", .port_type = PCIE_ANY_PORT, .service = PCIE_PORT_SERVICE_HP, - .probe = dummy_probe, + .probe = dummy_probe, }; static int __init select_detection_mode(void) { struct dummy_slot *slot, *tmp; + if (pcie_port_service_register(&dummy_driver)) return PCIEHP_DETECT_ACPI; pcie_port_service_unregister(&dummy_driver); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 53b58debc28..a2297db8081 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -108,6 +108,7 @@ static int init_slot(struct controller *ctrl) ops = kzalloc(sizeof(*ops), GFP_KERNEL); if (!ops) goto out; + ops->enable_slot = enable_slot; ops->disable_slot = disable_slot; ops->get_power_status = get_power_status; @@ -265,8 +266,7 @@ static int pciehp_probe(struct pcie_device *dev) rc = init_slot(ctrl); if (rc) { if (rc == -EBUSY) - ctrl_warn(ctrl, "Slot already registered by another " - "hotplug driver\n"); + ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n"); else ctrl_err(ctrl, "Slot initialization failed\n"); goto err_out_release_ctlr; @@ -283,8 +283,11 @@ static int pciehp_probe(struct pcie_device *dev) slot = ctrl->slot; pciehp_get_adapter_status(slot, &occupied); pciehp_get_power_status(slot, &poweron); - if (occupied && pciehp_force) + if (occupied && pciehp_force) { + mutex_lock(&slot->hotplug_lock); pciehp_enable_slot(slot); + mutex_unlock(&slot->hotplug_lock); + } /* If empty slot's power status is on, turn power off */ if (!occupied && poweron && POWER_CTRL(ctrl)) pciehp_power_off_slot(slot); @@ -308,12 +311,12 @@ static void pciehp_remove(struct pcie_device *dev) } #ifdef CONFIG_PM -static int pciehp_suspend (struct pcie_device *dev) +static int pciehp_suspend(struct pcie_device *dev) { return 0; } -static int pciehp_resume (struct pcie_device *dev) +static int pciehp_resume(struct pcie_device *dev) { struct controller *ctrl; struct slot *slot; @@ -328,10 +331,12 @@ static int pciehp_resume (struct pcie_device *dev) /* Check if slot is occupied */ pciehp_get_adapter_status(slot, &status); + mutex_lock(&slot->hotplug_lock); if (status) pciehp_enable_slot(slot); else pciehp_disable_slot(slot); + mutex_unlock(&slot->hotplug_lock); return 0; } #endif /* PM */ diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 50628487597..ff32e85e1de 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -150,11 +150,32 @@ u8 pciehp_handle_power_fault(struct slot *p_slot) return 1; } +void pciehp_handle_linkstate_change(struct slot *p_slot) +{ + u32 event_type; + struct controller *ctrl = p_slot->ctrl; + + /* Link Status Change */ + ctrl_dbg(ctrl, "Data Link Layer State change\n"); + + if (pciehp_check_link_active(ctrl)) { + ctrl_info(ctrl, "slot(%s): Link Up event\n", + slot_name(p_slot)); + event_type = INT_LINK_UP; + } else { + ctrl_info(ctrl, "slot(%s): Link Down event\n", + slot_name(p_slot)); + event_type = INT_LINK_DOWN; + } + + queue_interrupt_event(p_slot, event_type); +} + /* The following routines constitute the bulk of the hotplug controller logic */ -static void set_slot_off(struct controller *ctrl, struct slot * pslot) +static void set_slot_off(struct controller *ctrl, struct slot *pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl)) { @@ -212,7 +233,8 @@ static int board_added(struct slot *p_slot) if (retval) { ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n", pci_domain_nr(parent), parent->number); - goto err_exit; + if (retval != -EEXIST) + goto err_exit; } pciehp_green_led_on(p_slot); @@ -255,6 +277,9 @@ static int remove_board(struct slot *p_slot) struct power_work_info { struct slot *p_slot; struct work_struct work; + unsigned int req; +#define DISABLE_REQ 0 +#define ENABLE_REQ 1 }; /** @@ -269,30 +294,38 @@ static void pciehp_power_thread(struct work_struct *work) struct power_work_info *info = container_of(work, struct power_work_info, work); struct slot *p_slot = info->p_slot; + int ret; - mutex_lock(&p_slot->lock); - switch (p_slot->state) { - case POWEROFF_STATE: - mutex_unlock(&p_slot->lock); + switch (info->req) { + case DISABLE_REQ: ctrl_dbg(p_slot->ctrl, "Disabling domain:bus:device=%04x:%02x:00\n", pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), p_slot->ctrl->pcie->port->subordinate->number); + mutex_lock(&p_slot->hotplug_lock); pciehp_disable_slot(p_slot); + mutex_unlock(&p_slot->hotplug_lock); mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; - break; - case POWERON_STATE: mutex_unlock(&p_slot->lock); - if (pciehp_enable_slot(p_slot)) + break; + case ENABLE_REQ: + ctrl_dbg(p_slot->ctrl, + "Enabling domain:bus:device=%04x:%02x:00\n", + pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), + p_slot->ctrl->pcie->port->subordinate->number); + mutex_lock(&p_slot->hotplug_lock); + ret = pciehp_enable_slot(p_slot); + mutex_unlock(&p_slot->hotplug_lock); + if (ret) pciehp_green_led_off(p_slot); mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; + mutex_unlock(&p_slot->lock); break; default: break; } - mutex_unlock(&p_slot->lock); kfree(info); } @@ -315,9 +348,11 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) switch (p_slot->state) { case BLINKINGOFF_STATE: p_slot->state = POWEROFF_STATE; + info->req = DISABLE_REQ; break; case BLINKINGON_STATE: p_slot->state = POWERON_STATE; + info->req = ENABLE_REQ; break; default: kfree(info); @@ -341,14 +376,12 @@ static void handle_button_press_event(struct slot *p_slot) pciehp_get_power_status(p_slot, &getstatus); if (getstatus) { p_slot->state = BLINKINGOFF_STATE; - ctrl_info(ctrl, - "PCI slot #%s - powering off due to button " - "press.\n", slot_name(p_slot)); + ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n", + slot_name(p_slot)); } else { p_slot->state = BLINKINGON_STATE; - ctrl_info(ctrl, - "PCI slot #%s - powering on due to button " - "press.\n", slot_name(p_slot)); + ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n", + slot_name(p_slot)); } /* blink green LED and turn off amber */ pciehp_green_led_blink(p_slot); @@ -364,14 +397,13 @@ static void handle_button_press_event(struct slot *p_slot) */ ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot)); cancel_delayed_work(&p_slot->work); - if (p_slot->state == BLINKINGOFF_STATE) { + if (p_slot->state == BLINKINGOFF_STATE) pciehp_green_led_on(p_slot); - } else { + else pciehp_green_led_off(p_slot); - } pciehp_set_attention_status(p_slot, 0); - ctrl_info(ctrl, "PCI slot #%s - action canceled " - "due to button press\n", slot_name(p_slot)); + ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n", + slot_name(p_slot)); p_slot->state = STATIC_STATE; break; case POWEROFF_STATE: @@ -407,14 +439,81 @@ static void handle_surprise_event(struct slot *p_slot) INIT_WORK(&info->work, pciehp_power_thread); pciehp_get_adapter_status(p_slot, &getstatus); - if (!getstatus) + if (!getstatus) { p_slot->state = POWEROFF_STATE; - else + info->req = DISABLE_REQ; + } else { p_slot->state = POWERON_STATE; + info->req = ENABLE_REQ; + } queue_work(p_slot->wq, &info->work); } +/* + * Note: This function must be called with slot->lock held + */ +static void handle_link_event(struct slot *p_slot, u32 event) +{ + struct controller *ctrl = p_slot->ctrl; + struct power_work_info *info; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n", + __func__); + return; + } + info->p_slot = p_slot; + info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ; + INIT_WORK(&info->work, pciehp_power_thread); + + switch (p_slot->state) { + case BLINKINGON_STATE: + case BLINKINGOFF_STATE: + cancel_delayed_work(&p_slot->work); + /* Fall through */ + case STATIC_STATE: + p_slot->state = event == INT_LINK_UP ? + POWERON_STATE : POWEROFF_STATE; + queue_work(p_slot->wq, &info->work); + break; + case POWERON_STATE: + if (event == INT_LINK_UP) { + ctrl_info(ctrl, + "Link Up event ignored on slot(%s): already powering on\n", + slot_name(p_slot)); + kfree(info); + } else { + ctrl_info(ctrl, + "Link Down event queued on slot(%s): currently getting powered on\n", + slot_name(p_slot)); + p_slot->state = POWEROFF_STATE; + queue_work(p_slot->wq, &info->work); + } + break; + case POWEROFF_STATE: + if (event == INT_LINK_UP) { + ctrl_info(ctrl, + "Link Up event queued on slot(%s): currently getting powered off\n", + slot_name(p_slot)); + p_slot->state = POWERON_STATE; + queue_work(p_slot->wq, &info->work); + } else { + ctrl_info(ctrl, + "Link Down event ignored on slot(%s): already powering off\n", + slot_name(p_slot)); + kfree(info); + } + break; + default: + ctrl_err(ctrl, "Not a valid state on slot(%s)\n", + slot_name(p_slot)); + kfree(info); + break; + } +} + static void interrupt_event_handler(struct work_struct *work) { struct event_info *info = container_of(work, struct event_info, work); @@ -433,12 +532,23 @@ static void interrupt_event_handler(struct work_struct *work) pciehp_green_led_off(p_slot); break; case INT_PRESENCE_ON: - case INT_PRESENCE_OFF: if (!HP_SUPR_RM(ctrl)) break; + ctrl_dbg(ctrl, "Surprise Insertion\n"); + handle_surprise_event(p_slot); + break; + case INT_PRESENCE_OFF: + /* + * Regardless of surprise capability, we need to + * definitely remove a card that has been pulled out! + */ ctrl_dbg(ctrl, "Surprise Removal\n"); handle_surprise_event(p_slot); break; + case INT_LINK_UP: + case INT_LINK_DOWN: + handle_link_event(p_slot, info->event_type); + break; default: break; } @@ -447,6 +557,9 @@ static void interrupt_event_handler(struct work_struct *work) kfree(info); } +/* + * Note: This function must be called with slot->hotplug_lock held + */ int pciehp_enable_slot(struct slot *p_slot) { u8 getstatus = 0; @@ -479,13 +592,15 @@ int pciehp_enable_slot(struct slot *p_slot) pciehp_get_latch_status(p_slot, &getstatus); rc = board_added(p_slot); - if (rc) { + if (rc) pciehp_get_latch_status(p_slot, &getstatus); - } + return rc; } - +/* + * Note: This function must be called with slot->hotplug_lock held + */ int pciehp_disable_slot(struct slot *p_slot) { u8 getstatus = 0; @@ -494,24 +609,6 @@ int pciehp_disable_slot(struct slot *p_slot) if (!p_slot->ctrl) return 1; - if (!HP_SUPR_RM(p_slot->ctrl)) { - pciehp_get_adapter_status(p_slot, &getstatus); - if (!getstatus) { - ctrl_info(ctrl, "No adapter on slot(%s)\n", - slot_name(p_slot)); - return -ENODEV; - } - } - - if (MRL_SENS(p_slot->ctrl)) { - pciehp_get_latch_status(p_slot, &getstatus); - if (getstatus) { - ctrl_info(ctrl, "Latch open on slot(%s)\n", - slot_name(p_slot)); - return -ENODEV; - } - } - if (POWER_CTRL(p_slot->ctrl)) { pciehp_get_power_status(p_slot, &getstatus); if (!getstatus) { @@ -536,7 +633,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot) case STATIC_STATE: p_slot->state = POWERON_STATE; mutex_unlock(&p_slot->lock); + mutex_lock(&p_slot->hotplug_lock); retval = pciehp_enable_slot(p_slot); + mutex_unlock(&p_slot->hotplug_lock); mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; break; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 14acfccb767..42914e04d11 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -159,6 +159,8 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); if (slot_status & PCI_EXP_SLTSTA_CC) { + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_CC); if (!ctrl->no_cmd_complete) { /* * After 1 sec and CMD_COMPLETED still not set, just @@ -172,12 +174,10 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) * event even though it supports none of power * controller, attention led, power led and EMI. */ - ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Need to " - "wait for command completed event.\n"); + ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Need to wait for command completed event\n"); ctrl->no_cmd_complete = 0; } else { - ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Maybe " - "the controller is broken.\n"); + ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Maybe the controller is broken\n"); } } @@ -201,12 +201,12 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) if (!(slot_ctrl & PCI_EXP_SLTCTL_HPIE) || !(slot_ctrl & PCI_EXP_SLTCTL_CCIE)) poll = 1; - pcie_wait_cmd(ctrl, poll); + pcie_wait_cmd(ctrl, poll); } mutex_unlock(&ctrl->ctrl_lock); } -static bool check_link_active(struct controller *ctrl) +bool pciehp_check_link_active(struct controller *ctrl) { struct pci_dev *pdev = ctrl_dev(ctrl); u16 lnk_status; @@ -225,12 +225,12 @@ static void __pcie_wait_link_active(struct controller *ctrl, bool active) { int timeout = 1000; - if (check_link_active(ctrl) == active) + if (pciehp_check_link_active(ctrl) == active) return; while (timeout > 0) { msleep(10); timeout -= 10; - if (check_link_active(ctrl) == active) + if (pciehp_check_link_active(ctrl) == active) return; } ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n", @@ -242,11 +242,6 @@ static void pcie_wait_link_active(struct controller *ctrl) __pcie_wait_link_active(ctrl, true); } -static void pcie_wait_link_not_active(struct controller *ctrl) -{ - __pcie_wait_link_active(ctrl, false); -} - static bool pci_bus_check_dev(struct pci_bus *bus, int devfn) { u32 l; @@ -279,15 +274,15 @@ int pciehp_check_link_status(struct controller *ctrl) bool found; u16 lnk_status; - /* - * Data Link Layer Link Active Reporting must be capable for - * hot-plug capable downstream port. But old controller might - * not implement it. In this case, we wait for 1000 ms. - */ - if (ctrl->link_active_reporting) - pcie_wait_link_active(ctrl); - else - msleep(1000); + /* + * Data Link Layer Link Active Reporting must be capable for + * hot-plug capable downstream port. But old controller might + * not implement it. In this case, we wait for 1000 ms. + */ + if (ctrl->link_active_reporting) + pcie_wait_link_active(ctrl); + else + msleep(1000); /* wait 100ms before read pci conf, and try in 1s */ msleep(100); @@ -298,7 +293,7 @@ int pciehp_check_link_status(struct controller *ctrl) ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); if ((lnk_status & PCI_EXP_LNKSTA_LT) || !(lnk_status & PCI_EXP_LNKSTA_NLW)) { - ctrl_err(ctrl, "Link Training Error occurs \n"); + ctrl_err(ctrl, "Link Training Error occurs\n"); return -1; } @@ -332,11 +327,6 @@ static int pciehp_link_enable(struct controller *ctrl) return __pciehp_link_set(ctrl, true); } -static int pciehp_link_disable(struct controller *ctrl) -{ - return __pciehp_link_set(ctrl, false); -} - void pciehp_get_attention_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; @@ -422,7 +412,7 @@ void pciehp_set_attention_status(struct slot *slot, u8 value) return; switch (value) { - case 0 : /* turn off */ + case 0: /* turn off */ slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_OFF; break; case 1: /* turn on */ @@ -478,7 +468,7 @@ void pciehp_green_led_blink(struct slot *slot) PCI_EXP_SLTCTL_PWR_IND_BLINK); } -int pciehp_power_on_slot(struct slot * slot) +int pciehp_power_on_slot(struct slot *slot) { struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(ctrl); @@ -504,18 +494,10 @@ int pciehp_power_on_slot(struct slot * slot) return retval; } -void pciehp_power_off_slot(struct slot * slot) +void pciehp_power_off_slot(struct slot *slot) { struct controller *ctrl = slot->ctrl; - /* Disable the link at first */ - pciehp_link_disable(ctrl); - /* wait the link is down */ - if (ctrl->link_active_reporting) - pcie_wait_link_not_active(ctrl); - else - msleep(1000); - pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, @@ -540,7 +522,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | - PCI_EXP_SLTSTA_CC); + PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC); detected &= ~intr_loc; intr_loc |= detected; if (!intr_loc) @@ -579,6 +561,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) ctrl->power_fault_detected = 1; pciehp_handle_power_fault(slot); } + + if (intr_loc & PCI_EXP_SLTSTA_DLLSC) + pciehp_handle_linkstate_change(slot); + return IRQ_HANDLED; } @@ -596,9 +582,17 @@ void pcie_enable_notification(struct controller *ctrl) * when it is cleared in the interrupt service routine, and * next power fault detected interrupt was notified again. */ - cmd = PCI_EXP_SLTCTL_PDCE; + + /* + * Always enable link events: thus link-up and link-down shall + * always be treated as hotplug and unplug respectively. Enable + * presence detect only if Attention Button is not present. + */ + cmd = PCI_EXP_SLTCTL_DLLSCE; if (ATTN_BUTTN(ctrl)) cmd |= PCI_EXP_SLTCTL_ABPE; + else + cmd |= PCI_EXP_SLTCTL_PDCE; if (MRL_SENS(ctrl)) cmd |= PCI_EXP_SLTCTL_MRLSCE; if (!pciehp_poll_mode) @@ -606,7 +600,8 @@ void pcie_enable_notification(struct controller *ctrl) mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | - PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); + PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | + PCI_EXP_SLTCTL_DLLSCE); pcie_write_cmd(ctrl, cmd, mask); } @@ -624,33 +619,38 @@ static void pcie_disable_notification(struct controller *ctrl) /* * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary - * bus reset of the bridge, but if the slot supports surprise removal we need - * to disable presence detection around the bus reset and clear any spurious + * bus reset of the bridge, but at the same time we want to ensure that it is + * not seen as a hot-unplug, followed by the hot-plug of the device. Thus, + * disable link state notification and presence detection change notification + * momentarily, if we see that they could interfere. Also, clear any spurious * events after. */ int pciehp_reset_slot(struct slot *slot, int probe) { struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(ctrl); + u16 stat_mask = 0, ctrl_mask = 0; if (probe) return 0; - if (HP_SUPR_RM(ctrl)) { - pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE); - if (pciehp_poll_mode) - del_timer_sync(&ctrl->poll_timer); + if (!ATTN_BUTTN(ctrl)) { + ctrl_mask |= PCI_EXP_SLTCTL_PDCE; + stat_mask |= PCI_EXP_SLTSTA_PDC; } + ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE; + stat_mask |= PCI_EXP_SLTSTA_DLLSC; + + pcie_write_cmd(ctrl, 0, ctrl_mask); + if (pciehp_poll_mode) + del_timer_sync(&ctrl->poll_timer); pci_reset_bridge_secondary_bus(ctrl->pcie->port); - if (HP_SUPR_RM(ctrl)) { - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PDC); - pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE); - if (pciehp_poll_mode) - int_poll_timeout(ctrl->poll_timer.data); - } + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); + pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask); + if (pciehp_poll_mode) + int_poll_timeout(ctrl->poll_timer.data); return 0; } @@ -687,6 +687,7 @@ static int pcie_init_slot(struct controller *ctrl) slot->ctrl = ctrl; mutex_init(&slot->lock); + mutex_init(&slot->hotplug_lock); INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); ctrl->slot = slot; return 0; @@ -753,7 +754,7 @@ static inline void dbg_ctrl(struct controller *ctrl) ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); } -#define FLAG(x,y) (((x) & (y)) ? '+' : '-') +#define FLAG(x, y) (((x) & (y)) ? '+' : '-') struct controller *pcie_init(struct pcie_device *dev) { @@ -780,14 +781,14 @@ struct controller *pcie_init(struct pcie_device *dev) */ if (NO_CMD_CMPL(ctrl) || !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) - ctrl->no_cmd_complete = 1; - - /* Check if Data Link Layer Link Active Reporting is implemented */ - pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); - if (link_cap & PCI_EXP_LNKCAP_DLLLARC) { - ctrl_dbg(ctrl, "Link Active Reporting supported\n"); - ctrl->link_active_reporting = 1; - } + ctrl->no_cmd_complete = 1; + + /* Check if Data Link Layer Link Active Reporting is implemented */ + pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); + if (link_cap & PCI_EXP_LNKCAP_DLLLARC) { + ctrl_dbg(ctrl, "Link Active Reporting supported\n"); + ctrl->link_active_reporting = 1; + } /* Clear all remaining event bits in Slot Status register */ pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index b07d7cc2d69..5f871f4c4af 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -46,11 +46,10 @@ int pciehp_configure_device(struct slot *p_slot) dev = pci_get_slot(parent, PCI_DEVFN(0, 0)); if (dev) { - ctrl_err(ctrl, "Device %s already exists " - "at %04x:%02x:00, cannot hot-add\n", pci_name(dev), - pci_domain_nr(parent), parent->number); + ctrl_err(ctrl, "Device %s already exists at %04x:%02x:00, cannot hot-add\n", + pci_name(dev), pci_domain_nr(parent), parent->number); pci_dev_put(dev); - ret = -EINVAL; + ret = -EEXIST; goto out; } @@ -62,8 +61,7 @@ int pciehp_configure_device(struct slot *p_slot) } list_for_each_entry(dev, &parent->devices, bus_list) - if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + if (pci_is_bridge(dev)) pci_hp_add_bridge(dev); pci_assign_unassigned_bridge_resources(bridge); diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index ac69094e4b2..d062c008fc9 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -51,7 +51,7 @@ static LIST_HEAD(slot_list); #define dbg(format, arg...) \ do { \ if (debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ + printk(KERN_DEBUG "%s: " format "\n", \ MY_NAME , ## arg); \ } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) @@ -128,18 +128,18 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); switch (status) { - case 0: - /* - * Fill in code here to turn light off - */ - break; - - case 1: - default: - /* - * Fill in code here to turn light on - */ - break; + case 0: + /* + * Fill in code here to turn light off + */ + break; + + case 1: + default: + /* + * Fill in code here to turn light on + */ + break; } return retval; @@ -153,12 +153,12 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value) dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); switch (value) { - case 0: - /* Specify a test here */ - break; - case 1: - /* Specify another test here */ - break; + case 0: + /* Specify a test here */ + break; + case 1: + /* Specify another test here */ + break; } return retval; diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c index 16f92035231..e246a10a0d2 100644 --- a/drivers/pci/hotplug/pcihp_slot.c +++ b/drivers/pci/hotplug/pcihp_slot.c @@ -160,8 +160,7 @@ void pci_configure_slot(struct pci_dev *dev) (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) return; - if (dev->bus) - pcie_bus_configure_settings(dev->bus); + pcie_bus_configure_settings(dev->bus); memset(&hpp, 0, sizeof(hpp)); ret = pci_get_hp_params(dev, &hpp); diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index 4fcdeedda31..7660232ef46 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -157,8 +157,7 @@ static void dlpar_pci_add_bus(struct device_node *dn) } /* Scan below the new bridge */ - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + if (pci_is_bridge(dev)) of_scan_pci_bridge(dev); /* Map IO space for child bus, which may or may not succeed */ diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 4796c15fba9..93aa29f6d39 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -39,6 +39,7 @@ bool rpaphp_debug; LIST_HEAD(rpaphp_slot_head); +EXPORT_SYMBOL_GPL(rpaphp_slot_head); #define DRIVER_VERSION "0.1" #define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>" @@ -88,7 +89,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) * @hotplug_slot: slot to get status * @value: pointer to store status */ -static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { int retval, level; struct slot *slot = (struct slot *)hotplug_slot->private; @@ -104,14 +105,14 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) * @hotplug_slot: slot to get status * @value: pointer to store status */ -static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = (struct slot *)hotplug_slot->private; *value = slot->hotplug_slot->info->attention_status; return 0; } -static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) +static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = (struct slot *)hotplug_slot->private; int rc, state; @@ -223,16 +224,16 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, type_tmp = (char *) &types[1]; /* Iterate through parent properties, looking for my-drc-index */ - for (i = 0; i < indexes[0]; i++) { + for (i = 0; i < be32_to_cpu(indexes[0]); i++) { if ((unsigned int) indexes[i + 1] == *my_index) { if (drc_name) *drc_name = name_tmp; if (drc_type) *drc_type = type_tmp; if (drc_index) - *drc_index = *my_index; + *drc_index = be32_to_cpu(*my_index); if (drc_power_domain) - *drc_power_domain = domains[i+1]; + *drc_power_domain = be32_to_cpu(domains[i+1]); return 0; } name_tmp += (strlen(name_tmp) + 1); @@ -241,6 +242,7 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index, return -EINVAL; } +EXPORT_SYMBOL_GPL(rpaphp_get_drc_props); static int is_php_type(char *drc_type) { @@ -321,16 +323,19 @@ int rpaphp_add_slot(struct device_node *dn) /* register PCI devices */ name = (char *) &names[1]; type = (char *) &types[1]; - for (i = 0; i < indexes[0]; i++) { + for (i = 0; i < be32_to_cpu(indexes[0]); i++) { + int index; - slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]); + index = be32_to_cpu(indexes[i + 1]); + slot = alloc_slot_struct(dn, index, name, + be32_to_cpu(power_domains[i + 1])); if (!slot) return -ENOMEM; slot->type = simple_strtoul(type, NULL, 10); dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n", - indexes[i + 1], name, type); + index, name, type); retval = rpaphp_enable_slot(slot); if (!retval) @@ -347,6 +352,7 @@ int rpaphp_add_slot(struct device_node *dn) /* XXX FIXME: reports a failure only if last entry in loop failed */ return retval; } +EXPORT_SYMBOL_GPL(rpaphp_add_slot); static void __exit cleanup_slots(void) { @@ -440,7 +446,3 @@ struct hotplug_slot_ops rpaphp_hotplug_slot_ops = { module_init(rpaphp_init); module_exit(rpaphp_exit); - -EXPORT_SYMBOL_GPL(rpaphp_add_slot); -EXPORT_SYMBOL_GPL(rpaphp_slot_head); -EXPORT_SYMBOL_GPL(rpaphp_get_drc_props); diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index 8d2ce22151e..d1332d2f873 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -15,7 +15,6 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> -#include <linux/init.h> #include <asm/pci_debug.h> #include <asm/sclp.h> diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 613043f7576..bada2099987 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -188,7 +188,7 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, return 0; } -static struct hotplug_slot * sn_hp_destroy(void) +static struct hotplug_slot *sn_hp_destroy(void) { struct slot *slot; struct pci_slot *pci_slot; @@ -250,15 +250,13 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, } if (rc == PCI_L1_ERR) { - dev_dbg(&slot->pci_bus->self->dev, - "L1 failure %d with message: %s", + dev_dbg(&slot->pci_bus->self->dev, "L1 failure %d with message: %s", resp.resp_sub_errno, resp.resp_l1_msg); return -EPERM; } if (rc) { - dev_dbg(&slot->pci_bus->self->dev, - "insert failed with error %d sub-error %d\n", + dev_dbg(&slot->pci_bus->self->dev, "insert failed with error %d sub-error %d\n", rc, resp.resp_sub_errno); return -EIO; } @@ -288,21 +286,18 @@ static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, } if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) { - dev_dbg(&slot->pci_bus->self->dev, - "Cannot remove last 33MHz card\n"); + dev_dbg(&slot->pci_bus->self->dev, "Cannot remove last 33MHz card\n"); return -EPERM; } if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) { - dev_dbg(&slot->pci_bus->self->dev, - "L1 failure %d with message \n%s\n", + dev_dbg(&slot->pci_bus->self->dev, "L1 failure %d with message \n%s\n", resp.resp_sub_errno, resp.resp_l1_msg); return -EPERM; } if ((action == PCI_REQ_SLOT_ELIGIBLE) && rc) { - dev_dbg(&slot->pci_bus->self->dev, - "remove failed with error %d sub-error %d\n", + dev_dbg(&slot->pci_bus->self->dev, "remove failed with error %d sub-error %d\n", rc, resp.resp_sub_errno); return -EIO; } @@ -417,8 +412,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion); if (acpi_bus_get_device(phandle, &pdevice)) { - dev_dbg(&slot->pci_bus->self->dev, - "no parent device, assuming NULL\n"); + dev_dbg(&slot->pci_bus->self->dev, "no parent device, assuming NULL\n"); pdevice = NULL; } @@ -447,10 +441,8 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) ret = acpi_bus_scan(chandle); if (ACPI_FAILURE(ret)) { - printk(KERN_ERR "%s: acpi_bus_scan " - "failed (0x%x) for slot %d " - "func %d\n", __func__, - ret, (int)(adr>>16), + printk(KERN_ERR "%s: acpi_bus_scan failed (0x%x) for slot %d func %d\n", + __func__, ret, (int)(adr>>16), (int)(adr&0xffff)); /* try to continue on */ } @@ -471,11 +463,9 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) mutex_unlock(&sn_hotplug_mutex); if (rc == 0) - dev_dbg(&slot->pci_bus->self->dev, - "insert operation successful\n"); + dev_dbg(&slot->pci_bus->self->dev, "insert operation successful\n"); else - dev_dbg(&slot->pci_bus->self->dev, - "insert operation failed rc = %d\n", rc); + dev_dbg(&slot->pci_bus->self->dev, "insert operation failed rc = %d\n", rc); return rc; } @@ -561,8 +551,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) acpi_status ret; ret = acpi_unload_table_id(ssdt_id); if (ACPI_FAILURE(ret)) { - printk(KERN_ERR "%s: acpi_unload_table_id " - "failed (0x%x) for id %d\n", + printk(KERN_ERR "%s: acpi_unload_table_id failed (0x%x) for id %d\n", __func__, ret, ssdt_id); /* try to continue on */ } diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 61529097464..5897d516427 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -180,7 +180,7 @@ int shpchp_configure_device(struct slot *p_slot); int shpchp_unconfigure_device(struct slot *p_slot); void cleanup_slots(struct controller *ctrl); void shpchp_queue_pushbutton_work(struct work_struct *work); -int shpc_init( struct controller *ctrl, struct pci_dev *pdev); +int shpc_init(struct controller *ctrl, struct pci_dev *pdev); static inline const char *slot_name(struct slot *slot) { @@ -295,7 +295,7 @@ static inline void amd_pogo_errata_restore_misc_reg(struct slot *p_slot) pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, rse_set); } /* restore MiscII register */ - pci_read_config_dword( p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp ); + pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp ); if (p_slot->ctrl->pcix_misc2_reg & SERRFATALENABLE_MASK) pcix_misc2_temp |= SERRFATALENABLE_MASK; diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index faf13abd5b9..294ef4b10cf 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -143,8 +143,7 @@ static int init_slots(struct controller *ctrl) snprintf(name, SLOT_NAME_SIZE, "%d", slot->number); hotplug_slot->ops = &shpchp_hotplug_slot_ops; - ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x " - "hp_slot=%x sun=%x slot_device_offset=%x\n", + ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x hp_slot=%x sun=%x slot_device_offset=%x\n", pci_domain_nr(ctrl->pci_dev->subordinate), slot->bus, slot->device, slot->hp_slot, slot->number, ctrl->slot_device_offset); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 58499277903..a81fb67ea9a 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -162,7 +162,7 @@ u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl) p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { + if (!(p_slot->hpc_ops->query_power_fault(p_slot))) { /* * Power fault Cleared */ @@ -196,8 +196,8 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, ctrl_dbg(ctrl, "Change speed to %d\n", speed); if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) { - ctrl_err(ctrl, "%s: Issue of set bus speed mode command " - "failed\n", __func__); + ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n", + __func__); return WRONG_BUS_FREQUENCY; } return rc; @@ -215,8 +215,8 @@ static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, */ if (flag) { if (asp < bsp) { - ctrl_err(ctrl, "Speed of bus %x and adapter %x " - "mismatch\n", bsp, asp); + ctrl_err(ctrl, "Speed of bus %x and adapter %x mismatch\n", + bsp, asp); rc = WRONG_BUS_FREQUENCY; } return rc; @@ -250,8 +250,7 @@ static int board_added(struct slot *p_slot) hp_slot = p_slot->device - ctrl->slot_device_offset; - ctrl_dbg(ctrl, - "%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", + ctrl_dbg(ctrl, "%s: p_slot->device, slot_offset, hp_slot = %d, %d ,%d\n", __func__, p_slot->device, ctrl->slot_device_offset, hp_slot); /* Power on slot without connecting to bus */ @@ -263,8 +262,8 @@ static int board_added(struct slot *p_slot) if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { - ctrl_err(ctrl, "%s: Issue of set bus speed mode command" - " failed\n", __func__); + ctrl_err(ctrl, "%s: Issue of set bus speed mode command failed\n", + __func__); return WRONG_BUS_FREQUENCY; } @@ -277,20 +276,19 @@ static int board_added(struct slot *p_slot) rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); if (rc) { - ctrl_err(ctrl, "Can't get adapter speed or " - "bus mode mismatch\n"); + ctrl_err(ctrl, "Can't get adapter speed or bus mode mismatch\n"); return WRONG_BUS_FREQUENCY; } - bsp = ctrl->pci_dev->bus->cur_bus_speed; - msp = ctrl->pci_dev->bus->max_bus_speed; + bsp = ctrl->pci_dev->subordinate->cur_bus_speed; + msp = ctrl->pci_dev->subordinate->max_bus_speed; /* Check if there are other slots or devices on the same bus */ if (!list_empty(&ctrl->pci_dev->subordinate->devices)) slots_not_empty = 1; - ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d," - " max_bus_speed %d\n", __func__, slots_not_empty, asp, + ctrl_dbg(ctrl, "%s: slots_not_empty %d, adapter_speed %d, bus_speed %d, max_bus_speed %d\n", + __func__, slots_not_empty, asp, bsp, msp); rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, asp, bsp, msp); @@ -490,12 +488,12 @@ static void handle_button_press_event(struct slot *p_slot) p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (getstatus) { p_slot->state = BLINKINGOFF_STATE; - ctrl_info(ctrl, "PCI slot #%s - powering off due to " - "button press.\n", slot_name(p_slot)); + ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n", + slot_name(p_slot)); } else { p_slot->state = BLINKINGON_STATE; - ctrl_info(ctrl, "PCI slot #%s - powering on due to " - "button press.\n", slot_name(p_slot)); + ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n", + slot_name(p_slot)); } /* blink green LED and turn off amber */ p_slot->hpc_ops->green_led_blink(p_slot); @@ -518,8 +516,8 @@ static void handle_button_press_event(struct slot *p_slot) else p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->set_attention_status(p_slot, 0); - ctrl_info(ctrl, "PCI slot #%s - action canceled due to " - "button press\n", slot_name(p_slot)); + ctrl_info(ctrl, "PCI slot #%s - action canceled due to button press\n", + slot_name(p_slot)); p_slot->state = STATIC_STATE; break; case POWEROFF_STATE: diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 2d7f474ca0e..29e22352822 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -341,8 +341,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) cmd_status = hpc_check_cmd_status(slot->ctrl); if (cmd_status) { - ctrl_err(ctrl, - "Failed to issued command 0x%x (error code = %d)\n", + ctrl_err(ctrl, "Failed to issued command 0x%x (error code = %d)\n", cmd, cmd_status); retval = -EIO; } @@ -404,7 +403,7 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) return 0; } -static int hpc_get_power_status(struct slot * slot, u8 *status) +static int hpc_get_power_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); @@ -528,7 +527,7 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) return retval; } -static int hpc_query_power_fault(struct slot * slot) +static int hpc_query_power_fault(struct slot *slot) { struct controller *ctrl = slot->ctrl; u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); @@ -614,7 +613,7 @@ static void hpc_release_ctlr(struct controller *ctrl) release_mem_region(ctrl->mmio_base, ctrl->mmio_size); } -static int hpc_power_on_slot(struct slot * slot) +static int hpc_power_on_slot(struct slot *slot) { int retval; @@ -625,7 +624,7 @@ static int hpc_power_on_slot(struct slot * slot) return retval; } -static int hpc_slot_enable(struct slot * slot) +static int hpc_slot_enable(struct slot *slot) { int retval; @@ -638,7 +637,7 @@ static int hpc_slot_enable(struct slot * slot) return retval; } -static int hpc_slot_disable(struct slot * slot) +static int hpc_slot_disable(struct slot *slot) { int retval; @@ -720,7 +719,7 @@ static int shpc_get_cur_bus_speed(struct controller *ctrl) } -static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) +static int hpc_set_bus_speed_mode(struct slot *slot, enum pci_bus_speed value) { int retval; struct controller *ctrl = slot->ctrl; @@ -974,8 +973,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) for (i = 0; i < 9 + num_slots; i++) { rc = shpc_indirect_read(ctrl, i, &tempdword); if (rc) { - ctrl_err(ctrl, - "Cannot read creg (index = %d)\n", i); + ctrl_err(ctrl, "Cannot read creg (index = %d)\n", + i); goto abort; } ctrl_dbg(ctrl, " offset %d: value %x\n", i, tempdword); @@ -1060,10 +1059,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) /* Installs the interrupt handler */ rc = pci_enable_msi(pdev); if (rc) { - ctrl_info(ctrl, - "Can't get msi for the hotplug controller\n"); - ctrl_info(ctrl, - "Use INTx for the hotplug controller\n"); + ctrl_info(ctrl, "Can't get msi for the hotplug controller\n"); + ctrl_info(ctrl, "Use INTx for the hotplug controller\n"); } rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED, @@ -1071,8 +1068,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) ctrl_dbg(ctrl, "request_irq %d (returns %d)\n", ctrl->pci_dev->irq, rc); if (rc) { - ctrl_err(ctrl, "Can't get irq %d for the hotplug " - "controller\n", ctrl->pci_dev->irq); + ctrl_err(ctrl, "Can't get irq %d for the hotplug controller\n", + ctrl->pci_dev->irq); goto abort_iounmap; } } diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 2bf69fe1926..469454e0cc4 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c @@ -34,7 +34,7 @@ #include "../pci.h" #include "shpchp.h" -int __ref shpchp_configure_device(struct slot *p_slot) +int shpchp_configure_device(struct slot *p_slot) { struct pci_dev *dev; struct controller *ctrl = p_slot->ctrl; @@ -46,9 +46,9 @@ int __ref shpchp_configure_device(struct slot *p_slot) dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); if (dev) { - ctrl_err(ctrl, "Device %s already exists " - "at %04x:%02x:%02x, cannot hot-add\n", pci_name(dev), - pci_domain_nr(parent), p_slot->bus, p_slot->device); + ctrl_err(ctrl, "Device %s already exists at %04x:%02x:%02x, cannot hot-add\n", + pci_name(dev), pci_domain_nr(parent), + p_slot->bus, p_slot->device); pci_dev_put(dev); ret = -EINVAL; goto out; @@ -64,8 +64,7 @@ int __ref shpchp_configure_device(struct slot *p_slot) list_for_each_entry(dev, &parent->devices, bus_list) { if (PCI_SLOT(dev->devfn) != p_slot->device) continue; - if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || - (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) + if (pci_is_bridge(dev)) pci_hp_add_bridge(dev); } diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index e8c31fe2056..52875b36046 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c @@ -38,7 +38,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev; - char * out = buf; + char *out = buf; int index, busnr; struct resource *res; struct pci_bus *bus; diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 6e373ea57b3..a94dd2c4183 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -87,12 +87,9 @@ void unmask_ht_irq(struct irq_data *data) int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) { struct ht_irq_cfg *cfg; + int max_irq, pos, irq; unsigned long flags; u32 data; - int max_irq; - int pos; - int irq; - int node; pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ); if (!pos) @@ -105,7 +102,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) spin_unlock_irqrestore(&ht_irq_lock, flags); max_irq = (data >> 16) & 0xff; - if ( idx > max_irq) + if (idx > max_irq) return -EINVAL; cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); @@ -120,10 +117,8 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) cfg->msg.address_lo = 0xffffffff; cfg->msg.address_hi = 0xffffffff; - node = dev_to_node(&dev->dev); - irq = create_irq_nr(0, node); - - if (irq <= 0) { + irq = irq_alloc_hwirq(dev_to_node(&dev->dev)); + if (!irq) { kfree(cfg); return -EBUSY; } @@ -136,6 +131,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) return irq; } +EXPORT_SYMBOL(__ht_create_irq); /** * ht_create_irq - create an irq and attach it to a device. @@ -151,6 +147,7 @@ int ht_create_irq(struct pci_dev *dev, int idx) { return __ht_create_irq(dev, idx, NULL); } +EXPORT_SYMBOL(ht_create_irq); /** * ht_destroy_irq - destroy an irq created with ht_create_irq @@ -166,11 +163,8 @@ void ht_destroy_irq(unsigned int irq) cfg = irq_get_handler_data(irq); irq_set_chip(irq, NULL); irq_set_handler_data(irq, NULL); - destroy_irq(irq); + irq_free_hwirq(irq); kfree(cfg); } - -EXPORT_SYMBOL(__ht_create_irq); -EXPORT_SYMBOL(ht_create_irq); EXPORT_SYMBOL(ht_destroy_irq); diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 9dce7c5e2a7..cb6f24740ee 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -106,7 +106,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); - rc = pci_bus_add_device(virtfn); + pci_bus_add_device(virtfn); sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); if (rc) @@ -170,97 +170,6 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset) pci_dev_put(dev); } -static int sriov_migration(struct pci_dev *dev) -{ - u16 status; - struct pci_sriov *iov = dev->sriov; - - if (!iov->num_VFs) - return 0; - - if (!(iov->cap & PCI_SRIOV_CAP_VFM)) - return 0; - - pci_read_config_word(dev, iov->pos + PCI_SRIOV_STATUS, &status); - if (!(status & PCI_SRIOV_STATUS_VFM)) - return 0; - - schedule_work(&iov->mtask); - - return 1; -} - -static void sriov_migration_task(struct work_struct *work) -{ - int i; - u8 state; - u16 status; - struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask); - - for (i = iov->initial_VFs; i < iov->num_VFs; i++) { - state = readb(iov->mstate + i); - if (state == PCI_SRIOV_VFM_MI) { - writeb(PCI_SRIOV_VFM_AV, iov->mstate + i); - state = readb(iov->mstate + i); - if (state == PCI_SRIOV_VFM_AV) - virtfn_add(iov->self, i, 1); - } else if (state == PCI_SRIOV_VFM_MO) { - virtfn_remove(iov->self, i, 1); - writeb(PCI_SRIOV_VFM_UA, iov->mstate + i); - state = readb(iov->mstate + i); - if (state == PCI_SRIOV_VFM_AV) - virtfn_add(iov->self, i, 0); - } - } - - pci_read_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, &status); - status &= ~PCI_SRIOV_STATUS_VFM; - pci_write_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, status); -} - -static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn) -{ - int bir; - u32 table; - resource_size_t pa; - struct pci_sriov *iov = dev->sriov; - - if (nr_virtfn <= iov->initial_VFs) - return 0; - - pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table); - bir = PCI_SRIOV_VFM_BIR(table); - if (bir > PCI_STD_RESOURCE_END) - return -EIO; - - table = PCI_SRIOV_VFM_OFFSET(table); - if (table + nr_virtfn > pci_resource_len(dev, bir)) - return -EIO; - - pa = pci_resource_start(dev, bir) + table; - iov->mstate = ioremap(pa, nr_virtfn); - if (!iov->mstate) - return -ENOMEM; - - INIT_WORK(&iov->mtask, sriov_migration_task); - - iov->ctrl |= PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR; - pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); - - return 0; -} - -static void sriov_disable_migration(struct pci_dev *dev) -{ - struct pci_sriov *iov = dev->sriov; - - iov->ctrl &= ~(PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR); - pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); - - cancel_work_sync(&iov->mtask); - iounmap(iov->mstate); -} - static int sriov_enable(struct pci_dev *dev, int nr_virtfn) { int rc; @@ -351,12 +260,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) goto failed; } - if (iov->cap & PCI_SRIOV_CAP_VFM) { - rc = sriov_enable_migration(dev, nr_virtfn); - if (rc) - goto failed; - } - kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE); iov->num_VFs = nr_virtfn; @@ -387,9 +290,6 @@ static void sriov_disable(struct pci_dev *dev) if (!iov->num_VFs) return; - if (iov->cap & PCI_SRIOV_CAP_VFM) - sriov_disable_migration(dev); - for (i = 0; i < iov->num_VFs; i++) virtfn_remove(dev, i, 0); @@ -688,25 +588,6 @@ void pci_disable_sriov(struct pci_dev *dev) EXPORT_SYMBOL_GPL(pci_disable_sriov); /** - * pci_sriov_migration - notify SR-IOV core of Virtual Function Migration - * @dev: the PCI device - * - * Returns IRQ_HANDLED if the IRQ is handled, or IRQ_NONE if not. - * - * Physical Function driver is responsible to register IRQ handler using - * VF Migration Interrupt Message Number, and call this function when the - * interrupt is generated by the hardware. - */ -irqreturn_t pci_sriov_migration(struct pci_dev *dev) -{ - if (!dev->is_physfn) - return IRQ_NONE; - - return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE; -} -EXPORT_SYMBOL_GPL(pci_sriov_migration); - -/** * pci_num_vf - return number of VFs associated with a PF device_release_driver * @dev: the PCI device * diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 7a0fec6ce57..13f3d303727 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -10,7 +10,6 @@ #include <linux/mm.h> #include <linux/irq.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/export.h> #include <linux/ioport.h> #include <linux/pci.h> @@ -414,7 +413,7 @@ static void free_msi_irqs(struct pci_dev *dev) if (dev->msi_irq_groups) { sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups); msi_attrs = dev->msi_irq_groups[0]->attrs; - list_for_each_entry(entry, &dev->msi_list, list) { + while (msi_attrs[count]) { dev_attr = container_of(msi_attrs[count], struct device_attribute, attr); kfree(dev_attr->attr.name); @@ -544,16 +543,18 @@ static int populate_msi_sysfs(struct pci_dev *pdev) if (!msi_attrs) return -ENOMEM; list_for_each_entry(entry, &pdev->msi_list, list) { - char *name = kmalloc(20, GFP_KERNEL); msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL); if (!msi_dev_attr) goto error_attrs; - sprintf(name, "%d", entry->irq); + msi_attrs[count] = &msi_dev_attr->attr; + sysfs_attr_init(&msi_dev_attr->attr); - msi_dev_attr->attr.name = name; + msi_dev_attr->attr.name = kasprintf(GFP_KERNEL, "%d", + entry->irq); + if (!msi_dev_attr->attr.name) + goto error_attrs; msi_dev_attr->attr.mode = S_IRUGO; msi_dev_attr->show = msi_mode_show; - msi_attrs[count] = &msi_dev_attr->attr; ++count; } @@ -589,6 +590,7 @@ error_attrs: ++count; msi_attr = msi_attrs[count]; } + kfree(msi_attrs); return ret; } @@ -876,50 +878,6 @@ int pci_msi_vec_count(struct pci_dev *dev) } EXPORT_SYMBOL(pci_msi_vec_count); -/** - * pci_enable_msi_block - configure device's MSI capability structure - * @dev: device to configure - * @nvec: number of interrupts to configure - * - * Allocate IRQs for a device with the MSI capability. - * This function returns a negative errno if an error occurs. If it - * is unable to allocate the number of interrupts requested, it returns - * the number of interrupts it might be able to allocate. If it successfully - * allocates at least the number of interrupts requested, it returns 0 and - * updates the @dev's irq member to the lowest new interrupt number; the - * other interrupt numbers allocated to this device are consecutive. - */ -int pci_enable_msi_block(struct pci_dev *dev, int nvec) -{ - int status, maxvec; - - if (dev->current_state != PCI_D0) - return -EINVAL; - - maxvec = pci_msi_vec_count(dev); - if (maxvec < 0) - return maxvec; - if (nvec > maxvec) - return maxvec; - - status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI); - if (status) - return status; - - WARN_ON(!!dev->msi_enabled); - - /* Check whether driver already requested MSI-X irqs */ - if (dev->msix_enabled) { - dev_info(&dev->dev, "can't enable MSI " - "(MSI-X already enabled)\n"); - return -EINVAL; - } - - status = msi_capability_init(dev, nvec); - return status; -} -EXPORT_SYMBOL(pci_enable_msi_block); - void pci_msi_shutdown(struct pci_dev *dev) { struct msi_desc *desc; @@ -959,7 +917,6 @@ EXPORT_SYMBOL(pci_disable_msi); /** * pci_msix_vec_count - return the number of device's MSI-X table entries * @dev: pointer to the pci_dev data structure of MSI-X device function - * This function returns the number of device's MSI-X table entries and * therefore the number of MSI-X vectors device is capable of sending. * It returns a negative errno if the device is not capable of sending MSI-X @@ -1023,8 +980,7 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) /* Check whether driver already requested for MSI irq */ if (dev->msi_enabled) { - dev_info(&dev->dev, "can't enable MSI-X " - "(MSI IRQ already assigned)\n"); + dev_info(&dev->dev, "can't enable MSI-X (MSI IRQ already assigned)\n"); return -EINVAL; } status = msix_capability_init(dev, entries, nvec); @@ -1126,14 +1082,45 @@ void pci_msi_init_pci_dev(struct pci_dev *dev) **/ int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) { - int nvec = maxvec; + int nvec; int rc; + if (dev->current_state != PCI_D0) + return -EINVAL; + + WARN_ON(!!dev->msi_enabled); + + /* Check whether driver already requested MSI-X irqs */ + if (dev->msix_enabled) { + dev_info(&dev->dev, + "can't enable MSI (MSI-X already enabled)\n"); + return -EINVAL; + } + if (maxvec < minvec) return -ERANGE; + nvec = pci_msi_vec_count(dev); + if (nvec < 0) + return nvec; + else if (nvec < minvec) + return -EINVAL; + else if (nvec > maxvec) + nvec = maxvec; + + do { + rc = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI); + if (rc < 0) { + return rc; + } else if (rc > 0) { + if (rc < minvec) + return -ENOSPC; + nvec = rc; + } + } while (rc); + do { - rc = pci_enable_msi_block(dev, nvec); + rc = msi_capability_init(dev, nvec); if (rc < 0) { return rc; } else if (rc > 0) { diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index f49abef8848..ca4927ba843 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -309,13 +309,7 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev) bool check_children; u64 addr; - /* - * pci_is_bridge() is not suitable here, because pci_dev->subordinate - * is set only after acpi_pci_find_device() has been called for the - * given device. - */ - check_children = pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE - || pci_dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; + check_children = pci_is_bridge(pci_dev); /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 25f0bc65916..3f8e3dbcaa7 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -77,6 +77,7 @@ int pci_add_dynid(struct pci_driver *drv, return retval; } +EXPORT_SYMBOL_GPL(pci_add_dynid); static void pci_free_dynids(struct pci_driver *drv) { @@ -98,16 +99,16 @@ static void pci_free_dynids(struct pci_driver *drv) * * Allow PCI IDs to be added to an existing driver via sysfs. */ -static ssize_t -store_new_id(struct device_driver *driver, const char *buf, size_t count) +static ssize_t store_new_id(struct device_driver *driver, const char *buf, + size_t count) { struct pci_driver *pdrv = to_pci_driver(driver); const struct pci_device_id *ids = pdrv->id_table; - __u32 vendor, device, subvendor=PCI_ANY_ID, - subdevice=PCI_ANY_ID, class=0, class_mask=0; - unsigned long driver_data=0; - int fields=0; - int retval; + __u32 vendor, device, subvendor = PCI_ANY_ID, + subdevice = PCI_ANY_ID, class = 0, class_mask = 0; + unsigned long driver_data = 0; + int fields = 0; + int retval = 0; fields = sscanf(buf, "%x %x %x %x %x %x %lx", &vendor, &device, &subvendor, &subdevice, @@ -115,6 +116,26 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) if (fields < 2) return -EINVAL; + if (fields != 7) { + struct pci_dev *pdev = kzalloc(sizeof(*pdev), GFP_KERNEL); + if (!pdev) + return -ENOMEM; + + pdev->vendor = vendor; + pdev->device = device; + pdev->subsystem_vendor = subvendor; + pdev->subsystem_device = subdevice; + pdev->class = class; + + if (pci_match_id(pdrv->id_table, pdev)) + retval = -EEXIST; + + kfree(pdev); + + if (retval) + return retval; + } + /* Only accept driver_data values that match an existing id_table entry */ if (ids) { @@ -146,8 +167,8 @@ static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); * * Removes a dynamic pci device ID to this driver. */ -static ssize_t -store_remove_id(struct device_driver *driver, const char *buf, size_t count) +static ssize_t store_remove_id(struct device_driver *driver, const char *buf, + size_t count) { struct pci_dynid *dynid, *n; struct pci_driver *pdrv = to_pci_driver(driver); @@ -215,6 +236,14 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, } return NULL; } +EXPORT_SYMBOL(pci_match_id); + +static const struct pci_device_id pci_device_id_any = { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}; /** * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure @@ -229,18 +258,30 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_dev *dev) { struct pci_dynid *dynid; + const struct pci_device_id *found_id = NULL; + + /* When driver_override is set, only bind to the matching driver */ + if (dev->driver_override && strcmp(dev->driver_override, drv->name)) + return NULL; /* Look at the dynamic ids first, before the static ones */ spin_lock(&drv->dynids.lock); list_for_each_entry(dynid, &drv->dynids.list, node) { if (pci_match_one_device(&dynid->id, dev)) { - spin_unlock(&drv->dynids.lock); - return &dynid->id; + found_id = &dynid->id; + break; } } spin_unlock(&drv->dynids.lock); - return pci_match_id(drv->id_table, dev); + if (!found_id) + found_id = pci_match_id(drv->id_table, dev); + + /* driver_override will always match, send a dummy id */ + if (!found_id && dev->driver_override) + found_id = &pci_device_id_any; + + return found_id; } struct drv_dev_and_id { @@ -333,8 +374,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, * returns 0 on success, else error. * side-effect: pci_dev->driver is set to drv when drv claims pci_dev. */ -static int -__pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) +static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) { const struct pci_device_id *id; int error = 0; @@ -351,7 +391,7 @@ __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) return error; } -static int pci_device_probe(struct device * dev) +static int pci_device_probe(struct device *dev) { int error = 0; struct pci_driver *drv; @@ -367,10 +407,10 @@ static int pci_device_probe(struct device * dev) return error; } -static int pci_device_remove(struct device * dev) +static int pci_device_remove(struct device *dev) { - struct pci_dev * pci_dev = to_pci_dev(dev); - struct pci_driver * drv = pci_dev->driver; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; if (drv) { if (drv->remove) { @@ -498,8 +538,8 @@ static int pci_pm_reenable_device(struct pci_dev *pci_dev) static int pci_legacy_suspend(struct device *dev, pm_message_t state) { - struct pci_dev * pci_dev = to_pci_dev(dev); - struct pci_driver * drv = pci_dev->driver; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; if (drv && drv->suspend) { pci_power_t prev = pci_dev->current_state; @@ -525,8 +565,8 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state) static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) { - struct pci_dev * pci_dev = to_pci_dev(dev); - struct pci_driver * drv = pci_dev->driver; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; if (drv && drv->suspend_late) { pci_power_t prev = pci_dev->current_state; @@ -556,8 +596,8 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state) static int pci_legacy_resume_early(struct device *dev) { - struct pci_dev * pci_dev = to_pci_dev(dev); - struct pci_driver * drv = pci_dev->driver; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; return drv && drv->resume_early ? drv->resume_early(pci_dev) : 0; @@ -565,8 +605,8 @@ static int pci_legacy_resume_early(struct device *dev) static int pci_legacy_resume(struct device *dev) { - struct pci_dev * pci_dev = to_pci_dev(dev); - struct pci_driver * drv = pci_dev->driver; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; pci_fixup_device(pci_fixup_resume, pci_dev); @@ -580,14 +620,14 @@ static void pci_pm_default_resume(struct pci_dev *pci_dev) { pci_fixup_device(pci_fixup_resume, pci_dev); - if (!pci_is_bridge(pci_dev)) + if (!pci_has_subordinate(pci_dev)) pci_enable_wake(pci_dev, PCI_D0, false); } static void pci_pm_default_suspend(struct pci_dev *pci_dev) { /* Disable non-bridge devices without PM support */ - if (!pci_is_bridge(pci_dev)) + if (!pci_has_subordinate(pci_dev)) pci_disable_enabled_device(pci_dev); } @@ -616,15 +656,11 @@ static int pci_pm_prepare(struct device *dev) int error = 0; /* - * PCI devices suspended at run time need to be resumed at this - * point, because in general it is necessary to reconfigure them for - * system suspend. Namely, if the device is supposed to wake up the - * system from the sleep state, we may need to reconfigure it for this - * purpose. In turn, if the device is not supposed to wake up the - * system from the sleep state, we'll have to prevent it from signaling - * wake-up. + * Devices having power.ignore_children set may still be necessary for + * suspending their children in the next phase of device suspend. */ - pm_runtime_resume(dev); + if (dev->power.ignore_children) + pm_runtime_resume(dev); if (drv && drv->pm && drv->pm->prepare) error = drv->pm->prepare(dev); @@ -654,6 +690,16 @@ static int pci_pm_suspend(struct device *dev) goto Fixup; } + /* + * PCI devices suspended at run time need to be resumed at this point, + * because in general it is necessary to reconfigure them for system + * suspend. Namely, if the device is supposed to wake up the system + * from the sleep state, we may need to reconfigure it for this purpose. + * In turn, if the device is not supposed to wake up the system from the + * sleep state, we'll have to prevent it from signaling wake-up. + */ + pm_runtime_resume(dev); + pci_dev->state_saved = false; if (pm->suspend) { pci_power_t prev = pci_dev->current_state; @@ -711,7 +757,7 @@ static int pci_pm_suspend_noirq(struct device *dev) if (!pci_dev->state_saved) { pci_save_state(pci_dev); - if (!pci_is_bridge(pci_dev)) + if (!pci_has_subordinate(pci_dev)) pci_prepare_to_sleep(pci_dev); } @@ -808,6 +854,14 @@ static int pci_pm_freeze(struct device *dev) return 0; } + /* + * This used to be done in pci_pm_prepare() for all devices and some + * drivers may depend on it, so do it here. Ideally, runtime-suspended + * devices should not be touched during freeze/thaw transitions, + * however. + */ + pm_runtime_resume(dev); + pci_dev->state_saved = false; if (pm->freeze) { int error; @@ -915,6 +969,9 @@ static int pci_pm_poweroff(struct device *dev) goto Fixup; } + /* The reason to do that is the same as in pci_pm_suspend(). */ + pm_runtime_resume(dev); + pci_dev->state_saved = false; if (pm->poweroff) { int error; @@ -954,7 +1011,7 @@ static int pci_pm_poweroff_noirq(struct device *dev) return error; } - if (!pci_dev->state_saved && !pci_is_bridge(pci_dev)) + if (!pci_dev->state_saved && !pci_has_subordinate(pci_dev)) pci_prepare_to_sleep(pci_dev); /* @@ -1199,6 +1256,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, /* register with core */ return driver_register(&drv->driver); } +EXPORT_SYMBOL(__pci_register_driver); /** * pci_unregister_driver - unregister a pci driver @@ -1210,12 +1268,12 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, * driverless. */ -void -pci_unregister_driver(struct pci_driver *drv) +void pci_unregister_driver(struct pci_driver *drv) { driver_unregister(&drv->driver); pci_free_dynids(drv); } +EXPORT_SYMBOL(pci_unregister_driver); static struct pci_driver pci_compat_driver = { .name = "compat" @@ -1228,19 +1286,19 @@ static struct pci_driver pci_compat_driver = { * Returns the appropriate pci_driver structure or %NULL if there is no * registered driver for the device. */ -struct pci_driver * -pci_dev_driver(const struct pci_dev *dev) +struct pci_driver *pci_dev_driver(const struct pci_dev *dev) { if (dev->driver) return dev->driver; else { int i; - for(i=0; i<=PCI_ROM_RESOURCE; i++) + for (i = 0; i <= PCI_ROM_RESOURCE; i++) if (dev->resource[i].flags & IORESOURCE_BUSY) return &pci_compat_driver; } return NULL; } +EXPORT_SYMBOL(pci_dev_driver); /** * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure @@ -1286,6 +1344,7 @@ struct pci_dev *pci_dev_get(struct pci_dev *dev) get_device(&dev->dev); return dev; } +EXPORT_SYMBOL(pci_dev_get); /** * pci_dev_put - release a use of the pci device structure @@ -1299,6 +1358,7 @@ void pci_dev_put(struct pci_dev *dev) if (dev) put_device(&dev->dev); } +EXPORT_SYMBOL(pci_dev_put); static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { @@ -1308,8 +1368,6 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENODEV; pdev = to_pci_dev(dev); - if (!pdev) - return -ENODEV; if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) return -ENOMEM; @@ -1330,6 +1388,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), (u8)(pdev->class))) return -ENOMEM; + return 0; } @@ -1345,19 +1404,10 @@ struct bus_type pci_bus_type = { .drv_groups = pci_drv_groups, .pm = PCI_PM_OPS_PTR, }; +EXPORT_SYMBOL(pci_bus_type); static int __init pci_driver_init(void) { return bus_register(&pci_bus_type); } - postcore_initcall(pci_driver_init); - -EXPORT_SYMBOL_GPL(pci_add_dynid); -EXPORT_SYMBOL(pci_match_id); -EXPORT_SYMBOL(__pci_register_driver); -EXPORT_SYMBOL(pci_unregister_driver); -EXPORT_SYMBOL(pci_dev_driver); -EXPORT_SYMBOL(pci_bus_type); -EXPORT_SYMBOL(pci_dev_get); -EXPORT_SYMBOL(pci_dev_put); diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index 45113daaa77..a3fbe2012ea 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -40,9 +40,8 @@ enum smbios_attr_enum { SMBIOS_ATTR_INSTANCE_SHOW, }; -static size_t -find_smbios_instance_string(struct pci_dev *pdev, char *buf, - enum smbios_attr_enum attribute) +static size_t find_smbios_instance_string(struct pci_dev *pdev, char *buf, + enum smbios_attr_enum attribute) { const struct dmi_device *dmi; struct dmi_dev_onboard *donboard; @@ -74,9 +73,8 @@ find_smbios_instance_string(struct pci_dev *pdev, char *buf, return 0; } -static umode_t -smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr, - int n) +static umode_t smbios_instance_string_exist(struct kobject *kobj, + struct attribute *attr, int n) { struct device *dev; struct pci_dev *pdev; @@ -88,8 +86,8 @@ smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr, S_IRUGO : 0; } -static ssize_t -smbioslabel_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t smbioslabel_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct pci_dev *pdev; pdev = to_pci_dev(dev); @@ -98,9 +96,8 @@ smbioslabel_show(struct device *dev, struct device_attribute *attr, char *buf) SMBIOS_ATTR_LABEL_SHOW); } -static ssize_t -smbiosinstance_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t smbiosinstance_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct pci_dev *pdev; pdev = to_pci_dev(dev); @@ -130,26 +127,22 @@ static struct attribute_group smbios_attr_group = { .is_visible = smbios_instance_string_exist, }; -static int -pci_create_smbiosname_file(struct pci_dev *pdev) +static int pci_create_smbiosname_file(struct pci_dev *pdev) { return sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group); } -static void -pci_remove_smbiosname_file(struct pci_dev *pdev) +static void pci_remove_smbiosname_file(struct pci_dev *pdev) { sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group); } #else -static inline int -pci_create_smbiosname_file(struct pci_dev *pdev) +static inline int pci_create_smbiosname_file(struct pci_dev *pdev) { return -1; } -static inline void -pci_remove_smbiosname_file(struct pci_dev *pdev) +static inline void pci_remove_smbiosname_file(struct pci_dev *pdev) { } #endif @@ -175,8 +168,8 @@ static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf) buf[len] = '\n'; } -static int -dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) +static int dsm_get_label(struct device *dev, char *buf, + enum acpi_attr_enum attr) { acpi_handle handle; union acpi_object *obj, *tmp; @@ -212,8 +205,7 @@ dsm_get_label(struct device *dev, char *buf, enum acpi_attr_enum attr) return len; } -static bool -device_has_dsm(struct device *dev) +static bool device_has_dsm(struct device *dev) { acpi_handle handle; @@ -225,8 +217,8 @@ device_has_dsm(struct device *dev) 1 << DEVICE_LABEL_DSM); } -static umode_t -acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n) +static umode_t acpi_index_string_exist(struct kobject *kobj, + struct attribute *attr, int n) { struct device *dev; @@ -238,14 +230,14 @@ acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n) return 0; } -static ssize_t -acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t acpilabel_show(struct device *dev, + struct device_attribute *attr, char *buf) { return dsm_get_label(dev, buf, ACPI_ATTR_LABEL_SHOW); } -static ssize_t -acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t acpiindex_show(struct device *dev, + struct device_attribute *attr, char *buf) { return dsm_get_label(dev, buf, ACPI_ATTR_INDEX_SHOW); } @@ -271,33 +263,28 @@ static struct attribute_group acpi_attr_group = { .is_visible = acpi_index_string_exist, }; -static int -pci_create_acpi_index_label_files(struct pci_dev *pdev) +static int pci_create_acpi_index_label_files(struct pci_dev *pdev) { return sysfs_create_group(&pdev->dev.kobj, &acpi_attr_group); } -static int -pci_remove_acpi_index_label_files(struct pci_dev *pdev) +static int pci_remove_acpi_index_label_files(struct pci_dev *pdev) { sysfs_remove_group(&pdev->dev.kobj, &acpi_attr_group); return 0; } #else -static inline int -pci_create_acpi_index_label_files(struct pci_dev *pdev) +static inline int pci_create_acpi_index_label_files(struct pci_dev *pdev) { return -1; } -static inline int -pci_remove_acpi_index_label_files(struct pci_dev *pdev) +static inline int pci_remove_acpi_index_label_files(struct pci_dev *pdev) { return -1; } -static inline bool -device_has_dsm(struct device *dev) +static inline bool device_has_dsm(struct device *dev) { return false; } diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c index 2ff77509d8e..886fb357027 100644 --- a/drivers/pci/pci-stub.c +++ b/drivers/pci/pci-stub.c @@ -55,7 +55,7 @@ static int __init pci_stub_init(void) p = ids; while ((id = strsep(&p, ","))) { unsigned int vendor, device, subvendor = PCI_ANY_ID, - subdevice = PCI_ANY_ID, class=0, class_mask=0; + subdevice = PCI_ANY_ID, class = 0, class_mask = 0; int fields; if (!strlen(id)) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 276ef9c1880..9ff0a901ecf 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/vgaarb.h> #include <linux/pm_runtime.h> +#include <linux/of.h> #include "pci.h" static int sysfs_initialized; /* = 0 */ @@ -40,8 +41,8 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pci_dev *pdev; \ \ - pdev = to_pci_dev (dev); \ - return sprintf (buf, format_string, pdev->field); \ + pdev = to_pci_dev(dev); \ + return sprintf(buf, format_string, pdev->field); \ } \ static DEVICE_ATTR_RO(field) @@ -57,7 +58,7 @@ static ssize_t broken_parity_status_show(struct device *dev, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf (buf, "%u\n", pdev->broken_parity_status); + return sprintf(buf, "%u\n", pdev->broken_parity_status); } static ssize_t broken_parity_status_store(struct device *dev, @@ -76,10 +77,8 @@ static ssize_t broken_parity_status_store(struct device *dev, } static DEVICE_ATTR_RW(broken_parity_status); -static ssize_t pci_dev_show_local_cpu(struct device *dev, - int type, - struct device_attribute *attr, - char *buf) +static ssize_t pci_dev_show_local_cpu(struct device *dev, int type, + struct device_attribute *attr, char *buf) { const struct cpumask *mask; int len; @@ -100,14 +99,14 @@ static ssize_t pci_dev_show_local_cpu(struct device *dev, } static ssize_t local_cpus_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { return pci_dev_show_local_cpu(dev, 1, attr, buf); } static DEVICE_ATTR_RO(local_cpus); static ssize_t local_cpulist_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { return pci_dev_show_local_cpu(dev, 0, attr, buf); } @@ -116,8 +115,7 @@ static DEVICE_ATTR_RO(local_cpulist); /* * PCI Bus Class Devices */ -static ssize_t pci_bus_show_cpuaffinity(struct device *dev, - int type, +static ssize_t pci_bus_show_cpuaffinity(struct device *dev, int type, struct device_attribute *attr, char *buf) { @@ -148,11 +146,11 @@ static ssize_t cpulistaffinity_show(struct device *dev, static DEVICE_ATTR_RO(cpulistaffinity); /* show resources */ -static ssize_t -resource_show(struct device * dev, struct device_attribute *attr, char * buf) +static ssize_t resource_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct pci_dev * pci_dev = to_pci_dev(dev); - char * str = buf; + struct pci_dev *pci_dev = to_pci_dev(dev); + char *str = buf; int i; int max; resource_size_t start, end; @@ -165,7 +163,7 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) for (i = 0; i < max; i++) { struct resource *res = &pci_dev->resource[i]; pci_resource_to_user(pci_dev, i, res, &start, &end); - str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n", + str += sprintf(str, "0x%016llx 0x%016llx 0x%016llx\n", (unsigned long long)start, (unsigned long long)end, (unsigned long long)res->flags); @@ -174,7 +172,8 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) } static DEVICE_ATTR_RO(resource); -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -186,9 +185,8 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(modalias); -static ssize_t enabled_store(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t enabled_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; @@ -212,57 +210,56 @@ static ssize_t enabled_store(struct device *dev, return result < 0 ? result : count; } -static ssize_t enabled_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct pci_dev *pdev; - pdev = to_pci_dev (dev); - return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt)); + pdev = to_pci_dev(dev); + return sprintf(buf, "%u\n", atomic_read(&pdev->enable_cnt)); } static DEVICE_ATTR_RW(enabled); #ifdef CONFIG_NUMA -static ssize_t -numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf (buf, "%d\n", dev->numa_node); + return sprintf(buf, "%d\n", dev->numa_node); } static DEVICE_ATTR_RO(numa_node); #endif -static ssize_t -dma_mask_bits_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t dma_mask_bits_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf (buf, "%d\n", fls64(pdev->dma_mask)); + return sprintf(buf, "%d\n", fls64(pdev->dma_mask)); } static DEVICE_ATTR_RO(dma_mask_bits); -static ssize_t -consistent_dma_mask_bits_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t consistent_dma_mask_bits_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - return sprintf (buf, "%d\n", fls64(dev->coherent_dma_mask)); + return sprintf(buf, "%d\n", fls64(dev->coherent_dma_mask)); } static DEVICE_ATTR_RO(consistent_dma_mask_bits); -static ssize_t -msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct pci_dev *pdev = to_pci_dev(dev); if (!pdev->subordinate) return 0; - return sprintf (buf, "%u\n", - !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)); + return sprintf(buf, "%u\n", + !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)); } -static ssize_t -msi_bus_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t msi_bus_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; @@ -289,8 +286,8 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, !!val) { pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI; - dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI," - " bad things could happen\n", val ? "" : " not"); + dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI, bad things could happen\n", + val ? "" : " not"); } return count; @@ -330,9 +327,9 @@ const struct attribute_group *pci_bus_groups[] = { NULL, }; -static ssize_t -dev_rescan_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t dev_rescan_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { unsigned long val; struct pci_dev *pdev = to_pci_dev(dev); @@ -351,37 +348,25 @@ static struct device_attribute dev_rescan_attr = __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store); -static void remove_callback(struct device *dev) -{ - pci_stop_and_remove_bus_device_locked(to_pci_dev(dev)); -} - -static ssize_t -remove_store(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) +static ssize_t remove_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - int ret = 0; unsigned long val; if (kstrtoul(buf, 0, &val) < 0) return -EINVAL; - /* An attribute cannot be unregistered by one of its own methods, - * so we have to use this roundabout approach. - */ - if (val) - ret = device_schedule_callback(dev, remove_callback); - if (ret) - count = ret; + if (val && device_remove_file_self(dev, attr)) + pci_stop_and_remove_bus_device_locked(to_pci_dev(dev)); return count; } static struct device_attribute dev_remove_attr = __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store); -static ssize_t -dev_bus_rescan_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t dev_bus_rescan_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { unsigned long val; struct pci_bus *bus = to_pci_bus(dev); @@ -422,11 +407,25 @@ static ssize_t d3cold_allowed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf (buf, "%u\n", pdev->d3cold_allowed); + return sprintf(buf, "%u\n", pdev->d3cold_allowed); } static DEVICE_ATTR_RW(d3cold_allowed); #endif +#ifdef CONFIG_OF +static ssize_t devspec_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct device_node *np = pci_device_to_OF_node(pdev); + + if (np == NULL || np->full_name == NULL) + return 0; + return sprintf(buf, "%s", np->full_name); +} +static DEVICE_ATTR_RO(devspec); +#endif + #ifdef CONFIG_PCI_IOV static ssize_t sriov_totalvfs_show(struct device *dev, struct device_attribute *attr, @@ -510,6 +509,45 @@ static struct device_attribute sriov_numvfs_attr = sriov_numvfs_show, sriov_numvfs_store); #endif /* CONFIG_PCI_IOV */ +static ssize_t driver_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + char *driver_override, *old = pdev->driver_override, *cp; + + if (count > PATH_MAX) + return -EINVAL; + + driver_override = kstrndup(buf, count, GFP_KERNEL); + if (!driver_override) + return -ENOMEM; + + cp = strchr(driver_override, '\n'); + if (cp) + *cp = '\0'; + + if (strlen(driver_override)) { + pdev->driver_override = driver_override; + } else { + kfree(driver_override); + pdev->driver_override = NULL; + } + + kfree(old); + + return count; +} + +static ssize_t driver_override_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return sprintf(buf, "%s\n", pdev->driver_override); +} +static DEVICE_ATTR_RW(driver_override); + static struct attribute *pci_dev_attrs[] = { &dev_attr_resource.attr, &dev_attr_vendor.attr, @@ -532,6 +570,10 @@ static struct attribute *pci_dev_attrs[] = { #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) &dev_attr_d3cold_allowed.attr, #endif +#ifdef CONFIG_OF + &dev_attr_devspec.attr, +#endif + &dev_attr_driver_override.attr, NULL, }; @@ -560,8 +602,8 @@ const struct attribute_group *pcibus_groups[] = { NULL, }; -static ssize_t -boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t boot_vga_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *vga_dev = vga_default_device(); @@ -575,22 +617,21 @@ boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) } static struct device_attribute vga_attr = __ATTR_RO(boot_vga); -static ssize_t -pci_read_config(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t pci_read_config(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { - struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); + struct pci_dev *dev = to_pci_dev(container_of(kobj, struct device, + kobj)); unsigned int size = 64; loff_t init_off = off; - u8 *data = (u8*) buf; + u8 *data = (u8 *) buf; /* Several chips lock up trying to read undefined config space */ - if (security_capable(filp->f_cred, &init_user_ns, CAP_SYS_ADMIN) == 0) { + if (security_capable(filp->f_cred, &init_user_ns, CAP_SYS_ADMIN) == 0) size = dev->cfg_size; - } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { + else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) size = 128; - } if (off > size) return 0; @@ -653,15 +694,15 @@ pci_read_config(struct file *filp, struct kobject *kobj, return count; } -static ssize_t -pci_write_config(struct file* filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t pci_write_config(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { - struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); + struct pci_dev *dev = to_pci_dev(container_of(kobj, struct device, + kobj)); unsigned int size = count; loff_t init_off = off; - u8 *data = (u8*) buf; + u8 *data = (u8 *) buf; if (off > dev->cfg_size) return 0; @@ -681,10 +722,10 @@ pci_write_config(struct file* filp, struct kobject *kobj, if ((off & 3) && size > 2) { u16 val = data[off - init_off]; val |= (u16) data[off - init_off + 1] << 8; - pci_user_write_config_word(dev, off, val); - off += 2; - size -= 2; - } + pci_user_write_config_word(dev, off, val); + off += 2; + size -= 2; + } while (size > 3) { u32 val = data[off - init_off]; @@ -715,10 +756,9 @@ pci_write_config(struct file* filp, struct kobject *kobj, return count; } -static ssize_t -read_vpd_attr(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t read_vpd_attr(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct pci_dev *dev = to_pci_dev(container_of(kobj, struct device, kobj)); @@ -731,10 +771,9 @@ read_vpd_attr(struct file *filp, struct kobject *kobj, return pci_read_vpd(dev, off, count, buf); } -static ssize_t -write_vpd_attr(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t write_vpd_attr(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct pci_dev *dev = to_pci_dev(container_of(kobj, struct device, kobj)); @@ -760,20 +799,18 @@ write_vpd_attr(struct file *filp, struct kobject *kobj, * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific * callback routine (pci_legacy_read). */ -static ssize_t -pci_read_legacy_io(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t pci_read_legacy_io(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { - struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct device, + struct pci_bus *bus = to_pci_bus(container_of(kobj, struct device, kobj)); - /* Only support 1, 2 or 4 byte accesses */ - if (count != 1 && count != 2 && count != 4) - return -EINVAL; + /* Only support 1, 2 or 4 byte accesses */ + if (count != 1 && count != 2 && count != 4) + return -EINVAL; - return pci_legacy_read(bus, off, (u32 *)buf, count); + return pci_legacy_read(bus, off, (u32 *)buf, count); } /** @@ -788,19 +825,18 @@ pci_read_legacy_io(struct file *filp, struct kobject *kobj, * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific * callback routine (pci_legacy_write). */ -static ssize_t -pci_write_legacy_io(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { - struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct device, + struct pci_bus *bus = to_pci_bus(container_of(kobj, struct device, kobj)); - /* Only support 1, 2 or 4 byte accesses */ - if (count != 1 && count != 2 && count != 4) - return -EINVAL; - return pci_legacy_write(bus, off, *(u32 *)buf, count); + /* Only support 1, 2 or 4 byte accesses */ + if (count != 1 && count != 2 && count != 4) + return -EINVAL; + + return pci_legacy_write(bus, off, *(u32 *)buf, count); } /** @@ -814,16 +850,14 @@ pci_write_legacy_io(struct file *filp, struct kobject *kobj, * legacy memory space (first meg of bus space) into application virtual * memory space. */ -static int -pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - struct vm_area_struct *vma) +static int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) { - struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct device, + struct pci_bus *bus = to_pci_bus(container_of(kobj, struct device, kobj)); - return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem); + return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem); } /** @@ -837,16 +871,14 @@ pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj, * legacy IO space (first meg of bus space) into application virtual * memory space. Returns -ENOSYS if the operation isn't supported */ -static int -pci_mmap_legacy_io(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - struct vm_area_struct *vma) +static int pci_mmap_legacy_io(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) { - struct pci_bus *bus = to_pci_bus(container_of(kobj, - struct device, + struct pci_bus *bus = to_pci_bus(container_of(kobj, struct device, kobj)); - return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io); + return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io); } /** @@ -856,10 +888,9 @@ pci_mmap_legacy_io(struct file *filp, struct kobject *kobj, * * Stub implementation. Can be overridden by arch if necessary. */ -void __weak -pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type) +void __weak pci_adjust_legacy_attr(struct pci_bus *b, + enum pci_mmap_state mmap_type) { - return; } /** @@ -914,8 +945,7 @@ legacy_io_err: kfree(b->legacy_io); b->legacy_io = NULL; kzalloc_err: - printk(KERN_WARNING "pci: warning: could not create legacy I/O port " - "and ISA memory resources to sysfs\n"); + printk(KERN_WARNING "pci: warning: could not create legacy I/O port and ISA memory resources to sysfs\n"); return; } @@ -958,9 +988,8 @@ int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma, * * Use the regular PCI mapping routines to map a PCI resource into userspace. */ -static int -pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, - struct vm_area_struct *vma, int write_combine) +static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, + struct vm_area_struct *vma, int write_combine) { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); @@ -976,8 +1005,7 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, return -ENODEV; if (!pci_mmap_fits(pdev, i, vma, PCI_MMAP_SYSFS)) { - WARN(1, "process \"%s\" tried to map 0x%08lx bytes " - "at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n", + WARN(1, "process \"%s\" tried to map 0x%08lx bytes at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n", current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff, pci_name(pdev), i, (u64)pci_resource_start(pdev, i), @@ -999,26 +1027,23 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); } -static int -pci_mmap_resource_uc(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - struct vm_area_struct *vma) +static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) { return pci_mmap_resource(kobj, attr, vma, 0); } -static int -pci_mmap_resource_wc(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - struct vm_area_struct *vma) +static int pci_mmap_resource_wc(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) { return pci_mmap_resource(kobj, attr, vma, 1); } -static ssize_t -pci_resource_io(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count, bool write) +static ssize_t pci_resource_io(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count, bool write) { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); @@ -1063,18 +1088,16 @@ pci_resource_io(struct file *filp, struct kobject *kobj, return -EINVAL; } -static ssize_t -pci_read_resource_io(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) +static ssize_t pci_read_resource_io(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) { return pci_resource_io(filp, kobj, attr, buf, off, count, false); } -static ssize_t -pci_write_resource_io(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) +static ssize_t pci_write_resource_io(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) { return pci_resource_io(filp, kobj, attr, buf, off, count, true); } @@ -1086,8 +1109,7 @@ pci_write_resource_io(struct file *filp, struct kobject *kobj, * If we created resource files for @pdev, remove them from sysfs and * free their resources. */ -static void -pci_remove_resource_files(struct pci_dev *pdev) +static void pci_remove_resource_files(struct pci_dev *pdev) { int i; @@ -1190,10 +1212,9 @@ void __weak pci_remove_resource_files(struct pci_dev *dev) { return; } * * writing anything except 0 enables it */ -static ssize_t -pci_write_rom(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t pci_write_rom(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); @@ -1217,10 +1238,9 @@ pci_write_rom(struct file *filp, struct kobject *kobj, * Put @count bytes starting at @off into @buf from the ROM in the PCI * device corresponding to @kobj. */ -static ssize_t -pci_read_rom(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t pci_read_rom(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); void __iomem *rom; @@ -1266,14 +1286,8 @@ static struct bin_attribute pcie_config_attr = { .write = pci_write_config, }; -int __weak pcibios_add_platform_entries(struct pci_dev *dev) -{ - return 0; -} - -static ssize_t reset_store(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t reset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; @@ -1340,7 +1354,7 @@ error: return retval; } -int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) +int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev) { int retval; int rom_size = 0; @@ -1386,11 +1400,6 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) pdev->rom_attr = attr; } - /* add platform-specific attributes */ - retval = pcibios_add_platform_entries(pdev); - if (retval) - goto err_rom_file; - /* add sysfs entries for various capabilities */ retval = pci_create_capabilities_sysfs(pdev); if (retval) @@ -1483,7 +1492,6 @@ static int __init pci_sysfs_init(void) return 0; } - late_initcall(pci_sysfs_init); static struct attribute *pci_dev_dev_attrs[] = { @@ -1492,7 +1500,7 @@ static struct attribute *pci_dev_dev_attrs[] = { }; static umode_t pci_dev_attrs_are_visible(struct kobject *kobj, - struct attribute *a, int n) + struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); struct pci_dev *pdev = to_pci_dev(dev); @@ -1511,7 +1519,7 @@ static struct attribute *pci_dev_hp_attrs[] = { }; static umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj, - struct attribute *a, int n) + struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); struct pci_dev *pdev = to_pci_dev(dev); @@ -1535,7 +1543,7 @@ static struct attribute *sriov_dev_attrs[] = { }; static umode_t sriov_attrs_are_visible(struct kobject *kobj, - struct attribute *a, int n) + struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c3ce3d61091..1c8592b0e14 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -106,15 +106,15 @@ static bool pcie_ari_disabled; * Given a PCI bus, returns the highest PCI bus number present in the set * including the given PCI bus and its list of child PCI buses. */ -unsigned char pci_bus_max_busnr(struct pci_bus* bus) +unsigned char pci_bus_max_busnr(struct pci_bus *bus) { - struct list_head *tmp; + struct pci_bus *tmp; unsigned char max, n; max = bus->busn_res.end; - list_for_each(tmp, &bus->children) { - n = pci_bus_max_busnr(pci_bus_b(tmp)); - if(n > max) + list_for_each_entry(tmp, &bus->children, node) { + n = pci_bus_max_busnr(tmp); + if (n > max) max = n; } return max; @@ -226,6 +226,7 @@ int pci_find_capability(struct pci_dev *dev, int cap) return pos; } +EXPORT_SYMBOL(pci_find_capability); /** * pci_bus_find_capability - query for devices' capabilities @@ -253,6 +254,7 @@ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) return pos; } +EXPORT_SYMBOL(pci_bus_find_capability); /** * pci_find_next_ext_capability - Find an extended capability @@ -403,8 +405,8 @@ EXPORT_SYMBOL_GPL(pci_find_ht_capability); * For given resource region of given device, return the resource * region of parent bus the given region is contained in. */ -struct resource * -pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) +struct resource *pci_find_parent_resource(const struct pci_dev *dev, + struct resource *res) { const struct pci_bus *bus = dev->bus; struct resource *r; @@ -436,6 +438,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) } return NULL; } +EXPORT_SYMBOL(pci_find_parent_resource); /** * pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos @@ -470,8 +473,7 @@ int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask) * Restore the BAR values for a given device, so as to make it * accessible by its driver. */ -static void -pci_restore_bars(struct pci_dev *dev) +static void pci_restore_bars(struct pci_dev *dev) { int i; @@ -496,7 +498,7 @@ static inline bool platform_pci_power_manageable(struct pci_dev *dev) } static inline int platform_pci_set_power_state(struct pci_dev *dev, - pci_power_t t) + pci_power_t t) { return pci_platform_pm ? pci_platform_pm->set_state(dev, t) : -ENOSYS; } @@ -553,8 +555,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) */ if (state != PCI_D0 && dev->current_state <= PCI_D3cold && dev->current_state > state) { - dev_err(&dev->dev, "invalid power transition " - "(from state %d to %d)\n", dev->current_state, state); + dev_err(&dev->dev, "invalid power transition (from state %d to %d)\n", + dev->current_state, state); return -EINVAL; } @@ -601,8 +603,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); if (dev->current_state != state && printk_ratelimit()) - dev_info(&dev->dev, "Refused to change power state, " - "currently in D%d\n", dev->current_state); + dev_info(&dev->dev, "Refused to change power state, currently in D%d\n", + dev->current_state); /* * According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT @@ -846,6 +848,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) return error; } +EXPORT_SYMBOL(pci_set_power_state); /** * pci_choose_state - Choose the power state of a PCI device @@ -884,12 +887,10 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) } return PCI_D0; } - EXPORT_SYMBOL(pci_choose_state); #define PCI_EXP_SAVE_REGS 7 - static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev, u16 cap, bool extended) { @@ -1001,8 +1002,7 @@ static void pci_restore_pcix_state(struct pci_dev *dev) * pci_save_state - save the PCI configuration space of a device before suspending * @dev: - PCI device that we're dealing with */ -int -pci_save_state(struct pci_dev *dev) +int pci_save_state(struct pci_dev *dev) { int i; /* XXX: 100% dword access ok here? */ @@ -1017,6 +1017,7 @@ pci_save_state(struct pci_dev *dev) return i; return 0; } +EXPORT_SYMBOL(pci_save_state); static void pci_restore_config_dword(struct pci_dev *pdev, int offset, u32 saved_val, int retry) @@ -1028,8 +1029,8 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset, return; for (;;) { - dev_dbg(&pdev->dev, "restoring config space at offset " - "%#x (was %#x, writing %#x)\n", offset, val, saved_val); + dev_dbg(&pdev->dev, "restoring config space at offset %#x (was %#x, writing %#x)\n", + offset, val, saved_val); pci_write_config_dword(pdev, offset, saved_val); if (retry-- <= 0) return; @@ -1087,6 +1088,7 @@ void pci_restore_state(struct pci_dev *dev) dev->state_saved = false; } +EXPORT_SYMBOL(pci_restore_state); struct pci_saved_state { u32 config_space[16]; @@ -1193,6 +1195,8 @@ int __weak pcibios_enable_device(struct pci_dev *dev, int bars) static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; + u16 cmd; + u8 pin; err = pci_set_power_state(dev, PCI_D0); if (err < 0 && err != -EIO) @@ -1202,6 +1206,17 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars) return err; pci_fixup_device(pci_fixup_enable, dev); + if (dev->msi_enabled || dev->msix_enabled) + return 0; + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_INTX_DISABLE) + pci_write_config_word(dev, PCI_COMMAND, + cmd & ~PCI_COMMAND_INTX_DISABLE); + } + return 0; } @@ -1218,6 +1233,7 @@ int pci_reenable_device(struct pci_dev *dev) return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1); return 0; } +EXPORT_SYMBOL(pci_reenable_device); static void pci_enable_bridge(struct pci_dev *dev) { @@ -1292,6 +1308,7 @@ int pci_enable_device_io(struct pci_dev *dev) { return pci_enable_device_flags(dev, IORESOURCE_IO); } +EXPORT_SYMBOL(pci_enable_device_io); /** * pci_enable_device_mem - Initialize a device for use with Memory space @@ -1305,6 +1322,7 @@ int pci_enable_device_mem(struct pci_dev *dev) { return pci_enable_device_flags(dev, IORESOURCE_MEM); } +EXPORT_SYMBOL(pci_enable_device_mem); /** * pci_enable_device - Initialize device before it's used by a driver. @@ -1321,6 +1339,7 @@ int pci_enable_device(struct pci_dev *dev) { return pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO); } +EXPORT_SYMBOL(pci_enable_device); /* * Managed PCI resources. This manages device on/off, intx/msi/msix @@ -1358,7 +1377,7 @@ static void pcim_release(struct device *gendev, void *res) pci_disable_device(dev); } -static struct pci_devres * get_pci_dr(struct pci_dev *pdev) +static struct pci_devres *get_pci_dr(struct pci_dev *pdev) { struct pci_devres *dr, *new_dr; @@ -1372,7 +1391,7 @@ static struct pci_devres * get_pci_dr(struct pci_dev *pdev) return devres_get(&pdev->dev, new_dr, NULL, NULL); } -static struct pci_devres * find_pci_dr(struct pci_dev *pdev) +static struct pci_devres *find_pci_dr(struct pci_dev *pdev) { if (pci_is_managed(pdev)) return devres_find(&pdev->dev, pcim_release, NULL, NULL); @@ -1403,6 +1422,7 @@ int pcim_enable_device(struct pci_dev *pdev) } return rc; } +EXPORT_SYMBOL(pcim_enable_device); /** * pcim_pin_device - Pin managed PCI device @@ -1421,6 +1441,7 @@ void pcim_pin_device(struct pci_dev *pdev) if (dr) dr->pinned = 1; } +EXPORT_SYMBOL(pcim_pin_device); /* * pcibios_add_device - provide arch specific hooks when adding device dev @@ -1430,7 +1451,7 @@ void pcim_pin_device(struct pci_dev *pdev) * devices are added. This is the default implementation. Architecture * implementations can override this. */ -int __weak pcibios_add_device (struct pci_dev *dev) +int __weak pcibios_add_device(struct pci_dev *dev) { return 0; } @@ -1455,6 +1476,17 @@ void __weak pcibios_release_device(struct pci_dev *dev) {} */ void __weak pcibios_disable_device (struct pci_dev *dev) {} +/** + * pcibios_penalize_isa_irq - penalize an ISA IRQ + * @irq: ISA IRQ to penalize + * @active: IRQ active or not + * + * Permits the platform to provide architecture-specific functionality when + * penalizing ISA IRQs. This is the default implementation. Architecture + * implementations can override this. + */ +void __weak pcibios_penalize_isa_irq(int irq, int active) {} + static void do_pci_disable_device(struct pci_dev *dev) { u16 pci_command; @@ -1491,8 +1523,7 @@ void pci_disable_enabled_device(struct pci_dev *dev) * Note we don't actually disable the device until all callers of * pci_enable_device() have called pci_disable_device(). */ -void -pci_disable_device(struct pci_dev *dev) +void pci_disable_device(struct pci_dev *dev) { struct pci_devres *dr; @@ -1510,6 +1541,7 @@ pci_disable_device(struct pci_dev *dev) dev->is_busmaster = 0; } +EXPORT_SYMBOL(pci_disable_device); /** * pcibios_set_pcie_reset_state - set reset state for device dev @@ -1538,6 +1570,7 @@ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) { return pcibios_set_pcie_reset_state(dev, state); } +EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state); /** * pci_check_pme_status - Check if given device has generated PME. @@ -1617,35 +1650,34 @@ bool pci_pme_capable(struct pci_dev *dev, pci_power_t state) return !!(dev->pme_support & (1 << state)); } +EXPORT_SYMBOL(pci_pme_capable); static void pci_pme_list_scan(struct work_struct *work) { struct pci_pme_device *pme_dev, *n; mutex_lock(&pci_pme_list_mutex); - if (!list_empty(&pci_pme_list)) { - list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) { - if (pme_dev->dev->pme_poll) { - struct pci_dev *bridge; - - bridge = pme_dev->dev->bus->self; - /* - * If bridge is in low power state, the - * configuration space of subordinate devices - * may be not accessible - */ - if (bridge && bridge->current_state != PCI_D0) - continue; - pci_pme_wakeup(pme_dev->dev, NULL); - } else { - list_del(&pme_dev->list); - kfree(pme_dev); - } + list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) { + if (pme_dev->dev->pme_poll) { + struct pci_dev *bridge; + + bridge = pme_dev->dev->bus->self; + /* + * If bridge is in low power state, the + * configuration space of subordinate devices + * may be not accessible + */ + if (bridge && bridge->current_state != PCI_D0) + continue; + pci_pme_wakeup(pme_dev->dev, NULL); + } else { + list_del(&pme_dev->list); + kfree(pme_dev); } - if (!list_empty(&pci_pme_list)) - schedule_delayed_work(&pci_pme_work, - msecs_to_jiffies(PME_TIMEOUT)); } + if (!list_empty(&pci_pme_list)) + schedule_delayed_work(&pci_pme_work, + msecs_to_jiffies(PME_TIMEOUT)); mutex_unlock(&pci_pme_list_mutex); } @@ -1723,6 +1755,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable) dev_dbg(&dev->dev, "PME# %s\n", enable ? "enabled" : "disabled"); } +EXPORT_SYMBOL(pci_pme_active); /** * __pci_enable_wake - enable PCI device as wakeup event source @@ -1808,6 +1841,7 @@ int pci_wake_from_d3(struct pci_dev *dev, bool enable) pci_enable_wake(dev, PCI_D3cold, enable) : pci_enable_wake(dev, PCI_D3hot, enable); } +EXPORT_SYMBOL(pci_wake_from_d3); /** * pci_target_state - find an appropriate low power state for a given PCI dev @@ -1886,6 +1920,7 @@ int pci_prepare_to_sleep(struct pci_dev *dev) return error; } +EXPORT_SYMBOL(pci_prepare_to_sleep); /** * pci_back_from_sleep - turn PCI device on during system-wide transition into working state @@ -1898,6 +1933,7 @@ int pci_back_from_sleep(struct pci_dev *dev) pci_enable_wake(dev, PCI_D0, false); return pci_set_power_state(dev, PCI_D0); } +EXPORT_SYMBOL(pci_back_from_sleep); /** * pci_finish_runtime_suspend - Carry out PCI-specific part of runtime suspend. @@ -2192,21 +2228,18 @@ void pci_request_acs(void) } /** - * pci_enable_acs - enable ACS if hardware support it + * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites * @dev: the PCI device */ -void pci_enable_acs(struct pci_dev *dev) +static int pci_std_enable_acs(struct pci_dev *dev) { int pos; u16 cap; u16 ctrl; - if (!pci_acs_enable) - return; - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS); if (!pos) - return; + return -ENODEV; pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap); pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl); @@ -2224,6 +2257,23 @@ void pci_enable_acs(struct pci_dev *dev) ctrl |= (cap & PCI_ACS_UF); pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl); + + return 0; +} + +/** + * pci_enable_acs - enable ACS if hardware support it + * @dev: the PCI device + */ +void pci_enable_acs(struct pci_dev *dev) +{ + if (!pci_acs_enable) + return; + + if (!pci_std_enable_acs(dev)) + return; + + pci_dev_specific_enable_acs(dev); } static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) @@ -2379,8 +2429,7 @@ u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin) return (((pin - 1) + slot) % 4) + 1; } -int -pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) +int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) { u8 pin; @@ -2442,6 +2491,7 @@ void pci_release_region(struct pci_dev *pdev, int bar) if (dr) dr->region_mask &= ~(1 << bar); } +EXPORT_SYMBOL(pci_release_region); /** * __pci_request_region - Reserved PCI I/O and memory resource @@ -2462,8 +2512,8 @@ void pci_release_region(struct pci_dev *pdev, int bar) * Returns 0 on success, or %EBUSY on error. A warning * message is also printed on failure. */ -static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_name, - int exclusive) +static int __pci_request_region(struct pci_dev *pdev, int bar, + const char *res_name, int exclusive) { struct pci_devres *dr; @@ -2474,8 +2524,7 @@ static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_n if (!request_region(pci_resource_start(pdev, bar), pci_resource_len(pdev, bar), res_name)) goto err_out; - } - else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { + } else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { if (!__request_mem_region(pci_resource_start(pdev, bar), pci_resource_len(pdev, bar), res_name, exclusive)) @@ -2512,6 +2561,7 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) { return __pci_request_region(pdev, bar, res_name, 0); } +EXPORT_SYMBOL(pci_request_region); /** * pci_request_region_exclusive - Reserved PCI I/O and memory resource @@ -2531,10 +2581,13 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) * explicitly not allowed to map the resource via /dev/mem or * sysfs. */ -int pci_request_region_exclusive(struct pci_dev *pdev, int bar, const char *res_name) +int pci_request_region_exclusive(struct pci_dev *pdev, int bar, + const char *res_name) { return __pci_request_region(pdev, bar, res_name, IORESOURCE_EXCLUSIVE); } +EXPORT_SYMBOL(pci_request_region_exclusive); + /** * pci_release_selected_regions - Release selected PCI I/O and memory resources * @pdev: PCI device whose resources were previously reserved @@ -2551,9 +2604,10 @@ void pci_release_selected_regions(struct pci_dev *pdev, int bars) if (bars & (1 << i)) pci_release_region(pdev, i); } +EXPORT_SYMBOL(pci_release_selected_regions); static int __pci_request_selected_regions(struct pci_dev *pdev, int bars, - const char *res_name, int excl) + const char *res_name, int excl) { int i; @@ -2564,7 +2618,7 @@ static int __pci_request_selected_regions(struct pci_dev *pdev, int bars, return 0; err_out: - while(--i >= 0) + while (--i >= 0) if (bars & (1 << i)) pci_release_region(pdev, i); @@ -2583,13 +2637,15 @@ int pci_request_selected_regions(struct pci_dev *pdev, int bars, { return __pci_request_selected_regions(pdev, bars, res_name, 0); } +EXPORT_SYMBOL(pci_request_selected_regions); -int pci_request_selected_regions_exclusive(struct pci_dev *pdev, - int bars, const char *res_name) +int pci_request_selected_regions_exclusive(struct pci_dev *pdev, int bars, + const char *res_name) { return __pci_request_selected_regions(pdev, bars, res_name, IORESOURCE_EXCLUSIVE); } +EXPORT_SYMBOL(pci_request_selected_regions_exclusive); /** * pci_release_regions - Release reserved PCI I/O and memory resources @@ -2604,6 +2660,7 @@ void pci_release_regions(struct pci_dev *pdev) { pci_release_selected_regions(pdev, (1 << 6) - 1); } +EXPORT_SYMBOL(pci_release_regions); /** * pci_request_regions - Reserved PCI I/O and memory resources @@ -2622,6 +2679,7 @@ int pci_request_regions(struct pci_dev *pdev, const char *res_name) { return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name); } +EXPORT_SYMBOL(pci_request_regions); /** * pci_request_regions_exclusive - Reserved PCI I/O and memory resources @@ -2644,6 +2702,7 @@ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name) return pci_request_selected_regions_exclusive(pdev, ((1 << 6) - 1), res_name); } +EXPORT_SYMBOL(pci_request_regions_exclusive); static void __pci_set_master(struct pci_dev *dev, bool enable) { @@ -2713,6 +2772,7 @@ void pci_set_master(struct pci_dev *dev) __pci_set_master(dev, true); pcibios_set_master(dev); } +EXPORT_SYMBOL(pci_set_master); /** * pci_clear_master - disables bus-mastering for device dev @@ -2722,6 +2782,7 @@ void pci_clear_master(struct pci_dev *dev) { __pci_set_master(dev, false); } +EXPORT_SYMBOL(pci_clear_master); /** * pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed @@ -2754,30 +2815,13 @@ int pci_set_cacheline_size(struct pci_dev *dev) if (cacheline_size == pci_cache_line_size) return 0; - dev_printk(KERN_DEBUG, &dev->dev, "cache line size of %d is not " - "supported\n", pci_cache_line_size << 2); + dev_printk(KERN_DEBUG, &dev->dev, "cache line size of %d is not supported\n", + pci_cache_line_size << 2); return -EINVAL; } EXPORT_SYMBOL_GPL(pci_set_cacheline_size); -#ifdef PCI_DISABLE_MWI -int pci_set_mwi(struct pci_dev *dev) -{ - return 0; -} - -int pci_try_set_mwi(struct pci_dev *dev) -{ - return 0; -} - -void pci_clear_mwi(struct pci_dev *dev) -{ -} - -#else - /** * pci_set_mwi - enables memory-write-invalidate PCI transaction * @dev: the PCI device for which MWI is enabled @@ -2786,9 +2830,11 @@ void pci_clear_mwi(struct pci_dev *dev) * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -int -pci_set_mwi(struct pci_dev *dev) +int pci_set_mwi(struct pci_dev *dev) { +#ifdef PCI_DISABLE_MWI + return 0; +#else int rc; u16 cmd; @@ -2797,14 +2843,15 @@ pci_set_mwi(struct pci_dev *dev) return rc; pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (! (cmd & PCI_COMMAND_INVALIDATE)) { + if (!(cmd & PCI_COMMAND_INVALIDATE)) { dev_dbg(&dev->dev, "enabling Mem-Wr-Inval\n"); cmd |= PCI_COMMAND_INVALIDATE; pci_write_config_word(dev, PCI_COMMAND, cmd); } - return 0; +#endif } +EXPORT_SYMBOL(pci_set_mwi); /** * pci_try_set_mwi - enables memory-write-invalidate PCI transaction @@ -2817,9 +2864,13 @@ pci_set_mwi(struct pci_dev *dev) */ int pci_try_set_mwi(struct pci_dev *dev) { - int rc = pci_set_mwi(dev); - return rc; +#ifdef PCI_DISABLE_MWI + return 0; +#else + return pci_set_mwi(dev); +#endif } +EXPORT_SYMBOL(pci_try_set_mwi); /** * pci_clear_mwi - disables Memory-Write-Invalidate for device dev @@ -2827,9 +2878,9 @@ int pci_try_set_mwi(struct pci_dev *dev) * * Disables PCI Memory-Write-Invalidate transaction on the device */ -void -pci_clear_mwi(struct pci_dev *dev) +void pci_clear_mwi(struct pci_dev *dev) { +#ifndef PCI_DISABLE_MWI u16 cmd; pci_read_config_word(dev, PCI_COMMAND, &cmd); @@ -2837,8 +2888,9 @@ pci_clear_mwi(struct pci_dev *dev) cmd &= ~PCI_COMMAND_INVALIDATE; pci_write_config_word(dev, PCI_COMMAND, cmd); } +#endif } -#endif /* ! PCI_DISABLE_MWI */ +EXPORT_SYMBOL(pci_clear_mwi); /** * pci_intx - enables/disables PCI INTx for device dev @@ -2847,18 +2899,16 @@ pci_clear_mwi(struct pci_dev *dev) * * Enables/disables PCI INTx for device dev */ -void -pci_intx(struct pci_dev *pdev, int enable) +void pci_intx(struct pci_dev *pdev, int enable) { u16 pci_command, new; pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - if (enable) { + if (enable) new = pci_command & ~PCI_COMMAND_INTX_DISABLE; - } else { + else new = pci_command | PCI_COMMAND_INTX_DISABLE; - } if (new != pci_command) { struct pci_devres *dr; @@ -2872,6 +2922,7 @@ pci_intx(struct pci_dev *pdev, int enable) } } } +EXPORT_SYMBOL_GPL(pci_intx); /** * pci_intx_mask_supported - probe for INTx masking support @@ -2901,8 +2952,8 @@ bool pci_intx_mask_supported(struct pci_dev *dev) * go ahead and check it. */ if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) { - dev_err(&dev->dev, "Command register changed from " - "0x%x to 0x%x: driver or hardware bug?\n", orig, new); + dev_err(&dev->dev, "Command register changed from 0x%x to 0x%x: driver or hardware bug?\n", + orig, new); } else if ((new ^ orig) & PCI_COMMAND_INTX_DISABLE) { mask_supported = true; pci_write_config_word(dev, PCI_COMMAND, orig); @@ -3042,7 +3093,8 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev) if (!pci_is_pcie(dev)) return 1; - return pci_wait_for_pending(dev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_TRPND); + return pci_wait_for_pending(dev, pci_pcie_cap(dev) + PCI_EXP_DEVSTA, + PCI_EXP_DEVSTA_TRPND); } EXPORT_SYMBOL(pci_wait_for_pending_transaction); @@ -3083,12 +3135,16 @@ static int pci_af_flr(struct pci_dev *dev, int probe) if (probe) return 0; - /* Wait for Transaction Pending bit clean */ - if (pci_wait_for_pending(dev, PCI_AF_STATUS, PCI_AF_STATUS_TP)) + /* + * Wait for Transaction Pending bit to clear. A word-aligned test + * is used, so we use the conrol offset rather than status and shift + * the test bit to match. + */ + if (pci_wait_for_pending(dev, pos + PCI_AF_CTRL, + PCI_AF_STATUS_TP << 8)) goto clear; - dev_err(&dev->dev, "transaction is not cleared; " - "proceeding with reset anyway\n"); + dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n"); clear: pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); @@ -3142,14 +3198,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) return 0; } -/** - * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge. - * @dev: Bridge device - * - * Use the bridge control register to assert reset on the secondary bus. - * Devices on the secondary bus are left in power-on state. - */ -void pci_reset_bridge_secondary_bus(struct pci_dev *dev) +void __weak pcibios_reset_secondary_bus(struct pci_dev *dev) { u16 ctrl; @@ -3174,6 +3223,18 @@ void pci_reset_bridge_secondary_bus(struct pci_dev *dev) */ ssleep(1); } + +/** + * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge. + * @dev: Bridge device + * + * Use the bridge control register to assert reset on the secondary bus. + * Devices on the secondary bus are left in power-on state. + */ +void pci_reset_bridge_secondary_bus(struct pci_dev *dev) +{ + pcibios_reset_secondary_bus(dev); +} EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus); static int pci_parent_bus_reset(struct pci_dev *dev, int probe) @@ -3280,8 +3341,27 @@ static void pci_dev_unlock(struct pci_dev *dev) pci_cfg_access_unlock(dev); } +/** + * pci_reset_notify - notify device driver of reset + * @dev: device to be notified of reset + * @prepare: 'true' if device is about to be reset; 'false' if reset attempt + * completed + * + * Must be called prior to device access being disabled and after device + * access is restored. + */ +static void pci_reset_notify(struct pci_dev *dev, bool prepare) +{ + const struct pci_error_handlers *err_handler = + dev->driver ? dev->driver->err_handler : NULL; + if (err_handler && err_handler->reset_notify) + err_handler->reset_notify(dev, prepare); +} + static void pci_dev_save_and_disable(struct pci_dev *dev) { + pci_reset_notify(dev, true); + /* * Wake-up device prior to save. PM registers default to D0 after * reset and a simple register restore doesn't reliably return @@ -3303,6 +3383,7 @@ static void pci_dev_save_and_disable(struct pci_dev *dev) static void pci_dev_restore(struct pci_dev *dev) { pci_restore_state(dev); + pci_reset_notify(dev, false); } static int pci_dev_reset(struct pci_dev *dev, int probe) @@ -3319,6 +3400,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) return rc; } + /** * __pci_reset_function - reset a PCI device function * @dev: PCI device to reset @@ -4037,6 +4119,7 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags) bars |= (1 << i); return bars; } +EXPORT_SYMBOL(pci_select_bars); /** * pci_resource_bar - get position of the BAR associated with a resource @@ -4076,7 +4159,7 @@ void __init pci_register_set_vga_state(arch_set_vga_state_t func) } static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode, - unsigned int command_bits, u32 flags) + unsigned int command_bits, u32 flags) { if (arch_set_vga_state) return arch_set_vga_state(dev, decode, command_bits, @@ -4100,7 +4183,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, u16 cmd; int rc; - WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY))); + WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) && (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY))); /* ARCH specific VGA enables */ rc = pci_set_vga_state_arch(dev, decode, command_bits, flags); @@ -4188,11 +4271,10 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev) bus == dev->bus->number && slot == PCI_SLOT(dev->devfn) && func == PCI_FUNC(dev->devfn)) { - if (align_order == -1) { + if (align_order == -1) align = PAGE_SIZE; - } else { + else align = 1 << align_order; - } /* Found */ break; } @@ -4310,7 +4392,6 @@ static int __init pci_resource_alignment_sysfs_init(void) return bus_create_file(&pci_bus_type, &bus_attr_resource_alignment); } - late_initcall(pci_resource_alignment_sysfs_init); static void pci_no_domains(void) @@ -4389,41 +4470,3 @@ static int __init pci_setup(char *str) return 0; } early_param("pci", pci_setup); - -EXPORT_SYMBOL(pci_reenable_device); -EXPORT_SYMBOL(pci_enable_device_io); -EXPORT_SYMBOL(pci_enable_device_mem); -EXPORT_SYMBOL(pci_enable_device); -EXPORT_SYMBOL(pcim_enable_device); -EXPORT_SYMBOL(pcim_pin_device); -EXPORT_SYMBOL(pci_disable_device); -EXPORT_SYMBOL(pci_find_capability); -EXPORT_SYMBOL(pci_bus_find_capability); -EXPORT_SYMBOL(pci_release_regions); -EXPORT_SYMBOL(pci_request_regions); -EXPORT_SYMBOL(pci_request_regions_exclusive); -EXPORT_SYMBOL(pci_release_region); -EXPORT_SYMBOL(pci_request_region); -EXPORT_SYMBOL(pci_request_region_exclusive); -EXPORT_SYMBOL(pci_release_selected_regions); -EXPORT_SYMBOL(pci_request_selected_regions); -EXPORT_SYMBOL(pci_request_selected_regions_exclusive); -EXPORT_SYMBOL(pci_set_master); -EXPORT_SYMBOL(pci_clear_master); -EXPORT_SYMBOL(pci_set_mwi); -EXPORT_SYMBOL(pci_try_set_mwi); -EXPORT_SYMBOL(pci_clear_mwi); -EXPORT_SYMBOL_GPL(pci_intx); -EXPORT_SYMBOL(pci_assign_resource); -EXPORT_SYMBOL(pci_find_parent_resource); -EXPORT_SYMBOL(pci_select_bars); - -EXPORT_SYMBOL(pci_set_power_state); -EXPORT_SYMBOL(pci_save_state); -EXPORT_SYMBOL(pci_restore_state); -EXPORT_SYMBOL(pci_pme_capable); -EXPORT_SYMBOL(pci_pme_active); -EXPORT_SYMBOL(pci_wake_from_d3); -EXPORT_SYMBOL(pci_prepare_to_sleep); -EXPORT_SYMBOL(pci_back_from_sleep); -EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4df38df224f..0601890db22 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,8 +1,6 @@ #ifndef DRIVERS_PCI_H #define DRIVERS_PCI_H -#include <linux/workqueue.h> - #define PCI_CFG_SPACE_SIZE 256 #define PCI_CFG_SPACE_EXP_SIZE 4096 @@ -79,7 +77,7 @@ static inline void pci_wakeup_event(struct pci_dev *dev) pm_wakeup_event(&dev->dev, 100); } -static inline bool pci_is_bridge(struct pci_dev *pci_dev) +static inline bool pci_has_subordinate(struct pci_dev *pci_dev) { return !!(pci_dev->subordinate); } @@ -203,11 +201,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, struct resource *res, unsigned int reg); int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type); void pci_configure_ari(struct pci_dev *dev); -void __ref __pci_bus_size_bridges(struct pci_bus *bus, +void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head); -void __ref __pci_bus_assign_resources(const struct pci_bus *bus, - struct list_head *realloc_head, - struct list_head *fail_head); +void __pci_bus_assign_resources(const struct pci_bus *bus, + struct list_head *realloc_head, + struct list_head *fail_head); /** * pci_ari_enabled - query ARI forwarding status @@ -240,8 +238,6 @@ struct pci_sriov { struct pci_dev *dev; /* lowest numbered PF */ struct pci_dev *self; /* this PF */ struct mutex lock; /* lock for VF bus */ - struct work_struct mtask; /* VF Migration task */ - u8 __iomem *mstate; /* VF Migration State Array */ }; #ifdef CONFIG_PCI_ATS diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index 587e7e85310..182224acedb 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -397,16 +397,14 @@ static int aer_inject(struct aer_error_inj *einj) if (!aer_mask_override && einj->cor_status && !(einj->cor_status & ~cor_mask)) { ret = -EINVAL; - printk(KERN_WARNING "The correctable error(s) is masked " - "by device\n"); + printk(KERN_WARNING "The correctable error(s) is masked by device\n"); spin_unlock_irqrestore(&inject_lock, flags); goto out_put; } if (!aer_mask_override && einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { ret = -EINVAL; - printk(KERN_WARNING "The uncorrectable error(s) is masked " - "by device\n"); + printk(KERN_WARNING "The uncorrectable error(s) is masked by device\n"); spin_unlock_irqrestore(&inject_lock, flags); goto out_put; } @@ -464,8 +462,7 @@ static int aer_inject(struct aer_error_inj *einj) goto out_put; } aer_irq(-1, edev); - } - else + } else ret = -EINVAL; out_put: kfree(err_alloc); diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index b2c8881da76..5653ea94547 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -542,8 +542,7 @@ static void aer_recover_work_func(struct work_struct *work); #define AER_RECOVER_RING_ORDER 4 #define AER_RECOVER_RING_SIZE (1 << AER_RECOVER_RING_ORDER) -struct aer_recover_entry -{ +struct aer_recover_entry { u8 bus; u8 devfn; u16 domain; diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 34ff7026440..36ed31b5219 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -172,9 +172,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) int id = ((dev->bus->number << 8) | dev->devfn); if (!info->status) { - dev_err(&dev->dev, - "PCIe Bus Error: severity=%s, type=Unaccessible, " - "id=%04x(Unregistered Agent ID)\n", + dev_err(&dev->dev, "PCIe Bus Error: severity=%s, type=Unaccessible, id=%04x(Unregistered Agent ID)\n", aer_error_severity_string[info->severity], id); goto out; } @@ -182,13 +180,11 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) layer = AER_GET_LAYER_ERROR(info->severity, info->status); agent = AER_GET_AGENT(info->severity, info->status); - dev_err(&dev->dev, - "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", + dev_err(&dev->dev, "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", aer_error_severity_string[info->severity], aer_error_layer[layer], id, aer_agent_string[agent]); - dev_err(&dev->dev, - " device [%04x:%04x] error status/mask=%08x/%08x\n", + dev_err(&dev->dev, " device [%04x:%04x] error status/mask=%08x/%08x\n", dev->vendor, dev->device, info->status, info->mask); diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index bbc3bdd2b18..82e06a86cd7 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -199,8 +199,7 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) * assuming that the PME was reported by a PCIe-PCI bridge that * used devfn different from zero. */ - dev_dbg(&port->dev, "PME interrupt generated for " - "non-existent device %02x:%02x.%d\n", + dev_dbg(&port->dev, "PME interrupt generated for non-existent device %02x:%02x.%d\n", busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); found = pcie_pme_from_pci_bridge(bus, 0); } diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 986f8eadfd3..2f0ce668a77 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -99,7 +99,7 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) for (i = 0; i < nr_entries; i++) msix_entries[i].entry = i; - status = pci_enable_msix(dev, msix_entries, nr_entries); + status = pci_enable_msix_exact(dev, msix_entries, nr_entries); if (status) goto Exit; @@ -171,7 +171,7 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) pci_disable_msix(dev); /* Now allocate the MSI-X vectors for real */ - status = pci_enable_msix(dev, msix_entries, nvec); + status = pci_enable_msix_exact(dev, msix_entries, nvec); if (status) goto Exit; } @@ -379,10 +379,13 @@ int pcie_port_device_register(struct pci_dev *dev) /* * Initialize service irqs. Don't use service devices that * require interrupts if there is no way to generate them. + * However, some drivers may have a polling mode (e.g. pciehp_poll_mode) + * that can be used in the absence of irqs. Allow them to determine + * if that is to be used. */ status = init_service_irqs(dev, irqs, capabilities); if (status) { - capabilities &= PCIE_PORT_SERVICE_VC; + capabilities &= PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_HP; if (!capabilities) goto error_disable; } diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 0d8fdc48e64..80887eaa066 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -204,8 +204,8 @@ static int pcie_portdrv_probe(struct pci_dev *dev, return -ENODEV; if (!dev->irq && dev->pin) { - dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; " - "check vendor BIOS\n", dev->vendor, dev->device); + dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; check vendor BIOS\n", + dev->vendor, dev->device); } status = pcie_port_device_register(dev); if (status) @@ -397,7 +397,7 @@ static struct pci_driver pcie_portdriver = { static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d) { pr_notice("%s detected: will not use MSI for PCIe PME signaling\n", - d->ident); + d->ident); pcie_pme_disable_msi(); return 0; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 78335efbbb7..e3cf8a2e629 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -168,12 +168,13 @@ static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar) * Returns 1 if the BAR is 64-bit, or 0 if 32-bit. */ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, - struct resource *res, unsigned int pos) + struct resource *res, unsigned int pos) { u32 l, sz, mask; + u64 l64, sz64, mask64; u16 orig_cmd; struct pci_bus_region region, inverted_region; - bool bar_too_big = false, bar_disabled = false; + bool bar_too_big = false, bar_too_high = false, bar_invalid = false; mask = type ? PCI_ROM_ADDRESS_MASK : ~0; @@ -226,9 +227,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, } if (res->flags & IORESOURCE_MEM_64) { - u64 l64 = l; - u64 sz64 = sz; - u64 mask64 = mask | (u64)~0 << 32; + l64 = l; + sz64 = sz; + mask64 = mask | (u64)~0 << 32; pci_read_config_dword(dev, pos + 4, &l); pci_write_config_dword(dev, pos + 4, ~0); @@ -243,19 +244,22 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, if (!sz64) goto fail; - if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { + if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && + sz64 > 0x100000000ULL) { + res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; + res->start = 0; + res->end = 0; bar_too_big = true; - goto fail; + goto out; } - if ((sizeof(resource_size_t) < 8) && l) { - /* Address above 32-bit boundary; disable the BAR */ - pci_write_config_dword(dev, pos, 0); - pci_write_config_dword(dev, pos + 4, 0); + if ((sizeof(dma_addr_t) < 8) && l) { + /* Above 32-bit boundary; try to reallocate */ res->flags |= IORESOURCE_UNSET; - region.start = 0; - region.end = sz64; - bar_disabled = true; + res->start = 0; + res->end = sz64; + bar_too_high = true; + goto out; } else { region.start = l64; region.end = l64 + sz64; @@ -285,11 +289,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, * be claimed by the device. */ if (inverted_region.start != region.start) { - dev_info(&dev->dev, "reg 0x%x: initial BAR value %pa invalid; forcing reassignment\n", - pos, ®ion.start); res->flags |= IORESOURCE_UNSET; - res->end -= res->start; res->start = 0; + res->end = region.end - region.start; + bar_invalid = true; } goto out; @@ -303,8 +306,15 @@ out: pci_write_config_word(dev, PCI_COMMAND, orig_cmd); if (bar_too_big) - dev_err(&dev->dev, "reg 0x%x: can't handle 64-bit BAR\n", pos); - if (res->flags && !bar_disabled) + dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n", + pos, (unsigned long long) sz64); + if (bar_too_high) + dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4G (bus address %#010llx)\n", + pos, (unsigned long long) l64); + if (bar_invalid) + dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n", + pos, (unsigned long long) region.start); + if (res->flags) dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; @@ -423,8 +433,7 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child) limit |= ((unsigned long) mem_limit_hi) << 32; #else if (mem_base_hi || mem_limit_hi) { - dev_err(&dev->dev, "can't handle 64-bit " - "address space for bridge\n"); + dev_err(&dev->dev, "can't handle 64-bit address space for bridge\n"); return; } #endif @@ -465,7 +474,7 @@ void pci_read_bridge_bases(struct pci_bus *child) if (dev->transparent) { pci_bus_for_each_resource(child->parent, res, i) { - if (res) { + if (res && res->flags) { pci_bus_add_resource(child, res, PCI_SUBTRACTIVE_DECODE); dev_printk(KERN_DEBUG, &dev->dev, @@ -594,7 +603,6 @@ static enum pci_bus_speed agp_speed(int agp3, int agpstat) return agp_speeds[index]; } - static void pci_set_bus_speed(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; @@ -626,11 +634,10 @@ static void pci_set_bus_speed(struct pci_bus *bus) } else if (status & PCI_X_SSTATUS_266MHZ) { max = PCI_SPEED_133MHz_PCIX_266; } else if (status & PCI_X_SSTATUS_133MHZ) { - if ((status & PCI_X_SSTATUS_VERS) == PCI_X_SSTATUS_V2) { + if ((status & PCI_X_SSTATUS_VERS) == PCI_X_SSTATUS_V2) max = PCI_SPEED_133MHz_PCIX_ECC; - } else { + else max = PCI_SPEED_133MHz_PCIX; - } } else { max = PCI_SPEED_66MHz_PCIX; } @@ -654,7 +661,6 @@ static void pci_set_bus_speed(struct pci_bus *bus) } } - static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { @@ -719,7 +725,8 @@ add_dev: return child; } -struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) +struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, + int busnr) { struct pci_bus *child; @@ -731,22 +738,7 @@ struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *de } return child; } - -static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) -{ - struct pci_bus *parent = child->parent; - - /* Attempts to fix that up are really dangerous unless - we're going to re-assign all bus numbers. */ - if (!pcibios_assign_all_busses()) - return; - - while (parent->parent && parent->busn_res.end < max) { - parent->busn_res.end = max; - pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max); - parent = parent->parent; - } -} +EXPORT_SYMBOL(pci_add_new_bus); /* * If it's a bridge, configure it and scan the bus behind it. @@ -783,7 +775,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) /* Check if setup is sensible at all */ if (!pass && (primary != bus->number || secondary <= bus->number || - secondary > subordinate)) { + secondary > subordinate || subordinate > bus->busn_res.end)) { dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n", secondary, subordinate); broken = 1; @@ -806,11 +798,10 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) goto out; /* - * If we already got to this bus through a different bridge, - * don't re-add it. This can happen with the i450NX chipset. - * - * However, we continue to descend down the hierarchy and - * scan remaining child buses. + * The bus might already exist for two reasons: Either we are + * rescanning the bus or the bus is reachable through more than + * one bridge. The second case can happen with the i450NX + * chipset. */ child = pci_find_bus(pci_domain_nr(bus), secondary); if (!child) { @@ -823,17 +814,19 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) } cmax = pci_scan_child_bus(child); - if (cmax > max) - max = cmax; - if (child->busn_res.end > max) - max = child->busn_res.end; + if (cmax > subordinate) + dev_warn(&dev->dev, "bridge has subordinate %02x but max busn %02x\n", + subordinate, cmax); + /* subordinate should equal child->busn_res.end */ + if (subordinate > max) + max = subordinate; } else { /* * We need to assign a number to this bus which we always * do in the second pass. */ if (!pass) { - if (pcibios_assign_all_busses() || broken) + if (pcibios_assign_all_busses() || broken || is_cardbus) /* Temporarily disable forwarding of the configuration cycles on all bridges in this bus segment to avoid possible @@ -845,19 +838,25 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) goto out; } + if (max >= bus->busn_res.end) { + dev_warn(&dev->dev, "can't allocate child bus %02x from %pR\n", + max, &bus->busn_res); + goto out; + } + /* Clear errors */ pci_write_config_word(dev, PCI_STATUS, 0xffff); - /* Prevent assigning a bus number that already exists. - * This can happen when a bridge is hot-plugged, so in - * this case we only re-scan this bus. */ + /* The bus will already exist if we are rescanning */ child = pci_find_bus(pci_domain_nr(bus), max+1); if (!child) { - child = pci_add_new_bus(bus, dev, ++max); + child = pci_add_new_bus(bus, dev, max+1); if (!child) goto out; - pci_bus_insert_busn_res(child, max, 0xff); + pci_bus_insert_busn_res(child, max+1, + bus->busn_res.end); } + max++; buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->busn_res.start) << 8) @@ -879,27 +878,14 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) if (!is_cardbus) { child->bridge_ctl = bctl; - /* - * Adjust subordinate busnr in parent buses. - * We do this before scanning for children because - * some devices may not be detected if the bios - * was lazy. - */ - pci_fixup_parent_subordinate_busnr(child, max); - /* Now we can scan all subordinate buses... */ max = pci_scan_child_bus(child); - /* - * now fix it up again since we have found - * the real value of max. - */ - pci_fixup_parent_subordinate_busnr(child, max); } else { /* * For CardBus bridges, we leave 4 bus numbers * as cards with a PCI-to-PCI bridge can be * inserted later. */ - for (i=0; i<CARDBUS_RESERVE_BUSNR; i++) { + for (i = 0; i < CARDBUS_RESERVE_BUSNR; i++) { struct pci_bus *parent = bus; if (pci_find_bus(pci_domain_nr(bus), max+i+1)) @@ -923,11 +909,15 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) } } max += i; - pci_fixup_parent_subordinate_busnr(child, max); } /* * Set the subordinate bus number to its real value. */ + if (max > bus->busn_res.end) { + dev_warn(&dev->dev, "max busn %02x is outside %pR\n", + max, &bus->busn_res); + max = bus->busn_res.end; + } pci_bus_update_busn_res_end(child, max); pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); } @@ -942,8 +932,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) (child->number > bus->busn_res.end) || (child->number < bus->number) || (child->busn_res.end < bus->number)) { - dev_info(&child->dev, "%pR %s " - "hidden behind%s bridge %s %pR\n", + dev_info(&child->dev, "%pR %s hidden behind%s bridge %s %pR\n", &child->busn_res, (bus->number > child->busn_res.end && bus->busn_res.end < child->number) ? @@ -960,6 +949,7 @@ out: return max; } +EXPORT_SYMBOL(pci_scan_bridge); /* * Read interrupt line and base address registers. @@ -1000,6 +990,42 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev) pdev->is_hotplug_bridge = 1; } +/** + * pci_ext_cfg_is_aliased - is ext config space just an alias of std config? + * @dev: PCI device + * + * PCI Express to PCI/PCI-X Bridge Specification, rev 1.0, 4.1.4 says that + * when forwarding a type1 configuration request the bridge must check that + * the extended register address field is zero. The bridge is not permitted + * to forward the transactions and must handle it as an Unsupported Request. + * Some bridges do not follow this rule and simply drop the extended register + * bits, resulting in the standard config space being aliased, every 256 + * bytes across the entire configuration space. Test for this condition by + * comparing the first dword of each potential alias to the vendor/device ID. + * Known offenders: + * ASM1083/1085 PCIe-to-PCI Reversible Bridge (1b21:1080, rev 01 & 03) + * AMD/ATI SBx00 PCI to PCI Bridge (1002:4384, rev 40) + */ +static bool pci_ext_cfg_is_aliased(struct pci_dev *dev) +{ +#ifdef CONFIG_PCI_QUIRKS + int pos; + u32 header, tmp; + + pci_read_config_dword(dev, PCI_VENDOR_ID, &header); + + for (pos = PCI_CFG_SPACE_SIZE; + pos < PCI_CFG_SPACE_EXP_SIZE; pos += PCI_CFG_SPACE_SIZE) { + if (pci_read_config_dword(dev, pos, &tmp) != PCIBIOS_SUCCESSFUL + || header != tmp) + return false; + } + + return true; +#else + return false; +#endif +} /** * pci_cfg_space_size - get the configuration space size of the PCI device. @@ -1019,7 +1045,7 @@ static int pci_cfg_space_size_ext(struct pci_dev *dev) if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL) goto fail; - if (status == 0xffffffff) + if (status == 0xffffffff || pci_ext_cfg_is_aliased(dev)) goto fail; return PCI_CFG_SPACE_EXP_SIZE; @@ -1126,10 +1152,10 @@ int pci_setup_device(struct pci_dev *dev) pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); /* - * Do the ugly legacy mode stuff here rather than broken chip - * quirk code. Legacy mode ATA controllers have fixed - * addresses. These are not always echoed in BAR0-3, and - * BAR0-3 in a few cases contain junk! + * Do the ugly legacy mode stuff here rather than broken chip + * quirk code. Legacy mode ATA controllers have fixed + * addresses. These are not always echoed in BAR0-3, and + * BAR0-3 in a few cases contain junk! */ if (class == PCI_CLASS_STORAGE_IDE) { u8 progif; @@ -1140,11 +1166,15 @@ int pci_setup_device(struct pci_dev *dev) res = &dev->resource[0]; res->flags = LEGACY_IO_RESOURCE; pcibios_bus_to_resource(dev->bus, res, ®ion); + dev_info(&dev->dev, "legacy IDE quirk: reg 0x10: %pR\n", + res); region.start = 0x3F6; region.end = 0x3F6; res = &dev->resource[1]; res->flags = LEGACY_IO_RESOURCE; pcibios_bus_to_resource(dev->bus, res, ®ion); + dev_info(&dev->dev, "legacy IDE quirk: reg 0x14: %pR\n", + res); } if ((progif & 4) == 0) { region.start = 0x170; @@ -1152,11 +1182,15 @@ int pci_setup_device(struct pci_dev *dev) res = &dev->resource[2]; res->flags = LEGACY_IO_RESOURCE; pcibios_bus_to_resource(dev->bus, res, ®ion); + dev_info(&dev->dev, "legacy IDE quirk: reg 0x18: %pR\n", + res); region.start = 0x376; region.end = 0x376; res = &dev->resource[3]; res->flags = LEGACY_IO_RESOURCE; pcibios_bus_to_resource(dev->bus, res, ®ion); + dev_info(&dev->dev, "legacy IDE quirk: reg 0x1c: %pR\n", + res); } } break; @@ -1188,13 +1222,13 @@ int pci_setup_device(struct pci_dev *dev) break; default: /* unknown header */ - dev_err(&dev->dev, "unknown header type %02x, " - "ignoring device\n", dev->hdr_type); + dev_err(&dev->dev, "unknown header type %02x, ignoring device\n", + dev->hdr_type); return -EIO; bad: - dev_err(&dev->dev, "ignoring class %#08x (doesn't match header " - "type %02x)\n", dev->class, dev->hdr_type); + dev_err(&dev->dev, "ignoring class %#08x (doesn't match header type %02x)\n", + dev->class, dev->hdr_type); dev->class = PCI_CLASS_NOT_DEFINED; } @@ -1225,6 +1259,7 @@ static void pci_release_dev(struct device *dev) pci_release_of_node(pci_dev); pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); + kfree(pci_dev->driver_override); kfree(pci_dev); } @@ -1245,7 +1280,7 @@ struct pci_dev *pci_alloc_dev(struct pci_bus *bus) EXPORT_SYMBOL(pci_alloc_dev); bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, - int crs_timeout) + int crs_timeout) { int delay = 1; @@ -1268,10 +1303,9 @@ bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, return false; /* Card hasn't responded in 60 seconds? Must be stuck. */ if (delay > crs_timeout) { - printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not " - "responding\n", pci_domain_nr(bus), - bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn)); + printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not responding\n", + pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn)); return false; } } @@ -1379,7 +1413,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) WARN_ON(ret < 0); } -struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) +struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) { struct pci_dev *dev; @@ -1481,6 +1515,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) return nr; } +EXPORT_SYMBOL(pci_scan_slot); static int pcie_find_smpss(struct pci_dev *dev, void *data) { @@ -1575,9 +1610,7 @@ static void pcie_write_mrrs(struct pci_dev *dev) } if (mrrs < 128) - dev_err(&dev->dev, "MRRS was unable to be configured with a " - "safe value. If problems are experienced, try running " - "with pci=pcie_bus_safe.\n"); + dev_err(&dev->dev, "MRRS was unable to be configured with a safe value. If problems are experienced, try running with pci=pcie_bus_safe\n"); } static void pcie_bus_detect_mps(struct pci_dev *dev) @@ -1614,8 +1647,8 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) pcie_write_mps(dev, mps); pcie_write_mrrs(dev); - dev_info(&dev->dev, "Max Payload Size set to %4d/%4d (was %4d), " - "Max Read Rq %4d\n", pcie_get_mps(dev), 128 << dev->pcie_mpss, + dev_info(&dev->dev, "Max Payload Size set to %4d/%4d (was %4d), Max Read Rq %4d\n", + pcie_get_mps(dev), 128 << dev->pcie_mpss, orig_mps, pcie_get_readrq(dev)); return 0; @@ -1627,7 +1660,7 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) */ void pcie_bus_configure_settings(struct pci_bus *bus) { - u8 smpss; + u8 smpss = 0; if (!bus->self) return; @@ -1678,10 +1711,9 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus) bus->is_added = 1; } - for (pass=0; pass < 2; pass++) + for (pass = 0; pass < 2; pass++) list_for_each_entry(dev, &bus->devices, bus_list) { - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + if (pci_is_bridge(dev)) max = pci_scan_bridge(bus, dev, max, pass); } @@ -1695,6 +1727,7 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus) dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max); return max; } +EXPORT_SYMBOL_GPL(pci_scan_child_bus); /** * pcibios_root_bridge_prepare - Platform-specific host bridge setup. @@ -1836,7 +1869,7 @@ int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) res->flags |= IORESOURCE_PCI_FIXED; } - conflict = insert_resource_conflict(parent_res, res); + conflict = request_resource_conflict(parent_res, res); if (conflict) dev_printk(KERN_DEBUG, &b->dev, @@ -1968,7 +2001,7 @@ EXPORT_SYMBOL(pci_scan_bus); * * Returns the max number of subordinate bus discovered. */ -unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge) +unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge) { unsigned int max; struct pci_bus *bus = bridge->subordinate; @@ -1991,7 +2024,7 @@ unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge) * * Returns the max number of subordinate bus discovered. */ -unsigned int __ref pci_rescan_bus(struct pci_bus *bus) +unsigned int pci_rescan_bus(struct pci_bus *bus) { unsigned int max; @@ -2003,11 +2036,6 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus) } EXPORT_SYMBOL_GPL(pci_rescan_bus); -EXPORT_SYMBOL(pci_add_new_bus); -EXPORT_SYMBOL(pci_scan_slot); -EXPORT_SYMBOL(pci_scan_bridge); -EXPORT_SYMBOL_GPL(pci_scan_child_bus); - /* * pci_rescan_bus(), pci_rescan_bus_bridge_resize() and PCI device removal * routines should always be executed under this mutex. @@ -2026,7 +2054,8 @@ void pci_unlock_rescan_remove(void) } EXPORT_SYMBOL_GPL(pci_unlock_rescan_remove); -static int __init pci_sort_bf_cmp(const struct device *d_a, const struct device *d_b) +static int __init pci_sort_bf_cmp(const struct device *d_a, + const struct device *d_b) { const struct pci_dev *a = to_pci_dev(d_a); const struct pci_dev *b = to_pci_dev(d_b); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 46d1378f2e9..3f155e78513 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -17,15 +17,14 @@ static int proc_initialized; /* = 0 */ -static loff_t -proc_bus_pci_lseek(struct file *file, loff_t off, int whence) +static loff_t proc_bus_pci_lseek(struct file *file, loff_t off, int whence) { struct pci_dev *dev = PDE_DATA(file_inode(file)); return fixed_size_llseek(file, off, whence, dev->cfg_size); } -static ssize_t -proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +static ssize_t proc_bus_pci_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) { struct pci_dev *dev = PDE_DATA(file_inode(file)); unsigned int pos = *ppos; @@ -108,8 +107,8 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp return nbytes; } -static ssize_t -proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) +static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) { struct inode *ino = file_inode(file); struct pci_dev *dev = PDE_DATA(ino); @@ -413,7 +412,7 @@ int pci_proc_detach_device(struct pci_dev *dev) return 0; } -int pci_proc_detach_bus(struct pci_bus* bus) +int pci_proc_detach_bus(struct pci_bus *bus) { proc_remove(bus->procdir); return 0; @@ -423,6 +422,7 @@ static int proc_bus_pci_dev_open(struct inode *inode, struct file *file) { return seq_open(file, &proc_bus_pci_devices_op); } + static const struct file_operations proc_bus_pci_dev_operations = { .owner = THIS_MODULE, .open = proc_bus_pci_dev_open, @@ -443,6 +443,4 @@ static int __init pci_proc_init(void) return 0; } - device_initcall(pci_proc_init); - diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 6e596ab77fb..d0f69269eb6 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -48,8 +48,8 @@ static void quirk_mellanox_tavor(struct pci_dev *dev) { dev->broken_parity_status = 1; /* This device gives false positives */ } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR, quirk_mellanox_tavor); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE, quirk_mellanox_tavor); /* Deal with broken BIOSes that neglect to enable passive release, which can cause problems in combination with the 82441FX/PPro MTRRs */ @@ -82,7 +82,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_p static void quirk_isa_dma_hangs(struct pci_dev *dev) { if (!isa_dma_bridge_buggy) { - isa_dma_bridge_buggy=1; + isa_dma_bridge_buggy = 1; dev_info(&dev->dev, "Activating ISA DMA hang workarounds\n"); } } @@ -123,7 +123,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGP_LPC, quirk */ static void quirk_nopcipci(struct pci_dev *dev) { - if ((pci_pci_problems & PCIPCI_FAIL)==0) { + if ((pci_pci_problems & PCIPCI_FAIL) == 0) { dev_info(&dev->dev, "Disabling direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_FAIL; } @@ -148,7 +148,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopci */ static void quirk_triton(struct pci_dev *dev) { - if ((pci_pci_problems&PCIPCI_TRITON)==0) { + if ((pci_pci_problems&PCIPCI_TRITON) == 0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_TRITON; } @@ -163,8 +163,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_ * Made according to a windows driver based patch by George E. Breese * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm * and http://www.georgebreese.com/net/software/#PCI - * Also see http://www.au-ja.org/review-kt133a-1-en.phtml for - * the info on which Mr Breese based his work. + * Also see http://www.au-ja.org/review-kt133a-1-en.phtml for + * the info on which Mr Breese based his work. * * Updated based on further information from the site and also on * information provided by VIA @@ -177,14 +177,14 @@ static void quirk_vialatency(struct pci_dev *dev) a buggy southbridge */ p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); - if (p!=NULL) { + if (p != NULL) { /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ /* Check for buggy part revisions */ if (p->revision < 0x40 || p->revision > 0x42) goto exit; } else { p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); - if (p==NULL) /* No problem parts */ + if (p == NULL) /* No problem parts */ goto exit; /* Check for buggy part revisions */ if (p->revision < 0x10 || p->revision > 0x12) @@ -227,7 +227,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_viala */ static void quirk_viaetbf(struct pci_dev *dev) { - if ((pci_pci_problems&PCIPCI_VIAETBF)==0) { + if ((pci_pci_problems&PCIPCI_VIAETBF) == 0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_VIAETBF; } @@ -236,7 +236,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_via static void quirk_vsfx(struct pci_dev *dev) { - if ((pci_pci_problems&PCIPCI_VSFX)==0) { + if ((pci_pci_problems&PCIPCI_VSFX) == 0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_VSFX; } @@ -251,7 +251,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx) */ static void quirk_alimagik(struct pci_dev *dev) { - if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) { + if ((pci_pci_problems&PCIPCI_ALIMAGIK) == 0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON; } @@ -265,7 +265,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimagi */ static void quirk_natoma(struct pci_dev *dev) { - if ((pci_pci_problems&PCIPCI_NATOMA)==0) { + if ((pci_pci_problems&PCIPCI_NATOMA) == 0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); pci_pci_problems |= PCIPCI_NATOMA; } @@ -315,8 +315,7 @@ static void quirk_cs5536_vsa(struct pci_dev *dev) if (pci_resource_len(dev, 0) != 8) { struct resource *res = &dev->resource[0]; res->end = res->start + 8 - 1; - dev_info(&dev->dev, "CS5536 ISA bridge bug detected " - "(incorrect header); workaround applied.\n"); + dev_info(&dev->dev, "CS5536 ISA bridge bug detected (incorrect header); workaround applied\n"); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa); @@ -400,7 +399,8 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p * let's get enough confirmation reports first. */ base &= -size; - dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1); + dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, + base + size - 1); } static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable) @@ -425,7 +425,8 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int * reserve it, but let's get enough confirmation reports first. */ base &= -size; - dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1); + dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, + base + size - 1); } /* @@ -668,8 +669,7 @@ static void quirk_xio2000a(struct pci_dev *dev) struct pci_dev *pdev; u16 command; - dev_warn(&dev->dev, "TI XIO2000a quirk detected; " - "secondary bus fast back-to-back transfers disabled\n"); + dev_warn(&dev->dev, "TI XIO2000a quirk detected; secondary bus fast back-to-back transfers disabled\n"); list_for_each_entry(pdev, &dev->subordinate->devices, bus_list) { pci_read_config_word(pdev, PCI_COMMAND, &command); if (command & PCI_COMMAND_FAST_BACK) @@ -703,7 +703,7 @@ static void quirk_via_ioapic(struct pci_dev *dev) tmp == 0 ? "Disa" : "Ena"); /* Offset 0x58: External APIC IRQ output control */ - pci_write_config_byte (dev, 0x58, tmp); + pci_write_config_byte(dev, 0x58, tmp); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic); @@ -761,8 +761,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw); static void quirk_amd_8131_mmrbc(struct pci_dev *dev) { if (dev->subordinate && dev->revision <= 0x12) { - dev_info(&dev->dev, "AMD8131 rev %x detected; " - "disabling PCI-X MMRBC\n", dev->revision); + dev_info(&dev->dev, "AMD8131 rev %x detected; disabling PCI-X MMRBC\n", + dev->revision); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC; } } @@ -916,12 +916,12 @@ static void quirk_amd_ordering(struct pci_dev *dev) { u32 pcic; pci_read_config_dword(dev, 0x4C, &pcic); - if ((pcic&6)!=6) { + if ((pcic & 6) != 6) { pcic |= 6; dev_warn(&dev->dev, "BIOS failed to enable PCI standards compliance; fixing this error\n"); pci_write_config_dword(dev, 0x4C, pcic); pci_read_config_dword(dev, 0x84, &pcic); - pcic |= (1<<23); /* Required in this mode */ + pcic |= (1 << 23); /* Required in this mode */ pci_write_config_dword(dev, 0x84, pcic); } } @@ -937,7 +937,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C */ static void quirk_dunord(struct pci_dev *dev) { - struct resource *r = &dev->resource [1]; + struct resource *r = &dev->resource[1]; r->flags |= IORESOURCE_UNSET; r->start = 0; @@ -967,11 +967,13 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge) static void quirk_mediagx_master(struct pci_dev *dev) { u8 reg; + pci_read_config_byte(dev, 0x41, ®); if (reg & 2) { reg &= ~2; - dev_info(&dev->dev, "Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg); - pci_write_config_byte(dev, 0x41, reg); + dev_info(&dev->dev, "Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", + reg); + pci_write_config_byte(dev, 0x41, reg); } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master); @@ -1120,7 +1122,7 @@ static void asus_hides_smbus_hostbridge(struct pci_dev *dev) { if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB) - switch(dev->subsystem_device) { + switch (dev->subsystem_device) { case 0x8025: /* P4B-LX */ case 0x8070: /* P4B */ case 0x8088: /* P4B533 */ @@ -1128,14 +1130,14 @@ static void asus_hides_smbus_hostbridge(struct pci_dev *dev) asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) - switch(dev->subsystem_device) { + switch (dev->subsystem_device) { case 0x80b1: /* P4GE-V */ case 0x80b2: /* P4PE */ case 0x8093: /* P4B533-V */ asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB) - switch(dev->subsystem_device) { + switch (dev->subsystem_device) { case 0x8030: /* P4T533 */ asus_hides_smbus = 1; } @@ -1175,7 +1177,7 @@ static void asus_hides_smbus_hostbridge(struct pci_dev *dev) } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) - switch(dev->subsystem_device) { + switch (dev->subsystem_device) { case 0x088C: /* HP Compaq nc8000 */ case 0x0890: /* HP Compaq nc6000 */ asus_hides_smbus = 1; @@ -1192,20 +1194,20 @@ static void asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x12bf: /* HP xw4100 */ asus_hides_smbus = 1; } - } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) { - if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) - switch(dev->subsystem_device) { - case 0xC00C: /* Samsung P35 notebook */ - asus_hides_smbus = 1; - } + } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) { + if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) + switch (dev->subsystem_device) { + case 0xC00C: /* Samsung P35 notebook */ + asus_hides_smbus = 1; + } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) - switch(dev->subsystem_device) { + switch (dev->subsystem_device) { case 0x0058: /* Compaq Evo N620c */ asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82810_IG3) - switch(dev->subsystem_device) { + switch (dev->subsystem_device) { case 0xB16C: /* Compaq Deskpro EP 401963-001 (PCA# 010174) */ /* Motherboard doesn't have Host bridge * subvendor/subdevice IDs, therefore checking @@ -1213,7 +1215,7 @@ static void asus_hides_smbus_hostbridge(struct pci_dev *dev) asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_2) - switch(dev->subsystem_device) { + switch (dev->subsystem_device) { case 0x00b8: /* Compaq Evo D510 CMT */ case 0x00b9: /* Compaq Evo D510 SFF */ case 0x00ba: /* Compaq Evo D510 USDT */ @@ -1261,7 +1263,8 @@ static void asus_hides_smbus_lpc(struct pci_dev *dev) pci_write_config_word(dev, 0xF2, val & (~0x8)); pci_read_config_word(dev, 0xF2, &val); if (val & 0x8) - dev_info(&dev->dev, "i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val); + dev_info(&dev->dev, "i801 SMBus device continues to play 'hide and seek'! 0x%x\n", + val); else dev_info(&dev->dev, "Enabled i801 SMBus device\n"); } @@ -1409,7 +1412,8 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev) pci_write_config_byte(dev, 0x50, val & (~0xc0)); pci_read_config_byte(dev, 0x50, &val); if (val & 0xc0) - dev_info(&dev->dev, "Onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val); + dev_info(&dev->dev, "Onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", + val); else dev_info(&dev->dev, "Enabled onboard AC97/MC97 devices\n"); } @@ -1514,10 +1518,8 @@ static void quirk_alder_ioapic(struct pci_dev *pdev) /* The next five BARs all seem to be rubbish, so just clean * them out */ - for (i=1; i < 6; i++) { + for (i = 1; i < 6; i++) memset(&pdev->resource[i], 0, sizeof(pdev->resource[i])); - } - } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic); #endif @@ -1552,7 +1554,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_pci * Some Intel PCI Express chipsets have trouble with downstream * device power management. */ -static void quirk_intel_pcie_pm(struct pci_dev * dev) +static void quirk_intel_pcie_pm(struct pci_dev *dev) { pci_pm_d3_delay = 120; dev->no_d1d2 = 1; @@ -1721,8 +1723,8 @@ static void quirk_disable_amd_8111_boot_interrupt(struct pci_dev *dev) pci_read_config_word(dev, AMD_8111_PCI_IRQ_ROUTING, &pci_config_word); if (!pci_config_word) { - dev_info(&dev->dev, "boot interrupts on device [%04x:%04x] " - "already disabled\n", dev->vendor, dev->device); + dev_info(&dev->dev, "boot interrupts on device [%04x:%04x] already disabled\n", + dev->vendor, dev->device); return; } pci_write_config_word(dev, AMD_8111_PCI_IRQ_ROUTING, 0); @@ -1770,8 +1772,7 @@ static void quirk_plx_pci9050(struct pci_dev *dev) if (pci_resource_len(dev, bar) == 0x80 && (pci_resource_start(dev, bar) & 0x80)) { struct resource *r = &dev->resource[bar]; - dev_info(&dev->dev, - "Re-allocating PLX PCI 9050 BAR %u to length 256 to avoid bit 7 bug\n", + dev_info(&dev->dev, "Re-allocating PLX PCI 9050 BAR %u to length 256 to avoid bit 7 bug\n", bar); r->flags |= IORESOURCE_UNSET; r->start = 0; @@ -1818,9 +1819,7 @@ static void quirk_netmos(struct pci_dev *dev) case PCI_DEVICE_ID_NETMOS_9845: case PCI_DEVICE_ID_NETMOS_9855: if (num_parallel) { - dev_info(&dev->dev, "Netmos %04x (%u parallel, " - "%u serial); changing class SERIAL to OTHER " - "(use parport_serial)\n", + dev_info(&dev->dev, "Netmos %04x (%u parallel, %u serial); changing class SERIAL to OTHER (use parport_serial)\n", dev->device, num_parallel, num_serial); dev->class = (PCI_CLASS_COMMUNICATION_OTHER << 8) | (dev->class & 0xff); @@ -1887,8 +1886,7 @@ static void quirk_e100_interrupt(struct pci_dev *dev) cmd_hi = readb(csr + 3); if (cmd_hi == 0) { - dev_warn(&dev->dev, "Firmware left e100 interrupts enabled; " - "disabling\n"); + dev_warn(&dev->dev, "Firmware left e100 interrupts enabled; disabling\n"); writeb(1, csr + 3); } @@ -1958,8 +1956,7 @@ static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) if (pci_read_config_byte(dev, 0xf41, &b) == 0) { if (!(b & 0x20)) { pci_write_config_byte(dev, 0xf41, b | 0x20); - dev_info(&dev->dev, - "Linking AER extended capability\n"); + dev_info(&dev->dev, "Linking AER extended capability\n"); } } } @@ -1997,8 +1994,7 @@ static void quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) /* Turn off PCI Bus Parking */ pci_write_config_byte(dev, 0x76, b ^ 0x40); - dev_info(&dev->dev, - "Disabling VIA CX700 PCI parking\n"); + dev_info(&dev->dev, "Disabling VIA CX700 PCI parking\n"); } } @@ -2013,8 +2009,7 @@ static void quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) /* Disable "Read FIFO Timer" */ pci_write_config_byte(dev, 0x77, 0x0); - dev_info(&dev->dev, - "Disabling VIA CX700 PCI caching\n"); + dev_info(&dev->dev, "Disabling VIA CX700 PCI caching\n"); } } } @@ -2149,8 +2144,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disab static void quirk_disable_msi(struct pci_dev *dev) { if (dev->subordinate) { - dev_warn(&dev->dev, "MSI quirk detected; " - "subordinate MSI disabled\n"); + dev_warn(&dev->dev, "MSI quirk detected; subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } } @@ -2189,8 +2183,7 @@ static int msi_ht_cap_enabled(struct pci_dev *dev) u8 flags; if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, - &flags) == 0) - { + &flags) == 0) { dev_info(&dev->dev, "Found %s HT MSI Mapping\n", flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled"); @@ -2207,8 +2200,7 @@ static int msi_ht_cap_enabled(struct pci_dev *dev) static void quirk_msi_ht_cap(struct pci_dev *dev) { if (dev->subordinate && !msi_ht_cap_enabled(dev)) { - dev_warn(&dev->dev, "MSI quirk detected; " - "subordinate MSI disabled\n"); + dev_warn(&dev->dev, "MSI quirk detected; subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } } @@ -2232,8 +2224,7 @@ static void quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) if (!pdev) return; if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) { - dev_warn(&dev->dev, "MSI quirk detected; " - "subordinate MSI disabled\n"); + dev_warn(&dev->dev, "MSI quirk detected; subordinate MSI disabled\n"); dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; } pci_dev_put(pdev); @@ -2279,8 +2270,7 @@ static void nvenet_msi_disable(struct pci_dev *dev) if (board_name && (strstr(board_name, "P5N32-SLI PREMIUM") || strstr(board_name, "P5N32-E SLI"))) { - dev_info(&dev->dev, - "Disabling msi for MCP55 NIC on P5N32-SLI\n"); + dev_info(&dev->dev, "Disabling msi for MCP55 NIC on P5N32-SLI\n"); dev->no_msi = 1; } } @@ -2489,8 +2479,7 @@ static void __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all) */ host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); if (host_bridge == NULL) { - dev_warn(&dev->dev, - "nv_msi_ht_cap_quirk didn't locate host bridge\n"); + dev_warn(&dev->dev, "nv_msi_ht_cap_quirk didn't locate host bridge\n"); return; } @@ -2817,8 +2806,7 @@ static void quirk_intel_mc_errata(struct pci_dev *dev) */ err = pci_read_config_word(dev, 0x48, &rcc); if (err) { - dev_err(&dev->dev, "Error attempting to read the read " - "completion coalescing register.\n"); + dev_err(&dev->dev, "Error attempting to read the read completion coalescing register\n"); return; } @@ -2829,13 +2817,11 @@ static void quirk_intel_mc_errata(struct pci_dev *dev) err = pci_write_config_word(dev, 0x48, rcc); if (err) { - dev_err(&dev->dev, "Error attempting to write the read " - "completion coalescing register.\n"); + dev_err(&dev->dev, "Error attempting to write the read completion coalescing register\n"); return; } - pr_info_once("Read completion coalescing disabled due to hardware " - "errata relating to 256B MPS.\n"); + pr_info_once("Read completion coalescing disabled due to hardware errata relating to 256B MPS\n"); } /* Intel 5000 series memory controllers and ports 2-7 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x25c0, quirk_intel_mc_errata); @@ -2944,8 +2930,7 @@ static void disable_igfx_irq(struct pci_dev *dev) /* Check if any interrupt line is still enabled */ if (readl(regs + I915_DEIER_REG) != 0) { - dev_warn(&dev->dev, "BIOS left Intel GPU interrupts enabled; " - "disabling\n"); + dev_warn(&dev->dev, "BIOS left Intel GPU interrupts enabled; disabling\n"); writel(0, regs + I915_DEIER_REG); } @@ -2954,6 +2939,7 @@ static void disable_igfx_irq(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); /* * PCI devices which are on Intel chips can skip the 10ms delay @@ -2991,6 +2977,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, 0x0030, quirk_broken_intx_masking); DECLARE_PCI_FIXUP_HEADER(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */ quirk_broken_intx_masking); +/* + * Realtek RTL8169 PCI Gigabit Ethernet Controller (rev 10) + * Subsystem: Realtek RTL8169/8110 Family PCI Gigabit Ethernet NIC + * + * RTL8110SC - Fails under PCI device assignment using DisINTx masking. + */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169, + quirk_broken_intx_masking); static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) @@ -3031,7 +3025,7 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) { struct pci_fixup *start, *end; - switch(pass) { + switch (pass) { case pci_fixup_early: start = __start_pci_fixups_early; end = __end_pci_fixups_early; @@ -3103,8 +3097,8 @@ static int __init pci_apply_final_quirks(void) if (!tmp || cls == tmp) continue; - printk(KERN_DEBUG "PCI: CLS mismatch (%u != %u), " - "using %u bytes\n", cls << 2, tmp << 2, + printk(KERN_DEBUG "PCI: CLS mismatch (%u != %u), using %u bytes\n", + cls << 2, tmp << 2, pci_dfl_cache_line_size << 2); pci_cache_line_size = pci_dfl_cache_line_size; } @@ -3333,6 +3327,85 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe) return -ENOTTY; } +static void quirk_dma_func0_alias(struct pci_dev *dev) +{ + if (PCI_FUNC(dev->devfn) != 0) { + dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0); + dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + } +} + +/* + * https://bugzilla.redhat.com/show_bug.cgi?id=605888 + * + * Some Ricoh devices use function 0 as the PCIe requester ID for DMA. + */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe832, quirk_dma_func0_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe476, quirk_dma_func0_alias); + +static void quirk_dma_func1_alias(struct pci_dev *dev) +{ + if (PCI_FUNC(dev->devfn) != 1) { + dev->dma_alias_devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 1); + dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + } +} + +/* + * Marvell 88SE9123 uses function 1 as the requester ID for DMA. In some + * SKUs function 1 is present and is a legacy IDE controller, in other + * SKUs this function is not present, making this a ghost requester. + * https://bugzilla.kernel.org/show_bug.cgi?id=42679 + */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9123, + quirk_dma_func1_alias); +/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9130, + quirk_dma_func1_alias); +/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c47 + c57 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9172, + quirk_dma_func1_alias); +/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c59 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x917a, + quirk_dma_func1_alias); +/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0, + quirk_dma_func1_alias); +/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c49 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230, + quirk_dma_func1_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0642, + quirk_dma_func1_alias); +/* https://bugs.gentoo.org/show_bug.cgi?id=497630 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON, + PCI_DEVICE_ID_JMICRON_JMB388_ESD, + quirk_dma_func1_alias); + +/* + * A few PCIe-to-PCI bridges fail to expose a PCIe capability, resulting in + * using the wrong DMA alias for the device. Some of these devices can be + * used as either forward or reverse bridges, so we need to test whether the + * device is operating in the correct mode. We could probably apply this + * quirk to PCI_ANY_ID, but for now we'll just use known offenders. The test + * is for a non-root, non-PCIe bridge where the upstream device is PCIe and + * is not a PCIe-to-PCI bridge, then @pdev is actually a PCIe-to-PCI bridge. + */ +static void quirk_use_pcie_bridge_dma_alias(struct pci_dev *pdev) +{ + if (!pci_is_root_bus(pdev->bus) && + pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE && + !pci_is_pcie(pdev) && pci_is_pcie(pdev->bus->self) && + pci_pcie_type(pdev->bus->self) != PCI_EXP_TYPE_PCI_BRIDGE) + pdev->dev_flags |= PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS; +} +/* ASM1083/1085, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c46 */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ASMEDIA, 0x1080, + quirk_use_pcie_bridge_dma_alias); +/* Tundra 8113, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c43 */ +DECLARE_PCI_FIXUP_HEADER(0x10e3, 0x8113, quirk_use_pcie_bridge_dma_alias); +/* ITE 8892, https://bugzilla.kernel.org/show_bug.cgi?id=73551 */ +DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); + static struct pci_dev *pci_func_0_dma_source(struct pci_dev *dev) { if (!PCI_FUNC(dev->devfn)) @@ -3428,6 +3501,63 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags) #endif } +/* + * Many Intel PCH root ports do provide ACS-like features to disable peer + * transactions and validate bus numbers in requests, but do not provide an + * actual PCIe ACS capability. This is the list of device IDs known to fall + * into that category as provided by Intel in Red Hat bugzilla 1037684. + */ +static const u16 pci_quirk_intel_pch_acs_ids[] = { + /* Ibexpeak PCH */ + 0x3b42, 0x3b43, 0x3b44, 0x3b45, 0x3b46, 0x3b47, 0x3b48, 0x3b49, + 0x3b4a, 0x3b4b, 0x3b4c, 0x3b4d, 0x3b4e, 0x3b4f, 0x3b50, 0x3b51, + /* Cougarpoint PCH */ + 0x1c10, 0x1c11, 0x1c12, 0x1c13, 0x1c14, 0x1c15, 0x1c16, 0x1c17, + 0x1c18, 0x1c19, 0x1c1a, 0x1c1b, 0x1c1c, 0x1c1d, 0x1c1e, 0x1c1f, + /* Pantherpoint PCH */ + 0x1e10, 0x1e11, 0x1e12, 0x1e13, 0x1e14, 0x1e15, 0x1e16, 0x1e17, + 0x1e18, 0x1e19, 0x1e1a, 0x1e1b, 0x1e1c, 0x1e1d, 0x1e1e, 0x1e1f, + /* Lynxpoint-H PCH */ + 0x8c10, 0x8c11, 0x8c12, 0x8c13, 0x8c14, 0x8c15, 0x8c16, 0x8c17, + 0x8c18, 0x8c19, 0x8c1a, 0x8c1b, 0x8c1c, 0x8c1d, 0x8c1e, 0x8c1f, + /* Lynxpoint-LP PCH */ + 0x9c10, 0x9c11, 0x9c12, 0x9c13, 0x9c14, 0x9c15, 0x9c16, 0x9c17, + 0x9c18, 0x9c19, 0x9c1a, 0x9c1b, + /* Wildcat PCH */ + 0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97, + 0x9c98, 0x9c99, 0x9c9a, 0x9c9b, + /* Patsburg (X79) PCH */ + 0x1d10, 0x1d12, 0x1d14, 0x1d16, 0x1d18, 0x1d1a, 0x1d1c, 0x1d1e, +}; + +static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev) +{ + int i; + + /* Filter out a few obvious non-matches first */ + if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) + return false; + + for (i = 0; i < ARRAY_SIZE(pci_quirk_intel_pch_acs_ids); i++) + if (pci_quirk_intel_pch_acs_ids[i] == dev->device) + return true; + + return false; +} + +#define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV) + +static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags) +{ + u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ? + INTEL_PCH_ACS_FLAGS : 0; + + if (!pci_quirk_intel_pch_acs_match(dev)) + return -ENOTTY; + + return acs_flags & ~flags ? 0 : 1; +} + static const struct pci_dev_acs_enabled { u16 vendor; u16 device; @@ -3439,6 +3569,7 @@ static const struct pci_dev_acs_enabled { { PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs }, { PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs }, { PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs }, + { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs }, { 0 } }; @@ -3466,3 +3597,132 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) return -ENOTTY; } + +/* Config space offset of Root Complex Base Address register */ +#define INTEL_LPC_RCBA_REG 0xf0 +/* 31:14 RCBA address */ +#define INTEL_LPC_RCBA_MASK 0xffffc000 +/* RCBA Enable */ +#define INTEL_LPC_RCBA_ENABLE (1 << 0) + +/* Backbone Scratch Pad Register */ +#define INTEL_BSPR_REG 0x1104 +/* Backbone Peer Non-Posted Disable */ +#define INTEL_BSPR_REG_BPNPD (1 << 8) +/* Backbone Peer Posted Disable */ +#define INTEL_BSPR_REG_BPPD (1 << 9) + +/* Upstream Peer Decode Configuration Register */ +#define INTEL_UPDCR_REG 0x1114 +/* 5:0 Peer Decode Enable bits */ +#define INTEL_UPDCR_REG_MASK 0x3f + +static int pci_quirk_enable_intel_lpc_acs(struct pci_dev *dev) +{ + u32 rcba, bspr, updcr; + void __iomem *rcba_mem; + + /* + * Read the RCBA register from the LPC (D31:F0). PCH root ports + * are D28:F* and therefore get probed before LPC, thus we can't + * use pci_get_slot/pci_read_config_dword here. + */ + pci_bus_read_config_dword(dev->bus, PCI_DEVFN(31, 0), + INTEL_LPC_RCBA_REG, &rcba); + if (!(rcba & INTEL_LPC_RCBA_ENABLE)) + return -EINVAL; + + rcba_mem = ioremap_nocache(rcba & INTEL_LPC_RCBA_MASK, + PAGE_ALIGN(INTEL_UPDCR_REG)); + if (!rcba_mem) + return -ENOMEM; + + /* + * The BSPR can disallow peer cycles, but it's set by soft strap and + * therefore read-only. If both posted and non-posted peer cycles are + * disallowed, we're ok. If either are allowed, then we need to use + * the UPDCR to disable peer decodes for each port. This provides the + * PCIe ACS equivalent of PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF + */ + bspr = readl(rcba_mem + INTEL_BSPR_REG); + bspr &= INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD; + if (bspr != (INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD)) { + updcr = readl(rcba_mem + INTEL_UPDCR_REG); + if (updcr & INTEL_UPDCR_REG_MASK) { + dev_info(&dev->dev, "Disabling UPDCR peer decodes\n"); + updcr &= ~INTEL_UPDCR_REG_MASK; + writel(updcr, rcba_mem + INTEL_UPDCR_REG); + } + } + + iounmap(rcba_mem); + return 0; +} + +/* Miscellaneous Port Configuration register */ +#define INTEL_MPC_REG 0xd8 +/* MPC: Invalid Receive Bus Number Check Enable */ +#define INTEL_MPC_REG_IRBNCE (1 << 26) + +static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev) +{ + u32 mpc; + + /* + * When enabled, the IRBNCE bit of the MPC register enables the + * equivalent of PCI ACS Source Validation (PCI_ACS_SV), which + * ensures that requester IDs fall within the bus number range + * of the bridge. Enable if not already. + */ + pci_read_config_dword(dev, INTEL_MPC_REG, &mpc); + if (!(mpc & INTEL_MPC_REG_IRBNCE)) { + dev_info(&dev->dev, "Enabling MPC IRBNCE\n"); + mpc |= INTEL_MPC_REG_IRBNCE; + pci_write_config_word(dev, INTEL_MPC_REG, mpc); + } +} + +static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev) +{ + if (!pci_quirk_intel_pch_acs_match(dev)) + return -ENOTTY; + + if (pci_quirk_enable_intel_lpc_acs(dev)) { + dev_warn(&dev->dev, "Failed to enable Intel PCH ACS quirk\n"); + return 0; + } + + pci_quirk_enable_intel_rp_mpc_acs(dev); + + dev->dev_flags |= PCI_DEV_FLAGS_ACS_ENABLED_QUIRK; + + dev_info(&dev->dev, "Intel PCH root port ACS workaround enabled\n"); + + return 0; +} + +static const struct pci_dev_enable_acs { + u16 vendor; + u16 device; + int (*enable_acs)(struct pci_dev *dev); +} pci_dev_enable_acs[] = { + { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs }, + { 0 } +}; + +void pci_dev_specific_enable_acs(struct pci_dev *dev) +{ + const struct pci_dev_enable_acs *i; + int ret; + + for (i = pci_dev_enable_acs; i->enable_acs; i++) { + if ((i->vendor == dev->vendor || + i->vendor == (u16)PCI_ANY_ID) && + (i->device == dev->device || + i->device == (u16)PCI_ANY_ID)) { + ret = i->enable_acs(dev); + if (ret >= 0) + return; + } + } +} diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index c1839450d4d..f955edb9bea 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -38,6 +38,7 @@ int pci_enable_rom(struct pci_dev *pdev) pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); return 0; } +EXPORT_SYMBOL_GPL(pci_enable_rom); /** * pci_disable_rom - disable ROM decoding for a PCI device @@ -53,6 +54,7 @@ void pci_disable_rom(struct pci_dev *pdev) rom_addr &= ~PCI_ROM_ADDRESS_ENABLE; pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); } +EXPORT_SYMBOL_GPL(pci_disable_rom); /** * pci_get_rom_size - obtain the actual size of the ROM image @@ -135,7 +137,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) } else { /* assign the ROM an address if it doesn't have one */ if (res->parent == NULL && - pci_assign_resource(pdev,PCI_ROM_RESOURCE)) + pci_assign_resource(pdev, PCI_ROM_RESOURCE)) return NULL; start = pci_resource_start(pdev, PCI_ROM_RESOURCE); *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); @@ -166,6 +168,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) *size = pci_get_rom_size(pdev, rom, *size); return rom; } +EXPORT_SYMBOL(pci_map_rom); /** * pci_unmap_rom - unmap the ROM from kernel space @@ -187,6 +190,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) pci_disable_rom(pdev); } +EXPORT_SYMBOL(pci_unmap_rom); /** * pci_cleanup_rom - free the ROM copy created by pci_map_rom_copy @@ -199,7 +203,7 @@ void pci_cleanup_rom(struct pci_dev *pdev) struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; if (res->flags & IORESOURCE_ROM_COPY) { - kfree((void*)(unsigned long)res->start); + kfree((void *)(unsigned long)res->start); res->flags |= IORESOURCE_UNSET; res->flags &= ~IORESOURCE_ROM_COPY; res->start = 0; @@ -222,9 +226,4 @@ void __iomem *pci_platform_rom(struct pci_dev *pdev, size_t *size) return NULL; } - -EXPORT_SYMBOL(pci_map_rom); -EXPORT_SYMBOL(pci_unmap_rom); -EXPORT_SYMBOL_GPL(pci_enable_rom); -EXPORT_SYMBOL_GPL(pci_disable_rom); EXPORT_SYMBOL(pci_platform_rom); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 3ff2ac7c14e..827ad831f1d 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -7,7 +7,6 @@ * Copyright (C) 2003 -- 2004 Greg Kroah-Hartman <greg@kroah.com> */ -#include <linux/init.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/module.h> @@ -18,14 +17,100 @@ DECLARE_RWSEM(pci_bus_sem); EXPORT_SYMBOL_GPL(pci_bus_sem); /* + * pci_for_each_dma_alias - Iterate over DMA aliases for a device + * @pdev: starting downstream device + * @fn: function to call for each alias + * @data: opaque data to pass to @fn + * + * Starting @pdev, walk up the bus calling @fn for each possible alias + * of @pdev at the root bus. + */ +int pci_for_each_dma_alias(struct pci_dev *pdev, + int (*fn)(struct pci_dev *pdev, + u16 alias, void *data), void *data) +{ + struct pci_bus *bus; + int ret; + + ret = fn(pdev, PCI_DEVID(pdev->bus->number, pdev->devfn), data); + if (ret) + return ret; + + /* + * If the device is broken and uses an alias requester ID for + * DMA, iterate over that too. + */ + if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) { + ret = fn(pdev, PCI_DEVID(pdev->bus->number, + pdev->dma_alias_devfn), data); + if (ret) + return ret; + } + + for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) { + struct pci_dev *tmp; + + /* Skip virtual buses */ + if (!bus->self) + continue; + + tmp = bus->self; + + /* + * PCIe-to-PCI/X bridges alias transactions from downstream + * devices using the subordinate bus number (PCI Express to + * PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3). For all cases + * where the upstream bus is PCI/X we alias to the bridge + * (there are various conditions in the previous reference + * where the bridge may take ownership of transactions, even + * when the secondary interface is PCI-X). + */ + if (pci_is_pcie(tmp)) { + switch (pci_pcie_type(tmp)) { + case PCI_EXP_TYPE_ROOT_PORT: + case PCI_EXP_TYPE_UPSTREAM: + case PCI_EXP_TYPE_DOWNSTREAM: + continue; + case PCI_EXP_TYPE_PCI_BRIDGE: + ret = fn(tmp, + PCI_DEVID(tmp->subordinate->number, + PCI_DEVFN(0, 0)), data); + if (ret) + return ret; + continue; + case PCI_EXP_TYPE_PCIE_BRIDGE: + ret = fn(tmp, + PCI_DEVID(tmp->bus->number, + tmp->devfn), data); + if (ret) + return ret; + continue; + } + } else { + if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS) + ret = fn(tmp, + PCI_DEVID(tmp->subordinate->number, + PCI_DEVFN(0, 0)), data); + else + ret = fn(tmp, + PCI_DEVID(tmp->bus->number, + tmp->devfn), data); + if (ret) + return ret; + } + } + + return ret; +} + +/* * find the upstream PCIe-to-PCI bridge of a PCI device * if the device is PCIE, return NULL * if the device isn't connected to a PCIe bridge (that is its parent is a * legacy PCI bridge and the bridge is directly connected to bus 0), return its * parent */ -struct pci_dev * -pci_find_upstream_pcie_bridge(struct pci_dev *pdev) +struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev) { struct pci_dev *tmp = NULL; @@ -54,15 +139,15 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev) static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) { - struct pci_bus* child; - struct list_head *tmp; + struct pci_bus *child; + struct pci_bus *tmp; - if(bus->number == busnr) + if (bus->number == busnr) return bus; - list_for_each(tmp, &bus->children) { - child = pci_do_find_bus(pci_bus_b(tmp), busnr); - if(child) + list_for_each_entry(tmp, &bus->children, node) { + child = pci_do_find_bus(tmp, busnr); + if (child) return child; } return NULL; @@ -77,7 +162,7 @@ static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) * in the global list of PCI buses. If the bus is found, a pointer to its * data structure is returned. If no bus is found, %NULL is returned. */ -struct pci_bus * pci_find_bus(int domain, int busnr) +struct pci_bus *pci_find_bus(int domain, int busnr) { struct pci_bus *bus = NULL; struct pci_bus *tmp_bus; @@ -91,6 +176,7 @@ struct pci_bus * pci_find_bus(int domain, int busnr) } return NULL; } +EXPORT_SYMBOL(pci_find_bus); /** * pci_find_next_bus - begin or continue searching for a PCI bus @@ -101,8 +187,7 @@ struct pci_bus * pci_find_bus(int domain, int busnr) * @from is not %NULL, searches continue from next device on the * global list. */ -struct pci_bus * -pci_find_next_bus(const struct pci_bus *from) +struct pci_bus *pci_find_next_bus(const struct pci_bus *from) { struct list_head *n; struct pci_bus *b = NULL; @@ -111,10 +196,11 @@ pci_find_next_bus(const struct pci_bus *from) down_read(&pci_bus_sem); n = from ? from->node.next : pci_root_buses.next; if (n != &pci_root_buses) - b = pci_bus_b(n); + b = list_entry(n, struct pci_bus, node); up_read(&pci_bus_sem); return b; } +EXPORT_SYMBOL(pci_find_next_bus); /** * pci_get_slot - locate PCI device for a given PCI slot @@ -148,6 +234,7 @@ struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn) up_read(&pci_bus_sem); return dev; } +EXPORT_SYMBOL(pci_get_slot); /** * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot @@ -252,6 +339,7 @@ struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, return pci_get_dev_by_id(&id, from); } +EXPORT_SYMBOL(pci_get_subsys); /** * pci_get_device - begin or continue searching for a PCI device by vendor/device id @@ -267,11 +355,12 @@ struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, * from next device on the global list. The reference count for @from is * always decremented if it is not %NULL. */ -struct pci_dev * -pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from) +struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, + struct pci_dev *from) { return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); } +EXPORT_SYMBOL(pci_get_device); /** * pci_get_class - begin or continue searching for a PCI device by class @@ -300,6 +389,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) return pci_get_dev_by_id(&id, from); } +EXPORT_SYMBOL(pci_get_class); /** * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not. @@ -329,12 +419,3 @@ int pci_dev_present(const struct pci_device_id *ids) return 0; } EXPORT_SYMBOL(pci_dev_present); - -/* For boot time work */ -EXPORT_SYMBOL(pci_find_bus); -EXPORT_SYMBOL(pci_find_next_bus); -/* For everyone */ -EXPORT_SYMBOL(pci_get_device); -EXPORT_SYMBOL(pci_get_subsys); -EXPORT_SYMBOL(pci_get_slot); -EXPORT_SYMBOL(pci_get_class); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 138bdd6393b..a5a63ecfb62 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -68,7 +68,7 @@ static int add_to_list(struct list_head *head, tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) { - pr_warning("add_to_list: kmalloc() failed!\n"); + pr_warn("add_to_list: kmalloc() failed!\n"); return -ENOMEM; } @@ -148,8 +148,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) - panic("pdev_sort_resources(): " - "kmalloc() failed!\n"); + panic("pdev_sort_resources(): kmalloc() failed!\n"); tmp->res = r; tmp->dev = dev; @@ -713,12 +712,11 @@ static void pci_bridge_check_ranges(struct pci_bus *bus) bus resource of a given type. Note: we intentionally skip the bus resources which have already been assigned (that is, have non-NULL parent resource). */ -static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type) +static struct resource *find_free_bus_resource(struct pci_bus *bus, + unsigned long type_mask, unsigned long type) { int i; struct resource *r; - unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | - IORESOURCE_PREFETCH; pci_bus_for_each_resource(bus, r, i) { if (r == &ioport_resource || r == &iomem_resource) @@ -737,7 +735,7 @@ static resource_size_t calculate_iosize(resource_size_t size, { if (size < min_size) size = min_size; - if (old_size == 1 ) + if (old_size == 1) old_size = 0; /* To be fixed in 2.5: we should have sort of HAVE_ISA flag in the struct pci_bus. */ @@ -758,7 +756,7 @@ static resource_size_t calculate_memsize(resource_size_t size, { if (size < min_size) size = min_size; - if (old_size == 1 ) + if (old_size == 1) old_size = 0; if (size < old_size) size = old_size; @@ -815,7 +813,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, resource_size_t add_size, struct list_head *realloc_head) { struct pci_dev *dev; - struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); + struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO, + IORESOURCE_IO); resource_size_t size = 0, size0 = 0, size1 = 0; resource_size_t children_add_size = 0; resource_size_t min_align, align; @@ -859,9 +858,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, resource_size(b_res), min_align); if (!size0 && !size1) { if (b_res->start || b_res->end) - dev_info(&bus->self->dev, "disabling bridge window " - "%pR to %pR (unused)\n", b_res, - &bus->busn_res); + dev_info(&bus->self->dev, "disabling bridge window %pR to %pR (unused)\n", + b_res, &bus->busn_res); b_res->flags = 0; return; } @@ -872,10 +870,9 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, if (size1 > size0 && realloc_head) { add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); - dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " - "%pR to %pR add_size %llx\n", b_res, - &bus->busn_res, - (unsigned long long)size1-size0); + dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window %pR to %pR add_size %llx\n", + b_res, &bus->busn_res, + (unsigned long long)size1-size0); } } @@ -907,36 +904,40 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns, * @bus : the bus * @mask: mask the resource flag, then compare it with type * @type: the type of free resource from bridge + * @type2: second match type + * @type3: third match type * @min_size : the minimum memory window that must to be allocated * @add_size : additional optional memory window * @realloc_head : track the additional memory window on this list * * Calculate the size of the bus and minimal alignment which * guarantees that all child resources fit in this size. + * + * Returns -ENOSPC if there's no available bus resource of the desired type. + * Otherwise, sets the bus resource start/end to indicate the required + * size, adds things to realloc_head (if supplied), and returns 0. */ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, - unsigned long type, resource_size_t min_size, - resource_size_t add_size, - struct list_head *realloc_head) + unsigned long type, unsigned long type2, + unsigned long type3, + resource_size_t min_size, resource_size_t add_size, + struct list_head *realloc_head) { struct pci_dev *dev; resource_size_t min_align, align, size, size0, size1; - resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */ + resource_size_t aligns[14]; /* Alignments from 1Mb to 8Gb */ int order, max_order; - struct resource *b_res = find_free_bus_resource(bus, type); - unsigned int mem64_mask = 0; + struct resource *b_res = find_free_bus_resource(bus, + mask | IORESOURCE_PREFETCH, type); resource_size_t children_add_size = 0; if (!b_res) - return 0; + return -ENOSPC; memset(aligns, 0, sizeof(aligns)); max_order = 0; size = 0; - mem64_mask = b_res->flags & IORESOURCE_MEM_64; - b_res->flags &= ~IORESOURCE_MEM_64; - list_for_each_entry(dev, &bus->devices, bus_list) { int i; @@ -944,7 +945,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, struct resource *r = &dev->resource[i]; resource_size_t r_size; - if (r->parent || (r->flags & mask) != type) + if (r->parent || ((r->flags & mask) != type && + (r->flags & mask) != type2 && + (r->flags & mask) != type3)) continue; r_size = resource_size(r); #ifdef CONFIG_PCI_IOV @@ -957,26 +960,29 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, continue; } #endif - /* For bridges size != alignment */ + /* + * aligns[0] is for 1MB (since bridge memory + * windows are always at least 1MB aligned), so + * keep "order" from being negative for smaller + * resources. + */ align = pci_resource_alignment(dev, r); order = __ffs(align) - 20; - if (order > 11) { - dev_warn(&dev->dev, "disabling BAR %d: %pR " - "(bad alignment %#llx)\n", i, r, - (unsigned long long) align); + if (order < 0) + order = 0; + if (order >= ARRAY_SIZE(aligns)) { + dev_warn(&dev->dev, "disabling BAR %d: %pR (bad alignment %#llx)\n", + i, r, (unsigned long long) align); r->flags = 0; continue; } size += r_size; - if (order < 0) - order = 0; /* Exclude ranges with size > align from calculation of the alignment. */ if (r_size == align) aligns[order] += align; if (order > max_order) max_order = order; - mem64_mask &= r->flags & IORESOURCE_MEM_64; if (realloc_head) children_add_size += get_res_add_size(realloc_head, r); @@ -993,22 +999,21 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, resource_size(b_res), min_align); if (!size0 && !size1) { if (b_res->start || b_res->end) - dev_info(&bus->self->dev, "disabling bridge window " - "%pR to %pR (unused)\n", b_res, - &bus->busn_res); + dev_info(&bus->self->dev, "disabling bridge window %pR to %pR (unused)\n", + b_res, &bus->busn_res); b_res->flags = 0; - return 1; + return 0; } b_res->start = min_align; b_res->end = size0 + min_align - 1; - b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; + b_res->flags |= IORESOURCE_STARTALIGN; if (size1 > size0 && realloc_head) { add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); - dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " - "%pR to %pR add_size %llx\n", b_res, - &bus->busn_res, (unsigned long long)size1-size0); + dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window %pR to %pR add_size %llx\n", + b_res, &bus->busn_res, + (unsigned long long)size1-size0); } - return 1; + return 0; } unsigned long pci_cardbus_resource_alignment(struct resource *res) @@ -1113,12 +1118,13 @@ handle_done: ; } -void __ref __pci_bus_size_bridges(struct pci_bus *bus, - struct list_head *realloc_head) +void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) { struct pci_dev *dev; - unsigned long mask, prefmask; + unsigned long mask, prefmask, type2 = 0, type3 = 0; resource_size_t additional_mem_size = 0, additional_io_size = 0; + struct resource *b_res; + int ret; list_for_each_entry(dev, &bus->devices, bus_list) { struct pci_bus *b = dev->subordinate; @@ -1152,41 +1158,93 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, additional_io_size = pci_hotplug_io_size; additional_mem_size = pci_hotplug_mem_size; } - /* - * Follow thru - */ + /* Fall through */ default: pbus_size_io(bus, realloc_head ? 0 : additional_io_size, additional_io_size, realloc_head); - /* If the bridge supports prefetchable range, size it - separately. If it doesn't, or its prefetchable window - has already been allocated by arch code, try - non-prefetchable range for both types of PCI memory - resources. */ + + /* + * If there's a 64-bit prefetchable MMIO window, compute + * the size required to put all 64-bit prefetchable + * resources in it. + */ + b_res = &bus->self->resource[PCI_BRIDGE_RESOURCES]; mask = IORESOURCE_MEM; prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; - if (pbus_size_mem(bus, prefmask, prefmask, + if (b_res[2].flags & IORESOURCE_MEM_64) { + prefmask |= IORESOURCE_MEM_64; + ret = pbus_size_mem(bus, prefmask, prefmask, + prefmask, prefmask, realloc_head ? 0 : additional_mem_size, - additional_mem_size, realloc_head)) - mask = prefmask; /* Success, size non-prefetch only. */ - else - additional_mem_size += additional_mem_size; - pbus_size_mem(bus, mask, IORESOURCE_MEM, + additional_mem_size, realloc_head); + + /* + * If successful, all non-prefetchable resources + * and any 32-bit prefetchable resources will go in + * the non-prefetchable window. + */ + if (ret == 0) { + mask = prefmask; + type2 = prefmask & ~IORESOURCE_MEM_64; + type3 = prefmask & ~IORESOURCE_PREFETCH; + } + } + + /* + * If there is no 64-bit prefetchable window, compute the + * size required to put all prefetchable resources in the + * 32-bit prefetchable window (if there is one). + */ + if (!type2) { + prefmask &= ~IORESOURCE_MEM_64; + ret = pbus_size_mem(bus, prefmask, prefmask, + prefmask, prefmask, + realloc_head ? 0 : additional_mem_size, + additional_mem_size, realloc_head); + + /* + * If successful, only non-prefetchable resources + * will go in the non-prefetchable window. + */ + if (ret == 0) + mask = prefmask; + else + additional_mem_size += additional_mem_size; + + type2 = type3 = IORESOURCE_MEM; + } + + /* + * Compute the size required to put everything else in the + * non-prefetchable window. This includes: + * + * - all non-prefetchable resources + * - 32-bit prefetchable resources if there's a 64-bit + * prefetchable window or no prefetchable window at all + * - 64-bit prefetchable resources if there's no + * prefetchable window at all + * + * Note that the strategy in __pci_assign_resource() must + * match that used here. Specifically, we cannot put a + * 32-bit prefetchable resource in a 64-bit prefetchable + * window. + */ + pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3, realloc_head ? 0 : additional_mem_size, additional_mem_size, realloc_head); break; } } -void __ref pci_bus_size_bridges(struct pci_bus *bus) +void pci_bus_size_bridges(struct pci_bus *bus) { __pci_bus_size_bridges(bus, NULL); } EXPORT_SYMBOL(pci_bus_size_bridges); -void __ref __pci_bus_assign_resources(const struct pci_bus *bus, - struct list_head *realloc_head, - struct list_head *fail_head) +void __pci_bus_assign_resources(const struct pci_bus *bus, + struct list_head *realloc_head, + struct list_head *fail_head) { struct pci_bus *b; struct pci_dev *dev; @@ -1211,22 +1269,22 @@ void __ref __pci_bus_assign_resources(const struct pci_bus *bus, break; default: - dev_info(&dev->dev, "not setting up bridge for bus " - "%04x:%02x\n", pci_domain_nr(b), b->number); + dev_info(&dev->dev, "not setting up bridge for bus %04x:%02x\n", + pci_domain_nr(b), b->number); break; } } } -void __ref pci_bus_assign_resources(const struct pci_bus *bus) +void pci_bus_assign_resources(const struct pci_bus *bus) { __pci_bus_assign_resources(bus, NULL, NULL); } EXPORT_SYMBOL(pci_bus_assign_resources); -static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, - struct list_head *add_head, - struct list_head *fail_head) +static void __pci_bridge_assign_resources(const struct pci_dev *bridge, + struct list_head *add_head, + struct list_head *fail_head) { struct pci_bus *b; @@ -1249,50 +1307,74 @@ static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, break; default: - dev_info(&bridge->dev, "not setting up bridge for bus " - "%04x:%02x\n", pci_domain_nr(b), b->number); + dev_info(&bridge->dev, "not setting up bridge for bus %04x:%02x\n", + pci_domain_nr(b), b->number); break; } } static void pci_bridge_release_resources(struct pci_bus *bus, unsigned long type) { - int idx; - bool changed = false; - struct pci_dev *dev; + struct pci_dev *dev = bus->self; struct resource *r; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | - IORESOURCE_PREFETCH; + IORESOURCE_PREFETCH | IORESOURCE_MEM_64; + unsigned old_flags = 0; + struct resource *b_res; + int idx = 1; - dev = bus->self; - for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END; - idx++) { - r = &dev->resource[idx]; - if ((r->flags & type_mask) != type) - continue; - if (!r->parent) - continue; - /* - * if there are children under that, we should release them - * all - */ - release_child_resources(r); - if (!release_resource(r)) { - dev_printk(KERN_DEBUG, &dev->dev, - "resource %d %pR released\n", idx, r); - /* keep the old size */ - r->end = resource_size(r) - 1; - r->start = 0; - r->flags = 0; - changed = true; - } - } + b_res = &dev->resource[PCI_BRIDGE_RESOURCES]; + + /* + * 1. if there is io port assign fail, will release bridge + * io port. + * 2. if there is non pref mmio assign fail, release bridge + * nonpref mmio. + * 3. if there is 64bit pref mmio assign fail, and bridge pref + * is 64bit, release bridge pref mmio. + * 4. if there is pref mmio assign fail, and bridge pref is + * 32bit mmio, release bridge pref mmio + * 5. if there is pref mmio assign fail, and bridge pref is not + * assigned, release bridge nonpref mmio. + */ + if (type & IORESOURCE_IO) + idx = 0; + else if (!(type & IORESOURCE_PREFETCH)) + idx = 1; + else if ((type & IORESOURCE_MEM_64) && + (b_res[2].flags & IORESOURCE_MEM_64)) + idx = 2; + else if (!(b_res[2].flags & IORESOURCE_MEM_64) && + (b_res[2].flags & IORESOURCE_PREFETCH)) + idx = 2; + else + idx = 1; + + r = &b_res[idx]; + + if (!r->parent) + return; + + /* + * if there are children under that, we should release them + * all + */ + release_child_resources(r); + if (!release_resource(r)) { + type = old_flags = r->flags & type_mask; + dev_printk(KERN_DEBUG, &dev->dev, "resource %d %pR released\n", + PCI_BRIDGE_RESOURCES + idx, r); + /* keep the old size */ + r->end = resource_size(r) - 1; + r->start = 0; + r->flags = 0; - if (changed) { /* avoiding touch the one without PREF */ if (type & IORESOURCE_PREFETCH) type = IORESOURCE_PREFETCH; __pci_setup_bridge(bus, type); + /* for next child res under same bridge */ + r->flags = old_flags; } } @@ -1304,9 +1386,9 @@ enum release_type { * try to release pci bridge resources that is from leaf bridge, * so we can allocate big new one later */ -static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus, - unsigned long type, - enum release_type rel_type) +static void pci_bus_release_bridge_resources(struct pci_bus *bus, + unsigned long type, + enum release_type rel_type) { struct pci_dev *dev; bool is_leaf_bridge = true; @@ -1343,10 +1425,10 @@ static void pci_bus_dump_res(struct pci_bus *bus) pci_bus_for_each_resource(bus, res, i) { if (!res || !res->end || !res->flags) - continue; + continue; dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res); - } + } } static void pci_bus_dump_resources(struct pci_bus *bus) @@ -1371,7 +1453,7 @@ static int pci_bus_get_depth(struct pci_bus *bus) int depth = 0; struct pci_bus *child_bus; - list_for_each_entry(child_bus, &bus->children, node){ + list_for_each_entry(child_bus, &bus->children, node) { int ret; ret = pci_bus_get_depth(child_bus); @@ -1471,7 +1553,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) LIST_HEAD(fail_head); struct pci_dev_resource *fail_res; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | - IORESOURCE_PREFETCH; + IORESOURCE_PREFETCH | IORESOURCE_MEM_64; int pci_try_num = 1; enum enable_type enable_local; @@ -1629,9 +1711,7 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus) down_read(&pci_bus_sem); list_for_each_entry(dev, &bus->devices, bus_list) - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) - if (dev->subordinate) + if (pci_is_bridge(dev) && pci_has_subordinate(dev)) __pci_bus_size_bridges(dev->subordinate, &add_list); up_read(&pci_bus_sem); diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 9bd6864ec5d..4e2d595d50c 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -10,7 +10,6 @@ */ -#include <linux/init.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/errno.h> @@ -23,10 +22,9 @@ 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)) +static void pdev_fixup_irq(struct pci_dev *dev, + u8 (*swizzle)(struct pci_dev *, u8 *), + int (*map_irq)(const struct pci_dev *, u8, u8)) { u8 pin, slot; int irq = 0; @@ -59,11 +57,11 @@ pdev_fixup_irq(struct pci_dev *dev, pcibios_update_irq(dev, irq); } -void -pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), - int (*map_irq)(const struct pci_dev *, u8, u8)) +void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), + int (*map_irq)(const struct pci_dev *, u8, u8)) { struct pci_dev *dev = NULL; + for_each_pci_dev(dev) pdev_fixup_irq(dev, swizzle, map_irq); } diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 7eed671d558..caed1ce6fac 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -16,7 +16,6 @@ * Resource sorting */ -#include <linux/init.h> #include <linux/kernel.h> #include <linux/export.h> #include <linux/pci.h> @@ -97,8 +96,8 @@ void pci_update_resource(struct pci_dev *dev, int resno) pci_write_config_dword(dev, reg + 4, new); pci_read_config_dword(dev, reg + 4, &check); if (check != new) { - dev_err(&dev->dev, "BAR %d: error updating " - "(high %#08x != %#08x)\n", resno, new, check); + dev_err(&dev->dev, "BAR %d: error updating (high %#08x != %#08x)\n", + resno, new, check); } } @@ -209,21 +208,42 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; - /* First, try exact prefetching match.. */ + /* + * First, try exact prefetching match. Even if a 64-bit + * prefetchable bridge window is below 4GB, we can't put a 32-bit + * prefetchable resource in it because pbus_size_mem() assumes a + * 64-bit window will contain no 32-bit resources. If we assign + * things differently than they were sized, not everything will fit. + */ ret = pci_bus_alloc_resource(bus, res, size, align, min, - IORESOURCE_PREFETCH, + IORESOURCE_PREFETCH | IORESOURCE_MEM_64, pcibios_align_resource, dev); + if (ret == 0) + return 0; - if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) { - /* - * That failed. - * - * But a prefetching area can handle a non-prefetching - * window (it will just not perform as well). - */ - ret = pci_bus_alloc_resource(bus, res, size, align, min, 0, + /* + * If the prefetchable window is only 32 bits wide, we can put + * 64-bit prefetchable resources in it. + */ + if ((res->flags & (IORESOURCE_PREFETCH | IORESOURCE_MEM_64)) == + (IORESOURCE_PREFETCH | IORESOURCE_MEM_64)) { + ret = pci_bus_alloc_resource(bus, res, size, align, min, + IORESOURCE_PREFETCH, pcibios_align_resource, dev); + if (ret == 0) + return 0; } + + /* + * If we didn't find a better match, we can put any memory resource + * in a non-prefetchable window. If this resource is 32 bits and + * non-prefetchable, the first call already tried the only possibility + * so we don't need to try again. + */ + if (res->flags & (IORESOURCE_PREFETCH | IORESOURCE_MEM_64)) + ret = pci_bus_alloc_resource(bus, res, size, align, min, 0, + pcibios_align_resource, dev); + return ret; } @@ -269,8 +289,8 @@ int pci_assign_resource(struct pci_dev *dev, int resno) res->flags |= IORESOURCE_UNSET; align = pci_resource_alignment(dev, res); if (!align) { - dev_info(&dev->dev, "BAR %d: can't assign %pR " - "(bogus alignment)\n", resno, res); + dev_info(&dev->dev, "BAR %d: can't assign %pR (bogus alignment)\n", + resno, res); return -EINVAL; } @@ -294,6 +314,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno) } return ret; } +EXPORT_SYMBOL(pci_assign_resource); int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize, resource_size_t min_align) @@ -304,8 +325,8 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz res->flags |= IORESOURCE_UNSET; if (!res->parent) { - dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR " - "\n", resno, res); + dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR\n", + resno, res); return -EINVAL; } diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 7dd62fa9d0b..396c200b9dd 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -116,11 +116,11 @@ static void pci_slot_release(struct kobject *kobj) } static struct pci_slot_attribute pci_slot_attr_address = - __ATTR(address, (S_IFREG | S_IRUGO), address_read_file, NULL); + __ATTR(address, S_IRUGO, address_read_file, NULL); static struct pci_slot_attribute pci_slot_attr_max_speed = - __ATTR(max_bus_speed, (S_IFREG | S_IRUGO), max_speed_read_file, NULL); + __ATTR(max_bus_speed, S_IRUGO, max_speed_read_file, NULL); static struct pci_slot_attribute pci_slot_attr_cur_speed = - __ATTR(cur_bus_speed, (S_IFREG | S_IRUGO), cur_speed_read_file, NULL); + __ATTR(cur_bus_speed, S_IRUGO, cur_speed_read_file, NULL); static struct attribute *pci_slot_default_attrs[] = { &pci_slot_attr_address.attr, diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index 24750a1b39b..b91c4da6836 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -99,7 +99,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, if (!dev) return -ENODEV; - switch(len) { + switch (len) { case 1: err = get_user(byte, (u8 __user *)buf); if (err) diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 179b8edc226..53df39a22c8 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -662,9 +662,9 @@ static void pcifront_do_aer(struct work_struct *data) notify_remote_via_evtchn(pdev->evtchn); /*in case of we lost an aer request in four lines time_window*/ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(_PDEVB_op_active, &pdev->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); schedule_pcifront_aer_op(pdev); |
