aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r--arch/mips/kernel/traps.c60
1 files changed, 54 insertions, 6 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index c3b41e24c05a..33984c04b60b 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -46,6 +46,7 @@
46#include <asm/fpu.h> 46#include <asm/fpu.h>
47#include <asm/fpu_emulator.h> 47#include <asm/fpu_emulator.h>
48#include <asm/idle.h> 48#include <asm/idle.h>
49#include <asm/mips-r2-to-r6-emul.h>
49#include <asm/mipsregs.h> 50#include <asm/mipsregs.h>
50#include <asm/mipsmtregs.h> 51#include <asm/mipsmtregs.h>
51#include <asm/module.h> 52#include <asm/module.h>
@@ -837,7 +838,7 @@ out:
837 exception_exit(prev_state); 838 exception_exit(prev_state);
838} 839}
839 840
840static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, 841void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
841 const char *str) 842 const char *str)
842{ 843{
843 siginfo_t info; 844 siginfo_t info;
@@ -1027,7 +1028,34 @@ asmlinkage void do_ri(struct pt_regs *regs)
1027 unsigned int opcode = 0; 1028 unsigned int opcode = 0;
1028 int status = -1; 1029 int status = -1;
1029 1030
1031 /*
1032 * Avoid any kernel code. Just emulate the R2 instruction
1033 * as quickly as possible.
1034 */
1035 if (mipsr2_emulation && cpu_has_mips_r6 &&
1036 likely(user_mode(regs))) {
1037 if (likely(get_user(opcode, epc) >= 0)) {
1038 status = mipsr2_decoder(regs, opcode);
1039 switch (status) {
1040 case 0:
1041 case SIGEMT:
1042 task_thread_info(current)->r2_emul_return = 1;
1043 return;
1044 case SIGILL:
1045 goto no_r2_instr;
1046 default:
1047 process_fpemu_return(status,
1048 &current->thread.cp0_baduaddr);
1049 task_thread_info(current)->r2_emul_return = 1;
1050 return;
1051 }
1052 }
1053 }
1054
1055no_r2_instr:
1056
1030 prev_state = exception_enter(); 1057 prev_state = exception_enter();
1058
1031 if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), 1059 if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs),
1032 SIGILL) == NOTIFY_STOP) 1060 SIGILL) == NOTIFY_STOP)
1033 goto out; 1061 goto out;
@@ -1134,10 +1162,29 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
1134 return NOTIFY_OK; 1162 return NOTIFY_OK;
1135} 1163}
1136 1164
1165static int wait_on_fp_mode_switch(atomic_t *p)
1166{
1167 /*
1168 * The FP mode for this task is currently being switched. That may
1169 * involve modifications to the format of this tasks FP context which
1170 * make it unsafe to proceed with execution for the moment. Instead,
1171 * schedule some other task.
1172 */
1173 schedule();
1174 return 0;
1175}
1176
1137static int enable_restore_fp_context(int msa) 1177static int enable_restore_fp_context(int msa)
1138{ 1178{
1139 int err, was_fpu_owner, prior_msa; 1179 int err, was_fpu_owner, prior_msa;
1140 1180
1181 /*
1182 * If an FP mode switch is currently underway, wait for it to
1183 * complete before proceeding.
1184 */
1185 wait_on_atomic_t(&current->mm->context.fp_mode_switching,
1186 wait_on_fp_mode_switch, TASK_KILLABLE);
1187
1141 if (!used_math()) { 1188 if (!used_math()) {
1142 /* First time FP context user. */ 1189 /* First time FP context user. */
1143 preempt_disable(); 1190 preempt_disable();
@@ -1541,6 +1588,7 @@ static inline void parity_protection_init(void)
1541 case CPU_INTERAPTIV: 1588 case CPU_INTERAPTIV:
1542 case CPU_PROAPTIV: 1589 case CPU_PROAPTIV:
1543 case CPU_P5600: 1590 case CPU_P5600:
1591 case CPU_QEMU_GENERIC:
1544 { 1592 {
1545#define ERRCTL_PE 0x80000000 1593#define ERRCTL_PE 0x80000000
1546#define ERRCTL_L2P 0x00800000 1594#define ERRCTL_L2P 0x00800000
@@ -1630,7 +1678,7 @@ asmlinkage void cache_parity_error(void)
1630 printk("Decoded c0_cacheerr: %s cache fault in %s reference.\n", 1678 printk("Decoded c0_cacheerr: %s cache fault in %s reference.\n",
1631 reg_val & (1<<30) ? "secondary" : "primary", 1679 reg_val & (1<<30) ? "secondary" : "primary",
1632 reg_val & (1<<31) ? "data" : "insn"); 1680 reg_val & (1<<31) ? "data" : "insn");
1633 if (cpu_has_mips_r2 && 1681 if ((cpu_has_mips_r2_r6) &&
1634 ((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS)) { 1682 ((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS)) {
1635 pr_err("Error bits: %s%s%s%s%s%s%s%s\n", 1683 pr_err("Error bits: %s%s%s%s%s%s%s%s\n",
1636 reg_val & (1<<29) ? "ED " : "", 1684 reg_val & (1<<29) ? "ED " : "",
@@ -1670,7 +1718,7 @@ asmlinkage void do_ftlb(void)
1670 unsigned int reg_val; 1718 unsigned int reg_val;
1671 1719
1672 /* For the moment, report the problem and hang. */ 1720 /* For the moment, report the problem and hang. */
1673 if (cpu_has_mips_r2 && 1721 if ((cpu_has_mips_r2_r6) &&
1674 ((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS)) { 1722 ((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS)) {
1675 pr_err("FTLB error exception, cp0_ecc=0x%08x:\n", 1723 pr_err("FTLB error exception, cp0_ecc=0x%08x:\n",
1676 read_c0_ecc()); 1724 read_c0_ecc());
@@ -1959,7 +2007,7 @@ static void configure_hwrena(void)
1959{ 2007{
1960 unsigned int hwrena = cpu_hwrena_impl_bits; 2008 unsigned int hwrena = cpu_hwrena_impl_bits;
1961 2009
1962 if (cpu_has_mips_r2) 2010 if (cpu_has_mips_r2_r6)
1963 hwrena |= 0x0000000f; 2011 hwrena |= 0x0000000f;
1964 2012
1965 if (!noulri && cpu_has_userlocal) 2013 if (!noulri && cpu_has_userlocal)
@@ -2003,7 +2051,7 @@ void per_cpu_trap_init(bool is_boot_cpu)
2003 * o read IntCtl.IPTI to determine the timer interrupt 2051 * o read IntCtl.IPTI to determine the timer interrupt
2004 * o read IntCtl.IPPCI to determine the performance counter interrupt 2052 * o read IntCtl.IPPCI to determine the performance counter interrupt
2005 */ 2053 */
2006 if (cpu_has_mips_r2) { 2054 if (cpu_has_mips_r2_r6) {
2007 cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; 2055 cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
2008 cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7; 2056 cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;
2009 cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7; 2057 cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7;
@@ -2094,7 +2142,7 @@ void __init trap_init(void)
2094#else 2142#else
2095 ebase = CKSEG0; 2143 ebase = CKSEG0;
2096#endif 2144#endif
2097 if (cpu_has_mips_r2) 2145 if (cpu_has_mips_r2_r6)
2098 ebase += (read_c0_ebase() & 0x3ffff000); 2146 ebase += (read_c0_ebase() & 0x3ffff000);
2099 } 2147 }
2100 2148