serial: 8250_omap: Handle optional overrun-throttle-ms property
authorTony Lindgren <tony@atomide.com>
Tue, 27 Jul 2021 10:35:33 +0000 (13:35 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Aug 2021 12:01:25 +0000 (14:01 +0200)
Handle optional overrun-throttle-ms property as done for 8250_fsl in commit
6d7f677a2afa ("serial: 8250: Rate limit serial port rx interrupts during
input overruns"). This can be used to rate limit the UART interrupts on
noisy lines that end up producing messages like the following:

ttyS ttyS2: 4 input overrun(s)

At least on droid4, the multiplexed USB and UART port is left to UART mode
by the bootloader for a debug console, and if a USB charger is connected
on boot, we get noise on the UART until the PMIC related drivers for PHY
and charger are loaded.

With this patch and overrun-throttle-ms = <500> we avoid the extra rx
interrupts.

Cc: Carl Philipp Klemm <philipp@uvos.xyz>
Cc: Merlijn Wajer <merlijn@wizzup.org>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Sebastian Reichel <sre@kernel.org>
Cc: Vignesh Raghavendra <vigneshr@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Link: https://lore.kernel.org/r/20210727103533.51547-2-tony@atomide.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250_omap.c

index b81d1bdc7b8872494fd55339aee67bde86bd7282..891fd8345e2533dc4f6f5d53f4fe1c743b9165e3 100644 (file)
@@ -617,7 +617,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
        struct uart_port *port = dev_id;
        struct omap8250_priv *priv = port->private_data;
        struct uart_8250_port *up = up_to_u8250p(port);
-       unsigned int iir;
+       unsigned int iir, lsr;
        int ret;
 
 #ifdef CONFIG_SERIAL_8250_DMA
@@ -628,6 +628,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
 #endif
 
        serial8250_rpm_get(up);
+       lsr = serial_port_in(port, UART_LSR);
        iir = serial_port_in(port, UART_IIR);
        ret = serial8250_handle_irq(port, iir);
 
@@ -642,6 +643,24 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
                serial_port_in(port, UART_RX);
        }
 
+       /* Stop processing interrupts on input overrun */
+       if ((lsr & UART_LSR_OE) && up->overrun_backoff_time_ms > 0) {
+               unsigned long delay;
+
+               up->ier = port->serial_in(port, UART_IER);
+               if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
+                       port->ops->stop_rx(port);
+               } else {
+                       /* Keep restarting the timer until
+                        * the input overrun subsides.
+                        */
+                       cancel_delayed_work(&up->overrun_backoff);
+               }
+
+               delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
+               schedule_delayed_work(&up->overrun_backoff, delay);
+       }
+
        serial8250_rpm_put(up);
 
        return IRQ_RETVAL(ret);
@@ -1353,6 +1372,10 @@ static int omap8250_probe(struct platform_device *pdev)
                }
        }
 
+       if (of_property_read_u32(np, "overrun-throttle-ms",
+                                &up.overrun_backoff_time_ms) != 0)
+               up.overrun_backoff_time_ms = 0;
+
        priv->wakeirq = irq_of_parse_and_map(np, 1);
 
        pdata = of_device_get_match_data(&pdev->dev);