Commit 90889a63 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge branch 'fortglx/3.9/time' of git://git.linaro.org/people/jstultz/linux into timers/core

Trivial conflict in arch/x86/Kconfig
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parents a9037430 6f16eebe
...@@ -6598,7 +6598,7 @@ F: drivers/dma/dw_dmac_regs.h ...@@ -6598,7 +6598,7 @@ F: drivers/dma/dw_dmac_regs.h
F: drivers/dma/dw_dmac.c F: drivers/dma/dw_dmac.c
TIMEKEEPING, NTP TIMEKEEPING, NTP
M: John Stultz <johnstul@us.ibm.com> M: John Stultz <john.stultz@linaro.org>
M: Thomas Gleixner <tglx@linutronix.de> M: Thomas Gleixner <tglx@linutronix.de>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
S: Supported S: Supported
......
...@@ -668,7 +668,7 @@ int update_persistent_clock(struct timespec now) ...@@ -668,7 +668,7 @@ int update_persistent_clock(struct timespec now)
struct rtc_time tm; struct rtc_time tm;
if (!ppc_md.set_rtc_time) if (!ppc_md.set_rtc_time)
return 0; return -ENODEV;
to_tm(now.tv_sec + 1 + timezone_offset, &tm); to_tm(now.tv_sec + 1 + timezone_offset, &tm);
tm.tm_year -= 1900; tm.tm_year -= 1900;
......
...@@ -106,6 +106,7 @@ config X86 ...@@ -106,6 +106,7 @@ config X86
select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
select GENERIC_TIME_VSYSCALL if X86_64 select GENERIC_TIME_VSYSCALL if X86_64
select KTIME_SCALAR if X86_32 select KTIME_SCALAR if X86_32
select ALWAYS_USE_PERSISTENT_CLOCK
select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER
select HAVE_CONTEXT_TRACKING if X86_64 select HAVE_CONTEXT_TRACKING if X86_64
......
...@@ -623,7 +623,8 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) ...@@ -623,7 +623,8 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
ns_now = __cycles_2_ns(tsc_now); ns_now = __cycles_2_ns(tsc_now);
if (cpu_khz) { if (cpu_khz) {
*scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz; *scale = ((NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR) +
cpu_khz / 2) / cpu_khz;
*offset = ns_now - mult_frac(tsc_now, *scale, *offset = ns_now - mult_frac(tsc_now, *scale,
(1UL << CYC2NS_SCALE_FACTOR)); (1UL << CYC2NS_SCALE_FACTOR));
} }
......
...@@ -20,14 +20,24 @@ if RTC_CLASS ...@@ -20,14 +20,24 @@ if RTC_CLASS
config RTC_HCTOSYS config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume" bool "Set system time from RTC on startup and resume"
default y default y
depends on !ALWAYS_USE_PERSISTENT_CLOCK
help help
If you say yes here, the system time (wall clock) will be set using If you say yes here, the system time (wall clock) will be set using
the value read from a specified RTC device. This is useful to avoid the value read from a specified RTC device. This is useful to avoid
unnecessary fsck runs at boot time, and to network better. unnecessary fsck runs at boot time, and to network better.
config RTC_SYSTOHC
bool "Set the RTC time based on NTP synchronization"
default y
depends on !ALWAYS_USE_PERSISTENT_CLOCK
help
If you say yes here, the system time (wall clock) will be stored
in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
minutes if userspace reports synchronized NTP status.
config RTC_HCTOSYS_DEVICE config RTC_HCTOSYS_DEVICE
string "RTC used to set the system time" string "RTC used to set the system time"
depends on RTC_HCTOSYS = y depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y
default "rtc0" default "rtc0"
help help
The RTC device that will be used to (re)initialize the system The RTC device that will be used to (re)initialize the system
......
...@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG ...@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG
obj-$(CONFIG_RTC_LIB) += rtc-lib.o obj-$(CONFIG_RTC_LIB) += rtc-lib.o
obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
obj-$(CONFIG_RTC_SYSTOHC) += systohc.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o rtc-core-y := class.o interface.o
......
...@@ -50,6 +50,10 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) ...@@ -50,6 +50,10 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg)
struct rtc_device *rtc = to_rtc_device(dev); struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm; struct rtc_time tm;
struct timespec delta, delta_delta; struct timespec delta, delta_delta;
if (has_persistent_clock())
return 0;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0; return 0;
...@@ -88,6 +92,9 @@ static int rtc_resume(struct device *dev) ...@@ -88,6 +92,9 @@ static int rtc_resume(struct device *dev)
struct timespec new_system, new_rtc; struct timespec new_system, new_rtc;
struct timespec sleep_time; struct timespec sleep_time;
if (has_persistent_clock())
return 0;
rtc_hctosys_ret = -ENODEV; rtc_hctosys_ret = -ENODEV;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0; return 0;
......
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
*/
#include <linux/rtc.h>
#include <linux/time.h>
/**
* rtc_set_ntp_time - Save NTP synchronized time to the RTC
* @now: Current time of day
*
* Replacement for the NTP platform function update_persistent_clock
* that stores time for later retrieval by rtc_hctosys.
*
* Returns 0 on successful RTC update, -ENODEV if a RTC update is not
* possible at all, and various other -errno for specific temporary failure
* cases.
*
* If temporary failure is indicated the caller should try again 'soon'
*/
int rtc_set_ntp_time(struct timespec now)
{
struct rtc_device *rtc;
struct rtc_time tm;
int err = -ENODEV;
if (now.tv_nsec < (NSEC_PER_SEC >> 1))
rtc_time_to_tm(now.tv_sec, &tm);
else
rtc_time_to_tm(now.tv_sec + 1, &tm);
rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
if (rtc) {
/* rtc_hctosys exclusively uses UTC, so we call set_time here,
* not set_mmss. */
if (rtc->ops && (rtc->ops->set_time || rtc->ops->set_mmss))
err = rtc_set_time(rtc, &tm);
rtc_class_close(rtc);
}
return err;
}
...@@ -167,12 +167,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, ...@@ -167,12 +167,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
{ {
char *hdr; char *hdr;
struct timeval timestamp; struct timespec timestamp;
size_t len; size_t len;
do_gettimeofday(&timestamp); /* Report zeroed timestamp if called before timekeeping has resumed. */
if (__getnstimeofday(&timestamp)) {
timestamp.tv_sec = 0;
timestamp.tv_nsec = 0;
}
hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n", hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
(long)timestamp.tv_sec, (long)timestamp.tv_usec); (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000));
WARN_ON_ONCE(!hdr); WARN_ON_ONCE(!hdr);
len = hdr ? strlen(hdr) : 0; len = hdr ? strlen(hdr) : 0;
persistent_ram_write(prz, hdr, len); persistent_ram_write(prz, hdr, len);
......
...@@ -138,6 +138,7 @@ extern void rtc_device_unregister(struct rtc_device *rtc); ...@@ -138,6 +138,7 @@ extern void rtc_device_unregister(struct rtc_device *rtc);
extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs); extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs);
extern int rtc_set_ntp_time(struct timespec now);
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
extern int rtc_read_alarm(struct rtc_device *rtc, extern int rtc_read_alarm(struct rtc_device *rtc,
struct rtc_wkalrm *alrm); struct rtc_wkalrm *alrm);
......
...@@ -115,6 +115,17 @@ static inline bool timespec_valid_strict(const struct timespec *ts) ...@@ -115,6 +115,17 @@ static inline bool timespec_valid_strict(const struct timespec *ts)
return true; return true;
} }
extern bool persistent_clock_exist;
#ifdef ALWAYS_USE_PERSISTENT_CLOCK
#define has_persistent_clock() true
#else
static inline bool has_persistent_clock(void)
{
return persistent_clock_exist;
}
#endif
extern void read_persistent_clock(struct timespec *ts); extern void read_persistent_clock(struct timespec *ts);
extern void read_boot_clock(struct timespec *ts); extern void read_boot_clock(struct timespec *ts);
extern int update_persistent_clock(struct timespec now); extern int update_persistent_clock(struct timespec now);
...@@ -158,6 +169,7 @@ extern int do_setitimer(int which, struct itimerval *value, ...@@ -158,6 +169,7 @@ extern int do_setitimer(int which, struct itimerval *value,
struct itimerval *ovalue); struct itimerval *ovalue);
extern unsigned int alarm_setitimer(unsigned int seconds); extern unsigned int alarm_setitimer(unsigned int seconds);
extern int do_getitimer(int which, struct itimerval *value); extern int do_getitimer(int which, struct itimerval *value);
extern int __getnstimeofday(struct timespec *tv);
extern void getnstimeofday(struct timespec *tv); extern void getnstimeofday(struct timespec *tv);
extern void getrawmonotonic(struct timespec *ts); extern void getrawmonotonic(struct timespec *ts);
extern void getnstime_raw_and_real(struct timespec *ts_raw, extern void getnstime_raw_and_real(struct timespec *ts_raw,
......
...@@ -997,7 +997,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, ...@@ -997,7 +997,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
err = kc->clock_adj(which_clock, &ktx); err = kc->clock_adj(which_clock, &ktx);
if (!err && copy_to_user(utx, &ktx, sizeof(ktx))) if (err >= 0 && copy_to_user(utx, &ktx, sizeof(ktx)))
return -EFAULT; return -EFAULT;
return err; return err;
......
...@@ -12,6 +12,11 @@ config CLOCKSOURCE_WATCHDOG ...@@ -12,6 +12,11 @@ config CLOCKSOURCE_WATCHDOG
config ARCH_CLOCKSOURCE_DATA config ARCH_CLOCKSOURCE_DATA
bool bool
# Platforms has a persistent clock
config ALWAYS_USE_PERSISTENT_CLOCK
bool
default n
# Timekeeping vsyscall support # Timekeeping vsyscall support
config GENERIC_TIME_VSYSCALL config GENERIC_TIME_VSYSCALL
bool bool
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/rtc.h>
#include "tick-internal.h" #include "tick-internal.h"
...@@ -483,8 +484,7 @@ int second_overflow(unsigned long secs) ...@@ -483,8 +484,7 @@ int second_overflow(unsigned long secs)
return leap; return leap;
} }
#ifdef CONFIG_GENERIC_CMOS_UPDATE #if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
static void sync_cmos_clock(struct work_struct *work); static void sync_cmos_clock(struct work_struct *work);
static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
...@@ -510,14 +510,22 @@ static void sync_cmos_clock(struct work_struct *work) ...@@ -510,14 +510,22 @@ static void sync_cmos_clock(struct work_struct *work)
} }
getnstimeofday(&now); getnstimeofday(&now);
if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) {
fail = -ENODEV;
#ifdef CONFIG_GENERIC_CMOS_UPDATE
fail = update_persistent_clock(now); fail = update_persistent_clock(now);
#endif
#ifdef CONFIG_RTC_SYSTOHC
if (fail == -ENODEV)
fail = rtc_set_ntp_time(now);
#endif
}
next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2); next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2);
if (next.tv_nsec <= 0) if (next.tv_nsec <= 0)
next.tv_nsec += NSEC_PER_SEC; next.tv_nsec += NSEC_PER_SEC;
if (!fail) if (!fail || fail == -ENODEV)
next.tv_sec = 659; next.tv_sec = 659;
else else
next.tv_sec = 0; next.tv_sec = 0;
......
...@@ -29,6 +29,9 @@ static struct timekeeper timekeeper; ...@@ -29,6 +29,9 @@ static struct timekeeper timekeeper;
/* flag for if timekeeping is suspended */ /* flag for if timekeeping is suspended */
int __read_mostly timekeeping_suspended; int __read_mostly timekeeping_suspended;
/* Flag for if there is a persistent clock on this platform */
bool __read_mostly persistent_clock_exist = false;
static inline void tk_normalize_xtime(struct timekeeper *tk) static inline void tk_normalize_xtime(struct timekeeper *tk)
{ {
while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) {
...@@ -264,19 +267,18 @@ static void timekeeping_forward_now(struct timekeeper *tk) ...@@ -264,19 +267,18 @@ static void timekeeping_forward_now(struct timekeeper *tk)
} }
/** /**
* getnstimeofday - Returns the time of day in a timespec * __getnstimeofday - Returns the time of day in a timespec.
* @ts: pointer to the timespec to be set * @ts: pointer to the timespec to be set
* *
* Returns the time of day in a timespec. * Updates the time of day in the timespec.
* Returns 0 on success, or -ve when suspended (timespec will be undefined).
*/ */
void getnstimeofday(struct timespec *ts) int __getnstimeofday(struct timespec *ts)
{ {
struct timekeeper *tk = &timekeeper; struct timekeeper *tk = &timekeeper;
unsigned long seq; unsigned long seq;
s64 nsecs = 0; s64 nsecs = 0;
WARN_ON(timekeeping_suspended);
do { do {
seq = read_seqbegin(&tk->lock); seq = read_seqbegin(&tk->lock);
...@@ -287,6 +289,26 @@ void getnstimeofday(struct timespec *ts) ...@@ -287,6 +289,26 @@ void getnstimeofday(struct timespec *ts)
ts->tv_nsec = 0; ts->tv_nsec = 0;
timespec_add_ns(ts, nsecs); timespec_add_ns(ts, nsecs);
/*
* Do not bail out early, in case there were callers still using
* the value, even in the face of the WARN_ON.
*/
if (unlikely(timekeeping_suspended))
return -EAGAIN;
return 0;
}
EXPORT_SYMBOL(__getnstimeofday);
/**
* getnstimeofday - Returns the time of day in a timespec.
* @ts: pointer to the timespec to be set
*
* Returns the time of day in a timespec (WARN if suspended).
*/
void getnstimeofday(struct timespec *ts)
{
WARN_ON(__getnstimeofday(ts));
} }
EXPORT_SYMBOL(getnstimeofday); EXPORT_SYMBOL(getnstimeofday);
...@@ -640,12 +662,14 @@ void __init timekeeping_init(void) ...@@ -640,12 +662,14 @@ void __init timekeeping_init(void)
struct timespec now, boot, tmp; struct timespec now, boot, tmp;
read_persistent_clock(&now); read_persistent_clock(&now);
if (!timespec_valid_strict(&now)) { if (!timespec_valid_strict(&now)) {
pr_warn("WARNING: Persistent clock returned invalid value!\n" pr_warn("WARNING: Persistent clock returned invalid value!\n"
" Check your CMOS/BIOS settings.\n"); " Check your CMOS/BIOS settings.\n");
now.tv_sec = 0; now.tv_sec = 0;
now.tv_nsec = 0; now.tv_nsec = 0;
} } else if (now.tv_sec || now.tv_nsec)
persistent_clock_exist = true;
read_boot_clock(&boot); read_boot_clock(&boot);
if (!timespec_valid_strict(&boot)) { if (!timespec_valid_strict(&boot)) {
...@@ -718,11 +742,12 @@ void timekeeping_inject_sleeptime(struct timespec *delta) ...@@ -718,11 +742,12 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
{ {
struct timekeeper *tk = &timekeeper; struct timekeeper *tk = &timekeeper;
unsigned long flags; unsigned long flags;
struct timespec ts;
/* Make sure we don't set the clock twice */ /*
read_persistent_clock(&ts); * Make sure we don't set the clock twice, as timekeeping_resume()
if (!(ts.tv_sec == 0 && ts.tv_nsec == 0)) * already did it
*/
if (has_persistent_clock())
return; return;
write_seqlock_irqsave(&tk->lock, flags); write_seqlock_irqsave(&tk->lock, flags);
......
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