]> git.ipfire.org Git - people/ms/linux.git/blobdiff - drivers/mailbox/mailbox.c
mailbox: forward the hrtimer if not queued and under a lock
[people/ms/linux.git] / drivers / mailbox / mailbox.c
index 3e7d4b20ab34fa852f5582105b08cc5dc318819c..4229b9b5da98f865ec36226c3f31310a70c96158 100644 (file)
@@ -82,11 +82,11 @@ static void msg_submit(struct mbox_chan *chan)
 exit:
        spin_unlock_irqrestore(&chan->lock, flags);
 
-       /* kick start the timer immediately to avoid delays */
        if (!err && (chan->txdone_method & TXDONE_BY_POLL)) {
-               /* but only if not already active */
-               if (!hrtimer_active(&chan->mbox->poll_hrt))
-                       hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
+               /* kick start the timer immediately to avoid delays */
+               spin_lock_irqsave(&chan->mbox->poll_hrt_lock, flags);
+               hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
+               spin_unlock_irqrestore(&chan->mbox->poll_hrt_lock, flags);
        }
 }
 
@@ -120,20 +120,26 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
                container_of(hrtimer, struct mbox_controller, poll_hrt);
        bool txdone, resched = false;
        int i;
+       unsigned long flags;
 
        for (i = 0; i < mbox->num_chans; 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) {
-               hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
+               spin_lock_irqsave(&mbox->poll_hrt_lock, flags);
+               if (!hrtimer_is_queued(hrtimer))
+                       hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
+               spin_unlock_irqrestore(&mbox->poll_hrt_lock, flags);
+
                return HRTIMER_RESTART;
        }
        return HRTIMER_NORESTART;
@@ -500,6 +506,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
                hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC,
                             HRTIMER_MODE_REL);
                mbox->poll_hrt.function = txdone_hrtimer;
+               spin_lock_init(&mbox->poll_hrt_lock);
        }
 
        for (i = 0; i < mbox->num_chans; i++) {