diff options
author | Daniel Thompson <daniel.thompson@linaro.org> | 2014-07-16 09:30:13 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-17 21:19:40 -0400 |
commit | c8b29f049eb2645dd21e40a6613c09f15c731650 (patch) | |
tree | 1068dcafa1bcbe2959c4696fa8c010e9cdc7b51a /drivers/tty | |
parent | 3d1c90d48cbe335a47a6a5a05ff731a86eacf6fb (diff) |
tty: kgdb_nmi: Automatically manage tty enable
At present it is not possible to boot with the ttyNMI0 console treating
character input normally, instead character input triggers a prompt
telling the user how to trigger the knock detector and enter the
debugger. To use the console normally requires that kdb be entered and
the nmi_console command be used to enable the console (or if only kgdb
is present then gdb must directly manipulate the value of
kgdb_nmi_tty_enabled).
This patch automates the management of kgdb_nmi_tty_enabled by keeping
track of the number of file handles that are open for reading and using
that to determine how to tty should operate.
The approach means that:
1. Behaviour before init starts is unchanged.
2. If the userspace runs a getty or some other interactive process on
/dev/console (or explicitly on /dev/ttyNMI0) the tty will treat
character input like any other tty.
3. If the userspace doesn't use /dev/console or if it uses /dev/console
only to log messages (O_WRONLY) then the user prompt is retained.
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
Cc: Jason Wessel <jason.wessel@windriver.com>
Cc: kgdb-bugreport@lists.sourceforge.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/kgdb_nmi.c | 36 |
1 files changed, 15 insertions, 21 deletions
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index cfadf2971b12..6ec7501b464d 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c | |||
@@ -42,7 +42,7 @@ static char *kgdb_nmi_magic = "$3#33"; | |||
42 | module_param_named(magic, kgdb_nmi_magic, charp, 0600); | 42 | module_param_named(magic, kgdb_nmi_magic, charp, 0600); |
43 | MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)"); | 43 | MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)"); |
44 | 44 | ||
45 | static bool kgdb_nmi_tty_enabled; | 45 | static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0); |
46 | 46 | ||
47 | static int kgdb_nmi_console_setup(struct console *co, char *options) | 47 | static int kgdb_nmi_console_setup(struct console *co, char *options) |
48 | { | 48 | { |
@@ -136,7 +136,7 @@ static int kgdb_nmi_poll_one_knock(void) | |||
136 | n = 0; | 136 | n = 0; |
137 | } | 137 | } |
138 | 138 | ||
139 | if (kgdb_nmi_tty_enabled) { | 139 | if (atomic_read(&kgdb_nmi_num_readers)) { |
140 | kgdb_tty_recv(c); | 140 | kgdb_tty_recv(c); |
141 | return 0; | 141 | return 0; |
142 | } | 142 | } |
@@ -197,7 +197,8 @@ static void kgdb_nmi_tty_receiver(unsigned long data) | |||
197 | priv->timer.expires = jiffies + (HZ/100); | 197 | priv->timer.expires = jiffies + (HZ/100); |
198 | add_timer(&priv->timer); | 198 | add_timer(&priv->timer); |
199 | 199 | ||
200 | if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo))) | 200 | if (likely(!atomic_read(&kgdb_nmi_num_readers) || |
201 | !kfifo_len(&priv->fifo))) | ||
201 | return; | 202 | return; |
202 | 203 | ||
203 | while (kfifo_out(&priv->fifo, &ch, 1)) | 204 | while (kfifo_out(&priv->fifo, &ch, 1)) |
@@ -270,13 +271,23 @@ static void kgdb_nmi_tty_cleanup(struct tty_struct *tty) | |||
270 | static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file) | 271 | static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file) |
271 | { | 272 | { |
272 | struct kgdb_nmi_tty_priv *priv = tty->driver_data; | 273 | struct kgdb_nmi_tty_priv *priv = tty->driver_data; |
274 | unsigned int mode = file->f_flags & O_ACCMODE; | ||
275 | int ret; | ||
276 | |||
277 | ret = tty_port_open(&priv->port, tty, file); | ||
278 | if (!ret && (mode == O_RDONLY || mode == O_RDWR)) | ||
279 | atomic_inc(&kgdb_nmi_num_readers); | ||
273 | 280 | ||
274 | return tty_port_open(&priv->port, tty, file); | 281 | return ret; |
275 | } | 282 | } |
276 | 283 | ||
277 | static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file) | 284 | static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file) |
278 | { | 285 | { |
279 | struct kgdb_nmi_tty_priv *priv = tty->driver_data; | 286 | struct kgdb_nmi_tty_priv *priv = tty->driver_data; |
287 | unsigned int mode = file->f_flags & O_ACCMODE; | ||
288 | |||
289 | if (mode == O_RDONLY || mode == O_RDWR) | ||
290 | atomic_dec(&kgdb_nmi_num_readers); | ||
280 | 291 | ||
281 | tty_port_close(&priv->port, tty, file); | 292 | tty_port_close(&priv->port, tty, file); |
282 | } | 293 | } |
@@ -313,12 +324,6 @@ static const struct tty_operations kgdb_nmi_tty_ops = { | |||
313 | .write = kgdb_nmi_tty_write, | 324 | .write = kgdb_nmi_tty_write, |
314 | }; | 325 | }; |
315 | 326 | ||
316 | static int kgdb_nmi_enable_console(int argc, const char *argv[]) | ||
317 | { | ||
318 | kgdb_nmi_tty_enabled = !(argc == 1 && !strcmp(argv[1], "off")); | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | int kgdb_register_nmi_console(void) | 327 | int kgdb_register_nmi_console(void) |
323 | { | 328 | { |
324 | int ret; | 329 | int ret; |
@@ -348,19 +353,10 @@ int kgdb_register_nmi_console(void) | |||
348 | goto err_drv_reg; | 353 | goto err_drv_reg; |
349 | } | 354 | } |
350 | 355 | ||
351 | ret = kdb_register("nmi_console", kgdb_nmi_enable_console, "[off]", | ||
352 | "switch to Linux NMI console", 0); | ||
353 | if (ret) { | ||
354 | pr_err("%s: can't register kdb command: %d\n", __func__, ret); | ||
355 | goto err_kdb_reg; | ||
356 | } | ||
357 | |||
358 | register_console(&kgdb_nmi_console); | 356 | register_console(&kgdb_nmi_console); |
359 | arch_kgdb_ops.enable_nmi(1); | 357 | arch_kgdb_ops.enable_nmi(1); |
360 | 358 | ||
361 | return 0; | 359 | return 0; |
362 | err_kdb_reg: | ||
363 | tty_unregister_driver(kgdb_nmi_tty_driver); | ||
364 | err_drv_reg: | 360 | err_drv_reg: |
365 | put_tty_driver(kgdb_nmi_tty_driver); | 361 | put_tty_driver(kgdb_nmi_tty_driver); |
366 | return ret; | 362 | return ret; |
@@ -375,8 +371,6 @@ int kgdb_unregister_nmi_console(void) | |||
375 | return 0; | 371 | return 0; |
376 | arch_kgdb_ops.enable_nmi(0); | 372 | arch_kgdb_ops.enable_nmi(0); |
377 | 373 | ||
378 | kdb_unregister("nmi_console"); | ||
379 | |||
380 | ret = unregister_console(&kgdb_nmi_console); | 374 | ret = unregister_console(&kgdb_nmi_console); |
381 | if (ret) | 375 | if (ret) |
382 | return ret; | 376 | return ret; |