Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (27 commits)
PCI: Don't use dmi_name_in_vendors in quirk
PCI: remove unused AER functions
PCI/sysfs: move bus cpuaffinity to class dev_attrs
PCI: add rescan to /sys/.../pci_bus/.../
PCI: update bridge resources to get more big ranges when allocating space (again)
KVM: Use pci_store/load_saved_state() around VM device usage
PCI: Add interfaces to store and load the device saved state
PCI: Track the size of each saved capability data area
PCI/e1000e: Add and use pci_disable_link_state_locked()
x86/PCI: derive pcibios_last_bus from ACPI MCFG
PCI: add latency tolerance reporting enable/disable support
PCI: add OBFF enable/disable support
PCI: add ID-based ordering enable/disable support
PCI hotplug: acpiphp: assume device is in state D0 after powering on a slot.
PCI: Set PCIE maxpayload for card during hotplug insertion
PCI/ACPI: Report _OSC control mask returned on failure to get control
x86/PCI: irq and pci_ids patch for Intel Panther Point DeviceIDs
PCI: handle positive error codes
PCI: check pci_vpd_pci22_wait() return
PCI: Use ICH6_GPIO_EN in ich6_lpc_acpi_gpio
...
Fix up trivial conflicts in include/linux/pci_ids.h: commit a6e5e2be44
moved the intel SMBUS ID definitons to the i2c-i801.c driver.
This commit is contained in:
@@ -991,30 +991,139 @@ 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
|
||||
pci_assign_unassigned_resources(void)
|
||||
{
|
||||
struct pci_bus *bus;
|
||||
struct resource_list_x add_list; /* list of resources that
|
||||
want additional resources */
|
||||
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;
|
||||
add_list.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
|
||||
subordinate buses. */
|
||||
list_for_each_entry(bus, &pci_root_buses, node) {
|
||||
list_for_each_entry(bus, &pci_root_buses, node)
|
||||
__pci_bus_size_bridges(bus, &add_list);
|
||||
}
|
||||
|
||||
/* Depth last, allocate resources and update the hardware. */
|
||||
list_for_each_entry(bus, &pci_root_buses, node) {
|
||||
__pci_bus_assign_resources(bus, &add_list, NULL);
|
||||
pci_enable_bridges(bus);
|
||||
}
|
||||
list_for_each_entry(bus, &pci_root_buses, node)
|
||||
__pci_bus_assign_resources(bus, &add_list, &head);
|
||||
BUG_ON(add_list.next);
|
||||
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_list(resource_list_x, &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_list(resource_list_x, &head);
|
||||
|
||||
goto again;
|
||||
|
||||
enable_and_dump:
|
||||
/* Depth last, update the hardware. */
|
||||
list_for_each_entry(bus, &pci_root_buses, node)
|
||||
pci_enable_bridges(bus);
|
||||
|
||||
/* dump the resource on buses */
|
||||
list_for_each_entry(bus, &pci_root_buses, node) {
|
||||
list_for_each_entry(bus, &pci_root_buses, node)
|
||||
pci_bus_dump_resources(bus);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
|
||||
|
Reference in New Issue
Block a user