Takashi Iwai f1aff8
From 9a1de9db921a0f39445e92e8f4a1a84ea85b43c1 Mon Sep 17 00:00:00 2001
Takashi Iwai f1aff8
From: Tony Lindgren <tony@atomide.com>
Takashi Iwai f1aff8
Date: Tue, 27 Jul 2021 13:35:33 +0300
Takashi Iwai f1aff8
Subject: [PATCH] serial: 8250_omap: Handle optional overrun-throttle-ms property
Takashi Iwai f1aff8
Git-commit: 1fe0e1fa3209ad8e9124147775bd27b1d9f04bd4
Takashi Iwai f1aff8
Patch-mainline: v5.15-rc1
Takashi Iwai f1aff8
References: stable-5.14.6
Takashi Iwai f1aff8
Takashi Iwai f1aff8
[ Upstream commit 1fe0e1fa3209ad8e9124147775bd27b1d9f04bd4 ]
Takashi Iwai f1aff8
Takashi Iwai f1aff8
Handle optional overrun-throttle-ms property as done for 8250_fsl in commit
Takashi Iwai f1aff8
6d7f677a2afa ("serial: 8250: Rate limit serial port rx interrupts during
Takashi Iwai f1aff8
input overruns"). This can be used to rate limit the UART interrupts on
Takashi Iwai f1aff8
noisy lines that end up producing messages like the following:
Takashi Iwai f1aff8
Takashi Iwai f1aff8
ttyS ttyS2: 4 input overrun(s)
Takashi Iwai f1aff8
Takashi Iwai f1aff8
At least on droid4, the multiplexed USB and UART port is left to UART mode
Takashi Iwai f1aff8
by the bootloader for a debug console, and if a USB charger is connected
Takashi Iwai f1aff8
on boot, we get noise on the UART until the PMIC related drivers for PHY
Takashi Iwai f1aff8
and charger are loaded.
Takashi Iwai f1aff8
Takashi Iwai f1aff8
With this patch and overrun-throttle-ms = <500> we avoid the extra rx
Takashi Iwai f1aff8
interrupts.
Takashi Iwai f1aff8
Takashi Iwai f1aff8
Cc: Carl Philipp Klemm <philipp@uvos.xyz>
Takashi Iwai f1aff8
Cc: Merlijn Wajer <merlijn@wizzup.org>
Takashi Iwai f1aff8
Cc: Pavel Machek <pavel@ucw.cz>
Takashi Iwai f1aff8
Cc: Sebastian Reichel <sre@kernel.org>
Takashi Iwai f1aff8
Cc: Vignesh Raghavendra <vigneshr@ti.com>
Takashi Iwai f1aff8
Signed-off-by: Tony Lindgren <tony@atomide.com>
Takashi Iwai f1aff8
Link: https://lore.kernel.org/r/20210727103533.51547-2-tony@atomide.com
Takashi Iwai f1aff8
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Takashi Iwai f1aff8
Signed-off-by: Sasha Levin <sashal@kernel.org>
Takashi Iwai f1aff8
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai f1aff8
Takashi Iwai f1aff8
---
Takashi Iwai f1aff8
 drivers/tty/serial/8250/8250_omap.c | 25 ++++++++++++++++++++++++-
Takashi Iwai f1aff8
 1 file changed, 24 insertions(+), 1 deletion(-)
Takashi Iwai f1aff8
Takashi Iwai f1aff8
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
Takashi Iwai f1aff8
index 79418d4beb48..b6c731a267d2 100644
Takashi Iwai f1aff8
--- a/drivers/tty/serial/8250/8250_omap.c
Takashi Iwai f1aff8
+++ b/drivers/tty/serial/8250/8250_omap.c
Takashi Iwai f1aff8
@@ -617,7 +617,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
Takashi Iwai f1aff8
 	struct uart_port *port = dev_id;
Takashi Iwai f1aff8
 	struct omap8250_priv *priv = port->private_data;
Takashi Iwai f1aff8
 	struct uart_8250_port *up = up_to_u8250p(port);
Takashi Iwai f1aff8
-	unsigned int iir;
Takashi Iwai f1aff8
+	unsigned int iir, lsr;
Takashi Iwai f1aff8
 	int ret;
Takashi Iwai f1aff8
 
Takashi Iwai f1aff8
 #ifdef CONFIG_SERIAL_8250_DMA
Takashi Iwai f1aff8
@@ -628,6 +628,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
Takashi Iwai f1aff8
 #endif
Takashi Iwai f1aff8
 
Takashi Iwai f1aff8
 	serial8250_rpm_get(up);
Takashi Iwai f1aff8
+	lsr = serial_port_in(port, UART_LSR);
Takashi Iwai f1aff8
 	iir = serial_port_in(port, UART_IIR);
Takashi Iwai f1aff8
 	ret = serial8250_handle_irq(port, iir);
Takashi Iwai f1aff8
 
Takashi Iwai f1aff8
@@ -642,6 +643,24 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
Takashi Iwai f1aff8
 		serial_port_in(port, UART_RX);
Takashi Iwai f1aff8
 	}
Takashi Iwai f1aff8
 
Takashi Iwai f1aff8
+	/* Stop processing interrupts on input overrun */
Takashi Iwai f1aff8
+	if ((lsr & UART_LSR_OE) && up->overrun_backoff_time_ms > 0) {
Takashi Iwai f1aff8
+		unsigned long delay;
Takashi Iwai f1aff8
+
Takashi Iwai f1aff8
+		up->ier = port->serial_in(port, UART_IER);
Takashi Iwai f1aff8
+		if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
Takashi Iwai f1aff8
+			port->ops->stop_rx(port);
Takashi Iwai f1aff8
+		} else {
Takashi Iwai f1aff8
+			/* Keep restarting the timer until
Takashi Iwai f1aff8
+			 * the input overrun subsides.
Takashi Iwai f1aff8
+			 */
Takashi Iwai f1aff8
+			cancel_delayed_work(&up->overrun_backoff);
Takashi Iwai f1aff8
+		}
Takashi Iwai f1aff8
+
Takashi Iwai f1aff8
+		delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
Takashi Iwai f1aff8
+		schedule_delayed_work(&up->overrun_backoff, delay);
Takashi Iwai f1aff8
+	}
Takashi Iwai f1aff8
+
Takashi Iwai f1aff8
 	serial8250_rpm_put(up);
Takashi Iwai f1aff8
 
Takashi Iwai f1aff8
 	return IRQ_RETVAL(ret);
Takashi Iwai f1aff8
@@ -1353,6 +1372,10 @@ static int omap8250_probe(struct platform_device *pdev)
Takashi Iwai f1aff8
 		}
Takashi Iwai f1aff8
 	}
Takashi Iwai f1aff8
 
Takashi Iwai f1aff8
+	if (of_property_read_u32(np, "overrun-throttle-ms",
Takashi Iwai f1aff8
+				 &up.overrun_backoff_time_ms) != 0)
Takashi Iwai f1aff8
+		up.overrun_backoff_time_ms = 0;
Takashi Iwai f1aff8
+
Takashi Iwai f1aff8
 	priv->wakeirq = irq_of_parse_and_map(np, 1);
Takashi Iwai f1aff8
 
Takashi Iwai f1aff8
 	pdata = of_device_get_match_data(&pdev->dev);
Takashi Iwai f1aff8
-- 
Takashi Iwai f1aff8
2.26.2
Takashi Iwai f1aff8