MALI: add midgard src dir
[firefly-linux-kernel-4.4.55.git] / drivers / mailbox / mailbox.c
index afcb430508eceac7887ee436ec19c15fcfad89cd..6a4811f857056aaa64baff75265902b59be12ac9 100644 (file)
@@ -21,9 +21,7 @@
 #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);
@@ -60,7 +58,7 @@ static void msg_submit(struct mbox_chan *chan)
        unsigned count, idx;
        unsigned long flags;
        void *data;
-       int err;
+       int err = -EBUSY;
 
        spin_lock_irqsave(&chan->lock, flags);
 
@@ -76,6 +74,8 @@ static void msg_submit(struct mbox_chan *chan)
 
        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) {
@@ -84,6 +84,11 @@ static void msg_submit(struct mbox_chan *chan)
        }
 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)
@@ -107,9 +112,10 @@ 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;
 
@@ -117,16 +123,19 @@ static void poll_txdone(unsigned long data)
                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;
 }
 
 /**
@@ -252,9 +261,6 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
 
        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;
@@ -315,7 +321,7 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
                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);
@@ -324,7 +330,12 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
 
        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);
@@ -354,6 +365,35 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
 }
 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.
@@ -387,7 +427,7 @@ of_mbox_index_xlate(struct mbox_controller *mbox,
        int ind = sp->args[0];
 
        if (ind >= mbox->num_chans)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        return &mbox->chans[ind];
 }
@@ -414,9 +454,9 @@ int mbox_controller_register(struct mbox_controller *mbox)
                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++) {
@@ -458,7 +498,7 @@ void mbox_controller_unregister(struct mbox_controller *mbox)
                mbox_free_channel(&mbox->chans[i]);
 
        if (mbox->txdone_poll)
-               del_timer_sync(&mbox->poll);
+               hrtimer_cancel(&mbox->poll_hrt);
 
        mutex_unlock(&con_mutex);
 }