From: Frank Rowand <frank.row...@sonymobile.com>

f7e54d7ad743 added support for poll_{get,put}_char()
Additional fixes to cope with single character mode on RX FIFO for
qcom,msm-uartdm-v1.4.

With these fixes, kgdb properly communicates with the dragon board, but
following the continue command, the serial driver does not get any stale
(UART_IMR_RXSTALE) interrupts until 48 characters have been read, which
triggers a high water interrupt.  After the high water interrupt has been
processed, the driver resumes properly getting stale interrupts.

Not-signed-off-by-yet: Frank Rowand <frank.row...@sonymobile.com>

---
 drivers/tty/serial/msm_serial.c |   74 ++++++++++++++++++++++++++++++++--------
 1 file changed, 61 insertions(+), 13 deletions(-)

Index: b/drivers/tty/serial/msm_serial.c
===================================================================
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -54,6 +54,7 @@ struct msm_port {
        unsigned int            imr;
        void __iomem            *gsbi_base;
        int                     is_uartdm;
+       int                     rx_sc_enabled;
        unsigned int            old_snap_state;
 };
 
@@ -104,7 +105,10 @@ static void handle_rx_dm(struct uart_por
        struct tty_port *tport = &port->state->port;
        unsigned int sr;
        int count = 0;
+       int imr_rx_stale = misr & UART_IMR_RXSTALE;
        struct msm_port *msm_port = UART_TO_MSM(port);
+       int res;
+       char *cp;
 
        if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
                port->icount.overrun++;
@@ -112,12 +116,14 @@ static void handle_rx_dm(struct uart_por
                msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
        }
 
-       if (misr & UART_IMR_RXSTALE) {
+       if (imr_rx_stale) {
                count = msm_read(port, UARTDM_RX_TOTAL_SNAP) -
                        msm_port->old_snap_state;
                msm_port->old_snap_state = 0;
        } else {
-               count = 4 * (msm_read(port, UART_RFWR));
+               count = msm_read(port, UART_RFWR);
+               if (!msm_port->rx_sc_enabled)
+                       count = 4 * count;
                msm_port->old_snap_state += count;
        }
 
@@ -130,28 +136,60 @@ static void handle_rx_dm(struct uart_por
 
                sr = msm_read(port, UART_SR);
                if ((sr & UART_SR_RX_READY) == 0) {
-                       msm_port->old_snap_state -= count;
+                       if (!imr_rx_stale)
+                               msm_port->old_snap_state -= count;
                        break;
                }
+
                c = msm_read(port, UARTDM_RF);
+
                if (sr & UART_SR_RX_BREAK) {
                        port->icount.brk++;
-                       if (uart_handle_break(port))
-                               continue;
+                       uart_handle_break(port);
+                       if (msm_port->rx_sc_enabled)
+                               count -= 1;
+                       else
+                               count -= 4;
+                       continue;
                } else if (sr & UART_SR_PAR_FRAME_ERR)
                        port->icount.frame++;
 
-               /* TODO: handle sysrq */
-               tty_insert_flip_string(tport, (char *)&c,
-                                      (count > 4) ? 4 : count);
-               count -= 4;
+               if (msm_port->rx_sc_enabled) {
+                       cp = (char *)&c;
+
+                       spin_unlock(&port->lock);
+                       res = uart_handle_sysrq_char(port, *cp);
+                       spin_lock(&port->lock);
+
+                       if (!res)
+                               tty_insert_flip_string(tport, cp, 1);
+                       count -= 1;
+               } else {
+                       cp = (char *)&c;
+
+                       spin_unlock(&port->lock);
+                       res = uart_handle_sysrq_char(port, *cp);
+                       spin_lock(&port->lock);
+
+                       if (res) {
+                               count -= 1;
+                               cp++;
+                               tty_insert_flip_string(tport, cp,
+                                              (count > 3) ? 3 : count);
+                               count -= 3;
+                       } else {
+                               tty_insert_flip_string(tport, cp,
+                                                      (count > 4) ? 4 : count);
+                               count -= 4;
+                       }
+               }
        }
 
        spin_unlock(&port->lock);
        tty_flip_buffer_push(tport);
        spin_lock(&port->lock);
 
-       if (misr & (UART_IMR_RXSTALE))
+       if (imr_rx_stale)
                msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
        msm_write(port, 0xFFFFFF, UARTDM_DMRX);
        msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
@@ -413,8 +451,11 @@ static int msm_set_baud_rate(struct uart
        watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
        msm_write(port, watermark, UART_IPR);
 
-       /* set RX watermark */
-       watermark = (port->fifosize * 3) / 4;
+       /* set RX watermark (number of words) */
+       if (msm_port->rx_sc_enabled)
+               watermark = (port->fifosize * 3) / 4;  /* 1 byte per word */
+       else
+               watermark = (port->fifosize * 3) / 16;  /* 4 bytes per word */
        msm_write(port, watermark, UART_RFWR);
 
        /* set TX watermark */
@@ -728,10 +769,17 @@ static void msm_power(struct uart_port *
 static int msm_poll_init(struct uart_port *port)
 {
        struct msm_port *msm_port = UART_TO_MSM(port);
+       unsigned int watermark;
 
        /* Enable single character mode on RX FIFO */
-       if (msm_port->is_uartdm >= UARTDM_1P4)
+       if (msm_port->is_uartdm >= UARTDM_1P4) {
                msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN);
+               msm_port->rx_sc_enabled = 1;
+       }
+
+       /* set RX watermark (number of words) */
+       watermark = (port->fifosize * 3) / 4;  /* 1 byte per word */
+       msm_write(port, watermark, UART_RFWR);
 
        return 0;
 }
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to