Skip to content

Commit

Permalink
MIPS: jump label: Add MIPS support.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Daney authored and Ralf Baechle committed Jan 18, 2011
1 parent 8d662c8 commit 94bb0c1
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/mips/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ config MIPS
select HAVE_DMA_API_DEBUG
select HAVE_GENERIC_HARDIRQS
select GENERIC_IRQ_PROBE
select HAVE_ARCH_JUMP_LABEL

menu "Machine selection"

Expand Down
48 changes: 48 additions & 0 deletions arch/mips/include/asm/jump_label.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (c) 2010 Cavium Networks, Inc.
*/
#ifndef _ASM_MIPS_JUMP_LABEL_H
#define _ASM_MIPS_JUMP_LABEL_H

#include <linux/types.h>

#ifdef __KERNEL__

#define JUMP_LABEL_NOP_SIZE 4

#ifdef CONFIG_64BIT
#define WORD_INSN ".dword"
#else
#define WORD_INSN ".word"
#endif

#define JUMP_LABEL(key, label) \
do { \
asm goto("1:\tnop\n\t" \
"nop\n\t" \
".pushsection __jump_table, \"a\"\n\t" \
WORD_INSN " 1b, %l[" #label "], %0\n\t" \
".popsection\n\t" \
: : "i" (key) : : label); \
} while (0)


#endif /* __KERNEL__ */

#ifdef CONFIG_64BIT
typedef u64 jump_label_t;
#else
typedef u32 jump_label_t;
#endif

struct jump_entry {
jump_label_t code;
jump_label_t target;
jump_label_t key;
};

#endif /* _ASM_MIPS_JUMP_LABEL_H */
2 changes: 2 additions & 0 deletions arch/mips/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,6 @@ obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/

obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o

obj-$(CONFIG_JUMP_LABEL) += jump_label.o

CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
54 changes: 54 additions & 0 deletions arch/mips/kernel/jump_label.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (c) 2010 Cavium Networks, Inc.
*/

#include <linux/jump_label.h>
#include <linux/kernel.h>
#include <linux/memory.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/cpu.h>

#include <asm/cacheflush.h>
#include <asm/inst.h>

#ifdef HAVE_JUMP_LABEL

#define J_RANGE_MASK ((1ul << 28) - 1)

void arch_jump_label_transform(struct jump_entry *e,
enum jump_label_type type)
{
union mips_instruction insn;
union mips_instruction *insn_p =
(union mips_instruction *)(unsigned long)e->code;

/* Jump only works within a 256MB aligned region. */
BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK));

/* Target must have 4 byte alignment. */
BUG_ON((e->target & 3) != 0);

if (type == JUMP_LABEL_ENABLE) {
insn.j_format.opcode = j_op;
insn.j_format.target = (e->target & J_RANGE_MASK) >> 2;
} else {
insn.word = 0; /* nop */
}

get_online_cpus();
mutex_lock(&text_mutex);
*insn_p = insn;

flush_icache_range((unsigned long)insn_p,
(unsigned long)insn_p + sizeof(*insn_p));

mutex_unlock(&text_mutex);
put_online_cpus();
}

#endif /* HAVE_JUMP_LABEL */
5 changes: 5 additions & 0 deletions arch/mips/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/jump_label.h>

#include <asm/pgtable.h> /* MODULE_START */

struct mips_hi16 {
Expand Down Expand Up @@ -382,6 +384,9 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *s;
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;

/* Make jump label nops. */
jump_label_apply_nops(me);

INIT_LIST_HEAD(&me->arch.dbe_list);
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
if (strcmp("__dbe_table", secstrings + s->sh_name) != 0)
Expand Down

0 comments on commit 94bb0c1

Please sign in to comment.