From 99178b036c97293a65004ff5ec5cff9f833aaecd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 26 Aug 2008 11:00:57 -0500 Subject: Driver core: add bus_sort_breadthfirst() function 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 Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers/base/bus.c') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 39b9b58c6974..5aee1c0169ea 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -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); -- cgit v1.2.2