aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorKumar Gala <galak@kernel.crashing.org>2008-07-01 11:16:40 -0400
committerPaul Mackerras <paulus@samba.org>2008-07-03 02:58:10 -0400
commit2d1b2027626d5151fff8ef7c06ca8e7876a1a510 (patch)
tree6ecc861f4f45a5d26309bf12683aa0372358ef7c /arch/powerpc
parent5888da18765ca9af7f10015263d8bc8e3057f128 (diff)
powerpc: Fixup lwsync at runtime
To allow for a single kernel image on e500 v1/v2/mc we need to fixup lwsync at runtime. On e500v1/v2 lwsync causes an illop so we need to patch up the code. We default to 'sync' since that is always safe and if the cpu is capable we will replace 'sync' with 'lwsync'. We introduce CPU_FTR_LWSYNC as a way to determine at runtime if this is needed. This flag could be moved elsewhere since we dont really use it for the normal CPU_FTR purpose. Finally we only store the relative offset in the fixup section to keep it as small as possible rather than using a full fixup_entry. Signed-off-by: Kumar Gala <galak@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/module.c6
-rw-r--r--arch/powerpc/kernel/setup_32.c4
-rw-r--r--arch/powerpc/kernel/setup_64.c2
-rw-r--r--arch/powerpc/kernel/vdso.c10
-rw-r--r--arch/powerpc/kernel/vdso32/vdso32.lds.S3
-rw-r--r--arch/powerpc/kernel/vdso64/vdso64.lds.S3
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S6
-rw-r--r--arch/powerpc/lib/feature-fixups-test.S15
-rw-r--r--arch/powerpc/lib/feature-fixups.c36
9 files changed, 85 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c
index 40dd52d81c18..af07003573c4 100644
--- a/arch/powerpc/kernel/module.c
+++ b/arch/powerpc/kernel/module.c
@@ -86,6 +86,12 @@ int module_finalize(const Elf_Ehdr *hdr,
86 (void *)sect->sh_addr + sect->sh_size); 86 (void *)sect->sh_addr + sect->sh_size);
87#endif 87#endif
88 88
89 sect = find_section(hdr, sechdrs, "__lwsync_fixup");
90 if (sect != NULL)
91 do_lwsync_fixups(cur_cpu_spec->cpu_features,
92 (void *)sect->sh_addr,
93 (void *)sect->sh_addr + sect->sh_size);
94
89 return 0; 95 return 0;
90} 96}
91 97
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 9e83add54290..0109e7f0ccf9 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -101,6 +101,10 @@ unsigned long __init early_init(unsigned long dt_ptr)
101 PTRRELOC(&__start___ftr_fixup), 101 PTRRELOC(&__start___ftr_fixup),
102 PTRRELOC(&__stop___ftr_fixup)); 102 PTRRELOC(&__stop___ftr_fixup));
103 103
104 do_lwsync_fixups(spec->cpu_features,
105 PTRRELOC(&__start___lwsync_fixup),
106 PTRRELOC(&__stop___lwsync_fixup));
107
104 return KERNELBASE + offset; 108 return KERNELBASE + offset;
105} 109}
106 110
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 098fd96a394a..04d8de9f0fc6 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -363,6 +363,8 @@ void __init setup_system(void)
363 &__start___ftr_fixup, &__stop___ftr_fixup); 363 &__start___ftr_fixup, &__stop___ftr_fixup);
364 do_feature_fixups(powerpc_firmware_features, 364 do_feature_fixups(powerpc_firmware_features,
365 &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); 365 &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
366 do_lwsync_fixups(cur_cpu_spec->cpu_features,
367 &__start___lwsync_fixup, &__stop___lwsync_fixup);
366 368
367 /* 369 /*
368 * Unflatten the device-tree passed by prom_init or kexec 370 * Unflatten the device-tree passed by prom_init or kexec
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index ce245a850db2..f177c60ea766 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -571,6 +571,11 @@ static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
571 if (start64) 571 if (start64)
572 do_feature_fixups(powerpc_firmware_features, 572 do_feature_fixups(powerpc_firmware_features,
573 start64, start64 + size64); 573 start64, start64 + size64);
574
575 start64 = find_section64(v64->hdr, "__lwsync_fixup", &size64);
576 if (start64)
577 do_lwsync_fixups(cur_cpu_spec->cpu_features,
578 start64, start64 + size64);
574#endif /* CONFIG_PPC64 */ 579#endif /* CONFIG_PPC64 */
575 580
576 start32 = find_section32(v32->hdr, "__ftr_fixup", &size32); 581 start32 = find_section32(v32->hdr, "__ftr_fixup", &size32);
@@ -585,6 +590,11 @@ static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
585 start32, start32 + size32); 590 start32, start32 + size32);
586#endif /* CONFIG_PPC64 */ 591#endif /* CONFIG_PPC64 */
587 592
593 start32 = find_section32(v32->hdr, "__lwsync_fixup", &size32);
594 if (start32)
595 do_lwsync_fixups(cur_cpu_spec->cpu_features,
596 start32, start32 + size32);
597
588 return 0; 598 return 0;
589} 599}
590 600
diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S
index 271793577cdc..be3b6a41dc09 100644
--- a/arch/powerpc/kernel/vdso32/vdso32.lds.S
+++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S
@@ -33,6 +33,9 @@ SECTIONS
33 . = ALIGN(8); 33 . = ALIGN(8);
34 __ftr_fixup : { *(__ftr_fixup) } 34 __ftr_fixup : { *(__ftr_fixup) }
35 35
36 . = ALIGN(8);
37 __lwsync_fixup : { *(__lwsync_fixup) }
38
36#ifdef CONFIG_PPC64 39#ifdef CONFIG_PPC64
37 . = ALIGN(8); 40 . = ALIGN(8);
38 __fw_ftr_fixup : { *(__fw_ftr_fixup) } 41 __fw_ftr_fixup : { *(__fw_ftr_fixup) }
diff --git a/arch/powerpc/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S
index e608d1bd3bff..d0b2526dd38d 100644
--- a/arch/powerpc/kernel/vdso64/vdso64.lds.S
+++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S
@@ -35,6 +35,9 @@ SECTIONS
35 __ftr_fixup : { *(__ftr_fixup) } 35 __ftr_fixup : { *(__ftr_fixup) }
36 36
37 . = ALIGN(8); 37 . = ALIGN(8);
38 __lwsync_fixup : { *(__lwsync_fixup) }
39
40 . = ALIGN(8);
38 __fw_ftr_fixup : { *(__fw_ftr_fixup) } 41 __fw_ftr_fixup : { *(__fw_ftr_fixup) }
39 42
40 /* 43 /*
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 3c07811989fc..6856f6c15727 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -127,6 +127,12 @@ SECTIONS
127 *(__ftr_fixup) 127 *(__ftr_fixup)
128 __stop___ftr_fixup = .; 128 __stop___ftr_fixup = .;
129 } 129 }
130 . = ALIGN(8);
131 __lwsync_fixup : AT(ADDR(__lwsync_fixup) - LOAD_OFFSET) {
132 __start___lwsync_fixup = .;
133 *(__lwsync_fixup)
134 __stop___lwsync_fixup = .;
135 }
130#ifdef CONFIG_PPC64 136#ifdef CONFIG_PPC64
131 . = ALIGN(8); 137 . = ALIGN(8);
132 __fw_ftr_fixup : AT(ADDR(__fw_ftr_fixup) - LOAD_OFFSET) { 138 __fw_ftr_fixup : AT(ADDR(__fw_ftr_fixup) - LOAD_OFFSET) {
diff --git a/arch/powerpc/lib/feature-fixups-test.S b/arch/powerpc/lib/feature-fixups-test.S
index 0549be04399c..cb737484c5aa 100644
--- a/arch/powerpc/lib/feature-fixups-test.S
+++ b/arch/powerpc/lib/feature-fixups-test.S
@@ -10,6 +10,7 @@
10 10
11#include <asm/feature-fixups.h> 11#include <asm/feature-fixups.h>
12#include <asm/ppc_asm.h> 12#include <asm/ppc_asm.h>
13#include <asm/synch.h>
13 14
14 .text 15 .text
15 16
@@ -725,3 +726,17 @@ MAKE_MACRO_TEST_EXPECTED(FTR);
725MAKE_MACRO_TEST(FW_FTR); 726MAKE_MACRO_TEST(FW_FTR);
726MAKE_MACRO_TEST_EXPECTED(FW_FTR); 727MAKE_MACRO_TEST_EXPECTED(FW_FTR);
727#endif 728#endif
729
730globl(lwsync_fixup_test)
7311: or 1,1,1
732 LWSYNC
733globl(end_lwsync_fixup_test)
734
735globl(lwsync_fixup_test_expected_LWSYNC)
7361: or 1,1,1
737 lwsync
738
739globl(lwsync_fixup_test_expected_SYNC)
7401: or 1,1,1
741 sync
742
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 48e1ed89052d..4e43702b9813 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -110,6 +110,22 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
110 } 110 }
111} 111}
112 112
113void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
114{
115 unsigned int *start, *end, *dest;
116
117 if (!(value & CPU_FTR_LWSYNC))
118 return ;
119
120 start = fixup_start;
121 end = fixup_end;
122
123 for (; start < end; start++) {
124 dest = (void *)start + *start;
125 patch_instruction(dest, PPC_LWSYNC_INSTR);
126 }
127}
128
113#ifdef CONFIG_FTR_FIXUP_SELFTEST 129#ifdef CONFIG_FTR_FIXUP_SELFTEST
114 130
115#define check(x) \ 131#define check(x) \
@@ -295,6 +311,25 @@ static void test_fw_macros(void)
295#endif 311#endif
296} 312}
297 313
314static void test_lwsync_macros(void)
315{
316 extern void lwsync_fixup_test;
317 extern void end_lwsync_fixup_test;
318 extern void lwsync_fixup_test_expected_LWSYNC;
319 extern void lwsync_fixup_test_expected_SYNC;
320 unsigned long size = &end_lwsync_fixup_test -
321 &lwsync_fixup_test;
322
323 /* The fixups have already been done for us during boot */
324 if (cur_cpu_spec->cpu_features & CPU_FTR_LWSYNC) {
325 check(memcmp(&lwsync_fixup_test,
326 &lwsync_fixup_test_expected_LWSYNC, size) == 0);
327 } else {
328 check(memcmp(&lwsync_fixup_test,
329 &lwsync_fixup_test_expected_SYNC, size) == 0);
330 }
331}
332
298static int __init test_feature_fixups(void) 333static int __init test_feature_fixups(void)
299{ 334{
300 printk(KERN_DEBUG "Running feature fixup self-tests ...\n"); 335 printk(KERN_DEBUG "Running feature fixup self-tests ...\n");
@@ -307,6 +342,7 @@ static int __init test_feature_fixups(void)
307 test_alternative_case_with_external_branch(); 342 test_alternative_case_with_external_branch();
308 test_cpu_macros(); 343 test_cpu_macros();
309 test_fw_macros(); 344 test_fw_macros();
345 test_lwsync_macros();
310 346
311 return 0; 347 return 0;
312} 348}