Driver core: add bus_sort_breadthfirst() function
authorGreg Kroah-Hartman <gregkh@suse.de>
Tue, 26 Aug 2008 16:00:57 +0000 (11:00 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 16 Oct 2008 16:24:52 +0000 (09:24 -0700)
The PCI core wants to reorder the devices in the bus list.  So move this
functionality out of the pci core and into the driver core so that
anyone else can also do this if needed.  This also lets us change how
struct device is attached to drivers in the future without messing with
the PCI core.

Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/base/bus.c
drivers/pci/probe.c
include/linux/device.h

index 39b9b58c6974c72c75e8d2a5293a4ab3adc13819..5aee1c0169eafed102c699281b5bb4875fefd20c 100644 (file)
@@ -980,6 +980,56 @@ struct klist *bus_get_device_klist(struct bus_type *bus)
 }
 EXPORT_SYMBOL_GPL(bus_get_device_klist);
 
+/*
+ * Yes, this forcably breaks the klist abstraction temporarily.  It
+ * just wants to sort the klist, not change reference counts and
+ * take/drop locks rapidly in the process.  It does all this while
+ * holding the lock for the list, so objects can't otherwise be
+ * added/removed while we're swizzling.
+ */
+static void device_insertion_sort_klist(struct device *a, struct list_head *list,
+                                       int (*compare)(const struct device *a,
+                                                       const struct device *b))
+{
+       struct list_head *pos;
+       struct klist_node *n;
+       struct device *b;
+
+       list_for_each(pos, list) {
+               n = container_of(pos, struct klist_node, n_node);
+               b = container_of(n, struct device, knode_bus);
+               if (compare(a, b) <= 0) {
+                       list_move_tail(&a->knode_bus.n_node,
+                                      &b->knode_bus.n_node);
+                       return;
+               }
+       }
+       list_move_tail(&a->knode_bus.n_node, list);
+}
+
+void bus_sort_breadthfirst(struct bus_type *bus,
+                          int (*compare)(const struct device *a,
+                                         const struct device *b))
+{
+       LIST_HEAD(sorted_devices);
+       struct list_head *pos, *tmp;
+       struct klist_node *n;
+       struct device *dev;
+       struct klist *device_klist;
+
+       device_klist = bus_get_device_klist(bus);
+
+       spin_lock(&device_klist->k_lock);
+       list_for_each_safe(pos, tmp, &device_klist->k_list) {
+               n = container_of(pos, struct klist_node, n_node);
+               dev = container_of(n, struct device, knode_bus);
+               device_insertion_sort_klist(dev, &sorted_devices, compare);
+       }
+       list_splice(&sorted_devices, &device_klist->k_list);
+       spin_unlock(&device_klist->k_lock);
+}
+EXPORT_SYMBOL_GPL(bus_sort_breadthfirst);
+
 int __init buses_init(void)
 {
        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
index 36698e57b97f659dbc20f03f4f6df6fe0e718694..dd9161a054e1c1264891a918a634d5a60fa0d062 100644 (file)
@@ -1237,8 +1237,11 @@ EXPORT_SYMBOL(pci_scan_bridge);
 EXPORT_SYMBOL_GPL(pci_scan_child_bus);
 #endif
 
-static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b)
+static int __init pci_sort_bf_cmp(const struct device *d_a, const struct device *d_b)
 {
+       const struct pci_dev *a = to_pci_dev(d_a);
+       const struct pci_dev *b = to_pci_dev(d_b);
+
        if      (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1;
        else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return  1;
 
@@ -1251,50 +1254,7 @@ static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev
        return 0;
 }
 
-/*
- * Yes, this forcably breaks the klist abstraction temporarily.  It
- * just wants to sort the klist, not change reference counts and
- * take/drop locks rapidly in the process.  It does all this while
- * holding the lock for the list, so objects can't otherwise be
- * added/removed while we're swizzling.
- */
-static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list)
-{
-       struct list_head *pos;
-       struct klist_node *n;
-       struct device *dev;
-       struct pci_dev *b;
-
-       list_for_each(pos, list) {
-               n = container_of(pos, struct klist_node, n_node);
-               dev = container_of(n, struct device, knode_bus);
-               b = to_pci_dev(dev);
-               if (pci_sort_bf_cmp(a, b) <= 0) {
-                       list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node);
-                       return;
-               }
-       }
-       list_move_tail(&a->dev.knode_bus.n_node, list);
-}
-
 void __init pci_sort_breadthfirst(void)
 {
-       LIST_HEAD(sorted_devices);
-       struct list_head *pos, *tmp;
-       struct klist_node *n;
-       struct device *dev;
-       struct pci_dev *pdev;
-       struct klist *device_klist;
-
-       device_klist = bus_get_device_klist(&pci_bus_type);
-
-       spin_lock(&device_klist->k_lock);
-       list_for_each_safe(pos, tmp, &device_klist->k_list) {
-               n = container_of(pos, struct klist_node, n_node);
-               dev = container_of(n, struct device, knode_bus);
-               pdev = to_pci_dev(dev);
-               pci_insertion_sort_klist(pdev, &sorted_devices);
-       }
-       list_splice(&sorted_devices, &device_klist->k_list);
-       spin_unlock(&device_klist->k_lock);
+       bus_sort_breadthfirst(&pci_bus_type, &pci_sort_bf_cmp);
 }
index ec90e79f6a00e80d671ef10dfb93fe7ad99360bb..987f5912720a2d6ffd6d32a33a062e3b4ef27892 100644 (file)
@@ -90,6 +90,9 @@ int __must_check bus_for_each_drv(struct bus_type *bus,
                                  struct device_driver *start, void *data,
                                  int (*fn)(struct device_driver *, void *));
 
+void bus_sort_breadthfirst(struct bus_type *bus,
+                          int (*compare)(const struct device *a,
+                                         const struct device *b));
 /*
  * Bus notifiers: Get notified of addition/removal of devices
  * and binding/unbinding of drivers to devices.