162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  NMI backtrace support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Gratuitously copied from arch/x86/kernel/apic/hw_nmi.c by Russell King,
662306a36Sopenharmony_ci * with the following header:
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  HW NMI watchdog support
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *  Arch specific calls to support NMI watchdog
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Bits copied from original nmi.c file
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci#include <linux/cpumask.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/kprobes.h>
1962306a36Sopenharmony_ci#include <linux/nmi.h>
2062306a36Sopenharmony_ci#include <linux/cpu.h>
2162306a36Sopenharmony_ci#include <linux/sched/debug.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#ifdef arch_trigger_cpumask_backtrace
2462306a36Sopenharmony_ci/* For reliability, we're prepared to waste bits here. */
2562306a36Sopenharmony_cistatic DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* "in progress" flag of arch_trigger_cpumask_backtrace */
2862306a36Sopenharmony_cistatic unsigned long backtrace_flag;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * When raise() is called it will be passed a pointer to the
3262306a36Sopenharmony_ci * backtrace_mask. Architectures that call nmi_cpu_backtrace()
3362306a36Sopenharmony_ci * directly from their raise() functions may rely on the mask
3462306a36Sopenharmony_ci * they are passed being updated as a side effect of this call.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_civoid nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
3762306a36Sopenharmony_ci				   int exclude_cpu,
3862306a36Sopenharmony_ci				   void (*raise)(cpumask_t *mask))
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	int i, this_cpu = get_cpu();
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (test_and_set_bit(0, &backtrace_flag)) {
4362306a36Sopenharmony_ci		/*
4462306a36Sopenharmony_ci		 * If there is already a trigger_all_cpu_backtrace() in progress
4562306a36Sopenharmony_ci		 * (backtrace_flag == 1), don't output double cpu dump infos.
4662306a36Sopenharmony_ci		 */
4762306a36Sopenharmony_ci		put_cpu();
4862306a36Sopenharmony_ci		return;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	cpumask_copy(to_cpumask(backtrace_mask), mask);
5262306a36Sopenharmony_ci	if (exclude_cpu != -1)
5362306a36Sopenharmony_ci		cpumask_clear_cpu(exclude_cpu, to_cpumask(backtrace_mask));
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/*
5662306a36Sopenharmony_ci	 * Don't try to send an NMI to this cpu; it may work on some
5762306a36Sopenharmony_ci	 * architectures, but on others it may not, and we'll get
5862306a36Sopenharmony_ci	 * information at least as useful just by doing a dump_stack() here.
5962306a36Sopenharmony_ci	 * Note that nmi_cpu_backtrace(NULL) will clear the cpu bit.
6062306a36Sopenharmony_ci	 */
6162306a36Sopenharmony_ci	if (cpumask_test_cpu(this_cpu, to_cpumask(backtrace_mask)))
6262306a36Sopenharmony_ci		nmi_cpu_backtrace(NULL);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (!cpumask_empty(to_cpumask(backtrace_mask))) {
6562306a36Sopenharmony_ci		pr_info("Sending NMI from CPU %d to CPUs %*pbl:\n",
6662306a36Sopenharmony_ci			this_cpu, nr_cpumask_bits, to_cpumask(backtrace_mask));
6762306a36Sopenharmony_ci		nmi_backtrace_stall_snap(to_cpumask(backtrace_mask));
6862306a36Sopenharmony_ci		raise(to_cpumask(backtrace_mask));
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Wait for up to 10 seconds for all CPUs to do the backtrace */
7262306a36Sopenharmony_ci	for (i = 0; i < 10 * 1000; i++) {
7362306a36Sopenharmony_ci		if (cpumask_empty(to_cpumask(backtrace_mask)))
7462306a36Sopenharmony_ci			break;
7562306a36Sopenharmony_ci		mdelay(1);
7662306a36Sopenharmony_ci		touch_softlockup_watchdog();
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	nmi_backtrace_stall_check(to_cpumask(backtrace_mask));
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/*
8162306a36Sopenharmony_ci	 * Force flush any remote buffers that might be stuck in IRQ context
8262306a36Sopenharmony_ci	 * and therefore could not run their irq_work.
8362306a36Sopenharmony_ci	 */
8462306a36Sopenharmony_ci	printk_trigger_flush();
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	clear_bit_unlock(0, &backtrace_flag);
8762306a36Sopenharmony_ci	put_cpu();
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci// Dump stacks even for idle CPUs.
9162306a36Sopenharmony_cistatic bool backtrace_idle;
9262306a36Sopenharmony_cimodule_param(backtrace_idle, bool, 0644);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cibool nmi_cpu_backtrace(struct pt_regs *regs)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	int cpu = smp_processor_id();
9762306a36Sopenharmony_ci	unsigned long flags;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
10062306a36Sopenharmony_ci		/*
10162306a36Sopenharmony_ci		 * Allow nested NMI backtraces while serializing
10262306a36Sopenharmony_ci		 * against other CPUs.
10362306a36Sopenharmony_ci		 */
10462306a36Sopenharmony_ci		printk_cpu_sync_get_irqsave(flags);
10562306a36Sopenharmony_ci		if (!READ_ONCE(backtrace_idle) && regs && cpu_in_idle(instruction_pointer(regs))) {
10662306a36Sopenharmony_ci			pr_warn("NMI backtrace for cpu %d skipped: idling at %pS\n",
10762306a36Sopenharmony_ci				cpu, (void *)instruction_pointer(regs));
10862306a36Sopenharmony_ci		} else {
10962306a36Sopenharmony_ci			pr_warn("NMI backtrace for cpu %d\n", cpu);
11062306a36Sopenharmony_ci			if (regs)
11162306a36Sopenharmony_ci				show_regs(regs);
11262306a36Sopenharmony_ci			else
11362306a36Sopenharmony_ci				dump_stack();
11462306a36Sopenharmony_ci		}
11562306a36Sopenharmony_ci		printk_cpu_sync_put_irqrestore(flags);
11662306a36Sopenharmony_ci		cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
11762306a36Sopenharmony_ci		return true;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return false;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ciNOKPROBE_SYMBOL(nmi_cpu_backtrace);
12362306a36Sopenharmony_ci#endif
124