When DW UART is !uart_16550_compatible, it can indicate BUSY at any
point (when under constant Rx pressure) unless a complex sequence of
steps is performed. Any LCR write can run a foul with the condition
that prevents writing LCR while the UART is BUSY, which triggers
BUSY_DETECT interrupt that seems unmaskable using IER bits.
Normal flow is that dw8250_handle_irq() handles BUSY_DETECT condition
by reading USR register. This BUSY feature, however, breaks the
assumptions made in serial8250_do_shutdown(), which runs
synchronize_irq() after clearing IER and assumes no interrupts can
occur after that point but then proceeds to update LCR, which on DW
UART can trigger an interrupt.
If serial8250_do_shutdown() releases the interrupt handler before the
handler has run and processed the BUSY_DETECT condition by read the USR
register, the IRQ is not deasserted resulting in interrupt storm that
triggers "irq x: nobody cared" warning leading to disabling the IRQ.
Add late synchronize_irq() into serial8250_do_shutdown() to ensure
BUSY_DETECT from DW UART is handled before port's interrupt handler is
released. Alternative would be to add DW UART specific shutdown
function but it would mostly duplicate the generic code and the extra
synchronize_irq() seems pretty harmless in serial8250_do_shutdown().
Fixes: 7d4008ebb1c9 ("tty: add a DesignWare 8250 driver")
Cc: stable@vger.kernel.org
Reported-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/tty/serial/8250/8250_port.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index bc223eb1f474..fb0b8397cd4b 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2401,6 +2401,12 @@ void serial8250_do_shutdown(struct uart_port *port)
* the IRQ chain.
*/
serial_port_in(port, UART_RX);
+ /*
+ * LCR writes on DW UART can trigger late (unmaskable) IRQs.
+ * Handle them before releasing the handler.
+ */
+ synchronize_irq(port->irq);
+
serial8250_rpm_put(up);
up->ops->release_irq(up);
--
2.39.5
On Wed, Jan 28, 2026 at 12:53:00PM +0200, Ilpo Järvinen wrote: > When DW UART is !uart_16550_compatible, it can indicate BUSY at any > point (when under constant Rx pressure) unless a complex sequence of > steps is performed. Any LCR write can run a foul with the condition > that prevents writing LCR while the UART is BUSY, which triggers > BUSY_DETECT interrupt that seems unmaskable using IER bits. > > Normal flow is that dw8250_handle_irq() handles BUSY_DETECT condition > by reading USR register. This BUSY feature, however, breaks the > assumptions made in serial8250_do_shutdown(), which runs > synchronize_irq() after clearing IER and assumes no interrupts can > occur after that point but then proceeds to update LCR, which on DW > UART can trigger an interrupt. > > If serial8250_do_shutdown() releases the interrupt handler before the > handler has run and processed the BUSY_DETECT condition by read the USR > register, the IRQ is not deasserted resulting in interrupt storm that > triggers "irq x: nobody cared" warning leading to disabling the IRQ. > > Add late synchronize_irq() into serial8250_do_shutdown() to ensure > BUSY_DETECT from DW UART is handled before port's interrupt handler is > released. Alternative would be to add DW UART specific shutdown > function but it would mostly duplicate the generic code and the extra > synchronize_irq() seems pretty harmless in serial8250_do_shutdown(). Dunno if the triggered interrupt may lead to a new DMA transfers (since this is generic 8520 code...) in some cases. Anyway I've just sent a patch that is Cc'ed to you to prevent that from happening. Not sure if it needs to be incorporated into your series or should have a Fixes tag. Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> -- With Best Regards, Andy Shevchenko
On Wed, 28 Jan 2026, Andy Shevchenko wrote: > On Wed, Jan 28, 2026 at 12:53:00PM +0200, Ilpo Järvinen wrote: > > When DW UART is !uart_16550_compatible, it can indicate BUSY at any > > point (when under constant Rx pressure) unless a complex sequence of > > steps is performed. Any LCR write can run a foul with the condition > > that prevents writing LCR while the UART is BUSY, which triggers > > BUSY_DETECT interrupt that seems unmaskable using IER bits. > > > > Normal flow is that dw8250_handle_irq() handles BUSY_DETECT condition > > by reading USR register. This BUSY feature, however, breaks the > > assumptions made in serial8250_do_shutdown(), which runs > > synchronize_irq() after clearing IER and assumes no interrupts can > > occur after that point but then proceeds to update LCR, which on DW > > UART can trigger an interrupt. > > > > If serial8250_do_shutdown() releases the interrupt handler before the > > handler has run and processed the BUSY_DETECT condition by read the USR > > register, the IRQ is not deasserted resulting in interrupt storm that > > triggers "irq x: nobody cared" warning leading to disabling the IRQ. > > > > Add late synchronize_irq() into serial8250_do_shutdown() to ensure > > BUSY_DETECT from DW UART is handled before port's interrupt handler is > > released. Alternative would be to add DW UART specific shutdown > > function but it would mostly duplicate the generic code and the extra > > synchronize_irq() seems pretty harmless in serial8250_do_shutdown(). > > Dunno if the triggered interrupt may lead to a new DMA transfers (since > this is generic 8520 code...) in some cases. If BUSY_DETECT interrupt fires (like I'd expect), the handler won't start anything but exits early from dw8250_handle_irq(). > Anyway I've just sent a patch > that is Cc'ed to you to prevent that from happening. Not sure if it needs > to be incorporated into your series or should have a Fixes tag. > > Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> -- i.
© 2016 - 2026 Red Hat, Inc.