summaryrefslogtreecommitdiff
path: root/arch/csky/kernel/ftrace.c
diff options
context:
space:
mode:
authorGuo Ren <guoren@linux.alibaba.com>2020-03-31 22:15:42 +0800
committerGuo Ren <guoren@linux.alibaba.com>2020-03-31 22:15:42 +0800
commitdd7c983e78a28ff0b22f8bcf32a303b4f79cb318 (patch)
tree459801c869b68f658e573b20e7f094490b63af3e /arch/csky/kernel/ftrace.c
parent89a3927a775c0a7212e2e3c4e2d42cd48895bee0 (diff)
downloadlinux-sh-dd7c983e78a28ff0b22f8bcf32a303b4f79cb318.tar.gz
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 <guoren@linux.alibaba.com>
Diffstat (limited to 'arch/csky/kernel/ftrace.c')
-rw-r--r--arch/csky/kernel/ftrace.c31
1 files changed, 31 insertions, 0 deletions
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 <linux/ftrace.h>
#include <linux/uaccess.h>
+#include <linux/stop_machine.h>
#include <asm/cacheflush.h>
#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(&param->cpu_count) == 1) {
+ ftrace_modify_all_code(param->command);
+ atomic_inc(&param->cpu_count);
+ } else {
+ while (atomic_read(&param->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, &param, cpu_online_mask);
+}
+#endif
+
/* _mcount is defined in abi's mcount.S */
EXPORT_SYMBOL(_mcount);