From 6b8e087b86c59c3941e125738d30cf38014089e0 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 12 Jan 2010 21:42:51 +0100 Subject: pcmcia: add locking to set_mem_map() Protect the pccard_operations callback "set_mem_map" by a new mutex ops_mutex. This mutex also protects the following values in struct pcmcia_socket: pccard_mem_map win[] pccard_mem_map cis_mem void __iomem *cis_virt Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cistpl.c | 6 ++++++ drivers/pcmcia/cs.c | 1 + drivers/pcmcia/pcmcia_resource.c | 20 +++++++++++++++----- drivers/pcmcia/rsrc_nonstatic.c | 8 ++++++++ include/pcmcia/ss.h | 2 ++ 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 936417c..9ad66c9 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->ops_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->ops_mutex); } /* @@ -88,11 +90,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->ops_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->ops_mutex); return NULL; } s->cis_virt = NULL; @@ -108,6 +112,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->ops_mutex); return NULL; } @@ -117,6 +122,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag s->cis_virt = ioremap(mem->static_start, s->map_size); } + mutex_unlock(&s->ops_mutex); return s->cis_virt; } diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 43c90f6..91aa1f2 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -222,6 +222,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->ops_mutex); spin_lock_init(&socket->thread_lock); if (socket->resource_ops->init) { diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 8ceb7ab..f31ba89 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -223,6 +223,7 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, memreq_t *req) { struct pcmcia_socket *s = p_dev->socket; + int ret; wh--; if (wh >= MAX_WIN) @@ -231,12 +232,13 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, dev_dbg(&s->dev, "failure: requested page is zero\n"); return -EINVAL; } + mutex_lock(&s->ops_mutex); s->win[wh].card_start = req->CardOffset; - if (s->ops->set_mem_map(s, &s->win[wh]) != 0) { - dev_dbg(&s->dev, "failed to set_mem_map\n"); - return -EIO; - } - return 0; + ret = s->ops->set_mem_map(s, &s->win[wh]); + if (ret) + dev_warn(&s->dev, "failed to set_mem_map\n"); + mutex_unlock(&s->ops_mutex); + return ret; } /* pcmcia_map_mem_page */ EXPORT_SYMBOL(pcmcia_map_mem_page); @@ -437,10 +439,12 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) if (wh >= MAX_WIN) return -EINVAL; + mutex_lock(&s->ops_mutex); win = &s->win[wh]; if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) { dev_dbg(&s->dev, "not releasing unknown window\n"); + mutex_unlock(&s->ops_mutex); return -EINVAL; } @@ -456,6 +460,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) win->res = NULL; } p_dev->_win &= ~CLIENT_WIN_REQ(wh); + mutex_unlock(&s->ops_mutex); return 0; } /* pcmcia_release_window */ @@ -829,6 +834,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha return -EINVAL; } + mutex_lock(&s->ops_mutex); win = &s->win[w]; if (!(s->features & SS_CAP_STATIC_MAP)) { @@ -836,6 +842,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha (req->Attributes & WIN_MAP_BELOW_1MB), s); if (!win->res) { dev_dbg(&s->dev, "allocating mem region failed\n"); + mutex_unlock(&s->ops_mutex); return -EINVAL; } } @@ -854,8 +861,10 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha if (req->Attributes & WIN_USE_WAIT) win->flags |= MAP_USE_WAIT; win->card_start = 0; + if (s->ops->set_mem_map(s, win) != 0) { dev_dbg(&s->dev, "failed to set memory mapping\n"); + mutex_unlock(&s->ops_mutex); return -EIO; } s->state |= SOCKET_WIN_REQ(w); @@ -866,6 +875,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha else req->Base = win->res->start; + mutex_unlock(&s->ops_mutex); *wh = w + 1; return 0; diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 91626c1..1de46cf 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -274,17 +274,21 @@ static int readable(struct pcmcia_socket *s, struct resource *res, { int ret = -EINVAL; + mutex_lock(&s->ops_mutex); s->cis_mem.res = res; s->cis_virt = ioremap(res->start, s->map_size); if (s->cis_virt) { + mutex_unlock(&s->ops_mutex); /* as we're only called from pcmcia.c, we're safe */ if (s->callback->validate) ret = s->callback->validate(s, count); /* invalidate mapping */ + mutex_lock(&s->ops_mutex); iounmap(s->cis_virt); s->cis_virt = NULL; } s->cis_mem.res = NULL; + mutex_unlock(&s->ops_mutex); if ((ret) || (*count == 0)) return -EINVAL; return 0; @@ -300,6 +304,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res, int i, a = 0, b = -1, d; void __iomem *virt; + mutex_lock(&s->ops_mutex); + virt = ioremap(res->start, s->map_size); if (virt) { map.map = 0; @@ -322,6 +328,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res, iounmap(virt); } + mutex_unlock(&s->ops_mutex); + if (b == -1) return -EINVAL; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 9ab53d8..e756069 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -203,6 +203,8 @@ struct pcmcia_socket { unsigned int thread_events; /* protects socket h/w state */ struct mutex skt_mutex; + /* protects PCMCIA state */ + struct mutex ops_mutex; /* protects thread_events */ spinlock_t thread_lock; -- cgit v1.1