summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-08-08 19:48:21 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-08-08 19:48:21 +0000
commita7ce7d5e94c98ef5b867f61b2ebecd563f4b6ec9 (patch)
treef3dc5381e660de7685258f75d16c381c4c47694a /drivers/pci
parent57445428488a2862840c4d7c96d7746c11031aaf (diff)
Merge with Linux 2.4.0-test6-pre7.
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/setup-res.c89
1 files changed, 57 insertions, 32 deletions
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 6b4654d7b..9fac0e1ce 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -50,45 +50,70 @@ pci_claim_resource(struct pci_dev *dev, int resource)
return err;
}
-int
-pci_assign_resource(struct pci_dev *dev, int i)
+/*
+ * 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)
{
- struct resource *root, *res;
- unsigned long size, min;
+ int i;
- res = &dev->resource[i];
+ type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
+ for (i = 0 ; i < 4; i++) {
+ struct resource *r = bus->resource[i];
+ if (!r)
+ continue;
- /* Determine the root we allocate from. */
- res->end -= res->start;
- res->start = 0;
- root = pci_find_parent_resource(dev, res);
- if (root == NULL) {
- printk(KERN_ERR "PCI: Cannot find parent resource for "
- "device %s\n", dev->slot_name);
- return -EINVAL;
- }
+ /* 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;
- min = (res->flags & IORESOURCE_IO ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM);
- size = res->end + 1;
- DBGC((" for root[%lx:%lx] min[%lx] size[%lx]\n",
- root->start, root->end, min, size));
-
- if (allocate_resource(root, res, size, min, -1, size,
- pcibios_align_resource, dev) < 0) {
- printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n",
- i, dev->name);
- printk(KERN_ERR " failed root[%lx:%lx] min[%lx] size[%lx]\n",
- root->start, root->end, min, size);
- printk(KERN_ERR " failed res[%lx:%lx]\n",
- res->start, res->end);
- return -EBUSY;
+ /* 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, i);
+ 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;
- DBGC((" got res[%lx:%lx] for resource %d\n",
- res->start, res->end, i));
+ 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) < 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) < 0) {
+ printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n", i, dev->name);
+ return -EBUSY;
+ }
+ }
- /* Update PCI config space. */
- pcibios_update_resource(dev, root, res, i);
+ DBGC((" got res[%lx:%lx] for resource %d\n", res->start, res->end, i));
return 0;
}