Commit a03fdb76 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (34 commits)
  time: Prevent 32 bit overflow with set_normalized_timespec()
  clocksource: Delay clocksource down rating to late boot
  clocksource: clocksource_select must be called with mutex locked
  clocksource: Resolve cpu hotplug dead lock with TSC unstable, fix crash
  timers: Drop a function prototype
  clocksource: Resolve cpu hotplug dead lock with TSC unstable
  timer.c: Fix S/390 comments
  timekeeping: Fix invalid getboottime() value
  timekeeping: Fix up read_persistent_clock() breakage on sh
  timekeeping: Increase granularity of read_persistent_clock(), build fix
  time: Introduce CLOCK_REALTIME_COARSE
  x86: Do not unregister PIT clocksource on PIT oneshot setup/shutdown
  clocksource: Avoid clocksource watchdog circular locking dependency
  clocksource: Protect the watchdog rating changes with clocksource_mutex
  clocksource: Call clocksource_change_rating() outside of watchdog_lock
  timekeeping: Introduce read_boot_clock
  timekeeping: Increase granularity of read_persistent_clock()
  timekeeping: Update clocksource with stop_machine
  timekeeping: Add timekeeper read_clock helper functions
  timekeeping: Move NTP adjusted clock multiplier to struct timekeeper
  ...

Fix trivial conflict due to MIPS lemote -> loongson renaming.
parents 202c4675 12e09337
......@@ -253,11 +253,8 @@ static struct clocksource clocksource_32k = {
*/
unsigned long long sched_clock(void)
{
unsigned long long ret;
ret = (unsigned long long)clocksource_32k.read(&clocksource_32k);
ret = (ret * clocksource_32k.mult_orig) >> clocksource_32k.shift;
return ret;
return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k),
clocksource_32k.mult, clocksource_32k.shift);
}
static int __init omap_init_clocksource_32k(void)
......
......@@ -72,9 +72,10 @@ static unsigned long read_rtc_mmss(void)
return mktime(year, mon, day, hour, min, sec);
}
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
return read_rtc_mmss();
ts->tv_sec = read_rtc_mmss();
ts->tv_nsec = 0;
}
int update_persistent_clock(struct timespec now)
......
......@@ -18,7 +18,7 @@
#include <asm/dec/ioasic.h>
#include <asm/dec/machtype.h>
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
unsigned int year, mon, day, hour, min, sec, real_year;
unsigned long flags;
......@@ -53,7 +53,8 @@ unsigned long read_persistent_clock(void)
year += real_year - 72 + 2000;
return mktime(year, mon, day, hour, min, sec);
ts->tv_sec = mktime(year, mon, day, hour, min, sec);
ts->tv_nsec = 0;
}
/*
......
......@@ -135,7 +135,7 @@ static void rtc_end_op(void)
lasat_ndelay(1000);
}
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
unsigned long word;
unsigned long flags;
......@@ -147,7 +147,8 @@ unsigned long read_persistent_clock(void)
rtc_end_op();
spin_unlock_irqrestore(&rtc_lock, flags);
return word;
ts->tv_sec = word;
ts->tv_nsec = 0;
}
int rtc_mips_set_mmss(unsigned long time)
......
......@@ -92,10 +92,12 @@ static int rtctmp;
int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp, loff_t *ppos)
{
struct timespec ts;
int r;
if (!write) {
rtctmp = read_persistent_clock();
read_persistent_clock(&ts);
rtctmp = ts.tv_sec;
/* check for time < 0 and set to 0 */
if (rtctmp < 0)
rtctmp = 0;
......@@ -134,9 +136,11 @@ int sysctl_lasat_rtc(ctl_table *table,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen)
{
struct timespec ts;
int r;
rtctmp = read_persistent_clock();
read_persistent_clock(&ts);
rtctmp = ts.tv_sec;
if (rtctmp < 0)
rtctmp = 0;
r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
......
......@@ -21,7 +21,8 @@ void __init plat_time_init(void)
mips_hpt_frequency = cpu_clock_freq / 2;
}
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
return mc146818_get_cmos_time();
ts->tv_sec = return mc146818_get_cmos_time();
ts->tv_nsec = 0;
}
......@@ -100,9 +100,10 @@ static unsigned int __init estimate_cpu_frequency(void)
return count;
}
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
return mc146818_get_cmos_time();
ts->tv_sec = mc146818_get_cmos_time();
ts->tv_nsec = 0;
}
static void __init plat_perf_setup(void)
......
......@@ -70,7 +70,7 @@ void __init bus_error_init(void)
}
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
unsigned int year, month, day, hour, min, sec;
unsigned long flags;
......@@ -92,7 +92,8 @@ unsigned long read_persistent_clock(void)
m48t37_base->control = 0x00;
spin_unlock_irqrestore(&rtc_lock, flags);
return mktime(year, month, day, hour, min, sec);
ts->tv_sec = mktime(year, month, day, hour, min, sec);
ts->tv_nsec = 0;
}
int rtc_mips_set_time(unsigned long tim)
......
......@@ -87,19 +87,26 @@ enum swarm_rtc_type {
enum swarm_rtc_type swarm_rtc_type;
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
unsigned long sec;
switch (swarm_rtc_type) {
case RTC_XICOR:
return xicor_get_time();
sec = xicor_get_time();
break;
case RTC_M4LT81:
return m41t81_get_time();
sec = m41t81_get_time();
break;
case RTC_NONE:
default:
return mktime(2000, 1, 1, 0, 0, 0);
sec = mktime(2000, 1, 1, 0, 0, 0);
break;
}
ts->tv_sec = sec;
tv->tv_nsec = 0;
}
int rtc_mips_set_time(unsigned long sec)
......
......@@ -182,7 +182,8 @@ void __init plat_time_init(void)
setup_pit_timer();
}
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
return -1;
ts->tv_sec = -1;
ts->tv_nsec = 0;
}
......@@ -774,11 +774,12 @@ int update_persistent_clock(struct timespec now)
return ppc_md.set_rtc_time(&tm);
}
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
struct rtc_time tm;
static int first = 1;
ts->tv_nsec = 0;
/* XXX this is a litle fragile but will work okay in the short term */
if (first) {
first = 0;
......@@ -786,14 +787,18 @@ unsigned long read_persistent_clock(void)
timezone_offset = ppc_md.time_init();
/* get_boot_time() isn't guaranteed to be safe to call late */
if (ppc_md.get_boot_time)
return ppc_md.get_boot_time() -timezone_offset;
if (ppc_md.get_boot_time) {
ts->tv_sec = ppc_md.get_boot_time() - timezone_offset;
return;
}
}
if (!ppc_md.get_rtc_time) {
ts->tv_sec = 0;
return;
}
if (!ppc_md.get_rtc_time)
return 0;
ppc_md.get_rtc_time(&tm);
return mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
ts->tv_sec = mktime(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
}
/* clocksource code */
......
......@@ -184,12 +184,14 @@ static void timing_alert_interrupt(__u16 code)
static void etr_reset(void);
static void stp_reset(void);
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
struct timespec ts;
tod_to_timeval(get_clock() - TOD_UNIX_EPOCH, ts);
}
tod_to_timeval(get_clock() - TOD_UNIX_EPOCH, &ts);
return ts.tv_sec;
void read_boot_clock(struct timespec *ts)
{
tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, ts);
}
static cycle_t read_tod_clock(struct clocksource *cs)
......@@ -207,6 +209,10 @@ static struct clocksource clocksource_tod = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
struct clocksource * __init clocksource_default_clock(void)
{
return &clocksource_tod;
}
void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
{
......@@ -244,10 +250,6 @@ void update_vsyscall_tz(void)
*/
void __init time_init(void)
{
struct timespec ts;
unsigned long flags;
cycle_t now;
/* Reset time synchronization interfaces. */
etr_reset();
stp_reset();
......@@ -263,26 +265,6 @@ void __init time_init(void)
if (clocksource_register(&clocksource_tod) != 0)
panic("Could not register TOD clock source");
/*
* The TOD clock is an accurate clock. The xtime should be
* initialized in a way that the difference between TOD and
* xtime is reasonably small. Too bad that timekeeping_init
* sets xtime.tv_nsec to zero. In addition the clock source
* change from the jiffies clock source to the TOD clock
* source add another error of up to 1/HZ second. The same
* function sets wall_to_monotonic to a value that is too
* small for /proc/uptime to be accurate.
* Reset xtime and wall_to_monotonic to sane values.
*/
write_seqlock_irqsave(&xtime_lock, flags);
now = get_clock();
tod_to_timeval(now - TOD_UNIX_EPOCH, &xtime);
clocksource_tod.cycle_last = now;
clocksource_tod.raw_time = xtime;
tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &ts);
set_normalized_timespec(&wall_to_monotonic, -ts.tv_sec, -ts.tv_nsec);
write_sequnlock_irqrestore(&xtime_lock, flags);
/* Enable TOD clock interrupts on the boot cpu. */
init_cpu_timer();
......
......@@ -39,11 +39,9 @@ void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
#ifdef CONFIG_GENERIC_CMOS_UPDATE
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
struct timespec tv;
rtc_sh_get_time(&tv);
return tv.tv_sec;
rtc_sh_get_time(ts);
}
int update_persistent_clock(struct timespec now)
......
......@@ -21,6 +21,7 @@ struct vsyscall_gtod_data {
u32 shift;
} clock;
struct timespec wall_to_monotonic;
struct timespec wall_time_coarse;
};
extern struct vsyscall_gtod_data __vsyscall_gtod_data
__section_vsyscall_gtod_data;
......
......@@ -19,12 +19,6 @@
DEFINE_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock);
#ifdef CONFIG_X86_32
static void pit_disable_clocksource(void);
#else
static inline void pit_disable_clocksource(void) { }
#endif
/*
* HPET replaces the PIT, when enabled. So we need to know, which of
* the two timers is used
......@@ -57,12 +51,10 @@ static void init_pit_timer(enum clock_event_mode mode,
outb_pit(0, PIT_CH0);
outb_pit(0, PIT_CH0);
}
pit_disable_clocksource();
break;
case CLOCK_EVT_MODE_ONESHOT:
/* One shot setup */
pit_disable_clocksource();
outb_pit(0x38, PIT_MODE);
break;
......@@ -200,17 +192,6 @@ static struct clocksource pit_cs = {
.shift = 20,
};
static void pit_disable_clocksource(void)
{
/*
* Use mult to check whether it is registered or not
*/
if (pit_cs.mult) {
clocksource_unregister(&pit_cs);
pit_cs.mult = 0;
}
}
static int __init init_pit_clocksource(void)
{
/*
......
......@@ -178,7 +178,7 @@ static int set_rtc_mmss(unsigned long nowtime)
}
/* not static: needed by APM */
unsigned long read_persistent_clock(void)
void read_persistent_clock(struct timespec *ts)
{
unsigned long retval, flags;
......@@ -186,7 +186,8 @@ unsigned long read_persistent_clock(void)
retval = get_wallclock();
spin_unlock_irqrestore(&rtc_lock, flags);
return retval;
ts->tv_sec = retval;
ts->tv_nsec = 0;
}
int update_persistent_clock(struct timespec now)
......
......@@ -744,10 +744,16 @@ static cycle_t __vsyscall_fn vread_tsc(void)
}
#endif
static void resume_tsc(void)
{
clocksource_tsc.cycle_last = 0;
}
static struct clocksource clocksource_tsc = {
.name = "tsc",
.rating = 300,
.read = read_tsc,
.resume = resume_tsc,
.mask = CLOCKSOURCE_MASK(64),
.shift = 22,
.flags = CLOCK_SOURCE_IS_CONTINUOUS |
......@@ -761,12 +767,14 @@ void mark_tsc_unstable(char *reason)
{
if (!tsc_unstable) {
tsc_unstable = 1;
printk("Marking TSC unstable due to %s\n", reason);
printk(KERN_INFO "Marking TSC unstable due to %s\n", reason);
/* Change only the rating, when not registered */
if (clocksource_tsc.mult)
clocksource_change_rating(&clocksource_tsc, 0);
else
clocksource_mark_unstable(&clocksource_tsc);
else {
clocksource_tsc.flags |= CLOCK_SOURCE_UNSTABLE;
clocksource_tsc.rating = 0;
}
}
}
......
......@@ -87,6 +87,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
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 = wall_to_monotonic;
vsyscall_gtod_data.wall_time_coarse = __current_kernel_time();
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}
......
......@@ -86,14 +86,47 @@ notrace static noinline int do_monotonic(struct timespec *ts)
return 0;
}
notrace static noinline int do_realtime_coarse(struct timespec *ts)
{
unsigned long seq;
do {
seq = read_seqbegin(&gtod->lock);
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)));
return 0;
}
notrace static noinline int do_monotonic_coarse(struct timespec *ts)
{
unsigned long seq, ns, secs;
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)));
vset_normalized_timespec(ts, secs, ns);
return 0;
}
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
if (likely(gtod->sysctl_enabled && gtod->clock.vread))
if (likely(gtod->sysctl_enabled))
switch (clock) {
case CLOCK_REALTIME:
return do_realtime(ts);
if (likely(gtod->clock.vread))
return do_realtime(ts);
break;
case CLOCK_MONOTONIC:
return do_monotonic(ts);
if (likely(gtod->clock.vread))
return 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);
}
......
......@@ -59,9 +59,8 @@ static struct irqaction timer_irqaction = {
void __init time_init(void)
{
xtime.tv_nsec = 0;
xtime.tv_sec = read_persistent_clock();
/* FIXME: xtime&wall_to_monotonic are set in timekeeping_init. */
read_persistent_clock(&xtime);
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
......
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