Commit 6b8e087b authored by Dominik Brodowski's avatar Dominik Brodowski

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: default avatarWolfram Sang <w.sang@pengutronix.de>
Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
parent c6958fdb
...@@ -64,6 +64,7 @@ module_param(cis_width, int, 0444); ...@@ -64,6 +64,7 @@ module_param(cis_width, int, 0444);
void release_cis_mem(struct pcmcia_socket *s) void release_cis_mem(struct pcmcia_socket *s)
{ {
mutex_lock(&s->ops_mutex);
if (s->cis_mem.flags & MAP_ACTIVE) { if (s->cis_mem.flags & MAP_ACTIVE) {
s->cis_mem.flags &= ~MAP_ACTIVE; s->cis_mem.flags &= ~MAP_ACTIVE;
s->ops->set_mem_map(s, &s->cis_mem); s->ops->set_mem_map(s, &s->cis_mem);
...@@ -75,6 +76,7 @@ void release_cis_mem(struct pcmcia_socket *s) ...@@ -75,6 +76,7 @@ void release_cis_mem(struct pcmcia_socket *s)
iounmap(s->cis_virt); iounmap(s->cis_virt);
s->cis_virt = NULL; 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 ...@@ -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; pccard_mem_map *mem = &s->cis_mem;
int ret; int ret;
mutex_lock(&s->ops_mutex);
if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) { 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); mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
if (mem->res == NULL) { if (mem->res == NULL) {
dev_printk(KERN_NOTICE, &s->dev, dev_printk(KERN_NOTICE, &s->dev,
"cs: unable to map card memory!\n"); "cs: unable to map card memory!\n");
mutex_unlock(&s->ops_mutex);
return NULL; return NULL;
} }
s->cis_virt = NULL; s->cis_virt = NULL;
...@@ -108,6 +112,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag ...@@ -108,6 +112,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
if (ret) { if (ret) {
iounmap(s->cis_virt); iounmap(s->cis_virt);
s->cis_virt = NULL; s->cis_virt = NULL;
mutex_unlock(&s->ops_mutex);
return NULL; return NULL;
} }
...@@ -117,6 +122,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag ...@@ -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); s->cis_virt = ioremap(mem->static_start, s->map_size);
} }
mutex_unlock(&s->ops_mutex);
return s->cis_virt; return s->cis_virt;
} }
......
...@@ -222,6 +222,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) ...@@ -222,6 +222,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
init_completion(&socket->socket_released); init_completion(&socket->socket_released);
init_completion(&socket->thread_done); init_completion(&socket->thread_done);
mutex_init(&socket->skt_mutex); mutex_init(&socket->skt_mutex);
mutex_init(&socket->ops_mutex);
spin_lock_init(&socket->thread_lock); spin_lock_init(&socket->thread_lock);
if (socket->resource_ops->init) { if (socket->resource_ops->init) {
......
...@@ -223,6 +223,7 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, ...@@ -223,6 +223,7 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
memreq_t *req) memreq_t *req)
{ {
struct pcmcia_socket *s = p_dev->socket; struct pcmcia_socket *s = p_dev->socket;
int ret;
wh--; wh--;
if (wh >= MAX_WIN) if (wh >= MAX_WIN)
...@@ -231,12 +232,13 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, ...@@ -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"); dev_dbg(&s->dev, "failure: requested page is zero\n");
return -EINVAL; return -EINVAL;
} }
mutex_lock(&s->ops_mutex);
s->win[wh].card_start = req->CardOffset; s->win[wh].card_start = req->CardOffset;
if (s->ops->set_mem_map(s, &s->win[wh]) != 0) { ret = s->ops->set_mem_map(s, &s->win[wh]);
dev_dbg(&s->dev, "failed to set_mem_map\n"); if (ret)
return -EIO; dev_warn(&s->dev, "failed to set_mem_map\n");
} mutex_unlock(&s->ops_mutex);
return 0; return ret;
} /* pcmcia_map_mem_page */ } /* pcmcia_map_mem_page */
EXPORT_SYMBOL(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) ...@@ -437,10 +439,12 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
if (wh >= MAX_WIN) if (wh >= MAX_WIN)
return -EINVAL; return -EINVAL;
mutex_lock(&s->ops_mutex);
win = &s->win[wh]; win = &s->win[wh];
if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) { if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) {
dev_dbg(&s->dev, "not releasing unknown window\n"); dev_dbg(&s->dev, "not releasing unknown window\n");
mutex_unlock(&s->ops_mutex);
return -EINVAL; return -EINVAL;
} }
...@@ -456,6 +460,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) ...@@ -456,6 +460,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh)
win->res = NULL; win->res = NULL;
} }
p_dev->_win &= ~CLIENT_WIN_REQ(wh); p_dev->_win &= ~CLIENT_WIN_REQ(wh);
mutex_unlock(&s->ops_mutex);
return 0; return 0;
} /* pcmcia_release_window */ } /* pcmcia_release_window */
...@@ -829,6 +834,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha ...@@ -829,6 +834,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
return -EINVAL; return -EINVAL;
} }
mutex_lock(&s->ops_mutex);
win = &s->win[w]; win = &s->win[w];
if (!(s->features & SS_CAP_STATIC_MAP)) { 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 ...@@ -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); (req->Attributes & WIN_MAP_BELOW_1MB), s);
if (!win->res) { if (!win->res) {
dev_dbg(&s->dev, "allocating mem region failed\n"); dev_dbg(&s->dev, "allocating mem region failed\n");
mutex_unlock(&s->ops_mutex);
return -EINVAL; return -EINVAL;
} }
} }
...@@ -854,8 +861,10 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha ...@@ -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) if (req->Attributes & WIN_USE_WAIT)
win->flags |= MAP_USE_WAIT; win->flags |= MAP_USE_WAIT;
win->card_start = 0; win->card_start = 0;
if (s->ops->set_mem_map(s, win) != 0) { if (s->ops->set_mem_map(s, win) != 0) {
dev_dbg(&s->dev, "failed to set memory mapping\n"); dev_dbg(&s->dev, "failed to set memory mapping\n");
mutex_unlock(&s->ops_mutex);
return -EIO; return -EIO;
} }
s->state |= SOCKET_WIN_REQ(w); 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 ...@@ -866,6 +875,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
else else
req->Base = win->res->start; req->Base = win->res->start;
mutex_unlock(&s->ops_mutex);
*wh = w + 1; *wh = w + 1;
return 0; return 0;
......
...@@ -274,17 +274,21 @@ static int readable(struct pcmcia_socket *s, struct resource *res, ...@@ -274,17 +274,21 @@ static int readable(struct pcmcia_socket *s, struct resource *res,
{ {
int ret = -EINVAL; int ret = -EINVAL;
mutex_lock(&s->ops_mutex);
s->cis_mem.res = res; s->cis_mem.res = res;
s->cis_virt = ioremap(res->start, s->map_size); s->cis_virt = ioremap(res->start, s->map_size);
if (s->cis_virt) { if (s->cis_virt) {
mutex_unlock(&s->ops_mutex);
/* as we're only called from pcmcia.c, we're safe */ /* as we're only called from pcmcia.c, we're safe */
if (s->callback->validate) if (s->callback->validate)
ret = s->callback->validate(s, count); ret = s->callback->validate(s, count);
/* invalidate mapping */ /* invalidate mapping */
mutex_lock(&s->ops_mutex);
iounmap(s->cis_virt); iounmap(s->cis_virt);
s->cis_virt = NULL; s->cis_virt = NULL;
} }
s->cis_mem.res = NULL; s->cis_mem.res = NULL;
mutex_unlock(&s->ops_mutex);
if ((ret) || (*count == 0)) if ((ret) || (*count == 0))
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -300,6 +304,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res, ...@@ -300,6 +304,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res,
int i, a = 0, b = -1, d; int i, a = 0, b = -1, d;
void __iomem *virt; void __iomem *virt;
mutex_lock(&s->ops_mutex);
virt = ioremap(res->start, s->map_size); virt = ioremap(res->start, s->map_size);
if (virt) { if (virt) {
map.map = 0; map.map = 0;
...@@ -322,6 +328,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res, ...@@ -322,6 +328,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res,
iounmap(virt); iounmap(virt);
} }
mutex_unlock(&s->ops_mutex);
if (b == -1) if (b == -1)
return -EINVAL; return -EINVAL;
......
...@@ -203,6 +203,8 @@ struct pcmcia_socket { ...@@ -203,6 +203,8 @@ struct pcmcia_socket {
unsigned int thread_events; unsigned int thread_events;
/* protects socket h/w state */ /* protects socket h/w state */
struct mutex skt_mutex; struct mutex skt_mutex;
/* protects PCMCIA state */
struct mutex ops_mutex;
/* protects thread_events */ /* protects thread_events */
spinlock_t thread_lock; spinlock_t thread_lock;
......
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