Hey, On Thu, Jan 07, 2010 at 09:56:59PM +0900, Komuro wrote: > I got the kernel-oops by pcmcia-check-broken-cis > at kernel 2.6.33-rc3. > > Do you think this is the same as CIS problem?
I have a bad feeling about this... might it be that cistpl.c isn't thread safe at all? Could you test out this patch, please? Thanks, Dominik diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 25b1cd2..b7eec6e 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -64,6 +64,7 @@ module_param(cis_width, int, 0444); void release_cis_mem(struct pcmcia_socket *s) { + mutex_lock(&s->card_mutex); if (s->cis_mem.flags & MAP_ACTIVE) { s->cis_mem.flags &= ~MAP_ACTIVE; s->ops->set_mem_map(s, &s->cis_mem); @@ -75,6 +76,7 @@ void release_cis_mem(struct pcmcia_socket *s) iounmap(s->cis_virt); s->cis_virt = NULL; } + mutex_unlock(&s->card_mutex); } EXPORT_SYMBOL(release_cis_mem); @@ -89,11 +91,13 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag pccard_mem_map *mem = &s->cis_mem; int ret; + mutex_lock(&s->card_mutex); if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) { mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s); if (mem->res == NULL) { dev_printk(KERN_NOTICE, &s->dev, "cs: unable to map card memory!\n"); + mutex_unlock(&s->card_mutex); return NULL; } s->cis_virt = NULL; @@ -109,6 +113,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag if (ret) { iounmap(s->cis_virt); s->cis_virt = NULL; + mutex_unlock(&s->card_mutex); return NULL; } @@ -117,6 +122,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag iounmap(s->cis_virt); s->cis_virt = ioremap(mem->static_start, s->map_size); } + mutex_unlock(&s->card_mutex); return s->cis_virt; } @@ -271,27 +277,34 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, struct cis_cache_entry *cis; int ret; + mutex_lock(&s->card_mutex); if (s->fake_cis) { if (s->fake_cis_len >= addr+len) memcpy(ptr, s->fake_cis+addr, len); else memset(ptr, 0xff, len); + mutex_unlock(&s->card_mutex); return; } list_for_each_entry(cis, &s->cis_cache, node) { if (cis->addr == addr && cis->len == len && cis->attr == attr) { memcpy(ptr, cis->cache, len); + mutex_unlock(&s->card_mutex); return; } } + mutex_unlock(&s->card_mutex); #ifdef CONFIG_CARDBUS if (s->state & SOCKET_CARDBUS) ret = read_cb_mem(s, attr, addr, len, ptr); else #endif + { + mutex_lock(&s->card_mutex); ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr); + } if (ret == 0) { /* Copy data into the cache */ @@ -304,6 +317,7 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, list_add(&cis->node, &s->cis_cache); } } + mutex_unlock(&s->card_mutex); } static void @@ -311,24 +325,28 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) { struct cis_cache_entry *cis; + mutex_lock(&s->card_mutex); list_for_each_entry(cis, &s->cis_cache, node) if (cis->addr == addr && cis->len == len && cis->attr == attr) { list_del(&cis->node); kfree(cis); break; } + mutex_unlock(&s->card_mutex); } void destroy_cis_cache(struct pcmcia_socket *s) { struct list_head *l, *n; + mutex_lock(&s->card_mutex); list_for_each_safe(l, n, &s->cis_cache) { struct cis_cache_entry *cis = list_entry(l, struct cis_cache_entry, node); list_del(&cis->node); kfree(cis); } + mutex_unlock(&s->card_mutex); /* * If there was a fake CIS, destroy that as well. @@ -356,6 +374,7 @@ int verify_cis_cache(struct pcmcia_socket *s) "no memory for verifying CIS\n"); return -ENOMEM; } + mutex_lock(&s->card_mutex); list_for_each_entry(cis, &s->cis_cache, node) { int len = cis->len; @@ -369,10 +388,12 @@ int verify_cis_cache(struct pcmcia_socket *s) pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); if (memcmp(buf, cis->cache, len) != 0) { + mutex_unlock(&s->card_mutex); kfree(buf); return -1; } } + mutex_unlock(&s->card_mutex); kfree(buf); return 0; } @@ -391,14 +412,17 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n"); return -EINVAL; } + mutex_lock(&s->card_mutex); kfree(s->fake_cis); s->fake_cis = kmalloc(len, GFP_KERNEL); if (s->fake_cis == NULL) { dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n"); + mutex_unlock(&s->card_mutex); return -ENOMEM; } s->fake_cis_len = len; memcpy(s->fake_cis, data, len); + mutex_unlock(&s->card_mutex); return 0; } EXPORT_SYMBOL(pcmcia_replace_cis); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 6d6f82b..0b694b5 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -228,6 +228,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) init_completion(&socket->socket_released); init_completion(&socket->thread_done); mutex_init(&socket->skt_mutex); + mutex_init(&socket->card_mutex); spin_lock_init(&socket->thread_lock); if (socket->resource_ops->init) { diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index cbfba88..fa76a6b 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -237,6 +237,9 @@ struct pcmcia_socket { /* for adding further pseudo-multifunction devices */ struct work_struct device_add; + /* protects card h/w state */ + struct mutex card_mutex; + #ifdef CONFIG_PCMCIA_IOCTL struct user_info_t *user; wait_queue_head_t queue; _______________________________________________ Linux PCMCIA reimplementation list http://lists.infradead.org/mailman/listinfo/linux-pcmcia