Merge tag 'split-asm_system_h-for-linus-20120328' of git://git.kernel.org/pub/scm...
[linux-2.6.git] / kernel / debug / debug_core.c
index de50f7d..1dc53ba 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/sysrq.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/kgdb.h>
 #include <linux/kdb.h>
@@ -74,6 +75,8 @@ static int                    exception_level;
 struct kgdb_io         *dbg_io_ops;
 static DEFINE_SPINLOCK(kgdb_registration_lock);
 
+/* Action for the reboot notifiter, a global allow kdb to change it */
+static int kgdbreboot;
 /* kgdb console driver is loaded */
 static int kgdb_con_registered;
 /* determine if kgdb console output should be used */
@@ -95,6 +98,7 @@ static int __init opt_kgdb_con(char *str)
 early_param("kgdbcon", opt_kgdb_con);
 
 module_param(kgdb_use_con, int, 0644);
+module_param(kgdbreboot, int, 0644);
 
 /*
  * Holds information about breakpoints in a kernel. These breakpoints are
@@ -783,6 +787,33 @@ void __init dbg_late_init(void)
        kdb_init(KDB_INIT_FULL);
 }
 
+static int
+dbg_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+       /*
+        * Take the following action on reboot notify depending on value:
+        *    1 == Enter debugger
+        *    0 == [the default] detatch debug client
+        *   -1 == Do nothing... and use this until the board resets
+        */
+       switch (kgdbreboot) {
+       case 1:
+               kgdb_breakpoint();
+       case -1:
+               goto done;
+       }
+       if (!dbg_kdb_mode)
+               gdbstub_exit(code);
+done:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block dbg_reboot_notifier = {
+       .notifier_call          = dbg_notify_reboot,
+       .next                   = NULL,
+       .priority               = INT_MAX,
+};
+
 static void kgdb_register_callbacks(void)
 {
        if (!kgdb_io_module_registered) {
@@ -790,6 +821,7 @@ static void kgdb_register_callbacks(void)
                kgdb_arch_init();
                if (!dbg_is_early)
                        kgdb_arch_late();
+               register_reboot_notifier(&dbg_reboot_notifier);
                atomic_notifier_chain_register(&panic_notifier_list,
                                               &kgdb_panic_event_nb);
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -811,6 +843,7 @@ static void kgdb_unregister_callbacks(void)
         */
        if (kgdb_io_module_registered) {
                kgdb_io_module_registered = 0;
+               unregister_reboot_notifier(&dbg_reboot_notifier);
                atomic_notifier_chain_unregister(&panic_notifier_list,
                                               &kgdb_panic_event_nb);
                kgdb_arch_exit();