diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-01-12 15:42:51 -0500 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-02-17 11:48:13 -0500 |
commit | 6b8e087b86c59c3941e125738d30cf38014089e0 (patch) | |
tree | 08f77e50e5237e3bbe5e4c8f114fddc09f242628 | |
parent | c6958fdb041db6ed77f24e871dd4af5f059d1a2b (diff) |
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>
-rw-r--r-- | drivers/pcmcia/cistpl.c | 6 | ||||
-rw-r--r-- | drivers/pcmcia/cs.c | 1 | ||||
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 20 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 8 | ||||
-rw-r--r-- | 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 936417c3e79e..9ad66c9848e3 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c | |||
@@ -64,6 +64,7 @@ module_param(cis_width, int, 0444); | |||
64 | 64 | ||
65 | void release_cis_mem(struct pcmcia_socket *s) | 65 | void release_cis_mem(struct pcmcia_socket *s) |
66 | { | 66 | { |
67 | mutex_lock(&s->ops_mutex); | ||
67 | if (s->cis_mem.flags & MAP_ACTIVE) { | 68 | if (s->cis_mem.flags & MAP_ACTIVE) { |
68 | s->cis_mem.flags &= ~MAP_ACTIVE; | 69 | s->cis_mem.flags &= ~MAP_ACTIVE; |
69 | s->ops->set_mem_map(s, &s->cis_mem); | 70 | s->ops->set_mem_map(s, &s->cis_mem); |
@@ -75,6 +76,7 @@ void release_cis_mem(struct pcmcia_socket *s) | |||
75 | iounmap(s->cis_virt); | 76 | iounmap(s->cis_virt); |
76 | s->cis_virt = NULL; | 77 | s->cis_virt = NULL; |
77 | } | 78 | } |
79 | mutex_unlock(&s->ops_mutex); | ||
78 | } | 80 | } |
79 | 81 | ||
80 | /* | 82 | /* |
@@ -88,11 +90,13 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag | |||
88 | pccard_mem_map *mem = &s->cis_mem; | 90 | pccard_mem_map *mem = &s->cis_mem; |
89 | int ret; | 91 | int ret; |
90 | 92 | ||
93 | mutex_lock(&s->ops_mutex); | ||
91 | if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) { | 94 | if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) { |
92 | mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s); | 95 | mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s); |
93 | if (mem->res == NULL) { | 96 | if (mem->res == NULL) { |
94 | dev_printk(KERN_NOTICE, &s->dev, | 97 | dev_printk(KERN_NOTICE, &s->dev, |
95 | "cs: unable to map card memory!\n"); | 98 | "cs: unable to map card memory!\n"); |
99 | mutex_unlock(&s->ops_mutex); | ||
96 | return NULL; | 100 | return NULL; |
97 | } | 101 | } |
98 | s->cis_virt = NULL; | 102 | s->cis_virt = NULL; |
@@ -108,6 +112,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag | |||
108 | if (ret) { | 112 | if (ret) { |
109 | iounmap(s->cis_virt); | 113 | iounmap(s->cis_virt); |
110 | s->cis_virt = NULL; | 114 | s->cis_virt = NULL; |
115 | mutex_unlock(&s->ops_mutex); | ||
111 | return NULL; | 116 | return NULL; |
112 | } | 117 | } |
113 | 118 | ||
@@ -117,6 +122,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag | |||
117 | s->cis_virt = ioremap(mem->static_start, s->map_size); | 122 | s->cis_virt = ioremap(mem->static_start, s->map_size); |
118 | } | 123 | } |
119 | 124 | ||
125 | mutex_unlock(&s->ops_mutex); | ||
120 | return s->cis_virt; | 126 | return s->cis_virt; |
121 | } | 127 | } |
122 | 128 | ||
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 43c90f69a7a5..91aa1f284068 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c | |||
@@ -222,6 +222,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) | |||
222 | init_completion(&socket->socket_released); | 222 | init_completion(&socket->socket_released); |
223 | init_completion(&socket->thread_done); | 223 | init_completion(&socket->thread_done); |
224 | mutex_init(&socket->skt_mutex); | 224 | mutex_init(&socket->skt_mutex); |
225 | mutex_init(&socket->ops_mutex); | ||
225 | spin_lock_init(&socket->thread_lock); | 226 | spin_lock_init(&socket->thread_lock); |
226 | 227 | ||
227 | if (socket->resource_ops->init) { | 228 | if (socket->resource_ops->init) { |
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 8ceb7abc580a..f31ba89e40d3 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, | |||
223 | memreq_t *req) | 223 | memreq_t *req) |
224 | { | 224 | { |
225 | struct pcmcia_socket *s = p_dev->socket; | 225 | struct pcmcia_socket *s = p_dev->socket; |
226 | int ret; | ||
226 | 227 | ||
227 | wh--; | 228 | wh--; |
228 | if (wh >= MAX_WIN) | 229 | if (wh >= MAX_WIN) |
@@ -231,12 +232,13 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, | |||
231 | dev_dbg(&s->dev, "failure: requested page is zero\n"); | 232 | dev_dbg(&s->dev, "failure: requested page is zero\n"); |
232 | return -EINVAL; | 233 | return -EINVAL; |
233 | } | 234 | } |
235 | mutex_lock(&s->ops_mutex); | ||
234 | s->win[wh].card_start = req->CardOffset; | 236 | s->win[wh].card_start = req->CardOffset; |
235 | if (s->ops->set_mem_map(s, &s->win[wh]) != 0) { | 237 | ret = s->ops->set_mem_map(s, &s->win[wh]); |
236 | dev_dbg(&s->dev, "failed to set_mem_map\n"); | 238 | if (ret) |
237 | return -EIO; | 239 | dev_warn(&s->dev, "failed to set_mem_map\n"); |
238 | } | 240 | mutex_unlock(&s->ops_mutex); |
239 | return 0; | 241 | return ret; |
240 | } /* pcmcia_map_mem_page */ | 242 | } /* pcmcia_map_mem_page */ |
241 | EXPORT_SYMBOL(pcmcia_map_mem_page); | 243 | EXPORT_SYMBOL(pcmcia_map_mem_page); |
242 | 244 | ||
@@ -437,10 +439,12 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) | |||
437 | if (wh >= MAX_WIN) | 439 | if (wh >= MAX_WIN) |
438 | return -EINVAL; | 440 | return -EINVAL; |
439 | 441 | ||
442 | mutex_lock(&s->ops_mutex); | ||
440 | win = &s->win[wh]; | 443 | win = &s->win[wh]; |
441 | 444 | ||
442 | if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) { | 445 | if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) { |
443 | dev_dbg(&s->dev, "not releasing unknown window\n"); | 446 | dev_dbg(&s->dev, "not releasing unknown window\n"); |
447 | mutex_unlock(&s->ops_mutex); | ||
444 | return -EINVAL; | 448 | return -EINVAL; |
445 | } | 449 | } |
446 | 450 | ||
@@ -456,6 +460,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) | |||
456 | win->res = NULL; | 460 | win->res = NULL; |
457 | } | 461 | } |
458 | p_dev->_win &= ~CLIENT_WIN_REQ(wh); | 462 | p_dev->_win &= ~CLIENT_WIN_REQ(wh); |
463 | mutex_unlock(&s->ops_mutex); | ||
459 | 464 | ||
460 | return 0; | 465 | return 0; |
461 | } /* pcmcia_release_window */ | 466 | } /* pcmcia_release_window */ |
@@ -829,6 +834,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha | |||
829 | return -EINVAL; | 834 | return -EINVAL; |
830 | } | 835 | } |
831 | 836 | ||
837 | mutex_lock(&s->ops_mutex); | ||
832 | win = &s->win[w]; | 838 | win = &s->win[w]; |
833 | 839 | ||
834 | if (!(s->features & SS_CAP_STATIC_MAP)) { | 840 | 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 | (req->Attributes & WIN_MAP_BELOW_1MB), s); | 842 | (req->Attributes & WIN_MAP_BELOW_1MB), s); |
837 | if (!win->res) { | 843 | if (!win->res) { |
838 | dev_dbg(&s->dev, "allocating mem region failed\n"); | 844 | dev_dbg(&s->dev, "allocating mem region failed\n"); |
845 | mutex_unlock(&s->ops_mutex); | ||
839 | return -EINVAL; | 846 | return -EINVAL; |
840 | } | 847 | } |
841 | } | 848 | } |
@@ -854,8 +861,10 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha | |||
854 | if (req->Attributes & WIN_USE_WAIT) | 861 | if (req->Attributes & WIN_USE_WAIT) |
855 | win->flags |= MAP_USE_WAIT; | 862 | win->flags |= MAP_USE_WAIT; |
856 | win->card_start = 0; | 863 | win->card_start = 0; |
864 | |||
857 | if (s->ops->set_mem_map(s, win) != 0) { | 865 | if (s->ops->set_mem_map(s, win) != 0) { |
858 | dev_dbg(&s->dev, "failed to set memory mapping\n"); | 866 | dev_dbg(&s->dev, "failed to set memory mapping\n"); |
867 | mutex_unlock(&s->ops_mutex); | ||
859 | return -EIO; | 868 | return -EIO; |
860 | } | 869 | } |
861 | s->state |= SOCKET_WIN_REQ(w); | 870 | 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 | else | 875 | else |
867 | req->Base = win->res->start; | 876 | req->Base = win->res->start; |
868 | 877 | ||
878 | mutex_unlock(&s->ops_mutex); | ||
869 | *wh = w + 1; | 879 | *wh = w + 1; |
870 | 880 | ||
871 | return 0; | 881 | return 0; |
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 91626c17f97b..1de46cf2772f 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, | |||
274 | { | 274 | { |
275 | int ret = -EINVAL; | 275 | int ret = -EINVAL; |
276 | 276 | ||
277 | mutex_lock(&s->ops_mutex); | ||
277 | s->cis_mem.res = res; | 278 | s->cis_mem.res = res; |
278 | s->cis_virt = ioremap(res->start, s->map_size); | 279 | s->cis_virt = ioremap(res->start, s->map_size); |
279 | if (s->cis_virt) { | 280 | if (s->cis_virt) { |
281 | mutex_unlock(&s->ops_mutex); | ||
280 | /* as we're only called from pcmcia.c, we're safe */ | 282 | /* as we're only called from pcmcia.c, we're safe */ |
281 | if (s->callback->validate) | 283 | if (s->callback->validate) |
282 | ret = s->callback->validate(s, count); | 284 | ret = s->callback->validate(s, count); |
283 | /* invalidate mapping */ | 285 | /* invalidate mapping */ |
286 | mutex_lock(&s->ops_mutex); | ||
284 | iounmap(s->cis_virt); | 287 | iounmap(s->cis_virt); |
285 | s->cis_virt = NULL; | 288 | s->cis_virt = NULL; |
286 | } | 289 | } |
287 | s->cis_mem.res = NULL; | 290 | s->cis_mem.res = NULL; |
291 | mutex_unlock(&s->ops_mutex); | ||
288 | if ((ret) || (*count == 0)) | 292 | if ((ret) || (*count == 0)) |
289 | return -EINVAL; | 293 | return -EINVAL; |
290 | return 0; | 294 | return 0; |
@@ -300,6 +304,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res, | |||
300 | int i, a = 0, b = -1, d; | 304 | int i, a = 0, b = -1, d; |
301 | void __iomem *virt; | 305 | void __iomem *virt; |
302 | 306 | ||
307 | mutex_lock(&s->ops_mutex); | ||
308 | |||
303 | virt = ioremap(res->start, s->map_size); | 309 | virt = ioremap(res->start, s->map_size); |
304 | if (virt) { | 310 | if (virt) { |
305 | map.map = 0; | 311 | map.map = 0; |
@@ -322,6 +328,8 @@ static int checksum(struct pcmcia_socket *s, struct resource *res, | |||
322 | iounmap(virt); | 328 | iounmap(virt); |
323 | } | 329 | } |
324 | 330 | ||
331 | mutex_unlock(&s->ops_mutex); | ||
332 | |||
325 | if (b == -1) | 333 | if (b == -1) |
326 | return -EINVAL; | 334 | return -EINVAL; |
327 | 335 | ||
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 9ab53d872489..e756069859b5 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h | |||
@@ -203,6 +203,8 @@ struct pcmcia_socket { | |||
203 | unsigned int thread_events; | 203 | unsigned int thread_events; |
204 | /* protects socket h/w state */ | 204 | /* protects socket h/w state */ |
205 | struct mutex skt_mutex; | 205 | struct mutex skt_mutex; |
206 | /* protects PCMCIA state */ | ||
207 | struct mutex ops_mutex; | ||
206 | /* protects thread_events */ | 208 | /* protects thread_events */ |
207 | spinlock_t thread_lock; | 209 | spinlock_t thread_lock; |
208 | 210 | ||