aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorJohn Stultz <johnstul@us.ibm.com>2007-02-16 04:27:31 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-16 11:13:57 -0500
commitc1d370e167d66b10bca3b602d3740405469383de (patch)
tree493ed9821cad0b2b035337da152cc11cc2223eb1 /arch/i386
parent411187fb05cd11676b0979d9fbf3291db69dbce2 (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.c44
-rw-r--r--arch/i386/kernel/time.c54
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
239extern unsigned long get_cmos_time(void);
240extern void machine_real_restart(unsigned char *, int); 239extern 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
1179static 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
1189static 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
1201static void reinit_timer(void) 1178static 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 */
215unsigned long get_cmos_time(void) 215unsigned 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}
228EXPORT_SYMBOL(get_cmos_time);
229 228
230static void sync_cmos_clock(unsigned long dummy); 229static 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
281static long clock_cmos_diff;
282static unsigned long sleep_start;
283
284static 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
297static int timer_resume(struct sys_device *dev) 280static 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
330static struct sysdev_class timer_sysclass = { 291static 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 */
356static void __init hpet_time_init(void) 316static 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
372void __init time_init(void) 326void __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}