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

Configure Feed

Select the types of activity you want to include in your feed.

serial: sc16is7xx: fix unconditional activation of THRI interrupt

Commit cc4c1d05eb10 ("sc16is7xx: Properly resume TX after stop") changed
behavior to unconditionnaly set the THRI interrupt in sc16is7xx_tx_proc().

For example when sending a 65 bytes message, and assuming the Tx FIFO is
initially empty, sc16is7xx_handle_tx() will write the first 64 bytes of the
message to the FIFO and sc16is7xx_tx_proc() will then activate THRI. When
the THRI IRQ is fired, the driver will write the remaining byte of the
message to the FIFO, and disable THRI by calling sc16is7xx_stop_tx().

When sending a 2 bytes message, sc16is7xx_handle_tx() will write the 2
bytes of the message to the FIFO and call sc16is7xx_stop_tx(), disabling
THRI. After sc16is7xx_handle_tx() exits, control returns to
sc16is7xx_tx_proc() which will unconditionally set THRI. When the THRI IRQ
is fired, the driver simply acknowledges the interrupt and does nothing
more, since all the data has already been written to the FIFO. This results
in 2 register writes and 4 register reads all for nothing and taking
precious cycles from the I2C/SPI bus.

Fix this by enabling the THRI interrupt only when we fill the Tx FIFO to
its maximum capacity and there are remaining bytes to send in the message.

Fixes: cc4c1d05eb10 ("sc16is7xx: Properly resume TX after stop")
Cc: <stable@vger.kernel.org>
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Link: https://lore.kernel.org/r/20231211171353.2901416-7-hugo@hugovil.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Hugo Villeneuve and committed by
Greg Kroah-Hartman
99157530 dbf4ab82

+2 -5
+2 -5
drivers/tty/serial/sc16is7xx.c
··· 687 687 688 688 if (uart_circ_empty(xmit)) 689 689 sc16is7xx_stop_tx(port); 690 + else 691 + sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT); 690 692 uart_port_unlock_irqrestore(port, flags); 691 693 } 692 694 ··· 817 815 { 818 816 struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port); 819 817 struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); 820 - unsigned long flags; 821 818 822 819 if ((port->rs485.flags & SER_RS485_ENABLED) && 823 820 (port->rs485.delay_rts_before_send > 0)) ··· 825 824 mutex_lock(&one->efr_lock); 826 825 sc16is7xx_handle_tx(port); 827 826 mutex_unlock(&one->efr_lock); 828 - 829 - uart_port_lock_irqsave(port, &flags); 830 - sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT); 831 - uart_port_unlock_irqrestore(port, flags); 832 827 } 833 828 834 829 static void sc16is7xx_reconf_rs485(struct uart_port *port)