aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKanigeri, Hari <h-kanigeri2@ti.com>2010-11-29 15:24:14 -0500
committerHari Kanigeri <h-kanigeri2@ti.com>2010-12-02 06:43:16 -0500
commit582563074a691eb45cb22d2eca70eed8f2091c5f (patch)
treea10cfb02f1dd2c35f773d7892e6a8f75c3c7544c
parenta42743c26a53a2a5f2b2018a9659ab3fb604d5bc (diff)
OMAP: mailbox: add notification support for multiple readers
In the current mailbox driver, the mailbox internal pointer for callback can be directly manipulated by the Users, so a second User can easily corrupt the first user's callback pointer. The initial effort to correct this issue can be referred here: https://patchwork.kernel.org/patch/107520/ Along with fixing the above stated issue, this patch adds the flexibility option to register notifications from multiple readers to the events received on a mailbox instance. The discussion regarding this can be referred here. http://www.mail-archive.com/linux-omap@vger.kernel.org/msg30671.html Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com> Signed-off-by: Fernando Guzman Lugo <x0095840@ti.com> Acked-by: Hiroshi Doyu <hiroshi.doyu@nokia.com>
-rw-r--r--arch/arm/plat-omap/include/plat/mailbox.h7
-rw-r--r--arch/arm/plat-omap/mailbox.c103
2 files changed, 61 insertions, 49 deletions
diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h
index 13f2ef3ea0ff..cc3921e9059c 100644
--- a/arch/arm/plat-omap/include/plat/mailbox.h
+++ b/arch/arm/plat-omap/include/plat/mailbox.h
@@ -46,7 +46,6 @@ struct omap_mbox_queue {
46 struct kfifo fifo; 46 struct kfifo fifo;
47 struct work_struct work; 47 struct work_struct work;
48 struct tasklet_struct tasklet; 48 struct tasklet_struct tasklet;
49 int (*callback)(void *);
50 struct omap_mbox *mbox; 49 struct omap_mbox *mbox;
51 bool full; 50 bool full;
52}; 51};
@@ -58,13 +57,15 @@ struct omap_mbox {
58 struct omap_mbox_ops *ops; 57 struct omap_mbox_ops *ops;
59 struct device *dev; 58 struct device *dev;
60 void *priv; 59 void *priv;
60 int use_count;
61 struct blocking_notifier_head notifier;
61}; 62};
62 63
63int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg); 64int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg);
64void omap_mbox_init_seq(struct omap_mbox *); 65void omap_mbox_init_seq(struct omap_mbox *);
65 66
66struct omap_mbox *omap_mbox_get(const char *); 67struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb);
67void omap_mbox_put(struct omap_mbox *); 68void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb);
68 69
69int omap_mbox_register(struct device *parent, struct omap_mbox **); 70int omap_mbox_register(struct device *parent, struct omap_mbox **);
70int omap_mbox_unregister(void); 71int omap_mbox_unregister(void);
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index cc58b44325f2..459b319a9fad 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -28,6 +28,7 @@
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/kfifo.h> 29#include <linux/kfifo.h>
30#include <linux/err.h> 30#include <linux/err.h>
31#include <linux/notifier.h>
31 32
32#include <plat/mailbox.h> 33#include <plat/mailbox.h>
33 34
@@ -150,8 +151,8 @@ static void mbox_rx_work(struct work_struct *work)
150 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); 151 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
151 WARN_ON(len != sizeof(msg)); 152 WARN_ON(len != sizeof(msg));
152 153
153 if (mq->callback) 154 blocking_notifier_call_chain(&mq->mbox->notifier, len,
154 mq->callback((void *)msg); 155 (void *)msg);
155 spin_lock_irq(&mq->lock); 156 spin_lock_irq(&mq->lock);
156 if (mq->full) { 157 if (mq->full) {
157 mq->full = false; 158 mq->full = false;
@@ -249,41 +250,40 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
249 int ret = 0; 250 int ret = 0;
250 struct omap_mbox_queue *mq; 251 struct omap_mbox_queue *mq;
251 252
252 if (mbox->ops->startup) { 253 mutex_lock(&mbox_configured_lock);
253 mutex_lock(&mbox_configured_lock); 254 if (!mbox_configured++) {
254 if (!mbox_configured) 255 if (likely(mbox->ops->startup)) {
255 ret = mbox->ops->startup(mbox); 256 ret = mbox->ops->startup(mbox);
256 257 if (unlikely(ret))
257 if (ret) { 258 goto fail_startup;
258 mutex_unlock(&mbox_configured_lock); 259 } else
259 return ret; 260 goto fail_startup;
260 }
261 mbox_configured++;
262 mutex_unlock(&mbox_configured_lock);
263 } 261 }
264 262
265 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, 263 if (!mbox->use_count++) {
266 mbox->name, mbox); 264 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
267 if (ret) { 265 mbox->name, mbox);
268 printk(KERN_ERR 266 if (unlikely(ret)) {
269 "failed to register mailbox interrupt:%d\n", ret); 267 pr_err("failed to register mailbox interrupt:%d\n",
270 goto fail_request_irq; 268 ret);
271 } 269 goto fail_request_irq;
272 270 }
273 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); 271 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
274 if (!mq) { 272 if (!mq) {
275 ret = -ENOMEM; 273 ret = -ENOMEM;
276 goto fail_alloc_txq; 274 goto fail_alloc_txq;
277 } 275 }
278 mbox->txq = mq; 276 mbox->txq = mq;
279 277
280 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); 278 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
281 if (!mq) { 279 if (!mq) {
282 ret = -ENOMEM; 280 ret = -ENOMEM;
283 goto fail_alloc_rxq; 281 goto fail_alloc_rxq;
282 }
283 mbox->rxq = mq;
284 mq->mbox = mbox;
284 } 285 }
285 mbox->rxq = mq; 286 mutex_unlock(&mbox_configured_lock);
286
287 return 0; 287 return 0;
288 288
289fail_alloc_rxq: 289fail_alloc_rxq:
@@ -293,29 +293,34 @@ fail_alloc_txq:
293fail_request_irq: 293fail_request_irq:
294 if (mbox->ops->shutdown) 294 if (mbox->ops->shutdown)
295 mbox->ops->shutdown(mbox); 295 mbox->ops->shutdown(mbox);
296 296 mbox->use_count--;
297fail_startup:
298 mbox_configured--;
299 mutex_unlock(&mbox_configured_lock);
297 return ret; 300 return ret;
298} 301}
299 302
300static void omap_mbox_fini(struct omap_mbox *mbox) 303static void omap_mbox_fini(struct omap_mbox *mbox)
301{ 304{
302 free_irq(mbox->irq, mbox); 305 mutex_lock(&mbox_configured_lock);
303 tasklet_kill(&mbox->txq->tasklet); 306
304 flush_work(&mbox->rxq->work); 307 if (!--mbox->use_count) {
305 mbox_queue_free(mbox->txq); 308 free_irq(mbox->irq, mbox);
306 mbox_queue_free(mbox->rxq); 309 tasklet_kill(&mbox->txq->tasklet);
310 flush_work(&mbox->rxq->work);
311 mbox_queue_free(mbox->txq);
312 mbox_queue_free(mbox->rxq);
313 }
307 314
308 if (mbox->ops->shutdown) { 315 if (likely(mbox->ops->shutdown)) {
309 mutex_lock(&mbox_configured_lock); 316 if (!--mbox_configured)
310 if (mbox_configured > 0)
311 mbox_configured--;
312 if (!mbox_configured)
313 mbox->ops->shutdown(mbox); 317 mbox->ops->shutdown(mbox);
314 mutex_unlock(&mbox_configured_lock);
315 } 318 }
319
320 mutex_unlock(&mbox_configured_lock);
316} 321}
317 322
318struct omap_mbox *omap_mbox_get(const char *name) 323struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
319{ 324{
320 struct omap_mbox *mbox; 325 struct omap_mbox *mbox;
321 int ret; 326 int ret;
@@ -334,12 +339,16 @@ struct omap_mbox *omap_mbox_get(const char *name)
334 if (ret) 339 if (ret)
335 return ERR_PTR(-ENODEV); 340 return ERR_PTR(-ENODEV);
336 341
342 if (nb)
343 blocking_notifier_chain_register(&mbox->notifier, nb);
344
337 return mbox; 345 return mbox;
338} 346}
339EXPORT_SYMBOL(omap_mbox_get); 347EXPORT_SYMBOL(omap_mbox_get);
340 348
341void omap_mbox_put(struct omap_mbox *mbox) 349void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
342{ 350{
351 blocking_notifier_chain_unregister(&mbox->notifier, nb);
343 omap_mbox_fini(mbox); 352 omap_mbox_fini(mbox);
344} 353}
345EXPORT_SYMBOL(omap_mbox_put); 354EXPORT_SYMBOL(omap_mbox_put);
@@ -363,6 +372,8 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list)
363 ret = PTR_ERR(mbox->dev); 372 ret = PTR_ERR(mbox->dev);
364 goto err_out; 373 goto err_out;
365 } 374 }
375
376 BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
366 } 377 }
367 return 0; 378 return 0;
368 379