Merge remote-tracking branch 'asoc/topic/wm8994' into asoc-next
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / sgi-xp / xpc_main.c
index 8d082b46426b756681c0590581501b8d8cac198a..d971817182f79b92e5136e64eebf79351a40f0d7 100644 (file)
 #include <linux/kthread.h>
 #include "xpc.h"
 
+#ifdef CONFIG_X86_64
+#include <asm/traps.h>
+#endif
+
 /* define two XPC debug device structures to be used with dev_dbg() et al */
 
 struct device_driver xpc_dbg_name = {
@@ -1079,6 +1083,9 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
        return NOTIFY_DONE;
 }
 
+/* Used to only allow one cpu to complete disconnect */
+static unsigned int xpc_die_disconnecting;
+
 /*
  * Notify other partitions to deactivate from us by first disengaging from all
  * references to our memory.
@@ -1092,6 +1099,9 @@ xpc_die_deactivate(void)
        long keep_waiting;
        long wait_to_print;
 
+       if (cmpxchg(&xpc_die_disconnecting, 0, 1))
+               return;
+
        /* keep xpc_hb_checker thread from doing anything (just in case) */
        xpc_exiting = 1;
 
@@ -1159,7 +1169,7 @@ xpc_die_deactivate(void)
  * about the lack of a heartbeat.
  */
 static int
-xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
+xpc_system_die(struct notifier_block *nb, unsigned long event, void *_die_args)
 {
 #ifdef CONFIG_IA64             /* !!! temporary kludge */
        switch (event) {
@@ -1191,7 +1201,27 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
                break;
        }
 #else
-       xpc_die_deactivate();
+       struct die_args *die_args = _die_args;
+
+       switch (event) {
+       case DIE_TRAP:
+               if (die_args->trapnr == X86_TRAP_DF)
+                       xpc_die_deactivate();
+
+               if (((die_args->trapnr == X86_TRAP_MF) ||
+                    (die_args->trapnr == X86_TRAP_XF)) &&
+                   !user_mode_vm(die_args->regs))
+                       xpc_die_deactivate();
+
+               break;
+       case DIE_INT3:
+       case DIE_DEBUG:
+               break;
+       case DIE_OOPS:
+       case DIE_GPF:
+       default:
+               xpc_die_deactivate();
+       }
 #endif
 
        return NOTIFY_DONE;