aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2008-08-26 12:00:57 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-10-16 12:24:52 -0400
commit99178b036c97293a65004ff5ec5cff9f833aaecd (patch)
treec83ac6855710038ad9846f79b952b7fdcca528f8
parent26853ab6f9a4c482be4b638477335704724d4854 (diff)
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 <jbarnes@virtuousgeek.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/base/bus.c50
-rw-r--r--drivers/pci/probe.c50
-rw-r--r--include/linux/device.h3
3 files changed, 58 insertions, 45 deletions
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)
980} 980}
981EXPORT_SYMBOL_GPL(bus_get_device_klist); 981EXPORT_SYMBOL_GPL(bus_get_device_klist);
982 982
983/*
984 * Yes, this forcably breaks the klist abstraction temporarily. It
985 * just wants to sort the klist, not change reference counts and
986 * take/drop locks rapidly in the process. It does all this while
987 * holding the lock for the list, so objects can't otherwise be
988 * added/removed while we're swizzling.
989 */
990static void device_insertion_sort_klist(struct device *a, struct list_head *list,
991 int (*compare)(const struct device *a,
992 const struct device *b))
993{
994 struct list_head *pos;
995 struct klist_node *n;
996 struct device *b;
997
998 list_for_each(pos, list) {
999 n = container_of(pos, struct klist_node, n_node);
1000 b = container_of(n, struct device, knode_bus);
1001 if (compare(a, b) <= 0) {
1002 list_move_tail(&a->knode_bus.n_node,
1003 &b->knode_bus.n_node);
1004 return;
1005 }
1006 }
1007 list_move_tail(&a->knode_bus.n_node, list);
1008}
1009
1010void bus_sort_breadthfirst(struct bus_type *bus,
1011 int (*compare)(const struct device *a,
1012 const struct device *b))
1013{
1014 LIST_HEAD(sorted_devices);
1015 struct list_head *pos, *tmp;
1016 struct klist_node *n;
1017 struct device *dev;
1018 struct klist *device_klist;
1019
1020 device_klist = bus_get_device_klist(bus);
1021
1022 spin_lock(&device_klist->k_lock);
1023 list_for_each_safe(pos, tmp, &device_klist->k_list) {
1024 n = container_of(pos, struct klist_node, n_node);
1025 dev = container_of(n, struct device, knode_bus);
1026 device_insertion_sort_klist(dev, &sorted_devices, compare);
1027 }
1028 list_splice(&sorted_devices, &device_klist->k_list);
1029 spin_unlock(&device_klist->k_lock);
1030}
1031EXPORT_SYMBOL_GPL(bus_sort_breadthfirst);
1032
983int __init buses_init(void) 1033int __init buses_init(void)
984{ 1034{
985 bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); 1035 bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 36698e57b97f..dd9161a054e1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1237,8 +1237,11 @@ EXPORT_SYMBOL(pci_scan_bridge);
1237EXPORT_SYMBOL_GPL(pci_scan_child_bus); 1237EXPORT_SYMBOL_GPL(pci_scan_child_bus);
1238#endif 1238#endif
1239 1239
1240static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b) 1240static int __init pci_sort_bf_cmp(const struct device *d_a, const struct device *d_b)
1241{ 1241{
1242 const struct pci_dev *a = to_pci_dev(d_a);
1243 const struct pci_dev *b = to_pci_dev(d_b);
1244
1242 if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1; 1245 if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1;
1243 else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1; 1246 else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1;
1244 1247
@@ -1251,50 +1254,7 @@ static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev
1251 return 0; 1254 return 0;
1252} 1255}
1253 1256
1254/*
1255 * Yes, this forcably breaks the klist abstraction temporarily. It
1256 * just wants to sort the klist, not change reference counts and
1257 * take/drop locks rapidly in the process. It does all this while
1258 * holding the lock for the list, so objects can't otherwise be
1259 * added/removed while we're swizzling.
1260 */
1261static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list)
1262{
1263 struct list_head *pos;
1264 struct klist_node *n;
1265 struct device *dev;
1266 struct pci_dev *b;
1267
1268 list_for_each(pos, list) {
1269 n = container_of(pos, struct klist_node, n_node);
1270 dev = container_of(n, struct device, knode_bus);
1271 b = to_pci_dev(dev);
1272 if (pci_sort_bf_cmp(a, b) <= 0) {
1273 list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node);
1274 return;
1275 }
1276 }
1277 list_move_tail(&a->dev.knode_bus.n_node, list);
1278}
1279
1280void __init pci_sort_breadthfirst(void) 1257void __init pci_sort_breadthfirst(void)
1281{ 1258{
1282 LIST_HEAD(sorted_devices); 1259 bus_sort_breadthfirst(&pci_bus_type, &pci_sort_bf_cmp);
1283 struct list_head *pos, *tmp;
1284 struct klist_node *n;
1285 struct device *dev;
1286 struct pci_dev *pdev;
1287 struct klist *device_klist;
1288
1289 device_klist = bus_get_device_klist(&pci_bus_type);
1290
1291 spin_lock(&device_klist->k_lock);
1292 list_for_each_safe(pos, tmp, &device_klist->k_list) {
1293 n = container_of(pos, struct klist_node, n_node);
1294 dev = container_of(n, struct device, knode_bus);
1295 pdev = to_pci_dev(dev);
1296 pci_insertion_sort_klist(pdev, &sorted_devices);
1297 }
1298 list_splice(&sorted_devices, &device_klist->k_list);
1299 spin_unlock(&device_klist->k_lock);
1300} 1260}
diff --git a/include/linux/device.h b/include/linux/device.h
index ec90e79f6a00..987f5912720a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -90,6 +90,9 @@ int __must_check bus_for_each_drv(struct bus_type *bus,
90 struct device_driver *start, void *data, 90 struct device_driver *start, void *data,
91 int (*fn)(struct device_driver *, void *)); 91 int (*fn)(struct device_driver *, void *));
92 92
93void bus_sort_breadthfirst(struct bus_type *bus,
94 int (*compare)(const struct device *a,
95 const struct device *b));
93/* 96/*
94 * Bus notifiers: Get notified of addition/removal of devices 97 * Bus notifiers: Get notified of addition/removal of devices
95 * and binding/unbinding of drivers to devices. 98 * and binding/unbinding of drivers to devices.