]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/time/tick-broadcast.c
MIPS: RBTX4927: More explicit initialization
[linux-2.6-omap-h63xx.git] / kernel / time / tick-broadcast.c
index 2bc1f046151ce67efe02840c986643003774b2ee..cb01cd8f919b2752cfb7d97b4dc9ea4e87834a97 100644 (file)
@@ -235,9 +235,9 @@ static void tick_do_broadcast_on_off(void *why)
        case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
                if (!cpu_isset(cpu, tick_broadcast_mask)) {
                        cpu_set(cpu, tick_broadcast_mask);
-                       if (td->mode == TICKDEV_MODE_PERIODIC)
-                               clockevents_set_mode(dev,
-                                                    CLOCK_EVT_MODE_SHUTDOWN);
+                       if (tick_broadcast_device.mode ==
+                           TICKDEV_MODE_PERIODIC)
+                               clockevents_shutdown(dev);
                }
                if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
                        tick_broadcast_force = 1;
@@ -246,7 +246,8 @@ static void tick_do_broadcast_on_off(void *why)
                if (!tick_broadcast_force &&
                    cpu_isset(cpu, tick_broadcast_mask)) {
                        cpu_clear(cpu, tick_broadcast_mask);
-                       if (td->mode == TICKDEV_MODE_PERIODIC)
+                       if (tick_broadcast_device.mode ==
+                           TICKDEV_MODE_PERIODIC)
                                tick_setup_periodic(dev, 0);
                }
                break;
@@ -254,7 +255,7 @@ static void tick_do_broadcast_on_off(void *why)
 
        if (cpus_empty(tick_broadcast_mask)) {
                if (!bc_stopped)
-                       clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+                       clockevents_shutdown(bc);
        } else if (bc_stopped) {
                if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
                        tick_broadcast_start_periodic(bc);
@@ -306,7 +307,7 @@ void tick_shutdown_broadcast(unsigned int *cpup)
 
        if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
                if (bc && cpus_empty(tick_broadcast_mask))
-                       clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+                       clockevents_shutdown(bc);
        }
 
        spin_unlock_irqrestore(&tick_broadcast_lock, flags);
@@ -321,7 +322,7 @@ void tick_suspend_broadcast(void)
 
        bc = tick_broadcast_device.evtdev;
        if (bc)
-               clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
+               clockevents_shutdown(bc);
 
        spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
@@ -491,6 +492,18 @@ static void tick_broadcast_clear_oneshot(int cpu)
        cpu_clear(cpu, tick_broadcast_oneshot_mask);
 }
 
+static void tick_broadcast_init_next_event(cpumask_t *mask, ktime_t expires)
+{
+       struct tick_device *td;
+       int cpu;
+
+       for_each_cpu_mask_nr(cpu, *mask) {
+               td = &per_cpu(tick_cpu_device, cpu);
+               if (td->evtdev)
+                       td->evtdev->next_event = expires;
+       }
+}
+
 /**
  * tick_broadcast_setup_oneshot - setup the broadcast device
  */
@@ -498,9 +511,32 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
        /* Set it up only once ! */
        if (bc->event_handler != tick_handle_oneshot_broadcast) {
+               int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC;
+               int cpu = smp_processor_id();
+               cpumask_t mask;
+
                bc->event_handler = tick_handle_oneshot_broadcast;
                clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
-               bc->next_event.tv64 = KTIME_MAX;
+
+               /* Take the do_timer update */
+               tick_do_timer_cpu = cpu;
+
+               /*
+                * We must be careful here. There might be other CPUs
+                * waiting for periodic broadcast. We need to set the
+                * oneshot_mask bits for those and program the
+                * broadcast device to fire.
+                */
+               mask = tick_broadcast_mask;
+               cpu_clear(cpu, mask);
+               cpus_or(tick_broadcast_oneshot_mask,
+                       tick_broadcast_oneshot_mask, mask);
+
+               if (was_periodic && !cpus_empty(mask)) {
+                       tick_broadcast_init_next_event(&mask, tick_next_period);
+                       tick_broadcast_set_event(tick_next_period, 1);
+               } else
+                       bc->next_event.tv64 = KTIME_MAX;
        }
 }
 
@@ -541,4 +577,12 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
        spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
 
+/*
+ * Check, whether the broadcast device is in one shot mode
+ */
+int tick_broadcast_oneshot_active(void)
+{
+       return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT;
+}
+
 #endif