Commit 8a3d0b80 authored by Ivan Kokshaysky's avatar Ivan Kokshaysky Committed by Linus Torvalds

[PATCH] 2.5.14: New PCI allocation code (alpha, arm, parisc) [1/2]

This changes PCI resource allocation algorithm to 3 passes vs.
current 2 passes. Extra pass is used for calculation of required
size and alignment of PCI buses behind PCI-PCI bridges. After
that, in the pass #3, these buses get allocated like regular
PCI devices. This gives tighter PCI IO and memory packing -
for instance, this fixes allocation problems on certain alphas
with very small (112Mb) PCI memory range. Also, the new code
- will allow mixed approach to resource allocation:
  architecture can keep BIOS settings for some devices,
  and re-allocate resources for others, including improperly
  initialized bridges;
- makes prefetchable ranges support much simpler;
- allows sizing of IO and memory ranges for the host
  bridges, which might be very useful in some situations.

It was tested on various alphas; I haven't heard any complaints
from rmk and rth, so probably all of this is ok. :-)

Part 1:
- for all archs, 4th argument (align) added to
  pcibios_align_resource (and its callers).
  It's necessary because this function will be called for
  bus resources as well, and in this case size != alignment.
- for several archs, dead/bogus code removed from
  pcibios_fixup_pbus_ranges().
parent 7c59354d
...@@ -128,7 +128,8 @@ struct pci_fixup pcibios_fixups[] __initdata = { ...@@ -128,7 +128,8 @@ struct pci_fixup pcibios_fixups[] __initdata = {
#define GB (1024*MB) #define GB (1024*MB)
void void
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
struct pci_dev *dev = data; struct pci_dev *dev = data;
struct pci_controller *hose = dev->sysdata; struct pci_controller *hose = dev->sysdata;
...@@ -168,7 +169,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size) ...@@ -168,7 +169,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size)
*/ */
/* Align to multiple of size of minimum base. */ /* Align to multiple of size of minimum base. */
alignto = MAX(0x1000, size); alignto = MAX(0x1000, align);
start = ALIGN(start, alignto); start = ALIGN(start, alignto);
if (hose->sparse_mem_base && size <= 7 * 16*MB) { if (hose->sparse_mem_base && size <= 7 * 16*MB) {
if (((start / (16*MB)) & 0x7) == 0) { if (((start / (16*MB)) & 0x7) == 0) {
......
...@@ -662,7 +662,8 @@ char * __init pcibios_setup(char *str) ...@@ -662,7 +662,8 @@ char * __init pcibios_setup(char *str)
* but we want to try to avoid allocating at 0x2900-0x2bff * but we want to try to avoid allocating at 0x2900-0x2bff
* which might be mirrored at 0x0100-0x03ff.. * which might be mirrored at 0x0100-0x03ff..
*/ */
void pcibios_align_resource(void *data, struct resource *res, unsigned long size) void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start; unsigned long start = res->start;
......
...@@ -75,7 +75,8 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, ...@@ -75,7 +75,8 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
* which might have be mirrored at 0x0100-0x03ff.. * which might have be mirrored at 0x0100-0x03ff..
*/ */
void void
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start; unsigned long start = res->start;
......
...@@ -259,10 +259,6 @@ pcibios_update_irq (struct pci_dev *dev, int irq) ...@@ -259,10 +259,6 @@ pcibios_update_irq (struct pci_dev *dev, int irq)
void __init void __init
pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges) pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
{ {
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
} }
int int
...@@ -278,7 +274,8 @@ pcibios_enable_device (struct pci_dev *dev) ...@@ -278,7 +274,8 @@ pcibios_enable_device (struct pci_dev *dev)
} }
void void
pcibios_align_resource (void *data, struct resource *res, unsigned long size) pcibios_align_resource (void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
} }
......
...@@ -319,10 +319,6 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq) ...@@ -319,10 +319,6 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges) struct pbus_set_ranges_data *ranges)
{ {
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
} }
int pcibios_enable_resources(struct pci_dev *dev) int pcibios_enable_resources(struct pci_dev *dev)
...@@ -396,7 +392,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root, ...@@ -396,7 +392,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
} }
void pcibios_align_resource(void *data, struct resource *res, void pcibios_align_resource(void *data, struct resource *res,
unsigned long size) unsigned long size, unsigned long align)
{ {
struct pci_dev *dev = data; struct pci_dev *dev = data;
......
...@@ -470,7 +470,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root, ...@@ -470,7 +470,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
} }
void pcibios_align_resource(void *data, struct resource *res, void pcibios_align_resource(void *data, struct resource *res,
unsigned long size) unsigned long size, unsigned long align)
{ {
struct pci_dev *dev = data; struct pci_dev *dev = data;
......
...@@ -164,7 +164,8 @@ char *pcibios_setup(char *str) ...@@ -164,7 +164,8 @@ char *pcibios_setup(char *str)
} }
void void
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
/* this should not be called */ /* this should not be called */
MIPS_ASSERT(1 == 0); MIPS_ASSERT(1 == 0);
......
...@@ -886,7 +886,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root, ...@@ -886,7 +886,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
} }
void pcibios_align_resource(void *data, struct resource *res, void pcibios_align_resource(void *data, struct resource *res,
unsigned long size) unsigned long size, unsigned long align)
{ {
struct pci_dev *dev = data; struct pci_dev *dev = data;
......
...@@ -241,7 +241,8 @@ pcibios_enable_device(struct pci_dev *dev) ...@@ -241,7 +241,8 @@ pcibios_enable_device(struct pci_dev *dev)
void __init void __init
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
printk("pcibios_align_resource\n"); printk("pcibios_align_resource\n");
} }
......
...@@ -161,7 +161,8 @@ char *pcibios_setup(char *str) ...@@ -161,7 +161,8 @@ char *pcibios_setup(char *str)
} }
void void
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
/* this should not be called */ /* this should not be called */
} }
......
...@@ -286,7 +286,8 @@ pcibios_enable_device(struct pci_dev *dev) ...@@ -286,7 +286,8 @@ pcibios_enable_device(struct pci_dev *dev)
} }
void __init void __init
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
} }
......
...@@ -199,7 +199,8 @@ int __init pcibios_enable_device(struct pci_dev *dev) ...@@ -199,7 +199,8 @@ int __init pcibios_enable_device(struct pci_dev *dev)
} }
void __init void __init
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
} }
......
...@@ -290,7 +290,8 @@ pcibios_enable_device(struct pci_dev *dev) ...@@ -290,7 +290,8 @@ pcibios_enable_device(struct pci_dev *dev)
} }
void __init void __init
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
} }
......
...@@ -238,10 +238,6 @@ void __init ...@@ -238,10 +238,6 @@ void __init
pcibios_fixup_pbus_ranges(struct pci_bus * bus, pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges) struct pbus_set_ranges_data * ranges)
{ {
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
} }
int __init int __init
...@@ -252,7 +248,8 @@ pcibios_enable_device(struct pci_dev *dev) ...@@ -252,7 +248,8 @@ pcibios_enable_device(struct pci_dev *dev)
} }
void __init void __init
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
} }
......
...@@ -329,7 +329,7 @@ char * __init pcibios_setup (char *str) ...@@ -329,7 +329,7 @@ char * __init pcibios_setup (char *str)
} }
void __init pcibios_align_resource (void *data, struct resource *res, void __init pcibios_align_resource (void *data, struct resource *res,
unsigned long size) unsigned long size, unsigned long align)
{ {
} }
...@@ -352,10 +352,6 @@ void __init pcibios_fixup_bus (struct pci_bus *b) ...@@ -352,10 +352,6 @@ void __init pcibios_fixup_bus (struct pci_bus *b)
void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus, void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus,
struct pbus_set_ranges_data * ranges) struct pbus_set_ranges_data * ranges)
{ {
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
} }
/* /*
......
...@@ -337,13 +337,15 @@ void pcibios_fixup_pbus_ranges( ...@@ -337,13 +337,15 @@ void pcibios_fixup_pbus_ranges(
** than res->start. ** than res->start.
*/ */
void __devinit void __devinit
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long alignment)
{ {
unsigned long mask, align; unsigned long mask, align;
DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx)\n", DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n",
((struct pci_dev *) data)->slot_name, ((struct pci_dev *) data)->slot_name,
res->parent, res->start, res->end, (int) res->flags, size); res->parent, res->start, res->end,
(int) res->flags, size, alignment);
/* has resource already been aligned/assigned? */ /* has resource already been aligned/assigned? */
if (res->parent) if (res->parent)
...@@ -400,11 +402,11 @@ pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer) ...@@ -400,11 +402,11 @@ pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
if (res.flags & IORESOURCE_IO) { if (res.flags & IORESOURCE_IO) {
res.start = inner.io_end; res.start = inner.io_end;
pcibios_align_resource(dev, &res, size); pcibios_align_resource(dev, &res, size, 0);
inner.io_end += res.start + size; inner.io_end += res.start + size;
} else if (res.flags & IORESOURCE_MEM) { } else if (res.flags & IORESOURCE_MEM) {
res.start = inner.mem_end; res.start = inner.mem_end;
pcibios_align_resource(dev, &res, size); pcibios_align_resource(dev, &res, size, 0);
inner.mem_end = res.start + size; inner.mem_end = res.start + size;
} }
......
...@@ -1083,10 +1083,6 @@ common_swizzle(struct pci_dev *dev, unsigned char *pinp) ...@@ -1083,10 +1083,6 @@ common_swizzle(struct pci_dev *dev, unsigned char *pinp)
void __init void __init
pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
{ {
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
} }
unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
......
...@@ -180,7 +180,8 @@ pcibios_fixup_resources(struct pci_dev* dev) ...@@ -180,7 +180,8 @@ pcibios_fixup_resources(struct pci_dev* dev)
* which might have be mirrored at 0x0100-0x03ff.. * which might have be mirrored at 0x0100-0x03ff..
*/ */
void void
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
struct pci_dev *dev = data; struct pci_dev *dev = data;
......
...@@ -414,10 +414,6 @@ void __init ...@@ -414,10 +414,6 @@ void __init
pcibios_fixup_pbus_ranges(struct pci_bus *bus, pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges) struct pbus_set_ranges_data *ranges)
{ {
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
} }
void __init pcibios_init(void) void __init pcibios_init(void)
......
...@@ -60,7 +60,8 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, ...@@ -60,7 +60,8 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
* addresses to be allocated in the 0x000-0x0ff region * addresses to be allocated in the 0x000-0x0ff region
* modulo 0x400. * modulo 0x400.
*/ */
void pcibios_align_resource(void *data, struct resource *res, unsigned long size) void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start; unsigned long start = res->start;
......
...@@ -865,7 +865,8 @@ void pcibios_update_resource(struct pci_dev *pdev, struct resource *res1, ...@@ -865,7 +865,8 @@ void pcibios_update_resource(struct pci_dev *pdev, struct resource *res1,
{ {
} }
void pcibios_align_resource(void *data, struct resource *res, unsigned long size) void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
} }
......
...@@ -311,7 +311,8 @@ void pcibios_fixup_pbus_ranges(struct pci_bus *pbus, ...@@ -311,7 +311,8 @@ void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
{ {
} }
void pcibios_align_resource(void *data, struct resource *res, unsigned long size) void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
} }
......
...@@ -136,7 +136,8 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, ...@@ -136,7 +136,8 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
* which might have be mirrored at 0x0100-0x03ff.. * which might have be mirrored at 0x0100-0x03ff..
*/ */
void void
pcibios_align_resource(void *data, struct resource *res, unsigned long size) pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{ {
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start; unsigned long start = res->start;
......
...@@ -69,6 +69,7 @@ static int pci_assign_bus_resource(const struct pci_bus *bus, ...@@ -69,6 +69,7 @@ static int pci_assign_bus_resource(const struct pci_bus *bus,
unsigned int type_mask, unsigned int type_mask,
int resno) int resno)
{ {
unsigned long align;
int i; int i;
type_mask |= IORESOURCE_IO | IORESOURCE_MEM; type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
...@@ -81,12 +82,20 @@ static int pci_assign_bus_resource(const struct pci_bus *bus, ...@@ -81,12 +82,20 @@ static int pci_assign_bus_resource(const struct pci_bus *bus,
if ((res->flags ^ r->flags) & type_mask) if ((res->flags ^ r->flags) & type_mask)
continue; continue;
/* We cannot allocate a non-prefetching resource from a pre-fetching area */ /* We cannot allocate a non-prefetching resource
if ((r->flags & IORESOURCE_PREFETCH) && !(res->flags & IORESOURCE_PREFETCH)) from a pre-fetching area */
if ((r->flags & IORESOURCE_PREFETCH) &&
!(res->flags & IORESOURCE_PREFETCH))
continue; 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.. */ /* Ok, try it out.. */
if (allocate_resource(r, res, size, min, -1, size, pcibios_align_resource, dev) < 0) if (allocate_resource(r, res, size, min, -1, align,
pcibios_align_resource, dev) < 0)
continue; continue;
/* Update PCI config space. */ /* Update PCI config space. */
......
...@@ -92,7 +92,8 @@ extern int allocate_resource(struct resource *root, struct resource *new, ...@@ -92,7 +92,8 @@ extern int allocate_resource(struct resource *root, struct resource *new,
unsigned long size, unsigned long size,
unsigned long min, unsigned long max, unsigned long min, unsigned long max,
unsigned long align, unsigned long align,
void (*alignf)(void *, struct resource *, unsigned long), void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data); void *alignf_data);
/* Convenience shorthand with allocation */ /* Convenience shorthand with allocation */
......
...@@ -500,7 +500,8 @@ int pcibios_enable_device(struct pci_dev *); ...@@ -500,7 +500,8 @@ int pcibios_enable_device(struct pci_dev *);
char *pcibios_setup (char *str); char *pcibios_setup (char *str);
/* Used only when drivers/pci/setup.c is used */ /* Used only when drivers/pci/setup.c is used */
void pcibios_align_resource(void *, struct resource *, unsigned long); void pcibios_align_resource(void *, struct resource *,
unsigned long, unsigned long);
void pcibios_update_resource(struct pci_dev *, struct resource *, void pcibios_update_resource(struct pci_dev *, struct resource *,
struct resource *, int); struct resource *, int);
void pcibios_update_irq(struct pci_dev *, int irq); void pcibios_update_irq(struct pci_dev *, int irq);
......
...@@ -152,7 +152,8 @@ static int find_resource(struct resource *root, struct resource *new, ...@@ -152,7 +152,8 @@ static int find_resource(struct resource *root, struct resource *new,
unsigned long size, unsigned long size,
unsigned long min, unsigned long max, unsigned long min, unsigned long max,
unsigned long align, unsigned long align,
void (*alignf)(void *, struct resource *, unsigned long), void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data) void *alignf_data)
{ {
struct resource *this = root->child; struct resource *this = root->child;
...@@ -169,7 +170,7 @@ static int find_resource(struct resource *root, struct resource *new, ...@@ -169,7 +170,7 @@ static int find_resource(struct resource *root, struct resource *new,
new->end = max; new->end = max;
new->start = (new->start + align - 1) & ~(align - 1); new->start = (new->start + align - 1) & ~(align - 1);
if (alignf) if (alignf)
alignf(alignf_data, new, size); alignf(alignf_data, new, size, align);
if (new->start < new->end && new->end - new->start + 1 >= size) { if (new->start < new->end && new->end - new->start + 1 >= size) {
new->end = new->start + size - 1; new->end = new->start + size - 1;
return 0; return 0;
...@@ -189,7 +190,8 @@ int allocate_resource(struct resource *root, struct resource *new, ...@@ -189,7 +190,8 @@ int allocate_resource(struct resource *root, struct resource *new,
unsigned long size, unsigned long size,
unsigned long min, unsigned long max, unsigned long min, unsigned long max,
unsigned long align, unsigned long align,
void (*alignf)(void *, struct resource *, unsigned long), void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data) void *alignf_data)
{ {
int err; int err;
......
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