xref: /OK3568_Linux_fs/kernel/drivers/tty/serial/kgdb_nmi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * KGDB NMI serial console
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2010 Google, Inc.
6*4882a593Smuzhiyun  *		  Arve Hjønnevåg <arve@android.com>
7*4882a593Smuzhiyun  *		  Colin Cross <ccross@android.com>
8*4882a593Smuzhiyun  * Copyright 2012 Linaro Ltd.
9*4882a593Smuzhiyun  *		  Anton Vorontsov <anton.vorontsov@linaro.org>
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/compiler.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/errno.h>
17*4882a593Smuzhiyun #include <linux/atomic.h>
18*4882a593Smuzhiyun #include <linux/console.h>
19*4882a593Smuzhiyun #include <linux/tty.h>
20*4882a593Smuzhiyun #include <linux/tty_driver.h>
21*4882a593Smuzhiyun #include <linux/tty_flip.h>
22*4882a593Smuzhiyun #include <linux/serial_core.h>
23*4882a593Smuzhiyun #include <linux/interrupt.h>
24*4882a593Smuzhiyun #include <linux/hrtimer.h>
25*4882a593Smuzhiyun #include <linux/tick.h>
26*4882a593Smuzhiyun #include <linux/kfifo.h>
27*4882a593Smuzhiyun #include <linux/kgdb.h>
28*4882a593Smuzhiyun #include <linux/kdb.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static int kgdb_nmi_knock = 1;
31*4882a593Smuzhiyun module_param_named(knock, kgdb_nmi_knock, int, 0600);
32*4882a593Smuzhiyun MODULE_PARM_DESC(knock, "if set to 1 (default), the special '$3#33' command " \
33*4882a593Smuzhiyun 			"must be used to enter the debugger; when set to 0, " \
34*4882a593Smuzhiyun 			"hitting return key is enough to enter the debugger; " \
35*4882a593Smuzhiyun 			"when set to -1, the debugger is entered immediately " \
36*4882a593Smuzhiyun 			"upon NMI");
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun static char *kgdb_nmi_magic = "$3#33";
39*4882a593Smuzhiyun module_param_named(magic, kgdb_nmi_magic, charp, 0600);
40*4882a593Smuzhiyun MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
43*4882a593Smuzhiyun 
kgdb_nmi_console_setup(struct console * co,char * options)44*4882a593Smuzhiyun static int kgdb_nmi_console_setup(struct console *co, char *options)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	arch_kgdb_ops.enable_nmi(1);
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	/* The NMI console uses the dbg_io_ops to issue console messages. To
49*4882a593Smuzhiyun 	 * avoid duplicate messages during kdb sessions we must inform kdb's
50*4882a593Smuzhiyun 	 * I/O utilities that messages sent to the console will automatically
51*4882a593Smuzhiyun 	 * be displayed on the dbg_io.
52*4882a593Smuzhiyun 	 */
53*4882a593Smuzhiyun 	dbg_io_ops->cons = co;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
kgdb_nmi_console_write(struct console * co,const char * s,uint c)58*4882a593Smuzhiyun static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	int i;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	for (i = 0; i < c; i++)
63*4882a593Smuzhiyun 		dbg_io_ops->write_char(s[i]);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun static struct tty_driver *kgdb_nmi_tty_driver;
67*4882a593Smuzhiyun 
kgdb_nmi_console_device(struct console * co,int * idx)68*4882a593Smuzhiyun static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	*idx = co->index;
71*4882a593Smuzhiyun 	return kgdb_nmi_tty_driver;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun static struct console kgdb_nmi_console = {
75*4882a593Smuzhiyun 	.name	= "ttyNMI",
76*4882a593Smuzhiyun 	.setup  = kgdb_nmi_console_setup,
77*4882a593Smuzhiyun 	.write	= kgdb_nmi_console_write,
78*4882a593Smuzhiyun 	.device	= kgdb_nmi_console_device,
79*4882a593Smuzhiyun 	.flags	= CON_PRINTBUFFER | CON_ANYTIME,
80*4882a593Smuzhiyun 	.index	= -1,
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /*
84*4882a593Smuzhiyun  * This is usually the maximum rate on debug ports. We make fifo large enough
85*4882a593Smuzhiyun  * to make copy-pasting to the terminal usable.
86*4882a593Smuzhiyun  */
87*4882a593Smuzhiyun #define KGDB_NMI_BAUD		115200
88*4882a593Smuzhiyun #define KGDB_NMI_FIFO_SIZE	roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ)
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun struct kgdb_nmi_tty_priv {
91*4882a593Smuzhiyun 	struct tty_port port;
92*4882a593Smuzhiyun 	struct timer_list timer;
93*4882a593Smuzhiyun 	STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
94*4882a593Smuzhiyun };
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun static struct tty_port *kgdb_nmi_port;
97*4882a593Smuzhiyun 
kgdb_tty_recv(int ch)98*4882a593Smuzhiyun static void kgdb_tty_recv(int ch)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv;
101*4882a593Smuzhiyun 	char c = ch;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if (!kgdb_nmi_port || ch < 0)
104*4882a593Smuzhiyun 		return;
105*4882a593Smuzhiyun 	/*
106*4882a593Smuzhiyun 	 * Can't use port->tty->driver_data as tty might be not there. Timer
107*4882a593Smuzhiyun 	 * will check for tty and will get the ref, but here we don't have to
108*4882a593Smuzhiyun 	 * do that, and actually, we can't: we're in NMI context, no locks are
109*4882a593Smuzhiyun 	 * possible.
110*4882a593Smuzhiyun 	 */
111*4882a593Smuzhiyun 	priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port);
112*4882a593Smuzhiyun 	kfifo_in(&priv->fifo, &c, 1);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
kgdb_nmi_poll_one_knock(void)115*4882a593Smuzhiyun static int kgdb_nmi_poll_one_knock(void)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	static int n;
118*4882a593Smuzhiyun 	int c = -1;
119*4882a593Smuzhiyun 	const char *magic = kgdb_nmi_magic;
120*4882a593Smuzhiyun 	size_t m = strlen(magic);
121*4882a593Smuzhiyun 	bool printch = false;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	c = dbg_io_ops->read_char();
124*4882a593Smuzhiyun 	if (c == NO_POLL_CHAR)
125*4882a593Smuzhiyun 		return c;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	if (!kgdb_nmi_knock && (c == '\r' || c == '\n')) {
128*4882a593Smuzhiyun 		return 1;
129*4882a593Smuzhiyun 	} else if (c == magic[n]) {
130*4882a593Smuzhiyun 		n = (n + 1) % m;
131*4882a593Smuzhiyun 		if (!n)
132*4882a593Smuzhiyun 			return 1;
133*4882a593Smuzhiyun 		printch = true;
134*4882a593Smuzhiyun 	} else {
135*4882a593Smuzhiyun 		n = 0;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	if (atomic_read(&kgdb_nmi_num_readers)) {
139*4882a593Smuzhiyun 		kgdb_tty_recv(c);
140*4882a593Smuzhiyun 		return 0;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (printch) {
144*4882a593Smuzhiyun 		kdb_printf("%c", c);
145*4882a593Smuzhiyun 		return 0;
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	kdb_printf("\r%s %s to enter the debugger> %*s",
149*4882a593Smuzhiyun 		   kgdb_nmi_knock ? "Type" : "Hit",
150*4882a593Smuzhiyun 		   kgdb_nmi_knock ? magic  : "<return>", (int)m, "");
151*4882a593Smuzhiyun 	while (m--)
152*4882a593Smuzhiyun 		kdb_printf("\b");
153*4882a593Smuzhiyun 	return 0;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun /**
157*4882a593Smuzhiyun  * kgdb_nmi_poll_knock - Check if it is time to enter the debugger
158*4882a593Smuzhiyun  *
159*4882a593Smuzhiyun  * "Serial ports are often noisy, especially when muxed over another port (we
160*4882a593Smuzhiyun  * often use serial over the headset connector). Noise on the async command
161*4882a593Smuzhiyun  * line just causes characters that are ignored, on a command line that blocked
162*4882a593Smuzhiyun  * execution noise would be catastrophic." -- Colin Cross
163*4882a593Smuzhiyun  *
164*4882a593Smuzhiyun  * So, this function implements KGDB/KDB knocking on the serial line: we won't
165*4882a593Smuzhiyun  * enter the debugger until we receive a known magic phrase (which is actually
166*4882a593Smuzhiyun  * "$3#33", known as "escape to KDB" command. There is also a relaxed variant
167*4882a593Smuzhiyun  * of knocking, i.e. just pressing the return key is enough to enter the
168*4882a593Smuzhiyun  * debugger. And if knocking is disabled, the function always returns 1.
169*4882a593Smuzhiyun  */
kgdb_nmi_poll_knock(void)170*4882a593Smuzhiyun bool kgdb_nmi_poll_knock(void)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	if (kgdb_nmi_knock < 0)
173*4882a593Smuzhiyun 		return true;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	while (1) {
176*4882a593Smuzhiyun 		int ret;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 		ret = kgdb_nmi_poll_one_knock();
179*4882a593Smuzhiyun 		if (ret == NO_POLL_CHAR)
180*4882a593Smuzhiyun 			return false;
181*4882a593Smuzhiyun 		else if (ret == 1)
182*4882a593Smuzhiyun 			break;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 	return true;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun /*
188*4882a593Smuzhiyun  * The tasklet is cheap, it does not cause wakeups when reschedules itself,
189*4882a593Smuzhiyun  * instead it waits for the next tick.
190*4882a593Smuzhiyun  */
kgdb_nmi_tty_receiver(struct timer_list * t)191*4882a593Smuzhiyun static void kgdb_nmi_tty_receiver(struct timer_list *t)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv = from_timer(priv, t, timer);
194*4882a593Smuzhiyun 	char ch;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	priv->timer.expires = jiffies + (HZ/100);
197*4882a593Smuzhiyun 	add_timer(&priv->timer);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (likely(!atomic_read(&kgdb_nmi_num_readers) ||
200*4882a593Smuzhiyun 		   !kfifo_len(&priv->fifo)))
201*4882a593Smuzhiyun 		return;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	while (kfifo_out(&priv->fifo, &ch, 1))
204*4882a593Smuzhiyun 		tty_insert_flip_char(&priv->port, ch, TTY_NORMAL);
205*4882a593Smuzhiyun 	tty_flip_buffer_push(&priv->port);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
kgdb_nmi_tty_activate(struct tty_port * port,struct tty_struct * tty)208*4882a593Smuzhiyun static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv =
211*4882a593Smuzhiyun 	    container_of(port, struct kgdb_nmi_tty_priv, port);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	kgdb_nmi_port = port;
214*4882a593Smuzhiyun 	priv->timer.expires = jiffies + (HZ/100);
215*4882a593Smuzhiyun 	add_timer(&priv->timer);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
kgdb_nmi_tty_shutdown(struct tty_port * port)220*4882a593Smuzhiyun static void kgdb_nmi_tty_shutdown(struct tty_port *port)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv =
223*4882a593Smuzhiyun 	    container_of(port, struct kgdb_nmi_tty_priv, port);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	del_timer(&priv->timer);
226*4882a593Smuzhiyun 	kgdb_nmi_port = NULL;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun static const struct tty_port_operations kgdb_nmi_tty_port_ops = {
230*4882a593Smuzhiyun 	.activate	= kgdb_nmi_tty_activate,
231*4882a593Smuzhiyun 	.shutdown	= kgdb_nmi_tty_shutdown,
232*4882a593Smuzhiyun };
233*4882a593Smuzhiyun 
kgdb_nmi_tty_install(struct tty_driver * drv,struct tty_struct * tty)234*4882a593Smuzhiyun static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv;
237*4882a593Smuzhiyun 	int ret;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
240*4882a593Smuzhiyun 	if (!priv)
241*4882a593Smuzhiyun 		return -ENOMEM;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	INIT_KFIFO(priv->fifo);
244*4882a593Smuzhiyun 	timer_setup(&priv->timer, kgdb_nmi_tty_receiver, 0);
245*4882a593Smuzhiyun 	tty_port_init(&priv->port);
246*4882a593Smuzhiyun 	priv->port.ops = &kgdb_nmi_tty_port_ops;
247*4882a593Smuzhiyun 	tty->driver_data = priv;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	ret = tty_port_install(&priv->port, drv, tty);
250*4882a593Smuzhiyun 	if (ret) {
251*4882a593Smuzhiyun 		pr_err("%s: can't install tty port: %d\n", __func__, ret);
252*4882a593Smuzhiyun 		goto err;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 	return 0;
255*4882a593Smuzhiyun err:
256*4882a593Smuzhiyun 	tty_port_destroy(&priv->port);
257*4882a593Smuzhiyun 	kfree(priv);
258*4882a593Smuzhiyun 	return ret;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
kgdb_nmi_tty_cleanup(struct tty_struct * tty)261*4882a593Smuzhiyun static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	tty->driver_data = NULL;
266*4882a593Smuzhiyun 	tty_port_destroy(&priv->port);
267*4882a593Smuzhiyun 	kfree(priv);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
kgdb_nmi_tty_open(struct tty_struct * tty,struct file * file)270*4882a593Smuzhiyun static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
273*4882a593Smuzhiyun 	unsigned int mode = file->f_flags & O_ACCMODE;
274*4882a593Smuzhiyun 	int ret;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	ret = tty_port_open(&priv->port, tty, file);
277*4882a593Smuzhiyun 	if (!ret && (mode == O_RDONLY || mode == O_RDWR))
278*4882a593Smuzhiyun 		atomic_inc(&kgdb_nmi_num_readers);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	return ret;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
kgdb_nmi_tty_close(struct tty_struct * tty,struct file * file)283*4882a593Smuzhiyun static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
286*4882a593Smuzhiyun 	unsigned int mode = file->f_flags & O_ACCMODE;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	if (mode == O_RDONLY || mode == O_RDWR)
289*4882a593Smuzhiyun 		atomic_dec(&kgdb_nmi_num_readers);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	tty_port_close(&priv->port, tty, file);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
kgdb_nmi_tty_hangup(struct tty_struct * tty)294*4882a593Smuzhiyun static void kgdb_nmi_tty_hangup(struct tty_struct *tty)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct kgdb_nmi_tty_priv *priv = tty->driver_data;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	tty_port_hangup(&priv->port);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
kgdb_nmi_tty_write_room(struct tty_struct * tty)301*4882a593Smuzhiyun static int kgdb_nmi_tty_write_room(struct tty_struct *tty)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	/* Actually, we can handle any amount as we use polled writes. */
304*4882a593Smuzhiyun 	return 2048;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
kgdb_nmi_tty_write(struct tty_struct * tty,const unchar * buf,int c)307*4882a593Smuzhiyun static int kgdb_nmi_tty_write(struct tty_struct *tty, const unchar *buf, int c)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	int i;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	for (i = 0; i < c; i++)
312*4882a593Smuzhiyun 		dbg_io_ops->write_char(buf[i]);
313*4882a593Smuzhiyun 	return c;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun static const struct tty_operations kgdb_nmi_tty_ops = {
317*4882a593Smuzhiyun 	.open		= kgdb_nmi_tty_open,
318*4882a593Smuzhiyun 	.close		= kgdb_nmi_tty_close,
319*4882a593Smuzhiyun 	.install	= kgdb_nmi_tty_install,
320*4882a593Smuzhiyun 	.cleanup	= kgdb_nmi_tty_cleanup,
321*4882a593Smuzhiyun 	.hangup		= kgdb_nmi_tty_hangup,
322*4882a593Smuzhiyun 	.write_room	= kgdb_nmi_tty_write_room,
323*4882a593Smuzhiyun 	.write		= kgdb_nmi_tty_write,
324*4882a593Smuzhiyun };
325*4882a593Smuzhiyun 
kgdb_register_nmi_console(void)326*4882a593Smuzhiyun int kgdb_register_nmi_console(void)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	int ret;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (!arch_kgdb_ops.enable_nmi)
331*4882a593Smuzhiyun 		return 0;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	kgdb_nmi_tty_driver = alloc_tty_driver(1);
334*4882a593Smuzhiyun 	if (!kgdb_nmi_tty_driver) {
335*4882a593Smuzhiyun 		pr_err("%s: cannot allocate tty\n", __func__);
336*4882a593Smuzhiyun 		return -ENOMEM;
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun 	kgdb_nmi_tty_driver->driver_name	= "ttyNMI";
339*4882a593Smuzhiyun 	kgdb_nmi_tty_driver->name		= "ttyNMI";
340*4882a593Smuzhiyun 	kgdb_nmi_tty_driver->num		= 1;
341*4882a593Smuzhiyun 	kgdb_nmi_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
342*4882a593Smuzhiyun 	kgdb_nmi_tty_driver->subtype		= SERIAL_TYPE_NORMAL;
343*4882a593Smuzhiyun 	kgdb_nmi_tty_driver->flags		= TTY_DRIVER_REAL_RAW;
344*4882a593Smuzhiyun 	kgdb_nmi_tty_driver->init_termios	= tty_std_termios;
345*4882a593Smuzhiyun 	tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,
346*4882a593Smuzhiyun 				     KGDB_NMI_BAUD, KGDB_NMI_BAUD);
347*4882a593Smuzhiyun 	tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	ret = tty_register_driver(kgdb_nmi_tty_driver);
350*4882a593Smuzhiyun 	if (ret) {
351*4882a593Smuzhiyun 		pr_err("%s: can't register tty driver: %d\n", __func__, ret);
352*4882a593Smuzhiyun 		goto err_drv_reg;
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	register_console(&kgdb_nmi_console);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	return 0;
358*4882a593Smuzhiyun err_drv_reg:
359*4882a593Smuzhiyun 	put_tty_driver(kgdb_nmi_tty_driver);
360*4882a593Smuzhiyun 	return ret;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);
363*4882a593Smuzhiyun 
kgdb_unregister_nmi_console(void)364*4882a593Smuzhiyun int kgdb_unregister_nmi_console(void)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	int ret;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	if (!arch_kgdb_ops.enable_nmi)
369*4882a593Smuzhiyun 		return 0;
370*4882a593Smuzhiyun 	arch_kgdb_ops.enable_nmi(0);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	ret = unregister_console(&kgdb_nmi_console);
373*4882a593Smuzhiyun 	if (ret)
374*4882a593Smuzhiyun 		return ret;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	ret = tty_unregister_driver(kgdb_nmi_tty_driver);
377*4882a593Smuzhiyun 	if (ret)
378*4882a593Smuzhiyun 		return ret;
379*4882a593Smuzhiyun 	put_tty_driver(kgdb_nmi_tty_driver);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	return 0;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console);
384