Skip to content

Commit 9b932aa

Browse files
guoren83palmer-dabbelt
authored andcommitted
riscv: kexec: Fixup crash_smp_send_stop without multi cores
Current crash_smp_send_stop is the same as the generic one in kernel/panic and misses crash_save_cpu in percpu. This patch is inspired by 78fd584 ("arm64: kdump: implement machine_crash_shutdown()") and adds the same mechanism for riscv. Before this patch, test result: crash> help -r CPU 0: [OFFLINE] CPU 1: epc : ffffffff80009ff0 ra : ffffffff800b789a sp : ff2000001098bb40 gp : ffffffff815fca60 tp : ff60000004680000 t0 : 6666666666663c5b t1 : 0000000000000000 t2 : 666666666666663c s0 : ff2000001098bc90 s1 : ffffffff81600798 a0 : ff2000001098bb48 a1 : 0000000000000000 a2 : 0000000000000000 a3 : 0000000000000001 a4 : 0000000000000000 a5 : ff60000004690800 a6 : 0000000000000000 a7 : 0000000000000000 s2 : ff2000001098bb48 s3 : ffffffff81093ec8 s4 : ffffffff816004ac s5 : 0000000000000000 s6 : 0000000000000007 s7 : ffffffff80e7f720 s8 : 00fffffffffff3f0 s9 : 0000000000000007 s10: 00aaaaaaaab98700 s11: 0000000000000001 t3 : ffffffff819a8097 t4 : ffffffff819a8097 t5 : ffffffff819a8098 t6 : ff2000001098b9a8 CPU 2: [OFFLINE] CPU 3: [OFFLINE] After this patch, test result: crash> help -r CPU 0: epc : ffffffff80003f34 ra : ffffffff808caa7c sp : ffffffff81403eb0 gp : ffffffff815fcb48 tp : ffffffff81413400 t0 : 0000000000000000 t1 : 0000000000000000 t2 : 0000000000000000 s0 : ffffffff81403ec0 s1 : 0000000000000000 a0 : 0000000000000000 a1 : 0000000000000000 a2 : 0000000000000000 a3 : 0000000000000000 a4 : 0000000000000000 a5 : 0000000000000000 a6 : 0000000000000000 a7 : 0000000000000000 s2 : ffffffff816001c8 s3 : ffffffff81600370 s4 : ffffffff80c32e18 s5 : ffffffff819d3018 s6 : ffffffff810e2110 s7 : 0000000000000000 s8 : 0000000000000000 s9 : 0000000080039eac s10: 0000000000000000 s11: 0000000000000000 t3 : 0000000000000000 t4 : 0000000000000000 t5 : 0000000000000000 t6 : 0000000000000000 CPU 1: epc : ffffffff80003f34 ra : ffffffff808caa7c sp : ff2000000068bf30 gp : ffffffff815fcb48 tp : ff6000000240d400 t0 : 0000000000000000 t1 : 0000000000000000 t2 : 0000000000000000 s0 : ff2000000068bf40 s1 : 0000000000000001 a0 : 0000000000000000 a1 : 0000000000000000 a2 : 0000000000000000 a3 : 0000000000000000 a4 : 0000000000000000 a5 : 0000000000000000 a6 : 0000000000000000 a7 : 0000000000000000 s2 : ffffffff816001c8 s3 : ffffffff81600370 s4 : ffffffff80c32e18 s5 : ffffffff819d3018 s6 : ffffffff810e2110 s7 : 0000000000000000 s8 : 0000000000000000 s9 : 0000000080039ea8 s10: 0000000000000000 s11: 0000000000000000 t3 : 0000000000000000 t4 : 0000000000000000 t5 : 0000000000000000 t6 : 0000000000000000 CPU 2: epc : ffffffff80003f34 ra : ffffffff808caa7c sp : ff20000000693f30 gp : ffffffff815fcb48 tp : ff6000000240e900 t0 : 0000000000000000 t1 : 0000000000000000 t2 : 0000000000000000 s0 : ff20000000693f40 s1 : 0000000000000002 a0 : 0000000000000000 a1 : 0000000000000000 a2 : 0000000000000000 a3 : 0000000000000000 a4 : 0000000000000000 a5 : 0000000000000000 a6 : 0000000000000000 a7 : 0000000000000000 s2 : ffffffff816001c8 s3 : ffffffff81600370 s4 : ffffffff80c32e18 s5 : ffffffff819d3018 s6 : ffffffff810e2110 s7 : 0000000000000000 s8 : 0000000000000000 s9 : 0000000080039eb0 s10: 0000000000000000 s11: 0000000000000000 t3 : 0000000000000000 t4 : 0000000000000000 t5 : 0000000000000000 t6 : 0000000000000000 CPU 3: epc : ffffffff8000a1e4 ra : ffffffff800b7bba sp : ff200000109bbb40 gp : ffffffff815fcb48 tp : ff6000000373aa00 t0 : 6666666666663c5b t1 : 0000000000000000 t2 : 666666666666663c s0 : ff200000109bbc90 s1 : ffffffff816007a0 a0 : ff200000109bbb48 a1 : 0000000000000000 a2 : 0000000000000000 a3 : 0000000000000001 a4 : 0000000000000000 a5 : ff60000002c61c00 a6 : 0000000000000000 a7 : 0000000000000000 s2 : ff200000109bbb48 s3 : ffffffff810941a8 s4 : ffffffff816004b4 s5 : 0000000000000000 s6 : 0000000000000007 s7 : ffffffff80e7f7a0 s8 : 00fffffffffff3f0 s9 : 0000000000000007 s10: 00aaaaaaaab98700 s11: 0000000000000001 t3 : ffffffff819a8097 t4 : ffffffff819a8097 t5 : ffffffff819a8098 t6 : ff200000109bb9a8 Fixes: ad94389 ("RISC-V: Fixup schedule out issue in machine_crash_shutdown()") Reviewed-by: Xianting Tian <[email protected]> Signed-off-by: Guo Ren <[email protected]> Signed-off-by: Guo Ren <[email protected]> Cc: Nick Kossifidis <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent b17d19a commit 9b932aa

File tree

3 files changed

+103
-18
lines changed

3 files changed

+103
-18
lines changed

arch/riscv/include/asm/smp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops);
5050
/* Clear IPI for current CPU */
5151
void riscv_clear_ipi(void);
5252

53+
/* Check other CPUs stop or not */
54+
bool smp_crash_stop_failed(void);
55+
5356
/* Secondary hart entry */
5457
asmlinkage void smp_callin(void);
5558

arch/riscv/kernel/machine_kexec.c

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -140,22 +140,6 @@ void machine_shutdown(void)
140140
#endif
141141
}
142142

143-
/* Override the weak function in kernel/panic.c */
144-
void crash_smp_send_stop(void)
145-
{
146-
static int cpus_stopped;
147-
148-
/*
149-
* This function can be called twice in panic path, but obviously
150-
* we execute this only once.
151-
*/
152-
if (cpus_stopped)
153-
return;
154-
155-
smp_send_stop();
156-
cpus_stopped = 1;
157-
}
158-
159143
static void machine_kexec_mask_interrupts(void)
160144
{
161145
unsigned int i;
@@ -230,6 +214,11 @@ machine_kexec(struct kimage *image)
230214
void *control_code_buffer = page_address(image->control_code_page);
231215
riscv_kexec_method kexec_method = NULL;
232216

217+
#ifdef CONFIG_SMP
218+
WARN(smp_crash_stop_failed(),
219+
"Some CPUs may be stale, kdump will be unreliable.\n");
220+
#endif
221+
233222
if (image->type != KEXEC_TYPE_CRASH)
234223
kexec_method = control_code_buffer;
235224
else

arch/riscv/kernel/smp.c

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/clockchips.h>
1313
#include <linux/interrupt.h>
1414
#include <linux/module.h>
15+
#include <linux/kexec.h>
1516
#include <linux/profile.h>
1617
#include <linux/smp.h>
1718
#include <linux/sched.h>
@@ -22,11 +23,13 @@
2223
#include <asm/sbi.h>
2324
#include <asm/tlbflush.h>
2425
#include <asm/cacheflush.h>
26+
#include <asm/cpu_ops.h>
2527

2628
enum ipi_message_type {
2729
IPI_RESCHEDULE,
2830
IPI_CALL_FUNC,
2931
IPI_CPU_STOP,
32+
IPI_CPU_CRASH_STOP,
3033
IPI_IRQ_WORK,
3134
IPI_TIMER,
3235
IPI_MAX
@@ -71,6 +74,32 @@ static void ipi_stop(void)
7174
wait_for_interrupt();
7275
}
7376

77+
#ifdef CONFIG_KEXEC_CORE
78+
static atomic_t waiting_for_crash_ipi = ATOMIC_INIT(0);
79+
80+
static inline void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
81+
{
82+
crash_save_cpu(regs, cpu);
83+
84+
atomic_dec(&waiting_for_crash_ipi);
85+
86+
local_irq_disable();
87+
88+
#ifdef CONFIG_HOTPLUG_CPU
89+
if (cpu_has_hotplug(cpu))
90+
cpu_ops[cpu]->cpu_stop();
91+
#endif
92+
93+
for(;;)
94+
wait_for_interrupt();
95+
}
96+
#else
97+
static inline void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
98+
{
99+
unreachable();
100+
}
101+
#endif
102+
74103
static const struct riscv_ipi_ops *ipi_ops __ro_after_init;
75104

76105
void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops)
@@ -124,8 +153,9 @@ void arch_irq_work_raise(void)
124153

125154
void handle_IPI(struct pt_regs *regs)
126155
{
127-
unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
128-
unsigned long *stats = ipi_data[smp_processor_id()].stats;
156+
unsigned int cpu = smp_processor_id();
157+
unsigned long *pending_ipis = &ipi_data[cpu].bits;
158+
unsigned long *stats = ipi_data[cpu].stats;
129159

130160
riscv_clear_ipi();
131161

@@ -154,6 +184,10 @@ void handle_IPI(struct pt_regs *regs)
154184
ipi_stop();
155185
}
156186

187+
if (ops & (1 << IPI_CPU_CRASH_STOP)) {
188+
ipi_cpu_crash_stop(cpu, get_irq_regs());
189+
}
190+
157191
if (ops & (1 << IPI_IRQ_WORK)) {
158192
stats[IPI_IRQ_WORK]++;
159193
irq_work_run();
@@ -176,6 +210,7 @@ static const char * const ipi_names[] = {
176210
[IPI_RESCHEDULE] = "Rescheduling interrupts",
177211
[IPI_CALL_FUNC] = "Function call interrupts",
178212
[IPI_CPU_STOP] = "CPU stop interrupts",
213+
[IPI_CPU_CRASH_STOP] = "CPU stop (for crash dump) interrupts",
179214
[IPI_IRQ_WORK] = "IRQ work interrupts",
180215
[IPI_TIMER] = "Timer broadcast interrupts",
181216
};
@@ -235,6 +270,64 @@ void smp_send_stop(void)
235270
cpumask_pr_args(cpu_online_mask));
236271
}
237272

273+
#ifdef CONFIG_KEXEC_CORE
274+
/*
275+
* The number of CPUs online, not counting this CPU (which may not be
276+
* fully online and so not counted in num_online_cpus()).
277+
*/
278+
static inline unsigned int num_other_online_cpus(void)
279+
{
280+
unsigned int this_cpu_online = cpu_online(smp_processor_id());
281+
282+
return num_online_cpus() - this_cpu_online;
283+
}
284+
285+
void crash_smp_send_stop(void)
286+
{
287+
static int cpus_stopped;
288+
cpumask_t mask;
289+
unsigned long timeout;
290+
291+
/*
292+
* This function can be called twice in panic path, but obviously
293+
* we execute this only once.
294+
*/
295+
if (cpus_stopped)
296+
return;
297+
298+
cpus_stopped = 1;
299+
300+
/*
301+
* If this cpu is the only one alive at this point in time, online or
302+
* not, there are no stop messages to be sent around, so just back out.
303+
*/
304+
if (num_other_online_cpus() == 0)
305+
return;
306+
307+
cpumask_copy(&mask, cpu_online_mask);
308+
cpumask_clear_cpu(smp_processor_id(), &mask);
309+
310+
atomic_set(&waiting_for_crash_ipi, num_other_online_cpus());
311+
312+
pr_crit("SMP: stopping secondary CPUs\n");
313+
send_ipi_mask(&mask, IPI_CPU_CRASH_STOP);
314+
315+
/* Wait up to one second for other CPUs to stop */
316+
timeout = USEC_PER_SEC;
317+
while ((atomic_read(&waiting_for_crash_ipi) > 0) && timeout--)
318+
udelay(1);
319+
320+
if (atomic_read(&waiting_for_crash_ipi) > 0)
321+
pr_warn("SMP: failed to stop secondary CPUs %*pbl\n",
322+
cpumask_pr_args(&mask));
323+
}
324+
325+
bool smp_crash_stop_failed(void)
326+
{
327+
return (atomic_read(&waiting_for_crash_ipi) > 0);
328+
}
329+
#endif
330+
238331
void smp_send_reschedule(int cpu)
239332
{
240333
send_ipi_single(cpu, IPI_RESCHEDULE);

0 commit comments

Comments
 (0)