aboutsummaryrefslogtreecommitdiff
path: root/drivers/tty/serial/kgdb_nmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/kgdb_nmi.c')
-rw-r--r--drivers/tty/serial/kgdb_nmi.c54
1 files changed, 32 insertions, 22 deletions
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 129dc5be6028..1a6a4fb5e63c 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -29,6 +29,7 @@
#include <linux/kfifo.h>
#include <linux/kgdb.h>
#include <linux/kdb.h>
+#include <linux/irq.h>
static int kgdb_nmi_knock = 1;
module_param_named(knock, kgdb_nmi_knock, int, 0600);
@@ -44,15 +45,12 @@ MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
+static int kgdb_nmi_set_enable(int enabled);
+
static int kgdb_nmi_console_setup(struct console *co, char *options)
{
- arch_kgdb_ops.enable_nmi(1);
+ (void) kgdb_nmi_set_enable(1);
- /* The NMI console uses the dbg_io_ops to issue console messages. To
- * avoid duplicate messages during kdb sessions we must inform kdb's
- * I/O utilities that messages sent to the console will automatically
- * be displayed on the dbg_io.
- */
dbg_io_ops->is_console = true;
return 0;
@@ -157,7 +155,7 @@ static int kgdb_nmi_poll_one_knock(void)
}
/**
- * kgdb_nmi_poll_knock - Check if it is time to enter the debugger
+ * kgdb_handle_nmi_poll_knock - Check if it is time to enter the debugger
*
* "Serial ports are often noisy, especially when muxed over another port (we
* often use serial over the headset connector). Noise on the async command
@@ -170,23 +168,42 @@ static int kgdb_nmi_poll_one_knock(void)
* of knocking, i.e. just pressing the return key is enough to enter the
* debugger. And if knocking is disabled, the function always returns 1.
*/
-bool kgdb_nmi_poll_knock(void)
+static irqreturn_t kgdb_handle_nmi_poll_knock(int irq, void *unused)
{
+ int ret = IRQ_NONE;
+
if (kgdb_nmi_knock < 0)
return 1;
while (1) {
- int ret;
-
- ret = kgdb_nmi_poll_one_knock();
- if (ret == NO_POLL_CHAR)
- return 0;
- else if (ret == 1)
+ switch (kgdb_nmi_poll_one_knock()) {
+ case NO_POLL_CHAR:
+ return ret;
+ case 1:
+ kgdb_handle_exception(1, 0, 0, get_irq_regs());
+ return IRQ_HANDLED;
+ default:
+ ret = IRQ_HANDLED;
break;
+ }
}
- return 1;
+
+ return IRQ_HANDLED;
}
+static int kgdb_nmi_set_enable(int enabled)
+{
+ int res = 0;
+
+ if (enabled)
+ res = dbg_io_ops->request_nmi(kgdb_handle_nmi_poll_knock);
+ else
+ dbg_io_ops->free_nmi();
+
+ return res;
+}
+
+
/*
* The tasklet is cheap, it does not cause wakeups when reschedules itself,
* instead it waits for the next tick.
@@ -330,9 +347,6 @@ int kgdb_register_nmi_console(void)
{
int ret;
- if (!arch_kgdb_ops.enable_nmi)
- return 0;
-
kgdb_nmi_tty_driver = alloc_tty_driver(1);
if (!kgdb_nmi_tty_driver) {
pr_err("%s: cannot allocate tty\n", __func__);
@@ -368,10 +382,6 @@ int kgdb_unregister_nmi_console(void)
{
int ret;
- if (!arch_kgdb_ops.enable_nmi)
- return 0;
- arch_kgdb_ops.enable_nmi(0);
-
ret = unregister_console(&kgdb_nmi_console);
if (ret)
return ret;