From f5316b4aea024da9266d740322a5481657f6ce59 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 20 May 2010 21:04:22 -0500 Subject: kgdb,8250,pl011: Return immediately from console poll The design of the kdb shell requires that every device that can provide input to kdb have a polling routine that exits immediately if there is no character available. This is required in order to get the page scrolling mechanism working. Changing the kernel debugger I/O API to require all polling character routines to exit immediately if there is no data allows the kernel debugger to process multiple input channels. NO_POLL_CHAR will be the return code to the polling routine when ever there is no character available. CC: linux-serial@vger.kernel.org Signed-off-by: Jason Wessel --- drivers/serial/8250.c | 4 ++-- drivers/serial/amba-pl011.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 2b1ea3d4c4f4..891e1dd65f24 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1891,8 +1891,8 @@ static int serial8250_get_poll_char(struct uart_port *port) struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned char lsr = serial_inp(up, UART_LSR); - while (!(lsr & UART_LSR_DR)) - lsr = serial_inp(up, UART_LSR); + if (!(lsr & UART_LSR_DR)) + return NO_POLL_CHAR; return serial_inp(up, UART_RX); } diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 743ebf5f16da..eb4cb480b93e 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -342,9 +342,9 @@ static int pl010_get_poll_char(struct uart_port *port) struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status; - do { - status = readw(uap->port.membase + UART01x_FR); - } while (status & UART01x_FR_RXFE); + status = readw(uap->port.membase + UART01x_FR); + if (status & UART01x_FR_RXFE) + return NO_POLL_CHAR; return readw(uap->port.membase + UART01x_DR); } -- cgit v1.2.3 From 3f255eb37e97e97dfec7cb8d4c75d543de231812 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 20 May 2010 21:04:23 -0500 Subject: sh,sh-sci: Use NO_POLL_CHAR in the SCIF polled console code The sci_poll_get_char() needs to return immediately if there is no input from the chip to process, and must return a value of NO_POLL_CHAR. This allows kgdboc to process multiple polled devices while kgdb is active. Signed-off-by: Jason Wessel Acked-by: Paul Mundt --- drivers/serial/sh-sci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/serial') diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 8d993c4cceac..f250a610a268 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -151,7 +151,11 @@ static int sci_poll_get_char(struct uart_port *port) handle_error(port); continue; } - } while (!(status & SCxSR_RDxF(port))); + break; + } while (1); + + if (!(status & SCxSR_RDxF(port))) + return NO_POLL_CHAR; c = sci_in(port, SCxRDR); -- cgit v1.2.3 From 6d45a1aed34b0cd7b298967eb9cb72b77afcb33b Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 20 May 2010 21:04:23 -0500 Subject: sparc,sunzilog: Add console polling support for sunzilog serial driver Allow kgdboc to work on sparc hardware with the Zilog serial chips. Signed-off-by: Jason Wessel Acked-by: David S. Miller --- drivers/serial/sunzilog.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 2c7a66af4f52..978b3cee02d7 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -102,6 +102,8 @@ struct uart_sunzilog_port { #endif }; +static void sunzilog_putchar(struct uart_port *port, int ch); + #define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase)) #define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT)) @@ -996,6 +998,50 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se return -EINVAL; } +#ifdef CONFIG_CONSOLE_POLL +static int sunzilog_get_poll_char(struct uart_port *port) +{ + unsigned char ch, r1; + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port; + struct zilog_channel __iomem *channel + = ZILOG_CHANNEL_FROM_PORT(&up->port); + + + r1 = read_zsreg(channel, R1); + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { + writeb(ERR_RES, &channel->control); + ZSDELAY(); + ZS_WSYNC(channel); + } + + ch = readb(&channel->control); + ZSDELAY(); + + /* This funny hack depends upon BRK_ABRT not interfering + * with the other bits we care about in R1. + */ + if (ch & BRK_ABRT) + r1 |= BRK_ABRT; + + if (!(ch & Rx_CH_AV)) + return NO_POLL_CHAR; + + ch = readb(&channel->data); + ZSDELAY(); + + ch &= up->parity_mask; + return ch; +} + +static void sunzilog_put_poll_char(struct uart_port *port, + unsigned char ch) +{ + struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port; + + sunzilog_putchar(&up->port, ch); +} +#endif /* CONFIG_CONSOLE_POLL */ + static struct uart_ops sunzilog_pops = { .tx_empty = sunzilog_tx_empty, .set_mctrl = sunzilog_set_mctrl, @@ -1013,6 +1059,10 @@ static struct uart_ops sunzilog_pops = { .request_port = sunzilog_request_port, .config_port = sunzilog_config_port, .verify_port = sunzilog_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = sunzilog_get_poll_char, + .poll_put_char = sunzilog_put_poll_char, +#endif }; static int uart_chip_count; -- cgit v1.2.3 From ada64e4c98eb5f04a9ca223c5ff9e7ac22ce6404 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 20 May 2010 21:04:24 -0500 Subject: kgdboc,keyboard: Keyboard driver for kdb with kgdb This patch adds in the kdb PS/2 keyboard driver. This was mostly a direct port from the original kdb where I cleaned up the code against checkpatch.pl and added the glue to stitch it into kgdb. This patch also enables early kdb debug via kgdbwait and the keyboard. All the access to configure kdb using either a serial console or the keyboard is done via kgdboc. If you want to use only the keyboard and want to break in early you would add to your kernel command arguments: kgdboc=kbd kgdbwait If you wanted serial and or the keyboard access you could use: kgdboc=kbd,ttyS0 You can also configure kgdboc as a kernel module or at run time with the sysfs where you can activate and deactivate kgdb. Turn it on: echo kbd,ttyS0 > /sys/module/kgdboc/parameters/kgdboc Turn it off: echo "" > /sys/module/kgdboc/parameters/kgdboc Signed-off-by: Jason Wessel Reviewed-by: Dmitry Torokhov --- drivers/serial/kgdboc.c | 61 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-) (limited to 'drivers/serial') diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index eadc1ab6bbce..ecef6e1a599a 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #define MAX_CONFIG_LEN 40 @@ -32,6 +33,40 @@ static struct kparam_string kps = { static struct tty_driver *kgdb_tty_driver; static int kgdb_tty_line; +#ifdef CONFIG_KDB_KEYBOARD +static int kgdboc_register_kbd(char **cptr) +{ + if (strncmp(*cptr, "kbd", 3) == 0) { + if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { + kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; + kdb_poll_idx++; + if (cptr[0][3] == ',') + *cptr += 4; + else + return 1; + } + } + return 0; +} + +static void kgdboc_unregister_kbd(void) +{ + int i; + + for (i = 0; i < kdb_poll_idx; i++) { + if (kdb_poll_funcs[i] == kdb_get_kbd_char) { + kdb_poll_idx--; + kdb_poll_funcs[i] = kdb_poll_funcs[kdb_poll_idx]; + kdb_poll_funcs[kdb_poll_idx] = NULL; + i--; + } + } +} +#else /* ! CONFIG_KDB_KEYBOARD */ +#define kgdboc_register_kbd(x) 0 +#define kgdboc_unregister_kbd() +#endif /* ! CONFIG_KDB_KEYBOARD */ + static int kgdboc_option_setup(char *opt) { if (strlen(opt) > MAX_CONFIG_LEN) { @@ -45,25 +80,38 @@ static int kgdboc_option_setup(char *opt) __setup("kgdboc=", kgdboc_option_setup); +static void cleanup_kgdboc(void) +{ + kgdboc_unregister_kbd(); + if (configured == 1) + kgdb_unregister_io_module(&kgdboc_io_ops); +} + static int configure_kgdboc(void) { struct tty_driver *p; int tty_line = 0; int err; + char *cptr = config; err = kgdboc_option_setup(config); if (err || !strlen(config) || isspace(config[0])) goto noconfig; err = -ENODEV; + kgdb_tty_driver = NULL; + + if (kgdboc_register_kbd(&cptr)) + goto do_register; - p = tty_find_polling_driver(config, &tty_line); + p = tty_find_polling_driver(cptr, &tty_line); if (!p) goto noconfig; kgdb_tty_driver = p; kgdb_tty_line = tty_line; +do_register: err = kgdb_register_io_module(&kgdboc_io_ops); if (err) goto noconfig; @@ -75,6 +123,7 @@ static int configure_kgdboc(void) noconfig: config[0] = 0; configured = 0; + cleanup_kgdboc(); return err; } @@ -88,20 +137,18 @@ static int __init init_kgdboc(void) return configure_kgdboc(); } -static void cleanup_kgdboc(void) -{ - if (configured == 1) - kgdb_unregister_io_module(&kgdboc_io_ops); -} - static int kgdboc_get_char(void) { + if (!kgdb_tty_driver) + return -1; return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, kgdb_tty_line); } static void kgdboc_put_char(u8 chr) { + if (!kgdb_tty_driver) + return; kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr); } -- cgit v1.2.3 From efe2f29e324fd20e0449bcd6dc6dbe4734c2ba94 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 20 May 2010 21:04:26 -0500 Subject: kgdboc,kdb: Allow kdb to work on a non open console port If kdb is open on a serial port that is not actually a console make sure to call the poll routines to emit and receive characters. Signed-off-by: Jason Wessel Acked-by: Martin Hicks --- drivers/serial/kgdboc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/serial') diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index ecef6e1a599a..b765ab48dfe7 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -16,6 +16,7 @@ #include #include #include +#include #define MAX_CONFIG_LEN 40 @@ -93,12 +94,14 @@ static int configure_kgdboc(void) int tty_line = 0; int err; char *cptr = config; + struct console *cons; err = kgdboc_option_setup(config); if (err || !strlen(config) || isspace(config[0])) goto noconfig; err = -ENODEV; + kgdboc_io_ops.is_console = 0; kgdb_tty_driver = NULL; if (kgdboc_register_kbd(&cptr)) @@ -108,6 +111,17 @@ static int configure_kgdboc(void) if (!p) goto noconfig; + cons = console_drivers; + while (cons) { + int idx; + if (cons->device && cons->device(cons, &idx) == p && + idx == tty_line) { + kgdboc_io_ops.is_console = 1; + break; + } + cons = cons->next; + } + kgdb_tty_driver = p; kgdb_tty_line = tty_line; -- cgit v1.2.3