tile/jump_label: add jump label support for TILE-Gx
authorZhigang Lu <zlu@ezchip.com>
Wed, 30 Sep 2015 02:11:45 +0000 (10:11 +0800)
committerChris Metcalf <cmetcalf@ezchip.com>
Mon, 4 Jan 2016 20:09:31 +0000 (15:09 -0500)
Add the arch-specific code to support jump label for TILE-Gx. This
code shares NOP instruction with ftrace, so we move it to a common
header file.

Reviewed-by: Chris Metcalf <cmetcalf@ezchip.com>
Signed-off-by: Zhigang Lu <zlu@ezchip.com>
Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
arch/tile/Kconfig
arch/tile/include/asm/insn.h [new file with mode: 0644]
arch/tile/include/asm/jump_label.h [new file with mode: 0644]
arch/tile/kernel/Makefile
arch/tile/kernel/ftrace.c
arch/tile/kernel/jump_label.c [new file with mode: 0644]

index 106c21bd7f449d947094db5fdefce8a9a6e1b142..49be476f9feb8f463721401274479b152af74f38 100644 (file)
@@ -143,6 +143,7 @@ config TILEGX
        select HAVE_KRETPROBES
        select HAVE_ARCH_KGDB
        select ARCH_SUPPORTS_ATOMIC_RMW
+       select HAVE_ARCH_JUMP_LABEL
 
 config TILEPRO
        def_bool !TILEGX
diff --git a/arch/tile/include/asm/insn.h b/arch/tile/include/asm/insn.h
new file mode 100644 (file)
index 0000000..f78ba5c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+#ifndef __ASM_TILE_INSN_H
+#define __ASM_TILE_INSN_H
+
+#include <arch/opcode.h>
+
+static inline tilegx_bundle_bits NOP(void)
+{
+       return create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) |
+               create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) |
+               create_Opcode_X0(RRR_0_OPCODE_X0) |
+               create_UnaryOpcodeExtension_X1(NOP_UNARY_OPCODE_X1) |
+               create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) |
+               create_Opcode_X1(RRR_0_OPCODE_X1);
+}
+
+static inline tilegx_bundle_bits tilegx_gen_branch(unsigned long pc,
+                                           unsigned long addr,
+                                           bool link)
+{
+       tilegx_bundle_bits opcode_x0, opcode_x1;
+       long pcrel_by_instr = (addr - pc) >> TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES;
+
+       if (link) {
+               /* opcode: jal addr */
+               opcode_x1 =
+                       create_Opcode_X1(JUMP_OPCODE_X1) |
+                       create_JumpOpcodeExtension_X1(JAL_JUMP_OPCODE_X1) |
+                       create_JumpOff_X1(pcrel_by_instr);
+       } else {
+               /* opcode: j addr */
+               opcode_x1 =
+                       create_Opcode_X1(JUMP_OPCODE_X1) |
+                       create_JumpOpcodeExtension_X1(J_JUMP_OPCODE_X1) |
+                       create_JumpOff_X1(pcrel_by_instr);
+       }
+
+       /* opcode: fnop */
+       opcode_x0 =
+               create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) |
+               create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) |
+               create_Opcode_X0(RRR_0_OPCODE_X0);
+
+       return opcode_x1 | opcode_x0;
+}
+
+#endif /* __ASM_TILE_INSN_H */
diff --git a/arch/tile/include/asm/jump_label.h b/arch/tile/include/asm/jump_label.h
new file mode 100644 (file)
index 0000000..cde7573
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _ASM_TILE_JUMP_LABEL_H
+#define _ASM_TILE_JUMP_LABEL_H
+
+#include <arch/opcode.h>
+
+#define JUMP_LABEL_NOP_SIZE    TILE_BUNDLE_SIZE_IN_BYTES
+
+static __always_inline bool arch_static_branch(struct static_key *key,
+                                              bool branch)
+{
+       asm_volatile_goto("1:\n\t"
+               "nop" "\n\t"
+               ".pushsection __jump_table,  \"aw\"\n\t"
+               ".quad 1b, %l[l_yes], %0 + %1 \n\t"
+               ".popsection\n\t"
+               : :  "i" (key), "i" (branch) : : l_yes);
+       return false;
+l_yes:
+       return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key *key,
+                                                   bool branch)
+{
+       asm_volatile_goto("1:\n\t"
+               "j %l[l_yes]" "\n\t"
+               ".pushsection __jump_table,  \"aw\"\n\t"
+               ".quad 1b, %l[l_yes], %0 + %1 \n\t"
+               ".popsection\n\t"
+               : :  "i" (key), "i" (branch) : : l_yes);
+       return false;
+l_yes:
+       return true;
+}
+
+typedef u64 jump_label_t;
+
+struct jump_entry {
+       jump_label_t code;
+       jump_label_t target;
+       jump_label_t key;
+};
+
+#endif /* _ASM_TILE_JUMP_LABEL_H */
index 21f77bf68c690a438c8ca9540e0f9e7574872c17..09936d0bcb42a811a1da6b2d72b970e8a40277a7 100644 (file)
@@ -32,5 +32,6 @@ obj-$(CONFIG_TILE_HVGLUE_TRACE)       += hvglue_trace.o
 obj-$(CONFIG_FUNCTION_TRACER)  += ftrace.o mcount_64.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_KGDB)             += kgdb.o
+obj-$(CONFIG_JUMP_LABEL)       += jump_label.o
 
 obj-y                          += vdso/
index 4180ccdf9cd090db1985ca726e7af33e53843875..4a572088b270bec26a0b10cce0453ab2d15e6c20 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/ftrace.h>
 #include <asm/sections.h>
+#include <asm/insn.h>
 
 #include <arch/opcode.h>
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
-static inline tilegx_bundle_bits NOP(void)
-{
-       return create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) |
-               create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) |
-               create_Opcode_X0(RRR_0_OPCODE_X0) |
-               create_UnaryOpcodeExtension_X1(NOP_UNARY_OPCODE_X1) |
-               create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) |
-               create_Opcode_X1(RRR_0_OPCODE_X1);
-}
-
 static int machine_stopped __read_mostly;
 
 int ftrace_arch_code_modify_prepare(void)
diff --git a/arch/tile/kernel/jump_label.c b/arch/tile/kernel/jump_label.c
new file mode 100644 (file)
index 0000000..07802d5
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * jump label TILE-Gx support
+ */
+
+#include <linux/jump_label.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+
+#include <asm/cacheflush.h>
+#include <asm/insn.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+static void __jump_label_transform(struct jump_entry *e,
+                                  enum jump_label_type type)
+{
+       tilegx_bundle_bits opcode;
+       /* Operate on writable kernel text mapping. */
+       unsigned long pc_wr = ktext_writable_addr(e->code);
+
+       if (type == JUMP_LABEL_JMP)
+               opcode = tilegx_gen_branch(e->code, e->target, false);
+       else
+               opcode = NOP();
+
+       *(tilegx_bundle_bits *)pc_wr = opcode;
+       /* Make sure that above mem writes were issued towards the memory. */
+       smp_wmb();
+}
+
+void arch_jump_label_transform(struct jump_entry *e,
+                               enum jump_label_type type)
+{
+       get_online_cpus();
+       mutex_lock(&text_mutex);
+
+       __jump_label_transform(e, type);
+       flush_icache_range(e->code, e->code + sizeof(tilegx_bundle_bits));
+
+       mutex_unlock(&text_mutex);
+       put_online_cpus();
+}
+
+__init_or_module void arch_jump_label_transform_static(struct jump_entry *e,
+                                               enum jump_label_type type)
+{
+       __jump_label_transform(e, type);
+}
+
+#endif /* HAVE_JUMP_LABEL */