From: Russell King <li...@arm.linux.org.uk>

Currently arm does not implement arch_trigger_all_cpu_backtrace because,
on SMP systems, there has never before been a means to route a
non-maskable interrupt to the other CPUs in the system. With the
introduction of IPI FIQ this is no longer the case. This patch
provides an implementation of arch_trigger_all_cpu_backtrace and
the associated KConfig machinary to enable it.

This is mostly Russell's code but since it was shared as an example rather
than a fully fledged patch currently this code is currently
Not-yet-signed-off-by: Russell King <li...@arm.linux.org.uk>

[Fill in headers and Kconfig, checkpatch.pl substitutions: CONFIG_NR_CPUS
for NR_CPUS and pr_warn() for printk(KERN_WARNING, )]
Signed-off-by: Daniel Thompson <daniel.thomp...@linaro.org>
---
 arch/arm/Kconfig.debug     | 14 +++++++++++
 arch/arm/include/asm/irq.h |  5 ++++
 arch/arm/include/asm/smp.h |  4 ++++
 arch/arm/kernel/smp.c      | 60 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/traps.c    |  3 +++
 5 files changed, 86 insertions(+)

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index b11ad54..2fa932d 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1281,4 +1281,18 @@ config DEBUG_SET_MODULE_RONX
          against certain classes of kernel exploits.
          If in doubt, say "N".
 
+config ARM_BACKTRACE_TRIGGERING
+       bool "Support non-maskable backtrace triggering"
+       depends on SMP
+       select FIQ
+       help
+         Say Y here if you want to provide support for non-maskable
+         backtrace triggering. This is used to generate a backtrace
+         from all CPUs in a non-responsive system. Backtrace requests
+         can be issued by lockup and hung task detectors, spin lock
+         debugging or magic sysrq.
+
+         This option is only effective when the kernel is run on a
+         platform capable of generating FIQs.
+
 endmenu
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index 53c15de..a5cc2ed 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *);
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 #endif
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+void arch_trigger_all_cpu_backtrace(bool);
+#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 0e23384..d20bd95 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -90,6 +90,10 @@ extern void arch_send_wakeup_ipi_mask(const struct cpumask 
*mask);
 
 extern int register_ipi_completion(struct completion *completion, int cpu);
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+extern void ipi_cpu_backtrace(struct pt_regs *regs);
+#endif
+
 struct smp_operations {
 #ifdef CONFIG_SMP
        /*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b2404d0..d1765a6 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -554,6 +554,63 @@ static void ipi_complete(unsigned int cpu)
        complete(per_cpu(cpu_completion, cpu));
 }
 
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, CONFIG_NR_CPUS) __read_mostly;
+
+void ipi_cpu_backtrace(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+               static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+               arch_spin_lock(&lock);
+               pr_warn("FIQ backtrace for cpu %d\n", cpu);
+               show_regs(regs);
+               arch_spin_unlock(&lock);
+               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+       }
+}
+
+void arch_trigger_all_cpu_backtrace(bool include_self)
+{
+       static unsigned long backtrace_flag;
+       int i, cpu = get_cpu();
+
+       if (test_and_set_bit(0, &backtrace_flag)) {
+               /*
+                * If there is already a trigger_all_cpu_backtrace() in progress
+                * (backtrace_flag == 1), don't output double cpu dump infos.
+                */
+               put_cpu();
+               return;
+       }
+
+       cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+       if (!include_self)
+               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+       if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+               pr_info("Sending FIQ to %s CPUs:\n",
+                       (include_self ? "all" : "other"));
+               smp_cross_call(to_cpumask(backtrace_mask), IPI_FIQ);
+       }
+
+       /* Wait for up to 10 seconds for all CPUs to do the backtrace */
+       for (i = 0; i < 10 * 1000; i++) {
+               if (cpumask_empty(to_cpumask(backtrace_mask)))
+                       break;
+
+               mdelay(1);
+       }
+
+       clear_bit(0, &backtrace_flag);
+       smp_mb__after_atomic();
+       put_cpu();
+}
+#endif
+
 /*
  * Main handler for inter-processor interrupts
  */
@@ -623,6 +680,9 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
        case IPI_FIQ:
                BUILD_BUG_ON(SMP_IPI_FIQ_MASK != BIT(IPI_FIQ));
                pr_warn("CPU%u: IPI FIQ delivered via IRQ vector\n", cpu);
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+               ipi_cpu_backtrace(regs);
+#endif
                break;
 
        default:
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 2c219c7..b7e1e85 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -484,6 +484,9 @@ asmlinkage void __exception_irq_entry 
handle_fiq_as_nmi(struct pt_regs *regs)
 #ifdef CONFIG_ARM_GIC
        gic_handle_fiq_ipi();
 #endif
+#ifdef CONFIG_ARM_BACKTRACE_TRIGGERING
+       ipi_cpu_backtrace(regs);
+#endif
 
        nmi_exit();
 
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to