timer changes for v3.9
Subsystems (7)
Ingo Molnar
maintainerLinus,
Please pull the latest timers-core-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers-core-for-linus
HEAD: 36dfbbf136db0d645bacfd42ce7d9d6928ea532d timers/x86/hpet: Use HPET_COUNTER to specify the hpet counter in vread_hpet()
Main changes:
* ntp: Add CONFIG_RTC_SYSTOHC: a generic RTC driver facility complementing the existing CONFIG_RTC_HCTOSYS, which uses NTP to keep the hardware clock updated.
* posix-timers: Fix clock_adjtime to always return timex data on success. This is changing the ABI, but no breakage was expected and found - caution is warranted nevertheless.
* platform persistent clock improvements/cleanups.
* clockevents: refactor timer broadcast handling to be more generic and less duplicated with matching architecture code. (mostly ARM motivated.)
* various fixes and cleanups
Thanks,
Ingo
------------------>
Bernd Faust (1):
Round the calculated scale factor in set_cyc2ns_scale()
Bjorn Helgaas (1):
x86/time/rtc: Don't print extended CMOS year when reading RTC
Feng Tang (3):
timekeeping: Add persistent_clock_exist flag
rtc: Skip the suspend/resume handling if persistent clock exist
timekeeping: Add CONFIG_HAS_PERSISTENT_CLOCK option
Jason Gunthorpe (1):
NTP: Add a CONFIG_RTC_SYSTOHC configuration
John Stultz (3):
MAINTAINERS: Update John Stultz's email
x86: Select HAS_PERSISTENT_CLOCK on x86
timekeeping: Switch HAS_PERSISTENT_CLOCK to ALWAYS_USE_PERSISTENT_CLOCK
Kees Cook (1):
time: create __getnstimeofday for WARNless calls
Leonid Shatz (1):
hrtimer: Prevent hrtimer_enqueue_reprogram race
Mark Rutland (3):
clockevents: Add generic timer broadcast receiver
clockevents: Add generic timer broadcast function
clockevents: Fix generic broadcast for FEAT_C3STOP
Miroslav Lichvar (1):
posix-timers: Fix clock_adjtime to always return timex data on success
Prarit Bhargava (1):
time, Fix setting of hardware clock in NTP code
Satoru Takeuchi (1):
timers/x86/hpet: Use HPET_COUNTER to specify the hpet counter in vread_hpet()
Stanislaw Gruszka (1):
posix-cpu-timers: Fix nanosleep task_struct leak
MAINTAINERS | 2 +- arch/powerpc/kernel/time.c | 2 +- arch/x86/Kconfig | 1 + arch/x86/kernel/rtc.c | 1 - arch/x86/kernel/tsc.c | 3 ++- arch/x86/vdso/vclock_gettime.c | 2 +- drivers/rtc/Kconfig | 12 ++++++++++- drivers/rtc/Makefile | 1 + drivers/rtc/class.c | 7 +++++++ drivers/rtc/systohc.c | 44 +++++++++++++++++++++++++++++++++++++++++ fs/pstore/ram.c | 10 +++++++--- include/linux/clockchips.h | 9 +++++++++ include/linux/rtc.h | 1 + include/linux/time.h | 13 ++++++++++++ kernel/hrtimer.c | 36 ++++++++++++++++----------------- kernel/posix-cpu-timers.c | 23 +++++++++++++++++++-- kernel/posix-timers.c | 2 +- kernel/time.c | 8 ++++++++ kernel/time/Kconfig | 9 +++++++++ kernel/time/ntp.c | 22 ++++++++++++++++----- kernel/time/tick-broadcast.c | 38 ++++++++++++++++++++++++++++++++++- kernel/time/timekeeping.c | 45 ++++++++++++++++++++++++++++++++---------- 22 files changed, 245 insertions(+), 46 deletions(-) create mode 100644 drivers/rtc/systohc.c
MAINTAINERS +1 -1
@@ -6598,7 +6598,7 @@ F: drivers/dma/dw_dmac_regs.h F: drivers/dma/dw_dmac.c TIMEKEEPING, NTP -M: John Stultz <[email protected]> +M: John Stultz <[email protected]> M: Thomas Gleixner <[email protected]> T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Supported
arch/powerpc/kernel/time.c +1 -1
@@ -668,7 +668,7 @@ int update_persistent_clock(struct timespec now)struct rtc_time tm;if (!ppc_md.set_rtc_time) -return 0 ; +return -ENODEV ;to_tm (now.tv_sec +1 + timezone_offset, &tm); tm.tm_year -=1900 ;
arch/x86/Kconfig +1 -0
@@ -106,6 +106,7 @@ config X86 select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) select GENERIC_TIME_VSYSCALL if X86_64 select KTIME_SCALAR if X86_32 + select ALWAYS_USE_PERSISTENT_CLOCK select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select HAVE_CONTEXT_TRACKING if X86_64
arch/x86/kernel/rtc.c +0 -1
@@ -149,7 +149,6 @@ unsigned long mach_get_cmos_time(void)if (century) { century =bcd2bin (century); year += century *100 ; -printk (KERN_INFO "Extended CMOS year: %d\n" , century *100 ); }else year +=CMOS_YEARS_OFFS ;
arch/x86/kernel/tsc.c +2 -1
@@ -623,7 +623,8 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) ns_now =__cycles_2_ns (tsc_now);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, (1UL <<CYC2NS_SCALE_FACTOR )); }
arch/x86/vdso/vclock_gettime.c +1 -1
@@ -60,7 +60,7 @@ notrace static cycle_t vread_tsc(void) static notrace cycle_t vread_hpet(void) { -return readl ((const void __iomem *)fix_to_virt (VSYSCALL_HPET ) +0xf0 ); +return readl ((const void __iomem *)fix_to_virt (VSYSCALL_HPET ) +HPET_COUNTER ); }#ifdef CONFIG_PARAVIRT_CLOCK
drivers/rtc/Kconfig +11 -1
@@ -20,14 +20,24 @@ if RTC_CLASS config RTC_HCTOSYS bool "Set system time from RTC on startup and resume" default y + depends on !ALWAYS_USE_PERSISTENT_CLOCK help 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 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 string "RTC used to set the system time" - depends on RTC_HCTOSYS = y + depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y default "rtc0" help The RTC device that will be used to (re)initialize the system
drivers/rtc/Makefile +1 -0
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG obj-$(CONFIG_RTC_LIB) += rtc-lib.o obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o +obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o rtc-core-y := class.o interface.o
drivers/rtc/class.c +7 -0
@@ -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_time tm;struct timespec delta, delta_delta; + +if (has_persistent_clock ()) +return 0 ; +if (strcmp (dev_name (&rtc->dev),CONFIG_RTC_HCTOSYS_DEVICE ) !=0 )return 0 ;
@@ -88,6 +92,9 @@ static int rtc_resume(struct device *dev)struct timespec new_system, new_rtc;struct timespec sleep_time; +if (has_persistent_clock ()) +return 0 ; + rtc_hctosys_ret = -ENODEV ;if (strcmp (dev_name (&rtc->dev),CONFIG_RTC_HCTOSYS_DEVICE ) !=0 )return 0 ;
drivers/rtc/systohc.c new file +44 -0
44 lines not on this page · raw message
fs/pstore/ram.c +7 -3
@@ -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) {char *hdr; -struct timeval timestamp; +struct timespec timestamp;size_t len; -do_gettimeofday (×tamp); +/* Report zeroed timestamp if called before timekeeping has resumed. */ +if (__getnstimeofday (×tamp)) { + timestamp.tv_sec =0 ; + timestamp.tv_nsec =0 ; + } 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); len = hdr ?strlen (hdr) :0 ;persistent_ram_write (prz, hdr, len);
include/linux/clockchips.h +9 -0
@@ -161,6 +161,15 @@ clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 minsec)extern void clockevents_suspend (void );extern void clockevents_resume (void ); +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +#ifdef CONFIG_ARCH_HAS_TICK_BROADCAST +extern void tick_broadcast (const struct cpumask *mask); +#else +#define tick_broadcast NULL +#endif +extern int tick_receive_broadcast (void ); +#endif +#ifdef CONFIG_GENERIC_CLOCKEVENTS extern void clockevents_notify (unsigned long reason,void *arg);#else
include/linux/rtc.h +1 -0
@@ -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_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_ntp_time (struct timespec now);int __rtc_read_alarm (struct rtc_device *rtc,struct rtc_wkalrm *alarm);extern int rtc_read_alarm (struct rtc_device *rtc,struct rtc_wkalrm *alrm);
include/linux/time.h +13 -0
@@ -115,8 +115,20 @@ static inline bool timespec_valid_strict(const struct timespec *ts)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_boot_clock (struct timespec *ts); +extern int persistent_clock_is_local;extern int update_persistent_clock (struct timespec now);void timekeeping_init (void );extern int timekeeping_suspended;
@@ -158,6 +170,7 @@ extern int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue);extern unsigned int alarm_setitimer (unsigned int seconds);extern int do_getitimer (int which,struct itimerval *value); +extern int __getnstimeofday (struct timespec *tv);extern void getnstimeofday (struct timespec *tv);extern void getrawmonotonic (struct timespec *ts); extern void getnstime_raw_and_real(struct timespec *ts_raw,
kernel/hrtimer.c +18 -18
@@ -640,21 +640,9 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)* and expiry check is done in the hrtimer_interrupt or in the softirq. */ static inline int hrtimer_enqueue_reprogram (struct hrtimer *timer, -struct hrtimer_clock_base *base, -int wakeup) +struct hrtimer_clock_base *base) { -if (base->cpu_base->hres_active &&hrtimer_reprogram (timer, base)) { -if (wakeup) { -raw_spin_unlock (&base->cpu_base->lock); -raise_softirq_irqoff (HRTIMER_SOFTIRQ ); -raw_spin_lock (&base->cpu_base->lock); - }else -__raise_softirq_irqoff (HRTIMER_SOFTIRQ ); - -return 1 ; - } - -return 0 ; +return base->cpu_base->hres_active &&hrtimer_reprogram (timer, base); }static inline ktime_t hrtimer_update_base (struct hrtimer_cpu_base *base)
@@ -735,8 +723,7 @@ static inline int hrtimer_switch_to_hres(void) { return 0; }static inline void hrtimer_force_reprogram (struct hrtimer_cpu_base *base,int skip_equal) { }static inline int hrtimer_enqueue_reprogram (struct hrtimer *timer, -struct hrtimer_clock_base *base, -int wakeup) +struct hrtimer_clock_base *base) {return 0 ; }
@@ -995,8 +982,21 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,* * XXX send_remote_softirq() ? */ -if (leftmost && new_base->cpu_base == &__get_cpu_var (hrtimer_bases)) -hrtimer_enqueue_reprogram (timer, new_base, wakeup); +if (leftmost && new_base->cpu_base == &__get_cpu_var (hrtimer_bases) + &&hrtimer_enqueue_reprogram (timer, new_base)) { +if (wakeup) { +/* +* We need to drop cpu_base->lock to avoid a +* lock ordering issue vs. rq->lock. +*/ +raw_spin_unlock (&new_base->cpu_base->lock); +raise_softirq_irqoff (HRTIMER_SOFTIRQ ); +local_irq_restore (flags); +return ret; + }else { +__raise_softirq_irqoff (HRTIMER_SOFTIRQ ); + } + }unlock_hrtimer_base (timer, &flags);
kernel/posix-cpu-timers.c +21 -2
@@ -1401,8 +1401,10 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,while (!signal_pending (current)) {if (timer.it.cpu.expires.sched ==0 ) {/* -* Our timer fired and was reset. +* Our timer fired and was reset, below +* deletion can not fail. */ +posix_cpu_timer_del (&timer);spin_unlock_irq (&timer.it_lock);return 0 ; }
@@ -1420,9 +1422,26 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,* We were interrupted by a signal. */ sample_to_timespec (which_clock, timer.it.cpu.expires, rqtp); -posix_cpu_timer_set (&timer,0 , &zero_it, it); + error =posix_cpu_timer_set (&timer,0 , &zero_it, it); +if (!error) { +/* +* Timer is now unarmed, deletion can not fail. +*/ +posix_cpu_timer_del (&timer); + }spin_unlock_irq (&timer.it_lock); +while (error ==TIMER_RETRY ) { +/* +* We need to handle case when timer was or is in the +* middle of firing. In other cases we already freed +* resources. +*/ +spin_lock_irq (&timer.it_lock); + error =posix_cpu_timer_del (&timer); +spin_unlock_irq (&timer.it_lock); + } +if ((it->it_value.tv_sec | it->it_value.tv_nsec) ==0 ) {/* * It actually did fire already.
kernel/posix-timers.c +1 -1
@@ -997,7 +997,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, err = kc->clock_adj (which_clock, &ktx); -if (!err &©_to_user (utx, &ktx,sizeof (ktx))) +if (err >=0 &©_to_user (utx, &ktx,sizeof (ktx)))return -EFAULT ;return err;
kernel/time.c +8 -0
@@ -115,6 +115,12 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv, }/* +* Indicates if there is an offset between the system clock and the hardware +* clock/persistent clock/rtc. +*/ +int persistent_clock_is_local; + +/* * Adjust the time obtained from the CMOS to be UTC time instead of * local time. *
@@ -135,6 +141,8 @@ static inline void warp_clock(void)struct timespec adjust; adjust =current_kernel_time (); +if (sys_tz.tz_minuteswest !=0 ) + persistent_clock_is_local =1 ; adjust.tv_sec += sys_tz.tz_minuteswest *60 ;do_settimeofday (&adjust); }
kernel/time/Kconfig +9 -0
@@ -12,6 +12,11 @@ config CLOCKSOURCE_WATCHDOG config ARCH_CLOCKSOURCE_DATA bool +# Platforms has a persistent clock +config ALWAYS_USE_PERSISTENT_CLOCK + bool + default n + # Timekeeping vsyscall support config GENERIC_TIME_VSYSCALL bool
@@ -38,6 +43,10 @@ config GENERIC_CLOCKEVENTS_BUILD default y depends on GENERIC_CLOCKEVENTS +# Architecture can handle broadcast in a driver-agnostic way +config ARCH_HAS_TICK_BROADCAST + bool + # Clockevents broadcasting infrastructure config GENERIC_CLOCKEVENTS_BROADCAST bool
kernel/time/ntp.c +17 -5
@@ -15,6 +15,7 @@#include <linux/time.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/rtc.h> #include "tick-internal.h"
@@ -483,8 +484,7 @@ out: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 DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
@@ -510,14 +510,26 @@ static void sync_cmos_clock(struct work_struct *work) }getnstimeofday (&now); -if (abs (now.tv_nsec - (NSEC_PER_SEC /2 )) <= tick_nsec /2 ) - fail =update_persistent_clock (now); +if (abs (now.tv_nsec - (NSEC_PER_SEC /2 )) <= tick_nsec /2 ) { +struct timespec adjust = now; + + fail = -ENODEV ; +if (persistent_clock_is_local) + adjust.tv_sec -= (sys_tz.tz_minuteswest *60 ); +#ifdef CONFIG_GENERIC_CMOS_UPDATE + fail =update_persistent_clock (adjust); +#endif +#ifdef CONFIG_RTC_SYSTOHC +if (fail == -ENODEV ) + fail =rtc_set_ntp_time (adjust); +#endif + } next.tv_nsec = (NSEC_PER_SEC /2 ) - now.tv_nsec - (TICK_NSEC /2 );if (next.tv_nsec <=0 ) next.tv_nsec +=NSEC_PER_SEC ; -if (!fail) +if (!fail || fail == -ENODEV ) next.tv_sec =659 ;else next.tv_sec =0 ;
kernel/time/tick-broadcast.c +37 -1
@@ -18,6 +18,7 @@#include <linux/percpu.h> #include <linux/profile.h> #include <linux/sched.h> +#include <linux/smp.h> #include "tick-internal.h"
@@ -86,6 +87,22 @@ int tick_is_broadcast_device(struct clock_event_device *dev)return (dev && tick_broadcast_device.evtdev == dev); } +static void err_broadcast (const struct cpumask *mask) +{ +pr_crit_once ("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n" ); +} + +static void tick_device_setup_broadcast_func (struct clock_event_device *dev) +{ +if (!dev->broadcast) + dev->broadcast = tick_broadcast; +if (!dev->broadcast) { +pr_warn_once ("%s depends on broadcast, but no broadcast function available\n" , + dev->name); + dev->broadcast = err_broadcast; + } +} +/* * Check, if the device is disfunctional and a place holder, which * needs to be handled by the broadcast device.
@@ -105,6 +122,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)*/ if (!tick_device_is_functional (dev)) { dev->event_handler = tick_handle_periodic; +tick_device_setup_broadcast_func (dev);cpumask_set_cpu (cpu,tick_get_broadcast_mask ());tick_broadcast_start_periodic (tick_broadcast_device.evtdev); ret =1 ;
@@ -116,15 +134,33 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)*/ if (!(dev->features &CLOCK_EVT_FEAT_C3STOP )) {int cpu =smp_processor_id (); -cpumask_clear_cpu (cpu,tick_get_broadcast_mask ());tick_broadcast_clear_oneshot (cpu); + }else { +tick_device_setup_broadcast_func (dev); } }raw_spin_unlock_irqrestore (&tick_broadcast_lock, flags);return ret; } +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +int tick_receive_broadcast (void ) +{ +struct tick_device *td =this_cpu_ptr (&tick_cpu_device); +struct clock_event_device *evt = td->evtdev; + +if (!evt) +return -ENODEV ; + +if (!evt->event_handler) +return -EINVAL ; + + evt->event_handler (evt); +return 0 ; +} +#endif +/* * Broadcast the event to the cpus, which are set in the mask (mangled). */
kernel/time/timekeeping.c +35 -10
89 lines not on this page · raw message