vserver 1.9.5.x5
[linux-2.6.git] / arch / i386 / kernel / time.c
index a9711fc..22d38b3 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/sysdev.h>
 #include <linux/bcd.h>
 #include <linux/efi.h>
+#include <linux/mca.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -80,9 +81,9 @@ unsigned long cpu_khz;        /* Detected as we calibrate the TSC */
 
 extern unsigned long wall_jiffies;
 
-spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(rtc_lock);
 
-spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
 
 struct timer_opts *cur_timer = &timer_none;
@@ -261,8 +262,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id,
                        last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
        }
 
-#ifdef CONFIG_MCA
-       if( MCA_bus ) {
+       if (MCA_bus) {
                /* The PS/2 uses level-triggered interrupts.  You can't
                turn them off, nor would you want to (any attempt to
                enable edge-triggered interrupts usually gets intercepted by a
@@ -275,7 +275,6 @@ static inline void do_timer_interrupt(int irq, void *dev_id,
                irq = inb_p( 0x61 );    /* read the current state */
                outb_p( irq|0x80, 0x61 );       /* reset the IRQ */
        }
-#endif
 }
 
 /*
@@ -319,47 +318,58 @@ unsigned long get_cmos_time(void)
        return retval;
 }
 
-static long clock_cmos_diff;
+static long clock_cmos_diff, sleep_start;
 
-static int time_suspend(struct sys_device *dev, u32 state)
+static int timer_suspend(struct sys_device *dev, u32 state)
 {
        /*
         * Estimate time zone so that set_time can update the clock
         */
        clock_cmos_diff = -get_cmos_time();
        clock_cmos_diff += get_seconds();
+       sleep_start = get_cmos_time();
        return 0;
 }
 
-static int time_resume(struct sys_device *dev)
+static int timer_resume(struct sys_device *dev)
 {
        unsigned long flags;
-       unsigned long sec = get_cmos_time() + clock_cmos_diff;
+       unsigned long sec;
+       unsigned long sleep_length;
+
+#ifdef CONFIG_HPET_TIMER
+       if (is_hpet_enabled())
+               hpet_reenable();
+#endif
+       sec = get_cmos_time() + clock_cmos_diff;
+       sleep_length = (get_cmos_time() - sleep_start) * HZ;
        write_seqlock_irqsave(&xtime_lock, flags);
        xtime.tv_sec = sec;
        xtime.tv_nsec = 0;
        write_sequnlock_irqrestore(&xtime_lock, flags);
+       jiffies += sleep_length;
+       wall_jiffies += sleep_length;
        return 0;
 }
 
-static struct sysdev_class pit_sysclass = {
-       .resume = time_resume,
-       .suspend = time_suspend,
-       set_kset_name("pit"),
+static struct sysdev_class timer_sysclass = {
+       .resume = timer_resume,
+       .suspend = timer_suspend,
+       set_kset_name("timer"),
 };
 
 
 /* XXX this driverfs stuff should probably go elsewhere later -john */
-static struct sys_device device_i8253 = {
+static struct sys_device device_timer = {
        .id     = 0,
-       .cls    = &pit_sysclass,
+       .cls    = &timer_sysclass,
 };
 
 static int time_init_device(void)
 {
-       int error = sysdev_class_register(&pit_sysclass);
+       int error = sysdev_class_register(&timer_sysclass);
        if (!error)
-               error = sysdev_register(&device_i8253);
+               error = sysdev_register(&device_timer);
        return error;
 }
 
@@ -371,9 +381,9 @@ extern void (*late_time_init)(void);
 void __init hpet_time_init(void)
 {
        xtime.tv_sec = get_cmos_time();
-       wall_to_monotonic.tv_sec = -xtime.tv_sec;
        xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-       wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
+       set_normalized_timespec(&wall_to_monotonic,
+               -xtime.tv_sec, -xtime.tv_nsec);
 
        if (hpet_enable() >= 0) {
                printk("Using HPET for base-timer\n");
@@ -399,9 +409,9 @@ void __init time_init(void)
        }
 #endif
        xtime.tv_sec = get_cmos_time();
-       wall_to_monotonic.tv_sec = -xtime.tv_sec;
        xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-       wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
+       set_normalized_timespec(&wall_to_monotonic,
+               -xtime.tv_sec, -xtime.tv_nsec);
 
        cur_timer = select_timer();
        printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);