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 = {
#define GB (1024*MB)
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_controller *hose = dev->sysdata;
......@@ -168,7 +169,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size)
*/
/* Align to multiple of size of minimum base. */
alignto = MAX(0x1000, size);
alignto = MAX(0x1000, align);
start = ALIGN(start, alignto);
if (hose->sparse_mem_base && size <= 7 * 16*MB) {
if (((start / (16*MB)) & 0x7) == 0) {
......
......@@ -662,7 +662,8 @@ char * __init pcibios_setup(char *str)
* but we want to try to avoid allocating at 0x2900-0x2bff
* 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) {
unsigned long start = res->start;
......
......@@ -75,7 +75,8 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
* which might have be mirrored at 0x0100-0x03ff..
*/
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) {
unsigned long start = res->start;
......
......@@ -259,10 +259,6 @@ pcibios_update_irq (struct pci_dev *dev, int irq)
void __init
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
......@@ -278,7 +274,8 @@ pcibios_enable_device (struct pci_dev *dev)
}
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)
void __init 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 pcibios_enable_resources(struct pci_dev *dev)
......@@ -396,7 +392,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size)
unsigned long size, unsigned long align)
{
struct pci_dev *dev = data;
......
......@@ -470,7 +470,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size)
unsigned long size, unsigned long align)
{
struct pci_dev *dev = data;
......
......@@ -164,7 +164,8 @@ char *pcibios_setup(char *str)
}
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 */
MIPS_ASSERT(1 == 0);
......
......@@ -886,7 +886,7 @@ void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size)
unsigned long size, unsigned long align)
{
struct pci_dev *dev = data;
......
......@@ -241,7 +241,8 @@ pcibios_enable_device(struct pci_dev *dev)
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");
}
......
......@@ -161,7 +161,8 @@ char *pcibios_setup(char *str)
}
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 */
}
......
......@@ -286,7 +286,8 @@ pcibios_enable_device(struct pci_dev *dev)
}
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)
}
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)
}
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
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 __init
......@@ -252,7 +248,8 @@ pcibios_enable_device(struct pci_dev *dev)
}
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)
}
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)
void __init 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;
}
/*
......
......@@ -337,13 +337,15 @@ void pcibios_fixup_pbus_ranges(
** than res->start.
*/
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;
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,
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? */
if (res->parent)
......@@ -400,11 +402,11 @@ pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
if (res.flags & IORESOURCE_IO) {
res.start = inner.io_end;
pcibios_align_resource(dev, &res, size);
pcibios_align_resource(dev, &res, size, 0);
inner.io_end += res.start + size;
} else if (res.flags & IORESOURCE_MEM) {
res.start = inner.mem_end;
pcibios_align_resource(dev, &res, size);
pcibios_align_resource(dev, &res, size, 0);
inner.mem_end = res.start + size;
}
......
......@@ -1083,10 +1083,6 @@ common_swizzle(struct pci_dev *dev, unsigned char *pinp)
void __init
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,
......
......@@ -180,7 +180,8 @@ pcibios_fixup_resources(struct pci_dev* dev)
* which might have be mirrored at 0x0100-0x03ff..
*/
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;
......
......@@ -414,10 +414,6 @@ void __init
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;
}
void __init pcibios_init(void)
......
......@@ -60,7 +60,8 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
* addresses to be allocated in the 0x000-0x0ff region
* 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) {
unsigned long start = res->start;
......
......@@ -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,
{
}
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,
* which might have be mirrored at 0x0100-0x03ff..
*/
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) {
unsigned long start = res->start;
......
......@@ -69,6 +69,7 @@ static int pci_assign_bus_resource(const struct pci_bus *bus,
unsigned int type_mask,
int resno)
{
unsigned long align;
int i;
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
......@@ -81,12 +82,20 @@ static int pci_assign_bus_resource(const struct pci_bus *bus,
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))
/* 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, size, pcibios_align_resource, dev) < 0)
if (allocate_resource(r, res, size, min, -1, align,
pcibios_align_resource, dev) < 0)
continue;
/* Update PCI config space. */
......
......@@ -92,7 +92,8 @@ extern int allocate_resource(struct resource *root, struct resource *new,
unsigned long size,
unsigned long min, unsigned long max,
unsigned long align,
void (*alignf)(void *, struct resource *, unsigned long),
void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data);
/* Convenience shorthand with allocation */
......
......@@ -500,7 +500,8 @@ int pcibios_enable_device(struct pci_dev *);
char *pcibios_setup (char *str);
/* 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 *,
struct resource *, int);
void pcibios_update_irq(struct pci_dev *, int irq);
......
......@@ -152,7 +152,8 @@ static int find_resource(struct resource *root, struct resource *new,
unsigned long size,
unsigned long min, unsigned long max,
unsigned long align,
void (*alignf)(void *, struct resource *, unsigned long),
void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data)
{
struct resource *this = root->child;
......@@ -169,7 +170,7 @@ static int find_resource(struct resource *root, struct resource *new,
new->end = max;
new->start = (new->start + align - 1) & ~(align - 1);
if (alignf)
alignf(alignf_data, new, size);
alignf(alignf_data, new, size, align);
if (new->start < new->end && new->end - new->start + 1 >= size) {
new->end = new->start + size - 1;
return 0;
......@@ -189,7 +190,8 @@ int allocate_resource(struct resource *root, struct resource *new,
unsigned long size,
unsigned long min, unsigned long max,
unsigned long align,
void (*alignf)(void *, struct resource *, unsigned long),
void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data)
{
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