diff options
author | David Howells <dhowells@redhat.com> | 2011-03-18 17:54:32 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2011-03-18 17:54:32 +0100 |
commit | 52885b32a5f7326d9505ca45969a695bad2459c4 (patch) | |
tree | a849c4dfad098fc42a9b5b74dcd23931cc662c00 | |
parent | MN10300: Emulate single stepping in KGDB on MN10300 (diff) | |
download | linux-52885b32a5f7326d9505ca45969a695bad2459c4.tar.xz linux-52885b32a5f7326d9505ca45969a695bad2459c4.zip |
MN10300: Allow KGDB to use the MN10300 serial ports
Allow KGDB to use the MN10300 serial ports through the polled I/O interface
provided via the TTY/serial layer and the kgdboc driver. This allows the
kernel to be started with something like:
kgdboc=ttySM0,115200
added to the command line.
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | arch/mn10300/kernel/mn10300-serial.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c index 93c53739cfc9..efca426a2ed4 100644 --- a/arch/mn10300/kernel/mn10300-serial.c +++ b/arch/mn10300/kernel/mn10300-serial.c @@ -119,6 +119,10 @@ static int mn10300_serial_request_port(struct uart_port *); static void mn10300_serial_config_port(struct uart_port *, int); static int mn10300_serial_verify_port(struct uart_port *, struct serial_struct *); +#ifdef CONFIG_CONSOLE_POLL +static void mn10300_serial_poll_put_char(struct uart_port *, unsigned char); +static int mn10300_serial_poll_get_char(struct uart_port *); +#endif static const struct uart_ops mn10300_serial_ops = { .tx_empty = mn10300_serial_tx_empty, @@ -138,6 +142,10 @@ static const struct uart_ops mn10300_serial_ops = { .request_port = mn10300_serial_request_port, .config_port = mn10300_serial_config_port, .verify_port = mn10300_serial_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_put_char = mn10300_serial_poll_put_char, + .poll_get_char = mn10300_serial_poll_get_char, +#endif }; static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id); @@ -1634,3 +1642,70 @@ static int __init mn10300_serial_console_init(void) console_initcall(mn10300_serial_console_init); #endif + +#ifdef CONFIG_CONSOLE_POLL +/* + * Polled character reception for the kernel debugger + */ +static int mn10300_serial_poll_get_char(struct uart_port *_port) +{ + struct mn10300_serial_port *port = + container_of(_port, struct mn10300_serial_port, uart); + unsigned ix; + u8 st, ch; + + _enter("%s", port->name); + + do { + /* pull chars out of the hat */ + ix = port->rx_outp; + if (ix == port->rx_inp) + return NO_POLL_CHAR; + + ch = port->rx_buffer[ix++]; + st = port->rx_buffer[ix++]; + smp_rmb(); + port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1); + + } while (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF)); + + return ch; +} + + +/* + * Polled character transmission for the kernel debugger + */ +static void mn10300_serial_poll_put_char(struct uart_port *_port, + unsigned char ch) +{ + struct mn10300_serial_port *port = + container_of(_port, struct mn10300_serial_port, uart); + u8 intr, tmp; + + /* wait for the transmitter to finish anything it might be doing (and + * this includes the virtual DMA handler, so it might take a while) */ + while (*port->_status & (SC01STR_TBF | SC01STR_TXF)) + continue; + + /* disable the Tx ready interrupt */ + intr = *port->_intr; + *port->_intr = intr & ~SC01ICR_TI; + tmp = *port->_intr; + + if (ch == 0x0a) { + *(u8 *) port->_txb = 0x0d; + while (*port->_status & SC01STR_TBF) + continue; + } + + *(u8 *) port->_txb = ch; + while (*port->_status & SC01STR_TBF) + continue; + + /* restore the Tx interrupt flag */ + *port->_intr = intr; + tmp = *port->_intr; +} + +#endif /* CONFIG_CONSOLE_POLL */ |