Merge master.kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-drm-fsl-dcu.git] / arch / sparc64 / kernel / traps.c
index fe1796c939c395618e945b18b017c75d8717f5ed..dc652f2102906b54192196ee35f100cbc1f80221 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/sched.h>  /* for jiffies */
+#include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/kallsyms.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/kdebug.h>
 
 #include <asm/delay.h>
 #include <asm/system.h>
 #include <asm/psrcompat.h>
 #include <asm/processor.h>
 #include <asm/timer.h>
-#include <asm/kdebug.h>
 #include <asm/head.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
 #include <asm/prom.h>
 
-ATOMIC_NOTIFIER_HEAD(sparc64die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&sparc64die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&sparc64die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
 
 /* When an irrecoverable trap occurs at tl > 0, the trap entry
  * code logs the trap state registers at every level in the trap
@@ -1873,6 +1859,16 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
 
        put_cpu();
 
+       if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) {
+               /* If err_type is 0x4, it's a powerdown request.  Do
+                * not do the usual resumable error log because that
+                * makes it look like some abnormal error.
+                */
+               printk(KERN_INFO "Power down request...\n");
+               kill_cad_pid(SIGINT, 1);
+               return;
+       }
+
        sun4v_log_error(regs, &local_copy, cpu,
                        KERN_ERR "RESUMABLE ERROR",
                        &sun4v_resum_oflow_cnt);
@@ -2261,8 +2257,12 @@ void die_if_kernel(char *str, struct pt_regs *regs)
        do_exit(SIGSEGV);
 }
 
+#define VIS_OPCODE_MASK        ((0x3 << 30) | (0x3f << 19))
+#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19))
+
 extern int handle_popc(u32 insn, struct pt_regs *regs);
 extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
+extern int vis_emul(struct pt_regs *, unsigned int);
 
 void do_illegal_instruction(struct pt_regs *regs)
 {
@@ -2287,10 +2287,18 @@ void do_illegal_instruction(struct pt_regs *regs)
                        if (handle_ldf_stq(insn, regs))
                                return;
                } else if (tlb_type == hypervisor) {
-                       extern int vis_emul(struct pt_regs *, unsigned int);
+                       if ((insn & VIS_OPCODE_MASK) == VIS_OPCODE_VAL) {
+                               if (!vis_emul(regs, insn))
+                                       return;
+                       } else {
+                               struct fpustate *f = FPUSTATE;
 
-                       if (!vis_emul(regs, insn))
-                               return;
+                               /* XXX maybe verify XFSR bits like
+                                * XXX do_fpother() does?
+                                */
+                               if (do_mathemu(regs, f))
+                                       return;
+                       }
                }
        }
        info.si_signo = SIGILL;