riscv: kexec: Fixup crash_save percpu and machine_kexec_mask_interrupts
Subsystems (2)
v2 cover riscv: kexec: Fixup crash_save percpu and machine_kexec_mask_interrupts
From: Guo Ren <[email protected]>
Current riscv kexec can't crash_save percpu states and disable interrupts properly. The patch series fix them, make kexec work correct.
Changes in v2:
- Add Fixes tags
- Remove extern from bool smp_crash_stop_failed(void)
v1: https://lore.kernel.org/linux-riscv/[email protected]/
Guo Ren (2):
riscv: kexec: Disable all interrupts in kexec crash path
riscv: kexec: Fixup crash_smp_send_stop with percpu crash_save_cpu
arch/riscv/include/asm/smp.h | 6 +++ arch/riscv/kernel/machine_kexec.c | 44 +++++++++++---- arch/riscv/kernel/smp.c | 89 ++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 13 deletions(-)
Signature · 7 lines
2.36.1 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
PATCH v2 1/2 riscv: kexec: Disable all interrupts in kexec crash path
From: Guo Ren <[email protected]>
If a crash happens on cpu3 and all interrupts are binding on cpu0, the bad irq routing will cause a crash kernel which can't receive any irq. Because crash kernel won't clean up all harts' PLIC enable bits in enable registers. This patch is similar to 9141a003a491 ("ARM: 7316/1:
kexec: EOI active and mask all interrupts in kexec crash path") and 78fd584cdec0 ("arm64: kdump: implement machine_crash_shutdown()"), and PowerPC also has the same mechanism.
--- arch/riscv/kernel/machine_kexec.c | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
arch/riscv/kernel/machine_kexec.c +35 -0
@@ -15,6 +15,8 @@#include <linux/compiler.h> /* For unreachable() */ #include <linux/cpu.h> /* For cpu_down() */ #include <linux/reboot.h> +#include <linux/interrupt.h> +#include <linux/irq.h> /* * kexec_image_info - Print received image details
@@ -154,6 +156,37 @@ void crash_smp_send_stop(void) cpus_stopped =1 ; } +static void machine_kexec_mask_interrupts (void ) +{ +unsigned int i; +struct irq_desc *desc; + +for_each_irq_desc (i, desc) { +struct irq_chip *chip; +int ret; + + chip =irq_desc_get_chip (desc); +if (!chip) +continue ; + +/* +* First try to remove the active state. If this +* fails, try to EOI the interrupt. +*/ + ret =irq_set_irqchip_state (i,IRQCHIP_STATE_ACTIVE , false); + +if (ret &&irqd_irq_inprogress (&desc->irq_data) && + chip->irq_eoi) + chip->irq_eoi (&desc->irq_data); + +if (chip->irq_mask) + chip->irq_mask (&desc->irq_data); + +if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) + chip->irq_disable (&desc->irq_data); + } +} +/* * machine_crash_shutdown - Prepare to kexec after a kernel crash *
@@ -169,6 +202,8 @@ machine_crash_shutdown(struct pt_regs *regs)crash_smp_send_stop ();crash_save_cpu (regs,smp_processor_id ()); +machine_kexec_mask_interrupts (); +pr_info ("Starting crashdump kernel...\n" ); }
Signature · 7 lines
2.36.1 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
Re: [PATCH V2 1/2] riscv: kexec: Disable all interrupts in kexec crash path
It is ok for me
Quoted 80 lines · 在 2022/8/18 上午12:12, [email protected] 写道:
From: Guo Ren <[email protected]>
If a crash happens on cpu3 and all interrupts are binding on cpu0, the bad irq routing will cause a crash kernel which can't receive any irq. Because crash kernel won't clean up all harts' PLIC enable bits in enable registers. This patch is similar to
9141a003a491("ARM: 7316/1:
kexec: EOI active and mask all interrupts in kexec crash path") and78fd584cdec0("arm64: kdump: implementmachine_crash_shutdown()"), and PowerPC also has the same mechanism.Fixes fba8a8674f68 ("RISC-V: Add kexec support")Signed-off-by Guo Ren <[email protected]>Signed-off-by Guo Ren <[email protected]>Cc Will Deacon <[email protected]>Cc AKASHI Takahiro <[email protected]>Cc Nick Kossifidis <[email protected]>--- arch/riscv/kernel/machine_kexec.c | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)arch/riscv/kernel/machine_kexec.c +35
-0@@ -15,6 +15,8 @@#include <linux/compiler.h> /* For unreachable() */ #include <linux/cpu.h> /* For cpu_down() */ #include <linux/reboot.h> +#include <linux/interrupt.h> +#include <linux/irq.h> /* * kexec_image_info - Print received image details @@ -154,6 +156,37 @@ void crash_smp_send_stop(void) cpus_stopped =1 ; } +static void machine_kexec_mask_interrupts (void ) +{ +unsigned int i; +struct irq_desc *desc; + +for_each_irq_desc (i, desc) { +struct irq_chip *chip; +int ret; + + chip =irq_desc_get_chip (desc); +if (!chip) +continue ; + +/* +* First try to remove the active state. If this +* fails, try to EOI the interrupt. +*/ + ret =irq_set_irqchip_state (i,IRQCHIP_STATE_ACTIVE , false); + +if (ret &&irqd_irq_inprogress (&desc->irq_data) && + chip->irq_eoi) + chip->irq_eoi (&desc->irq_data); + +if (chip->irq_mask) + chip->irq_mask (&desc->irq_data); + +if (chip->irq_disable && !irqd_irq_disabled (&desc->irq_data)) + chip->irq_disable (&desc->irq_data); + } +} +/* * machine_crash_shutdown - Prepare to kexec after a kernel crash * @@ -169,6 +202,8 @@ machine_crash_shutdown(struct pt_regs *regs)crash_smp_send_stop ();crash_save_cpu (regs,smp_processor_id ()); +machine_kexec_mask_interrupts (); +pr_info ("Starting crashdump kernel...\n" ); }
PATCH v2 2/2 riscv: kexec: Fixup crash_smp_send_stop with percpu crash_save_cpu
In reply to [email protected]From: Guo Ren <[email protected]>
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 78fd584cdec0 ("arm64: kdump: implement machine_crash_shutdown()") and adds the same mechanism for riscv.
--- arch/riscv/include/asm/smp.h | 6 +++ arch/riscv/kernel/machine_kexec.c | 19 ++----- arch/riscv/kernel/smp.c | 89 ++++++++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 18 deletions(-)
arch/riscv/include/asm/smp.h +6 -0
@@ -50,6 +50,12 @@ void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops);/* Clear IPI for current CPU */ void riscv_clear_ipi (void ); +/* stop and save status for other CPUs */ +void crash_smp_send_stop (void ); + +/* Check other CPUs stop or not */ +bool smp_crash_stop_failed (void ); +/* Secondary hart entry */ asmlinkage void smp_callin(void);
arch/riscv/kernel/machine_kexec.c +3 -16
@@ -140,22 +140,6 @@ void machine_shutdown(void)#endif } -/* Override the weak function in kernel/panic.c */ -void crash_smp_send_stop (void ) -{ -static int cpus_stopped; - -/* -* This function can be called twice in panic path, but obviously -* we execute this only once. -*/ -if (cpus_stopped) -return ; - -smp_send_stop (); - cpus_stopped =1 ; -} -static void machine_kexec_mask_interrupts (void ) {unsigned int i;
@@ -230,6 +214,9 @@ machine_kexec(struct kimage *image)void *control_code_buffer =page_address (image->control_code_page);riscv_kexec_method kexec_method =NULL ; +WARN (smp_crash_stop_failed (), +"Some CPUs may be stale, kdump will be unreliable.\n" ); +if (image->type !=KEXEC_TYPE_CRASH ) kexec_method = control_code_buffer;else
arch/riscv/kernel/smp.c +87 -2
131 lines not on this page · raw message
Signature · 7 lines
2.36.1 _______________________________________________ linux-riscv mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-riscv
Re: [PATCH V2 2/2] riscv: kexec: Fixup crash_smp_send_stop with percpu crash_save_cpu
It is ok for me
Quoted 213 lines · 在 2022/8/18 上午12:12, [email protected] 写道:
From: Guo Ren <[email protected]>
Current
crash_smp_send_stopis the same as the generic one in kernel/panic and missescrash_save_cpuin percpu. This patch is inspired by78fd584cdec0("arm64: kdump: implementmachine_crash_shutdown()") and adds the same mechanism for riscv.Fixes ad943893d5f1 ("RISC-V: Fixup schedule out issue in machine_crash_shutdown()")Signed-off-by Guo Ren <[email protected]>Signed-off-by Guo Ren <[email protected]>Cc AKASHI Takahiro <[email protected]>--- arch/riscv/include/asm/smp.h | 6 +++ arch/riscv/kernel/machine_kexec.c | 19 ++----- arch/riscv/kernel/smp.c | 89 ++++++++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 18 deletions(-)arch/riscv/include/asm/smp.h +6
-0@@ -50,6 +50,12 @@ void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops);/* Clear IPI for current CPU */ void riscv_clear_ipi (void ); +/* stop and save status for other CPUs */ +void crash_smp_send_stop (void ); + +/* Check other CPUs stop or not */ +bool smp_crash_stop_failed (void ); +/* Secondary hart entry */ asmlinkage void smp_callin(void);arch/riscv/kernel/machine_kexec.c +3
-16@@ -140,22 +140,6 @@ void machine_shutdown(void)#endif } -/* Override the weak function in kernel/panic.c */ -void crash_smp_send_stop (void ) -{ -static int cpus_stopped; - -/* -* This function can be called twice in panic path, but obviously -* we execute this only once. -*/ -if (cpus_stopped) -return ; - -smp_send_stop (); - cpus_stopped =1 ; -} -static void machine_kexec_mask_interrupts (void ) {unsigned int i;@@ -230,6 +214,9 @@ machine_kexec(struct kimage *image)void *control_code_buffer =page_address (image->control_code_page);riscv_kexec_method kexec_method =NULL ; +WARN (smp_crash_stop_failed (), +"Some CPUs may be stale, kdump will be unreliable.\n" ); +if (image->type !=KEXEC_TYPE_CRASH ) kexec_method = control_code_buffer;else arch/riscv/kernel/smp.c +87
-2@@ -12,6 +12,7 @@#include <linux/clockchips.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/kexec.h> #include <linux/profile.h> #include <linux/smp.h> #include <linux/sched.h> @@ -27,6 +28,7 @@ enum ipi_message_type {IPI_RESCHEDULE ,IPI_CALL_FUNC ,IPI_CPU_STOP , +IPI_CPU_CRASH_STOP ,IPI_IRQ_WORK ,IPI_TIMER ,IPI_MAX @@ -71,6 +73,22 @@ static void ipi_stop(void)wait_for_interrupt (); } +#ifdef CONFIG_KEXEC_CORE +static atomic_t waiting_for_crash_ipi =ATOMIC_INIT (0 ); + +static void ipi_cpu_crash_stop (unsigned int cpu,struct pt_regs *regs) +{ +crash_save_cpu (regs, cpu); + +atomic_dec (&waiting_for_crash_ipi); + +local_irq_disable (); + +while (1 ) +wait_for_interrupt (); +} +#endif +static const struct riscv_ipi_ops *ipi_ops__ro_after_init ;void riscv_set_ipi_ops (const struct riscv_ipi_ops *ops)@@ -124,8 +142,9 @@ void arch_irq_work_raise(void)void handle_IPI (struct pt_regs *regs) { -unsigned long *pending_ipis = &ipi_data[smp_processor_id ()].bits; -unsigned long *stats = ipi_data[smp_processor_id ()].stats; +unsigned int cpu =smp_processor_id (); +unsigned long *pending_ipis = &ipi_data[cpu].bits; +unsigned long *stats = ipi_data[cpu].stats;riscv_clear_ipi ();@@ -154,6 +173,13 @@ void handle_IPI(struct pt_regs *regs)ipi_stop (); } +if (ops & (1 <<IPI_CPU_CRASH_STOP )) { +#ifdef CONFIG_KEXEC_CORE +ipi_cpu_crash_stop (cpu,get_irq_regs ()); +#endif +unreachable (); + } +if (ops & (1 <<IPI_IRQ_WORK )) { stats[IPI_IRQ_WORK ]++;irq_work_run ();@@ -176,6 +202,7 @@ static const char * const ipi_names[] = { [IPI_RESCHEDULE] = "Rescheduling interrupts", [IPI_CALL_FUNC] = "Function call interrupts", [IPI_CPU_STOP] = "CPU stop interrupts", + [IPI_CPU_CRASH_STOP] = "CPU stop (for crash dump) interrupts", [IPI_IRQ_WORK] = "IRQ work interrupts", [IPI_TIMER] = "Timer broadcast interrupts", };@@ -235,6 +262,64 @@ void smp_send_stop(void) cpumask_pr_args(cpu_online_mask)); } +#ifdef CONFIG_KEXEC_CORE +/* +* The number of CPUs online, not counting this CPU (which may not be +* fully online and so not counted in num_online_cpus()). +*/ +static inline unsigned int num_other_online_cpus (void ) +{ +unsigned int this_cpu_online =cpu_online (smp_processor_id ()); + +return num_online_cpus () - this_cpu_online; +} + +void crash_smp_send_stop (void ) +{ +static int cpus_stopped; +cpumask_t mask; +unsigned long timeout; + +/* +* This function can be called twice in panic path, but obviously +* we execute this only once. +*/ +if (cpus_stopped) +return ; + + cpus_stopped =1 ; + +/* +* If this cpu is the only one alive at this point in time, online or +* not, there are no stop messages to be sent around, so just back out. +*/ +if (num_other_online_cpus () ==0 ) +return ; + +cpumask_copy (&mask, cpu_online_mask); +cpumask_clear_cpu (smp_processor_id (), &mask); + +atomic_set (&waiting_for_crash_ipi,num_other_online_cpus ()); + +pr_crit ("SMP: stopping secondary CPUs\n" ); +send_ipi_mask (&mask,IPI_CPU_CRASH_STOP ); + +/* Wait up to one second for other CPUs to stop */ + timeout =USEC_PER_SEC ; +while ((atomic_read (&waiting_for_crash_ipi) >0 ) && timeout--) +udelay (1 ); + +if (atomic_read (&waiting_for_crash_ipi) >0 ) +pr_warn ("SMP: failed to stop secondary CPUs %*pbl\n" , +cpumask_pr_args (&mask)); +} + +bool smp_crash_stop_failed (void ) +{ +return (atomic_read (&waiting_for_crash_ipi) >0 ); +} +#endif +void smp_send_reschedule (int cpu) {send_ipi_single (cpu,IPI_RESCHEDULE );