Skip to content

Commit bca1a10

Browse files
bjornaxisJassiBrar
authored andcommitted
mailbox: forward the hrtimer if not queued and under a lock
This reverts commit c7dacf5, "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: c7dacf5 ("mailbox: avoid timer start from callback") Signed-off-by: Björn Ardö <[email protected]> Signed-off-by: Jassi Brar <[email protected]>
1 parent c25f778 commit bca1a10

File tree

2 files changed

+14
-6
lines changed

2 files changed

+14
-6
lines changed

drivers/mailbox/mailbox.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,11 @@ static void msg_submit(struct mbox_chan *chan)
8282
exit:
8383
spin_unlock_irqrestore(&chan->lock, flags);
8484

85-
/* kick start the timer immediately to avoid delays */
8685
if (!err && (chan->txdone_method & TXDONE_BY_POLL)) {
87-
/* but only if not already active */
88-
if (!hrtimer_active(&chan->mbox->poll_hrt))
89-
hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
86+
/* kick start the timer immediately to avoid delays */
87+
spin_lock_irqsave(&chan->mbox->poll_hrt_lock, flags);
88+
hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
89+
spin_unlock_irqrestore(&chan->mbox->poll_hrt_lock, flags);
9090
}
9191
}
9292

@@ -120,20 +120,26 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
120120
container_of(hrtimer, struct mbox_controller, poll_hrt);
121121
bool txdone, resched = false;
122122
int i;
123+
unsigned long flags;
123124

124125
for (i = 0; i < mbox->num_chans; i++) {
125126
struct mbox_chan *chan = &mbox->chans[i];
126127

127128
if (chan->active_req && chan->cl) {
128-
resched = true;
129129
txdone = chan->mbox->ops->last_tx_done(chan);
130130
if (txdone)
131131
tx_tick(chan, 0);
132+
else
133+
resched = true;
132134
}
133135
}
134136

135137
if (resched) {
136-
hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
138+
spin_lock_irqsave(&mbox->poll_hrt_lock, flags);
139+
if (!hrtimer_is_queued(hrtimer))
140+
hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
141+
spin_unlock_irqrestore(&mbox->poll_hrt_lock, flags);
142+
137143
return HRTIMER_RESTART;
138144
}
139145
return HRTIMER_NORESTART;
@@ -500,6 +506,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
500506
hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC,
501507
HRTIMER_MODE_REL);
502508
mbox->poll_hrt.function = txdone_hrtimer;
509+
spin_lock_init(&mbox->poll_hrt_lock);
503510
}
504511

505512
for (i = 0; i < mbox->num_chans; i++) {

include/linux/mailbox_controller.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct mbox_controller {
8383
const struct of_phandle_args *sp);
8484
/* Internal to API */
8585
struct hrtimer poll_hrt;
86+
spinlock_t poll_hrt_lock;
8687
struct list_head node;
8788
};
8889

0 commit comments

Comments
 (0)