linux/drivers/tty/serial
Ilpo Järvinen a7b9ce39fb serial: 8250_dw: Ensure BUSY is deasserted
DW UART cannot write to LCR, DLL, and DLH while BUSY is asserted.
Existance of BUSY depends on uart_16550_compatible, if UART HW is
configured with it those registers can always be written.

There currently is dw8250_force_idle() which attempts to achieve
non-BUSY state by disabling FIFO, however, the solution is unreliable
when Rx keeps getting more and more characters.

Create a sequence of operations that ensures UART cannot keep BUSY
asserted indefinitely. The new sequence relies on enabling loopback mode
temporarily to prevent incoming Rx characters keeping UART BUSY.

Ensure no Tx in ongoing while the UART is switches into the loopback
mode (requires exporting serial8250_fifo_wait_for_lsr_thre() and adding
DMA Tx pause/resume functions).

According to tests performed by Adriana Nicolae <adriana@arista.com>,
simply disabling FIFO or clearing FIFOs only once does not always
ensure BUSY is deasserted but up to two tries may be needed. This could
be related to ongoing Rx of a character (a guess, not known for sure).
Therefore, retry FIFO clearing a few times (retry limit 4 is arbitrary
number but using, e.g., p->fifosize seems overly large). Tests
performed by others did not exhibit similar challenge but it does not
seem harmful to leave the FIFO clearing loop in place for all DW UARTs
with BUSY functionality.

Use the new dw8250_idle_enter/exit() to do divisor writes and LCR
writes. In case of plain LCR writes, opportunistically try to update
LCR first and only invoke dw8250_idle_enter() if the write did not
succeed (it has been observed that in practice most LCR writes do
succeed without complications).

This issue was first reported by qianfan Zhao who put lots of debugging
effort into understanding the solution space.

Fixes: c49436b657 ("serial: 8250_dw: Improve unwritable LCR workaround")
Fixes: 7d4008ebb1 ("tty: add a DesignWare 8250 driver")
Cc: stable <stable@kernel.org>
Reported-by: qianfan Zhao <qianfanguijin@163.com>
Link: https://lore.kernel.org/linux-serial/289bb78a-7509-1c5c-2923-a04ed3b6487d@163.com/
Reported-by: Adriana Nicolae <adriana@arista.com>
Link: https://lore.kernel.org/linux-serial/20250819182322.3451959-1-adriana@arista.com/
Reported-by: Bandal, Shankar <shankar.bandal@intel.com>
Tested-by: Bandal, Shankar <shankar.bandal@intel.com>
Tested-by: Murthy, Shanth <shanth.murthy@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://patch.msgid.link/20260203171049.4353-8-ilpo.jarvinen@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2026-03-12 15:34:29 +01:00
..
8250 serial: 8250_dw: Ensure BUSY is deasserted 2026-03-12 15:34:29 +01:00
jsm Convert more 'alloc_obj' cases to default GFP_KERNEL arguments 2026-02-21 20:03:00 -08:00
21285.c
Kconfig serial: SH_SCI: improve "DMA support" prompt 2026-01-16 14:25:16 +01:00
Makefile serial: sh-sci: Add support for RZ/T2H SCI 2025-07-09 13:45:30 +02:00
altera_jtaguart.c serial: altera_jtaguart: Use KBUILD_MODNAME 2024-12-04 16:35:53 +01:00
altera_uart.c treewide, timers: Rename from_timer() to timer_container_of() 2025-06-08 09:07:37 +02:00
amba-pl010.c serial: amba-pl010: Switch to irq_get_nr_irqs() 2024-10-16 21:56:58 +02:00
amba-pl011.c serial: amba-pl011: prefer dma_mapping_error() over explicit address checking 2025-10-28 15:26:47 +01:00
apbuart.c serial: apbuart: fix console prompt on qemu 2024-01-04 16:21:06 +01:00
apbuart.h
ar933x_uart.c serial: ar933x: Add polling support 2025-10-22 12:04:43 +02:00
arc_uart.c tty: serial: switch from circ_buf to kfifo 2024-04-09 15:28:03 +02:00
atmel_serial.c treewide, timers: Rename from_timer() to timer_container_of() 2025-06-08 09:07:37 +02:00
atmel_serial.h
bcm63xx_uart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
clps711x.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
cpm_uart.c TTY / Serial driver updates for 6.13-rc1 2024-11-30 09:03:16 -08:00
cpm_uart.h
digicolor-usart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
dz.c tty: serial: switch from circ_buf to kfifo 2024-04-09 15:28:03 +02:00
dz.h
earlycon-riscv-sbi.c tty/serial: Add RISC-V SBI debug console based earlycon 2024-01-10 07:04:04 -08:00
earlycon-semihost.c
earlycon.c init: Don't proxy `console=` to earlycon 2024-10-01 14:11:39 +02:00
esp32_acm.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
esp32_uart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
fsl_linflexuart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
fsl_lpuart.c tty: serial: fsl_lpuart: Add missing wakeup event reporting 2025-10-22 12:04:51 +02:00
icom.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
imx.c tty: serial: imx: Add missing wakeup event reporting 2025-10-22 12:06:35 +02:00
imx_earlycon.c
ip22zilog.c tty: serial: ip22zilog: Use platform device for probing 2025-08-14 11:58:40 +02:00
ip22zilog.h
kgdboc.c drivers: serial: kgdboc: Drop checks for CON_ENABLED and CON_BOOT 2025-11-27 15:54:50 +01:00
lantiq.c serial: lantiq: Remove unnecessary print function dev_err() 2025-04-11 16:51:49 +02:00
liteuart.c treewide, timers: Rename from_timer() to timer_container_of() 2025-06-08 09:07:37 +02:00
lpc32xx_hs.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
ma35d1_serial.c tty: serial: pl011: remove incorrect of_match_ptr annotation 2025-03-20 08:09:56 -07:00
max310x.c serial: max310x: improve interrupt handling 2025-09-12 16:10:16 +02:00
max3100.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
mcf.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
men_z135_uart.c serial: men_z135_uart: drop unneeded MODULE_ALIAS 2026-01-16 14:25:04 +01:00
meson_uart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
milbeaut_usio.c serial: Fix potential null-ptr-deref in mlb_usio_probe() 2025-04-11 16:53:34 +02:00
mpc52xx_uart.c serial: mpc52xx_uart: Remove legacy PM hook 2025-02-04 14:38:32 +01:00
mps2-uart.c
msm_serial.c tty: remove redundant condition checks 2025-09-06 15:49:58 +02:00
mux.c serial: mux: Fix kernel doc for mux_poll() 2025-11-26 13:11:17 +01:00
mvebu-uart.c tty: serial: mvebu-uart: convert from round_rate() to determine_rate() 2025-08-14 11:59:04 +02:00
mxs-auart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
omap-serial.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
owl-uart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
pch_uart.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
pic32_uart.c serial: pic32_uart: update include to use pic32.h from platform_data 2026-01-30 15:29:08 +01:00
pmac_zilog.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
pmac_zilog.h
pxa.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
qcom_geni_serial.c serial: qcom_geni: Fix BT failure regression on RB2 platform 2026-01-16 14:28:49 +01:00
rda-uart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
rp2.c serial: rp2: Replace deprecated PCI functions 2024-10-30 16:07:38 -05:00
rsci.c serial: rsci: Convert to FIELD_MODIFY() 2025-12-23 11:52:31 +01:00
rsci.h serial: sh-sci: Add support for RZ/G3E RSCI 2025-12-17 15:07:07 +01:00
sa1100.c treewide, timers: Rename from_timer() to timer_container_of() 2025-06-08 09:07:37 +02:00
samsung_tty.c tty: serial: samsung: Declare earlycon for Exynos850 2025-11-26 13:11:55 +01:00
sb1250-duart.c tty: serial: switch from circ_buf to kfifo 2024-04-09 15:28:03 +02:00
sc16is7xx.c serial: sc16is7xx: add comments for lock requirements 2025-10-28 15:25:41 +01:00
sc16is7xx.h serial: sc16is7xx: use KBUILD_MODNAME 2025-10-28 15:25:41 +01:00
sc16is7xx_i2c.c serial: sc16is7xx: use KBUILD_MODNAME 2025-10-28 15:25:41 +01:00
sc16is7xx_spi.c serial: sc16is7xx: use KBUILD_MODNAME 2025-10-28 15:25:41 +01:00
sccnxp.c treewide, timers: Rename from_timer() to timer_container_of() 2025-06-08 09:07:37 +02:00
serial-tegra.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
serial_base.h serial: core: Add serial_base_match_and_update_preferred_console() 2024-07-04 15:41:44 +02:00
serial_base_bus.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
serial_core.c serial: core: fix infinite loop in handle_tx() for PORT_UNKNOWN 2026-03-12 15:31:41 +01:00
serial_ctrl.c
serial_mctrl_gpio.c serial: mctrl_gpio: split disable_ms into sync and no_sync APIs 2025-02-19 15:08:36 +01:00
serial_mctrl_gpio.h serial: mctrl_gpio: split disable_ms into sync and no_sync APIs 2025-02-19 15:08:36 +01:00
serial_port.c serial: port: Make ->iotype validation global in __uart_read_properties() 2025-02-04 14:44:44 +01:00
serial_txx9.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
sh-sci-common.h serial: sh-sci: Add finish_console_write() callback 2025-12-17 15:07:07 +01:00
sh-sci.c Merge 6.19-rc3 into tty-next 2025-12-29 09:31:39 +01:00
sifive.c Linux 6.15-rc4 2025-04-28 10:13:28 +02:00
sprd_serial.c serial: sprd: Return -EPROBE_DEFER when uart clock is not ready 2025-11-26 13:12:19 +01:00
st-asc.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
stm32-usart.c serial: stm32: do not deassert RS485 RTS GPIO prematurely 2025-03-20 08:30:44 -07:00
stm32-usart.h serial: stm32: get FIFO size from hwcfg register 2024-01-27 19:04:11 -08:00
suncore.c
sunhv.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
sunplus-uart.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
sunsab.c Convert remaining multi-line kmalloc_obj/flex GFP_KERNEL uses 2026-02-22 08:26:33 -08:00
sunsab.h
sunsu.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
sunzilog.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
sunzilog.h
tegra-tcu.c serial: Switch back to struct platform_driver::remove() 2024-10-11 08:13:28 +02:00
tegra-utc.c serial: tegra-utc: Remove unneeded semicolon 2025-04-11 16:52:21 +02:00
timbuart.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
timbuart.h
uartlite.c serial: uartlite: fix PM runtime usage count underflow on probe 2026-03-12 15:30:51 +01:00
ucc_uart.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
vt8500_serial.c serial: vt8500: Use port lock wrappers 2023-09-18 11:18:16 +02:00
xilinx_uartps.c serial: xilinx_uartps: fix rs485 delay_rts_after_send 2025-12-23 11:55:16 +01:00
zs.c tty: serial: switch from circ_buf to kfifo 2024-04-09 15:28:03 +02:00
zs.h