Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer core update from Thomas Gleixner: - Bug fixes (one for a longstanding dead loop issue) - Rework of time related vsyscalls - Alarm timer updates - Jiffies updates to remove compile time dependencies * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: timekeeping: Cast raw_interval to u64 to avoid shift overflow timers: Fix endless looping between cascade() and internal_add_timer() time/jiffies: bring back unconditional LATCH definition time: Convert x86_64 to using new update_vsyscall time: Only do nanosecond rounding on GENERIC_TIME_VSYSCALL_OLD systems time: Introduce new GENERIC_TIME_VSYSCALL time: Convert CONFIG_GENERIC_TIME_VSYSCALL to CONFIG_GENERIC_TIME_VSYSCALL_OLD time: Move update_vsyscall definitions to timekeeper_internal.h time: Move timekeeper structure to timekeeper_internal.h for vsyscall changes jiffies: Remove compile time assumptions about CLOCK_TICK_RATE jiffies: Kill unused TICK_USEC_TO_NSEC alarmtimer: Rename alarmtimer_remove to alarmtimer_dequeue alarmtimer: Remove unused helpers & defines alarmtimer: Use hrtimer per-alarm instead of per-base alarmtimer: Implement minimum alarm interval for allowing suspend
This commit is contained in:
commit
03d3602a83
|
@ -39,7 +39,7 @@ config IA64
|
||||||
select ARCH_TASK_STRUCT_ALLOCATOR
|
select ARCH_TASK_STRUCT_ALLOCATOR
|
||||||
select ARCH_THREAD_INFO_ALLOCATOR
|
select ARCH_THREAD_INFO_ALLOCATOR
|
||||||
select ARCH_CLOCKSOURCE_DATA
|
select ARCH_CLOCKSOURCE_DATA
|
||||||
select GENERIC_TIME_VSYSCALL
|
select GENERIC_TIME_VSYSCALL_OLD
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
The Itanium Processor Family is Intel's 64-bit successor to
|
The Itanium Processor Family is Intel's 64-bit successor to
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/efi.h>
|
#include <linux/efi.h>
|
||||||
#include <linux/timex.h>
|
#include <linux/timex.h>
|
||||||
#include <linux/clocksource.h>
|
#include <linux/timekeeper_internal.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
#include <asm/machvec.h>
|
#include <asm/machvec.h>
|
||||||
|
@ -454,7 +454,7 @@ void update_vsyscall_tz(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_vsyscall(struct timespec *wall, struct timespec *wtm,
|
void update_vsyscall_old(struct timespec *wall, struct timespec *wtm,
|
||||||
struct clocksource *c, u32 mult)
|
struct clocksource *c, u32 mult)
|
||||||
{
|
{
|
||||||
write_seqcount_begin(&fsyscall_gtod_data.seq);
|
write_seqcount_begin(&fsyscall_gtod_data.seq);
|
||||||
|
|
|
@ -137,7 +137,7 @@ config PPC
|
||||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select GENERIC_CMOS_UPDATE
|
select GENERIC_CMOS_UPDATE
|
||||||
select GENERIC_TIME_VSYSCALL
|
select GENERIC_TIME_VSYSCALL_OLD
|
||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
select GENERIC_STRNCPY_FROM_USER
|
select GENERIC_STRNCPY_FROM_USER
|
||||||
select GENERIC_STRNLEN_USER
|
select GENERIC_STRNLEN_USER
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
/* powerpc clocksource/clockevent code */
|
/* powerpc clocksource/clockevent code */
|
||||||
|
|
||||||
#include <linux/clockchips.h>
|
#include <linux/clockchips.h>
|
||||||
#include <linux/clocksource.h>
|
#include <linux/timekeeper_internal.h>
|
||||||
|
|
||||||
static cycle_t rtc_read(struct clocksource *);
|
static cycle_t rtc_read(struct clocksource *);
|
||||||
static struct clocksource clocksource_rtc = {
|
static struct clocksource clocksource_rtc = {
|
||||||
|
@ -727,7 +727,7 @@ static cycle_t timebase_read(struct clocksource *cs)
|
||||||
return (cycle_t)get_tb();
|
return (cycle_t)get_tb();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
|
void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm,
|
||||||
struct clocksource *clock, u32 mult)
|
struct clocksource *clock, u32 mult)
|
||||||
{
|
{
|
||||||
u64 new_tb_to_xs, new_stamp_xsec;
|
u64 new_tb_to_xs, new_stamp_xsec;
|
||||||
|
|
|
@ -131,7 +131,7 @@ config S390
|
||||||
select HAVE_UID16 if 32BIT
|
select HAVE_UID16 if 32BIT
|
||||||
select ARCH_WANT_IPC_PARSE_VERSION
|
select ARCH_WANT_IPC_PARSE_VERSION
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select GENERIC_TIME_VSYSCALL
|
select GENERIC_TIME_VSYSCALL_OLD
|
||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
select KTIME_SCALAR if 32BIT
|
select KTIME_SCALAR if 32BIT
|
||||||
select HAVE_ARCH_SECCOMP_FILTER
|
select HAVE_ARCH_SECCOMP_FILTER
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#include <linux/profile.h>
|
#include <linux/profile.h>
|
||||||
#include <linux/timex.h>
|
#include <linux/timex.h>
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/clocksource.h>
|
#include <linux/timekeeper_internal.h>
|
||||||
#include <linux/clockchips.h>
|
#include <linux/clockchips.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
#include <linux/kprobes.h>
|
#include <linux/kprobes.h>
|
||||||
|
@ -219,7 +219,7 @@ struct clocksource * __init clocksource_default_clock(void)
|
||||||
return &clocksource_tod;
|
return &clocksource_tod;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
|
void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm,
|
||||||
struct clocksource *clock, u32 mult)
|
struct clocksource *clock, u32 mult)
|
||||||
{
|
{
|
||||||
if (clock != &clocksource_tod)
|
if (clock != &clocksource_tod)
|
||||||
|
|
|
@ -17,8 +17,8 @@ struct vsyscall_gtod_data {
|
||||||
|
|
||||||
/* open coded 'struct timespec' */
|
/* open coded 'struct timespec' */
|
||||||
time_t wall_time_sec;
|
time_t wall_time_sec;
|
||||||
u32 wall_time_nsec;
|
u64 wall_time_snsec;
|
||||||
u32 monotonic_time_nsec;
|
u64 monotonic_time_snsec;
|
||||||
time_t monotonic_time_sec;
|
time_t monotonic_time_sec;
|
||||||
|
|
||||||
struct timezone sys_tz;
|
struct timezone sys_tz;
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
#include <linux/percpu.h>
|
#include <linux/percpu.h>
|
||||||
#include <linux/crash_dump.h>
|
#include <linux/crash_dump.h>
|
||||||
#include <linux/tboot.h>
|
#include <linux/tboot.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
|
||||||
#include <video/edid.h>
|
#include <video/edid.h>
|
||||||
|
|
||||||
|
@ -1032,6 +1033,8 @@ void __init setup_arch(char **cmdline_p)
|
||||||
mcheck_init();
|
mcheck_init();
|
||||||
|
|
||||||
arch_init_ideal_nops();
|
arch_init_ideal_nops();
|
||||||
|
|
||||||
|
register_refined_jiffies(CLOCK_TICK_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
#include <linux/topology.h>
|
#include <linux/topology.h>
|
||||||
#include <linux/clocksource.h>
|
#include <linux/timekeeper_internal.h>
|
||||||
#include <linux/getcpu.h>
|
#include <linux/getcpu.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
|
@ -82,32 +82,41 @@ void update_vsyscall_tz(void)
|
||||||
vsyscall_gtod_data.sys_tz = sys_tz;
|
vsyscall_gtod_data.sys_tz = sys_tz;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
|
void update_vsyscall(struct timekeeper *tk)
|
||||||
struct clocksource *clock, u32 mult)
|
|
||||||
{
|
{
|
||||||
struct timespec monotonic;
|
struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data;
|
||||||
|
|
||||||
write_seqcount_begin(&vsyscall_gtod_data.seq);
|
write_seqcount_begin(&vdata->seq);
|
||||||
|
|
||||||
/* copy vsyscall data */
|
/* copy vsyscall data */
|
||||||
vsyscall_gtod_data.clock.vclock_mode = clock->archdata.vclock_mode;
|
vdata->clock.vclock_mode = tk->clock->archdata.vclock_mode;
|
||||||
vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
|
vdata->clock.cycle_last = tk->clock->cycle_last;
|
||||||
vsyscall_gtod_data.clock.mask = clock->mask;
|
vdata->clock.mask = tk->clock->mask;
|
||||||
vsyscall_gtod_data.clock.mult = mult;
|
vdata->clock.mult = tk->mult;
|
||||||
vsyscall_gtod_data.clock.shift = clock->shift;
|
vdata->clock.shift = tk->shift;
|
||||||
|
|
||||||
vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
|
vdata->wall_time_sec = tk->xtime_sec;
|
||||||
vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
|
vdata->wall_time_snsec = tk->xtime_nsec;
|
||||||
|
|
||||||
monotonic = timespec_add(*wall_time, *wtm);
|
vdata->monotonic_time_sec = tk->xtime_sec
|
||||||
vsyscall_gtod_data.monotonic_time_sec = monotonic.tv_sec;
|
+ tk->wall_to_monotonic.tv_sec;
|
||||||
vsyscall_gtod_data.monotonic_time_nsec = monotonic.tv_nsec;
|
vdata->monotonic_time_snsec = tk->xtime_nsec
|
||||||
|
+ (tk->wall_to_monotonic.tv_nsec
|
||||||
|
<< tk->shift);
|
||||||
|
while (vdata->monotonic_time_snsec >=
|
||||||
|
(((u64)NSEC_PER_SEC) << tk->shift)) {
|
||||||
|
vdata->monotonic_time_snsec -=
|
||||||
|
((u64)NSEC_PER_SEC) << tk->shift;
|
||||||
|
vdata->monotonic_time_sec++;
|
||||||
|
}
|
||||||
|
|
||||||
vsyscall_gtod_data.wall_time_coarse = __current_kernel_time();
|
vdata->wall_time_coarse.tv_sec = tk->xtime_sec;
|
||||||
vsyscall_gtod_data.monotonic_time_coarse =
|
vdata->wall_time_coarse.tv_nsec = (long)(tk->xtime_nsec >> tk->shift);
|
||||||
timespec_add(vsyscall_gtod_data.wall_time_coarse, *wtm);
|
|
||||||
|
|
||||||
write_seqcount_end(&vsyscall_gtod_data.seq);
|
vdata->monotonic_time_coarse = timespec_add(vdata->wall_time_coarse,
|
||||||
|
tk->wall_to_monotonic);
|
||||||
|
|
||||||
|
write_seqcount_end(&vdata->seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
|
static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
|
||||||
|
|
|
@ -80,7 +80,7 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
notrace static inline long vgetns(void)
|
notrace static inline u64 vgetsns(void)
|
||||||
{
|
{
|
||||||
long v;
|
long v;
|
||||||
cycles_t cycles;
|
cycles_t cycles;
|
||||||
|
@ -91,21 +91,24 @@ notrace static inline long vgetns(void)
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask;
|
v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask;
|
||||||
return (v * gtod->clock.mult) >> gtod->clock.shift;
|
return v * gtod->clock.mult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
|
/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
|
||||||
notrace static int __always_inline do_realtime(struct timespec *ts)
|
notrace static int __always_inline do_realtime(struct timespec *ts)
|
||||||
{
|
{
|
||||||
unsigned long seq, ns;
|
unsigned long seq;
|
||||||
|
u64 ns;
|
||||||
int mode;
|
int mode;
|
||||||
|
|
||||||
|
ts->tv_nsec = 0;
|
||||||
do {
|
do {
|
||||||
seq = read_seqcount_begin(>od->seq);
|
seq = read_seqcount_begin(>od->seq);
|
||||||
mode = gtod->clock.vclock_mode;
|
mode = gtod->clock.vclock_mode;
|
||||||
ts->tv_sec = gtod->wall_time_sec;
|
ts->tv_sec = gtod->wall_time_sec;
|
||||||
ts->tv_nsec = gtod->wall_time_nsec;
|
ns = gtod->wall_time_snsec;
|
||||||
ns = vgetns();
|
ns += vgetsns();
|
||||||
|
ns >>= gtod->clock.shift;
|
||||||
} while (unlikely(read_seqcount_retry(>od->seq, seq)));
|
} while (unlikely(read_seqcount_retry(>od->seq, seq)));
|
||||||
|
|
||||||
timespec_add_ns(ts, ns);
|
timespec_add_ns(ts, ns);
|
||||||
|
@ -114,15 +117,18 @@ notrace static int __always_inline do_realtime(struct timespec *ts)
|
||||||
|
|
||||||
notrace static int do_monotonic(struct timespec *ts)
|
notrace static int do_monotonic(struct timespec *ts)
|
||||||
{
|
{
|
||||||
unsigned long seq, ns;
|
unsigned long seq;
|
||||||
|
u64 ns;
|
||||||
int mode;
|
int mode;
|
||||||
|
|
||||||
|
ts->tv_nsec = 0;
|
||||||
do {
|
do {
|
||||||
seq = read_seqcount_begin(>od->seq);
|
seq = read_seqcount_begin(>od->seq);
|
||||||
mode = gtod->clock.vclock_mode;
|
mode = gtod->clock.vclock_mode;
|
||||||
ts->tv_sec = gtod->monotonic_time_sec;
|
ts->tv_sec = gtod->monotonic_time_sec;
|
||||||
ts->tv_nsec = gtod->monotonic_time_nsec;
|
ns = gtod->monotonic_time_snsec;
|
||||||
ns = vgetns();
|
ns += vgetsns();
|
||||||
|
ns >>= gtod->clock.shift;
|
||||||
} while (unlikely(read_seqcount_retry(>od->seq, seq)));
|
} while (unlikely(read_seqcount_retry(>od->seq, seq)));
|
||||||
timespec_add_ns(ts, ns);
|
timespec_add_ns(ts, ns);
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ enum alarmtimer_restart {
|
||||||
|
|
||||||
#define ALARMTIMER_STATE_INACTIVE 0x00
|
#define ALARMTIMER_STATE_INACTIVE 0x00
|
||||||
#define ALARMTIMER_STATE_ENQUEUED 0x01
|
#define ALARMTIMER_STATE_ENQUEUED 0x01
|
||||||
#define ALARMTIMER_STATE_CALLBACK 0x02
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct alarm - Alarm timer structure
|
* struct alarm - Alarm timer structure
|
||||||
|
@ -35,6 +34,7 @@ enum alarmtimer_restart {
|
||||||
*/
|
*/
|
||||||
struct alarm {
|
struct alarm {
|
||||||
struct timerqueue_node node;
|
struct timerqueue_node node;
|
||||||
|
struct hrtimer timer;
|
||||||
enum alarmtimer_restart (*function)(struct alarm *, ktime_t now);
|
enum alarmtimer_restart (*function)(struct alarm *, ktime_t now);
|
||||||
enum alarmtimer_type type;
|
enum alarmtimer_type type;
|
||||||
int state;
|
int state;
|
||||||
|
@ -43,39 +43,12 @@ struct alarm {
|
||||||
|
|
||||||
void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
|
void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
|
||||||
enum alarmtimer_restart (*function)(struct alarm *, ktime_t));
|
enum alarmtimer_restart (*function)(struct alarm *, ktime_t));
|
||||||
void alarm_start(struct alarm *alarm, ktime_t start);
|
int alarm_start(struct alarm *alarm, ktime_t start);
|
||||||
int alarm_try_to_cancel(struct alarm *alarm);
|
int alarm_try_to_cancel(struct alarm *alarm);
|
||||||
int alarm_cancel(struct alarm *alarm);
|
int alarm_cancel(struct alarm *alarm);
|
||||||
|
|
||||||
u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval);
|
u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval);
|
||||||
|
|
||||||
/*
|
|
||||||
* A alarmtimer is active, when it is enqueued into timerqueue or the
|
|
||||||
* callback function is running.
|
|
||||||
*/
|
|
||||||
static inline int alarmtimer_active(const struct alarm *timer)
|
|
||||||
{
|
|
||||||
return timer->state != ALARMTIMER_STATE_INACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper function to check, whether the timer is on one of the queues
|
|
||||||
*/
|
|
||||||
static inline int alarmtimer_is_queued(struct alarm *timer)
|
|
||||||
{
|
|
||||||
return timer->state & ALARMTIMER_STATE_ENQUEUED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper function to check, whether the timer is running the callback
|
|
||||||
* function
|
|
||||||
*/
|
|
||||||
static inline int alarmtimer_callback_running(struct alarm *timer)
|
|
||||||
{
|
|
||||||
return timer->state & ALARMTIMER_STATE_CALLBACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Provide way to access the rtc device being used by alarmtimers */
|
/* Provide way to access the rtc device being used by alarmtimers */
|
||||||
struct rtc_device *alarmtimer_get_rtcdev(void);
|
struct rtc_device *alarmtimer_get_rtcdev(void);
|
||||||
|
|
||||||
|
|
|
@ -319,22 +319,6 @@ static inline void __clocksource_updatefreq_khz(struct clocksource *cs, u32 khz)
|
||||||
__clocksource_updatefreq_scale(cs, 1000, khz);
|
__clocksource_updatefreq_scale(cs, 1000, khz);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_GENERIC_TIME_VSYSCALL
|
|
||||||
extern void
|
|
||||||
update_vsyscall(struct timespec *ts, struct timespec *wtm,
|
|
||||||
struct clocksource *c, u32 mult);
|
|
||||||
extern void update_vsyscall_tz(void);
|
|
||||||
#else
|
|
||||||
static inline void
|
|
||||||
update_vsyscall(struct timespec *ts, struct timespec *wtm,
|
|
||||||
struct clocksource *c, u32 mult)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void update_vsyscall_tz(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void timekeeping_notify(struct clocksource *clock);
|
extern void timekeeping_notify(struct clocksource *clock);
|
||||||
|
|
||||||
|
|
|
@ -51,31 +51,17 @@
|
||||||
#define SH_DIV(NOM,DEN,LSH) ( (((NOM) / (DEN)) << (LSH)) \
|
#define SH_DIV(NOM,DEN,LSH) ( (((NOM) / (DEN)) << (LSH)) \
|
||||||
+ ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN))
|
+ ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN))
|
||||||
|
|
||||||
#ifdef CLOCK_TICK_RATE
|
|
||||||
/* LATCH is used in the interval timer and ftape setup. */
|
/* LATCH is used in the interval timer and ftape setup. */
|
||||||
# define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
|
#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
|
||||||
|
|
||||||
/*
|
extern int register_refined_jiffies(long clock_tick_rate);
|
||||||
* HZ is the requested value. However the CLOCK_TICK_RATE may not allow
|
|
||||||
* for exactly HZ. So SHIFTED_HZ is high res HZ ("<< 8" is for accuracy)
|
|
||||||
*/
|
|
||||||
# define SHIFTED_HZ (SH_DIV(CLOCK_TICK_RATE, LATCH, 8))
|
|
||||||
#else
|
|
||||||
# define SHIFTED_HZ (HZ << 8)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */
|
/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */
|
||||||
#define TICK_NSEC (SH_DIV(1000000UL * 1000, SHIFTED_HZ, 8))
|
#define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ)
|
||||||
|
|
||||||
/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
|
/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
|
||||||
#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
|
#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
|
||||||
|
|
||||||
/*
|
|
||||||
* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming SHIFTED_HZ and
|
|
||||||
* a value TUSEC for TICK_USEC (can be set bij adjtimex)
|
|
||||||
*/
|
|
||||||
#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV(TUSEC * USER_HZ * 1000, SHIFTED_HZ, 8))
|
|
||||||
|
|
||||||
/* some arch's have a small-data section that can be accessed register-relative
|
/* some arch's have a small-data section that can be accessed register-relative
|
||||||
* but that can only take up to, say, 4-byte variables. jiffies being part of
|
* but that can only take up to, say, 4-byte variables. jiffies being part of
|
||||||
* an 8-byte variable may not be correctly accessed unless we force the issue
|
* an 8-byte variable may not be correctly accessed unless we force the issue
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* You SHOULD NOT be including this unless you're vsyscall
|
||||||
|
* handling code or timekeeping internal code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_TIMEKEEPER_INTERNAL_H
|
||||||
|
#define _LINUX_TIMEKEEPER_INTERNAL_H
|
||||||
|
|
||||||
|
#include <linux/clocksource.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
|
||||||
|
/* Structure holding internal timekeeping values. */
|
||||||
|
struct timekeeper {
|
||||||
|
/* Current clocksource used for timekeeping. */
|
||||||
|
struct clocksource *clock;
|
||||||
|
/* NTP adjusted clock multiplier */
|
||||||
|
u32 mult;
|
||||||
|
/* The shift value of the current clocksource. */
|
||||||
|
u32 shift;
|
||||||
|
/* Number of clock cycles in one NTP interval. */
|
||||||
|
cycle_t cycle_interval;
|
||||||
|
/* Number of clock shifted nano seconds in one NTP interval. */
|
||||||
|
u64 xtime_interval;
|
||||||
|
/* shifted nano seconds left over when rounding cycle_interval */
|
||||||
|
s64 xtime_remainder;
|
||||||
|
/* Raw nano seconds accumulated per NTP interval. */
|
||||||
|
u32 raw_interval;
|
||||||
|
|
||||||
|
/* Current CLOCK_REALTIME time in seconds */
|
||||||
|
u64 xtime_sec;
|
||||||
|
/* Clock shifted nano seconds */
|
||||||
|
u64 xtime_nsec;
|
||||||
|
|
||||||
|
/* Difference between accumulated time and NTP time in ntp
|
||||||
|
* shifted nano seconds. */
|
||||||
|
s64 ntp_error;
|
||||||
|
/* Shift conversion between clock shifted nano seconds and
|
||||||
|
* ntp shifted nano seconds. */
|
||||||
|
u32 ntp_error_shift;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wall_to_monotonic is what we need to add to xtime (or xtime corrected
|
||||||
|
* for sub jiffie times) to get to monotonic time. Monotonic is pegged
|
||||||
|
* at zero at system boot time, so wall_to_monotonic will be negative,
|
||||||
|
* however, we will ALWAYS keep the tv_nsec part positive so we can use
|
||||||
|
* the usual normalization.
|
||||||
|
*
|
||||||
|
* wall_to_monotonic is moved after resume from suspend for the
|
||||||
|
* monotonic time not to jump. We need to add total_sleep_time to
|
||||||
|
* wall_to_monotonic to get the real boot based time offset.
|
||||||
|
*
|
||||||
|
* - wall_to_monotonic is no longer the boot time, getboottime must be
|
||||||
|
* used instead.
|
||||||
|
*/
|
||||||
|
struct timespec wall_to_monotonic;
|
||||||
|
/* Offset clock monotonic -> clock realtime */
|
||||||
|
ktime_t offs_real;
|
||||||
|
/* time spent in suspend */
|
||||||
|
struct timespec total_sleep_time;
|
||||||
|
/* Offset clock monotonic -> clock boottime */
|
||||||
|
ktime_t offs_boot;
|
||||||
|
/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
|
||||||
|
struct timespec raw_time;
|
||||||
|
/* Seqlock for all timekeeper values */
|
||||||
|
seqlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct timespec tk_xtime(struct timekeeper *tk)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
ts.tv_sec = tk->xtime_sec;
|
||||||
|
ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift);
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_GENERIC_TIME_VSYSCALL
|
||||||
|
|
||||||
|
extern void update_vsyscall(struct timekeeper *tk);
|
||||||
|
extern void update_vsyscall_tz(void);
|
||||||
|
|
||||||
|
#elif defined(CONFIG_GENERIC_TIME_VSYSCALL_OLD)
|
||||||
|
|
||||||
|
extern void update_vsyscall_old(struct timespec *ts, struct timespec *wtm,
|
||||||
|
struct clocksource *c, u32 mult);
|
||||||
|
extern void update_vsyscall_tz(void);
|
||||||
|
|
||||||
|
static inline void update_vsyscall(struct timekeeper *tk)
|
||||||
|
{
|
||||||
|
struct timespec xt;
|
||||||
|
|
||||||
|
xt = tk_xtime(tk);
|
||||||
|
update_vsyscall_old(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void update_vsyscall(struct timekeeper *tk)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static inline void update_vsyscall_tz(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _LINUX_TIMEKEEPER_INTERNAL_H */
|
|
@ -30,7 +30,7 @@
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/timex.h>
|
#include <linux/timex.h>
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/clocksource.h>
|
#include <linux/timekeeper_internal.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
|
|
|
@ -16,6 +16,10 @@ config ARCH_CLOCKSOURCE_DATA
|
||||||
config GENERIC_TIME_VSYSCALL
|
config GENERIC_TIME_VSYSCALL
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
# Timekeeping vsyscall support
|
||||||
|
config GENERIC_TIME_VSYSCALL_OLD
|
||||||
|
bool
|
||||||
|
|
||||||
# ktime_t scalar 64bit nsec representation
|
# ktime_t scalar 64bit nsec representation
|
||||||
config KTIME_SCALAR
|
config KTIME_SCALAR
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
static struct alarm_base {
|
static struct alarm_base {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct timerqueue_head timerqueue;
|
struct timerqueue_head timerqueue;
|
||||||
struct hrtimer timer;
|
|
||||||
ktime_t (*gettime)(void);
|
ktime_t (*gettime)(void);
|
||||||
clockid_t base_clockid;
|
clockid_t base_clockid;
|
||||||
} alarm_bases[ALARM_NUMTYPE];
|
} alarm_bases[ALARM_NUMTYPE];
|
||||||
|
@ -46,6 +45,8 @@ static struct alarm_base {
|
||||||
static ktime_t freezer_delta;
|
static ktime_t freezer_delta;
|
||||||
static DEFINE_SPINLOCK(freezer_delta_lock);
|
static DEFINE_SPINLOCK(freezer_delta_lock);
|
||||||
|
|
||||||
|
static struct wakeup_source *ws;
|
||||||
|
|
||||||
#ifdef CONFIG_RTC_CLASS
|
#ifdef CONFIG_RTC_CLASS
|
||||||
/* rtc timer and device for setting alarm wakeups at suspend */
|
/* rtc timer and device for setting alarm wakeups at suspend */
|
||||||
static struct rtc_timer rtctimer;
|
static struct rtc_timer rtctimer;
|
||||||
|
@ -130,50 +131,35 @@ static inline void alarmtimer_rtc_timer_init(void) { }
|
||||||
* @base: pointer to the base where the timer is being run
|
* @base: pointer to the base where the timer is being run
|
||||||
* @alarm: pointer to alarm being enqueued.
|
* @alarm: pointer to alarm being enqueued.
|
||||||
*
|
*
|
||||||
* Adds alarm to a alarm_base timerqueue and if necessary sets
|
* Adds alarm to a alarm_base timerqueue
|
||||||
* an hrtimer to run.
|
|
||||||
*
|
*
|
||||||
* Must hold base->lock when calling.
|
* Must hold base->lock when calling.
|
||||||
*/
|
*/
|
||||||
static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
|
static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
|
||||||
{
|
{
|
||||||
|
if (alarm->state & ALARMTIMER_STATE_ENQUEUED)
|
||||||
|
timerqueue_del(&base->timerqueue, &alarm->node);
|
||||||
|
|
||||||
timerqueue_add(&base->timerqueue, &alarm->node);
|
timerqueue_add(&base->timerqueue, &alarm->node);
|
||||||
alarm->state |= ALARMTIMER_STATE_ENQUEUED;
|
alarm->state |= ALARMTIMER_STATE_ENQUEUED;
|
||||||
|
|
||||||
if (&alarm->node == timerqueue_getnext(&base->timerqueue)) {
|
|
||||||
hrtimer_try_to_cancel(&base->timer);
|
|
||||||
hrtimer_start(&base->timer, alarm->node.expires,
|
|
||||||
HRTIMER_MODE_ABS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* alarmtimer_remove - Removes an alarm timer from an alarm_base timerqueue
|
* alarmtimer_dequeue - Removes an alarm timer from an alarm_base timerqueue
|
||||||
* @base: pointer to the base where the timer is running
|
* @base: pointer to the base where the timer is running
|
||||||
* @alarm: pointer to alarm being removed
|
* @alarm: pointer to alarm being removed
|
||||||
*
|
*
|
||||||
* Removes alarm to a alarm_base timerqueue and if necessary sets
|
* Removes alarm to a alarm_base timerqueue
|
||||||
* a new timer to run.
|
|
||||||
*
|
*
|
||||||
* Must hold base->lock when calling.
|
* Must hold base->lock when calling.
|
||||||
*/
|
*/
|
||||||
static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
|
static void alarmtimer_dequeue(struct alarm_base *base, struct alarm *alarm)
|
||||||
{
|
{
|
||||||
struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue);
|
|
||||||
|
|
||||||
if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED))
|
if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
timerqueue_del(&base->timerqueue, &alarm->node);
|
timerqueue_del(&base->timerqueue, &alarm->node);
|
||||||
alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
|
alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
|
||||||
|
|
||||||
if (next == &alarm->node) {
|
|
||||||
hrtimer_try_to_cancel(&base->timer);
|
|
||||||
next = timerqueue_getnext(&base->timerqueue);
|
|
||||||
if (!next)
|
|
||||||
return;
|
|
||||||
hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,42 +174,23 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
|
||||||
*/
|
*/
|
||||||
static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
|
static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
|
||||||
{
|
{
|
||||||
struct alarm_base *base = container_of(timer, struct alarm_base, timer);
|
struct alarm *alarm = container_of(timer, struct alarm, timer);
|
||||||
struct timerqueue_node *next;
|
struct alarm_base *base = &alarm_bases[alarm->type];
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
ktime_t now;
|
|
||||||
int ret = HRTIMER_NORESTART;
|
int ret = HRTIMER_NORESTART;
|
||||||
int restart = ALARMTIMER_NORESTART;
|
int restart = ALARMTIMER_NORESTART;
|
||||||
|
|
||||||
spin_lock_irqsave(&base->lock, flags);
|
spin_lock_irqsave(&base->lock, flags);
|
||||||
now = base->gettime();
|
alarmtimer_dequeue(base, alarm);
|
||||||
while ((next = timerqueue_getnext(&base->timerqueue))) {
|
spin_unlock_irqrestore(&base->lock, flags);
|
||||||
struct alarm *alarm;
|
|
||||||
ktime_t expired = next->expires;
|
|
||||||
|
|
||||||
if (expired.tv64 > now.tv64)
|
if (alarm->function)
|
||||||
break;
|
restart = alarm->function(alarm, base->gettime());
|
||||||
|
|
||||||
alarm = container_of(next, struct alarm, node);
|
spin_lock_irqsave(&base->lock, flags);
|
||||||
|
if (restart != ALARMTIMER_NORESTART) {
|
||||||
timerqueue_del(&base->timerqueue, &alarm->node);
|
hrtimer_set_expires(&alarm->timer, alarm->node.expires);
|
||||||
alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
|
alarmtimer_enqueue(base, alarm);
|
||||||
|
|
||||||
alarm->state |= ALARMTIMER_STATE_CALLBACK;
|
|
||||||
spin_unlock_irqrestore(&base->lock, flags);
|
|
||||||
if (alarm->function)
|
|
||||||
restart = alarm->function(alarm, now);
|
|
||||||
spin_lock_irqsave(&base->lock, flags);
|
|
||||||
alarm->state &= ~ALARMTIMER_STATE_CALLBACK;
|
|
||||||
|
|
||||||
if (restart != ALARMTIMER_NORESTART) {
|
|
||||||
timerqueue_add(&base->timerqueue, &alarm->node);
|
|
||||||
alarm->state |= ALARMTIMER_STATE_ENQUEUED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next) {
|
|
||||||
hrtimer_set_expires(&base->timer, next->expires);
|
|
||||||
ret = HRTIMER_RESTART;
|
ret = HRTIMER_RESTART;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&base->lock, flags);
|
spin_unlock_irqrestore(&base->lock, flags);
|
||||||
|
@ -250,6 +217,7 @@ static int alarmtimer_suspend(struct device *dev)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct rtc_device *rtc;
|
struct rtc_device *rtc;
|
||||||
int i;
|
int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&freezer_delta_lock, flags);
|
spin_lock_irqsave(&freezer_delta_lock, flags);
|
||||||
min = freezer_delta;
|
min = freezer_delta;
|
||||||
|
@ -279,8 +247,10 @@ static int alarmtimer_suspend(struct device *dev)
|
||||||
if (min.tv64 == 0)
|
if (min.tv64 == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* XXX - Should we enforce a minimum sleep time? */
|
if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
|
||||||
WARN_ON(min.tv64 < NSEC_PER_SEC);
|
__pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup an rtc timer to fire that far in the future */
|
/* Setup an rtc timer to fire that far in the future */
|
||||||
rtc_timer_cancel(rtc, &rtctimer);
|
rtc_timer_cancel(rtc, &rtctimer);
|
||||||
|
@ -288,9 +258,11 @@ static int alarmtimer_suspend(struct device *dev)
|
||||||
now = rtc_tm_to_ktime(tm);
|
now = rtc_tm_to_ktime(tm);
|
||||||
now = ktime_add(now, min);
|
now = ktime_add(now, min);
|
||||||
|
|
||||||
rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
|
/* Set alarm, if in the past reject suspend briefly to handle */
|
||||||
|
ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
|
||||||
return 0;
|
if (ret < 0)
|
||||||
|
__pm_wakeup_event(ws, MSEC_PER_SEC);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static int alarmtimer_suspend(struct device *dev)
|
static int alarmtimer_suspend(struct device *dev)
|
||||||
|
@ -324,6 +296,9 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
|
||||||
enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
|
enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
|
||||||
{
|
{
|
||||||
timerqueue_init(&alarm->node);
|
timerqueue_init(&alarm->node);
|
||||||
|
hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid,
|
||||||
|
HRTIMER_MODE_ABS);
|
||||||
|
alarm->timer.function = alarmtimer_fired;
|
||||||
alarm->function = function;
|
alarm->function = function;
|
||||||
alarm->type = type;
|
alarm->type = type;
|
||||||
alarm->state = ALARMTIMER_STATE_INACTIVE;
|
alarm->state = ALARMTIMER_STATE_INACTIVE;
|
||||||
|
@ -334,17 +309,19 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
|
||||||
* @alarm: ptr to alarm to set
|
* @alarm: ptr to alarm to set
|
||||||
* @start: time to run the alarm
|
* @start: time to run the alarm
|
||||||
*/
|
*/
|
||||||
void alarm_start(struct alarm *alarm, ktime_t start)
|
int alarm_start(struct alarm *alarm, ktime_t start)
|
||||||
{
|
{
|
||||||
struct alarm_base *base = &alarm_bases[alarm->type];
|
struct alarm_base *base = &alarm_bases[alarm->type];
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&base->lock, flags);
|
spin_lock_irqsave(&base->lock, flags);
|
||||||
if (alarmtimer_active(alarm))
|
|
||||||
alarmtimer_remove(base, alarm);
|
|
||||||
alarm->node.expires = start;
|
alarm->node.expires = start;
|
||||||
alarmtimer_enqueue(base, alarm);
|
alarmtimer_enqueue(base, alarm);
|
||||||
|
ret = hrtimer_start(&alarm->timer, alarm->node.expires,
|
||||||
|
HRTIMER_MODE_ABS);
|
||||||
spin_unlock_irqrestore(&base->lock, flags);
|
spin_unlock_irqrestore(&base->lock, flags);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,18 +335,12 @@ int alarm_try_to_cancel(struct alarm *alarm)
|
||||||
{
|
{
|
||||||
struct alarm_base *base = &alarm_bases[alarm->type];
|
struct alarm_base *base = &alarm_bases[alarm->type];
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = -1;
|
int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&base->lock, flags);
|
spin_lock_irqsave(&base->lock, flags);
|
||||||
|
ret = hrtimer_try_to_cancel(&alarm->timer);
|
||||||
if (alarmtimer_callback_running(alarm))
|
if (ret >= 0)
|
||||||
goto out;
|
alarmtimer_dequeue(base, alarm);
|
||||||
|
|
||||||
if (alarmtimer_is_queued(alarm)) {
|
|
||||||
alarmtimer_remove(base, alarm);
|
|
||||||
ret = 1;
|
|
||||||
} else
|
|
||||||
ret = 0;
|
|
||||||
out:
|
|
||||||
spin_unlock_irqrestore(&base->lock, flags);
|
spin_unlock_irqrestore(&base->lock, flags);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -802,10 +773,6 @@ static int __init alarmtimer_init(void)
|
||||||
for (i = 0; i < ALARM_NUMTYPE; i++) {
|
for (i = 0; i < ALARM_NUMTYPE; i++) {
|
||||||
timerqueue_init_head(&alarm_bases[i].timerqueue);
|
timerqueue_init_head(&alarm_bases[i].timerqueue);
|
||||||
spin_lock_init(&alarm_bases[i].lock);
|
spin_lock_init(&alarm_bases[i].lock);
|
||||||
hrtimer_init(&alarm_bases[i].timer,
|
|
||||||
alarm_bases[i].base_clockid,
|
|
||||||
HRTIMER_MODE_ABS);
|
|
||||||
alarm_bases[i].timer.function = alarmtimer_fired;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error = alarmtimer_rtc_interface_setup();
|
error = alarmtimer_rtc_interface_setup();
|
||||||
|
@ -821,6 +788,7 @@ static int __init alarmtimer_init(void)
|
||||||
error = PTR_ERR(pdev);
|
error = PTR_ERR(pdev);
|
||||||
goto out_drv;
|
goto out_drv;
|
||||||
}
|
}
|
||||||
|
ws = wakeup_source_register("alarmtimer");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_drv:
|
out_drv:
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* requested HZ value. It is also not recommended
|
* requested HZ value. It is also not recommended
|
||||||
* for "tick-less" systems.
|
* for "tick-less" systems.
|
||||||
*/
|
*/
|
||||||
#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/SHIFTED_HZ))
|
#define NSEC_PER_JIFFY ((NSEC_PER_SEC+HZ/2)/HZ)
|
||||||
|
|
||||||
/* Since jiffies uses a simple NSEC_PER_JIFFY multiplier
|
/* Since jiffies uses a simple NSEC_PER_JIFFY multiplier
|
||||||
* conversion, the .shift value could be zero. However
|
* conversion, the .shift value could be zero. However
|
||||||
|
@ -95,3 +95,33 @@ struct clocksource * __init __weak clocksource_default_clock(void)
|
||||||
{
|
{
|
||||||
return &clocksource_jiffies;
|
return &clocksource_jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct clocksource refined_jiffies;
|
||||||
|
|
||||||
|
int register_refined_jiffies(long cycles_per_second)
|
||||||
|
{
|
||||||
|
u64 nsec_per_tick, shift_hz;
|
||||||
|
long cycles_per_tick;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
refined_jiffies = clocksource_jiffies;
|
||||||
|
refined_jiffies.name = "refined-jiffies";
|
||||||
|
refined_jiffies.rating++;
|
||||||
|
|
||||||
|
/* Calc cycles per tick */
|
||||||
|
cycles_per_tick = (cycles_per_second + HZ/2)/HZ;
|
||||||
|
/* shift_hz stores hz<<8 for extra accuracy */
|
||||||
|
shift_hz = (u64)cycles_per_second << 8;
|
||||||
|
shift_hz += cycles_per_tick/2;
|
||||||
|
do_div(shift_hz, cycles_per_tick);
|
||||||
|
/* Calculate nsec_per_tick using shift_hz */
|
||||||
|
nsec_per_tick = (u64)NSEC_PER_SEC << 8;
|
||||||
|
nsec_per_tick += (u32)shift_hz/2;
|
||||||
|
do_div(nsec_per_tick, (u32)shift_hz);
|
||||||
|
|
||||||
|
refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT;
|
||||||
|
|
||||||
|
clocksource_register(&refined_jiffies);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/timekeeper_internal.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/percpu.h>
|
#include <linux/percpu.h>
|
||||||
|
@ -21,61 +22,6 @@
|
||||||
#include <linux/tick.h>
|
#include <linux/tick.h>
|
||||||
#include <linux/stop_machine.h>
|
#include <linux/stop_machine.h>
|
||||||
|
|
||||||
/* Structure holding internal timekeeping values. */
|
|
||||||
struct timekeeper {
|
|
||||||
/* Current clocksource used for timekeeping. */
|
|
||||||
struct clocksource *clock;
|
|
||||||
/* NTP adjusted clock multiplier */
|
|
||||||
u32 mult;
|
|
||||||
/* The shift value of the current clocksource. */
|
|
||||||
u32 shift;
|
|
||||||
/* Number of clock cycles in one NTP interval. */
|
|
||||||
cycle_t cycle_interval;
|
|
||||||
/* Number of clock shifted nano seconds in one NTP interval. */
|
|
||||||
u64 xtime_interval;
|
|
||||||
/* shifted nano seconds left over when rounding cycle_interval */
|
|
||||||
s64 xtime_remainder;
|
|
||||||
/* Raw nano seconds accumulated per NTP interval. */
|
|
||||||
u32 raw_interval;
|
|
||||||
|
|
||||||
/* Current CLOCK_REALTIME time in seconds */
|
|
||||||
u64 xtime_sec;
|
|
||||||
/* Clock shifted nano seconds */
|
|
||||||
u64 xtime_nsec;
|
|
||||||
|
|
||||||
/* Difference between accumulated time and NTP time in ntp
|
|
||||||
* shifted nano seconds. */
|
|
||||||
s64 ntp_error;
|
|
||||||
/* Shift conversion between clock shifted nano seconds and
|
|
||||||
* ntp shifted nano seconds. */
|
|
||||||
u32 ntp_error_shift;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* wall_to_monotonic is what we need to add to xtime (or xtime corrected
|
|
||||||
* for sub jiffie times) to get to monotonic time. Monotonic is pegged
|
|
||||||
* at zero at system boot time, so wall_to_monotonic will be negative,
|
|
||||||
* however, we will ALWAYS keep the tv_nsec part positive so we can use
|
|
||||||
* the usual normalization.
|
|
||||||
*
|
|
||||||
* wall_to_monotonic is moved after resume from suspend for the
|
|
||||||
* monotonic time not to jump. We need to add total_sleep_time to
|
|
||||||
* wall_to_monotonic to get the real boot based time offset.
|
|
||||||
*
|
|
||||||
* - wall_to_monotonic is no longer the boot time, getboottime must be
|
|
||||||
* used instead.
|
|
||||||
*/
|
|
||||||
struct timespec wall_to_monotonic;
|
|
||||||
/* Offset clock monotonic -> clock realtime */
|
|
||||||
ktime_t offs_real;
|
|
||||||
/* time spent in suspend */
|
|
||||||
struct timespec total_sleep_time;
|
|
||||||
/* Offset clock monotonic -> clock boottime */
|
|
||||||
ktime_t offs_boot;
|
|
||||||
/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
|
|
||||||
struct timespec raw_time;
|
|
||||||
/* Seqlock for all timekeeper values */
|
|
||||||
seqlock_t lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct timekeeper timekeeper;
|
static struct timekeeper timekeeper;
|
||||||
|
|
||||||
|
@ -96,15 +42,6 @@ static inline void tk_normalize_xtime(struct timekeeper *tk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct timespec tk_xtime(struct timekeeper *tk)
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
|
|
||||||
ts.tv_sec = tk->xtime_sec;
|
|
||||||
ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift);
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts)
|
static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts)
|
||||||
{
|
{
|
||||||
tk->xtime_sec = ts->tv_sec;
|
tk->xtime_sec = ts->tv_sec;
|
||||||
|
@ -246,14 +183,11 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
|
||||||
/* must hold write on timekeeper.lock */
|
/* must hold write on timekeeper.lock */
|
||||||
static void timekeeping_update(struct timekeeper *tk, bool clearntp)
|
static void timekeeping_update(struct timekeeper *tk, bool clearntp)
|
||||||
{
|
{
|
||||||
struct timespec xt;
|
|
||||||
|
|
||||||
if (clearntp) {
|
if (clearntp) {
|
||||||
tk->ntp_error = 0;
|
tk->ntp_error = 0;
|
||||||
ntp_clear();
|
ntp_clear();
|
||||||
}
|
}
|
||||||
xt = tk_xtime(tk);
|
update_vsyscall(tk);
|
||||||
update_vsyscall(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1113,7 +1047,7 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
|
||||||
accumulate_nsecs_to_secs(tk);
|
accumulate_nsecs_to_secs(tk);
|
||||||
|
|
||||||
/* Accumulate raw time */
|
/* Accumulate raw time */
|
||||||
raw_nsecs = tk->raw_interval << shift;
|
raw_nsecs = (u64)tk->raw_interval << shift;
|
||||||
raw_nsecs += tk->raw_time.tv_nsec;
|
raw_nsecs += tk->raw_time.tv_nsec;
|
||||||
if (raw_nsecs >= NSEC_PER_SEC) {
|
if (raw_nsecs >= NSEC_PER_SEC) {
|
||||||
u64 raw_secs = raw_nsecs;
|
u64 raw_secs = raw_nsecs;
|
||||||
|
@ -1130,6 +1064,33 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD
|
||||||
|
static inline void old_vsyscall_fixup(struct timekeeper *tk)
|
||||||
|
{
|
||||||
|
s64 remainder;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store only full nanoseconds into xtime_nsec after rounding
|
||||||
|
* it up and add the remainder to the error difference.
|
||||||
|
* XXX - This is necessary to avoid small 1ns inconsistnecies caused
|
||||||
|
* by truncating the remainder in vsyscalls. However, it causes
|
||||||
|
* additional work to be done in timekeeping_adjust(). Once
|
||||||
|
* the vsyscall implementations are converted to use xtime_nsec
|
||||||
|
* (shifted nanoseconds), and CONFIG_GENERIC_TIME_VSYSCALL_OLD
|
||||||
|
* users are removed, this can be killed.
|
||||||
|
*/
|
||||||
|
remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1);
|
||||||
|
tk->xtime_nsec -= remainder;
|
||||||
|
tk->xtime_nsec += 1ULL << tk->shift;
|
||||||
|
tk->ntp_error += remainder << tk->ntp_error_shift;
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define old_vsyscall_fixup(tk)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update_wall_time - Uses the current clocksource to increment the wall time
|
* update_wall_time - Uses the current clocksource to increment the wall time
|
||||||
*
|
*
|
||||||
|
@ -1141,7 +1102,6 @@ static void update_wall_time(void)
|
||||||
cycle_t offset;
|
cycle_t offset;
|
||||||
int shift = 0, maxshift;
|
int shift = 0, maxshift;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
s64 remainder;
|
|
||||||
|
|
||||||
write_seqlock_irqsave(&tk->lock, flags);
|
write_seqlock_irqsave(&tk->lock, flags);
|
||||||
|
|
||||||
|
@ -1183,20 +1143,11 @@ static void update_wall_time(void)
|
||||||
/* correct the clock when NTP error is too big */
|
/* correct the clock when NTP error is too big */
|
||||||
timekeeping_adjust(tk, offset);
|
timekeeping_adjust(tk, offset);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store only full nanoseconds into xtime_nsec after rounding
|
* XXX This can be killed once everyone converts
|
||||||
* it up and add the remainder to the error difference.
|
* to the new update_vsyscall.
|
||||||
* XXX - This is necessary to avoid small 1ns inconsistnecies caused
|
*/
|
||||||
* by truncating the remainder in vsyscalls. However, it causes
|
old_vsyscall_fixup(tk);
|
||||||
* additional work to be done in timekeeping_adjust(). Once
|
|
||||||
* the vsyscall implementations are converted to use xtime_nsec
|
|
||||||
* (shifted nanoseconds), this can be killed.
|
|
||||||
*/
|
|
||||||
remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1);
|
|
||||||
tk->xtime_nsec -= remainder;
|
|
||||||
tk->xtime_nsec += 1ULL << tk->shift;
|
|
||||||
tk->ntp_error += remainder << tk->ntp_error_shift;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally, make sure that after the rounding
|
* Finally, make sure that after the rounding
|
||||||
|
|
|
@ -63,6 +63,7 @@ EXPORT_SYMBOL(jiffies_64);
|
||||||
#define TVR_SIZE (1 << TVR_BITS)
|
#define TVR_SIZE (1 << TVR_BITS)
|
||||||
#define TVN_MASK (TVN_SIZE - 1)
|
#define TVN_MASK (TVN_SIZE - 1)
|
||||||
#define TVR_MASK (TVR_SIZE - 1)
|
#define TVR_MASK (TVR_SIZE - 1)
|
||||||
|
#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1))
|
||||||
|
|
||||||
struct tvec {
|
struct tvec {
|
||||||
struct list_head vec[TVN_SIZE];
|
struct list_head vec[TVN_SIZE];
|
||||||
|
@ -359,11 +360,12 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer)
|
||||||
vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
|
vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
/* If the timeout is larger than 0xffffffff on 64-bit
|
/* If the timeout is larger than MAX_TVAL (on 64-bit
|
||||||
* architectures then we use the maximum timeout:
|
* architectures or with CONFIG_BASE_SMALL=1) then we
|
||||||
|
* use the maximum timeout.
|
||||||
*/
|
*/
|
||||||
if (idx > 0xffffffffUL) {
|
if (idx > MAX_TVAL) {
|
||||||
idx = 0xffffffffUL;
|
idx = MAX_TVAL;
|
||||||
expires = idx + base->timer_jiffies;
|
expires = idx + base->timer_jiffies;
|
||||||
}
|
}
|
||||||
i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
|
i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
|
||||||
|
|
Loading…
Reference in New Issue