Skip to content

Commit

Permalink
PCI: clean up resource alignment management
Browse files Browse the repository at this point in the history
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: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Gary Hade <garyhade@us.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Ivan Kokshaysky authored and Greg Kroah-Hartman committed Apr 21, 2008
1 parent d75b305 commit 8845256
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 22 deletions.
5 changes: 3 additions & 2 deletions drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->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)) {
u32 szhi, lhi;

Expand Down Expand Up @@ -288,7 +288,8 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
if (sz) {
res->flags = (l & IORESOURCE_ROM_ENABLE) |
IORESOURCE_MEM | IORESOURCE_PREFETCH |
IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
IORESOURCE_READONLY | IORESOURCE_CACHEABLE |
IORESOURCE_SIZEALIGN;
res->start = l & PCI_ROM_ADDRESS_MASK;
res->end = res->start + (unsigned long) sz;
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/pci/setup-bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ static void pbus_assign_resources_sorted(struct pci_bus *bus)
res = list->res;
idx = res - &list->dev->resource[0];
if (pci_assign_resource(list->dev, idx)) {
/* FIXME: get rid of this */
res->start = 0;
res->end = 0;
res->flags = 0;
Expand Down Expand Up @@ -327,6 +328,7 @@ static void pbus_size_io(struct pci_bus *bus)
/* Alignment of the IO window is always 4K */
b_res->start = 4096;
b_res->end = b_res->start + size - 1;
b_res->flags |= IORESOURCE_STARTALIGN;
}

/* Calculate the size of the bus and minimal alignment which
Expand Down Expand Up @@ -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->end = size + min_align - 1;
b_res->flags |= IORESOURCE_STARTALIGN;
return 1;
}

Expand Down
42 changes: 23 additions & 19 deletions drivers/pci/setup-res.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,16 @@ int pci_assign_resource(struct pci_dev *dev, int resno)

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;

align = resource_alignment(res);
if (!align) {
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.. */
ret = pci_bus_alloc_resource(bus, res, size, align, min,
Expand All @@ -164,8 +170,10 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
res->flags & IORESOURCE_IO ? "I/O" : "mem",
resno, (unsigned long long)size,
(unsigned long long)res->start, pci_name(dev));
} else if (resno < PCI_BRIDGE_RESOURCES) {
pci_update_resource(dev, res, resno);
} else {
res->flags &= ~IORESOURCE_STARTALIGN;
if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, res, resno);
}

return ret;
Expand Down Expand Up @@ -226,29 +234,25 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
if (r->flags & IORESOURCE_PCI_FIXED)
continue;

r_align = r->end - r->start;

if (!(r->flags) || r->parent)
continue;

r_align = resource_alignment(r);
if (!r_align) {
printk(KERN_WARNING "PCI: Ignore bogus resource %d "
"[%llx:%llx] of %s\n",
printk(KERN_WARNING "PCI: bogus alignment of resource "
"%d [%llx:%llx] (flags %lx) of %s\n",
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;
}
r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
for (list = head; ; list = list->next) {
resource_size_t align = 0;
struct resource_list *ln = list->next;
int idx;

if (ln) {
idx = ln->res - &ln->dev->resource[0];
align = (idx < PCI_BRIDGE_RESOURCES) ?
ln->res->end - ln->res->start + 1 :
ln->res->start;
}
if (ln)
align = resource_alignment(ln->res);

if (r_align > align) {
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
Expand Down
5 changes: 4 additions & 1 deletion include/linux/ioport.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ struct resource_list {
#define IORESOURCE_CACHEABLE 0x00004000
#define IORESOURCE_RANGELENGTH 0x00008000
#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_UNSET 0x20000000
Expand Down Expand Up @@ -110,6 +112,7 @@ extern int allocate_resource(struct resource *root, struct resource *new,
void *alignf_data);
int adjust_resource(struct resource *res, resource_size_t start,
resource_size_t size);
resource_size_t resource_alignment(struct resource *res);

/* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
Expand Down
18 changes: 18 additions & 0 deletions kernel/resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,24 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t

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.
*
Expand Down

0 comments on commit 8845256

Please sign in to comment.