From nobody Sat Feb 7 05:44:09 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (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 3A1EA2DC798; Wed, 28 Jan 2026 10:53:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597603; cv=none; b=LxyTIUkFvgMqKn0uyAyMre2O8jgHBA8/n4FlpnH02dIChfRI8N8n+k37cNhg7Zxn+XTY7UgnjTO/KhkaEBq3etr4z8qcreDntFYb6+9KWLui/2oUsNWL343zTRaV29ifN4YnUSO3Z0Swtd4ehp3syMjMNZLi3UjnS6Mp4zGyNBM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597603; c=relaxed/simple; bh=cxqya6naV8BftSWo4ZmUemQF8/Oa+5qqwuL49Z2lcIo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=AyIRAv6Wlh/G3HCLgEGxqi50WbbDWNVId5vNQeyfQkCUGOaSOKlcsbs9lxXs7s1fXDpzhiR3U5v2dwqbmsd2vmrYKm5Y8e5IVic24r5MePtC+OVV/H3QtanIDIk5PXzlYm+o6cctQmcUsoaP+7FRt84trcs+3nHWEwkwQTKNh+w= 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=f/TqquI3; arc=none smtp.client-ip=198.175.65.18 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="f/TqquI3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1769597602; x=1801133602; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=cxqya6naV8BftSWo4ZmUemQF8/Oa+5qqwuL49Z2lcIo=; b=f/TqquI3EjBHsaF7qaOsNZ8f159FaHvKbYq3AXdEe6M44yyIBrDh19vx VyhgH38nArSp6NtX1kJKUIsMIg/+z9v2Rw6zie4R65NFhrwl8qc9w31qG bVe7f7fQvjGanDoTYOOWwdlDT5qea7WhbOZ/eXD1rqWcoB2mnTkRY81eH FiHreFDBKvReq9e2rUnr7YO4zPwiTh4YUgjv4miBhn/RWdiDd05qUfQzK n9MUUdlHamZ4UelPvwmhqkkQNQgArxn8w0sjP2KF5DgHqJcvOxVFWBsBk bT3BV9Sorl+u8L26JLvtto0h0OtyQKXZGvWCO5wJCIhUHHtvwt8qNT0yi w==; X-CSE-ConnectionGUID: 6de7jBFmSDS3mf665MITZw== X-CSE-MsgGUID: z4wS1iIhSyuWlmVT9L1xUA== X-IronPort-AV: E=McAfee;i="6800,10657,11684"; a="70848795" X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="70848795" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:21 -0800 X-CSE-ConnectionGUID: lC6IONHgR/+9JrPD17Z4Sg== X-CSE-MsgGUID: T3zc19QiRNeWuF2RlX4BoQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="212788070" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.14]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:17 -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 , linux-kernel@vger.kernel.org Cc: "Bandal, Shankar" , "Murthy, Shanth" , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , stable@vger.kernel.org Subject: [PATCH v2 1/7] serial: 8250: Protect LCR write in shutdown Date: Wed, 28 Jan 2026 12:52:55 +0200 Message-Id: <20260128105301.1869-2-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260128105301.1869-1-ilpo.jarvinen@linux.intel.com> References: <20260128105301.1869-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 The 8250_dw driver needs to potentially perform very complex operations during LCR writes because its BUSY handling prevents updates to LCR while UART is BUSY (which is not fully under our control without those complex operations). Thus, LCR writes should occur under port's lock. Move LCR write under port's lock in serial8250_do_shutdown(). Also split the LCR RMW so that the logic is on a separate line for clarity. Tested-by: "Bandal, Shankar" Tested-by: "Murthy, Shanth" Cc: stable@vger.kernel.org Signed-off-by: Ilpo J=C3=A4rvinen Reviewed-by: Andy Shevchenko --- drivers/tty/serial/8250/8250_port.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/= 8250_port.c index 719faf92aa8a..f7a3c5555204 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2350,6 +2350,7 @@ static int serial8250_startup(struct uart_port *port) void serial8250_do_shutdown(struct uart_port *port) { struct uart_8250_port *up =3D up_to_u8250p(port); + u32 lcr; =20 serial8250_rpm_get(up); /* @@ -2376,13 +2377,13 @@ void serial8250_do_shutdown(struct uart_port *port) port->mctrl &=3D ~TIOCM_OUT2; =20 serial8250_set_mctrl(port, port->mctrl); + + /* Disable break condition */ + lcr =3D serial_port_in(port, UART_LCR); + lcr &=3D ~UART_LCR_SBC; + serial_port_out(port, UART_LCR, lcr); } =20 - /* - * Disable break condition and FIFOs - */ - serial_port_out(port, UART_LCR, - serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); serial8250_clear_fifos(up); =20 rsa_disable(up); --=20 2.39.5 From nobody Sat Feb 7 05:44:09 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (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 2999D334C26; Wed, 28 Jan 2026 10:53:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597612; cv=none; b=nvu7PA3mI0atQshK816oidDsOvgXjsrOZSr+/79y90jsYG3U0jNggCcnxhdAhCPOQ/8inu1hZSBxNU75bI3SNQNaX+adKy15mf09mKFhhzqR22vgzAXcLbsWdYqeuCQnKAmvI26na+DRc3ita6CXColapuxKN6vwZqQWRc27wNw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597612; c=relaxed/simple; bh=FIz5xJLTndanpKNrJzyMrmqFWJ+/1vwNYlurmd/pc/k=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=DFquj2QIBfzEO3LWYRmdsRdG+bLGyM+VaF/bIUs0ClIQo7nRoRwww4Y+gqc8XzQowdKh0xkw61AJ5h0X0bNYOv+/EBVVqKSl8ROV78XqtwFJRiwlYpjOQ/emDO1xtl8asJmVsKwFCl5HKeVpugY/pB6fgO1FGCSh0GIITS2boQg= 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=aguRYnJB; arc=none smtp.client-ip=198.175.65.18 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="aguRYnJB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1769597611; x=1801133611; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FIz5xJLTndanpKNrJzyMrmqFWJ+/1vwNYlurmd/pc/k=; b=aguRYnJBpbYJZ69cDk6SFvdAWViI1K6DY+yWkpW1xQadvxlxb+RlyyIg iY1gfV4EJ8wqB8YZqLzCuVReA7XqcnViFBb2+qYD3QG+xGFc6oTw6m319 HhyDeE1tIdJ/VlQx7iY/j2JwCFj432e0+vZeMoM1NPkLKBWkbud+zs/eZ 3Als+gqmfWi69cJIi7h9Et/wH/P06PspZJt+0EcwauIf/IzSlGgaMSC/A Q6zulehLme866i6hLSB+Sbf9IC/VSqyq2uqIa/tKJ/2KfX6kuVjF+yOXq Q69intJ8qtJI9b1OyXIhV/GX+DUeL2PR2YhhHineFS89T+EB+VeAJn7hg g==; X-CSE-ConnectionGUID: 4szHQFI7SLe1B4CQn15d1A== X-CSE-MsgGUID: hFY5C1JxQiOStk2BbV6FGg== X-IronPort-AV: E=McAfee;i="6800,10657,11684"; a="70848804" X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="70848804" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:31 -0800 X-CSE-ConnectionGUID: J+DSp8ZZTjCub6U1qFJaaw== X-CSE-MsgGUID: dR51TslWT2eDUch6oHPzLA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="212788151" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.14]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:27 -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 v2 2/7] serial: 8250_dw: Avoid unnecessary LCR writes Date: Wed, 28 Jan 2026 12:52:56 +0200 Message-Id: <20260128105301.1869-3-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260128105301.1869-1-ilpo.jarvinen@linux.intel.com> References: <20260128105301.1869-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 Signed-off-by: Ilpo J=C3=A4rvinen Reviewed-by: Andy Shevchenko --- 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 From nobody Sat Feb 7 05:44:09 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (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 75633334C00; Wed, 28 Jan 2026 10:53:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597621; cv=none; b=hiEfoz2vX1ymxEl0MQnGk5eoyXjSs+uYMvPf9ftjIPvbnp1NnIIyG0NlZooJe+QLgx1XmY/OKgH+LNPLGkT/0cYkeapEeL4QjuZeKrZCrxN4CViM6SUy7XeU3lvjQEHMnOLon/zQu6ok3alFZkIfnO44FoQ4mnZNmE2g2onK/aQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597621; c=relaxed/simple; bh=LDJ8/6RGOQl1ENa/ArKQDEg5jmA+194e5W2zFz6rf68=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=uaFXUXiTMcMTagWWAv7WltgmOt1g+v6OyGjADaTP57ECUMxcpQkqJ1YeA7XG2TC/KfGaDwKcns7zh4Ncmlb9BZQLQvIBTioWydFxFqoHpASqI+rEejlCmtuAeOYX4FKVT7JWekRAx0adrRmeJtsMlSaxkKS2hCF++cRD0ISCqnE= 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=K5n9g5Mn; arc=none smtp.client-ip=198.175.65.18 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="K5n9g5Mn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1769597620; x=1801133620; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=LDJ8/6RGOQl1ENa/ArKQDEg5jmA+194e5W2zFz6rf68=; b=K5n9g5MnGaTTJKHzvPBFzF/oSjmK2EvAacpMSeRncNdaufiYGf/gyoh3 ezhEld5cxlN+M3/G3nCUKxl1xnoXyqT2Lavn8c9fZ9oqedCBoZ6WNiaZc 8L5PpRVtfdTbq0zuJmmtVwphMYzOPrKsOSJ6ZYtJltu/BbgoqvINgi072 4AelWMoJfG0zTj4krC9XfPlfjd5JsyWGrBbicldeFTwDN4cCgOE2lt0wt p1Td330HmQe2op7DFq2YcHRTdOh6fTX+0SSbEiIw5p+7z5Pijq81L9VmT 9/M6+iEdYt8aT4ojh8hgoc4HZ/2qSB1ZNehJ54EZLSd6CYM+3W9GE3wyY w==; X-CSE-ConnectionGUID: v9th1IMgQ/WoiB8ekuiXTw== X-CSE-MsgGUID: +WUt78CyQN+LYX3KpMMh/g== X-IronPort-AV: E=McAfee;i="6800,10657,11684"; a="70848807" X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="70848807" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:40 -0800 X-CSE-ConnectionGUID: 2146hrxkQI2VG0ac3/qLqw== X-CSE-MsgGUID: PRQZ4Z2KTcGkKoJyx036MQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="212788206" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.14]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:36 -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 , linux-kernel@vger.kernel.org Cc: "Bandal, Shankar" , "Murthy, Shanth" , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , stable@vger.kernel.org Subject: [PATCH v2 3/7] serial: 8250: Add serial8250_handle_irq_locked() Date: Wed, 28 Jan 2026 12:52:57 +0200 Message-Id: <20260128105301.1869-4-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260128105301.1869-1-ilpo.jarvinen@linux.intel.com> References: <20260128105301.1869-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 8250_port exports serial8250_handle_irq() to HW specific 8250 drivers. It takes port's lock within but a HW specific 8250 driver may want to take port's lock itself, do something, and then call the generic handler in 8250_port but to do that, the caller has to release port's lock for no good reason. Introduce serial8250_handle_irq_locked() which a HW specific driver can call while already holding port's lock. As this is new export, put it straight into a namespace (where all 8250 exports should eventually be moved). Tested-by: "Bandal, Shankar" Tested-by: "Murthy, Shanth" Cc: stable@vger.kernel.org Signed-off-by: Ilpo J=C3=A4rvinen Reviewed-by: Andy Shevchenko --- drivers/tty/serial/8250/8250_port.c | 24 ++++++++++++++++-------- include/linux/serial_8250.h | 1 + 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/= 8250_port.c index f7a3c5555204..bc223eb1f474 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1782,20 +1783,16 @@ static bool handle_rx_dma(struct uart_8250_port *up= , unsigned int iir) } =20 /* - * This handles the interrupt from one port. + * Context: port's lock must be held by the caller. */ -int serial8250_handle_irq(struct uart_port *port, unsigned int iir) +void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir) { struct uart_8250_port *up =3D up_to_u8250p(port); struct tty_port *tport =3D &port->state->port; bool skip_rx =3D false; - unsigned long flags; u16 status; =20 - if (iir & UART_IIR_NO_INT) - return 0; - - uart_port_lock_irqsave(port, &flags); + lockdep_assert_held_once(&port->lock); =20 status =3D serial_lsr_in(up); =20 @@ -1828,8 +1825,19 @@ int serial8250_handle_irq(struct uart_port *port, un= signed int iir) else if (!up->dma->tx_running) __stop_tx(up); } +} +EXPORT_SYMBOL_NS_GPL(serial8250_handle_irq_locked, "SERIAL_8250"); =20 - uart_unlock_and_check_sysrq_irqrestore(port, flags); +/* + * This handles the interrupt from one port. + */ +int serial8250_handle_irq(struct uart_port *port, unsigned int iir) +{ + if (iir & UART_IIR_NO_INT) + return 0; + + guard(uart_port_lock_irqsave)(port); + serial8250_handle_irq_locked(port, iir); =20 return 1; } diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 01efdce0fda0..a95b2d143d24 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -195,6 +195,7 @@ void serial8250_do_set_mctrl(struct uart_port *port, un= signed int mctrl); void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud, unsigned int quot); int fsl8250_handle_irq(struct uart_port *port); +void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir= ); int serial8250_handle_irq(struct uart_port *port, unsigned int iir); u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr); void serial8250_read_char(struct uart_8250_port *up, u16 lsr); --=20 2.39.5 From nobody Sat Feb 7 05:44:09 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (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 38C6033892C; Wed, 28 Jan 2026 10:53:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597630; cv=none; b=Qxq36/FTkYCO7yVyo+/8W4a/wHsACFa/kWxnJ+u/Y2Di/6XbO3W+KtTqqGicxICNqHE1SUZLxW7SFZ4yMa3aGhRfCXEeQfOYjCCgoNJVJ0p7hNwqLghvJ1nxOUpF6+yaKkEwsBRqTuF0uheDakfMEKzUp2KVkVIDCoFBWnrAWH8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597630; c=relaxed/simple; bh=/0iFyYLv7PJ1Qxa4bKP+RD/USX4IKcvtiIuGD/KAThQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=FeLODICCO0H+fmtAPwmN/lQ88bTrl5qaUSWlCQ/gZ3LRs7Y8UUU3tqw1jzUaecJVOXj22keqJozeNxYHEZRRm2gwSCQ1uoTsvJ7fxnYLhZbF8+zkdSI0VoK2vf9xSzzbp1Zq0WCGOTLg7sTXXXAkGl8xwQh9uHsiv+26DpzT7LY= 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=KdCGB60g; arc=none smtp.client-ip=198.175.65.18 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="KdCGB60g" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1769597629; x=1801133629; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=/0iFyYLv7PJ1Qxa4bKP+RD/USX4IKcvtiIuGD/KAThQ=; b=KdCGB60goh8ovz8o9nwWeouKmfv4JJmiK3HT9u4liQQ7YLvVoaZKGV6F nvNodrf05q3sdvpPu44p+Bb5TbbVnPmE0hWTxZbOjgdB7rzY2mxD1yZZj yVddD/dtMDMjklc9b+dJ5Ch5imYpPPyEft9u6/J7mZQORuHUZAlQAYboh qRwHi2HE9ocxgk+gbjRGHAagqajm+Iq1KAF/pKp0c4bwDRJvFGl8uvQQZ NN/jclRVKT/cM7LH/R2DxRBKRPCHpwEOZpLBK5gxTgsRNB2w1GAFt4hN2 jLJ20XARM0H0uN7S/u2ufehrt0mrHeCB/kTgcConYIU0xjOmO7VFjyUeQ g==; X-CSE-ConnectionGUID: Ci4JC7dwSsCOqhxS2Uwb3g== X-CSE-MsgGUID: ws0T10g0SCKSo2T8f1RjbA== X-IronPort-AV: E=McAfee;i="6800,10657,11684"; a="70848814" X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="70848814" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:49 -0800 X-CSE-ConnectionGUID: 5rP61DGdTX2VAun0merKQQ== X-CSE-MsgGUID: t/uRzboCQPi0yPDQfs182Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="212788222" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.14]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:45 -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 v2 4/7] serial: 8250_dw: Rework dw8250_handle_irq() locking and IIR handling Date: Wed, 28 Jan 2026 12:52:58 +0200 Message-Id: <20260128105301.1869-5-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260128105301.1869-1-ilpo.jarvinen@linux.intel.com> References: <20260128105301.1869-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 dw8250_handle_irq() takes port's lock multiple times with no good reason to release it in between and calls serial8250_handle_irq() that also takes port's lock. Take port's lock only once in dw8250_handle_irq() and use serial8250_handle_irq_locked() to avoid releasing port's lock in between. As IIR_NO_INT check in serial8250_handle_irq() was outside of port's lock, it has to be done already in dw8250_handle_irq(). DW UART can, in addition to IIR_NO_INT, report BUSY_DETECT (0x7) which collided with the IIR_NO_INT (0x1) check in serial8250_handle_irq() (because & is used instead of =3D=3D) meaning that no other work is done by serial8250_handle_irq() during an BUSY_DETECT interrupt. This allows reorganizing code in dw8250_handle_irq() to do both IIR_NO_INT and BUSY_DETECT handling right at the start simplifying the logic. Tested-by: "Bandal, Shankar" Tested-by: "Murthy, Shanth" Cc: stable@vger.kernel.org Signed-off-by: Ilpo J=C3=A4rvinen Reviewed-by: Andy Shevchenko --- drivers/tty/serial/8250/8250_dw.c | 37 ++++++++++++++++++------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/82= 50_dw.c index 7500b1ff1ac1..964750d17186 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -9,6 +9,9 @@ * LCR is written whilst busy. If it is, then a busy detect interrupt is * raised, the LCR needs to be rewritten and the uart status register read. */ +#include +#include +#include #include #include #include @@ -40,6 +43,8 @@ #define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */ =20 /* DesignWare specific register fields */ +#define DW_UART_IIR_IID GENMASK(3, 0) + #define DW_UART_MCR_SIRE BIT(6) =20 /* Renesas specific register fields */ @@ -312,7 +317,19 @@ static int dw8250_handle_irq(struct uart_port *p) bool rx_timeout =3D (iir & 0x3f) =3D=3D UART_IIR_RX_TIMEOUT; unsigned int quirks =3D d->pdata->quirks; unsigned int status; - unsigned long flags; + + switch (FIELD_GET(DW_UART_IIR_IID, iir)) { + case UART_IIR_NO_INT: + return 0; + + case UART_IIR_BUSY: + /* Clear the USR */ + serial_port_in(p, d->pdata->usr_reg); + + return 1; + } + + guard(uart_port_lock_irqsave)(p); =20 /* * There are ways to get Designware-based UARTs into a state where @@ -325,20 +342,15 @@ static int dw8250_handle_irq(struct uart_port *p) * so we limit the workaround only to non-DMA mode. */ if (!up->dma && rx_timeout) { - uart_port_lock_irqsave(p, &flags); status =3D serial_lsr_in(up); =20 if (!(status & (UART_LSR_DR | UART_LSR_BI))) serial_port_in(p, UART_RX); - - uart_port_unlock_irqrestore(p, flags); } =20 /* Manually stop the Rx DMA transfer when acting as flow controller */ if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running &&= rx_timeout) { - uart_port_lock_irqsave(p, &flags); status =3D serial_lsr_in(up); - uart_port_unlock_irqrestore(p, flags); =20 if (status & (UART_LSR_DR | UART_LSR_BI)) { dw8250_writel_ext(p, RZN1_UART_RDMACR, 0); @@ -346,17 +358,9 @@ static int dw8250_handle_irq(struct uart_port *p) } } =20 - if (serial8250_handle_irq(p, iir)) - return 1; - - if ((iir & UART_IIR_BUSY) =3D=3D UART_IIR_BUSY) { - /* Clear the USR */ - serial_port_in(p, d->pdata->usr_reg); + serial8250_handle_irq_locked(p, iir); =20 - return 1; - } - - return 0; + return 1; } =20 static void dw8250_clk_work_cb(struct work_struct *work) @@ -858,6 +862,7 @@ static struct platform_driver dw8250_platform_driver = =3D { =20 module_platform_driver(dw8250_platform_driver); =20 +MODULE_IMPORT_NS("SERIAL_8250"); MODULE_AUTHOR("Jamie Iles"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver"); --=20 2.39.5 From nobody Sat Feb 7 05:44:09 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (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 0AEB533BBDF; Wed, 28 Jan 2026 10:53:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597639; cv=none; b=lJ0zeNot7lBMHanW0yUZ6ythj2BC4+m4mGiKkqzsPSjHUCd/0uKhIfR4080n7hoIYln0IgXIFCZBnf7kYgMRGCNq6+qm/WbQfDym/ozB7aGbIa84SBAau+t0DWJ87pDOGj2FWWt2AMOD0Et9keRH+zeHLhcMqebEPhaiTQ5P11Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597639; c=relaxed/simple; bh=SZe9wBAYOq1k5nwlxTcqv6zFpar/W30tmjbFIpCQBCE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=YaA/LtQsU6u9GSJ+rUCMD+BgnvO+wx1JE3824rIJfsis0YYbVM12kujvD/sk7hHKMcdrn4kx00wbH/r3CFzM50GbiffQmmu1bdfJnstExWK/Mvr43SQPJvf0RilYwNVAljrARib07MalGMsLK6/k/jcaDQcnAGUHcyUO3jNVUW4= 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=kP/D7jQL; arc=none smtp.client-ip=198.175.65.18 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="kP/D7jQL" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1769597638; x=1801133638; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SZe9wBAYOq1k5nwlxTcqv6zFpar/W30tmjbFIpCQBCE=; b=kP/D7jQLcmtFF1nVP2NDZ9/sVB5IBOfASXNCaCqCjo0ZugOxALYVci88 XXjxlzhU8jchgyGnc59OVx3Drwnn9AyrOfpt5bWMBUPgLc+NjTO7YfI8n mIS91i0tMgyr2Ee+UPrK8S0rgFy8optYlbmHtuK6iiUOY8S9fL1WWYWbj k7dAJOroK34GkBT77t/3z0AMshJjnTaQKiiDtiNNL+sCS8bq4Wr6oqQqO oVeftoeMHA1JtS6eQgHsyNbzIBUkPpNaLMHvWkoTFcljLp5jMYh53ZUu/ RMj+ID6kfzasIoIplIvBD6PxWzOHseArJbrirhRA/TFNuCog6tQYfM860 w==; X-CSE-ConnectionGUID: nIj0015PTkSjdHmUKpseRw== X-CSE-MsgGUID: ajvOlKv+TbaRJC81fNOmkw== X-IronPort-AV: E=McAfee;i="6800,10657,11684"; a="70848819" X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="70848819" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:58 -0800 X-CSE-ConnectionGUID: rOe0t35ATzmJnURqqg6GfA== X-CSE-MsgGUID: 7cIhblR3R92h7IBY/ndMZg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="212788238" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.14]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:53:54 -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 v2 5/7] serial: 8250_dw: Rework IIR_NO_INT handling to stop interrupt storm Date: Wed, 28 Jan 2026 12:52:59 +0200 Message-Id: <20260128105301.1869-6-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260128105301.1869-1-ilpo.jarvinen@linux.intel.com> References: <20260128105301.1869-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 INTC10EE UART can end up into an interrupt storm where it reports IIR_NO_INT (0x1). If the storm happens during active UART operation, it is promptly stopped by IIR value change due to Rx or Tx events. However, when there is no activity, either due to idle serial line or due to specific circumstances such as during shutdown that writes IER=3D0, there is nothing to stop the storm. During shutdown the storm is particularly problematic because serial8250_do_shutdown() calls synchronize_irq() that will hang in waiting for the storm to finish which never happens. This problem can also result in triggering a warning: irq 45: nobody cared (try booting with the "irqpoll" option) [...snip...] handlers: serial8250_interrupt Disabling IRQ #45 Normal means to reset interrupt status by reading LSR, MSR, USR, or RX register do not result in the UART deasserting the IRQ. Add a quirk to INTC10EE UARTs to enable Tx interrupts if UART's Tx is currently empty and inactive. Rework IIR_NO_INT to keep track of the number of consecutive IIR_NO_INT, and on fourth one perform the quirk. Enabling Tx interrupts should change IIR value from IIR_NO_INT to IIR_THRI which has been observed to stop the storm. Fixes: e92fad024929 ("serial: 8250_dw: Add ACPI ID for Granite Rapids-D UAR= T") Cc: stable@vger.kernel.org Reported-by: "Bandal, Shankar" Tested-by: "Bandal, Shankar" Tested-by: "Murthy, Shanth" Signed-off-by: Ilpo J=C3=A4rvinen Reviewed-by: Andy Shevchenko --- drivers/tty/serial/8250/8250_dw.c | 67 +++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/82= 50_dw.c index 964750d17186..edae359b1c3f 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -61,6 +61,13 @@ #define DW_UART_QUIRK_IS_DMA_FC BIT(3) #define DW_UART_QUIRK_APMC0D08 BIT(4) #define DW_UART_QUIRK_CPR_VALUE BIT(5) +#define DW_UART_QUIRK_IER_KICK BIT(6) + +/* + * Number of consecutive IIR_NO_INT interrupts required to trigger interru= pt + * storm prevention code. + */ +#define DW_UART_QUIRK_IER_KICK_THRES 4 =20 struct dw8250_platform_data { u8 usr_reg; @@ -82,6 +89,8 @@ struct dw8250_data { =20 unsigned int skip_autocfg:1; unsigned int uart_16550_compatible:1; + + u8 no_int_count; }; =20 static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *= data) @@ -308,6 +317,29 @@ static u32 dw8250_serial_in32be(struct uart_port *p, u= nsigned int offset) return dw8250_modify_msr(p, offset, value); } =20 +/* + * INTC10EE UART can IRQ storm while reporting IIR_NO_INT. Inducing IIR va= lue + * change has been observed to break the storm. + * + * If Tx is empty (THRE asserted), we use here IER_THRI to cause IIR_NO_IN= T -> + * IIR_THRI transition. + */ +static void dw8250_quirk_ier_kick(struct uart_port *p) +{ + struct uart_8250_port *up =3D up_to_u8250p(p); + u32 lsr; + + if (up->ier & UART_IER_THRI) + return; + + lsr =3D serial_lsr_in(up); + if (!(lsr & UART_LSR_THRE)) + return; + + serial_port_out(p, UART_IER, up->ier | UART_IER_THRI); + serial_port_in(p, UART_LCR); /* safe, no side-effects */ + serial_port_out(p, UART_IER, up->ier); +} =20 static int dw8250_handle_irq(struct uart_port *p) { @@ -318,18 +350,30 @@ static int dw8250_handle_irq(struct uart_port *p) unsigned int quirks =3D d->pdata->quirks; unsigned int status; =20 + guard(uart_port_lock_irqsave)(p); + switch (FIELD_GET(DW_UART_IIR_IID, iir)) { case UART_IIR_NO_INT: + if (d->uart_16550_compatible || up->dma) + return 0; + + if (quirks & DW_UART_QUIRK_IER_KICK && + d->no_int_count =3D=3D (DW_UART_QUIRK_IER_KICK_THRES - 1)) + dw8250_quirk_ier_kick(p); + d->no_int_count =3D (d->no_int_count + 1) % DW_UART_QUIRK_IER_KICK_THRES; + return 0; =20 case UART_IIR_BUSY: /* Clear the USR */ serial_port_in(p, d->pdata->usr_reg); =20 + d->no_int_count =3D 0; + return 1; } =20 - guard(uart_port_lock_irqsave)(p); + d->no_int_count =3D 0; =20 /* * There are ways to get Designware-based UARTs into a state where @@ -562,6 +606,14 @@ static void dw8250_reset_control_assert(void *data) reset_control_assert(data); } =20 +static void dw8250_shutdown(struct uart_port *port) +{ + struct dw8250_data *d =3D to_dw8250_data(port->private_data); + + serial8250_do_shutdown(port); + d->no_int_count =3D 0; +} + static int dw8250_probe(struct platform_device *pdev) { struct uart_8250_port uart =3D {}, *up =3D &uart; @@ -685,10 +737,12 @@ static int dw8250_probe(struct platform_device *pdev) dw8250_quirks(p, data); =20 /* If the Busy Functionality is not implemented, don't handle it */ - if (data->uart_16550_compatible) + if (data->uart_16550_compatible) { p->handle_irq =3D NULL; - else if (data->pdata) + } else if (data->pdata) { p->handle_irq =3D dw8250_handle_irq; + p->shutdown =3D dw8250_shutdown; + } =20 dw8250_setup_dma_filter(p, data); =20 @@ -815,6 +869,11 @@ static const struct dw8250_platform_data dw8250_skip_s= et_rate_data =3D { .quirks =3D DW_UART_QUIRK_SKIP_SET_RATE, }; =20 +static const struct dw8250_platform_data dw8250_intc10ee =3D { + .usr_reg =3D DW_UART_USR, + .quirks =3D DW_UART_QUIRK_IER_KICK, +}; + static const struct of_device_id dw8250_of_match[] =3D { { .compatible =3D "snps,dw-apb-uart", .data =3D &dw8250_dw_apb }, { .compatible =3D "cavium,octeon-3860-uart", .data =3D &dw8250_octeon_386= 0_data }, @@ -844,7 +903,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = =3D { { "INT33C5", (kernel_ulong_t)&dw8250_dw_apb }, { "INT3434", (kernel_ulong_t)&dw8250_dw_apb }, { "INT3435", (kernel_ulong_t)&dw8250_dw_apb }, - { "INTC10EE", (kernel_ulong_t)&dw8250_dw_apb }, + { "INTC10EE", (kernel_ulong_t)&dw8250_intc10ee }, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); --=20 2.39.5 From nobody Sat Feb 7 05:44:09 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (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 A80EB33A01B; Wed, 28 Jan 2026 10:54:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597649; cv=none; b=dwL3US3CCFzXqJVW4UmtD7N9LuJVtBMyDWM0Cajpy8kCGoLz6oaNEpi2CQWFcfIe6cL2Ypxw3sgHFBVK37A6ykXtaGdwmxiVbRJy8n/VYQsuceNFiNN8uzemWSWW1INpJUUGqvTY2z9hNecr+Cm3hXPlUaJDmw4vItsE1uZ+YTU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597649; c=relaxed/simple; bh=B843BIjDmM6+7b2O2RW8TrN+hegMpPSgt0H4J0YgJq0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=rnJn/g1kwa9XUvDVI4apVJtHenYUCyDgknjQb9weQOZe/3pCYAhZz+A0yMuAnataJZxMNwV1VYGlefYCkP2/XzYJuyrFENL4eKCYCnrVeZ4495J7mvJDCfvDi+CvZ7gk8L42lHRr38+AhyRN2m8GtmekkEO+osPQ0UHBbQ50j6M= 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=AQ82Agas; arc=none smtp.client-ip=198.175.65.18 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="AQ82Agas" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1769597648; x=1801133648; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=B843BIjDmM6+7b2O2RW8TrN+hegMpPSgt0H4J0YgJq0=; b=AQ82AgastBaEr3XQq65EI+cbr1JOvDZiXtU+NKN7ca/ZrBeJwBtEqL98 ykNCmjUTSaCoOR+NHszi1xR5P+Bkqb4bEPwEg+Bu5gebWA6tdAjpzB/yC Q/9N5WP5bZ2xCTvQ8r9UxOduUcWdcMpX4itVWXZ/Kq4FNAsDHfKnsEHHl A/AM6wnlF2FUvh0yQZ/BHideEZo/OG4eS1uhzfo1h6oxGT06rw6j+BYHk QSh7YOS37/IHzXyPPed7LGzyQtozKMs74DdQAsqmt92jkVsoHeQ5fO8FA rhad9fRvifLVkUhhJyqtAfBkG+TGcXH2X+shc4M17ZbE9cKo+IT9NGJji g==; X-CSE-ConnectionGUID: naEuDEVLS1+/EyBPz/TRbA== X-CSE-MsgGUID: n1TbmFMAR9yYwVTe8ySfqA== X-IronPort-AV: E=McAfee;i="6800,10657,11684"; a="70848834" X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="70848834" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:54:07 -0800 X-CSE-ConnectionGUID: 9YKcn0ylRO2H9XyYrheoIQ== X-CSE-MsgGUID: LbG3T3AgSqO98afKuBt7gA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="212788259" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.14]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:54:03 -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 , Jamie Iles , linux-kernel@vger.kernel.org Cc: "Bandal, Shankar" , "Murthy, Shanth" , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , stable@vger.kernel.org Subject: [PATCH v2 6/7] serial: 8250: Add late synchronize_irq() to shutdown to handle DW UART BUSY Date: Wed, 28 Jan 2026 12:53:00 +0200 Message-Id: <20260128105301.1869-7-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260128105301.1869-1-ilpo.jarvinen@linux.intel.com> References: <20260128105301.1869-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 !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" Tested-by: "Bandal, Shankar" Tested-by: "Murthy, Shanth" Signed-off-by: Ilpo J=C3=A4rvinen Reviewed-by: Andy Shevchenko --- 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); =20 up->ops->release_irq(up); --=20 2.39.5 From nobody Sat Feb 7 05:44:09 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 C63E133123C; Wed, 28 Jan 2026 10:54:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597660; cv=none; b=jgDxMOTeYiL/nmT+fZ5cq69g3BQ/b+5lqoa9rJ4cA9tuAxlflFc8gnATkPWwtqXlJHWHsdQwI9o+bcFNEMDG4RA2y27r7SfoacEMtLrAtKsy7iVfMO0fXbYpUqvVy/Ko/CaCrMfxstR93cyd9pStNL3v5Lgo9hcxwYzShpay8K4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769597660; c=relaxed/simple; bh=Z90hlP0XcmsRIfmn0WBBIRH5G60zq3OgKK7bcWl15Hk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=nZalkdjnuliIvKe2lCSyET0os1B5LGdNPQUJv/2JkEDAlTEn9BOSWpOMEubUyzHdoxhw6WHGNgd+UiUPdTvdxiGuF8Qzloc2HqNBsKPEvEBxISDAP3IopoewZdm+PLXO+4hKU2nbXVb0XtMn/UfWVNrCt3JElca/SAN/FRUWXFI= 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=FZlXAZZJ; arc=none smtp.client-ip=198.175.65.11 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="FZlXAZZJ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1769597659; x=1801133659; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Z90hlP0XcmsRIfmn0WBBIRH5G60zq3OgKK7bcWl15Hk=; b=FZlXAZZJ7gxPANAEoL/zPCrU88+ZZovqoW8J+hAejFUTyAtwifnBroDZ /jBkn7Tt5couFdJ2onx5dqiC717UrNzmClu02mEo+RmidJHgG0lXOA04X caBaRChiQKKJBIyY/szYBlPIUkblc+QcqO6wvpU5U/fyVB19BgOo8iQO6 UoH6E7mQvlc4hQ82TJ1GGz7YXxAU6xIHmHgfdbqWbKB92TDHOoluQKJdY L8lmYAW9kw/cv4iMeNgtJhCNpNDdTCL7BH9Vda+tYmaTj9r3kD2CBIXMW aRq6u13yesp/Gdugs4LL/coSm5JMQ+3T5yR2LxxEz6O0XMhi0w2y5tUZM Q==; X-CSE-ConnectionGUID: 5oZP2ro3QL6rv2h3V3e40Q== X-CSE-MsgGUID: pTze2bcGRKe3ybLjcOa3+Q== X-IronPort-AV: E=McAfee;i="6800,10657,11684"; a="81121437" X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="81121437" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:54:18 -0800 X-CSE-ConnectionGUID: K/gBpYUQQTaKVGI48H8Usw== X-CSE-MsgGUID: YkzrJXOXSySU2x70CW30Vw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,258,1763452800"; d="scan'208";a="245847360" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.14]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Jan 2026 02:54:13 -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?= , Tim Kryger , Matt Porter , Heikki Krogerus , Markus Mayer , Jamie Iles , linux-kernel@vger.kernel.org Cc: "Bandal, Shankar" , "Murthy, Shanth" , stable@vger.kernel.org Subject: [PATCH v2 7/7] serial: 8250_dw: Ensure BUSY is deasserted Date: Wed, 28 Jan 2026 12:53:01 +0200 Message-Id: <20260128105301.1869-8-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260128105301.1869-1-ilpo.jarvinen@linux.intel.com> References: <20260128105301.1869-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 DW UART cannot write to LCR, DLL, and DLH while BUSY is asserted. Existance of BUSY depends on uart_16550_compatible, if UART HW is configured with it those registers can always be written. There currently is dw8250_force_idle() which attempts to achieve non-BUSY state by disabling FIFO, however, the solution is unreliable when Rx keeps getting more and more characters. Create a sequence of operations that ensures UART cannot keep BUSY asserted indefinitely. The new sequence relies on enabling loopback mode temporarily to prevent incoming Rx characters keeping UART BUSY. Ensure no Tx in ongoing while the UART is switches into the loopback mode (requires exporting serial8250_fifo_wait_for_lsr_thre() and adding DMA Tx pause/resume functions). According to tests performed by Adriana Nicolae , simply disabling FIFO or clearing FIFOs only once does not always ensure BUSY is deasserted but up to two tries may be needed. This could be related to ongoing Rx of a character (a guess, not known for sure). Therefore, retry FIFO clearing a few times (retry limit 4 is arbitrary number but using, e.g., p->fifosize seems overly large). Tests performed by others did not exhibit similar challenge but it does not seem harmful to leave the FIFO clearing loop in place for all DW UARTs with BUSY functionality. Use the new dw8250_idle_enter/exit() to do divisor writes and LCR writes. In case of plain LCR writes, opportunistically try to update LCR first and only invoke dw8250_idle_enter() if the write did not succeed (it has been observed that in practice most LCR writes do succeed without complications). This issue was first reported by qianfan Zhao who put lots of debugging effort into understanding the solution space. Fixes: c49436b657d0 ("serial: 8250_dw: Improve unwritable LCR workaround") Fixes: 7d4008ebb1c9 ("tty: add a DesignWare 8250 driver") Cc: Reported-by: qianfan Zhao Link: https://lore.kernel.org/linux-serial/289bb78a-7509-1c5c-2923-a04ed3b6= 487d@163.com/ Reported-by: Adriana Nicolae Link: https://lore.kernel.org/linux-serial/20250819182322.3451959-1-adriana= @arista.com/ Reported-by: "Bandal, Shankar" Tested-by: "Bandal, Shankar" Tested-by: "Murthy, Shanth" Signed-off-by: Ilpo J=C3=A4rvinen Reviewed-by: Andy Shevchenko --- drivers/tty/serial/8250/8250.h | 25 ++++ drivers/tty/serial/8250/8250_dw.c | 176 ++++++++++++++++++++-------- drivers/tty/serial/8250/8250_port.c | 28 +++-- 3 files changed, 170 insertions(+), 59 deletions(-) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 8caecfc85d93..77fe0588fd6b 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -175,7 +175,9 @@ static unsigned int __maybe_unused serial_icr_read(stru= ct uart_8250_port *up, return value; } =20 +void serial8250_clear_fifos(struct uart_8250_port *p); void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); +void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned= int count); =20 void serial8250_rpm_get(struct uart_8250_port *p); void serial8250_rpm_put(struct uart_8250_port *p); @@ -400,6 +402,26 @@ static inline bool serial8250_tx_dma_running(struct ua= rt_8250_port *p) =20 return dma && dma->tx_running; } + +static inline void serial8250_tx_dma_pause(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma =3D p->dma; + + if (!dma->tx_running) + return; + + dmaengine_pause(dma->txchan); +} + +static inline void serial8250_tx_dma_resume(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma =3D p->dma; + + if (!dma->tx_running) + return; + + dmaengine_resume(dma->txchan); +} #else static inline int serial8250_tx_dma(struct uart_8250_port *p) { @@ -421,6 +443,9 @@ static inline bool serial8250_tx_dma_running(struct uar= t_8250_port *p) { return false; } + +static inline void serial8250_tx_dma_pause(struct uart_8250_port *p) { } +static inline void serial8250_tx_dma_resume(struct uart_8250_port *p) { } #endif =20 static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/82= 50_dw.c index edae359b1c3f..ca527be96179 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,8 @@ =20 #define DW_UART_MCR_SIRE BIT(6) =20 +#define DW_UART_USR_BUSY BIT(0) + /* Renesas specific register fields */ #define RZN1_UART_xDMACR_DMA_EN BIT(0) #define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1) @@ -89,6 +92,7 @@ struct dw8250_data { =20 unsigned int skip_autocfg:1; unsigned int uart_16550_compatible:1; + unsigned int in_idle:1; =20 u8 no_int_count; }; @@ -122,77 +126,155 @@ static inline u32 dw8250_modify_msr(struct uart_port= *p, unsigned int offset, u3 } =20 /* - * This function is being called as part of the uart_port::serial_out() - * routine. Hence, it must not call serial_port_out() or serial_out() - * against the modified registers here, i.e. LCR. + * Ensure BUSY is not asserted. If DW UART is configured with + * !uart_16550_compatible, the writes to LCR, DLL, and DLH fail while + * BUSY is asserted. + * + * Context: port's lock must be held */ -static void dw8250_force_idle(struct uart_port *p) +static int dw8250_idle_enter(struct uart_port *p) { + struct dw8250_data *d =3D to_dw8250_data(p->private_data); struct uart_8250_port *up =3D up_to_u8250p(p); - unsigned int lsr; + unsigned int usr_reg =3D DW_UART_USR; + int retries; + u32 lsr; =20 - /* - * The following call currently performs serial_out() - * against the FCR register. Because it differs to LCR - * there will be no infinite loop, but if it ever gets - * modified, we might need a new custom version of it - * that avoids infinite recursion. - */ - serial8250_clear_and_reinit_fifos(up); + lockdep_assert_held_once(&p->lock); + + if (d->uart_16550_compatible) + return 0; + + if (d->pdata) + usr_reg =3D d->pdata->usr_reg; + + d->in_idle =3D 1; + + /* Prevent triggering interrupt from RBR filling */ + serial_port_out(p, UART_IER, 0); + + if (up->dma) { + serial8250_rx_dma_flush(up); + if (serial8250_tx_dma_running(up)) + serial8250_tx_dma_pause(up); + } =20 /* - * With PSLVERR_RESP_EN parameter set to 1, the device generates an - * error response when an attempt to read an empty RBR with FIFO - * enabled. + * Wait until Tx becomes empty + one extra frame time to ensure all bits + * have been sent on the wire. + * + * FIXME: frame_time delay is too long with very low baudrates. */ - if (up->fcr & UART_FCR_ENABLE_FIFO) { - lsr =3D serial_port_in(p, UART_LSR); - if (!(lsr & UART_LSR_DR)) - return; + serial8250_fifo_wait_for_lsr_thre(up, p->fifosize); + ndelay(p->frame_time); + + serial_port_out(p, UART_MCR, up->mcr | UART_MCR_LOOP); + + retries =3D 4; /* Arbitrary limit, 2 was always enough in tests */ + do { + serial8250_clear_fifos(up); + if (!(serial_port_in(p, usr_reg) & DW_UART_USR_BUSY)) + break; + /* FIXME: frame_time delay is too long with very low baudrates. */ + ndelay(p->frame_time); + } while (--retries); + + lsr =3D serial_lsr_in(up); + if (lsr & UART_LSR_DR) { + serial_port_in(p, UART_RX); + up->lsr_saved_flags =3D 0; } =20 - serial_port_in(p, UART_RX); + /* Now guaranteed to have BUSY deasserted? Just sanity check */ + if (serial_port_in(p, usr_reg) & DW_UART_USR_BUSY) + return -EBUSY; + + return 0; +} + +static void dw8250_idle_exit(struct uart_port *p) +{ + struct dw8250_data *d =3D to_dw8250_data(p->private_data); + struct uart_8250_port *up =3D up_to_u8250p(p); + + if (d->uart_16550_compatible) + return; + + if (up->capabilities & UART_CAP_FIFO) + serial_port_out(p, UART_FCR, up->fcr); + serial_port_out(p, UART_MCR, up->mcr); + serial_port_out(p, UART_IER, up->ier); + + /* DMA Rx is restarted by IRQ handler as needed. */ + if (up->dma) + serial8250_tx_dma_resume(up); + + d->in_idle =3D 0; +} + +static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + struct uart_8250_port *up =3D up_to_u8250p(p); + int ret; + + ret =3D dw8250_idle_enter(p); + if (ret < 0) + goto idle_failed; + + serial_port_out(p, UART_LCR, up->lcr | UART_LCR_DLAB); + if (!(serial_port_in(p, UART_LCR) & UART_LCR_DLAB)) + goto idle_failed; + + serial_dl_write(up, quot); + serial_port_out(p, UART_LCR, up->lcr); + +idle_failed: + dw8250_idle_exit(p); } =20 /* * This function is being called as part of the uart_port::serial_out() - * routine. Hence, it must not call serial_port_out() or serial_out() - * against the modified registers here, i.e. LCR. + * routine. Hence, special care must be taken when serial_port_out() or + * serial_out() against the modified registers here, i.e. LCR (d->in_idle = is + * used to break recursion loop). */ static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32= value) { struct dw8250_data *d =3D to_dw8250_data(p->private_data); - void __iomem *addr =3D p->membase + (offset << p->regshift); - int tries =3D 1000; + u32 lcr; + int ret; =20 if (offset !=3D UART_LCR || d->uart_16550_compatible) return; =20 - /* Make sure LCR write wasn't ignored */ - while (tries--) { - u32 lcr =3D serial_port_in(p, offset); + lcr =3D serial_port_in(p, UART_LCR); =20 - if ((value & ~UART_LCR_SPAR) =3D=3D (lcr & ~UART_LCR_SPAR)) - return; + /* Make sure LCR write wasn't ignored */ + if ((value & ~UART_LCR_SPAR) =3D=3D (lcr & ~UART_LCR_SPAR)) + return; =20 - dw8250_force_idle(p); + if (d->in_idle) { + /* + * FIXME: this deadlocks if port->lock is already held + * dev_err(p->dev, "Couldn't set LCR to %d\n", value); + */ + return; + } =20 -#ifdef CONFIG_64BIT - if (p->type =3D=3D PORT_OCTEON) - __raw_writeq(value & 0xff, addr); - else -#endif - if (p->iotype =3D=3D UPIO_MEM32) - writel(value, addr); - else if (p->iotype =3D=3D UPIO_MEM32BE) - iowrite32be(value, addr); - else - writeb(value, addr); + ret =3D dw8250_idle_enter(p); + if (ret < 0) { + /* + * FIXME: this deadlocks if port->lock is already held + * dev_err(p->dev, "Couldn't set LCR to %d\n", value); + */ + goto idle_failed; } - /* - * FIXME: this deadlocks if port->lock is already held - * dev_err(p->dev, "Couldn't set LCR to %d\n", value); - */ + + serial_port_out(p, UART_LCR, value); + +idle_failed: + dw8250_idle_exit(p); } =20 /* @@ -632,8 +714,10 @@ static int dw8250_probe(struct platform_device *pdev) p->type =3D PORT_8250; p->flags =3D UPF_FIXED_PORT; p->dev =3D dev; + p->set_ldisc =3D dw8250_set_ldisc; p->set_termios =3D dw8250_set_termios; + p->set_divisor =3D dw8250_set_divisor; =20 data =3D devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/= 8250_port.c index fb0b8397cd4b..8b31b72e4676 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -489,7 +489,7 @@ serial_port_out_sync(struct uart_port *p, int offset, i= nt value) /* * FIFO support. */ -static void serial8250_clear_fifos(struct uart_8250_port *p) +void serial8250_clear_fifos(struct uart_8250_port *p) { if (p->capabilities & UART_CAP_FIFO) { serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); @@ -498,6 +498,7 @@ static void serial8250_clear_fifos(struct uart_8250_por= t *p) serial_out(p, UART_FCR, 0); } } +EXPORT_SYMBOL_NS_GPL(serial8250_clear_fifos, "SERIAL_8250"); =20 static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtime= r *t); static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer= *t); @@ -3200,6 +3201,17 @@ void serial8250_set_defaults(struct uart_8250_port *= up) } EXPORT_SYMBOL_GPL(serial8250_set_defaults); =20 +void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned= int count) +{ + unsigned int i; + + for (i =3D 0; i < count; i++) { + if (wait_for_lsr(up, UART_LSR_THRE)) + return; + } +} +EXPORT_SYMBOL_NS_GPL(serial8250_fifo_wait_for_lsr_thre, "SERIAL_8250"); + #ifdef CONFIG_SERIAL_8250_CONSOLE =20 static void serial8250_console_putchar(struct uart_port *port, unsigned ch= ar ch) @@ -3241,16 +3253,6 @@ static void serial8250_console_restore(struct uart_8= 250_port *up) serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS); } =20 -static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int coun= t) -{ - unsigned int i; - - for (i =3D 0; i < count; i++) { - if (wait_for_lsr(up, UART_LSR_THRE)) - return; - } -} - /* * Print a string to the serial port using the device FIFO * @@ -3269,7 +3271,7 @@ static void serial8250_console_fifo_write(struct uart= _8250_port *up, =20 while (s !=3D end) { /* Allow timeout for each byte of a possibly full FIFO */ - fifo_wait_for_lsr(up, fifosize); + serial8250_fifo_wait_for_lsr_thre(up, fifosize); =20 for (i =3D 0; i < fifosize && s !=3D end; ++i) { if (*s =3D=3D '\n' && !cr_sent) { @@ -3287,7 +3289,7 @@ static void serial8250_console_fifo_write(struct uart= _8250_port *up, * Allow timeout for each byte written since the caller will only wait * for UART_LSR_BOTH_EMPTY using the timeout of a single character */ - fifo_wait_for_lsr(up, tx_count); + serial8250_fifo_wait_for_lsr_thre(up, tx_count); } =20 /* --=20 2.39.5