bk://bk.arm.linux.org.uk/linux-2.6-pcmcia rmk@flint.arm.linux.org.uk|ChangeSet|20040518210238|47341 rmk # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/05/18 22:02:38+01:00 rmk@flint.arm.linux.org.uk # [PCMCIA] Convert IO resource allocation to use struct resource. # # This causes PCMCIA to use struct resource internally for IO resources. # This means that we can keep track of the resource pointer, expand # this resource if necessary, and use release_resource() on it when # we're done. # # This eventually means that we can change these to normal resources # which aren't marked busy. # # include/pcmcia/ss.h # 2004/05/18 22:00:16+01:00 rmk@flint.arm.linux.org.uk +1 -0 # Add struct resource to io_window_t. # # drivers/pcmcia/rsrc_mgr.c # 2004/05/18 22:00:16+01:00 rmk@flint.arm.linux.org.uk +32 -7 # Add adjust_io_region to expand already allocated IO resources. # find_io_region now returns a struct resource. # # drivers/pcmcia/cs_internal.h # 2004/05/18 22:00:15+01:00 rmk@flint.arm.linux.org.uk +3 -1 # Add and update function prototypes for find_io_region and # adjust_io_region. # # drivers/pcmcia/cs.c # 2004/05/18 22:00:15+01:00 rmk@flint.arm.linux.org.uk +13 -7 # Use struct resource when manipulating IO regions. # # ChangeSet # 2004/05/18 21:52:46+01:00 rmk@flint.arm.linux.org.uk # [PCMCIA] Fix a couple of resource bugs. # # Fix resource database bug where base + num wraps to zero. Also, # ensure that we always take the resource semaphore whenever we # allocate a resource. # # drivers/pcmcia/rsrc_mgr.c # 2004/05/18 21:50:46+01:00 rmk@flint.arm.linux.org.uk +6 -10 # Fix resource database bug where base + num wraps to zero. # Ensure that we always take the resource semaphore whenever we # allocate a resource. # diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c --- a/drivers/pcmcia/cs.c Fri May 21 19:05:35 2004 +++ b/drivers/pcmcia/cs.c Fri May 21 19:05:35 2004 @@ -789,9 +789,10 @@ return 1; for (i = 0; i < MAX_IO_WIN; i++) { if (s->io[i].NumPorts == 0) { - if (find_io_region(base, num, align, name, s) == 0) { + s->io[i].res = find_io_region(*base, num, align, name, s); + if (s->io[i].res) { s->io[i].Attributes = attr; - s->io[i].BasePort = *base; + s->io[i].BasePort = *base = s->io[i].res->start; s->io[i].NumPorts = s->io[i].InUse = num; break; } else @@ -801,7 +802,8 @@ /* Try to extend top of window */ try = s->io[i].BasePort + s->io[i].NumPorts; if ((*base == 0) || (*base == try)) - if (find_io_region(&try, num, 0, name, s) == 0) { + if (adjust_io_region(s->io[i].res, s->io[i].res->start, + s->io[i].res->end + num, s) == 0) { *base = try; s->io[i].NumPorts += num; s->io[i].InUse += num; @@ -810,7 +812,8 @@ /* Try to extend bottom of window */ try = s->io[i].BasePort - num; if ((*base == 0) || (*base == try)) - if (find_io_region(&try, num, 0, name, s) == 0) { + if (adjust_io_region(s->io[i].res, s->io[i].res->start - num, + s->io[i].res->end, s) == 0) { s->io[i].BasePort = *base = try; s->io[i].NumPorts += num; s->io[i].InUse += num; @@ -824,15 +827,18 @@ ioaddr_t num) { int i; - if(!(s->features & SS_CAP_STATIC_MAP)) - release_region(base, num); + for (i = 0; i < MAX_IO_WIN; i++) { if ((s->io[i].BasePort <= base) && (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) { s->io[i].InUse -= num; /* Free the window if no one else is using it */ - if (s->io[i].InUse == 0) + if (s->io[i].InUse == 0) { s->io[i].NumPorts = 0; + release_resource(s->io[i].res); + kfree(s->io[i].res); + s->io[i].res = NULL; + } } } } diff -Nru a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h --- a/drivers/pcmcia/cs_internal.h Fri May 21 19:05:35 2004 +++ b/drivers/pcmcia/cs_internal.h Fri May 21 19:05:35 2004 @@ -181,8 +181,10 @@ /* In rsrc_mgr */ void validate_mem(struct pcmcia_socket *s); -int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align, +struct resource *find_io_region(unsigned long base, int num, unsigned long align, char *name, struct pcmcia_socket *s); +int adjust_io_region(struct resource *res, unsigned long r_start, + unsigned long r_end, struct pcmcia_socket *s); int find_mem_region(u_long *base, u_long num, u_long align, int low, char *name, struct pcmcia_socket *s); int try_irq(u_int Attributes, int irq, int specific); diff -Nru a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c --- a/drivers/pcmcia/rsrc_mgr.c Fri May 21 19:05:35 2004 +++ b/drivers/pcmcia/rsrc_mgr.c Fri May 21 19:05:35 2004 @@ -550,7 +550,7 @@ for (m = data->map->next; m != data->map; m = m->next) { unsigned long start = m->base; - unsigned long end = m->base + m->num; + unsigned long end = m->base + m->num - 1; /* * If the lower resources are not available, try aligning @@ -569,7 +569,7 @@ if (res->start >= res->end) break; - if ((res->start + size) <= end) + if ((res->start + size - 1) <= end) break; } @@ -580,6 +580,32 @@ res->start = res->end; } +/* + * Adjust an existing IO region allocation, but making sure that we don't + * encroach outside the resources which the user supplied. + */ +int adjust_io_region(struct resource *res, unsigned long r_start, + unsigned long r_end, struct pcmcia_socket *s) +{ + resource_map_t *m; + int ret = -ENOMEM; + + down(&rsrc_sem); + for (m = io_db.next; m != &io_db; m = m->next) { + unsigned long start = m->base; + unsigned long end = m->base + m->num - 1; + + if (start > r_start || r_end > end) + continue; + + ret = adjust_resource(res, r_start, r_end - r_start + 1); + break; + } + up(&rsrc_sem); + + return ret; +} + /*====================================================================== These find ranges of I/O ports or memory addresses that are not @@ -593,40 +619,37 @@ ======================================================================*/ -int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align, - char *name, struct pcmcia_socket *s) +struct resource *find_io_region(unsigned long base, int num, + unsigned long align, char *name, struct pcmcia_socket *s) { struct resource *res = make_resource(0, num, IORESOURCE_IO, name); struct pcmcia_align_data data; - unsigned long min = *base; + unsigned long min = base; int ret; if (align == 0) align = 0x10000; data.mask = align - 1; - data.offset = *base & data.mask; + data.offset = base & data.mask; data.map = &io_db; + down(&rsrc_sem); #ifdef CONFIG_PCI if (s->cb_dev) { ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, min, 0, pcmcia_align, &data); } else #endif - { - down(&rsrc_sem); ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, 0, pcmcia_align, &data); - up(&rsrc_sem); - } + up(&rsrc_sem); if (ret != 0) { kfree(res); - } else { - *base = res->start; + res = NULL; } - return ret; + return res; } int find_mem_region(u_long *base, u_long num, u_long align, @@ -652,6 +675,7 @@ min = 0x100000UL + *base; } + down(&rsrc_sem); #ifdef CONFIG_PCI if (s->cb_dev) { ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, @@ -659,12 +683,9 @@ pcmcia_align, &data); } else #endif - { - down(&rsrc_sem); ret = allocate_resource(&iomem_resource, res, num, min, max, 0, pcmcia_align, &data); - up(&rsrc_sem); - } + up(&rsrc_sem); if (ret == 0 || low) break; low = 1; diff -Nru a/include/pcmcia/ss.h b/include/pcmcia/ss.h --- a/include/pcmcia/ss.h Fri May 21 19:05:35 2004 +++ b/include/pcmcia/ss.h Fri May 21 19:05:35 2004 @@ -145,6 +145,7 @@ u_int Attributes; ioaddr_t BasePort, NumPorts; ioaddr_t InUse, Config; + struct resource *res; } io_window_t; #define WINDOW_MAGIC 0xB35C