#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
-#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 */
+#include "mailbox.h"
static LIST_HEAD(mbox_cons);
static DEFINE_MUTEX(con_mutex);
unsigned count, idx;
unsigned long flags;
void *data;
- int err;
+ int err = -EBUSY;
spin_lock_irqsave(&chan->lock, flags);
data = chan->msg_data[idx];
+ if (chan->cl->tx_prepare)
+ chan->cl->tx_prepare(chan->cl, data);
/* Try to submit a message to the MBOX controller */
err = chan->mbox->ops->send_data(chan, data);
if (!err) {
}
exit:
spin_unlock_irqrestore(&chan->lock, flags);
+
+ if (!err && (chan->txdone_method & TXDONE_BY_POLL))
+ /* kick start the timer immediately to avoid delays */
+ hrtimer_start(&chan->mbox->poll_hrt, ktime_set(0, 0),
+ HRTIMER_MODE_REL);
}
static void tx_tick(struct mbox_chan *chan, int r)
complete(&chan->tx_complete);
}
-static void poll_txdone(unsigned long data)
+static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
{
- struct mbox_controller *mbox = (struct mbox_controller *)data;
+ struct mbox_controller *mbox =
+ container_of(hrtimer, struct mbox_controller, poll_hrt);
bool txdone, resched = false;
int i;
struct mbox_chan *chan = &mbox->chans[i];
if (chan->active_req && chan->cl) {
- resched = true;
txdone = chan->mbox->ops->last_tx_done(chan);
if (txdone)
tx_tick(chan, 0);
+ else
+ resched = true;
}
}
- if (resched)
- mod_timer(&mbox->poll, jiffies +
- msecs_to_jiffies(mbox->txpoll_period));
+ if (resched) {
+ hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
+ return HRTIMER_RESTART;
+ }
+ return HRTIMER_NORESTART;
}
/**
msg_submit(chan);
- if (chan->txdone_method == TXDONE_BY_POLL)
- poll_txdone((unsigned long)chan->mbox);
-
if (chan->cl->tx_block && chan->active_req) {
unsigned long wait;
int ret;
return ERR_PTR(-ENODEV);
}
- chan = NULL;
+ chan = ERR_PTR(-EPROBE_DEFER);
list_for_each_entry(mbox, &mbox_cons, node)
if (mbox->dev->of_node == spec.np) {
chan = mbox->of_xlate(mbox, &spec);
of_node_put(spec.np);
- if (!chan || chan->cl || !try_module_get(mbox->dev->driver->owner)) {
+ if (IS_ERR(chan)) {
+ mutex_unlock(&con_mutex);
+ return chan;
+ }
+
+ if (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(-EBUSY);
}
EXPORT_SYMBOL_GPL(mbox_request_channel);
+struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
+ const char *name)
+{
+ struct device_node *np = cl->dev->of_node;
+ struct property *prop;
+ const char *mbox_name;
+ int index = 0;
+
+ if (!np) {
+ dev_err(cl->dev, "%s() currently only supports DT\n", __func__);
+ return ERR_PTR(-ENOSYS);
+ }
+
+ if (!of_get_property(np, "mbox-names", NULL)) {
+ dev_err(cl->dev,
+ "%s() requires an \"mbox-names\" property\n", __func__);
+ return ERR_PTR(-ENOSYS);
+ }
+
+ of_property_for_each_string(np, "mbox-names", prop, mbox_name) {
+ if (!strncmp(name, mbox_name, strlen(name)))
+ break;
+ index++;
+ }
+
+ return mbox_request_channel(cl, index);
+}
+EXPORT_SYMBOL_GPL(mbox_request_channel_byname);
+
/**
* mbox_free_channel - The client relinquishes control of a mailbox
* channel by this call.
int ind = sp->args[0];
if (ind >= mbox->num_chans)
- return NULL;
+ return ERR_PTR(-EINVAL);
return &mbox->chans[ind];
}
txdone = TXDONE_BY_ACK;
if (txdone == TXDONE_BY_POLL) {
- mbox->poll.function = &poll_txdone;
- mbox->poll.data = (unsigned long)mbox;
- init_timer(&mbox->poll);
+ hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ mbox->poll_hrt.function = txdone_hrtimer;
}
for (i = 0; i < mbox->num_chans; i++) {
mbox_free_channel(&mbox->chans[i]);
if (mbox->txdone_poll)
- del_timer_sync(&mbox->poll);
+ hrtimer_cancel(&mbox->poll_hrt);
mutex_unlock(&con_mutex);
}