Commit 4e6d7c2a authored by Ingo Molnar's avatar Ingo Molnar

Merge branch 'timers/core' into perf/timer, to apply dependent patch

An upcoming patch will depend on tai_ns() and NMI-safe ktime_get_raw_fast(),
so merge timers/core here in a separate topic branch until it's all cooked
and timers/core is merged upstream.
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 3c435c1e fe5fba05
...@@ -103,7 +103,7 @@ int __init omap_init_clocksource_32k(void __iomem *vbase) ...@@ -103,7 +103,7 @@ int __init omap_init_clocksource_32k(void __iomem *vbase)
/* /*
* 120000 rough estimate from the calculations in * 120000 rough estimate from the calculations in
* __clocksource_updatefreq_scale. * __clocksource_update_freq_scale.
*/ */
clocks_calc_mult_shift(&persistent_mult, &persistent_shift, clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
32768, NSEC_PER_SEC, 120000); 32768, NSEC_PER_SEC, 120000);
......
...@@ -200,7 +200,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, ...@@ -200,7 +200,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
void update_vsyscall(struct timekeeper *tk) void update_vsyscall(struct timekeeper *tk)
{ {
struct timespec xtime_coarse; struct timespec xtime_coarse;
u32 use_syscall = strcmp(tk->tkr.clock->name, "arch_sys_counter"); u32 use_syscall = strcmp(tk->tkr_mono.clock->name, "arch_sys_counter");
++vdso_data->tb_seq_count; ++vdso_data->tb_seq_count;
smp_wmb(); smp_wmb();
...@@ -213,11 +213,11 @@ void update_vsyscall(struct timekeeper *tk) ...@@ -213,11 +213,11 @@ void update_vsyscall(struct timekeeper *tk)
vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec;
if (!use_syscall) { if (!use_syscall) {
vdso_data->cs_cycle_last = tk->tkr.cycle_last; vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last;
vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_sec = tk->xtime_sec;
vdso_data->xtime_clock_nsec = tk->tkr.xtime_nsec; vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec;
vdso_data->cs_mult = tk->tkr.mult; vdso_data->cs_mult = tk->tkr_mono.mult;
vdso_data->cs_shift = tk->tkr.shift; vdso_data->cs_shift = tk->tkr_mono.shift;
} }
smp_wmb(); smp_wmb();
......
...@@ -215,20 +215,20 @@ void update_vsyscall(struct timekeeper *tk) ...@@ -215,20 +215,20 @@ void update_vsyscall(struct timekeeper *tk)
{ {
u64 nsecps; u64 nsecps;
if (tk->tkr.clock != &clocksource_tod) if (tk->tkr_mono.clock != &clocksource_tod)
return; return;
/* Make userspace gettimeofday spin until we're done. */ /* Make userspace gettimeofday spin until we're done. */
++vdso_data->tb_update_count; ++vdso_data->tb_update_count;
smp_wmb(); smp_wmb();
vdso_data->xtime_tod_stamp = tk->tkr.cycle_last; vdso_data->xtime_tod_stamp = tk->tkr_mono.cycle_last;
vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_sec = tk->xtime_sec;
vdso_data->xtime_clock_nsec = tk->tkr.xtime_nsec; vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec;
vdso_data->wtom_clock_sec = vdso_data->wtom_clock_sec =
tk->xtime_sec + tk->wall_to_monotonic.tv_sec; tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
vdso_data->wtom_clock_nsec = tk->tkr.xtime_nsec + vdso_data->wtom_clock_nsec = tk->tkr_mono.xtime_nsec +
+ ((u64) tk->wall_to_monotonic.tv_nsec << tk->tkr.shift); + ((u64) tk->wall_to_monotonic.tv_nsec << tk->tkr_mono.shift);
nsecps = (u64) NSEC_PER_SEC << tk->tkr.shift; nsecps = (u64) NSEC_PER_SEC << tk->tkr_mono.shift;
while (vdso_data->wtom_clock_nsec >= nsecps) { while (vdso_data->wtom_clock_nsec >= nsecps) {
vdso_data->wtom_clock_nsec -= nsecps; vdso_data->wtom_clock_nsec -= nsecps;
vdso_data->wtom_clock_sec++; vdso_data->wtom_clock_sec++;
...@@ -236,7 +236,7 @@ void update_vsyscall(struct timekeeper *tk) ...@@ -236,7 +236,7 @@ void update_vsyscall(struct timekeeper *tk)
vdso_data->xtime_coarse_sec = tk->xtime_sec; vdso_data->xtime_coarse_sec = tk->xtime_sec;
vdso_data->xtime_coarse_nsec = vdso_data->xtime_coarse_nsec =
(long)(tk->tkr.xtime_nsec >> tk->tkr.shift); (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
vdso_data->wtom_coarse_sec = vdso_data->wtom_coarse_sec =
vdso_data->xtime_coarse_sec + tk->wall_to_monotonic.tv_sec; vdso_data->xtime_coarse_sec + tk->wall_to_monotonic.tv_sec;
vdso_data->wtom_coarse_nsec = vdso_data->wtom_coarse_nsec =
...@@ -246,8 +246,8 @@ void update_vsyscall(struct timekeeper *tk) ...@@ -246,8 +246,8 @@ void update_vsyscall(struct timekeeper *tk)
vdso_data->wtom_coarse_sec++; vdso_data->wtom_coarse_sec++;
} }
vdso_data->tk_mult = tk->tkr.mult; vdso_data->tk_mult = tk->tkr_mono.mult;
vdso_data->tk_shift = tk->tkr.shift; vdso_data->tk_shift = tk->tkr_mono.shift;
smp_wmb(); smp_wmb();
++vdso_data->tb_update_count; ++vdso_data->tb_update_count;
} }
...@@ -283,7 +283,7 @@ void __init time_init(void) ...@@ -283,7 +283,7 @@ void __init time_init(void)
if (register_external_irq(EXT_IRQ_TIMING_ALERT, timing_alert_interrupt)) if (register_external_irq(EXT_IRQ_TIMING_ALERT, timing_alert_interrupt))
panic("Couldn't request external interrupt 0x1406"); panic("Couldn't request external interrupt 0x1406");
if (clocksource_register(&clocksource_tod) != 0) if (__clocksource_register(&clocksource_tod) != 0)
panic("Could not register TOD clock source"); panic("Could not register TOD clock source");
/* Enable TOD clock interrupts on the boot cpu. */ /* Enable TOD clock interrupts on the boot cpu. */
......
...@@ -181,17 +181,13 @@ static struct clocksource timer_cs = { ...@@ -181,17 +181,13 @@ static struct clocksource timer_cs = {
.rating = 100, .rating = 100,
.read = timer_cs_read, .read = timer_cs_read,
.mask = CLOCKSOURCE_MASK(64), .mask = CLOCKSOURCE_MASK(64),
.shift = 2,
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
static __init int setup_timer_cs(void) static __init int setup_timer_cs(void)
{ {
timer_cs_enabled = 1; timer_cs_enabled = 1;
timer_cs.mult = clocksource_hz2mult(sparc_config.clock_rate, return clocksource_register_hz(&timer_cs, sparc_config.clock_rate);
timer_cs.shift);
return clocksource_register(&timer_cs);
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
......
...@@ -257,34 +257,34 @@ void update_vsyscall_tz(void) ...@@ -257,34 +257,34 @@ void update_vsyscall_tz(void)
void update_vsyscall(struct timekeeper *tk) void update_vsyscall(struct timekeeper *tk)
{ {
if (tk->tkr.clock != &cycle_counter_cs) if (tk->tkr_mono.clock != &cycle_counter_cs)
return; return;
write_seqcount_begin(&vdso_data->tb_seq); write_seqcount_begin(&vdso_data->tb_seq);
vdso_data->cycle_last = tk->tkr.cycle_last; vdso_data->cycle_last = tk->tkr_mono.cycle_last;
vdso_data->mask = tk->tkr.mask; vdso_data->mask = tk->tkr_mono.mask;
vdso_data->mult = tk->tkr.mult; vdso_data->mult = tk->tkr_mono.mult;
vdso_data->shift = tk->tkr.shift; vdso_data->shift = tk->tkr_mono.shift;
vdso_data->wall_time_sec = tk->xtime_sec; vdso_data->wall_time_sec = tk->xtime_sec;
vdso_data->wall_time_snsec = tk->tkr.xtime_nsec; vdso_data->wall_time_snsec = tk->tkr_mono.xtime_nsec;
vdso_data->monotonic_time_sec = tk->xtime_sec vdso_data->monotonic_time_sec = tk->xtime_sec
+ tk->wall_to_monotonic.tv_sec; + tk->wall_to_monotonic.tv_sec;
vdso_data->monotonic_time_snsec = tk->tkr.xtime_nsec vdso_data->monotonic_time_snsec = tk->tkr_mono.xtime_nsec
+ ((u64)tk->wall_to_monotonic.tv_nsec + ((u64)tk->wall_to_monotonic.tv_nsec
<< tk->tkr.shift); << tk->tkr_mono.shift);
while (vdso_data->monotonic_time_snsec >= while (vdso_data->monotonic_time_snsec >=
(((u64)NSEC_PER_SEC) << tk->tkr.shift)) { (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
vdso_data->monotonic_time_snsec -= vdso_data->monotonic_time_snsec -=
((u64)NSEC_PER_SEC) << tk->tkr.shift; ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift;
vdso_data->monotonic_time_sec++; vdso_data->monotonic_time_sec++;
} }
vdso_data->wall_time_coarse_sec = tk->xtime_sec; vdso_data->wall_time_coarse_sec = tk->xtime_sec;
vdso_data->wall_time_coarse_nsec = (long)(tk->tkr.xtime_nsec >> vdso_data->wall_time_coarse_nsec = (long)(tk->tkr_mono.xtime_nsec >>
tk->tkr.shift); tk->tkr_mono.shift);
vdso_data->monotonic_time_coarse_sec = vdso_data->monotonic_time_coarse_sec =
vdso_data->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; vdso_data->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec;
......
...@@ -31,30 +31,30 @@ void update_vsyscall(struct timekeeper *tk) ...@@ -31,30 +31,30 @@ void update_vsyscall(struct timekeeper *tk)
gtod_write_begin(vdata); gtod_write_begin(vdata);
/* copy vsyscall data */ /* copy vsyscall data */
vdata->vclock_mode = tk->tkr.clock->archdata.vclock_mode; vdata->vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode;
vdata->cycle_last = tk->tkr.cycle_last; vdata->cycle_last = tk->tkr_mono.cycle_last;
vdata->mask = tk->tkr.mask; vdata->mask = tk->tkr_mono.mask;
vdata->mult = tk->tkr.mult; vdata->mult = tk->tkr_mono.mult;
vdata->shift = tk->tkr.shift; vdata->shift = tk->tkr_mono.shift;
vdata->wall_time_sec = tk->xtime_sec; vdata->wall_time_sec = tk->xtime_sec;
vdata->wall_time_snsec = tk->tkr.xtime_nsec; vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec;
vdata->monotonic_time_sec = tk->xtime_sec vdata->monotonic_time_sec = tk->xtime_sec
+ tk->wall_to_monotonic.tv_sec; + tk->wall_to_monotonic.tv_sec;
vdata->monotonic_time_snsec = tk->tkr.xtime_nsec vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec
+ ((u64)tk->wall_to_monotonic.tv_nsec + ((u64)tk->wall_to_monotonic.tv_nsec
<< tk->tkr.shift); << tk->tkr_mono.shift);
while (vdata->monotonic_time_snsec >= while (vdata->monotonic_time_snsec >=
(((u64)NSEC_PER_SEC) << tk->tkr.shift)) { (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
vdata->monotonic_time_snsec -= vdata->monotonic_time_snsec -=
((u64)NSEC_PER_SEC) << tk->tkr.shift; ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift;
vdata->monotonic_time_sec++; vdata->monotonic_time_sec++;
} }
vdata->wall_time_coarse_sec = tk->xtime_sec; vdata->wall_time_coarse_sec = tk->xtime_sec;
vdata->wall_time_coarse_nsec = (long)(tk->tkr.xtime_nsec >> vdata->wall_time_coarse_nsec = (long)(tk->tkr_mono.xtime_nsec >>
tk->tkr.shift); tk->tkr_mono.shift);
vdata->monotonic_time_coarse_sec = vdata->monotonic_time_coarse_sec =
vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec;
......
...@@ -1070,19 +1070,19 @@ static void update_pvclock_gtod(struct timekeeper *tk) ...@@ -1070,19 +1070,19 @@ static void update_pvclock_gtod(struct timekeeper *tk)
struct pvclock_gtod_data *vdata = &pvclock_gtod_data; struct pvclock_gtod_data *vdata = &pvclock_gtod_data;
u64 boot_ns; u64 boot_ns;
boot_ns = ktime_to_ns(ktime_add(tk->tkr.base_mono, tk->offs_boot)); boot_ns = ktime_to_ns(ktime_add(tk->tkr_mono.base, tk->offs_boot));
write_seqcount_begin(&vdata->seq); write_seqcount_begin(&vdata->seq);
/* copy pvclock gtod data */ /* copy pvclock gtod data */
vdata->clock.vclock_mode = tk->tkr.clock->archdata.vclock_mode; vdata->clock.vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode;
vdata->clock.cycle_last = tk->tkr.cycle_last; vdata->clock.cycle_last = tk->tkr_mono.cycle_last;
vdata->clock.mask = tk->tkr.mask; vdata->clock.mask = tk->tkr_mono.mask;
vdata->clock.mult = tk->tkr.mult; vdata->clock.mult = tk->tkr_mono.mult;
vdata->clock.shift = tk->tkr.shift; vdata->clock.shift = tk->tkr_mono.shift;
vdata->boot_ns = boot_ns; vdata->boot_ns = boot_ns;
vdata->nsec_base = tk->tkr.xtime_nsec; vdata->nsec_base = tk->tkr_mono.xtime_nsec;
write_seqcount_end(&vdata->seq); write_seqcount_end(&vdata->seq);
} }
......
...@@ -210,7 +210,7 @@ static int em_sti_clocksource_enable(struct clocksource *cs) ...@@ -210,7 +210,7 @@ static int em_sti_clocksource_enable(struct clocksource *cs)
ret = em_sti_start(p, USER_CLOCKSOURCE); ret = em_sti_start(p, USER_CLOCKSOURCE);
if (!ret) if (!ret)
__clocksource_updatefreq_hz(cs, p->rate); __clocksource_update_freq_hz(cs, p->rate);
return ret; return ret;
} }
......
...@@ -641,7 +641,7 @@ static int sh_cmt_clocksource_enable(struct clocksource *cs) ...@@ -641,7 +641,7 @@ static int sh_cmt_clocksource_enable(struct clocksource *cs)
ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE); ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE);
if (!ret) { if (!ret) {
__clocksource_updatefreq_hz(cs, ch->rate); __clocksource_update_freq_hz(cs, ch->rate);
ch->cs_enabled = true; ch->cs_enabled = true;
} }
return ret; return ret;
......
...@@ -272,7 +272,7 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs) ...@@ -272,7 +272,7 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs)
ret = sh_tmu_enable(ch); ret = sh_tmu_enable(ch);
if (!ret) { if (!ret) {
__clocksource_updatefreq_hz(cs, ch->rate); __clocksource_update_freq_hz(cs, ch->rate);
ch->cs_enabled = true; ch->cs_enabled = true;
} }
......
...@@ -39,6 +39,8 @@ enum clock_event_mode { ...@@ -39,6 +39,8 @@ enum clock_event_mode {
CLOCK_EVT_MODE_PERIODIC, CLOCK_EVT_MODE_PERIODIC,
CLOCK_EVT_MODE_ONESHOT, CLOCK_EVT_MODE_ONESHOT,
CLOCK_EVT_MODE_RESUME, CLOCK_EVT_MODE_RESUME,
/* Legacy ->set_mode() callback doesn't support below modes */
}; };
/* /*
...@@ -81,7 +83,11 @@ enum clock_event_mode { ...@@ -81,7 +83,11 @@ enum clock_event_mode {
* @mode: operating mode assigned by the management code * @mode: operating mode assigned by the management code
* @features: features * @features: features
* @retries: number of forced programming retries * @retries: number of forced programming retries
* @set_mode: set mode function * @set_mode: legacy set mode function, only for modes <= CLOCK_EVT_MODE_RESUME.
* @set_mode_periodic: switch mode to periodic, if !set_mode
* @set_mode_oneshot: switch mode to oneshot, if !set_mode
* @set_mode_shutdown: switch mode to shutdown, if !set_mode
* @set_mode_resume: resume clkevt device, if !set_mode
* @broadcast: function to broadcast events * @broadcast: function to broadcast events
* @min_delta_ticks: minimum delta value in ticks stored for reconfiguration * @min_delta_ticks: minimum delta value in ticks stored for reconfiguration
* @max_delta_ticks: maximum delta value in ticks stored for reconfiguration * @max_delta_ticks: maximum delta value in ticks stored for reconfiguration
...@@ -108,9 +114,20 @@ struct clock_event_device { ...@@ -108,9 +114,20 @@ struct clock_event_device {
unsigned int features; unsigned int features;
unsigned long retries; unsigned long retries;
void (*broadcast)(const struct cpumask *mask); /*
* Mode transition callback(s): Only one of the two groups should be
* defined:
* - set_mode(), only for modes <= CLOCK_EVT_MODE_RESUME.
* - set_mode_{shutdown|periodic|oneshot|resume}().
*/
void (*set_mode)(enum clock_event_mode mode, void (*set_mode)(enum clock_event_mode mode,
struct clock_event_device *); struct clock_event_device *);
int (*set_mode_periodic)(struct clock_event_device *);
int (*set_mode_oneshot)(struct clock_event_device *);
int (*set_mode_shutdown)(struct clock_event_device *);
int (*set_mode_resume)(struct clock_event_device *);
void (*broadcast)(const struct cpumask *mask);
void (*suspend)(struct clock_event_device *); void (*suspend)(struct clock_event_device *);
void (*resume)(struct clock_event_device *); void (*resume)(struct clock_event_device *);
unsigned long min_delta_ticks; unsigned long min_delta_ticks;
......
...@@ -56,6 +56,7 @@ struct module; ...@@ -56,6 +56,7 @@ struct module;
* @shift: cycle to nanosecond divisor (power of two) * @shift: cycle to nanosecond divisor (power of two)
* @max_idle_ns: max idle time permitted by the clocksource (nsecs) * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
* @maxadj: maximum adjustment value to mult (~11%) * @maxadj: maximum adjustment value to mult (~11%)
* @max_cycles: maximum safe cycle value which won't overflow on multiplication
* @flags: flags describing special properties * @flags: flags describing special properties
* @archdata: arch-specific data * @archdata: arch-specific data
* @suspend: suspend function for the clocksource, if necessary * @suspend: suspend function for the clocksource, if necessary
...@@ -76,7 +77,7 @@ struct clocksource { ...@@ -76,7 +77,7 @@ struct clocksource {
#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
struct arch_clocksource_data archdata; struct arch_clocksource_data archdata;
#endif #endif
u64 max_cycles;
const char *name; const char *name;
struct list_head list; struct list_head list;
int rating; int rating;
...@@ -178,7 +179,6 @@ static inline s64 clocksource_cyc2ns(cycle_t cycles, u32 mult, u32 shift) ...@@ -178,7 +179,6 @@ static inline s64 clocksource_cyc2ns(cycle_t cycles, u32 mult, u32 shift)
} }
extern int clocksource_register(struct clocksource*);
extern int clocksource_unregister(struct clocksource*); extern int clocksource_unregister(struct clocksource*);
extern void clocksource_touch_watchdog(void); extern void clocksource_touch_watchdog(void);
extern struct clocksource* clocksource_get_next(void); extern struct clocksource* clocksource_get_next(void);
...@@ -189,7 +189,7 @@ extern struct clocksource * __init clocksource_default_clock(void); ...@@ -189,7 +189,7 @@ extern struct clocksource * __init clocksource_default_clock(void);
extern void clocksource_mark_unstable(struct clocksource *cs); extern void clocksource_mark_unstable(struct clocksource *cs);
extern u64 extern u64
clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask); clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cycles);
extern void extern void
clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec); clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec);
...@@ -200,7 +200,16 @@ clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec); ...@@ -200,7 +200,16 @@ clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec);
extern int extern int
__clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq); __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq);
extern void extern void
__clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq); __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq);
/*
* Don't call this unless you are a default clocksource
* (AKA: jiffies) and absolutely have to.
*/
static inline int __clocksource_register(struct clocksource *cs)
{
return __clocksource_register_scale(cs, 1, 0);
}
static inline int clocksource_register_hz(struct clocksource *cs, u32 hz) static inline int clocksource_register_hz(struct clocksource *cs, u32 hz)
{ {
...@@ -212,14 +221,14 @@ static inline int clocksource_register_khz(struct clocksource *cs, u32 khz) ...@@ -212,14 +221,14 @@ static inline int clocksource_register_khz(struct clocksource *cs, u32 khz)
return __clocksource_register_scale(cs, 1000, khz); return __clocksource_register_scale(cs, 1000, khz);
} }
static inline void __clocksource_updatefreq_hz(struct clocksource *cs, u32 hz) static inline void __clocksource_update_freq_hz(struct clocksource *cs, u32 hz)
{ {
__clocksource_updatefreq_scale(cs, 1, hz); __clocksource_update_freq_scale(cs, 1, hz);
} }
static inline void __clocksource_updatefreq_khz(struct clocksource *cs, u32 khz) static inline void __clocksource_update_freq_khz(struct clocksource *cs, u32 khz)
{ {
__clocksource_updatefreq_scale(cs, 1000, khz); __clocksource_update_freq_scale(cs, 1000, khz);
} }
......
...@@ -16,16 +16,16 @@ ...@@ -16,16 +16,16 @@
* @read: Read function of @clock * @read: Read function of @clock
* @mask: Bitmask for two's complement subtraction of non 64bit clocks * @mask: Bitmask for two's complement subtraction of non 64bit clocks
* @cycle_last: @clock cycle value at last update * @cycle_last: @clock cycle value at last update
* @mult: NTP adjusted multiplier for scaled math conversion * @mult: (NTP adjusted) multiplier for scaled math conversion
* @shift: Shift value for scaled math conversion * @shift: Shift value for scaled math conversion
* @xtime_nsec: Shifted (fractional) nano seconds offset for readout * @xtime_nsec: Shifted (fractional) nano seconds offset for readout
* @base_mono: ktime_t (nanoseconds) base time for readout * @base: ktime_t (nanoseconds) base time for readout
* *
* This struct has size 56 byte on 64 bit. Together with a seqcount it * This struct has size 56 byte on 64 bit. Together with a seqcount it
* occupies a single 64byte cache line. * occupies a single 64byte cache line.
* *
* The struct is separate from struct timekeeper as it is also used * The struct is separate from struct timekeeper as it is also used
* for a fast NMI safe accessor to clock monotonic. * for a fast NMI safe accessors.
*/ */
struct tk_read_base { struct tk_read_base {
struct clocksource *clock; struct clocksource *clock;
...@@ -35,12 +35,13 @@ struct tk_read_base { ...@@ -35,12 +35,13 @@ struct tk_read_base {
u32 mult; u32 mult;
u32 shift; u32 shift;
u64 xtime_nsec; u64 xtime_nsec;
ktime_t base_mono; ktime_t base;
}; };
/** /**
* struct timekeeper - Structure holding internal timekeeping values. * struct timekeeper - Structure holding internal timekeeping values.
* @tkr: The readout base structure * @tkr_mono: The readout base structure for CLOCK_MONOTONIC
* @tkr_raw: The readout base structure for CLOCK_MONOTONIC_RAW
* @xtime_sec: Current CLOCK_REALTIME time in seconds * @xtime_sec: Current CLOCK_REALTIME time in seconds
* @ktime_sec: Current CLOCK_MONOTONIC time in seconds * @ktime_sec: Current CLOCK_MONOTONIC time in seconds
* @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset * @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset
...@@ -48,7 +49,6 @@ struct tk_read_base { ...@@ -48,7 +49,6 @@ struct tk_read_base {
* @offs_boot: Offset clock monotonic -> clock boottime * @offs_boot: Offset clock monotonic -> clock boottime
* @offs_tai: Offset clock monotonic -> clock tai * @offs_tai: Offset clock monotonic -> clock tai
* @tai_offset: The current UTC to TAI offset in seconds * @tai_offset: The current UTC to TAI offset in seconds
* @base_raw: Monotonic raw base time in ktime_t format
* @raw_time: Monotonic raw base time in timespec64 format * @raw_time: Monotonic raw base time in timespec64 format
* @cycle_interval: Number of clock cycles in one NTP interval * @cycle_interval: Number of clock cycles in one NTP interval
* @xtime_interval: Number of clock shifted nano seconds in one NTP * @xtime_interval: Number of clock shifted nano seconds in one NTP
...@@ -76,7 +76,8 @@ struct tk_read_base { ...@@ -76,7 +76,8 @@ struct tk_read_base {
* used instead. * used instead.
*/ */
struct timekeeper { struct timekeeper {
struct tk_read_base tkr; struct tk_read_base tkr_mono;
struct tk_read_base tkr_raw;
u64 xtime_sec; u64 xtime_sec;
unsigned long ktime_sec; unsigned long ktime_sec;
struct timespec64 wall_to_monotonic; struct timespec64 wall_to_monotonic;
...@@ -84,7 +85,6 @@ struct timekeeper { ...@@ -84,7 +85,6 @@ struct timekeeper {
ktime_t offs_boot; ktime_t offs_boot;
ktime_t offs_tai; ktime_t offs_tai;
s32 tai_offset; s32 tai_offset;
ktime_t base_raw;
struct timespec64 raw_time; struct timespec64 raw_time;
/* The following members are for timekeeping internal use */ /* The following members are for timekeeping internal use */
......
...@@ -214,12 +214,18 @@ static inline u64 ktime_get_boot_ns(void) ...@@ -214,12 +214,18 @@ static inline u64 ktime_get_boot_ns(void)
return ktime_to_ns(ktime_get_boottime()); return ktime_to_ns(ktime_get_boottime());
} }
static inline u64 ktime_get_tai_ns(void)
{
return ktime_to_ns(ktime_get_clocktai());
}
static inline u64 ktime_get_raw_ns(void) static inline u64 ktime_get_raw_ns(void)
{ {
return ktime_to_ns(ktime_get_raw()); return ktime_to_ns(ktime_get_raw());
} }
extern u64 ktime_get_mono_fast_ns(void); extern u64 ktime_get_mono_fast_ns(void);
extern u64 ktime_get_raw_fast_ns(void);
/* /*
* Timespec interfaces utilizing the ktime based ones * Timespec interfaces utilizing the ktime based ones
......
...@@ -94,6 +94,57 @@ u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt) ...@@ -94,6 +94,57 @@ u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
} }
EXPORT_SYMBOL_GPL(clockevent_delta2ns); EXPORT_SYMBOL_GPL(clockevent_delta2ns);
static int __clockevents_set_mode(struct clock_event_device *dev,
enum clock_event_mode mode)
{
/* Transition with legacy set_mode() callback */
if (dev->set_mode) {
/* Legacy callback doesn't support new modes */
if (mode > CLOCK_EVT_MODE_RESUME)
return -ENOSYS;
dev->set_mode(mode, dev);
return 0;
}
if (dev->features & CLOCK_EVT_FEAT_DUMMY)
return 0;
/* Transition with new mode-specific callbacks */
switch (mode) {
case CLOCK_EVT_MODE_UNUSED:
/*
* This is an internal state, which is guaranteed to go from
* SHUTDOWN to UNUSED. No driver interaction required.
*/
return 0;
case CLOCK_EVT_MODE_SHUTDOWN:
return dev->set_mode_shutdown(dev);
case CLOCK_EVT_MODE_PERIODIC:
/* Core internal bug */
if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC))
return -ENOSYS;
return dev->set_mode_periodic(dev);
case CLOCK_EVT_MODE_ONESHOT:
/* Core internal bug */
if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
return -ENOSYS;
return dev->set_mode_oneshot(dev);
case CLOCK_EVT_MODE_RESUME:
/* Optional callback */
if (dev->set_mode_resume)
return dev->set_mode_resume(dev);
else
return 0;
default:
return -ENOSYS;
}
}
/** /**
* clockevents_set_mode - set the operating mode of a clock event device * clockevents_set_mode - set the operating mode of a clock event device
* @dev: device to modify * @dev: device to modify
...@@ -105,7 +156,9 @@ void clockevents_set_mode(struct clock_event_device *dev, ...@@ -105,7 +156,9 @@ void clockevents_set_mode(struct clock_event_device *dev,
enum clock_event_mode mode) enum clock_event_mode mode)
{ {
if (dev->mode != mode) { if (dev->mode != mode) {
dev->set_mode(mode, dev); if (__clockevents_set_mode(dev, mode))
return;
dev->mode = mode; dev->mode = mode;
/* /*
...@@ -373,6 +426,35 @@ int clockevents_unbind_device(struct clock_event_device *ced, int cpu) ...@@ -373,6 +426,35 @@ int clockevents_unbind_device(struct clock_event_device *ced, int cpu)
} }
EXPORT_SYMBOL_GPL(clockevents_unbind); EXPORT_SYMBOL_GPL(clockevents_unbind);
/* Sanity check of mode transition callbacks */
static int clockevents_sanity_check(struct clock_event_device *dev)
{
/* Legacy set_mode() callback */
if (dev->set_mode) {
/* We shouldn't be supporting new modes now */
WARN_ON(dev->set_mode_periodic || dev->set_mode_oneshot ||
dev->set_mode_shutdown || dev->set_mode_resume);
return 0;
}
if (dev->features & CLOCK_EVT_FEAT_DUMMY)
return 0;
/* New mode-specific callbacks */
if (!dev->set_mode_shutdown)
return -EINVAL;
if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
!dev->set_mode_periodic)
return -EINVAL;
if ((dev->features & CLOCK_EVT_FEAT_ONESHOT) &&
!dev->set_mode_oneshot)
return -EINVAL;
return 0;
}
/** /**
* clockevents_register_device - register a clock event device * clockevents_register_device - register a clock event device
* @dev: device to register * @dev: device to register
...@@ -382,6 +464,8 @@ void clockevents_register_device(struct clock_event_device *dev) ...@@ -382,6 +464,8 @@ void clockevents_register_device(struct clock_event_device *dev)
unsigned long flags; unsigned long flags;
BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED); BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
BUG_ON(clockevents_sanity_check(dev));
if (!dev->cpumask) { if (!dev->cpumask) {
WARN_ON(num_possible_cpus() > 1); WARN_ON(num_possible_cpus() > 1);
dev->cpumask = cpumask_of(smp_processor_id()); dev->cpumask = cpumask_of(smp_processor_id());
...@@ -449,7 +533,7 @@ int __clockevents_update_freq(struct clock_event_device *dev, u32 freq) ...@@ -449,7 +533,7 @@ int __clockevents_update_freq(struct clock_event_device *dev, u32 freq)
return clockevents_program_event(dev, dev->next_event, false); return clockevents_program_event(dev, dev->next_event, false);
if (dev->mode == CLOCK_EVT_MODE_PERIODIC) if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
dev->set_mode(CLOCK_EVT_MODE_PERIODIC, dev); return __clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
return 0; return 0;
} }
......
...@@ -142,13 +142,6 @@ static void __clocksource_unstable(struct clocksource *cs) ...@@ -142,13 +142,6 @@ static void __clocksource_unstable(struct clocksource *cs)
schedule_work(&watchdog_work); schedule_work(&watchdog_work);
} }
static void clocksource_unstable(struct clocksource *cs, int64_t delta)
{
printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n",
cs->name, delta);
__clocksource_unstable(cs);
}
/** /**
* clocksource_mark_unstable - mark clocksource unstable via watchdog * clocksource_mark_unstable - mark clocksource unstable via watchdog
* @cs: clocksource to be marked unstable * @cs: clocksource to be marked unstable
...@@ -174,7 +167,7 @@ void clocksource_mark_unstable(struct clocksource *cs) ...@@ -174,7 +167,7 @@ void clocksource_mark_unstable(struct clocksource *cs)
static void clocksource_watchdog(unsigned long data) static void clocksource_watchdog(unsigned long data)
{ {
struct clocksource *cs; struct clocksource *cs;
cycle_t csnow, wdnow, delta; cycle_t csnow, wdnow, cslast, wdlast, delta;
int64_t wd_nsec, cs_nsec; int64_t wd_nsec, cs_nsec;
int next_cpu, reset_pending; int next_cpu, reset_pending;
...@@ -213,6 +206,8 @@ static void clocksource_watchdog(unsigned long data) ...@@ -213,6 +206,8 @@ static void clocksource_watchdog(unsigned long data)
delta = clocksource_delta(csnow, cs->cs_last, cs->mask); delta = clocksource_delta(csnow, cs->cs_last, cs->mask);
cs_nsec = clocksource_cyc2ns(delta, cs->mult, cs->shift); cs_nsec = clocksource_cyc2ns(delta, cs->mult, cs->shift);
wdlast = cs->wd_last; /* save these in case we print them */
cslast = cs->cs_last;
cs->cs_last = csnow; cs->cs_last = csnow;
cs->wd_last = wdnow; cs->wd_last = wdnow;
...@@ -221,7 +216,12 @@ static void clocksource_watchdog(unsigned long data) ...@@ -221,7 +216,12 @@ static void clocksource_watchdog(unsigned long data)
/* Check the deviation from the watchdog clocksource. */ /* Check the deviation from the watchdog clocksource. */
if ((abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD)) { if ((abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD)) {
clocksource_unstable(cs, cs_nsec - wd_nsec); pr_warn("timekeeping watchdog: Marking clocksource '%s' as unstable, because the skew is too large:\n", cs->name);
pr_warn(" '%s' wd_now: %llx wd_last: %llx mask: %llx\n",
watchdog->name, wdnow, wdlast, watchdog->mask);
pr_warn(" '%s' cs_now: %llx cs_last: %llx mask: %llx\n",
cs->name, csnow, cslast, cs->mask);
__clocksource_unstable(cs);
continue; continue;
} }
...@@ -469,26 +469,22 @@ static u32 clocksource_max_adjustment(struct clocksource *cs) ...@@ -469,26 +469,22 @@ static u32 clocksource_max_adjustment(struct clocksource *cs)
* @shift: cycle to nanosecond divisor (power of two) * @shift: cycle to nanosecond divisor (power of two)
* @maxadj: maximum adjustment value to mult (~11%) * @maxadj: maximum adjustment value to mult (~11%)
* @mask: bitmask for two's complement subtraction of non 64 bit counters * @mask: bitmask for two's complement subtraction of non 64 bit counters
* @max_cyc: maximum cycle value before potential overflow (does not include
* any safety margin)
*
* NOTE: This function includes a safety margin of 50%, so that bad clock values
* can be detected.
*/ */
u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask) u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cyc)
{ {
u64 max_nsecs, max_cycles; u64 max_nsecs, max_cycles;
/* /*
* Calculate the maximum number of cycles that we can pass to the * Calculate the maximum number of cycles that we can pass to the
* cyc2ns function without overflowing a 64-bit signed result. The * cyc2ns() function without overflowing a 64-bit result.
* maximum number of cycles is equal to ULLONG_MAX/(mult+maxadj)
* which is equivalent to the below.
* max_cycles < (2^63)/(mult + maxadj)
* max_cycles < 2^(log2((2^63)/(mult + maxadj)))
* max_cycles < 2^(log2(2^63) - log2(mult + maxadj))
* max_cycles < 2^(63 - log2(mult + maxadj))
* max_cycles < 1 << (63 - log2(mult + maxadj))
* Please note that we add 1 to the result of the log2 to account for
* any rounding errors, ensure the above inequality is satisfied and
* no overflow will occur.
*/ */
max_cycles = 1ULL << (63 - (ilog2(mult + maxadj) + 1)); max_cycles = ULLONG_MAX;
do_div(max_cycles, mult+maxadj);
/* /*
* The actual maximum number of cycles we can defer the clocksource is * The actual maximum number of cycles we can defer the clocksource is
...@@ -499,27 +495,26 @@ u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask) ...@@ -499,27 +495,26 @@ u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask)
max_cycles = min(max_cycles, mask); max_cycles = min(max_cycles, mask);
max_nsecs = clocksource_cyc2ns(max_cycles, mult - maxadj, shift); max_nsecs = clocksource_cyc2ns(max_cycles, mult - maxadj, shift);
/* return the max_cycles value as well if requested */
if (max_cyc)
*max_cyc = max_cycles;
/* Return 50% of the actual maximum, so we can detect bad values */
max_nsecs >>= 1;
return max_nsecs; return max_nsecs;
} }
/** /**
* clocksource_max_deferment - Returns max time the clocksource can be deferred * clocksource_update_max_deferment - Updates the clocksource max_idle_ns & max_cycles
* @cs: Pointer to clocksource * @cs: Pointer to clocksource to be updated
* *
*/ */
static u64 clocksource_max_deferment(struct clocksource *cs) static inline void clocksource_update_max_deferment(struct clocksource *cs)
{ {
u64 max_nsecs; cs->max_idle_ns = clocks_calc_max_nsecs(cs->mult, cs->shift,
cs->maxadj, cs->mask,
max_nsecs = clocks_calc_max_nsecs(cs->mult, cs->shift, cs->maxadj, &cs->max_cycles);
cs->mask);
/*
* To ensure that the clocksource does not wrap whilst we are idle,
* limit the time the clocksource can be deferred by 12.5%. Please
* note a margin of 12.5% is used because this can be computed with
* a shift, versus say 10% which would require division.
*/
return max_nsecs - (max_nsecs >> 3);
} }
#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET #ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
...@@ -648,7 +643,7 @@ static void clocksource_enqueue(struct clocksource *cs) ...@@ -648,7 +643,7 @@ static void clocksource_enqueue(struct clocksource *cs)
} }
/** /**
* __clocksource_updatefreq_scale - Used update clocksource with new freq * __clocksource_update_freq_scale - Used update clocksource with new freq
* @cs: clocksource to be registered * @cs: clocksource to be registered
* @scale: Scale factor multiplied against freq to get clocksource hz * @scale: Scale factor multiplied against freq to get clocksource hz
* @freq: clocksource frequency (cycles per second) divided by scale * @freq: clocksource frequency (cycles per second) divided by scale
...@@ -656,48 +651,64 @@ static void clocksource_enqueue(struct clocksource *cs) ...@@ -656,48 +651,64 @@ static void clocksource_enqueue(struct clocksource *cs)
* This should only be called from the clocksource->enable() method. * This should only be called from the clocksource->enable() method.
* *
* This *SHOULD NOT* be called directly! Please use the * This *SHOULD NOT* be called directly! Please use the
* clocksource_updatefreq_hz() or clocksource_updatefreq_khz helper functions. * __clocksource_update_freq_hz() or __clocksource_update_freq_khz() helper
* functions.
*/ */
void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) void __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq)
{ {
u64 sec; u64 sec;
/* /*
* Calc the maximum number of seconds which we can run before * Default clocksources are *special* and self-define their mult/shift.
* wrapping around. For clocksources which have a mask > 32bit * But, you're not special, so you should specify a freq value.
* we need to limit the max sleep time to have a good
* conversion precision. 10 minutes is still a reasonable
* amount. That results in a shift value of 24 for a
* clocksource with mask >= 40bit and f >= 4GHz. That maps to
* ~ 0.06ppm granularity for NTP. We apply the same 12.5%
* margin as we do in clocksource_max_deferment()
*/ */
sec = (cs->mask - (cs->mask >> 3)); if (freq) {
do_div(sec, freq); /*
do_div(sec, scale); * Calc the maximum number of seconds which we can run before
if (!sec) * wrapping around. For clocksources which have a mask > 32-bit
sec = 1; * we need to limit the max sleep time to have a good
else if (sec > 600 && cs->mask > UINT_MAX) * conversion precision. 10 minutes is still a reasonable
sec = 600; * amount. That results in a shift value of 24 for a
* clocksource with mask >= 40-bit and f >= 4GHz. That maps to
clocks_calc_mult_shift(&cs->mult, &cs->shift, freq, * ~ 0.06ppm granularity for NTP.
NSEC_PER_SEC / scale, sec * scale); */
sec = cs->mask;
do_div(sec, freq);
do_div(sec, scale);
if (!sec)
sec = 1;
else if (sec > 600 && cs->mask > UINT_MAX)
sec = 600;
clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
NSEC_PER_SEC / scale, sec * scale);
}
/* /*
* for clocksources that have large mults, to avoid overflow. * Ensure clocksources that have large 'mult' values don't overflow
* Since mult may be adjusted by ntp, add an safety extra margin * when adjusted.
*
*/ */
cs->maxadj = clocksource_max_adjustment(cs); cs->maxadj = clocksource_max_adjustment(cs);
while ((cs->mult + cs->maxadj < cs->mult) while (freq && ((cs->mult + cs->maxadj < cs->mult)
|| (cs->mult - cs->maxadj > cs->mult)) { || (cs->mult - cs->maxadj > cs->mult))) {
cs->mult >>= 1; cs->mult >>= 1;
cs->shift--; cs->shift--;
cs->maxadj = clocksource_max_adjustment(cs); cs->maxadj = clocksource_max_adjustment(cs);
} }
cs->max_idle_ns = clocksource_max_deferment(cs); /*
* Only warn for *special* clocksources that self-define
* their mult/shift values and don't specify a freq.
*/
WARN_ONCE(cs->mult + cs->maxadj < cs->mult,
"timekeeping: Clocksource %s might overflow on 11%% adjustment\n",
cs->name);
clocksource_update_max_deferment(cs);
pr_info("clocksource %s: mask: 0x%llx max_cycles: 0x%llx, max_idle_ns: %lld ns\n",
cs->name, cs->mask, cs->max_cycles, cs->max_idle_ns);
} }
EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale); EXPORT_SYMBOL_GPL(__clocksource_update_freq_scale);
/** /**
* __clocksource_register_scale - Used to install new clocksources * __clocksource_register_scale - Used to install new clocksources
...@@ -714,7 +725,7 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) ...@@ -714,7 +725,7 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
{ {
/* Initialize mult/shift and max_idle_ns */ /* Initialize mult/shift and max_idle_ns */
__clocksource_updatefreq_scale(cs, scale, freq); __clocksource_update_freq_scale(cs, scale, freq);
/* Add clocksource to the clocksource list */ /* Add clocksource to the clocksource list */
mutex_lock(&clocksource_mutex); mutex_lock(&clocksource_mutex);
...@@ -726,33 +737,6 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) ...@@ -726,33 +737,6 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
} }
EXPORT_SYMBOL_GPL(__clocksource_register_scale); EXPORT_SYMBOL_GPL(__clocksource_register_scale);
/**
* clocksource_register - Used to install new clocksources
* @cs: clocksource to be registered
*
* Returns -EBUSY if registration fails, zero otherwise.
*/
int clocksource_register(struct clocksource *cs)
{
/* calculate max adjustment for given mult/shift */
cs->maxadj = clocksource_max_adjustment(cs);
WARN_ONCE(cs->mult + cs->maxadj < cs->mult,
"Clocksource %s might overflow on 11%% adjustment\n",
cs->name);
/* calculate max idle time permitted for this clocksource */
cs->max_idle_ns = clocksource_max_deferment(cs);
mutex_lock(&clocksource_mutex);
clocksource_enqueue(cs);
clocksource_enqueue_watchdog(cs);
clocksource_select();
mutex_unlock(&clocksource_mutex);
return 0;
}
EXPORT_SYMBOL(clocksource_register);
static void __clocksource_change_rating(struct clocksource *cs, int rating) static void __clocksource_change_rating(struct clocksource *cs, int rating)
{ {
list_del(&cs->list); list_del(&cs->list);
......
...@@ -71,6 +71,7 @@ static struct clocksource clocksource_jiffies = { ...@@ -71,6 +71,7 @@ static struct clocksource clocksource_jiffies = {
.mask = 0xffffffff, /*32bits*/ .mask = 0xffffffff, /*32bits*/
.mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */ .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
.shift = JIFFIES_SHIFT, .shift = JIFFIES_SHIFT,
.max_cycles = 10,
}; };
__cacheline_aligned_in_smp DEFINE_SEQLOCK(jiffies_lock); __cacheline_aligned_in_smp DEFINE_SEQLOCK(jiffies_lock);
...@@ -94,7 +95,7 @@ EXPORT_SYMBOL(jiffies); ...@@ -94,7 +95,7 @@ EXPORT_SYMBOL(jiffies);
static int __init init_jiffies_clocksource(void) static int __init init_jiffies_clocksource(void)
{ {
return clocksource_register(&clocksource_jiffies); return __clocksource_register(&clocksource_jiffies);
} }
core_initcall(init_jiffies_clocksource); core_initcall(init_jiffies_clocksource);
...@@ -130,6 +131,6 @@ int register_refined_jiffies(long cycles_per_second) ...@@ -130,6 +131,6 @@ int register_refined_jiffies(long cycles_per_second)
refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT; refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT;
clocksource_register(&refined_jiffies); __clocksource_register(&refined_jiffies);
return 0; return 0;
} }
This diff is collapsed.
This diff is collapsed.
...@@ -228,9 +228,35 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu) ...@@ -228,9 +228,35 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
print_name_offset(m, dev->set_next_event); print_name_offset(m, dev->set_next_event);
SEQ_printf(m, "\n"); SEQ_printf(m, "\n");
SEQ_printf(m, " set_mode: "); if (dev->set_mode) {
print_name_offset(m, dev->set_mode); SEQ_printf(m, " set_mode: ");
SEQ_printf(m, "\n"); print_name_offset(m, dev->set_mode);
SEQ_printf(m, "\n");
} else {
if (dev->set_mode_shutdown) {
SEQ_printf(m, " shutdown: ");
print_name_offset(m, dev->set_mode_shutdown);
SEQ_printf(m, "\n");
}
if (dev->set_mode_periodic) {
SEQ_printf(m, " periodic: ");
print_name_offset(m, dev->set_mode_periodic);
SEQ_printf(m, "\n");
}
if (dev->set_mode_oneshot) {
SEQ_printf(m, " oneshot: ");
print_name_offset(m, dev->set_mode_oneshot);
SEQ_printf(m, "\n");
}
if (dev->set_mode_resume) {
SEQ_printf(m, " resume: ");
print_name_offset(m, dev->set_mode_resume);
SEQ_printf(m, "\n");
}
}
SEQ_printf(m, " event_handler: "); SEQ_printf(m, " event_handler: ");
print_name_offset(m, dev->event_handler); print_name_offset(m, dev->event_handler);
......
...@@ -865,6 +865,19 @@ config SCHED_STACK_END_CHECK ...@@ -865,6 +865,19 @@ config SCHED_STACK_END_CHECK
data corruption or a sporadic crash at a later stage once the region data corruption or a sporadic crash at a later stage once the region
is examined. The runtime overhead introduced is minimal. is examined. The runtime overhead introduced is minimal.
config DEBUG_TIMEKEEPING
bool "Enable extra timekeeping sanity checking"
help
This option will enable additional timekeeping sanity checks
which may be helpful when diagnosing issues where timekeeping
problems are suspected.
This may include checks in the timekeeping hotpaths, so this
option may have a (very small) performance impact to some
workloads.
If unsure, say N.
config TIMER_STATS config TIMER_STATS
bool "Collect kernel timers statistics" bool "Collect kernel timers statistics"
depends on DEBUG_KERNEL && PROC_FS depends on DEBUG_KERNEL && PROC_FS
......
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