提交 99178b03 编写于 作者: G Greg Kroah-Hartman

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: NJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 26853ab6
......@@ -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);
......
......@@ -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);
}
......@@ -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.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册