10c57dfccSAnton Vorontsov /* 20c57dfccSAnton Vorontsov * KGDB NMI serial console 30c57dfccSAnton Vorontsov * 40c57dfccSAnton Vorontsov * Copyright 2010 Google, Inc. 50c57dfccSAnton Vorontsov * Arve Hjønnevåg <arve@android.com> 60c57dfccSAnton Vorontsov * Colin Cross <ccross@android.com> 70c57dfccSAnton Vorontsov * Copyright 2012 Linaro Ltd. 80c57dfccSAnton Vorontsov * Anton Vorontsov <anton.vorontsov@linaro.org> 90c57dfccSAnton Vorontsov * 100c57dfccSAnton Vorontsov * This program is free software; you can redistribute it and/or modify it 110c57dfccSAnton Vorontsov * under the terms of the GNU General Public License version 2 as published 120c57dfccSAnton Vorontsov * by the Free Software Foundation. 130c57dfccSAnton Vorontsov */ 140c57dfccSAnton Vorontsov 150c57dfccSAnton Vorontsov #include <linux/kernel.h> 160c57dfccSAnton Vorontsov #include <linux/module.h> 170c57dfccSAnton Vorontsov #include <linux/compiler.h> 180c57dfccSAnton Vorontsov #include <linux/slab.h> 190c57dfccSAnton Vorontsov #include <linux/errno.h> 200c57dfccSAnton Vorontsov #include <linux/atomic.h> 210c57dfccSAnton Vorontsov #include <linux/console.h> 220c57dfccSAnton Vorontsov #include <linux/tty.h> 230c57dfccSAnton Vorontsov #include <linux/tty_driver.h> 240c57dfccSAnton Vorontsov #include <linux/tty_flip.h> 2516559ae4SGreg Kroah-Hartman #include <linux/serial_core.h> 260c57dfccSAnton Vorontsov #include <linux/interrupt.h> 270c57dfccSAnton Vorontsov #include <linux/hrtimer.h> 280c57dfccSAnton Vorontsov #include <linux/tick.h> 290c57dfccSAnton Vorontsov #include <linux/kfifo.h> 300c57dfccSAnton Vorontsov #include <linux/kgdb.h> 310c57dfccSAnton Vorontsov #include <linux/kdb.h> 320c57dfccSAnton Vorontsov 330c57dfccSAnton Vorontsov static int kgdb_nmi_knock = 1; 340c57dfccSAnton Vorontsov module_param_named(knock, kgdb_nmi_knock, int, 0600); 350c57dfccSAnton Vorontsov MODULE_PARM_DESC(knock, "if set to 1 (default), the special '$3#33' command " \ 360c57dfccSAnton Vorontsov "must be used to enter the debugger; when set to 0, " \ 370c57dfccSAnton Vorontsov "hitting return key is enough to enter the debugger; " \ 380c57dfccSAnton Vorontsov "when set to -1, the debugger is entered immediately " \ 390c57dfccSAnton Vorontsov "upon NMI"); 400c57dfccSAnton Vorontsov 410c57dfccSAnton Vorontsov static char *kgdb_nmi_magic = "$3#33"; 420c57dfccSAnton Vorontsov module_param_named(magic, kgdb_nmi_magic, charp, 0600); 430c57dfccSAnton Vorontsov MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)"); 440c57dfccSAnton Vorontsov 450c57dfccSAnton Vorontsov static bool kgdb_nmi_tty_enabled; 460c57dfccSAnton Vorontsov 47bd71a1c0SDaniel Thompson static int kgdb_nmi_console_setup(struct console *co, char *options) 48bd71a1c0SDaniel Thompson { 49bd71a1c0SDaniel Thompson /* The NMI console uses the dbg_io_ops to issue console messages. To 50bd71a1c0SDaniel Thompson * avoid duplicate messages during kdb sessions we must inform kdb's 51bd71a1c0SDaniel Thompson * I/O utilities that messages sent to the console will automatically 52bd71a1c0SDaniel Thompson * be displayed on the dbg_io. 53bd71a1c0SDaniel Thompson */ 54bd71a1c0SDaniel Thompson dbg_io_ops->is_console = true; 55bd71a1c0SDaniel Thompson 56bd71a1c0SDaniel Thompson return 0; 57bd71a1c0SDaniel Thompson } 58bd71a1c0SDaniel Thompson 590c57dfccSAnton Vorontsov static void kgdb_nmi_console_write(struct console *co, const char *s, uint c) 600c57dfccSAnton Vorontsov { 610c57dfccSAnton Vorontsov int i; 620c57dfccSAnton Vorontsov 630c57dfccSAnton Vorontsov for (i = 0; i < c; i++) 640c57dfccSAnton Vorontsov dbg_io_ops->write_char(s[i]); 650c57dfccSAnton Vorontsov } 660c57dfccSAnton Vorontsov 670c57dfccSAnton Vorontsov static struct tty_driver *kgdb_nmi_tty_driver; 680c57dfccSAnton Vorontsov 690c57dfccSAnton Vorontsov static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx) 700c57dfccSAnton Vorontsov { 710c57dfccSAnton Vorontsov *idx = co->index; 720c57dfccSAnton Vorontsov return kgdb_nmi_tty_driver; 730c57dfccSAnton Vorontsov } 740c57dfccSAnton Vorontsov 750c57dfccSAnton Vorontsov static struct console kgdb_nmi_console = { 760c57dfccSAnton Vorontsov .name = "ttyNMI", 77bd71a1c0SDaniel Thompson .setup = kgdb_nmi_console_setup, 780c57dfccSAnton Vorontsov .write = kgdb_nmi_console_write, 790c57dfccSAnton Vorontsov .device = kgdb_nmi_console_device, 800c57dfccSAnton Vorontsov .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, 810c57dfccSAnton Vorontsov .index = -1, 820c57dfccSAnton Vorontsov }; 830c57dfccSAnton Vorontsov 840c57dfccSAnton Vorontsov /* 850c57dfccSAnton Vorontsov * This is usually the maximum rate on debug ports. We make fifo large enough 860c57dfccSAnton Vorontsov * to make copy-pasting to the terminal usable. 870c57dfccSAnton Vorontsov */ 880c57dfccSAnton Vorontsov #define KGDB_NMI_BAUD 115200 890c57dfccSAnton Vorontsov #define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ) 900c57dfccSAnton Vorontsov 910c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv { 920c57dfccSAnton Vorontsov struct tty_port port; 938a0ff60fSDaniel Thompson struct timer_list timer; 940c57dfccSAnton Vorontsov STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo; 950c57dfccSAnton Vorontsov }; 960c57dfccSAnton Vorontsov 970c57dfccSAnton Vorontsov static struct tty_port *kgdb_nmi_port; 980c57dfccSAnton Vorontsov 990c57dfccSAnton Vorontsov static void kgdb_tty_recv(int ch) 1000c57dfccSAnton Vorontsov { 1010c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv; 1020c57dfccSAnton Vorontsov char c = ch; 1030c57dfccSAnton Vorontsov 1040c57dfccSAnton Vorontsov if (!kgdb_nmi_port || ch < 0) 1050c57dfccSAnton Vorontsov return; 1060c57dfccSAnton Vorontsov /* 1078a0ff60fSDaniel Thompson * Can't use port->tty->driver_data as tty might be not there. Timer 1080c57dfccSAnton Vorontsov * will check for tty and will get the ref, but here we don't have to 1090c57dfccSAnton Vorontsov * do that, and actually, we can't: we're in NMI context, no locks are 1100c57dfccSAnton Vorontsov * possible. 1110c57dfccSAnton Vorontsov */ 11206d18289SDaniel Thompson priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port); 1130c57dfccSAnton Vorontsov kfifo_in(&priv->fifo, &c, 1); 1140c57dfccSAnton Vorontsov } 1150c57dfccSAnton Vorontsov 1160c57dfccSAnton Vorontsov static int kgdb_nmi_poll_one_knock(void) 1170c57dfccSAnton Vorontsov { 1180c57dfccSAnton Vorontsov static int n; 1190c57dfccSAnton Vorontsov int c = -1; 1200c57dfccSAnton Vorontsov const char *magic = kgdb_nmi_magic; 1210c57dfccSAnton Vorontsov size_t m = strlen(magic); 1220c57dfccSAnton Vorontsov bool printch = 0; 1230c57dfccSAnton Vorontsov 1240c57dfccSAnton Vorontsov c = dbg_io_ops->read_char(); 1250c57dfccSAnton Vorontsov if (c == NO_POLL_CHAR) 1260c57dfccSAnton Vorontsov return c; 1270c57dfccSAnton Vorontsov 1280c57dfccSAnton Vorontsov if (!kgdb_nmi_knock && (c == '\r' || c == '\n')) { 1290c57dfccSAnton Vorontsov return 1; 1300c57dfccSAnton Vorontsov } else if (c == magic[n]) { 1310c57dfccSAnton Vorontsov n = (n + 1) % m; 1320c57dfccSAnton Vorontsov if (!n) 1330c57dfccSAnton Vorontsov return 1; 1340c57dfccSAnton Vorontsov printch = 1; 1350c57dfccSAnton Vorontsov } else { 1360c57dfccSAnton Vorontsov n = 0; 1370c57dfccSAnton Vorontsov } 1380c57dfccSAnton Vorontsov 1390c57dfccSAnton Vorontsov if (kgdb_nmi_tty_enabled) { 1400c57dfccSAnton Vorontsov kgdb_tty_recv(c); 1410c57dfccSAnton Vorontsov return 0; 1420c57dfccSAnton Vorontsov } 1430c57dfccSAnton Vorontsov 1440c57dfccSAnton Vorontsov if (printch) { 1450c57dfccSAnton Vorontsov kdb_printf("%c", c); 1460c57dfccSAnton Vorontsov return 0; 1470c57dfccSAnton Vorontsov } 1480c57dfccSAnton Vorontsov 1490c57dfccSAnton Vorontsov kdb_printf("\r%s %s to enter the debugger> %*s", 1500c57dfccSAnton Vorontsov kgdb_nmi_knock ? "Type" : "Hit", 1510c57dfccSAnton Vorontsov kgdb_nmi_knock ? magic : "<return>", (int)m, ""); 1520c57dfccSAnton Vorontsov while (m--) 1530c57dfccSAnton Vorontsov kdb_printf("\b"); 1540c57dfccSAnton Vorontsov return 0; 1550c57dfccSAnton Vorontsov } 1560c57dfccSAnton Vorontsov 1570c57dfccSAnton Vorontsov /** 1580c57dfccSAnton Vorontsov * kgdb_nmi_poll_knock - Check if it is time to enter the debugger 1590c57dfccSAnton Vorontsov * 1600c57dfccSAnton Vorontsov * "Serial ports are often noisy, especially when muxed over another port (we 1610c57dfccSAnton Vorontsov * often use serial over the headset connector). Noise on the async command 1620c57dfccSAnton Vorontsov * line just causes characters that are ignored, on a command line that blocked 1630c57dfccSAnton Vorontsov * execution noise would be catastrophic." -- Colin Cross 1640c57dfccSAnton Vorontsov * 1650c57dfccSAnton Vorontsov * So, this function implements KGDB/KDB knocking on the serial line: we won't 1660c57dfccSAnton Vorontsov * enter the debugger until we receive a known magic phrase (which is actually 1670c57dfccSAnton Vorontsov * "$3#33", known as "escape to KDB" command. There is also a relaxed variant 1680c57dfccSAnton Vorontsov * of knocking, i.e. just pressing the return key is enough to enter the 1690c57dfccSAnton Vorontsov * debugger. And if knocking is disabled, the function always returns 1. 1700c57dfccSAnton Vorontsov */ 1710c57dfccSAnton Vorontsov bool kgdb_nmi_poll_knock(void) 1720c57dfccSAnton Vorontsov { 1730c57dfccSAnton Vorontsov if (kgdb_nmi_knock < 0) 1740c57dfccSAnton Vorontsov return 1; 1750c57dfccSAnton Vorontsov 1760c57dfccSAnton Vorontsov while (1) { 1770c57dfccSAnton Vorontsov int ret; 1780c57dfccSAnton Vorontsov 1790c57dfccSAnton Vorontsov ret = kgdb_nmi_poll_one_knock(); 1800c57dfccSAnton Vorontsov if (ret == NO_POLL_CHAR) 1810c57dfccSAnton Vorontsov return 0; 1820c57dfccSAnton Vorontsov else if (ret == 1) 1830c57dfccSAnton Vorontsov break; 1840c57dfccSAnton Vorontsov } 1850c57dfccSAnton Vorontsov return 1; 1860c57dfccSAnton Vorontsov } 1870c57dfccSAnton Vorontsov 1880c57dfccSAnton Vorontsov /* 1890c57dfccSAnton Vorontsov * The tasklet is cheap, it does not cause wakeups when reschedules itself, 1900c57dfccSAnton Vorontsov * instead it waits for the next tick. 1910c57dfccSAnton Vorontsov */ 1920c57dfccSAnton Vorontsov static void kgdb_nmi_tty_receiver(unsigned long data) 1930c57dfccSAnton Vorontsov { 1940c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = (void *)data; 1950c57dfccSAnton Vorontsov char ch; 1960c57dfccSAnton Vorontsov 1978a0ff60fSDaniel Thompson priv->timer.expires = jiffies + (HZ/100); 1988a0ff60fSDaniel Thompson add_timer(&priv->timer); 1990c57dfccSAnton Vorontsov 2000c57dfccSAnton Vorontsov if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo))) 2010c57dfccSAnton Vorontsov return; 2020c57dfccSAnton Vorontsov 2030c57dfccSAnton Vorontsov while (kfifo_out(&priv->fifo, &ch, 1)) 20492a19f9cSJiri Slaby tty_insert_flip_char(&priv->port, ch, TTY_NORMAL); 2052e124b4aSJiri Slaby tty_flip_buffer_push(&priv->port); 2060c57dfccSAnton Vorontsov } 2070c57dfccSAnton Vorontsov 2080c57dfccSAnton Vorontsov static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty) 2090c57dfccSAnton Vorontsov { 21006d18289SDaniel Thompson struct kgdb_nmi_tty_priv *priv = 21106d18289SDaniel Thompson container_of(port, struct kgdb_nmi_tty_priv, port); 2120c57dfccSAnton Vorontsov 2130c57dfccSAnton Vorontsov kgdb_nmi_port = port; 2148a0ff60fSDaniel Thompson priv->timer.expires = jiffies + (HZ/100); 2158a0ff60fSDaniel Thompson add_timer(&priv->timer); 2168a0ff60fSDaniel Thompson 2170c57dfccSAnton Vorontsov return 0; 2180c57dfccSAnton Vorontsov } 2190c57dfccSAnton Vorontsov 2200c57dfccSAnton Vorontsov static void kgdb_nmi_tty_shutdown(struct tty_port *port) 2210c57dfccSAnton Vorontsov { 22206d18289SDaniel Thompson struct kgdb_nmi_tty_priv *priv = 22306d18289SDaniel Thompson container_of(port, struct kgdb_nmi_tty_priv, port); 2240c57dfccSAnton Vorontsov 2258a0ff60fSDaniel Thompson del_timer(&priv->timer); 2260c57dfccSAnton Vorontsov kgdb_nmi_port = NULL; 2270c57dfccSAnton Vorontsov } 2280c57dfccSAnton Vorontsov 2290c57dfccSAnton Vorontsov static const struct tty_port_operations kgdb_nmi_tty_port_ops = { 2300c57dfccSAnton Vorontsov .activate = kgdb_nmi_tty_activate, 2310c57dfccSAnton Vorontsov .shutdown = kgdb_nmi_tty_shutdown, 2320c57dfccSAnton Vorontsov }; 2330c57dfccSAnton Vorontsov 2340c57dfccSAnton Vorontsov static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty) 2350c57dfccSAnton Vorontsov { 2360c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv; 2370c57dfccSAnton Vorontsov int ret; 2380c57dfccSAnton Vorontsov 2390c57dfccSAnton Vorontsov priv = kzalloc(sizeof(*priv), GFP_KERNEL); 2400c57dfccSAnton Vorontsov if (!priv) 2410c57dfccSAnton Vorontsov return -ENOMEM; 2420c57dfccSAnton Vorontsov 2430c57dfccSAnton Vorontsov INIT_KFIFO(priv->fifo); 2448a0ff60fSDaniel Thompson setup_timer(&priv->timer, kgdb_nmi_tty_receiver, (unsigned long)priv); 2450c57dfccSAnton Vorontsov tty_port_init(&priv->port); 2460c57dfccSAnton Vorontsov priv->port.ops = &kgdb_nmi_tty_port_ops; 2470c57dfccSAnton Vorontsov tty->driver_data = priv; 2480c57dfccSAnton Vorontsov 2490c57dfccSAnton Vorontsov ret = tty_port_install(&priv->port, drv, tty); 2500c57dfccSAnton Vorontsov if (ret) { 2510c57dfccSAnton Vorontsov pr_err("%s: can't install tty port: %d\n", __func__, ret); 2520c57dfccSAnton Vorontsov goto err; 2530c57dfccSAnton Vorontsov } 2540c57dfccSAnton Vorontsov return 0; 2550c57dfccSAnton Vorontsov err: 256191c5f10SJiri Slaby tty_port_destroy(&priv->port); 2570c57dfccSAnton Vorontsov kfree(priv); 2580c57dfccSAnton Vorontsov return ret; 2590c57dfccSAnton Vorontsov } 2600c57dfccSAnton Vorontsov 2610c57dfccSAnton Vorontsov static void kgdb_nmi_tty_cleanup(struct tty_struct *tty) 2620c57dfccSAnton Vorontsov { 2630c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = tty->driver_data; 2640c57dfccSAnton Vorontsov 2650c57dfccSAnton Vorontsov tty->driver_data = NULL; 266191c5f10SJiri Slaby tty_port_destroy(&priv->port); 2670c57dfccSAnton Vorontsov kfree(priv); 2680c57dfccSAnton Vorontsov } 2690c57dfccSAnton Vorontsov 2700c57dfccSAnton Vorontsov static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file) 2710c57dfccSAnton Vorontsov { 2720c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = tty->driver_data; 2730c57dfccSAnton Vorontsov 2740c57dfccSAnton Vorontsov return tty_port_open(&priv->port, tty, file); 2750c57dfccSAnton Vorontsov } 2760c57dfccSAnton Vorontsov 2770c57dfccSAnton Vorontsov static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file) 2780c57dfccSAnton Vorontsov { 2790c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = tty->driver_data; 2800c57dfccSAnton Vorontsov 2810c57dfccSAnton Vorontsov tty_port_close(&priv->port, tty, file); 2820c57dfccSAnton Vorontsov } 2830c57dfccSAnton Vorontsov 2840c57dfccSAnton Vorontsov static void kgdb_nmi_tty_hangup(struct tty_struct *tty) 2850c57dfccSAnton Vorontsov { 2860c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = tty->driver_data; 2870c57dfccSAnton Vorontsov 2880c57dfccSAnton Vorontsov tty_port_hangup(&priv->port); 2890c57dfccSAnton Vorontsov } 2900c57dfccSAnton Vorontsov 2910c57dfccSAnton Vorontsov static int kgdb_nmi_tty_write_room(struct tty_struct *tty) 2920c57dfccSAnton Vorontsov { 2930c57dfccSAnton Vorontsov /* Actually, we can handle any amount as we use polled writes. */ 2940c57dfccSAnton Vorontsov return 2048; 2950c57dfccSAnton Vorontsov } 2960c57dfccSAnton Vorontsov 2970c57dfccSAnton Vorontsov static int kgdb_nmi_tty_write(struct tty_struct *tty, const unchar *buf, int c) 2980c57dfccSAnton Vorontsov { 2990c57dfccSAnton Vorontsov int i; 3000c57dfccSAnton Vorontsov 3010c57dfccSAnton Vorontsov for (i = 0; i < c; i++) 3020c57dfccSAnton Vorontsov dbg_io_ops->write_char(buf[i]); 3030c57dfccSAnton Vorontsov return c; 3040c57dfccSAnton Vorontsov } 3050c57dfccSAnton Vorontsov 3060c57dfccSAnton Vorontsov static const struct tty_operations kgdb_nmi_tty_ops = { 3070c57dfccSAnton Vorontsov .open = kgdb_nmi_tty_open, 3080c57dfccSAnton Vorontsov .close = kgdb_nmi_tty_close, 3090c57dfccSAnton Vorontsov .install = kgdb_nmi_tty_install, 3100c57dfccSAnton Vorontsov .cleanup = kgdb_nmi_tty_cleanup, 3110c57dfccSAnton Vorontsov .hangup = kgdb_nmi_tty_hangup, 3120c57dfccSAnton Vorontsov .write_room = kgdb_nmi_tty_write_room, 3130c57dfccSAnton Vorontsov .write = kgdb_nmi_tty_write, 3140c57dfccSAnton Vorontsov }; 3150c57dfccSAnton Vorontsov 3160c57dfccSAnton Vorontsov static int kgdb_nmi_enable_console(int argc, const char *argv[]) 3170c57dfccSAnton Vorontsov { 3180c57dfccSAnton Vorontsov kgdb_nmi_tty_enabled = !(argc == 1 && !strcmp(argv[1], "off")); 3190c57dfccSAnton Vorontsov return 0; 3200c57dfccSAnton Vorontsov } 3210c57dfccSAnton Vorontsov 3220c57dfccSAnton Vorontsov int kgdb_register_nmi_console(void) 3230c57dfccSAnton Vorontsov { 3240c57dfccSAnton Vorontsov int ret; 3250c57dfccSAnton Vorontsov 3260c57dfccSAnton Vorontsov if (!arch_kgdb_ops.enable_nmi) 3270c57dfccSAnton Vorontsov return 0; 3280c57dfccSAnton Vorontsov 3290c57dfccSAnton Vorontsov kgdb_nmi_tty_driver = alloc_tty_driver(1); 3300c57dfccSAnton Vorontsov if (!kgdb_nmi_tty_driver) { 3310c57dfccSAnton Vorontsov pr_err("%s: cannot allocate tty\n", __func__); 3320c57dfccSAnton Vorontsov return -ENOMEM; 3330c57dfccSAnton Vorontsov } 3340c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->driver_name = "ttyNMI"; 3350c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->name = "ttyNMI"; 3360c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->num = 1; 3370c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; 3380c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL; 3390c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->flags = TTY_DRIVER_REAL_RAW; 3400c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->init_termios = tty_std_termios; 3410c57dfccSAnton Vorontsov tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios, 3420c57dfccSAnton Vorontsov KGDB_NMI_BAUD, KGDB_NMI_BAUD); 3430c57dfccSAnton Vorontsov tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops); 3440c57dfccSAnton Vorontsov 3450c57dfccSAnton Vorontsov ret = tty_register_driver(kgdb_nmi_tty_driver); 3460c57dfccSAnton Vorontsov if (ret) { 3470c57dfccSAnton Vorontsov pr_err("%s: can't register tty driver: %d\n", __func__, ret); 3480c57dfccSAnton Vorontsov goto err_drv_reg; 3490c57dfccSAnton Vorontsov } 3500c57dfccSAnton Vorontsov 3510c57dfccSAnton Vorontsov ret = kdb_register("nmi_console", kgdb_nmi_enable_console, "[off]", 3520c57dfccSAnton Vorontsov "switch to Linux NMI console", 0); 3530c57dfccSAnton Vorontsov if (ret) { 3540c57dfccSAnton Vorontsov pr_err("%s: can't register kdb command: %d\n", __func__, ret); 3550c57dfccSAnton Vorontsov goto err_kdb_reg; 3560c57dfccSAnton Vorontsov } 3570c57dfccSAnton Vorontsov 3580c57dfccSAnton Vorontsov register_console(&kgdb_nmi_console); 3590c57dfccSAnton Vorontsov arch_kgdb_ops.enable_nmi(1); 3600c57dfccSAnton Vorontsov 3610c57dfccSAnton Vorontsov return 0; 3620c57dfccSAnton Vorontsov err_kdb_reg: 3630c57dfccSAnton Vorontsov tty_unregister_driver(kgdb_nmi_tty_driver); 3640c57dfccSAnton Vorontsov err_drv_reg: 3650c57dfccSAnton Vorontsov put_tty_driver(kgdb_nmi_tty_driver); 3660c57dfccSAnton Vorontsov return ret; 3670c57dfccSAnton Vorontsov } 3680c57dfccSAnton Vorontsov EXPORT_SYMBOL_GPL(kgdb_register_nmi_console); 3690c57dfccSAnton Vorontsov 3700c57dfccSAnton Vorontsov int kgdb_unregister_nmi_console(void) 3710c57dfccSAnton Vorontsov { 3720c57dfccSAnton Vorontsov int ret; 3730c57dfccSAnton Vorontsov 3740c57dfccSAnton Vorontsov if (!arch_kgdb_ops.enable_nmi) 3750c57dfccSAnton Vorontsov return 0; 3760c57dfccSAnton Vorontsov arch_kgdb_ops.enable_nmi(0); 3770c57dfccSAnton Vorontsov 3780c57dfccSAnton Vorontsov kdb_unregister("nmi_console"); 3790c57dfccSAnton Vorontsov 3800c57dfccSAnton Vorontsov ret = unregister_console(&kgdb_nmi_console); 3810c57dfccSAnton Vorontsov if (ret) 3820c57dfccSAnton Vorontsov return ret; 3830c57dfccSAnton Vorontsov 3840c57dfccSAnton Vorontsov ret = tty_unregister_driver(kgdb_nmi_tty_driver); 3850c57dfccSAnton Vorontsov if (ret) 3860c57dfccSAnton Vorontsov return ret; 3870c57dfccSAnton Vorontsov put_tty_driver(kgdb_nmi_tty_driver); 3880c57dfccSAnton Vorontsov 3890c57dfccSAnton Vorontsov return 0; 3900c57dfccSAnton Vorontsov } 3910c57dfccSAnton Vorontsov EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console); 392