Revert "PCI: update bridge resources to get more big ranges in PCI assign unssigned"
This reverts commit 977d17bb17
, because it
can cause problems with some devices not getting any resources at all
when the resource tree is re-allocated.
For an example of this, see
https://bugzilla.kernel.org/show_bug.cgi?id=15960
(originally https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4982)
(lkml thread: http://lkml.org/lkml/2010/4/19/20)
where Peter Henriksson reported his Xonar DX sound card gone, because
the IO port region was no longer allocated.
Reported-bisected-and-tested-by: Peter Henriksson <peter.henriksson@gmail.com>
Requested-by: Andrew Morton <akpm@linux-foundation.org>
Requested-by: Clemens Ladisch <clemens@ladisch.de>
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
7ac512aa82
commit
769d9968e4
1 changed files with 2 additions and 112 deletions
|
@ -838,65 +838,11 @@ static void pci_bus_dump_resources(struct pci_bus *bus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init pci_bus_get_depth(struct pci_bus *bus)
|
|
||||||
{
|
|
||||||
int depth = 0;
|
|
||||||
struct pci_dev *dev;
|
|
||||||
|
|
||||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
|
||||||
int ret;
|
|
||||||
struct pci_bus *b = dev->subordinate;
|
|
||||||
if (!b)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ret = pci_bus_get_depth(b);
|
|
||||||
if (ret + 1 > depth)
|
|
||||||
depth = ret + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return depth;
|
|
||||||
}
|
|
||||||
static int __init pci_get_max_depth(void)
|
|
||||||
{
|
|
||||||
int depth = 0;
|
|
||||||
struct pci_bus *bus;
|
|
||||||
|
|
||||||
list_for_each_entry(bus, &pci_root_buses, node) {
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = pci_bus_get_depth(bus);
|
|
||||||
if (ret > depth)
|
|
||||||
depth = ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* first try will not touch pci bridge res
|
|
||||||
* second and later try will clear small leaf bridge res
|
|
||||||
* will stop till to the max deepth if can not find good one
|
|
||||||
*/
|
|
||||||
void __init
|
void __init
|
||||||
pci_assign_unassigned_resources(void)
|
pci_assign_unassigned_resources(void)
|
||||||
{
|
{
|
||||||
struct pci_bus *bus;
|
struct pci_bus *bus;
|
||||||
int tried_times = 0;
|
|
||||||
enum release_type rel_type = leaf_only;
|
|
||||||
struct resource_list_x head, *list;
|
|
||||||
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
|
|
||||||
IORESOURCE_PREFETCH;
|
|
||||||
unsigned long failed_type;
|
|
||||||
int max_depth = pci_get_max_depth();
|
|
||||||
int pci_try_num;
|
|
||||||
|
|
||||||
head.next = NULL;
|
|
||||||
|
|
||||||
pci_try_num = max_depth + 1;
|
|
||||||
printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
|
|
||||||
max_depth, pci_try_num);
|
|
||||||
|
|
||||||
again:
|
|
||||||
/* Depth first, calculate sizes and alignments of all
|
/* Depth first, calculate sizes and alignments of all
|
||||||
subordinate buses. */
|
subordinate buses. */
|
||||||
list_for_each_entry(bus, &pci_root_buses, node) {
|
list_for_each_entry(bus, &pci_root_buses, node) {
|
||||||
|
@ -904,65 +850,9 @@ pci_assign_unassigned_resources(void)
|
||||||
}
|
}
|
||||||
/* Depth last, allocate resources and update the hardware. */
|
/* Depth last, allocate resources and update the hardware. */
|
||||||
list_for_each_entry(bus, &pci_root_buses, node) {
|
list_for_each_entry(bus, &pci_root_buses, node) {
|
||||||
__pci_bus_assign_resources(bus, &head);
|
pci_bus_assign_resources(bus);
|
||||||
}
|
|
||||||
tried_times++;
|
|
||||||
|
|
||||||
/* any device complain? */
|
|
||||||
if (!head.next)
|
|
||||||
goto enable_and_dump;
|
|
||||||
failed_type = 0;
|
|
||||||
for (list = head.next; list;) {
|
|
||||||
failed_type |= list->flags;
|
|
||||||
list = list->next;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* io port are tight, don't try extra
|
|
||||||
* or if reach the limit, don't want to try more
|
|
||||||
*/
|
|
||||||
failed_type &= type_mask;
|
|
||||||
if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
|
|
||||||
free_failed_list(&head);
|
|
||||||
goto enable_and_dump;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
|
|
||||||
tried_times + 1);
|
|
||||||
|
|
||||||
/* third times and later will not check if it is leaf */
|
|
||||||
if ((tried_times + 1) > 2)
|
|
||||||
rel_type = whole_subtree;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to release leaf bridge's resources that doesn't fit resource of
|
|
||||||
* child device under that bridge
|
|
||||||
*/
|
|
||||||
for (list = head.next; list;) {
|
|
||||||
bus = list->dev->bus;
|
|
||||||
pci_bus_release_bridge_resources(bus, list->flags & type_mask,
|
|
||||||
rel_type);
|
|
||||||
list = list->next;
|
|
||||||
}
|
|
||||||
/* restore size and flags */
|
|
||||||
for (list = head.next; list;) {
|
|
||||||
struct resource *res = list->res;
|
|
||||||
|
|
||||||
res->start = list->start;
|
|
||||||
res->end = list->end;
|
|
||||||
res->flags = list->flags;
|
|
||||||
if (list->dev->subordinate)
|
|
||||||
res->flags = 0;
|
|
||||||
|
|
||||||
list = list->next;
|
|
||||||
}
|
|
||||||
free_failed_list(&head);
|
|
||||||
|
|
||||||
goto again;
|
|
||||||
|
|
||||||
enable_and_dump:
|
|
||||||
/* Depth last, update the hardware. */
|
|
||||||
list_for_each_entry(bus, &pci_root_buses, node)
|
|
||||||
pci_enable_bridges(bus);
|
pci_enable_bridges(bus);
|
||||||
|
}
|
||||||
|
|
||||||
/* dump the resource on buses */
|
/* dump the resource on buses */
|
||||||
list_for_each_entry(bus, &pci_root_buses, node) {
|
list_for_each_entry(bus, &pci_root_buses, node) {
|
||||||
|
|
Loading…
Reference in a new issue