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.
Unified · Split
| @@ -82,11 +82,11 @@ static void msg_submit(struct mbox_chan *chan) · 81 unmodified lines | |||
| 82 | exit: | 82 | exit: |
| 83 | spin_unlock_irqrestore(&chan->lock, flags); | 83 | spin_unlock_irqrestore(&chan->lock, flags); |
| 84 | 84 | ||
| 85 | /* kick start the timer immediately to avoid delays */ | ||
| 86 | if (!err && (chan->txdone_method & TXDONE_BY_POLL)) { | 85 | if (!err && (chan->txdone_method & TXDONE_BY_POLL)) { |
| 87 | /* but only if not already active */ | 86 | /* kick start the timer immediately to avoid delays */ |
| 88 | if (!hrtimer_active(&chan->mbox->poll_hrt)) | 87 | spin_lock_irqsave(&chan->mbox->poll_hrt_lock, flags); |
| 89 | hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL); | 88 | hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL); |
| 89 | spin_unlock_irqrestore(&chan->mbox->poll_hrt_lock, flags); | ||
| 90 | } | 90 | } |
| 91 | } | 91 | } |
| 92 | 92 | ||
| @@ -120,20 +120,26 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) · 27 unmodified lines | |||
| 120 | container_of(hrtimer, struct mbox_controller, poll_hrt); | 120 | container_of(hrtimer, struct mbox_controller, poll_hrt); |
| 121 | bool txdone, resched = false; | 121 | bool txdone, resched = false; |
| 122 | int i; | 122 | int i; |
| 123 | unsigned long flags; | ||
| 123 | 124 | ||
| 124 | for (i = 0; i < mbox->num_chans; i++) { | 125 | for (i = 0; i < mbox->num_chans; i++) { |
| 125 | struct mbox_chan *chan = &mbox->chans[i]; | 126 | struct mbox_chan *chan = &mbox->chans[i]; |
| 126 | 127 | ||
| 127 | if (chan->active_req && chan->cl) { | 128 | if (chan->active_req && chan->cl) { |
| 128 | resched = true; | ||
| 129 | txdone = chan->mbox->ops->last_tx_done(chan); | 129 | txdone = chan->mbox->ops->last_tx_done(chan); |
| 130 | if (txdone) | 130 | if (txdone) |
| 131 | tx_tick(chan, 0); | 131 | tx_tick(chan, 0); |
| 132 | else | ||
| 133 | resched = true; | ||
| 132 | } | 134 | } |
| 133 | } | 135 | } |
| 134 | 136 | ||
| 135 | if (resched) { | 137 | 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 | |||
| 137 | return HRTIMER_RESTART; | 143 | return HRTIMER_RESTART; |
| 138 | } | 144 | } |
| 139 | return HRTIMER_NORESTART; | 145 | return HRTIMER_NORESTART; |
| @@ -500,6 +506,7 @@ int mbox_controller_register(struct mbox_controller *mbox) · 360 unmodified lines | |||
| 500 | hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC, | 506 | hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC, |
| 501 | HRTIMER_MODE_REL); | 507 | HRTIMER_MODE_REL); |
| 502 | mbox->poll_hrt.function = txdone_hrtimer; | 508 | mbox->poll_hrt.function = txdone_hrtimer; |
| 509 | spin_lock_init(&mbox->poll_hrt_lock); | ||
| 503 | } | 510 | } |
| 504 | 511 | ||
| 505 | for (i = 0; i < mbox->num_chans; i++) { | 512 | for (i = 0; i < mbox->num_chans; i++) { |
| @@ -83,6 +83,7 @@ struct mbox_controller { · 82 unmodified lines | |||
| 83 | const struct of_phandle_args *sp); | 83 | const struct of_phandle_args *sp); |
| 84 | /* Internal to API */ | 84 | /* Internal to API */ |
| 85 | struct hrtimer poll_hrt; | 85 | struct hrtimer poll_hrt; |
| 86 | spinlock_t poll_hrt_lock; | ||
| 86 | struct list_head node; | 87 | struct list_head node; |
| 87 | }; | 88 | }; |
| 88 | 89 | ||