Merge branch 'timers-nohz-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 9 Oct 2014 10:30:57 +0000 (06:30 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 9 Oct 2014 10:30:57 +0000 (06:30 -0400)
Pull timer fixes from Ingo Molnar:
 "Main changes:

  - Fix the deadlock reported by Dave Jones et al
  - Clean up and fix nohz_full interaction with arch abilities
  - nohz init code consolidation/cleanup"

* 'timers-nohz-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  nohz: nohz full depends on irq work self IPI support
  nohz: Consolidate nohz full init code
  arm64: Tell irq work about self IPI support
  arm: Tell irq work about self IPI support
  x86: Tell irq work about self IPI support
  irq_work: Force raised irq work to run on irq work interrupt
  irq_work: Introduce arch_irq_work_has_interrupt()
  nohz: Move nohz full init call to tick init

43 files changed:
arch/alpha/include/asm/Kbuild
arch/arc/include/asm/Kbuild
arch/arm/include/asm/irq_work.h [new file with mode: 0644]
arch/arm/kernel/smp.c
arch/arm64/include/asm/Kbuild
arch/arm64/include/asm/irq_work.h [new file with mode: 0644]
arch/arm64/include/asm/smp.h
arch/arm64/kernel/smp.c
arch/avr32/include/asm/Kbuild
arch/blackfin/include/asm/Kbuild
arch/c6x/include/asm/Kbuild
arch/cris/include/asm/Kbuild
arch/frv/include/asm/Kbuild
arch/hexagon/include/asm/Kbuild
arch/ia64/include/asm/Kbuild
arch/m32r/include/asm/Kbuild
arch/m68k/include/asm/Kbuild
arch/metag/include/asm/Kbuild
arch/microblaze/include/asm/Kbuild
arch/mips/include/asm/Kbuild
arch/mn10300/include/asm/Kbuild
arch/openrisc/include/asm/Kbuild
arch/parisc/include/asm/Kbuild
arch/powerpc/include/asm/Kbuild
arch/s390/include/asm/Kbuild
arch/score/include/asm/Kbuild
arch/sh/include/asm/Kbuild
arch/sparc/include/asm/Kbuild
arch/tile/include/asm/Kbuild
arch/um/include/asm/Kbuild
arch/unicore32/include/asm/Kbuild
arch/x86/include/asm/irq_work.h [new file with mode: 0644]
arch/x86/kernel/irq_work.c
arch/xtensa/include/asm/Kbuild
include/asm-generic/irq_work.h [new file with mode: 0644]
include/linux/irq_work.h
include/linux/tick.h
init/main.c
kernel/irq_work.c
kernel/time/tick-common.c
kernel/time/tick-internal.h
kernel/time/tick-sched.c
kernel/time/timer.c

index e858aa0ad8af3cc4008b464914c264acd39e3980..a52cbf178c3ad063defccabf4ccb23aa4eb7db4a 100644 (file)
@@ -4,6 +4,7 @@ generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += exec.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
index e76fd79f32b0126ee2e83dfaa5ba05d3d4c98452..b8fffc1a2ac237b8feca4a42cc0fd036a9bc8ba2 100644 (file)
@@ -18,6 +18,7 @@ generic-y += ioctl.h
 generic-y += ioctls.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
 generic-y += local.h
diff --git a/arch/arm/include/asm/irq_work.h b/arch/arm/include/asm/irq_work.h
new file mode 100644 (file)
index 0000000..712d03e
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __ASM_ARM_IRQ_WORK_H
+#define __ASM_ARM_IRQ_WORK_H
+
+#include <asm/smp_plat.h>
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+       return is_smp();
+}
+
+#endif /* _ASM_ARM_IRQ_WORK_H */
index 39c74a2c3df9c7370fe2ca9cf2b67ea6dd8985fd..13396d3d600ee26f3578e62edd24e8b7b09315f9 100644 (file)
@@ -499,7 +499,7 @@ void arch_send_call_function_single_ipi(int cpu)
 #ifdef CONFIG_IRQ_WORK
 void arch_irq_work_raise(void)
 {
-       if (is_smp())
+       if (arch_irq_work_has_interrupt())
                smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
 }
 #endif
index 0b3fcf86e6ba735b3b074a4a028c0ec94e62fbe1..c1968475cc4e2bb915f6fe13abfcc594aa565208 100644 (file)
@@ -9,8 +9,8 @@ generic-y += current.h
 generic-y += delay.h
 generic-y += div64.h
 generic-y += dma.h
-generic-y += emergency-restart.h
 generic-y += early_ioremap.h
+generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += ftrace.h
 generic-y += hash.h
diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h
new file mode 100644 (file)
index 0000000..8e24ef3
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __ASM_IRQ_WORK_H
+#define __ASM_IRQ_WORK_H
+
+#include <asm/smp.h>
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+       return !!__smp_cross_call;
+}
+
+#endif /* __ASM_IRQ_WORK_H */
index a498f2cd2c2ad606d612a2192d09c93475bb1ded..780f82c827b6e733da94fab939380364c9e2b279 100644 (file)
@@ -48,6 +48,8 @@ extern void smp_init_cpus(void);
  */
 extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int));
 
+extern void (*__smp_cross_call)(const struct cpumask *, unsigned int);
+
 /*
  * Called from the secondary holding pen, this is the secondary CPU entry point.
  */
index 474339718105823e9dc55201dccfeb017df7c588..b06d1d90ee8cb223c70612515a0bed75048cc806 100644 (file)
@@ -470,7 +470,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        }
 }
 
-static void (*__smp_cross_call)(const struct cpumask *, unsigned int);
+void (*__smp_cross_call)(const struct cpumask *, unsigned int);
 
 void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
 {
index 00a0f3ccd6eb994a67071d8e544762475f1ca792..2a71b1cb984821418f1f0f5b84fb19c9bbd6e72f 100644 (file)
@@ -9,6 +9,7 @@ generic-y += exec.h
 generic-y += futex.h
 generic-y += hash.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
index 0d93b9a79ca9561399a152d25a3545a09496b858..46ed6bb9c6798a6ff3ff749f38b0f255e0b64d6e 100644 (file)
@@ -15,6 +15,7 @@ generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
index 8dbdce8421b08c0e58322db87002ef314778cd1b..e77e0c1dbe75ee81a189f4b74702a7110c1328fa 100644 (file)
@@ -22,6 +22,7 @@ generic-y += ioctl.h
 generic-y += ioctls.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += local.h
index 31742dfadff903d0dd7a953e79f4c8cd2d780379..802b94c4ca861e362c3e3b43f314908659c2fe3e 100644 (file)
@@ -8,6 +8,7 @@ generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += exec.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += kvm_para.h
 generic-y += linkage.h
 generic-y += mcs_spinlock.h
index 5b73921b6e9d32f125366a07f0f1270b0d46e260..3caf05cabfc520a06506e6318203421ad7014f66 100644 (file)
@@ -3,6 +3,7 @@ generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += exec.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
index 0e69796b58c763d83e5b5eb99ed19cdfb951b9eb..5f234a5a23201319e26e9972abd1a31ab44f2d9c 100644 (file)
@@ -23,6 +23,7 @@ generic-y += ioctls.h
 generic-y += iomap.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += local.h
index e8317d2d6c8d4462fe2536e5863ba628e3e44194..747320be9d0e1c4a94bc72cad21ed3b44ab2c3f8 100644 (file)
@@ -2,6 +2,7 @@
 generic-y += clkdev.h
 generic-y += exec.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += kvm_para.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
index accc10a3dc78f09bd7dab56a0907ed1be2925da9..e02448b0648bb7144a7fec2982c38a2df985aff3 100644 (file)
@@ -3,6 +3,7 @@ generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += exec.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += module.h
 generic-y += preempt.h
index c67c94a2d67229a461239a4335def5d90d597abe..dbaf9f3065e8da6802e4beb32706a936264d597c 100644 (file)
@@ -11,6 +11,7 @@ generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
index c29ead89a31778da9d5f217b6cc984c1176a6772..7b8111c8f937ba5d5f0820ad64e56cf1e5e4ef6b 100644 (file)
@@ -19,6 +19,7 @@ generic-y += ioctl.h
 generic-y += ioctls.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
index 27a3acda6c1904a05167b96efb006dcdd56f83ce..448143b8cabd1a8f5e5460d4c79461b0ef6b6bc6 100644 (file)
@@ -5,6 +5,7 @@ generic-y += cputime.h
 generic-y += device.h
 generic-y += exec.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
index 335e5290ec759f670aea360e53cd85293cdfa7f3..57012ef1f51ea102faf35f911009aa14ce846a98 100644 (file)
@@ -3,6 +3,7 @@ generic-y += cputime.h
 generic-y += current.h
 generic-y += emergency-restart.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
 generic-y += mutex.h
index ecbd6676bd338c70a5ad9d1d2ece7b28f996dc21..77eb1a68d13b5eda56c7bca78598225459d56681 100644 (file)
@@ -4,6 +4,7 @@ generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += exec.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
index 480af0d9c2f5dbe20fb39dc6331648dacb043a97..89b61d7dc790ee7b0127072b1a66d181eae11522 100644 (file)
@@ -31,6 +31,7 @@ generic-y += ioctl.h
 generic-y += ioctls.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
index ecf25e6678ad5a2f0e2bd63761699e85c9d2d759..ffb024b8423fa55a282fbfa05fbf4fb13464d4c4 100644 (file)
@@ -10,6 +10,7 @@ generic-y += exec.h
 generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kvm_para.h
 generic-y += local.h
index 7f23f162ce9c0c40a9e29eebba12cdd1db4c6704..31e8f59aff38894c0b16629b2ce7cc18fecbfb2c 100644 (file)
@@ -1,6 +1,7 @@
 
 generic-y += clkdev.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += rwsem.h
index b3fea0722ff1f80e71809f45f61ad48b66805ea1..773f866765882fc3de528298c3e97ff9095f5f72 100644 (file)
@@ -2,6 +2,7 @@
 
 generic-y += clkdev.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
index d26c48fc93c958827d6f7429d28b9752b8365358..3fe5681744f1ed8e37419c8fe65f1b3f5d6af740 100644 (file)
@@ -6,6 +6,7 @@ generic-y += barrier.h
 generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += hash.h
+generic-y += irq_work.h
 generic-y += mcs_spinlock.h
 generic-y += preempt.h
 generic-y += scatterlist.h
index c19e47dacb31bceec56abeac4c96ca32ad3a2977..5a6c9acff0d21eea4fcb802624eecbe854da9400 100644 (file)
@@ -12,6 +12,7 @@ generic-y += hash.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kvm_para.h
 generic-y += local.h
 generic-y += local64.h
index cdd1b447bb6cac1f10cc2a5239e1a477f7e6bb06..f5f94ce1692c42ddab2088c1c0a8d480a6294bfa 100644 (file)
@@ -8,6 +8,7 @@ generic-y += emergency-restart.h
 generic-y += exec.h
 generic-y += hash.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += linkage.h
 generic-y += local.h
 generic-y += local64.h
index 0aa5675e7025e1f791da57ed9bc52133dd4121da..e6462b8a62842534f8e8ffe9eb628e586aaf8ec3 100644 (file)
@@ -17,6 +17,7 @@ generic-y += ioctl.h
 generic-y += ioctls.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += local.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
index 7bd64aa2e94a40599211460fc615fe0dd12c7680..244b12c8cb391b9e7fec48c2846a818a9e4db93e 100644 (file)
@@ -14,6 +14,7 @@ generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += io.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += mcs_spinlock.h
 generic-y += mutex.h
index 1e5fb872a4aa60d3292705b8bc34a69a9038d85a..5a2bb53faa42137607feafad23e3896e9249d078 100644 (file)
@@ -22,6 +22,7 @@ generic-y += ioctl.h
 generic-y += ioctls.h
 generic-y += ipcbuf.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += local.h
diff --git a/arch/x86/include/asm/irq_work.h b/arch/x86/include/asm/irq_work.h
new file mode 100644 (file)
index 0000000..78162f8
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _ASM_IRQ_WORK_H
+#define _ASM_IRQ_WORK_H
+
+#include <asm/processor.h>
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+       return cpu_has_apic;
+}
+
+#endif /* _ASM_IRQ_WORK_H */
index 1de84e3ab4e0737df845648aad772e815908c2f8..15d741ddfeeb7c4497e28052e1ad7ea08e68c252 100644 (file)
@@ -41,7 +41,7 @@ __visible void smp_trace_irq_work_interrupt(struct pt_regs *regs)
 void arch_irq_work_raise(void)
 {
 #ifdef CONFIG_X86_LOCAL_APIC
-       if (!cpu_has_apic)
+       if (!arch_irq_work_has_interrupt())
                return;
 
        apic->send_IPI_self(IRQ_WORK_VECTOR);
index c3d20ba6eb86d6f7d42102f076f6085bcbe096c8..105d38922c442624fd4bfadb5a5e475857adf041 100644 (file)
@@ -12,6 +12,7 @@ generic-y += hardirq.h
 generic-y += hash.h
 generic-y += ioctl.h
 generic-y += irq_regs.h
+generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
diff --git a/include/asm-generic/irq_work.h b/include/asm-generic/irq_work.h
new file mode 100644 (file)
index 0000000..a44f452
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ASM_IRQ_WORK_H
+#define __ASM_IRQ_WORK_H
+
+static inline bool arch_irq_work_has_interrupt(void)
+{
+       return false;
+}
+
+#endif /* __ASM_IRQ_WORK_H */
+
index bf9422c3aefe22ddd7efa63b3f88502c0659b0b5..bf3fe719c7ce9d3c0efa3c2449cc0d2a7e5b43ad 100644 (file)
@@ -39,9 +39,12 @@ bool irq_work_queue_on(struct irq_work *work, int cpu);
 #endif
 
 void irq_work_run(void);
+void irq_work_tick(void);
 void irq_work_sync(struct irq_work *work);
 
 #ifdef CONFIG_IRQ_WORK
+#include <asm/irq_work.h>
+
 bool irq_work_needs_cpu(void);
 #else
 static inline bool irq_work_needs_cpu(void) { return false; }
index 9a82c7dc3fdd9f1fd35d62fb2ab0734516c9ad6c..595ee86f5e0dba847e6a0d7199fac8b5739d6d0f 100644 (file)
@@ -181,14 +181,12 @@ static inline bool tick_nohz_full_cpu(int cpu)
        return cpumask_test_cpu(cpu, tick_nohz_full_mask);
 }
 
-extern void tick_nohz_init(void);
 extern void __tick_nohz_full_check(void);
 extern void tick_nohz_full_kick(void);
 extern void tick_nohz_full_kick_cpu(int cpu);
 extern void tick_nohz_full_kick_all(void);
 extern void __tick_nohz_task_switch(struct task_struct *tsk);
 #else
-static inline void tick_nohz_init(void) { }
 static inline bool tick_nohz_full_enabled(void) { return false; }
 static inline bool tick_nohz_full_cpu(int cpu) { return false; }
 static inline void __tick_nohz_full_check(void) { }
index bb1aed928f21391b63493112c6bb1a1eae39077f..8af2f1abfe38d5f36eade88169f4f9cd04d8ec5a 100644 (file)
@@ -577,7 +577,6 @@ asmlinkage __visible void __init start_kernel(void)
                local_irq_disable();
        idr_init_cache();
        rcu_init();
-       tick_nohz_init();
        context_tracking_init();
        radix_tree_init();
        /* init some links before init_ISA_irqs() */
index e6bcbe756663abd64adf9c416eddee7a91c9a2c9..385b85aded199f5f2be0ee590278b559ac53b136 100644 (file)
@@ -115,8 +115,10 @@ bool irq_work_needs_cpu(void)
 
        raised = &__get_cpu_var(raised_list);
        lazy = &__get_cpu_var(lazy_list);
-       if (llist_empty(raised) && llist_empty(lazy))
-               return false;
+
+       if (llist_empty(raised) || arch_irq_work_has_interrupt())
+               if (llist_empty(lazy))
+                       return false;
 
        /* All work should have been flushed before going offline */
        WARN_ON_ONCE(cpu_is_offline(smp_processor_id()));
@@ -171,6 +173,15 @@ void irq_work_run(void)
 }
 EXPORT_SYMBOL_GPL(irq_work_run);
 
+void irq_work_tick(void)
+{
+       struct llist_head *raised = &__get_cpu_var(raised_list);
+
+       if (!llist_empty(raised) && !arch_irq_work_has_interrupt())
+               irq_work_run_list(raised);
+       irq_work_run_list(&__get_cpu_var(lazy_list));
+}
+
 /*
  * Synchronize against the irq_work @entry, ensures the entry is not
  * currently in use.
index 0a0608edeb2665e88d2cb1c917b4cf4f112a4e8e..052b4b53c3d6610b59bb426e785450707b6253f3 100644 (file)
@@ -400,4 +400,5 @@ void tick_resume(void)
 void __init tick_init(void)
 {
        tick_broadcast_init();
+       tick_nohz_init();
 }
index c19c1d84b6f34f66e84b32627b702756364e614a..366aeb4f2c6696ee6239e501ea4904f3812cd44c 100644 (file)
@@ -99,6 +99,13 @@ static inline int tick_broadcast_oneshot_active(void) { return 0; }
 static inline bool tick_broadcast_oneshot_available(void) { return false; }
 #endif /* !TICK_ONESHOT */
 
+/* NO_HZ_FULL internal */
+#ifdef CONFIG_NO_HZ_FULL
+extern void tick_nohz_init(void);
+# else
+static inline void tick_nohz_init(void) { }
+#endif
+
 /*
  * Broadcasting support
  */
index f654a8a298fad5cac36465bdcb23fddeb854f2ef..5a9ff243588cc20a4019d4af496f9a9893d6cb8a 100644 (file)
@@ -295,22 +295,12 @@ out:
 /* Parse the boot-time nohz CPU list from the kernel parameters. */
 static int __init tick_nohz_full_setup(char *str)
 {
-       int cpu;
-
        alloc_bootmem_cpumask_var(&tick_nohz_full_mask);
-       alloc_bootmem_cpumask_var(&housekeeping_mask);
        if (cpulist_parse(str, tick_nohz_full_mask) < 0) {
                pr_warning("NOHZ: Incorrect nohz_full cpumask\n");
+               free_bootmem_cpumask_var(tick_nohz_full_mask);
                return 1;
        }
-
-       cpu = smp_processor_id();
-       if (cpumask_test_cpu(cpu, tick_nohz_full_mask)) {
-               pr_warning("NO_HZ: Clearing %d from nohz_full range for timekeeping\n", cpu);
-               cpumask_clear_cpu(cpu, tick_nohz_full_mask);
-       }
-       cpumask_andnot(housekeeping_mask,
-                      cpu_possible_mask, tick_nohz_full_mask);
        tick_nohz_full_running = true;
 
        return 1;
@@ -349,18 +339,11 @@ static int tick_nohz_init_all(void)
 
 #ifdef CONFIG_NO_HZ_FULL_ALL
        if (!alloc_cpumask_var(&tick_nohz_full_mask, GFP_KERNEL)) {
-               pr_err("NO_HZ: Can't allocate full dynticks cpumask\n");
-               return err;
-       }
-       if (!alloc_cpumask_var(&housekeeping_mask, GFP_KERNEL)) {
-               pr_err("NO_HZ: Can't allocate not-full dynticks cpumask\n");
+               WARN(1, "NO_HZ: Can't allocate full dynticks cpumask\n");
                return err;
        }
        err = 0;
        cpumask_setall(tick_nohz_full_mask);
-       cpumask_clear_cpu(smp_processor_id(), tick_nohz_full_mask);
-       cpumask_clear(housekeeping_mask);
-       cpumask_set_cpu(smp_processor_id(), housekeeping_mask);
        tick_nohz_full_running = true;
 #endif
        return err;
@@ -375,6 +358,37 @@ void __init tick_nohz_init(void)
                        return;
        }
 
+       if (!alloc_cpumask_var(&housekeeping_mask, GFP_KERNEL)) {
+               WARN(1, "NO_HZ: Can't allocate not-full dynticks cpumask\n");
+               cpumask_clear(tick_nohz_full_mask);
+               tick_nohz_full_running = false;
+               return;
+       }
+
+       /*
+        * Full dynticks uses irq work to drive the tick rescheduling on safe
+        * locking contexts. But then we need irq work to raise its own
+        * interrupts to avoid circular dependency on the tick
+        */
+       if (!arch_irq_work_has_interrupt()) {
+               pr_warning("NO_HZ: Can't run full dynticks because arch doesn't "
+                          "support irq work self-IPIs\n");
+               cpumask_clear(tick_nohz_full_mask);
+               cpumask_copy(housekeeping_mask, cpu_possible_mask);
+               tick_nohz_full_running = false;
+               return;
+       }
+
+       cpu = smp_processor_id();
+
+       if (cpumask_test_cpu(cpu, tick_nohz_full_mask)) {
+               pr_warning("NO_HZ: Clearing %d from nohz_full range for timekeeping\n", cpu);
+               cpumask_clear_cpu(cpu, tick_nohz_full_mask);
+       }
+
+       cpumask_andnot(housekeeping_mask,
+                      cpu_possible_mask, tick_nohz_full_mask);
+
        for_each_cpu(cpu, tick_nohz_full_mask)
                context_tracking_cpu_set(cpu);
 
index aca5dfe2fa3de5df0738b6dc495b2e186483a593..9bbb8344ed3bf675c9605383c0614be37cc4ddb5 100644 (file)
@@ -1385,7 +1385,7 @@ void update_process_times(int user_tick)
        rcu_check_callbacks(cpu, user_tick);
 #ifdef CONFIG_IRQ_WORK
        if (in_irq())
-               irq_work_run();
+               irq_work_tick();
 #endif
        scheduler_tick();
        run_posix_cpu_timers(p);