time: RCU permitted to stop idle entry via softirq
authorPaul E. McKenney <paul.mckenney@linaro.org>
Thu, 23 Aug 2012 15:34:07 +0000 (08:34 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Sun, 23 Sep 2012 14:42:52 +0000 (07:42 -0700)
The can_stop_idle_tick() function complains if a softirq vector is
raised too late in the idle-entry process, presumably in order to
prevent dangling softirq invocations from being delayed across the
full idle period, which might be indefinitely long -- and if softirq
was asserted any later than the call to this function, such a delay
might well happen.

However, RCU needs to be able to use softirq to stop idle entry in
order to be able to drain RCU callbacks from the current CPU, which in
turn enables faster entry into dyntick-idle mode, which in turn reduces
power consumption.  Because RCU takes this action at a well-defined
point in the idle-entry path, it is safe for RCU to take this approach.

This commit therefore silences the error message that is sometimes
produced when the going-idle CPU suddenly finds that it has an RCU_SOFTIRQ
to process.  The error message will continue to be issued for other
softirq vectors.

Reported-by: Sedat Dilek <sedat.dilek@gmail.com>
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
include/linux/interrupt.h
kernel/time/tick-sched.c

index c5f856a040b9252f116a3c58744176a2feba0b19..5e4e6170f43a5ef672ddd0d28694849669e310cb 100644 (file)
@@ -430,6 +430,8 @@ enum
        NR_SOFTIRQS
 };
 
+#define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ))
+
 /* map softirq index to softirq name. update 'softirq_to_name' in
  * kernel/softirq.c when adding a new softirq.
  */
index 024540f97f74c3e94205826f33d3968ea765f626..4b1785a7bb8315c844019b7e1ef77888198a245b 100644 (file)
@@ -436,7 +436,8 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
        if (unlikely(local_softirq_pending() && cpu_online(cpu))) {
                static int ratelimit;
 
-               if (ratelimit < 10) {
+               if (ratelimit < 10 &&
+                   (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) {
                        printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
                               (unsigned int) local_softirq_pending());
                        ratelimit++;