Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 39906
b: refs/heads/master
c: 6b4b78f
h: refs/heads/master
v: v3
  • Loading branch information
Matt Domsch authored and Greg Kroah-Hartman committed Oct 18, 2006
1 parent b0771c1 commit ea10ded
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 49c61cca2b6591a28ffa4abb73c718091f569746
refs/heads/master: 6b4b78fed47e7380dfe9280b154e8b9bfcd4c86c
5 changes: 5 additions & 0 deletions trunk/Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1231,6 +1231,11 @@ and is between 256 and 4096 characters. It is defined in the file
machine check when some devices' config space
is read. But various workarounds are disabled
and some IOMMU drivers will not work.
bfsort Sort PCI devices into breadth-first order.
This sorting is done to get a device
order compatible with older (<= 2.4) kernels.
nobfsort Don't sort PCI devices into breadth-first order.

pcmv= [HW,PCMCIA] BadgePAD 4

pd. [PARIDE]
Expand Down
59 changes: 57 additions & 2 deletions trunk/arch/i386/pci/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
PCI_PROBE_MMCONF;

int pci_bf_sort;
int pci_routeirq;
int pcibios_last_bus = -1;
unsigned long pirq_table_addr;
Expand Down Expand Up @@ -117,6 +118,20 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b)
pci_read_bridge_bases(b);
}

/*
* Only use DMI information to set this if nothing was passed
* on the kernel command line (which was parsed earlier).
*/

static int __devinit set_bf_sort(struct dmi_system_id *d)
{
if (pci_bf_sort == pci_bf_sort_default) {
pci_bf_sort = pci_dmi_bf;
printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident);
}
return 0;
}

/*
* Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
*/
Expand All @@ -130,11 +145,11 @@ static int __devinit assign_all_busses(struct dmi_system_id *d)
}
#endif

static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
#ifdef __i386__
/*
* Laptops which need pci=assign-busses to see Cardbus cards
*/
static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
#ifdef __i386__
{
.callback = assign_all_busses,
.ident = "Samsung X20 Laptop",
Expand All @@ -144,6 +159,38 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
},
},
#endif /* __i386__ */
{
.callback = set_bf_sort,
.ident = "Dell PowerEdge 1950",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"),
},
},
{
.callback = set_bf_sort,
.ident = "Dell PowerEdge 1955",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"),
},
},
{
.callback = set_bf_sort,
.ident = "Dell PowerEdge 2900",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"),
},
},
{
.callback = set_bf_sort,
.ident = "Dell PowerEdge 2950",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"),
},
},
{}
};

Expand Down Expand Up @@ -189,6 +236,8 @@ static int __init pcibios_init(void)

pcibios_resource_survey();

if (pci_bf_sort >= pci_force_bf)
pci_sort_breadthfirst();
#ifdef CONFIG_PCI_BIOS
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
pcibios_sort();
Expand All @@ -203,6 +252,12 @@ char * __devinit pcibios_setup(char *str)
if (!strcmp(str, "off")) {
pci_probe = 0;
return NULL;
} else if (!strcmp(str, "bfsort")) {
pci_bf_sort = pci_force_bf;
return NULL;
} else if (!strcmp(str, "nobfsort")) {
pci_bf_sort = pci_force_nobf;
return NULL;
}
#ifdef CONFIG_PCI_BIOS
else if (!strcmp(str, "bios")) {
Expand Down
7 changes: 7 additions & 0 deletions trunk/arch/i386/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;

enum pci_bf_sort_state {
pci_bf_sort_default,
pci_force_nobf,
pci_force_bf,
pci_dmi_bf,
};

/* pci-i386.c */

extern unsigned int pcibios_max_latency;
Expand Down
92 changes: 92 additions & 0 deletions trunk/drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

1 change: 1 addition & 0 deletions trunk/include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ extern void pci_remove_bus(struct pci_bus *b);
extern void pci_remove_bus_device(struct pci_dev *dev);
extern void pci_stop_bus_device(struct pci_dev *dev);
void pci_setup_cardbus(struct pci_bus *bus);
extern void pci_sort_breadthfirst(void);

/* Generic PCI functions exported to card drivers */

Expand Down

0 comments on commit ea10ded

Please sign in to comment.