Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: Test for no tx data on tx restart

Commit 717f3bbab3c7628736ef738fdbf3d9a28578c26c,
'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: Aaro 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: Peter Hurley <peter@hurleysoftware.com>
Cc: stable <stable@vger.kernel.org> # 3.15
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Peter Hurley and committed by
Greg Kroah-Hartman
c557d392 cd3de83f

+18 -3
+3
drivers/tty/serial/imx.c
··· 567 567 struct imx_port *sport = (struct imx_port *)port; 568 568 unsigned long temp; 569 569 570 + if (uart_circ_empty(&port.state->xmit)) 571 + return; 572 + 570 573 if (USE_IRDA(sport)) { 571 574 /* half duplex in IrDA mode; have to disable receive mode */ 572 575 temp = readl(sport->port.membase + UCR4);
+2
drivers/tty/serial/ip22zilog.c
··· 603 603 } else { 604 604 struct circ_buf *xmit = &port->state->xmit; 605 605 606 + if (uart_circ_empty(xmit)) 607 + return; 606 608 writeb(xmit->buf[xmit->tail], &channel->data); 607 609 ZSDELAY(); 608 610 ZS_WSYNC(channel);
+5 -3
drivers/tty/serial/m32r_sio.c
··· 266 266 if (!(up->ier & UART_IER_THRI)) { 267 267 up->ier |= UART_IER_THRI; 268 268 serial_out(up, UART_IER, up->ier); 269 - serial_out(up, UART_TX, xmit->buf[xmit->tail]); 270 - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 271 - up->port.icount.tx++; 269 + if (!uart_circ_empty(xmit)) { 270 + serial_out(up, UART_TX, xmit->buf[xmit->tail]); 271 + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 272 + up->port.icount.tx++; 273 + } 272 274 } 273 275 while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY); 274 276 #else
+3
drivers/tty/serial/pmac_zilog.c
··· 653 653 } else { 654 654 struct circ_buf *xmit = &port->state->xmit; 655 655 656 + if (uart_circ_empty(xmit)) 657 + goto out; 656 658 write_zsdata(uap, xmit->buf[xmit->tail]); 657 659 zssync(uap); 658 660 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ··· 663 661 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 664 662 uart_write_wakeup(&uap->port); 665 663 } 664 + out: 666 665 pmz_debug("pmz: start_tx() done.\n"); 667 666 } 668 667
+3
drivers/tty/serial/sunsab.c
··· 427 427 struct circ_buf *xmit = &up->port.state->xmit; 428 428 int i; 429 429 430 + if (uart_circ_empty(xmit)) 431 + return; 432 + 430 433 up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); 431 434 writeb(up->interrupt_mask1, &up->regs->w.imr1); 432 435
+2
drivers/tty/serial/sunzilog.c
··· 703 703 } else { 704 704 struct circ_buf *xmit = &port->state->xmit; 705 705 706 + if (uart_circ_empty(xmit)) 707 + return; 706 708 writeb(xmit->buf[xmit->tail], &channel->data); 707 709 ZSDELAY(); 708 710 ZS_WSYNC(channel);