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 45c8b29f04SDaniel Thompson static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0); 460c57dfccSAnton Vorontsov 47bd71a1c0SDaniel Thompson static int kgdb_nmi_console_setup(struct console *co, char *options) 48bd71a1c0SDaniel Thompson { 49287f03c0SDaniel Thompson arch_kgdb_ops.enable_nmi(1); 50287f03c0SDaniel Thompson 51bd71a1c0SDaniel Thompson /* The NMI console uses the dbg_io_ops to issue console messages. To 52bd71a1c0SDaniel Thompson * avoid duplicate messages during kdb sessions we must inform kdb's 53bd71a1c0SDaniel Thompson * I/O utilities that messages sent to the console will automatically 54bd71a1c0SDaniel Thompson * be displayed on the dbg_io. 55bd71a1c0SDaniel Thompson */ 56bd71a1c0SDaniel Thompson dbg_io_ops->is_console = true; 57bd71a1c0SDaniel Thompson 58bd71a1c0SDaniel Thompson return 0; 59bd71a1c0SDaniel Thompson } 60bd71a1c0SDaniel Thompson 610c57dfccSAnton Vorontsov static void kgdb_nmi_console_write(struct console *co, const char *s, uint c) 620c57dfccSAnton Vorontsov { 630c57dfccSAnton Vorontsov int i; 640c57dfccSAnton Vorontsov 650c57dfccSAnton Vorontsov for (i = 0; i < c; i++) 660c57dfccSAnton Vorontsov dbg_io_ops->write_char(s[i]); 670c57dfccSAnton Vorontsov } 680c57dfccSAnton Vorontsov 690c57dfccSAnton Vorontsov static struct tty_driver *kgdb_nmi_tty_driver; 700c57dfccSAnton Vorontsov 710c57dfccSAnton Vorontsov static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx) 720c57dfccSAnton Vorontsov { 730c57dfccSAnton Vorontsov *idx = co->index; 740c57dfccSAnton Vorontsov return kgdb_nmi_tty_driver; 750c57dfccSAnton Vorontsov } 760c57dfccSAnton Vorontsov 770c57dfccSAnton Vorontsov static struct console kgdb_nmi_console = { 780c57dfccSAnton Vorontsov .name = "ttyNMI", 79bd71a1c0SDaniel Thompson .setup = kgdb_nmi_console_setup, 800c57dfccSAnton Vorontsov .write = kgdb_nmi_console_write, 810c57dfccSAnton Vorontsov .device = kgdb_nmi_console_device, 82287f03c0SDaniel Thompson .flags = CON_PRINTBUFFER | CON_ANYTIME, 830c57dfccSAnton Vorontsov .index = -1, 840c57dfccSAnton Vorontsov }; 850c57dfccSAnton Vorontsov 860c57dfccSAnton Vorontsov /* 870c57dfccSAnton Vorontsov * This is usually the maximum rate on debug ports. We make fifo large enough 880c57dfccSAnton Vorontsov * to make copy-pasting to the terminal usable. 890c57dfccSAnton Vorontsov */ 900c57dfccSAnton Vorontsov #define KGDB_NMI_BAUD 115200 910c57dfccSAnton Vorontsov #define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ) 920c57dfccSAnton Vorontsov 930c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv { 940c57dfccSAnton Vorontsov struct tty_port port; 958a0ff60fSDaniel Thompson struct timer_list timer; 960c57dfccSAnton Vorontsov STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo; 970c57dfccSAnton Vorontsov }; 980c57dfccSAnton Vorontsov 990c57dfccSAnton Vorontsov static struct tty_port *kgdb_nmi_port; 1000c57dfccSAnton Vorontsov 1010c57dfccSAnton Vorontsov static void kgdb_tty_recv(int ch) 1020c57dfccSAnton Vorontsov { 1030c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv; 1040c57dfccSAnton Vorontsov char c = ch; 1050c57dfccSAnton Vorontsov 1060c57dfccSAnton Vorontsov if (!kgdb_nmi_port || ch < 0) 1070c57dfccSAnton Vorontsov return; 1080c57dfccSAnton Vorontsov /* 1098a0ff60fSDaniel Thompson * Can't use port->tty->driver_data as tty might be not there. Timer 1100c57dfccSAnton Vorontsov * will check for tty and will get the ref, but here we don't have to 1110c57dfccSAnton Vorontsov * do that, and actually, we can't: we're in NMI context, no locks are 1120c57dfccSAnton Vorontsov * possible. 1130c57dfccSAnton Vorontsov */ 11406d18289SDaniel Thompson priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port); 1150c57dfccSAnton Vorontsov kfifo_in(&priv->fifo, &c, 1); 1160c57dfccSAnton Vorontsov } 1170c57dfccSAnton Vorontsov 1180c57dfccSAnton Vorontsov static int kgdb_nmi_poll_one_knock(void) 1190c57dfccSAnton Vorontsov { 1200c57dfccSAnton Vorontsov static int n; 1210c57dfccSAnton Vorontsov int c = -1; 1220c57dfccSAnton Vorontsov const char *magic = kgdb_nmi_magic; 1230c57dfccSAnton Vorontsov size_t m = strlen(magic); 1240c57dfccSAnton Vorontsov bool printch = 0; 1250c57dfccSAnton Vorontsov 1260c57dfccSAnton Vorontsov c = dbg_io_ops->read_char(); 1270c57dfccSAnton Vorontsov if (c == NO_POLL_CHAR) 1280c57dfccSAnton Vorontsov return c; 1290c57dfccSAnton Vorontsov 1300c57dfccSAnton Vorontsov if (!kgdb_nmi_knock && (c == '\r' || c == '\n')) { 1310c57dfccSAnton Vorontsov return 1; 1320c57dfccSAnton Vorontsov } else if (c == magic[n]) { 1330c57dfccSAnton Vorontsov n = (n + 1) % m; 1340c57dfccSAnton Vorontsov if (!n) 1350c57dfccSAnton Vorontsov return 1; 1360c57dfccSAnton Vorontsov printch = 1; 1370c57dfccSAnton Vorontsov } else { 1380c57dfccSAnton Vorontsov n = 0; 1390c57dfccSAnton Vorontsov } 1400c57dfccSAnton Vorontsov 141c8b29f04SDaniel Thompson if (atomic_read(&kgdb_nmi_num_readers)) { 1420c57dfccSAnton Vorontsov kgdb_tty_recv(c); 1430c57dfccSAnton Vorontsov return 0; 1440c57dfccSAnton Vorontsov } 1450c57dfccSAnton Vorontsov 1460c57dfccSAnton Vorontsov if (printch) { 1470c57dfccSAnton Vorontsov kdb_printf("%c", c); 1480c57dfccSAnton Vorontsov return 0; 1490c57dfccSAnton Vorontsov } 1500c57dfccSAnton Vorontsov 1510c57dfccSAnton Vorontsov kdb_printf("\r%s %s to enter the debugger> %*s", 1520c57dfccSAnton Vorontsov kgdb_nmi_knock ? "Type" : "Hit", 1530c57dfccSAnton Vorontsov kgdb_nmi_knock ? magic : "<return>", (int)m, ""); 1540c57dfccSAnton Vorontsov while (m--) 1550c57dfccSAnton Vorontsov kdb_printf("\b"); 1560c57dfccSAnton Vorontsov return 0; 1570c57dfccSAnton Vorontsov } 1580c57dfccSAnton Vorontsov 1590c57dfccSAnton Vorontsov /** 1600c57dfccSAnton Vorontsov * kgdb_nmi_poll_knock - Check if it is time to enter the debugger 1610c57dfccSAnton Vorontsov * 1620c57dfccSAnton Vorontsov * "Serial ports are often noisy, especially when muxed over another port (we 1630c57dfccSAnton Vorontsov * often use serial over the headset connector). Noise on the async command 1640c57dfccSAnton Vorontsov * line just causes characters that are ignored, on a command line that blocked 1650c57dfccSAnton Vorontsov * execution noise would be catastrophic." -- Colin Cross 1660c57dfccSAnton Vorontsov * 1670c57dfccSAnton Vorontsov * So, this function implements KGDB/KDB knocking on the serial line: we won't 1680c57dfccSAnton Vorontsov * enter the debugger until we receive a known magic phrase (which is actually 1690c57dfccSAnton Vorontsov * "$3#33", known as "escape to KDB" command. There is also a relaxed variant 1700c57dfccSAnton Vorontsov * of knocking, i.e. just pressing the return key is enough to enter the 1710c57dfccSAnton Vorontsov * debugger. And if knocking is disabled, the function always returns 1. 1720c57dfccSAnton Vorontsov */ 1730c57dfccSAnton Vorontsov bool kgdb_nmi_poll_knock(void) 1740c57dfccSAnton Vorontsov { 1750c57dfccSAnton Vorontsov if (kgdb_nmi_knock < 0) 1760c57dfccSAnton Vorontsov return 1; 1770c57dfccSAnton Vorontsov 1780c57dfccSAnton Vorontsov while (1) { 1790c57dfccSAnton Vorontsov int ret; 1800c57dfccSAnton Vorontsov 1810c57dfccSAnton Vorontsov ret = kgdb_nmi_poll_one_knock(); 1820c57dfccSAnton Vorontsov if (ret == NO_POLL_CHAR) 1830c57dfccSAnton Vorontsov return 0; 1840c57dfccSAnton Vorontsov else if (ret == 1) 1850c57dfccSAnton Vorontsov break; 1860c57dfccSAnton Vorontsov } 1870c57dfccSAnton Vorontsov return 1; 1880c57dfccSAnton Vorontsov } 1890c57dfccSAnton Vorontsov 1900c57dfccSAnton Vorontsov /* 1910c57dfccSAnton Vorontsov * The tasklet is cheap, it does not cause wakeups when reschedules itself, 1920c57dfccSAnton Vorontsov * instead it waits for the next tick. 1930c57dfccSAnton Vorontsov */ 1940c57dfccSAnton Vorontsov static void kgdb_nmi_tty_receiver(unsigned long data) 1950c57dfccSAnton Vorontsov { 1960c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = (void *)data; 1970c57dfccSAnton Vorontsov char ch; 1980c57dfccSAnton Vorontsov 1998a0ff60fSDaniel Thompson priv->timer.expires = jiffies + (HZ/100); 2008a0ff60fSDaniel Thompson add_timer(&priv->timer); 2010c57dfccSAnton Vorontsov 202c8b29f04SDaniel Thompson if (likely(!atomic_read(&kgdb_nmi_num_readers) || 203c8b29f04SDaniel Thompson !kfifo_len(&priv->fifo))) 2040c57dfccSAnton Vorontsov return; 2050c57dfccSAnton Vorontsov 2060c57dfccSAnton Vorontsov while (kfifo_out(&priv->fifo, &ch, 1)) 20792a19f9cSJiri Slaby tty_insert_flip_char(&priv->port, ch, TTY_NORMAL); 2082e124b4aSJiri Slaby tty_flip_buffer_push(&priv->port); 2090c57dfccSAnton Vorontsov } 2100c57dfccSAnton Vorontsov 2110c57dfccSAnton Vorontsov static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty) 2120c57dfccSAnton Vorontsov { 21306d18289SDaniel Thompson struct kgdb_nmi_tty_priv *priv = 21406d18289SDaniel Thompson container_of(port, struct kgdb_nmi_tty_priv, port); 2150c57dfccSAnton Vorontsov 2160c57dfccSAnton Vorontsov kgdb_nmi_port = port; 2178a0ff60fSDaniel Thompson priv->timer.expires = jiffies + (HZ/100); 2188a0ff60fSDaniel Thompson add_timer(&priv->timer); 2198a0ff60fSDaniel Thompson 2200c57dfccSAnton Vorontsov return 0; 2210c57dfccSAnton Vorontsov } 2220c57dfccSAnton Vorontsov 2230c57dfccSAnton Vorontsov static void kgdb_nmi_tty_shutdown(struct tty_port *port) 2240c57dfccSAnton Vorontsov { 22506d18289SDaniel Thompson struct kgdb_nmi_tty_priv *priv = 22606d18289SDaniel Thompson container_of(port, struct kgdb_nmi_tty_priv, port); 2270c57dfccSAnton Vorontsov 2288a0ff60fSDaniel Thompson del_timer(&priv->timer); 2290c57dfccSAnton Vorontsov kgdb_nmi_port = NULL; 2300c57dfccSAnton Vorontsov } 2310c57dfccSAnton Vorontsov 2320c57dfccSAnton Vorontsov static const struct tty_port_operations kgdb_nmi_tty_port_ops = { 2330c57dfccSAnton Vorontsov .activate = kgdb_nmi_tty_activate, 2340c57dfccSAnton Vorontsov .shutdown = kgdb_nmi_tty_shutdown, 2350c57dfccSAnton Vorontsov }; 2360c57dfccSAnton Vorontsov 2370c57dfccSAnton Vorontsov static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty) 2380c57dfccSAnton Vorontsov { 2390c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv; 2400c57dfccSAnton Vorontsov int ret; 2410c57dfccSAnton Vorontsov 2420c57dfccSAnton Vorontsov priv = kzalloc(sizeof(*priv), GFP_KERNEL); 2430c57dfccSAnton Vorontsov if (!priv) 2440c57dfccSAnton Vorontsov return -ENOMEM; 2450c57dfccSAnton Vorontsov 2460c57dfccSAnton Vorontsov INIT_KFIFO(priv->fifo); 2478a0ff60fSDaniel Thompson setup_timer(&priv->timer, kgdb_nmi_tty_receiver, (unsigned long)priv); 2480c57dfccSAnton Vorontsov tty_port_init(&priv->port); 2490c57dfccSAnton Vorontsov priv->port.ops = &kgdb_nmi_tty_port_ops; 2500c57dfccSAnton Vorontsov tty->driver_data = priv; 2510c57dfccSAnton Vorontsov 2520c57dfccSAnton Vorontsov ret = tty_port_install(&priv->port, drv, tty); 2530c57dfccSAnton Vorontsov if (ret) { 2540c57dfccSAnton Vorontsov pr_err("%s: can't install tty port: %d\n", __func__, ret); 2550c57dfccSAnton Vorontsov goto err; 2560c57dfccSAnton Vorontsov } 2570c57dfccSAnton Vorontsov return 0; 2580c57dfccSAnton Vorontsov err: 259191c5f10SJiri Slaby tty_port_destroy(&priv->port); 2600c57dfccSAnton Vorontsov kfree(priv); 2610c57dfccSAnton Vorontsov return ret; 2620c57dfccSAnton Vorontsov } 2630c57dfccSAnton Vorontsov 2640c57dfccSAnton Vorontsov static void kgdb_nmi_tty_cleanup(struct tty_struct *tty) 2650c57dfccSAnton Vorontsov { 2660c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = tty->driver_data; 2670c57dfccSAnton Vorontsov 2680c57dfccSAnton Vorontsov tty->driver_data = NULL; 269191c5f10SJiri Slaby tty_port_destroy(&priv->port); 2700c57dfccSAnton Vorontsov kfree(priv); 2710c57dfccSAnton Vorontsov } 2720c57dfccSAnton Vorontsov 2730c57dfccSAnton Vorontsov static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file) 2740c57dfccSAnton Vorontsov { 2750c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = tty->driver_data; 276c8b29f04SDaniel Thompson unsigned int mode = file->f_flags & O_ACCMODE; 277c8b29f04SDaniel Thompson int ret; 2780c57dfccSAnton Vorontsov 279c8b29f04SDaniel Thompson ret = tty_port_open(&priv->port, tty, file); 280c8b29f04SDaniel Thompson if (!ret && (mode == O_RDONLY || mode == O_RDWR)) 281c8b29f04SDaniel Thompson atomic_inc(&kgdb_nmi_num_readers); 282c8b29f04SDaniel Thompson 283c8b29f04SDaniel Thompson return ret; 2840c57dfccSAnton Vorontsov } 2850c57dfccSAnton Vorontsov 2860c57dfccSAnton Vorontsov static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file) 2870c57dfccSAnton Vorontsov { 2880c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = tty->driver_data; 289c8b29f04SDaniel Thompson unsigned int mode = file->f_flags & O_ACCMODE; 290c8b29f04SDaniel Thompson 291c8b29f04SDaniel Thompson if (mode == O_RDONLY || mode == O_RDWR) 292c8b29f04SDaniel Thompson atomic_dec(&kgdb_nmi_num_readers); 2930c57dfccSAnton Vorontsov 2940c57dfccSAnton Vorontsov tty_port_close(&priv->port, tty, file); 2950c57dfccSAnton Vorontsov } 2960c57dfccSAnton Vorontsov 2970c57dfccSAnton Vorontsov static void kgdb_nmi_tty_hangup(struct tty_struct *tty) 2980c57dfccSAnton Vorontsov { 2990c57dfccSAnton Vorontsov struct kgdb_nmi_tty_priv *priv = tty->driver_data; 3000c57dfccSAnton Vorontsov 3010c57dfccSAnton Vorontsov tty_port_hangup(&priv->port); 3020c57dfccSAnton Vorontsov } 3030c57dfccSAnton Vorontsov 3040c57dfccSAnton Vorontsov static int kgdb_nmi_tty_write_room(struct tty_struct *tty) 3050c57dfccSAnton Vorontsov { 3060c57dfccSAnton Vorontsov /* Actually, we can handle any amount as we use polled writes. */ 3070c57dfccSAnton Vorontsov return 2048; 3080c57dfccSAnton Vorontsov } 3090c57dfccSAnton Vorontsov 3100c57dfccSAnton Vorontsov static int kgdb_nmi_tty_write(struct tty_struct *tty, const unchar *buf, int c) 3110c57dfccSAnton Vorontsov { 3120c57dfccSAnton Vorontsov int i; 3130c57dfccSAnton Vorontsov 3140c57dfccSAnton Vorontsov for (i = 0; i < c; i++) 3150c57dfccSAnton Vorontsov dbg_io_ops->write_char(buf[i]); 3160c57dfccSAnton Vorontsov return c; 3170c57dfccSAnton Vorontsov } 3180c57dfccSAnton Vorontsov 3190c57dfccSAnton Vorontsov static const struct tty_operations kgdb_nmi_tty_ops = { 3200c57dfccSAnton Vorontsov .open = kgdb_nmi_tty_open, 3210c57dfccSAnton Vorontsov .close = kgdb_nmi_tty_close, 3220c57dfccSAnton Vorontsov .install = kgdb_nmi_tty_install, 3230c57dfccSAnton Vorontsov .cleanup = kgdb_nmi_tty_cleanup, 3240c57dfccSAnton Vorontsov .hangup = kgdb_nmi_tty_hangup, 3250c57dfccSAnton Vorontsov .write_room = kgdb_nmi_tty_write_room, 3260c57dfccSAnton Vorontsov .write = kgdb_nmi_tty_write, 3270c57dfccSAnton Vorontsov }; 3280c57dfccSAnton Vorontsov 3290c57dfccSAnton Vorontsov int kgdb_register_nmi_console(void) 3300c57dfccSAnton Vorontsov { 3310c57dfccSAnton Vorontsov int ret; 3320c57dfccSAnton Vorontsov 3330c57dfccSAnton Vorontsov if (!arch_kgdb_ops.enable_nmi) 3340c57dfccSAnton Vorontsov return 0; 3350c57dfccSAnton Vorontsov 3360c57dfccSAnton Vorontsov kgdb_nmi_tty_driver = alloc_tty_driver(1); 3370c57dfccSAnton Vorontsov if (!kgdb_nmi_tty_driver) { 3380c57dfccSAnton Vorontsov pr_err("%s: cannot allocate tty\n", __func__); 3390c57dfccSAnton Vorontsov return -ENOMEM; 3400c57dfccSAnton Vorontsov } 3410c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->driver_name = "ttyNMI"; 3420c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->name = "ttyNMI"; 3430c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->num = 1; 3440c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; 3450c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL; 3460c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->flags = TTY_DRIVER_REAL_RAW; 3470c57dfccSAnton Vorontsov kgdb_nmi_tty_driver->init_termios = tty_std_termios; 3480c57dfccSAnton Vorontsov tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios, 3490c57dfccSAnton Vorontsov KGDB_NMI_BAUD, KGDB_NMI_BAUD); 3500c57dfccSAnton Vorontsov tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops); 3510c57dfccSAnton Vorontsov 3520c57dfccSAnton Vorontsov ret = tty_register_driver(kgdb_nmi_tty_driver); 3530c57dfccSAnton Vorontsov if (ret) { 3540c57dfccSAnton Vorontsov pr_err("%s: can't register tty driver: %d\n", __func__, ret); 3550c57dfccSAnton Vorontsov goto err_drv_reg; 3560c57dfccSAnton Vorontsov } 3570c57dfccSAnton Vorontsov 3580c57dfccSAnton Vorontsov register_console(&kgdb_nmi_console); 3590c57dfccSAnton Vorontsov 3600c57dfccSAnton Vorontsov return 0; 3610c57dfccSAnton Vorontsov err_drv_reg: 3620c57dfccSAnton Vorontsov put_tty_driver(kgdb_nmi_tty_driver); 3630c57dfccSAnton Vorontsov return ret; 3640c57dfccSAnton Vorontsov } 3650c57dfccSAnton Vorontsov EXPORT_SYMBOL_GPL(kgdb_register_nmi_console); 3660c57dfccSAnton Vorontsov 3670c57dfccSAnton Vorontsov int kgdb_unregister_nmi_console(void) 3680c57dfccSAnton Vorontsov { 3690c57dfccSAnton Vorontsov int ret; 3700c57dfccSAnton Vorontsov 3710c57dfccSAnton Vorontsov if (!arch_kgdb_ops.enable_nmi) 3720c57dfccSAnton Vorontsov return 0; 3730c57dfccSAnton Vorontsov arch_kgdb_ops.enable_nmi(0); 3740c57dfccSAnton Vorontsov 3750c57dfccSAnton Vorontsov ret = unregister_console(&kgdb_nmi_console); 3760c57dfccSAnton Vorontsov if (ret) 3770c57dfccSAnton Vorontsov return ret; 3780c57dfccSAnton Vorontsov 3790c57dfccSAnton Vorontsov ret = tty_unregister_driver(kgdb_nmi_tty_driver); 3800c57dfccSAnton Vorontsov if (ret) 3810c57dfccSAnton Vorontsov return ret; 3820c57dfccSAnton Vorontsov put_tty_driver(kgdb_nmi_tty_driver); 3830c57dfccSAnton Vorontsov 3840c57dfccSAnton Vorontsov return 0; 3850c57dfccSAnton Vorontsov } 3860c57dfccSAnton Vorontsov EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console); 387