mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-27 22:24:11 +08:00
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: 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>
This commit is contained in:
parent
d75b305295
commit
884525655d
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
|
|
||||||
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,8 +170,10 @@ 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 {
|
||||||
pci_update_resource(dev, res, resno);
|
res->flags &= ~IORESOURCE_STARTALIGN;
|
||||||
|
if (resno < PCI_BRIDGE_RESOURCES)
|
||||||
|
pci_update_resource(dev, res, resno);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -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 {
|
|||||||
#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,
|
|||||||
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
|
|||||||
|
|
||||||
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.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user