Commit f2820e1d authored by Russell King's avatar Russell King Committed by Linus Torvalds

[PATCH] Separate out pci bus resource allocator

- Separate out bus resource allocator (pci_bus_alloc_resource)
- Provide pci_enable_bridges to setup command register for all
  pci bridges.
parent aadabe8b
......@@ -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
......
/*
* 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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
/**
* 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);
......@@ -55,84 +55,47 @@ pci_claim_resource(struct pci_dev *dev, int resource)
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 < 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)
int pci_assign_resource(struct pci_dev *dev, int resno)
{
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 */
......
......@@ -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 *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment