* [test patch 1/4] fix msm_serial for kgdb
2014-08-05 0:59 [request for help] tty: serial: kgdb: fix msm_serial for kgdb Frank Rowand
@ 2014-08-05 1:03 ` Frank Rowand
2014-08-05 1:04 ` [test patch 2/4] add poll_post_exception framework Frank Rowand
` (3 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Frank Rowand @ 2014-08-05 1:03 UTC (permalink / raw)
To: Stephen Boyd
Cc: David Brown, Daniel Walker, Bryan Huntsman, Greg Kroah-Hartman,
Jiri Slaby, linux-arm-msm@vger.kernel.org, linux-serial,
Linux Kernel list, Jason Wessel, kgdb-bugreport
From: Frank Rowand <frank.rowand@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.rowand@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;
}
^ permalink raw reply [flat|nested] 11+ messages in thread
* [test patch 2/4] add poll_post_exception framework
2014-08-05 0:59 [request for help] tty: serial: kgdb: fix msm_serial for kgdb Frank Rowand
2014-08-05 1:03 ` [test patch 1/4] " Frank Rowand
@ 2014-08-05 1:04 ` Frank Rowand
2014-08-05 1:06 ` [test patch 3/4] use poll_post_exception in msm_serial Frank Rowand
` (2 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Frank Rowand @ 2014-08-05 1:04 UTC (permalink / raw)
To: frowand.list
Cc: Stephen Boyd, David Brown, Daniel Walker, Bryan Huntsman,
Greg Kroah-Hartman, Jiri Slaby, linux-arm-msm@vger.kernel.org,
linux-serial, Linux Kernel list, Jason Wessel, kgdb-bugreport
From: Frank Rowand <frank.rowand@sonymobile.com>
Add framework to allow serial driver to fixup state after operating in
polled mode, before returning to interrupt mode.
Not-signed-off-by-yet: Frank Rowand <frank.rowand@sonymobile.com>
---
drivers/tty/serial/kgdboc.c | 3 +++
drivers/tty/serial/serial_core.c | 15 +++++++++++++++
include/linux/serial_core.h | 1 +
include/linux/tty_driver.h | 1 +
4 files changed, 20 insertions(+)
Index: b/drivers/tty/serial/kgdboc.c
===================================================================
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -302,6 +302,9 @@ static void kgdboc_post_exp_handler(void
con_debug_leave();
}
kgdboc_restore_input();
+
+ if (kgdb_tty_driver->ops->poll_post_exception)
+ kgdb_tty_driver->ops->poll_post_exception(kgdb_tty_driver, kgdb_tty_line);
}
static struct kgdb_io kgdboc_io_ops = {
Index: b/drivers/tty/serial/serial_core.c
===================================================================
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2237,6 +2237,20 @@ static void uart_poll_put_char(struct tt
port = state->uart_port;
port->ops->poll_put_char(port, ch);
}
+
+static void uart_poll_post_exception(struct tty_driver *driver, int line)
+{
+ struct uart_driver *drv = driver->driver_state;
+ struct uart_state *state = drv->state + line;
+ struct uart_port *port;
+
+ if (!state || !state->uart_port)
+ return;
+
+ port = state->uart_port;
+ if (port->ops->poll_post_exception)
+ port->ops->poll_post_exception(port);
+}
#endif
static const struct tty_operations uart_ops = {
@@ -2269,6 +2283,7 @@ static const struct tty_operations uart_
.poll_init = uart_poll_init,
.poll_get_char = uart_poll_get_char,
.poll_put_char = uart_poll_put_char,
+ .poll_post_exception = uart_poll_post_exception,
#endif
};
Index: b/include/linux/tty_driver.h
===================================================================
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -283,6 +283,7 @@ struct tty_operations {
int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line);
void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
+ void (*poll_post_exception)(struct tty_driver *driver, int line);
#endif
const struct file_operations *proc_fops;
};
Index: b/include/linux/serial_core.h
===================================================================
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -90,6 +90,7 @@ struct uart_ops {
int (*poll_init)(struct uart_port *);
void (*poll_put_char)(struct uart_port *, unsigned char);
int (*poll_get_char)(struct uart_port *);
+ void (*poll_post_exception)(struct uart_port *);
#endif
};
^ permalink raw reply [flat|nested] 11+ messages in thread
* [test patch 3/4] use poll_post_exception in msm_serial
2014-08-05 0:59 [request for help] tty: serial: kgdb: fix msm_serial for kgdb Frank Rowand
2014-08-05 1:03 ` [test patch 1/4] " Frank Rowand
2014-08-05 1:04 ` [test patch 2/4] add poll_post_exception framework Frank Rowand
@ 2014-08-05 1:06 ` Frank Rowand
2014-08-05 1:08 ` [test patch 4/4] debug hackery to trace msm_serial receive interrupts Frank Rowand
2014-08-05 1:33 ` [request for help] tty: serial: kgdb: fix msm_serial for kgdb Stephen Boyd
4 siblings, 0 replies; 11+ messages in thread
From: Frank Rowand @ 2014-08-05 1:06 UTC (permalink / raw)
Cc: Stephen Boyd, David Brown, Daniel Walker, Bryan Huntsman,
Greg Kroah-Hartman, Jiri Slaby, linux-arm-msm@vger.kernel.org,
linux-serial, Linux Kernel list, Jason Wessel, kgdb-bugreport
From: Frank Rowand <frank.rowand@sonymobile.com>
**********************************************************
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@sonymobile.com>
---
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
};
^ permalink raw reply [flat|nested] 11+ messages in thread
* [test patch 4/4] debug hackery to trace msm_serial receive interrupts
2014-08-05 0:59 [request for help] tty: serial: kgdb: fix msm_serial for kgdb Frank Rowand
` (2 preceding siblings ...)
2014-08-05 1:06 ` [test patch 3/4] use poll_post_exception in msm_serial Frank Rowand
@ 2014-08-05 1:08 ` Frank Rowand
2014-08-05 1:33 ` [request for help] tty: serial: kgdb: fix msm_serial for kgdb Stephen Boyd
4 siblings, 0 replies; 11+ messages in thread
From: Frank Rowand @ 2014-08-05 1:08 UTC (permalink / raw)
Cc: Stephen Boyd, David Brown, Daniel Walker, Bryan Huntsman,
Greg Kroah-Hartman, Jiri Slaby, linux-arm-msm@vger.kernel.org,
linux-serial, Linux Kernel list, Jason Wessel, kgdb-bugreport
From: Frank Rowand <frank.rowand@sonymobile.com>
Not intended to be applied to mainline.
This is debug code that captures a trace of msm_serial reads by handle_rx_dm().
The trace is printed to the console when the sys_sync() system call is
invoked (that is, when the sync user space command is executed).
Not-signed-off-by-yet: Frank Rowand <frank.rowand@sonymobile.com>
---
arch/arm/boot/dts/qcom-msm8974.dtsi | 1
drivers/tty/serial/msm_serial.c | 110 ++++++++++++++++++++++++++++++++++++
fs/sync.c | 5 +
3 files changed, 116 insertions(+)
Index: b/drivers/tty/serial/msm_serial.c
===================================================================
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -100,6 +100,80 @@ static void msm_enable_ms(struct uart_po
msm_write(port, msm_port->imr, UART_IMR);
}
+#define dbg_rx_c_MAX 95
+struct dbg_rx {
+ unsigned int rx_break;
+ unsigned int stale;
+ unsigned int count_exhausted;
+ unsigned int rx_total_snap;
+ unsigned int count;
+ unsigned int old_snap_state_1;
+ unsigned int old_snap_state_2;
+ unsigned int c_idx;
+ unsigned int c[dbg_rx_c_MAX + 1];
+};
+
+#define dbg_rx_MAX 4000
+static struct dbg_rx dbg_rx[dbg_rx_MAX + 1];
+static int dbg_rx_idx = -1;
+
+#define BUF_MAX 4095
+#define BUF_SIZE (BUF_MAX + 1)
+static unsigned char buf[BUF_SIZE];
+void print_dbg_rx(void)
+{
+ unsigned char c;
+ int k;
+ int j;
+ int i;
+ struct dbg_rx *d = &dbg_rx[0];
+ unsigned char *bufp;
+
+ pr_err(
+ " B S E\n"
+ " r t x old_\n"
+ " e a h snap_state\n"
+ " a l s ---------- tot\n"
+ " k t t 1 2 snap count c_idx --- data\n"
+ "---- - - - ---- ---- ---- ----- ----- --- --------\n");
+
+ for (k = 0; k <= dbg_rx_idx; k++, d++) {
+ bufp = &buf[0];
+ bufp += scnprintf(bufp, BUF_SIZE, "%4d %c %c %c %4d %4d %4d %5d %5d --- ",
+ k,
+ d->rx_break ? 'B' : ' ',
+ d->stale ? 'S' : 'H',
+ d->count_exhausted ? 'E' : ' ',
+ d->old_snap_state_1,
+ d->old_snap_state_2,
+ d->rx_total_snap,
+ d->count,
+ d->c_idx
+ );
+ for (j = 0; j < d->c_idx; j++) {
+ bufp += scnprintf(bufp,
+ BUF_SIZE - (bufp - &buf[0]),
+ "%08x ", d->c[j]);
+ }
+ for (j = 0; j < d->c_idx; j++) {
+ for (i = 3; i >= 0; i--) {
+ c = (d->c[j] >> (8 * i)) & 0xff;
+ bufp += scnprintf(bufp,
+ BUF_SIZE - (bufp - &buf[0]),
+ "%c",
+ ((c >= 0x20) && (c <= 0x7e)) ? c : '.');
+ }
+ bufp += scnprintf(bufp,
+ BUF_SIZE - (bufp - &buf[0]),
+ " ");
+ }
+ bufp += scnprintf(bufp,
+ BUF_SIZE - (bufp - &buf[0]),
+ "\n");
+ pr_err("%s", buf);
+ }
+}
+
static void handle_rx_dm(struct uart_port *port, unsigned int misr)
{
struct tty_port *tport = &port->state->port;
@@ -110,6 +184,13 @@ static void handle_rx_dm(struct uart_por
int res;
char *cp;
+ dbg_rx_idx++;
+ if (dbg_rx_idx > dbg_rx_MAX)
+ dbg_rx_idx = 0;
+ memset(&dbg_rx[dbg_rx_idx], 0, sizeof(dbg_rx[0]));
+ dbg_rx[dbg_rx_idx].old_snap_state_1 = msm_port->old_snap_state;
+ dbg_rx[dbg_rx_idx].stale = imr_rx_stale;
+
if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
port->icount.overrun++;
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
@@ -117,8 +198,14 @@ static void handle_rx_dm(struct uart_por
}
if (imr_rx_stale) {
+#if 1
+ int rx_total_snap = msm_read(port, UARTDM_RX_TOTAL_SNAP);
+ dbg_rx[dbg_rx_idx].rx_total_snap = rx_total_snap;
+ count = rx_total_snap - msm_port->old_snap_state;
+#else
count = msm_read(port, UARTDM_RX_TOTAL_SNAP) -
msm_port->old_snap_state;
+#endif
msm_port->old_snap_state = 0;
} else {
count = msm_read(port, UART_RFWR);
@@ -126,6 +213,7 @@ static void handle_rx_dm(struct uart_por
count = 4 * count;
msm_port->old_snap_state += count;
}
+ dbg_rx[dbg_rx_idx].count = count;
/* TODO: Precise error reporting */
@@ -138,12 +226,15 @@ static void handle_rx_dm(struct uart_por
if ((sr & UART_SR_RX_READY) == 0) {
if (!imr_rx_stale)
msm_port->old_snap_state -= count;
+ dbg_rx[dbg_rx_idx].count_exhausted = 1;
break;
}
c = msm_read(port, UARTDM_RF);
+ dbg_rx[dbg_rx_idx].c[dbg_rx[dbg_rx_idx].c_idx++] = c;
if (sr & UART_SR_RX_BREAK) {
+ dbg_rx[dbg_rx_idx].rx_break = 1;
port->icount.brk++;
uart_handle_break(port);
if (msm_port->rx_sc_enabled)
@@ -193,6 +284,7 @@ static void handle_rx_dm(struct uart_por
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);
+ dbg_rx[dbg_rx_idx].old_snap_state_2 = msm_port->old_snap_state;
}
static void handle_rx(struct uart_port *port)
@@ -771,6 +863,9 @@ static int msm_poll_init(struct uart_por
struct msm_port *msm_port = UART_TO_MSM(port);
unsigned int watermark;
+ pr_err("enter msm_poll_init()\n");
+ pr_err("msm_port->is_uartdm %d\n", msm_port->is_uartdm);
+
/* Enable single character mode on RX FIFO */
if (msm_port->is_uartdm >= UARTDM_1P4) {
msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN);
@@ -1273,6 +1368,21 @@ static int __init msm_console_setup(stru
printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
+#if 1
+{
+ /* zzz debug info */
+
+ unsigned int version;
+
+ version = msm_read(port, 0xd8);
+ pr_err("msm_serial: HW_VERSION %d.%d.%d\n",
+ (version >> 28) & 0xf,
+ (version >> 16) & 0xfff,
+ (version ) & 0xffff);
+
+}
+#endif
+
return uart_set_options(port, co, baud, parity, bits, flow);
}
Index: b/fs/sync.c
===================================================================
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -99,10 +99,15 @@ static void fdatawait_one_bdev(struct bl
* just write metadata (such as inodes or bitmaps) to block device page cache
* and do not sync it on their own in ->sync_fs().
*/
+void print_dbg_rx(void);
+int zzz_print_dbg_rx = 1;
SYSCALL_DEFINE0(sync)
{
int nowait = 0, wait = 1;
+ if (zzz_print_dbg_rx)
+ print_dbg_rx();
+
wakeup_flusher_threads(0, WB_REASON_SYNC);
iterate_supers(sync_inodes_one_sb, NULL);
iterate_supers(sync_fs_one_sb, &nowait);
Index: b/arch/arm/boot/dts/qcom-msm8974.dtsi
===================================================================
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -227,6 +227,7 @@
serial@f991e000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ /* compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; */
reg = <0xf991e000 0x1000>;
interrupts = <0 108 0x0>;
clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [request for help] tty: serial: kgdb: fix msm_serial for kgdb
2014-08-05 0:59 [request for help] tty: serial: kgdb: fix msm_serial for kgdb Frank Rowand
` (3 preceding siblings ...)
2014-08-05 1:08 ` [test patch 4/4] debug hackery to trace msm_serial receive interrupts Frank Rowand
@ 2014-08-05 1:33 ` Stephen Boyd
2014-08-05 2:09 ` Frank Rowand
4 siblings, 1 reply; 11+ messages in thread
From: Stephen Boyd @ 2014-08-05 1:33 UTC (permalink / raw)
To: frowand.list
Cc: David Brown, Daniel Walker, Bryan Huntsman, Greg Kroah-Hartman,
Jiri Slaby, linux-arm-msm@vger.kernel.org, linux-serial,
Linux Kernel list, Jason Wessel, kgdb-bugreport
On 08/04/14 17:59, Frank Rowand wrote:
> Stephen,
>
> I made some changes to drivers/tty/serial/msm_serial.c to allow kgdb
> to work with the dragon board (which has a qcom,msm-uartdm-v1.4 serial
> port).
>
> I will reply to this email with the patches.
>
> 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.
>
> I am hoping you can help me figure out how to get the stale interrupt to
> occur for the first character after gdb continues, instead of having to
> first get a high water interrupt.
>
> Patch 2 adds a framework to fix up the state of the driver and/or hardware
> after gdb continues. Patch 3 is a series of experiments trying to fix
> things up for msm_serial. I don't have complete documentation and
> understanding of the hardware, so some of the experiments might be less
> than intelligent.
>
> Can you give me some suggestions of What should I be doing in the fix up
> function?
Hmm... I've never gotten the serial console to come back after
continuing because I only have one serial port and I use it for the
console so switching it into kgdb makes me lose the console. How do you
work around this? Use adb shell?
I think the big problem is
msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN)
in msm_poll_init() which forces the uart into single character mode.
That causes all sorts of problems but is required to make the get_char
stuff work cleanly. I really wanted the msm_poll_get_char_dm_1p3() to
work for the 1.4 version of the hardware but I guess they made the
hardware different again for some unknown reason so it doesn't work. I
never got around to figuring it out or talking to the hardware people.
It took a while to develop the 1p3 version of the get_char code because
of the "fifo" centric design.
Do you know if that 1p3 version of the code works for you on 1.3
hardware? Just curious if that actually has the same bugs or not. I
probably won't have much time to look at this anytime soon, but I'll try
and send an email off to the hardware designers to figure out a way to
avoid switching the mode.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [request for help] tty: serial: kgdb: fix msm_serial for kgdb
2014-08-05 1:33 ` [request for help] tty: serial: kgdb: fix msm_serial for kgdb Stephen Boyd
@ 2014-08-05 2:09 ` Frank Rowand
2014-08-05 19:22 ` Stephen Boyd
0 siblings, 1 reply; 11+ messages in thread
From: Frank Rowand @ 2014-08-05 2:09 UTC (permalink / raw)
To: Stephen Boyd
Cc: David Brown, Daniel Walker, Bryan Huntsman, Greg Kroah-Hartman,
Jiri Slaby, linux-arm-msm@vger.kernel.org, linux-serial,
Linux Kernel list, Jason Wessel, kgdb-bugreport
On 8/4/2014 6:33 PM, Stephen Boyd wrote:
> On 08/04/14 17:59, Frank Rowand wrote:
>> Stephen,
>>
>> I made some changes to drivers/tty/serial/msm_serial.c to allow kgdb
>> to work with the dragon board (which has a qcom,msm-uartdm-v1.4 serial
>> port).
>>
>> I will reply to this email with the patches.
>>
>> 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.
>>
>> I am hoping you can help me figure out how to get the stale interrupt to
>> occur for the first character after gdb continues, instead of having to
>> first get a high water interrupt.
>>
>> Patch 2 adds a framework to fix up the state of the driver and/or hardware
>> after gdb continues. Patch 3 is a series of experiments trying to fix
>> things up for msm_serial. I don't have complete documentation and
>> understanding of the hardware, so some of the experiments might be less
>> than intelligent.
>>
>> Can you give me some suggestions of What should I be doing in the fix up
>> function?
>
> Hmm... I've never gotten the serial console to come back after
> continuing because I only have one serial port and I use it for the
> console so switching it into kgdb makes me lose the console. How do you
> work around this? Use adb shell?
I use kdmx2 to share the host serial port between gdb for kgdb and minicom
for the console input and output. I had to update kdmx2 to work in my
environment. You can download it from:
http://elinux.org/images/a/a7/Kdmx-2.00_v140730a.tar.gz
Whenever that link is updated, the new link can be found at:
http://elinux.org/Kgdb
>
> I think the big problem is
>
> msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN)
>
> in msm_poll_init() which forces the uart into single character mode.
Yep, most of my fixes deal with the fact that in single character mode
echo fifo word only contains a single character of data. All of that
works now. So my only problem is not getting a stale interrupt until
after I've gotten a high water interrupt.
> That causes all sorts of problems but is required to make the get_char
> stuff work cleanly. I really wanted the msm_poll_get_char_dm_1p3() to
> work for the 1.4 version of the hardware but I guess they made the
> hardware different again for some unknown reason so it doesn't work. I
> never got around to figuring it out or talking to the hardware people.
> It took a while to develop the 1p3 version of the get_char code because
> of the "fifo" centric design.
>
> Do you know if that 1p3 version of the code works for you on 1.3
> hardware? Just curious if that actually has the same bugs or not. I
> probably won't have much time to look at this anytime soon, but I'll try
> and send an email off to the hardware designers to figure out a way to
> avoid switching the mode.
>
I don't have any 1.3 hardware on my desk. I'll have to see if I can find
some when I get a chance. I did try telling the driver that I was using
1.3 hardware even though it is 1.4; I had to make some changes to
msm_poll_get_char_dm_1p3() to make it kind of sort of work, but not well.
Instead of spending more time on that I just went back to making the single
character mode work.
-Frank
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [request for help] tty: serial: kgdb: fix msm_serial for kgdb
2014-08-05 2:09 ` Frank Rowand
@ 2014-08-05 19:22 ` Stephen Boyd
2014-08-05 23:53 ` Stephen Boyd
0 siblings, 1 reply; 11+ messages in thread
From: Stephen Boyd @ 2014-08-05 19:22 UTC (permalink / raw)
To: frowand.list
Cc: David Brown, Daniel Walker, Bryan Huntsman, Greg Kroah-Hartman,
Jiri Slaby, linux-arm-msm@vger.kernel.org, linux-serial,
Linux Kernel list, Jason Wessel, kgdb-bugreport
On 08/04/14 19:09, Frank Rowand wrote:
> On 8/4/2014 6:33 PM, Stephen Boyd wrote:
>> On 08/04/14 17:59, Frank Rowand wrote:
>>> Stephen,
>>>
>>> I made some changes to drivers/tty/serial/msm_serial.c to allow kgdb
>>> to work with the dragon board (which has a qcom,msm-uartdm-v1.4 serial
>>> port).
>>>
>>> I will reply to this email with the patches.
>>>
>>> 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.
>>>
>>> I am hoping you can help me figure out how to get the stale interrupt to
>>> occur for the first character after gdb continues, instead of having to
>>> first get a high water interrupt.
>>>
>>> Patch 2 adds a framework to fix up the state of the driver and/or hardware
>>> after gdb continues. Patch 3 is a series of experiments trying to fix
>>> things up for msm_serial. I don't have complete documentation and
>>> understanding of the hardware, so some of the experiments might be less
>>> than intelligent.
>>>
>>> Can you give me some suggestions of What should I be doing in the fix up
>>> function?
>> Hmm... I've never gotten the serial console to come back after
>> continuing because I only have one serial port and I use it for the
>> console so switching it into kgdb makes me lose the console. How do you
>> work around this? Use adb shell?
> I use kdmx2 to share the host serial port between gdb for kgdb and minicom
> for the console input and output. I had to update kdmx2 to work in my
> environment. You can download it from:
>
> http://elinux.org/images/a/a7/Kdmx-2.00_v140730a.tar.gz
>
> Whenever that link is updated, the new link can be found at:
>
> http://elinux.org/Kgdb
Cool. Thanks for the pointer.
>
>> I think the big problem is
>>
>> msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN)
>>
>> in msm_poll_init() which forces the uart into single character mode.
> Yep, most of my fixes deal with the fact that in single character mode
> echo fifo word only contains a single character of data. All of that
> works now. So my only problem is not getting a stale interrupt until
> after I've gotten a high water interrupt.
>
>> That causes all sorts of problems but is required to make the get_char
>> stuff work cleanly. I really wanted the msm_poll_get_char_dm_1p3() to
>> work for the 1.4 version of the hardware but I guess they made the
>> hardware different again for some unknown reason so it doesn't work. I
>> never got around to figuring it out or talking to the hardware people.
>> It took a while to develop the 1p3 version of the get_char code because
>> of the "fifo" centric design.
>>
>> Do you know if that 1p3 version of the code works for you on 1.3
>> hardware? Just curious if that actually has the same bugs or not. I
>> probably won't have much time to look at this anytime soon, but I'll try
>> and send an email off to the hardware designers to figure out a way to
>> avoid switching the mode.
>>
> I don't have any 1.3 hardware on my desk. I'll have to see if I can find
> some when I get a chance. I did try telling the driver that I was using
> 1.3 hardware even though it is 1.4; I had to make some changes to
> msm_poll_get_char_dm_1p3() to make it kind of sort of work, but not well.
> Instead of spending more time on that I just went back to making the single
> character mode work.
>
>
I tried it and it doesn't work either. Typing lots of characters finally
unjams it like you see on 1.4 hardware.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [request for help] tty: serial: kgdb: fix msm_serial for kgdb
2014-08-05 19:22 ` Stephen Boyd
@ 2014-08-05 23:53 ` Stephen Boyd
2014-08-06 0:55 ` Frank Rowand
0 siblings, 1 reply; 11+ messages in thread
From: Stephen Boyd @ 2014-08-05 23:53 UTC (permalink / raw)
To: frowand.list
Cc: David Brown, Daniel Walker, Bryan Huntsman, Greg Kroah-Hartman,
Jiri Slaby, linux-arm-msm@vger.kernel.org, linux-serial,
Linux Kernel list, Jason Wessel, kgdb-bugreport
On 08/05/14 12:22, Stephen Boyd wrote:
>
> I tried it and it doesn't work either. Typing lots of characters finally
> unjams it like you see on 1.4 hardware.
>
Can you try this? It seems to work for me on both 1.3 and 1.4 hardware
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 72000a6d5af0..fbcb0c657d5f 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -680,17 +680,6 @@ static void msm_power(struct uart_port *port, unsigned int state,
}
#ifdef CONFIG_CONSOLE_POLL
-static int msm_poll_init(struct uart_port *port)
-{
- struct msm_port *msm_port = UART_TO_MSM(port);
-
- /* Enable single character mode on RX FIFO */
- if (msm_port->is_uartdm >= UARTDM_1P4)
- msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN);
-
- return 0;
-}
-
static int msm_poll_get_char_single(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
@@ -702,7 +691,7 @@ static int msm_poll_get_char_single(struct uart_port *port)
return msm_read(port, rf_reg) & 0xff;
}
-static int msm_poll_get_char_dm_1p3(struct uart_port *port)
+static int msm_poll_get_char_dm(struct uart_port *port)
{
int c;
static u32 slop;
@@ -726,6 +715,9 @@ static int msm_poll_get_char_dm_1p3(struct uart_port *port)
slop = msm_read(port, UARTDM_RF);
c = sp[0];
count--;
+ 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);
} else {
c = NO_POLL_CHAR;
}
@@ -749,8 +741,8 @@ static int msm_poll_get_char(struct uart_port *port)
imr = msm_read(port, UART_IMR);
msm_write(port, 0, UART_IMR);
- if (msm_port->is_uartdm == UARTDM_1P3)
- c = msm_poll_get_char_dm_1p3(port);
+ if (msm_port->is_uartdm)
+ c = msm_poll_get_char_dm(port);
else
c = msm_poll_get_char_single(port);
@@ -809,7 +801,6 @@ static struct uart_ops msm_uart_pops = {
.verify_port = msm_verify_port,
.pm = msm_power,
#ifdef CONFIG_CONSOLE_POLL
- .poll_init = msm_poll_init,
.poll_get_char = msm_poll_get_char,
.poll_put_char = msm_poll_put_char,
#endif
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [request for help] tty: serial: kgdb: fix msm_serial for kgdb
2014-08-05 23:53 ` Stephen Boyd
@ 2014-08-06 0:55 ` Frank Rowand
2014-08-06 1:19 ` Stephen Boyd
0 siblings, 1 reply; 11+ messages in thread
From: Frank Rowand @ 2014-08-06 0:55 UTC (permalink / raw)
To: Stephen Boyd
Cc: David Brown, Daniel Walker, Bryan Huntsman, Greg Kroah-Hartman,
Jiri Slaby, linux-arm-msm@vger.kernel.org, linux-serial,
Linux Kernel list, Jason Wessel, kgdb-bugreport
On 8/5/2014 4:53 PM, Stephen Boyd wrote:
> On 08/05/14 12:22, Stephen Boyd wrote:
>>
>> I tried it and it doesn't work either. Typing lots of characters finally
>> unjams it like you see on 1.4 hardware.
>>
>
> Can you try this? It seems to work for me on both 1.3 and 1.4 hardware
Yes, much better getting rid of the single character mode! Works for me
on the dragonboard (1.4 hardware).
Reviewed-by: Frank Rowand <frank.rowand@sonymobile.com>
Tested-by: Frank Rowand <frank.rowand@sonymobile.com>
Thanks for figuring this out.
I'll send a patch to handle sysrq after I see this patch upstream.
-Frank
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [request for help] tty: serial: kgdb: fix msm_serial for kgdb
2014-08-06 0:55 ` Frank Rowand
@ 2014-08-06 1:19 ` Stephen Boyd
0 siblings, 0 replies; 11+ messages in thread
From: Stephen Boyd @ 2014-08-06 1:19 UTC (permalink / raw)
To: frowand.list
Cc: David Brown, Daniel Walker, Bryan Huntsman, Greg Kroah-Hartman,
Jiri Slaby, linux-arm-msm@vger.kernel.org, linux-serial,
Linux Kernel list, Jason Wessel, kgdb-bugreport
On 08/05/14 17:55, Frank Rowand wrote:
> On 8/5/2014 4:53 PM, Stephen Boyd wrote:
>> On 08/05/14 12:22, Stephen Boyd wrote:
>>> I tried it and it doesn't work either. Typing lots of characters finally
>>> unjams it like you see on 1.4 hardware.
>>>
>> Can you try this? It seems to work for me on both 1.3 and 1.4 hardware
> Yes, much better getting rid of the single character mode! Works for me
> on the dragonboard (1.4 hardware).
>
> Reviewed-by: Frank Rowand <frank.rowand@sonymobile.com>
> Tested-by: Frank Rowand <frank.rowand@sonymobile.com>
>
>
Great, I'll send an official patch with some commit text that hopefully
makes sense.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 11+ messages in thread