add suspend/resume for timer
PATCH 1/1 add suspend/resume for timer
Hi,
The timers lack .suspend/.resume methods. Because of this, jiffies got a big compensation after a S3 resume. And then softlockup watchdog reports an oops. This occured with HPET enabled, but it's also possible for other timers.
I know Linux will introduce a new timer core system, but it maybe take a long time, so I send this patch to fix bugs at hand. If the new timer system will be merged soon, please ignore this one.
Thanks,
Shaohua
---
linux-2.6.12-mm1-root/arch/i386/kernel/time.c | 10 ++++ linux-2.6.12-mm1-root/arch/i386/kernel/timers/timer_hpet.c | 14 ++++++ linux-2.6.12-mm1-root/arch/i386/kernel/timers/timer_pit.c | 27 ------------- linux-2.6.12-mm1-root/arch/i386/kernel/timers/timer_pm.c | 9 ++++ linux-2.6.12-mm1-root/arch/i386/kernel/timers/timer_tsc.c | 14 ++++++ linux-2.6.12-mm1-root/include/asm-i386/timer.h | 3 + 6 files changed, 50 insertions(+), 27 deletions(-)
include/asm-i386/timer.h renamed from include/asm-i386/timer.h~last_tick_fix +3 -0
@@ -1,6 +1,7 @@#ifndef _ASMi386_TIMER_H#define _ASMi386_TIMER_H#include <linux/init.h> +#include <linux/pm.h> /** * struct timer_ops - used to define a timer source
@@ -23,6 +24,8 @@ struct timer_opts {unsigned long long (*monotonic_clock)(void );void (*delay)(unsigned long );unsigned long (*read_timer)(void ); +int (*suspend)(pm_message_t state); +int (*resume)(void ); };struct init_timer_opts {
arch/i386/kernel/timers/timer_hpet.c renamed from arch/i386/kernel/timers/timer_hpet.c~last_tick_fix +14 -0
@@ -177,6 +177,19 @@ static int __init init_hpet(char* overrireturn 0 ; } +static int hpet_resume (void ) +{ +write_seqlock (&monotonic_lock); +/* Assume this is the last mark offset time */ +rdtsc (last_tsc_low, last_tsc_high); + +if (hpet_use_timer) + hpet_last =hpet_readl (HPET_T0_CMP ) - hpet_tick; +else + hpet_last =hpet_readl (HPET_COUNTER ); +write_sequnlock (&monotonic_lock); +return 0 ; +}/************************************************************/ /* tsc timer_opts struct */
@@ -187,6 +200,7 @@ static struct timer_opts timer_hpet __ca .monotonic_clock = monotonic_clock_hpet, .delay = delay_hpet, .read_timer = read_timer_tsc, + .resume = hpet_resume, };struct init_timer_opts __initdata timer_hpet_init = {
arch/i386/kernel/timers/timer_pit.c renamed from arch/i386/kernel/timers/timer_pit.c~last_tick_fix +0 -27
@@ -177,30 +177,3 @@ void setup_pit_timer(void)outb (LATCH >>8 ,PIT_CH0 );/* MSB */ spin_unlock_irqrestore (&i8253_lock, flags); } - -static int timer_resume (struct sys_device *dev) -{ -setup_pit_timer (); -return 0 ; -} - -static struct sysdev_class timer_sysclass = { -set_kset_name ("timer_pit" ), - .resume = timer_resume, -}; - -static struct sys_device device_timer = { - .id =0 , - .cls = &timer_sysclass, -}; - -static int __init init_timer_sysfs (void ) -{ -int error =sysdev_class_register (&timer_sysclass); -if (!error) - error =sysdev_register (&device_timer); -return error; -} - -device_initcall (init_timer_sysfs); -
arch/i386/kernel/timers/timer_tsc.c renamed from arch/i386/kernel/timers/timer_tsc.c~last_tick_fix +14 -0
@@ -544,6 +544,19 @@ static int __init init_tsc(char* overridreturn -ENODEV ; } +static int tsc_resume (void ) +{ +write_seqlock (&monotonic_lock); +/* Assume this is the last mark offset time */ +rdtsc (last_tsc_low, last_tsc_high); +#ifdef CONFIG_HPET_TIMER +if (is_hpet_enabled () && hpet_use_timer) + hpet_last =hpet_readl (HPET_COUNTER ); +#endif +write_sequnlock (&monotonic_lock); +return 0 ; +} +#ifndef CONFIG_X86_TSC /* disable flag for tsc. Takes effect by clearing the TSC cpu flag * in cpu/common.c */
@@ -574,6 +587,7 @@ static struct timer_opts timer_tsc = { .monotonic_clock = monotonic_clock_tsc, .delay = delay_tsc, .read_timer = read_timer_tsc, + .resume = tsc_resume, };struct init_timer_opts __initdata timer_tsc_init = {
arch/i386/kernel/timers/timer_pm.c renamed from arch/i386/kernel/timers/timer_pm.c~last_tick_fix +9 -0
@@ -186,6 +186,14 @@ static void mark_offset_pmtmr(void) } } +static int pmtmr_resume (void ) +{ +write_seqlock (&monotonic_lock); +/* Assume this is the last mark offset time */ + offset_tick =read_pmtmr (); +write_sequnlock (&monotonic_lock); +return 0 ; +}static unsigned long long monotonic_clock_pmtmr (void ) {
@@ -247,6 +255,7 @@ static struct timer_opts timer_pmtmr = { .monotonic_clock = monotonic_clock_pmtmr, .delay = delay_pmtmr, .read_timer = read_timer_tsc, + .resume = pmtmr_resume, };struct init_timer_opts __initdata timer_pmtmr_init = {
arch/i386/kernel/time.c renamed from arch/i386/kernel/time.c~last_tick_fix +10 -0
@@ -380,6 +380,7 @@ void notify_arch_cmos_timer(void)static long clock_cmos_diff, sleep_start; +static struct timer_opts *last_timer;static int timer_suspend (struct sys_device *dev,pm_message_t state) {/*
@@ -388,6 +389,10 @@ static int timer_suspend(struct sys_devi clock_cmos_diff = -get_cmos_time (); clock_cmos_diff +=get_seconds (); sleep_start =get_cmos_time (); + last_timer = cur_timer; + cur_timer = &timer_none; +if (last_timer->suspend) + last_timer->suspend (state);return 0 ; }
@@ -401,6 +406,7 @@ static int timer_resume(struct sys_devicif (is_hpet_enabled ())hpet_reenable ();#endif +setup_pit_timer (); sec =get_cmos_time () + clock_cmos_diff; sleep_length = (get_cmos_time () - sleep_start) *HZ ;write_seqlock_irqsave (&xtime_lock, flags);
@@ -410,6 +416,10 @@ static int timer_resume(struct sys_devic jiffies += sleep_length; wall_jiffies += sleep_length;touch_softlockup_watchdog (); +if (last_timer->resume) + last_timer->resume (); + cur_timer = last_timer; + last_timer =NULL ;return 0 ; }
_
Hi!
Quoted 7 lines
The timers lack .suspend/.resume methods. Because of this, jiffies got a big compensation after a S3 resume. And then softlockup watchdog reports an oops. This occured with HPET enabled, but it's also possible for other timers.
I know Linux will introduce a new timer core system, but it maybe take a long time, so I send this patch to fix bugs at hand. If the new timer system will be merged soon, please ignore this one.
Patch looks good to me. Setting up timers as system devices was ugly, and this fixes it. Good.
Pavel
Signature · 1 line
Boycott Kodak -- for their patent abuse against Java.