Merge tag 'pci-v3.19-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 23 Jan 2015 22:58:47 +0000 (10:58 +1200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 23 Jan 2015 22:58:47 +0000 (10:58 +1200)
Pull PCI fixes from Bjorn Helgaas:
 "These are fixes for:

   - a resource management problem that causes a Radeon "Fatal error
     during GPU init" on machines where the BIOS programmed an invalid
     Root Port window.  This was a regression in v3.16.

   - an Atheros AR93xx device that doesn't handle PCI bus resets
     correctly.  This was a regression in v3.14.

   - an out-of-date email address"

* tag 'pci-v3.19-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  MAINTAINERS: Update Richard Zhu's email address
  sparc/PCI: Clip bridge windows to fit in upstream windows
  powerpc/PCI: Clip bridge windows to fit in upstream windows
  parisc/PCI: Clip bridge windows to fit in upstream windows
  mn10300/PCI: Clip bridge windows to fit in upstream windows
  microblaze/PCI: Clip bridge windows to fit in upstream windows
  ia64/PCI: Clip bridge windows to fit in upstream windows
  frv/PCI: Clip bridge windows to fit in upstream windows
  alpha/PCI: Clip bridge windows to fit in upstream windows
  x86/PCI: Clip bridge windows to fit in upstream windows
  PCI: Add pci_claim_bridge_resource() to clip window if necessary
  PCI: Add pci_bus_clip_resource() to clip to fit upstream window
  PCI: Pass bridge device, not bus, when updating bridge windows
  PCI: Mark Atheros AR93xx to avoid bus reset
  PCI: Add flag for devices where we can't use bus reset

17 files changed:
MAINTAINERS
arch/alpha/kernel/pci.c
arch/frv/mb93090-mb00/pci-frv.c
arch/ia64/pci/pci.c
arch/microblaze/pci/pci-common.c
arch/mn10300/unit-asb2305/pci-asb2305.c
arch/mn10300/unit-asb2305/pci.c
arch/powerpc/kernel/pci-common.c
arch/sparc/kernel/pci.c
arch/x86/pci/i386.c
drivers/parisc/lba_pci.c
drivers/pci/bus.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/quirks.c
drivers/pci/setup-bus.c
include/linux/pci.h

index 55b7024579abb88d48ad0a2822de54fda7c951c3..6b7a694bf454935fd767f675ddd7e4ba529634b0 100644 (file)
@@ -7274,7 +7274,7 @@ S:        Maintained
 F:     drivers/pci/host/*layerscape*
 
 PCI DRIVER FOR IMX6
-M:     Richard Zhu <r65037@freescale.com>
+M:     Richard Zhu <Richard.Zhu@freescale.com>
 M:     Lucas Stach <l.stach@pengutronix.de>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
index 076c35cd6cde7c2d782a46fe3942b8962369230e..98a1525fa164df0178fd4cb5fc0267129b2844e3 100644 (file)
@@ -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);
+                       }
                }
        }
 
index 67b1d16857593ddc083bf45cc8fd9e19d5430994..0635bd6c2af392fc372b0e02002b1a669a88e33c 100644 (file)
@@ -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);
index 291a582777cf3dd0320f4757ea1f9c1fc39dd17c..900cc93e540961903816fd8d69769a3311fdbbf3 100644 (file)
@@ -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);
+       }
 }
 
 /*
index b30e41c0c0335cf2ab79e716c9c41c0ebced18e8..48528fb81effa07ef5c992c08efba2cad6a75ff0 100644 (file)
@@ -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);
                }
        }
 
index febb9cd83177177e4c0edffa6d4c2d34b4a2b2a0..b5b036f64275b0fe0176132b74f4715f185f7503 100644 (file)
@@ -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",
index 6b4339f8c9c2e1e757f13fddccb9053c2c292b0c..471ff398090cd88e89089b5387d1a1f4dc0dcc0a 100644 (file)
@@ -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)
index 37d512d35943400737d36be40448c063f9ee76f0..2a525c938158e7937445837ef6448354b5147758 100644 (file)
@@ -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);
                }
        }
 
index b36365f49478c573d715816d53582e2dfb153227..9ce5afe167ff509288b21605a2f9a35f96ff36dc 100644 (file)
@@ -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);
                }
        }
 
index 9b18ef315a559bca66ba227da77ac2d329475f19..349c0d32cc0b140222141cfec5fa29a8c6ddbace 100644 (file)
@@ -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
index 37e71ff6408dca41ff5790417f549eead9ddea97..dceb9ddfd99af6d754b0190fe2eb99431f64f4a6 100644 (file)
@@ -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;
index 73aef51a28f0760fefa6b4344235e7f341bebb3d..8fb16188cd82aaff9d346a70f46e0257e468fe29 100644 (file)
@@ -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) { }
 
 /**
index cab05f31223f08166cc0a8e179759fc99812a286..e9d4fd861ba1c84a82f9561841d4e1da26715a2a 100644 (file)
@@ -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)
index 8aff29a804ffa6e9ddaa30e2277d5d654f1df508..d54632a1db43cbed30d89fb91b84fef489cbc4a4 100644 (file)
@@ -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
index ed6f89b6efe5c2cab127dd15613cab59be736fd7..e52356aa09b87adc778a29bbc3ca40c1ffdf638d 100644 (file)
@@ -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.
index 0482235eee9262f79ecd69f907c8c41c2364d914..e3e17f3c0f0f2929da94d7411c0740a391dc56c6 100644 (file)
@@ -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, &region, 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, &region, 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, &region, 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);
 }
@@ -649,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. */
index 360a966a97a5807f7ff13441748c0c93850ff7e1..9603094ed59b2adb5defa9eb93a955c5ce93e543 100644 (file)
@@ -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 {
@@ -1065,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);