On Wed, 2007-02-07 at 00:12 +0100, Tilman Schmidt wrote:
> > No, not this. Anyway the last patch Thomas forwarded does fix the
> > problem.
> 
> Which one would that be? I might try it for comparison.

Find the combined patch of all fixlets on top of -mm3 below.

        tglx

Index: linux-2.6.20/kernel/timer.c
===================================================================
--- linux-2.6.20.orig/kernel/timer.c
+++ linux-2.6.20/kernel/timer.c
@@ -985,8 +985,9 @@ static int timekeeping_resume(struct sys
 
        if (now && (now > timekeeping_suspend_time)) {
                unsigned long sleep_length = now - timekeeping_suspend_time;
+
                xtime.tv_sec += sleep_length;
-               jiffies_64 += (u64)sleep_length * HZ;
+               wall_to_monotonic.tv_sec -= sleep_length;
        }
        /* re-base the last cycle value */
        clock->cycle_last = clocksource_read(clock);
@@ -994,7 +995,7 @@ static int timekeeping_resume(struct sys
        timekeeping_suspended = 0;
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
-       clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
+       touch_softlockup_watchdog();
        /* Resume hrtimers */
        clock_was_set();
 
Index: linux-2.6.20/kernel/time/clockevents.c
===================================================================
--- linux-2.6.20.orig/kernel/time/clockevents.c
+++ linux-2.6.20/kernel/time/clockevents.c
@@ -42,8 +42,8 @@ unsigned long clockevent_delta2ns(unsign
        u64 clc = ((u64) latch << evt->shift);
 
        do_div(clc, evt->mult);
-       if (clc < KTIME_MONOTONIC_RES.tv64)
-               clc = KTIME_MONOTONIC_RES.tv64;
+       if (clc < 1000)
+               clc = 1000;
        if (clc > LONG_MAX)
                clc = LONG_MAX;
 
@@ -72,18 +72,22 @@ void clockevents_set_mode(struct clock_e
  *
  * Returns 0 on success, -ETIME when the event is in the past.
  */
-int clockevents_program_event(struct clock_event_device *dev, ktime_t expires)
+int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,
+                             ktime_t now)
 {
        unsigned long long clc;
        int64_t delta;
 
-       delta = ktime_to_ns(ktime_sub(expires, ktime_get()));
+       delta = ktime_to_ns(ktime_sub(expires, now));
 
        if (delta <= 0)
                return -ETIME;
 
        dev->next_event = expires;
 
+       if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
+               return 0;
+
        if (delta > dev->max_delta_ns)
                delta = dev->max_delta_ns;
        if (delta < dev->min_delta_ns)
Index: linux-2.6.20/kernel/time/tick-broadcast.c
===================================================================
--- linux-2.6.20.orig/kernel/time/tick-broadcast.c
+++ linux-2.6.20/kernel/time/tick-broadcast.c
@@ -159,6 +159,8 @@ static void tick_do_periodic_broadcast(v
  */
 static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
 {
+       dev->next_event.tv64 = KTIME_MAX;
+
        tick_do_periodic_broadcast();
 
        /*
@@ -174,7 +176,7 @@ static void tick_handle_periodic_broadca
        for (;;) {
                ktime_t next = ktime_add(dev->next_event, tick_period);
 
-               if (!clockevents_program_event(dev, next))
+               if (!clockevents_program_event(dev, next, ktime_get()))
                        return;
                tick_do_periodic_broadcast();
        }
@@ -294,17 +296,31 @@ cpumask_t *tick_get_broadcast_oneshot_ma
        return &tick_broadcast_oneshot_mask;
 }
 
+static int tick_broadcast_set_event(ktime_t expires, int force)
+{
+       struct clock_event_device *bc = tick_broadcast_device.evtdev;
+       ktime_t now = ktime_get();
+       int res;
+
+       for(;;) {
+               res = clockevents_program_event(bc, expires, now);
+               if (!res || !force)
+                       return res;
+               now = ktime_get();
+               expires = ktime_add(now, ktime_set(0, bc->min_delta_ns));
+       }
+}
+
 /*
  * Reprogram the broadcast device:
  *
  * Called with tick_broadcast_lock held and interrupts disabled.
  */
-static int tick_broadcast_reprogram(int force)
+static int tick_broadcast_reprogram(void)
 {
-       struct clock_event_device *bc = tick_broadcast_device.evtdev;
-       ktime_t tmp, expires = { .tv64 = KTIME_MAX };
+       ktime_t expires = { .tv64 = KTIME_MAX };
        struct tick_device *td;
-       int cpu, res;
+       int cpu;
 
        /*
         * Find the event which expires next:
@@ -319,13 +335,7 @@ static int tick_broadcast_reprogram(int 
        if (expires.tv64 == KTIME_MAX)
                return 0;
 
-       for(;;) {
-               res = clockevents_program_event(bc, expires);
-               if (!res || !force)
-                       return res;
-               tmp = ktime_set(0, bc->min_delta_ns << 1);
-               expires = ktime_add(ktime_get(), tmp);
-       }
+       return tick_broadcast_set_event(expires, 0);
 }
 
 /*
@@ -333,14 +343,15 @@ static int tick_broadcast_reprogram(int 
  */
 static void tick_handle_oneshot_broadcast(struct clock_event_device *dev)
 {
-       ktime_t now;
        struct tick_device *td;
-       cpumask_t mask = CPU_MASK_NONE;
+       cpumask_t mask;
+       ktime_t now;
        int cpu;
 
        spin_lock(&tick_broadcast_lock);
-
 again:
+       dev->next_event.tv64 = KTIME_MAX;
+       mask = CPU_MASK_NONE;
        now = ktime_get();
        /* Find all expired events */
        for (cpu = first_cpu(tick_broadcast_oneshot_mask); cpu != NR_CPUS;
@@ -360,7 +371,7 @@ again:
                 * events. This happens in dyntick mode, as the
                 * maximum PIT delta is quite small.
                 */
-               if (tick_broadcast_reprogram(0))
+               if (tick_broadcast_reprogram())
                        goto again;
        }
        spin_unlock(&tick_broadcast_lock);
@@ -398,6 +409,8 @@ void tick_broadcast_oneshot_control(unsi
                if (!cpu_isset(cpu, tick_broadcast_oneshot_mask)) {
                        cpu_set(cpu, tick_broadcast_oneshot_mask);
                        clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
+                       if (dev->next_event.tv64 < bc->next_event.tv64)
+                               tick_broadcast_set_event(dev->next_event, 1);
                }
        } else {
                if (cpu_isset(cpu, tick_broadcast_oneshot_mask)) {
@@ -408,8 +421,6 @@ void tick_broadcast_oneshot_control(unsi
                }
        }
 
-       if (!cpus_empty(tick_broadcast_oneshot_mask))
-               tick_broadcast_reprogram(1);
 out:
        spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
@@ -422,6 +433,7 @@ void tick_broadcast_setup_oneshot(struct
        if (bc->mode != CLOCK_EVT_MODE_ONESHOT) {
                bc->event_handler = tick_handle_oneshot_broadcast;
                clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
+               bc->next_event.tv64 = KTIME_MAX;
        }
 }
 
Index: linux-2.6.20/include/linux/clockchips.h
===================================================================
--- linux-2.6.20.orig/include/linux/clockchips.h
+++ linux-2.6.20/include/linux/clockchips.h
@@ -128,7 +128,7 @@ extern void clockevents_set_mode(struct 
 extern int clockevents_register_notifier(struct notifier_block *nb);
 extern void clockevents_unregister_notifier(struct notifier_block *nb);
 extern int clockevents_program_event(struct clock_event_device *dev,
-                                    ktime_t expires);
+                                    ktime_t expires, ktime_t now);
 
 extern void clockevents_notify(unsigned long reason, void *arg);
 
Index: linux-2.6.20/kernel/time/tick-common.c
===================================================================
--- linux-2.6.20.orig/kernel/time/tick-common.c
+++ linux-2.6.20/kernel/time/tick-common.c
@@ -89,7 +89,7 @@ void tick_handle_periodic(struct clock_e
        for (;;) {
                ktime_t next = ktime_add(dev->next_event, tick_period);
 
-               if (!clockevents_program_event(dev, next))
+               if (!clockevents_program_event(dev, next, ktime_get()))
                        return;
                tick_periodic(cpu);
        }
@@ -120,7 +120,7 @@ void tick_setup_periodic(struct clock_ev
                clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
 
                for (;;) {
-                       if (!clockevents_program_event(dev, next))
+                       if (!clockevents_program_event(dev, next, ktime_get()))
                                return;
                        next = ktime_add(next, tick_period);
                }
Index: linux-2.6.20/kernel/time/tick-oneshot.c
===================================================================
--- linux-2.6.20.orig/kernel/time/tick-oneshot.c
+++ linux-2.6.20/kernel/time/tick-oneshot.c
@@ -28,14 +28,15 @@
 int tick_program_event(ktime_t expires, int force)
 {
        struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
+       ktime_t now = ktime_get();
 
        while (1) {
-               int ret = clockevents_program_event(dev, expires);
+               int ret = clockevents_program_event(dev, expires, now);
 
                if (!ret || !force)
                        return ret;
-               expires = ktime_add(expires,
-                                   ktime_set(0, dev->min_delta_ns << 2));
+               now = ktime_get();
+               expires = ktime_add(now, ktime_set(0, dev->min_delta_ns));
        }
 }
 
@@ -48,7 +49,7 @@ void tick_setup_oneshot(struct clock_eve
 {
        newdev->event_handler = handler;
        clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT);
-       clockevents_program_event(newdev, next_event);
+       clockevents_program_event(newdev, next_event, ktime_get());
 }
 
 /**
Index: linux-2.6.20/kernel/time/tick-sched.c
===================================================================
--- linux-2.6.20.orig/kernel/time/tick-sched.c
+++ linux-2.6.20/kernel/time/tick-sched.c
@@ -137,13 +137,15 @@ __setup("nohz=", setup_tick_nohz);
  */
 void tick_nohz_update_jiffies(void)
 {
-       struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
+       int cpu = smp_processor_id();
+       struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
        unsigned long flags;
        ktime_t now;
 
        if (!ts->tick_stopped)
                return;
 
+       cpu_clear(cpu, nohz_cpu_mask);
        now = ktime_get();
 
        local_irq_save(flags);
@@ -161,17 +163,24 @@ void tick_nohz_update_jiffies(void)
 void tick_nohz_stop_sched_tick(void)
 {
        unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
-       struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
+       struct tick_sched *ts;
        ktime_t last_update, expires, now, delta;
-
-       if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
-               return;
+       int cpu;
 
        local_irq_save(flags);
 
+       cpu = smp_processor_id();
+       ts = &per_cpu(tick_cpu_sched, cpu);
+
+       if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
+               goto end;
+
        if (need_resched())
                goto end;
 
+       cpu = smp_processor_id();
+       BUG_ON(local_softirq_pending());
+
        now = ktime_get();
        /*
         * When called from irq_exit we need to account the idle sleep time
@@ -196,12 +205,20 @@ void tick_nohz_stop_sched_tick(void)
        next_jiffies = get_next_timer_interrupt(last_jiffies);
        delta_jiffies = next_jiffies - last_jiffies;
 
-       /* Do not stop the tick, if we are only one off */
-       if (!ts->tick_stopped && delta_jiffies == 1)
+       /*
+        * Do not stop the tick, if we are only one off
+        * or if the cpu is required for rcu
+        */
+       if (!ts->tick_stopped && (delta_jiffies == 1 || rcu_needs_cpu(cpu)))
                goto out;
 
        /* Schedule the tick, if we are at least one jiffie off */
        if ((long)delta_jiffies >= 1) {
+
+               if (rcu_needs_cpu(cpu))
+                       delta_jiffies = 1;
+               else
+                       cpu_set(cpu, nohz_cpu_mask);
                /*
                 * nohz_stop_sched_tick can be called several times before
                 * the nohz_restart_sched_tick is called. This happens when
@@ -237,6 +254,7 @@ void tick_nohz_stop_sched_tick(void)
                 * softirq.
                 */
                tick_do_update_jiffies64(ktime_get());
+               cpu_clear(cpu, nohz_cpu_mask);
        }
        raise_softirq_irqoff(TIMER_SOFTIRQ);
 out:
@@ -253,7 +271,8 @@ end:
  */
 void tick_nohz_restart_sched_tick(void)
 {
-       struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
+       int cpu = smp_processor_id();
+       struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
        unsigned long ticks;
        ktime_t now, delta;
 
@@ -265,6 +284,7 @@ void tick_nohz_restart_sched_tick(void)
 
        local_irq_disable();
        tick_do_update_jiffies64(now);
+       cpu_clear(cpu, nohz_cpu_mask);
 
        /* Account the idle time */
        delta = ktime_sub(now, ts->idle_entrytime);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to