/* * 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 */ /* * Nov 2000, Ivan Kokshaysky * Resource sorting */ #include #include #include #include #include #include #include #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) { 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; /* Ok, try it out.. */ if (allocate_resource(r, res, size, min, -1, size, 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 of a given type by alignment */ void __init pdev_sort_resources(struct pci_dev *dev, struct resource_list *head, u32 type_mask) { int i; for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *r; struct resource_list *list, *tmp; unsigned long r_size; /* PCI-PCI bridges may have I/O ports or memory on the primary bus */ if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI && i >= PCI_BRIDGE_RESOURCES) continue; r = &dev->resource[i]; r_size = r->end - r->start; if (!(r->flags & type_mask) || r->parent) continue; if (!r_size) { printk(KERN_WARNING "PCI: Ignore bogus resource %d " "[%lx:%lx] of %s\n", i, r->start, r->end, dev->name); continue; } for (list = head; ; list = list->next) { unsigned long size = 0; struct resource_list *ln = list->next; if (ln) size = ln->res->end - ln->res->start; if (r_size > size) { tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) { printk(KERN_ERR "pdev_sort_resources(): kmalloc() failed!\n"); continue; } 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)); }