diff options
-rw-r--r-- | drivers/base/bus.c | 50 | ||||
-rw-r--r-- | drivers/pci/probe.c | 50 | ||||
-rw-r--r-- | include/linux/device.h | 3 |
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 | } |
981 | EXPORT_SYMBOL_GPL(bus_get_device_klist); | 981 | EXPORT_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 | */ | ||
990 | static 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 | |||
1010 | void 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 | } | ||
1031 | EXPORT_SYMBOL_GPL(bus_sort_breadthfirst); | ||
1032 | |||
983 | int __init buses_init(void) | 1033 | int __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); | |||
1237 | EXPORT_SYMBOL_GPL(pci_scan_child_bus); | 1237 | EXPORT_SYMBOL_GPL(pci_scan_child_bus); |
1238 | #endif | 1238 | #endif |
1239 | 1239 | ||
1240 | static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b) | 1240 | static 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 | */ | ||
1261 | static 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 | |||
1280 | void __init pci_sort_breadthfirst(void) | 1257 | void __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 | ||
93 | void 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. |