]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mailbox: forward the hrtimer if not queued and under a lock
authorBjörn Ardö <bjorn.ardo@axis.com>
Thu, 31 Mar 2022 07:01:15 +0000 (09:01 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 14 Jun 2022 14:59:25 +0000 (16:59 +0200)
[ Upstream commit bca1a1004615efe141fd78f360ecc48c60bc4ad5 ]

This reverts commit c7dacf5b0f32957b24ef29df1207dc2cd8307743,
"mailbox: avoid timer start from callback"

The previous commit was reverted since it lead to a race that
caused the hrtimer to not be started at all. The check for
hrtimer_active() in msg_submit() will return true if the
callback function txdone_hrtimer() is currently running. This
function could return HRTIMER_NORESTART and then the timer
will not be restarted, and also msg_submit() will not start
the timer. This will lead to a message actually being submitted
but no timer will start to check for its compleation.

The original fix that added checking hrtimer_active() was added to
avoid a warning with hrtimer_forward. Looking in the kernel
another solution to avoid this warning is to check hrtimer_is_queued()
before calling hrtimer_forward_now() instead. This however requires a
lock so the timer is not started by msg_submit() inbetween this check
and the hrtimer_forward() call.

Fixes: c7dacf5b0f32 ("mailbox: avoid timer start from callback")
Signed-off-by: Björn Ardö <bjorn.ardo@axis.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/mailbox/mailbox.c
include/linux/mailbox_controller.h

index 10a559cfb7ea361f655874cd0e8ea273dccb61a9..aa28fdcb81b9c04e13a69003fe2f2cd3a7b30122 100644 (file)
@@ -85,11 +85,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);
        }
 }
 
@@ -123,20 +123,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;
@@ -473,6 +479,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++) {
index 74deadb42d76747e8f8f66b32bc839b052ed20a8..5a4524f66ea16c2d84d1a349b73284b880a0f5f8 100644 (file)
@@ -83,6 +83,7 @@ struct mbox_controller {
                                      const struct of_phandle_args *sp);
        /* Internal to API */
        struct hrtimer poll_hrt;
+       spinlock_t poll_hrt_lock;
        struct list_head node;
 };