Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58256307 authored by Kanigeri, Hari's avatar Kanigeri, Hari Committed by Hari Kanigeri
Browse files

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: default avatarHari Kanigeri <h-kanigeri2@ti.com>
Signed-off-by: default avatarFernando Guzman Lugo <x0095840@ti.com>
Acked-by: default avatarHiroshi Doyu <hiroshi.doyu@nokia.com>
parent a42743c2
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -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;
};
@@ -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);
+57 −46
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/kfifo.h>
#include <linux/err.h>
#include <linux/notifier.h>

#include <plat/mailbox.h>

@@ -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;
@@ -249,27 +250,24 @@ 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)
	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;
	}

	if (!mbox->use_count++) {
		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);
		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;
@@ -283,7 +281,9 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
			goto fail_alloc_rxq;
		}
		mbox->rxq = mq;

		mq->mbox = mbox;
	}
	mutex_unlock(&mbox_configured_lock);
	return 0;

fail_alloc_rxq:
@@ -293,29 +293,34 @@ fail_alloc_txq:
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)
{
	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;
@@ -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);
@@ -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;