diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2013-07-18 19:21:16 -0400 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2013-07-30 14:24:20 -0400 |
commit | a08ca5d1089da03724f96fa0870c64968e66765b (patch) | |
tree | 763e988f9f4d412681f2859bc12370edbfe565de /kernel/time | |
parent | 85c3d2dd15be4d577a37ffb8bbbd019fc8e3280a (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.c | 38 |
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 | ||
19 | struct clock_data { | 20 | struct 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 | ||
29 | static void sched_clock_poll(unsigned long wrap_ticks); | 31 | static struct hrtimer sched_clock_timer; |
30 | static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0); | ||
31 | static int irqtime = -1; | 32 | static int irqtime = -1; |
32 | 33 | ||
33 | core_param(irqtime, irqtime, int, 0400); | 34 | core_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 | ||
96 | static void sched_clock_poll(unsigned long wrap_ticks) | 97 | static 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 | ||
102 | void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) | 104 | void __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 | ||
178 | static int sched_clock_suspend(void) | 182 | static 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 | } |