[PATCH] pcmcia: validate_mem shouldn't be void
Add a return value to pcmcia_validate_mem. Only if we have enough memory available to map the CIS, we should proceed in trying to determine information about the device. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
This commit is contained in:
parent
9da4bc6d6a
commit
de75914ee1
|
@ -117,7 +117,7 @@ int verify_cis_cache(struct pcmcia_socket *s);
|
|||
int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse);
|
||||
|
||||
/* In rsrc_mgr */
|
||||
void pcmcia_validate_mem(struct pcmcia_socket *s);
|
||||
int pcmcia_validate_mem(struct pcmcia_socket *s);
|
||||
struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align,
|
||||
struct pcmcia_socket *s);
|
||||
int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
|
||||
|
|
|
@ -583,7 +583,9 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
|
|||
if (!(s->resource_setup_done))
|
||||
return -EAGAIN; /* try again, but later... */
|
||||
|
||||
pcmcia_validate_mem(s);
|
||||
if (pcmcia_validate_mem(s))
|
||||
return -EAGAIN; /* try again, but later... */
|
||||
|
||||
ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);
|
||||
if (ret || !cisinfo.Chains) {
|
||||
ds_dbg(0, "invalid CIS or invalid resources\n");
|
||||
|
|
|
@ -98,10 +98,12 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
|
|||
}
|
||||
EXPORT_SYMBOL(pcmcia_adjust_resource_info);
|
||||
|
||||
void pcmcia_validate_mem(struct pcmcia_socket *s)
|
||||
int pcmcia_validate_mem(struct pcmcia_socket *s)
|
||||
{
|
||||
if (s->resource_ops->validate_mem)
|
||||
s->resource_ops->validate_mem(s);
|
||||
return s->resource_ops->validate_mem(s);
|
||||
/* if there is no callback, we can assume that everything is OK */
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pcmcia_validate_mem);
|
||||
|
||||
|
|
|
@ -407,56 +407,62 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
|
|||
|
||||
static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
|
||||
{
|
||||
struct socket_data *s_data = s->resource_data;
|
||||
u_long ok;
|
||||
if (m == &s_data->mem_db)
|
||||
return 0;
|
||||
ok = inv_probe(m->next, s);
|
||||
if (ok) {
|
||||
if (m->base >= 0x100000)
|
||||
sub_interval(&s_data->mem_db, m->base, m->num);
|
||||
return ok;
|
||||
}
|
||||
if (m->base < 0x100000)
|
||||
return 0;
|
||||
return do_mem_probe(m->base, m->num, s);
|
||||
struct socket_data *s_data = s->resource_data;
|
||||
u_long ok;
|
||||
if (m == &s_data->mem_db)
|
||||
return 0;
|
||||
ok = inv_probe(m->next, s);
|
||||
if (ok) {
|
||||
if (m->base >= 0x100000)
|
||||
sub_interval(&s_data->mem_db, m->base, m->num);
|
||||
return ok;
|
||||
}
|
||||
if (m->base < 0x100000)
|
||||
return 0;
|
||||
return do_mem_probe(m->base, m->num, s);
|
||||
}
|
||||
|
||||
static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
|
||||
static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
|
||||
{
|
||||
struct resource_map *m, mm;
|
||||
static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
|
||||
u_long b, i, ok = 0;
|
||||
struct socket_data *s_data = s->resource_data;
|
||||
struct resource_map *m, mm;
|
||||
static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
|
||||
unsigned long b, i, ok = 0;
|
||||
struct socket_data *s_data = s->resource_data;
|
||||
|
||||
/* We do up to four passes through the list */
|
||||
if (probe_mask & MEM_PROBE_HIGH) {
|
||||
if (inv_probe(s_data->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 = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
|
||||
mm = *m;
|
||||
/* Only probe < 1 MB */
|
||||
if (mm.base >= 0x100000) continue;
|
||||
if ((mm.base | mm.num) & 0xffff) {
|
||||
ok += do_mem_probe(mm.base, mm.num, s);
|
||||
continue;
|
||||
/* We do up to four passes through the list */
|
||||
if (probe_mask & MEM_PROBE_HIGH) {
|
||||
if (inv_probe(s_data->mem_db.next, s) > 0)
|
||||
return 0;
|
||||
printk(KERN_NOTICE "cs: warning: no high memory space "
|
||||
"available!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
/* Special probe for 64K-aligned block */
|
||||
for (i = 0; i < 4; i++) {
|
||||
b = order[i] << 12;
|
||||
if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
|
||||
if (ok >= mem_limit)
|
||||
sub_interval(&s_data->mem_db, b, 0x10000);
|
||||
else
|
||||
ok += do_mem_probe(b, 0x10000, s);
|
||||
}
|
||||
|
||||
for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
|
||||
mm = *m;
|
||||
/* Only probe < 1 MB */
|
||||
if (mm.base >= 0x100000)
|
||||
continue;
|
||||
if ((mm.base | mm.num) & 0xffff) {
|
||||
ok += do_mem_probe(mm.base, mm.num, s);
|
||||
continue;
|
||||
}
|
||||
/* Special probe for 64K-aligned block */
|
||||
for (i = 0; i < 4; i++) {
|
||||
b = order[i] << 12;
|
||||
if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
|
||||
if (ok >= mem_limit)
|
||||
sub_interval(&s_data->mem_db, b, 0x10000);
|
||||
else
|
||||
ok += do_mem_probe(b, 0x10000, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ok > 0)
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#else /* CONFIG_PCMCIA_PROBE */
|
||||
|
@ -478,27 +484,30 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
|
|||
/*
|
||||
* Locking note: Must be called with skt_sem held!
|
||||
*/
|
||||
static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
|
||||
static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
|
||||
{
|
||||
struct socket_data *s_data = s->resource_data;
|
||||
if (probe_mem) {
|
||||
unsigned int probe_mask;
|
||||
unsigned int probe_mask = MEM_PROBE_LOW;
|
||||
int ret = 0;
|
||||
|
||||
down(&rsrc_sem);
|
||||
if (!probe_mem)
|
||||
return 0;
|
||||
|
||||
probe_mask = MEM_PROBE_LOW;
|
||||
if (s->features & SS_CAP_PAGE_REGS)
|
||||
probe_mask = MEM_PROBE_HIGH;
|
||||
down(&rsrc_sem);
|
||||
|
||||
if (probe_mask & ~s_data->rsrc_mem_probe) {
|
||||
if (s->features & SS_CAP_PAGE_REGS)
|
||||
probe_mask = MEM_PROBE_HIGH;
|
||||
|
||||
if (probe_mask & ~s_data->rsrc_mem_probe) {
|
||||
if (s->state & SOCKET_PRESENT)
|
||||
ret = validate_mem(s, probe_mask);
|
||||
if (!ret)
|
||||
s_data->rsrc_mem_probe |= probe_mask;
|
||||
|
||||
if (s->state & SOCKET_PRESENT)
|
||||
validate_mem(s, probe_mask);
|
||||
}
|
||||
|
||||
up(&rsrc_sem);
|
||||
}
|
||||
|
||||
up(&rsrc_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct pcmcia_align_data {
|
||||
|
|
|
@ -125,7 +125,7 @@ struct pccard_operations {
|
|||
};
|
||||
|
||||
struct pccard_resource_ops {
|
||||
void (*validate_mem) (struct pcmcia_socket *s);
|
||||
int (*validate_mem) (struct pcmcia_socket *s);
|
||||
int (*adjust_io_region) (struct resource *res,
|
||||
unsigned long r_start,
|
||||
unsigned long r_end,
|
||||
|
|
Loading…
Reference in New Issue