MN10300: Allow KGDB to use the MN10300 serial ports
authorDavid Howells <dhowells@redhat.com>
Fri, 18 Mar 2011 16:54:32 +0000 (16:54 +0000)
committerDavid Howells <dhowells@redhat.com>
Fri, 18 Mar 2011 16:54:32 +0000 (16:54 +0000)
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>
arch/mn10300/kernel/mn10300-serial.c

index 93c5373..efca426 100644 (file)
@@ -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 */