diff options
author | John Stultz <johnstul@us.ibm.com> | 2007-02-16 04:27:31 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:57 -0500 |
commit | c1d370e167d66b10bca3b602d3740405469383de (patch) | |
tree | 493ed9821cad0b2b035337da152cc11cc2223eb1 /arch/i386 | |
parent | 411187fb05cd11676b0979d9fbf3291db69dbce2 (diff) |
[PATCH] i386: use GTOD persistent clock support
Persistent clock support: do proper timekeeping across suspend/resume, i386
arch support.
[bunk@stusta.de: cleanup]
Build-fixes-from: Andrew Morton <akpm@osdl.org>
Signed-off-by: John Stultz <johnstul@us.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Cc: Roman Zippel <zippel@linux-m68k.org>
Cc: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/apm.c | 44 | ||||
-rw-r--r-- | arch/i386/kernel/time.c | 54 |
2 files changed, 1 insertions, 97 deletions
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index f9ba0af7ee1f..064bbf2861f4 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c | |||
@@ -236,7 +236,6 @@ | |||
236 | 236 | ||
237 | #include "io_ports.h" | 237 | #include "io_ports.h" |
238 | 238 | ||
239 | extern unsigned long get_cmos_time(void); | ||
240 | extern void machine_real_restart(unsigned char *, int); | 239 | extern void machine_real_restart(unsigned char *, int); |
241 | 240 | ||
242 | #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) | 241 | #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) |
@@ -1176,28 +1175,6 @@ out: | |||
1176 | spin_unlock(&user_list_lock); | 1175 | spin_unlock(&user_list_lock); |
1177 | } | 1176 | } |
1178 | 1177 | ||
1179 | static void set_time(void) | ||
1180 | { | ||
1181 | struct timespec ts; | ||
1182 | if (got_clock_diff) { /* Must know time zone in order to set clock */ | ||
1183 | ts.tv_sec = get_cmos_time() + clock_cmos_diff; | ||
1184 | ts.tv_nsec = 0; | ||
1185 | do_settimeofday(&ts); | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | static void get_time_diff(void) | ||
1190 | { | ||
1191 | #ifndef CONFIG_APM_RTC_IS_GMT | ||
1192 | /* | ||
1193 | * Estimate time zone so that set_time can update the clock | ||
1194 | */ | ||
1195 | clock_cmos_diff = -get_cmos_time(); | ||
1196 | clock_cmos_diff += get_seconds(); | ||
1197 | got_clock_diff = 1; | ||
1198 | #endif | ||
1199 | } | ||
1200 | |||
1201 | static void reinit_timer(void) | 1178 | static void reinit_timer(void) |
1202 | { | 1179 | { |
1203 | #ifdef INIT_TIMER_AFTER_SUSPEND | 1180 | #ifdef INIT_TIMER_AFTER_SUSPEND |
@@ -1237,19 +1214,6 @@ static int suspend(int vetoable) | |||
1237 | local_irq_disable(); | 1214 | local_irq_disable(); |
1238 | device_power_down(PMSG_SUSPEND); | 1215 | device_power_down(PMSG_SUSPEND); |
1239 | 1216 | ||
1240 | /* serialize with the timer interrupt */ | ||
1241 | write_seqlock(&xtime_lock); | ||
1242 | |||
1243 | /* protect against access to timer chip registers */ | ||
1244 | spin_lock(&i8253_lock); | ||
1245 | |||
1246 | get_time_diff(); | ||
1247 | /* | ||
1248 | * Irq spinlock must be dropped around set_system_power_state. | ||
1249 | * We'll undo any timer changes due to interrupts below. | ||
1250 | */ | ||
1251 | spin_unlock(&i8253_lock); | ||
1252 | write_sequnlock(&xtime_lock); | ||
1253 | local_irq_enable(); | 1217 | local_irq_enable(); |
1254 | 1218 | ||
1255 | save_processor_state(); | 1219 | save_processor_state(); |
@@ -1258,7 +1222,6 @@ static int suspend(int vetoable) | |||
1258 | restore_processor_state(); | 1222 | restore_processor_state(); |
1259 | 1223 | ||
1260 | local_irq_disable(); | 1224 | local_irq_disable(); |
1261 | set_time(); | ||
1262 | reinit_timer(); | 1225 | reinit_timer(); |
1263 | 1226 | ||
1264 | if (err == APM_NO_ERROR) | 1227 | if (err == APM_NO_ERROR) |
@@ -1288,11 +1251,6 @@ static void standby(void) | |||
1288 | 1251 | ||
1289 | local_irq_disable(); | 1252 | local_irq_disable(); |
1290 | device_power_down(PMSG_SUSPEND); | 1253 | device_power_down(PMSG_SUSPEND); |
1291 | /* serialize with the timer interrupt */ | ||
1292 | write_seqlock(&xtime_lock); | ||
1293 | /* If needed, notify drivers here */ | ||
1294 | get_time_diff(); | ||
1295 | write_sequnlock(&xtime_lock); | ||
1296 | local_irq_enable(); | 1254 | local_irq_enable(); |
1297 | 1255 | ||
1298 | err = set_system_power_state(APM_STATE_STANDBY); | 1256 | err = set_system_power_state(APM_STATE_STANDBY); |
@@ -1386,7 +1344,6 @@ static void check_events(void) | |||
1386 | ignore_bounce = 1; | 1344 | ignore_bounce = 1; |
1387 | if ((event != APM_NORMAL_RESUME) | 1345 | if ((event != APM_NORMAL_RESUME) |
1388 | || (ignore_normal_resume == 0)) { | 1346 | || (ignore_normal_resume == 0)) { |
1389 | set_time(); | ||
1390 | device_resume(); | 1347 | device_resume(); |
1391 | pm_send_all(PM_RESUME, (void *)0); | 1348 | pm_send_all(PM_RESUME, (void *)0); |
1392 | queue_event(event, NULL); | 1349 | queue_event(event, NULL); |
@@ -1402,7 +1359,6 @@ static void check_events(void) | |||
1402 | break; | 1359 | break; |
1403 | 1360 | ||
1404 | case APM_UPDATE_TIME: | 1361 | case APM_UPDATE_TIME: |
1405 | set_time(); | ||
1406 | break; | 1362 | break; |
1407 | 1363 | ||
1408 | case APM_CRITICAL_SUSPEND: | 1364 | case APM_CRITICAL_SUSPEND: |
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index a4f67a6e6821..044c17572eef 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -212,7 +212,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
212 | } | 212 | } |
213 | 213 | ||
214 | /* not static: needed by APM */ | 214 | /* not static: needed by APM */ |
215 | unsigned long get_cmos_time(void) | 215 | unsigned long read_persistent_clock(void) |
216 | { | 216 | { |
217 | unsigned long retval; | 217 | unsigned long retval; |
218 | unsigned long flags; | 218 | unsigned long flags; |
@@ -225,7 +225,6 @@ unsigned long get_cmos_time(void) | |||
225 | 225 | ||
226 | return retval; | 226 | return retval; |
227 | } | 227 | } |
228 | EXPORT_SYMBOL(get_cmos_time); | ||
229 | 228 | ||
230 | static void sync_cmos_clock(unsigned long dummy); | 229 | static void sync_cmos_clock(unsigned long dummy); |
231 | 230 | ||
@@ -278,58 +277,19 @@ void notify_arch_cmos_timer(void) | |||
278 | mod_timer(&sync_cmos_timer, jiffies + 1); | 277 | mod_timer(&sync_cmos_timer, jiffies + 1); |
279 | } | 278 | } |
280 | 279 | ||
281 | static long clock_cmos_diff; | ||
282 | static unsigned long sleep_start; | ||
283 | |||
284 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | ||
285 | { | ||
286 | /* | ||
287 | * Estimate time zone so that set_time can update the clock | ||
288 | */ | ||
289 | unsigned long ctime = get_cmos_time(); | ||
290 | |||
291 | clock_cmos_diff = -ctime; | ||
292 | clock_cmos_diff += get_seconds(); | ||
293 | sleep_start = ctime; | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int timer_resume(struct sys_device *dev) | 280 | static int timer_resume(struct sys_device *dev) |
298 | { | 281 | { |
299 | unsigned long flags; | ||
300 | unsigned long sec; | ||
301 | unsigned long ctime = get_cmos_time(); | ||
302 | long sleep_length = (ctime - sleep_start) * HZ; | ||
303 | struct timespec ts; | ||
304 | |||
305 | if (sleep_length < 0) { | ||
306 | printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n"); | ||
307 | /* The time after the resume must not be earlier than the time | ||
308 | * before the suspend or some nasty things will happen | ||
309 | */ | ||
310 | sleep_length = 0; | ||
311 | ctime = sleep_start; | ||
312 | } | ||
313 | #ifdef CONFIG_HPET_TIMER | 282 | #ifdef CONFIG_HPET_TIMER |
314 | if (is_hpet_enabled()) | 283 | if (is_hpet_enabled()) |
315 | hpet_reenable(); | 284 | hpet_reenable(); |
316 | #endif | 285 | #endif |
317 | setup_pit_timer(); | 286 | setup_pit_timer(); |
318 | |||
319 | sec = ctime + clock_cmos_diff; | ||
320 | ts.tv_sec = sec; | ||
321 | ts.tv_nsec = 0; | ||
322 | do_settimeofday(&ts); | ||
323 | write_seqlock_irqsave(&xtime_lock, flags); | ||
324 | jiffies_64 += sleep_length; | ||
325 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
326 | touch_softlockup_watchdog(); | 287 | touch_softlockup_watchdog(); |
327 | return 0; | 288 | return 0; |
328 | } | 289 | } |
329 | 290 | ||
330 | static struct sysdev_class timer_sysclass = { | 291 | static struct sysdev_class timer_sysclass = { |
331 | .resume = timer_resume, | 292 | .resume = timer_resume, |
332 | .suspend = timer_suspend, | ||
333 | set_kset_name("timer"), | 293 | set_kset_name("timer"), |
334 | }; | 294 | }; |
335 | 295 | ||
@@ -355,12 +315,6 @@ extern void (*late_time_init)(void); | |||
355 | /* Duplicate of time_init() below, with hpet_enable part added */ | 315 | /* Duplicate of time_init() below, with hpet_enable part added */ |
356 | static void __init hpet_time_init(void) | 316 | static void __init hpet_time_init(void) |
357 | { | 317 | { |
358 | struct timespec ts; | ||
359 | ts.tv_sec = get_cmos_time(); | ||
360 | ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
361 | |||
362 | do_settimeofday(&ts); | ||
363 | |||
364 | if ((hpet_enable() >= 0) && hpet_use_timer) { | 318 | if ((hpet_enable() >= 0) && hpet_use_timer) { |
365 | printk("Using HPET for base-timer\n"); | 319 | printk("Using HPET for base-timer\n"); |
366 | } | 320 | } |
@@ -371,7 +325,6 @@ static void __init hpet_time_init(void) | |||
371 | 325 | ||
372 | void __init time_init(void) | 326 | void __init time_init(void) |
373 | { | 327 | { |
374 | struct timespec ts; | ||
375 | #ifdef CONFIG_HPET_TIMER | 328 | #ifdef CONFIG_HPET_TIMER |
376 | if (is_hpet_capable()) { | 329 | if (is_hpet_capable()) { |
377 | /* | 330 | /* |
@@ -382,10 +335,5 @@ void __init time_init(void) | |||
382 | return; | 335 | return; |
383 | } | 336 | } |
384 | #endif | 337 | #endif |
385 | ts.tv_sec = get_cmos_time(); | ||
386 | ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
387 | |||
388 | do_settimeofday(&ts); | ||
389 | |||
390 | do_time_init(); | 338 | do_time_init(); |
391 | } | 339 | } |