public inbox for linux-serial@vger.kernel.org
 help / color / mirror / Atom feed
From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Jiri Slaby" <jirislaby@kernel.org>,
	linux-serial@vger.kernel.org,
	"Andy Shevchenko" <andriy.shevchenko@linux.intel.com>,
	"qianfan Zhao" <qianfanguijin@163.com>,
	"Adriana Nicolae" <adriana@arista.com>,
	"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
	linux-kernel@vger.kernel.org
Cc: "Bandal, Shankar" <shankar.bandal@intel.com>,
	"Murthy, Shanth" <shanth.murthy@intel.com>,
	stable@vger.kernel.org
Subject: [PATCH v2 2/7] serial: 8250_dw: Avoid unnecessary LCR writes
Date: Wed, 28 Jan 2026 12:52:56 +0200	[thread overview]
Message-ID: <20260128105301.1869-3-ilpo.jarvinen@linux.intel.com> (raw)
In-Reply-To: <20260128105301.1869-1-ilpo.jarvinen@linux.intel.com>

When DW UART is configured with BUSY flag, LCR writes may not always
succeed which can make any LCR write complex and very expensive.
Performing write directly can trigger IRQ and the driver has to perform
complex and distruptive sequence while retrying the write.

Therefore, it's better to avoid doing LCR write that would not change
the value of the LCR register. Add LCR write avoidance code into the
8250_dw driver's .serial_out() functions.

Reported-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
 drivers/tty/serial/8250/8250_dw.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 27af83f0ff46..7500b1ff1ac1 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -181,6 +181,22 @@ static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value
 	 */
 }
 
+/*
+ * With BUSY, LCR writes can be very expensive (IRQ + complex retry logic).
+ * If the write does not change the value of the LCR register, skip it entirely.
+ */
+static bool dw8250_can_skip_reg_write(struct uart_port *p, unsigned int offset, u32 value)
+{
+	struct dw8250_data *d = to_dw8250_data(p->private_data);
+	u32 lcr;
+
+	if (offset != UART_LCR || d->uart_16550_compatible)
+		return false;
+
+	lcr = serial_port_in(p, offset);
+	return lcr == value;
+}
+
 /* Returns once the transmitter is empty or we run out of retries */
 static void dw8250_tx_wait_empty(struct uart_port *p)
 {
@@ -207,12 +223,18 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
 
 static void dw8250_serial_out(struct uart_port *p, unsigned int offset, u32 value)
 {
+	if (dw8250_can_skip_reg_write(p, offset, value))
+		return;
+
 	writeb(value, p->membase + (offset << p->regshift));
 	dw8250_check_lcr(p, offset, value);
 }
 
 static void dw8250_serial_out38x(struct uart_port *p, unsigned int offset, u32 value)
 {
+	if (dw8250_can_skip_reg_write(p, offset, value))
+		return;
+
 	/* Allow the TX to drain before we reconfigure */
 	if (offset == UART_LCR)
 		dw8250_tx_wait_empty(p);
@@ -237,6 +259,9 @@ static u32 dw8250_serial_inq(struct uart_port *p, unsigned int offset)
 
 static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 value)
 {
+	if (dw8250_can_skip_reg_write(p, offset, value))
+		return;
+
 	value &= 0xff;
 	__raw_writeq(value, p->membase + (offset << p->regshift));
 	/* Read back to ensure register write ordering. */
@@ -248,6 +273,9 @@ static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 val
 
 static void dw8250_serial_out32(struct uart_port *p, unsigned int offset, u32 value)
 {
+	if (dw8250_can_skip_reg_write(p, offset, value))
+		return;
+
 	writel(value, p->membase + (offset << p->regshift));
 	dw8250_check_lcr(p, offset, value);
 }
@@ -261,6 +289,9 @@ static u32 dw8250_serial_in32(struct uart_port *p, unsigned int offset)
 
 static void dw8250_serial_out32be(struct uart_port *p, unsigned int offset, u32 value)
 {
+	if (dw8250_can_skip_reg_write(p, offset, value))
+		return;
+
 	iowrite32be(value, p->membase + (offset << p->regshift));
 	dw8250_check_lcr(p, offset, value);
 }
-- 
2.39.5


  parent reply	other threads:[~2026-01-28 10:53 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-28 10:52 [PATCH v2 0/7] 8250 DW UART fixes when under constant Rx pressure Ilpo Järvinen
2026-01-28 10:52 ` [PATCH v2 1/7] serial: 8250: Protect LCR write in shutdown Ilpo Järvinen
2026-01-28 13:12   ` Andy Shevchenko
2026-01-28 10:52 ` Ilpo Järvinen [this message]
2026-01-28 13:36   ` [PATCH v2 2/7] serial: 8250_dw: Avoid unnecessary LCR writes Andy Shevchenko
2026-01-28 10:52 ` [PATCH v2 3/7] serial: 8250: Add serial8250_handle_irq_locked() Ilpo Järvinen
2026-01-28 13:20   ` Andy Shevchenko
2026-01-28 13:26     ` Ilpo Järvinen
2026-01-28 10:52 ` [PATCH v2 4/7] serial: 8250_dw: Rework dw8250_handle_irq() locking and IIR handling Ilpo Järvinen
2026-01-28 13:48   ` Andy Shevchenko
2026-01-28 14:00     ` Ilpo Järvinen
2026-01-28 10:52 ` [PATCH v2 5/7] serial: 8250_dw: Rework IIR_NO_INT handling to stop interrupt storm Ilpo Järvinen
2026-01-28 14:03   ` Andy Shevchenko
2026-01-28 10:53 ` [PATCH v2 6/7] serial: 8250: Add late synchronize_irq() to shutdown to handle DW UART BUSY Ilpo Järvinen
2026-01-28 14:37   ` Andy Shevchenko
2026-01-28 15:07     ` Ilpo Järvinen
2026-01-28 10:53 ` [PATCH v2 7/7] serial: 8250_dw: Ensure BUSY is deasserted Ilpo Järvinen
2026-01-28 15:42   ` Andy Shevchenko
2026-01-30 12:44     ` Ilpo Järvinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260128105301.1869-3-ilpo.jarvinen@linux.intel.com \
    --to=ilpo.jarvinen@linux.intel.com \
    --cc=adriana@arista.com \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jirislaby@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=qianfanguijin@163.com \
    --cc=shankar.bandal@intel.com \
    --cc=shanth.murthy@intel.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox