diff options
Diffstat (limited to 'arch/arm/plat-omap/mailbox.c')
-rw-r--r-- | arch/arm/plat-omap/mailbox.c | 84 |
1 files changed, 58 insertions, 26 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 49d3208793e..6412fad5e05 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -34,6 +34,7 @@ static struct workqueue_struct *mboxd; static struct omap_mbox **mboxes; +static DEFINE_MUTEX(mboxes_lock); static int mbox_configured; static DEFINE_MUTEX(mbox_configured_lock); @@ -152,7 +153,7 @@ static void mbox_rx_work(struct work_struct *work) WARN_ON(len != sizeof(msg)); blocking_notifier_call_chain(&mq->mbox->notifier, len, - (void *)msg); + (void *)msg); spin_lock_irq(&mq->lock); if (mq->full) { mq->full = false; @@ -167,37 +168,59 @@ static void mbox_rx_work(struct work_struct *work) */ static void __mbox_tx_interrupt(struct omap_mbox *mbox) { - omap_mbox_disable_irq(mbox, IRQ_TX); - ack_mbox_irq(mbox, IRQ_TX); - tasklet_schedule(&mbox->txq->tasklet); + struct omap_mbox *mbox_curr; + int i =0; + + while (mboxes[i]) { + mbox_curr = mboxes[i]; + if (!mbox_fifo_full(mbox_curr)) { + omap_mbox_disable_irq(mbox_curr, IRQ_TX); + ack_mbox_irq(mbox_curr, IRQ_TX); + tasklet_schedule(&mbox_curr->txq->tasklet); + } + i++; + } } static void __mbox_rx_interrupt(struct omap_mbox *mbox) { - struct omap_mbox_queue *mq = mbox->rxq; + struct omap_mbox_queue *mq; mbox_msg_t msg; int len; - - while (!mbox_fifo_empty(mbox)) { - if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { - omap_mbox_disable_irq(mbox, IRQ_RX); - mq->full = true; - goto nomem; + int i = 0; + struct omap_mbox *mbox_curr; + bool msg_rx; + + while (mboxes[i]) { + mbox_curr = mboxes[i]; + mq = mbox_curr->rxq; + msg_rx = false; + while (!mbox_fifo_empty(mbox_curr)) { + msg_rx = true; + if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { + omap_mbox_disable_irq(mbox_curr, IRQ_RX); + mq->full = true; + goto nomem; + } + + msg = mbox_fifo_read(mbox_curr); + + len = kfifo_in(&mq->fifo, (unsigned char *)&msg, + sizeof(msg)); + if (unlikely(len != sizeof(msg))) + pr_err("%s: kfifo_in anomaly detected\n", + __func__); + if (mbox->ops->type == OMAP_MBOX_TYPE1) + break; } + /* no more messages in the fifo. clear IRQ source. */ + if (msg_rx) + ack_mbox_irq(mbox_curr, IRQ_RX); +nomem: + queue_work(mboxd, &mbox->rxq->work); - msg = mbox_fifo_read(mbox); - - len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); - WARN_ON(len != sizeof(msg)); - - if (mbox->ops->type == OMAP_MBOX_TYPE1) - break; + i++; } - - /* no more messages in the fifo. clear IRQ source. */ - ack_mbox_irq(mbox, IRQ_RX); -nomem: - queue_work(mboxd, &mbox->rxq->work); } static irqreturn_t mbox_interrupt(int irq, void *p) @@ -291,7 +314,7 @@ fail_alloc_rxq: fail_alloc_txq: free_irq(mbox->irq, mbox); fail_request_irq: - if (mbox->ops->shutdown) + if (likely(mbox->ops->shutdown)) mbox->ops->shutdown(mbox); mbox->use_count--; fail_startup: @@ -335,8 +358,11 @@ struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb) } } - if (!mbox) + if (!mbox) { + mutex_unlock(&mboxes_lock); return ERR_PTR(-ENOENT); + } + mutex_unlock(&mboxes_lock); ret = omap_mbox_startup(mbox); if (ret) @@ -351,7 +377,8 @@ EXPORT_SYMBOL(omap_mbox_get); void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb) { - blocking_notifier_chain_unregister(&mbox->notifier, nb); + if (nb) + blocking_notifier_chain_unregister(&mbox->notifier, nb); omap_mbox_fini(mbox); } EXPORT_SYMBOL(omap_mbox_put); @@ -366,6 +393,7 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list) mboxes = list; if (!mboxes) return -EINVAL; + mutex_lock(&mboxes_lock); for (i = 0; mboxes[i]; i++) { struct omap_mbox *mbox = mboxes[i]; @@ -378,11 +406,13 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list) BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier); } + mutex_unlock(&mboxes_lock); return 0; err_out: while (i--) device_unregister(mboxes[i]->dev); + mutex_unlock(&mboxes_lock); return ret; } EXPORT_SYMBOL(omap_mbox_register); @@ -394,9 +424,11 @@ int omap_mbox_unregister(void) if (!mboxes) return -EINVAL; + mutex_lock(&mboxes_lock); for (i = 0; mboxes[i]; i++) device_unregister(mboxes[i]->dev); mboxes = NULL; + mutex_unlock(&mboxes_lock); return 0; } EXPORT_SYMBOL(omap_mbox_unregister); |