Skip to content

Commit

Permalink
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/tip/tip

Pull timer core updates from Thomas Gleixner.

* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  ia64: vsyscall: Add missing paranthesis
  alarmtimer: Don't call rtc_timer_init() when CONFIG_RTC_CLASS=n
  x86: vdso: Put declaration before code
  x86-64: Inline vdso clock_gettime helpers
  x86-64: Simplify and optimize vdso clock_gettime monotonic variants
  kernel-time: fix s/then/than/ spelling errors
  time: remove no_sync_cmos_clock
  time: Avoid scary backtraces when warning of > 11% adj
  alarmtimer: Make sure we initialize the rtctimer
  ntp: Fix leap-second hrtimer livelock
  x86, tsc: Skip refined tsc calibration on systems with reliable TSC
  rtc: Provide flag for rtc devices that don't support UIE
  ia64: vsyscall: Use seqcount instead of seqlock
  x86: vdso: Use seqcount instead of seqlock
  x86: vdso: Remove bogus locking in update_vsyscall_tz()
  time: Remove bogus comments
  time: Fix change_clocksource locking
  time: x86: Fix race switching from vsyscall to non-vsyscall clock
  • Loading branch information
Linus Torvalds committed Mar 29, 2012
2 parents 93f3788 + 646783a commit bcd5507
Show file tree
Hide file tree
Showing 18 changed files with 193 additions and 226 deletions.
4 changes: 2 additions & 2 deletions arch/ia64/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ void foo(void)
BLANK();

/* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
DEFINE(IA64_GTOD_LOCK_OFFSET,
offsetof (struct fsyscall_gtod_data_t, lock));
DEFINE(IA64_GTOD_SEQ_OFFSET,
offsetof (struct fsyscall_gtod_data_t, seq));
DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
offsetof (struct fsyscall_gtod_data_t, wall_time));
DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
Expand Down
2 changes: 1 addition & 1 deletion arch/ia64/kernel/fsys.S
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ ENTRY(fsys_set_tid_address)
FSYS_RETURN
END(fsys_set_tid_address)

#if IA64_GTOD_LOCK_OFFSET !=0
#if IA64_GTOD_SEQ_OFFSET !=0
#error fsys_gettimeofday incompatible with changes to struct fsyscall_gtod_data_t
#endif
#if IA64_ITC_JITTER_OFFSET !=0
Expand Down
2 changes: 1 addition & 1 deletion arch/ia64/kernel/fsyscall_gtod_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

struct fsyscall_gtod_data_t {
seqlock_t lock;
seqcount_t seq;
struct timespec wall_time;
struct timespec monotonic_time;
cycle_t clk_mask;
Expand Down
10 changes: 3 additions & 7 deletions arch/ia64/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@

static cycle_t itc_get_cycles(struct clocksource *cs);

struct fsyscall_gtod_data_t fsyscall_gtod_data = {
.lock = __SEQLOCK_UNLOCKED(fsyscall_gtod_data.lock),
};
struct fsyscall_gtod_data_t fsyscall_gtod_data;

struct itc_jitter_data_t itc_jitter_data;

Expand Down Expand Up @@ -459,9 +457,7 @@ void update_vsyscall_tz(void)
void update_vsyscall(struct timespec *wall, struct timespec *wtm,
struct clocksource *c, u32 mult)
{
unsigned long flags;

write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);
write_seqcount_begin(&fsyscall_gtod_data.seq);

/* copy fsyscall clock data */
fsyscall_gtod_data.clk_mask = c->mask;
Expand All @@ -484,6 +480,6 @@ void update_vsyscall(struct timespec *wall, struct timespec *wtm,
fsyscall_gtod_data.monotonic_time.tv_sec++;
}

write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
write_seqcount_end(&fsyscall_gtod_data.seq);
}

17 changes: 10 additions & 7 deletions arch/x86/include/asm/vgtod.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@
#include <linux/clocksource.h>

struct vsyscall_gtod_data {
seqlock_t lock;
seqcount_t seq;

/* open coded 'struct timespec' */
time_t wall_time_sec;
u32 wall_time_nsec;

struct timezone sys_tz;
struct { /* extract of a clocksource struct */
int vclock_mode;
cycle_t cycle_last;
cycle_t mask;
u32 mult;
u32 shift;
} clock;
struct timespec wall_to_monotonic;

/* open coded 'struct timespec' */
time_t wall_time_sec;
u32 wall_time_nsec;
u32 monotonic_time_nsec;
time_t monotonic_time_sec;

struct timezone sys_tz;
struct timespec wall_time_coarse;
struct timespec monotonic_time_coarse;
};
extern struct vsyscall_gtod_data vsyscall_gtod_data;

Expand Down
10 changes: 10 additions & 0 deletions arch/x86/kernel/tsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,16 @@ static int __init init_tsc_clocksource(void)
clocksource_tsc.rating = 0;
clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
}

/*
* Trust the results of the earlier calibration on systems
* exporting a reliable TSC.
*/
if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) {
clocksource_register_khz(&clocksource_tsc, tsc_khz);
return 0;
}

schedule_delayed_work(&tsc_irqwork, 0);
return 0;
}
Expand Down
25 changes: 12 additions & 13 deletions arch/x86/kernel/vsyscall_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@
#include "vsyscall_trace.h"

DEFINE_VVAR(int, vgetcpu_mode);
DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) =
{
.lock = __SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock),
};
DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data);

static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;

Expand All @@ -80,33 +77,35 @@ early_param("vsyscall", vsyscall_setup);

void update_vsyscall_tz(void)
{
unsigned long flags;

write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
/* sys_tz has changed */
vsyscall_gtod_data.sys_tz = sys_tz;
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}

void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
struct clocksource *clock, u32 mult)
{
unsigned long flags;
struct timespec monotonic;

write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
write_seqcount_begin(&vsyscall_gtod_data.seq);

/* copy vsyscall data */
vsyscall_gtod_data.clock.vclock_mode = clock->archdata.vclock_mode;
vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
vsyscall_gtod_data.clock.mask = clock->mask;
vsyscall_gtod_data.clock.mult = mult;
vsyscall_gtod_data.clock.shift = clock->shift;

vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
vsyscall_gtod_data.wall_to_monotonic = *wtm;

monotonic = timespec_add(*wall_time, *wtm);
vsyscall_gtod_data.monotonic_time_sec = monotonic.tv_sec;
vsyscall_gtod_data.monotonic_time_nsec = monotonic.tv_nsec;

vsyscall_gtod_data.wall_time_coarse = __current_kernel_time();
vsyscall_gtod_data.monotonic_time_coarse =
timespec_add(vsyscall_gtod_data.wall_time_coarse, *wtm);

write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
write_seqcount_end(&vsyscall_gtod_data.seq);
}

static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
Expand Down
135 changes: 67 additions & 68 deletions arch/x86/vdso/vclock_gettime.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,133 +70,132 @@ notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
return ret;
}

notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
{
long ret;

asm("syscall" : "=a" (ret) :
"0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
return ret;
}


notrace static inline long vgetns(void)
{
long v;
cycles_t cycles;
if (gtod->clock.vclock_mode == VCLOCK_TSC)
cycles = vread_tsc();
else
else if (gtod->clock.vclock_mode == VCLOCK_HPET)
cycles = vread_hpet();
else
return 0;
v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask;
return (v * gtod->clock.mult) >> gtod->clock.shift;
}

notrace static noinline int do_realtime(struct timespec *ts)
/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
notrace static int __always_inline do_realtime(struct timespec *ts)
{
unsigned long seq, ns;
int mode;

do {
seq = read_seqbegin(&gtod->lock);
seq = read_seqcount_begin(&gtod->seq);
mode = gtod->clock.vclock_mode;
ts->tv_sec = gtod->wall_time_sec;
ts->tv_nsec = gtod->wall_time_nsec;
ns = vgetns();
} while (unlikely(read_seqretry(&gtod->lock, seq)));
} while (unlikely(read_seqcount_retry(&gtod->seq, seq)));

timespec_add_ns(ts, ns);
return 0;
return mode;
}

notrace static noinline int do_monotonic(struct timespec *ts)
notrace static int do_monotonic(struct timespec *ts)
{
unsigned long seq, ns, secs;
unsigned long seq, ns;
int mode;

do {
seq = read_seqbegin(&gtod->lock);
secs = gtod->wall_time_sec;
ns = gtod->wall_time_nsec + vgetns();
secs += gtod->wall_to_monotonic.tv_sec;
ns += gtod->wall_to_monotonic.tv_nsec;
} while (unlikely(read_seqretry(&gtod->lock, seq)));

/* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec
* are all guaranteed to be nonnegative.
*/
while (ns >= NSEC_PER_SEC) {
ns -= NSEC_PER_SEC;
++secs;
}
ts->tv_sec = secs;
ts->tv_nsec = ns;
seq = read_seqcount_begin(&gtod->seq);
mode = gtod->clock.vclock_mode;
ts->tv_sec = gtod->monotonic_time_sec;
ts->tv_nsec = gtod->monotonic_time_nsec;
ns = vgetns();
} while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
timespec_add_ns(ts, ns);

return 0;
return mode;
}

notrace static noinline int do_realtime_coarse(struct timespec *ts)
notrace static int do_realtime_coarse(struct timespec *ts)
{
unsigned long seq;
do {
seq = read_seqbegin(&gtod->lock);
seq = read_seqcount_begin(&gtod->seq);
ts->tv_sec = gtod->wall_time_coarse.tv_sec;
ts->tv_nsec = gtod->wall_time_coarse.tv_nsec;
} while (unlikely(read_seqretry(&gtod->lock, seq)));
} while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
return 0;
}

notrace static noinline int do_monotonic_coarse(struct timespec *ts)
notrace static int do_monotonic_coarse(struct timespec *ts)
{
unsigned long seq, ns, secs;
unsigned long seq;
do {
seq = read_seqbegin(&gtod->lock);
secs = gtod->wall_time_coarse.tv_sec;
ns = gtod->wall_time_coarse.tv_nsec;
secs += gtod->wall_to_monotonic.tv_sec;
ns += gtod->wall_to_monotonic.tv_nsec;
} while (unlikely(read_seqretry(&gtod->lock, seq)));

/* wall_time_nsec and wall_to_monotonic.tv_nsec are
* guaranteed to be between 0 and NSEC_PER_SEC.
*/
if (ns >= NSEC_PER_SEC) {
ns -= NSEC_PER_SEC;
++secs;
}
ts->tv_sec = secs;
ts->tv_nsec = ns;
seq = read_seqcount_begin(&gtod->seq);
ts->tv_sec = gtod->monotonic_time_coarse.tv_sec;
ts->tv_nsec = gtod->monotonic_time_coarse.tv_nsec;
} while (unlikely(read_seqcount_retry(&gtod->seq, seq)));

return 0;
}

notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
int ret = VCLOCK_NONE;

switch (clock) {
case CLOCK_REALTIME:
if (likely(gtod->clock.vclock_mode != VCLOCK_NONE))
return do_realtime(ts);
ret = do_realtime(ts);
break;
case CLOCK_MONOTONIC:
if (likely(gtod->clock.vclock_mode != VCLOCK_NONE))
return do_monotonic(ts);
ret = do_monotonic(ts);
break;
case CLOCK_REALTIME_COARSE:
return do_realtime_coarse(ts);
case CLOCK_MONOTONIC_COARSE:
return do_monotonic_coarse(ts);
}

return vdso_fallback_gettime(clock, ts);
if (ret == VCLOCK_NONE)
return vdso_fallback_gettime(clock, ts);
return 0;
}
int clock_gettime(clockid_t, struct timespec *)
__attribute__((weak, alias("__vdso_clock_gettime")));

notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
{
long ret;
if (likely(gtod->clock.vclock_mode != VCLOCK_NONE)) {
if (likely(tv != NULL)) {
BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
offsetof(struct timespec, tv_nsec) ||
sizeof(*tv) != sizeof(struct timespec));
do_realtime((struct timespec *)tv);
tv->tv_usec /= 1000;
}
if (unlikely(tz != NULL)) {
/* Avoid memcpy. Some old compilers fail to inline it */
tz->tz_minuteswest = gtod->sys_tz.tz_minuteswest;
tz->tz_dsttime = gtod->sys_tz.tz_dsttime;
}
return 0;
long ret = VCLOCK_NONE;

if (likely(tv != NULL)) {
BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
offsetof(struct timespec, tv_nsec) ||
sizeof(*tv) != sizeof(struct timespec));
ret = do_realtime((struct timespec *)tv);
tv->tv_usec /= 1000;
}
asm("syscall" : "=a" (ret) :
"0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
return ret;
if (unlikely(tz != NULL)) {
/* Avoid memcpy. Some old compilers fail to inline it */
tz->tz_minuteswest = gtod->sys_tz.tz_minuteswest;
tz->tz_dsttime = gtod->sys_tz.tz_dsttime;
}

if (ret == VCLOCK_NONE)
return vdso_fallback_gtod(tv, tz);
return 0;
}
int gettimeofday(struct timeval *, struct timezone *)
__attribute__((weak, alias("__vdso_gettimeofday")));
Expand Down
5 changes: 5 additions & 0 deletions drivers/rtc/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,11 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
if (rtc->uie_rtctimer.enabled == enabled)
goto out;

if (rtc->uie_unsupported) {
err = -EINVAL;
goto out;
}

if (enabled) {
struct rtc_time tm;
ktime_t now, onesec;
Expand Down
2 changes: 2 additions & 0 deletions drivers/rtc/rtc-mpc5121.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op)
&mpc5200_rtc_ops, THIS_MODULE);
}

rtc->rtc->uie_unsupported = 1;

if (IS_ERR(rtc->rtc)) {
err = PTR_ERR(rtc->rtc);
goto out_free_irq;
Expand Down
3 changes: 2 additions & 1 deletion include/linux/rtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ struct rtc_device
struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
int pie_enabled;
struct work_struct irqwork;

/* Some hardware can't support UIE mode */
int uie_unsupported;

#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
struct work_struct uie_task;
Expand Down
Loading

0 comments on commit bcd5507

Please sign in to comment.