From: Frank Rowand <frank.rowand@xxxxxxxxxxxxxx> ********************************************************** I need help with this patch - it does not fix the issue. ********************************************************** Use framework to allow msm_serial driver to fixup state after operating in polled mode, before returning to interrupt mode. I do not have complete documentation on the hardware, so this patch is a set of shots in the dark. Each experiment can be enabled by enabling a #define. The issue I am trying to resolve with this patch is: 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. msm_poll_post_exception() will be called near the tail end of kgdb_cpu_enter(), via the path invoked by: /* Call the I/O driver's post_exception routine */ if (dbg_io_ops->post_exception) dbg_io_ops->post_exception(); Not-signed-off-by-yet: Frank Rowand <frank.rowand@xxxxxxxxxxxxxx> --- drivers/tty/serial/msm_serial.c | 196 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) Index: b/drivers/tty/serial/msm_serial.c =================================================================== --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -881,6 +881,201 @@ static void msm_poll_put_char(struct uar return; } + +int zzz_poll_put_char_reset; +static void msm_poll_post_exception(struct uart_port *port) +{ + int misr; + struct msm_port *msm_port = UART_TO_MSM(port); + + zzz_poll_put_char_reset++; + + msm_port->old_snap_state = 0; + +// #define ZZZ_ALT_1 +#ifdef ZZZ_ALT_1 + /* + * zzz alternate 1 -- trigger high water after continue <---- bad + * high water count == 48, set old_snap_state = 48 + * then stale total snap == 49, so count == 1 <---- good + * + * better than alternate 2 + */ + msm_read(port, UARTDM_RX_TOTAL_SNAP); + +#if 0 + misr = msm_read(port, UART_MISR); + if (misr & (UART_IMR_RXSTALE)) +#endif + 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); +#endif /* ZZZ_ALT_1 */ + + +// #define ZZZ_ALT_2 +#ifdef ZZZ_ALT_2 + /* + * zzz alternate 2 -- trigger high water after continue <---- bad + * high water count == 48, set old_snap_state = 48 + * next total snap == 310 + * then stale total snap == 310, so count == 262 <---- bad + */ + msm_read(port, UARTDM_RX_TOTAL_SNAP); + + msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); +#endif + + +// #define ZZZ_ALT_3_4 +#ifdef ZZZ_ALT_3_4 + /* + * zzz alternate 3 -- never trigger after continue <---- bad + */ + msm_read(port, UARTDM_RX_TOTAL_SNAP); + + msm_write(port, 0xFFFFFF, UARTDM_DMRX); + msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + + msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); + +#if 0 + /* + * zzz alternate 3, #if 1 this block + * zzz alternate 4, #if 0 this block + * zzz alternate 4 -- trigger high water after continue <---- bad + * high water count == 48, set old_snap_state = 48 + * then stale total snap == 49, so count == 1 <---- good + */ + misr = msm_read(port, UART_MISR); + while (!(misr & (UART_IMR_RXSTALE))) { + cpu_relax(); + misr = msm_read(port, UART_MISR); + } +#endif + +#endif /* ZZZ_ALT_3_4 */ + + +// #define ZZZ_ALT_5 +#ifdef ZZZ_ALT_5 + /* + * zzz alternate 5 -- trigger high water after continue <---- bad + * high water count == 48, set old_snap_state = 48 + * then stale total snap == 49, so count == 1 <---- good + */ + msm_read(port, UARTDM_RX_TOTAL_SNAP); + +#if 0 + misr = msm_read(port, UART_MISR); + if (misr & (UART_IMR_RXSTALE)) +#endif + 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); + + /* zzz should not have to do this, trying anyway */ + /* restore interrupt */ + msm_write(port, msm_port->imr, UART_IMR); +#endif /* ZZZ_ALT_5 */ + + +// #define ZZZ_ALT_6 +#ifdef ZZZ_ALT_6 + /* + * zzz alternate 6 -- trigger high water after continue <---- bad + * high water count == 48, set old_snap_state = 48 + * then stale total snap == 49, so count == 1 <---- good + */ + msm_read(port, UARTDM_RX_TOTAL_SNAP); + + msm_write(port, 0, UART_IMR); /* disable interrupt */ + + misr = msm_read(port, UART_MISR); + if (misr & (UART_IMR_RXSTALE)) + 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); + + msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); + + /* restore interrupt */ + msm_write(port, msm_port->imr, UART_IMR); + +#endif /* ZZZ_ALT_6 */ + + +#define ZZZ_ALT_7 +#ifdef ZZZ_ALT_7 + /* + * Try to emulate entire interrupt driver read path.... + * + * zzzzzz what is missing that is fixed by the high water irq??? + * + * same result for versions A, B, C + * zzz alternate 7 -- trigger high water after continue <---- bad + * high water count == 48, set old_snap_state = 48 + * then stale total snap == 49, so count == 1 <---- good + */ + +{ + int imr_rx_stale; + unsigned int sr; + + /* + * zzz Grabbing a lock here will result in a deadlock if a breakpoint + * zzz is hit while the lock is held elsewhere. It would be best to + * zzz avoid this lock if possible. + * + * zzz It would be better to do a trylock and warn on failure to + * zzz acquire. + */ + spin_lock(&port->lock); + + misr = msm_read(port, UART_MISR); + imr_rx_stale = misr & UART_IMR_RXSTALE; + + msm_write(port, 0, UART_IMR); /* disable interrupt */ + + if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + + + /* zzz version A, read _either_ UARTDM_RX_TOTAL_SNAP or UART_RFWR */ + /* zzz version B, read UARTDM_RX_TOTAL_SNAP and UART_RFWR */ + /* zzz version C, read UART_RFWR */ + if (imr_rx_stale) + msm_read(port, UARTDM_RX_TOTAL_SNAP); + else + msm_read(port, UART_RFWR); + + sr = msm_read(port, UART_SR); + /* zzz this could be: while (sr & ...) {UARTDM_RF; UART_SR;} */ + while ((sr & UART_SR_RX_READY) != 0) { + msm_read(port, UARTDM_RF); + sr = msm_read(port, UART_SR); + } + + 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); + + msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ + + spin_unlock(&port->lock); +} + +#endif /* ZZZ_ALT_7 */ + + + + return; +} + + + #endif static struct uart_ops msm_uart_pops = { @@ -905,6 +1100,7 @@ static struct uart_ops msm_uart_pops = { .poll_init = msm_poll_init, .poll_get_char = msm_poll_get_char, .poll_put_char = msm_poll_put_char, + .poll_post_exception = msm_poll_post_exception, #endif }; -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html