Commit 00dbc966 authored by Russell King's avatar Russell King

[PCMCIA] pcmcia-8/9: Clean up CIS setup.

- Re-order functions in cistpl.c.
- Combine setup_cis_mem and set_cis_map into one function.
- Move cis_readable(), checksum() and checksum_match() into rsrc_mgr.c
- Only pass the socket structure to validate_mem()
- Remove socket_info_t *vs variable, and the race condition along
  with it.
- Pass the socket_info_t through validate_mem(), do_mem_probe() and
  inv_probe() to these functions.
- Call cis_readable() and checksum_match() directly from
  do_mem_probe().
parent 4769dd4c
......@@ -84,6 +84,52 @@ static const u_int exponent[] = {
INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */
void release_cis_mem(socket_info_t *s)
{
if (s->cis_mem.sys_start != 0) {
s->cis_mem.flags &= ~MAP_ACTIVE;
s->ss_entry->set_mem_map(s->sock, &s->cis_mem);
if (!(s->cap.features & SS_CAP_STATIC_MAP))
release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
iounmap(s->cis_virt);
s->cis_mem.sys_start = 0;
s->cis_virt = NULL;
}
}
/*
* Map the card memory at "card_offset" into virtual space.
* If flags & MAP_ATTRIB, map the attribute space, otherwise
* map the memory space.
*/
static unsigned char *
set_cis_map(socket_info_t *s, unsigned int card_offset, unsigned int flags)
{
pccard_mem_map *mem = &s->cis_mem;
if (!(s->cap.features & SS_CAP_STATIC_MAP) &&
mem->sys_start == 0) {
int low = !(s->cap.features & SS_CAP_PAGE_REGS);
validate_mem(s);
mem->sys_start = 0;
if (find_mem_region(&mem->sys_start, s->cap.map_size,
s->cap.map_size, low, "card services", s)) {
printk(KERN_NOTICE "cs: unable to map card memory!\n");
return NULL;
}
mem->sys_stop = mem->sys_start+s->cap.map_size-1;
s->cis_virt = ioremap(mem->sys_start, s->cap.map_size);
}
mem->card_start = card_offset;
mem->flags = flags;
s->ss_entry->set_mem_map(s->sock, mem);
if (s->cap.features & SS_CAP_STATIC_MAP) {
if (s->cis_virt)
iounmap(s->cis_virt);
s->cis_virt = ioremap(mem->sys_start, s->cap.map_size);
}
return s->cis_virt;
}
/*======================================================================
Low-level functions to read and write CIS memory. I think the
......@@ -95,39 +141,28 @@ INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */
#define IS_ATTR 1
#define IS_INDIRECT 8
static int setup_cis_mem(socket_info_t *s);
static void set_cis_map(socket_info_t *s, pccard_mem_map *mem)
{
s->ss_entry->set_mem_map(s->sock, mem);
if (s->cap.features & SS_CAP_STATIC_MAP) {
if (s->cis_virt)
iounmap(s->cis_virt);
s->cis_virt = ioremap(mem->sys_start, s->cap.map_size);
}
}
int read_cis_mem(socket_info_t *s, int attr, u_int addr,
u_int len, void *ptr)
{
pccard_mem_map *mem = &s->cis_mem;
u_char *sys, *buf = ptr;
u_char *sys, *end, *buf = ptr;
DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
if (setup_cis_mem(s) != 0) {
memset(ptr, 0xff, len);
return -1;
}
mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr & IS_INDIRECT) {
/* Indirect accesses use a bunch of special registers at fixed
locations in common memory */
u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
mem->card_start = 0; mem->flags = MAP_ACTIVE;
set_cis_map(s, mem);
sys = s->cis_virt;
if (attr & IS_ATTR) {
addr *= 2;
flags = ICTRL0_AUTOINC;
}
sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0));
if (!sys) {
memset(ptr, 0xff, len);
return -1;
}
writeb(flags, sys+CISREG_ICTRL0);
writeb(addr & 0xff, sys+CISREG_IADDR0);
writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
......@@ -136,18 +171,30 @@ int read_cis_mem(socket_info_t *s, int attr, u_int addr,
for ( ; len > 0; len--, buf++)
*buf = readb(sys+CISREG_IDATA0);
} else {
u_int inc = 1;
if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
sys += (addr & (s->cap.map_size-1));
mem->card_start = addr & ~(s->cap.map_size-1);
u_int inc = 1, card_offset, flags;
flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr) {
flags |= MAP_ATTRIB;
inc++;
addr *= 2;
}
card_offset = addr & ~(s->cap.map_size-1);
while (len) {
set_cis_map(s, mem);
sys = s->cis_virt + (addr & (s->cap.map_size-1));
sys = set_cis_map(s, card_offset, flags);
if (!sys) {
memset(ptr, 0xff, len);
return -1;
}
end = sys + s->cap.map_size;
sys = sys + (addr & (s->cap.map_size-1));
for ( ; len > 0; len--, buf++, sys += inc) {
if (sys == s->cis_virt+s->cap.map_size) break;
if (sys == end)
break;
*buf = readb(sys);
}
mem->card_start += s->cap.map_size;
card_offset += s->cap.map_size;
addr = 0;
}
}
......@@ -160,21 +207,23 @@ int read_cis_mem(socket_info_t *s, int attr, u_int addr,
void write_cis_mem(socket_info_t *s, int attr, u_int addr,
u_int len, void *ptr)
{
pccard_mem_map *mem = &s->cis_mem;
u_char *sys, *buf = ptr;
u_char *sys, *end, *buf = ptr;
DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
if (setup_cis_mem(s) != 0) return;
mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr & IS_INDIRECT) {
/* Indirect accesses use a bunch of special registers at fixed
locations in common memory */
u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
mem->card_start = 0; mem->flags = MAP_ACTIVE;
set_cis_map(s, mem);
sys = s->cis_virt;
if (attr & IS_ATTR) {
addr *= 2;
flags = ICTRL0_AUTOINC;
}
sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0));
if (!sys)
return; /* FIXME: Error */
writeb(flags, sys+CISREG_ICTRL0);
writeb(addr & 0xff, sys+CISREG_IADDR0);
writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
......@@ -183,114 +232,34 @@ void write_cis_mem(socket_info_t *s, int attr, u_int addr,
for ( ; len > 0; len--, buf++)
writeb(*buf, sys+CISREG_IDATA0);
} else {
int inc = 1;
if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
mem->card_start = addr & ~(s->cap.map_size-1);
u_int inc = 1, card_offset, flags;
flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr & IS_ATTR) {
flags |= MAP_ATTRIB;
inc++;
addr *= 2;
}
card_offset = addr & ~(s->cap.map_size-1);
while (len) {
set_cis_map(s, mem);
sys = s->cis_virt + (addr & (s->cap.map_size-1));
sys = set_cis_map(s, card_offset, flags);
if (!sys)
return; /* FIXME: error */
end = sys + s->cap.map_size;
sys = sys + (addr & (s->cap.map_size-1));
for ( ; len > 0; len--, buf++, sys += inc) {
if (sys == s->cis_virt+s->cap.map_size) break;
if (sys == end)
break;
writeb(*buf, sys);
}
mem->card_start += s->cap.map_size;
card_offset += s->cap.map_size;
addr = 0;
}
}
}
/*======================================================================
This is tricky... when we set up CIS memory, we try to validate
the memory window space allocations.
======================================================================*/
/* Scratch pointer to the socket we use for validation */
static socket_info_t *vs = NULL;
/* Validation function for cards with a valid CIS */
static int cis_readable(u_long base)
{
cisinfo_t info1, info2;
int ret;
vs->cis_mem.sys_start = base;
vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
vs->cis_virt = ioremap(base, vs->cap.map_size);
ret = pcmcia_validate_cis(vs->clients, &info1);
/* invalidate mapping and CIS cache */
iounmap(vs->cis_virt);
vs->cis_used = 0;
if ((ret != 0) || (info1.Chains == 0))
return 0;
vs->cis_mem.sys_start = base+vs->cap.map_size;
vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1;
vs->cis_virt = ioremap(base+vs->cap.map_size, vs->cap.map_size);
ret = pcmcia_validate_cis(vs->clients, &info2);
iounmap(vs->cis_virt);
vs->cis_used = 0;
return ((ret == 0) && (info1.Chains == info2.Chains));
}
/* Validation function for simple memory cards */
static int checksum(u_long base)
{
int i, a, b, d;
vs->cis_mem.sys_start = base;
vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
vs->cis_virt = ioremap(base, vs->cap.map_size);
vs->cis_mem.card_start = 0;
vs->cis_mem.flags = MAP_ACTIVE;
vs->ss_entry->set_mem_map(vs->sock, &vs->cis_mem);
/* Don't bother checking every word... */
a = 0; b = -1;
for (i = 0; i < vs->cap.map_size; i += 44) {
d = readl(vs->cis_virt+i);
a += d; b &= d;
}
iounmap(vs->cis_virt);
return (b == -1) ? -1 : (a>>1);
}
static int checksum_match(u_long base)
{
int a = checksum(base), b = checksum(base+vs->cap.map_size);
return ((a == b) && (a >= 0));
}
static int setup_cis_mem(socket_info_t *s)
{
if (!(s->cap.features & SS_CAP_STATIC_MAP) &&
(s->cis_mem.sys_start == 0)) {
int low = !(s->cap.features & SS_CAP_PAGE_REGS);
vs = s;
validate_mem(cis_readable, checksum_match, low, s);
s->cis_mem.sys_start = 0;
vs = NULL;
if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
s->cap.map_size, low, "card services", s)) {
printk(KERN_NOTICE "cs: unable to map card memory!\n");
return -1;
}
s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
s->cis_virt = ioremap(s->cis_mem.sys_start, s->cap.map_size);
}
return 0;
}
void release_cis_mem(socket_info_t *s)
{
if (s->cis_mem.sys_start != 0) {
s->cis_mem.flags &= ~MAP_ACTIVE;
s->ss_entry->set_mem_map(s->sock, &s->cis_mem);
if (!(s->cap.features & SS_CAP_STATIC_MAP))
release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
iounmap(s->cis_virt);
s->cis_mem.sys_start = 0;
s->cis_virt = NULL;
}
}
/*======================================================================
This is a wrapper around read_cis_mem, with the same interface,
......
......@@ -233,8 +233,7 @@ int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
int copy_memory(memory_handle_t handle, copy_op_t *req);
/* In rsrc_mgr */
void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
int force_low, socket_info_t *s);
void validate_mem(socket_info_t *s);
int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
char *name, socket_info_t *s);
int find_mem_region(u_long *base, u_long num, u_long align,
......
......@@ -335,6 +335,62 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num)
}
#endif
/*======================================================================
This is tricky... when we set up CIS memory, we try to validate
the memory window space allocations.
======================================================================*/
/* Validation function for cards with a valid CIS */
static int cis_readable(socket_info_t *s, u_long base)
{
cisinfo_t info1, info2;
int ret;
s->cis_mem.sys_start = base;
s->cis_mem.sys_stop = base+s->cap.map_size-1;
s->cis_virt = ioremap(base, s->cap.map_size);
ret = pcmcia_validate_cis(s->clients, &info1);
/* invalidate mapping and CIS cache */
iounmap(s->cis_virt);
s->cis_used = 0;
if ((ret != 0) || (info1.Chains == 0))
return 0;
s->cis_mem.sys_start = base+s->cap.map_size;
s->cis_mem.sys_stop = base+2*s->cap.map_size-1;
s->cis_virt = ioremap(base+s->cap.map_size, s->cap.map_size);
ret = pcmcia_validate_cis(s->clients, &info2);
iounmap(s->cis_virt);
s->cis_used = 0;
return ((ret == 0) && (info1.Chains == info2.Chains));
}
/* Validation function for simple memory cards */
static int checksum(socket_info_t *s, u_long base)
{
int i, a, b, d;
s->cis_mem.sys_start = base;
s->cis_mem.sys_stop = base+s->cap.map_size-1;
s->cis_virt = ioremap(base, s->cap.map_size);
s->cis_mem.card_start = 0;
s->cis_mem.flags = MAP_ACTIVE;
s->ss_entry->set_mem_map(s->sock, &s->cis_mem);
/* Don't bother checking every word... */
a = 0; b = -1;
for (i = 0; i < s->cap.map_size; i += 44) {
d = readl(s->cis_virt+i);
a += d; b &= d;
}
iounmap(s->cis_virt);
return (b == -1) ? -1 : (a>>1);
}
static int checksum_match(socket_info_t *s, u_long base)
{
int a = checksum(s, base), b = checksum(s, base+s->cap.map_size);
return ((a == b) && (a >= 0));
}
/*======================================================================
The memory probe. If the memory list includes a 64K-aligned block
......@@ -343,9 +399,7 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num)
======================================================================*/
static int do_mem_probe(u_long base, u_long num,
int (*is_valid)(u_long), int (*do_cksum)(u_long),
socket_info_t *s)
static int do_mem_probe(u_long base, u_long num, socket_info_t *s)
{
u_long i, j, bad, fail, step;
......@@ -353,18 +407,21 @@ static int do_mem_probe(u_long base, u_long num,
base, base+num-1);
bad = fail = 0;
step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
/* cis_readable wants to map 2x map_size */
if (step < 2 * s->cap.map_size)
step = 2 * s->cap.map_size;
for (i = j = base; i < base+num; i = j + step) {
if (!fail) {
for (j = i; j < base+num; j += step)
if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) &&
is_valid(j))
cis_readable(s, j))
break;
fail = ((i == base) && (j == base+num));
}
if (fail) {
for (j = i; j < base+num; j += 2*step)
if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) &&
do_cksum(j) && do_cksum(j+step))
checksum_match(s, j) && checksum_match(s, j + step))
break;
}
if (i != j) {
......@@ -380,14 +437,12 @@ static int do_mem_probe(u_long base, u_long num,
#ifdef CONFIG_PCMCIA_PROBE
static u_long inv_probe(int (*is_valid)(u_long),
int (*do_cksum)(u_long),
resource_map_t *m, socket_info_t *s)
static u_long inv_probe(resource_map_t *m, socket_info_t *s)
{
u_long ok;
if (m == &mem_db)
return 0;
ok = inv_probe(is_valid, do_cksum, m->next, s);
ok = inv_probe(m->next, s);
if (ok) {
if (m->base >= 0x100000)
sub_interval(&mem_db, m->base, m->num);
......@@ -395,16 +450,16 @@ static u_long inv_probe(int (*is_valid)(u_long),
}
if (m->base < 0x100000)
return 0;
return do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
return do_mem_probe(m->base, m->num, s);
}
void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
int force_low, socket_info_t *s)
void validate_mem(socket_info_t *s)
{
resource_map_t *m, *n;
static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
static int hi = 0, lo = 0;
u_long b, i, ok = 0;
int force_low = !(s->cap.features & SS_CAP_PAGE_REGS);
if (!probe_mem)
return;
......@@ -412,7 +467,7 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
down(&rsrc_sem);
/* We do up to four passes through the list */
if (!force_low) {
if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0))
if (hi++ || (inv_probe(mem_db.next, s) > 0))
goto out;
printk(KERN_NOTICE "cs: warning: no high memory space "
"available!\n");
......@@ -424,7 +479,7 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
/* Only probe < 1 MB */
if (m->base >= 0x100000) continue;
if ((m->base | m->num) & 0xffff) {
ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
ok += do_mem_probe(m->base, m->num, s);
continue;
}
/* Special probe for 64K-aligned block */
......@@ -434,7 +489,7 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
if (ok >= mem_limit)
sub_interval(&mem_db, b, 0x10000);
else
ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s);
ok += do_mem_probe(b, 0x10000, s);
}
}
}
......@@ -444,8 +499,7 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
#else /* CONFIG_PCMCIA_PROBE */
void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
int force_low, socket_info_t *s)
void validate_mem(socket_info_t *s)
{
resource_map_t *m;
static int done = 0;
......@@ -453,7 +507,7 @@ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
if (probe_mem && done++ == 0) {
down(&rsrc_sem);
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, s))
break;
up(&rsrc_sem);
}
......
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