@@ -68,13 +68,15 @@ struct omap_mbox {
void *priv;
void (*err_notify)(void);
+ atomic_t 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 *, struct notifier_block *nb);
int omap_mbox_register(struct device *parent, struct omap_mbox *);
int omap_mbox_unregister(struct omap_mbox *);
@@ -149,8 +149,8 @@ static void mbox_rx_work(struct work_struct *work)
if (unlikely(len != sizeof(msg)))
pr_err("%s: kfifo_out anomaly detected\n", __func__);
- if (mq->callback)
- mq->callback((void *)msg);
+ blocking_notifier_call_chain(&mq->mbox->notifier, len,
+ (void *)msg);
}
}
@@ -252,28 +252,30 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
}
}
- ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
- mbox->name, mbox);
- if (unlikely(ret)) {
- printk(KERN_ERR
- "failed to register mailbox interrupt:%d\n", ret);
- goto fail_request_irq;
- }
+ if (atomic_inc_return(&mbox->use_count) == 1) {
+ ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
+ mbox->name, mbox);
+ if (unlikely(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;
+ 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;
-
return 0;
fail_alloc_rxq:
@@ -281,6 +283,7 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
fail_alloc_txq:
free_irq(mbox->irq, mbox);
fail_request_irq:
+ atomic_dec(&mbox->use_count);
if (likely(mbox->ops->shutdown)) {
if (atomic_dec_return(&mbox_refcount) == 0)
mbox->ops->shutdown(mbox);
@@ -291,10 +294,12 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
static void omap_mbox_fini(struct omap_mbox *mbox)
{
- mbox_queue_free(mbox->txq);
- mbox_queue_free(mbox->rxq);
- free_irq(mbox->irq, mbox);
+ if (atomic_dec_return(&mbox->use_count) == 0) {
+ mbox_queue_free(mbox->txq);
+ mbox_queue_free(mbox->rxq);
+ free_irq(mbox->irq, mbox);
+ }
if (likely(mbox->ops->shutdown)) {
if (atomic_dec_return(&mbox_refcount) == 0)
@@ -314,7 +319,7 @@ static struct omap_mbox **find_mboxes(const char *name)
return p;
}
-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;
@@ -325,19 +330,21 @@ struct omap_mbox *omap_mbox_get(const char *name)
spin_unlock(&mboxes_lock);
return ERR_PTR(-ENOENT);
}
-
spin_unlock(&mboxes_lock);
ret = omap_mbox_startup(mbox);
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);
@@ -361,6 +368,8 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox)
}
*tmp = mbox;
spin_unlock(&mboxes_lock);
+ BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
+ atomic_set(&mbox->use_count, 0);
return 0;