mirror-linux/drivers/tty/serial
Ilpo Järvinen e736180eaf serial: 8250: Prevent starting up DMA Rx on THRI interrupt
commit 90b8596ac4 upstream.

Hans de Goede reported Bluetooth adapters (HCIs) connected over an UART
connection failed due corrupted Rx payload. The problem was narrowed
down to DMA Rx starting on UART_IIR_THRI interrupt. The problem occurs
despite LSR having DR bit set, which is precondition for attempting to
start DMA Rx in the first place.

From a debug patch:
[x.807834] 8250irq: iir=cc lsr+saved=60 received=0/15 ier=0f dma_t/rx/err=0/0/0
[x.808676] 8250irq: iir=c2 lsr+saved=61 received=0/0 ier=0f dma_t/rx/err=0/0/0
[x.808776] 8250irq: iir=cc lsr+saved=60 received=1/12 ier=0d dma_t/rx/err=0/1/0
[x.808870] Bluetooth: hci0: Frame reassembly failed (-84)

In the debug snippet, received field indicates 1 byte was transferred
over DMA and 12 bytes after that with the non-DMA Rx. The sole byte DMA
handled was corrupted (gets zeroed) which leads to the HCI failure.

This problem became apparent after commit e8ffbb71f7 ("serial: 8250:
use THRE & __stop_tx also with DMA") changed Tx stop behavior. Tx stop
is now triggered from a THRI interrupt.

Despite that this problem looks like a HW bug, this fix is not adding
UART_BUG_xx flag to the driver beucase it seems useful in general to
avoid starting DMA when there are only a few bytes to transfer.
Skipping DMA for small transfers avoids the extra overhead DMA incurs.

Thus, don't setup DMA Rx on UART_IIR_THRI but leave it to a subsequent
interrupt which has Rx a related IIR value.

By returning false from handle_rx_dma(), the DMA vs non-DMA decision is
postponed until either UART_IIR_RDI (FIFO threshold worth of bytes
awaiting) or UART_IIR_TIMEOUT (inter-character timeout) triggers at a
later time which allows better to discern whether the number of bytes
warrants starting DMA or not.

Reported-by: Hans de Goede <hdegoede@redhat.com>
Tested-by: Hans de Goede <hdegoede@redhat.com>
Fixes: e8ffbb71f7 ("serial: 8250: use THRE & __stop_tx also with DMA")
Cc: stable@vger.kernel.org
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Acked-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20230317103034.12881-1-ilpo.jarvinen@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2023-04-13 16:55:28 +02:00
..
8250 serial: 8250: Prevent starting up DMA Rx on THRI interrupt 2023-04-13 16:55:28 +02:00
cpm_uart serial: cpm_uart: Don't request IRQ too early for console port 2022-09-30 14:59:19 +02:00
jsm drivers: serial: jsm: fix some leaks in probe 2022-09-22 16:11:43 +02:00
21285.c TTY/Serial driver update for 6.1-rc1 2022-10-07 16:36:24 -07:00
Kconfig Revert "tty: serial: fsl_lpuart: adjust SERIAL_FSL_LPUART_CONSOLE config dependency" 2023-03-22 13:33:55 +01:00
Makefile serial: remove VR41XX serial driver 2022-07-16 08:16:01 +02:00
altera_jtaguart.c tty: serial: do unlock on a common path in altera_jtaguart_console_putc() 2022-09-30 14:58:46 +02:00
altera_uart.c serial: altera_uart: fix locking in polling mode 2022-12-31 13:32:40 +01:00
amba-pl010.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
amba-pl011.c serial: amba-pl011: fix high priority character transmission in rs486 mode 2023-01-24 07:24:39 +01:00
apbuart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
apbuart.h
ar933x_uart.c serial: ar933x: Deassert Transmit Enable on ->rs485_config() 2022-09-22 16:43:05 +02:00
arc_uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
atmel_serial.c serial: atmel: fix incorrect baudrate setup 2023-01-24 07:24:39 +01:00
atmel_serial.h tty: serial: atmel: Use FIELD_PREP/FIELD_GET 2022-09-22 16:32:25 +02:00
bcm63xx_uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
clps711x.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
digicolor-usart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
dz.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
dz.h
earlycon-arm-semihost.c
earlycon-riscv-sbi.c
earlycon.c tty: move from strlcpy with unused retval to strscpy 2022-08-30 14:21:59 +02:00
fsl_linflexuart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
fsl_lpuart.c tty: serial: fsl_lpuart: avoid checking for transfer complete when UARTCTRL_SBK is asserted in lpuart32_tx_empty 2023-04-13 16:55:28 +02:00
icom.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
imx.c tty: serial: imx: disable Ageing Timer interrupt request irq 2023-03-10 09:33:37 +01:00
imx_earlycon.c
ip22zilog.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
ip22zilog.h
kgdb_nmi.c
kgdboc.c serial: kgdboc: Fix typo in comment 2022-06-27 14:37:09 +02:00
lantiq.c tty: serial: use FIELD_GET() in lqasc_tx_ready() 2022-09-30 14:58:45 +02:00
liteuart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
lpc32xx_hs.c tty: serial: extract tx_ready() from __serial_lpc32xx_tx() 2022-09-22 16:14:08 +02:00
max310x.c TTY/Serial driver update for 6.1-rc1 2022-10-07 16:36:24 -07:00
max3100.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
mcf.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
men_z135_uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
meson_uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
milbeaut_usio.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
mpc52xx_uart.c tty: serial: switch mpc52xx_uart_int_{r,t}x_chars() to bool 2022-09-22 16:14:08 +02:00
mps2-uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
msm_serial.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
mux.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
mvebu-uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
mxs-auart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
omap-serial.c tty: serial: extract serial_omap_put_char() from transmit_chars() 2022-09-22 16:14:08 +02:00
owl-uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
pch_uart.c tty: pcn_uart: fix memory leak with using debugfs_lookup() 2023-03-11 13:55:39 +01:00
pic32_uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
pmac_zilog.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
pmac_zilog.h
pxa.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
qcom_geni_serial.c tty: serial: qcom-geni-serial: fix slab-out-of-bounds on RX FIFO buffer 2023-01-24 07:24:37 +01:00
rda-uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
rp2.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
sa1100.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
samsung_tty.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
sb1250-duart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
sc16is7xx.c serial: sc16is7xx: setup GPIO controller later in probe 2023-03-11 13:55:34 +01:00
sccnxp.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
serial-tegra.c serial: tegra: Add missing clk_disable_unprepare() in tegra_uart_hw_init() 2023-03-10 09:33:32 +01:00
serial_core.c serial: Deassert Transmit Enable on probe in driver-specific way 2022-09-25 09:28:57 +02:00
serial_mctrl_gpio.c Documentation: serial: move GPIO kernel-doc to the functions 2022-07-28 10:37:42 +02:00
serial_mctrl_gpio.h
serial_txx9.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
sh-sci.c tty: serial: sh-sci: Fix Rx on RZ/G2L SCI 2023-04-13 16:55:28 +02:00
sh-sci.h
sifive.c Merge 7e2cd21e02 ("Merge tag 'tty-6.0-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty") into tty-next 2022-09-25 09:22:13 +02:00
sprd_serial.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
st-asc.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
stm32-usart.c serial: stm32: Merge hard IRQ and threaded IRQ handling into single IRQ handler 2023-02-09 11:28:23 +01:00
stm32-usart.h serial: stm32: make info structs static to avoid sparse warnings 2022-07-28 10:35:23 +02:00
suncore.c
sunhv.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
sunplus-uart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
sunsab.c serial: sunsab: Fix error handling in sunsab_init() 2022-12-31 13:32:40 +01:00
sunsab.h
sunsu.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
sunzilog.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
sunzilog.h
tegra-tcu.c Merge 7e2cd21e02 ("Merge tag 'tty-6.0-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty") into tty-next 2022-09-25 09:22:13 +02:00
timbuart.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
timbuart.h
uartlite.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
ucc_uart.c serial: ucc_uart: Remove custom frame size calculation 2022-08-30 14:28:33 +02:00
vt8500_serial.c tty: serial: move and cleanup vt8500_tx_empty() 2022-09-22 16:14:07 +02:00
xilinx_uartps.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
zs.c serial: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
zs.h