diff options
Diffstat (limited to 'arch/mips/kernel')
28 files changed, 1921 insertions, 1217 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 1c1b71752c84..26c6175e1379 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o obj-$(CONFIG_SYNC_R4K) += sync-r4k.o +obj-$(CONFIG_DEBUG_FS) += segment.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_MODULES) += mips_ksyms.o module.o obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o @@ -55,7 +56,11 @@ obj-$(CONFIG_MIPS_CMP) += smp-cmp.o obj-$(CONFIG_CPU_MIPSR2) += spram.o obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o +obj-$(CONFIG_MIPS_VPE_LOADER_CMP) += vpe-cmp.o +obj-$(CONFIG_MIPS_VPE_LOADER_MT) += vpe-mt.o obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o +obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o +obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o obj-$(CONFIG_I8259) += i8259.o obj-$(CONFIG_IRQ_CPU) += irq_cpu.o diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 202e581e6096..7faf5f2bee25 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -28,6 +28,18 @@ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; /* + * In order to be sure that we don't attempt to execute an O32 binary which + * requires 64 bit FP (FR=1) on a system which does not support it we refuse + * to execute any binary which has bits specified by the following macro set + * in its ELF header flags. + */ +#ifdef CONFIG_MIPS_O32_FP64_SUPPORT +# define __MIPS_O32_FP64_MUST_BE_ZERO 0 +#else +# define __MIPS_O32_FP64_MUST_BE_ZERO EF_MIPS_FP64 +#endif + +/* * This is used to ensure we don't load something for the wrong architecture. */ #define elf_check_arch(hdr) \ @@ -44,6 +56,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; if (((__h->e_flags & EF_MIPS_ABI) != 0) && \ ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32)) \ __res = 0; \ + if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO) \ + __res = 0; \ \ __res; \ }) diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S index bd79c4f9bff4..a5bf73d22fcc 100644 --- a/arch/mips/kernel/bmips_vec.S +++ b/arch/mips/kernel/bmips_vec.S @@ -8,11 +8,11 @@ * Reset/NMI/re-entry vectors for BMIPS processors */ -#include <linux/init.h> #include <asm/asm.h> #include <asm/asmmacro.h> #include <asm/cacheops.h> +#include <asm/cpu.h> #include <asm/regdef.h> #include <asm/mipsregs.h> #include <asm/stackframe.h> @@ -91,12 +91,18 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp) beqz k0, bmips_smp_entry #if defined(CONFIG_CPU_BMIPS5000) + mfc0 k0, CP0_PRID + li k1, PRID_IMP_BMIPS5000 + andi k0, 0xff00 + bne k0, k1, 1f + /* if we're not on core 0, this must be the SMP boot signal */ li k1, (3 << 25) mfc0 k0, $22 and k0, k1 bnez k0, bmips_smp_entry -#endif +1: +#endif /* CONFIG_CPU_BMIPS5000 */ #endif /* CONFIG_SMP */ /* nope, it's just a regular NMI */ @@ -139,7 +145,12 @@ bmips_smp_entry: xori k0, 0x04 mtc0 k0, CP0_CONFIG + mfc0 k0, CP0_PRID + andi k0, 0xff00 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) + li k1, PRID_IMP_BMIPS43XX + bne k0, k1, 2f + /* initialize CPU1's local I-cache */ li k0, 0x80000000 li k1, 0x80010000 @@ -150,14 +161,21 @@ bmips_smp_entry: 1: cache Index_Store_Tag_I, 0(k0) addiu k0, 16 bne k0, k1, 1b -#elif defined(CONFIG_CPU_BMIPS5000) + + b 3f +2: +#endif /* CONFIG_CPU_BMIPS4350 || CONFIG_CPU_BMIPS4380 */ +#if defined(CONFIG_CPU_BMIPS5000) /* set exception vector base */ + li k1, PRID_IMP_BMIPS5000 + bne k0, k1, 3f + la k0, ebase lw k0, 0(k0) mtc0 k0, $15, 1 BARRIER -#endif - +#endif /* CONFIG_CPU_BMIPS5000 */ +3: /* jump back to kseg0 in case we need to remap the kseg1 area */ la k0, 1f jr k0 @@ -221,8 +239,18 @@ END(bmips_smp_int_vec) LEAF(bmips_enable_xks01) #if defined(CONFIG_XKS01) - + mfc0 t0, CP0_PRID + andi t2, t0, 0xff00 #if defined(CONFIG_CPU_BMIPS4380) + li t1, PRID_IMP_BMIPS43XX + bne t2, t1, 1f + + andi t0, 0xff + addiu t1, t0, -PRID_REV_BMIPS4380_HI + bgtz t1, 2f + addiu t0, -PRID_REV_BMIPS4380_LO + bltz t0, 2f + mfc0 t0, $22, 3 li t1, 0x1ff0 li t2, (1 << 12) | (1 << 9) @@ -231,7 +259,13 @@ LEAF(bmips_enable_xks01) or t0, t2 mtc0 t0, $22, 3 BARRIER -#elif defined(CONFIG_CPU_BMIPS5000) + b 2f +1: +#endif /* CONFIG_CPU_BMIPS4380 */ +#if defined(CONFIG_CPU_BMIPS5000) + li t1, PRID_IMP_BMIPS5000 + bne t2, t1, 2f + mfc0 t0, $22, 5 li t1, 0x01ff li t2, (1 << 8) | (1 << 5) @@ -240,12 +274,8 @@ LEAF(bmips_enable_xks01) or t0, t2 mtc0 t0, $22, 5 BARRIER -#else - -#error Missing XKS01 setup - -#endif - +#endif /* CONFIG_CPU_BMIPS5000 */ +2: #endif /* defined(CONFIG_XKS01) */ jr ra diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index c814287bdf5d..530f832de02c 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -112,7 +112,7 @@ static inline unsigned long cpu_get_fpu_id(void) unsigned long tmp, fpu_id; tmp = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); fpu_id = read_32bit_cp1_register(CP1_REVISION); write_c0_status(tmp); return fpu_id; @@ -163,6 +163,25 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa) static char unknown_isa[] = KERN_ERR \ "Unsupported ISA type, c0.config0: %d."; +static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) +{ + unsigned int config6; + /* + * Config6 is implementation dependent and it's currently only + * used by proAptiv + */ + if (c->cputype == CPU_PROAPTIV) { + config6 = read_c0_config6(); + if (enable) + /* Enable FTLB */ + write_c0_config6(config6 | MIPS_CONF6_FTLBEN); + else + /* Disable FTLB */ + write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); + back_to_back_c0_hazard(); + } +} + static inline unsigned int decode_config0(struct cpuinfo_mips *c) { unsigned int config0; @@ -170,8 +189,13 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c) config0 = read_c0_config(); - if (((config0 & MIPS_CONF_MT) >> 7) == 1) + /* + * Look for Standard TLB or Dual VTLB and FTLB + */ + if ((((config0 & MIPS_CONF_MT) >> 7) == 1) || + (((config0 & MIPS_CONF_MT) >> 7) == 4)) c->options |= MIPS_CPU_TLB; + isa = (config0 & MIPS_CONF_AT) >> 13; switch (isa) { case 0: @@ -226,8 +250,11 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c) c->options |= MIPS_CPU_FPU; c->options |= MIPS_CPU_32FPR; } - if (cpu_has_tlb) + if (cpu_has_tlb) { c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1; + c->tlbsizevtlb = c->tlbsize; + c->tlbsizeftlbsets = 0; + } return config1 & MIPS_CONF_M; } @@ -272,6 +299,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->options |= MIPS_CPU_MICROMIPS; if (config3 & MIPS_CONF3_VZ) c->ases |= MIPS_ASE_VZ; + if (config3 & MIPS_CONF3_SC) + c->options |= MIPS_CPU_SEGMENTS; return config3 & MIPS_CONF_M; } @@ -279,12 +308,51 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) static inline unsigned int decode_config4(struct cpuinfo_mips *c) { unsigned int config4; + unsigned int newcf4; + unsigned int mmuextdef; + unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE; config4 = read_c0_config4(); - if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT - && cpu_has_tlb) - c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; + if (cpu_has_tlb) { + if (((config4 & MIPS_CONF4_IE) >> 29) == 2) + c->options |= MIPS_CPU_TLBINV; + mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; + switch (mmuextdef) { + case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT: + c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; + c->tlbsizevtlb = c->tlbsize; + break; + case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT: + c->tlbsizevtlb += + ((config4 & MIPS_CONF4_VTLBSIZEEXT) >> + MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40; + c->tlbsize = c->tlbsizevtlb; + ftlb_page = MIPS_CONF4_VFTLBPAGESIZE; + /* fall through */ + case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT: + newcf4 = (config4 & ~ftlb_page) | + (page_size_ftlb(mmuextdef) << + MIPS_CONF4_FTLBPAGESIZE_SHIFT); + write_c0_config4(newcf4); + back_to_back_c0_hazard(); + config4 = read_c0_config4(); + if (config4 != newcf4) { + pr_err("PAGE_SIZE 0x%lx is not supported by FTLB (config4=0x%x)\n", + PAGE_SIZE, config4); + /* Switch FTLB off */ + set_ftlb_enable(c, 0); + break; + } + c->tlbsizeftlbsets = 1 << + ((config4 & MIPS_CONF4_FTLBSETS) >> + MIPS_CONF4_FTLBSETS_SHIFT); + c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >> + MIPS_CONF4_FTLBWAYS_SHIFT) + 2; + c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets; + break; + } + } c->kscratch_mask = (config4 >> 16) & 0xff; @@ -312,6 +380,9 @@ static void decode_configs(struct cpuinfo_mips *c) c->scache.flags = MIPS_CACHE_NOT_PRESENT; + /* Enable FTLB if present */ + set_ftlb_enable(c, 1); + ok = decode_config0(c); /* Read Config registers. */ BUG_ON(!ok); /* Arch spec violation! */ if (ok) @@ -675,7 +746,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) { - decode_configs(c); switch (c->processor_id & PRID_IMP_MASK) { case PRID_IMP_4KC: c->cputype = CPU_4KC; @@ -739,8 +809,26 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_74K; __cpu_name[cpu] = "MIPS 1074Kc"; break; + case PRID_IMP_INTERAPTIV_UP: + c->cputype = CPU_INTERAPTIV; + __cpu_name[cpu] = "MIPS interAptiv"; + break; + case PRID_IMP_INTERAPTIV_MP: + c->cputype = CPU_INTERAPTIV; + __cpu_name[cpu] = "MIPS interAptiv (multi)"; + break; + case PRID_IMP_PROAPTIV_UP: + c->cputype = CPU_PROAPTIV; + __cpu_name[cpu] = "MIPS proAptiv"; + break; + case PRID_IMP_PROAPTIV_MP: + c->cputype = CPU_PROAPTIV; + __cpu_name[cpu] = "MIPS proAptiv (multi)"; + break; } + decode_configs(c); + spram_config(); } @@ -943,6 +1031,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) switch (c->processor_id & PRID_IMP_MASK) { case PRID_IMP_NETLOGIC_XLP2XX: + case PRID_IMP_NETLOGIC_XLP9XX: c->cputype = CPU_XLP; __cpu_name[cpu] = "Broadcom XLPII"; break; diff --git a/arch/mips/kernel/crash.c b/arch/mips/kernel/crash.c index 93aa302948d7..d21264681e97 100644 --- a/arch/mips/kernel/crash.c +++ b/arch/mips/kernel/crash.c @@ -5,7 +5,6 @@ #include <linux/bootmem.h> #include <linux/crash_dump.h> #include <linux/delay.h> -#include <linux/init.h> #include <linux/irq.h> #include <linux/types.h> #include <linux/sched.h> diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 47d7583cd67f..d84f6a509502 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -476,6 +476,7 @@ NESTED(nmi_handler, PT_SIZE, sp) BUILD_HANDLER ov ov sti silent /* #12 */ BUILD_HANDLER tr tr sti silent /* #13 */ BUILD_HANDLER fpe fpe fpe silent /* #15 */ + BUILD_HANDLER ftlb ftlb none silent /* #16 */ BUILD_HANDLER mdmx mdmx sti silent /* #22 */ #ifdef CONFIG_HARDWARE_WATCHPOINTS /* diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index f7991d95bff9..3553243bf9d6 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -184,6 +184,8 @@ void __init check_wait(void) case CPU_24K: case CPU_34K: case CPU_1004K: + case CPU_INTERAPTIV: + case CPU_PROAPTIV: cpu_wait = r4k_wait; if (read_c0_config7() & MIPS_CONF7_WII) cpu_wait = r4k_wait_irqoff; diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 8c58d8a84bf3..00d20974b3e7 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -65,26 +65,25 @@ static int show_cpuinfo(struct seq_file *m, void *v) cpu_data[n].watch_reg_masks[i]); seq_printf(m, "]\n"); } - if (cpu_has_mips_r) { - seq_printf(m, "isa\t\t\t: mips1"); - if (cpu_has_mips_2) - seq_printf(m, "%s", " mips2"); - if (cpu_has_mips_3) - seq_printf(m, "%s", " mips3"); - if (cpu_has_mips_4) - seq_printf(m, "%s", " mips4"); - if (cpu_has_mips_5) - seq_printf(m, "%s", " mips5"); - if (cpu_has_mips32r1) - seq_printf(m, "%s", " mips32r1"); - if (cpu_has_mips32r2) - seq_printf(m, "%s", " mips32r2"); - if (cpu_has_mips64r1) - seq_printf(m, "%s", " mips64r1"); - if (cpu_has_mips64r2) - seq_printf(m, "%s", " mips64r2"); - seq_printf(m, "\n"); - } + + seq_printf(m, "isa\t\t\t: mips1"); + if (cpu_has_mips_2) + seq_printf(m, "%s", " mips2"); + if (cpu_has_mips_3) + seq_printf(m, "%s", " mips3"); + if (cpu_has_mips_4) + seq_printf(m, "%s", " mips4"); + if (cpu_has_mips_5) + seq_printf(m, "%s", " mips5"); + if (cpu_has_mips32r1) + seq_printf(m, "%s", " mips32r1"); + if (cpu_has_mips32r2) + seq_printf(m, "%s", " mips32r2"); + if (cpu_has_mips64r1) + seq_printf(m, "%s", " mips64r1"); + if (cpu_has_mips64r2) + seq_printf(m, "%s", " mips64r2"); + seq_printf(m, "\n"); seq_printf(m, "ASEs implemented\t:"); if (cpu_has_mips16) seq_printf(m, "%s", " mips16"); @@ -107,7 +106,14 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "kscratch registers\t: %d\n", hweight8(cpu_data[n].kscratch_mask)); seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); - +#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) + if (cpu_has_mipsmt) { + seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id); +#if defined(CONFIG_MIPS_MT_SMTC) + seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id); +#endif + } +#endif sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", cpu_has_vce ? "%u" : "not available"); seq_printf(m, fmt, 'D', vced_count); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index ddc76103e78c..6ae540e133b2 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -60,15 +60,11 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) /* New thread loses kernel privileges. */ status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK); -#ifdef CONFIG_64BIT - status |= test_thread_flag(TIF_32BIT_REGS) ? 0 : ST0_FR; -#endif status |= KU_USER; regs->cp0_status = status; clear_used_math(); clear_fpu_owner(); - if (cpu_has_dsp) - __init_dsp(); + init_dsp(); regs->cp0_epc = pc; regs->regs[29] = sp; } diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index b52e1d2b33e0..7da9b76db4d9 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -137,13 +137,13 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data) if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); write_c0_status(flags); evpe(vpflags); } else { flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); write_c0_status(flags); } @@ -408,6 +408,7 @@ long arch_ptrace(struct task_struct *child, long request, /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { struct pt_regs *regs; + fpureg_t *fregs; unsigned long tmp = 0; regs = task_pt_regs(child); @@ -418,26 +419,28 @@ long arch_ptrace(struct task_struct *child, long request, tmp = regs->regs[addr]; break; case FPR_BASE ... FPR_BASE + 31: - if (tsk_used_math(child)) { - fpureg_t *fregs = get_fpu_regs(child); + if (!tsk_used_math(child)) { + /* FP not yet used */ + tmp = -1; + break; + } + fregs = get_fpu_regs(child); #ifdef CONFIG_32BIT + if (test_thread_flag(TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even * registers - unless we're using r2k_switch.S. */ if (addr & 1) - tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32); + tmp = fregs[(addr & ~1) - 32] >> 32; else - tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff); -#endif -#ifdef CONFIG_64BIT - tmp = fregs[addr - FPR_BASE]; -#endif - } else { - tmp = -1; /* FP not yet used */ + tmp = fregs[addr - 32]; + break; } +#endif + tmp = fregs[addr - FPR_BASE]; break; case PC: tmp = regs->cp0_epc; @@ -483,13 +486,13 @@ long arch_ptrace(struct task_struct *child, long request, if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); write_c0_status(flags); evpe(vpflags); } else { flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); write_c0_status(flags); } @@ -554,22 +557,25 @@ long arch_ptrace(struct task_struct *child, long request, child->thread.fpu.fcr31 = 0; } #ifdef CONFIG_32BIT - /* - * The odd registers are actually the high order bits - * of the values stored in the even registers - unless - * we're using r2k_switch.S. - */ - if (addr & 1) { - fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff; - fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32; - } else { - fregs[addr - FPR_BASE] &= ~0xffffffffLL; - fregs[addr - FPR_BASE] |= data; + if (test_thread_flag(TIF_32BIT_FPREGS)) { + /* + * The odd registers are actually the high + * order bits of the values stored in the even + * registers - unless we're using r2k_switch.S. + */ + if (addr & 1) { + fregs[(addr & ~1) - FPR_BASE] &= + 0xffffffff; + fregs[(addr & ~1) - FPR_BASE] |= + ((u64)data) << 32; + } else { + fregs[addr - FPR_BASE] &= ~0xffffffffLL; + fregs[addr - FPR_BASE] |= data; + } + break; } #endif -#ifdef CONFIG_64BIT fregs[addr - FPR_BASE] = data; -#endif break; } case PC: diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 9486055ba660..b8aa2dd5b00b 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -80,6 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { struct pt_regs *regs; + fpureg_t *fregs; unsigned int tmp; regs = task_pt_regs(child); @@ -90,21 +91,25 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, tmp = regs->regs[addr]; break; case FPR_BASE ... FPR_BASE + 31: - if (tsk_used_math(child)) { - fpureg_t *fregs = get_fpu_regs(child); - + if (!tsk_used_math(child)) { + /* FP not yet used */ + tmp = -1; + break; + } + fregs = get_fpu_regs(child); + if (test_thread_flag(TIF_32BIT_FPREGS)) { /* * The odd registers are actually the high * order bits of the values stored in the even * registers - unless we're using r2k_switch.S. */ if (addr & 1) - tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32); + tmp = fregs[(addr & ~1) - 32] >> 32; else - tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff); - } else { - tmp = -1; /* FP not yet used */ + tmp = fregs[addr - 32]; + break; } + tmp = fregs[addr - FPR_BASE]; break; case PC: tmp = regs->cp0_epc; @@ -147,13 +152,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); write_c0_status(flags); evpe(vpflags); } else { flags = read_c0_status(); - __enable_fpu(); + __enable_fpu(FPU_AS_IS); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); write_c0_status(flags); } @@ -236,20 +241,24 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, sizeof(child->thread.fpu)); child->thread.fpu.fcr31 = 0; } - /* - * The odd registers are actually the high order bits - * of the values stored in the even registers - unless - * we're using r2k_switch.S. - */ - if (addr & 1) { - fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff; - fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32; - } else { - fregs[addr - FPR_BASE] &= ~0xffffffffLL; - /* Must cast, lest sign extension fill upper - bits! */ - fregs[addr - FPR_BASE] |= (unsigned int)data; + if (test_thread_flag(TIF_32BIT_FPREGS)) { + /* + * The odd registers are actually the high + * order bits of the values stored in the even + * registers - unless we're using r2k_switch.S. + */ + if (addr & 1) { + fregs[(addr & ~1) - FPR_BASE] &= + 0xffffffff; + fregs[(addr & ~1) - FPR_BASE] |= + ((u64)data) << 32; + } else { + fregs[addr - FPR_BASE] &= ~0xffffffffLL; + fregs[addr - FPR_BASE] |= data; + } + break; } + fregs[addr - FPR_BASE] = data; break; } case PC: diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 55ffe149dae9..253b2fb52026 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -35,7 +35,15 @@ LEAF(_save_fp_context) cfc1 t1, fcr31 -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2) + .set push +#ifdef CONFIG_MIPS32_R2 + .set mips64r2 + mfc0 t0, CP0_STATUS + sll t0, t0, 5 + bgez t0, 1f # skip storing odd if FR=0 + nop +#endif /* Store the 16 odd double precision registers */ EX sdc1 $f1, SC_FPREGS+8(a0) EX sdc1 $f3, SC_FPREGS+24(a0) @@ -53,6 +61,7 @@ LEAF(_save_fp_context) EX sdc1 $f27, SC_FPREGS+216(a0) EX sdc1 $f29, SC_FPREGS+232(a0) EX sdc1 $f31, SC_FPREGS+248(a0) +1: .set pop #endif /* Store the 16 even double precision registers */ @@ -82,7 +91,31 @@ LEAF(_save_fp_context) LEAF(_save_fp_context32) cfc1 t1, fcr31 - EX sdc1 $f0, SC32_FPREGS+0(a0) + mfc0 t0, CP0_STATUS + sll t0, t0, 5 + bgez t0, 1f # skip storing odd if FR=0 + nop + + /* Store the 16 odd double precision registers */ + EX sdc1 $f1, SC32_FPREGS+8(a0) + EX sdc1 $f3, SC32_FPREGS+24(a0) + EX sdc1 $f5, SC32_FPREGS+40(a0) + EX sdc1 $f7, SC32_FPREGS+56(a0) + EX sdc1 $f9, SC32_FPREGS+72(a0) + EX sdc1 $f11, SC32_FPREGS+88(a0) + EX sdc1 $f13, SC32_FPREGS+104(a0) + EX sdc1 $f15, SC32_FPREGS+120(a0) + EX sdc1 $f17, SC32_FPREGS+136(a0) + EX sdc1 $f19, SC32_FPREGS+152(a0) + EX sdc1 $f21, SC32_FPREGS+168(a0) + EX sdc1 $f23, SC32_FPREGS+184(a0) + EX sdc1 $f25, SC32_FPREGS+200(a0) + EX sdc1 $f27, SC32_FPREGS+216(a0) + EX sdc1 $f29, SC32_FPREGS+232(a0) + EX sdc1 $f31, SC32_FPREGS+248(a0) + + /* Store the 16 even double precision registers */ +1: EX sdc1 $f0, SC32_FPREGS+0(a0) EX sdc1 $f2, SC32_FPREGS+16(a0) EX sdc1 $f4, SC32_FPREGS+32(a0) EX sdc1 $f6, SC32_FPREGS+48(a0) @@ -114,7 +147,16 @@ LEAF(_save_fp_context32) */ LEAF(_restore_fp_context) EX lw t0, SC_FPC_CSR(a0) -#ifdef CONFIG_64BIT + +#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2) + .set push +#ifdef CONFIG_MIPS32_R2 + .set mips64r2 + mfc0 t0, CP0_STATUS + sll t0, t0, 5 + bgez t0, 1f # skip loading odd if FR=0 + nop +#endif EX ldc1 $f1, SC_FPREGS+8(a0) EX ldc1 $f3, SC_FPREGS+24(a0) EX ldc1 $f5, SC_FPREGS+40(a0) @@ -131,6 +173,7 @@ LEAF(_restore_fp_context) EX ldc1 $f27, SC_FPREGS+216(a0) EX ldc1 $f29, SC_FPREGS+232(a0) EX ldc1 $f31, SC_FPREGS+248(a0) +1: .set pop #endif EX ldc1 $f0, SC_FPREGS+0(a0) EX ldc1 $f2, SC_FPREGS+16(a0) @@ -157,7 +200,30 @@ LEAF(_restore_fp_context) LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ EX lw t0, SC32_FPC_CSR(a0) - EX ldc1 $f0, SC32_FPREGS+0(a0) + + mfc0 t0, CP0_STATUS + sll t0, t0, 5 + bgez t0, 1f # skip loading odd if FR=0 + nop + + EX ldc1 $f1, SC32_FPREGS+8(a0) + EX ldc1 $f3, SC32_FPREGS+24(a0) + EX ldc1 $f5, SC32_FPREGS+40(a0) + EX ldc1 $f7, SC32_FPREGS+56(a0) + EX ldc1 $f9, SC32_FPREGS+72(a0) + EX ldc1 $f11, SC32_FPREGS+88(a0) + EX ldc1 $f13, SC32_FPREGS+104(a0) + EX ldc1 $f15, SC32_FPREGS+120(a0) + EX ldc1 $f17, SC32_FPREGS+136(a0) + EX ldc1 $f19, SC32_FPREGS+152(a0) + EX ldc1 $f21, SC32_FPREGS+168(a0) + EX ldc1 $f23, SC32_FPREGS+184(a0) + EX ldc1 $f25, SC32_FPREGS+200(a0) + EX ldc1 $f27, SC32_FPREGS+216(a0) + EX ldc1 $f29, SC32_FPREGS+232(a0) + EX ldc1 $f31, SC32_FPREGS+248(a0) + +1: EX ldc1 $f0, SC32_FPREGS+0(a0) EX ldc1 $f2, SC32_FPREGS+16(a0) EX ldc1 $f4, SC32_FPREGS+32(a0) EX ldc1 $f6, SC32_FPREGS+48(a0) diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 078de5eaca8f..cc78dd9a17c7 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -123,7 +123,7 @@ * Save a thread's fp context. */ LEAF(_save_fp) -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) mfc0 t0, CP0_STATUS #endif fpu_save_double a0 t0 t1 # clobbers t1 @@ -134,7 +134,7 @@ LEAF(_save_fp) * Restore a thread's fp context. */ LEAF(_restore_fp) -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) mfc0 t0, CP0_STATUS #endif fpu_restore_double a0 t0 t1 # clobbers t1 @@ -228,6 +228,47 @@ LEAF(_init_fpu) mtc1 t1, $f29 mtc1 t1, $f30 mtc1 t1, $f31 + +#ifdef CONFIG_CPU_MIPS32_R2 + .set push + .set mips64r2 + sll t0, t0, 5 # is Status.FR set? + bgez t0, 1f # no: skip setting upper 32b + + mthc1 t1, $f0 + mthc1 t1, $f1 + mthc1 t1, $f2 + mthc1 t1, $f3 + mthc1 t1, $f4 + mthc1 t1, $f5 + mthc1 t1, $f6 + mthc1 t1, $f7 + mthc1 t1, $f8 + mthc1 t1, $f9 + mthc1 t1, $f10 + mthc1 t1, $f11 + mthc1 t1, $f12 + mthc1 t1, $f13 + mthc1 t1, $f14 + mthc1 t1, $f15 |
