Commit a08ca5d1 authored by Stephen Boyd's avatar Stephen Boyd Committed by John Stultz

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: default avatarStephen Boyd <sboyd@codeaurora.org>
[jstultz: Fixup hrtimer intitialization order issue]
Signed-off-by: default avatarJohn Stultz <john.stultz@linaro.org>
parent 85c3d2dd
...@@ -8,15 +8,17 @@ ...@@ -8,15 +8,17 @@
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/ktime.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/timer.h> #include <linux/hrtimer.h>
#include <linux/sched_clock.h> #include <linux/sched_clock.h>
#include <linux/seqlock.h> #include <linux/seqlock.h>
struct clock_data { struct clock_data {
ktime_t wrap_kt;
u64 epoch_ns; u64 epoch_ns;
u32 epoch_cyc; u32 epoch_cyc;
seqcount_t seq; seqcount_t seq;
...@@ -26,8 +28,7 @@ struct clock_data { ...@@ -26,8 +28,7 @@ struct clock_data {
bool suspended; bool suspended;
}; };
static void sched_clock_poll(unsigned long wrap_ticks); static struct hrtimer sched_clock_timer;
static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0);
static int irqtime = -1; static int irqtime = -1;
core_param(irqtime, irqtime, int, 0400); core_param(irqtime, irqtime, int, 0400);
...@@ -93,15 +94,16 @@ static void notrace update_sched_clock(void) ...@@ -93,15 +94,16 @@ static void notrace update_sched_clock(void)
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
} }
static void sched_clock_poll(unsigned long wrap_ticks) static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
{ {
mod_timer(&sched_clock_timer, round_jiffies(jiffies + wrap_ticks));
update_sched_clock(); update_sched_clock();
hrtimer_forward_now(hrt, cd.wrap_kt);
return HRTIMER_RESTART;
} }
void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
{ {
unsigned long r, w; unsigned long r;
u64 res, wrap; u64 res, wrap;
char r_unit; char r_unit;
...@@ -129,19 +131,13 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate) ...@@ -129,19 +131,13 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
/* calculate how many ns until we wrap */ /* calculate how many ns until we wrap */
wrap = cyc_to_ns((1ULL << bits) - 1, cd.mult, cd.shift); wrap = cyc_to_ns((1ULL << bits) - 1, cd.mult, cd.shift);
do_div(wrap, NSEC_PER_MSEC); cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
w = wrap;
/* calculate the ns resolution of this counter */ /* calculate the ns resolution of this counter */
res = cyc_to_ns(1ULL, cd.mult, cd.shift); res = cyc_to_ns(1ULL, cd.mult, cd.shift);
pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lums\n", pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
bits, r, r_unit, res, w); bits, r, r_unit, res, wrap);
/*
* Start the timer to keep sched_clock() properly updated and
* sets the initial epoch.
*/
sched_clock_timer.data = msecs_to_jiffies(w - (w / 10));
update_sched_clock(); update_sched_clock();
/* /*
...@@ -172,12 +168,20 @@ void __init sched_clock_postinit(void) ...@@ -172,12 +168,20 @@ void __init sched_clock_postinit(void)
if (read_sched_clock == jiffy_sched_clock_read) if (read_sched_clock == jiffy_sched_clock_read)
setup_sched_clock(jiffy_sched_clock_read, 32, HZ); setup_sched_clock(jiffy_sched_clock_read, 32, HZ);
sched_clock_poll(sched_clock_timer.data); update_sched_clock();
/*
* Start the timer to keep sched_clock() properly updated and
* sets the initial epoch.
*/
hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sched_clock_timer.function = sched_clock_poll;
hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
} }
static int sched_clock_suspend(void) static int sched_clock_suspend(void)
{ {
sched_clock_poll(sched_clock_timer.data); sched_clock_poll(&sched_clock_timer);
cd.suspended = true; cd.suspended = true;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment