* Re: [PATCH v8] tty: tty_port: add workqueue to flip TTY buffer
From: Xin Zhao @ 2026-01-29 10:31 UTC (permalink / raw)
To: m.szyprowski
Cc: gregkh, hch, jackzxcui1989, jirislaby, linux-kernel, linux-serial,
tj, tommaso.merciai.xr, geert
In-Reply-To: <d1942304-ee30-478d-90fb-279519f3ae81@samsung.com>
Hi all,
Sorry for the problems! I didn't consider all the situation.
On Tue, 27 Jan 2026 11:34:32 +0100 Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> It looks that driver->name is not unique on some systems, see:
>
> $ git grep ttyMSM drivers/tty/
> drivers/tty/serial/msm_serial.c: .name = "ttyMSM",
> drivers/tty/serial/msm_serial.c: .dev_name = "ttyMSM",
> drivers/tty/serial/qcom_geni_serial.c: .name = "ttyMSM",
> drivers/tty/serial/qcom_geni_serial.c: .dev_name = "ttyMSM",
>
> This fails on Qualcomm RB5 boards, breaking the boot process (booting
> hangs, because drivers try to use the unregistered wq):
I think I should use the name format "%s-%s-flip-wq", ..., driver->name, driver->driver_name
as you suggested, and remove the 'flip-wq' part to avoid exceeding the WQ_NAME_LEN limit.
I checked the lengths of all dev_name + driver_name in all tty/* files, and none exceeded
WQ_NAME_LEN (32).
> The other issue with this patch I've observed on ARM Juno R1 board. With
> one of the above fixes for the workqueue name, the boot process is still
> broken because of the NULL pointer dereference:
>
> input: gpio-keys as /de ** replaying previous printk message ** input:
> gpio-keys as /devices/platform/gpio-keys/input/input3 Unable to handle
> kernel NULL pointer dereference at virtual address 00000000000001c0 Mem
> abort info: ... [00000000000001c0] user address but active_mm is swapper
> Internal error: Oops: 0000000096000004 [#1] SMP Modules linked in: CPU:
> 1 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.19.0-rc7-next-20260126+
> #16443 PREEMPT Hardware name: ARM Juno development board (r1) (DT)
> pstate: 400000c5 (nZcv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc :
> __queue_work+0x30/0x7c4 lr : queue_work_on+0xac/0xdc ... Call trace:
> __queue_work+0x30/0x7c4 (P) queue_work_on+0xac/0xdc
> tty_flip_buffer_push+0x2c/0x38 k_fn.part.0+0x7c/0xc8 k_fn+0x20/0x2c
> kbd_event+0x2d8/0x504 input_handle_events_default+0x50/0x74
> input_pass_values+0x148/0x2b4 input_handle_event+0xcc/0x5e0
> input_event+0x64/0xa4 gpio_keys_open+0x9c/0xc4
> input_open_device+0x8c/0x128 kbd_connect+0x84/0xa0
> input_attach_handler+0x9c/0xf4 input_register_device+0x308/0x48c
> gpio_keys_probe+0x40c/0xafc platform_probe+0x5c/0xac
> really_probe+0xbc/0x298 __driver_probe_device+0x78/0x12c
> driver_probe_device+0xdc/0x164 __driver_attach+0xe4/0x224
> bus_for_each_dev+0x74/0xd0 driver_attach+0x24/0x30
> bus_add_driver+0xe4/0x208 driver_register+0x60/0x128
> __platform_driver_register+0x24/0x30 gpio_keys_init+0x1c/0x28
> do_one_initcall+0x64/0x308 kernel_init_freeable+0x284/0x508
> kernel_init+0x24/0x1dc ret_from_fork+0x10/0x20 Code: a9025bf5 a90573fb
> aa0203fb 35001843 (b941c260) ---[ end trace 0000000000000000 ]--- note:
> swapper/0[1] exited with irqs disabled note: swapper/0[1] exited with
> preempt_count 3 Kernel panic - not syncing: Attempted to kill init!
> exitcode=0x0000000b SMP: stopping secondary CPUs Kernel Offset: disabled
> CPU features: 0x1040000,41858004,00020000,0400421b Memory Limit: none
> ---[ end Kernel panic - not syncing: Attempted to kill init!
> exitcode=0x0000000b ]---
>
> Reverting $subject on top of current linux-next fixes this issue.
Thank you very much for your detailed stack; it has been very helpful to me.
I followed the call stack in detail and found that the line in kbd_keycode(),
(*k_handler[type])(vc, KVAL(keysym), !down);
calls k_fn(), which ultimately calls tty_flip_buffer_push().
In kbd_keycode(), vc is set as follows:
struct vc_data *vc = vc_cons[fg_console].d;
fg_console is set to 0 in con_init().
con_init() calls tty_port_init() to init vc_cons[0].d->port but do not call
tty_port_install() which link flip_wq to the port.
Although tty_port_install() is dedicated for in-memory devices like PTY to
link port allocated on demand, the logic of tty_port_install() is so simple
that people may not call it. vc_cons[0].d->port is one such case.
On the other hand, not all instances during tty_port_init() have easy access
to the corresponding driver pointer, which makes it inconvenient to directly
link flip_wq during all tty_port_init calls. Below are some other code that
I found, which may not link wq, potentially leading to flip_wq being null:
drivers/s390/char/sclp_vt220.c:
sclp_vt220_con_init
__sclp_vt220_init
tty_port_init
drivers/tty/n_gsm.c
gsm_queue
gsm_dlci_alloc
tty_port_init
drivers/tty/vcc.c
vcc_install
tty_port_init
drivers/usb/serial/usb-serial.c
usb_serial_probe
tty_port_init
Maybe in tty_flip_buffer_push() 'checking whether flip_wq is NULL and use
system_dfl_wq instead if it is NULL' is a better choice.
--
Xin Zhao
^ permalink raw reply
* Re: [PATCH] tty: synclink_gt: remove broken driver
From: Jiri Slaby @ 2026-01-29 11:41 UTC (permalink / raw)
To: Ethan Nelson-Moore, linux-serial, linux-doc, netdev
Cc: linux-api, Jonathan Corbet, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Greg Kroah-Hartman, Haren Myneni, Bagas Sanjaya, Simon Horman,
Eric Biggers
In-Reply-To: <20260129075200.38060-1-enelsonmoore@gmail.com>
On 29. 01. 26, 8:51, Ethan Nelson-Moore wrote:
> The synclink_gt driver was marked as broken in commit 426263d5fb40
> ("tty: synclink_gt: mark as BROKEN") in July 2023 because it had severe
> structural problems and there had been no evidence of users since 2016.
> Since then, no meaningful improvements have been made to the driver,
> and it is unlikely that will ever happen due to the lack of interest.
> Drop the driver and references to it in comments and documentation.
Overall, I am all for it, but a few remarks:
> Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
> ---
> .../userspace-api/ioctl/ioctl-number.rst | 2 +-
> arch/powerpc/configs/ppc6xx_defconfig | 1 -
> drivers/net/ppp/Kconfig | 4 +-
> drivers/tty/Kconfig | 11 +-
> drivers/tty/Makefile | 1 -
> drivers/tty/n_hdlc.c | 7 -
> drivers/tty/synclink_gt.c | 5038 -----------------
> include/linux/synclink.h | 37 -
vvvvvvvvvvvvvvvvvvvvvvvvvvvvv
> include/uapi/linux/synclink.h | 301 -
Have you checked this is not included in any relevant userspace? How?
Hints: debian code search, github...
> diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
> index 7232b3544cec..8abedab9fea7 100644
> --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
> +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
> @@ -271,7 +271,7 @@ Code Seq# Include File Comments
> 'm' 00-09 linux/mmtimer.h conflict!
> 'm' all linux/mtio.h conflict!
> 'm' all linux/soundcard.h conflict!
> -'m' all linux/synclink.h conflict!
> +'m' all linux/synclink.h Dead since 2026
I would just drop the line, removing one conflicting entry. The letter
is not going to be dead.
Or is this Dead note some ioctl-number's policy?
> --- a/drivers/tty/n_hdlc.c
> +++ b/drivers/tty/n_hdlc.c
> @@ -4,8 +4,6 @@
> * Written by Paul Fulghum paulkf@microgate.com
> * for Microgate Corporation
> *
> - * Microgate and SyncLink are registered trademarks of Microgate Corporation
> - *
> * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
> * Al Longyear <longyear@netcom.com>,
> * Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
> @@ -54,11 +52,6 @@
> * this line discipline (or another line discipline that is frame
> * oriented such as N_PPP).
> *
> - * The SyncLink driver (synclink.c) implements both asynchronous
> - * (using standard line discipline N_TTY) and synchronous HDLC
> - * (using N_HDLC) communications, with the latter using the above
> - * conventions.
This paragraph actually talks about long removed synclink.c, removed in:
a1f714b44e34 tty: Remove redundant synclink driver
But OK, let's kick all the remaining traces of synclinks.
thanks,
--
js
suse labs
^ permalink raw reply
* [syzbot] Monthly serial report (Jan 2026)
From: syzbot @ 2026-01-29 11:51 UTC (permalink / raw)
To: gregkh, linux-kernel, linux-serial, syzkaller-bugs
Hello serial maintainers/developers,
This is a 31-day syzbot report for the serial subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/serial
During the period, 1 new issues were detected and 0 were fixed.
In total, 15 issues are still open and 45 have already been fixed.
Some of the still happening issues:
Ref Crashes Repro Title
<1> 3669 Yes possible deadlock in console_lock_spinning_enable (5)
https://syzkaller.appspot.com/bug?extid=622acb507894a48b2ce9
<2> 3002 Yes KMSAN: uninit-value in n_tty_receive_buf_standard
https://syzkaller.appspot.com/bug?extid=559c7fe4b8bac56d38c2
<3> 265 Yes KASAN: slab-use-after-free Read in tty_write_room (2)
https://syzkaller.appspot.com/bug?extid=2a81fdd5c6ddffee3894
<4> 261 Yes KMSAN: uninit-value in n_tty_receive_buf_closing (3)
https://syzkaller.appspot.com/bug?extid=dd514b5f0cf048aec256
<5> 238 Yes INFO: task can't die in show_free_areas
https://syzkaller.appspot.com/bug?extid=8f41dccfb6c03cc36fd6
<6> 120 Yes possible deadlock in tty_buffer_flush (3)
https://syzkaller.appspot.com/bug?extid=52cf91760dcb1dac6376
<7> 53 No KMSAN: uninit-value in n_tty_lookahead_flow_ctrl (2)
https://syzkaller.appspot.com/bug?extid=290abdcd4f509377a0eb
<8> 18 Yes INFO: rcu detected stall in console_callback
https://syzkaller.appspot.com/bug?extid=32af18ae7b894a681f2d
<9> 6 Yes INFO: task hung in paste_selection (2)
https://syzkaller.appspot.com/bug?extid=275e275bd3f536725dd8
<10> 3 No possible deadlock in stop_tty
https://syzkaller.appspot.com/bug?extid=7ca5a40e8164fe2609fd
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders
To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem
You may send multiple commands in a single email message.
^ permalink raw reply
* Re: [PATCH v3] serial: 8250: Fix fifo underflow on flush
From: Raul E Rangel @ 2026-01-30 3:54 UTC (permalink / raw)
To: John Keeping
Cc: Greg Kroah-Hartman, stable, Jiri Slaby, Andy Shevchenko,
Sunil V L, Petr Mladek, Arnd Bergmann, John Ogness,
Ilpo Järvinen, Ferry Toth, Niklas Schnelle, Serge Semin,
Heikki Krogerus, linux-kernel, linux-serial
In-Reply-To: <20250208124148.1189191-1-jkeeping@inmusicbrands.com>
On Sat, Feb 08, 2025 at 12:41:44PM +0000, John Keeping wrote:
> When flushing the serial port's buffer, uart_flush_buffer() calls
> kfifo_reset() but if there is an outstanding DMA transfer then the
> completion function will consume data from the kfifo via
> uart_xmit_advance(), underflowing and leading to ongoing DMA as the
> driver tries to transmit another 2^32 bytes.
>
> This is readily reproduced with serial-generic and amidi sending even
> short messages as closing the device on exit will wait for the fifo to
> drain and in the underflow case amidi hangs for 30 seconds on exit in
> tty_wait_until_sent(). A trace of that gives:
>
> kworker/1:1-84 [001] 51.769423: bprint: serial8250_tx_dma: tx_size=3 fifo_len=3
> amidi-763 [001] 51.769460: bprint: uart_flush_buffer: resetting fifo
> irq/21-fe530000-76 [000] 51.769474: bprint: __dma_tx_complete: tx_size=3
> irq/21-fe530000-76 [000] 51.769479: bprint: serial8250_tx_dma: tx_size=4096 fifo_len=4294967293
> irq/21-fe530000-76 [000] 51.781295: bprint: __dma_tx_complete: tx_size=4096
> irq/21-fe530000-76 [000] 51.781301: bprint: serial8250_tx_dma: tx_size=4096 fifo_len=4294963197
> irq/21-fe530000-76 [000] 51.793131: bprint: __dma_tx_complete: tx_size=4096
> irq/21-fe530000-76 [000] 51.793135: bprint: serial8250_tx_dma: tx_size=4096 fifo_len=4294959101
> irq/21-fe530000-76 [000] 51.804949: bprint: __dma_tx_complete: tx_size=4096
>
> Since the port lock is held in when the kfifo is reset in
> uart_flush_buffer() and in __dma_tx_complete(), adding a flush_buffer
> hook to adjust the outstanding DMA byte count is sufficient to avoid the
> kfifo underflow.
>
> Fixes: 9ee4b83e51f74 ("serial: 8250: Add support for dmaengine")
> Cc: stable@vger.kernel.org
> Signed-off-by: John Keeping <jkeeping@inmusicbrands.com>
> ---
> Changes in v3:
> - Fix !CONFIG_SERIAL_8250_DMA build
> Changes in v2:
> - Add Fixes: tag
> - Return early to reduce indentation in serial8250_tx_dma_flush()
>
> drivers/tty/serial/8250/8250.h | 2 ++
> drivers/tty/serial/8250/8250_dma.c | 16 ++++++++++++++++
> drivers/tty/serial/8250/8250_port.c | 9 +++++++++
> 3 files changed, 27 insertions(+)
>
> diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
> index 11e05aa014e54..b861585ca02ac 100644
> --- a/drivers/tty/serial/8250/8250.h
> +++ b/drivers/tty/serial/8250/8250.h
> @@ -374,6 +374,7 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
>
> #ifdef CONFIG_SERIAL_8250_DMA
> extern int serial8250_tx_dma(struct uart_8250_port *);
> +extern void serial8250_tx_dma_flush(struct uart_8250_port *);
> extern int serial8250_rx_dma(struct uart_8250_port *);
> extern void serial8250_rx_dma_flush(struct uart_8250_port *);
> extern int serial8250_request_dma(struct uart_8250_port *);
> @@ -406,6 +407,7 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p)
> {
> return -1;
> }
> +static inline void serial8250_tx_dma_flush(struct uart_8250_port *p) { }
> static inline int serial8250_rx_dma(struct uart_8250_port *p)
> {
> return -1;
> diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
> index d215c494ee24c..f245a84f4a508 100644
> --- a/drivers/tty/serial/8250/8250_dma.c
> +++ b/drivers/tty/serial/8250/8250_dma.c
> @@ -149,6 +149,22 @@ int serial8250_tx_dma(struct uart_8250_port *p)
> return ret;
> }
>
> +void serial8250_tx_dma_flush(struct uart_8250_port *p)
> +{
> + struct uart_8250_dma *dma = p->dma;
> +
> + if (!dma->tx_running)
> + return;
> +
> + /*
> + * kfifo_reset() has been called by the serial core, avoid
> + * advancing and underflowing in __dma_tx_complete().
> + */
> + dma->tx_size = 0;
> +
> + dmaengine_terminate_async(dma->rxchan);
Hrmm, I think this is causing a deadlock.
If the DMA transaction is canceled, then the callback might not run.
This leaves dma->tx_running set to 1 causing the channel to never
restart the channel.
I tried the following fix (and it works for me), but I'm not sure it's
the correct fix.
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index bdd26c9f34bd..58b914c20d98 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -162,7 +162,22 @@ void serial8250_tx_dma_flush(struct uart_8250_port *p)
*/
dma->tx_size = 0;
+ /*
+ * We can't use `dmaengine_terminate_sync` because `uart_flush_buffer` is
+ * holding the uart port spinlock.
+ */
dmaengine_terminate_async(dma->txchan);
+
+ /*
+ * The callback might or might not run. If it doesn't run, we need to ensure
+ * that `tx_running` is cleared so that we can schedule new transactions.
+ * If it does run, then the zombie callback will clear `tx_running` for us
+ * and perform a no-op since `tx_size` was cleared.
+ *
+ * In either case, we assume DMA transaction will be terminated or the
+ * callback will run before we issue a new `serial8250_tx_dma`.
+ */
+ dma->tx_running = 0;
}
int serial8250_rx_dma(struct uart_8250_port *p)
The problem is IIUC, that we need to either use dmaengine_terminate_sync
or dmaengine_synchronize so we can guarantee that the hardware is
stopped, the callback is done, and we can free-reuse the resources.
I think a better approach might be to add a `tx_flushing` bool and push
a job onto a work queue that calls `dmaengine_terminate_sync`, and then
sets `tx_running=0` and `tx_flushing=0`. I'm not sure what happens
though if something comes along and starts writing to the UART registers
while we are waiting for the DMA transaction to complete.
Thoughts?
---
Here is the debug trace I took that shows the problem:
< lots of tty_write omitted >
3250.941306 | 0) | tty_write() {
3250.941307 | 0) 0.174 us | tty_ldisc_ref_wait();
3250.941307 | 0) 0.154 us | tty_hung_up_p();
3250.941307 | 0) | tty_write_room() {
3250.941308 | 0) 0.211 us | uart_write_room();
3250.941308 | 0) 0.542 us | }
3250.941308 | 0) | uart_write() {
3250.941308 | 0) | serial8250_start_tx() {
3250.941309 | 0) | serial8250_tx_dma() {
3250.941309 | 0) | /* serial8250_tx_dma: tx_running => 1 */
3250.941309 | 0) 0.408 us | }
3250.941309 | 0) 0.714 us | }
3250.941309 | 0) 1.261 us | }
3250.941310 | 0) | tty_write_room() {
3250.941310 | 0) 0.217 us | uart_write_room();
3250.941310 | 0) 0.489 us | }
3250.941310 | 0) | uart_flush_chars() {
3250.941310 | 0) | uart_start() {
3250.941311 | 0) | serial8250_start_tx() {
3250.941311 | 0) | serial8250_tx_dma() {
3250.941311 | 0) | /* serial8250_tx_dma: tx_running => 1 */
3250.941311 | 0) 0.389 us | }
3250.941311 | 0) 0.681 us | }
3250.941312 | 0) 1.207 us | }
3250.941312 | 0) 1.488 us | }
3251.008825 | 10) | serial8250_interrupt() {
3251.008828 | 10) | serial8250_default_handle_irq() {
3251.008830 | 10) + 17.915 us | dw8250_serial_in32 [8250_dw]();
3251.008848 | 10) 0.207 us | serial8250_handle_irq();
3251.008849 | 10) + 20.208 us | }
3251.008849 | 10) + 27.505 us | }
3251.008862 | 10) | /* __dma_tx_complete: tx_running <= 0 */
3251.008863 | 10) | serial8250_tx_dma() {
3251.008864 | 10) | /* serial8250_tx_dma: tx_running => 0 */
3251.008872 | 10) | /* serial8250_tx_dma: tx_running <= 1 */
3251.008879 | 10) 9.410 us | }
3251.107685 | 10) | serial8250_interrupt() {
3251.107688 | 10) | serial8250_default_handle_irq() {
3251.107689 | 10) + 18.007 us | dw8250_serial_in32 [8250_dw]();
3251.107707 | 10) | serial8250_handle_irq() {
3251.107708 | 10) 1.847 us | dw8250_serial_in32 [8250_dw]();
3251.107713 | 10) 1.003 us | serial8250_rx_dma_flush();
3251.107714 | 10) | serial8250_read_char() {
3251.107715 | 10) + 17.452 us | dw8250_serial_in32 [8250_dw]();
3251.107732 | 10) 1.008 us | uart_insert_char();
3251.107734 | 10) + 19.136 us | }
3251.107734 | 10) 3.914 us | dw8250_serial_in32 [8250_dw]();
3251.107739 | 10) 6.789 us | tty_flip_buffer_push();
3251.107746 | 10) | serial8250_modem_status() {
3251.107746 | 10) + 17.556 us | dw8250_serial_in32 [8250_dw]();
3251.107764 | 10) + 18.039 us | }
3251.107764 | 10) + 56.710 us | }
3251.107764 | 10) + 76.870 us | }
3251.107765 | 10) | serial8250_default_handle_irq() {
3251.107765 | 10) 4.205 us | dw8250_serial_in32 [8250_dw]();
3251.107769 | 10) 0.219 us | serial8250_handle_irq();
3251.107770 | 10) 5.076 us | }
3251.107770 | 10) + 88.331 us | }
3251.107805 | 6) | tty_port_default_receive_buf() {
3251.107808 | 6) 1.377 us | tty_ldisc_ref();
3251.107810 | 6) | tty_ldisc_receive_buf() {
3251.107813 | 6) 0.639 us | tty_get_pgrp();
3251.107823 | 6) | tty_driver_flush_buffer() {
3251.107824 | 6) | uart_flush_buffer() {
3251.107825 | 6) | serial8250_flush_buffer() {
3251.107826 | 6) | serial8250_tx_dma_flush() {
3251.107829 | 6) | /* serial8250_tx_dma_flush: tx_running => 1 */
/* Notice the callback is never ran */
3251.108186 | 6) ! 360.293 us | }
3251.108186 | 6) ! 361.125 us | }
3251.108196 | 6) | tty_port_tty_wakeup() {
3251.108196 | 6) | tty_port_default_wakeup() {
3251.108196 | 6) 1.146 us | tty_wakeup();
3251.108198 | 6) 0.247 us | tty_kref_put();
3251.108198 | 6) 2.359 us | }
3251.108199 | 6) 2.987 us | }
3251.108199 | 6) ! 374.727 us | }
3251.108199 | 6) ! 375.679 us | }
3251.108202 | 6) | tty_write_room() {
3251.108203 | 6) 0.286 us | uart_write_room();
3251.108203 | 6) 1.074 us | }
3251.108204 | 6) | tty_put_char() {
3251.108204 | 6) 0.487 us | uart_put_char();
3251.108205 | 6) 1.177 us | }
3251.108205 | 6) | tty_put_char() {
3251.108205 | 6) 0.261 us | uart_put_char();
3251.108206 | 6) 0.677 us | }
3251.108206 | 6) | uart_flush_chars() {
3251.108207 | 6) | uart_start() {
3251.108208 | 6) | serial8250_start_tx() {
3251.108209 | 6) | serial8250_tx_dma() {
3251.108210 | 6) | /* serial8250_tx_dma: tx_running => 1 */
3251.108210 | 6) 1.194 us | }
3251.108211 | 6) 2.251 us | }
3251.108213 | 6) 5.829 us | }
3251.108213 | 6) 6.532 us | }
3251.108214 | 6) ! 404.132 us | }
3251.108214 | 6) 0.238 us | tty_ldisc_deref();
3251.108214 | 6) ! 411.672 us | }
3251.108260 | 0) 3.102 us | tty_ldisc_deref();
3251.108263 | 0) @ 166956.2 us | }
3251.108270 | 0) 0.465 us | tty_audit_exit();
3251.109013 | 11) 2.680 us | tty_kref_put();
3251.109059 | 11) | tty_ioctl() {
3251.109060 | 11) | tty_jobctrl_ioctl() {
3251.109060 | 11) 0.622 us | __tty_check_change();
3251.109062 | 11) 2.450 us | }
3251.109063 | 11) 4.003 us | }
3251.109064 | 11) | tty_ioctl() {
3251.109064 | 11) 0.225 us | tty_jobctrl_ioctl();
3251.109065 | 11) 1.550 us | uart_ioctl();
3251.109067 | 11) 0.554 us | tty_ldisc_ref_wait();
3251.109069 | 11) | tty_mode_ioctl() {
3251.109069 | 11) | tty_check_change() {
3251.109070 | 11) 0.282 us | __tty_check_change();
3251.109070 | 11) 0.662 us | }
3251.109071 | 11) 0.477 us | tty_termios_input_baud_rate();
3251.109071 | 11) 0.214 us | tty_termios_baud_rate();
3251.109072 | 11) 0.483 us | uart_chars_in_buffer();
3251.109073 | 11) 0.247 us | uart_chars_in_buffer();
------------------------------------------
11) sh-7708 => kworker-90
------------------------------------------
3251.686493 | 11) | serial8250_start_tx() {
3251.686496 | 11) | serial8250_tx_dma() {
3251.686500 | 11) | /* serial8250_tx_dma: tx_running => 1 */
3251.686501 | 11) 4.696 us | }
3251.686501 | 11) + 12.203 us | }
3252.311575 | 11) | serial8250_start_tx() {
3252.311579 | 11) | serial8250_tx_dma() {
3252.311582 | 11) | /* serial8250_tx_dma: tx_running => 1 */
3252.311583 | 11) 4.020 us | }
3252.311583 | 11) + 10.556 us | }
3252.936657 | 11) | serial8250_start_tx() {
3252.936661 | 11) | serial8250_tx_dma() {
3252.936664 | 11) | /* serial8250_tx_dma: tx_running => 1 */
3252.936665 | 11) 3.989 us | }
3252.936665 | 11) + 10.880 us | }
Thanks,
Raul
^ permalink raw reply related
* Re: [PATCH] tty: synclink_gt: remove broken driver
From: Ethan Nelson-Moore @ 2026-01-30 4:46 UTC (permalink / raw)
To: Jiri Slaby
Cc: linux-serial, linux-doc, netdev, linux-api, Jonathan Corbet,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Greg Kroah-Hartman,
Haren Myneni, Bagas Sanjaya, Simon Horman, Eric Biggers
In-Reply-To: <24935907-76b8-4369-a221-f408c9747642@kernel.org>
Hi, Jiri,
Thanks for your feedback.
On Thu, Jan 29, 2026 at 3:41 AM Jiri Slaby <jirislaby@kernel.org> wrote:
> Have you checked this is not included in any relevant userspace? How?
> Hints: debian code search, github...
The only references in Debian Code Search outside the kernel are in
libexplain (which has a configure test for the presence of this header
and should be fine), lists of files, and lists of ioctls, e.g. in
strace, which do not include the header itself.
The only reference of note on GitHub (although I can't look past the
5th page of results) is in
https://github.com/sunfishcode/linux-raw-sys, which includes every
Linux header as part of its binding generation process, and has
already had to drop other headers as they were removed:
https://github.com/sunfishcode/linux-raw-sys/commit/a804ac01491f63c8ce879ef27254d27dfcf89ff2
The package ships a generated version of the bindings, so the header
is not needed by normal users.
If this commit is merged, I will send a pull request to remove
<linux/synclink.h> from the code.
It was also used in old versions of
https://github.com/jerome-pouiller/ioctl but recent versions
automatically generate the list of ioctls on every build.
Is this okay with you, or should I send a new version of the patch
with <linux/synclink.h> retained?
> I would just drop the line, removing one conflicting entry. The letter
> is not going to be dead.
>
> Or is this Dead note some ioctl-number's policy?
It was used in quite a few other entries, so I just followed their example.
> This paragraph actually talks about long removed synclink.c, removed in:
> a1f714b44e34 tty: Remove redundant synclink driver
Good to know.
Ethan
^ permalink raw reply
* [PATCH] tty: hvc_iucv: fix off-by-one in number of supported devices
From: Randy Dunlap @ 2026-01-30 7:29 UTC (permalink / raw)
To: linux-kernel
Cc: Randy Dunlap, Ahelenia Ziemiańska, Hendrik Brueckner,
linuxppc-dev, Greg Kroah-Hartman, Jiri Slaby, linux-serial,
Andrew Morton, Borislav Petkov (AMD)
MAX_HVC_IUCV_LINES == HVC_ALLOC_TTY_ADAPTERS == 8.
This is the number of entries in:
static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES];
Sometimes hvc_iucv_table[] is limited by:
(a) if (num > hvc_iucv_devices) // for error detection
or
(b) for (i = 0; i < hvc_iucv_devices; i++) // in 2 places
(so these 2 don't agree; second one appears to be correct to me.)
hvc_iucv_devices can be 0..8. This is a counter.
(c) if (hvc_iucv_devices > MAX_HVC_IUCV_LINES)
If hvc_iucv_devices == 8, (a) allows the code to access hvc_iucv_table[8].
Oops.
Fixes: 44a01d5ba8a4 ("[S390] s390/hvc_console: z/VM IUCV hypervisor console support")
Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
---
No, I haven't seen an issue with this out in the wild.
Cc: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
Cc: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jirislaby@kernel.org>
Cc: linux-serial@vger.kernel.org
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: "Borislav Petkov (AMD)" <bp@alien8.de>
drivers/tty/hvc/hvc_iucv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- linux-next-20260128.orig/drivers/tty/hvc/hvc_iucv.c
+++ linux-next-20260128/drivers/tty/hvc/hvc_iucv.c
@@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_hand
*/
static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
{
- if (num > hvc_iucv_devices)
+ if (num >= hvc_iucv_devices)
return NULL;
return hvc_iucv_table[num];
}
^ permalink raw reply
* Re: [PATCH v2 7/7] serial: 8250_dw: Ensure BUSY is deasserted
From: Ilpo Järvinen @ 2026-01-30 12:44 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Greg Kroah-Hartman, Jiri Slaby, linux-serial, qianfan Zhao,
Adriana Nicolae, Tim Kryger, Matt Porter, Heikki Krogerus,
Markus Mayer, Jamie Iles, LKML, Bandal, Shankar, Murthy, Shanth,
stable
In-Reply-To: <aXouStgDF635dYya@smile.fi.intel.com>
[-- Attachment #1: Type: text/plain, Size: 4083 bytes --]
On Wed, 28 Jan 2026, Andy Shevchenko wrote:
> On Wed, Jan 28, 2026 at 12:53:01PM +0200, Ilpo Järvinen wrote:
> > 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 <adriana@arista.com>,
> > 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.
>
> Some nit-picks below, otherwise seems good to go
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> ...
>
> > Reported-by: qianfan Zhao <qianfanguijin@163.com>
> > Link: https://lore.kernel.org/linux-serial/289bb78a-7509-1c5c-2923-a04ed3b6487d@163.com/
> > Reported-by: Adriana Nicolae <adriana@arista.com>
> > Link: https://lore.kernel.org/linux-serial/20250819182322.3451959-1-adriana@arista.com/
>
> Shouldn't these Link:s be Closes: tags?
To not possibly give wrong signals, until they confirm their cases are
indeed solved by this patch, I'd like to keep these as Link tag only.
> > + struct dw8250_data *d = to_dw8250_data(p->private_data);
> > struct uart_8250_port *up = up_to_u8250p(p);
> > + unsigned int usr_reg = DW_UART_USR;
> > + int retries;
> > + u32 lsr;
>
>
> > + if (d->pdata)
> > + usr_reg = d->pdata->usr_reg;
>
> I would unite this with definition above:
>
> unsigned int usr_reg = d->pdata ? d->pdata->usr_reg : DW_UART_USR;
>
> > + lsr = serial_lsr_in(up);
>
> > + if (lsr & UART_LSR_DR) {
> > + serial_port_in(p, UART_RX);
> > + up->lsr_saved_flags = 0;
> > }
>
> This seems repeating a top of serial8250_read_char(). Perhaps we can do it
> in a helper at some point?
I don't see enough similarity as I'd need to deal with lsr_saved_flags
somehow still here.
> > + 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);
> > + */
>
> Does it make sense to print an error here (assuming it will work with nbcon)?
> If so, maybe leave it at the end of the function, after dw8250_idle_exit()
> and goto there?
I think the print would be useful. I'll leave the FIXME+commented out
print into the end of the function in v3.
I also realized that on error, dw8250_idle_enter() should undo what it
changed, that is, call dw8250_idle_exit() within which will simplify
caller-side error handling slightly.
--
i.
^ permalink raw reply
* [PATCH v3 0/7] 8250 DW UART fixes when under constant Rx pressure
From: Ilpo Järvinen @ 2026-01-30 13:28 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andy Shevchenko,
qianfan Zhao, Adriana Nicolae
Cc: linux-kernel, Bandal, Shankar, Murthy, Shanth, Ilpo Järvinen
Hi all,
Here are fixes to 8250 DW UART conditions that mostly occur in scenarios
under constant Rx pressure which are made complicated by BUSY handling
of DW UARTs (used when !uart_16550_compatible).
A few of the changes touch also 8250_port but it's mostly moving existing
code around (except for the extra synchronize_irq() in shutdown).
Pending cleanups (to be sent separately):
- 8250_dw: UART_IIR_RX_TIMEOUT move to switch/case
- 8250: include sorting
- 8250: iir types to u8
v3:
- Rollback dw8250_idle_enter() failures within
- usr_reg = ... ? ... : ...;
- Leave LCR write fail dev_err() where it was (commented out)
v2:
- Added Fixes tags pointing DW & INTC10EE introducing commits
- Added Cc stable to prerequisite patches
- Separate adding serial8250_handle_irq_locked() to own patch
- Put new exports to SERIAL_8250 namespace (eventually all 8250
exports should move there, but out-of-scope for this series)
- Changes to no_int_count
- Change type to u8
- Use modulo in increment, add a define for it
- Perform kick only on 4th NO_INT
- Use serial_port_in/out() throughout the series
- Add FIXME comments to ndelay(frame_time) about very low baud rates
- Add cleanup.h
- Tweak lockdep.h place among misordered includes
- Wording tweaks to changelogs and comments
Ilpo Järvinen (7):
serial: 8250: Protect LCR write in shutdown
serial: 8250_dw: Avoid unnecessary LCR writes
serial: 8250: Add serial8250_handle_irq_locked()
serial: 8250_dw: Rework dw8250_handle_irq() locking and IIR handling
serial: 8250_dw: Rework IIR_NO_INT handling to stop interrupt storm
serial: 8250: Add late synchronize_irq() to shutdown to handle DW UART
BUSY
serial: 8250_dw: Ensure BUSY is deasserted
drivers/tty/serial/8250/8250.h | 25 +++
drivers/tty/serial/8250/8250_dw.c | 295 ++++++++++++++++++++++------
drivers/tty/serial/8250/8250_port.c | 69 ++++---
include/linux/serial_8250.h | 1 +
4 files changed, 303 insertions(+), 87 deletions(-)
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
--
2.39.5
^ permalink raw reply
* [PATCH v3 1/7] serial: 8250: Protect LCR write in shutdown
From: Ilpo Järvinen @ 2026-01-30 13:28 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andy Shevchenko,
qianfan Zhao, Adriana Nicolae, linux-kernel
Cc: Bandal, Shankar, Murthy, Shanth, Ilpo Järvinen, stable
In-Reply-To: <20260130132857.13124-1-ilpo.jarvinen@linux.intel.com>
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.
Reported-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Cc: stable@vger.kernel.org
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
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 = up_to_u8250p(port);
+ u32 lcr;
serial8250_rpm_get(up);
/*
@@ -2376,13 +2377,13 @@ void serial8250_do_shutdown(struct uart_port *port)
port->mctrl &= ~TIOCM_OUT2;
serial8250_set_mctrl(port, port->mctrl);
+
+ /* Disable break condition */
+ lcr = serial_port_in(port, UART_LCR);
+ lcr &= ~UART_LCR_SBC;
+ serial_port_out(port, UART_LCR, lcr);
}
- /*
- * Disable break condition and FIFOs
- */
- serial_port_out(port, UART_LCR,
- serial_port_in(port, UART_LCR) & ~UART_LCR_SBC);
serial8250_clear_fifos(up);
rsa_disable(up);
--
2.39.5
^ permalink raw reply related
* [PATCH v3 2/7] serial: 8250_dw: Avoid unnecessary LCR writes
From: Ilpo Järvinen @ 2026-01-30 13:28 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andy Shevchenko,
qianfan Zhao, Adriana Nicolae, Ilpo Järvinen, linux-kernel
Cc: Bandal, Shankar, Murthy, Shanth, stable
In-Reply-To: <20260130132857.13124-1-ilpo.jarvinen@linux.intel.com>
When DW UART is configured with BUSY flag, LCR writes may not always
succeed which can make any LCR write complex and very expensive.
Performing write directly can trigger IRQ and the driver has to perform
complex and distruptive sequence while retrying the write.
Therefore, it's better to avoid doing LCR write that would not change
the value of the LCR register. Add LCR write avoidance code into the
8250_dw driver's .serial_out() functions.
Reported-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Cc: stable@vger.kernel.org
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/tty/serial/8250/8250_dw.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 27af83f0ff46..7500b1ff1ac1 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -181,6 +181,22 @@ static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value
*/
}
+/*
+ * With BUSY, LCR writes can be very expensive (IRQ + complex retry logic).
+ * If the write does not change the value of the LCR register, skip it entirely.
+ */
+static bool dw8250_can_skip_reg_write(struct uart_port *p, unsigned int offset, u32 value)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ u32 lcr;
+
+ if (offset != UART_LCR || d->uart_16550_compatible)
+ return false;
+
+ lcr = serial_port_in(p, offset);
+ return lcr == value;
+}
+
/* Returns once the transmitter is empty or we run out of retries */
static void dw8250_tx_wait_empty(struct uart_port *p)
{
@@ -207,12 +223,18 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
static void dw8250_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
writeb(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
static void dw8250_serial_out38x(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
/* Allow the TX to drain before we reconfigure */
if (offset == UART_LCR)
dw8250_tx_wait_empty(p);
@@ -237,6 +259,9 @@ static u32 dw8250_serial_inq(struct uart_port *p, unsigned int offset)
static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
@@ -248,6 +273,9 @@ static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 val
static void dw8250_serial_out32(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
writel(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
@@ -261,6 +289,9 @@ static u32 dw8250_serial_in32(struct uart_port *p, unsigned int offset)
static void dw8250_serial_out32be(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
iowrite32be(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
--
2.39.5
^ permalink raw reply related
* [PATCH v3 3/7] serial: 8250: Add serial8250_handle_irq_locked()
From: Ilpo Järvinen @ 2026-01-30 13:28 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andy Shevchenko,
qianfan Zhao, Adriana Nicolae, linux-kernel
Cc: Bandal, Shankar, Murthy, Shanth, Ilpo Järvinen, stable
In-Reply-To: <20260130132857.13124-1-ilpo.jarvinen@linux.intel.com>
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" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Cc: stable@vger.kernel.org
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
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 <linux/irq.h>
#include <linux/console.h>
#include <linux/gpio/consumer.h>
+#include <linux/lockdep.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -1782,20 +1783,16 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
}
/*
- * 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 = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
bool skip_rx = false;
- unsigned long flags;
u16 status;
- if (iir & UART_IIR_NO_INT)
- return 0;
-
- uart_port_lock_irqsave(port, &flags);
+ lockdep_assert_held_once(&port->lock);
status = serial_lsr_in(up);
@@ -1828,8 +1825,19 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
else if (!up->dma->tx_running)
__stop_tx(up);
}
+}
+EXPORT_SYMBOL_NS_GPL(serial8250_handle_irq_locked, "SERIAL_8250");
- 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);
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, unsigned 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);
--
2.39.5
^ permalink raw reply related
* [PATCH v3 4/7] serial: 8250_dw: Rework dw8250_handle_irq() locking and IIR handling
From: Ilpo Järvinen @ 2026-01-30 13:28 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andy Shevchenko,
qianfan Zhao, Adriana Nicolae, Ilpo Järvinen, linux-kernel
Cc: Bandal, Shankar, Murthy, Shanth, stable
In-Reply-To: <20260130132857.13124-1-ilpo.jarvinen@linux.intel.com>
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 ==) 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" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Cc: stable@vger.kernel.org
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
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/8250_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 <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -40,6 +43,8 @@
#define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */
/* DesignWare specific register fields */
+#define DW_UART_IIR_IID GENMASK(3, 0)
+
#define DW_UART_MCR_SIRE BIT(6)
/* Renesas specific register fields */
@@ -312,7 +317,19 @@ static int dw8250_handle_irq(struct uart_port *p)
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
unsigned int quirks = 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);
/*
* 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 = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
serial_port_in(p, UART_RX);
-
- uart_port_unlock_irqrestore(p, flags);
}
/* 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 = serial_lsr_in(up);
- uart_port_unlock_irqrestore(p, flags);
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)
}
}
- if (serial8250_handle_irq(p, iir))
- return 1;
-
- if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
- /* Clear the USR */
- serial_port_in(p, d->pdata->usr_reg);
+ serial8250_handle_irq_locked(p, iir);
- return 1;
- }
-
- return 0;
+ return 1;
}
static void dw8250_clk_work_cb(struct work_struct *work)
@@ -858,6 +862,7 @@ static struct platform_driver dw8250_platform_driver = {
module_platform_driver(dw8250_platform_driver);
+MODULE_IMPORT_NS("SERIAL_8250");
MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
--
2.39.5
^ permalink raw reply related
* [PATCH v3 5/7] serial: 8250_dw: Rework IIR_NO_INT handling to stop interrupt storm
From: Ilpo Järvinen @ 2026-01-30 13:28 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andy Shevchenko,
qianfan Zhao, Adriana Nicolae, Ilpo Järvinen, linux-kernel
Cc: Bandal, Shankar, Murthy, Shanth, stable
In-Reply-To: <20260130132857.13124-1-ilpo.jarvinen@linux.intel.com>
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=0, 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 UART")
Cc: stable@vger.kernel.org
Reported-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
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/8250_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 interrupt
+ * storm prevention code.
+ */
+#define DW_UART_QUIRK_IER_KICK_THRES 4
struct dw8250_platform_data {
u8 usr_reg;
@@ -82,6 +89,8 @@ struct dw8250_data {
unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
+
+ u8 no_int_count;
};
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, unsigned int offset)
return dw8250_modify_msr(p, offset, value);
}
+/*
+ * INTC10EE UART can IRQ storm while reporting IIR_NO_INT. Inducing IIR value
+ * change has been observed to break the storm.
+ *
+ * If Tx is empty (THRE asserted), we use here IER_THRI to cause IIR_NO_INT ->
+ * IIR_THRI transition.
+ */
+static void dw8250_quirk_ier_kick(struct uart_port *p)
+{
+ struct uart_8250_port *up = up_to_u8250p(p);
+ u32 lsr;
+
+ if (up->ier & UART_IER_THRI)
+ return;
+
+ lsr = 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);
+}
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 = d->pdata->quirks;
unsigned int status;
+ 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 == (DW_UART_QUIRK_IER_KICK_THRES - 1))
+ dw8250_quirk_ier_kick(p);
+ d->no_int_count = (d->no_int_count + 1) % DW_UART_QUIRK_IER_KICK_THRES;
+
return 0;
case UART_IIR_BUSY:
/* Clear the USR */
serial_port_in(p, d->pdata->usr_reg);
+ d->no_int_count = 0;
+
return 1;
}
- guard(uart_port_lock_irqsave)(p);
+ d->no_int_count = 0;
/*
* 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);
}
+static void dw8250_shutdown(struct uart_port *port)
+{
+ struct dw8250_data *d = to_dw8250_data(port->private_data);
+
+ serial8250_do_shutdown(port);
+ d->no_int_count = 0;
+}
+
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {}, *up = &uart;
@@ -685,10 +737,12 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
- if (data->uart_16550_compatible)
+ if (data->uart_16550_compatible) {
p->handle_irq = NULL;
- else if (data->pdata)
+ } else if (data->pdata) {
p->handle_irq = dw8250_handle_irq;
+ p->shutdown = dw8250_shutdown;
+ }
dw8250_setup_dma_filter(p, data);
@@ -815,6 +869,11 @@ static const struct dw8250_platform_data dw8250_skip_set_rate_data = {
.quirks = DW_UART_QUIRK_SKIP_SET_RATE,
};
+static const struct dw8250_platform_data dw8250_intc10ee = {
+ .usr_reg = DW_UART_USR,
+ .quirks = DW_UART_QUIRK_IER_KICK,
+};
+
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
@@ -844,7 +903,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "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);
--
2.39.5
^ permalink raw reply related
* [PATCH v3 6/7] serial: 8250: Add late synchronize_irq() to shutdown to handle DW UART BUSY
From: Ilpo Järvinen @ 2026-01-30 13:28 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andy Shevchenko,
qianfan Zhao, Adriana Nicolae, Jamie Iles, linux-kernel
Cc: Bandal, Shankar, Murthy, Shanth, Ilpo Järvinen, stable
In-Reply-To: <20260130132857.13124-1-ilpo.jarvinen@linux.intel.com>
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" <shankar.bandal@intel.com>
Tested-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
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);
up->ops->release_irq(up);
--
2.39.5
^ permalink raw reply related
* [PATCH v3 7/7] serial: 8250_dw: Ensure BUSY is deasserted
From: Ilpo Järvinen @ 2026-01-30 13:28 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Andy Shevchenko,
qianfan Zhao, Adriana Nicolae, Ilpo Järvinen, Tim Kryger,
Matt Porter, Heikki Krogerus, Markus Mayer, Jamie Iles,
linux-kernel
Cc: Bandal, Shankar, Murthy, Shanth, stable
In-Reply-To: <20260130132857.13124-1-ilpo.jarvinen@linux.intel.com>
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 <adriana@arista.com>,
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: <stable@vger.kernel.org>
Reported-by: qianfan Zhao <qianfanguijin@163.com>
Link: https://lore.kernel.org/linux-serial/289bb78a-7509-1c5c-2923-a04ed3b6487d@163.com/
Reported-by: Adriana Nicolae <adriana@arista.com>
Link: https://lore.kernel.org/linux-serial/20250819182322.3451959-1-adriana@arista.com/
Reported-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Bandal, Shankar" <shankar.bandal@intel.com>
Tested-by: "Murthy, Shanth" <shanth.murthy@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
---
drivers/tty/serial/8250/8250.h | 25 +++++
drivers/tty/serial/8250/8250_dw.c | 162 ++++++++++++++++++++--------
drivers/tty/serial/8250/8250_port.c | 28 ++---
3 files changed, 160 insertions(+), 55 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(struct uart_8250_port *up,
return value;
}
+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);
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 uart_8250_port *p)
return dma && dma->tx_running;
}
+
+static inline void serial8250_tx_dma_pause(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = 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 = 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 uart_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
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/8250_dw.c
index edae359b1c3f..422e93ce8fa5 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/lockdep.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
@@ -47,6 +48,8 @@
#define DW_UART_MCR_SIRE BIT(6)
+#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 {
unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
+ unsigned int in_idle:1;
u8 no_int_count;
};
@@ -121,74 +125,146 @@ static inline u32 dw8250_modify_msr(struct uart_port *p, unsigned int offset, u3
return value;
}
+static void dw8250_idle_exit(struct uart_port *p)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = 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 = 0;
+}
+
/*
- * 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 = to_dw8250_data(p->private_data);
+ unsigned int usr_reg = d->pdata ? d->pdata->usr_reg : DW_UART_USR;
struct uart_8250_port *up = up_to_u8250p(p);
- unsigned int lsr;
+ int retries;
+ u32 lsr;
- /*
- * 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;
+
+ d->in_idle = 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);
+ }
/*
- * 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 = 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 = 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 = serial_lsr_in(up);
+ if (lsr & UART_LSR_DR) {
+ serial_port_in(p, UART_RX);
+ up->lsr_saved_flags = 0;
}
- 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) {
+ dw8250_idle_exit(p);
+ return -EBUSY;
+ }
+
+ return 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 = up_to_u8250p(p);
+ int ret;
+
+ ret = dw8250_idle_enter(p);
+ if (ret < 0)
+ return;
+
+ 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);
}
/*
* 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 = to_dw8250_data(p->private_data);
- void __iomem *addr = p->membase + (offset << p->regshift);
- int tries = 1000;
+ u32 lcr;
+ int ret;
if (offset != UART_LCR || d->uart_16550_compatible)
return;
+ lcr = serial_port_in(p, UART_LCR);
+
/* Make sure LCR write wasn't ignored */
- while (tries--) {
- u32 lcr = serial_port_in(p, offset);
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
+ if (d->in_idle)
+ goto write_err;
- dw8250_force_idle(p);
+ ret = dw8250_idle_enter(p);
+ if (ret < 0)
+ goto write_err;
-#ifdef CONFIG_64BIT
- if (p->type == PORT_OCTEON)
- __raw_writeq(value & 0xff, addr);
- else
-#endif
- if (p->iotype == UPIO_MEM32)
- writel(value, addr);
- else if (p->iotype == UPIO_MEM32BE)
- iowrite32be(value, addr);
- else
- writeb(value, addr);
- }
+ serial_port_out(p, UART_LCR, value);
+ dw8250_idle_exit(p);
+ return;
+
+write_err:
/*
* FIXME: this deadlocks if port->lock is already held
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
@@ -632,8 +708,10 @@ static int dw8250_probe(struct platform_device *pdev)
p->type = PORT_8250;
p->flags = UPF_FIXED_PORT;
p->dev = dev;
+
p->set_ldisc = dw8250_set_ldisc;
p->set_termios = dw8250_set_termios;
+ p->set_divisor = dw8250_set_divisor;
data = 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, int 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_port *p)
serial_out(p, UART_FCR, 0);
}
}
+EXPORT_SYMBOL_NS_GPL(serial8250_clear_fifos, "SERIAL_8250");
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *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);
+void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 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
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
@@ -3241,16 +3253,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
}
-static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
-{
- unsigned int i;
-
- for (i = 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,
while (s != 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);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\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);
}
/*
--
2.39.5
^ permalink raw reply related
* Re: [PATCH v2 00/16] MIPS: move pic32.h header file from asm to platform_data
From: Thomas Bogendoerfer @ 2026-01-30 14:37 UTC (permalink / raw)
To: Brian Masney
Cc: Claudiu Beznea, linux-mips, linux-kernel, Michael Turquette,
Stephen Boyd, linux-clk, Thomas Gleixner, Adrian Hunter,
Ulf Hansson, linux-mmc, Linus Walleij, linux-gpio,
Alexandre Belloni, linux-rtc, Greg Kroah-Hartman, Jiri Slaby,
linux-serial, Guenter Roeck, Wim Van Sebroeck, linux-watchdog
In-Reply-To: <20260112-mips-pic32-header-move-v2-0-927d516b1ff9@redhat.com>
On Mon, Jan 12, 2026 at 05:47:54PM -0500, Brian Masney wrote:
> There are currently some pic32 MIPS drivers that are in tree, and are
> only configured to be compiled on the MIPS pic32 platform. There's a
> risk of breaking some of these drivers when migrating drivers away from
> legacy APIs. It happened to me with a pic32 clk driver.
>
> Let's go ahead and move the pic32.h from the asm to the platform_data
> include directory in the tree. This will make it easier, and cleaner to
> enable COMPILE_TEST for some of these pic32 drivers. To do this requires
> updating some includes, which I do at the beginning of this series.
>
> This series was compile tested on a centos-stream-10 arm64 host in two
> different configurations:
>
> - native arm64 build with COMPILE_TEST (via make allmodconfig)
> - MIPS cross compile on arm64 with:
> ARCH=mips CROSS_COMPILE=mips64-linux-gnu- make pic32mzda_defconfig
>
> Note that there is a separate MIPS compile error in linux-next, and I
> reported it at https://lore.kernel.org/all/aWVs2gVB418WiMVa@redhat.com/
>
> I included a patch at the end that shows enabling COMPILE_TEST for a
> pic32 clk driver.
>
> Merge Strategy
> ==============
> - Patches 1-15 can go through the MIPS tree.
> - Patch 16 I can repost to Claudiu after patches 1-15 are in Linus's
> tree after the next merge window. There is a separate patch set that
> fixes a compiler error I unintentionally introduced via the clk tree.
> https://lore.kernel.org/linux-clk/CABx5tq+eOocJ41X-GSgkGy6S+s+Am1yCS099wqP695NtwALTmg@mail.gmail.com/T/
>
> Signed-off-by: Brian Masney <bmasney@redhat.com>
> ---
> Changes in v2:
> - Fix native MIPS build by updating include files
> - Link to v1: https://lore.kernel.org/r/20260109-mips-pic32-header-move-v1-0-99859c55783d@redhat.com
>
> ---
> Brian Masney (16):
> MIPS: pic32: include linux/io.h header on several files
> MIPS: pic32: include linux/types.h on pic32.h
> MIPS: pic32: drop unused include linux/io.h from pic32.h
> MIPS: copy pic32.h header file from asm/mach-pic32/ to include/platform-data/
> MAINTAINERS: add include/linux/platform_data/pic32.h to MIPS entry
> MIPS: update include to use pic32.h from platform_data
> clk: microchip: core: update include to use pic32.h from platform_data
> irqchip/irq-pic32-evic: update include to use pic32.h from platform_data
> mmc: sdhci-pic32: update include to use pic32.h from platform_data
> pinctrl: pic32: update include to use pic32.h from platform_data
> rtc: pic32: update include to use pic32.h from platform_data
> serial: pic32_uart: update include to use pic32.h from platform_data
> watchdog: pic32-dmt: update include to use pic32.h from platform_data
> watchdog: pic32-wdt: update include to use pic32.h from platform_data
> MIPS: drop unused pic32.h header
> clk: microchip: core: allow driver to be compiled with COMPILE_TEST
>
> MAINTAINERS | 1 +
> arch/mips/pic32/common/reset.c | 3 ++-
> arch/mips/pic32/pic32mzda/config.c | 3 +--
> arch/mips/pic32/pic32mzda/early_clk.c | 3 ++-
> arch/mips/pic32/pic32mzda/early_console.c | 3 ++-
> drivers/clk/microchip/Kconfig | 2 +-
> drivers/clk/microchip/clk-core.c | 6 +++++-
> drivers/irqchip/irq-pic32-evic.c | 2 +-
> drivers/mmc/host/sdhci-pic32.c | 2 +-
> drivers/pinctrl/pinctrl-pic32.c | 3 +--
> drivers/rtc/rtc-pic32.c | 3 +--
> drivers/tty/serial/pic32_uart.c | 3 +--
> drivers/watchdog/pic32-dmt.c | 3 +--
> drivers/watchdog/pic32-wdt.c | 3 +--
> .../mach-pic32 => include/linux/platform_data}/pic32.h | 17 ++++++++++-------
> 15 files changed, 31 insertions(+), 26 deletions(-)
> ---
> base-commit: f417b7ffcbef7d76b0d8860518f50dae0e7e5eda
> change-id: 20260109-mips-pic32-header-move-6ac9965aa70a
series applied to mips-next
Thomas.
--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]
^ permalink raw reply
* Re: [PATCH 01/19] printk/nbcon: Use an enum to specify the required callback in console_is_usable()
From: John Ogness @ 2026-01-30 15:31 UTC (permalink / raw)
To: Petr Mladek, Marcos Paulo de Souza
Cc: Richard Weinberger, Anton Ivanov, Johannes Berg,
Greg Kroah-Hartman, Jason Wessel, Daniel Thompson,
Douglas Anderson, Steven Rostedt, Sergey Senozhatsky, Jiri Slaby,
Breno Leitao, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Geert Uytterhoeven, Kees Cook,
Tony Luck, Guilherme G. Piccoli, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Andreas Larsson, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Jacky Huang, Shan-Chun Hung, Laurentiu Tudor,
linux-um, linux-kernel, kgdb-bugreport, linux-serial, netdev,
linux-m68k, linux-hardening, linuxppc-dev, sparclinux,
linux-stm32, linux-arm-kernel, linux-fsdevel
In-Reply-To: <aWZyEHsOJFLRLRKT@pathway.suse.cz>
On 2026-01-13, Petr Mladek <pmladek@suse.com> wrote:
> On Sat 2025-12-27 09:16:08, Marcos Paulo de Souza wrote:
>> The current usage of console_is_usable() is clumsy. The parameter
>> @use_atomic is boolean and thus not self-explanatory. The function is
>> called twice in situations when there are no-strict requirements.
>>
>> Replace it with enum nbcon_write_cb which provides a more descriptive
>> values for all 3 situations: atomic, thread or any.
>>
>> Note that console_is_usable() checks only NBCON_USE_ATOMIC because
>> .write_thread() callback is mandatory. But the other two values still
>> make sense because they describe the intention of the caller.
>>
>> --- a/include/linux/console.h
>> +++ b/include/linux/console.h
>> @@ -202,6 +202,19 @@ enum cons_flags {
>> CON_NBCON_ATOMIC_UNSAFE = BIT(9),
>> };
>>
>> +/**
>> + * enum nbcon_write_cb - Defines which nbcon write() callback must be used based
>> + * on the caller context.
>> + * @NBCON_USE_ATOMIC: Use con->write_atomic().
>> + * @NBCON_USE_THREAD: Use con->write_thread().
>> + * @NBCON_USE_ANY: The caller does not have any strict requirements.
>> + */
>> +enum nbcon_write_cb {
>> + NBCON_USE_ATOMIC,
>> + NBCON_USE_THREAD,
>> + NBCON_USE_ANY,
>
> AFAIK, this would define NBCON_USE_ATOMIC as zero. See below.
Yes, although the start value is not guaranteed. And anyway if is to be
used as bits, it should be explicitly set so (such as with enum
cons_flags).
But in reality, we only care about NBCON_USE_ATOMIC and
!NBCON_USE_ATOMIC, so I agree with your comments below about keeping it
a simple enum and not caring about the numerical value.
>> @@ -631,7 +645,7 @@ static inline bool console_is_usable(struct console *con, short flags, bool use_
>> return false;
>>
>> if (flags & CON_NBCON) {
>> - if (use_atomic) {
>> + if (nwc & NBCON_USE_ATOMIC) {
>
> Let's keep it defined by as zero and use here:
>
> if (nwc == NBCON_USE_ATOMIC) {
>
> Note that we do _not_ want to return "false" for "NBCON_USE_ANY"
> when con->write_atomic does not exist.
I agree.
If changed to "nwc == NBCON_USE_ATOMIC":
Reviewed-by: John Ogness <john.ogness@linutronix.de>
^ permalink raw reply
* Re: [PATCH 02/19] printk: Introduce console_is_nbcon
From: John Ogness @ 2026-01-30 15:50 UTC (permalink / raw)
To: Marcos Paulo de Souza, Richard Weinberger, Anton Ivanov,
Johannes Berg, Greg Kroah-Hartman, Jason Wessel, Daniel Thompson,
Douglas Anderson, Petr Mladek, Steven Rostedt, Sergey Senozhatsky,
Jiri Slaby, Breno Leitao, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Geert Uytterhoeven,
Kees Cook, Tony Luck, Guilherme G. Piccoli, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Andreas Larsson, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Jacky Huang, Shan-Chun Hung, Laurentiu Tudor
Cc: linux-um, linux-kernel, kgdb-bugreport, linux-serial, netdev,
linux-m68k, linux-hardening, linuxppc-dev, sparclinux,
linux-stm32, linux-arm-kernel, linux-fsdevel,
Marcos Paulo de Souza
In-Reply-To: <20251227-printk-cleanup-part3-v1-2-21a291bcf197@suse.com>
On 2025-12-27, Marcos Paulo de Souza <mpdesouza@suse.com> wrote:
> Besides checking if the current console is NBCON or not, console->flags
> is also being read in order to serve as argument of the console_is_usable
> function.
>
> But CON_NBCON flag is unique: it's set just once in the console
> registration and never cleared. In this case it can be possible to read
> the flag when console_srcu_lock is held (which is the case when using
> for_each_console).
>
> This change makes possible to remove the flags argument from
> console_is_usable in the next patches.
Note that console_is_usable() now also checks for the flag
CON_NBCON_ATOMIC_UNSAFE as well.
> diff --git a/include/linux/console.h b/include/linux/console.h
> index 35c03fc4ed51..dd4ec7a5bff9 100644
> --- a/include/linux/console.h
> +++ b/include/linux/console.h
> @@ -561,6 +561,33 @@ static inline void console_srcu_write_flags(struct console *con, short flags)
> WRITE_ONCE(con->flags, flags);
> }
>
> +/**
> + * console_srcu_is_nbcon - Locklessly check whether the console is nbcon
> + * @con: struct console pointer of console to check
> + *
> + * Requires console_srcu_read_lock to be held, which implies that @con might
> + * be a registered console. The purpose of holding console_srcu_read_lock is
> + * to guarantee that no exit/cleanup routines will run if the console
> + * is currently undergoing unregistration.
> + *
> + * If the caller is holding the console_list_lock or it is _certain_ that
> + * @con is not and will not become registered, the caller may read
> + * @con->flags directly instead.
> + *
> + * Context: Any context.
> + * Return: True when CON_NBCON flag is set.
> + */
> +static inline bool console_is_nbcon(const struct console *con)
> +{
> + WARN_ON_ONCE(!console_srcu_read_lock_is_held());
> +
> + /*
> + * The CON_NBCON flag is statically initialized and is never
> + * set or cleared at runtime.
> + */
> + return data_race(con->flags & CON_NBCON);
If this flag is statically initialized and is never set or cleared at
runtime, why is the console_srcu_read_lock required? Why not just:
static inline bool console_is_nbcon(const struct console *con)
{
/*
* The CON_NBCON flag is statically initialized and is never
* set or cleared at runtime.
*/
return data_race(con->flags & CON_NBCON);
}
And even if you do need the console_srcu_read_lock, why copy/paste the
implementation and comments of console_srcu_read_flags()? Just do:
static inline bool console_is_nbcon(const struct console *con)
{
return console_srcu_read_flags(con) & CON_NBCON;
}
John Ogness
^ permalink raw reply
* Re: [PATCH 05/19] printk: Add more context to suspend/resume functions
From: John Ogness @ 2026-01-30 17:27 UTC (permalink / raw)
To: Marcos Paulo de Souza, Richard Weinberger, Anton Ivanov,
Johannes Berg, Greg Kroah-Hartman, Jason Wessel, Daniel Thompson,
Douglas Anderson, Petr Mladek, Steven Rostedt, Sergey Senozhatsky,
Jiri Slaby, Breno Leitao, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Geert Uytterhoeven,
Kees Cook, Tony Luck, Guilherme G. Piccoli, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin, Christophe Leroy,
Andreas Larsson, Alexander Shishkin, Maxime Coquelin,
Alexandre Torgue, Jacky Huang, Shan-Chun Hung, Laurentiu Tudor
Cc: linux-um, linux-kernel, kgdb-bugreport, linux-serial, netdev,
linux-m68k, linux-hardening, linuxppc-dev, sparclinux,
linux-stm32, linux-arm-kernel, linux-fsdevel,
Marcos Paulo de Souza
In-Reply-To: <20251227-printk-cleanup-part3-v1-5-21a291bcf197@suse.com>
On 2025-12-27, Marcos Paulo de Souza <mpdesouza@suse.com> wrote:
> The new comments clarifies from where the functions are supposed to be
> called.
>
> Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
> ---
> kernel/printk/printk.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 173c14e08afe..85a8b6521d9e 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -2734,7 +2734,8 @@ MODULE_PARM_DESC(console_no_auto_verbose, "Disable console loglevel raise to hig
> /**
> * console_suspend_all - suspend the console subsystem
> *
> - * This disables printk() while we go into suspend states
> + * This disables printk() while we go into suspend states. Called by the power
> + * management subsystem.
Since you are touching this comment, I would prefer to make it
technically accurate. It is not printk() that is disabled, it is console
printing that is disabled. Perhaps something like:
* Block all console printing while the system goes into suspend state.
* Called by the power management subsystem.
> */
> void console_suspend_all(void)
> {
> @@ -2766,6 +2767,12 @@ void console_suspend_all(void)
> synchronize_srcu(&console_srcu);
> }
>
> +/**
> + * console_resume_all - resume the console subsystem
> + *
> + * This resumes printk() when the system is being restored. Called by the power
> + * management subsystem.
And something similar here:
* Allow all console printing when the system resumes from suspend. Called by
* the power management system.
> + */
> void console_resume_all(void)
> {
> struct console_flush_type ft;
John Ogness
^ permalink raw reply
* Re: [PATCH v3 7/7] serial: 8250_dw: Ensure BUSY is deasserted
From: kernel test robot @ 2026-01-30 20:59 UTC (permalink / raw)
To: Ilpo Järvinen, Greg Kroah-Hartman, Jiri Slaby, linux-serial,
Andy Shevchenko, qianfan Zhao, Adriana Nicolae, Tim Kryger,
Matt Porter, Heikki Krogerus, Markus Mayer, Jamie Iles,
linux-kernel
Cc: oe-kbuild-all, Bandal, Shankar, Murthy, Shanth, stable
In-Reply-To: <20260130132857.13124-8-ilpo.jarvinen@linux.intel.com>
Hi Ilpo,
kernel test robot noticed the following build errors:
[auto build test ERROR on 8f0b4cce4481fb22653697cced8d0d04027cb1e8]
url: https://github.com/intel-lab-lkp/linux/commits/Ilpo-J-rvinen/serial-8250-Protect-LCR-write-in-shutdown/20260130-213314
base: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
patch link: https://lore.kernel.org/r/20260130132857.13124-8-ilpo.jarvinen%40linux.intel.com
patch subject: [PATCH v3 7/7] serial: 8250_dw: Ensure BUSY is deasserted
config: parisc-randconfig-001-20260131 (https://download.01.org/0day-ci/archive/20260131/202601310404.Rdq0kVXE-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260131/202601310404.Rdq0kVXE-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601310404.Rdq0kVXE-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/tty/serial/8250/8250_dw.c: In function 'dw8250_check_lcr':
>> drivers/tty/serial/8250/8250_dw.c:267:1: error: label at end of compound statement
write_err:
^~~~~~~~~
vim +267 drivers/tty/serial/8250/8250_dw.c
234
235 /*
236 * This function is being called as part of the uart_port::serial_out()
237 * routine. Hence, special care must be taken when serial_port_out() or
238 * serial_out() against the modified registers here, i.e. LCR (d->in_idle is
239 * used to break recursion loop).
240 */
241 static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value)
242 {
243 struct dw8250_data *d = to_dw8250_data(p->private_data);
244 u32 lcr;
245 int ret;
246
247 if (offset != UART_LCR || d->uart_16550_compatible)
248 return;
249
250 lcr = serial_port_in(p, UART_LCR);
251
252 /* Make sure LCR write wasn't ignored */
253 if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
254 return;
255
256 if (d->in_idle)
257 goto write_err;
258
259 ret = dw8250_idle_enter(p);
260 if (ret < 0)
261 goto write_err;
262
263 serial_port_out(p, UART_LCR, value);
264 dw8250_idle_exit(p);
265 return;
266
> 267 write_err:
268 /*
269 * FIXME: this deadlocks if port->lock is already held
270 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
271 */
272 }
273
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: (subset) [PATCH v4 0/6] dt-bindings: goldfish: Convert to DT schema
From: Sebastian Reichel @ 2026-01-30 22:24 UTC (permalink / raw)
To: airlied, simona, maarten.lankhorst, mripard, tzimmermann, robh,
krzk+dt, conor+dt, dmitry.torokhov, sre, gregkh, jirislaby,
lgirdwood, broonie, Kuan-Wei Chiu
Cc: jserv, dri-devel, devicetree, linux-kernel, linux-input, linux-pm,
linux-serial, linux-sound, Yu-Chun Lin
In-Reply-To: <20260113092602.3197681-1-visitorckw@gmail.com>
On Tue, 13 Jan 2026 09:25:56 +0000, Kuan-Wei Chiu wrote:
> Convert the Android Goldfish emulator platform bindings from text
> format to DT schema.
>
> Most of these bindings are currently located in
> Documentation/devicetree/bindings/goldfish/. Move them to the
> appropriate subsystem directories (serial, input, power, sound, misc)
> to align with the kernel directory structure.
>
> [...]
Applied, thanks!
[4/6] dt-bindings: power: supply: google,goldfish-battery: Convert to DT schema
commit: 4c3f02f843999a590f4481791f59a2f9a7f34fe4
Best regards,
--
Sebastian Reichel <sebastian.reichel@collabora.com>
^ permalink raw reply
* Re: [PATCH v5 00/11] Add support for Microchip LAN969x
From: Herbert Xu @ 2026-01-31 2:57 UTC (permalink / raw)
To: Robert Marko
Cc: robh, krzk+dt, conor+dt, nicolas.ferre, alexandre.belloni,
claudiu.beznea, davem, lee, andrew+netdev, edumazet, kuba, pabeni,
Steen.Hegelund, daniel.machon, UNGLinuxDriver, linusw, olivia,
richard.genoud, radu_nicolae.pirea, gregkh, richardcochran,
horatiu.vultur, Ryan.Wanner, tudor.ambarus, kavyasree.kotagiri,
lars.povlsen, devicetree, linux-arm-kernel, linux-kernel,
linux-crypto, netdev, linux-gpio, linux-spi, linux-serial,
luka.perkov
In-Reply-To: <20260115114021.111324-1-robert.marko@sartura.hr>
On Thu, Jan 15, 2026 at 12:37:25PM +0100, Robert Marko wrote:
> This series adds support for the Microchip LAN969x switch SoC family.
>
> Series is a bit long since after discussions in previous versions, it was
> recommended[1][2] to add SoC specific compatibles for device nodes so it
> includes the required bindings updates.
>
> [1] https://lore.kernel.org/all/20251203-splendor-cubbyhole-eda2d6982b46@spud/
> [2] https://lore.kernel.org/all/173412c8-c2fb-4c38-8de7-5b1c2eebdbf9@microchip.com/
> [3] https://lore.kernel.org/all/20251203-duly-leotard-86b83bd840c6@spud/
> [4] https://lore.kernel.org/all/756ead5d-8c9b-480d-8ae5-71667575ab7c@kernel.org/
>
> Signed-off-by: Robert Marko <robert.marko@sartura.hr>
>
> Changes in v5:
> * Picked Acked-by and Reviewed-by tags
> * Change clock header license to match the DTSI one
> * Alphabetize EV23X71A pin nodes
> * Remove the requirment for all ethernet-port nodes to have phys property
> as when RGMII is used there is no SERDES being used
> * Drop phys from RGMII port on EV23X71A
> * Drop USB, DMA, MIIM, SPI and I2C bindings as those were already picked
>
> Changes in v4:
> * Pick Acked-by from Andi for I2C bindings
> * Move clock indexes from dt-bindings into a DTS header as suggested by
> Krzysztof[4]
>
> Changes in v3:
> * Pick Acked-by from Conor
> * Drop HWMON binding as it was picked into hwmon already
> * Document EV23X71A into AT91 binding
> * Drop SparX-5 and AT91 bindings merge
> * Apply remark from Conor on DMA binding regarding merging cases
>
> Changes in v2:
> * Change LAN969x wildcards to LAN9691 in patches
> * Split SoC DTSI and evaluation board patches
> * Add the suggested binding changes required for SoC specific compatibles
> * Merge SparX-5 and AT91 bindings as suggested[3]
>
> Robert Marko (11):
> dt-bindings: mfd: atmel,sama5d2-flexcom: add microchip,lan9691-flexcom
> dt-bindings: serial: atmel,at91-usart: add microchip,lan9691-usart
> dt-bindings: rng: atmel,at91-trng: add microchip,lan9691-trng
> dt-bindings: crypto: atmel,at91sam9g46-aes: add microchip,lan9691-aes
> dt-bindings: crypto: atmel,at91sam9g46-sha: add microchip,lan9691-sha
> dt-bindings: pinctrl: pinctrl-microchip-sgpio: add LAN969x
> arm64: dts: microchip: add LAN969x clock header file
> arm64: dts: microchip: add LAN969x support
> dt-bindings: arm: AT91: document EV23X71A board
> dt-bindings: net: sparx5: do not require phys when RGMII is used
> arm64: dts: microchip: add EV23X71A board
>
> .../devicetree/bindings/arm/atmel-at91.yaml | 6 +
> .../crypto/atmel,at91sam9g46-aes.yaml | 1 +
> .../crypto/atmel,at91sam9g46-sha.yaml | 1 +
> .../bindings/mfd/atmel,sama5d2-flexcom.yaml | 1 +
> .../bindings/net/microchip,sparx5-switch.yaml | 15 +-
> .../pinctrl/microchip,sparx5-sgpio.yaml | 20 +-
> .../bindings/rng/atmel,at91-trng.yaml | 1 +
> .../bindings/serial/atmel,at91-usart.yaml | 1 +
> arch/arm64/boot/dts/microchip/Makefile | 1 +
> arch/arm64/boot/dts/microchip/clk-lan9691.h | 24 +
> arch/arm64/boot/dts/microchip/lan9691.dtsi | 488 +++++++++++
> .../boot/dts/microchip/lan9696-ev23x71a.dts | 756 ++++++++++++++++++
> 12 files changed, 1309 insertions(+), 6 deletions(-)
> create mode 100644 arch/arm64/boot/dts/microchip/clk-lan9691.h
> create mode 100644 arch/arm64/boot/dts/microchip/lan9691.dtsi
> create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
>
> --
> 2.52.0
Patches 4-5 applied. Thanks.
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [syzbot] [serial?] general protection fault in puts_queue
From: syzbot @ 2026-01-31 3:14 UTC (permalink / raw)
To: gregkh, jirislaby, linux-kernel, linux-serial, syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: 615aad0f61e0 Add linux-next specific files for 20260126
git tree: linux-next
console output: https://syzkaller.appspot.com/x/log.txt?x=16d3705a580000
kernel config: https://syzkaller.appspot.com/x/.config?x=750532df2c47a03
dashboard link: https://syzkaller.appspot.com/bug?extid=c3693b491545af43db87
compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=109cb98a580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=179d4ec6580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/6a23e465e877/disk-615aad0f.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/e1ef2e20639b/vmlinux-615aad0f.xz
kernel image: https://storage.googleapis.com/syzbot-assets/e82b02375a3f/bzImage-615aad0f.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+c3693b491545af43db87@syzkaller.appspotmail.com
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000038: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range [0x00000000000001c0-0x00000000000001c7]
CPU: 1 UID: 0 PID: 5996 Comm: udevd Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/13/2026
RIP: 0010:__queue_work+0xa2/0xf90 kernel/workqueue.c:2269
Code: 11 31 ff 89 ee e8 4e f4 37 00 85 ed 0f 85 ef 0c 00 00 e8 01 f0 37 00 4d 8d b7 c0 01 00 00 4c 89 f0 48 c1 e8 03 48 89 44 24 28 <42> 0f b6 04 20 84 c0 0f 85 22 0d 00 00 4c 89 34 24 41 8b 2e 89 ee
RSP: 0018:ffffc90000a07ed8 EFLAGS: 00010002
RAX: 0000000000000038 RBX: 0000000000000008 RCX: ffff88802d660000
RDX: 0000000000000100 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000000 R08: ffff88813fe32017 R09: 1ffff11027fc6402
R10: dffffc0000000000 R11: ffffed1027fc6403 R12: dffffc0000000000
R13: ffff88813fe32010 R14: 00000000000001c0 R15: 0000000000000000
FS: 00007fc71835f880(0000) GS:ffff888125163000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00002000000011f8 CR3: 000000007b69a000 CR4: 00000000003526f0
Call Trace:
<IRQ>
queue_work_on+0x106/0x1d0 kernel/workqueue.c:2405
puts_queue+0xa3/0xe0 drivers/tty/vt/keyboard.c:334
k_fn+0x7c/0xd0 drivers/tty/vt/keyboard.c:763
k_pad+0x79a/0xa90 drivers/tty/vt/keyboard.c:-1
kbd_keycode drivers/tty/vt/keyboard.c:1497 [inline]
kbd_event+0x2ec1/0x40d0 drivers/tty/vt/keyboard.c:1515
input_handle_events_default+0xd4/0x1a0 drivers/input/input.c:2541
input_pass_values+0x288/0x890 drivers/input/input.c:128
input_event_dispose+0x3e5/0x6b0 drivers/input/input.c:353
input_event+0x89/0xe0 drivers/input/input.c:396
hidinput_hid_event+0x1487/0x1e60 drivers/hid/hid-input.c:1747
hid_process_event+0x4be/0x620 drivers/hid/hid-core.c:1565
hid_input_array_field+0x41c/0x5f0 drivers/hid/hid-core.c:1677
hid_process_report drivers/hid/hid-core.c:1719 [inline]
hid_report_raw_event+0xdd7/0x1720 drivers/hid/hid-core.c:2074
__hid_input_report drivers/hid/hid-core.c:2144 [inline]
hid_input_report+0x44b/0x580 drivers/hid/hid-core.c:2166
hid_irq_in+0x47e/0x6d0 drivers/hid/usbhid/hid-core.c:286
__usb_hcd_giveback_urb+0x376/0x540 drivers/usb/core/hcd.c:1657
dummy_timer+0xbbd/0x45d0 drivers/usb/gadget/udc/dummy_hcd.c:1995
__run_hrtimer kernel/time/hrtimer.c:1785 [inline]
__hrtimer_run_queues+0x529/0xc30 kernel/time/hrtimer.c:1849
hrtimer_run_softirq+0x182/0x5a0 kernel/time/hrtimer.c:1866
handle_softirqs+0x22a/0x7c0 kernel/softirq.c:626
do_softirq+0x76/0xd0 kernel/softirq.c:523
</IRQ>
<TASK>
__local_bh_enable_ip+0xf8/0x130 kernel/softirq.c:450
sha256_blocks lib/crypto/x86/sha256.h:37 [inline]
__sha256_update+0xf7/0x150 lib/crypto/sha256.c:208
sha256_update include/crypto/sha2.h:356 [inline]
crypto_sha256_update+0x27/0x40 crypto/sha256.c:145
crypto_shash_update include/crypto/hash.h:1006 [inline]
ima_calc_file_hash_tfm security/integrity/ima/ima_crypto.c:491 [inline]
ima_calc_file_shash security/integrity/ima/ima_crypto.c:511 [inline]
ima_calc_file_hash+0x1300/0x17f0 security/integrity/ima/ima_crypto.c:568
ima_collect_measurement+0x48b/0x930 security/integrity/ima/ima_api.c:294
process_measurement+0x12cd/0x1c80 security/integrity/ima/ima_main.c:407
ima_bprm_check+0x121/0x180 security/integrity/ima/ima_main.c:589
security_bprm_check+0xcd/0x240 security/security.c:794
search_binary_handler fs/exec.c:1654 [inline]
exec_binprm fs/exec.c:1696 [inline]
bprm_execve+0x896/0x1410 fs/exec.c:1748
do_execveat_common+0x50d/0x690 fs/exec.c:1846
__do_sys_execve fs/exec.c:1930 [inline]
__se_sys_execve fs/exec.c:1924 [inline]
__x64_sys_execve+0x97/0xc0 fs/exec.c:1924
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fc717cf2107
Code: 0f 00 64 c7 00 07 00 00 00 b8 ff ff ff ff c9 c3 0f 1f 00 48 8b 05 a9 ee 0f 00 48 8b 10 e9 01 00 00 00 90 b8 3b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d c1 ec 0f 00 f7 d8 64 89 01 48
RSP: 002b:00007ffc10b356d8 EFLAGS: 00000206 ORIG_RAX: 000000000000003b
RAX: ffffffffffffffda RBX: 00005646a103f140 RCX: 00007fc717cf2107
RDX: 00005646a1e9e9c0 RSI: 00007ffc10b357f0 RDI: 00007ffc10b35ff0
RBP: 0000000000000008 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000008 R11: 0000000000000206 R12: 00005646a1e9e9c0
R13: 00007ffc10b357f0 R14: 000000000000000d R15: 0000000000000009
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:__queue_work+0xa2/0xf90 kernel/workqueue.c:2269
Code: 11 31 ff 89 ee e8 4e f4 37 00 85 ed 0f 85 ef 0c 00 00 e8 01 f0 37 00 4d 8d b7 c0 01 00 00 4c 89 f0 48 c1 e8 03 48 89 44 24 28 <42> 0f b6 04 20 84 c0 0f 85 22 0d 00 00 4c 89 34 24 41 8b 2e 89 ee
RSP: 0018:ffffc90000a07ed8 EFLAGS: 00010002
RAX: 0000000000000038 RBX: 0000000000000008 RCX: ffff88802d660000
RDX: 0000000000000100 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000000 R08: ffff88813fe32017 R09: 1ffff11027fc6402
R10: dffffc0000000000 R11: ffffed1027fc6403 R12: dffffc0000000000
R13: ffff88813fe32010 R14: 00000000000001c0 R15: 0000000000000000
FS: 00007fc71835f880(0000) GS:ffff888125163000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00002000000011f8 CR3: 000000007b69a000 CR4: 00000000003526f0
----------------
Code disassembly (best guess), 1 bytes skipped:
0: 31 ff xor %edi,%edi
2: 89 ee mov %ebp,%esi
4: e8 4e f4 37 00 call 0x37f457
9: 85 ed test %ebp,%ebp
b: 0f 85 ef 0c 00 00 jne 0xd00
11: e8 01 f0 37 00 call 0x37f017
16: 4d 8d b7 c0 01 00 00 lea 0x1c0(%r15),%r14
1d: 4c 89 f0 mov %r14,%rax
20: 48 c1 e8 03 shr $0x3,%rax
24: 48 89 44 24 28 mov %rax,0x28(%rsp)
* 29: 42 0f b6 04 20 movzbl (%rax,%r12,1),%eax <-- trapping instruction
2e: 84 c0 test %al,%al
30: 0f 85 22 0d 00 00 jne 0xd58
36: 4c 89 34 24 mov %r14,(%rsp)
3a: 41 8b 2e mov (%r14),%ebp
3d: 89 ee mov %ebp,%esi
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply
* [syzbot] [serial?] general protection fault in k_meta
From: syzbot @ 2026-01-31 14:57 UTC (permalink / raw)
To: gregkh, jirislaby, linux-kernel, linux-serial, syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: 4f938c7d3b25 Add linux-next specific files for 20260127
git tree: linux-next
console output: https://syzkaller.appspot.com/x/log.txt?x=1503b1b2580000
kernel config: https://syzkaller.appspot.com/x/.config?x=d51c584a7396ddf1
dashboard link: https://syzkaller.appspot.com/bug?extid=03f79366754268a0f20c
compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
Unfortunately, I don't have any reproducer for this issue yet.
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/cc0457d4d9f3/disk-4f938c7d.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/c54b095e6488/vmlinux-4f938c7d.xz
kernel image: https://storage.googleapis.com/syzbot-assets/5c734206eb97/bzImage-4f938c7d.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+03f79366754268a0f20c@syzkaller.appspotmail.com
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000038: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range [0x00000000000001c0-0x00000000000001c7]
CPU: 0 UID: 0 PID: 14584 Comm: syz.4.2379 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/13/2026
RIP: 0010:__queue_work+0xa2/0xf90 kernel/workqueue.c:2269
Code: 11 31 ff 89 ee e8 2e f3 37 00 85 ed 0f 85 ef 0c 00 00 e8 e1 ee 37 00 4d 8d b7 c0 01 00 00 4c 89 f0 48 c1 e8 03 48 89 44 24 28 <42> 0f b6 04 20 84 c0 0f 85 22 0d 00 00 4c 89 34 24 41 8b 2e 89 ee
RSP: 0018:ffffc9001ac9f4b8 EFLAGS: 00010002
RAX: 0000000000000038 RBX: 0000000000000008 RCX: 0000000000080000
RDX: ffffc9000c3c2000 RSI: 00000000000007c1 RDI: 00000000000007c2
RBP: 0000000000000000 R08: ffff88813ff72017 R09: 1ffff11027fee402
R10: dffffc0000000000 R11: ffffed1027fee403 R12: dffffc0000000000
R13: ffff88813ff72010 R14: 00000000000001c0 R15: 0000000000000000
FS: 00007fded38f66c0(0000) GS:ffff8881252af000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000020000015a000 CR3: 0000000077524000 CR4: 00000000003526f0
Call Trace:
<TASK>
queue_work_on+0x106/0x1d0 kernel/workqueue.c:2405
put_queue drivers/tty/vt/keyboard.c:328 [inline]
k_meta+0x3e7/0x7f0 drivers/tty/vt/keyboard.c:884
kbd_keycode drivers/tty/vt/keyboard.c:1497 [inline]
kbd_event+0x2ec1/0x40d0 drivers/tty/vt/keyboard.c:1515
input_handle_events_default+0xd4/0x1a0 drivers/input/input.c:2541
input_pass_values+0x288/0x890 drivers/input/input.c:128
input_event_dispose+0x330/0x6b0 drivers/input/input.c:342
input_inject_event+0x1dd/0x340 drivers/input/input.c:424
evdev_write+0x325/0x4c0 drivers/input/evdev.c:528
vfs_write+0x29a/0xb90 fs/read_write.c:686
ksys_write+0x150/0x270 fs/read_write.c:740
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fded299aeb9
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fded38f6028 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 00007fded2c15fa0 RCX: 00007fded299aeb9
RDX: 0000000000002250 RSI: 0000200000000040 RDI: 0000000000000004
RBP: 00007fded2a08c1f R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fded2c16038 R14: 00007fded2c15fa0 R15: 00007ffff85354c8
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:__queue_work+0xa2/0xf90 kernel/workqueue.c:2269
Code: 11 31 ff 89 ee e8 2e f3 37 00 85 ed 0f 85 ef 0c 00 00 e8 e1 ee 37 00 4d 8d b7 c0 01 00 00 4c 89 f0 48 c1 e8 03 48 89 44 24 28 <42> 0f b6 04 20 84 c0 0f 85 22 0d 00 00 4c 89 34 24 41 8b 2e 89 ee
RSP: 0018:ffffc9001ac9f4b8 EFLAGS: 00010002
RAX: 0000000000000038 RBX: 0000000000000008 RCX: 0000000000080000
RDX: ffffc9000c3c2000 RSI: 00000000000007c1 RDI: 00000000000007c2
RBP: 0000000000000000 R08: ffff88813ff72017 R09: 1ffff11027fee402
R10: dffffc0000000000 R11: ffffed1027fee403 R12: dffffc0000000000
R13: ffff88813ff72010 R14: 00000000000001c0 R15: 0000000000000000
FS: 00007fded38f66c0(0000) GS:ffff8881252af000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000020000015a000 CR3: 0000000077524000 CR4: 00000000003526f0
----------------
Code disassembly (best guess), 1 bytes skipped:
0: 31 ff xor %edi,%edi
2: 89 ee mov %ebp,%esi
4: e8 2e f3 37 00 call 0x37f337
9: 85 ed test %ebp,%ebp
b: 0f 85 ef 0c 00 00 jne 0xd00
11: e8 e1 ee 37 00 call 0x37eef7
16: 4d 8d b7 c0 01 00 00 lea 0x1c0(%r15),%r14
1d: 4c 89 f0 mov %r14,%rax
20: 48 c1 e8 03 shr $0x3,%rax
24: 48 89 44 24 28 mov %rax,0x28(%rsp)
* 29: 42 0f b6 04 20 movzbl (%rax,%r12,1),%eax <-- trapping instruction
2e: 84 c0 test %al,%al
30: 0f 85 22 0d 00 00 jne 0xd58
36: 4c 89 34 24 mov %r14,(%rsp)
3a: 41 8b 2e mov (%r14),%ebp
3d: 89 ee mov %ebp,%esi
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply
* [PATCH] serial: 8250: add CONFIG_SERIAL_8250_PROBE_BAUD option
From: Sheng Yu @ 2026-02-01 4:18 UTC (permalink / raw)
To: gregkh; +Cc: jirislaby, linux-serial, linux-kernel, Sheng Yu
Currently, the 8250 driver defaults to 9600 baud if no console options
are provided via the command line. This can result in garbled output if
the firmware or bootloader has already initialized the UART to a
different speed.
Introduce CONFIG_SERIAL_8250_PROBE_BAUD. When enabled, the driver will
attempt to read the current baud rate from the hardware registers if
no options are specified, rather than forcing the 9600 default.
Signed-off-by: Sheng Yu <yushenglive@gmail.com>
---
drivers/tty/serial/8250/8250_core.c | 2 +-
drivers/tty/serial/8250/8250_port.c | 6 +++++-
drivers/tty/serial/8250/Kconfig | 12 ++++++++++++
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 0e81f78c6063..c11b19921a1f 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -427,7 +427,7 @@ static int univ8250_console_setup(struct console *co, char *options)
/* link port to console */
uart_port_set_cons(port, co);
- retval = serial8250_console_setup(port, options, false);
+ retval = serial8250_console_setup(port, options, IS_ENABLED(CONFIG_SERIAL_8250_PROBE_BAUD));
if (retval != 0)
uart_port_set_cons(port, NULL);
return retval;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 719faf92aa8a..dbc0ef56f995 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -3399,8 +3399,12 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
- else if (probe)
+ else if (probe) {
baud = probe_baud(port);
+ pr_info("console [%s%d] probed baud rate: %d\n",
+ port->cons->name, port->cons->index, baud);
+
+ }
ret = uart_set_options(port, port->cons, baud, parity, bits, flow);
if (ret)
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index c488ff6f2865..bee6a82023d4 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -596,3 +596,15 @@ config SERIAL_OF_PLATFORM
are probed through devicetree, including Open Firmware based
PowerPC systems and embedded systems on architectures using the
flattened device tree format.
+
+config SERIAL_8250_PROBE_BAUD
+ bool "Probe baud rate if console options are missing"
+ depends on SERIAL_8250
+ help
+ If the "console=" command line parameter is missing options (e.g.,
+ "console=ttyS0" instead of "console=ttyS0,115200n8"), this option
+ allows the kernel to probe the baud rate from hardware instead of
+ defaulting to 9600.
+
+ If a baud rate is explicitly provided in the options, that value
+ is always respected.
--
2.51.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox