Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d8b9f57 authored by Björn Ardö's avatar Björn Ardö Committed by Greg Kroah-Hartman
Browse files

mailbox: forward the hrtimer if not queued and under a lock



[ 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: default avatarBjörn Ardö <bjorn.ardo@axis.com>
Signed-off-by: default avatarJassi Brar <jaswinder.singh@linaro.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 49c1e32e
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -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))
		/* 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) {
		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++) {
+1 −0
Original line number Diff line number Diff line
@@ -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;
};