diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/Kconfig | 6 | ||||
-rw-r--r-- | drivers/pci/access.c | 2 | ||||
-rw-r--r-- | drivers/pci/host/pci-imx6.c | 13 | ||||
-rw-r--r-- | drivers/pci/host/pci-keystone-dw.c | 6 | ||||
-rw-r--r-- | drivers/pci/host/pci-keystone.h | 2 | ||||
-rw-r--r-- | drivers/pci/host/pci-mvebu.c | 13 | ||||
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 63 | ||||
-rw-r--r-- | drivers/pci/host/pci-xgene.c | 7 | ||||
-rw-r--r-- | drivers/pci/host/pcie-designware.c | 32 | ||||
-rw-r--r-- | drivers/pci/host/pcie-designware.h | 2 | ||||
-rw-r--r-- | drivers/pci/host/pcie-rcar.c | 31 | ||||
-rw-r--r-- | drivers/pci/host/pcie-xilinx.c | 37 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 7 | ||||
-rw-r--r-- | drivers/pci/msi.c | 403 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 8 | ||||
-rw-r--r-- | drivers/pci/pci.h | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/pme.c | 6 | ||||
-rw-r--r-- | drivers/pci/probe.c | 30 |
18 files changed, 461 insertions, 209 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 893503f..cced842 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -4,6 +4,7 @@ config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" depends on PCI + select GENERIC_MSI_IRQ help This allows device drivers to enable MSI (Message Signaled Interrupts). Message Signaled Interrupts enable a device to @@ -16,6 +17,11 @@ config PCI_MSI If you don't know what to do here, say Y. +config PCI_MSI_IRQ_DOMAIN + bool + depends on PCI_MSI + select GENERIC_MSI_IRQ_DOMAIN + config PCI_DEBUG bool "PCI Debugging" depends on PCI && DEBUG_KERNEL diff --git a/drivers/pci/access.c b/drivers/pci/access.c index d292d7c..49dd766 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -444,7 +444,7 @@ static inline int pcie_cap_version(const struct pci_dev *dev) return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS; } -static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev) +bool pcie_cap_has_lnkctl(const struct pci_dev *dev) { int type = pci_pcie_type(dev); diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 8a7530b..d1a26d1 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -275,15 +275,22 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) goto err_pcie; } - /* allow the clocks to stabilize */ - usleep_range(200, 500); - /* power up core phy and enable ref clock */ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18); + /* + * the async reset input need ref clock to sync internally, + * when the ref clock comes after reset, internal synced + * reset time is too short, cannot meet the requirement. + * add one ~10us delay here. + */ + udelay(10); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); + /* allow the clocks to stabilize */ + usleep_range(200, 500); + /* Some boards don't have PCIe reset GPIO. */ if (gpio_is_valid(imx6_pcie->reset_gpio)) { gpio_set_value(imx6_pcie->reset_gpio, 0); diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c index 4a97cd1..66d8ea4 100644 --- a/drivers/pci/host/pci-keystone-dw.c +++ b/drivers/pci/host/pci-keystone-dw.c @@ -155,7 +155,7 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) /* Mask the end point if PVM implemented */ if (IS_ENABLED(CONFIG_PCI_MSI)) { if (msi->msi_attrib.maskbit) - mask_msi_irq(d); + pci_msi_mask_irq(d); } ks_dw_pcie_msi_clear_irq(pp, offset); @@ -177,7 +177,7 @@ static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d) /* Mask the end point if PVM implemented */ if (IS_ENABLED(CONFIG_PCI_MSI)) { if (msi->msi_attrib.maskbit) - unmask_msi_irq(d); + pci_msi_unmask_irq(d); } ks_dw_pcie_msi_set_irq(pp, offset); @@ -205,7 +205,7 @@ static const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = { .map = ks_dw_pcie_msi_map, }; -int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_chip *chip) +int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_controller *chip) { struct keystone_pcie *ks_pcie = to_keystone_pcie(pp); int i; diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h index 1fc1fce..478d932 100644 --- a/drivers/pci/host/pci-keystone.h +++ b/drivers/pci/host/pci-keystone.h @@ -55,4 +55,4 @@ void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq); void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq); void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp); int ks_dw_pcie_msi_host_init(struct pcie_port *pp, - struct msi_chip *chip); + struct msi_controller *chip); diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index e45f88e..fed3fab 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -99,7 +99,7 @@ struct mvebu_pcie_port; struct mvebu_pcie { struct platform_device *pdev; struct mvebu_pcie_port *ports; - struct msi_chip *msi; + struct msi_controller *msi; struct resource io; char io_name[30]; struct resource realio; @@ -776,12 +776,6 @@ static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys) return bus; } -static void mvebu_pcie_add_bus(struct pci_bus *bus) -{ - struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); - bus->msi = pcie->msi; -} - static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, const struct resource *res, resource_size_t start, @@ -818,6 +812,10 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie) memset(&hw, 0, sizeof(hw)); +#ifdef CONFIG_PCI_MSI + hw.msi_ctrl = pcie->msi; +#endif + hw.nr_controllers = 1; hw.private_data = (void **)&pcie; hw.setup = mvebu_pcie_setup; @@ -825,7 +823,6 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie) hw.map_irq = of_irq_parse_and_map_pci; hw.ops = &mvebu_pcie_ops; hw.align_resource = mvebu_pcie_align_resource; - hw.add_bus = mvebu_pcie_add_bus; pci_common_init(&hw); } diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 3d43874..feccfa6 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -238,7 +238,7 @@ ) struct tegra_msi { - struct msi_chip chip; + struct msi_controller chip; DECLARE_BITMAP(used, INT_PCI_MSI_NR); struct irq_domain *domain; unsigned long pages; @@ -259,7 +259,7 @@ struct tegra_pcie_soc_data { bool has_gen2; }; -static inline struct tegra_msi *to_tegra_msi(struct msi_chip *chip) +static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip) { return container_of(chip, struct tegra_msi, chip); } @@ -276,6 +276,7 @@ struct tegra_pcie { struct resource all; struct resource io; + struct resource pio; struct resource mem; struct resource prefetch; struct resource busn; @@ -658,7 +659,6 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) { struct tegra_pcie *pcie = sys_to_pcie(sys); int err; - phys_addr_t io_start; err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem); if (err < 0) @@ -668,14 +668,12 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) if (err) return err; - io_start = pci_pio_to_address(pcie->io.start); - pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); pci_add_resource_offset(&sys->resources, &pcie->prefetch, sys->mem_offset); pci_add_resource(&sys->resources, &pcie->busn); - pci_ioremap_io(nr * SZ_64K, io_start); + pci_ioremap_io(pcie->pio.start, pcie->io.start); return 1; } @@ -694,15 +692,6 @@ static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) return irq; } -static void tegra_pcie_add_bus(struct pci_bus *bus) -{ - if (IS_ENABLED(CONFIG_PCI_MSI)) { - struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata); - - bus->msi = &pcie->msi.chip; - } -} - static struct pci_bus *tegra_pcie_scan_bus(int nr, struct pci_sys_data *sys) { struct tegra_pcie *pcie = sys_to_pcie(sys); @@ -786,7 +775,6 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) { u32 fpci_bar, size, axi_address; - phys_addr_t io_start = pci_pio_to_address(pcie->io.start); /* Bar 0: type 1 extended configuration space */ fpci_bar = 0xfe100000; @@ -799,7 +787,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) /* Bar 1: downstream IO bar */ fpci_bar = 0xfdfc0000; size = resource_size(&pcie->io); - axi_address = io_start; + axi_address = pcie->io.start; afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); @@ -1283,8 +1271,8 @@ static irqreturn_t tegra_pcie_msi_irq(int irq, void *data) return processed > 0 ? IRQ_HANDLED : IRQ_NONE; } -static int tegra_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, - struct msi_desc *desc) +static int tegra_msi_setup_irq(struct msi_controller *chip, + struct pci_dev *pdev, struct msi_desc *desc) { struct tegra_msi *msi = to_tegra_msi(chip); struct msi_msg msg; @@ -1308,12 +1296,13 @@ static int tegra_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, msg.address_hi = 0; msg.data = hwirq; - write_msi_msg(irq, &msg); + pci_write_msi_msg(irq, &msg); return 0; } -static void tegra_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) +static void tegra_msi_teardown_irq(struct msi_controller *chip, + unsigned int irq) { struct tegra_msi *msi = to_tegra_msi(chip); struct irq_data *d = irq_get_irq_data(irq); @@ -1325,10 +1314,10 @@ static void tegra_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) static struct irq_chip tegra_msi_irq_chip = { .name = "Tegra PCIe MSI", - .irq_enable = unmask_msi_irq, - .irq_disable = mask_msi_irq, - .irq_mask = mask_msi_irq, - .irq_unmask = unmask_msi_irq, + .irq_enable = pci_msi_unmask_irq, + .irq_disable = pci_msi_mask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, }; static int tegra_msi_map(struct irq_domain *domain, unsigned int irq, @@ -1690,8 +1679,23 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) switch (res.flags & IORESOURCE_TYPE_BITS) { case IORESOURCE_IO: - memcpy(&pcie->io, &res, sizeof(res)); - pcie->io.name = np->full_name; + memcpy(&pcie->pio, &res, sizeof(res)); + pcie->pio.name = np->full_name; + + /* + * The Tegra PCIe host bridge uses this to program the + * mapping of the I/O space to the physical address, + * so we override the .start and .end fields here that + * of_pci_range_to_resource() converted to I/O space. + * We also set the IORESOURCE_MEM type to clarify that + * the resource is in the physical memory space. + */ + pcie->io.start = range.cpu_addr; + pcie->io.end = range.cpu_addr + range.size - 1; + pcie->io.flags = IORESOURCE_MEM; + pcie->io.name = "I/O"; + + memcpy(&res, &pcie->io, sizeof(res)); break; case IORESOURCE_MEM: @@ -1881,11 +1885,14 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie) memset(&hw, 0, sizeof(hw)); +#ifdef CONFIG_PCI_MSI + hw.msi_ctrl = &pcie->msi.chip; +#endif + hw.nr_controllers = 1; hw.private_data = (void **)&pcie; hw.setup = tegra_pcie_setup; hw.map_irq = tegra_pcie_map_irq; - hw.add_bus = tegra_pcie_add_bus; hw.scan = tegra_pcie_scan_bus; hw.ops = &tegra_pcie_ops; diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index 9ecabfa..2988fe1 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -631,10 +631,15 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) if (ret) return ret; - bus = pci_scan_root_bus(&pdev->dev, 0, &xgene_pcie_ops, port, &res); + bus = pci_create_root_bus(&pdev->dev, 0, + &xgene_pcie_ops, port, &res); if (!bus) return -ENOMEM; + pci_scan_child_bus(bus); + pci_assign_unassigned_bus_resources(bus); + pci_bus_add_devices(bus); + platform_set_drvdata(pdev, port); return 0; } diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index f9be371..df781cd 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -152,10 +152,10 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, static struct irq_chip dw_msi_irq_chip = { .name = "PCI-MSI", - .irq_enable = unmask_msi_irq, - .irq_disable = mask_msi_irq, - .irq_mask = mask_msi_irq, - .irq_unmask = unmask_msi_irq, + .irq_enable = pci_msi_unmask_irq, + .irq_disable = pci_msi_mask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, }; /* MSI int handler */ @@ -276,7 +276,7 @@ no_valid_irq: return -ENOSPC; } -static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, +static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, struct msi_desc *desc) { int irq, pos; @@ -298,12 +298,12 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, else msg.data = pos; - write_msi_msg(irq, &msg); + pci_write_msi_msg(irq, &msg); return 0; } -static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) +static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) { struct irq_data *data = irq_get_irq_data(irq); struct msi_desc *msi = irq_data_get_msi(data); @@ -312,7 +312,7 @@ static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) clear_irq_range(pp, irq, 1, data->hwirq); } -static struct msi_chip dw_pcie_msi_chip = { +static struct msi_controller dw_pcie_msi_chip = { .setup_irq = dw_msi_setup_irq, .teardown_irq = dw_msi_teardown_irq, }; @@ -499,6 +499,11 @@ int __init dw_pcie_host_init(struct pcie_port *pp) val |= PORT_LOGIC_SPEED_CHANGE; dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val); +#ifdef CONFIG_PCI_MSI + dw_pcie_msi_chip.dev = pp->dev; + dw_pci.msi_ctrl = &dw_pcie_msi_chip; +#endif + dw_pci.nr_controllers = 1; dw_pci.private_data = (void **)&pp; @@ -748,21 +753,10 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) return irq; } -static void dw_pcie_add_bus(struct pci_bus *bus) -{ - if (IS_ENABLED(CONFIG_PCI_MSI)) { - struct pcie_port *pp = sys_to_pcie(bus->sysdata); - - dw_pcie_msi_chip.dev = pp->dev; - bus->msi = &dw_pcie_msi_chip; - } -} - static struct hw_pci dw_pci = { .setup = dw_pcie_setup, .scan = dw_pcie_scan_bus, .map_irq = dw_pcie_map_irq, - .add_bus = dw_pcie_add_bus, }; void dw_pcie_setup_rc(struct pcie_port *pp) diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index c625675..d0bbd27 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -73,7 +73,7 @@ struct pcie_host_ops { u32 (*get_msi_addr)(struct pcie_port *pp); u32 (*get_msi_data)(struct pcie_port *pp, int pos); void (*scan_bus)(struct pcie_port *pp); - int (*msi_host_init)(struct pcie_port *pp, struct msi_chip *chip); + int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip); }; int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 0df9b29..5519e93 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -111,14 +111,14 @@ struct rcar_msi { DECLARE_BITMAP(used, INT_PCI_MSI_NR); struct irq_domain *domain; - struct msi_chip chip; + struct msi_controller chip; unsigned long pages; struct mutex lock; int irq1; int irq2; }; -static inline struct rcar_msi *to_rcar_msi(struct msi_chip *chip) +static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip) { return container_of(chip, struct rcar_msi, chip); } @@ -380,20 +380,10 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys) 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; - } -} - static 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) @@ -402,6 +392,9 @@ static void rcar_pcie_enable(struct rcar_pcie *pcie) rcar_pci.nr_controllers = 1; rcar_pci.private_data = (void **)&pcie; +#ifdef CONFIG_PCI_MSI + rcar_pci.msi_ctrl = &pcie->msi.chip; +#endif pci_common_init_dev(&pdev->dev, &rcar_pci); #ifdef CONFIG_PCI_DOMAINS @@ -622,7 +615,7 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data) return IRQ_HANDLED; } -static int rcar_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, +static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, struct msi_desc *desc) { struct rcar_msi *msi = to_rcar_msi(chip); @@ -647,12 +640,12 @@ static int rcar_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, msg.address_hi = rcar_pci_read_reg(pcie, PCIEMSIAUR); msg.data = hwirq; - write_msi_msg(irq, &msg); + pci_write_msi_msg(irq, &msg); return 0; } -static void rcar_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) +static void rcar_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) { struct rcar_msi *msi = to_rcar_msi(chip); struct irq_data *d = irq_get_irq_data(irq); @@ -662,10 +655,10 @@ static void rcar_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) 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, + .irq_enable = pci_msi_unmask_irq, + .irq_disable = pci_msi_mask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, }; static int rcar_msi_map(struct irq_domain *domain, unsigned int irq, diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index ccc496b..2f50fa5 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -335,7 +335,8 @@ static int xilinx_pcie_assign_msi(struct xilinx_pcie_port *port) * @chip: MSI Chip descriptor * @irq: MSI IRQ to destroy */ -static void xilinx_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) +static void xilinx_msi_teardown_irq(struct msi_controller *chip, + unsigned int irq) { xilinx_pcie_destroy_msi(irq); } @@ -348,7 +349,7 @@ static void xilinx_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) * * Return: '0' on success and error value on failure */ -static int xilinx_pcie_msi_setup_irq(struct msi_chip *chip, +static int xilinx_pcie_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, struct msi_desc *desc) { @@ -374,13 +375,13 @@ static int xilinx_pcie_msi_setup_irq(struct msi_chip *chip, msg.address_lo = msg_addr; msg.data = irq; - write_msi_msg(irq, &msg); + pci_write_msi_msg(irq, &msg); return 0; } /* MSI Chip Descriptor */ -static struct msi_chip xilinx_pcie_msi_chip = { +static struct msi_controller xilinx_pcie_msi_chip = { .setup_irq = xilinx_pcie_msi_setup_irq, .teardown_irq = xilinx_msi_teardown_irq, }; @@ -388,10 +389,10 @@ static struct msi_chip xilinx_pcie_msi_chip = { /* HW Interrupt Chip Descriptor */ static struct irq_chip xilinx_msi_irq_chip = { .name = "Xilinx PCIe MSI", - .irq_enable = unmask_msi_irq, - .irq_disable = mask_msi_irq, - .irq_mask = mask_msi_irq, - .irq_unmask = unmask_msi_irq, + .irq_enable = pci_msi_unmask_irq, + .irq_disable = pci_msi_mask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, }; /** @@ -431,20 +432,6 @@ static void xilinx_pcie_enable_msi(struct xilinx_pcie_port *port) pcie_write(port, msg_addr, XILINX_PCIE_REG_MSIBASE2); } -/** - * xilinx_pcie_add_bus - Add MSI chip info to PCIe bus - * @bus: PCIe bus - */ -static void xilinx_pcie_add_bus(struct pci_bus *bus) -{ - if (IS_ENABLED(CONFIG_PCI_MSI)) { - struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata); - - xilinx_pcie_msi_chip.dev = port->dev; - bus->msi = &xilinx_pcie_msi_chip; - } -} - /* INTx Functions */ /** @@ -924,10 +911,14 @@ static int xilinx_pcie_probe(struct platform_device *pdev) .private_data = (void **)&port, .setup = xilinx_pcie_setup, .map_irq = of_irq_parse_and_map_pci, - .add_bus = xilinx_pcie_add_bus, .scan = xilinx_pcie_scan_bus, .ops = &xilinx_pcie_ops, }; + +#ifdef CONFIG_PCI_MSI + xilinx_pcie_msi_chip.dev = port->dev; + hw.msi_ctrl = &xilinx_pcie_msi_chip; +#endif pci_common_init_dev(dev, &hw); return 0; diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 3a5e7e2..07aa722 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -262,13 +262,6 @@ static int pciehp_probe(struct pcie_device *dev) goto err_out_none; } - if (!dev->port->subordinate) { - /* Can happen if we run out of bus numbers during probe */ - dev_err(&dev->device, - "Hotplug bridge without secondary bus, ignoring\n"); - goto err_out_none; - } - ctrl = pcie_init(dev); if (!ctrl) { dev_err(&dev->device, "Controller initialization failed\n"); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index d9a92cf..fd60806 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -19,6 +19,7 @@ #include <linux/errno.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/irqdomain.h> #include "pci.h" @@ -27,12 +28,73 @@ int pci_msi_ignore_mask; #define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +static struct irq_domain *pci_msi_default_domain; +static DEFINE_MUTEX(pci_msi_domain_lock); + +struct irq_domain * __weak arch_get_pci_msi_domain(struct pci_dev *dev) +{ + return pci_msi_default_domain; +} + +static struct irq_domain *pci_msi_get_domain(struct pci_dev *dev) +{ + struct irq_domain *domain = NULL; + + if (dev->bus->msi) + domain = dev->bus->msi->domain; + if (!domain) + domain = arch_get_pci_msi_domain(dev); + + return domain; +} + +static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + struct irq_domain *domain; + + domain = pci_msi_get_domain(dev); + if (domain) + return pci_msi_domain_alloc_irqs(domain, dev, nvec, type); + + return arch_setup_msi_irqs(dev, nvec, type); +} + +static void pci_msi_teardown_msi_irqs(struct pci_dev *dev) +{ + struct irq_domain *domain; + + domain = pci_msi_get_domain(dev); + if (domain) + pci_msi_domain_free_irqs(domain, dev); + else + arch_teardown_msi_irqs(dev); +} +#else +#define pci_msi_setup_msi_irqs arch_setup_msi_irqs +#define pci_msi_teardown_msi_irqs arch_teardown_msi_irqs +#endif /* Arch hooks */ +struct msi_controller * __weak pcibios_msi_controller(struct pci_dev *dev) +{ + return NULL; +} + +static struct msi_controller *pci_msi_controller(struct pci_dev *dev) +{ + struct msi_controller *msi_ctrl = dev->bus->msi; + + if (msi_ctrl) + return msi_ctrl; + + return pcibios_msi_controller(dev); +} + int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) { - struct msi_chip *chip = dev->bus->msi; + struct msi_controller *chip = pci_msi_controller(dev); int err; if (!chip || !chip->setup_irq) @@ -49,7 +111,7 @@ int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) void __weak arch_teardown_msi_irq(unsigned int irq) { - struct msi_chip *chip = irq_get_chip_data(irq); + struct msi_controller *chip = irq_get_chip_data(irq); if (!chip || !chip->teardown_irq) return; @@ -86,19 +148,13 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) */ void default_teardown_msi_irqs(struct pci_dev *dev) { + int i; struct msi_desc *entry; - list_for_each_entry(entry, &dev->msi_list, list) { - int i, nvec; - if (entry->irq == 0) - continue; - if (entry->nvec_used) - nvec = entry->nvec_used; - else - nvec = 1 << entry->msi_attrib.multiple; - for (i = 0; i < nvec; i++) - arch_teardown_msi_irq(entry->irq + i); - } + list_for_each_entry(entry, &dev->msi_list, list) + if (entry->irq) + for (i = 0; i < entry->nvec_used; i++) + arch_teardown_msi_irq(entry->irq + i); } void __weak arch_teardown_msi_irqs(struct pci_dev *dev) @@ -121,7 +177,7 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq) } if (entry) - __write_msi_msg(entry, &entry->msg); + __pci_write_msi_msg(entry, &entry->msg); } void __weak arch_restore_msi_irqs(struct pci_dev *dev) @@ -164,7 +220,7 @@ static inline __attribute_const__ u32 msi_mask(unsigned x) * reliably as devices without an INTx disable bit will then generate a * level IRQ which will never be cleared. */ -u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) +u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) { u32 mask_bits = desc->masked; @@ -180,7 +236,7 @@ u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) { - desc->masked = __msi_mask_irq(desc, mask, flag); + desc->masked = __pci_msi_desc_mask_irq(desc, mask, flag); } /* @@ -190,7 +246,7 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) * file. This saves a few milliseconds when initialising devices with lots * of MSI-X interrupts. */ -u32 __msix_mask_irq(struct msi_desc *desc, u32 flag) +u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag) { u32 mask_bits = desc->masked; unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + @@ -209,7 +265,7 @@ u32 __msix_mask_irq(struct msi_desc *desc, u32 flag) static void msix_mask_irq(struct msi_desc *desc, u32 flag) { - desc->masked = __msix_mask_irq(desc, flag); + desc->masked = __pci_msix_desc_mask_irq(desc, flag); } static void msi_set_mask_bit(struct irq_data *data, u32 flag) @@ -225,12 +281,20 @@ static void msi_set_mask_bit(struct irq_data *data, u32 flag) } } -void mask_msi_irq(struct irq_data *data) +/** + * pci_msi_mask_irq - Generic irq chip callback to mask PCI/MSI interrupts + * @data: pointer to irqdata associated to that interrupt + */ +void pci_msi_mask_irq(struct irq_data *data) { msi_set_mask_bit(data, 1); } -void unmask_msi_irq(struct irq_data *data) +/** + * pci_msi_unmask_irq - Generic irq chip callback to unmask PCI/MSI interrupts + * @data: pointer to irqdata associated to that interrupt + */ +void pci_msi_unmask_irq(struct irq_data *data) { msi_set_mask_bit(data, 0); } @@ -239,12 +303,11 @@ void default_restore_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry; - list_for_each_entry(entry, &dev->msi_list, list) { + list_for_each_entry(entry, &dev->msi_list, list) default_restore_msi_irq(dev, entry->irq); - } } -void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) +void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { BUG_ON(entry->dev->current_state != PCI_D0); @@ -274,32 +337,7 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) } } -void read_msi_msg(unsigned int irq, struct msi_msg *msg) -{ - struct msi_desc *entry = irq_get_msi_desc(irq); - - __read_msi_msg(entry, msg); -} - -void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg) -{ - /* Assert that the cache is valid, assuming that - * valid messages are not all-zeroes. */ - BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo | - entry->msg.data)); - - *msg = entry->msg; -} - -void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) -{ - struct msi_desc *entry = irq_get_msi_desc(irq); - - __get_cached_msi_msg(entry, msg); -} -EXPORT_SYMBOL_GPL(get_cached_msi_msg); - -void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) +void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { if (entry->dev->current_state != PCI_D0) { /* Don't touch the hardware now */ @@ -336,34 +374,27 @@ void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) entry->msg = *msg; } -void write_msi_msg(unsigned int irq, struct msi_msg *msg) +void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg) { struct msi_desc *entry = irq_get_msi_desc(irq); - __write_msi_msg(entry, msg); + __pci_write_msi_msg(entry, msg); } -EXPORT_SYMBOL_GPL(write_msi_msg); +EXPORT_SYMBOL_GPL(pci_write_msi_msg); static void free_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry, *tmp; struct attribute **msi_attrs; struct device_attribute *dev_attr; - int count = 0; + int i, count = 0; - list_for_each_entry(entry, &dev->msi_list, list) { - int i, nvec; - if (!entry->irq) - continue; - if (entry->nvec_used) - nvec = entry->nvec_used; - else - nvec = 1 << entry->msi_attrib.multiple; - for (i = 0; i < nvec; i++) - BUG_ON(irq_has_action(entry->irq + i)); - } + list_for_each_entry(entry, &dev->msi_list, list) + if (entry->irq) + for (i = 0; i < entry->nvec_used; i++) + BUG_ON(irq_has_action(entry->irq + i)); - arch_teardown_msi_irqs(dev); + pci_msi_teardown_msi_irqs(dev); list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { if (entry->msi_attrib.is_msix) { @@ -446,9 +477,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev) PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL); arch_restore_msi_irqs(dev); - list_for_each_entry(entry, &dev->msi_list, list) { + list_for_each_entry(entry, &dev->msi_list, list) msix_mask_irq(entry, entry->masked); - } msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0); } @@ -492,9 +522,8 @@ static int populate_msi_sysfs(struct pci_dev *pdev) int count = 0; /* Determine how many msi entries we have */ - list_for_each_entry(entry, &pdev->msi_list, list) { + list_for_each_entry(entry, &pdev->msi_list, list) ++num_msi; - } if (!num_msi) return 0; @@ -554,7 +583,7 @@ error_attrs: return ret; } -static struct msi_desc *msi_setup_entry(struct pci_dev *dev) +static struct msi_desc *msi_setup_entry(struct pci_dev *dev, int nvec) { u16 control; struct msi_desc *entry; @@ -572,6 +601,8 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev) entry->msi_attrib.maskbit = !!(control & PCI_MSI_FLAGS_MASKBIT); entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1; + entry->msi_attrib.multiple = ilog2(__roundup_pow_of_two(nvec)); + entry->nvec_used = nvec; if (control & PCI_MSI_FLAGS_64BIT) entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64; @@ -585,6 +616,20 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev) return entry; } +static int msi_verify_entries(struct pci_dev *dev) +{ + struct msi_desc *entry; + + list_for_each_entry(entry, &dev->msi_list, list) { + if (!dev->no_64bit_msi || !entry->msg.address_hi) + continue; + dev_err(&dev->dev, "Device has broken 64-bit MSI but arch" + " tried to assign one above 4G\n"); + return -EIO; + } + return 0; +} + /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function @@ -604,7 +649,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) msi_set_enable(dev, 0); /* Disable MSI during set up */ - entry = msi_setup_entry(dev); + entry = msi_setup_entry(dev, nvec); if (!entry) return -ENOMEM; @@ -615,7 +660,14 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) list_add_tail(&entry->list, &dev->msi_list); /* Configure MSI capability structure */ - ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI); + ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI); + if (ret) { + msi_mask_irq(entry, mask, ~mask); + free_msi_irqs(dev); + return ret; + } + + ret = msi_verify_entries(dev); if (ret) { msi_mask_irq(entry, mask, ~mask); free_msi_irqs(dev); @@ -675,6 +727,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, entry->msi_attrib.entry_nr = entries[i].entry; entry->msi_attrib.default_irq = dev->irq; entry->mask_base = base; + entry->nvec_used = 1; list_add_tail(&entry->list, &dev->msi_list); } @@ -693,7 +746,6 @@ static void msix_program_entries(struct pci_dev *dev, PCI_MSIX_ENTRY_VECTOR_CTRL; entries[i].vector = entry->irq; - irq_set_msi_desc(entry->irq, entry); entry->masked = readl(entry->mask_base + offset); msix_mask_irq(entry, 1); i++; @@ -730,10 +782,15 @@ static int msix_capability_init(struct pci_dev *dev, if (ret) return ret; - ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); + ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); if (ret) goto out_avail; + /* Check if all MSI entries honor device restrictions */ + ret = msi_verify_entries(dev); + if (ret) + goto out_free; + /* * Some devices require MSI-X to be enabled before we can touch the * MSI-X registers. We need to mask all the vectors to prevent @@ -864,7 +921,7 @@ void pci_msi_shutdown(struct pci_dev *dev) /* Return the device with MSI unmasked as initial states */ mask = msi_mask(desc->msi_attrib.multi_cap); /* Keep cached state to be restored */ - __msi_mask_irq(desc, mask, ~mask); + __pci_msi_desc_mask_irq(desc, mask, ~mask); /* Restore dev->irq to its default pin-assertion irq */ dev->irq = desc->msi_attrib.default_irq; @@ -962,7 +1019,7 @@ void pci_msix_shutdown(struct pci_dev *dev) /* Return the device with MSI-X masked as initial states */ list_for_each_entry(entry, &dev->msi_list, list) { /* Keep cached states to be restored */ - __msix_mask_irq(entry, 1); + __pci_msix_desc_mask_irq(entry, 1); } msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); @@ -1107,3 +1164,197 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, return nvec; } EXPORT_SYMBOL(pci_enable_msix_range); + +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +/** + * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space + * @irq_data: Pointer to interrupt data of the MSI interrupt + * @msg: Pointer to the message + */ +void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg) +{ + struct msi_desc *desc = irq_data->msi_desc; + + /* + * For MSI-X desc->irq is always equal to irq_data->irq. For + * MSI only the first interrupt of MULTI MSI passes the test. + */ + if (desc->irq == irq_data->irq) + __pci_write_msi_msg(desc, msg); +} + +/** + * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source + * @dev: Pointer to the PCI device + * @desc: Pointer to the msi descriptor + * + * The ID number is only used within the irqdomain. + */ +irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev, + struct msi_desc *desc) +{ + return (irq_hw_number_t)desc->msi_attrib.entry_nr | + PCI_DEVID(dev->bus->number, dev->devfn) << 11 | + (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27; +} + +static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc) +{ + return !desc->msi_attrib.is_msix && desc->nvec_used > 1; +} + +/** + * pci_msi_domain_check_cap - Verify that @domain supports the capabilities for @dev + * @domain: The interrupt domain to check + * @info: The domain info for verification + * @dev: The device to check + * + * Returns: + * 0 if the functionality is supported + * 1 if Multi MSI is requested, but the domain does not support it + * -ENOTSUPP otherwise + */ +int pci_msi_domain_check_cap(struct irq_domain *domain, + struct msi_domain_info *info, struct device *dev) +{ + struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev)); + + /* Special handling to support pci_enable_msi_range() */ + if (pci_msi_desc_is_multi_msi(desc) && + !(info->flags & MSI_FLAG_MULTI_PCI_MSI)) + return 1; + else if (desc->msi_attrib.is_msix && !(info->flags & MSI_FLAG_PCI_MSIX)) + return -ENOTSUPP; + + return 0; +} + +static int pci_msi_domain_handle_error(struct irq_domain *domain, + struct msi_desc *desc, int error) +{ + /* Special handling to support pci_enable_msi_range() */ + if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC) + return 1; + + return error; +} + +#ifdef GENERIC_MSI_DOMAIN_OPS +static void pci_msi_domain_set_desc(msi_alloc_info_t *arg, + struct msi_desc *desc) +{ + arg->desc = desc; + arg->hwirq = pci_msi_domain_calc_hwirq(msi_desc_to_pci_dev(desc), + desc); +} +#else +#define pci_msi_domain_set_desc NULL +#endif + +static struct msi_domain_ops pci_msi_domain_ops_default = { + .set_desc = pci_msi_domain_set_desc, + .msi_check = pci_msi_domain_check_cap, + .handle_error = pci_msi_domain_handle_error, +}; + +static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info) +{ + struct msi_domain_ops *ops = info->ops; + + if (ops == NULL) { + info->ops = &pci_msi_domain_ops_default; + } else { + if (ops->set_desc == NULL) + ops->set_desc = pci_msi_domain_set_desc; + if (ops->msi_check == NULL) + ops->msi_check = pci_msi_domain_check_cap; + if (ops->handle_error == NULL) + ops->handle_error = pci_msi_domain_handle_error; + } +} + +static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info) +{ + struct irq_chip *chip = info->chip; + + BUG_ON(!chip); + if (!chip->irq_write_msi_msg) + chip->irq_write_msi_msg = pci_msi_domain_write_msg; +} + +/** + * pci_msi_create_irq_domain - Creat a MSI interrupt domain + * @node: Optional device-tree node of the interrupt controller + * @info: MSI domain info + * @parent: Parent irq domain + * + * Updates the domain and chip ops and creates a MSI interrupt domain. + * + * Returns: + * A domain pointer or NULL in case of failure. + */ +struct irq_domain *pci_msi_create_irq_domain(struct device_node *node, + struct msi_domain_info *info, + struct irq_domain *parent) +{ + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) + pci_msi_domain_update_dom_ops(info); + if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) + pci_msi_domain_update_chip_ops(info); + + return msi_create_irq_domain(node, info, parent); +} + +/** + * pci_msi_domain_alloc_irqs - Allocate interrupts for @dev in @domain + * @domain: The interrupt domain to allocate from + * @dev: The device for which to allocate + * @nvec: The number of interrupts to allocate + * @type: Unused to allow simpler migration from the arch_XXX interfaces + * + * Returns: + * A virtual interrupt number or an error code in case of failure + */ +int pci_msi_domain_alloc_irqs(struct irq_domain *domain, struct pci_dev *dev, + int nvec, int type) +{ + return msi_domain_alloc_irqs(domain, &dev->dev, nvec); +} + +/** + * pci_msi_domain_free_irqs - Free interrupts for @dev in @domain + * @domain: The interrupt domain + * @dev: The device for which to free interrupts + */ +void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev) +{ + msi_domain_free_irqs(domain, &dev->dev); +} + +/** + * pci_msi_create_default_irq_domain - Create a default MSI interrupt domain + * @node: Optional device-tree node of the interrupt controller + * @info: MSI domain info + * @parent: Parent irq domain + * + * Returns: A domain pointer or NULL in case of failure. If successful + * the default PCI/MSI irqdomain pointer is updated. + */ +struct irq_domain *pci_msi_create_default_irq_domain(struct device_node *node, + struct msi_domain_info *info, struct irq_domain *parent) +{ + struct irq_domain *domain; + + mutex_lock(&pci_msi_domain_lock); + if (pci_msi_default_domain) { + pr_err("PCI: default irq domain for PCI MSI has already been created.\n"); + domain = NULL; + } else { + domain = pci_msi_create_irq_domain(node, info, parent); + pci_msi_default_domain = domain; + } + mutex_unlock(&pci_msi_domain_lock); + + return domain; +} +#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */ diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 91e760f..a5addbc 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -185,7 +185,7 @@ 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, +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); @@ -210,7 +210,7 @@ static ssize_t enabled_store(struct device *dev, struct device_attribute *attr, return result < 0 ? result : count; } -static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, +static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pci_dev *pdev; @@ -218,7 +218,7 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, pdev = to_pci_dev(dev); return sprintf(buf, "%u\n", atomic_read(&pdev->enable_cnt)); } -static DEVICE_ATTR_RW(enabled); +static DEVICE_ATTR_RW(enable); #ifdef CONFIG_NUMA static ssize_t numa_node_store(struct device *dev, @@ -588,7 +588,7 @@ static struct attribute *pci_dev_attrs[] = { #endif &dev_attr_dma_mask_bits.attr, &dev_attr_consistent_dma_mask_bits.attr, - &dev_attr_enabled.attr, + &dev_attr_enable.attr, &dev_attr_broken_parity_status.attr, &dev_attr_msi_bus.attr, #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a0905a0..8aff29a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -6,6 +6,8 @@ extern const unsigned char pcie_link_speed[]; +bool pcie_cap_has_lnkctl(const struct pci_dev *dev); + /* Functions internal to the PCI core code */ int pci_create_sysfs_dev_files(struct pci_dev *pdev); diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index a9f9c46..63fc639 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -397,6 +397,7 @@ static int pcie_pme_suspend(struct pcie_device *srv) struct pcie_pme_service_data *data = get_service_data(srv); struct pci_dev *port = srv->port; bool wakeup; + int ret; if (device_may_wakeup(&port->dev)) { wakeup = true; @@ -407,9 +408,10 @@ static int pcie_pme_suspend(struct pcie_device *srv) } spin_lock_irq(&data->lock); if (wakeup) { - enable_irq_wake(srv->irq); + ret = enable_irq_wake(srv->irq); data->suspend_level = PME_SUSPEND_WAKEUP; - } else { + } + if (!wakeup || ret) { struct pci_dev *port = srv->port; pcie_pme_interrupt_enable(port, false); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a9e34ca1..23212f8 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -397,15 +397,16 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child) { struct pci_dev *dev = child->self; u16 mem_base_lo, mem_limit_lo; - unsigned long base, limit; + u64 base64, limit64; + dma_addr_t base, limit; struct pci_bus_region region; struct resource *res; res = child->resource[2]; pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); - base = ((unsigned long) mem_base_lo & PCI_PREF_RANGE_MASK) << 16; - limit = ((unsigned long) mem_limit_lo & PCI_PREF_RANGE_MASK) << 16; + base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; + limit64 = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16; if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { u32 mem_base_hi, mem_limit_hi; @@ -419,17 +420,20 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child) * this, just assume they are not being used. */ if (mem_base_hi <= mem_limit_hi) { -#if BITS_PER_LONG == 64 - base |= ((unsigned long) mem_base_hi) << 32; - 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"); - return; - } -#endif + base64 |= (u64) mem_base_hi << 32; + limit64 |= (u64) mem_limit_hi << 32; } } + + base = (dma_addr_t) base64; + limit = (dma_addr_t) limit64; + + if (base != base64) { + dev_err(&dev->dev, "can't handle bridge window above 4GB (bus address %#010llx)\n", + (unsigned long long) base64); + return; + } + if (base <= limit) { res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH; @@ -1313,7 +1317,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) ~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or); /* Initialize Link Control Register */ - if (dev->subordinate) + if (pcie_cap_has_lnkctl(dev)) pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL, ~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or); |