aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/clockchips.h
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2015-04-02 23:34:04 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-05-19 10:18:02 -0400
commit8fff52fd50934580c5108afed12043a774edf728 (patch)
tree4dc2f8bf4790a3497bdad649ccb4037dd7236165 /include/linux/clockchips.h
parentc3b5d3cea508d2c8ff493ef18c45a9cc58fb7015 (diff)
clockevents: Introduce CLOCK_EVT_STATE_ONESHOT_STOPPED state
When no timers/hrtimers are pending, the expiry time is set to a special value: 'KTIME_MAX'. This normally happens with NO_HZ_{IDLE|FULL} in both LOWRES/HIGHRES modes. When 'expiry == KTIME_MAX', we either cancel the 'tick-sched' hrtimer (NOHZ_MODE_HIGHRES) or skip reprogramming clockevent device (NOHZ_MODE_LOWRES). But, the clockevent device is already reprogrammed from the tick-handler for next tick. As the clock event device is programmed in ONESHOT mode it will at least fire one more time (unnecessarily). Timers on few implementations (like arm_arch_timer, etc.) only support PERIODIC mode and their drivers emulate ONESHOT over that. Which means that on these platforms we will get spurious interrupts periodically (at last programmed interval rate, normally tick rate). In order to avoid spurious interrupts, the clockevent device should be stopped or its interrupts should be masked. A simple (yet hacky) solution to get this fixed could be: update hrtimer_force_reprogram() to always reprogram clockevent device and update clockevent drivers to STOP generating events (or delay it to max time) when 'expires' is set to KTIME_MAX. But the drawback here is that every clockevent driver has to be hacked for this particular case and its very easy for new ones to miss this. However, Thomas suggested to add an optional state ONESHOT_STOPPED to solve this problem: lkml.org/lkml/2014/5/9/508. This patch adds support for ONESHOT_STOPPED state in clockevents core. It will only be available to drivers that implement the state-specific callbacks instead of the legacy ->set_mode() callback. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Preeti U. Murthy <preeti@linux.vnet.ibm.com> Cc: linaro-kernel@lists.linaro.org Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Kevin Hilman <khilman@linaro.org> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/b8b383a03ac07b13312c16850b5106b82e4245b5.1428031396.git.viresh.kumar@linaro.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'include/linux/clockchips.h')
-rw-r--r--include/linux/clockchips.h7
1 files changed, 6 insertions, 1 deletions
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 96c280b2c263..271fa4c8eb29 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -37,12 +37,15 @@ enum clock_event_mode {
37 * reached from DETACHED or SHUTDOWN. 37 * reached from DETACHED or SHUTDOWN.
38 * ONESHOT: Device is programmed to generate event only once. Can be reached 38 * ONESHOT: Device is programmed to generate event only once. Can be reached
39 * from DETACHED or SHUTDOWN. 39 * from DETACHED or SHUTDOWN.
40 * ONESHOT_STOPPED: Device was programmed in ONESHOT mode and is temporarily
41 * stopped.
40 */ 42 */
41enum clock_event_state { 43enum clock_event_state {
42 CLOCK_EVT_STATE_DETACHED, 44 CLOCK_EVT_STATE_DETACHED,
43 CLOCK_EVT_STATE_SHUTDOWN, 45 CLOCK_EVT_STATE_SHUTDOWN,
44 CLOCK_EVT_STATE_PERIODIC, 46 CLOCK_EVT_STATE_PERIODIC,
45 CLOCK_EVT_STATE_ONESHOT, 47 CLOCK_EVT_STATE_ONESHOT,
48 CLOCK_EVT_STATE_ONESHOT_STOPPED,
46}; 49};
47 50
48/* 51/*
@@ -90,6 +93,7 @@ enum clock_event_state {
90 * @set_mode: legacy set mode function, only for modes <= CLOCK_EVT_MODE_RESUME. 93 * @set_mode: legacy set mode function, only for modes <= CLOCK_EVT_MODE_RESUME.
91 * @set_state_periodic: switch state to periodic, if !set_mode 94 * @set_state_periodic: switch state to periodic, if !set_mode
92 * @set_state_oneshot: switch state to oneshot, if !set_mode 95 * @set_state_oneshot: switch state to oneshot, if !set_mode
96 * @set_state_oneshot_stopped: switch state to oneshot_stopped, if !set_mode
93 * @set_state_shutdown: switch state to shutdown, if !set_mode 97 * @set_state_shutdown: switch state to shutdown, if !set_mode
94 * @tick_resume: resume clkevt device, if !set_mode 98 * @tick_resume: resume clkevt device, if !set_mode
95 * @broadcast: function to broadcast events 99 * @broadcast: function to broadcast events
@@ -121,11 +125,12 @@ struct clock_event_device {
121 * State transition callback(s): Only one of the two groups should be 125 * State transition callback(s): Only one of the two groups should be
122 * defined: 126 * defined:
123 * - set_mode(), only for modes <= CLOCK_EVT_MODE_RESUME. 127 * - set_mode(), only for modes <= CLOCK_EVT_MODE_RESUME.
124 * - set_state_{shutdown|periodic|oneshot}(), tick_resume(). 128 * - set_state_{shutdown|periodic|oneshot|oneshot_stopped}(), tick_resume().
125 */ 129 */
126 void (*set_mode)(enum clock_event_mode mode, struct clock_event_device *); 130 void (*set_mode)(enum clock_event_mode mode, struct clock_event_device *);
127 int (*set_state_periodic)(struct clock_event_device *); 131 int (*set_state_periodic)(struct clock_event_device *);
128 int (*set_state_oneshot)(struct clock_event_device *); 132 int (*set_state_oneshot)(struct clock_event_device *);
133 int (*set_state_oneshot_stopped)(struct clock_event_device *);
129 int (*set_state_shutdown)(struct clock_event_device *); 134 int (*set_state_shutdown)(struct clock_event_device *);
130 int (*tick_resume)(struct clock_event_device *); 135 int (*tick_resume)(struct clock_event_device *);
131 136