aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-11-18 01:44:58 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-06 17:14:02 -0500
commitcff6d2096e9a57c2497dd5ee4aed3c97149bfc9e (patch)
treea269f55f7d1043b3cfbbde550e080982be5b8fad /arch/sparc
parentfde939495571ffd22458e94745b0c2e6af33478d (diff)
sparc64: Patch sun4v code sequences properly on module load.
[ Upstream commit 0b64120cceb86e93cb1bda0dc055f13016646907 ] Some of the sun4v code patching occurs in inline functions visible to, and usable by, modules. Therefore we have to patch them up during module load. Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/kernel/entry.h7
-rw-r--r--arch/sparc/kernel/module.c27
-rw-r--r--arch/sparc/kernel/setup_64.c48
3 files changed, 63 insertions, 19 deletions
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h
index e27f8ea8656..0c218e4c088 100644
--- a/arch/sparc/kernel/entry.h
+++ b/arch/sparc/kernel/entry.h
@@ -42,6 +42,9 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
42extern void fpload(unsigned long *fpregs, unsigned long *fsr); 42extern void fpload(unsigned long *fpregs, unsigned long *fsr);
43 43
44#else /* CONFIG_SPARC32 */ 44#else /* CONFIG_SPARC32 */
45
46#include <asm/trap_block.h>
47
45struct popc_3insn_patch_entry { 48struct popc_3insn_patch_entry {
46 unsigned int addr; 49 unsigned int addr;
47 unsigned int insns[3]; 50 unsigned int insns[3];
@@ -57,6 +60,10 @@ extern struct popc_6insn_patch_entry __popc_6insn_patch,
57 __popc_6insn_patch_end; 60 __popc_6insn_patch_end;
58 61
59extern void __init per_cpu_patch(void); 62extern void __init per_cpu_patch(void);
63extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *,
64 struct sun4v_1insn_patch_entry *);
65extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *,
66 struct sun4v_2insn_patch_entry *);
60extern void __init sun4v_patch(void); 67extern void __init sun4v_patch(void);
61extern void __init boot_cpu_id_too_large(int cpu); 68extern void __init boot_cpu_id_too_large(int cpu);
62extern unsigned int dcache_parity_tl1_occurred; 69extern unsigned int dcache_parity_tl1_occurred;
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index 99ba5baa949..8172c18d844 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -17,6 +17,8 @@
17#include <asm/processor.h> 17#include <asm/processor.h>
18#include <asm/spitfire.h> 18#include <asm/spitfire.h>
19 19
20#include "entry.h"
21
20#ifdef CONFIG_SPARC64 22#ifdef CONFIG_SPARC64
21 23
22#include <linux/jump_label.h> 24#include <linux/jump_label.h>
@@ -220,6 +222,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
220} 222}
221 223
222#ifdef CONFIG_SPARC64 224#ifdef CONFIG_SPARC64
225static void do_patch_sections(const Elf_Ehdr *hdr,
226 const Elf_Shdr *sechdrs)
227{
228 const Elf_Shdr *s, *sun4v_1insn = NULL, *sun4v_2insn = NULL;
229 char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
230
231 for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
232 if (!strcmp(".sun4v_1insn_patch", secstrings + s->sh_name))
233 sun4v_1insn = s;
234 if (!strcmp(".sun4v_2insn_patch", secstrings + s->sh_name))
235 sun4v_2insn = s;
236 }
237
238 if (sun4v_1insn && tlb_type == hypervisor) {
239 void *p = (void *) sun4v_1insn->sh_addr;
240 sun4v_patch_1insn_range(p, p + sun4v_1insn->sh_size);
241 }
242 if (sun4v_2insn && tlb_type == hypervisor) {
243 void *p = (void *) sun4v_2insn->sh_addr;
244 sun4v_patch_2insn_range(p, p + sun4v_2insn->sh_size);
245 }
246}
247
223int module_finalize(const Elf_Ehdr *hdr, 248int module_finalize(const Elf_Ehdr *hdr,
224 const Elf_Shdr *sechdrs, 249 const Elf_Shdr *sechdrs,
225 struct module *me) 250 struct module *me)
@@ -227,6 +252,8 @@ int module_finalize(const Elf_Ehdr *hdr,
227 /* make jump label nops */ 252 /* make jump label nops */
228 jump_label_apply_nops(me); 253 jump_label_apply_nops(me);
229 254
255 do_patch_sections(hdr, sechdrs);
256
230 /* Cheetah's I-cache is fully coherent. */ 257 /* Cheetah's I-cache is fully coherent. */
231 if (tlb_type == spitfire) { 258 if (tlb_type == spitfire) {
232 unsigned long va; 259 unsigned long va;
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 3c5bb784214..4e7d3ff0ccb 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -234,40 +234,50 @@ void __init per_cpu_patch(void)
234 } 234 }
235} 235}
236 236
237void __init sun4v_patch(void) 237void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *start,
238 struct sun4v_1insn_patch_entry *end)
238{ 239{
239 extern void sun4v_hvapi_init(void); 240 while (start < end) {
240 struct sun4v_1insn_patch_entry *p1; 241 unsigned long addr = start->addr;
241 struct sun4v_2insn_patch_entry *p2;
242
243 if (tlb_type != hypervisor)
244 return;
245 242
246 p1 = &__sun4v_1insn_patch; 243 *(unsigned int *) (addr + 0) = start->insn;
247 while (p1 < &__sun4v_1insn_patch_end) {
248 unsigned long addr = p1->addr;
249
250 *(unsigned int *) (addr + 0) = p1->insn;
251 wmb(); 244 wmb();
252 __asm__ __volatile__("flush %0" : : "r" (addr + 0)); 245 __asm__ __volatile__("flush %0" : : "r" (addr + 0));
253 246
254 p1++; 247 start++;
255 } 248 }
249}
256 250
257 p2 = &__sun4v_2insn_patch; 251void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
258 while (p2 < &__sun4v_2insn_patch_end) { 252 struct sun4v_2insn_patch_entry *end)
259 unsigned long addr = p2->addr; 253{
254 while (start < end) {
255 unsigned long addr = start->addr;
260 256
261 *(unsigned int *) (addr + 0) = p2->insns[0]; 257 *(unsigned int *) (addr + 0) = start->insns[0];
262 wmb(); 258 wmb();
263 __asm__ __volatile__("flush %0" : : "r" (addr + 0)); 259 __asm__ __volatile__("flush %0" : : "r" (addr + 0));
264 260
265 *(unsigned int *) (addr + 4) = p2->insns[1]; 261 *(unsigned int *) (addr + 4) = start->insns[1];
266 wmb(); 262 wmb();
267 __asm__ __volatile__("flush %0" : : "r" (addr + 4)); 263 __asm__ __volatile__("flush %0" : : "r" (addr + 4));
268 264
269 p2++; 265 start++;
270 } 266 }
267}
268
269void __init sun4v_patch(void)
270{
271 extern void sun4v_hvapi_init(void);
272
273 if (tlb_type != hypervisor)
274 return;
275
276 sun4v_patch_1insn_range(&__sun4v_1insn_patch,
277 &__sun4v_1insn_patch_end);
278
279 sun4v_patch_2insn_range(&__sun4v_2insn_patch,
280 &__sun4v_2insn_patch_end);
271 281
272 sun4v_hvapi_init(); 282 sun4v_hvapi_init();
273} 283}