sched: Enable might_sleep before initializing drivers.
[linux-2.6.git] / kernel / time / tick-common.c
index 21a5ca8..119528d 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/percpu.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
-#include <linux/tick.h>
 
 #include <asm/irq_regs.h>
 
@@ -34,7 +33,7 @@ DEFINE_PER_CPU(struct tick_device, tick_cpu_device);
 ktime_t tick_next_period;
 ktime_t tick_period;
 int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT;
-DEFINE_SPINLOCK(tick_device_lock);
+static DEFINE_RAW_SPINLOCK(tick_device_lock);
 
 /*
  * Debugging: see timer_list.c
@@ -49,9 +48,13 @@ struct tick_device *tick_get_device(int cpu)
  */
 int tick_is_oneshot_available(void)
 {
-       struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
+       struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
 
-       return dev && (dev->features & CLOCK_EVT_FEAT_ONESHOT);
+       if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT))
+               return 0;
+       if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
+               return 1;
+       return tick_broadcast_oneshot_available();
 }
 
 /*
@@ -93,7 +96,17 @@ void tick_handle_periodic(struct clock_event_device *dev)
        for (;;) {
                if (!clockevents_program_event(dev, next, ktime_get()))
                        return;
-               tick_periodic(cpu);
+               /*
+                * Have to be careful here. If we're in oneshot mode,
+                * before we call tick_periodic() in a loop, we need
+                * to be sure we're using a real hardware clocksource.
+                * Otherwise we could get trapped in an infinite
+                * loop, as the tick_periodic() increments jiffies,
+                * when then will increment time, posibly causing
+                * the loop to trigger again and again.
+                */
+               if (timekeeping_valid_for_hres())
+                       tick_periodic(cpu);
                next = ktime_add(next, tick_period);
        }
 }
@@ -199,7 +212,7 @@ static int tick_check_new_device(struct clock_event_device *newdev)
        int cpu, ret = NOTIFY_OK;
        unsigned long flags;
 
-       spin_lock_irqsave(&tick_device_lock, flags);
+       raw_spin_lock_irqsave(&tick_device_lock, flags);
 
        cpu = smp_processor_id();
        if (!cpumask_test_cpu(cpu, newdev->cpumask))
@@ -258,7 +271,7 @@ static int tick_check_new_device(struct clock_event_device *newdev)
        if (newdev->features & CLOCK_EVT_FEAT_ONESHOT)
                tick_oneshot_notify();
 
-       spin_unlock_irqrestore(&tick_device_lock, flags);
+       raw_spin_unlock_irqrestore(&tick_device_lock, flags);
        return NOTIFY_STOP;
 
 out_bc:
@@ -268,7 +281,7 @@ out_bc:
        if (tick_check_broadcast_device(newdev))
                ret = NOTIFY_STOP;
 
-       spin_unlock_irqrestore(&tick_device_lock, flags);
+       raw_spin_unlock_irqrestore(&tick_device_lock, flags);
 
        return ret;
 }
@@ -301,7 +314,7 @@ static void tick_shutdown(unsigned int *cpup)
        struct clock_event_device *dev = td->evtdev;
        unsigned long flags;
 
-       spin_lock_irqsave(&tick_device_lock, flags);
+       raw_spin_lock_irqsave(&tick_device_lock, flags);
        td->mode = TICKDEV_MODE_PERIODIC;
        if (dev) {
                /*
@@ -312,7 +325,7 @@ static void tick_shutdown(unsigned int *cpup)
                clockevents_exchange_device(dev, NULL);
                td->evtdev = NULL;
        }
-       spin_unlock_irqrestore(&tick_device_lock, flags);
+       raw_spin_unlock_irqrestore(&tick_device_lock, flags);
 }
 
 static void tick_suspend(void)
@@ -320,9 +333,9 @@ static void tick_suspend(void)
        struct tick_device *td = &__get_cpu_var(tick_cpu_device);
        unsigned long flags;
 
-       spin_lock_irqsave(&tick_device_lock, flags);
+       raw_spin_lock_irqsave(&tick_device_lock, flags);
        clockevents_shutdown(td->evtdev);
-       spin_unlock_irqrestore(&tick_device_lock, flags);
+       raw_spin_unlock_irqrestore(&tick_device_lock, flags);
 }
 
 static void tick_resume(void)
@@ -331,7 +344,7 @@ static void tick_resume(void)
        unsigned long flags;
        int broadcast = tick_resume_broadcast();
 
-       spin_lock_irqsave(&tick_device_lock, flags);
+       raw_spin_lock_irqsave(&tick_device_lock, flags);
        clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME);
 
        if (!broadcast) {
@@ -340,7 +353,7 @@ static void tick_resume(void)
                else
                        tick_resume_oneshot();
        }
-       spin_unlock_irqrestore(&tick_device_lock, flags);
+       raw_spin_unlock_irqrestore(&tick_device_lock, flags);
 }
 
 /*