Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mailbox: switch to hrtimer for tx_complete polling

The mailbox core uses jiffy based timer to handle polling for the
transmit completion. If the client/protocol have/support notification
of the last packet transmit completion via ACK packet, then we tick the
Tx state machine immediately in the callback. However if the client
doesn't support that mechanism we might end-up waiting for atleast a
jiffy even though the remote is ready to receive the next request.

This patch switches the timer used for that polling from jiffy-based
to hrtimer-based so that we can support polling at much higher time
resolution.

Reported-and-suggested-by: Juri Lelli <Juri.Lelli@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>

authored by

Sudeep Holla and committed by
Jassi Brar
0cc67945 63d5e127

+19 -15
+15 -12
drivers/mailbox/mailbox.c
··· 26 26 static LIST_HEAD(mbox_cons); 27 27 static DEFINE_MUTEX(con_mutex); 28 28 29 - static void poll_txdone(unsigned long data); 30 - 31 29 static int add_to_rbuf(struct mbox_chan *chan, void *mssg) 32 30 { 33 31 int idx; ··· 86 88 spin_unlock_irqrestore(&chan->lock, flags); 87 89 88 90 if (!err && (chan->txdone_method & TXDONE_BY_POLL)) 89 - poll_txdone((unsigned long)chan->mbox); 91 + /* kick start the timer immediately to avoid delays */ 92 + hrtimer_start(&chan->mbox->poll_hrt, ktime_set(0, 0), 93 + HRTIMER_MODE_REL); 90 94 } 91 95 92 96 static void tx_tick(struct mbox_chan *chan, int r) ··· 112 112 complete(&chan->tx_complete); 113 113 } 114 114 115 - static void poll_txdone(unsigned long data) 115 + static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) 116 116 { 117 - struct mbox_controller *mbox = (struct mbox_controller *)data; 117 + struct mbox_controller *mbox = 118 + container_of(hrtimer, struct mbox_controller, poll_hrt); 118 119 bool txdone, resched = false; 119 120 int i; 120 121 ··· 131 130 } 132 131 } 133 132 134 - if (resched) 135 - mod_timer(&mbox->poll, jiffies + 136 - msecs_to_jiffies(mbox->txpoll_period)); 133 + if (resched) { 134 + hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period)); 135 + return HRTIMER_RESTART; 136 + } 137 + return HRTIMER_NORESTART; 137 138 } 138 139 139 140 /** ··· 454 451 txdone = TXDONE_BY_ACK; 455 452 456 453 if (txdone == TXDONE_BY_POLL) { 457 - mbox->poll.function = &poll_txdone; 458 - mbox->poll.data = (unsigned long)mbox; 459 - init_timer(&mbox->poll); 454 + hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC, 455 + HRTIMER_MODE_REL); 456 + mbox->poll_hrt.function = txdone_hrtimer; 460 457 } 461 458 462 459 for (i = 0; i < mbox->num_chans; i++) { ··· 498 495 mbox_free_channel(&mbox->chans[i]); 499 496 500 497 if (mbox->txdone_poll) 501 - del_timer_sync(&mbox->poll); 498 + hrtimer_cancel(&mbox->poll_hrt); 502 499 503 500 mutex_unlock(&con_mutex); 504 501 }
+4 -3
include/linux/mailbox_controller.h
··· 9 9 10 10 #include <linux/of.h> 11 11 #include <linux/types.h> 12 - #include <linux/timer.h> 12 + #include <linux/hrtimer.h> 13 13 #include <linux/device.h> 14 14 #include <linux/completion.h> 15 15 ··· 67 67 * @txpoll_period: If 'txdone_poll' is in effect, the API polls for 68 68 * last TX's status after these many millisecs 69 69 * @of_xlate: Controller driver specific mapping of channel via DT 70 - * @poll: API private. Used to poll for TXDONE on all channels. 70 + * @poll_hrt: API private. hrtimer used to poll for TXDONE on all 71 + * channels. 71 72 * @node: API private. To hook into list of controllers. 72 73 */ 73 74 struct mbox_controller { ··· 82 81 struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox, 83 82 const struct of_phandle_args *sp); 84 83 /* Internal to API */ 85 - struct timer_list poll; 84 + struct hrtimer poll_hrt; 86 85 struct list_head node; 87 86 }; 88 87