2019-05-06 08:23:36

by liwei (GF)

[permalink] [raw]
Subject: [PATCH 0/3] arm64: Add support for on-demand backtrace by NMI-like IPI

In this patch series, we add the backtracing support of other CPUs in the
system on lockups, which is based on the arm64 NMI-like IPI.

The test log is as follows (pmr_save == 0x70 means the IRQ is OFF):

[ 272.165995] watchdog: BUG: soft lockup - CPU#5 stuck for 82s! [lockup_test5:255]
[ 272.166342] Modules linked in: lockup_test(OE) [last unloaded: lockup_test]
[ 272.166835] CPU: 5 PID: 255 Comm: lockup_test5 Tainted: G OEL 5.1.0-rc7+ #10
[ 272.167179] Hardware name: linux,dummy-virt (DT)
[ 272.167432] pstate: 60000005 (nZCv daif -PAN -UAO)
[ 272.167751] pc : hardlockup_test_loop+0x7c/0xe8 [lockup_test]
[ 272.168529] lr : hardlockup_test_loop+0xc4/0xe8 [lockup_test]
[ 272.168889] sp : ffff0000149abe00
[ 272.169069] pmr_save: 000000f0
[ 272.169241] x29: ffff0000149abe00 x28: 0000000000000000
[ 272.169521] x27: ffff000014983a98 x26: ffff8003ec8b23b8
[ 272.169819] x25: ffff000008d671b8 x24: 0000000000000000
[ 272.170097] x23: ffff000011081f58 x22: 000000003b9ac9ff
[ 272.170369] x21: 0000000000000005 x20: ffff000008d68110
[ 272.170642] x19: ffff000008d69000 x18: ffffffffffffffff
[ 272.170915] x17: 0000000000000000 x16: 0000000000000000
[ 272.171187] x15: ffff0000117dd708 x14: ffff0000949abb27
[ 272.171461] x13: ffff0000149abb35 x12: 0000000000000000
[ 272.171734] x11: ffff000011807000 x10: 0000000005f5e0ff
[ 272.172425] x9 : 00000000ffffffd0 x8 : 000000000002835b
[ 272.172716] x7 : 0000000000000870 x6 : ffff0000119f5bf1
[ 272.172989] x5 : ffff0000117df7a0 x4 : 0000000000000000
[ 272.173283] x3 : 0000000000000000 x2 : 3ebac9b03882d300
[ 272.173561] x1 : 0000000000000004 x0 : 00000000000000f0
[ 272.173853] Call trace:
[ 272.174044] hardlockup_test_loop+0x7c/0xe8 [lockup_test]
[ 272.174322] lockup_test+0x50/0x88 [lockup_test]
[ 272.174584] kthread+0x100/0x130
[ 272.174789] ret_from_fork+0x10/0x18
[ 272.175053] Sending NMI from CPU 5 to CPUs 0-4,6-7:
[ 272.176800] NMI backtrace for cpu 6
[ 272.176850] CPU: 6 PID: 0 Comm: swapper/6 Tainted: G OEL 5.1.0-rc7+ #10
[ 272.176870] Hardware name: linux,dummy-virt (DT)
[ 272.176889] pstate: 60000005 (nZCv daif -PAN -UAO)
[ 272.176912] pc : cpu_do_idle+0x6c/0x78
[ 272.176933] lr : arch_cpu_idle+0x30/0x1b0
[ 272.176950] sp : ffff000011cebee0
[ 272.176969] pmr_save: 00000070
[ 272.176989] x29: ffff000011cebee0 x28: 0000000000000000
[ 272.177119] x27: 0000000000000000 x26: 0000000000000000
[ 272.177192] x25: 0000000000000000 x24: ffff000011483338
[ 272.177244] x23: ffff0000117dd000 x22: ffff0000117df000
[ 272.177288] x21: 0000000000000040 x20: ffff000011476000
[ 272.177336] x19: ffff0000117df7a0 x18: 0000000000000000
[ 272.177385] x17: 0000000000054164 x16: 0000000000000000
[ 272.177425] x15: 0000000000000000 x14: 0000000000000000
[ 272.177469] x13: 0000000000000000 x12: 0000000000000000
[ 272.177521] x11: 0000000000000800 x10: 0000000000000b00
[ 272.177573] x9 : ffff000011cebe70 x8 : ffff8003edecd7a0
[ 272.177634] x7 : 0000000000000010 x6 : 000000040a4f5e90
[ 272.177684] x5 : 00ffffffffffffff x4 : 00008003eeb3b000
[ 272.177732] x3 : ffff000011cebf10 x2 : 00000000000000f0
[ 272.177779] x1 : 0000000000000000 x0 : 0000000000000070
[ 272.177826] Call trace:
[ 272.177847] cpu_do_idle+0x6c/0x78
[ 272.177865] arch_cpu_idle+0x30/0x1b0
[ 272.177885] default_idle_call+0x20/0x3c
[ 272.177901] do_idle+0x1e4/0x2b0
[ 272.177917] cpu_startup_entry+0x2c/0x30
[ 272.177936] secondary_start_kernel+0x1fc/0x230
[ 272.177978] NMI backtrace for cpu 0
[ 272.178012] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G OEL 5.1.0-rc7+ #10
[ 272.178058] Hardware name: linux,dummy-virt (DT)
[ 272.178102] pstate: 60000005 (nZCv daif -PAN -UAO)
[ 272.178285] pc : cpu_do_idle+0x6c/0x78
[ 272.178327] lr : arch_cpu_idle+0x30/0x1b0
[ 272.178392] sp : ffff0000117d3e70
[ 272.178429] pmr_save: 00000070
[ 272.178496] x29: ffff0000117d3e70 x28: 0000000041240018
[ 272.178603] x27: 0000000000000000 x26: 0000000000000000
[ 272.178731] x25: 0000000000000000 x24: ffff000011483338
[ 272.178834] x23: ffff0000117dd000 x22: ffff0000117df000
[ 272.178953] x21: 0000000000000001 x20: ffff000011476000
[ 272.179061] x19: ffff0000117df7a0 x18: 0000000000000014
[ 272.179177] x17: 0000000000053c08 x16: 0000000000000000
[ 272.179270] x15: 0000000028c8de8d x14: 00000000000c8000
[ 272.179377] x13: 0000000000000000 x12: 0000000000000000
[ 272.179472] x11: 0000000000000000 x10: 0000000000000b00
[ 272.179577] x9 : ffff0000117d3e00 x8 : ffff0000117ea820
[ 272.179650] x7 : 0000000000000010 x6 : 0000000417cf7c30
[ 272.179697] x5 : 00ffffffffffffff x4 : 00008003eeaa5000
[ 272.179825] x3 : ffff0000117d3ea0 x2 : 00000000000000f0
[ 272.179888] x1 : 0000000000000000 x0 : 0000000000000070
[ 272.179990] Call trace:
[ 272.180054] cpu_do_idle+0x6c/0x78
[ 272.180078] arch_cpu_idle+0x30/0x1b0
[ 272.180123] default_idle_call+0x20/0x3c
[ 272.180164] do_idle+0x1e4/0x2b0
[ 272.180213] cpu_startup_entry+0x28/0x30
[ 272.180255] rest_init+0xbc/0xc8
[ 272.180305] arch_call_rest_init+0x14/0x1c
[ 272.180340] start_kernel+0x508/0x534
[ 272.180419] NMI backtrace for cpu 2
[ 272.180486] CPU: 2 PID: 0 Comm: swapper/2 Tainted: G OEL 5.1.0-rc7+ #10
[ 272.180587] Hardware name: linux,dummy-virt (DT)
[ 272.180635] pstate: 60000005 (nZCv daif -PAN -UAO)
[ 272.180666] pc : cpu_do_idle+0x6c/0x78
[ 272.180723] lr : arch_cpu_idle+0x30/0x1b0
[ 272.180756] sp : ffff000011ccbee0
[ 272.180824] pmr_save: 00000070
[ 272.180848] x29: ffff000011ccbee0 x28: 0000000000000000
[ 272.180956] x27: 0000000000000000 x26: 0000000000000000
[ 272.181116] x25: 0000000000000000 x24: ffff000011483338
[ 272.181221] x23: ffff0000117dd000 x22: ffff0000117df000
[ 272.181358] x21: 0000000000000004 x20: ffff000011476000
[ 272.181623] x19: ffff0000117df7a0 x18: 0000000000000035
[ 272.181697] x17: 00000000000533e8 x16: 0000000000000000
[ 272.181997] x15: 0000000000000019 x14: ffff000011801128
[ 272.182402] x13: 0000000000000000 x12: 0000000000000000
[ 272.183012] x11: 0000000000000800 x10: 0000000000000b00
[ 272.183932] x9 : ffff000011ccbe70 x8 : ffff8003ede829e0
[ 272.184055] x7 : 0000000000000010 x6 : 000000040a30da10
[ 272.184218] x5 : 00ffffffffffffff x4 : 00008003eead7000
[ 272.184329] x3 : ffff000011ccbf10 x2 : 00000000000000f0
[ 272.184671] x1 : 0000000000000000 x0 : 0000000000000070
[ 272.185191] Call trace:
[ 272.185226] cpu_do_idle+0x6c/0x78
[ 272.185432] arch_cpu_idle+0x30/0x1b0
[ 272.185670] default_idle_call+0x20/0x3c
[ 272.185752] do_idle+0x1e4/0x2b0
[ 272.185781] cpu_startup_entry+0x2c/0x30
[ 272.185832] secondary_start_kernel+0x1fc/0x230
[ 272.185889] NMI backtrace for cpu 4
[ 272.185958] CPU: 4 PID: 0 Comm: swapper/4 Tainted: G OEL 5.1.0-rc7+ #10
[ 272.186004] Hardware name: linux,dummy-virt (DT)
[ 272.186080] pstate: 60000005 (nZCv daif -PAN -UAO)
[ 272.186169] pc : cpu_do_idle+0x6c/0x78
[ 272.186232] lr : arch_cpu_idle+0x30/0x1b0
[ 272.186461] sp : ffff000011cdbee0
[ 272.186489] pmr_save: 00000070
[ 272.186521] x29: ffff000011cdbee0 x28: 0000000000000000
[ 272.186606] x27: 0000000000000000 x26: 0000000000000000
[ 272.186675] x25: 0000000000000000 x24: ffff000011483338
[ 272.186804] x23: ffff0000117dd000 x22: ffff0000117df000
[ 272.186898] x21: 0000000000000010 x20: ffff000011476000
[ 272.186968] x19: ffff0000117df7a0 x18: 0000000000000000
[ 272.187070] x17: 0000000000054204 x16: 0000000000000000
[ 272.187171] x15: 0000000000000000 x14: 0000000000000000
[ 272.187265] x13: 0000000000000000 x12: 0000000000000000
[ 272.187338] x11: 0000000000000800 x10: 0000000000000b00
[ 272.187432] x9 : ffff000011cdbe70 x8 : ffff8003ede87620
[ 272.187542] x7 : 0000000000000010 x6 : 0000000412985750
[ 272.187629] x5 : 00ffffffffffffff x4 : 00008003eeb09000
[ 272.187729] x3 : ffff000011cdbf10 x2 : 00000000000000f0
[ 272.187824] x1 : 0000000000000000 x0 : 0000000000000070
[ 272.187904] Call trace:
[ 272.187938] cpu_do_idle+0x6c/0x78
[ 272.187952] arch_cpu_idle+0x30/0x1b0
[ 272.188020] default_idle_call+0x20/0x3c
[ 272.188046] do_idle+0x1e4/0x2b0
[ 272.188139] cpu_startup_entry+0x2c/0x30
[ 272.188225] secondary_start_kernel+0x1fc/0x230
[ 272.188381] NMI backtrace for cpu 1
[ 272.188459] CPU: 1 PID: 253 Comm: lockup_test1 Tainted: G OEL 5.1.0-rc7+ #10
[ 272.188538] Hardware name: linux,dummy-virt (DT)
[ 272.188573] pstate: 80000005 (Nzcv daif -PAN -UAO)
[ 272.188627] pc : hardlockup_test_loop+0xa0/0xe8 [lockup_test]
[ 272.188709] lr : hardlockup_test_loop+0x6c/0xe8 [lockup_test]
[ 272.188746] sp : ffff000014973e00
[ 272.188823] pmr_save: 00000070
[ 272.188842] x29: ffff000014973e00 x28: 0000000000000000
[ 272.189010] x27: ffff000014983a98 x26: ffff8003ed835038
[ 272.189079] x25: ffff000008d671b8 x24: 0000000000000000
[ 272.189226] x23: ffff000011081f58 x22: 000000003b9ac9ff
[ 272.189321] x21: 0000000000000001 x20: ffff000008d68110
[ 272.189410] x19: ffff000008d69000 x18: ffffffffffffffff
[ 272.189549] x17: 0000000000000000 x16: 0000000000000000
[ 272.189640] x15: ffff0000117dd708 x14: ffff000094973b27
[ 272.189673] x13: ffff000014973b35 x12: 0000000000000000
[ 272.189726] x11: ffff000011807000 x10: 0000000005f5e0ff
[ 272.189829] x9 : 00000000ffffffd0 x8 : 0000000000063aab
[ 272.189916] x7 : 000000000000086c x6 : ffff0000119f5bf1
[ 272.190011] x5 : ffff0000117df7a0 x4 : 0000000000000000
[ 272.190117] x3 : 0000000000000000 x2 : 3ebac9b03882d300
[ 272.190234] x1 : 0000000004208040 x0 : 00000000397e3f58
[ 272.190388] Call trace:
[ 272.190439] hardlockup_test_loop+0xa0/0xe8 [lockup_test]
[ 272.190477] lockup_test+0x50/0x88 [lockup_test]
[ 272.190510] kthread+0x100/0x130
[ 272.190577] ret_from_fork+0x10/0x18
[ 272.190730] NMI backtrace for cpu 3
[ 272.190767] CPU: 3 PID: 254 Comm: lockup_test3 Tainted: G OEL 5.1.0-rc7+ #10
[ 272.190800] Hardware name: linux,dummy-virt (DT)
[ 272.190825] pstate: 80000005 (Nzcv daif -PAN -UAO)
[ 272.190860] pc : hardlockup_test_loop+0xa0/0xe8 [lockup_test]
[ 272.190898] lr : hardlockup_test_loop+0x6c/0xe8 [lockup_test]
[ 272.190932] sp : ffff00001499be00
[ 272.190993] pmr_save: 00000070
[ 272.191054] x29: ffff00001499be00 x28: 0000000000000000
[ 272.191171] x27: ffff000014983a98 x26: ffff8003eca41eb8
[ 272.191249] x25: ffff000008d671b8 x24: 0000000000000000
[ 272.191391] x23: ffff000011081f58 x22: 000000003b9ac9ff
[ 272.191501] x21: 0000000000000003 x20: ffff000008d68110
[ 272.191593] x19: ffff000008d69000 x18: ffffffffffffffff
[ 272.191718] x17: 0000000000000000 x16: 0000000000000000
[ 272.191895] x15: ffff0000117dd708 x14: ffff00009499bb27
[ 272.192062] x13: ffff00001499bb35 x12: 0000000000000000
[ 272.192282] x11: ffff000011807000 x10: 0000000005f5e0ff
[ 272.192451] x9 : 00000000ffffffd0 x8 : 00000000000dceb8
[ 272.192555] x7 : 000000000000086e x6 : ffff0000119f5bf1
[ 272.192715] x5 : ffff0000117df7a0 x4 : 0000000000000000
[ 272.192887] x3 : 0000000000000000 x2 : 3ebac9b03882d300
[ 272.192962] x1 : 0000000004208040 x0 : 0000000039e93260
[ 272.193041] Call trace:
[ 272.193077] hardlockup_test_loop+0xa0/0xe8 [lockup_test]
[ 272.193117] lockup_test+0x50/0x88 [lockup_test]
[ 272.193152] kthread+0x100/0x130
[ 272.193225] ret_from_fork+0x10/0x18
[ 272.193421] NMI backtrace for cpu 7
[ 272.193475] CPU: 7 PID: 256 Comm: lockup_test7 Tainted: G OEL 5.1.0-rc7+ #10
[ 272.193495] Hardware name: linux,dummy-virt (DT)
[ 272.193562] pstate: 80000005 (Nzcv daif -PAN -UAO)
[ 272.193619] pc : hardlockup_test_loop+0xa0/0xe8 [lockup_test]
[ 272.193634] lr : hardlockup_test_loop+0x6c/0xe8 [lockup_test]
[ 272.193647] sp : ffff0000149bbe00
[ 272.193661] pmr_save: 00000070
[ 272.193710] x29: ffff0000149bbe00 x28: 0000000000000000
[ 272.193848] x27: ffff000014983a98 x26: ffff8003ecb5fbb8
[ 272.193921] x25: ffff000008d671b8 x24: 0000000000000000
[ 272.194056] x23: ffff000011081f58 x22: 000000003b9ac9ff
[ 272.194162] x21: 0000000000000007 x20: ffff000008d68110
[ 272.194263] x19: ffff000008d69000 x18: ffffffffffffffff
[ 272.194343] x17: 0000000000000000 x16: 0000000000000000
[ 272.194463] x15: ffff0000117dd708 x14: ffff0000949bbb27
[ 272.194566] x13: ffff0000149bbb35 x12: ffff00001148898f
[ 272.194667] x11: ffff000011807000 x10: 0000000005f5e0ff
[ 272.194809] x9 : 00000000ffffffd0 x8 : 0000000000066bb1
[ 272.194962] x7 : 000000000000086d x6 : ffff0000119f5bf1
[ 272.195121] x5 : ffff0000117df7a0 x4 : 0000000000000000
[ 272.195249] x3 : 0000000000000000 x2 : 3ebac9b03882d300
[ 272.195344] x1 : 0000000004208040 x0 : 000000003b728080
[ 272.195428] Call trace:
[ 272.195463] hardlockup_test_loop+0xa0/0xe8 [lockup_test]
[ 272.195540] lockup_test+0x50/0x88 [lockup_test]
[ 272.195600] kthread+0x100/0x130
[ 272.195638] ret_from_fork+0x10/0x18

Wei Li (3):
arm64: Add pseudo NMI support of GICv3 SGIs
arm64: Add support for on-demand backtrace of other CPUs
arm64: Avoid entering NMI context improperly

arch/arm64/include/asm/arch_gicv3.h | 8 ++++
arch/arm64/include/asm/hardirq.h | 2 +-
arch/arm64/include/asm/irq.h | 6 +++
arch/arm64/include/asm/smp.h | 2 +
arch/arm64/kernel/smp.c | 36 ++++++++++++++++-
drivers/irqchip/irq-gic-v3.c | 54 ++++++++++++++++++--------
include/linux/irqchip/arm-gic-common.h | 1 +
include/linux/irqchip/arm-gic-v3.h | 1 +
8 files changed, 92 insertions(+), 18 deletions(-)

--
2.17.1


2019-05-06 08:24:12

by liwei (GF)

[permalink] [raw]
Subject: [PATCH 2/3] arm64: Add support for on-demand backtrace of other CPUs

To support backtracing of other CPUs in the system on lockups, add the
implementation of arch_trigger_cpumask_backtrace() for arm64.

In this patch, we add an arm64 NMI-like IPI based backtracer, referring
to the implementation on arm by Russell King and Chris Metcalf.

Signed-off-by: Wei Li <[email protected]>
---
arch/arm64/include/asm/hardirq.h | 2 +-
arch/arm64/include/asm/irq.h | 6 ++++++
arch/arm64/kernel/smp.c | 22 +++++++++++++++++++++-
3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index 89691c86640a..a5d94aa59c7c 100644
--- a/arch/arm64/include/asm/hardirq.h
+++ b/arch/arm64/include/asm/hardirq.h
@@ -24,7 +24,7 @@
#include <asm/kvm_arm.h>
#include <asm/sysreg.h>

-#define NR_IPI 7
+#define NR_IPI 8

typedef struct {
unsigned int __softirq_pending;
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index b2b0c6405eb0..28471df488c0 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -13,5 +13,11 @@ static inline int nr_legacy_irqs(void)
return 0;
}

+#ifdef CONFIG_SMP
+extern void arch_trigger_cpumask_backtrace(const cpumask_t *mask,
+ bool exclude_self);
+#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace
+#endif
+
#endif /* !__ASSEMBLER__ */
#endif
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index bd8fdf6fcd8e..7e862f9124f3 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -35,6 +35,7 @@
#include <linux/smp.h>
#include <linux/seq_file.h>
#include <linux/irq.h>
+#include <linux/nmi.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/percpu.h>
#include <linux/clockchips.h>
@@ -83,7 +84,8 @@ enum ipi_msg_type {
IPI_CPU_CRASH_STOP,
IPI_TIMER,
IPI_IRQ_WORK,
- IPI_WAKEUP
+ IPI_WAKEUP,
+ IPI_CPU_BACKTRACE
};

#ifdef CONFIG_HOTPLUG_CPU
@@ -787,6 +789,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
S(IPI_TIMER, "Timer broadcast interrupts"),
S(IPI_IRQ_WORK, "IRQ work interrupts"),
S(IPI_WAKEUP, "CPU wake-up interrupts"),
+ S(IPI_CPU_BACKTRACE, "Backtrace interrupts"),
};

static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -946,6 +949,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
break;
#endif

+ case IPI_CPU_BACKTRACE:
+ nmi_enter();
+ nmi_cpu_backtrace(regs);
+ nmi_exit();
+ break;
+
default:
pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
break;
@@ -1070,4 +1079,15 @@ bool cpus_are_stuck_in_kernel(void)

void ipi_gic_nmi_setup(void __iomem *base)
{
+ gic_sgi_set_prio(base, IPI_CPU_BACKTRACE, GICD_INT_NMI_PRI);
+}
+
+static void raise_nmi(cpumask_t *mask)
+{
+ smp_cross_call(mask, IPI_CPU_BACKTRACE);
+}
+
+void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self)
+{
+ nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_nmi);
}
--
2.17.1

2019-05-06 08:24:21

by liwei (GF)

[permalink] [raw]
Subject: [PATCH 1/3] arm64: Add pseudo NMI support of GICv3 SGIs

Currently, only PPIs and SPIs can be set as NMIs. IPIs being currently
hardcoded IRQ numbers, there isn't a generic interface to set SGIs as NMI
for now.

In this patch, we do:
1. Add an interface for setting priority of SGIs.
2. Export GICD_INT_NMI_PRI for setting priority of SGIs as NMI.
3. Move the gic_enable_nmi_support() earlier to make the gic_supports_nmi()
check works in gic_cpu_init().

Signed-off-by: Wei Li <[email protected]>
Cc: Julien Thierry <[email protected]>
---
arch/arm64/include/asm/smp.h | 2 ++
arch/arm64/kernel/smp.c | 4 +++
drivers/irqchip/irq-gic-v3.c | 46 +++++++++++++++++++++-----
include/linux/irqchip/arm-gic-common.h | 1 +
include/linux/irqchip/arm-gic-v3.h | 1 +
5 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 18553f399e08..84d7ea073d84 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -158,6 +158,8 @@ bool cpus_are_stuck_in_kernel(void);
extern void crash_smp_send_stop(void);
extern bool smp_crash_stop_failed(void);

+extern void ipi_gic_nmi_setup(void __iomem *base);
+
#endif /* ifndef __ASSEMBLY__ */

#endif /* ifndef __ASM_SMP_H */
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 824de7038967..bd8fdf6fcd8e 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -1067,3 +1067,7 @@ bool cpus_are_stuck_in_kernel(void)

return !!cpus_stuck_in_kernel || smp_spin_tables;
}
+
+void ipi_gic_nmi_setup(void __iomem *base)
+{
+}
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 15e55d327505..394aa5668dd6 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -42,8 +42,6 @@

#include "irq-gic-common.h"

-#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)
-
#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0)

struct redist_region {
@@ -324,6 +322,23 @@ static int gic_irq_get_irqchip_state(struct irq_data *d,
return 0;
}

+void gic_sgi_set_prio(void __iomem *base, u32 irqnr, u8 prio)
+{
+ u32 val, offset;
+
+ offset = GICR_IPRIORITYR0 + ((irqnr / 4) * 4);
+
+ /*
+ * Using writeb here may cause hardware error on some CPUs,
+ * aovid this quirk by using writel.
+ */
+ val = readl_relaxed(base + offset);
+ val &= ~(0xff << ((irqnr % 4) * 8));
+ val |= prio << ((irqnr % 4) * 8);
+
+ writel_relaxed(val, base + offset);
+}
+
static void gic_irq_set_prio(struct irq_data *d, u8 prio)
{
void __iomem *base = gic_dist_base(d);
@@ -474,6 +489,16 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
{
int err;

+ if (unlikely(irqnr < 16)) {
+ gic_write_eoir(irqnr);
+ if (static_branch_likely(&supports_deactivate_key))
+ gic_write_dir(irqnr);
+#ifdef CONFIG_SMP
+ handle_IPI(irqnr, regs);
+#endif
+ return;
+ }
+
if (static_branch_likely(&supports_deactivate_key))
gic_write_eoir(irqnr);
/*
@@ -859,6 +884,9 @@ static void gic_cpu_init(void)

gic_cpu_config(rbase, gic_redist_wait_for_rwp);

+ if (gic_supports_nmi())
+ ipi_gic_nmi_setup(rbase);
+
/* initialise system registers */
gic_cpu_sys_reg_init();
}
@@ -1335,6 +1363,13 @@ static int __init gic_init_bases(void __iomem *dist_base,

gic_update_vlpi_properties();

+ if (gic_prio_masking_enabled()) {
+ if (!gic_has_group0() || gic_dist_security_disabled())
+ gic_enable_nmi_support();
+ else
+ pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
+ }
+
gic_smp_init();
gic_dist_init();
gic_cpu_init();
@@ -1345,13 +1380,6 @@ static int __init gic_init_bases(void __iomem *dist_base,
its_cpu_init();
}

- if (gic_prio_masking_enabled()) {
- if (!gic_has_group0() || gic_dist_security_disabled())
- gic_enable_nmi_support();
- else
- pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
- }
-
return 0;

out_free:
diff --git a/include/linux/irqchip/arm-gic-common.h b/include/linux/irqchip/arm-gic-common.h
index 9a1a479a2bf4..d8c973295179 100644
--- a/include/linux/irqchip/arm-gic-common.h
+++ b/include/linux/irqchip/arm-gic-common.h
@@ -18,6 +18,7 @@
(GICD_INT_DEF_PRI << 16) |\
(GICD_INT_DEF_PRI << 8) |\
GICD_INT_DEF_PRI)
+#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)

enum gic_type {
GIC_V2,
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index c848a7cc502e..dc1c418229e7 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -606,6 +606,7 @@ int its_cpu_init(void);
int its_init(struct fwnode_handle *handle, struct rdists *rdists,
struct irq_domain *domain);
int mbi_init(struct fwnode_handle *fwnode, struct irq_domain *parent);
+void gic_sgi_set_prio(void __iomem *base, u32 irqnr, u8 prio);

static inline bool gic_enable_sre(void)
{
--
2.17.1

2019-05-13 09:56:47

by Julien Thierry

[permalink] [raw]
Subject: Re: [PATCH 1/3] arm64: Add pseudo NMI support of GICv3 SGIs

Hi Wei,

On 06/05/2019 09:25, Wei Li wrote:
> Currently, only PPIs and SPIs can be set as NMIs. IPIs being currently
> hardcoded IRQ numbers, there isn't a generic interface to set SGIs as NMI
> for now.
>
> In this patch, we do:
> 1. Add an interface for setting priority of SGIs.
> 2. Export GICD_INT_NMI_PRI for setting priority of SGIs as NMI.
> 3. Move the gic_enable_nmi_support() earlier to make the gic_supports_nmi()
> check works in gic_cpu_init().
>
> Signed-off-by: Wei Li <[email protected]>
> Cc: Julien Thierry <[email protected]>
> ---
> arch/arm64/include/asm/smp.h | 2 ++
> arch/arm64/kernel/smp.c | 4 +++
> drivers/irqchip/irq-gic-v3.c | 46 +++++++++++++++++++++-----
> include/linux/irqchip/arm-gic-common.h | 1 +
> include/linux/irqchip/arm-gic-v3.h | 1 +
> 5 files changed, 45 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
> index 18553f399e08..84d7ea073d84 100644
> --- a/arch/arm64/include/asm/smp.h
> +++ b/arch/arm64/include/asm/smp.h
> @@ -158,6 +158,8 @@ bool cpus_are_stuck_in_kernel(void);
> extern void crash_smp_send_stop(void);
> extern bool smp_crash_stop_failed(void);
>
> +extern void ipi_gic_nmi_setup(void __iomem *base);
> +
> #endif /* ifndef __ASSEMBLY__ */
>
> #endif /* ifndef __ASM_SMP_H */
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index 824de7038967..bd8fdf6fcd8e 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -1067,3 +1067,7 @@ bool cpus_are_stuck_in_kernel(void)
>
> return !!cpus_stuck_in_kernel || smp_spin_tables;
> }
> +
> +void ipi_gic_nmi_setup(void __iomem *base)
> +{
> +}
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index 15e55d327505..394aa5668dd6 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -42,8 +42,6 @@
>
> #include "irq-gic-common.h"
>
> -#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)
> -
> #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0)
>
> struct redist_region {
> @@ -324,6 +322,23 @@ static int gic_irq_get_irqchip_state(struct irq_data *d,
> return 0;
> }
>
> +void gic_sgi_set_prio(void __iomem *base, u32 irqnr, u8 prio)
> +{
> + u32 val, offset;
> +
> + offset = GICR_IPRIORITYR0 + ((irqnr / 4) * 4);
> +
> + /*
> + * Using writeb here may cause hardware error on some CPUs,
> + * aovid this quirk by using writel.
> + */
> + val = readl_relaxed(base + offset);
> + val &= ~(0xff << ((irqnr % 4) * 8));
> + val |= prio << ((irqnr % 4) * 8);
> +
> + writel_relaxed(val, base + offset);
> +}
> +
> static void gic_irq_set_prio(struct irq_data *d, u8 prio)
> {
> void __iomem *base = gic_dist_base(d);
> @@ -474,6 +489,16 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
> {
> int err;
>
> + if (unlikely(irqnr < 16)) {
> + gic_write_eoir(irqnr);
> + if (static_branch_likely(&supports_deactivate_key))
> + gic_write_dir(irqnr);
> +#ifdef CONFIG_SMP
> + handle_IPI(irqnr, regs);
> +#endif
> + return;
> + }
> +
> if (static_branch_likely(&supports_deactivate_key))
> gic_write_eoir(irqnr);
> /*
> @@ -859,6 +884,9 @@ static void gic_cpu_init(void)
>
> gic_cpu_config(rbase, gic_redist_wait_for_rwp);
>
> + if (gic_supports_nmi())
> + ipi_gic_nmi_setup(rbase);
> +
> /* initialise system registers */
> gic_cpu_sys_reg_init();
> }
> @@ -1335,6 +1363,13 @@ static int __init gic_init_bases(void __iomem *dist_base,
>
> gic_update_vlpi_properties();
>
> + if (gic_prio_masking_enabled()) {
> + if (!gic_has_group0() || gic_dist_security_disabled())
> + gic_enable_nmi_support();
> + else
> + pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
> + }
> +
> gic_smp_init();
> gic_dist_init();
> gic_cpu_init();
> @@ -1345,13 +1380,6 @@ static int __init gic_init_bases(void __iomem *dist_base,
> its_cpu_init();
> }
>
> - if (gic_prio_masking_enabled()) {
> - if (!gic_has_group0() || gic_dist_security_disabled())
> - gic_enable_nmi_support();
> - else
> - pr_warn("SCR_EL3.FIQ is cleared, cannot enable use of pseudo-NMIs\n");
> - }
> -
> return 0;
>
> out_free:
> diff --git a/include/linux/irqchip/arm-gic-common.h b/include/linux/irqchip/arm-gic-common.h
> index 9a1a479a2bf4..d8c973295179 100644
> --- a/include/linux/irqchip/arm-gic-common.h
> +++ b/include/linux/irqchip/arm-gic-common.h
> @@ -18,6 +18,7 @@
> (GICD_INT_DEF_PRI << 16) |\
> (GICD_INT_DEF_PRI << 8) |\
> GICD_INT_DEF_PRI)
> +#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)
>
> enum gic_type {
> GIC_V2,
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index c848a7cc502e..dc1c418229e7 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -606,6 +606,7 @@ int its_cpu_init(void);
> int its_init(struct fwnode_handle *handle, struct rdists *rdists,
> struct irq_domain *domain);
> int mbi_init(struct fwnode_handle *fwnode, struct irq_domain *parent);
> +void gic_sgi_set_prio(void __iomem *base, u32 irqnr, u8 prio);

This is a bit too generic to expose (even if it is not visible to modules):

- Callers of this function should have at least a way to check whether
the interrupt is enabled and, if it is, a way to disable it before
modifying its priority

- Even if the name contains "sgi", nothing is preventing from using this
to modify priority of PPIs and SPIs if irqnr >= 16.

- The caller can give any priority it wants when there are only two
priorities the GICv3 driver correctly handles correctly. Whatever gets
exposed outside of the driver should only allow to switch between those
two priorities.


A cleaner way to do what your series tries to achieve might be to have
arm64 IPI use the kernel IRQ allocation API so it can reuse what was
done for NMIs.

Thanks,

--
Julien Thierry