From dd7c983e78a28ff0b22f8bcf32a303b4f79cb318 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 31 Mar 2020 22:15:42 +0800 Subject: csky/ftrace: Fixup ftrace_modify_code deadlock without CPU_HAS_ICACHE_INS If ICACHE_INS is not supported, we use IPI to sync icache on each core. But ftrace_modify_code is called from stop_machine from default implementation of arch_ftrace_update_code and stop_machine callback is irq_disabled. When you call ipi with irq_disabled, a deadlock will happen. We couldn't use icache_flush with irq_disabled, but startup make_nop is specific case and it needn't ipi other cores. Signed-off-by: Guo Ren --- arch/csky/kernel/ftrace.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'arch/csky/kernel') diff --git a/arch/csky/kernel/ftrace.c b/arch/csky/kernel/ftrace.c index b4502cd2eabe..44628e3f7fa6 100644 --- a/arch/csky/kernel/ftrace.c +++ b/arch/csky/kernel/ftrace.c @@ -3,6 +3,7 @@ #include #include +#include #include #ifdef CONFIG_DYNAMIC_FTRACE @@ -201,5 +202,35 @@ int ftrace_disable_ftrace_graph_caller(void) #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +#ifndef CONFIG_CPU_HAS_ICACHE_INS +struct ftrace_modify_param { + int command; + atomic_t cpu_count; +}; + +static int __ftrace_modify_code(void *data) +{ + struct ftrace_modify_param *param = data; + + if (atomic_inc_return(¶m->cpu_count) == 1) { + ftrace_modify_all_code(param->command); + atomic_inc(¶m->cpu_count); + } else { + while (atomic_read(¶m->cpu_count) <= num_online_cpus()) + cpu_relax(); + local_icache_inv_all(NULL); + } + + return 0; +} + +void arch_ftrace_update_code(int command) +{ + struct ftrace_modify_param param = { command, ATOMIC_INIT(0) }; + + stop_machine(__ftrace_modify_code, ¶m, cpu_online_mask); +} +#endif + /* _mcount is defined in abi's mcount.S */ EXPORT_SYMBOL(_mcount); -- cgit