/* * 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; /* 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; 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)); /* Something is wrong with the region. * Invalidate the resource to prevent * child resource allocations in this * range. */ r->start = r->end = 0; r->flags = 0; } } } pcibios_allocate_bus_resources(&bus->children); }
/* ** Determine if a device is already configured. ** If so, reserve it resources. ** ** Read PCI cfg command register and see if I/O or MMIO is enabled. ** PAT has to enable the devices it's using. ** ** Note: resources are fixed up before we try to claim them. */ static void lba_claim_dev_resources(struct pci_dev *dev) { u16 cmd; int i, srch_flags; (void) pci_read_config_word(dev, PCI_COMMAND, &cmd); srch_flags = (cmd & PCI_COMMAND_IO) ? IORESOURCE_IO : 0; if (cmd & PCI_COMMAND_MEMORY) srch_flags |= IORESOURCE_MEM; if (!srch_flags) return; for (i = 0; i <= PCI_ROM_RESOURCE; i++) { if (dev->resource[i].flags & srch_flags) { pci_claim_resource(dev, i); DBG(" claimed %s %d [%lx,%lx]/%lx\n", pci_name(dev), i, dev->resource[i].start, dev->resource[i].end, dev->resource[i].flags ); } } }
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); } }
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 __devinit pcibios_fixup_resources(struct pci_dev *dev, int start, int limit) { struct pci_bus_region region; int i; for (i = start; i < limit; i++) { if (!dev->resource[i].flags) continue; region.start = dev->resource[i].start; region.end = dev->resource[i].end; pcibios_bus_to_resource(dev, &dev->resource[i], ®ion); if ((is_valid_resource(dev, i))) pci_claim_resource(dev, i); } }
static void pcibios_fixup_device_resources(struct pci_dev *dev) { int idx; if (!dev->bus) return; for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { struct resource *r = &dev->resource[idx]; if (!r->flags || r->parent || !r->start) continue; pci_claim_resource(dev, idx); } }
static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) { struct pci_bus_region region; int i; int limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? \ PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES; for (i = 0; i < limit; i++) { if (!dev->resource[i].flags) continue; region.start = dev->resource[i].start; region.end = dev->resource[i].end; pcibios_bus_to_resource(dev, &dev->resource[i], ®ion); if ((is_valid_resource(dev, i))) pci_claim_resource(dev, i); } }