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 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,  extern void fpload(unsigned long *fpregs, unsigned long *fsr);  #else /* CONFIG_SPARC32 */ + +#include <asm/trap_block.h> +  struct popc_3insn_patch_entry {  	unsigned int	addr;  	unsigned int	insns[3]; @@ -57,6 +60,10 @@ extern struct popc_6insn_patch_entry __popc_6insn_patch,  	__popc_6insn_patch_end;  extern void __init per_cpu_patch(void); +extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, +				    struct sun4v_1insn_patch_entry *); +extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *, +				    struct sun4v_2insn_patch_entry *);  extern void __init sun4v_patch(void);  extern void __init boot_cpu_id_too_large(int cpu);  extern unsigned int dcache_parity_tl1_occurred; diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index da0c6c70ccb..e5519870c3d 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -17,6 +17,8 @@  #include <asm/processor.h>  #include <asm/spitfire.h> +#include "entry.h" +  #ifdef CONFIG_SPARC64  #include <linux/jump_label.h> @@ -203,6 +205,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs,  }  #ifdef CONFIG_SPARC64 +static void do_patch_sections(const Elf_Ehdr *hdr, +			      const Elf_Shdr *sechdrs) +{ +	const Elf_Shdr *s, *sun4v_1insn = NULL, *sun4v_2insn = NULL; +	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + +	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { +		if (!strcmp(".sun4v_1insn_patch", secstrings + s->sh_name)) +			sun4v_1insn = s; +		if (!strcmp(".sun4v_2insn_patch", secstrings + s->sh_name)) +			sun4v_2insn = s; +	} + +	if (sun4v_1insn && tlb_type == hypervisor) { +		void *p = (void *) sun4v_1insn->sh_addr; +		sun4v_patch_1insn_range(p, p + sun4v_1insn->sh_size); +	} +	if (sun4v_2insn && tlb_type == hypervisor) { +		void *p = (void *) sun4v_2insn->sh_addr; +		sun4v_patch_2insn_range(p, p + sun4v_2insn->sh_size); +	} +} +  int module_finalize(const Elf_Ehdr *hdr,  		    const Elf_Shdr *sechdrs,  		    struct module *me) @@ -210,6 +235,8 @@ int module_finalize(const Elf_Ehdr *hdr,  	/* make jump label nops */  	jump_label_apply_nops(me); +	do_patch_sections(hdr, sechdrs); +  	/* Cheetah's I-cache is fully coherent.  */  	if (tlb_type == spitfire) {  		unsigned long va; diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index c965595aa7e..a854a1c240f 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)  	}  } -void __init sun4v_patch(void) +void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *start, +			     struct sun4v_1insn_patch_entry *end)  { -	extern void sun4v_hvapi_init(void); -	struct sun4v_1insn_patch_entry *p1; -	struct sun4v_2insn_patch_entry *p2; - -	if (tlb_type != hypervisor) -		return; +	while (start < end) { +		unsigned long addr = start->addr; -	p1 = &__sun4v_1insn_patch; -	while (p1 < &__sun4v_1insn_patch_end) { -		unsigned long addr = p1->addr; - -		*(unsigned int *) (addr +  0) = p1->insn; +		*(unsigned int *) (addr +  0) = start->insn;  		wmb();  		__asm__ __volatile__("flush	%0" : : "r" (addr +  0)); -		p1++; +		start++;  	} +} -	p2 = &__sun4v_2insn_patch; -	while (p2 < &__sun4v_2insn_patch_end) { -		unsigned long addr = p2->addr; +void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start, +			     struct sun4v_2insn_patch_entry *end) +{ +	while (start < end) { +		unsigned long addr = start->addr; -		*(unsigned int *) (addr +  0) = p2->insns[0]; +		*(unsigned int *) (addr +  0) = start->insns[0];  		wmb();  		__asm__ __volatile__("flush	%0" : : "r" (addr +  0)); -		*(unsigned int *) (addr +  4) = p2->insns[1]; +		*(unsigned int *) (addr +  4) = start->insns[1];  		wmb();  		__asm__ __volatile__("flush	%0" : : "r" (addr +  4)); -		p2++; +		start++;  	} +} + +void __init sun4v_patch(void) +{ +	extern void sun4v_hvapi_init(void); + +	if (tlb_type != hypervisor) +		return; + +	sun4v_patch_1insn_range(&__sun4v_1insn_patch, +				&__sun4v_1insn_patch_end); + +	sun4v_patch_2insn_range(&__sun4v_2insn_patch, +				&__sun4v_2insn_patch_end);  	sun4v_hvapi_init();  }  |