Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 94bb0c1a authored by David Daney's avatar David Daney Committed by Ralf Baechle
Browse files

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: default avatarDavid 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: default avatarRalf Baechle <ralf@linux-mips.org>
parent 8d662c8d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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"

+48 −0
Original line number Diff line number Diff line
/*
 * 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 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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 −0
Original line number Diff line number Diff line
@@ -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 {
@@ -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)