tick: Dynamically set broadcast irq affinity
[platform/adaptation/renesas_rcar/renesas_kernel.git] / kernel / time / tick-broadcast.c
index 70dd98c..380910d 100644 (file)
@@ -401,13 +401,34 @@ struct cpumask *tick_get_broadcast_oneshot_mask(void)
        return tick_broadcast_oneshot_mask;
 }
 
-static int tick_broadcast_set_event(struct clock_event_device *bc,
+/*
+ * Set broadcast interrupt affinity
+ */
+static void tick_broadcast_set_affinity(struct clock_event_device *bc,
+                                       const struct cpumask *cpumask)
+{
+       if (!(bc->features & CLOCK_EVT_FEAT_DYNIRQ))
+               return;
+
+       if (cpumask_equal(bc->cpumask, cpumask))
+               return;
+
+       bc->cpumask = cpumask;
+       irq_set_affinity(bc->irq, bc->cpumask);
+}
+
+static int tick_broadcast_set_event(struct clock_event_device *bc, int cpu,
                                    ktime_t expires, int force)
 {
+       int ret;
+
        if (bc->mode != CLOCK_EVT_MODE_ONESHOT)
                clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
 
-       return clockevents_program_event(bc, expires, force);
+       ret = clockevents_program_event(bc, expires, force);
+       if (!ret)
+               tick_broadcast_set_affinity(bc, cpumask_of(cpu));
+       return ret;
 }
 
 int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
@@ -436,7 +457,7 @@ static void tick_handle_oneshot_broadcast(struct clock_event_device *dev)
 {
        struct tick_device *td;
        ktime_t now, next_event;
-       int cpu;
+       int cpu, next_cpu = 0;
 
        raw_spin_lock(&tick_broadcast_lock);
 again:
@@ -447,10 +468,12 @@ again:
        /* Find all expired events */
        for_each_cpu(cpu, tick_broadcast_oneshot_mask) {
                td = &per_cpu(tick_cpu_device, cpu);
-               if (td->evtdev->next_event.tv64 <= now.tv64)
+               if (td->evtdev->next_event.tv64 <= now.tv64) {
                        cpumask_set_cpu(cpu, tmpmask);
-               else if (td->evtdev->next_event.tv64 < next_event.tv64)
+               } else if (td->evtdev->next_event.tv64 < next_event.tv64) {
                        next_event.tv64 = td->evtdev->next_event.tv64;
+                       next_cpu = cpu;
+               }
        }
 
        /*
@@ -473,7 +496,7 @@ again:
                 * Rearm the broadcast device. If event expired,
                 * repeat the above
                 */
-               if (tick_broadcast_set_event(dev, next_event, 0))
+               if (tick_broadcast_set_event(dev, next_cpu, next_event, 0))
                        goto again;
        }
        raw_spin_unlock(&tick_broadcast_lock);
@@ -515,7 +538,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
                if (!cpumask_test_and_set_cpu(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(bc, dev->next_event, 1);
+                               tick_broadcast_set_event(bc, cpu, dev->next_event, 1);
                }
        } else {
                if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
@@ -581,7 +604,7 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
                        clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
                        tick_broadcast_init_next_event(tmpmask,
                                                       tick_next_period);
-                       tick_broadcast_set_event(bc, tick_next_period, 1);
+                       tick_broadcast_set_event(bc, cpu, tick_next_period, 1);
                } else
                        bc->next_event.tv64 = KTIME_MAX;
        } else {