aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Kokshaysky <ink@jurassic.park.msu.ru>2008-03-30 11:50:14 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-21 00:47:08 -0400
commit884525655d07fdee9245716b998ecdc45cdd8007 (patch)
tree975cbf2b5079430240d3496323df1a266be95d27
parentd75b305295c38ba9610ff3b2200f7d1989dc55fd (diff)
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>
-rw-r--r--drivers/pci/probe.c5
-rw-r--r--drivers/pci/setup-bus.c3
-rw-r--r--drivers/pci/setup-res.c42
-rw-r--r--include/linux/ioport.h5
-rw-r--r--kernel/resource.c18
5 files changed, 51 insertions, 22 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c2e99fd87faf..33d9b8bea6e0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -235,7 +235,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
235 res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; 235 res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
236 } 236 }
237 res->end = res->start + (unsigned long) sz; 237 res->end = res->start + (unsigned long) sz;
238 res->flags |= pci_calc_resource_flags(l); 238 res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
239 if (is_64bit_memory(l)) { 239 if (is_64bit_memory(l)) {
240 u32 szhi, lhi; 240 u32 szhi, lhi;
241 241
@@ -288,7 +288,8 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
288 if (sz) { 288 if (sz) {
289 res->flags = (l & IORESOURCE_ROM_ENABLE) | 289 res->flags = (l & IORESOURCE_ROM_ENABLE) |
290 IORESOURCE_MEM | IORESOURCE_PREFETCH | 290 IORESOURCE_MEM | IORESOURCE_PREFETCH |
291 IORESOURCE_READONLY | IORESOURCE_CACHEABLE; 291 IORESOURCE_READONLY | IORESOURCE_CACHEABLE |
292 IORESOURCE_SIZEALIGN;
292 res->start = l & PCI_ROM_ADDRESS_MASK; 293 res->start = l & PCI_ROM_ADDRESS_MASK;
293 res->end = res->start + (unsigned long) sz; 294 res->end = res->start + (unsigned long) sz;
294 } 295 }
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index f7cb8e0758b4..5cf84568c9e4 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -65,6 +65,7 @@ static void pbus_assign_resources_sorted(struct pci_bus *bus)
65 res = list->res; 65 res = list->res;
66 idx = res - &list->dev->resource[0]; 66 idx = res - &list->dev->resource[0];
67 if (pci_assign_resource(list->dev, idx)) { 67 if (pci_assign_resource(list->dev, idx)) {
68 /* FIXME: get rid of this */
68 res->start = 0; 69 res->start = 0;
69 res->end = 0; 70 res->end = 0;
70 res->flags = 0; 71 res->flags = 0;
@@ -327,6 +328,7 @@ static void pbus_size_io(struct pci_bus *bus)
327 /* Alignment of the IO window is always 4K */ 328 /* Alignment of the IO window is always 4K */
328 b_res->start = 4096; 329 b_res->start = 4096;
329 b_res->end = b_res->start + size - 1; 330 b_res->end = b_res->start + size - 1;
331 b_res->flags |= IORESOURCE_STARTALIGN;
330} 332}
331 333
332/* Calculate the size of the bus and minimal alignment which 334/* 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 } 403 }
402 b_res->start = min_align; 404 b_res->start = min_align;
403 b_res->end = size + min_align - 1; 405 b_res->end = size + min_align - 1;
406 b_res->flags |= IORESOURCE_STARTALIGN;
404 return 1; 407 return 1;
405} 408}
406 409
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index bad509e40fbc..7d35cdf4579f 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -137,10 +137,16 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
137 137
138 size = res->end - res->start + 1; 138 size = res->end - res->start + 1;
139 min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; 139 min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
140 /* The bridge resources are special, as their 140
141 size != alignment. Sizing routines return 141 align = resource_alignment(res);
142 required alignment in the "start" field. */ 142 if (!align) {
143 align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start; 143 printk(KERN_ERR "PCI: Cannot allocate resource (bogus "
144 "alignment) %d [%llx:%llx] (flags %lx) of %s\n",
145 resno, (unsigned long long)res->start,
146 (unsigned long long)res->end, res->flags,
147 pci_name(dev));
148 return -EINVAL;
149 }
144 150
145 /* First, try exact prefetching match.. */ 151 /* First, try exact prefetching match.. */
146 ret = pci_bus_alloc_resource(bus, res, size, align, min, 152 ret = pci_bus_alloc_resource(bus, res, size, align, min,
@@ -164,8 +170,10 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
164 res->flags & IORESOURCE_IO ? "I/O" : "mem", 170 res->flags & IORESOURCE_IO ? "I/O" : "mem",
165 resno, (unsigned long long)size, 171 resno, (unsigned long long)size,
166 (unsigned long long)res->start, pci_name(dev)); 172 (unsigned long long)res->start, pci_name(dev));
167 } else if (resno < PCI_BRIDGE_RESOURCES) { 173 } else {
168 pci_update_resource(dev, res, resno); 174 res->flags &= ~IORESOURCE_STARTALIGN;
175 if (resno < PCI_BRIDGE_RESOURCES)
176 pci_update_resource(dev, res, resno);
169 } 177 }
170 178
171 return ret; 179 return ret;
@@ -226,29 +234,25 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
226 if (r->flags & IORESOURCE_PCI_FIXED) 234 if (r->flags & IORESOURCE_PCI_FIXED)
227 continue; 235 continue;
228 236
229 r_align = r->end - r->start;
230
231 if (!(r->flags) || r->parent) 237 if (!(r->flags) || r->parent)
232 continue; 238 continue;
239
240 r_align = resource_alignment(r);
233 if (!r_align) { 241 if (!r_align) {
234 printk(KERN_WARNING "PCI: Ignore bogus resource %d " 242 printk(KERN_WARNING "PCI: bogus alignment of resource "
235 "[%llx:%llx] of %s\n", 243 "%d [%llx:%llx] (flags %lx) of %s\n",
236 i, (unsigned long long)r->start, 244 i, (unsigned long long)r->start,
237 (unsigned long long)r->end, pci_name(dev)); 245 (unsigned long long)r->end, r->flags,
246 pci_name(dev));
238 continue; 247 continue;
239 } 248 }
240 r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
241 for (list = head; ; list = list->next) { 249 for (list = head; ; list = list->next) {
242 resource_size_t align = 0; 250 resource_size_t align = 0;
243 struct resource_list *ln = list->next; 251 struct resource_list *ln = list->next;
244 int idx;
245 252
246 if (ln) { 253 if (ln)
247 idx = ln->res - &ln->dev->resource[0]; 254 align = resource_alignment(ln->res);
248 align = (idx < PCI_BRIDGE_RESOURCES) ? 255
249 ln->res->end - ln->res->start + 1 :
250 ln->res->start;
251 }
252 if (r_align > align) { 256 if (r_align > align) {
253 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); 257 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
254 if (!tmp) 258 if (!tmp)
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 605d237364d2..d5d40a9f7929 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -44,7 +44,9 @@ struct resource_list {
44#define IORESOURCE_CACHEABLE 0x00004000 44#define IORESOURCE_CACHEABLE 0x00004000
45#define IORESOURCE_RANGELENGTH 0x00008000 45#define IORESOURCE_RANGELENGTH 0x00008000
46#define IORESOURCE_SHADOWABLE 0x00010000 46#define IORESOURCE_SHADOWABLE 0x00010000
47#define IORESOURCE_BUS_HAS_VGA 0x00080000 47
48#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */
49#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */
48 50
49#define IORESOURCE_DISABLED 0x10000000 51#define IORESOURCE_DISABLED 0x10000000
50#define IORESOURCE_UNSET 0x20000000 52#define IORESOURCE_UNSET 0x20000000
@@ -110,6 +112,7 @@ extern int allocate_resource(struct resource *root, struct resource *new,
110 void *alignf_data); 112 void *alignf_data);
111int adjust_resource(struct resource *res, resource_size_t start, 113int adjust_resource(struct resource *res, resource_size_t start,
112 resource_size_t size); 114 resource_size_t size);
115resource_size_t resource_alignment(struct resource *res);
113 116
114/* Convenience shorthand with allocation */ 117/* Convenience shorthand with allocation */
115#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) 118#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
diff --git a/kernel/resource.c b/kernel/resource.c
index 82aea814d409..cee12cc47cab 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -486,6 +486,24 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t
486 486
487EXPORT_SYMBOL(adjust_resource); 487EXPORT_SYMBOL(adjust_resource);
488 488
489/**
490 * resource_alignment - calculate resource's alignment
491 * @res: resource pointer
492 *
493 * Returns alignment on success, 0 (invalid alignment) on failure.
494 */
495resource_size_t resource_alignment(struct resource *res)
496{
497 switch (res->flags & (IORESOURCE_SIZEALIGN | IORESOURCE_STARTALIGN)) {
498 case IORESOURCE_SIZEALIGN:
499 return res->end - res->start + 1;
500 case IORESOURCE_STARTALIGN:
501 return res->start;
502 default:
503 return 0;
504 }
505}
506
489/* 507/*
490 * This is compatibility stuff for IO resources. 508 * This is compatibility stuff for IO resources.
491 * 509 *