Commit 0b64120c authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parent 3e37fd31
...@@ -42,6 +42,9 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, ...@@ -42,6 +42,9 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
extern void fpload(unsigned long *fpregs, unsigned long *fsr); extern void fpload(unsigned long *fpregs, unsigned long *fsr);
#else /* CONFIG_SPARC32 */ #else /* CONFIG_SPARC32 */
#include <asm/trap_block.h>
struct popc_3insn_patch_entry { struct popc_3insn_patch_entry {
unsigned int addr; unsigned int addr;
unsigned int insns[3]; unsigned int insns[3];
...@@ -57,6 +60,10 @@ extern struct popc_6insn_patch_entry __popc_6insn_patch, ...@@ -57,6 +60,10 @@ extern struct popc_6insn_patch_entry __popc_6insn_patch,
__popc_6insn_patch_end; __popc_6insn_patch_end;
extern void __init per_cpu_patch(void); 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 sun4v_patch(void);
extern void __init boot_cpu_id_too_large(int cpu); extern void __init boot_cpu_id_too_large(int cpu);
extern unsigned int dcache_parity_tl1_occurred; extern unsigned int dcache_parity_tl1_occurred;
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/spitfire.h> #include <asm/spitfire.h>
#include "entry.h"
#ifdef CONFIG_SPARC64 #ifdef CONFIG_SPARC64
#include <linux/jump_label.h> #include <linux/jump_label.h>
...@@ -203,6 +205,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs, ...@@ -203,6 +205,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
} }
#ifdef CONFIG_SPARC64 #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, int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs, const Elf_Shdr *sechdrs,
struct module *me) struct module *me)
...@@ -210,6 +235,8 @@ int module_finalize(const Elf_Ehdr *hdr, ...@@ -210,6 +235,8 @@ int module_finalize(const Elf_Ehdr *hdr,
/* make jump label nops */ /* make jump label nops */
jump_label_apply_nops(me); jump_label_apply_nops(me);
do_patch_sections(hdr, sechdrs);
/* Cheetah's I-cache is fully coherent. */ /* Cheetah's I-cache is fully coherent. */
if (tlb_type == spitfire) { if (tlb_type == spitfire) {
unsigned long va; unsigned long va;
......
...@@ -234,40 +234,50 @@ void __init per_cpu_patch(void) ...@@ -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); while (start < end) {
struct sun4v_1insn_patch_entry *p1; unsigned long addr = start->addr;
struct sun4v_2insn_patch_entry *p2;
if (tlb_type != hypervisor)
return;
p1 = &__sun4v_1insn_patch; *(unsigned int *) (addr + 0) = start->insn;
while (p1 < &__sun4v_1insn_patch_end) {
unsigned long addr = p1->addr;
*(unsigned int *) (addr + 0) = p1->insn;
wmb(); wmb();
__asm__ __volatile__("flush %0" : : "r" (addr + 0)); __asm__ __volatile__("flush %0" : : "r" (addr + 0));
p1++; start++;
} }
}
p2 = &__sun4v_2insn_patch; void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
while (p2 < &__sun4v_2insn_patch_end) { struct sun4v_2insn_patch_entry *end)
unsigned long addr = p2->addr; {
while (start < end) {
unsigned long addr = start->addr;
*(unsigned int *) (addr + 0) = p2->insns[0]; *(unsigned int *) (addr + 0) = start->insns[0];
wmb(); wmb();
__asm__ __volatile__("flush %0" : : "r" (addr + 0)); __asm__ __volatile__("flush %0" : : "r" (addr + 0));
*(unsigned int *) (addr + 4) = p2->insns[1]; *(unsigned int *) (addr + 4) = start->insns[1];
wmb(); wmb();
__asm__ __volatile__("flush %0" : : "r" (addr + 4)); __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(); sun4v_hvapi_init();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment