aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2013-07-18 19:21:16 -0400
committerJohn Stultz <john.stultz@linaro.org>2013-07-30 14:24:20 -0400
commita08ca5d1089da03724f96fa0870c64968e66765b (patch)
tree763e988f9f4d412681f2859bc12370edbfe565de /kernel/time
parent85c3d2dd15be4d577a37ffb8bbbd019fc8e3280a (diff)
sched_clock: Use an hrtimer instead of timer
In the next patch we're going to increase the number of bits that the generic sched_clock can handle to be greater than 32. With more than 32 bits the wraparound time can be larger than what can fit into the units that msecs_to_jiffies takes (unsigned int). Luckily, the wraparound is initially calculated in nanoseconds which we can easily use with hrtimers, so switch to using an hrtimer. Cc: Russell King <linux@arm.linux.org.uk> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> [jstultz: Fixup hrtimer intitialization order issue] Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'kernel/time')
-rw-r--r--kernel/time/sched_clock.c38
1 files changed, 21 insertions, 17 deletions
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index 396f7b9dccc9..c018ffc59937 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -8,15 +8,17 @@
8#include <linux/clocksource.h> 8#include <linux/clocksource.h>
9#include <linux/init.h> 9#include <linux/init.h>
10#include <linux/jiffies.h> 10#include <linux/jiffies.h>
11#include <linux/ktime.h>
11#include <linux/kernel.h> 12#include <linux/kernel.h>
12#include <linux/moduleparam.h> 13#include <linux/moduleparam.h>
13#include <linux/sched.h> 14#include <linux/sched.h>
14#include <linux/syscore_ops.h> 15#include <linux/syscore_ops.h>
15#include <linux/timer.h> 16#include <linux/hrtimer.h>
16#include <linux/sched_clock.h> 17#include <linux/sched_clock.h>
17#include <linux/seqlock.h> 18#include <linux/seqlock.h>
18 19
19struct clock_data { 20struct clock_data {
21 ktime_t wrap_kt;
20 u64 epoch_ns; 22 u64 epoch_ns;
21 u32 epoch_cyc; 23 u32 epoch_cyc;
22 seqcount_t seq; 24 seqcount_t seq;
@@ -26,8 +28,7 @@ struct clock_data {
26 bool suspended; 28 bool suspended;
27}; 29};
28 30
29static void sched_clock_poll(unsigned long wrap_ticks); 31static struct hrtimer sched_clock_timer;
30static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0);
31static int irqtime = -1; 32static int irqtime = -1;
32 33
33core_param(irqtime, irqtime, int, 0400); 34core_param(irqtime, irqtime, int, 0400);
@@ -93,15 +94,16 @@ static void notrace update_sched_clock(void)
93 raw_local_irq_restore(flags); 94 raw_local_irq_restore(flags);
94} 95}
95 96
96static void sched_clock_poll(unsigned long wrap_ticks) 97static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
97{ 98{
98 mod_timer(&sched_clock_timer, round_jiffies(jiffies + wrap_ticks));
99 update_sched_clock(); 99 update_sched_clock();
100 hrtimer_forward_now(hrt, cd.wrap_kt);
101 return HRTIMER_RESTART;
100} 102}
101 103
102void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) 104void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
103{ 105{
104 unsigned long r, w; 106 unsigned long r;
105 u64 res, wrap; 107 u64 res, wrap;
106 char r_unit; 108 char r_unit;
107 109
@@ -129,19 +131,13 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
129 131
130 /* calculate how many ns until we wrap */ 132 /* calculate how many ns until we wrap */
131 wrap = cyc_to_ns((1ULL << bits) - 1, cd.mult, cd.shift); 133 wrap = cyc_to_ns((1ULL << bits) - 1, cd.mult, cd.shift);
132 do_div(wrap, NSEC_PER_MSEC); 134 cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
133 w = wrap;
134 135
135 /* calculate the ns resolution of this counter */ 136 /* calculate the ns resolution of this counter */
136 res = cyc_to_ns(1ULL, cd.mult, cd.shift); 137 res = cyc_to_ns(1ULL, cd.mult, cd.shift);
137 pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lums\n", 138 pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
138 bits, r, r_unit, res, w); 139 bits, r, r_unit, res, wrap);
139 140
140 /*
141 * Start the timer to keep sched_clock() properly updated and
142 * sets the initial epoch.
143 */
144 sched_clock_timer.data = msecs_to_jiffies(w - (w / 10));
145 update_sched_clock(); 141 update_sched_clock();
146 142
147 /* 143 /*
@@ -172,12 +168,20 @@ void __init sched_clock_postinit(void)
172 if (read_sched_clock == jiffy_sched_clock_read) 168 if (read_sched_clock == jiffy_sched_clock_read)
173 setup_sched_clock(jiffy_sched_clock_read, 32, HZ); 169 setup_sched_clock(jiffy_sched_clock_read, 32, HZ);
174 170
175 sched_clock_poll(sched_clock_timer.data); 171 update_sched_clock();
172
173 /*
174 * Start the timer to keep sched_clock() properly updated and
175 * sets the initial epoch.
176 */
177 hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
178 sched_clock_timer.function = sched_clock_poll;
179 hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
176} 180}
177 181
178static int sched_clock_suspend(void) 182static int sched_clock_suspend(void)
179{ 183{
180 sched_clock_poll(sched_clock_timer.data); 184 sched_clock_poll(&sched_clock_timer);
181 cd.suspended = true; 185 cd.suspended = true;
182 return 0; 186 return 0;
183} 187}