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 <w.sang@pengutronix.de> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
This commit is contained in:
parent
c6958fdb04
commit
6b8e087b86
5 changed files with 32 additions and 5 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue