diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-18 17:50:40 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-18 17:50:40 -0700 |
commit | b6aefcce747b3bc54d701d3c329416d0c9616f10 (patch) | |
tree | 18340f3dea5abf9f1c67b2ff0e0e4941a432b46e /drivers/pci/probe.c | |
parent | 65740356ccfa66703e7e0d47fbe372ba5193916b (diff) | |
parent | 7a54f25cef6c763f16c9fd49ae382de162147873 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/pci-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/pci-2.6: (22 commits)
PCI Hotplug: move pci_hotplug.h to include/linux/
change pci hotplug subsystem maintainer to Kristen
PCI: optionally sort device lists breadth-first
cpcihp_generic: prevent loading without "bridge" parameter
pci: Additional search functions
PCI: quirks: switch quirks code offender to use pci_get API
PCI: Update MSI-HOWTO.txt according to pci_msi_supported()
PCI: Improve pci_msi_supported() comments
PCI hotplug: ioremap balanced with iounmap
shpchp: remove unnecessary cmd_busy member from struct controller
shpchp: fix command completion check
pci: Stamp out pci_find_* usage in fakephp
PCI: fix pcie_portdrv_restore_config undefined without CONFIG_PM error
Fix DMA resource allocation in ACPIPnP
PCI: Turn pci_fixup_video into generic for embedded VGA
PCI: add ICH7/8 ACPI/GPIO io resource quirks
PCI: pcie-check-and-return-bus_register-errors fix
PCI: VIA IRQ quirk behaviour change
pciehp: Remove unnecessary check in pciehp_ctrl.c
pciehp - add missing locking
...
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a3b0a5eb505..e159d660449 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1067,3 +1067,95 @@ EXPORT_SYMBOL(pci_scan_bridge); EXPORT_SYMBOL(pci_scan_single_device); 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) +{ + 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; + + if (a->bus->number < b->bus->number) return -1; + else if (a->bus->number > b->bus->number) return 1; + + if (a->devfn < b->devfn) return -1; + else if (a->devfn > b->devfn) return 1; + + 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); +} + +static void __init pci_sort_breadthfirst_klist(void) +{ + LIST_HEAD(sorted_devices); + struct list_head *pos, *tmp; + struct klist_node *n; + struct device *dev; + struct pci_dev *pdev; + + spin_lock(&pci_bus_type.klist_devices.k_lock); + list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.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, &pci_bus_type.klist_devices.k_list); + spin_unlock(&pci_bus_type.klist_devices.k_lock); +} + +static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list) +{ + struct pci_dev *b; + + list_for_each_entry(b, list, global_list) { + if (pci_sort_bf_cmp(a, b) <= 0) { + list_move_tail(&a->global_list, &b->global_list); + return; + } + } + list_move_tail(&a->global_list, list); +} + +static void __init pci_sort_breadthfirst_devices(void) +{ + LIST_HEAD(sorted_devices); + struct pci_dev *dev, *tmp; + + down_write(&pci_bus_sem); + list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) { + pci_insertion_sort_devices(dev, &sorted_devices); + } + list_splice(&sorted_devices, &pci_devices); + up_write(&pci_bus_sem); +} + +void __init pci_sort_breadthfirst(void) +{ + pci_sort_breadthfirst_devices(); + pci_sort_breadthfirst_klist(); +} + |