vserver 2.0 rc7
[linux-2.6.git] / arch / s390 / kernel / time.c
index 995e2cd..8ca4856 100644 (file)
@@ -168,8 +168,17 @@ void account_ticks(struct pt_regs *regs)
        __u32 ticks, xticks;
 
        /* Calculate how many ticks have passed. */
-       if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer)
+       if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
+               /*
+                * We have to program the clock comparator even if
+                * no tick has passed. That happens if e.g. an i/o
+                * interrupt wakes up an idle processor that has
+                * switched off its hz timer.
+                */
+               tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
+               asm volatile ("SCKC %0" : : "m" (tmp));
                return;
+       }
        tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
        if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than two ticks ? */
                ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
@@ -235,7 +244,7 @@ int sysctl_hz_timer = 1;
  */
 static inline void stop_hz_timer(void)
 {
-       __u64 timer;
+       __u64 timer, todval;
 
        if (sysctl_hz_timer != 0)
                return;
@@ -256,8 +265,14 @@ static inline void stop_hz_timer(void)
         * for the next event.
         */
        timer = (__u64) (next_timer_interrupt() - jiffies) + jiffies_64;
-       timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY;
-       asm volatile ("SCKC %0" : : "m" (timer));
+       todval = -1ULL;
+       /* Be careful about overflows. */
+       if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) {
+               timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY;
+               if (timer >= jiffies_timer_cc)
+                       todval = timer;
+       }
+       asm volatile ("SCKC %0" : : "m" (todval));
 }
 
 /*