arm: tegra: register save and restore ops
[linux-3.10.git] / kernel / panic.c
index 4c13b1a..126b2ef 100644 (file)
 #include <linux/sysrq.h>
 #include <linux/init.h>
 #include <linux/nmi.h>
-#include <linux/dmi.h>
 
 #define PANIC_TIMER_STEP 100
 #define PANIC_BLINK_SPD 18
 
-int panic_on_oops;
+/* Machine specific panic information string */
+char *mach_panic_string;
+
+int panic_on_oops = CONFIG_PANIC_ON_OOPS_VALUE;
 static unsigned long tainted_mask;
 static int pause_on_oops;
 static int pause_on_oops_flag;
 static DEFINE_SPINLOCK(pause_on_oops_lock);
 
-int panic_timeout;
+#ifndef CONFIG_PANIC_TIMEOUT
+#define CONFIG_PANIC_TIMEOUT 0
+#endif
+int panic_timeout = CONFIG_PANIC_TIMEOUT;
+EXPORT_SYMBOL_GPL(panic_timeout);
 
 ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
 
@@ -48,6 +54,15 @@ static long no_blink(int state)
 long (*panic_blink)(int state);
 EXPORT_SYMBOL(panic_blink);
 
+/*
+ * Stop ourself in panic -- architecture code may override this
+ */
+void __weak panic_smp_self_stop(void)
+{
+       while (1)
+               cpu_relax();
+}
+
 /**
  *     panic - halt the system
  *     @fmt: The text string to print
@@ -56,19 +71,34 @@ EXPORT_SYMBOL(panic_blink);
  *
  *     This function never returns.
  */
-NORET_TYPE void panic(const char * fmt, ...)
+void panic(const char *fmt, ...)
 {
+       static DEFINE_SPINLOCK(panic_lock);
        static char buf[1024];
        va_list args;
        long i, i_next = 0;
        int state = 0;
 
        /*
+        * Disable local interrupts. This will prevent panic_smp_self_stop
+        * from deadlocking the first cpu that invokes the panic, since
+        * there is nothing to prevent an interrupt handler (that runs
+        * after the panic_lock is acquired) from invoking panic again.
+        */
+       local_irq_disable();
+
+       /*
         * It's possible to come here directly from a panic-assertion and
         * not have preempt disabled. Some functions called from here want
         * preempt to be disabled. No point enabling it later though...
+        *
+        * Only one CPU is allowed to execute the panic code from here. For
+        * multiple parallel invocations of panic, all other CPUs either
+        * stop themself or will wait until they are stopped by the 1st CPU
+        * with smp_send_stop().
         */
-       preempt_disable();
+       if (!spin_trylock(&panic_lock))
+               panic_smp_self_stop();
 
        console_verbose();
        bust_spinlocks(1);
@@ -77,7 +107,11 @@ NORET_TYPE void panic(const char * fmt, ...)
        va_end(args);
        printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
 #ifdef CONFIG_DEBUG_BUGVERBOSE
-       dump_stack();
+       /*
+        * Avoid nested stack-dumping if a panic occurs during oops processing
+        */
+       if (!test_taint(TAINT_DIE) && oops_in_progress <= 1)
+               dump_stack();
 #endif
 
        /*
@@ -87,8 +121,6 @@ NORET_TYPE void panic(const char * fmt, ...)
         */
        crash_kexec(NULL);
 
-       kmsg_dump(KMSG_DUMP_PANIC);
-
        /*
         * Note smp_send_stop is the usual smp shutdown function, which
         * unfortunately means it may not be hardened to work in a panic
@@ -96,6 +128,8 @@ NORET_TYPE void panic(const char * fmt, ...)
         */
        smp_send_stop();
 
+       kmsg_dump(KMSG_DUMP_PANIC);
+
        atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
 
        bust_spinlocks(0);
@@ -118,6 +152,8 @@ NORET_TYPE void panic(const char * fmt, ...)
                        }
                        mdelay(PANIC_TIMER_STEP);
                }
+       }
+       if (panic_timeout != 0) {
                /*
                 * This will not be a clean reboot, with everything
                 * shutting down.  But if there is a chance of
@@ -174,6 +210,7 @@ static const struct tnt tnts[] = {
        { TAINT_WARN,                   'W', ' ' },
        { TAINT_CRAP,                   'C', ' ' },
        { TAINT_FIRMWARE_WORKAROUND,    'I', ' ' },
+       { TAINT_OOT_MODULE,             'O', ' ' },
 };
 
 /**
@@ -191,6 +228,7 @@ static const struct tnt tnts[] = {
  *  'W' - Taint on warning.
  *  'C' - modules from drivers/staging are loaded.
  *  'I' - Working around severe firmware bug.
+ *  'O' - Out-of-tree module has been loaded.
  *
  *     The string is overwritten by the next call to print_tainted().
  */
@@ -226,17 +264,19 @@ unsigned long get_taint(void)
        return tainted_mask;
 }
 
-void add_taint(unsigned flag)
+/**
+ * add_taint: add a taint flag if not already set.
+ * @flag: one of the TAINT_* constants.
+ * @lockdep_ok: whether lock debugging is still OK.
+ *
+ * If something bad has gone wrong, you'll want @lockdebug_ok = false, but for
+ * some notewortht-but-not-corrupting cases, it can be set to true.
+ */
+void add_taint(unsigned flag, enum lockdep_ok lockdep_ok)
 {
-       /*
-        * Can't trust the integrity of the kernel anymore.
-        * We don't call directly debug_locks_off() because the issue
-        * is not necessarily serious enough to set oops_in_progress to 1
-        * Also we want to keep up lockdep for staging development and
-        * post-warning case.
-        */
-       if (flag != TAINT_CRAP && flag != TAINT_WARN && __debug_locks_off())
-               printk(KERN_WARNING "Disabling lock debugging due to kernel taint\n");
+       if (lockdep_ok == LOCKDEP_NOW_UNRELIABLE && __debug_locks_off())
+               printk(KERN_WARNING
+                      "Disabling lock debugging due to kernel taint\n");
 
        set_bit(flag, &tainted_mask);
 }
@@ -341,6 +381,11 @@ late_initcall(init_oops_id);
 void print_oops_end_marker(void)
 {
        init_oops_id();
+
+       if (mach_panic_string)
+               printk(KERN_WARNING "Board Information: %s\n",
+                      mach_panic_string);
+
        printk(KERN_WARNING "---[ end trace %016llx ]---\n",
                (unsigned long long)oops_id);
 }
@@ -365,13 +410,8 @@ struct slowpath_args {
 static void warn_slowpath_common(const char *file, int line, void *caller,
                                 unsigned taint, struct slowpath_args *args)
 {
-       const char *board;
-
        printk(KERN_WARNING "------------[ cut here ]------------\n");
        printk(KERN_WARNING "WARNING: at %s:%d %pS()\n", file, line, caller);
-       board = dmi_get_system_info(DMI_PRODUCT_NAME);
-       if (board)
-               printk(KERN_WARNING "Hardware name: %s\n", board);
 
        if (args)
                vprintk(args->fmt, args->args);
@@ -379,7 +419,8 @@ static void warn_slowpath_common(const char *file, int line, void *caller,
        print_modules();
        dump_stack();
        print_oops_end_marker();
-       add_taint(taint);
+       /* Just a warning, don't kill lockdep. */
+       add_taint(taint, LOCKDEP_STILL_OK);
 }
 
 void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
@@ -432,3 +473,13 @@ EXPORT_SYMBOL(__stack_chk_fail);
 
 core_param(panic, panic_timeout, int, 0644);
 core_param(pause_on_oops, pause_on_oops, int, 0644);
+
+static int __init oops_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       if (!strcmp(s, "panic"))
+               panic_on_oops = 1;
+       return 0;
+}
+early_param("oops", oops_setup);