From f331a859e0ee5a898c1f47596eddad4c4f02d657 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 15 Jan 2015 18:16:04 -0600 Subject: PCI: Add flag for devices where we can't use bus reset Enable a mechanism for devices to quirk that they do not behave when doing a PCI bus reset. We require a modest level of spec compliant behavior in order to do a reset, for instance the device should come out of reset without throwing errors and PCI config space should be accessible after reset. This is too much to ask for some devices. Link: http://lkml.kernel.org/r/20140923210318.498dacbd@dualc.maya.org Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.14+ --- drivers/pci/pci.c | 40 ++++++++++++++++++++++++++++++++++++---- include/linux/pci.h | 2 ++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cab05f31223..e9d4fd861ba 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3271,7 +3271,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe) { struct pci_dev *pdev; - if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self) + if (pci_is_root_bus(dev->bus) || dev->subordinate || + !dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET) return -ENOTTY; list_for_each_entry(pdev, &dev->bus->devices, bus_list) @@ -3305,7 +3306,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) { struct pci_dev *pdev; - if (dev->subordinate || !dev->slot) + if (dev->subordinate || !dev->slot || + dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET) return -ENOTTY; list_for_each_entry(pdev, &dev->bus->devices, bus_list) @@ -3557,6 +3559,20 @@ int pci_try_reset_function(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_try_reset_function); +/* Do any devices on or below this bus prevent a bus reset? */ +static bool pci_bus_resetable(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || + (dev->subordinate && !pci_bus_resetable(dev->subordinate))) + return false; + } + + return true; +} + /* Lock devices from the top of the tree down */ static void pci_bus_lock(struct pci_bus *bus) { @@ -3607,6 +3623,22 @@ unlock: return 0; } +/* Do any devices on or below this slot prevent a bus reset? */ +static bool pci_slot_resetable(struct pci_slot *slot) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &slot->bus->devices, bus_list) { + if (!dev->slot || dev->slot != slot) + continue; + if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || + (dev->subordinate && !pci_bus_resetable(dev->subordinate))) + return false; + } + + return true; +} + /* Lock devices from the top of the tree down */ static void pci_slot_lock(struct pci_slot *slot) { @@ -3728,7 +3760,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe) { int rc; - if (!slot) + if (!slot || !pci_slot_resetable(slot)) return -ENOTTY; if (!probe) @@ -3820,7 +3852,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot); static int pci_bus_reset(struct pci_bus *bus, int probe) { - if (!bus->self) + if (!bus->self || !pci_bus_resetable(bus)) return -ENOTTY; if (probe) diff --git a/include/linux/pci.h b/include/linux/pci.h index 360a966a97a..44627f1df4c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -175,6 +175,8 @@ enum pci_dev_flags { PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4), /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), + /* Do not use bus resets for device */ + PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6), }; enum pci_irq_reroute_variant { -- cgit v1.2.3-70-g09d2 From c3e59ee4e76686b0c84ca8faa1011d10cd4ca1b8 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 15 Jan 2015 18:17:12 -0600 Subject: PCI: Mark Atheros AR93xx to avoid bus reset Reports against the TL-WDN4800 card indicate that PCI bus reset of this Atheros device cause system lock-ups and resets. I've also been able to confirm this behavior on multiple systems. The device never returns from reset and attempts to access config space of the device after reset result in hangs. Blacklist bus reset for the device to avoid this issue. [bhelgaas: This regression appeared in v3.14. Andreas bisected it to 425c1b223dac ("PCI: Add Virtual Channel to save/restore support"), but we don't understand the mechanism by which that commit affects the reset path.] [bhelgaas: changelog, references] Link: http://lkml.kernel.org/r/20140923210318.498dacbd@dualc.maya.org Reported-by: Andreas Hartmann Tested-by: Andreas Hartmann Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.14+ --- drivers/pci/quirks.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ed6f89b6efe..e52356aa09b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3028,6 +3028,20 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169, DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, quirk_broken_intx_masking); +static void quirk_no_bus_reset(struct pci_dev *dev) +{ + dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET; +} + +/* + * Atheros AR93xx chips do not behave after a bus reset. The device will + * throw a Link Down error on AER-capable systems and regardless of AER, + * config space of the device is never accessible again and typically + * causes the system to hang or reset when access is attempted. + * http://www.spinics.net/lists/linux-pci/msg34797.html + */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset); + #ifdef CONFIG_ACPI /* * Apple: Shutdown Cactus Ridge Thunderbolt controller. -- cgit v1.2.3-70-g09d2 From 3f2f4dc456e9f80849b99d79600a7257690ca4b1 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 10:22:31 -0600 Subject: PCI: Pass bridge device, not bus, when updating bridge windows pci_setup_bridge_io(), pci_setup_bridge_mmio(), and pci_setup_bridge_mmio_pref() program the windows of PCI-PCI bridges. Previously they accepted a pointer to the pci_bus of the secondary bus, then looked up the bridge leading to that bus. Pass the bridge directly, which will make it more convenient for future callers. No functional change. [bhelgaas: changelog, split into separate patch] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.16+ --- drivers/pci/setup-bus.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 0482235eee9..802f56be214 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -530,9 +530,8 @@ EXPORT_SYMBOL(pci_setup_cardbus); config space writes, so it's quite possible that an I/O window of the bridge will have some undesirable address (e.g. 0) after the first write. Ditto 64-bit prefetchable MMIO. */ -static void pci_setup_bridge_io(struct pci_bus *bus) +static void pci_setup_bridge_io(struct pci_dev *bridge) { - struct pci_dev *bridge = bus->self; struct resource *res; struct pci_bus_region region; unsigned long io_mask; @@ -545,7 +544,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus) io_mask = PCI_IO_1K_RANGE_MASK; /* Set up the top and bottom of the PCI I/O segment for this bus. */ - res = bus->resource[0]; + res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0]; pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_IO) { pci_read_config_word(bridge, PCI_IO_BASE, &l); @@ -568,15 +567,14 @@ static void pci_setup_bridge_io(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); } -static void pci_setup_bridge_mmio(struct pci_bus *bus) +static void pci_setup_bridge_mmio(struct pci_dev *bridge) { - struct pci_dev *bridge = bus->self; struct resource *res; struct pci_bus_region region; u32 l; /* Set up the top and bottom of the PCI Memory segment for this bus. */ - res = bus->resource[1]; + res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1]; pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_MEM) { l = (region.start >> 16) & 0xfff0; @@ -588,9 +586,8 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); } -static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) +static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge) { - struct pci_dev *bridge = bus->self; struct resource *res; struct pci_bus_region region; u32 l, bu, lu; @@ -602,7 +599,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) /* Set up PREF base/limit. */ bu = lu = 0; - res = bus->resource[2]; + res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2]; pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_PREFETCH) { l = (region.start >> 16) & 0xfff0; @@ -630,13 +627,13 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) &bus->busn_res); if (type & IORESOURCE_IO) - pci_setup_bridge_io(bus); + pci_setup_bridge_io(bridge); if (type & IORESOURCE_MEM) - pci_setup_bridge_mmio(bus); + pci_setup_bridge_mmio(bridge); if (type & IORESOURCE_PREFETCH) - pci_setup_bridge_mmio_pref(bus); + pci_setup_bridge_mmio_pref(bridge); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } -- cgit v1.2.3-70-g09d2 From 0f7e7aee2f37119a32e6e8b63250922442528961 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:49 -0600 Subject: PCI: Add pci_bus_clip_resource() to clip to fit upstream window Add pci_bus_clip_resource(). If a PCI-PCI bridge window overlaps an upstream bridge window but is not completely contained by it, this clips the downstream window so it fits inside the upstream one. No functional change (this adds the function but no callers). [bhelgaas: changelog, split into separate patch] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.16+ --- drivers/pci/bus.c | 43 +++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 1 + 2 files changed, 44 insertions(+) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 73aef51a28f..8fb16188cd8 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -228,6 +228,49 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, } EXPORT_SYMBOL(pci_bus_alloc_resource); +/* + * The @idx resource of @dev should be a PCI-PCI bridge window. If this + * resource fits inside a window of an upstream bridge, do nothing. If it + * overlaps an upstream window but extends outside it, clip the resource so + * it fits completely inside. + */ +bool pci_bus_clip_resource(struct pci_dev *dev, int idx) +{ + struct pci_bus *bus = dev->bus; + struct resource *res = &dev->resource[idx]; + struct resource orig_res = *res; + struct resource *r; + int i; + + pci_bus_for_each_resource(bus, r, i) { + resource_size_t start, end; + + if (!r) + continue; + + if (resource_type(res) != resource_type(r)) + continue; + + start = max(r->start, res->start); + end = min(r->end, res->end); + + if (start > end) + continue; /* no overlap */ + + if (res->start == start && res->end == end) + return false; /* no change */ + + res->start = start; + res->end = end; + dev_printk(KERN_DEBUG, &dev->dev, "%pR clipped to %pR\n", + &orig_res, res); + + return true; + } + + return false; +} + void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } /** diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8aff29a804f..d54632a1db4 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -208,6 +208,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, void __pci_bus_assign_resources(const struct pci_bus *bus, struct list_head *realloc_head, struct list_head *fail_head); +bool pci_bus_clip_resource(struct pci_dev *dev, int idx); /** * pci_ari_enabled - query ARI forwarding status -- cgit v1.2.3-70-g09d2 From 8505e729a2f6eb0803ff943a15f133dd10afff3a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:49 -0600 Subject: PCI: Add pci_claim_bridge_resource() to clip window if necessary Add pci_claim_bridge_resource() to claim a PCI-PCI bridge window. This is like regular pci_claim_resource(), except that if we fail to claim the window, we check to see if we can reduce the size of the window and try again. This is for scenarios like this: pci_bus 0000:00: root bus resource [mem 0xc0000000-0xffffffff] pci 0000:00:01.0: bridge window [mem 0xbdf00000-0xddefffff 64bit pref] pci 0000:01:00.0: reg 0x10: [mem 0xc0000000-0xcfffffff pref] The 00:01.0 window is illegal: it starts before the host bridge window, so we have to assume the [0xbdf00000-0xbfffffff] region is inaccessible. We can make it legal by clipping it to [mem 0xc0000000-0xddefffff 64bit pref]. Previously we discarded the 00:01.0 window and tried to reassign that part of the hierarchy from scratch. That is a problem because Linux doesn't always assign things optimally. For example, in this case, BIOS put the 01:00.0 device in a prefetchable window below 4GB, but after 5b28541552ef, Linux puts the prefetchable window above 4GB where the 32-bit 01:00.0 device can't use it. Clipping the 00:01.0 window is less intrusive than completely reassigning things and is sufficient to let us use most of the BIOS configuration. Of course, it's possible that devices below 00:01.0 will no longer fit. If that's the case, we'll have to reassign things. But that's a separate problem. [bhelgaas: changelog, split into separate patch] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.16+ --- drivers/pci/setup-bus.c | 35 +++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 36 insertions(+) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 802f56be214..e3e17f3c0f0 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -646,6 +646,41 @@ void pci_setup_bridge(struct pci_bus *bus) __pci_setup_bridge(bus, type); } + +int pci_claim_bridge_resource(struct pci_dev *bridge, int i) +{ + if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END) + return 0; + + if (pci_claim_resource(bridge, i) == 0) + return 0; /* claimed the window */ + + if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI) + return 0; + + if (!pci_bus_clip_resource(bridge, i)) + return -EINVAL; /* clipping didn't change anything */ + + switch (i - PCI_BRIDGE_RESOURCES) { + case 0: + pci_setup_bridge_io(bridge); + break; + case 1: + pci_setup_bridge_mmio(bridge); + break; + case 2: + pci_setup_bridge_mmio_pref(bridge); + break; + default: + return -EINVAL; + } + + if (pci_claim_resource(bridge, i) == 0) + return 0; /* claimed a smaller window */ + + return -EINVAL; +} + /* Check whether the bridge supports optional I/O and prefetchable memory ranges. If not, the respective base/limit registers must be read-only and read as 0. */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 44627f1df4c..9603094ed59 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1067,6 +1067,7 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx); void pci_bus_assign_resources(const struct pci_bus *bus); void pci_bus_size_bridges(struct pci_bus *bus); int pci_claim_resource(struct pci_dev *, int); +int pci_claim_bridge_resource(struct pci_dev *bridge, int i); void pci_assign_unassigned_resources(void); void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); void pci_assign_unassigned_bus_resources(struct pci_bus *bus); -- cgit v1.2.3-70-g09d2 From 851b09369255a91e77f56d83e3643439ac5b209a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:49 -0600 Subject: x86/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Tested-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: Thomas Gleixner CC: Ingo Molnar CC: "H. Peter Anvin" CC: x86@kernel.org CC: stable@vger.kernel.org # v3.16+ --- arch/x86/pci/i386.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 9b18ef315a5..349c0d32cc0 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -216,7 +216,7 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev) continue; if (r->parent) /* Already allocated */ continue; - if (!r->start || pci_claim_resource(dev, idx) < 0) { + if (!r->start || pci_claim_bridge_resource(dev, idx) < 0) { /* * Something is wrong with the region. * Invalidate the resource to prevent -- cgit v1.2.3-70-g09d2 From b3e118224c011b885ef8331bd5b341f15b3bd69a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:49 -0600 Subject: alpha/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: Richard Henderson CC: Ivan Kokshaysky CC: Matt Turner CC: linux-alpha@vger.kernel.org --- arch/alpha/kernel/pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 076c35cd6cd..98a1525fa16 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -285,8 +285,12 @@ pcibios_claim_one_bus(struct pci_bus *b) if (r->parent || !r->start || !r->flags) continue; if (pci_has_flag(PCI_PROBE_ONLY) || - (r->flags & IORESOURCE_PCI_FIXED)) - pci_claim_resource(dev, i); + (r->flags & IORESOURCE_PCI_FIXED)) { + if (pci_claim_resource(dev, i) == 0) + continue; + + pci_claim_bridge_resource(dev, i); + } } } -- cgit v1.2.3-70-g09d2 From b0c568de32bad5dc19722ba90ebe07e358675e51 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:49 -0600 Subject: frv/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: David Howells CC: Paul Gortmaker --- arch/frv/mb93090-mb00/pci-frv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c index 67b1d168575..0635bd6c2af 100644 --- a/arch/frv/mb93090-mb00/pci-frv.c +++ b/arch/frv/mb93090-mb00/pci-frv.c @@ -94,7 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) r = &dev->resource[idx]; if (!r->start) continue; - pci_claim_resource(dev, idx); + pci_claim_bridge_resource(dev, idx); } } pcibios_allocate_bus_resources(&bus->children); -- cgit v1.2.3-70-g09d2 From ce821ef0333fc130154ed3091144a590c1909f4d Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:50 -0600 Subject: ia64/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: Tony Luck CC: Fenghua Yu CC: "Rafael J. Wysocki" CC: linux-ia64@vger.kernel.org --- arch/ia64/pci/pci.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 291a582777c..900cc93e540 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -487,45 +487,39 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) return 0; } -static int is_valid_resource(struct pci_dev *dev, int idx) +void pcibios_fixup_device_resources(struct pci_dev *dev) { - unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; - struct resource *devr = &dev->resource[idx], *busr; + int idx; if (!dev->bus) - return 0; - - pci_bus_for_each_resource(dev->bus, busr, i) { - if (!busr || ((busr->flags ^ devr->flags) & type_mask)) - continue; - if ((devr->start) && (devr->start >= busr->start) && - (devr->end <= busr->end)) - return 1; - } - return 0; -} + return; -static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit) -{ - int i; + for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; - for (i = start; i < limit; i++) { - if (!dev->resource[i].flags) + if (!r->flags || r->parent || !r->start) continue; - if ((is_valid_resource(dev, i))) - pci_claim_resource(dev, i); - } -} -void pcibios_fixup_device_resources(struct pci_dev *dev) -{ - pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES); + pci_claim_resource(dev, idx); + } } EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); static void pcibios_fixup_bridge_resources(struct pci_dev *dev) { - pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES); + int idx; + + if (!dev->bus) + return; + + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; + + if (!r->flags || r->parent || !r->start) + continue; + + pci_claim_bridge_resource(dev, idx); + } } /* -- cgit v1.2.3-70-g09d2 From 576e4385ff59f52ca0e9a6a953a55f1f76fc196b Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:50 -0600 Subject: microblaze/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: Michal Simek CC: Benjamin Herrenschmidt CC: Sebastian Ott --- arch/microblaze/pci/pci-common.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index b30e41c0c03..48528fb81ef 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -1026,6 +1026,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) pr, (pr && pr->name) ? pr->name : "nil"); if (pr && !(pr->flags & IORESOURCE_UNSET)) { + struct pci_dev *dev = bus->self; + if (request_resource(pr, res) == 0) continue; /* @@ -1035,6 +1037,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) */ if (reparent_resources(pr, res) == 0) continue; + + if (dev && i < PCI_BRIDGE_RESOURCE_NUM && + pci_claim_bridge_resource(dev, + i + PCI_BRIDGE_RESOURCES) == 0) + continue; + } pr_warn("PCI: Cannot allocate resource region "); pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number); @@ -1227,7 +1235,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) (unsigned long long)r->end, (unsigned int)r->flags); - pci_claim_resource(dev, i); + if (pci_claim_resource(dev, i) == 0) + continue; + + pci_claim_bridge_resource(dev, i); } } -- cgit v1.2.3-70-g09d2 From 4e348ba2dd1c1d6ea191566d7591655bbe9dde64 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:50 -0600 Subject: mn10300/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: David Howells CC: Koichi Yasutake CC: linux-am33-list@redhat.com --- arch/mn10300/unit-asb2305/pci-asb2305.c | 2 +- arch/mn10300/unit-asb2305/pci.c | 47 +++++++++++++++------------------ 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c index febb9cd8317..b5b036f6427 100644 --- a/arch/mn10300/unit-asb2305/pci-asb2305.c +++ b/arch/mn10300/unit-asb2305/pci-asb2305.c @@ -106,7 +106,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) if (!r->flags) continue; if (!r->start || - pci_claim_resource(dev, idx) < 0) { + pci_claim_bridge_resource(dev, idx) < 0) { printk(KERN_ERR "PCI:" " Cannot allocate resource" " region %d of bridge %s\n", diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c index 6b4339f8c9c..471ff398090 100644 --- a/arch/mn10300/unit-asb2305/pci.c +++ b/arch/mn10300/unit-asb2305/pci.c @@ -281,42 +281,37 @@ static int __init pci_check_direct(void) return -ENODEV; } -static int is_valid_resource(struct pci_dev *dev, int idx) +static void pcibios_fixup_device_resources(struct pci_dev *dev) { - unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; - struct resource *devr = &dev->resource[idx], *busr; - - if (dev->bus) { - pci_bus_for_each_resource(dev->bus, busr, i) { - if (!busr || (busr->flags ^ devr->flags) & type_mask) - continue; - - if (devr->start && - devr->start >= busr->start && - devr->end <= busr->end) - return 1; - } - } + int idx; - return 0; + if (!dev->bus) + return; + + for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; + + if (!r->flags || r->parent || !r->start) + continue; + + pci_claim_resource(dev, idx); + } } -static void pcibios_fixup_device_resources(struct pci_dev *dev) +static void pcibios_fixup_bridge_resources(struct pci_dev *dev) { - int limit, i; + int idx; - if (dev->bus->number != 0) + if (!dev->bus) return; - limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? - PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES; + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; - for (i = 0; i < limit; i++) { - if (!dev->resource[i].flags) + if (!r->flags || r->parent || !r->start) continue; - if (is_valid_resource(dev, i)) - pci_claim_resource(dev, i); + pci_claim_bridge_resource(dev, idx); } } @@ -330,7 +325,7 @@ void pcibios_fixup_bus(struct pci_bus *bus) if (bus->self) { pci_read_bridge_bases(bus); - pcibios_fixup_device_resources(bus->self); + pcibios_fixup_bridge_resources(bus->self); } list_for_each_entry(dev, &bus->devices, bus_list) -- cgit v1.2.3-70-g09d2 From 2e5e804a836ec89e126443c8efe666b56e4e58a9 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:50 -0600 Subject: parisc/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: "James E.J. Bottomley" CC: Helge Deller CC: linux-parisc@vger.kernel.org --- drivers/parisc/lba_pci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 37e71ff6408..dceb9ddfd99 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -694,9 +694,8 @@ lba_fixup_bus(struct pci_bus *bus) int i; /* PCI-PCI Bridge */ pci_read_bridge_bases(bus); - for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { - pci_claim_resource(bus->self, i); - } + for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) + pci_claim_bridge_resource(bus->self, i); } else { /* Host-PCI Bridge */ int err; -- cgit v1.2.3-70-g09d2 From 3ebfe46ac72c0bda0fee3d33dd4cfe88f43cefd9 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:51 -0600 Subject: powerpc/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: Benjamin Herrenschmidt CC: Paul Mackerras CC: Michael Ellerman CC: Gavin Shan CC: Anton Blanchard CC: Sebastian Ott CC: Wei Yang CC: Andrew Murray CC: linuxppc-dev@lists.ozlabs.org --- arch/powerpc/kernel/pci-common.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 37d512d3594..2a525c93815 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1184,6 +1184,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) pr, (pr && pr->name) ? pr->name : "nil"); if (pr && !(pr->flags & IORESOURCE_UNSET)) { + struct pci_dev *dev = bus->self; + if (request_resource(pr, res) == 0) continue; /* @@ -1193,6 +1195,11 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) */ if (reparent_resources(pr, res) == 0) continue; + + if (dev && i < PCI_BRIDGE_RESOURCE_NUM && + pci_claim_bridge_resource(dev, + i + PCI_BRIDGE_RESOURCES) == 0) + continue; } pr_warning("PCI: Cannot allocate resource region " "%d of PCI bridge %d, will remap\n", i, bus->number); @@ -1401,7 +1408,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) (unsigned long long)r->end, (unsigned int)r->flags); - pci_claim_resource(dev, i); + if (pci_claim_resource(dev, i) == 0) + continue; + + pci_claim_bridge_resource(dev, i); } } -- cgit v1.2.3-70-g09d2 From d63e2e1f3df904bf6bd150bdafb42ddbb3257ea8 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 15 Jan 2015 16:21:51 -0600 Subject: sparc/PCI: Clip bridge windows to fit in upstream windows Every PCI-PCI bridge window should fit inside an upstream bridge window because orphaned address space is unreachable from the primary side of the upstream bridge. If we inherit invalid bridge windows that overlap an upstream window from firmware, clip them to fit and update the bridge accordingly. [bhelgaas: changelog] Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491 Reported-by: Marek Kordik Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: David S. Miller CC: Paul Gortmaker CC: Yijing Wang CC: Sam Ravnborg CC: sparclinux@vger.kernel.org --- arch/sparc/kernel/pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index b36365f4947..9ce5afe167f 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -639,7 +639,10 @@ static void pci_claim_bus_resources(struct pci_bus *bus) (unsigned long long)r->end, (unsigned int)r->flags); - pci_claim_resource(dev, i); + if (pci_claim_resource(dev, i) == 0) + continue; + + pci_claim_bridge_resource(dev, i); } } -- cgit v1.2.3-70-g09d2 From f175aa2c9f6cc08f043e85ea37f44ef3676cbac1 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 19 Jan 2015 11:17:31 +0100 Subject: MAINTAINERS: Update Richard Zhu's email address The old cryptic address bounces, fix it by using a properly working one. Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Richard Zhu --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ddb9ac8d32b..c78f2d1fb58 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7229,7 +7229,7 @@ S: Maintained F: drivers/pci/host/*layerscape* PCI DRIVER FOR IMX6 -M: Richard Zhu +M: Richard Zhu M: Lucas Stach L: linux-pci@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -- cgit v1.2.3-70-g09d2