Make the io and mem db per-socket, as different sockets may have different requirements or may not even need the resource db at all (SS_CAP_STATIC_MAP). Updated to make rsrc_mem_probe per-socket and to remove unnecessary and even broken check for empty list as per Russell King's suggestions. Signed-off-by: Dominik Brodowski drivers/pcmcia/cs.c | 6 ++ drivers/pcmcia/cs_internal.h | 2 drivers/pcmcia/rsrc_mgr.c | 99 ++++++++++++++++++++----------------------- include/pcmcia/ss.h | 10 ++++ 4 files changed, 63 insertions(+), 54 deletions(-) diff -ruN linux-original/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- linux-original/drivers/pcmcia/cs.c 2004-11-07 13:07:18.950493544 +0100 +++ linux/drivers/pcmcia/cs.c 2004-11-07 13:07:39.706338176 +0100 @@ -250,6 +250,10 @@ socket->cis_mem.flags = 0; socket->cis_mem.speed = cis_speed; + /* init resource database */ + socket->mem_db.next = &socket->mem_db; + socket->io_db.next = &socket->io_db; + INIT_LIST_HEAD(&socket->cis_cache); spin_lock_init(&socket->lock); @@ -305,6 +309,7 @@ up_write(&pcmcia_socket_list_rwsem); /* wait for sysfs to drop all references */ + release_resource_db(socket); wait_for_completion(&socket->socket_released); } /* pcmcia_unregister_socket */ EXPORT_SYMBOL(pcmcia_unregister_socket); @@ -1879,7 +1884,6 @@ static void __exit exit_pcmcia_cs(void) { printk(KERN_INFO "unloading Kernel Card Services\n"); - release_resource_db(); class_interface_unregister(&pccard_sysfs_interface); class_unregister(&pcmcia_socket_class); } diff -ruN linux-original/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h --- linux-original/drivers/pcmcia/cs_internal.h 2004-11-07 13:07:18.950493544 +0100 +++ linux/drivers/pcmcia/cs_internal.h 2004-11-07 13:07:39.707338024 +0100 @@ -143,7 +143,7 @@ int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); -void release_resource_db(void); +void release_resource_db(struct pcmcia_socket *s); /* In socket_sysfs.c */ extern struct class_interface pccard_sysfs_interface; diff -ruN linux-original/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c --- linux-original/drivers/pcmcia/rsrc_mgr.c 2004-11-07 13:07:18.959492176 +0100 +++ linux/drivers/pcmcia/rsrc_mgr.c 2004-11-07 13:10:31.379239928 +0100 @@ -53,23 +53,10 @@ ======================================================================*/ -typedef struct resource_map_t { - u_long base, num; - struct resource_map_t *next; -} resource_map_t; - -/* Memory resource database */ -static resource_map_t mem_db = { - .next = &mem_db, -}; - -/* IO port resource database */ -static resource_map_t io_db = { - .next = &io_db, -}; +typedef struct resource_map_t resource_map_t; static DECLARE_MUTEX(rsrc_sem); -static unsigned int rsrc_mem_probe; + #define MEM_PROBE_LOW (1 << 0) #define MEM_PROBE_HIGH (1 << 1) @@ -208,7 +195,7 @@ ======================================================================*/ #ifdef CONFIG_PCMCIA_PROBE -static void do_io_probe(ioaddr_t base, ioaddr_t num) +static void do_io_probe(struct pcmcia_socket *s, ioaddr_t base, ioaddr_t num) { struct resource *res; ioaddr_t i, j, bad, any; @@ -253,7 +240,7 @@ bad = any = i; } else { if (bad) { - sub_interval(&io_db, bad, i-bad); + sub_interval(&s->io_db, bad, i-bad); printk(" %#04x-%#04x", bad, i-1); bad = 0; } @@ -264,7 +251,7 @@ printk(" nothing: probe failed.\n"); return; } else { - sub_interval(&io_db, bad, i-bad); + sub_interval(&s->io_db, bad, i-bad); printk(" %#04x-%#04x", bad, i-1); } } @@ -409,7 +396,7 @@ if (i != j) { if (!bad) printk(" excluding"); printk(" %#05lx-%#05lx", i, j-1); - sub_interval(&mem_db, i, j-i); + sub_interval(&s->mem_db, i, j-i); bad += j-i; } } @@ -422,12 +409,12 @@ static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s) { u_long ok; - if (m == &mem_db) + if (m == &s->mem_db) return 0; ok = inv_probe(m->next, s); if (ok) { if (m->base >= 0x100000) - sub_interval(&mem_db, m->base, m->num); + sub_interval(&s->mem_db, m->base, m->num); return ok; } if (m->base < 0x100000) @@ -443,14 +430,14 @@ /* We do up to four passes through the list */ if (probe_mask & MEM_PROBE_HIGH) { - if (inv_probe(mem_db.next, s) > 0) + if (inv_probe(s->mem_db.next, s) > 0) return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); } if ((probe_mask & MEM_PROBE_LOW) == 0) return; - for (m = mem_db.next; m != &mem_db; m = mm.next) { + for (m = s->mem_db.next; m != &s->mem_db; m = mm.next) { mm = *m; /* Only probe < 1 MB */ if (mm.base >= 0x100000) continue; @@ -463,7 +450,7 @@ b = order[i] << 12; if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { if (ok >= mem_limit) - sub_interval(&mem_db, b, 0x10000); + sub_interval(&s->mem_db, b, 0x10000); else ok += do_mem_probe(b, 0x10000, s); } @@ -477,7 +464,7 @@ { resource_map_t *m, mm; - for (m = mem_db.next; m != &mem_db; m = mm.next) { + for (m = s->mem_db.next; m != &s->mem_db; m = mm.next) { mm = *m; if (do_mem_probe(mm.base, mm.num, s)) break; @@ -501,8 +488,8 @@ if (s->features & SS_CAP_PAGE_REGS) probe_mask = MEM_PROBE_HIGH; - if (probe_mask & ~rsrc_mem_probe) { - rsrc_mem_probe |= probe_mask; + if (probe_mask & ~s->rsrc_mem_probe) { + s->rsrc_mem_probe |= probe_mask; down(&s->skt_sem); @@ -591,7 +578,7 @@ int ret = -ENOMEM; down(&rsrc_sem); - for (m = io_db.next; m != &io_db; m = m->next) { + for (m = s->io_db.next; m != &s->io_db; m = m->next) { unsigned long start = m->base; unsigned long end = m->base + m->num - 1; @@ -632,7 +619,7 @@ data.mask = align - 1; data.offset = base & data.mask; - data.map = &io_db; + data.map = &s->io_db; down(&rsrc_sem); #ifdef CONFIG_PCI @@ -664,7 +651,7 @@ data.mask = align - 1; data.offset = base & data.mask; - data.map = &mem_db; + data.map = &s->mem_db; for (i = 0; i < 2; i++) { if (low) { @@ -830,7 +817,7 @@ ======================================================================*/ -static int adjust_memory(adjust_t *adj) +static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) { u_long base, num; int ret; @@ -845,10 +832,10 @@ down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: - ret = add_interval(&mem_db, base, num); + ret = add_interval(&s->mem_db, base, num); break; case REMOVE_MANAGED_RESOURCE: - ret = sub_interval(&mem_db, base, num); + ret = sub_interval(&s->mem_db, base, num); if (ret == CS_SUCCESS) { struct pcmcia_socket *socket; down_read(&pcmcia_socket_list_rwsem); @@ -867,7 +854,7 @@ /*====================================================================*/ -static int adjust_io(adjust_t *adj) +static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) { int base, num, ret = CS_SUCCESS; @@ -881,17 +868,17 @@ down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: - if (add_interval(&io_db, base, num) != 0) { + if (add_interval(&s->io_db, base, num) != 0) { ret = CS_IN_USE; break; } #ifdef CONFIG_PCMCIA_PROBE if (probe_io) - do_io_probe(base, num); + do_io_probe(s, base, num); #endif break; case REMOVE_MANAGED_RESOURCE: - sub_interval(&io_db, base, num); + sub_interval(&s->io_db, base, num); break; default: ret = CS_UNSUPPORTED_FUNCTION; @@ -956,32 +943,40 @@ int pcmcia_adjust_resource_info(adjust_t *adj) { - switch (adj->Resource) { - case RES_MEMORY_RANGE: - return adjust_memory(adj); - break; - case RES_IO_RANGE: - return adjust_io(adj); - break; - case RES_IRQ: - return adjust_irq(adj); - break; - } - return CS_UNSUPPORTED_FUNCTION; + struct pcmcia_socket *s; + int ret = CS_UNSUPPORTED_FUNCTION; + + if (adj->Resource == RES_IRQ) + return adjust_irq(adj); + + down_read(&pcmcia_socket_list_rwsem); + list_for_each_entry(s, &pcmcia_socket_list, socket_list) { + switch (adj->Resource) { + case RES_MEMORY_RANGE: + ret = adjust_memory(s, adj); + break; + case RES_IO_RANGE: + ret = adjust_io(s, adj); + break; + } + } + up_read(&pcmcia_socket_list_rwsem); + + return (ret); } EXPORT_SYMBOL(pcmcia_adjust_resource_info); /*====================================================================*/ -void release_resource_db(void) +void release_resource_db(struct pcmcia_socket *s) { resource_map_t *p, *q; - for (p = mem_db.next; p != &mem_db; p = q) { + for (p = s->mem_db.next; p != &s->mem_db; p = q) { q = p->next; kfree(p); } - for (p = io_db.next; p != &io_db; p = q) { + for (p = s->io_db.next; p != &s->io_db; p = q) { q = p->next; kfree(p); } diff -ruN linux-original/include/pcmcia/ss.h linux/include/pcmcia/ss.h --- linux-original/include/pcmcia/ss.h 2004-11-07 13:07:18.988487768 +0100 +++ linux/include/pcmcia/ss.h 2004-11-07 13:14:19.299590768 +0100 @@ -146,6 +146,12 @@ struct region_t; struct pcmcia_callback; +/* for io_db and mem_db */ +struct resource_map_t { + u_long base, num; + struct resource_map_t *next; +}; + struct pcmcia_socket { struct module *owner; spinlock_t lock; @@ -170,6 +176,10 @@ struct list_head socket_list; struct completion socket_released; + struct resource_map_t mem_db; + struct resource_map_t io_db; + unsigned int rsrc_mem_probe; + /* deprecated */ unsigned int sock; /* socket number */