aboutsummaryrefslogtreecommitdiff
path: root/arch/arm64/kernel/smp.c
diff options
context:
space:
mode:
authorDaniel Thompson <daniel.thompson@linaro.org>2015-09-11 16:13:16 +0100
committerDaniel Thompson <daniel.thompson@linaro.org>2016-06-17 17:03:46 +0100
commit41d10cf0b562e8c680101b8b3972982a06ed5b0e (patch)
tree9e49fd0f72db828c4dfe7183938c1e38b64c232f /arch/arm64/kernel/smp.c
parent172bf4147ef51b277f9518bdb4f76f2dab6831b0 (diff)
downloadlinux-dev/arm64_nmi-v4.7-rc3.tar.gz
arm64: Implement IPI_CPU_BACKTRACE using pseudo-NMIsdev/arm64_nmi-v4.7-rc3
Recently arm64 gained the capability to (optionally) mask interrupts using the GIC PMR rather than the CPU PSR. That allows us to introduce an NMI-like means to handle backtrace requests. This provides a useful debug aid by allowing the kernel to robustly show a backtrace for every processor in the system when, for example, we hang trying to acquire a spin lock. Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Diffstat (limited to 'arch/arm64/kernel/smp.c')
-rw-r--r--arch/arm64/kernel/smp.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 206dceb725fc..103731f3d74f 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -863,11 +863,15 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
#endif
case IPI_CPU_BACKTRACE:
- printk_nmi_enter();
- irq_enter();
+ if (in_nmi()) {
+ printk_nmi_enter();
+ irq_enter();
+ }
nmi_cpu_backtrace(regs);
- irq_exit();
- printk_nmi_exit();
+ if (in_nmi()) {
+ irq_exit();
+ printk_nmi_exit();
+ }
break;
#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
@@ -934,13 +938,31 @@ int setup_profiling_timer(unsigned int multiplier)
return -EINVAL;
}
+/*
+ * IPI_CPU_BACKTRACE is either implemented either as a normal IRQ or,
+ * if the hardware can supports it, using a pseudo-NMI.
+ *
+ * The mechanism used to implement pseudo-NMI means that in both cases
+ * testing if the backtrace IPI is disabled requires us to check the
+ * PSR I bit. However in the later case we cannot use irqs_disabled()
+ * to check the I bit because, when the pseudo-NMI is active that
+ * function examines the GIC PMR instead.
+ */
+static unsigned long nmi_disabled(void)
+{
+ unsigned long flags;
+
+ asm volatile("mrs %0, daif" : "=r"(flags) :: "memory");
+ return flags & PSR_I_BIT;
+}
+
static void raise_nmi(cpumask_t *mask)
{
/*
* Generate the backtrace directly if we are running in a
* calling context that is not preemptible by the backtrace IPI.
*/
- if (cpumask_test_cpu(smp_processor_id(), mask) && irqs_disabled())
+ if (cpumask_test_cpu(smp_processor_id(), mask) && nmi_disabled())
nmi_cpu_backtrace(NULL);
smp_cross_call(mask, IPI_CPU_BACKTRACE);