| Message ID | cc358c2be6b0b4ea0323e4f694a581ffb667112d.1792439398.git.vinicius.eduardo.pedrosa@gmail.com (mailing list archive) |
|---|---|
| State | New |
| Headers |
Return-Path: <linux-sunxi+bounces-26749-sunxi=pue.re@lists.linux.dev>
X-Original-To: noreply@patchwork.local
Delivered-To: noreply@patchwork.local
Received: from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10])
by mxe881.netcup.net (Postfix) with ESMTPS id C61B51C239D
for <noreply@patchwork.local>; Mon, 19 Oct 2026 22:11:53 +0200 (CEST)
Authentication-Results: mxe881;
dkim=pass header.d=gmail.com;
spf=pass (sender IP is 172.234.253.10)
smtp.mailfrom=linux-sunxi+bounces-26749-noreply=patchwork.local@lists.linux.dev
smtp.helo=sea.lore.kernel.org
Received-SPF: pass (mxe881: domain of lists.linux.dev designates
172.234.253.10 as permitted sender) client-ip=172.234.253.10;
envelope-from=linux-sunxi+bounces-26749-noreply=patchwork.local@lists.linux.dev;
helo=sea.lore.kernel.org;
Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org
[100.77.114.92])
by sea.lore.kernel.org (Postfix) with ESMTP id 91BEF2EA74
for <noreply@patchwork.local>; Mon, 19 Oct 2026 20:06:55 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
arc=pass header.oldest-pass=0 smtp.remote-ip=127.0.0.1
ARC-Seal: i=2; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=pass;
t=1792440414;
b=Z62Hs/+vPR45FFw7UA/AwF/nYGYVxy+uSa1g35bs/5FvFZlvxswhJrLgPsPZTk7Pt0y7
pbwwwRmwfDEL/0hvUtPpKl7m82eNu33bfIHFBEPYvk+S+Byi8bSBxAXXyQt8KfXMNqmFu
qEpEopT4FlvyXcLtydHg/dvLVulMfPr0+zCCst8pyKkwpADJ7dsiXJKekw3TSqsouldba
VpedgG66tQlZIFkv4KDcHrn6SZnsn81MS6pDjBDwBq9cfcJ4j0LzbvmC55EngAdzLUDSY
+w84+ggdMCWXyDi1C7obrZnJi132KSTIEHWwnj9xVu79m+hBG5SWN88Fcg3o0jYol0A==
ARC-Message-Signature: i=2; d=subspace.kernel.org; s=arc20261015;
a=rsa-sha256; c=relaxed/relaxed; t=1792440414;
h=X-Original-To:Received:DMARC-Filter:Received:DKIM-Signature:
X-Google-DKIM-Signature:X-Forwarded-Encrypted:X-Gm-Message-State:
X-Gm-Gg:X-Received:Received:From:To:Cc:Subject:Date:Message-ID:
X-Mailer:In-Reply-To:References:X-Mailing-List:List-Id:List-Post:
List-Help:List-Subscribe:List-Unsubscribe:List-Owner:Precedence:
MIME-Version:Content-Transfer-Encoding;
bh=bFBNSvs3JDos8tPW/MP3a/GFNwGRHv00G3UEulH7lLI=;
b=bVptSvrNsmkVAOUs0W2XAmPAr51hwOr/wq5tEXxUFFVn87rXwdcIyLAwxGLGl7+6T/ex
m0kg5/pPDVK4ZMgMPBXInP1qikr6bvTKEpJHoA2ohwuLclzHM1lFRlhCIZ7vxMiJf9Gfe
+VRM04z2twKqFEgSCeRemjC5Ql4o+cL/evOUXDkMYtJKoUSvziCVA73258PwYlz+rTBFr
t9NAV99W/qLs0NEkV4I7vVA4DCFWODKFayB1g3nyl1iox98O/dpxOOZiJcAQSFqAGwBqS
y4NGkLJW0ZAavZlMu5NVWlzPtjGvvi2gGGZAqtUgXYkXhwm+iUwVTEg3PKFZTy1EDJw==
ARC-Authentication-Results: i=2; smtp.subspace.kernel.org;
dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256
header.s=20251104 header.b=WCrL+TWm;
dmarc=pass header.from=gmail.com;
spf=pass smtp.mailfrom=gmail.com;
arc=pass header.oldest-pass=0 smtp.remote-ip=127.0.0.1
Received: from localhost.localdomain (localhost [127.0.0.1])
by smtp.subspace.kernel.org (Postfix) with ESMTP id 65EE9606A31A;
Mon, 19 Oct 2026 20:06:54 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
dkim=pass (2048-bit key,
unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256
header.s=20251104 header.b=WCrL+TWm
X-Original-To: linux-sunxi@lists.linux.dev
Authentication-Results: smtp.subspace.kernel.org;
arc=none smtp.remote-ip=209.85.221.173
ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none;
t=1792440414;
b=vTNiNJNYLKnL8oDmeZBQJRYKFRgl+uqU2zjY1T5oLIngf3AANXtepVqR0//GOYDPzVha
8m6fatpCQRX9U3kGVuCvW+9SrhFZ7AYNgxkvtUdKeSQmqM5lhbbiOTLPMVLZEBp4GRI5T
1hiPe5qnWbXIpM8cW9cDV4T/cu104LgFcjilTIm47jVEYFExFe/Wfp8H9Jje+ktdN29bF
d2vOGP9Mm3Z8laLTrMDpPoqmzM4A8dqdfx4XHz/neYgRfNGtUvOwDpSpZtHEMAjSDgTHS
mD2XSajK8kwyUr9wkdY+qkCQIYRy+utJ43VjYOzUgNWqv07Hc6w05QiSjGmDzvK9MfA==
ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015;
a=rsa-sha256; c=relaxed/relaxed; t=1792440414;
h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature:
X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received:
From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References:
MIME-Version:Content-Transfer-Encoding;
bh=bFBNSvs3JDos8tPW/MP3a/GFNwGRHv00G3UEulH7lLI=;
b=3O6F+Hr2Jb/Wj5jRsWCjtkDZJ4ZvMnQqV6/43Wxa9mZjJetW0qbOpifQG9xMtHQE8HOU
l7yHL0il9Zap0h2dGjCdJcMDdYdMULG7M+EqjtCmLN3kk7GHsZYNf2msuT/U0SoYmbpPp
e/d2ZXDMYiEoaYwRgK7FpG0W1t+fUEwntgyFnLzxjjIxBVidBEOciZIGmD/c+oCUrGI5/
gVMrcHupMjRd8l9DrkmPDf/mdXbHrhQvIvRz3C6IRXTyKn8iuP8nhAOYcvcvMmeOfXYZD
q24qlfjL5zylt5f+/kveGTQK7dndimoiNiGGx7DVN5W7/N/keKEUL/l5+/SH8soYZLQ==
ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
dmarc=pass header.from=gmail.com;
spf=pass smtp.mailfrom=gmail.com;
dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256
header.s=20251104 header.b=WCrL+TWm;
arc=none smtp.remote-ip=209.85.221.173
Received: from mail-vk1-f173.google.com (mail-vk1-f173.google.com
[209.85.221.173])
(using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)
key-exchange X25519 server-signature ECDSA (prime256v1) server-digest
SHA256)
(No client certificate requested)
by smtp.subspace.kernel.org (Postfix) with ESMTPS id EE57B606A31E
for <linux-sunxi@lists.linux.dev>; Mon, 19 Oct 2026 20:06:53 +0000 (UTC)
DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org EE57B606A31E
Authentication-Results: smtp.subspace.kernel.org;
dmarc=pass (p=none dis=none) header.from=gmail.com
Authentication-Results: smtp.subspace.kernel.org;
spf=pass smtp.mailfrom=gmail.com
Received: by mail-vk1-f173.google.com with SMTP id
71dfb90a1353d-5eac48af23fso581792e0c.2
for <linux-sunxi@lists.linux.dev>;
Mon, 19 Oct 2026 13:06:53 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20251104; t=1792440413; x=1793045213;
darn=lists.linux.dev;
h=content-transfer-encoding:mime-version:references:in-reply-to
:message-id:date:subject:cc:to:from:from:to:cc:subject:date
:message-id:reply-to:content-type;
bh=bFBNSvs3JDos8tPW/MP3a/GFNwGRHv00G3UEulH7lLI=;
b=WCrL+TWmgftN//o7VLBx7xAJgrFL6LfABv+PjGf043723Sl6Ux4lFT2su1WdTXmoDG
0sKRSkUUCxN18qDHIBFgPP7OJTnzxbRiN6hy+j5V2s4kQUNVU2z1rKObKjNJk65XPmzB
DiHJCTbtOixetcQAjBPLqCC43D5e0NJYDr46EhANhbVHj6MYTWON5Wj8YhfJLYZry6Lh
71QAh/Bsqzcph763M9G5Tww1gF8otwIn6j6ZdPFSiXFEeygoxXJYymt7S5O7mH9QAaN7
6j+aosh9+WjddoKo+Ii1E+s94OetgMlrv+n6zJSjdrSqZcskxTME+icx7TXKIsMCVtAL
y+LQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20260707; t=1792440413; x=1793045213;
h=content-transfer-encoding:mime-version:references:in-reply-to
:message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from
:to:cc:subject:date:message-id:reply-to:content-type;
bh=bFBNSvs3JDos8tPW/MP3a/GFNwGRHv00G3UEulH7lLI=;
b=ufRoT5vdhmb5UfPo8EgBt7vv0PKxjfIGCXqnJYx2gj4cLTZHSDV2ZC9zD8OBaqZIFo
D8JFuoViOMiU2Hy/wfcJJ2EM9TtmQuqdKGRAL0tlSKsfy+aD5uICdosnrPLXi/gGJvYB
QSLoP/z/3acMVV2JceE0BPX3r6FNsLTY2TOOyWiCA0V8AL9O4h2sHOz5vlMPCIPElkL7
ePGxoGGf6LxeTwLwvTS844n38Tqu6I8HQhLUae21irZEpOYK/TdamhHSvs408LemlOLh
BMvUe0WnGBlb9NQ4U/WDjj11PodR/OKtHhhpvWO+/3O5I658ACuxP018v2DKFdTBAn8y
noaw==
X-Forwarded-Encrypted: i=1;
AKwUvBz9QrHJr7wRR49FVkx4HbGa7iEVVow1JjXYiCauD14FgykXRJza9GTR3CnoEqjqqVzQ0jjqHI2DvT7reA==@lists.linux.dev
X-Gm-Message-State: AFq9FYISVioH5qzjBSXVVnTtpTeibmKAAywRuYpUwjxCFyGz+1ZshiTc
I7S245C4FR62xfsCyHOnvRQ+E2/VDoUnzNdxpocrn64H4QWaT6B1t3BC
X-Gm-Gg: AYBFou3CP4XRw9+HtNChLqm6P7RL+VXL9giwNlGtDE5MpLZB7FuU/4tGzejP13sBwhh
G+DORdcUtNiZpVn2fYdvSztG4IGg0W5c3vrLG2FoCYxYD1g8H4w3ylvq5dlzTZBeuvtqnh9wS7j
yUALVKEvwtWuqqDhPxKw4HxyrIREeGmqsKVDSulzKR689dm6PJ6yvfEgd9xHXw5mJAls56Udzfe
jYczpl3Yg9FBRNxawkyam8nh1wcEsyUpP/X2DWBpghCtWSRVdmmQn7dRF5JQW9q95ZmW1KVGOP6
vq+YfwJ6Ldzs5uza5WuK0gN/QOwt+d8GlYCPc5gTr2vyrE12SPVRdQlvyHRFuQwtYbV6hEjUc4e
0MCDlDxEWzq+D4ZCuGjIJhJ3CC2usf/zu0iLUS92cizfoneC0hq0PXOStEBFK9Y/ZxezpvhFfc7
+RzU81dAfLX7uT3PtQ2VdEFxW1y9BJoTXJlaNcDxPTge5PI3BvbRcQC8C8klPiyLpcMvJsOw5xX
ND88Fja5W4MGCEMsd3R3b6O988tALYxYmDcNLqCbCGD5xNJwlGPj+5jTWylfZAMTQGvuO9w1D6Y
7ydOsS0=
X-Received: by 2002:a05:6122:1c02:b0:5de:ee96:75b with SMTP id
71dfb90a1353d-5eaaa68b961mr2904319e0c.12.1792440412948;
Mon, 19 Oct 2026 13:06:52 -0700 (PDT)
Received: from MaquinaLab.. ([179.179.244.163])
by smtp.gmail.com with ESMTPSA id
71dfb90a1353d-5ea9b4776b5sm10451611e0c.3.2026.10.19.13.06.46
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 19 Oct 2026 13:06:52 -0700 (PDT)
From: Vinicius Pedrosa <vinicius.eduardo.pedrosa@gmail.com>
To: linux-serial@vger.kernel.org
Cc: gregkh@linuxfoundation.org,
jirislaby@kernel.org,
robh@kernel.org,
krzk+dt@kernel.org,
conor+dt@kernel.org,
andriy.shevchenko@linux.intel.com,
ilpo.jarvinen@linux.intel.com,
devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-sunxi@lists.linux.dev,
Andre Przywara <andre.przywara@arm.com>,
Chen-Yu Tsai <wens@kernel.org>,
Jernej Skrabec <jernej.skrabec@gmail.com>,
Samuel Holland <samuel@sholland.org>,
Enzo Adriano <enzo.adriano.code@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH v2 1/4] serial: 8250_dw: Keep the BUSY-safe divisor hook when
DLF is present
Date: Mon, 19 Oct 2026 17:06:10 -0300
Message-ID:
<cc358c2be6b0b4ea0323e4f694a581ffb667112d.1792439398.git.vinicius.eduardo.pedrosa@gmail.com>
X-Mailer: git-send-email 2.43.0
In-Reply-To: <cover.1792439398.git.vinicius.eduardo.pedrosa@gmail.com>
References: <cover.1792439398.git.vinicius.eduardo.pedrosa@gmail.com>
X-Mailing-List: linux-sunxi@lists.linux.dev
List-Id: <linux-sunxi.lists.linux.dev>
List-Post: <mailto:linux-sunxi@lists.linux.dev>
List-Help: <mailto:linux-sunxi+help@lists.linux.dev>
List-Subscribe: <mailto:linux-sunxi+subscribe@lists.linux.dev>
List-Unsubscribe: <mailto:linux-sunxi+unsubscribe@lists.linux.dev>
List-Owner: <mailto:linux-sunxi+owner@lists.linux.dev>
Precedence: list
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Rspamd-Server: rspamd-worker-8404
X-Spamd-Result: default: False [4.81 / 15.00];
RBL_SENDERSCORE(2.00)[172.234.253.10:from];
SUSPICIOUS_RECIPS(1.50)[];
DMARC_POLICY_SOFTFAIL(1.00)[gmail.com : SPF not aligned (relaxed),
No valid DKIM,none];
R_MISSING_CHARSET(0.50)[];
MAILLIST(-0.18)[generic];
MIME_GOOD(-0.10)[text/plain];
BAD_REP_POLICIES(0.10)[];
HAS_LIST_UNSUB(-0.01)[];
ARC_ALLOW(0.00)[subspace.kernel.org:s=arc20261015:i=2];
FROM_HAS_DN(0.00)[];
TAGGED_RCPT(0.00)[dt];
FREEMAIL_CC(0.00)[linuxfoundation.org,kernel.org,linux.intel.com,vger.kernel.org,lists.linux.dev,arm.com,gmail.com,sholland.org];
FORGED_SENDER_MAILLIST(0.00)[];
DBL_BLOCKED_OPENRESOLVER(0.00)[sea.lore.kernel.org:helo,sea.lore.kernel.org:rdns];
RCPT_COUNT_TWELVE(0.00)[17];
RCVD_COUNT_FIVE(0.00)[6];
ASN(0.00)[asn:63949, ipnet:172.234.224.0/19, country:SG];
TAGGED_FROM(0.00)[bounces-26749-noreply=patchwork.local];
TO_DN_SOME(0.00)[];
FREEMAIL_FROM(0.00)[gmail.com];
RECEIVED_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[100.77.114.92:received,209.85.221.173:received];
RBL_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[172.234.253.10:from];
MID_RHS_MATCH_FROM(0.00)[];
R_SPF_ALLOW(0.00)[+ip4:172.234.253.10];
RECEIVED_SPAMHAUS_PBL(0.00)[179.179.244.163:received];
FROM_NEQ_ENVFROM(0.00)[viniciuseduardopedrosa@gmail.com,linux-sunxi@lists.linux.dev];
FORGED_RECIPIENTS_MAILLIST(0.00)[];
RCVD_TLS_LAST(0.00)[];
MIME_TRACE(0.00)[0:+];
RCVD_VIA_SMTP_AUTH(0.00)[]
X-Rspamd-Queue-Id: C61B51C239D
X-MORS-Enabled: yes
X-MORS-DOMAIN: patchwork.local
X-MORS-HOSTING: hosting172546
X-MORS-USER: hosting172546
X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?=
|
| Series |
serial: 8250_dw: Allwinner A733 UART support
|
|
Commit Message
Vinicius Pedrosa
Oct. 19, 2026, 8:06 p.m. UTC
dw8250_probe() installs dw8250_set_divisor(), which brackets the
DLAB/DLL/DLH sequence with dw8250_idle_enter() and dw8250_idle_exit()
so a BUSY UART cannot drop the divisor LCR write.
dw8250_setup_port() runs afterwards and replaces that hook with the
dwlib divisor hook whenever it detects DLF. The dwlib hook programs the
divisor through serial8250_do_set_divisor() without entering idle,
leaving the LCR|DLAB write exposed to BUSY.
When termios changes while the UART is transmitting, that LCR|DLAB
write can be ignored and dw8250_check_lcr() retries it between
dw8250_idle_enter() and dw8250_idle_exit(). dw8250_idle_exit() then
restores IER while DLAB is still set, so the value lands in DLH. The
real IER stays at the zero written by dw8250_idle_enter(), and the port
gets no further TX or RX interrupts while up->ier says they're enabled.
Do not replace a divisor hook the driver has already installed. Program
DLF from the BUSY-safe hook, inside the idle section, through a dwlib
helper that checks dlf_size.
Observed on an Allwinner A733 (Radxa Cubie A7Z), where
dw8250_setup_port() mistakes the RS485 control register for DLF (see the
next patch): the first interactive tcsetattr() during console output
left hardware IER at 0 and up->ier at 0x07. The shell never printed its
prompt or read input. With this change alone the same boot reached the
prompt and echoed input, and hardware IER matched up->ier afterwards.
Fixes: a7b9ce39fbe4 ("serial: 8250_dw: Ensure BUSY is deasserted")
Cc: stable@vger.kernel.org
Signed-off-by: Vinicius Pedrosa <vinicius.eduardo.pedrosa@gmail.com>
---
drivers/tty/serial/8250/8250_dw.c | 2 ++
drivers/tty/serial/8250/8250_dwlib.c | 16 ++++++++++++++--
drivers/tty/serial/8250/8250_dwlib.h | 1 +
3 files changed, 17 insertions(+), 2 deletions(-)
Comments
On Mon, Oct 19, 2026 at 05:06:10PM -0300, Vinicius Pedrosa wrote: > dw8250_probe() installs dw8250_set_divisor(), which brackets the > DLAB/DLL/DLH sequence with dw8250_idle_enter() and dw8250_idle_exit() > so a BUSY UART cannot drop the divisor LCR write. > > dw8250_setup_port() runs afterwards and replaces that hook with the > dwlib divisor hook whenever it detects DLF. The dwlib hook programs the > divisor through serial8250_do_set_divisor() without entering idle, > leaving the LCR|DLAB write exposed to BUSY. > > When termios changes while the UART is transmitting, that LCR|DLAB > write can be ignored and dw8250_check_lcr() retries it between > dw8250_idle_enter() and dw8250_idle_exit(). dw8250_idle_exit() then > restores IER while DLAB is still set, so the value lands in DLH. The > real IER stays at the zero written by dw8250_idle_enter(), and the port > gets no further TX or RX interrupts while up->ier says they're enabled. > > Do not replace a divisor hook the driver has already installed. Program > DLF from the BUSY-safe hook, inside the idle section, through a dwlib > helper that checks dlf_size. > > Observed on an Allwinner A733 (Radxa Cubie A7Z), where > dw8250_setup_port() mistakes the RS485 control register for DLF (see the > next patch): the first interactive tcsetattr() during console output > left hardware IER at 0 and up->ier at 0x07. The shell never printed its > prompt or read input. With this change alone the same boot reached the > prompt and echoed input, and hardware IER matched up->ier afterwards. ... > +/* Program the fractional part of the divisor, if the UART has one */ > +void __dw8250_set_divisor(struct uart_port *p, unsigned int quot_frac) Let's reduce amount of double underscore functions. Let's call it dw8250_update_dfl(). Also call the parameter just 'frac'. void dw8250_update_dfl(struct uart_port *p, unsigned int frac) ... > +++ b/drivers/tty/serial/8250/8250_dwlib.h > void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old); > void dw8250_setup_port(struct uart_port *p); > +void __dw8250_set_divisor(struct uart_port *p, unsigned int quot_frac); Put it rather after _writel_ext() implementation, because it's just a small wrapper on top of it. Or even make it 'static inline' there.
On Mon, Oct 19, 2026 at 05:06:10PM -0300, Vinicius Pedrosa wrote: ... > @@ -218,7 +228,9 @@ void dw8250_setup_port(struct uart_port *p) > if (reg) { > pd->dlf_size = fls(reg); > p->get_divisor = dw8250_get_divisor; In the case of existing _set_divisor, do we want to keep the possible set _get_divisor as well? Shouldn't we introduce a respective _get_divisor in 8250_dw.c? > - p->set_divisor = dw8250_set_divisor; > + /* Keep a hook the driver has already installed */ > + if (!p->set_divisor) > + p->set_divisor = dw8250_set_divisor; > } On top of my previous reply, why is this hunk needed? ... But now I see that we have same function name in two files. Can we rename those in dwlib to, for example, dw8250_get_divisor --> dw8250_get_dfl_divisor dw8250_set_divisor --> dw8250_set_dfl_divisor ?
Hi Andy, On Tue, 20 Oct 2026, Andy Shevchenko wrote: > > + /* Keep a hook the driver has already installed */ > > + if (!p->set_divisor) > > + p->set_divisor = dw8250_set_divisor; > > On top of my previous reply, why is this hunk needed? dw8250_probe() installs the BUSY-safe dw8250_set_divisor() before dw8250_setup_port() runs. Without the !p->set_divisor check, detecting DLF replaces it with the dwlib setter, which is the BUSY problem described in the commit message. > In the case of existing _set_divisor, do we want to keep the possible set > _get_divisor as well? Shouldn't we introduce a respective _get_divisor in > 8250_dw.c? 8250_dw.c doesn't install a get_divisor, so there's no existing getter to preserve. The dwlib getter is still needed when DLF is present, because it computes the fractional part used by the preserved BUSY-safe setter. > But now I see that we have same function name in two files. Can we rename > those in dwlib to, for example, > dw8250_get_divisor --> dw8250_get_dfl_divisor > dw8250_set_divisor --> dw8250_set_dfl_divisor I'll also clean up the naming in v3: dw8250_update_dlf() with a frac parameter, static inline after dw8250_writel_ext(), and the dwlib-local helpers renamed to dw8250_get_dlf_divisor() and dw8250_set_dlf_divisor(). Thanks, Vinicius
On Tue, Oct 20, 2026 at 07:47:53AM -0300, Vinicius Pedrosa wrote: > On Tue, 20 Oct 2026, Andy Shevchenko wrote: ... > > > + /* Keep a hook the driver has already installed */ > > > + if (!p->set_divisor) > > > + p->set_divisor = dw8250_set_divisor; > > > > On top of my previous reply, why is this hunk needed? > > dw8250_probe() installs the BUSY-safe dw8250_set_divisor() before > dw8250_setup_port() runs. Without the !p->set_divisor check, detecting > DLF replaces it with the dwlib setter, which is the BUSY problem > described in the commit message. > > > In the case of existing _set_divisor, do we want to keep the possible set > > _get_divisor as well? Shouldn't we introduce a respective _get_divisor in > > 8250_dw.c? > > 8250_dw.c doesn't install a get_divisor, so there's no existing getter > to preserve. Right. > The dwlib getter is still needed when DLF is present, > because it computes the fractional part used by the preserved BUSY-safe > setter. Right, but have you read my second question in the above paragraph? > > But now I see that we have same function name in two files. Can we rename > > those in dwlib to, for example, > > dw8250_get_divisor --> dw8250_get_dfl_divisor > > dw8250_set_divisor --> dw8250_set_dfl_divisor > > I'll also clean up the naming in v3: dw8250_update_dlf() with a frac > parameter, static inline after dw8250_writel_ext(), and the dwlib-local > helpers renamed to dw8250_get_dlf_divisor() and > dw8250_set_dlf_divisor().
Hi Andy,
On Wed, 21 Oct 2026, Andy Shevchenko wrote:
> Right, but have you read my second question in the above paragraph?
Sorry, I missed the second part of your question.
If I understand you correctly, since 8250_dw.c already has the BUSY-safe
set_divisor, you're suggesting that it should have the matching
get_divisor as well, instead of pairing it with the dwlib getter.
The dwlib getter would stay for the other users of dw8250_setup_port(),
like 8250_lpss. Is that the structure you had in mind?
Thanks,
Vinicius
On Wed, Oct 21, 2026 at 07:00:49AM -0300, Vinicius Pedrosa wrote: > On Wed, 21 Oct 2026, Andy Shevchenko wrote: > > > Right, but have you read my second question in the above paragraph? > > Sorry, I missed the second part of your question. > > If I understand you correctly, since 8250_dw.c already has the BUSY-safe > set_divisor, you're suggesting that it should have the matching > get_divisor as well, instead of pairing it with the dwlib getter. Exactly! > The dwlib getter would stay for the other users of dw8250_setup_port(), > like 8250_lpss. Is that the structure you had in mind? 8250_lpss doesn't redefine either of the _get/_set_divisor, so it won't be affected. But I think that 8250_lpss actually lacks of busy support that's why it uses simpler version of all this. Maybe we can refactor that (in the future?) so that we will have dwlib to provide the IDLE version of them for all and depending on the existence of busy functionality degrade to the same as just current DFL helpers. Can you check that approach? Ah, dw8250_idle_*() are already BUSY-functionality aware. So, what we need is to provide dw8250_idlej_*() callbacks via struct dw8250_port_data and make current 8250_dw::dw8250_set_divisor() to be part of dwlib. Patch 1 (dwlib): Add callback definitions for dw8250_idle_*() to struct dw8250_port_data Patch 2 (dw): Assign new callbacks and use them in dw8250_set_divisor() Patch 3 (lpss): Introduce stubs and assign new callbacks to them Patch 4 (dwlib): Use dw8250_idle_*() in dw8250_set_divisor() Patch 5 (dw): Kill now duplicate code pieces (Some of the patches might be combined, but I think the above split is not bad.) Would it work?
Hi Andy, On Wed, 21 Oct 2026, Andy Shevchenko wrote: > Ah, dw8250_idle_*() are already BUSY-functionality aware. So, what we need > is to provide dw8250_idlej_*() callbacks via struct dw8250_port_data and > make current 8250_dw::dw8250_set_divisor() to be part of dwlib. > > Patch 1 (dwlib): Add callback definitions for dw8250_idle_*() to struct dw8250_port_data > Patch 2 (dw): Assign new callbacks and use them in dw8250_set_divisor() > Patch 3 (lpss): Introduce stubs and assign new callbacks to them > Patch 4 (dwlib): Use dw8250_idle_*() in dw8250_set_divisor() > Patch 5 (dw): Kill now duplicate code pieces > > Would it work? Yes, I think the approach works. Two details from checking the call paths. dw8250_setup_port() is skipped for Octeon (skip_autocfg), so 8250_dw would still have to install the setter from probe. For LPSS, I wonder if the idle callbacks could simply be optional. 8250_dw would provide them and LPSS could leave them NULL, avoiding stubs and a separate LPSS patch. The common setter in dwlib would use them when present. I'd still prefer to keep patch 1 as the small fix with the stable tag and do the refactoring as a separate follow-up series. Would that work for you? I don't have LPSS hardware, but I can build-test the LPSS side. Thanks, Vinicius
On Wed, Oct 21, 2026 at 12:37:32PM -0300, Vinicius Pedrosa wrote: > On Wed, 21 Oct 2026, Andy Shevchenko wrote: > > > Ah, dw8250_idle_*() are already BUSY-functionality aware. So, what we need > > is to provide dw8250_idle_*() callbacks via struct dw8250_port_data and > > make current 8250_dw::dw8250_set_divisor() to be part of dwlib. > > > > Patch 1 (dwlib): Add callback definitions for dw8250_idle_*() to struct dw8250_port_data > > Patch 2 (dw): Assign new callbacks and use them in dw8250_set_divisor() > > Patch 3 (lpss): Introduce stubs and assign new callbacks to them > > Patch 4 (dwlib): Use dw8250_idle_*() in dw8250_set_divisor() > > Patch 5 (dw): Kill now duplicate code pieces > > > > Would it work? > > Yes, I think the approach works. Two details from checking the call > paths. > > dw8250_setup_port() is skipped for Octeon (skip_autocfg), so 8250_dw > would still have to install the setter from probe. No, just pass that as a 'bool autoconf' to it, and assign those callbacks there, while calling dw8250_setup_port() unconditionally from _probe(). It might require another patch, though (to make it a parameter first). > For LPSS, I wonder if the idle callbacks could simply be optional. > 8250_dw would provide them and LPSS could leave them NULL, avoiding > stubs and a separate LPSS patch. The common setter in dwlib would use > them when present. I think it would be less flexible, also it will add an additional branch (actually two) each time the set_divisor is called (not that it's critical but just wanted to mentioned that). > I'd still prefer to keep patch 1 as the small fix with the stable tag > and do the refactoring as a separate follow-up series. Would that work > for you? I dunno, I prefer just a longer solution, but I don't know how big this issue is that we need to backport in that way (and not taking the whole series as a fix). > I don't have LPSS hardware, but I can build-test the LPSS side. I have Intel Galileo board that uses 8250_lpss.
Hi Andy, On Wed, 21 Oct 2026, Andy Shevchenko wrote: > No, just pass that as a 'bool autoconf' to it, and assign those callbacks > there, while calling dw8250_setup_port() unconditionally from _probe(). I think the autoconf approach works for Octeon as long as everything dw8250_setup_port() probes today stays under it, including the RS485 detection and UART_CAP_NOTEMT, not just DLF/CPR. With autoconf=false it would only install the common divisor setter. > I think it would be less flexible, also it will add an additional branch > (actually two) each time the set_divisor is called (not that it's critical > but just wanted to mentioned that). The idle callbacks have to come from the drivers, since the dw8250_idle_*() functions are static in 8250_dw.c. Stubs for LPSS are fine with me. > I dunno, I prefer just a longer solution, but I don't know how big this issue > is that we need to backport in that way (and not taking the whole series as a > fix). On the severity: the IER restore comes from a7b9ce39fbe4. On the A733 I saw hardware IER left at 0 and the console stop taking TX/RX interrupts. I haven't tested this on hardware with a real DLF. Given that, how about keeping the small fix as patch 1 with the stable tag, and putting the refactoring after it in the same series? That would keep the fix independently backportable if needed, while mainline would still end up with the structure you proposed. > I have Intel Galileo board that uses 8250_lpss. The Galileo should be useful for checking the LPSS path. Thanks, Vinicius
On Wed, Oct 21, 2026 at 02:04:03PM -0300, Vinicius Pedrosa wrote: > On Wed, 21 Oct 2026, Andy Shevchenko wrote: ... > > I dunno, I prefer just a longer solution, but I don't know how big this issue > > is that we need to backport in that way (and not taking the whole series as a > > fix). > > On the severity: the IER restore comes from a7b9ce39fbe4. On the A733 I > saw hardware IER left at 0 and the console stop taking TX/RX > interrupts. I haven't tested this on hardware with a real DLF. Yes. but is it only a single device/platform affected or a big class of the devices? I assume only narrow part of them which unfortunately use DFL register offset for something else in their RTL. > Given that, how about keeping the small fix as patch 1 with the stable > tag, and putting the refactoring after it in the same series? That would > keep the fix independently backportable if needed, while mainline would > still end up with the structure you proposed. It all depends on the outcome of the above discussion. Maybe others can share their opinions, but I lean towards a series-as-a-fix rather than a bit ugly fix + proper refactoring on top. The whole approach doesn't seem to me like a pile of changes. The deduplication patch can be deferred for later actually.
Hi Andy, On Wed, 21 Oct 2026, Andy Shevchenko wrote: > Yes. but is it only a single device/platform affected or a big class of the > devices? I assume only narrow part of them which unfortunately use DFL register > offset for something else in their RTL. The A733 is the only case I've seen, and the false DLF is what exposed it. But I don't think the BUSY problem depends on the DLF offset being reused: with a real DLF on a UART that isn't 16550-compatible, dw8250_setup_port() also replaces the BUSY-safe setter with the dwlib one, so the same path exists. I haven't confirmed that on hardware. With patch 2 the A733 no longer takes that path. > It all depends on the outcome of the above discussion. Maybe others can share > their opinions, but I lean towards a series-as-a-fix rather than a bit ugly fix > + proper refactoring on top. I'm fine with a series-as-a-fix, and with deferring the deduplication patch. Thanks, Vinicius
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index eca02e8bd6d1..4c86aaf9c121 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -197,6 +197,8 @@ static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, if (ret < 0) return; + __dw8250_set_divisor(p, quot_frac); + serial_port_out(p, UART_LCR, up->lcr | UART_LCR_DLAB); if (!(serial_port_in(p, UART_LCR) & UART_LCR_DLAB)) goto idle_failed; diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index 9bb02a4ab11f..325793f20256 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -36,10 +36,20 @@ static unsigned int dw8250_get_divisor(struct uart_port *p, unsigned int baud, return quot; } +/* Program the fractional part of the divisor, if the UART has one */ +void __dw8250_set_divisor(struct uart_port *p, unsigned int quot_frac) +{ + struct dw8250_port_data *d = p->private_data; + + if (d->dlf_size) + dw8250_writel_ext(p, DW_UART_DLF, quot_frac); +} +EXPORT_SYMBOL_GPL(__dw8250_set_divisor); + static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, unsigned int quot, unsigned int quot_frac) { - dw8250_writel_ext(p, DW_UART_DLF, quot_frac); + __dw8250_set_divisor(p, quot_frac); serial8250_do_set_divisor(p, baud, quot); } @@ -218,7 +228,9 @@ void dw8250_setup_port(struct uart_port *p) if (reg) { pd->dlf_size = fls(reg); p->get_divisor = dw8250_get_divisor; - p->set_divisor = dw8250_set_divisor; + /* Keep a hook the driver has already installed */ + if (!p->set_divisor) + p->set_divisor = dw8250_set_divisor; } reg = dw8250_readl_ext(p, DW_UART_UCV); diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h index 39fcb1b323ad..4bb0ccb3e8ef 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -99,6 +99,7 @@ struct dw8250_port_data { void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old); void dw8250_setup_port(struct uart_port *p); +void __dw8250_set_divisor(struct uart_port *p, unsigned int quot_frac); static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) {