watchdog: use FIQ WDT for soft lockup stack dump
Renn Wu [Tue, 3 Feb 2015 02:27:18 +0000 (10:27 +0800)]
Using Tegra WDT to trigger FIQ when system is in soft lockup.

Bug 1581432

Change-Id: I853a88a3f6e9402c978db18c5a63e903c582040a
Signed-off-by: Renn Wu <rewu@nvidia.com>
Reviewed-on: http://git-master/r/265871
(cherry picked from commit f115f435d471af22ddec5e9d969662f79193f846)
Reviewed-on: http://git-master/r/680353
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: Winnie Hsu <whsu@nvidia.com>

arch/arm/common/Kconfig
arch/arm/common/fiq_debugger.c
arch/arm/configs/tegra12_defconfig
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/board-ardbeg.c
drivers/staging/android/Makefile
drivers/watchdog/tegra_wdt.c
include/linux/nmi.h
kernel/watchdog.c

index a73a5bd..709d853 100644 (file)
@@ -22,51 +22,6 @@ config FIQ_GLUE
        bool
        select FIQ
 
-config FIQ_DEBUGGER
-       bool "FIQ Mode Serial Debugger"
-       select FIQ
-       select FIQ_GLUE
-       default n
-       help
-         The FIQ serial debugger can accept commands even when the
-         kernel is unresponsive due to being stuck with interrupts
-         disabled.
-
-config FIQ_DEBUGGER_NO_SLEEP
-       bool "Keep serial debugger active"
-       depends on FIQ_DEBUGGER
-       default n
-       help
-         Enables the serial debugger at boot. Passing
-         fiq_debugger.no_sleep on the kernel commandline will
-         override this config option.
-
-config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
-       bool "Don't disable wakeup IRQ when debugger is active"
-       depends on FIQ_DEBUGGER
-       default n
-       help
-         Don't disable the wakeup irq when enabling the uart clock.  This will
-         cause extra interrupts, but it makes the serial debugger usable with
-         on some MSM radio builds that ignore the uart clock request in power
-         collapse.
-
-config FIQ_DEBUGGER_CONSOLE
-       bool "Console on FIQ Serial Debugger port"
-       depends on FIQ_DEBUGGER
-       default n
-       help
-         Enables a console so that printk messages are displayed on
-         the debugger serial port as the occur.
-
-config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE
-       bool "Put the FIQ debugger into console mode by default"
-       depends on FIQ_DEBUGGER_CONSOLE
-       default n
-       help
-         If enabled, this puts the fiq debugger into console mode by default.
-         Otherwise, the fiq debugger will start out in debug mode.
-
 config GIC_SET_MULTIPLE_CPUS
        bool "Use affinity hint to allow multiple CPUs for IRQ"
        depends on ARM_GIC && SMP
index 4156a7f..2f10fea 100644 (file)
@@ -454,15 +454,21 @@ static void fiq_debugger_help(struct fiq_debugger_state *state)
 #endif
 }
 
-static void fiq_debugger_take_affinity(void *info)
+
+static void change_cpu_affinity(int fiq, int cpu)
 {
-       struct fiq_debugger_state *state = info;
        struct cpumask cpumask;
 
        cpumask_clear(&cpumask);
-       cpumask_set_cpu(get_cpu(), &cpumask);
+       cpumask_set_cpu(cpu, &cpumask);
+       irq_set_affinity(fiq, &cpumask);
+}
 
-       irq_set_affinity(state->uart_irq, &cpumask);
+static void fiq_debugger_take_affinity(void *info)
+{
+       struct fiq_debugger_state *state = info;
+
+       change_cpu_affinity(state->uart_irq, get_cpu());
 }
 
 static void fiq_debugger_switch_cpu(struct fiq_debugger_state *state, int cpu)
@@ -739,11 +745,33 @@ static void fiq_debugger_fiq(struct fiq_glue_handler *h,
 
        unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
        bool need_irq;
+       unsigned int next_cpu;
+       static bool cpu0_again;
+
+       /*
+        * 1st FIQ always goes to CPU0. We will change FIQ CPU affinity, if CPU0
+        * enter the FIQ handler 2nd time, we know we have already done the
+        * stack dump for all CPUs and we can enter the debug console.
+        */
+       if (cpu0_again) {
+               need_irq = fiq_debugger_handle_uart_interrupt(state,
+                               this_cpu, regs, svc_sp);
+               if (need_irq)
+                       fiq_debugger_force_irq(state);
+               return;
+       }
+
+       fiq_debugger_dump_allregs(&state->output, regs);
+       fiq_debugger_dump_pc(&state->output, regs);
+       fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp);
+       /* let another online CPU handle the FIQ */
+       next_cpu = cpumask_next(this_cpu, cpu_online_mask);
+       if (next_cpu >= nr_cpu_ids) {
+               next_cpu = 0;
+               cpu0_again = true;
+       }
+       change_cpu_affinity(state->fiq, next_cpu);
 
-       need_irq = fiq_debugger_handle_uart_interrupt(state, this_cpu, regs,
-                       svc_sp);
-       if (need_irq)
-               fiq_debugger_force_irq(state);
 }
 #endif
 
index 01bcc94..19a6400 100644 (file)
@@ -564,13 +564,3 @@ CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_DEV_TEGRA_SE=y
-# CONFIG_FIQ is not set
-# CONFIG_TEGRA_FIQ_DEBUGGER is not set
-# CONFIG_FIQ_GLUE is not set
-# CONFIG_FIQ_DEBUGGER is not set
-# CONFIG_FIQ_DEBUGGER_NO_SLEEP is not set
-# CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON is not set
-# CONFIG_FIQ_DEBUGGER_CONSOLE is not set
-# CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE is not set
-# CONFIG_CONSOLE_POLL is not set
-
index 35f648f..d79a300 100644 (file)
@@ -240,6 +240,53 @@ config TEGRA_SIMULATION_SPLIT_MEM
           setup. Select this only if you are an NVIDIA developer
           working on a simulation platform.
 
+config FIQ_DEBUGGER
+       bool "FIQ Mode Serial Debugger"
+       select FIQ
+       select FIQ_GLUE
+       default n
+       help
+         The FIQ serial debugger can accept commands even when the
+         kernel is unresponsive due to being stuck with interrupts
+         disabled. Also, we can save kernel log in FIQ handler.
+         It will not work if FIQ not work or hardware hang.
+
+config FIQ_DEBUGGER_NO_SLEEP
+       bool "Keep serial debugger active"
+       depends on FIQ_DEBUGGER
+       default n
+       help
+         Enables the serial debugger at boot. Passing
+         fiq_debugger.no_sleep on the kernel commandline will
+         override this config option.
+         Enable this config then serial debugger will never off.
+
+config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
+       bool "Don't disable wakeup IRQ when debugger is active"
+       depends on FIQ_DEBUGGER
+       default n
+       help
+         Don't disable the wakeup irq when enabling the uart clock.  This will
+         cause extra interrupts, but it makes the serial debugger usable with
+         on some MSM radio builds that ignore the uart clock request in power
+         collapse.
+
+config FIQ_DEBUGGER_CONSOLE
+       bool "Console on FIQ Serial Debugger port"
+       depends on FIQ_DEBUGGER
+       default n
+       help
+         Enables a console so that printk messages are displayed on
+         the debugger serial port as the occur.
+
+config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE
+       bool "Put the FIQ debugger into console mode by default"
+       depends on FIQ_DEBUGGER_CONSOLE
+       default n
+       help
+         If enabled, this puts the fiq debugger into console mode by default.
+         Otherwise, the fiq debugger will start out in debug mode.
+
 config TEGRA_FIQ_DEBUGGER
        bool "Enable the FIQ serial debugger on Tegra"
        default n
@@ -247,6 +294,15 @@ config TEGRA_FIQ_DEBUGGER
        help
          Enables the FIQ serial debugger on Tegra
 
+config TEGRA_WDT_FIQ_SOFT_HANG_STACK_DUMP
+       bool "Enable Tegra system soft hang stack dump"
+       default n
+       help
+         This option will generate stack dump for all online CPUs upon
+         soft hang detection by using the FIQ debugger mechanism even
+         the IRQ is disabled on the CPU. This option is useful if we
+         only have one watchdog generating FIQ for all CPUs.
+
 config TEGRA_PTM
        bool "Enable PTM debugger on Tegra"
        default n
index f83ccfa..46c4d3f 100644 (file)
@@ -415,6 +415,7 @@ static void __init ardbeg_uart_init(void)
 #if !defined(CONFIG_TRUSTED_FOUNDATIONS) && \
        defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
        tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_AVP, NULL, -1, -1);
+       platform_device_register(uart_console_debug_device);
 #else
        tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1);
 #endif
index 907b62f..0a01e19 100644 (file)
@@ -1,7 +1,6 @@
 ccflags-y += -I$(src)                  # needed for trace events
 
 obj-y                                  += ion/
-obj-$(CONFIG_FIQ_DEBUGGER)             += fiq_debugger/
 
 obj-$(CONFIG_ANDROID_BINDER_IPC)       += binder.o
 obj-$(CONFIG_ASHMEM)                   += ashmem.o
index d83adef..59a4100 100644 (file)
@@ -157,6 +157,11 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id)
 #define PMC_RST_STATUS                 0x1b4
 
 struct tegra_wdt *tegra_wdt[MAX_NR_CPU_WDT];
+/*
+ * In order to generate the stack dump for the CPU which has IRQ off, we must
+ * use the FIQ. TEGRA WDT can generate the FIQ if we do not ACK the IRQ.
+ */
+bool wdt_nmi_ack_off;
 
 static inline void tegra_wdt_ping(struct tegra_wdt *wdt)
 {
@@ -170,7 +175,8 @@ static inline void tegra_wdt_ping(struct tegra_wdt *wdt)
 
 #if !defined(CONFIG_TRUSTED_FOUNDATIONS) && \
        defined(CONFIG_ARCH_TEGRA_12x_SOC) && defined(CONFIG_FIQ_DEBUGGER)
-       writel(WDT_CMD_START_COUNTER, wdt->wdt_avp_source + WDT_CMD);
+       if (wdt_nmi_ack_off == false)
+               writel(WDT_CMD_START_COUNTER, wdt->wdt_avp_source + WDT_CMD);
 #endif
 
 }
index a461766..73fc09b 100644 (file)
@@ -1,6 +1,8 @@
 /*
  *  linux/include/linux/nmi.h
+ *  Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.
  */
+
 #ifndef LINUX_NMI_H
 #define LINUX_NMI_H
 
@@ -57,4 +59,12 @@ extern int proc_dowatchdog(struct ctl_table *, int ,
 extern int watchdog_get_lockup_state(void);
 #endif
 
+static inline void set_wdt_nmi_ack_off(void)
+{
+#if defined(CONFIG_TEGRA_WDT_FIQ_SOFT_HANG_STACK_DUMP)
+       extern bool wdt_nmi_ack_off;
+       wdt_nmi_ack_off = true;
+#endif
+}
+
 #endif
index 274e737..38d0aab 100644 (file)
@@ -2,6 +2,7 @@
  * Detect hard and soft lockups on a system
  *
  * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
+ *  Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.
  *
  * Note: Most of this code is borrowed heavily from the original softlockup
  * detector, so thanks to Ingo for the initial implementation.
@@ -415,6 +416,8 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
                else
                        dump_stack();
 
+               set_wdt_nmi_ack_off();
+
                if (softlockup_panic)
                        panic("softlockup: hung tasks");
                __this_cpu_write(soft_watchdog_warn, true);