aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/time.c')
-rw-r--r--arch/i386/kernel/time.c73
1 files changed, 52 insertions, 21 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index edd00f6cee37..86944acfb647 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -130,18 +130,33 @@ static int set_rtc_mmss(unsigned long nowtime)
130 130
131int timer_ack; 131int timer_ack;
132 132
133#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
134unsigned long profile_pc(struct pt_regs *regs) 133unsigned long profile_pc(struct pt_regs *regs)
135{ 134{
136 unsigned long pc = instruction_pointer(regs); 135 unsigned long pc = instruction_pointer(regs);
137 136
138 if (!user_mode_vm(regs) && in_lock_functions(pc)) 137#ifdef CONFIG_SMP
138 if (!user_mode_vm(regs) && in_lock_functions(pc)) {
139#ifdef CONFIG_FRAME_POINTER
139 return *(unsigned long *)(regs->ebp + 4); 140 return *(unsigned long *)(regs->ebp + 4);
140 141#else
142 unsigned long *sp;
143 if ((regs->xcs & 3) == 0)
144 sp = (unsigned long *)&regs->esp;
145 else
146 sp = (unsigned long *)regs->esp;
147 /* Return address is either directly at stack pointer
148 or above a saved eflags. Eflags has bits 22-31 zero,
149 kernel addresses don't. */
150 if (sp[0] >> 22)
151 return sp[0];
152 if (sp[1] >> 22)
153 return sp[1];
154#endif
155 }
156#endif
141 return pc; 157 return pc;
142} 158}
143EXPORT_SYMBOL(profile_pc); 159EXPORT_SYMBOL(profile_pc);
144#endif
145 160
146/* 161/*
147 * This is the same as the above, except we _also_ save the current 162 * This is the same as the above, except we _also_ save the current
@@ -270,16 +285,19 @@ void notify_arch_cmos_timer(void)
270 mod_timer(&sync_cmos_timer, jiffies + 1); 285 mod_timer(&sync_cmos_timer, jiffies + 1);
271} 286}
272 287
273static long clock_cmos_diff, sleep_start; 288static long clock_cmos_diff;
289static unsigned long sleep_start;
274 290
275static int timer_suspend(struct sys_device *dev, pm_message_t state) 291static int timer_suspend(struct sys_device *dev, pm_message_t state)
276{ 292{
277 /* 293 /*
278 * Estimate time zone so that set_time can update the clock 294 * Estimate time zone so that set_time can update the clock
279 */ 295 */
280 clock_cmos_diff = -get_cmos_time(); 296 unsigned long ctime = get_cmos_time();
297
298 clock_cmos_diff = -ctime;
281 clock_cmos_diff += get_seconds(); 299 clock_cmos_diff += get_seconds();
282 sleep_start = get_cmos_time(); 300 sleep_start = ctime;
283 return 0; 301 return 0;
284} 302}
285 303
@@ -287,18 +305,29 @@ static int timer_resume(struct sys_device *dev)
287{ 305{
288 unsigned long flags; 306 unsigned long flags;
289 unsigned long sec; 307 unsigned long sec;
290 unsigned long sleep_length; 308 unsigned long ctime = get_cmos_time();
291 309 long sleep_length = (ctime - sleep_start) * HZ;
310 struct timespec ts;
311
312 if (sleep_length < 0) {
313 printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n");
314 /* The time after the resume must not be earlier than the time
315 * before the suspend or some nasty things will happen
316 */
317 sleep_length = 0;
318 ctime = sleep_start;
319 }
292#ifdef CONFIG_HPET_TIMER 320#ifdef CONFIG_HPET_TIMER
293 if (is_hpet_enabled()) 321 if (is_hpet_enabled())
294 hpet_reenable(); 322 hpet_reenable();
295#endif 323#endif
296 setup_pit_timer(); 324 setup_pit_timer();
297 sec = get_cmos_time() + clock_cmos_diff; 325
298 sleep_length = (get_cmos_time() - sleep_start) * HZ; 326 sec = ctime + clock_cmos_diff;
327 ts.tv_sec = sec;
328 ts.tv_nsec = 0;
329 do_settimeofday(&ts);
299 write_seqlock_irqsave(&xtime_lock, flags); 330 write_seqlock_irqsave(&xtime_lock, flags);
300 xtime.tv_sec = sec;
301 xtime.tv_nsec = 0;
302 jiffies_64 += sleep_length; 331 jiffies_64 += sleep_length;
303 wall_jiffies += sleep_length; 332 wall_jiffies += sleep_length;
304 write_sequnlock_irqrestore(&xtime_lock, flags); 333 write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -334,10 +363,11 @@ extern void (*late_time_init)(void);
334/* Duplicate of time_init() below, with hpet_enable part added */ 363/* Duplicate of time_init() below, with hpet_enable part added */
335static void __init hpet_time_init(void) 364static void __init hpet_time_init(void)
336{ 365{
337 xtime.tv_sec = get_cmos_time(); 366 struct timespec ts;
338 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); 367 ts.tv_sec = get_cmos_time();
339 set_normalized_timespec(&wall_to_monotonic, 368 ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
340 -xtime.tv_sec, -xtime.tv_nsec); 369
370 do_settimeofday(&ts);
341 371
342 if ((hpet_enable() >= 0) && hpet_use_timer) { 372 if ((hpet_enable() >= 0) && hpet_use_timer) {
343 printk("Using HPET for base-timer\n"); 373 printk("Using HPET for base-timer\n");
@@ -349,6 +379,7 @@ static void __init hpet_time_init(void)
349 379
350void __init time_init(void) 380void __init time_init(void)
351{ 381{
382 struct timespec ts;
352#ifdef CONFIG_HPET_TIMER 383#ifdef CONFIG_HPET_TIMER
353 if (is_hpet_capable()) { 384 if (is_hpet_capable()) {
354 /* 385 /*
@@ -359,10 +390,10 @@ void __init time_init(void)
359 return; 390 return;
360 } 391 }
361#endif 392#endif
362 xtime.tv_sec = get_cmos_time(); 393 ts.tv_sec = get_cmos_time();
363 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); 394 ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
364 set_normalized_timespec(&wall_to_monotonic, 395
365 -xtime.tv_sec, -xtime.tv_nsec); 396 do_settimeofday(&ts);
366 397
367 time_init_hook(); 398 time_init_hook();
368} 399}