Skip to content

Commit f97cdbb

Browse files
jhovoldgregkh
authored andcommitted
serial: qcom-geni: fix false console tx restart
Commit 663abb1 ("tty: serial: qcom_geni_serial: Fix UART hang") addressed an issue with stalled tx after the console code interrupted the last bytes of a tx command by reenabling the watermark interrupt if there is data in write buffer. This can however break software flow control by re-enabling tx after the user has stopped it. Address the original issue by not clearing the CMD_DONE flag after polling for command completion. This allows the interrupt handler to start another transfer when the CMD_DONE interrupt has not been disabled due to flow control. Fixes: c4f5287 ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP") Fixes: 663abb1 ("tty: serial: qcom_geni_serial: Fix UART hang") Cc: [email protected] # 4.17 Reviewed-by: Douglas Anderson <[email protected]> Tested-by: Nícolas F. R. A. Prado <[email protected]> Signed-off-by: Johan Hovold <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c80ee36 commit f97cdbb

File tree

1 file changed

+3
-10
lines changed

1 file changed

+3
-10
lines changed

drivers/tty/serial/qcom_geni_serial.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -306,18 +306,16 @@ static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
306306
static void qcom_geni_serial_poll_tx_done(struct uart_port *uport)
307307
{
308308
int done;
309-
u32 irq_clear = M_CMD_DONE_EN;
310309

311310
done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
312311
M_CMD_DONE_EN, true);
313312
if (!done) {
314313
writel(M_GENI_CMD_ABORT, uport->membase +
315314
SE_GENI_M_CMD_CTRL_REG);
316-
irq_clear |= M_CMD_ABORT_EN;
317315
qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
318316
M_CMD_ABORT_EN, true);
317+
writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
319318
}
320-
writel(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR);
321319
}
322320

323321
static void qcom_geni_serial_abort_rx(struct uart_port *uport)
@@ -378,6 +376,7 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
378376
unsigned char c)
379377
{
380378
writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
379+
writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
381380
qcom_geni_serial_setup_tx(uport, 1);
382381
WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
383382
M_TX_FIFO_WATERMARK_EN, true));
@@ -422,6 +421,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
422421
}
423422

424423
writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
424+
writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
425425
qcom_geni_serial_setup_tx(uport, bytes_to_send);
426426
for (i = 0; i < count; ) {
427427
size_t chars_to_write = 0;
@@ -463,7 +463,6 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
463463
bool locked = true;
464464
unsigned long flags;
465465
u32 geni_status;
466-
u32 irq_en;
467466

468467
WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
469468

@@ -495,12 +494,6 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
495494
* has been sent, in which case we need to look for done first.
496495
*/
497496
qcom_geni_serial_poll_tx_done(uport);
498-
499-
if (!kfifo_is_empty(&uport->state->port.xmit_fifo)) {
500-
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
501-
writel(irq_en | M_TX_FIFO_WATERMARK_EN,
502-
uport->membase + SE_GENI_M_IRQ_EN);
503-
}
504497
}
505498

506499
__qcom_geni_serial_console_write(uport, s, count);

0 commit comments

Comments
 (0)