Commit 8fda2958 authored by Russell King's avatar Russell King

[PCMCIA] pcmcia-5: Add locking to resource manager.

Add an element of locking to the resource manager - don't allow
the PCMCIA resource lists to be changed while the pcmcia code is
scanning them.
parent 88d681e2
...@@ -85,6 +85,8 @@ static resource_map_t mem_db = { 0, 0, &mem_db }; ...@@ -85,6 +85,8 @@ static resource_map_t mem_db = { 0, 0, &mem_db };
/* IO port resource database */ /* IO port resource database */
static resource_map_t io_db = { 0, 0, &io_db }; static resource_map_t io_db = { 0, 0, &io_db };
static DECLARE_MUTEX(rsrc_sem);
#ifdef CONFIG_ISA #ifdef CONFIG_ISA
typedef struct irq_info_t { typedef struct irq_info_t {
...@@ -404,15 +406,19 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), ...@@ -404,15 +406,19 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
static int hi = 0, lo = 0; static int hi = 0, lo = 0;
u_long b, i, ok = 0; u_long b, i, ok = 0;
if (!probe_mem) return; if (!probe_mem)
return;
down(&rsrc_sem);
/* We do up to four passes through the list */ /* We do up to four passes through the list */
if (!force_low) { if (!force_low) {
if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0)) if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0))
return; goto out;
printk(KERN_NOTICE "cs: warning: no high memory space " printk(KERN_NOTICE "cs: warning: no high memory space "
"available!\n"); "available!\n");
} }
if (lo++) return; if (lo++)
goto out;
for (m = mem_db.next; m != &mem_db; m = n) { for (m = mem_db.next; m != &mem_db; m = n) {
n = m->next; n = m->next;
/* Only probe < 1 MB */ /* Only probe < 1 MB */
...@@ -432,6 +438,8 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), ...@@ -432,6 +438,8 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
} }
} }
} }
out:
up(&rsrc_sem);
} }
#else /* CONFIG_ISA */ #else /* CONFIG_ISA */
...@@ -442,11 +450,13 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), ...@@ -442,11 +450,13 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
resource_map_t *m; resource_map_t *m;
static int done = 0; static int done = 0;
if (!probe_mem || done++) if (probe_mem && done++ == 0) {
return; down(&rsrc_sem);
for (m = mem_db.next; m != &mem_db; m = m->next) for (m = mem_db.next; m != &mem_db; m = m->next)
if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s)) if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s))
return; break;
up(&rsrc_sem);
}
} }
#endif /* CONFIG_ISA */ #endif /* CONFIG_ISA */
...@@ -469,7 +479,9 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, ...@@ -469,7 +479,9 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
{ {
ioaddr_t try; ioaddr_t try;
resource_map_t *m; resource_map_t *m;
int ret = -1;
down(&rsrc_sem);
for (m = io_db.next; m != &io_db; m = m->next) { for (m = io_db.next; m != &io_db; m = m->next) {
try = (m->base & ~(align-1)) + *base; try = (m->base & ~(align-1)) + *base;
for (try = (try >= m->base) ? try : try+align; for (try = (try >= m->base) ? try : try+align;
...@@ -477,12 +489,16 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, ...@@ -477,12 +489,16 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
try += align) { try += align) {
if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) { if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) {
*base = try; *base = try;
return 0; ret = 0;
goto out;
} }
if (!align) break; if (!align)
break;
} }
} }
return -1; out:
up(&rsrc_sem);
return ret;
} }
int find_mem_region(u_long *base, u_long num, u_long align, int find_mem_region(u_long *base, u_long num, u_long align,
...@@ -490,26 +506,35 @@ int find_mem_region(u_long *base, u_long num, u_long align, ...@@ -490,26 +506,35 @@ int find_mem_region(u_long *base, u_long num, u_long align,
{ {
u_long try; u_long try;
resource_map_t *m; resource_map_t *m;
int ret = -1;
down(&rsrc_sem);
while (1) { while (1) {
for (m = mem_db.next; m != &mem_db; m = m->next) { for (m = mem_db.next; m != &mem_db; m = m->next) {
/* first pass >1MB, second pass <1MB */ /* first pass >1MB, second pass <1MB */
if ((force_low != 0) ^ (m->base < 0x100000)) continue; if ((force_low != 0) ^ (m->base < 0x100000))
continue;
try = (m->base & ~(align-1)) + *base; try = (m->base & ~(align-1)) + *base;
for (try = (try >= m->base) ? try : try+align; for (try = (try >= m->base) ? try : try+align;
(try >= m->base) && (try+num <= m->base+m->num); (try >= m->base) && (try+num <= m->base+m->num);
try += align) { try += align) {
if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) { if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) {
*base = try; *base = try;
return 0; ret = 0;
goto out;
} }
if (!align) break; if (!align)
break;
} }
} }
if (force_low) break; if (force_low)
break;
force_low++; force_low++;
} }
return -1; out:
up(&rsrc_sem);
return ret;
} }
/*====================================================================== /*======================================================================
...@@ -534,53 +559,75 @@ static inline int check_irq(int irq) ...@@ -534,53 +559,75 @@ static inline int check_irq(int irq)
int try_irq(u_int Attributes, int irq, int specific) int try_irq(u_int Attributes, int irq, int specific)
{ {
irq_info_t *info = &irq_table[irq]; irq_info_t *info = &irq_table[irq];
int ret = 0;
down(&rsrc_sem);
if (info->Attributes & RES_ALLOCATED) { if (info->Attributes & RES_ALLOCATED) {
switch (Attributes & IRQ_TYPE) { switch (Attributes & IRQ_TYPE) {
case IRQ_TYPE_EXCLUSIVE: case IRQ_TYPE_EXCLUSIVE:
return CS_IN_USE; ret = CS_IN_USE;
break;
case IRQ_TYPE_TIME: case IRQ_TYPE_TIME:
if ((info->Attributes & RES_IRQ_TYPE) if ((info->Attributes & RES_IRQ_TYPE)
!= RES_IRQ_TYPE_TIME) != RES_IRQ_TYPE_TIME) {
return CS_IN_USE; ret = CS_IN_USE;
if (Attributes & IRQ_FIRST_SHARED) break;
return CS_BAD_ATTRIBUTE; }
if (Attributes & IRQ_FIRST_SHARED) {
ret = CS_BAD_ATTRIBUTE;
break;
}
info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED; info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
info->time_share++; info->time_share++;
break; break;
case IRQ_TYPE_DYNAMIC_SHARING: case IRQ_TYPE_DYNAMIC_SHARING:
if ((info->Attributes & RES_IRQ_TYPE) if ((info->Attributes & RES_IRQ_TYPE)
!= RES_IRQ_TYPE_DYNAMIC) != RES_IRQ_TYPE_DYNAMIC) {
return CS_IN_USE; ret = CS_IN_USE;
if (Attributes & IRQ_FIRST_SHARED) break;
return CS_BAD_ATTRIBUTE; }
if (Attributes & IRQ_FIRST_SHARED) {
ret = CS_BAD_ATTRIBUTE;
break;
}
info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED; info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
info->dyn_share++; info->dyn_share++;
break; break;
} }
} else { } else {
if ((info->Attributes & RES_RESERVED) && !specific) if ((info->Attributes & RES_RESERVED) && !specific) {
return CS_IN_USE; ret = CS_IN_USE;
if (check_irq(irq) != 0) goto out;
return CS_IN_USE; }
if (check_irq(irq) != 0) {
ret = CS_IN_USE;
goto out;
}
switch (Attributes & IRQ_TYPE) { switch (Attributes & IRQ_TYPE) {
case IRQ_TYPE_EXCLUSIVE: case IRQ_TYPE_EXCLUSIVE:
info->Attributes |= RES_ALLOCATED; info->Attributes |= RES_ALLOCATED;
break; break;
case IRQ_TYPE_TIME: case IRQ_TYPE_TIME:
if (!(Attributes & IRQ_FIRST_SHARED)) if (!(Attributes & IRQ_FIRST_SHARED)) {
return CS_BAD_ATTRIBUTE; ret = CS_BAD_ATTRIBUTE;
break;
}
info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED; info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
info->time_share = 1; info->time_share = 1;
break; break;
case IRQ_TYPE_DYNAMIC_SHARING: case IRQ_TYPE_DYNAMIC_SHARING:
if (!(Attributes & IRQ_FIRST_SHARED)) if (!(Attributes & IRQ_FIRST_SHARED)) {
return CS_BAD_ATTRIBUTE; ret = CS_BAD_ATTRIBUTE;
break;
}
info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED; info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
info->dyn_share = 1; info->dyn_share = 1;
break; break;
} }
} }
return 0; out:
up(&rsrc_sem);
return ret;
} }
#endif #endif
...@@ -594,6 +641,7 @@ void undo_irq(u_int Attributes, int irq) ...@@ -594,6 +641,7 @@ void undo_irq(u_int Attributes, int irq)
irq_info_t *info; irq_info_t *info;
info = &irq_table[irq]; info = &irq_table[irq];
down(&rsrc_sem);
switch (Attributes & IRQ_TYPE) { switch (Attributes & IRQ_TYPE) {
case IRQ_TYPE_EXCLUSIVE: case IRQ_TYPE_EXCLUSIVE:
info->Attributes &= RES_RESERVED; info->Attributes &= RES_RESERVED;
...@@ -609,6 +657,7 @@ void undo_irq(u_int Attributes, int irq) ...@@ -609,6 +657,7 @@ void undo_irq(u_int Attributes, int irq)
info->Attributes &= RES_RESERVED; info->Attributes &= RES_RESERVED;
break; break;
} }
up(&rsrc_sem);
} }
#endif #endif
...@@ -631,6 +680,8 @@ static int adjust_memory(adjust_t *adj) ...@@ -631,6 +680,8 @@ static int adjust_memory(adjust_t *adj)
return CS_BAD_SIZE; return CS_BAD_SIZE;
ret = CS_SUCCESS; ret = CS_SUCCESS;
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(&mem_db, base, num);
...@@ -649,6 +700,7 @@ static int adjust_memory(adjust_t *adj) ...@@ -649,6 +700,7 @@ static int adjust_memory(adjust_t *adj)
default: default:
ret = CS_UNSUPPORTED_FUNCTION; ret = CS_UNSUPPORTED_FUNCTION;
} }
up(&rsrc_sem);
return ret; return ret;
} }
...@@ -657,7 +709,7 @@ static int adjust_memory(adjust_t *adj) ...@@ -657,7 +709,7 @@ static int adjust_memory(adjust_t *adj)
static int adjust_io(adjust_t *adj) static int adjust_io(adjust_t *adj)
{ {
int base, num; int base, num, ret = CS_SUCCESS;
base = adj->resource.io.BasePort; base = adj->resource.io.BasePort;
num = adj->resource.io.NumPorts; num = adj->resource.io.NumPorts;
...@@ -666,10 +718,13 @@ static int adjust_io(adjust_t *adj) ...@@ -666,10 +718,13 @@ static int adjust_io(adjust_t *adj)
if ((num <= 0) || (base+num > 0x10000) || (base+num <= base)) if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
return CS_BAD_SIZE; return CS_BAD_SIZE;
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(&io_db, base, num) != 0) {
return CS_IN_USE; ret = CS_IN_USE;
break;
}
#ifdef CONFIG_ISA #ifdef CONFIG_ISA
if (probe_io) if (probe_io)
do_io_probe(base, num); do_io_probe(base, num);
...@@ -679,17 +734,19 @@ static int adjust_io(adjust_t *adj) ...@@ -679,17 +734,19 @@ static int adjust_io(adjust_t *adj)
sub_interval(&io_db, base, num); sub_interval(&io_db, base, num);
break; break;
default: default:
return CS_UNSUPPORTED_FUNCTION; ret = CS_UNSUPPORTED_FUNCTION;
break; break;
} }
up(&rsrc_sem);
return CS_SUCCESS; return ret;
} }
/*====================================================================*/ /*====================================================================*/
static int adjust_irq(adjust_t *adj) static int adjust_irq(adjust_t *adj)
{ {
int ret = CS_SUCCESS;
#ifdef CONFIG_ISA #ifdef CONFIG_ISA
int irq; int irq;
irq_info_t *info; irq_info_t *info;
...@@ -699,32 +756,40 @@ static int adjust_irq(adjust_t *adj) ...@@ -699,32 +756,40 @@ static int adjust_irq(adjust_t *adj)
return CS_BAD_IRQ; return CS_BAD_IRQ;
info = &irq_table[irq]; info = &irq_table[irq];
down(&rsrc_sem);
switch (adj->Action) { switch (adj->Action) {
case ADD_MANAGED_RESOURCE: case ADD_MANAGED_RESOURCE:
if (info->Attributes & RES_REMOVED) if (info->Attributes & RES_REMOVED)
info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED); info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
else else
if (adj->Attributes & RES_ALLOCATED) if (adj->Attributes & RES_ALLOCATED) {
return CS_IN_USE; ret = CS_IN_USE;
break;
}
if (adj->Attributes & RES_RESERVED) if (adj->Attributes & RES_RESERVED)
info->Attributes |= RES_RESERVED; info->Attributes |= RES_RESERVED;
else else
info->Attributes &= ~RES_RESERVED; info->Attributes &= ~RES_RESERVED;
break; break;
case REMOVE_MANAGED_RESOURCE: case REMOVE_MANAGED_RESOURCE:
if (info->Attributes & RES_REMOVED) if (info->Attributes & RES_REMOVED) {
return 0; ret = 0;
if (info->Attributes & RES_ALLOCATED) break;
return CS_IN_USE; }
if (info->Attributes & RES_ALLOCATED) {
ret = CS_IN_USE;
break;
}
info->Attributes |= RES_ALLOCATED|RES_REMOVED; info->Attributes |= RES_ALLOCATED|RES_REMOVED;
info->Attributes &= ~RES_RESERVED; info->Attributes &= ~RES_RESERVED;
break; break;
default: default:
return CS_UNSUPPORTED_FUNCTION; ret = CS_UNSUPPORTED_FUNCTION;
break; break;
} }
up(&rsrc_sem);
#endif #endif
return CS_SUCCESS; return ret;
} }
/*====================================================================*/ /*====================================================================*/
......
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