aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2010-12-28 16:26:23 -0500
committerRalf Baechle <ralf@linux-mips.org>2011-01-18 13:30:24 -0500
commit94bb0c1ab293c298a8852e4f10c4215bad6daa9b (patch)
treee4e7dfa18bf2ffd832a97d7ab67863b1b363c6fe /arch/mips
parent8d662c8d34a05e8e47deaa9e22fe770dc557c2d3 (diff)
MIPS: jump label: Add MIPS support.
In order not to be left behind, we add jump label support for MIPS. Tested on 64-bit big endian (Octeon), and 32-bit little endian (malta/qemu). Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Jason Baron <jbaron@redhat.com> Patchwork: https://patchwork.linux-mips.org/patch/1923/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/include/asm/jump_label.h48
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/jump_label.c54
-rw-r--r--arch/mips/kernel/module.c5
5 files changed, 110 insertions, 0 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2106781d7473..954304068228 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -21,6 +21,7 @@ config MIPS
21 select HAVE_DMA_API_DEBUG 21 select HAVE_DMA_API_DEBUG
22 select HAVE_GENERIC_HARDIRQS 22 select HAVE_GENERIC_HARDIRQS
23 select GENERIC_IRQ_PROBE 23 select GENERIC_IRQ_PROBE
24 select HAVE_ARCH_JUMP_LABEL
24 25
25menu "Machine selection" 26menu "Machine selection"
26 27
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h
new file mode 100644
index 000000000000..7622ccf75076
--- /dev/null
+++ b/arch/mips/include/asm/jump_label.h
@@ -0,0 +1,48 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (c) 2010 Cavium Networks, Inc.
7 */
8#ifndef _ASM_MIPS_JUMP_LABEL_H
9#define _ASM_MIPS_JUMP_LABEL_H
10
11#include <linux/types.h>
12
13#ifdef __KERNEL__
14
15#define JUMP_LABEL_NOP_SIZE 4
16
17#ifdef CONFIG_64BIT
18#define WORD_INSN ".dword"
19#else
20#define WORD_INSN ".word"
21#endif
22
23#define JUMP_LABEL(key, label) \
24 do { \
25 asm goto("1:\tnop\n\t" \
26 "nop\n\t" \
27 ".pushsection __jump_table, \"a\"\n\t" \
28 WORD_INSN " 1b, %l[" #label "], %0\n\t" \
29 ".popsection\n\t" \
30 : : "i" (key) : : label); \
31 } while (0)
32
33
34#endif /* __KERNEL__ */
35
36#ifdef CONFIG_64BIT
37typedef u64 jump_label_t;
38#else
39typedef u32 jump_label_t;
40#endif
41
42struct jump_entry {
43 jump_label_t code;
44 jump_label_t target;
45 jump_label_t key;
46};
47
48#endif /* _ASM_MIPS_JUMP_LABEL_H */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 39773979ca6d..cedee2bcbd18 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -107,4 +107,6 @@ obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
107 107
108obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o 108obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
109 109
110obj-$(CONFIG_JUMP_LABEL) += jump_label.o
111
110CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) 112CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c
new file mode 100644
index 000000000000..6001610cfe55
--- /dev/null
+++ b/arch/mips/kernel/jump_label.c
@@ -0,0 +1,54 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (c) 2010 Cavium Networks, Inc.
7 */
8
9#include <linux/jump_label.h>
10#include <linux/kernel.h>
11#include <linux/memory.h>
12#include <linux/mutex.h>
13#include <linux/types.h>
14#include <linux/cpu.h>
15
16#include <asm/cacheflush.h>
17#include <asm/inst.h>
18
19#ifdef HAVE_JUMP_LABEL
20
21#define J_RANGE_MASK ((1ul << 28) - 1)
22
23void arch_jump_label_transform(struct jump_entry *e,
24 enum jump_label_type type)
25{
26 union mips_instruction insn;
27 union mips_instruction *insn_p =
28 (union mips_instruction *)(unsigned long)e->code;
29
30 /* Jump only works within a 256MB aligned region. */
31 BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK));
32
33 /* Target must have 4 byte alignment. */
34 BUG_ON((e->target & 3) != 0);
35
36 if (type == JUMP_LABEL_ENABLE) {
37 insn.j_format.opcode = j_op;
38 insn.j_format.target = (e->target & J_RANGE_MASK) >> 2;
39 } else {
40 insn.word = 0; /* nop */
41 }
42
43 get_online_cpus();
44 mutex_lock(&text_mutex);
45 *insn_p = insn;
46
47 flush_icache_range((unsigned long)insn_p,
48 (unsigned long)insn_p + sizeof(*insn_p));
49
50 mutex_unlock(&text_mutex);
51 put_online_cpus();
52}
53
54#endif /* HAVE_JUMP_LABEL */
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
index d87a72e9fac7..dd940b701963 100644
--- a/arch/mips/kernel/module.c
+++ b/arch/mips/kernel/module.c
@@ -30,6 +30,8 @@
30#include <linux/kernel.h> 30#include <linux/kernel.h>
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/spinlock.h> 32#include <linux/spinlock.h>
33#include <linux/jump_label.h>
34
33#include <asm/pgtable.h> /* MODULE_START */ 35#include <asm/pgtable.h> /* MODULE_START */
34 36
35struct mips_hi16 { 37struct mips_hi16 {
@@ -382,6 +384,9 @@ int module_finalize(const Elf_Ehdr *hdr,
382 const Elf_Shdr *s; 384 const Elf_Shdr *s;
383 char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 385 char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
384 386
387 /* Make jump label nops. */
388 jump_label_apply_nops(me);
389
385 INIT_LIST_HEAD(&me->arch.dbe_list); 390 INIT_LIST_HEAD(&me->arch.dbe_list);
386 for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 391 for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
387 if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) 392 if (strcmp("__dbe_table", secstrings + s->sh_name) != 0)