aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/mailbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/mailbox.c')
-rw-r--r--arch/arm/plat-omap/mailbox.c130
1 files changed, 76 insertions, 54 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index d2fafb892f7f..459b319a9fad 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -28,12 +28,12 @@
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
34static struct workqueue_struct *mboxd; 35static struct workqueue_struct *mboxd;
35static struct omap_mbox **mboxes; 36static struct omap_mbox **mboxes;
36static bool rq_full;
37 37
38static int mbox_configured; 38static int mbox_configured;
39static DEFINE_MUTEX(mbox_configured_lock); 39static DEFINE_MUTEX(mbox_configured_lock);
@@ -93,20 +93,25 @@ int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
93 struct omap_mbox_queue *mq = mbox->txq; 93 struct omap_mbox_queue *mq = mbox->txq;
94 int ret = 0, len; 94 int ret = 0, len;
95 95
96 spin_lock(&mq->lock); 96 spin_lock_bh(&mq->lock);
97 97
98 if (kfifo_avail(&mq->fifo) < sizeof(msg)) { 98 if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
99 ret = -ENOMEM; 99 ret = -ENOMEM;
100 goto out; 100 goto out;
101 } 101 }
102 102
103 if (kfifo_is_empty(&mq->fifo) && !__mbox_poll_for_space(mbox)) {
104 mbox_fifo_write(mbox, msg);
105 goto out;
106 }
107
103 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); 108 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
104 WARN_ON(len != sizeof(msg)); 109 WARN_ON(len != sizeof(msg));
105 110
106 tasklet_schedule(&mbox->txq->tasklet); 111 tasklet_schedule(&mbox->txq->tasklet);
107 112
108out: 113out:
109 spin_unlock(&mq->lock); 114 spin_unlock_bh(&mq->lock);
110 return ret; 115 return ret;
111} 116}
112EXPORT_SYMBOL(omap_mbox_msg_send); 117EXPORT_SYMBOL(omap_mbox_msg_send);
@@ -146,8 +151,14 @@ static void mbox_rx_work(struct work_struct *work)
146 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); 151 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
147 WARN_ON(len != sizeof(msg)); 152 WARN_ON(len != sizeof(msg));
148 153
149 if (mq->callback) 154 blocking_notifier_call_chain(&mq->mbox->notifier, len,
150 mq->callback((void *)msg); 155 (void *)msg);
156 spin_lock_irq(&mq->lock);
157 if (mq->full) {
158 mq->full = false;
159 omap_mbox_enable_irq(mq->mbox, IRQ_RX);
160 }
161 spin_unlock_irq(&mq->lock);
151 } 162 }
152} 163}
153 164
@@ -170,7 +181,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
170 while (!mbox_fifo_empty(mbox)) { 181 while (!mbox_fifo_empty(mbox)) {
171 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { 182 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
172 omap_mbox_disable_irq(mbox, IRQ_RX); 183 omap_mbox_disable_irq(mbox, IRQ_RX);
173 rq_full = true; 184 mq->full = true;
174 goto nomem; 185 goto nomem;
175 } 186 }
176 187
@@ -239,73 +250,77 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
239 int ret = 0; 250 int ret = 0;
240 struct omap_mbox_queue *mq; 251 struct omap_mbox_queue *mq;
241 252
242 if (mbox->ops->startup) { 253 mutex_lock(&mbox_configured_lock);
243 mutex_lock(&mbox_configured_lock); 254 if (!mbox_configured++) {
244 if (!mbox_configured) 255 if (likely(mbox->ops->startup)) {
245 ret = mbox->ops->startup(mbox); 256 ret = mbox->ops->startup(mbox);
246 257 if (unlikely(ret))
247 if (ret) { 258 goto fail_startup;
248 mutex_unlock(&mbox_configured_lock); 259 } else
249 return ret; 260 goto fail_startup;
250 }
251 mbox_configured++;
252 mutex_unlock(&mbox_configured_lock);
253 }
254
255 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
256 mbox->name, mbox);
257 if (ret) {
258 printk(KERN_ERR
259 "failed to register mailbox interrupt:%d\n", ret);
260 goto fail_request_irq;
261 } 261 }
262 262
263 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); 263 if (!mbox->use_count++) {
264 if (!mq) { 264 ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
265 ret = -ENOMEM; 265 mbox->name, mbox);
266 goto fail_alloc_txq; 266 if (unlikely(ret)) {
267 } 267 pr_err("failed to register mailbox interrupt:%d\n",
268 mbox->txq = mq; 268 ret);
269 goto fail_request_irq;
270 }
271 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
272 if (!mq) {
273 ret = -ENOMEM;
274 goto fail_alloc_txq;
275 }
276 mbox->txq = mq;
269 277
270 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); 278 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
271 if (!mq) { 279 if (!mq) {
272 ret = -ENOMEM; 280 ret = -ENOMEM;
273 goto fail_alloc_rxq; 281 goto fail_alloc_rxq;
282 }
283 mbox->rxq = mq;
284 mq->mbox = mbox;
274 } 285 }
275 mbox->rxq = mq; 286 mutex_unlock(&mbox_configured_lock);
276
277 return 0; 287 return 0;
278 288
279 fail_alloc_rxq: 289fail_alloc_rxq:
280 mbox_queue_free(mbox->txq); 290 mbox_queue_free(mbox->txq);
281 fail_alloc_txq: 291fail_alloc_txq:
282 free_irq(mbox->irq, mbox); 292 free_irq(mbox->irq, mbox);
283 fail_request_irq: 293fail_request_irq:
284 if (mbox->ops->shutdown) 294 if (mbox->ops->shutdown)
285 mbox->ops->shutdown(mbox); 295 mbox->ops->shutdown(mbox);
286 296 mbox->use_count--;
297fail_startup:
298 mbox_configured--;
299 mutex_unlock(&mbox_configured_lock);
287 return ret; 300 return ret;
288} 301}
289 302
290static void omap_mbox_fini(struct omap_mbox *mbox) 303static void omap_mbox_fini(struct omap_mbox *mbox)
291{ 304{
292 free_irq(mbox->irq, mbox); 305 mutex_lock(&mbox_configured_lock);
293 tasklet_kill(&mbox->txq->tasklet); 306
294 flush_work(&mbox->rxq->work); 307 if (!--mbox->use_count) {
295 mbox_queue_free(mbox->txq); 308 free_irq(mbox->irq, mbox);
296 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 }
297 314
298 if (mbox->ops->shutdown) { 315 if (likely(mbox->ops->shutdown)) {
299 mutex_lock(&mbox_configured_lock); 316 if (!--mbox_configured)
300 if (mbox_configured > 0)
301 mbox_configured--;
302 if (!mbox_configured)
303 mbox->ops->shutdown(mbox); 317 mbox->ops->shutdown(mbox);
304 mutex_unlock(&mbox_configured_lock);
305 } 318 }
319
320 mutex_unlock(&mbox_configured_lock);
306} 321}
307 322
308struct omap_mbox *omap_mbox_get(const char *name) 323struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
309{ 324{
310 struct omap_mbox *mbox; 325 struct omap_mbox *mbox;
311 int ret; 326 int ret;
@@ -324,12 +339,16 @@ struct omap_mbox *omap_mbox_get(const char *name)
324 if (ret) 339 if (ret)
325 return ERR_PTR(-ENODEV); 340 return ERR_PTR(-ENODEV);
326 341
342 if (nb)
343 blocking_notifier_chain_register(&mbox->notifier, nb);
344
327 return mbox; 345 return mbox;
328} 346}
329EXPORT_SYMBOL(omap_mbox_get); 347EXPORT_SYMBOL(omap_mbox_get);
330 348
331void omap_mbox_put(struct omap_mbox *mbox) 349void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
332{ 350{
351 blocking_notifier_chain_unregister(&mbox->notifier, nb);
333 omap_mbox_fini(mbox); 352 omap_mbox_fini(mbox);
334} 353}
335EXPORT_SYMBOL(omap_mbox_put); 354EXPORT_SYMBOL(omap_mbox_put);
@@ -353,6 +372,8 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list)
353 ret = PTR_ERR(mbox->dev); 372 ret = PTR_ERR(mbox->dev);
354 goto err_out; 373 goto err_out;
355 } 374 }
375
376 BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
356 } 377 }
357 return 0; 378 return 0;
358 379
@@ -391,7 +412,8 @@ static int __init omap_mbox_init(void)
391 412
392 /* kfifo size sanity check: alignment and minimal size */ 413 /* kfifo size sanity check: alignment and minimal size */
393 mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); 414 mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
394 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(mbox_msg_t)); 415 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size,
416 sizeof(mbox_msg_t));
395 417
396 return 0; 418 return 0;
397} 419}