| /* |
| * drivers/pci/setup-res.c |
| * |
| * Extruded from code written by |
| * Dave Rusling (david.rusling@reo.mts.dec.com) |
| * David Mosberger (davidm@cs.arizona.edu) |
| * David Miller (davem@redhat.com) |
| * |
| * Support routines for initializing a PCI subsystem. |
| */ |
| |
| /* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */ |
| |
| /* |
| * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru> |
| * Resource sorting |
| */ |
| |
| #include <linux/init.h> |
| #include <linux/kernel.h> |
| #include <linux/pci.h> |
| #include <linux/errno.h> |
| #include <linux/ioport.h> |
| #include <linux/cache.h> |
| #include <linux/slab.h> |
| |
| |
| #define DEBUG_CONFIG 0 |
| #if DEBUG_CONFIG |
| # define DBGC(args) printk args |
| #else |
| # define DBGC(args) |
| #endif |
| |
| |
| int __init |
| pci_claim_resource(struct pci_dev *dev, int resource) |
| { |
| struct resource *res = &dev->resource[resource]; |
| struct resource *root = pci_find_parent_resource(dev, res); |
| int err; |
| |
| err = -EINVAL; |
| if (root != NULL) { |
| err = request_resource(root, res); |
| if (err) { |
| printk(KERN_ERR "PCI: Address space collision on " |
| "region %d of device %s [%lx:%lx]\n", |
| resource, dev->name, res->start, res->end); |
| } |
| } else { |
| printk(KERN_ERR "PCI: No parent found for region %d " |
| "of device %s\n", resource, dev->name); |
| } |
| |
| return err; |
| } |
| |
| /* |
| * Given the PCI bus a device resides on, try to |
| * find an acceptable resource allocation for a |
| * specific device resource.. |
| */ |
| static int pci_assign_bus_resource(const struct pci_bus *bus, |
| struct pci_dev *dev, |
| struct resource *res, |
| unsigned long size, |
| unsigned long min, |
| unsigned int type_mask, |
| int resno) |
| { |
| unsigned long align; |
| int i; |
| |
| type_mask |= IORESOURCE_IO | IORESOURCE_MEM; |
| for (i = 0 ; i < 4; i++) { |
| struct resource *r = bus->resource[i]; |
| if (!r) |
| continue; |
| |
| /* type_mask must match */ |
| if ((res->flags ^ r->flags) & type_mask) |
| continue; |
| |
| /* We cannot allocate a non-prefetching resource |
| from a pre-fetching area */ |
| if ((r->flags & IORESOURCE_PREFETCH) && |
| !(res->flags & IORESOURCE_PREFETCH)) |
| continue; |
| |
| /* The bridge resources are special, as their |
| size != alignment. Sizing routines return |
| required alignment in the "start" field. */ |
| align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start; |
| |
| /* Ok, try it out.. */ |
| if (allocate_resource(r, res, size, min, -1, align, |
| pcibios_align_resource, dev) < 0) |
| continue; |
| |
| /* Update PCI config space. */ |
| pcibios_update_resource(dev, r, res, resno); |
| return 0; |
| } |
| return -EBUSY; |
| } |
| |
| int |
| pci_assign_resource(struct pci_dev *dev, int i) |
| { |
| const struct pci_bus *bus = dev->bus; |
| struct resource *res = dev->resource + i; |
| unsigned long size, min; |
| |
| size = res->end - res->start + 1; |
| min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; |
| |
| /* First, try exact prefetching match.. */ |
| if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH, i) < 0) { |
| /* |
| * That failed. |
| * |
| * But a prefetching area can handle a non-prefetching |
| * window (it will just not perform as well). |
| */ |
| if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) { |
| printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n", |
| i, res->start, res->end, dev->slot_name); |
| return -EBUSY; |
| } |
| } |
| |
| DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %s\n", res->start, |
| res->end, i, dev->name)); |
| |
| return 0; |
| } |
| |
| /* Sort resources by alignment */ |
| void __init |
| pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) |
| { |
| int i; |
| |
| for (i = 0; i < PCI_NUM_RESOURCES; i++) { |
| struct resource *r; |
| struct resource_list *list, *tmp; |
| unsigned long r_align; |
| |
| r = &dev->resource[i]; |
| r_align = r->end - r->start; |
| |
| if (!(r->flags) || r->parent) |
| continue; |
| if (!r_align) { |
| printk(KERN_WARNING "PCI: Ignore bogus resource %d " |
| "[%lx:%lx] of %s\n", |
| i, r->start, r->end, dev->name); |
| continue; |
| } |
| r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start; |
| for (list = head; ; list = list->next) { |
| unsigned long align = 0; |
| struct resource_list *ln = list->next; |
| int idx; |
| |
| if (ln) { |
| idx = ln->res - &ln->dev->resource[0]; |
| align = (idx < PCI_BRIDGE_RESOURCES) ? |
| ln->res->end - ln->res->start + 1 : |
| ln->res->start; |
| } |
| if (r_align > align) { |
| tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); |
| if (!tmp) |
| panic("pdev_sort_resources(): " |
| "kmalloc() failed!\n"); |
| tmp->next = ln; |
| tmp->res = r; |
| tmp->dev = dev; |
| list->next = tmp; |
| break; |
| } |
| } |
| } |
| } |
| |
| void __init |
| pdev_enable_device(struct pci_dev *dev) |
| { |
| u32 reg; |
| u16 cmd; |
| int i; |
| |
| DBGC((KERN_ERR "PCI enable device: (%s)\n", dev->name)); |
| |
| pci_read_config_word(dev, PCI_COMMAND, &cmd); |
| |
| for (i = 0; i < PCI_NUM_RESOURCES; i++) { |
| struct resource *res = &dev->resource[i]; |
| |
| if (res->flags & IORESOURCE_IO) |
| cmd |= PCI_COMMAND_IO; |
| else if (res->flags & IORESOURCE_MEM) |
| cmd |= PCI_COMMAND_MEMORY; |
| } |
| |
| /* Special case, disable the ROM. Several devices act funny |
| (ie. do not respond to memory space writes) when it is left |
| enabled. A good example are QlogicISP adapters. */ |
| |
| if (dev->rom_base_reg) { |
| pci_read_config_dword(dev, dev->rom_base_reg, ®); |
| reg &= ~PCI_ROM_ADDRESS_ENABLE; |
| pci_write_config_dword(dev, dev->rom_base_reg, reg); |
| dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE; |
| } |
| |
| /* All of these (may) have I/O scattered all around and may not |
| use I/O base address registers at all. So we just have to |
| always enable IO to these devices. */ |
| if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED |
| || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA |
| || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE |
| || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { |
| cmd |= PCI_COMMAND_IO; |
| } |
| |
| /* ??? Always turn on bus mastering. If the device doesn't support |
| it, the bit will go into the bucket. */ |
| cmd |= PCI_COMMAND_MASTER; |
| |
| /* Set the cache line and default latency (32). */ |
| pci_write_config_word(dev, PCI_CACHE_LINE_SIZE, |
| (32 << 8) | (L1_CACHE_BYTES / sizeof(u32))); |
| |
| /* Enable the appropriate bits in the PCI command register. */ |
| pci_write_config_word(dev, PCI_COMMAND, cmd); |
| |
| DBGC((KERN_ERR " cmd reg 0x%x\n", cmd)); |
| } |