[test patch 1/4] fix msm_serial for kgdb

From: Frank Rowand
Date: Mon Aug 04 2014 - 21:03:15 EST


From: Frank Rowand <frank.rowand@xxxxxxxxxxxxxx>

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.rowand@xxxxxxxxxxxxxx>

---
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/