timer changes for v3.4
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: a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33 ntp: Fix integer overflow when setting time
Thanks,
Ingo
------------------>
Arjan van de Ven (1):
clocksource: Load the ACPI PM clocksource asynchronously
Frederic Weisbecker (2):
nohz: Remove ts->Einidle checks before restarting the tick
timer: Fix bad idle check on irq entry
Ingo Molnar (1):
clocksource: scx200_hrt: Fix the build
Jan Beulich (1):
x86/time: Eliminate unused irq0_irqs counter
Jens Rottmann (2):
cs5535-clockevt: Don't ignore MFGPT on SMP-capable kernels
cs5535-clockevt: Allow the MFGPT IRQ to be shared
Jim Cromie (1):
clocksource: scx200_hrt: use pr_<level> instead of printk
John Stultz (12):
rtc: Avoid setting alarm to a time in the past
time: Move total_sleep_time into the timekeeper structure
time: Move wall_to_monotonic into the timekeeper structure
time: Move xtime into timekeeeper structure
time: Move raw_time into timekeeper structure
time: Cleanup global variables and move them to the top
time: Add timekeeper lock
ntp: Cleanup timex.h
ntp: Access tick_length variable via ntp_tick_length()
ntp: Add ntp_lock to replace xtime_locking
time: Remove most of xtime_lock usage in timekeeping.c
clocksource: scx200_hrt: Convert scx200 to use clocksource_register_hz
Julia Lawall (1):
clocksource: cyclone: Add missing iounmap
Michal Hocko (1):
nohz: Remove update_ts_time_stat from tick_nohz_start_idle
NeilBrown (1):
rtc: Expire alarms after the time is set. (v2)
Rabin Vincent (1):
rtc: Disable the alarm in the hardware (v2)
Sasha Levin (2):
math: Introduce div64_long
ntp: Fix integer overflow when setting time
Suresh Siddha (2):
clockevents: Leave the broadcast device in shutdown mode when not needed x86/tsc: Reduce the TSC sync check time for core-siblings
Thomas Gleixner (2):
time: Reorder so the hot data is together
time: Move common updates to a function
Yong Zhang (2):
clocksource: dbx500: convert to clocksource_register_hz()
clocksource: Get rid of clocksource_calc_mult_shift()
arch/x86/include/asm/hardirq.h | 1 - arch/x86/kernel/time.c | 3 - arch/x86/kernel/tsc_sync.c | 29 ++- drivers/clocksource/acpi_pm.c | 24 ++- drivers/clocksource/clksrc-dbx500-prcmu.c | 5 +- drivers/clocksource/cs5535-clockevt.c | 3 +- drivers/clocksource/cyclone.c | 2 +- drivers/clocksource/scx200_hrt.c | 24 +-- drivers/rtc/interface.c | 30 +++- include/linux/clocksource.h | 7 - include/linux/math64.h | 4 + include/linux/timex.h | 17 +-- kernel/softirq.c | 2 +- kernel/time/ntp.c | 85 ++++++-- kernel/time/tick-broadcast.c | 4 + kernel/time/tick-sched.c | 17 +- kernel/time/timekeeping.c | 338 ++++++++++++++++------------- 17 files changed, 343 insertions(+), 252 deletions(-)
arch/x86/include/asm/hardirq.h +0 -1
@@ -7,7 +7,6 @@ typedef struct { unsigned int __softirq_pending; unsigned int __nmi_count; /* arch dependent */ - unsigned int irq0_irqs; #ifdef CONFIG_X86_LOCAL_APIC unsigned int apic_timer_irqs; /* arch dependent */ unsigned int irq_spurious_count;
arch/x86/kernel/time.c +0 -3
@@ -57,9 +57,6 @@ EXPORT_SYMBOL(profile_pc);*/ static irqreturn_t timer_interrupt (int irq,void *dev_id) { -/* Keep nmi watchdog up to date */ -inc_irq_stat (irq0_irqs); - global_clock_event->event_handler (global_clock_event);/* MCA bus quirk: Acknowledge irq0 by setting bit 7 in port 0x61 */
arch/x86/kernel/tsc_sync.c +24 -5
@@ -42,7 +42,7 @@ static __cpuinitdata int nr_warps;/* * TSC-warp measurement loop running on both CPUs: */ -static __cpuinit void check_tsc_warp (void ) +static __cpuinit void check_tsc_warp (unsigned int timeout) {cycles_t start, now, prev, end;int i;
@@ -51,9 +51,9 @@ static __cpuinit void check_tsc_warp(void) start =get_cycles ();rdtsc_barrier ();/* -* The measurement runs for 20 msecs: +* The measurement runs for 'timeout' msecs: */ - end = start + tsc_khz *20ULL ; + end = start + (cycles_t ) tsc_khz * timeout; now = start;for (i =0 ; ; i++) {
@@ -99,6 +99,25 @@ static __cpuinit void check_tsc_warp(void) }/* +* If the target CPU coming online doesn't have any of its core-siblings +* online, a timeout of 20msec will be used for the TSC-warp measurement +* loop. Otherwise a smaller timeout of 2msec will be used, as we have some +* information about this socket already (and this information grows as we +* have more and more logical-siblings in that socket). +* +* Ideally we should be able to skip the TSC sync check on the other +* core-siblings, if the first logical CPU in a socket passed the sync test. +* But as the TSC is per-logical CPU and can potentially be modified wrongly +* by the bios, TSC sync test for smaller duration should be able +* to catch such errors. Also this will catch the condition where all the +* cores in the socket doesn't get reset at the same time. +*/ +static inline unsigned int loop_timeout (int cpu) +{ +return (cpumask_weight (cpu_core_mask (cpu)) >1 ) ?2 :20 ; +} + +/* * Source CPU calls into this - it waits for the freshly booted * target CPU to arrive and then starts the measurement: */
@@ -135,7 +154,7 @@ void __cpuinit check_tsc_sync_source(int cpu)*/ atomic_inc (&start_count); -check_tsc_warp (); +check_tsc_warp (loop_timeout (cpu));while (atomic_read (&stop_count) != cpus-1 )cpu_relax ();
@@ -183,7 +202,7 @@ void __cpuinit check_tsc_sync_target(void)while (atomic_read (&start_count) != cpus)cpu_relax (); -check_tsc_warp (); +check_tsc_warp (loop_timeout (smp_processor_id ()));/* * Ok, we are done:
drivers/clocksource/acpi_pm.c +16 -8
@@ -23,6 +23,7 @@#include <linux/init.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/async.h> #include <asm/io.h> /*
@@ -179,17 +180,15 @@ static int verify_pmtmr_rate(void)/* Number of reads we try to get two different values */ #define ACPI_PM_READ_CHECKS 10000 -static int __init init_acpi_pm_clocksource (void ) +static void __init acpi_pm_clocksource_async (void *unused,async_cookie_t cookie) {cycle_t value1, value2;unsigned int i, j =0 ; -if (!pmtmr_ioport) -return -ENODEV ;/* "verify" this timing source: */ for (j =0 ; j <ACPI_PM_MONOTONICITY_CHECKS ; j++) { -udelay (100 * j); +usleep_range (100 * j,100 * j +100 ); value1 = clocksource_acpi_pm.read (&clocksource_acpi_pm);for (i =0 ; i <ACPI_PM_READ_CHECKS ; i++) { value2 = clocksource_acpi_pm.read (&clocksource_acpi_pm);
@@ -203,25 +202,34 @@ static int __init init_acpi_pm_clocksource(void)" 0x%#llx, 0x%#llx - aborting.\n" , value1, value2); pmtmr_ioport =0 ; -return -EINVAL ; +return ; }if (i ==ACPI_PM_READ_CHECKS ) {printk (KERN_INFO "PM-Timer failed consistency check " " (0x%#llx) - aborting.\n" , value1); pmtmr_ioport =0 ; -return -ENODEV ; +return ; } }if (verify_pmtmr_rate () !=0 ){ pmtmr_ioport =0 ; -return -ENODEV ; +return ; } -return clocksource_register_hz (&clocksource_acpi_pm, +clocksource_register_hz (&clocksource_acpi_pm,PMTMR_TICKS_PER_SEC ); } +static int __init init_acpi_pm_clocksource (void ) +{ +if (!pmtmr_ioport) +return -ENODEV ; + +async_schedule (acpi_pm_clocksource_async,NULL ); +return 0 ; +} +/* We use fs_initcall because we want the PCI fixups to have run * but we still need to load before device_initcall */
drivers/clocksource/clksrc-dbx500-prcmu.c +1 -4
@@ -52,7 +52,6 @@ static struct clocksource clocksource_dbx500_prcmu = { .name = "dbx500-prcmu-timer", .rating = 300, .read = clksrc_dbx500_prcmu_read, - .shift = 10, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, };
@@ -90,7 +89,5 @@ void __init clksrc_dbx500_prcmu_init(void __iomem *base)setup_sched_clock (dbx500_prcmu_sched_clock_read,32 ,RATE_32K );#endif -clocksource_calc_mult_shift (&clocksource_dbx500_prcmu, -RATE_32K ,SCHED_CLOCK_MIN_WRAP ); -clocksource_register (&clocksource_dbx500_prcmu); +clocksource_register_hz (&clocksource_dbx500_prcmu,RATE_32K ); }
drivers/clocksource/cs5535-clockevt.c +1 -2
@@ -100,7 +100,6 @@ static struct clock_event_device cs5535_clockevent = { .set_mode = mfgpt_set_mode, .set_next_event = mfgpt_next_event, .rating = 250, - .cpumask = cpu_all_mask, .shift = 32 };
@@ -133,7 +132,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)static struct irqaction mfgptirq = { .handler = mfgpt_tick, - .flags =IRQF_DISABLED |IRQF_NOBALANCING |IRQF_TIMER , + .flags =IRQF_DISABLED |IRQF_NOBALANCING |IRQF_TIMER |IRQF_SHARED , .name =DRV_NAME , };
drivers/clocksource/cyclone.c +1 -1
@@ -55,11 +55,11 @@ static int __init init_cyclone_clocksource(void) }/* even on 64bit systems, this is only 32bits: */ base =readl (reg); +iounmap (reg);if (!base) {printk (KERN_ERR "Summit chipset: Could not find valid CBAR value.\n" );return -ENODEV ; } -iounmap (reg);/* setup PMCC: */ offset = base +CYCLONE_PMCC_OFFSET ;
drivers/clocksource/scx200_hrt.c +8 -16
@@ -49,9 +49,6 @@ static cycle_t read_hrt(struct clocksource *cs)return (cycle_t )inl (scx200_cb_base + SCx200_TIMER_OFFSET); } -#define HRT_SHIFT_1 22 -#define HRT_SHIFT_27 26 -static struct clocksource cs_hrt = { .name ="scx200_hrt" , .rating =250 ,
@@ -63,6 +60,7 @@ static struct clocksource cs_hrt = {static int __init init_hrt_clocksource (void ) { +u32 freq;/* Make sure scx200 has initialized the configuration block */ if (!scx200_cb_present ())return -ENODEV ;
@@ -71,7 +69,7 @@ static int __init init_hrt_clocksource(void)if (!request_region (scx200_cb_base + SCx200_TIMER_OFFSET, SCx200_TIMER_SIZE,"NatSemi SCx200 High-Resolution Timer" )) { - printk(KERN_WARNING NAME ": unable to lock timer region\n"); +pr_warn ("unable to lock timer region\n" );return -ENODEV ; }
@@ -79,19 +77,13 @@ static int __init init_hrt_clocksource(void)outb (HR_TMEN | (mhz27 ?HR_TMCLKSEL :0 ), scx200_cb_base + SCx200_TMCNFG_OFFSET); -if (mhz27) { - cs_hrt.shift =HRT_SHIFT_27 ; - cs_hrt.mult =clocksource_hz2mult ((HRT_FREQ + ppm) *27 , - cs_hrt.shift); - }else { - cs_hrt.shift =HRT_SHIFT_1 ; - cs_hrt.mult =clocksource_hz2mult (HRT_FREQ + ppm, - cs_hrt.shift); - } -printk (KERN_INFO "enabling scx200 high-res timer (%s MHz +%d ppm)\n" , - mhz27 ?"27" :"1" , ppm); + freq = (HRT_FREQ + ppm); +if (mhz27) + freq *=27 ; + +pr_info ("enabling scx200 high-res timer (%s MHz +%d ppm)\n" , mhz27 ?"27" :"1" , ppm); -return clocksource_register (&cs_hrt); +return clocksource_register_hz (&cs_hrt, freq); }module_init (init_hrt_clocksource);
drivers/rtc/interface.c +27 -3
@@ -73,6 +73,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) err = -EINVAL ;mutex_unlock (&rtc->ops_lock); +/* A timer might have just expired */ +schedule_work (&rtc->irqwork);return err; }EXPORT_SYMBOL_GPL (rtc_set_time);
@@ -112,6 +114,8 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) err = -EINVAL ;mutex_unlock (&rtc->ops_lock); +/* A timer might have just expired */ +schedule_work (&rtc->irqwork);return err; }
@@ -380,18 +384,27 @@ EXPORT_SYMBOL_GPL(rtc_set_alarm);int rtc_initialize_alarm (struct rtc_device *rtc,struct rtc_wkalrm *alarm) {int err; +struct rtc_time now; err =rtc_valid_tm (&alarm->time);if (err !=0 )return err; + err =rtc_read_time (rtc, &now); +if (err) +return err; + err =mutex_lock_interruptible (&rtc->ops_lock);if (err)return err; rtc->aie_timer.node.expires =rtc_tm_to_ktime (alarm->time); rtc->aie_timer.period =ktime_set (0 ,0 ); -if (alarm->enabled) { + +/* Alarm has to be enabled & in the futrure for us to enqueue it */ +if (alarm->enabled && (rtc_tm_to_ktime (now).tv64 < + rtc->aie_timer.node.expires.tv64)) { + rtc->aie_timer.enabled =1 ;timerqueue_add (&rtc->timerqueue, &rtc->aie_timer.node); }
@@ -763,6 +776,14 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)return 0 ; } +static void rtc_alarm_disable (struct rtc_device *rtc) +{ +if (!rtc->ops || !rtc->ops->alarm_irq_enable) +return ; + + rtc->ops->alarm_irq_enable (rtc->dev.parent, false); +} +/** * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue * @rtc rtc device
@@ -784,8 +805,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)struct rtc_wkalrm alarm;int err; next =timerqueue_getnext (&rtc->timerqueue); -if (!next) +if (!next) { +rtc_alarm_disable (rtc);return ; + } alarm.time =rtc_ktime_to_tm (next->expires); alarm.enabled =1 ; err =__rtc_set_alarm (rtc, &alarm);
@@ -847,7 +870,8 @@ again: err =__rtc_set_alarm (rtc, &alarm);if (err == -ETIME ) goto again; - } + }else +rtc_alarm_disable (rtc);mutex_unlock (&rtc->ops_lock); }
include/linux/clocksource.h +0 -7
@@ -319,13 +319,6 @@ static inline void __clocksource_updatefreq_khz(struct clocksource *cs, u32 khz)__clocksource_updatefreq_scale (cs,1000 , khz); } -static inline void -clocksource_calc_mult_shift (struct clocksource *cs,u32 freq,u32 minsec) -{ -return clocks_calc_mult_shift (&cs->mult, &cs->shift, freq, -NSEC_PER_SEC , minsec); -} -#ifdef CONFIG_GENERIC_TIME_VSYSCALL extern void update_vsyscall(struct timespec *ts, struct timespec *wtm,
include/linux/math64.h +4 -0
@@ -6,6 +6,8 @@#if BITS_PER_LONG ==64 +#define div64_long (x,y) div64_s64((x),(y)) +/** * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder *
@@ -45,6 +47,8 @@ static inline s64 div64_s64(s64 dividend, s64 divisor) #elif BITS_PER_LONG == 32 +#define div64_long(x,y) div_s64((x),(y)) + #ifndef div_u64_rem static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) {
include/linux/timex.h +1 -16
@@ -234,23 +234,9 @@ struct timex {extern unsigned long tick_usec;/* USER_HZ period (usec) */ extern unsigned long tick_nsec;/* ACTHZ period (nsec) */ -/* -* phase-lock loop variables -*/ -extern int time_status;/* clock synchronization status bits */ -extern void ntp_init (void );extern void ntp_clear (void ); -/** -* ntp_synced - Returns 1 if the NTP status is not UNSYNC -* -*/ -static inline int ntp_synced (void ) -{ -return !(time_status &STA_UNSYNC ); -} -/* Required to safely shift negative values */ #define shift_right (x, s) ({ \ __typeof__(x) __x = (x); \
@@ -264,10 +250,9 @@ static inline int ntp_synced(void)#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */ -extern u64 tick_length; +extern u64 ntp_tick_length (void );extern void second_overflow (void ); -extern void update_ntp_one_tick (void );extern int do_adjtimex (struct timex *);extern void hardpps (const struct timespec *,const struct timespec *);
kernel/softirq.c +1 -1
@@ -297,7 +297,7 @@ void irq_enter(void)int cpu =smp_processor_id ();rcu_irq_enter (); -if (idle_cpu (cpu) && !in_interrupt ()) { +if (is_idle_task (current) && !in_interrupt ()) {/* * Prevent raise_softirq from needlessly waking up ksoftirqd * here, as softirq will be serviced on return from interrupt.
kernel/time/ntp.c +64 -21
230 lines not on this page · raw message
kernel/time/tick-broadcast.c +4 -0
@@ -575,11 +575,15 @@ void tick_broadcast_switch_to_oneshot(void)unsigned long flags;raw_spin_lock_irqsave (&tick_broadcast_lock, flags); +if (cpumask_empty (tick_get_broadcast_mask ())) + goto end; tick_broadcast_device.mode =TICKDEV_MODE_ONESHOT ; bc = tick_broadcast_device.evtdev;if (bc)tick_broadcast_setup_oneshot (bc); + +end:raw_spin_unlock_irqrestore (&tick_broadcast_lock, flags); }
kernel/time/tick-sched.c +7 -10
@@ -182,11 +182,7 @@ static void tick_nohz_stop_idle(int cpu, ktime_t now)static ktime_t tick_nohz_start_idle (int cpu,struct tick_sched *ts) { -ktime_t now; - - now =ktime_get (); - -update_ts_time_stats (cpu, ts, now,NULL ); +ktime_t now =ktime_get (); ts->idle_entrytime = now; ts->idle_active =1 ;
@@ -562,20 +558,21 @@ void tick_nohz_idle_exit(void)local_irq_disable (); -if (ts->idle_active || (ts->inidle && ts->tick_stopped)) +WARN_ON_ONCE (!ts->inidle); + + ts->inidle =0 ; + +if (ts->idle_active || ts->tick_stopped) now =ktime_get ();if (ts->idle_active)tick_nohz_stop_idle (cpu, now); -if (!ts->inidle || !ts->tick_stopped) { - ts->inidle =0 ; +if (!ts->tick_stopped) {local_irq_enable ();return ; } - ts->inidle =0 ; -/* Update jiffies first */ select_nohz_load_balancer (0 );tick_do_update_jiffies64 (now);
kernel/time/timekeeping.c +184 -154
650 lines not on this page · raw message