Commit c557d392 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman

serial: Test for no tx data on tx restart

Commit 717f3bba,
'serial_core: Fix conditional start_tx on ring buffer not empty'
exposes an incorrect assumption in several drivers' start_tx methods;
the tx ring buffer can, in fact, be empty when restarting tx while
performing flow control.

Affected drivers:
sunsab.c
ip22zilog.c
pmac_zilog.c
sunzilog.c
m32r_sio.c
imx.c

Other in-tree serial drivers either are not affected or already
test for empty tx ring buffer before transmitting.

Test for empty tx ring buffer in start_tx() method, after transmitting
x_char (if applicable).
Reported-by: default avatarAaro Koskinen <aaro.koskinen@iki.fi>
Cc: Seth Bollinger <sethb@digi.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Cc: stable <stable@vger.kernel.org> # 3.15
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent cd3de83f
...@@ -567,6 +567,9 @@ static void imx_start_tx(struct uart_port *port) ...@@ -567,6 +567,9 @@ static void imx_start_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = (struct imx_port *)port;
unsigned long temp; unsigned long temp;
if (uart_circ_empty(&port.state->xmit))
return;
if (USE_IRDA(sport)) { if (USE_IRDA(sport)) {
/* half duplex in IrDA mode; have to disable receive mode */ /* half duplex in IrDA mode; have to disable receive mode */
temp = readl(sport->port.membase + UCR4); temp = readl(sport->port.membase + UCR4);
......
...@@ -603,6 +603,8 @@ static void ip22zilog_start_tx(struct uart_port *port) ...@@ -603,6 +603,8 @@ static void ip22zilog_start_tx(struct uart_port *port)
} else { } else {
struct circ_buf *xmit = &port->state->xmit; struct circ_buf *xmit = &port->state->xmit;
if (uart_circ_empty(xmit))
return;
writeb(xmit->buf[xmit->tail], &channel->data); writeb(xmit->buf[xmit->tail], &channel->data);
ZSDELAY(); ZSDELAY();
ZS_WSYNC(channel); ZS_WSYNC(channel);
......
...@@ -266,9 +266,11 @@ static void m32r_sio_start_tx(struct uart_port *port) ...@@ -266,9 +266,11 @@ static void m32r_sio_start_tx(struct uart_port *port)
if (!(up->ier & UART_IER_THRI)) { if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI; up->ier |= UART_IER_THRI;
serial_out(up, UART_IER, up->ier); serial_out(up, UART_IER, up->ier);
serial_out(up, UART_TX, xmit->buf[xmit->tail]); if (!uart_circ_empty(xmit)) {
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); serial_out(up, UART_TX, xmit->buf[xmit->tail]);
up->port.icount.tx++; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
up->port.icount.tx++;
}
} }
while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY); while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);
#else #else
......
...@@ -653,6 +653,8 @@ static void pmz_start_tx(struct uart_port *port) ...@@ -653,6 +653,8 @@ static void pmz_start_tx(struct uart_port *port)
} else { } else {
struct circ_buf *xmit = &port->state->xmit; struct circ_buf *xmit = &port->state->xmit;
if (uart_circ_empty(xmit))
goto out;
write_zsdata(uap, xmit->buf[xmit->tail]); write_zsdata(uap, xmit->buf[xmit->tail]);
zssync(uap); zssync(uap);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
...@@ -661,6 +663,7 @@ static void pmz_start_tx(struct uart_port *port) ...@@ -661,6 +663,7 @@ static void pmz_start_tx(struct uart_port *port)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port); uart_write_wakeup(&uap->port);
} }
out:
pmz_debug("pmz: start_tx() done.\n"); pmz_debug("pmz: start_tx() done.\n");
} }
......
...@@ -427,6 +427,9 @@ static void sunsab_start_tx(struct uart_port *port) ...@@ -427,6 +427,9 @@ static void sunsab_start_tx(struct uart_port *port)
struct circ_buf *xmit = &up->port.state->xmit; struct circ_buf *xmit = &up->port.state->xmit;
int i; int i;
if (uart_circ_empty(xmit))
return;
up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
writeb(up->interrupt_mask1, &up->regs->w.imr1); writeb(up->interrupt_mask1, &up->regs->w.imr1);
......
...@@ -703,6 +703,8 @@ static void sunzilog_start_tx(struct uart_port *port) ...@@ -703,6 +703,8 @@ static void sunzilog_start_tx(struct uart_port *port)
} else { } else {
struct circ_buf *xmit = &port->state->xmit; struct circ_buf *xmit = &port->state->xmit;
if (uart_circ_empty(xmit))
return;
writeb(xmit->buf[xmit->tail], &channel->data); writeb(xmit->buf[xmit->tail], &channel->data);
ZSDELAY(); ZSDELAY();
ZS_WSYNC(channel); ZS_WSYNC(channel);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment