| David Daney | 94bb0c1 | 2010-12-28 13:26:23 -0800 | [diff] [blame] | 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 |  | 
|  | 23 | void 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 */ |