aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2008-06-23 21:32:22 -0400
committerPaul Mackerras <paulus@samba.org>2008-06-30 21:28:19 -0400
commite7a57273c6407bb6903fbaddec8c2119bf318617 (patch)
tree4d5b787c286e1d0ae64f757ef1f68fedd9743a3c
parentaaddd3eacaeaef3503035750b3f21ac2bfe97cbf (diff)
powerpc: Allow create_branch() to return errors
Currently create_branch() creates a branch instruction for you, and patches it into the call site. In some circumstances it would be nice to be able to create the instruction and patch it later, and also some code might want to check for errors in the branch creation before doing the patching. A future commit will change create_branch() to check for errors. For callers that don't care, replace create_branch() with patch_branch(), which just creates the branch and patches it directly. While we're touching all the callers, change to using unsigned int *, as this seems to match usage better. That allows (and requires) us to remove the volatile in the definition of vector in powermac/smp.c and mpc86xx_smp.c, that's correct because now that we're passing vector as an unsigned int * the compiler knows that it's value might change across the patch_branch() call. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Acked-by: Kumar Gala <galak@kernel.crashing.org> Acked-by: Jon Loeliger <jdl@freescale.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/crash_dump.c6
-rw-r--r--arch/powerpc/lib/code-patching.c20
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_smp.c5
-rw-r--r--arch/powerpc/platforms/powermac/smp.c5
-rw-r--r--include/asm-powerpc/code-patching.h6
5 files changed, 24 insertions, 18 deletions
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 35b9a668b0e1..26648544d5e4 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -34,6 +34,8 @@ void __init reserve_kdump_trampoline(void)
34 34
35static void __init create_trampoline(unsigned long addr) 35static void __init create_trampoline(unsigned long addr)
36{ 36{
37 unsigned int *p = (unsigned int *)addr;
38
37 /* The maximum range of a single instruction branch, is the current 39 /* The maximum range of a single instruction branch, is the current
38 * instruction's address + (32 MB - 4) bytes. For the trampoline we 40 * instruction's address + (32 MB - 4) bytes. For the trampoline we
39 * need to branch to current address + 32 MB. So we insert a nop at 41 * need to branch to current address + 32 MB. So we insert a nop at
@@ -42,8 +44,8 @@ static void __init create_trampoline(unsigned long addr)
42 * branch to "addr" we jump to ("addr" + 32 MB). Although it requires 44 * branch to "addr" we jump to ("addr" + 32 MB). Although it requires
43 * two instructions it doesn't require any registers. 45 * two instructions it doesn't require any registers.
44 */ 46 */
45 create_instruction(addr, 0x60000000); /* nop */ 47 patch_instruction(p, 0x60000000); /* nop */
46 create_branch(addr + 4, addr + PHYSICAL_START, 0); 48 patch_branch(++p, addr + PHYSICAL_START, 0);
47} 49}
48 50
49void __init setup_kdump_trampoline(void) 51void __init setup_kdump_trampoline(void)
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index 7afae88ed1d4..638dde313cbc 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c
@@ -11,23 +11,27 @@
11#include <asm/code-patching.h> 11#include <asm/code-patching.h>
12 12
13 13
14void create_instruction(unsigned long addr, unsigned int instr) 14void patch_instruction(unsigned int *addr, unsigned int instr)
15{ 15{
16 unsigned int *p; 16 *addr = instr;
17 p = (unsigned int *)addr; 17 asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (addr));
18 *p = instr;
19 asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (p));
20} 18}
21 19
22void create_branch(unsigned long addr, unsigned long target, int flags) 20void patch_branch(unsigned int *addr, unsigned long target, int flags)
21{
22 patch_instruction(addr, create_branch(addr, target, flags));
23}
24
25unsigned int create_branch(const unsigned int *addr,
26 unsigned long target, int flags)
23{ 27{
24 unsigned int instruction; 28 unsigned int instruction;
25 29
26 if (! (flags & BRANCH_ABSOLUTE)) 30 if (! (flags & BRANCH_ABSOLUTE))
27 target = target - addr; 31 target = target - (unsigned long)addr;
28 32
29 /* Mask out the flags and target, so they don't step on each other. */ 33 /* Mask out the flags and target, so they don't step on each other. */
30 instruction = 0x48000000 | (flags & 0x3) | (target & 0x03FFFFFC); 34 instruction = 0x48000000 | (flags & 0x3) | (target & 0x03FFFFFC);
31 35
32 create_instruction(addr, instruction); 36 return instruction;
33} 37}
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index 63f55853cd69..835f2dc24dc9 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -57,8 +57,7 @@ smp_86xx_kick_cpu(int nr)
57 unsigned int save_vector; 57 unsigned int save_vector;
58 unsigned long target, flags; 58 unsigned long target, flags;
59 int n = 0; 59 int n = 0;
60 volatile unsigned int *vector 60 unsigned int *vector = (unsigned int *)(KERNELBASE + 0x100);
61 = (volatile unsigned int *)(KERNELBASE + 0x100);
62 61
63 if (nr < 0 || nr >= NR_CPUS) 62 if (nr < 0 || nr >= NR_CPUS)
64 return; 63 return;
@@ -72,7 +71,7 @@ smp_86xx_kick_cpu(int nr)
72 71
73 /* Setup fake reset vector to call __secondary_start_mpc86xx. */ 72 /* Setup fake reset vector to call __secondary_start_mpc86xx. */
74 target = (unsigned long) __secondary_start_mpc86xx; 73 target = (unsigned long) __secondary_start_mpc86xx;
75 create_branch((unsigned long)vector, target, BRANCH_SET_LINK); 74 patch_branch(vector, target, BRANCH_SET_LINK);
76 75
77 /* Kick that CPU */ 76 /* Kick that CPU */
78 smp_86xx_release_core(nr); 77 smp_86xx_release_core(nr);
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index bf202f7eadf8..4ae3d00e0bdd 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -787,8 +787,7 @@ static void __devinit smp_core99_kick_cpu(int nr)
787{ 787{
788 unsigned int save_vector; 788 unsigned int save_vector;
789 unsigned long target, flags; 789 unsigned long target, flags;
790 volatile unsigned int *vector 790 unsigned int *vector = (unsigned int *)(KERNELBASE+0x100);
791 = ((volatile unsigned int *)(KERNELBASE+0x100));
792 791
793 if (nr < 0 || nr > 3) 792 if (nr < 0 || nr > 3)
794 return; 793 return;
@@ -805,7 +804,7 @@ static void __devinit smp_core99_kick_cpu(int nr)
805 * b __secondary_start_pmac_0 + nr*8 - KERNELBASE 804 * b __secondary_start_pmac_0 + nr*8 - KERNELBASE
806 */ 805 */
807 target = (unsigned long) __secondary_start_pmac_0 + nr * 8; 806 target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
808 create_branch((unsigned long)vector, target, BRANCH_SET_LINK); 807 patch_branch(vector, target, BRANCH_SET_LINK);
809 808
810 /* Put some life in our friend */ 809 /* Put some life in our friend */
811 pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); 810 pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
diff --git a/include/asm-powerpc/code-patching.h b/include/asm-powerpc/code-patching.h
index 0b91fdf944db..fdb187cbc40d 100644
--- a/include/asm-powerpc/code-patching.h
+++ b/include/asm-powerpc/code-patching.h
@@ -19,7 +19,9 @@
19#define BRANCH_SET_LINK 0x1 19#define BRANCH_SET_LINK 0x1
20#define BRANCH_ABSOLUTE 0x2 20#define BRANCH_ABSOLUTE 0x2
21 21
22extern void create_branch(unsigned long addr, unsigned long target, int flags); 22unsigned int create_branch(const unsigned int *addr,
23extern void create_instruction(unsigned long addr, unsigned int instr); 23 unsigned long target, int flags);
24void patch_branch(unsigned int *addr, unsigned long target, int flags);
25void patch_instruction(unsigned int *addr, unsigned int instr);
24 26
25#endif /* _ASM_POWERPC_CODE_PATCHING_H */ 27#endif /* _ASM_POWERPC_CODE_PATCHING_H */