aboutsummaryrefslogtreecommitdiff
path: root/drivers/mailbox/mailbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mailbox/mailbox.c')
-rw-r--r--drivers/mailbox/mailbox.c127
1 files changed, 53 insertions, 74 deletions
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 607dd91e87a1..9a937ef35068 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -1,7 +1,7 @@
/*
* Mailbox: Common code for Mailbox controllers and users
*
- * Copyright (C) 2014 Linaro Ltd.
+ * Copyright (C) 2013-2014 Linaro Ltd.
* Author: Jassi Brar <jassisinghbrar@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,17 +17,18 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/bitops.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
-#define TXDONE_BY_IRQ (1 << 0) /* controller has remote RTR irq */
-#define TXDONE_BY_POLL (1 << 1) /* controller can read status of last TX */
-#define TXDONE_BY_ACK (1 << 2) /* S/W ACK recevied by Client ticks the TX */
+#define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */
+#define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */
+#define TXDONE_BY_ACK BIT(2) /* S/W ACK recevied by Client ticks the TX */
static LIST_HEAD(mbox_cons);
static DEFINE_MUTEX(con_mutex);
-static int _add_to_rbuf(struct mbox_chan *chan, void *mssg)
+static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
{
int idx;
unsigned long flags;
@@ -37,7 +38,7 @@ static int _add_to_rbuf(struct mbox_chan *chan, void *mssg)
/* See if there is any space left */
if (chan->msg_count == MBOX_TX_QUEUE_LEN) {
spin_unlock_irqrestore(&chan->lock, flags);
- return -ENOMEM;
+ return -ENOBUFS;
}
idx = chan->msg_free;
@@ -54,7 +55,7 @@ static int _add_to_rbuf(struct mbox_chan *chan, void *mssg)
return idx;
}
-static void _msg_submit(struct mbox_chan *chan)
+static void msg_submit(struct mbox_chan *chan)
{
unsigned count, idx;
unsigned long flags;
@@ -63,10 +64,8 @@ static void _msg_submit(struct mbox_chan *chan)
spin_lock_irqsave(&chan->lock, flags);
- if (!chan->msg_count || chan->active_req) {
- spin_unlock_irqrestore(&chan->lock, flags);
- return;
- }
+ if (!chan->msg_count || chan->active_req)
+ goto exit;
count = chan->msg_count;
idx = chan->msg_free;
@@ -83,7 +82,7 @@ static void _msg_submit(struct mbox_chan *chan)
chan->active_req = data;
chan->msg_count--;
}
-
+exit:
spin_unlock_irqrestore(&chan->lock, flags);
}
@@ -98,13 +97,14 @@ static void tx_tick(struct mbox_chan *chan, int r)
spin_unlock_irqrestore(&chan->lock, flags);
/* Submit next message */
- _msg_submit(chan);
+ msg_submit(chan);
/* Notify the client */
+ if (mssg && chan->cl->tx_done)
+ chan->cl->tx_done(chan->cl, mssg, r);
+
if (chan->cl->tx_block)
complete(&chan->tx_complete);
- else if (mssg && chan->cl->tx_done)
- chan->cl->tx_done(chan->cl, mssg, r);
}
static void poll_txdone(unsigned long data)
@@ -125,15 +125,15 @@ static void poll_txdone(unsigned long data)
}
if (resched)
- mod_timer(&mbox->poll,
- jiffies + msecs_to_jiffies(mbox->period));
+ mod_timer(&mbox->poll, jiffies +
+ msecs_to_jiffies(mbox->period));
}
/**
* mbox_chan_received_data - A way for controller driver to push data
* received from remote to the upper layer.
* @chan: Pointer to the mailbox channel on which RX happened.
- * @data: Client specific message typecasted as void *
+ * @mssg: Client specific message typecasted as void *
*
* After startup and before shutdown any data received on the chan
* is passed on to the API via atomic mbox_chan_received_data().
@@ -160,7 +160,8 @@ EXPORT_SYMBOL_GPL(mbox_chan_received_data);
void mbox_chan_txdone(struct mbox_chan *chan, int r)
{
if (unlikely(!(chan->txdone_method & TXDONE_BY_IRQ))) {
- pr_err("Controller can't run the TX ticker\n");
+ dev_err(chan->mbox->dev,
+ "Controller can't run the TX ticker\n");
return;
}
@@ -180,7 +181,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_txdone);
void mbox_client_txdone(struct mbox_chan *chan, int r)
{
if (unlikely(!(chan->txdone_method & TXDONE_BY_ACK))) {
- pr_err("Client can't run the TX ticker\n");
+ dev_err(chan->mbox->dev, "Client can't run the TX ticker\n");
return;
}
@@ -227,8 +228,6 @@ EXPORT_SYMBOL_GPL(mbox_client_peek_data);
* is not queued, a negative token is returned. Upon failure or successful
* TX, the API calls 'tx_done' from atomic context, from which the client
* could submit yet another request.
- * In blocking mode, 'tx_done' is not called, effectively making the
- * queue length 1.
* The pointer to message should be preserved until it is sent
* over the chan, i.e, tx_done() is made.
* This function could be called from atomic context as it simply
@@ -245,15 +244,15 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
if (!chan || !chan->cl)
return -EINVAL;
- t = _add_to_rbuf(chan, mssg);
+ t = add_to_rbuf(chan, mssg);
if (t < 0) {
- pr_err("Try increasing MBOX_TX_QUEUE_LEN\n");
+ dev_err(chan->mbox->dev, "Try increasing MBOX_TX_QUEUE_LEN\n");
return t;
}
- _msg_submit(chan);
+ msg_submit(chan);
- init_completion(&chan->tx_complete);
+ INIT_COMPLETION(chan->tx_complete);
if (chan->txdone_method == TXDONE_BY_POLL)
poll_txdone((unsigned long)chan->mbox);
@@ -262,7 +261,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
unsigned long wait;
int ret;
- if (!chan->cl->tx_tout) /* wait for ever */
+ if (!chan->cl->tx_tout) /* wait forever */
wait = msecs_to_jiffies(3600000);
else
wait = msecs_to_jiffies(chan->cl->tx_tout);
@@ -281,6 +280,7 @@ EXPORT_SYMBOL_GPL(mbox_send_message);
/**
* mbox_request_channel - Request a mailbox channel.
* @cl: Identity of the client requesting the channel.
+ * @index: Index of mailbox specifier in 'mboxes' property.
*
* The Client specifies its requirements and capabilities while asking for
* a mailbox channel. It can't be called from atomic context.
@@ -294,64 +294,42 @@ EXPORT_SYMBOL_GPL(mbox_send_message);
* Return: Pointer to the channel assigned to the client if successful.
* ERR_PTR for request failure.
*/
-struct mbox_chan *mbox_request_channel(struct mbox_client *cl)
+struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
{
struct device *dev = cl->dev;
struct mbox_controller *mbox;
struct of_phandle_args spec;
struct mbox_chan *chan;
unsigned long flags;
- int count, i, ret;
+ int ret;
if (!dev || !dev->of_node) {
- pr_err("%s: No owner device node\n", __func__);
- return ERR_PTR(-ENODEV);
- }
-
- count = of_property_count_strings(dev->of_node, "mbox-names");
- if (count < 0) {
- pr_err("%s: mbox-names property of node '%s' missing\n",
- __func__, dev->of_node->full_name);
+ pr_debug("%s: No owner device node\n", __func__);
return ERR_PTR(-ENODEV);
}
mutex_lock(&con_mutex);
- ret = -ENODEV;
- for (i = 0; i < count; i++) {
- const char *s;
-
- if (of_property_read_string_index(dev->of_node,
- "mbox-names", i, &s))
- continue;
-
- if (strcmp(cl->chan_name, s))
- continue;
-
- if (of_parse_phandle_with_args(dev->of_node,
- "mbox", "#mbox-cells", i, &spec))
- continue;
-
- chan = NULL;
- list_for_each_entry(mbox, &mbox_cons, node)
- if (mbox->dev->of_node == spec.np) {
- chan = mbox->of_xlate(mbox, &spec);
- break;
- }
-
- of_node_put(spec.np);
-
- if (!chan)
- continue;
+ if (of_parse_phandle_with_args(dev->of_node, "mboxes",
+ "#mbox-cells", index, &spec)) {
+ dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__);
+ mutex_unlock(&con_mutex);
+ return ERR_PTR(-ENODEV);
+ }
- ret = -EBUSY;
- if (!chan->cl && try_module_get(mbox->dev->driver->owner))
+ chan = NULL;
+ list_for_each_entry(mbox, &mbox_cons, node)
+ if (mbox->dev->of_node == spec.np) {
+ chan = mbox->of_xlate(mbox, &spec);
break;
- }
+ }
- if (i == count) {
+ of_node_put(spec.np);
+
+ if (!chan || chan->cl || !try_module_get(mbox->dev->driver->owner)) {
+ dev_dbg(dev, "%s: mailbox not free\n", __func__);
mutex_unlock(&con_mutex);
- return ERR_PTR(ret);
+ return ERR_PTR(-EBUSY);
}
spin_lock_irqsave(&chan->lock, flags);
@@ -361,14 +339,14 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl)
chan->cl = cl;
init_completion(&chan->tx_complete);
- if (chan->txdone_method == TXDONE_BY_POLL
- && cl->knows_txdone)
+ if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
chan->txdone_method |= TXDONE_BY_ACK;
+
spin_unlock_irqrestore(&chan->lock, flags);
ret = chan->mbox->ops->startup(chan);
if (ret) {
- pr_err("Unable to startup the chan (%d)\n", ret);
+ dev_err(dev, "Unable to startup the chan (%d)\n", ret);
mbox_free_channel(chan);
chan = ERR_PTR(ret);
}
@@ -406,7 +384,7 @@ EXPORT_SYMBOL_GPL(mbox_free_channel);
static struct mbox_chan *
of_mbox_index_xlate(struct mbox_controller *mbox,
- const struct of_phandle_args *sp)
+ const struct of_phandle_args *sp)
{
int ind = sp->args[0];
@@ -420,7 +398,7 @@ of_mbox_index_xlate(struct mbox_controller *mbox,
* mbox_controller_register - Register the mailbox controller
* @mbox: Pointer to the mailbox controller.
*
- * The controller driver registers its communication chans
+ * The controller driver registers its communication channels
*/
int mbox_controller_register(struct mbox_controller *mbox)
{
@@ -445,6 +423,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
for (i = 0; i < mbox->num_chans; i++) {
struct mbox_chan *chan = &mbox->chans[i];
+
chan->cl = NULL;
chan->mbox = mbox;
chan->txdone_method = txdone;
@@ -463,7 +442,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
EXPORT_SYMBOL_GPL(mbox_controller_register);
/**
- * mbox_controller_unregister - UnRegister the mailbox controller
+ * mbox_controller_unregister - Unregister the mailbox controller
* @mbox: Pointer to the mailbox controller.
*/
void mbox_controller_unregister(struct mbox_controller *mbox)