/* * Handle resources of PCI devices. If the world were perfect, we could * just allocate all the resource regions and do nothing more. It isn't. * On the other hand, we cannot just re-allocate all devices, as it would * require us to know lots of host bridge internals. So we attempt to * keep as much of the original configuration as possible, but tweak it * when it's found to be wrong. * * Known BIOS problems we have to work around: * - I/O or memory regions not configured * - regions configured, but not enabled in the command register * - bogus I/O addresses above 64K used * - expansion ROMs left enabled (this may sound harmless, but given * the fact the PCI specs explicitly allow address decoders to be * shared between expansion ROMs and other resource regions, it's * at least dangerous) * * Our solution: * (1) Allocate resources for all buses behind PCI-to-PCI bridges. * This gives us fixed barriers on where we can allocate. * (2) Allocate resources for all enabled devices. If there is * a collision, just mark the resource as unallocated. Also * disable expansion ROMs during this step. * (3) Try to allocate resources for disabled devices. If the * resources were assigned correctly, everything goes well, * if they weren't, they won't disturb allocation of other * resources. * (4) Assign new addresses to resources which were either * not configured at all or misconfigured. If explicitly * requested by the user, configure expansion ROM address * as well. */ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { struct pci_bus *bus; struct pci_dev *dev; int idx; struct resource *r, *pr; /* Depth-First Search on bus tree */ list_for_each_entry(bus, bus_list, node) { dev = bus->self; if (dev) { for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { r = &dev->resource[idx]; if (!r->flags) continue; pr = pci_find_parent_resource(dev, r); if (!r->start || !pr || request_resource(pr, r) < 0) { printk(KERN_ERR "PCI:" " Cannot allocate resource" " region %d of bridge %s\n", idx, pci_name(dev)); /* Something is wrong with the region. * Invalidate the resource to prevent * child resource allocations in this * range. */ r->flags = 0; } } } pcibios_allocate_bus_resources(&bus->children); }
static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { struct pci_bus *bus; struct pci_dev *dev; int idx; struct resource *r; /* */ list_for_each_entry(bus, bus_list, node) { dev = bus->self; if (dev) { for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { r = &dev->resource[idx]; if (!r->flags) continue; if (!r->start || pci_claim_resource(dev, idx) < 0) { printk(KERN_ERR "PCI:" " Cannot allocate resource" " region %d of bridge %s\n", idx, pci_name(dev)); /* */ r->start = r->end = 0; r->flags = 0; } } } pcibios_allocate_bus_resources(&bus->children); }
static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { struct pci_bus *bus; struct pci_dev *dev; int idx; struct resource *r; /* Depth-First Search on bus tree */ list_for_each_entry(bus, bus_list, node) { if ((dev = bus->self)) { for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { r = &dev->resource[idx]; if (!r->flags) continue; if (!r->start || pci_claim_resource(dev, idx) < 0) { /* * Something is wrong with the region. * Invalidate the resource to prevent * child resource allocations in this * range. */ r->flags = 0; } } } pcibios_allocate_bus_resources(&bus->children); } }
void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { struct list_head *ln; struct pci_bus *bus; int i; struct resource *res, *pr; if(!bus_list) return; /* Depth-First Search on bus tree */ for (ln = bus_list->next; ln != bus_list; ln=ln->next) { bus = pci_bus_b(ln); pci_read_bridge_bases(bus); for (i = 0; i < 4; ++i) { if ((res = bus->resource[i]) == NULL || !res->flags) continue; if (bus->parent == NULL) pr = (res->flags & IORESOURCE_IO)? &ioport_resource: &iomem_resource; else pr = pci_find_parent_resource(bus->self, res); if (pr && request_resource(pr, res) == 0) continue; printk(KERN_ERR "PCI: Can not allocate resource region " "%d of PCI bridge %d\n", i, bus->number); DBG("PCI: resource is %lx..%lx (%lx)\n", res->start, res->end, res->flags); } pcibios_allocate_bus_resources(&bus->children); } }