From nobody Sat Feb 7 10:44:38 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.21]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7680639900D; Tue, 3 Feb 2026 17:11:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.21 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770138680; cv=none; b=jCvC7jpc9wht3TbA/c1tDI+oFBG7MssEI/6g9qoM2zYdMEd2i7z6RgLT0XO4FJegnQFVbwwSV6HSqwvo4h8ijqD+FuTSVIs0Vi7J6aFinss5OQxbMvBaJrst5Z2cU5btEPXq5R8+fGvGL+abe34DkVYczhRVLB+K72u1fGZqWQY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770138680; c=relaxed/simple; bh=SDHf+A0k6bK0v2kpFgTGPbdfB2E7Jjwj09y2K2i+MZA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=Qp08GQlnTH0bT0QFfXCXrHKLFzZ+/n+bJEUCVNKXYi7Kxp6uKvFEgo6bwXYlfUHRz+nDHavfDYeWyWT0rTqTxavyjvkwNNvIqiB4dNIRh5YJF34JXIT95fXpKzxip8x5qgkwU4/WvsFM+wnKUUg7szqYEblnGms6wJsluYLvcfo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=PE2Wyiue; arc=none smtp.client-ip=198.175.65.21 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="PE2Wyiue" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770138678; x=1801674678; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SDHf+A0k6bK0v2kpFgTGPbdfB2E7Jjwj09y2K2i+MZA=; b=PE2WyiuecyRvcGQyldE4TVckgP6HpVrh2emRYgG9cRuglBsFkiK0gArf +b2YlIrdyGvOKqyaqqD+rGpIF/ASeE6i8/VOnmPKiZfQ0vU6nD4w58vPe uYfOjfmOUEfF4bDCFS7DJhqibt9WUlOcJNQhp4jrtC3z5e4eQx+fpXqKj H2Jesw5ozXfaE8/ntrRBJKpsv57Yx9h0fcyqFadmru1KwMeDZjMtiqXAO aYnRx6/Trm9URIo9Szbc7AbxEWo6EqvquaMpGq+sbWa8A/iBQurdzQFfc cjaGnmiL2K7Sk0AUoBGASoleTd+mYrPze8hJVLZ/eIQ4E5oAwMFAE+D0h A==; X-CSE-ConnectionGUID: ikTGuzCeQFqKp6fCiGKrTw== X-CSE-MsgGUID: i0/xy754QZGwszJ9jNwORg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="71220790" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="71220790" Received: from orviesa002.jf.intel.com ([10.64.159.142]) by orvoesa113.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 09:11:18 -0800 X-CSE-ConnectionGUID: pyd54vgKTV2uH6if2xD7LQ== X-CSE-MsgGUID: 46RXGBMdRNSQ71UnabMTLA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="240589495" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.117]) by orviesa002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 09:11:14 -0800 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: Greg Kroah-Hartman , Jiri Slaby , linux-serial@vger.kernel.org, Andy Shevchenko , qianfan Zhao , Adriana Nicolae , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , linux-kernel@vger.kernel.org Cc: "Bandal, Shankar" , "Murthy, Shanth" , stable@vger.kernel.org Subject: [PATCH v4 2/7] serial: 8250_dw: Avoid unnecessary LCR writes Date: Tue, 3 Feb 2026 19:10:44 +0200 Message-Id: <20260203171049.4353-3-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260203171049.4353-1-ilpo.jarvinen@linux.intel.com> References: <20260203171049.4353-1-ilpo.jarvinen@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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" Tested-by: "Bandal, Shankar" Tested-by: "Murthy, Shanth" Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo J=C3=A4rvinen --- 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/82= 50_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, unsi= gned int offset, u32 value */ } =20 +/* + * 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 ent= irely. + */ +static bool dw8250_can_skip_reg_write(struct uart_port *p, unsigned int of= fset, u32 value) +{ + struct dw8250_data *d =3D to_dw8250_data(p->private_data); + u32 lcr; + + if (offset !=3D UART_LCR || d->uart_16550_compatible) + return false; + + lcr =3D serial_port_in(p, offset); + return lcr =3D=3D 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) =20 static void dw8250_serial_out(struct uart_port *p, unsigned int offset, u3= 2 value) { + if (dw8250_can_skip_reg_write(p, offset, value)) + return; + writeb(value, p->membase + (offset << p->regshift)); dw8250_check_lcr(p, offset, value); } =20 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 =3D=3D UART_LCR) dw8250_tx_wait_empty(p); @@ -237,6 +259,9 @@ static u32 dw8250_serial_inq(struct uart_port *p, unsig= ned int offset) =20 static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u= 32 value) { + if (dw8250_can_skip_reg_write(p, offset, value)) + return; + value &=3D 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, uns= igned int offset, u32 val =20 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, unsi= gned int offset) =20 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); } --=20 2.39.5