Skip to content

Commit 2d1b202

Browse files
kumargalapaulusmack
authored andcommitted
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 <[email protected]> Signed-off-by: Paul Mackerras <[email protected]>
1 parent 5888da1 commit 2d1b202

File tree

13 files changed

+131
-26
lines changed

13 files changed

+131
-26
lines changed

arch/powerpc/kernel/module.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ int module_finalize(const Elf_Ehdr *hdr,
8686
(void *)sect->sh_addr + sect->sh_size);
8787
#endif
8888

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+
8995
return 0;
9096
}
9197

arch/powerpc/kernel/setup_32.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ unsigned long __init early_init(unsigned long dt_ptr)
101101
PTRRELOC(&__start___ftr_fixup),
102102
PTRRELOC(&__stop___ftr_fixup));
103103

104+
do_lwsync_fixups(spec->cpu_features,
105+
PTRRELOC(&__start___lwsync_fixup),
106+
PTRRELOC(&__stop___lwsync_fixup));
107+
104108
return KERNELBASE + offset;
105109
}
106110

arch/powerpc/kernel/setup_64.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ void __init setup_system(void)
363363
&__start___ftr_fixup, &__stop___ftr_fixup);
364364
do_feature_fixups(powerpc_firmware_features,
365365
&__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
366+
do_lwsync_fixups(cur_cpu_spec->cpu_features,
367+
&__start___lwsync_fixup, &__stop___lwsync_fixup);
366368

367369
/*
368370
* Unflatten the device-tree passed by prom_init or kexec

arch/powerpc/kernel/vdso.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,11 @@ static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
571571
if (start64)
572572
do_feature_fixups(powerpc_firmware_features,
573573
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);
574579
#endif /* CONFIG_PPC64 */
575580

576581
start32 = find_section32(v32->hdr, "__ftr_fixup", &size32);
@@ -585,6 +590,11 @@ static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
585590
start32, start32 + size32);
586591
#endif /* CONFIG_PPC64 */
587592

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+
588598
return 0;
589599
}
590600

arch/powerpc/kernel/vdso32/vdso32.lds.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ SECTIONS
3333
. = ALIGN(8);
3434
__ftr_fixup : { *(__ftr_fixup) }
3535

36+
. = ALIGN(8);
37+
__lwsync_fixup : { *(__lwsync_fixup) }
38+
3639
#ifdef CONFIG_PPC64
3740
. = ALIGN(8);
3841
__fw_ftr_fixup : { *(__fw_ftr_fixup) }

arch/powerpc/kernel/vdso64/vdso64.lds.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ SECTIONS
3434
. = ALIGN(8);
3535
__ftr_fixup : { *(__ftr_fixup) }
3636

37+
. = ALIGN(8);
38+
__lwsync_fixup : { *(__lwsync_fixup) }
39+
3740
. = ALIGN(8);
3841
__fw_ftr_fixup : { *(__fw_ftr_fixup) }
3942

arch/powerpc/kernel/vmlinux.lds.S

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ SECTIONS
127127
*(__ftr_fixup)
128128
__stop___ftr_fixup = .;
129129
}
130+
. = ALIGN(8);
131+
__lwsync_fixup : AT(ADDR(__lwsync_fixup) - LOAD_OFFSET) {
132+
__start___lwsync_fixup = .;
133+
*(__lwsync_fixup)
134+
__stop___lwsync_fixup = .;
135+
}
130136
#ifdef CONFIG_PPC64
131137
. = ALIGN(8);
132138
__fw_ftr_fixup : AT(ADDR(__fw_ftr_fixup) - LOAD_OFFSET) {

arch/powerpc/lib/feature-fixups-test.S

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <asm/feature-fixups.h>
1212
#include <asm/ppc_asm.h>
13+
#include <asm/synch.h>
1314

1415
.text
1516

@@ -725,3 +726,17 @@ MAKE_MACRO_TEST_EXPECTED(FTR);
725726
MAKE_MACRO_TEST(FW_FTR);
726727
MAKE_MACRO_TEST_EXPECTED(FW_FTR);
727728
#endif
729+
730+
globl(lwsync_fixup_test)
731+
1: or 1,1,1
732+
LWSYNC
733+
globl(end_lwsync_fixup_test)
734+
735+
globl(lwsync_fixup_test_expected_LWSYNC)
736+
1: or 1,1,1
737+
lwsync
738+
739+
globl(lwsync_fixup_test_expected_SYNC)
740+
1: or 1,1,1
741+
sync
742+

arch/powerpc/lib/feature-fixups.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,22 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
110110
}
111111
}
112112

113+
void 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+
113129
#ifdef CONFIG_FTR_FIXUP_SELFTEST
114130

115131
#define check(x) \
@@ -295,6 +311,25 @@ static void test_fw_macros(void)
295311
#endif
296312
}
297313

314+
static 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+
298333
static int __init test_feature_fixups(void)
299334
{
300335
printk(KERN_DEBUG "Running feature fixup self-tests ...\n");
@@ -307,6 +342,7 @@ static int __init test_feature_fixups(void)
307342
test_alternative_case_with_external_branch();
308343
test_cpu_macros();
309344
test_fw_macros();
345+
test_lwsync_macros();
310346

311347
return 0;
312348
}

include/asm-powerpc/code-patching.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
#include <asm/types.h>
1414

15-
#define PPC_NOP_INSTR 0x60000000
15+
#define PPC_NOP_INSTR 0x60000000
16+
#define PPC_LWSYNC_INSTR 0x7c2004ac
1617

1718
/* Flags for create_branch:
1819
* "b" == create_branch(addr, target, 0);

include/asm-powerpc/cputable.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
156156
#define CPU_FTR_UNIFIED_ID_CACHE ASM_CONST(0x0000000001000000)
157157
#define CPU_FTR_SPE ASM_CONST(0x0000000002000000)
158158
#define CPU_FTR_NEED_PAIRED_STWCX ASM_CONST(0x0000000004000000)
159+
#define CPU_FTR_LWSYNC ASM_CONST(0x0000000008000000)
159160

160161
/*
161162
* Add the 64-bit processor unique features in the top half of the word;
@@ -369,43 +370,43 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
369370
CPU_FTR_NODSISRALIGN)
370371
#define CPU_FTRS_E500MC (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
371372
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN | \
372-
CPU_FTR_L2CSR)
373+
CPU_FTR_L2CSR | CPU_FTR_LWSYNC)
373374
#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
374375

375376
/* 64-bit CPUs */
376-
#define CPU_FTRS_POWER3 (CPU_FTR_USE_TB | \
377+
#define CPU_FTRS_POWER3 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
377378
CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | CPU_FTR_PPC_LE)
378-
#define CPU_FTRS_RS64 (CPU_FTR_USE_TB | \
379+
#define CPU_FTRS_RS64 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
379380
CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | \
380381
CPU_FTR_MMCRA | CPU_FTR_CTRL)
381-
#define CPU_FTRS_POWER4 (CPU_FTR_USE_TB | \
382+
#define CPU_FTRS_POWER4 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
382383
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
383384
CPU_FTR_MMCRA)
384-
#define CPU_FTRS_PPC970 (CPU_FTR_USE_TB | \
385+
#define CPU_FTRS_PPC970 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
385386
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
386387
CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA)
387-
#define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | \
388+
#define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
388389
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
389390
CPU_FTR_MMCRA | CPU_FTR_SMT | \
390391
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
391392
CPU_FTR_PURR)
392-
#define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | \
393+
#define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
393394
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
394395
CPU_FTR_MMCRA | CPU_FTR_SMT | \
395396
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
396397
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
397398
CPU_FTR_DSCR)
398-
#define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | \
399+
#define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
399400
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
400401
CPU_FTR_MMCRA | CPU_FTR_SMT | \
401402
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
402403
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
403404
CPU_FTR_DSCR)
404-
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | \
405+
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
405406
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
406407
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
407408
CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
408-
#define CPU_FTRS_PA6T (CPU_FTR_USE_TB | \
409+
#define CPU_FTRS_PA6T (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
409410
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
410411
CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
411412
CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B)

include/asm-powerpc/feature-fixups.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,14 @@ label##5: \
113113

114114
#endif /* __ASSEMBLY__ */
115115

116+
/* LWSYNC feature sections */
117+
#define START_LWSYNC_SECTION(label) label##1:
118+
#define MAKE_LWSYNC_SECTION_ENTRY(label, sect) \
119+
label##2: \
120+
.pushsection sect,"a"; \
121+
.align 2; \
122+
label##3: \
123+
.long label##1b-label##3b; \
124+
.popsection;
125+
116126
#endif /* __ASM_POWERPC_FEATURE_FIXUPS_H */

include/asm-powerpc/synch.h

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,42 @@
33
#ifdef __KERNEL__
44

55
#include <linux/stringify.h>
6+
#include <asm/feature-fixups.h>
67

7-
#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
8-
#define __SUBARCH_HAS_LWSYNC
9-
#endif
8+
#ifndef __ASSEMBLY__
9+
extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
10+
extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
11+
void *fixup_end);
12+
13+
static inline void eieio(void)
14+
{
15+
__asm__ __volatile__ ("eieio" : : : "memory");
16+
}
17+
18+
static inline void isync(void)
19+
{
20+
__asm__ __volatile__ ("isync" : : : "memory");
21+
}
22+
#endif /* __ASSEMBLY__ */
1023

11-
#ifdef __SUBARCH_HAS_LWSYNC
24+
#if defined(__powerpc64__)
1225
# define LWSYNC lwsync
26+
#elif defined(CONFIG_E500)
27+
# define LWSYNC \
28+
START_LWSYNC_SECTION(96); \
29+
sync; \
30+
MAKE_LWSYNC_SECTION_ENTRY(96, __lwsync_fixup);
1331
#else
1432
# define LWSYNC sync
1533
#endif
1634

1735
#ifdef CONFIG_SMP
1836
#define ISYNC_ON_SMP "\n\tisync\n"
19-
#define LWSYNC_ON_SMP __stringify(LWSYNC) "\n"
37+
#define LWSYNC_ON_SMP stringify_in_c(LWSYNC) "\n"
2038
#else
2139
#define ISYNC_ON_SMP
2240
#define LWSYNC_ON_SMP
2341
#endif
2442

25-
static inline void eieio(void)
26-
{
27-
__asm__ __volatile__ ("eieio" : : : "memory");
28-
}
29-
30-
static inline void isync(void)
31-
{
32-
__asm__ __volatile__ ("isync" : : : "memory");
33-
}
34-
3543
#endif /* __KERNEL__ */
3644
#endif /* _ASM_POWERPC_SYNCH_H */

0 commit comments

Comments
 (0)