Skip to content

Commit 7d05587

Browse files
jchandra-cavmgregkh
authored andcommitted
tty: amba-pl011: Fix spurious TX interrupts
On SMP systems, we see a lot of spurious TX interrupts when a program generates a steady stream of output to the pl011 UART. The problem can be easily seen when one CPU generates the output while another CPU handles the pl011 interrupts, and the rate of output is low enough not to fill the TX FIFO. The problem seems to be: -- CPU a -- -- CPU b -- (take port lock) pl011_start_tx pl011_start_tx_pio enable TXIM in REG_IMSC -> causes uart tx intr (pl011_int) pl011_tx_chars pl011_int ...tx chars, all done... (wait for port lock) pl011_stop_tx . disable TXIM . (release port lock) -> (take port lock) check for TXIM, not enabled (release port lock) return IRQ_NONE Enabling the TXIM in pl011_start_tx_pio() causes the interrupt to be generated and delivered to CPU b, even though pl011_tx_chars() is able to complete the TX and then disable the tx interrupt. Fix this by enabling TXIM only after pl011_tx_chars, if it is needed. pl011_tx_chars will return a boolean indicating whether the TX interrupts have to be enabled. Debugged-by: Vijaya Kumar <Vijaya.Kumar@cavium.com> Signed-off-by: Jayachandran C <jnair@caviumnetworks.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent ecfc577 commit 7d05587

File tree

1 file changed

+14
-9
lines changed

1 file changed

+14
-9
lines changed

drivers/tty/serial/amba-pl011.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,14 +1327,15 @@ static void pl011_stop_tx(struct uart_port *port)
13271327
pl011_dma_tx_stop(uap);
13281328
}
13291329

1330-
static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
1330+
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
13311331

13321332
/* Start TX with programmed I/O only (no DMA) */
13331333
static void pl011_start_tx_pio(struct uart_amba_port *uap)
13341334
{
1335-
uap->im |= UART011_TXIM;
1336-
pl011_write(uap->im, uap, REG_IMSC);
1337-
pl011_tx_chars(uap, false);
1335+
if (pl011_tx_chars(uap, false)) {
1336+
uap->im |= UART011_TXIM;
1337+
pl011_write(uap->im, uap, REG_IMSC);
1338+
}
13381339
}
13391340

13401341
static void pl011_start_tx(struct uart_port *port)
@@ -1414,25 +1415,26 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
14141415
return true;
14151416
}
14161417

1417-
static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
1418+
/* Returns true if tx interrupts have to be (kept) enabled */
1419+
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
14181420
{
14191421
struct circ_buf *xmit = &uap->port.state->xmit;
14201422
int count = uap->fifosize >> 1;
14211423

14221424
if (uap->port.x_char) {
14231425
if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
1424-
return;
1426+
return true;
14251427
uap->port.x_char = 0;
14261428
--count;
14271429
}
14281430
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
14291431
pl011_stop_tx(&uap->port);
1430-
return;
1432+
return false;
14311433
}
14321434

14331435
/* If we are using DMA mode, try to send some characters. */
14341436
if (pl011_dma_tx_irq(uap))
1435-
return;
1437+
return true;
14361438

14371439
do {
14381440
if (likely(from_irq) && count-- == 0)
@@ -1447,8 +1449,11 @@ static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
14471449
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
14481450
uart_write_wakeup(&uap->port);
14491451

1450-
if (uart_circ_empty(xmit))
1452+
if (uart_circ_empty(xmit)) {
14511453
pl011_stop_tx(&uap->port);
1454+
return false;
1455+
}
1456+
return true;
14521457
}
14531458

14541459
static void pl011_modem_status(struct uart_amba_port *uap)

0 commit comments

Comments
 (0)