tile/jump_label: add jump label support for TILE-Gx

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>
diff --git a/arch/tile/kernel/jump_label.c b/arch/tile/kernel/jump_label.c
new file mode 100644
index 0000000..07802d5
--- /dev/null
+++ b/arch/tile/kernel/jump_label.c
@@ -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 */