Commit 88452565 authored by Ivan Kokshaysky's avatar Ivan Kokshaysky Committed by Greg Kroah-Hartman

PCI: clean up resource alignment management

Done per Linus' request and suggestions. Linus has explained that
better than I'll be able to explain:

On Thu, Mar 27, 2008 at 10:12:10AM -0700, Linus Torvalds wrote:
> Actually, before we go any further, there might be a less intrusive
> alternative: add just a couple of flags to the resource flags field (we
> still have something like 8 unused bits on 32-bit), and use those to
> implement a generic "resource_alignment()" routine.
>
> Two flags would do it:
>
>  - IORESOURCE_SIZEALIGN: size indicates alignment (regular PCI device
>    resources)
>
>  - IORESOURCE_STARTALIGN: start field is alignment (PCI bus resources
>    during probing)
>
> and then the case of both flags zero (or both bits set) would actually be
> "invalid", and we would also clear the IORESOURCE_STARTALIGN flag when we
> actually allocate the resource (so that we don't use the "start" field as
> alignment incorrectly when it no longer indicates alignment).
>
> That wouldn't be totally generic, but it would have the nice property of
> automatically at least add sanity checking for that whole "res->start has
> the odd meaning of 'alignment' during probing" and remove the need for a
> new field, and it would allow us to have a generic "resource_alignment()"
> routine that just gets a resource pointer.

Besides, I removed IORESOURCE_BUS_HAS_VGA flag which was unused for ages.
Signed-off-by: default avatarIvan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Gary Hade <garyhade@us.ibm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d75b3052
...@@ -235,7 +235,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) ...@@ -235,7 +235,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
} }
res->end = res->start + (unsigned long) sz; res->end = res->start + (unsigned long) sz;
res->flags |= pci_calc_resource_flags(l); res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
if (is_64bit_memory(l)) { if (is_64bit_memory(l)) {
u32 szhi, lhi; u32 szhi, lhi;
...@@ -288,7 +288,8 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) ...@@ -288,7 +288,8 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
if (sz) { if (sz) {
res->flags = (l & IORESOURCE_ROM_ENABLE) | res->flags = (l & IORESOURCE_ROM_ENABLE) |
IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_MEM | IORESOURCE_PREFETCH |
IORESOURCE_READONLY | IORESOURCE_CACHEABLE; IORESOURCE_READONLY | IORESOURCE_CACHEABLE |
IORESOURCE_SIZEALIGN;
res->start = l & PCI_ROM_ADDRESS_MASK; res->start = l & PCI_ROM_ADDRESS_MASK;
res->end = res->start + (unsigned long) sz; res->end = res->start + (unsigned long) sz;
} }
......
...@@ -65,6 +65,7 @@ static void pbus_assign_resources_sorted(struct pci_bus *bus) ...@@ -65,6 +65,7 @@ static void pbus_assign_resources_sorted(struct pci_bus *bus)
res = list->res; res = list->res;
idx = res - &list->dev->resource[0]; idx = res - &list->dev->resource[0];
if (pci_assign_resource(list->dev, idx)) { if (pci_assign_resource(list->dev, idx)) {
/* FIXME: get rid of this */
res->start = 0; res->start = 0;
res->end = 0; res->end = 0;
res->flags = 0; res->flags = 0;
...@@ -327,6 +328,7 @@ static void pbus_size_io(struct pci_bus *bus) ...@@ -327,6 +328,7 @@ static void pbus_size_io(struct pci_bus *bus)
/* Alignment of the IO window is always 4K */ /* Alignment of the IO window is always 4K */
b_res->start = 4096; b_res->start = 4096;
b_res->end = b_res->start + size - 1; b_res->end = b_res->start + size - 1;
b_res->flags |= IORESOURCE_STARTALIGN;
} }
/* Calculate the size of the bus and minimal alignment which /* Calculate the size of the bus and minimal alignment which
...@@ -401,6 +403,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long ...@@ -401,6 +403,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
} }
b_res->start = min_align; b_res->start = min_align;
b_res->end = size + min_align - 1; b_res->end = size + min_align - 1;
b_res->flags |= IORESOURCE_STARTALIGN;
return 1; return 1;
} }
......
...@@ -137,10 +137,16 @@ int pci_assign_resource(struct pci_dev *dev, int resno) ...@@ -137,10 +137,16 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
size = res->end - res->start + 1; size = res->end - res->start + 1;
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
/* The bridge resources are special, as their
size != alignment. Sizing routines return align = resource_alignment(res);
required alignment in the "start" field. */ if (!align) {
align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start; printk(KERN_ERR "PCI: Cannot allocate resource (bogus "
"alignment) %d [%llx:%llx] (flags %lx) of %s\n",
resno, (unsigned long long)res->start,
(unsigned long long)res->end, res->flags,
pci_name(dev));
return -EINVAL;
}
/* First, try exact prefetching match.. */ /* First, try exact prefetching match.. */
ret = pci_bus_alloc_resource(bus, res, size, align, min, ret = pci_bus_alloc_resource(bus, res, size, align, min,
...@@ -164,7 +170,9 @@ int pci_assign_resource(struct pci_dev *dev, int resno) ...@@ -164,7 +170,9 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
res->flags & IORESOURCE_IO ? "I/O" : "mem", res->flags & IORESOURCE_IO ? "I/O" : "mem",
resno, (unsigned long long)size, resno, (unsigned long long)size,
(unsigned long long)res->start, pci_name(dev)); (unsigned long long)res->start, pci_name(dev));
} else if (resno < PCI_BRIDGE_RESOURCES) { } else {
res->flags &= ~IORESOURCE_STARTALIGN;
if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, res, resno); pci_update_resource(dev, res, resno);
} }
...@@ -226,29 +234,25 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) ...@@ -226,29 +234,25 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
if (r->flags & IORESOURCE_PCI_FIXED) if (r->flags & IORESOURCE_PCI_FIXED)
continue; continue;
r_align = r->end - r->start;
if (!(r->flags) || r->parent) if (!(r->flags) || r->parent)
continue; continue;
r_align = resource_alignment(r);
if (!r_align) { if (!r_align) {
printk(KERN_WARNING "PCI: Ignore bogus resource %d " printk(KERN_WARNING "PCI: bogus alignment of resource "
"[%llx:%llx] of %s\n", "%d [%llx:%llx] (flags %lx) of %s\n",
i, (unsigned long long)r->start, i, (unsigned long long)r->start,
(unsigned long long)r->end, pci_name(dev)); (unsigned long long)r->end, r->flags,
pci_name(dev));
continue; continue;
} }
r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
for (list = head; ; list = list->next) { for (list = head; ; list = list->next) {
resource_size_t align = 0; resource_size_t align = 0;
struct resource_list *ln = list->next; struct resource_list *ln = list->next;
int idx;
if (ln) { if (ln)
idx = ln->res - &ln->dev->resource[0]; align = resource_alignment(ln->res);
align = (idx < PCI_BRIDGE_RESOURCES) ?
ln->res->end - ln->res->start + 1 :
ln->res->start;
}
if (r_align > align) { if (r_align > align) {
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) if (!tmp)
......
...@@ -44,7 +44,9 @@ struct resource_list { ...@@ -44,7 +44,9 @@ struct resource_list {
#define IORESOURCE_CACHEABLE 0x00004000 #define IORESOURCE_CACHEABLE 0x00004000
#define IORESOURCE_RANGELENGTH 0x00008000 #define IORESOURCE_RANGELENGTH 0x00008000
#define IORESOURCE_SHADOWABLE 0x00010000 #define IORESOURCE_SHADOWABLE 0x00010000
#define IORESOURCE_BUS_HAS_VGA 0x00080000
#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */
#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */
#define IORESOURCE_DISABLED 0x10000000 #define IORESOURCE_DISABLED 0x10000000
#define IORESOURCE_UNSET 0x20000000 #define IORESOURCE_UNSET 0x20000000
...@@ -110,6 +112,7 @@ extern int allocate_resource(struct resource *root, struct resource *new, ...@@ -110,6 +112,7 @@ extern int allocate_resource(struct resource *root, struct resource *new,
void *alignf_data); void *alignf_data);
int adjust_resource(struct resource *res, resource_size_t start, int adjust_resource(struct resource *res, resource_size_t start,
resource_size_t size); resource_size_t size);
resource_size_t resource_alignment(struct resource *res);
/* Convenience shorthand with allocation */ /* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
......
...@@ -486,6 +486,24 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t ...@@ -486,6 +486,24 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t
EXPORT_SYMBOL(adjust_resource); EXPORT_SYMBOL(adjust_resource);
/**
* resource_alignment - calculate resource's alignment
* @res: resource pointer
*
* Returns alignment on success, 0 (invalid alignment) on failure.
*/
resource_size_t resource_alignment(struct resource *res)
{
switch (res->flags & (IORESOURCE_SIZEALIGN | IORESOURCE_STARTALIGN)) {
case IORESOURCE_SIZEALIGN:
return res->end - res->start + 1;
case IORESOURCE_STARTALIGN:
return res->start;
default:
return 0;
}
}
/* /*
* This is compatibility stuff for IO resources. * This is compatibility stuff for IO resources.
* *
......
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