aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2011-11-14 07:54:47 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-11-15 22:47:54 -0500
commitd715e433b7ad19c02fc4becf0d5e9a59f97925de (patch)
tree6c5ba4c3b21c4070b82a184f5eca26c9e6c8edf1
parent6d1e2c6c1a0b800473db4df8595c95745be548ea (diff)
powerpc: Copy down exception vectors after feature fixups
kdump fails because we try to execute an HV only instruction. Feature fixups are being applied after we copy the exception vectors down to 0 so they miss out on any updates. We have always had this issue but it only became critical in v3.0 when we added CFAR support (breaks POWER5) and v3.1 when we added POWERNV (breaks everyone). Signed-off-by: Anton Blanchard <anton@samba.org> Cc: <stable@kernel.org> [v3.0+] Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/sections.h2
-rw-r--r--arch/powerpc/include/asm/synch.h1
-rw-r--r--arch/powerpc/kernel/kvm.c1
-rw-r--r--arch/powerpc/kernel/setup_32.c2
-rw-r--r--arch/powerpc/kernel/setup_64.c1
-rw-r--r--arch/powerpc/lib/feature-fixups.c23
6 files changed, 28 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 6fbce725c710..a0f358d4a00c 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -8,7 +8,7 @@
8 8
9#ifdef __powerpc64__ 9#ifdef __powerpc64__
10 10
11extern char _end[]; 11extern char __end_interrupts[];
12 12
13static inline int in_kernel_text(unsigned long addr) 13static inline int in_kernel_text(unsigned long addr)
14{ 14{
diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h
index d7cab44643c5..87878c68d1c2 100644
--- a/arch/powerpc/include/asm/synch.h
+++ b/arch/powerpc/include/asm/synch.h
@@ -13,6 +13,7 @@
13extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup; 13extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
14extern void do_lwsync_fixups(unsigned long value, void *fixup_start, 14extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
15 void *fixup_end); 15 void *fixup_end);
16extern void do_final_fixups(void);
16 17
17static inline void eieio(void) 18static inline void eieio(void)
18{ 19{
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index 35f27646c4ff..2985338d0e10 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -132,7 +132,6 @@ static void kvm_patch_ins_b(u32 *inst, int addr)
132 /* On relocatable kernels interrupts handlers and our code 132 /* On relocatable kernels interrupts handlers and our code
133 can be in different regions, so we don't patch them */ 133 can be in different regions, so we don't patch them */
134 134
135 extern u32 __end_interrupts;
136 if ((ulong)inst < (ulong)&__end_interrupts) 135 if ((ulong)inst < (ulong)&__end_interrupts)
137 return; 136 return;
138#endif 137#endif
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index c1ce86357ecb..ac7610815113 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -107,6 +107,8 @@ notrace unsigned long __init early_init(unsigned long dt_ptr)
107 PTRRELOC(&__start___lwsync_fixup), 107 PTRRELOC(&__start___lwsync_fixup),
108 PTRRELOC(&__stop___lwsync_fixup)); 108 PTRRELOC(&__stop___lwsync_fixup));
109 109
110 do_final_fixups();
111
110 return KERNELBASE + offset; 112 return KERNELBASE + offset;
111} 113}
112 114
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 1a9dea80a69b..fb9bb46e7e88 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -359,6 +359,7 @@ void __init setup_system(void)
359 &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); 359 &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
360 do_lwsync_fixups(cur_cpu_spec->cpu_features, 360 do_lwsync_fixups(cur_cpu_spec->cpu_features,
361 &__start___lwsync_fixup, &__stop___lwsync_fixup); 361 &__start___lwsync_fixup, &__stop___lwsync_fixup);
362 do_final_fixups();
362 363
363 /* 364 /*
364 * Unflatten the device-tree passed by prom_init or kexec 365 * Unflatten the device-tree passed by prom_init or kexec
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 0d08d0171392..7a8a7487cee8 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -18,6 +18,8 @@
18#include <linux/init.h> 18#include <linux/init.h>
19#include <asm/cputable.h> 19#include <asm/cputable.h>
20#include <asm/code-patching.h> 20#include <asm/code-patching.h>
21#include <asm/page.h>
22#include <asm/sections.h>
21 23
22 24
23struct fixup_entry { 25struct fixup_entry {
@@ -128,6 +130,27 @@ void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
128 } 130 }
129} 131}
130 132
133void do_final_fixups(void)
134{
135#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
136 int *src, *dest;
137 unsigned long length;
138
139 if (PHYSICAL_START == 0)
140 return;
141
142 src = (int *)(KERNELBASE + PHYSICAL_START);
143 dest = (int *)KERNELBASE;
144 length = (__end_interrupts - _stext) / sizeof(int);
145
146 while (length--) {
147 patch_instruction(dest, *src);
148 src++;
149 dest++;
150 }
151#endif
152}
153
131#ifdef CONFIG_FTR_FIXUP_SELFTEST 154#ifdef CONFIG_FTR_FIXUP_SELFTEST
132 155
133#define check(x) \ 156#define check(x) \