diff -urN orig/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c --- orig/drivers/pcmcia/cistpl.c Sat Mar 15 22:38:33 2003 +++ linux/drivers/pcmcia/cistpl.c Sat Mar 15 22:43:35 2003 @@ -84,6 +84,113 @@ INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */ +/*====================================================================== + + 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)); +} + +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); + vs = s; + validate_mem(cis_readable, checksum_match, low, s); + mem->sys_start = 0; + vs = NULL; + 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 +202,28 @@ #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 +232,30 @@ 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 +268,23 @@ 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,112 +293,32 @@ 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; - } } /*======================================================================