pcmcia: add locking to set_mem_map()
Dominik Brodowski [Tue, 12 Jan 2010 20:42:51 +0000 (21:42 +0100)]
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>

drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/rsrc_nonstatic.c
include/pcmcia/ss.h

index 936417c..9ad66c9 100644 (file)
@@ -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;
 }
 
index 43c90f6..91aa1f2 100644 (file)
@@ -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) {
index 8ceb7ab..f31ba89 100644 (file)
@@ -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;
index 91626c1..1de46cf 100644 (file)
@@ -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;
 
index 9ab53d8..e756069 100644 (file)
@@ -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;