History

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

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.

Björn Ardö committed 4 years ago

Commit bca1a101 parent c25f7782 files · +14 −6Browse files

Unified · Split

2 files
  1. drivers/mailbox/mailbox.c +13 −6
  2. include/linux/mailbox_controller.h +1 −0
drivers/mailbox/mailbox.c+13−6
@@ -82,11 +82,11 @@ static void msg_submit(struct mbox_chan *chan) · 81 unmodified lines
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) · 27 unmodified lines
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) · 360 unmodified lines
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+1−0
@@ -83,6 +83,7 @@ struct mbox_controller { · 82 unmodified lines
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