diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 60 |
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 | ||
840 | static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, | 841 | void 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 | ¤t->thread.cp0_baduaddr); | ||
1049 | task_thread_info(current)->r2_emul_return = 1; | ||
1050 | return; | ||
1051 | } | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | no_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 | ||
1165 | static 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 | |||
1137 | static int enable_restore_fp_context(int msa) | 1177 | static 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(¤t->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 | ||