Patch from Russell King - Separate out bus resource allocator (pci_bus_alloc_resource) - Provide pci_enable_bridges to setup command register for all pci bridges 25-akpm/drivers/pci/Makefile | 2 25-akpm/drivers/pci/bus.c | 81 ++++++++++++++++++++++++++++++++++++ 25-akpm/drivers/pci/setup-res.c | 89 +++++++++++----------------------------- 25-akpm/include/linux/pci.h | 10 ++++ 4 files changed, 118 insertions(+), 64 deletions(-) diff -puN /dev/null drivers/pci/bus.c --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/pci/bus.c Tue Mar 4 16:48:29 2003 @@ -0,0 +1,81 @@ +/* + * drivers/pci/bus.c + * + * From setup-res.c, by: + * Dave Rusling (david.rusling@reo.mts.dec.com) + * David Mosberger (davidm@cs.arizona.edu) + * David Miller (davem@redhat.com) + * Ivan Kokshaysky (ink@jurassic.park.msu.ru) + */ +#include +#include +#include +#include +#include + +/** + * pci_bus_alloc_resource - allocate a resource from a parent bus + * @bus: PCI bus + * @res: resource to allocate + * @size: size of resource to allocate + * @align: alignment of resource to allocate + * @min: minimum /proc/iomem address to allocate + * @type_mask: IORESOURCE_* type flags + * @alignf: resource alignment function + * @alignf_data: data argument for resource alignment function + * + * Given the PCI bus a device resides on, the size, minimum address, + * alignment and type, try to find an acceptable resource allocation + * for a specific device resource. + */ +int +pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, + unsigned long size, unsigned long align, unsigned long min, + unsigned int type_mask, + void (*alignf)(void *, struct resource *, + unsigned long, unsigned long), + void *alignf_data) +{ + int i, ret = -ENOMEM; + + type_mask |= IORESOURCE_IO | IORESOURCE_MEM; + + for (i = 0; i < PCI_BUS_NUM_RESOURCES; 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.. */ + ret = allocate_resource(r, res, size, min, -1, align, + alignf, alignf_data); + if (ret == 0) + break; + } + return ret; +} + +void pci_enable_bridges(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + if (dev->subordinate) { + pci_enable_device(dev); + pci_set_master(dev); + pci_enable_bridges(dev->subordinate); + } + } +} + +EXPORT_SYMBOL(pci_bus_alloc_resource); +EXPORT_SYMBOL(pci_enable_bridges); diff -puN drivers/pci/Makefile~pci-1 drivers/pci/Makefile --- 25/drivers/pci/Makefile~pci-1 Tue Mar 4 16:48:29 2003 +++ 25-akpm/drivers/pci/Makefile Tue Mar 4 16:48:29 2003 @@ -2,7 +2,7 @@ # Makefile for the PCI bus specific drivers. # -obj-y += access.o probe.o pci.o pool.o quirks.o \ +obj-y += access.o bus.o probe.o pci.o pool.o quirks.o \ names.o pci-driver.o search.o hotplug.o \ pci-sysfs.o obj-$(CONFIG_PM) += power.o diff -puN drivers/pci/setup-res.c~pci-1 drivers/pci/setup-res.c --- 25/drivers/pci/setup-res.c~pci-1 Tue Mar 4 16:48:29 2003 +++ 25-akpm/drivers/pci/setup-res.c Tue Mar 4 16:48:29 2003 @@ -55,84 +55,47 @@ pci_claim_resource(struct pci_dev *dev, 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 pci_assign_resource(struct pci_dev *dev, int resno) { - unsigned long align; - int i; - - type_mask |= IORESOURCE_IO | IORESOURCE_MEM; - for (i = 0 ; i < PCI_BUS_NUM_RESOURCES; 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; + struct pci_bus *bus = dev->bus; + struct resource *res = dev->resource + resno; + unsigned long size, min, align; + int ret; size = res->end - res->start + 1; min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; + /* 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; /* First, try exact prefetching match.. */ - if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH, i) < 0) { + ret = pci_bus_alloc_resource(bus, res, size, align, min, + IORESOURCE_PREFETCH, + pcibios_align_resource, dev); + + if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) { /* * 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; - } + ret = pci_bus_alloc_resource(bus, res, size, align, min, 0, + pcibios_align_resource, dev); } - DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %s\n", res->start, - res->end, i, dev->dev.name)); + if (ret) { + printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n", + resno, res->start, res->end, dev->slot_name); + } else { + DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %s\n", + res->start, res->end, i, dev->dev.name)); + /* Update PCI config space. */ + pcibios_update_resource(dev, res->parent, res, resno); + } - return 0; + return ret; } /* Sort resources by alignment */ diff -puN include/linux/pci.h~pci-1 include/linux/pci.h --- 25/include/linux/pci.h~pci-1 Tue Mar 4 16:48:29 2003 +++ 25-akpm/include/linux/pci.h Tue Mar 4 16:48:29 2003 @@ -641,6 +641,16 @@ void pci_release_regions(struct pci_dev int pci_request_region(struct pci_dev *, int, char *); void pci_release_region(struct pci_dev *, int); +/* drivers/pci/bus.c */ + +int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, + unsigned long size, unsigned long align, + unsigned long min, unsigned int type_mask, + void (*alignf)(void *, struct resource *, + unsigned long, unsigned long), + void *alignf_data); +void pci_enable_bridges(struct pci_bus *bus); + /* New-style probing supporting hot-pluggable devices */ int pci_register_driver(struct pci_driver *); void pci_unregister_driver(struct pci_driver *); _