aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-11-18 01:44:58 -0500
committerDavid S. Miller <davem@davemloft.net>2011-11-18 01:44:58 -0500
commit0b64120cceb86e93cb1bda0dc055f13016646907 (patch)
tree5dcd3444fc219e5b9774734d846b655e0776575b /arch
parent3e37fd3153ac95088a74f5e7c569f7567e9f993a (diff)
sparc64: Patch sun4v code sequences properly on module load.
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>
Diffstat (limited to 'arch')
-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 e27f8ea8656e..0c218e4c0881 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 da0c6c70ccb2..e5519870c3d9 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>
@@ -203,6 +205,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
203} 205}
204 206
205#ifdef CONFIG_SPARC64 207#ifdef CONFIG_SPARC64
208static void do_patch_sections(const Elf_Ehdr *hdr,
209 const Elf_Shdr *sechdrs)
210{
211 const Elf_Shdr *s, *sun4v_1insn = NULL, *sun4v_2insn = NULL;
212 char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
213
214 for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
215 if (!strcmp(".sun4v_1insn_patch", secstrings + s->sh_name))
216 sun4v_1insn = s;
217 if (!strcmp(".sun4v_2insn_patch", secstrings + s->sh_name))
218 sun4v_2insn = s;
219 }
220
221 if (sun4v_1insn && tlb_type == hypervisor) {
222 void *p = (void *) sun4v_1insn->sh_addr;
223 sun4v_patch_1insn_range(p, p + sun4v_1insn->sh_size);
224 }
225 if (sun4v_2insn && tlb_type == hypervisor) {
226 void *p = (void *) sun4v_2insn->sh_addr;
227 sun4v_patch_2insn_range(p, p + sun4v_2insn->sh_size);
228 }
229}
230
206int module_finalize(const Elf_Ehdr *hdr, 231int module_finalize(const Elf_Ehdr *hdr,
207 const Elf_Shdr *sechdrs, 232 const Elf_Shdr *sechdrs,
208 struct module *me) 233 struct module *me)
@@ -210,6 +235,8 @@ int module_finalize(const Elf_Ehdr *hdr,
210 /* make jump label nops */ 235 /* make jump label nops */
211 jump_label_apply_nops(me); 236 jump_label_apply_nops(me);
212 237
238 do_patch_sections(hdr, sechdrs);
239
213 /* Cheetah's I-cache is fully coherent. */ 240 /* Cheetah's I-cache is fully coherent. */
214 if (tlb_type == spitfire) { 241 if (tlb_type == spitfire) {
215 unsigned long va; 242 unsigned long va;
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index c965595aa7e9..a854a1c240ff 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}