Commit dd9b7756 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[PATCH] pcmcia: per-socket resource database

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: default avatarDominik Brodowski <linux@brodo.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7d8bbc3a
...@@ -250,6 +250,10 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) ...@@ -250,6 +250,10 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
socket->cis_mem.flags = 0; socket->cis_mem.flags = 0;
socket->cis_mem.speed = cis_speed; 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); INIT_LIST_HEAD(&socket->cis_cache);
spin_lock_init(&socket->lock); spin_lock_init(&socket->lock);
...@@ -305,6 +309,7 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) ...@@ -305,6 +309,7 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
up_write(&pcmcia_socket_list_rwsem); up_write(&pcmcia_socket_list_rwsem);
/* wait for sysfs to drop all references */ /* wait for sysfs to drop all references */
release_resource_db(socket);
wait_for_completion(&socket->socket_released); wait_for_completion(&socket->socket_released);
} /* pcmcia_unregister_socket */ } /* pcmcia_unregister_socket */
EXPORT_SYMBOL(pcmcia_unregister_socket); EXPORT_SYMBOL(pcmcia_unregister_socket);
...@@ -1879,7 +1884,6 @@ static int __init init_pcmcia_cs(void) ...@@ -1879,7 +1884,6 @@ static int __init init_pcmcia_cs(void)
static void __exit exit_pcmcia_cs(void) static void __exit exit_pcmcia_cs(void)
{ {
printk(KERN_INFO "unloading Kernel Card Services\n"); printk(KERN_INFO "unloading Kernel Card Services\n");
release_resource_db();
class_interface_unregister(&pccard_sysfs_interface); class_interface_unregister(&pccard_sysfs_interface);
class_unregister(&pcmcia_socket_class); class_unregister(&pcmcia_socket_class);
} }
......
...@@ -143,7 +143,7 @@ struct resource *find_mem_region(u_long base, u_long num, u_long align, ...@@ -143,7 +143,7 @@ struct resource *find_mem_region(u_long base, u_long num, u_long align,
int try_irq(u_int Attributes, int irq, int specific); int try_irq(u_int Attributes, int irq, int specific);
void undo_irq(u_int Attributes, int irq); void undo_irq(u_int Attributes, int irq);
int adjust_resource_info(client_handle_t handle, adjust_t *adj); 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 */ /* In socket_sysfs.c */
extern struct class_interface pccard_sysfs_interface; extern struct class_interface pccard_sysfs_interface;
......
...@@ -53,23 +53,10 @@ INT_MODULE_PARM(mem_limit, 0x10000); ...@@ -53,23 +53,10 @@ INT_MODULE_PARM(mem_limit, 0x10000);
======================================================================*/ ======================================================================*/
typedef struct resource_map_t { typedef struct resource_map_t 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,
};
static DECLARE_MUTEX(rsrc_sem); static DECLARE_MUTEX(rsrc_sem);
static unsigned int rsrc_mem_probe;
#define MEM_PROBE_LOW (1 << 0) #define MEM_PROBE_LOW (1 << 0)
#define MEM_PROBE_HIGH (1 << 1) #define MEM_PROBE_HIGH (1 << 1)
...@@ -208,7 +195,7 @@ static int sub_interval(resource_map_t *map, u_long base, u_long num) ...@@ -208,7 +195,7 @@ static int sub_interval(resource_map_t *map, u_long base, u_long num)
======================================================================*/ ======================================================================*/
#ifdef CONFIG_PCMCIA_PROBE #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; struct resource *res;
ioaddr_t i, j, bad, any; ioaddr_t i, j, bad, any;
...@@ -253,7 +240,7 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num) ...@@ -253,7 +240,7 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num)
bad = any = i; bad = any = i;
} else { } else {
if (bad) { if (bad) {
sub_interval(&io_db, bad, i-bad); sub_interval(&s->io_db, bad, i-bad);
printk(" %#04x-%#04x", bad, i-1); printk(" %#04x-%#04x", bad, i-1);
bad = 0; bad = 0;
} }
...@@ -264,7 +251,7 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num) ...@@ -264,7 +251,7 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num)
printk(" nothing: probe failed.\n"); printk(" nothing: probe failed.\n");
return; return;
} else { } else {
sub_interval(&io_db, bad, i-bad); sub_interval(&s->io_db, bad, i-bad);
printk(" %#04x-%#04x", bad, i-1); printk(" %#04x-%#04x", bad, i-1);
} }
} }
...@@ -409,7 +396,7 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) ...@@ -409,7 +396,7 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
if (i != j) { if (i != j) {
if (!bad) printk(" excluding"); if (!bad) printk(" excluding");
printk(" %#05lx-%#05lx", i, j-1); printk(" %#05lx-%#05lx", i, j-1);
sub_interval(&mem_db, i, j-i); sub_interval(&s->mem_db, i, j-i);
bad += j-i; bad += j-i;
} }
} }
...@@ -422,12 +409,12 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) ...@@ -422,12 +409,12 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s) static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s)
{ {
u_long ok; u_long ok;
if (m == &mem_db) if (m == &s->mem_db)
return 0; return 0;
ok = inv_probe(m->next, s); ok = inv_probe(m->next, s);
if (ok) { if (ok) {
if (m->base >= 0x100000) if (m->base >= 0x100000)
sub_interval(&mem_db, m->base, m->num); sub_interval(&s->mem_db, m->base, m->num);
return ok; return ok;
} }
if (m->base < 0x100000) if (m->base < 0x100000)
...@@ -443,14 +430,14 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) ...@@ -443,14 +430,14 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
/* We do up to four passes through the list */ /* We do up to four passes through the list */
if (probe_mask & MEM_PROBE_HIGH) { if (probe_mask & MEM_PROBE_HIGH) {
if (inv_probe(mem_db.next, s) > 0) if (inv_probe(s->mem_db.next, s) > 0)
return; return;
printk(KERN_NOTICE "cs: warning: no high memory space " printk(KERN_NOTICE "cs: warning: no high memory space "
"available!\n"); "available!\n");
} }
if ((probe_mask & MEM_PROBE_LOW) == 0) if ((probe_mask & MEM_PROBE_LOW) == 0)
return; 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; mm = *m;
/* Only probe < 1 MB */ /* Only probe < 1 MB */
if (mm.base >= 0x100000) continue; if (mm.base >= 0x100000) continue;
...@@ -463,7 +450,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) ...@@ -463,7 +450,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
b = order[i] << 12; b = order[i] << 12;
if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
if (ok >= mem_limit) if (ok >= mem_limit)
sub_interval(&mem_db, b, 0x10000); sub_interval(&s->mem_db, b, 0x10000);
else else
ok += do_mem_probe(b, 0x10000, s); ok += do_mem_probe(b, 0x10000, s);
} }
...@@ -477,7 +464,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) ...@@ -477,7 +464,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
{ {
resource_map_t *m, mm; 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; mm = *m;
if (do_mem_probe(mm.base, mm.num, s)) if (do_mem_probe(mm.base, mm.num, s))
break; break;
...@@ -501,8 +488,8 @@ void pcmcia_validate_mem(struct pcmcia_socket *s) ...@@ -501,8 +488,8 @@ void pcmcia_validate_mem(struct pcmcia_socket *s)
if (s->features & SS_CAP_PAGE_REGS) if (s->features & SS_CAP_PAGE_REGS)
probe_mask = MEM_PROBE_HIGH; probe_mask = MEM_PROBE_HIGH;
if (probe_mask & ~rsrc_mem_probe) { if (probe_mask & ~s->rsrc_mem_probe) {
rsrc_mem_probe |= probe_mask; s->rsrc_mem_probe |= probe_mask;
down(&s->skt_sem); down(&s->skt_sem);
...@@ -591,7 +578,7 @@ int adjust_io_region(struct resource *res, unsigned long r_start, ...@@ -591,7 +578,7 @@ int adjust_io_region(struct resource *res, unsigned long r_start,
int ret = -ENOMEM; int ret = -ENOMEM;
down(&rsrc_sem); 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 start = m->base;
unsigned long end = m->base + m->num - 1; unsigned long end = m->base + m->num - 1;
...@@ -632,7 +619,7 @@ struct resource *find_io_region(unsigned long base, int num, ...@@ -632,7 +619,7 @@ struct resource *find_io_region(unsigned long base, int num,
data.mask = align - 1; data.mask = align - 1;
data.offset = base & data.mask; data.offset = base & data.mask;
data.map = &io_db; data.map = &s->io_db;
down(&rsrc_sem); down(&rsrc_sem);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
...@@ -664,7 +651,7 @@ struct resource *find_mem_region(u_long base, u_long num, u_long align, ...@@ -664,7 +651,7 @@ struct resource *find_mem_region(u_long base, u_long num, u_long align,
data.mask = align - 1; data.mask = align - 1;
data.offset = base & data.mask; data.offset = base & data.mask;
data.map = &mem_db; data.map = &s->mem_db;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (low) { if (low) {
...@@ -830,7 +817,7 @@ void undo_irq(u_int Attributes, int irq) ...@@ -830,7 +817,7 @@ void undo_irq(u_int Attributes, int irq)
======================================================================*/ ======================================================================*/
static int adjust_memory(adjust_t *adj) static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
{ {
u_long base, num; u_long base, num;
int ret; int ret;
...@@ -845,10 +832,10 @@ static int adjust_memory(adjust_t *adj) ...@@ -845,10 +832,10 @@ static int adjust_memory(adjust_t *adj)
down(&rsrc_sem); down(&rsrc_sem);
switch (adj->Action) { switch (adj->Action) {
case ADD_MANAGED_RESOURCE: case ADD_MANAGED_RESOURCE:
ret = add_interval(&mem_db, base, num); ret = add_interval(&s->mem_db, base, num);
break; break;
case REMOVE_MANAGED_RESOURCE: case REMOVE_MANAGED_RESOURCE:
ret = sub_interval(&mem_db, base, num); ret = sub_interval(&s->mem_db, base, num);
if (ret == CS_SUCCESS) { if (ret == CS_SUCCESS) {
struct pcmcia_socket *socket; struct pcmcia_socket *socket;
down_read(&pcmcia_socket_list_rwsem); down_read(&pcmcia_socket_list_rwsem);
...@@ -867,7 +854,7 @@ static int adjust_memory(adjust_t *adj) ...@@ -867,7 +854,7 @@ static int adjust_memory(adjust_t *adj)
/*====================================================================*/ /*====================================================================*/
static int adjust_io(adjust_t *adj) static int adjust_io(struct pcmcia_socket *s, adjust_t *adj)
{ {
int base, num, ret = CS_SUCCESS; int base, num, ret = CS_SUCCESS;
...@@ -881,17 +868,17 @@ static int adjust_io(adjust_t *adj) ...@@ -881,17 +868,17 @@ static int adjust_io(adjust_t *adj)
down(&rsrc_sem); down(&rsrc_sem);
switch (adj->Action) { switch (adj->Action) {
case ADD_MANAGED_RESOURCE: 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; ret = CS_IN_USE;
break; break;
} }
#ifdef CONFIG_PCMCIA_PROBE #ifdef CONFIG_PCMCIA_PROBE
if (probe_io) if (probe_io)
do_io_probe(base, num); do_io_probe(s, base, num);
#endif #endif
break; break;
case REMOVE_MANAGED_RESOURCE: case REMOVE_MANAGED_RESOURCE:
sub_interval(&io_db, base, num); sub_interval(&s->io_db, base, num);
break; break;
default: default:
ret = CS_UNSUPPORTED_FUNCTION; ret = CS_UNSUPPORTED_FUNCTION;
...@@ -956,32 +943,40 @@ static int adjust_irq(adjust_t *adj) ...@@ -956,32 +943,40 @@ static int adjust_irq(adjust_t *adj)
int pcmcia_adjust_resource_info(adjust_t *adj) int pcmcia_adjust_resource_info(adjust_t *adj)
{ {
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) { switch (adj->Resource) {
case RES_MEMORY_RANGE: case RES_MEMORY_RANGE:
return adjust_memory(adj); ret = adjust_memory(s, adj);
break; break;
case RES_IO_RANGE: case RES_IO_RANGE:
return adjust_io(adj); ret = adjust_io(s, adj);
break;
case RES_IRQ:
return adjust_irq(adj);
break; break;
} }
return CS_UNSUPPORTED_FUNCTION; }
up_read(&pcmcia_socket_list_rwsem);
return (ret);
} }
EXPORT_SYMBOL(pcmcia_adjust_resource_info); EXPORT_SYMBOL(pcmcia_adjust_resource_info);
/*====================================================================*/ /*====================================================================*/
void release_resource_db(void) void release_resource_db(struct pcmcia_socket *s)
{ {
resource_map_t *p, *q; 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; q = p->next;
kfree(p); 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; q = p->next;
kfree(p); kfree(p);
} }
......
...@@ -146,6 +146,12 @@ struct config_t; ...@@ -146,6 +146,12 @@ struct config_t;
struct region_t; struct region_t;
struct pcmcia_callback; 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 pcmcia_socket {
struct module *owner; struct module *owner;
spinlock_t lock; spinlock_t lock;
...@@ -170,6 +176,10 @@ struct pcmcia_socket { ...@@ -170,6 +176,10 @@ struct pcmcia_socket {
struct list_head socket_list; struct list_head socket_list;
struct completion socket_released; struct completion socket_released;
struct resource_map_t mem_db;
struct resource_map_t io_db;
unsigned int rsrc_mem_probe;
/* deprecated */ /* deprecated */
unsigned int sock; /* socket number */ unsigned int sock; /* socket number */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment