]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/pci/setup-bus.c
Merge tag 'trace-v5.5-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux.git] / drivers / pci / setup-bus.c
index e7dbe21705ba5b0f9c906287656bd2c03f4ece5d..f279826204eb4f51a8b7988802149da81e32eca6 100644 (file)
@@ -752,24 +752,32 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
 }
 
 /*
- * Helper function for sizing routines: find first available bus resource
- * of a given type.  Note: we intentionally skip the bus resources which
- * have already been assigned (that is, have non-NULL parent resource).
+ * Helper function for sizing routines.  Assigned resources have non-NULL
+ * parent resource.
+ *
+ * Return first unassigned resource of the correct type.  If there is none,
+ * return first assigned resource of the correct type.  If none of the
+ * above, return NULL.
+ *
+ * Returning an assigned resource of the correct type allows the caller to
+ * distinguish between already assigned and no resource of the correct type.
  */
-static struct resource *find_free_bus_resource(struct pci_bus *bus,
-                                              unsigned long type_mask,
-                                              unsigned long type)
+static struct resource *find_bus_resource_of_type(struct pci_bus *bus,
+                                                 unsigned long type_mask,
+                                                 unsigned long type)
 {
+       struct resource *r, *r_assigned = NULL;
        int i;
-       struct resource *r;
 
        pci_bus_for_each_resource(bus, r, i) {
                if (r == &ioport_resource || r == &iomem_resource)
                        continue;
                if (r && (r->flags & type_mask) == type && !r->parent)
                        return r;
+               if (r && (r->flags & type_mask) == type && !r_assigned)
+                       r_assigned = r;
        }
-       return NULL;
+       return r_assigned;
 }
 
 static resource_size_t calculate_iosize(resource_size_t size,
@@ -866,8 +874,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
                         struct list_head *realloc_head)
 {
        struct pci_dev *dev;
-       struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO,
-                                                       IORESOURCE_IO);
+       struct resource *b_res = find_bus_resource_of_type(bus, IORESOURCE_IO,
+                                                          IORESOURCE_IO);
        resource_size_t size = 0, size0 = 0, size1 = 0;
        resource_size_t children_add_size = 0;
        resource_size_t min_align, align;
@@ -875,6 +883,10 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
        if (!b_res)
                return;
 
+       /* If resource is already assigned, nothing more to do */
+       if (b_res->parent)
+               return;
+
        min_align = window_alignment(bus, IORESOURCE_IO);
        list_for_each_entry(dev, &bus->devices, bus_list) {
                int i;
@@ -978,7 +990,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        resource_size_t min_align, align, size, size0, size1;
        resource_size_t aligns[18]; /* Alignments from 1MB to 128GB */
        int order, max_order;
-       struct resource *b_res = find_free_bus_resource(bus,
+       struct resource *b_res = find_bus_resource_of_type(bus,
                                        mask | IORESOURCE_PREFETCH, type);
        resource_size_t children_add_size = 0;
        resource_size_t children_add_align = 0;
@@ -987,6 +999,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        if (!b_res)
                return -ENOSPC;
 
+       /* If resource is already assigned, nothing more to do */
+       if (b_res->parent)
+               return 0;
+
        memset(aligns, 0, sizeof(aligns));
        max_order = 0;
        size = 0;
@@ -1178,7 +1194,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
 {
        struct pci_dev *dev;
        unsigned long mask, prefmask, type2 = 0, type3 = 0;
-       resource_size_t additional_mem_size = 0, additional_io_size = 0;
+       resource_size_t additional_io_size = 0, additional_mmio_size = 0,
+                       additional_mmio_pref_size = 0;
        struct resource *b_res;
        int ret;
 
@@ -1212,7 +1229,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                pci_bridge_check_ranges(bus);
                if (bus->self->is_hotplug_bridge) {
                        additional_io_size  = pci_hotplug_io_size;
-                       additional_mem_size = pci_hotplug_mem_size;
+                       additional_mmio_size = pci_hotplug_mmio_size;
+                       additional_mmio_pref_size = pci_hotplug_mmio_pref_size;
                }
                /* Fall through */
        default:
@@ -1230,9 +1248,9 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                if (b_res[2].flags & IORESOURCE_MEM_64) {
                        prefmask |= IORESOURCE_MEM_64;
                        ret = pbus_size_mem(bus, prefmask, prefmask,
-                                 prefmask, prefmask,
-                                 realloc_head ? 0 : additional_mem_size,
-                                 additional_mem_size, realloc_head);
+                               prefmask, prefmask,
+                               realloc_head ? 0 : additional_mmio_pref_size,
+                               additional_mmio_pref_size, realloc_head);
 
                        /*
                         * If successful, all non-prefetchable resources
@@ -1254,9 +1272,9 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                if (!type2) {
                        prefmask &= ~IORESOURCE_MEM_64;
                        ret = pbus_size_mem(bus, prefmask, prefmask,
-                                        prefmask, prefmask,
-                                        realloc_head ? 0 : additional_mem_size,
-                                        additional_mem_size, realloc_head);
+                               prefmask, prefmask,
+                               realloc_head ? 0 : additional_mmio_pref_size,
+                               additional_mmio_pref_size, realloc_head);
 
                        /*
                         * If successful, only non-prefetchable resources
@@ -1265,7 +1283,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                        if (ret == 0)
                                mask = prefmask;
                        else
-                               additional_mem_size += additional_mem_size;
+                               additional_mmio_size += additional_mmio_pref_size;
 
                        type2 = type3 = IORESOURCE_MEM;
                }
@@ -1285,8 +1303,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
                 * prefetchable resource in a 64-bit prefetchable window.
                 */
                pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3,
-                               realloc_head ? 0 : additional_mem_size,
-                               additional_mem_size, realloc_head);
+                             realloc_head ? 0 : additional_mmio_size,
+                             additional_mmio_size, realloc_head);
                break;
        }
 }
@@ -2066,6 +2084,8 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
        unsigned int i;
        int ret;
 
+       down_read(&pci_bus_sem);
+
        /* Walk to the root hub, releasing bridge BARs when possible */
        next = bridge;
        do {
@@ -2100,8 +2120,10 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
                next = bridge->bus ? bridge->bus->self : NULL;
        } while (next);
 
-       if (list_empty(&saved))
+       if (list_empty(&saved)) {
+               up_read(&pci_bus_sem);
                return -ENOENT;
+       }
 
        __pci_bus_size_bridges(bridge->subordinate, &added);
        __pci_bridge_assign_resources(bridge, &added, &failed);
@@ -2122,6 +2144,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
        }
 
        free_list(&saved);
+       up_read(&pci_bus_sem);
        return 0;
 
 cleanup:
@@ -2150,6 +2173,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
                pci_setup_bridge(bridge->subordinate);
        }
        free_list(&saved);
+       up_read(&pci_bus_sem);
 
        return ret;
 }