aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorFlorian Achleitner <achleitner.florian@fronius.com>2015-11-18 03:04:12 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-12-13 22:59:48 -0500
commited7a85045d0a0688a51bdab9e1a1d6ee79cb33b6 (patch)
tree19c03da356744ef5f10ed6612fa9cbfe6192bfc9 /drivers/tty
parent63d8cb3f19dabb409a09b4f2b8827934ab9365a3 (diff)
sc16is7xx: Fix TX buffer overrun caused by wrong tx fifo level read-out
We found that our sc16is7xx on spi reported a TX fifo free space value (TXLVL_REG) of 255 ocassionally, which is obviously wrong, with a 64 byte fifo and caused a buffer overrun and a kernel crash. To trigger this, a large write to the tty is sufficient. The fifo fills, TXLVL_REG reads zero, but the handle_tx function does a zero-data-length write to the TX fifo anyways through sc16is7xx_fifo_write. The next TXLVL_REG read then yields 255, for unknown reasons. A subsequent read is ok. Prevent zero-data-length writes if the TX fifo is full, because they are pointless, and because they trigger wrong TXLVL read-outs. Furthermore, prevent a TX buffer overrun if the peripheral reports values larger than the buffer size and thus, don't allow the peripheral to crash the kernel. Signed-off-by: Florian Achleitner <achleitner.florian@fronius.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/sc16is7xx.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index edb5305b9d4d..5815bcbc55b2 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -389,6 +389,13 @@ static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send)
389 const u8 line = sc16is7xx_line(port); 389 const u8 line = sc16is7xx_line(port);
390 u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line; 390 u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line;
391 391
392 /*
393 * Don't send zero-length data, at least on SPI it confuses the chip
394 * delivering wrong TXLVL data.
395 */
396 if (unlikely(!to_send))
397 return;
398
392 regcache_cache_bypass(s->regmap, true); 399 regcache_cache_bypass(s->regmap, true);
393 regmap_raw_write(s->regmap, addr, s->buf, to_send); 400 regmap_raw_write(s->regmap, addr, s->buf, to_send);
394 regcache_cache_bypass(s->regmap, false); 401 regcache_cache_bypass(s->regmap, false);
@@ -630,6 +637,12 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
630 if (likely(to_send)) { 637 if (likely(to_send)) {
631 /* Limit to size of TX FIFO */ 638 /* Limit to size of TX FIFO */
632 txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); 639 txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
640 if (txlen > SC16IS7XX_FIFO_SIZE) {
641 dev_err_ratelimited(port->dev,
642 "chip reports %d free bytes in TX fifo, but it only has %d",
643 txlen, SC16IS7XX_FIFO_SIZE);
644 txlen = 0;
645 }
633 to_send = (to_send > txlen) ? txlen : to_send; 646 to_send = (to_send > txlen) ? txlen : to_send;
634 647
635 /* Add data to send */ 648 /* Add data to send */