diff options
| author | Steven Whitehouse <swhiteho@redhat.com> | 2006-09-28 08:29:59 -0400 |
|---|---|---|
| committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-09-28 08:29:59 -0400 |
| commit | 185a257f2f73bcd89050ad02da5bedbc28fc43fa (patch) | |
| tree | 5e32586114534ed3f2165614cba3d578f5d87307 /arch/i386/kernel/time.c | |
| parent | 3f1a9aaeffd8d1cbc5ab9776c45cbd66af1c9699 (diff) | |
| parent | a77c64c1a641950626181b4857abb701d8f38ccc (diff) | |
Merge branch 'master' into gfs2
Diffstat (limited to 'arch/i386/kernel/time.c')
| -rw-r--r-- | arch/i386/kernel/time.c | 73 |
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 | ||
| 131 | int timer_ack; | 131 | int timer_ack; |
| 132 | 132 | ||
| 133 | #if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER) | ||
| 134 | unsigned long profile_pc(struct pt_regs *regs) | 133 | unsigned 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 *)®s->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 | } |
| 143 | EXPORT_SYMBOL(profile_pc); | 159 | EXPORT_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 | ||
| 273 | static long clock_cmos_diff, sleep_start; | 288 | static long clock_cmos_diff; |
| 289 | static unsigned long sleep_start; | ||
| 274 | 290 | ||
| 275 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | 291 | static 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 */ |
| 335 | static void __init hpet_time_init(void) | 364 | static 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 | ||
| 350 | void __init time_init(void) | 380 | void __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 | } |
