diff options
| -rw-r--r-- | arch/sparc/kernel/entry.h | 7 | ||||
| -rw-r--r-- | arch/sparc/kernel/module.c | 27 | ||||
| -rw-r--r-- | arch/sparc/kernel/setup_64.c | 48 |
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, | |||
| 42 | extern void fpload(unsigned long *fpregs, unsigned long *fsr); | 42 | extern 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 | |||
| 45 | struct popc_3insn_patch_entry { | 48 | struct 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 | ||
| 59 | extern void __init per_cpu_patch(void); | 62 | extern void __init per_cpu_patch(void); |
| 63 | extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, | ||
| 64 | struct sun4v_1insn_patch_entry *); | ||
| 65 | extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *, | ||
| 66 | struct sun4v_2insn_patch_entry *); | ||
| 60 | extern void __init sun4v_patch(void); | 67 | extern void __init sun4v_patch(void); |
| 61 | extern void __init boot_cpu_id_too_large(int cpu); | 68 | extern void __init boot_cpu_id_too_large(int cpu); |
| 62 | extern unsigned int dcache_parity_tl1_occurred; | 69 | extern 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 |
| 208 | static 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 | |||
| 206 | int module_finalize(const Elf_Ehdr *hdr, | 231 | int 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 | ||
| 237 | void __init sun4v_patch(void) | 237 | void 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; | 251 | void 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 | |||
| 269 | void __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 | } |
