setup-res.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
- /*
- * 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 %sn", 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 %sn",
- i, res->start, res->end, dev->slot_name);
- return -EBUSY;
- }
- }
- DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %sn", 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 %sn",
- 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%xn", cmd));
- }