]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - kernel/panic.c
ARM: tegra3: initialize pll_a during boot
[linux-2.6.git] / kernel / panic.c
index 13d966b4c14a26f381a563aafe8721bc278a941d..41fc78ea3db9213158c57648a35e6600244baaa8 100644 (file)
 #include <linux/nmi.h>
 #include <linux/dmi.h>
 
+#define PANIC_TIMER_STEP 100
+#define PANIC_BLINK_SPD 18
+
+/* Machine specific panic information string */
+char *mach_panic_string;
+
 int panic_on_oops;
 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);
 
 EXPORT_SYMBOL(panic_notifier_list);
 
-/* Returns how long it waited in ms */
-long (*panic_blink)(long time);
-EXPORT_SYMBOL(panic_blink);
-
-static void panic_blink_one_second(void)
+static long no_blink(int state)
 {
-       static long i = 0, end;
-
-       if (panic_blink) {
-               end = i + MSEC_PER_SEC;
-
-               while (i < end) {
-                       i += panic_blink(i);
-                       mdelay(1);
-                       i++;
-               }
-       } else {
-               /*
-                * When running under a hypervisor a small mdelay may get
-                * rounded up to the hypervisor timeslice. For example, with
-                * a 1ms in 10ms hypervisor timeslice we might inflate a
-                * mdelay(1) loop by 10x.
-                *
-                * If we have nothing to blink, spin on 1 second calls to
-                * mdelay to avoid this.
-                */
-               mdelay(MSEC_PER_SEC);
-       }
+       return 0;
 }
 
+/* Returns how long it waited in ms */
+long (*panic_blink)(int state);
+EXPORT_SYMBOL(panic_blink);
+
 /**
  *     panic - halt the system
  *     @fmt: The text string to print
@@ -78,7 +67,8 @@ NORET_TYPE void panic(const char * fmt, ...)
 {
        static char buf[1024];
        va_list args;
-       long i;
+       long i, i_next = 0;
+       int state = 0;
 
        /*
         * It's possible to come here directly from a panic-assertion and
@@ -87,6 +77,7 @@ NORET_TYPE void panic(const char * fmt, ...)
         */
        preempt_disable();
 
+       console_verbose();
        bust_spinlocks(1);
        va_start(args, fmt);
        vsnprintf(buf, sizeof(buf), fmt, args);
@@ -116,6 +107,9 @@ NORET_TYPE void panic(const char * fmt, ...)
 
        bust_spinlocks(0);
 
+       if (!panic_blink)
+               panic_blink = no_blink;
+
        if (panic_timeout > 0) {
                /*
                 * Delay timeout seconds before rebooting the machine.
@@ -123,10 +117,16 @@ NORET_TYPE void panic(const char * fmt, ...)
                 */
                printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout);
 
-               for (i = 0; i < panic_timeout; i++) {
+               for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) {
                        touch_nmi_watchdog();
-                       panic_blink_one_second();
+                       if (i >= i_next) {
+                               i += panic_blink(state ^= 1);
+                               i_next = i + 3600 / PANIC_BLINK_SPD;
+                       }
+                       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
@@ -151,9 +151,13 @@ NORET_TYPE void panic(const char * fmt, ...)
        }
 #endif
        local_irq_enable();
-       while (1) {
+       for (i = 0; ; i += PANIC_TIMER_STEP) {
                touch_softlockup_watchdog();
-               panic_blink_one_second();
+               if (i >= i_next) {
+                       i += panic_blink(state ^= 1);
+                       i_next = i + 3600 / PANIC_BLINK_SPD;
+               }
+               mdelay(PANIC_TIMER_STEP);
        }
 }
 
@@ -178,6 +182,7 @@ static const struct tnt tnts[] = {
        { TAINT_OVERRIDDEN_ACPI_TABLE,  'A', ' ' },
        { TAINT_WARN,                   'W', ' ' },
        { TAINT_CRAP,                   'C', ' ' },
+       { TAINT_FIRMWARE_WORKAROUND,    'I', ' ' },
 };
 
 /**
@@ -194,6 +199,7 @@ static const struct tnt tnts[] = {
  *  'A' - ACPI table overridden.
  *  'W' - Taint on warning.
  *  'C' - modules from drivers/staging are loaded.
+ *  'I' - Working around severe firmware bug.
  *
  *     The string is overwritten by the next call to print_tainted().
  */
@@ -341,9 +347,14 @@ static int init_oops_id(void)
 }
 late_initcall(init_oops_id);
 
-static void print_oops_end_marker(void)
+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,7 +376,8 @@ struct slowpath_args {
        va_list args;
 };
 
-static void warn_slowpath_common(const char *file, int line, void *caller, struct slowpath_args *args)
+static void warn_slowpath_common(const char *file, int line, void *caller,
+                                unsigned taint, struct slowpath_args *args)
 {
        const char *board;
 
@@ -381,7 +393,7 @@ static void warn_slowpath_common(const char *file, int line, void *caller, struc
        print_modules();
        dump_stack();
        print_oops_end_marker();
-       add_taint(TAINT_WARN);
+       add_taint(taint);
 }
 
 void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
@@ -390,14 +402,29 @@ void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
 
        args.fmt = fmt;
        va_start(args.args, fmt);
-       warn_slowpath_common(file, line, __builtin_return_address(0), &args);
+       warn_slowpath_common(file, line, __builtin_return_address(0),
+                            TAINT_WARN, &args);
        va_end(args.args);
 }
 EXPORT_SYMBOL(warn_slowpath_fmt);
 
+void warn_slowpath_fmt_taint(const char *file, int line,
+                            unsigned taint, const char *fmt, ...)
+{
+       struct slowpath_args args;
+
+       args.fmt = fmt;
+       va_start(args.args, fmt);
+       warn_slowpath_common(file, line, __builtin_return_address(0),
+                            taint, &args);
+       va_end(args.args);
+}
+EXPORT_SYMBOL(warn_slowpath_fmt_taint);
+
 void warn_slowpath_null(const char *file, int line)
 {
-       warn_slowpath_common(file, line, __builtin_return_address(0), NULL);
+       warn_slowpath_common(file, line, __builtin_return_address(0),
+                            TAINT_WARN, NULL);
 }
 EXPORT_SYMBOL(warn_slowpath_null);
 #endif
@@ -419,3 +446,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);