powerpc/watchdog: Make use of watchdog_nmi_probe()
authorThomas Gleixner <tglx@linutronix.de>
Tue, 3 Oct 2017 14:39:02 +0000 (16:39 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 4 Oct 2017 08:53:54 +0000 (10:53 +0200)
The rework of the core hotplug code triggers the WARN_ON in start_wd_cpu()
on powerpc because it is called multiple times for the boot CPU.

The first call is via:

  start_wd_on_cpu+0x80/0x2f0
  watchdog_nmi_reconfigure+0x124/0x170
  softlockup_reconfigure_threads+0x110/0x130
  lockup_detector_init+0xbc/0xe0
  kernel_init_freeable+0x18c/0x37c
  kernel_init+0x2c/0x160
  ret_from_kernel_thread+0x5c/0xbc

And then again via the CPU hotplug registration:

  start_wd_on_cpu+0x80/0x2f0
  cpuhp_invoke_callback+0x194/0x620
  cpuhp_thread_fun+0x7c/0x1b0
  smpboot_thread_fn+0x290/0x2a0
  kthread+0x168/0x1b0
  ret_from_kernel_thread+0x5c/0xbc

This can be avoided by setting up the cpu hotplug state with nocalls and
move the initialization to the watchdog_nmi_probe() function. That
initializes the hotplug callbacks without invoking the callback and the
following core initialization function then configures the watchdog for the
online CPUs (in this case CPU0) via softlockup_reconfigure_threads().

Reported-and-tested-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Michael Ellerman <mpe@ellerman.id.au>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: linuxppc-dev@lists.ozlabs.org
arch/powerpc/kernel/watchdog.c
include/linux/nmi.h
kernel/watchdog.c

index f9b4c6352d24a72f7a45500cfa9991b3287d999f..c702a898145250aa4e4da3a88bd32a960ad4fb78 100644 (file)
@@ -373,22 +373,21 @@ void watchdog_nmi_start(void)
 }
 
 /*
- * This runs after lockup_detector_init() which sets up watchdog_cpumask.
+ * Invoked from core watchdog init.
  */
-static int __init powerpc_watchdog_init(void)
+int __init watchdog_nmi_probe(void)
 {
        int err;
 
-       watchdog_calc_timeouts();
-
-       err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powerpc/watchdog:online",
-                               start_wd_on_cpu, stop_wd_on_cpu);
-       if (err < 0)
+       err = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+                                       "powerpc/watchdog:online",
+                                       start_wd_on_cpu, stop_wd_on_cpu);
+       if (err < 0) {
                pr_warn("Watchdog could not be initialized");
-
+               return err;
+       }
        return 0;
 }
-arch_initcall(powerpc_watchdog_init);
 
 static void handle_backtrace_ipi(struct pt_regs *regs)
 {
index 0c9ed49fb21a2b0bea0e209aec8dcd65286b631e..27e249ed7c5c8dfcbd969e347ff844a56899edc7 100644 (file)
@@ -111,6 +111,7 @@ static inline int hardlockup_detector_perf_init(void) { return 0; }
 
 void watchdog_nmi_stop(void);
 void watchdog_nmi_start(void);
+int watchdog_nmi_probe(void);
 
 /**
  * touch_nmi_watchdog - restart NMI watchdog timeout.
index fff90fe100071bccf232c782e7bd12632ab84fdc..5c6fb7cd9ae8f07904d25d0cc3fcef6533f3294e 100644 (file)
@@ -608,7 +608,6 @@ static inline int watchdog_park_threads(void) { return 0; }
 static inline void watchdog_unpark_threads(void) { }
 static inline int watchdog_enable_all_cpus(void) { return 0; }
 static inline void watchdog_disable_all_cpus(void) { }
-static inline void softlockup_init_threads(void) { }
 static void softlockup_reconfigure_threads(void)
 {
        cpus_read_lock();
@@ -617,6 +616,10 @@ static void softlockup_reconfigure_threads(void)
        watchdog_nmi_start();
        cpus_read_unlock();
 }
+static inline void softlockup_init_threads(void)
+{
+       softlockup_reconfigure_threads();
+}
 #endif /* !CONFIG_SOFTLOCKUP_DETECTOR */
 
 static void __lockup_detector_cleanup(void)