diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2017-10-03 10:39:02 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2017-10-04 04:53:54 -0400 |
commit | 34ddaa3e5c0096fef52485186c7eb6cf56ddc686 (patch) | |
tree | 3d98dfe007218f46a0b9b287fb2fe58b4797a9d5 | |
parent | e31d6883f21c1cdfe5bc64e28411f8a92b783fde (diff) |
powerpc/watchdog: Make use of watchdog_nmi_probe()
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
-rw-r--r-- | arch/powerpc/kernel/watchdog.c | 17 | ||||
-rw-r--r-- | include/linux/nmi.h | 1 | ||||
-rw-r--r-- | kernel/watchdog.c | 5 |
3 files changed, 13 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c index f9b4c6352d24..c702a8981452 100644 --- a/arch/powerpc/kernel/watchdog.c +++ b/arch/powerpc/kernel/watchdog.c | |||
@@ -373,22 +373,21 @@ void watchdog_nmi_start(void) | |||
373 | } | 373 | } |
374 | 374 | ||
375 | /* | 375 | /* |
376 | * This runs after lockup_detector_init() which sets up watchdog_cpumask. | 376 | * Invoked from core watchdog init. |
377 | */ | 377 | */ |
378 | static int __init powerpc_watchdog_init(void) | 378 | int __init watchdog_nmi_probe(void) |
379 | { | 379 | { |
380 | int err; | 380 | int err; |
381 | 381 | ||
382 | watchdog_calc_timeouts(); | 382 | err = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, |
383 | 383 | "powerpc/watchdog:online", | |
384 | err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powerpc/watchdog:online", | 384 | start_wd_on_cpu, stop_wd_on_cpu); |
385 | start_wd_on_cpu, stop_wd_on_cpu); | 385 | if (err < 0) { |
386 | if (err < 0) | ||
387 | pr_warn("Watchdog could not be initialized"); | 386 | pr_warn("Watchdog could not be initialized"); |
388 | 387 | return err; | |
388 | } | ||
389 | return 0; | 389 | return 0; |
390 | } | 390 | } |
391 | arch_initcall(powerpc_watchdog_init); | ||
392 | 391 | ||
393 | static void handle_backtrace_ipi(struct pt_regs *regs) | 392 | static void handle_backtrace_ipi(struct pt_regs *regs) |
394 | { | 393 | { |
diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 0c9ed49fb21a..27e249ed7c5c 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h | |||
@@ -111,6 +111,7 @@ static inline int hardlockup_detector_perf_init(void) { return 0; } | |||
111 | 111 | ||
112 | void watchdog_nmi_stop(void); | 112 | void watchdog_nmi_stop(void); |
113 | void watchdog_nmi_start(void); | 113 | void watchdog_nmi_start(void); |
114 | int watchdog_nmi_probe(void); | ||
114 | 115 | ||
115 | /** | 116 | /** |
116 | * touch_nmi_watchdog - restart NMI watchdog timeout. | 117 | * touch_nmi_watchdog - restart NMI watchdog timeout. |
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index fff90fe10007..5c6fb7cd9ae8 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
@@ -608,7 +608,6 @@ static inline int watchdog_park_threads(void) { return 0; } | |||
608 | static inline void watchdog_unpark_threads(void) { } | 608 | static inline void watchdog_unpark_threads(void) { } |
609 | static inline int watchdog_enable_all_cpus(void) { return 0; } | 609 | static inline int watchdog_enable_all_cpus(void) { return 0; } |
610 | static inline void watchdog_disable_all_cpus(void) { } | 610 | static inline void watchdog_disable_all_cpus(void) { } |
611 | static inline void softlockup_init_threads(void) { } | ||
612 | static void softlockup_reconfigure_threads(void) | 611 | static void softlockup_reconfigure_threads(void) |
613 | { | 612 | { |
614 | cpus_read_lock(); | 613 | cpus_read_lock(); |
@@ -617,6 +616,10 @@ static void softlockup_reconfigure_threads(void) | |||
617 | watchdog_nmi_start(); | 616 | watchdog_nmi_start(); |
618 | cpus_read_unlock(); | 617 | cpus_read_unlock(); |
619 | } | 618 | } |
619 | static inline void softlockup_init_threads(void) | ||
620 | { | ||
621 | softlockup_reconfigure_threads(); | ||
622 | } | ||
620 | #endif /* !CONFIG_SOFTLOCKUP_DETECTOR */ | 623 | #endif /* !CONFIG_SOFTLOCKUP_DETECTOR */ |
621 | 624 | ||
622 | static void __lockup_detector_cleanup(void) | 625 | static void __lockup_detector_cleanup(void) |