Skip to content

Commit

Permalink
OMAP: mailbox: add notification support for multiple readers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kanigeri, Hari committed Dec 2, 2010
1 parent a42743c commit 5825630
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 49 deletions.
7 changes: 4 additions & 3 deletions arch/arm/plat-omap/include/plat/mailbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ struct omap_mbox_queue {
struct kfifo fifo;
struct work_struct work;
struct tasklet_struct tasklet;
int (*callback)(void *);
struct omap_mbox *mbox;
bool full;
};
Expand All @@ -58,13 +57,15 @@ struct omap_mbox {
struct omap_mbox_ops *ops;
struct device *dev;
void *priv;
int use_count;
struct blocking_notifier_head notifier;
};

int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg);
void omap_mbox_init_seq(struct omap_mbox *);

struct omap_mbox *omap_mbox_get(const char *);
void omap_mbox_put(struct omap_mbox *);
struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb);
void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb);

int omap_mbox_register(struct device *parent, struct omap_mbox **);
int omap_mbox_unregister(void);
Expand Down
103 changes: 57 additions & 46 deletions arch/arm/plat-omap/mailbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/kfifo.h>
#include <linux/err.h>
#include <linux/notifier.h>

#include <plat/mailbox.h>

Expand Down Expand Up @@ -150,8 +151,8 @@ static void mbox_rx_work(struct work_struct *work)
len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
WARN_ON(len != sizeof(msg));

if (mq->callback)
mq->callback((void *)msg);
blocking_notifier_call_chain(&mq->mbox->notifier, len,
(void *)msg);
spin_lock_irq(&mq->lock);
if (mq->full) {
mq->full = false;
Expand Down Expand Up @@ -249,41 +250,40 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
int ret = 0;
struct omap_mbox_queue *mq;

if (mbox->ops->startup) {
mutex_lock(&mbox_configured_lock);
if (!mbox_configured)
mutex_lock(&mbox_configured_lock);
if (!mbox_configured++) {
if (likely(mbox->ops->startup)) {
ret = mbox->ops->startup(mbox);

if (ret) {
mutex_unlock(&mbox_configured_lock);
return ret;
}
mbox_configured++;
mutex_unlock(&mbox_configured_lock);
if (unlikely(ret))
goto fail_startup;
} else
goto fail_startup;
}

ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
mbox->name, mbox);
if (ret) {
printk(KERN_ERR
"failed to register mailbox interrupt:%d\n", ret);
goto fail_request_irq;
}

mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
if (!mq) {
ret = -ENOMEM;
goto fail_alloc_txq;
}
mbox->txq = mq;
if (!mbox->use_count++) {
ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
mbox->name, mbox);
if (unlikely(ret)) {
pr_err("failed to register mailbox interrupt:%d\n",
ret);
goto fail_request_irq;
}
mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
if (!mq) {
ret = -ENOMEM;
goto fail_alloc_txq;
}
mbox->txq = mq;

mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
if (!mq) {
ret = -ENOMEM;
goto fail_alloc_rxq;
mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
if (!mq) {
ret = -ENOMEM;
goto fail_alloc_rxq;
}
mbox->rxq = mq;
mq->mbox = mbox;
}
mbox->rxq = mq;

mutex_unlock(&mbox_configured_lock);
return 0;

fail_alloc_rxq:
Expand All @@ -293,29 +293,34 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
fail_request_irq:
if (mbox->ops->shutdown)
mbox->ops->shutdown(mbox);

mbox->use_count--;
fail_startup:
mbox_configured--;
mutex_unlock(&mbox_configured_lock);
return ret;
}

static void omap_mbox_fini(struct omap_mbox *mbox)
{
free_irq(mbox->irq, mbox);
tasklet_kill(&mbox->txq->tasklet);
flush_work(&mbox->rxq->work);
mbox_queue_free(mbox->txq);
mbox_queue_free(mbox->rxq);
mutex_lock(&mbox_configured_lock);

if (!--mbox->use_count) {
free_irq(mbox->irq, mbox);
tasklet_kill(&mbox->txq->tasklet);
flush_work(&mbox->rxq->work);
mbox_queue_free(mbox->txq);
mbox_queue_free(mbox->rxq);
}

if (mbox->ops->shutdown) {
mutex_lock(&mbox_configured_lock);
if (mbox_configured > 0)
mbox_configured--;
if (!mbox_configured)
if (likely(mbox->ops->shutdown)) {
if (!--mbox_configured)
mbox->ops->shutdown(mbox);
mutex_unlock(&mbox_configured_lock);
}

mutex_unlock(&mbox_configured_lock);
}

struct omap_mbox *omap_mbox_get(const char *name)
struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
{
struct omap_mbox *mbox;
int ret;
Expand All @@ -334,12 +339,16 @@ struct omap_mbox *omap_mbox_get(const char *name)
if (ret)
return ERR_PTR(-ENODEV);

if (nb)
blocking_notifier_chain_register(&mbox->notifier, nb);

return mbox;
}
EXPORT_SYMBOL(omap_mbox_get);

void omap_mbox_put(struct omap_mbox *mbox)
void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
{
blocking_notifier_chain_unregister(&mbox->notifier, nb);
omap_mbox_fini(mbox);
}
EXPORT_SYMBOL(omap_mbox_put);
Expand All @@ -363,6 +372,8 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list)
ret = PTR_ERR(mbox->dev);
goto err_out;
}

BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
}
return 0;

Expand Down

0 comments on commit 5825630

Please sign in to comment.