* [PATCH] serial: 8250_omap: clear rx_running on zero-length DMA completes
From: Matthias Feser @ 2026-05-21 13:30 UTC (permalink / raw)
To: linux-serial@vger.kernel.org, gregkh@linuxfoundation.org,
jirislaby@kernel.org
Cc: linux-kernel@vger.kernel.org, k-willis@ti.com, m-shah@ti.com,
msp@baylibre.com, andriy.shevchenko@linux.intel.com
On AM33xx RX DMA only triggers when the FIFO reaches the
configured threshold (typically 48 bytes). For smaller bursts
no DMA request is issued and the FIFO is drained by RX timeout.
In this case __dma_rx_do_complete() can legitimately see count == 0.
The current code exits early in this case and does not clear
dma->rx_running, leaving the DMA state inconsistent. This can
prevent RX DMA from restarting and may cause
omap_8250_rx_dma_flush() to fail, marking DMA as broken.
Fix this by always clearing dma->rx_running on exit.
Signed-off-by: Matthias Feser <mfe@KBSgmbhfr.onmicrosoft.com>
---
drivers/tty/serial/8250/8250_omap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index c552c6b9a037..686e54859aa5 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -948,11 +948,11 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
goto out;
ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
- dma->rx_running = 0;
p->port.icount.rx += ret;
p->port.icount.buf_overrun += count - ret;
out:
+ dma->rx_running = 0;
tty_flip_buffer_push(tty_port);
}
--
2.39.5
^ permalink raw reply related
* Re: [PATCH v5 8/8] ARM: defconfig: Add a zx29 defconfig file
From: Stefan Dösinger @ 2026-05-21 8:00 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Linus Walleij, Jonathan Corbet, Shuah Khan, Russell King,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Krzysztof Kozlowski, Alexandre Belloni, Drew Fustini,
Greg Kroah-Hartman, Jiri Slaby, linux-doc, linux-kernel,
linux-arm-kernel, devicetree, soc, linux-serial
In-Reply-To: <30b96e0d-f296-4c31-8701-a15c568ebffc@app.fastmail.com>
[-- Attachment #1: Type: text/plain, Size: 3910 bytes --]
Hi Arnd,
I saw your reply to my defconfig pull request, but apparently never received your original reply. I only found this mail here. It looks like I have to look for a better E-Mail provider as gmail is choking on the volume of the linux-arm-kernel mailing list.
To answer your questions I found at https://lore.kernel.org/all/61452117-0cdc-4ec2-83eb-dc03ccbd410b@app.fastmail.com/ :
> Either way, the patch description above should at least explain
> why you think you need your own defconfig, as we don't normally
> take those.
It was more cluelessness / being new to kernel development that gave me the impression that boards should have defconfigs. Since then I ran across scripts/dt_to_config. I haven't tested it yet on my DT, but if it does the right thing I don't think this board needs a defconfig.
>> +CONFIG_CMDLINE="console=ttyAMA0 earlyprintk root=/dev/ram rw"
> A definconfig should normall not rely on earlyprintk, just add
> that when you actually need to debug the super-early boot
> stages. With "earlycon" it should pick up the right console
> from the stdout path and work almost as early.
>> +CONFIG_BINFMT_FLAT=y
> Are you actually using flat binaries? I wasn't aware that this
> is still possible on MMU-enabled kernels.
>> +CONFIG_BLK_DEV_RAM=y
>> +CONFIG_BLK_DEV_RAM_COUNT=4
> The old ramdisk boot is going away in the future, please use
> initramfs instead. This should also save a good amount of RAM.
I'll fix those in my tree and keep the defconfig around just in case, but otherwise drop it from the submission. We can revisit it later when the board is more complete.
>> +CONFIG_DEVTMPFS=y # FIXME: This is specific to my initrd. Remove
>> before upstream
>stale comment?
I believe I removed this in later versions though :-)
Cheers,
Stefan
> Am 24.04.2026 um 11:54 schrieb Arnd Bergmann <arnd@arndb.de>:
>
> On Fri, Apr 24, 2026, at 09:13, Linus Walleij wrote:
>> On Tue, Apr 21, 2026 at 10:24 PM Stefan Dösinger
>> <stefandoesinger@gmail.com> wrote:
>>
>>> This enables existing drivers that already are (UART) or will be (USB,
>>> GPIO) necessary to operate this board even if they aren't declared in
>>> the DTS yet.
>>>
>>> Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
>>
>> *I* personally (as SoC maintainer) think that having a few more defconfigs
>> is fine, even helpful.
>>
>> But I would defer this to the more senior SoC maintainers because I think
>> their stance is something like:
>>
>> - We have multi_v7_defconfig for compile testing
>>
>> - We know that binary gets way to big for your system: it's for build
>> testing and perhaps booting in QEMU or systems with many MB of
>> RAM, not for actually running it on products.
>>
>> - You are encouraged to keep your own defconfig out-of-tree.
>
> Right, we clearly need to do something better than what we are with
> the general defconfigs, as I'm sure many of the existing ones are
> never actually used for booting a machine, and are horribly out of
> date with the Kconfig options.
>
> I wouldn't object to adding another defconfig for a new (or revived)
> soc family, but I don't want to have more per-board ones.
> Overall, we have about 70 defconfigs and 55 soc families that have their
> own mach-* directory (plus a few without code), and the number of
> defconfigs alone makes it hard to keep them up to date.
>
>> However I even challenged this myself by adding a defconfig for memory
>> constrained Broadcoms a while back (NACKed/ignored ;) so if it was all
>> up to me I would merge this.
>
> I don't even remember that discussion ;-)
>
> One idea might be to have a tiny base defconfig, plus platform
> specific fragments that add drivers. The problem is agreeing
> what bits are essential enough to still get enabled in the
> tiny config.
>
> Arnd
[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] serial: max310x: fix I2C-only build
From: Arnd Bergmann @ 2026-05-20 14:34 UTC (permalink / raw)
To: Hugo Villeneuve
Cc: Arnd Bergmann, Greg Kroah-Hartman, Jiri Slaby, Hugo Villeneuve,
Randy Dunlap, Geert Uytterhoeven, linux-kernel, linux-serial
In-Reply-To: <20260520100457.0df23fe2d1c16fbb848a3de1@hugovil.com>
On Wed, May 20, 2026, at 16:04, Hugo Villeneuve wrote:
> On Wed, 20 May 2026 08:47:05 +0200
> "Arnd Bergmann" <arnd@arndb.de> wrote:
>> >> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
>> >> index 811250bbbd39..b9b40e80ea81 100644
>> >> --- a/drivers/tty/serial/Kconfig
>> >> +++ b/drivers/tty/serial/Kconfig
>> >> @@ -323,6 +323,7 @@ config SERIAL_MAX3100
>> >> config SERIAL_MAX310X
>> >> tristate "MAX310X support"
>> >> depends on SPI_MASTER || I2C
>> >> + depends on I2C || !I2C
>> >> select SERIAL_CORE
>> >> select REGMAP_SPI if SPI_MASTER
>> >> select REGMAP_I2C if I2C
>>
>> This is still required to avoid a link failure with
>> SERIAL_MAX310X=y and I2C=m. Do you want to include this in
>> a v3 of your patch, or should I send this separately?
>
> If I2C=m, i cannot select SERIAL_MAX310X=y, it is automatically set (or
> reset) to "m", even if I manually force it to "y", do you have the same
> behavior?
The problem happens only when SPI_MASTER=y, in which case the
current logic does allow SERIAL_MAX310X=y. When SPI_MASTER is
disabled, it works correctly as you describe.
> Before i converted the sc16is7xx driver to split i2c/spi, it was done
> like this:
>
> depends on (SPI_MASTER && !I2C) || I2C
>
> Based on what we agree on, I will include it in V3...
Right, the '(SPI_MASTER && !I2C) || I2C' expression is equivalent
to what I suggested. I picked the syntax that I find easier to
understand, but I'm fine with that as well.
Arnd
^ permalink raw reply
* Re: [PATCH] serial: max310x: fix I2C-only build
From: Hugo Villeneuve @ 2026-05-20 14:04 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Arnd Bergmann, Greg Kroah-Hartman, Jiri Slaby, Hugo Villeneuve,
Randy Dunlap, Geert Uytterhoeven, linux-kernel, linux-serial
In-Reply-To: <8478838f-3821-44ea-b281-c890441b9a12@app.fastmail.com>
Hi Arnd,
On Wed, 20 May 2026 08:47:05 +0200
"Arnd Bergmann" <arnd@arndb.de> wrote:
> [You don't often get email from arnd@arndb.de. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> On Tue, May 19, 2026, at 23:14, Hugo Villeneuve wrote:
> >> now causes build failures:
> >
> > A few days ago i sent v2 of a patch to fix this problem:
> >
> > https://lore.kernel.org/all/20260515183217.3554037-1-hugo@hugovil.com/raw
> >
> > Did you saw it?
>
> Sorry I hadn't checked for other patches. I verified that your
> changes are functionally the same as mine.
>
> The one change I have that you didn't include is
>
> >> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> >> index 811250bbbd39..b9b40e80ea81 100644
> >> --- a/drivers/tty/serial/Kconfig
> >> +++ b/drivers/tty/serial/Kconfig
> >> @@ -323,6 +323,7 @@ config SERIAL_MAX3100
> >> config SERIAL_MAX310X
> >> tristate "MAX310X support"
> >> depends on SPI_MASTER || I2C
> >> + depends on I2C || !I2C
> >> select SERIAL_CORE
> >> select REGMAP_SPI if SPI_MASTER
> >> select REGMAP_I2C if I2C
>
> This is still required to avoid a link failure with
> SERIAL_MAX310X=y and I2C=m. Do you want to include this in
> a v3 of your patch, or should I send this separately?
If I2C=m, i cannot select SERIAL_MAX310X=y, it is automatically set (or
reset) to "m", even if I manually force it to "y", do you have the same
behavior?
Before i converted the sc16is7xx driver to split i2c/spi, it was done
like this:
depends on (SPI_MASTER && !I2C) || I2C
Based on what we agree on, I will include it in V3...
--
Hugo Villeneuve
^ permalink raw reply
* Re: [PATCH] video: console: mdacon: remove this obsolete driver
From: Helge Deller @ 2026-05-20 11:45 UTC (permalink / raw)
To: Ethan Nelson-Moore, linux-doc, linux-alpha, linux-serial,
linux-fbdev, Linux DRI Development, linuxppc-dev
Cc: Jonathan Corbet, Shuah Khan, Richard Henderson, Matt Turner,
Magnus Lindholm, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Greg Kroah-Hartman,
Jiri Slaby, Nicolas Pitre
In-Reply-To: <20260520033155.17378-1-enelsonmoore@gmail.com>
On 5/20/26 05:31, Ethan Nelson-Moore wrote:
> The mdacon driver supports using ISA MDA or Hercules-compatible display
> adapters as a secondary text console. This was commonly used in the
> 1990s and earlier for debugging software which took over the primary
> display. It is highly unlikely anyone is doing so nowadays because
> serial consoles and much better methods of debugging exist.
>
> The driver is not enabled by any defconfig, nor any of the
> dozens of distro configs collected at [1]. It has been relegated to VTs
> 13-16 since commit 0b9cf3aa6b1e ("mdacon messing up default vc's - set
> default to vc13-16 again") in Linux 2.6.27 (and before Linux 2.5.53 -
> see the link in the message of the above commit). The change in 2.6.27
> was done because it was incorrectly detecting non-MDA adapters as MDA
> and taking over all VTs, rendering them unusable.
>
> Furthermore, vgacon supports using MDA/Hercules-compatible adapters as
> the primary text console, so any systems with only one of these
> adapters were already using vgacon and will not experience any loss in
> functionality from the removal of this driver.
>
> Given all of these factors, the mdacon driver is likely entirely
> unused. Remove it.
I've applied this patch to the fbdev git tree, since I also believe that
there is no use case or user left (with Linux kernels >= 7.0), which uses the mdacon.
If someone thinks we need to keep it, please speak up.
Helge
>
> [1] https://github.com/nyrahul/linux-kernel-configs/tree/f0bee86a135a0406ea427855f52702dd00d770f9
>
> Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
> ---
> .../admin-guide/kernel-parameters.txt | 5 -
> arch/alpha/kernel/io.c | 2 +-
> arch/powerpc/include/asm/vga.h | 4 +-
> drivers/tty/vt/vt.c | 3 -
> drivers/video/console/Kconfig | 15 -
> drivers/video/console/Makefile | 1 -
> drivers/video/console/mdacon.c | 566 ------------------
> include/linux/console.h | 2 -
> include/linux/vt_buffer.h | 2 +-
> 9 files changed, 4 insertions(+), 596 deletions(-)
> delete mode 100644 drivers/video/console/mdacon.c
^ permalink raw reply
* Re: [PATCH] serial: max310x: fix I2C-only build
From: Arnd Bergmann @ 2026-05-20 6:47 UTC (permalink / raw)
To: Hugo Villeneuve, Arnd Bergmann
Cc: Greg Kroah-Hartman, Jiri Slaby, Hugo Villeneuve, Randy Dunlap,
Geert Uytterhoeven, linux-kernel, linux-serial
In-Reply-To: <20260519171437.ff11a24d84c9ac8092348baf@hugovil.com>
On Tue, May 19, 2026, at 23:14, Hugo Villeneuve wrote:
>> now causes build failures:
>
> A few days ago i sent v2 of a patch to fix this problem:
>
> https://lore.kernel.org/all/20260515183217.3554037-1-hugo@hugovil.com/raw
>
> Did you saw it?
Sorry I hadn't checked for other patches. I verified that your
changes are functionally the same as mine.
The one change I have that you didn't include is
>> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
>> index 811250bbbd39..b9b40e80ea81 100644
>> --- a/drivers/tty/serial/Kconfig
>> +++ b/drivers/tty/serial/Kconfig
>> @@ -323,6 +323,7 @@ config SERIAL_MAX3100
>> config SERIAL_MAX310X
>> tristate "MAX310X support"
>> depends on SPI_MASTER || I2C
>> + depends on I2C || !I2C
>> select SERIAL_CORE
>> select REGMAP_SPI if SPI_MASTER
>> select REGMAP_I2C if I2C
This is still required to avoid a link failure with
SERIAL_MAX310X=y and I2C=m. Do you want to include this in
a v3 of your patch, or should I send this separately?
Arnd
^ permalink raw reply
* [PATCH] video: console: mdacon: remove this obsolete driver
From: Ethan Nelson-Moore @ 2026-05-20 3:31 UTC (permalink / raw)
To: linux-doc, linux-alpha, linux-serial, linux-fbdev
Cc: Ethan Nelson-Moore, Jonathan Corbet, Shuah Khan,
Richard Henderson, Matt Turner, Magnus Lindholm,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Greg Kroah-Hartman, Jiri Slaby,
Helge Deller, Nicolas Pitre
The mdacon driver supports using ISA MDA or Hercules-compatible display
adapters as a secondary text console. This was commonly used in the
1990s and earlier for debugging software which took over the primary
display. It is highly unlikely anyone is doing so nowadays because
serial consoles and much better methods of debugging exist.
The driver is not enabled by any defconfig, nor any of the
dozens of distro configs collected at [1]. It has been relegated to VTs
13-16 since commit 0b9cf3aa6b1e ("mdacon messing up default vc's - set
default to vc13-16 again") in Linux 2.6.27 (and before Linux 2.5.53 -
see the link in the message of the above commit). The change in 2.6.27
was done because it was incorrectly detecting non-MDA adapters as MDA
and taking over all VTs, rendering them unusable.
Furthermore, vgacon supports using MDA/Hercules-compatible adapters as
the primary text console, so any systems with only one of these
adapters were already using vgacon and will not experience any loss in
functionality from the removal of this driver.
Given all of these factors, the mdacon driver is likely entirely
unused. Remove it.
[1] https://github.com/nyrahul/linux-kernel-configs/tree/f0bee86a135a0406ea427855f52702dd00d770f9
Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
.../admin-guide/kernel-parameters.txt | 5 -
arch/alpha/kernel/io.c | 2 +-
arch/powerpc/include/asm/vga.h | 4 +-
drivers/tty/vt/vt.c | 3 -
drivers/video/console/Kconfig | 15 -
drivers/video/console/Makefile | 1 -
drivers/video/console/mdacon.c | 566 ------------------
include/linux/console.h | 2 -
include/linux/vt_buffer.h | 2 +-
9 files changed, 4 insertions(+), 596 deletions(-)
delete mode 100644 drivers/video/console/mdacon.c
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..e873b27cdd30 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -36,7 +36,6 @@
M68k M68k architecture is enabled.
These options have more detailed description inside of
Documentation/arch/m68k/kernel-options.rst.
- MDA MDA console support is enabled.
MIPS MIPS architecture is enabled.
MOUSE Appropriate mouse support is enabled.
MSI Message Signaled Interrupts (PCI).
@@ -3816,10 +3815,6 @@ Kernel parameters
md= [HW] RAID subsystems devices and level
See Documentation/admin-guide/md.rst.
- mdacon= [MDA]
- Format: <first>,<last>
- Specifies range of consoles to be captured by the MDA.
-
mds= [X86,INTEL,EARLY]
Control mitigation for the Micro-architectural Data
Sampling (MDS) vulnerability.
diff --git a/arch/alpha/kernel/io.c b/arch/alpha/kernel/io.c
index c28035d6d1e6..2bad1b4fb240 100644
--- a/arch/alpha/kernel/io.c
+++ b/arch/alpha/kernel/io.c
@@ -647,7 +647,7 @@ void _memset_c_io(volatile void __iomem *to, unsigned long c, long count)
EXPORT_SYMBOL(_memset_c_io);
-#if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE)
+#if IS_ENABLED(CONFIG_VGA_CONSOLE)
#include <asm/vga.h>
diff --git a/arch/powerpc/include/asm/vga.h b/arch/powerpc/include/asm/vga.h
index f2dc40e1c52a..e45063b02b45 100644
--- a/arch/powerpc/include/asm/vga.h
+++ b/arch/powerpc/include/asm/vga.h
@@ -14,7 +14,7 @@
#include <asm/io.h>
-#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_MDA_CONSOLE)
+#ifdef CONFIG_VGA_CONSOLE
#define VT_BUF_HAVE_RW
/*
@@ -40,7 +40,7 @@ static inline void scr_memsetw(u16 *s, u16 v, unsigned int n)
memset16(s, cpu_to_le16(v), n / 2);
}
-#endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */
+#endif /* !CONFIG_VGA_CONSOLE */
#ifdef __powerpc64__
#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s))
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index e99636ab9db5..3ca5e3dc5ac0 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3978,9 +3978,6 @@ int __init vty_init(const struct file_operations *console_fops)
panic("Couldn't register console driver\n");
kbd_init();
console_map_init();
-#ifdef CONFIG_MDA_CONSOLE
- mda_console_init();
-#endif
return 0;
}
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 12f54480f57f..9f81af3506da 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -23,21 +23,6 @@ config VGA_CONSOLE
Say Y.
-config MDA_CONSOLE
- depends on VGA_CONSOLE && ISA
- tristate "MDA text console (dual-headed)"
- help
- Say Y here if you have an old MDA or monochrome Hercules graphics
- adapter in your system acting as a second head ( = video card). You
- will then be able to use two monitors with your Linux system. Do not
- say Y here if your MDA card is the primary card in your system; the
- normal VGA driver will handle it.
-
- To compile this driver as a module, choose M here: the
- module will be called mdacon.
-
- If unsure, say N.
-
config SGI_NEWPORT_CONSOLE
tristate "SGI Newport Console support"
depends on SGI_IP22 && HAS_IOMEM
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index fd79016a0d95..f1000605210c 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -7,4 +7,3 @@ obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o
obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
obj-$(CONFIG_STI_CONSOLE) += sticon.o
obj-$(CONFIG_VGA_CONSOLE) += vgacon.o
-obj-$(CONFIG_MDA_CONSOLE) += mdacon.o
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
deleted file mode 100644
index d52cd99cd18b..000000000000
--- a/drivers/video/console/mdacon.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * linux/drivers/video/mdacon.c -- Low level MDA based console driver
- *
- * (c) 1998 Andrew Apted <ajapted@netspace.net.au>
- *
- * including portions (c) 1995-1998 Patrick Caulfield.
- *
- * slight improvements (c) 2000 Edward Betts <edward@debian.org>
- *
- * This file is based on the VGA console driver (vgacon.c):
- *
- * Created 28 Sep 1997 by Geert Uytterhoeven
- *
- * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
- *
- * and on the old console.c, vga.c and vesa_blank.c drivers:
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- * 1995 Jay Estabrook
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
- * Changelog:
- * Paul G. (03/2001) Fix mdacon= boot prompt to use __setup().
- */
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/string.h>
-#include <linux/kd.h>
-#include <linux/vt_kern.h>
-#include <linux/vt_buffer.h>
-#include <linux/selection.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/vga.h>
-
-static DEFINE_SPINLOCK(mda_lock);
-
-/* description of the hardware layout */
-
-static u16 *mda_vram_base; /* Base of video memory */
-static unsigned long mda_vram_len; /* Size of video memory */
-static unsigned int mda_num_columns; /* Number of text columns */
-static unsigned int mda_num_lines; /* Number of text lines */
-
-static unsigned int mda_index_port; /* Register select port */
-static unsigned int mda_value_port; /* Register value port */
-static unsigned int mda_mode_port; /* Mode control port */
-static unsigned int mda_status_port; /* Status and Config port */
-static unsigned int mda_gfx_port; /* Graphics control port */
-
-/* current hardware state */
-
-static int mda_cursor_loc=-1;
-static int mda_cursor_size_from=-1;
-static int mda_cursor_size_to=-1;
-
-static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type;
-static char *mda_type_name;
-
-/* console information */
-
-static int mda_first_vc = 13;
-static int mda_last_vc = 16;
-
-static struct vc_data *mda_display_fg = NULL;
-
-module_param(mda_first_vc, int, 0);
-MODULE_PARM_DESC(mda_first_vc, "First virtual console. Default: 13");
-module_param(mda_last_vc, int, 0);
-MODULE_PARM_DESC(mda_last_vc, "Last virtual console. Default: 16");
-
-/* MDA register values
- */
-
-#define MDA_CURSOR_BLINKING 0x00
-#define MDA_CURSOR_OFF 0x20
-#define MDA_CURSOR_SLOWBLINK 0x60
-
-#define MDA_MODE_GRAPHICS 0x02
-#define MDA_MODE_VIDEO_EN 0x08
-#define MDA_MODE_BLINK_EN 0x20
-#define MDA_MODE_GFX_PAGE1 0x80
-
-#define MDA_STATUS_HSYNC 0x01
-#define MDA_STATUS_VSYNC 0x80
-#define MDA_STATUS_VIDEO 0x08
-
-#define MDA_CONFIG_COL132 0x08
-#define MDA_GFX_MODE_EN 0x01
-#define MDA_GFX_PAGE_EN 0x02
-
-
-/*
- * MDA could easily be classified as "pre-dinosaur hardware".
- */
-
-static void write_mda_b(unsigned int val, unsigned char reg)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mda_lock, flags);
-
- outb_p(reg, mda_index_port);
- outb_p(val, mda_value_port);
-
- spin_unlock_irqrestore(&mda_lock, flags);
-}
-
-static void write_mda_w(unsigned int val, unsigned char reg)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mda_lock, flags);
-
- outb_p(reg, mda_index_port); outb_p(val >> 8, mda_value_port);
- outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port);
-
- spin_unlock_irqrestore(&mda_lock, flags);
-}
-
-#ifdef TEST_MDA_B
-static int test_mda_b(unsigned char val, unsigned char reg)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mda_lock, flags);
-
- outb_p(reg, mda_index_port);
- outb (val, mda_value_port);
-
- udelay(20); val = (inb_p(mda_value_port) == val);
-
- spin_unlock_irqrestore(&mda_lock, flags);
- return val;
-}
-#endif
-
-static inline void mda_set_cursor(unsigned int location)
-{
- if (mda_cursor_loc == location)
- return;
-
- write_mda_w(location >> 1, 0x0e);
-
- mda_cursor_loc = location;
-}
-
-static inline void mda_set_cursor_size(int from, int to)
-{
- if (mda_cursor_size_from==from && mda_cursor_size_to==to)
- return;
-
- if (from > to) {
- write_mda_b(MDA_CURSOR_OFF, 0x0a); /* disable cursor */
- } else {
- write_mda_b(from, 0x0a); /* cursor start */
- write_mda_b(to, 0x0b); /* cursor end */
- }
-
- mda_cursor_size_from = from;
- mda_cursor_size_to = to;
-}
-
-
-#ifndef MODULE
-static int __init mdacon_setup(char *str)
-{
- /* command line format: mdacon=<first>,<last> */
-
- int ints[3];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- if (ints[0] < 2)
- return 0;
-
- if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES ||
- ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
- return 0;
-
- mda_first_vc = ints[1];
- mda_last_vc = ints[2];
- return 1;
-}
-
-__setup("mdacon=", mdacon_setup);
-#endif
-
-static int mda_detect(void)
-{
- int count=0;
- u16 *p, p_save;
- u16 *q, q_save;
-
- /* do a memory check */
-
- p = mda_vram_base;
- q = mda_vram_base + 0x01000 / 2;
-
- p_save = scr_readw(p);
- q_save = scr_readw(q);
-
- scr_writew(0xAA55, p);
- if (scr_readw(p) == 0xAA55)
- count++;
-
- scr_writew(0x55AA, p);
- if (scr_readw(p) == 0x55AA)
- count++;
-
- scr_writew(p_save, p);
-
- if (count != 2) {
- return 0;
- }
-
- /* check if we have 4K or 8K */
-
- scr_writew(0xA55A, q);
- scr_writew(0x0000, p);
- if (scr_readw(q) == 0xA55A)
- count++;
-
- scr_writew(0x5AA5, q);
- scr_writew(0x0000, p);
- if (scr_readw(q) == 0x5AA5)
- count++;
-
- scr_writew(p_save, p);
- scr_writew(q_save, q);
-
- if (count == 4) {
- mda_vram_len = 0x02000;
- }
-
- /* Ok, there is definitely a card registering at the correct
- * memory location, so now we do an I/O port test.
- */
-
-#ifdef TEST_MDA_B
- /* Edward: These two mess `tests' mess up my cursor on bootup */
-
- /* cursor low register */
- if (!test_mda_b(0x66, 0x0f))
- return 0;
-
- /* cursor low register */
- if (!test_mda_b(0x99, 0x0f))
- return 0;
-#endif
-
- /* See if the card is a Hercules, by checking whether the vsync
- * bit of the status register is changing. This test lasts for
- * approximately 1/10th of a second.
- */
-
- p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC;
-
- for (count = 0; count < 50000 && p_save == q_save; count++) {
- q_save = inb(mda_status_port) & MDA_STATUS_VSYNC;
- udelay(2);
- }
-
- if (p_save != q_save) {
- switch (inb_p(mda_status_port) & 0x70) {
- case 0x10:
- mda_type = TYPE_HERCPLUS;
- mda_type_name = "HerculesPlus";
- break;
- case 0x50:
- mda_type = TYPE_HERCCOLOR;
- mda_type_name = "HerculesColor";
- break;
- default:
- mda_type = TYPE_HERC;
- mda_type_name = "Hercules";
- break;
- }
- }
-
- return 1;
-}
-
-static void mda_initialize(void)
-{
- write_mda_b(97, 0x00); /* horizontal total */
- write_mda_b(80, 0x01); /* horizontal displayed */
- write_mda_b(82, 0x02); /* horizontal sync pos */
- write_mda_b(15, 0x03); /* horizontal sync width */
-
- write_mda_b(25, 0x04); /* vertical total */
- write_mda_b(6, 0x05); /* vertical total adjust */
- write_mda_b(25, 0x06); /* vertical displayed */
- write_mda_b(25, 0x07); /* vertical sync pos */
-
- write_mda_b(2, 0x08); /* interlace mode */
- write_mda_b(13, 0x09); /* maximum scanline */
- write_mda_b(12, 0x0a); /* cursor start */
- write_mda_b(13, 0x0b); /* cursor end */
-
- write_mda_w(0x0000, 0x0c); /* start address */
- write_mda_w(0x0000, 0x0e); /* cursor location */
-
- outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
- outb_p(0x00, mda_status_port);
- outb_p(0x00, mda_gfx_port);
-}
-
-static const char *mdacon_startup(void)
-{
- mda_num_columns = 80;
- mda_num_lines = 25;
-
- mda_vram_len = 0x01000;
- mda_vram_base = (u16 *)VGA_MAP_MEM(0xb0000, mda_vram_len);
-
- mda_index_port = 0x3b4;
- mda_value_port = 0x3b5;
- mda_mode_port = 0x3b8;
- mda_status_port = 0x3ba;
- mda_gfx_port = 0x3bf;
-
- mda_type = TYPE_MDA;
- mda_type_name = "MDA";
-
- if (! mda_detect()) {
- printk("mdacon: MDA card not detected.\n");
- return NULL;
- }
-
- if (mda_type != TYPE_MDA) {
- mda_initialize();
- }
-
- /* cursor looks ugly during boot-up, so turn it off */
- mda_set_cursor(mda_vram_len - 1);
-
- printk("mdacon: %s with %ldK of memory detected.\n",
- mda_type_name, mda_vram_len/1024);
-
- return "MDA-2";
-}
-
-static void mdacon_init(struct vc_data *c, bool init)
-{
- c->vc_complement_mask = 0x0800; /* reverse video */
- c->vc_display_fg = &mda_display_fg;
-
- if (init) {
- c->vc_cols = mda_num_columns;
- c->vc_rows = mda_num_lines;
- } else
- vc_resize(c, mda_num_columns, mda_num_lines);
-
- /* make the first MDA console visible */
-
- if (mda_display_fg == NULL)
- mda_display_fg = c;
-}
-
-static void mdacon_deinit(struct vc_data *c)
-{
- /* con_set_default_unimap(c->vc_num); */
-
- if (mda_display_fg == c)
- mda_display_fg = NULL;
-}
-
-static inline u16 mda_convert_attr(u16 ch)
-{
- u16 attr = 0x0700;
-
- /* Underline and reverse-video are mutually exclusive on MDA.
- * Since reverse-video is used for cursors and selected areas,
- * it takes precedence.
- */
-
- if (ch & 0x0800) attr = 0x7000; /* reverse */
- else if (ch & 0x0400) attr = 0x0100; /* underline */
-
- return ((ch & 0x0200) << 2) | /* intensity */
- (ch & 0x8000) | /* blink */
- (ch & 0x00ff) | attr;
-}
-
-static u8 mdacon_build_attr(struct vc_data *c, u8 color,
- enum vc_intensity intensity,
- bool blink, bool underline, bool reverse,
- bool italic)
-{
- /* The attribute is just a bit vector:
- *
- * Bit 0..1 : intensity (0..2)
- * Bit 2 : underline
- * Bit 3 : reverse
- * Bit 7 : blink
- */
-
- return (intensity & VCI_MASK) |
- (underline << 2) |
- (reverse << 3) |
- (italic << 4) |
- (blink << 7);
-}
-
-static void mdacon_invert_region(struct vc_data *c, u16 *p, int count)
-{
- for (; count > 0; count--) {
- scr_writew(scr_readw(p) ^ 0x0800, p);
- p++;
- }
-}
-
-static inline u16 *mda_addr(unsigned int x, unsigned int y)
-{
- return mda_vram_base + y * mda_num_columns + x;
-}
-
-static void mdacon_putcs(struct vc_data *c, const u16 *s, unsigned int count,
- unsigned int y, unsigned int x)
-{
- u16 *dest = mda_addr(x, y);
-
- for (; count > 0; count--) {
- scr_writew(mda_convert_attr(scr_readw(s++)), dest++);
- }
-}
-
-static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x,
- unsigned int width)
-{
- u16 *dest = mda_addr(x, y);
- u16 eattr = mda_convert_attr(c->vc_video_erase_char);
-
- scr_memsetw(dest, eattr, width * 2);
-}
-
-static bool mdacon_switch(struct vc_data *c)
-{
- return true; /* redrawing needed */
-}
-
-static bool mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank,
- bool mode_switch)
-{
- if (mda_type == TYPE_MDA) {
- if (blank)
- scr_memsetw(mda_vram_base,
- mda_convert_attr(c->vc_video_erase_char),
- c->vc_screenbuf_size);
- /* Tell console.c that it has to restore the screen itself */
- return true;
- } else {
- if (blank)
- outb_p(0x00, mda_mode_port); /* disable video */
- else
- outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN,
- mda_mode_port);
- return false;
- }
-}
-
-static void mdacon_cursor(struct vc_data *c, bool enable)
-{
- if (!enable) {
- mda_set_cursor(mda_vram_len - 1);
- return;
- }
-
- mda_set_cursor(c->state.y * mda_num_columns * 2 + c->state.x * 2);
-
- switch (CUR_SIZE(c->vc_cursor_type)) {
-
- case CUR_LOWER_THIRD: mda_set_cursor_size(10, 13); break;
- case CUR_LOWER_HALF: mda_set_cursor_size(7, 13); break;
- case CUR_TWO_THIRDS: mda_set_cursor_size(4, 13); break;
- case CUR_BLOCK: mda_set_cursor_size(1, 13); break;
- case CUR_NONE: mda_set_cursor_size(14, 13); break;
- default: mda_set_cursor_size(12, 13); break;
- }
-}
-
-static bool mdacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
- enum con_scroll dir, unsigned int lines)
-{
- u16 eattr = mda_convert_attr(c->vc_video_erase_char);
-
- if (!lines)
- return false;
-
- if (lines > c->vc_rows) /* maximum realistic size */
- lines = c->vc_rows;
-
- switch (dir) {
-
- case SM_UP:
- scr_memmovew(mda_addr(0, t), mda_addr(0, t + lines),
- (b-t-lines)*mda_num_columns*2);
- scr_memsetw(mda_addr(0, b - lines), eattr,
- lines*mda_num_columns*2);
- break;
-
- case SM_DOWN:
- scr_memmovew(mda_addr(0, t + lines), mda_addr(0, t),
- (b-t-lines)*mda_num_columns*2);
- scr_memsetw(mda_addr(0, t), eattr, lines*mda_num_columns*2);
- break;
- }
-
- return false;
-}
-
-
-/*
- * The console `switch' structure for the MDA based console
- */
-
-static const struct consw mda_con = {
- .owner = THIS_MODULE,
- .con_startup = mdacon_startup,
- .con_init = mdacon_init,
- .con_deinit = mdacon_deinit,
- .con_clear = mdacon_clear,
- .con_putcs = mdacon_putcs,
- .con_cursor = mdacon_cursor,
- .con_scroll = mdacon_scroll,
- .con_switch = mdacon_switch,
- .con_blank = mdacon_blank,
- .con_build_attr = mdacon_build_attr,
- .con_invert_region = mdacon_invert_region,
-};
-
-int __init mda_console_init(void)
-{
- int err;
-
- if (mda_first_vc > mda_last_vc)
- return 1;
- console_lock();
- err = do_take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
- console_unlock();
- return err;
-}
-
-static void __exit mda_console_exit(void)
-{
- give_up_console(&mda_con);
-}
-
-module_init(mda_console_init);
-module_exit(mda_console_exit);
-
-MODULE_DESCRIPTION("MDA based console driver");
-MODULE_LICENSE("GPL");
-
diff --git a/include/linux/console.h b/include/linux/console.h
index 5520e4477ad7..d624200cfc17 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -718,8 +718,6 @@ extern bool console_suspend_enabled;
extern void console_suspend_all(void);
extern void console_resume_all(void);
-int mda_console_init(void);
-
void vcs_make_sysfs(int index);
void vcs_remove_sysfs(int index);
diff --git a/include/linux/vt_buffer.h b/include/linux/vt_buffer.h
index b6eeb8cb6070..6c15c6a15f74 100644
--- a/include/linux/vt_buffer.h
+++ b/include/linux/vt_buffer.h
@@ -16,7 +16,7 @@
#include <linux/string.h>
-#if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE)
+#if IS_ENABLED(CONFIG_VGA_CONSOLE)
#include <asm/vga.h>
#endif
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] serial: max310x: fix I2C-only build
From: Hugo Villeneuve @ 2026-05-19 21:14 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Greg Kroah-Hartman, Jiri Slaby, Hugo Villeneuve, Arnd Bergmann,
Randy Dunlap, Geert Uytterhoeven, linux-kernel, linux-serial
In-Reply-To: <20260519203506.1341241-1-arnd@kernel.org>
Hi Anrnd,
On Tue, 19 May 2026 22:34:25 +0200
Arnd Bergmann <arnd@kernel.org> wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> Allowing the driver to be built when CONFIG_SPI_MASTER is turned off
> now causes build failures:
A few days ago i sent v2 of a patch to fix this problem:
https://lore.kernel.org/all/20260515183217.3554037-1-hugo@hugovil.com/raw
Did you saw it?
>
> drivers/tty/serial/max310x.c: In function 'max310x_uart_init':
> drivers/tty/serial/max310x.c:1737:32: error: 'max310x_spi_driver' undeclared (first use in this function); did you mean 'max310x_i2c_driver'?
> 1737 | spi_unregister_driver(&max310x_spi_driver);
> | ^~~~~~~~~~~~~~~~~~
> | max310x_i2c_driver
> drivers/tty/serial/max310x.c:1737:32: note: each undeclared identifier is reported only once for each function it appears in
> drivers/tty/serial/max310x.c:1740:1: error: label 'err_spi_register' defined but not used [-Werror=unused-label]
> 1740 | err_spi_register:
> | ^~~~~~~~~~~~~~~~
> drivers/tty/serial/max310x.c: At top level:
> drivers/tty/serial/max310x.c:1502:29: error: 'regcfg' defined but not used [-Werror=unused-variable]
> 1502 | static struct regmap_config regcfg = {
> | ^~~~~~
>
> While fixing this, I ran into another problem with I2C=m, which
> previously would just not use I2C support.
>
> Fix the #ifdef checks to handle all combinations correctly, and
> change the Kconfig dependency to ensure that the driver cannot
> be built-in when I2C=m.
>
> Fixes: 20ffe4b3330a ("serial: max310x: allow driver to be built with SPI or I2C")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/tty/serial/Kconfig | 1 +
> drivers/tty/serial/max310x.c | 40 +++++++++++++++++++-----------------
> 2 files changed, 22 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index 811250bbbd39..b9b40e80ea81 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -323,6 +323,7 @@ config SERIAL_MAX3100
> config SERIAL_MAX310X
> tristate "MAX310X support"
> depends on SPI_MASTER || I2C
> + depends on I2C || !I2C
> select SERIAL_CORE
> select REGMAP_SPI if SPI_MASTER
> select REGMAP_I2C if I2C
> diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
> index 5168490a1cbb..042ae962c1f6 100644
> --- a/drivers/tty/serial/max310x.c
> +++ b/drivers/tty/serial/max310x.c
> @@ -1499,6 +1499,20 @@ static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
> };
> MODULE_DEVICE_TABLE(of, max310x_dt_ids);
>
> +static const char *max310x_regmap_name(u8 port_id)
> +{
> + switch (port_id) {
> + case 0: return "port0";
> + case 1: return "port1";
> + case 2: return "port2";
> + case 3: return "port3";
> + default:
> + WARN_ON(true);
> + return NULL;
> + }
> +}
> +
> +#ifdef CONFIG_SPI_MASTER
> static struct regmap_config regcfg = {
> .reg_bits = 8,
> .val_bits = 8,
> @@ -1514,20 +1528,6 @@ static struct regmap_config regcfg = {
> .max_raw_write = MAX310X_FIFO_SIZE,
> };
>
> -static const char *max310x_regmap_name(u8 port_id)
> -{
> - switch (port_id) {
> - case 0: return "port0";
> - case 1: return "port1";
> - case 2: return "port2";
> - case 3: return "port3";
> - default:
> - WARN_ON(true);
> - return NULL;
> - }
> -}
> -
> -#ifdef CONFIG_SPI_MASTER
> static int max310x_spi_extended_reg_enable(struct device *dev, bool enable)
> {
> struct max310x_port *s = dev_get_drvdata(dev);
> @@ -1598,7 +1598,7 @@ static struct spi_driver max310x_spi_driver = {
> };
> #endif
>
> -#ifdef CONFIG_I2C
> +#if IS_ENABLED(CONFIG_I2C)
> static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable)
> {
> return 0;
> @@ -1724,7 +1724,7 @@ static int __init max310x_uart_init(void)
> goto err_spi_register;
> #endif
>
> -#ifdef CONFIG_I2C
> +#if IS_ENABLED(CONFIG_I2C)
> ret = i2c_add_driver(&max310x_i2c_driver);
> if (ret)
> goto err_i2c_register;
> @@ -1732,12 +1732,14 @@ static int __init max310x_uart_init(void)
>
> return 0;
>
> -#ifdef CONFIG_I2C
> +#if IS_ENABLED(CONFIG_I2C)
> err_i2c_register:
> +#endif
> +#ifdef CONFIG_SPI_MASTER
> spi_unregister_driver(&max310x_spi_driver);
> +err_spi_register:
> #endif
>
> -err_spi_register:
> uart_unregister_driver(&max310x_uart);
>
> return ret;
> @@ -1746,7 +1748,7 @@ module_init(max310x_uart_init);
>
> static void __exit max310x_uart_exit(void)
> {
> -#ifdef CONFIG_I2C
> +#if IS_ENABLED(CONFIG_I2C)
> i2c_del_driver(&max310x_i2c_driver);
> #endif
>
> --
> 2.39.5
>
>
>
--
Hugo Villeneuve
^ permalink raw reply
* [PATCH] serial: max310x: fix I2C-only build
From: Arnd Bergmann @ 2026-05-19 20:34 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Hugo Villeneuve
Cc: Arnd Bergmann, Randy Dunlap, Geert Uytterhoeven, linux-kernel,
linux-serial
From: Arnd Bergmann <arnd@arndb.de>
Allowing the driver to be built when CONFIG_SPI_MASTER is turned off
now causes build failures:
drivers/tty/serial/max310x.c: In function 'max310x_uart_init':
drivers/tty/serial/max310x.c:1737:32: error: 'max310x_spi_driver' undeclared (first use in this function); did you mean 'max310x_i2c_driver'?
1737 | spi_unregister_driver(&max310x_spi_driver);
| ^~~~~~~~~~~~~~~~~~
| max310x_i2c_driver
drivers/tty/serial/max310x.c:1737:32: note: each undeclared identifier is reported only once for each function it appears in
drivers/tty/serial/max310x.c:1740:1: error: label 'err_spi_register' defined but not used [-Werror=unused-label]
1740 | err_spi_register:
| ^~~~~~~~~~~~~~~~
drivers/tty/serial/max310x.c: At top level:
drivers/tty/serial/max310x.c:1502:29: error: 'regcfg' defined but not used [-Werror=unused-variable]
1502 | static struct regmap_config regcfg = {
| ^~~~~~
While fixing this, I ran into another problem with I2C=m, which
previously would just not use I2C support.
Fix the #ifdef checks to handle all combinations correctly, and
change the Kconfig dependency to ensure that the driver cannot
be built-in when I2C=m.
Fixes: 20ffe4b3330a ("serial: max310x: allow driver to be built with SPI or I2C")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/tty/serial/Kconfig | 1 +
drivers/tty/serial/max310x.c | 40 +++++++++++++++++++-----------------
2 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 811250bbbd39..b9b40e80ea81 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -323,6 +323,7 @@ config SERIAL_MAX3100
config SERIAL_MAX310X
tristate "MAX310X support"
depends on SPI_MASTER || I2C
+ depends on I2C || !I2C
select SERIAL_CORE
select REGMAP_SPI if SPI_MASTER
select REGMAP_I2C if I2C
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 5168490a1cbb..042ae962c1f6 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1499,6 +1499,20 @@ static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, max310x_dt_ids);
+static const char *max310x_regmap_name(u8 port_id)
+{
+ switch (port_id) {
+ case 0: return "port0";
+ case 1: return "port1";
+ case 2: return "port2";
+ case 3: return "port3";
+ default:
+ WARN_ON(true);
+ return NULL;
+ }
+}
+
+#ifdef CONFIG_SPI_MASTER
static struct regmap_config regcfg = {
.reg_bits = 8,
.val_bits = 8,
@@ -1514,20 +1528,6 @@ static struct regmap_config regcfg = {
.max_raw_write = MAX310X_FIFO_SIZE,
};
-static const char *max310x_regmap_name(u8 port_id)
-{
- switch (port_id) {
- case 0: return "port0";
- case 1: return "port1";
- case 2: return "port2";
- case 3: return "port3";
- default:
- WARN_ON(true);
- return NULL;
- }
-}
-
-#ifdef CONFIG_SPI_MASTER
static int max310x_spi_extended_reg_enable(struct device *dev, bool enable)
{
struct max310x_port *s = dev_get_drvdata(dev);
@@ -1598,7 +1598,7 @@ static struct spi_driver max310x_spi_driver = {
};
#endif
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable)
{
return 0;
@@ -1724,7 +1724,7 @@ static int __init max310x_uart_init(void)
goto err_spi_register;
#endif
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&max310x_i2c_driver);
if (ret)
goto err_i2c_register;
@@ -1732,12 +1732,14 @@ static int __init max310x_uart_init(void)
return 0;
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
err_i2c_register:
+#endif
+#ifdef CONFIG_SPI_MASTER
spi_unregister_driver(&max310x_spi_driver);
+err_spi_register:
#endif
-err_spi_register:
uart_unregister_driver(&max310x_uart);
return ret;
@@ -1746,7 +1748,7 @@ module_init(max310x_uart_init);
static void __exit max310x_uart_exit(void)
{
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&max310x_i2c_driver);
#endif
--
2.39.5
^ permalink raw reply related
* Re: [PATCH v9] Bluetooth: hci_uart: fix UAFs and race conditions in close and init paths
From: patchwork-bot+bluetooth @ 2026-05-19 15:00 UTC (permalink / raw)
To: w15303746062
Cc: luiz.dentz, pmenzel, marcel, linux-bluetooth, linux-serial,
linux-kernel, greg, stable, 25181214217
In-Reply-To: <20260518024949.439299-1-w15303746062@163.com>
Hello:
This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Mon, 18 May 2026 10:49:49 +0800 you wrote:
> From: Mingyu Wang <25181214217@stu.xidian.edu.cn>
>
> Vulnerabilities leading to Use-After-Free (UAF) and Null Pointer
> Dereference (NPD) conditions were observed in the lifecycle management
> of hci_uart.
>
> The primary issue arises because the workqueues (init_ready and
> write_work) are only flushed/cancelled if the HCI_UART_PROTO_READY
> flag is set during TTY close. If a hangup occurs before setup completes,
> hci_uart_tty_close() skips the teardown of these workqueues and
> proceeds to free the `hu` struct. When the scheduled work executes
> later, it blindly dereferences the freed `hu` struct.
>
> [...]
Here is the summary with links:
- [v9] Bluetooth: hci_uart: fix UAFs and race conditions in close and init paths
https://git.kernel.org/bluetooth/bluetooth-next/c/7db62a762f61
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH RFC] serial: 8250: fix possible ISR soft lockup
From: Marco Felsch @ 2026-05-19 9:57 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: linux-kernel, linux-serial, k-willis, m-shah, kernel,
Marco Felsch
There are rare cases in which the host gets stuck in the ISR because it
is flooded with messages during the startup phase.
The reason for the soft lockup in the ISR is the missing FIFO error IRQ
(FIFOE) handling. Not handling it and reporting IRQ_HANDLED triggers
the IRQ immediately again.
Fix this by adding a check for the FIFOE status and clearing the FIFO
if no data is ready (DR).
This behavior was observed on an AM62L device which uses the OMAP 8250
driver. Fix it for all 8250 drivers, since the OMAP driver's special
IRQ setup handling may trigger this behavior more frequently, but it
is not ensured that other 8250 drivers aren't affected.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
drivers/tty/serial/8250/8250_port.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index af78cc02f38e719573becd0aea226f7790555a3e..f9135df3cc7c2662522197518995e5e1a6880ec2 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1797,6 +1797,13 @@ void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir)
status = serial_lsr_in(up);
+ /*
+ * Recover from no-data-ready and FIFO error condition to avoid getting
+ * stuck in the ISR.
+ */
+ if (!(status & UART_LSR_DR) && (status & UART_LSR_FIFOE))
+ serial8250_clear_and_reinit_fifos(up);
+
/*
* If port is stopped and there are no error conditions in the
* FIFO, then don't drain the FIFO, as this may lead to TTY buffer
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260519-v7-1-topic-serial-8250-03fc6537e35e
Best regards,
--
Marco Felsch <m.felsch@pengutronix.de>
^ permalink raw reply related
* Re: [PATCH 01/15] serial: 8250: split Moxa PCIe serial board support out of 8250_pci
From: Andy Shevchenko @ 2026-05-19 7:57 UTC (permalink / raw)
To: Crescent Hsieh
Cc: gregkh, jirislaby, ilpo.jarvinen, fangpingfp.cheng, linux-kernel,
linux-serial
In-Reply-To: <agsLvCVll66tPoFA@moxa-ThinkCentre-M90t>
On Mon, May 18, 2026 at 3:53 PM Crescent Hsieh
<crescentcy.hsieh@moxa.com> wrote:
> On Mon, May 04, 2026 at 04:27:44PM +0300, Andy Shevchenko wrote:
> > On Mon, May 4, 2026 at 11:49 AM Crescent Hsieh
> > <crescentcy.hsieh@moxa.com> wrote:
> > > +static void mxpcie8250_remove(struct pci_dev *pdev)
> > > +{
> > > + struct mxpcie8250 *priv = dev_get_drvdata(&pdev->dev);
> >
> > platform_get_drvdata() IIRC
>
> In a previous patchset, dev_get_drvdata() was suggested for similar
> cases [1].
The case is not similar, while looking familiar. Here we have a PCI
device already given as a parameter (sorry, I mixed it with platform
in my previous reply), and there the uart_port, from which you take
device, convert to PCI and use pci_get_drvdata(). There it's a detour
as one may use dev_get_drvdata(port->dev) without PCI being involved.
> Since 8250_mxpcie is a PCI driver, could you clarify what you would
> prefer here for retrieving the private data? I was not sure whether the
> intention was to use dev_get_drvdata(), pci_get_drvdata(), or something
> else, since platform_get_drvdata() does not seem to match this driver
> type.
pci_get_drvdata().
> [1]
> https://lore.kernel.org/all/CAHp75VcPanVWaLi39Wf-pq8nA+xbeJUs=v1BACz-+Sns0BVyWg@mail.gmail.com/
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH v3 2/2] serial: qcom-geni: Add tracepoints for Qualcomm GENI serial driver
From: Praveen Talari @ 2026-05-18 17:56 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Greg Kroah-Hartman, Jiri Slaby, Konrad Dybcio
Cc: linux-kernel, linux-trace-kernel, linux-arm-msm, linux-serial,
Mukesh Kumar Savaliya, Aniket Randive, chandana.chiluveru,
jyothi.seerapu, Praveen Talari
In-Reply-To: <20260518-add-tracepoints-for-qcom-geni-serial-v3-0-b4addb151376@oss.qualcomm.com>
Add tracing to the Qualcomm GENI serial driver to improve runtime
observability.
Trace hooks are added at key points including termios and clock
configuration, manual control get/set, interrupt handling, and data
TX/RX paths.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
---
v2->v3:
- Updated commit text(removed example as it was available on cover
letter).
---
drivers/tty/serial/qcom_geni_serial.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index e6b0a55f0cfb..9e2de074d799 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -7,6 +7,9 @@
/* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */
#define __DISABLE_TRACE_MMIO__
+#define CREATE_TRACE_POINTS
+#include <trace/events/qcom_geni_serial.h>
+
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/io.h>
@@ -225,7 +228,7 @@ static void qcom_geni_serial_config_port(struct uart_port *uport, int cfg_flags)
static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport)
{
unsigned int mctrl = TIOCM_DSR | TIOCM_CAR;
- u32 geni_ios;
+ u32 geni_ios = 0;
if (uart_console(uport)) {
mctrl |= TIOCM_CTS;
@@ -235,6 +238,8 @@ static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport)
mctrl |= TIOCM_CTS;
}
+ trace_geni_serial_get_mctrl(uport->dev, mctrl, geni_ios);
+
return mctrl;
}
@@ -253,6 +258,8 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport,
if (!(mctrl & TIOCM_RTS) && !uport->suspended)
uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY;
writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR);
+
+ trace_geni_serial_set_mctrl(uport->dev, mctrl, uart_manual_rfr);
}
static const char *qcom_geni_serial_get_type(struct uart_port *uport)
@@ -683,6 +690,8 @@ static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
xmit_size = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
UART_XMIT_SIZE);
+ trace_geni_serial_tx_data(uport->dev, tail, xmit_size);
+
qcom_geni_set_rs485_mode(uport, SER_RS485_RTS_ON_SEND);
qcom_geni_serial_setup_tx(uport, xmit_size);
@@ -909,8 +918,10 @@ static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop)
return;
}
- if (!drop)
+ if (!drop) {
+ trace_geni_serial_rx_data(uport->dev, port->rx_buf, rx_in);
handle_rx_uart(uport, rx_in);
+ }
ret = geni_se_rx_dma_prep(&port->se, port->rx_buf,
DMA_RX_BUF_SIZE,
@@ -1069,6 +1080,10 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
geni_status = readl(uport->membase + SE_GENI_STATUS);
dma = readl(uport->membase + SE_GENI_DMA_MODE_EN);
m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
+
+ trace_geni_serial_irq(uport->dev, m_irq_status, s_irq_status,
+ dma_tx_status, dma_rx_status);
+
writel(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
writel(dma_tx_status, uport->membase + SE_DMA_TX_IRQ_CLR);
@@ -1281,8 +1296,8 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
return -EINVAL;
}
- dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n, clk_idx = %u\n",
- baud * sampling_rate, clk_rate, clk_div, clk_idx);
+ trace_geni_serial_clk_cfg(uport->dev, baud * sampling_rate, clk_rate,
+ clk_div, clk_idx);
uport->uartclk = clk_rate;
port->clk_rate = clk_rate;
@@ -1432,6 +1447,10 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN);
writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN);
writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
+
+ trace_geni_serial_set_termios(uport->dev, baud, bits_per_char,
+ tx_trans_cfg, tx_parity_cfg, rx_trans_cfg,
+ rx_parity_cfg, stop_bit_len);
}
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
--
2.34.1
^ permalink raw reply related
* [PATCH v3 1/2] serial: qcom-geni: trace: Add tracepoint support for Qualcomm GENI serial
From: Praveen Talari @ 2026-05-18 17:56 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Greg Kroah-Hartman, Jiri Slaby, Konrad Dybcio
Cc: linux-kernel, linux-trace-kernel, linux-arm-msm, linux-serial,
Mukesh Kumar Savaliya, Aniket Randive, chandana.chiluveru,
jyothi.seerapu, Praveen Talari
In-Reply-To: <20260518-add-tracepoints-for-qcom-geni-serial-v3-0-b4addb151376@oss.qualcomm.com>
Add tracepoint support to the Qualcomm GENI serial driver to provide
runtime visibility into driver behavior without requiring invasive debug
patches.
The trace events cover UART termios configuration, clock setup, modem
control state, interrupt status, and TX/RX data, making it easier to
diagnose communication issues in the field.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
---
v2->v3:
- Removed \n from geni_serial_tx_data and geni_serial_rx_data events.
- Resolved aligment issues in geni_serial_data, geni_serial_tx_data and
geni_serial_rx_data events.
v1->v2:
- Removed multiple TX/RX trace events, instead used
DECLARE_EVENT_CLASS and DEFINE_EVENT.
---
include/trace/events/qcom_geni_serial.h | 164 ++++++++++++++++++++++++++++++++
1 file changed, 164 insertions(+)
diff --git a/include/trace/events/qcom_geni_serial.h b/include/trace/events/qcom_geni_serial.h
new file mode 100644
index 000000000000..417ec01f9fc8
--- /dev/null
+++ b/include/trace/events/qcom_geni_serial.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM qcom_geni_serial
+
+#if !defined(_TRACE_QCOM_GENI_SERIAL_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_QCOM_GENI_SERIAL_H
+
+#include <linux/device.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(geni_serial_set_termios,
+ TP_PROTO(struct device *dev, unsigned int baud,
+ unsigned int bits_per_char, u32 tx_trans_cfg,
+ u32 tx_parity_cfg, u32 rx_trans_cfg,
+ u32 rx_parity_cfg, u32 stop_bit_len),
+ TP_ARGS(dev, baud, bits_per_char, tx_trans_cfg, tx_parity_cfg,
+ rx_trans_cfg, rx_parity_cfg, stop_bit_len),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(unsigned int, baud)
+ __field(unsigned int, bits_per_char)
+ __field(u32, tx_trans_cfg)
+ __field(u32, tx_parity_cfg)
+ __field(u32, rx_trans_cfg)
+ __field(u32, rx_parity_cfg)
+ __field(u32, stop_bit_len)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->baud = baud;
+ __entry->bits_per_char = bits_per_char;
+ __entry->tx_trans_cfg = tx_trans_cfg;
+ __entry->tx_parity_cfg = tx_parity_cfg;
+ __entry->rx_trans_cfg = rx_trans_cfg;
+ __entry->rx_parity_cfg = rx_parity_cfg;
+ __entry->stop_bit_len = stop_bit_len;
+ ),
+
+ TP_printk("%s: baud=%u bpc=%u tx_trans=0x%08x tx_par=0x%08x rx_trans=0x%08x rx_par=0x%08x stop=%u",
+ __get_str(name), __entry->baud, __entry->bits_per_char,
+ __entry->tx_trans_cfg, __entry->tx_parity_cfg,
+ __entry->rx_trans_cfg, __entry->rx_parity_cfg,
+ __entry->stop_bit_len)
+);
+
+TRACE_EVENT(geni_serial_clk_cfg,
+ TP_PROTO(struct device *dev, unsigned int desired_rate,
+ unsigned long clk_rate, unsigned int clk_div,
+ unsigned int clk_idx),
+ TP_ARGS(dev, desired_rate, clk_rate, clk_div, clk_idx),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(unsigned int, desired_rate)
+ __field(unsigned long, clk_rate)
+ __field(unsigned int, clk_div)
+ __field(unsigned int, clk_idx)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->desired_rate = desired_rate;
+ __entry->clk_rate = clk_rate;
+ __entry->clk_div = clk_div;
+ __entry->clk_idx = clk_idx;
+ ),
+
+ TP_printk("%s: desired_rate=%u clk_rate=%lu clk_div=%u clk_idx=%u",
+ __get_str(name), __entry->desired_rate, __entry->clk_rate,
+ __entry->clk_div, __entry->clk_idx)
+);
+
+TRACE_EVENT(geni_serial_irq,
+ TP_PROTO(struct device *dev, u32 m_irq, u32 s_irq,
+ u32 dma_tx, u32 dma_rx),
+ TP_ARGS(dev, m_irq, s_irq, dma_tx, dma_rx),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(u32, m_irq)
+ __field(u32, s_irq)
+ __field(u32, dma_tx)
+ __field(u32, dma_rx)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->m_irq = m_irq;
+ __entry->s_irq = s_irq;
+ __entry->dma_tx = dma_tx;
+ __entry->dma_rx = dma_rx;
+ ),
+
+ TP_printk("%s: m_irq=0x%08x s_irq=0x%08x dma_tx=0x%08x dma_rx=0x%08x",
+ __get_str(name), __entry->m_irq, __entry->s_irq,
+ __entry->dma_tx, __entry->dma_rx)
+);
+
+DECLARE_EVENT_CLASS(geni_serial_data,
+ TP_PROTO(struct device *dev, const u8 *buf, unsigned int len),
+ TP_ARGS(dev, buf, len),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(unsigned int, len)
+ __dynamic_array(u8, data, len)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->len = len;
+ memcpy(__get_dynamic_array(data), buf, len);
+ ),
+
+ TP_printk("%s: len=%u data=%s",
+ __get_str(name), __entry->len,
+ __print_hex(__get_dynamic_array(data), __entry->len))
+);
+
+DEFINE_EVENT(geni_serial_data, geni_serial_tx_data,
+ TP_PROTO(struct device *dev, const u8 *buf, unsigned int len),
+ TP_ARGS(dev, buf, len)
+);
+
+DEFINE_EVENT(geni_serial_data, geni_serial_rx_data,
+ TP_PROTO(struct device *dev, const u8 *buf, unsigned int len),
+ TP_ARGS(dev, buf, len)
+);
+
+TRACE_EVENT(geni_serial_set_mctrl,
+ TP_PROTO(struct device *dev, unsigned int mctrl,
+ u32 uart_manual_rfr),
+ TP_ARGS(dev, mctrl, uart_manual_rfr),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(unsigned int, mctrl)
+ __field(u32, uart_manual_rfr)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->mctrl = mctrl;
+ __entry->uart_manual_rfr = uart_manual_rfr;
+ ),
+
+ TP_printk("%s: mctrl=0x%04x uart_manual_rfr=0x%08x",
+ __get_str(name), __entry->mctrl, __entry->uart_manual_rfr)
+);
+
+TRACE_EVENT(geni_serial_get_mctrl,
+ TP_PROTO(struct device *dev, unsigned int mctrl, u32 geni_ios),
+ TP_ARGS(dev, mctrl, geni_ios),
+
+ TP_STRUCT__entry(__string(name, dev_name(dev))
+ __field(unsigned int, mctrl)
+ __field(u32, geni_ios)
+ ),
+
+ TP_fast_assign(__assign_str(name);
+ __entry->mctrl = mctrl;
+ __entry->geni_ios = geni_ios;
+ ),
+
+ TP_printk("%s: mctrl=0x%04x geni_ios=0x%08x",
+ __get_str(name), __entry->mctrl, __entry->geni_ios)
+);
+
+#endif /* _TRACE_QCOM_GENI_SERIAL_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.34.1
^ permalink raw reply related
* [PATCH v3 0/2] Add tracepoints support for Qualcomm GENI Serial drivers
From: Praveen Talari @ 2026-05-18 17:56 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Greg Kroah-Hartman, Jiri Slaby, Konrad Dybcio
Cc: linux-kernel, linux-trace-kernel, linux-arm-msm, linux-serial,
Mukesh Kumar Savaliya, Aniket Randive, chandana.chiluveru,
jyothi.seerapu, Praveen Talari
Add tracepoints to the Qualcomm GENI (Generic Interface) serial driver.
These trace events enable runtime debugging and performance analysis of
UART operations.
The trace events cover UART termios configuration, clock setup, manual
control state, interrupt status, and actual transmitted/received data in
hexadecimal format.
Usage examples:
Enable all serial traces:
echo 1 > /sys/kernel/debug/tracing/events/qcom_geni_serial/enable
cat /sys/kernel/debug/tracing/trace_pipe
Example trace output:
2517.938432: geni_serial_clk_cfg: a94000.serial: desired_rate=1843200
clk_rate=7372800 clk_div=4 clk_idx=0
2517.938753: geni_serial_irq: a94000.serial: m_irq=0x88800000
s_irq=0x08000111 dma_tx=0x00000000 dma_rx=0x00000000
2517.938803: geni_serial_set_termios: a94000.serial: baud=115200 bpc=8
tx_trans=0x00000002 tx_par=0x00000000 rx_trans=0x00000000
rx_par=0x00000000 stop=0
2517.938807: geni_serial_set_mctrl: a94000.serial: mctrl=0x8006
uart_manual_rfr=0x00000000
2517.938818: geni_serial_get_mctrl: a94000.serial: mctrl=0x0160
geni_ios=0x00000001
2517.939165: geni_serial_irq: a94000.serial: m_irq=0x00400000
s_irq=0x00000000 dma_tx=0x00000000 dma_rx=0x00000000
2517.939592: geni_serial_tx_data: a94000.serial: tx_len=8 data=61 62 63
64 65 66 67 68
2517.940610: geni_serial_irq: a94000.serial: m_irq=0x00000001
s_irq=0x00000000 dma_tx=0x00000003 dma_rx=0x00000000
2517.942174: geni_serial_irq: a94000.serial: m_irq=0x08000000
s_irq=0x08000100 dma_tx=0x00000000 dma_rx=0x00000003
2517.942323: geni_serial_rx_data: a94000.serial: rx_len=8 data=61 62 63
64 65 66 67 68
2517.942680: geni_serial_set_mctrl: a94000.serial: mctrl=0x8000
uart_manual_rfr=0x80000002
Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
---
Changes in v3:
- Removed \n from geni_serial_tx_data and geni_serial_rx_data events.
- Resolved aligment issues in geni_serial_data, geni_serial_tx_data and
geni_serial_rx_data events.
- Link to v2: https://lore.kernel.org/r/20260512-add-tracepoints-for-qcom-geni-serial-v2-0-a5726421b3af@oss.qualcomm.com
Changes in v2:
- removed multiple trace events for TX/RX events, instead used
DECLARE_EVENT_CLASS and DEFINE_EVENT.
- Link to v1: https://lore.kernel.org/r/20260506-add-tracepoints-for-qcom-geni-serial-v1-0-544b22612e08@oss.qualcomm.com
---
Praveen Talari (2):
serial: qcom-geni: trace: Add tracepoint support for Qualcomm GENI serial
serial: qcom-geni: Add tracepoints for Qualcomm GENI serial driver
drivers/tty/serial/qcom_geni_serial.c | 27 +++++-
include/trace/events/qcom_geni_serial.h | 164 ++++++++++++++++++++++++++++++++
2 files changed, 187 insertions(+), 4 deletions(-)
---
base-commit: 1f5ffc672165ff851063a5fd044b727ab2517ae3
change-id: 20260427-add-tracepoints-for-qcom-geni-serial-948777218b7b
Best regards,
--
Praveen Talari <praveen.talari@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH 00/13] Add DMA support for LINFlexD UART driver
From: Enric Balletbo i Serra @ 2026-05-18 14:14 UTC (permalink / raw)
To: Jared Kangas
Cc: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas, linux-kernel,
linux-serial, devicetree, linux-media, dri-devel, linaro-mm-sig,
s32, imx, clizzi, aruizrui, echanude
In-Reply-To: <aaGkGwbk-sh0YJqj@jkangas-thinkpadp1gen3.rmtuswa.csb>
Hi all,
Any chance these series can be considered? They still apply on top of
the mainline kernel.
On Fri, Feb 27, 2026 at 3:03 PM Jared Kangas <jkangas@redhat.com> wrote:
>
> Hi Larisa,
>
> On Mon, Feb 16, 2026 at 04:01:52PM +0100, Larisa Grigore wrote:
> > This patchset enhances the LINFlexD UART driver and its device tree bindings to
> > support DMA transfers, configurable clock inputs, dynamic baudrate changes, and
> > termios features. It also includes a series of fixes and improvements to ensure
> > reliable operation across various modes and configurations.
> >
> > The changes added can be summarized as follows:
> > 1. Fixes with respect to FIFO handling, locking, interrupt related registers and
> > INITM mode transition.
>
> Tested this series with the default devicetree configuration by booting
> the board to a login prompt about 200 times. Without the series applied,
> I was seeing a bug roughly every 30-50 boots where the kernel would
> would hang in linflex_console_putchar() waiting for DTFTFF. In my tests
> with the series applied, I didn't see any regressions and the bug no
> longer appeared. Thanks for the fix!
>
> Tested-by: Jared Kangas <jkangas@redhat.com> # S32G3, interrupt-driven
>
FWIW I also reproduced the issue Jared faced. Current state of the
LinFLEX serial driver in mainline seems a bit buggy and I can confirm
that these fix the problem.
Tested-by: Enric Balletbo i Serra <eballetb@redhat.com>
> > 2. Removal of the earlycon workaround, as proper FIFO handling and INITM
> > transitions now ensure stable behavior.
> > 3. Support for configurable stop bits and dynamic baudrate changes based on
> > clock inputs and termios settings.
> > 4. Optional DMA support for RX and TX paths, preventing character loss during
> > high-throughput operations like copy-paste. Cyclic DMA is used for RX to avoid
> > gaps between transactions.
> >
> > Larisa Grigore (8):
> > serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend
> > serial: linflexuart: Check FIFO full before writing
> > serial: linflexuart: Correctly clear UARTSR in buffer mode
> > serial: linflexuart: Update RXEN/TXEN outside INITM mode
> > serial: linflexuart: Ensure FIFO is empty when entering INITM
> > serial: linflexuart: Revert earlycon workaround
> > serial: linflexuart: Add support for configurable stop bits
> > serial: linflexuart: Add DMA support
> >
> > Radu Pirea (5):
> > serial: linflexuart: Fix locking in set_termios
> > dt-bindings: serial: fsl-linflexuart: add clock input properties
> > dt-bindings: serial: fsl-linflexuart: add dma properties
> > serial: linflexuart: Add support for changing baudrate
> > serial: linflexuart: Avoid stopping DMA during receive operations
> >
> > .../bindings/serial/fsl,s32-linflexuart.yaml | 31 +
> > drivers/tty/serial/fsl_linflexuart.c | 972 +++++++++++++++---
> > 2 files changed, 846 insertions(+), 157 deletions(-)
> >
> > --
> > 2.47.0
> >
>
^ permalink raw reply
* Re: [PATCH v2 1/2] serial: qcom-geni: trace: Add tracepoint support for Qualcomm GENI serial
From: Konrad Dybcio @ 2026-05-18 13:48 UTC (permalink / raw)
To: Praveen Talari, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-kernel, linux-trace-kernel, linux-arm-msm, linux-serial,
Mukesh Kumar Savaliya, Aniket Randive, chandana.chiluveru,
jyothi.seerapu
In-Reply-To: <20260512-add-tracepoints-for-qcom-geni-serial-v2-1-a5726421b3af@oss.qualcomm.com>
On 5/12/26 7:14 PM, Praveen Talari wrote:
> Add tracepoint support to the Qualcomm GENI serial driver to provide
> runtime visibility into driver behavior without requiring invasive debug
> patches.
>
> The trace events cover UART termios configuration, clock setup, modem
> control state, interrupt status, and TX/RX data, making it easier to
> diagnose communication issues in the field.
>
> Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
> ---
> v1->v2:
> - Removed multiple TX/RX trace events, instead used
> DECLARE_EVENT_CLASS and DEFINE_EVENT.
> ---
> include/trace/events/qcom_geni_serial.h | 172 ++++++++++++++++++++++++++++++++
> 1 file changed, 172 insertions(+)
>
> diff --git a/include/trace/events/qcom_geni_serial.h b/include/trace/events/qcom_geni_serial.h
> new file mode 100644
> index 000000000000..5e23827881d0
> --- /dev/null
> +++ b/include/trace/events/qcom_geni_serial.h
Oh, I only noticed now that this isn't in a subsystem/driver-
local directory.. I suppose it's up to the other maintainers
whether they like that
Konrad
^ permalink raw reply
* Re: [PATCH v2 2/2] serial: qcom-geni: Add tracepoints for Qualcomm GENI serial driver
From: Konrad Dybcio @ 2026-05-18 13:41 UTC (permalink / raw)
To: Praveen Talari, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-kernel, linux-trace-kernel, linux-arm-msm, linux-serial,
Mukesh Kumar Savaliya, Aniket Randive, chandana.chiluveru,
jyothi.seerapu
In-Reply-To: <20260512-add-tracepoints-for-qcom-geni-serial-v2-2-a5726421b3af@oss.qualcomm.com>
On 5/12/26 7:14 PM, Praveen Talari wrote:
> Add tracing to the Qualcomm GENI serial driver to improve runtime
> observability.
>
> Trace hooks are added at key points including termios and clock
> configuration, manual control get/set, interrupt handling, and data
> TX/RX paths.
>
> Usage examples:
>
> Enable all serial traces:
> echo 1 > /sys/kernel/debug/tracing/events/qcom_geni_serial/enable
> cat /sys/kernel/debug/tracing/trace_pipe
>
> Example trace output:
>
> 2517.938432: geni_serial_clk_cfg: a94000.serial: desired_rate=1843200
> clk_rate=7372800 clk_div=4 clk_idx=0
> 2517.938753: geni_serial_irq: a94000.serial: m_irq=0x88800000
> s_irq=0x08000111 dma_tx=0x00000000 dma_rx=0x00000000
> 2517.938803: geni_serial_set_termios: a94000.serial: baud=115200 bpc=8
> tx_trans=0x00000002 tx_par=0x00000000 rx_trans=0x00000000
> rx_par=0x00000000 stop=0
> 2517.938807: geni_serial_set_mctrl: a94000.serial: mctrl=0x8006
> uart_manual_rfr=0x00000000
> 2517.938818: geni_serial_get_mctrl: a94000.serial: mctrl=0x0160
> geni_ios=0x00000001
> 2517.939165: geni_serial_irq: a94000.serial: m_irq=0x00400000
> s_irq=0x00000000 dma_tx=0x00000000 dma_rx=0x00000000
> 2517.939592: geni_serial_tx_data: a94000.serial: tx_len=8 data=61 62 63
> 64 65 66 67 68
> 2517.940610: geni_serial_irq: a94000.serial: m_irq=0x00000001
> s_irq=0x00000000 dma_tx=0x00000003 dma_rx=0x00000000
> 2517.942174: geni_serial_irq: a94000.serial: m_irq=0x08000000
> s_irq=0x08000100 dma_tx=0x00000000 dma_rx=0x00000003
> 2517.942323: geni_serial_rx_data: a94000.serial: rx_len=8 data=61 62 63
> 64 65 66 67 68
> 2517.942680: geni_serial_set_mctrl: a94000.serial: mctrl=0x8000
> uart_manual_rfr=0x80000002
I think the example (or at least the data that it produces) could go
under the --- line, there's plenty of docs regarding tracing on
docs.kernel.org
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH v2 1/2] serial: qcom-geni: trace: Add tracepoint support for Qualcomm GENI serial
From: Konrad Dybcio @ 2026-05-18 13:40 UTC (permalink / raw)
To: Praveen Talari, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-kernel, linux-trace-kernel, linux-arm-msm, linux-serial,
Mukesh Kumar Savaliya, Aniket Randive, chandana.chiluveru,
jyothi.seerapu
In-Reply-To: <20260512-add-tracepoints-for-qcom-geni-serial-v2-1-a5726421b3af@oss.qualcomm.com>
On 5/12/26 7:14 PM, Praveen Talari wrote:
> Add tracepoint support to the Qualcomm GENI serial driver to provide
> runtime visibility into driver behavior without requiring invasive debug
> patches.
>
> The trace events cover UART termios configuration, clock setup, modem
> control state, interrupt status, and TX/RX data, making it easier to
> diagnose communication issues in the field.
>
> Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
> ---
[...]
> +DEFINE_EVENT(geni_serial_data, geni_serial_tx_data,
> +
> + TP_PROTO(struct device *dev, const u8 *buf, unsigned int len),
> +
> + TP_ARGS(dev, buf, len)
> +
> +);
> +
> +DEFINE_EVENT(geni_serial_data, geni_serial_rx_data,
> +
> + TP_PROTO(struct device *dev, const u8 *buf, unsigned int len),
> +
> + TP_ARGS(dev, buf, len)
> +
> +);
stray \ns above
otherwise lgtm
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH 01/15] serial: 8250: split Moxa PCIe serial board support out of 8250_pci
From: Crescent Hsieh @ 2026-05-18 12:53 UTC (permalink / raw)
To: Andy Shevchenko
Cc: gregkh, jirislaby, ilpo.jarvinen, fangpingfp.cheng, linux-kernel,
linux-serial
In-Reply-To: <CAHp75VfFMLnLDP0V3U=4zG4Ayj71-ZgVkJsVtgNE=52tGQ963w@mail.gmail.com>
On Mon, May 04, 2026 at 04:27:44PM +0300, Andy Shevchenko wrote:
> On Mon, May 4, 2026 at 11:49 AM Crescent Hsieh
> <crescentcy.hsieh@moxa.com> wrote:
> > +static void mxpcie8250_remove(struct pci_dev *pdev)
> > +{
> > + struct mxpcie8250 *priv = dev_get_drvdata(&pdev->dev);
>
> platform_get_drvdata() IIRC
In a previous patchset, dev_get_drvdata() was suggested for similar
cases [1].
Since 8250_mxpcie is a PCI driver, could you clarify what you would
prefer here for retrieving the private data? I was not sure whether the
intention was to use dev_get_drvdata(), pci_get_drvdata(), or something
else, since platform_get_drvdata() does not seem to match this driver
type.
[1]
https://lore.kernel.org/all/CAHp75VcPanVWaLi39Wf-pq8nA+xbeJUs=v1BACz-+Sns0BVyWg@mail.gmail.com/
---
Sincerely,
Crescent Hsieh
^ permalink raw reply
* Re: [PATCH] drm: Use named initializers for arrays of i2c_device_data
From: Uwe Kleine-König (The Capable Hub) @ 2026-05-18 11:07 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Tapio Reijonen, Dan Carpenter,
Xichao Zhao, Bartosz Golaszewski, Hugo Villeneuve
Cc: linux-kernel, linux-serial
In-Reply-To: <20260518101456.632410-2-u.kleine-koenig@baylibre.com>
[-- Attachment #1: Type: text/plain, Size: 267 bytes --]
Hello,
I messed up the Subject, of course this should have been:
[PATCH] tty: serial: Use named initializers for arrays of i2c_device_data
please fix up accordingly iff you apply this version. If I should resend
for this reason, please tell me.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH] drm: Use named initializers for arrays of i2c_device_data
From: Uwe Kleine-König (The Capable Hub) @ 2026-05-18 10:14 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Tapio Reijonen, Dan Carpenter,
Xichao Zhao, Bartosz Golaszewski, Hugo Villeneuve
Cc: linux-kernel, linux-serial
While being less compact, using named initializers allows to more easily
see which members of the structs are assigned which value without having
to lookup the declaration of the struct. And it's also more robust
against changes to the struct definition.
The mentioned robustness is relevant for a planned change to struct
i2c_device_id that replaces .driver_data by an anonymous union.
While touching all these arrays, unify usage of whitespace in the list
terminator.
This patch doesn't modify the compiled arrays, only their representation
in source form benefits. The former was confirmed with x86 and arm64
builds.
Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
---
Hello,
the mentioned change to i2c_device_id is the following:
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 23ff24080dfd..aebd3a5e90af 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -477,7 +477,11 @@ struct rpmsg_device_id {
struct i2c_device_id {
char name[I2C_NAME_SIZE];
- kernel_ulong_t driver_data; /* Data private to the driver */
+ union {
+ /* Data private to the driver */
+ kernel_ulong_t driver_data;
+ const void *driver_data_ptr;
+ };
};
/* pci_epf */
and this requires that .driver_data is assigned via a named initializer
for static data. This requirement isn't a bad one because named
initializers are also much better readable than list initializers.
The union added to struct i2c_device_id enables further cleanups like:
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index 0123ca8157a8..dfb0b07500a7 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -207,8 +207,8 @@ struct ad5398_current_data_format {
static const struct ad5398_current_data_format df_10_4_120 = {10, 4, 0, 120000};
static const struct i2c_device_id ad5398_id[] = {
- { .name = "ad5398", .driver_data = (kernel_ulong_t)&df_10_4_120 },
- { .name = "ad5821", .driver_data = (kernel_ulong_t)&df_10_4_120 },
+ { .name = "ad5398", .driver_data_ptr = &df_10_4_120 },
+ { .name = "ad5821", .driver_data_ptr = &df_10_4_120 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad5398_id);
@@ -219,8 +219,7 @@ static int ad5398_probe(struct i2c_client *client)
struct regulator_init_data *init_data = dev_get_platdata(&client->dev);
struct regulator_config config = { };
struct ad5398_chip_info *chip;
- const struct ad5398_current_data_format *df =
- (struct ad5398_current_data_format *)id->driver_data;
+ const struct ad5398_current_data_format *df = id->driver_data;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
that are an improvement for readability (again!) and it keeps some
properties of the pointers (here: being const) without having to pay
attention for that. (I didn't find a serial driver that benefits, so
this is "only" a regulator driver example.)
My additional motivation for this effort is CHERI[1]. This is a hardware
extension that uses 128 bit pointers but unsigned long is still 64 bit.
So with CHERI you cannot store pointers in unsigned long variables.
Best regards
Uwe
[1] https://cheri-alliance.org/discover-cheri/
https://lwn.net/Articles/1037974/
drivers/tty/serial/max310x.c | 8 ++++----
drivers/tty/serial/sc16is7xx_i2c.c | 14 +++++++-------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index ac7d3f197c3a..742b8c23bacf 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1671,10 +1671,10 @@ static void max310x_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id max310x_i2c_id_table[] = {
- { "max3107", (kernel_ulong_t)&max3107_devtype, },
- { "max3108", (kernel_ulong_t)&max3108_devtype, },
- { "max3109", (kernel_ulong_t)&max3109_devtype, },
- { "max14830", (kernel_ulong_t)&max14830_devtype, },
+ { .name = "max3107", .driver_data = (kernel_ulong_t)&max3107_devtype },
+ { .name = "max3108", .driver_data = (kernel_ulong_t)&max3108_devtype },
+ { .name = "max3109", .driver_data = (kernel_ulong_t)&max3109_devtype },
+ { .name = "max14830", .driver_data = (kernel_ulong_t)&max14830_devtype },
{ }
};
MODULE_DEVICE_TABLE(i2c, max310x_i2c_id_table);
diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c
index 699376c3b3a5..6c2a697556a6 100644
--- a/drivers/tty/serial/sc16is7xx_i2c.c
+++ b/drivers/tty/serial/sc16is7xx_i2c.c
@@ -39,13 +39,13 @@ static void sc16is7xx_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
- { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
- { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
- { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
- { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
+ { .name = "sc16is74x", .driver_data = (kernel_ulong_t)&sc16is74x_devtype },
+ { .name = "sc16is740", .driver_data = (kernel_ulong_t)&sc16is74x_devtype },
+ { .name = "sc16is741", .driver_data = (kernel_ulong_t)&sc16is74x_devtype },
+ { .name = "sc16is750", .driver_data = (kernel_ulong_t)&sc16is750_devtype },
+ { .name = "sc16is752", .driver_data = (kernel_ulong_t)&sc16is752_devtype },
+ { .name = "sc16is760", .driver_data = (kernel_ulong_t)&sc16is760_devtype },
+ { .name = "sc16is762", .driver_data = (kernel_ulong_t)&sc16is762_devtype },
{ }
};
MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
--
2.47.3
^ permalink raw reply related
* Re: [PATCH v2] tty: serial: atmel: Ignore chars when CREAD is cleared
From: Richard GENOUD @ 2026-05-18 7:20 UTC (permalink / raw)
To: Rakesh Alasyam, gregkh
Cc: richard.genoud, jirislaby, nicolas.ferre, alexandre.belloni,
claudiu.beznea, linux-serial, linux-kernel, linux-arm-kernel
In-Reply-To: <20260511165913.36467-1-alasyamrakesh77@gmail.com>
Hi Rakesh,
Le 11/05/2026 à 18:59, Rakesh Alasyam a écrit :
> Ignore received characters when CREAD is cleared by adding RXRDY
> to ignore_status_mask.
>
> This replaces an existing TODO in the driver.
>
> Tested on hardware.
Could you be more precise?
Which board(s) did you test with? (e.g. sama5d3_explained, custom...)
Which SoC? (sam9g35, sama5d2...)
With DMA, PDC or none?
Regards,
Richard
>
> Signed-off-by: Rakesh Alasyam <alasyamrakesh77@gmail.com>
>
> ---
>
> v2:
> - Add blank line before comment
> - Tested on hardware
> ---
> drivers/tty/serial/atmel_serial.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 5d8c1cfc1c60..5c756dc904b0 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -2184,7 +2184,8 @@ static void atmel_set_termios(struct uart_port *port,
> if (termios->c_iflag & IGNPAR)
> port->ignore_status_mask |= ATMEL_US_OVRE;
> }
> - /* TODO: Ignore all characters if CREAD is set.*/
> + if (!(termios->c_cflag & CREAD))
> + port->ignore_status_mask |= ATMEL_US_RXRDY;
>
> /* update the per-port timeout */
> uart_update_timeout(port, termios->c_cflag, baud);
^ permalink raw reply
* [PATCH v9] Bluetooth: hci_uart: fix UAFs and race conditions in close and init paths
From: w15303746062 @ 2026-05-18 2:49 UTC (permalink / raw)
To: luiz.dentz, pmenzel, marcel, linux-bluetooth
Cc: linux-serial, linux-kernel, greg, stable, Mingyu Wang
In-Reply-To: <CABBYNZ+r3gm37FW5WqE79bRp+x9UZsaCtyvfz_FdixqEucAxGw@mail.gmail.com>
From: Mingyu Wang <25181214217@stu.xidian.edu.cn>
Vulnerabilities leading to Use-After-Free (UAF) and Null Pointer
Dereference (NPD) conditions were observed in the lifecycle management
of hci_uart.
The primary issue arises because the workqueues (init_ready and
write_work) are only flushed/cancelled if the HCI_UART_PROTO_READY
flag is set during TTY close. If a hangup occurs before setup completes,
hci_uart_tty_close() skips the teardown of these workqueues and
proceeds to free the `hu` struct. When the scheduled work executes
later, it blindly dereferences the freed `hu` struct.
Furthermore, several data races and UAFs were identified in the teardown
sequence:
1. Calling hci_uart_flush() from hci_uart_close() without effectively
disabling write_work causes a race condition where both can concurrently
double-free hu->tx_skb. This happens because protocol timers can
concurrently invoke hci_uart_tx_wakeup() and requeue write_work.
2. Calling hci_free_dev(hdev) before hu->proto->close(hu) causes a UAF
when vendor specific protocol close callbacks dereference hu->hdev.
3. In the initialization error paths, failing to take the proto_lock
write lock before clearing PROTO_READY leads to races with active
readers. Additionally, hci_uart_tty_receive() accesses hu->hdev
outside the read lock, leading to UAFs if the initialization error
path frees hdev concurrently.
Fix these synchronization and lifecycle issues by:
1. Re-ordering hci_uart_tty_close() to clear HCI_UART_PROTO_READY first,
followed immediately by a cancel_work_sync(&hu->write_work). Clearing
the flag locks out concurrent protocol timers from successfully invoking
hci_uart_tx_wakeup(), effectively rendering the cancellation permanent
and preventing the tx_skb double-free.
2. Note: Clearing PROTO_READY early causes hci_uart_close() to skip
hu->proto->flush(). This is perfectly safe in the tty_close path
because hu->proto->close() executes shortly after, which intrinsically
purges all protocol SKB queues and tears down the state.
3. Relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev)
across all close and error paths to prevent vendor-level UAFs.
4. Moving the hdev->stat.byte_rx increment in hci_uart_tty_receive()
inside the proto_lock read-side critical section to safely synchronize
with device unregistration.
5. Adding cancel_work_sync(&hu->write_work) to hci_uart_close() to safely
flush the workqueue before hci_uart_flush() is invoked via the HCI core.
6. Utilizing cancel_work_sync() instead of disable_work_sync() across
all paths to prevent permanently breaking user-space retry capabilities.
Fixes: 3b799254cf6f ("Bluetooth: hci_uart: Cancel init work before unregistering")
Cc: stable@vger.kernel.org
Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
---
Changes in v9:
- Addressed a critical flaw identified in v8 where premature cancellation of write_work allowed active protocol timers to immediately reschedule it. The teardown sequence in hci_uart_tty_close() now strictly clears HCI_UART_PROTO_READY *before* calling cancel_work_sync(&hu->write_work). This permanently locks out hci_uart_tx_wakeup(), completely resolving the lingering UAF and double-free races.
- Documented that skipping hu->proto->flush() via early flag clearance is intrinsically safe, as hu->proto->close() executes subsequently to purge all unacked/rel queues.
Changes in v8:
- Corrected the teardown sequence in hci_uart_tty_close() by unconditionally canceling write_work BEFORE hci_uart_close().
- Moved hu->hdev->stat.byte_rx increment inside the proto_lock read-side critical section in hci_uart_tty_receive() to prevent read-side UAF against concurrent registration failures.
- Added cancel_work_sync(&hu->write_work) inside hci_uart_close() to eliminate the race condition between write_work and hci_uart_flush() when the interface is brought down via the HCI core.
Changes in v7:
- Reverted disable_work_sync() back to cancel_work_sync() across all error and close paths to preserve user-space retry capabilities.
- Synchronized workqueue teardown safely by atomically clearing PROTO_READY / PROTO_INIT under proto_lock prior to calling cancel_work_sync().
- Fixed a Use-After-Free (UAF) vulnerability in the teardown sequence by relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev).
- Added cancel_work_sync(&hu->init_ready) at the very beginning of hci_uart_tty_close() to serialize teardown against active asynchronous registration.
Changes in v6:
- Fixed missing `hu->proto_lock` write lock in hci_uart_init_work() error path to prevent race with readers (reported by Sashiko).
- Added disable_work_sync() instead of cancel_work_sync() for `hu->write_work` in hci_uart_init_work() and hci_uart_register_dev() error paths.
Changes in v5:
- Relocated disable_work_sync() to the very top of hci_uart_tty_close(),
before hci_uart_close(), to ensure no new work is submitted during device teardown.
Changes in v4:
- Adopted Luiz's suggestion to use disable_work_sync() instead of
cancel_work_sync() in close path to prevent new work submissions.
Changes in v3:
- Added 'Cc: stable' tag as requested by the stable bot.
Changes in v2:
- Added KASAN/ODEBUG crash trace.
drivers/bluetooth/hci_ldisc.c | 48 +++++++++++++++++++++++++++++------
1 file changed, 40 insertions(+), 8 deletions(-)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 275ea865bc29..47f4902b40b4 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -194,7 +194,15 @@ void hci_uart_init_work(struct work_struct *work)
err = hci_register_dev(hu->hdev);
if (err < 0) {
BT_ERR("Can't register HCI device");
+
+ percpu_down_write(&hu->proto_lock);
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
+ percpu_up_write(&hu->proto_lock);
+
+ /* Safely cancel work after clearing flags */
+ cancel_work_sync(&hu->write_work);
+
+ /* Close protocol before freeing hdev */
hu->proto->close(hu);
hdev = hu->hdev;
hu->hdev = NULL;
@@ -263,8 +271,12 @@ static int hci_uart_open(struct hci_dev *hdev)
/* Close device */
static int hci_uart_close(struct hci_dev *hdev)
{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+
BT_DBG("hdev %p", hdev);
+ cancel_work_sync(&hu->write_work);
+
hci_uart_flush(hdev);
hdev->flush = NULL;
return 0;
@@ -531,6 +543,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
{
struct hci_uart *hu = tty->disc_data;
struct hci_dev *hdev;
+ bool proto_ready;
BT_DBG("tty %p", tty);
@@ -540,24 +553,38 @@ static void hci_uart_tty_close(struct tty_struct *tty)
if (!hu)
return;
- hdev = hu->hdev;
- if (hdev)
- hci_uart_close(hdev);
+ /* Wait for init_ready to finish to prevent registration races */
+ cancel_work_sync(&hu->init_ready);
- if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
+ proto_ready = test_bit(HCI_UART_PROTO_READY, &hu->flags);
+ if (proto_ready) {
percpu_down_write(&hu->proto_lock);
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
percpu_up_write(&hu->proto_lock);
+ }
- cancel_work_sync(&hu->init_ready);
- cancel_work_sync(&hu->write_work);
+ /*
+ * Unconditionally cancel write_work AFTER clearing PROTO_READY.
+ * This ensures that concurrent protocol timers cannot requeue
+ * write_work via hci_uart_tx_wakeup(), permanently preventing
+ * double-free races and UAFs.
+ */
+ cancel_work_sync(&hu->write_work);
+
+ hdev = hu->hdev;
+ if (hdev)
+ hci_uart_close(hdev); /* proto->flush is safely skipped */
+ if (proto_ready) {
if (hdev) {
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
hci_unregister_dev(hdev);
- hci_free_dev(hdev);
}
+ /* Close protocol before freeing hdev (intrinsically purges queues) */
hu->proto->close(hu);
+
+ if (hdev)
+ hci_free_dev(hdev);
}
clear_bit(HCI_UART_PROTO_SET, &hu->flags);
@@ -625,11 +652,12 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
* tty caller
*/
hu->proto->recv(hu, data, count);
- percpu_up_read(&hu->proto_lock);
if (hu->hdev)
hu->hdev->stat.byte_rx += count;
+ percpu_up_read(&hu->proto_lock);
+
tty_unthrottle(tty);
}
@@ -695,6 +723,10 @@ static int hci_uart_register_dev(struct hci_uart *hu)
percpu_down_write(&hu->proto_lock);
clear_bit(HCI_UART_PROTO_INIT, &hu->flags);
percpu_up_write(&hu->proto_lock);
+ /* Cancel work after clearing flags */
+ cancel_work_sync(&hu->write_work);
+
+ /* Close protocol before freeing hdev */
hu->proto->close(hu);
hu->hdev = NULL;
hci_free_dev(hdev);
--
2.34.1
^ permalink raw reply related
* [PATCH v8] Bluetooth: hci_uart: fix UAFs and race conditions in close and init paths
From: w15303746062 @ 2026-05-18 1:36 UTC (permalink / raw)
To: luiz.dentz, pmenzel, marcel, linux-bluetooth
Cc: linux-serial, linux-kernel, greg, stable, Mingyu Wang
In-Reply-To: <CABBYNZ+r3gm37FW5WqE79bRp+x9UZsaCtyvfz_FdixqEucAxGw@mail.gmail.com>
From: Mingyu Wang <25181214217@stu.xidian.edu.cn>
Vulnerabilities leading to Use-After-Free (UAF) and Null Pointer
Dereference (NPD) conditions were observed in the lifecycle management
of hci_uart.
The primary issue arises because the workqueues (init_ready and
write_work) are only flushed/cancelled if the HCI_UART_PROTO_READY
flag is set during TTY close. If a hangup occurs before setup completes,
hci_uart_tty_close() skips the teardown of these workqueues and
proceeds to free the `hu` struct. When the scheduled work executes
later, it blindly dereferences the freed `hu` struct.
Furthermore, several data races and UAFs were identified in the teardown
sequence:
1. Calling hci_uart_flush() from hci_uart_close() without canceling
write_work causes a race condition where both can concurrently
double-free hu->tx_skb. This occurs both in TTY hangup and when the
HCI device is closed via the HCI core.
2. Calling hci_free_dev(hdev) before hu->proto->close(hu) causes a UAF
when vendor specific protocol close callbacks dereference hu->hdev.
3. In the initialization error paths, failing to take the proto_lock
write lock before clearing PROTO_READY leads to races with active
readers. Additionally, hci_uart_tty_receive() accesses hu->hdev
outside the read lock, leading to UAFs if the initialization error
path frees hdev concurrently.
Fix these synchronization and lifecycle issues by:
1. Re-ordering hci_uart_tty_close() to unconditionally cancel init_ready
and write_work first. This prevents the double-free race in
hci_uart_flush(), while preserving the HCI_UART_PROTO_READY flag so
underlying hu->proto->flush() callbacks can still execute safely.
2. Relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev)
across all close and error paths to prevent vendor-level UAFs.
3. Moving the hdev->stat.byte_rx increment in hci_uart_tty_receive()
inside the proto_lock read-side critical section to safely synchronize
with device unregistration.
4. Adding cancel_work_sync(&hu->write_work) to hci_uart_close() to safely
flush the workqueue before hci_uart_flush() is invoked.
5. Utilizing cancel_work_sync() instead of disable_work_sync() after
flags are cleared to safely flush workqueues without permanently
breaking user-space retry capabilities.
Fixes: 3b799254cf6f ("Bluetooth: hci_uart: Cancel init work before unregistering")
Cc: stable@vger.kernel.org
Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
---
Changes in v8:
- Corrected the teardown sequence in hci_uart_tty_close() by unconditionally canceling write_work BEFORE hci_uart_close(). This completely prevents the tx_skb double-free without prematurely clearing PROTO_READY, ensuring underlying hu->proto->flush(hu) runs correctly.
- Moved hu->hdev->stat.byte_rx increment inside the proto_lock read-side critical section in hci_uart_tty_receive() to prevent read-side UAF against concurrent registration failures.
- Added cancel_work_sync(&hu->write_work) inside hci_uart_close() to eliminate the race condition between write_work and hci_uart_flush() when the interface is brought down via the HCI core.
Changes in v7:
- Reverted disable_work_sync() back to cancel_work_sync() across all error and close paths to preserve user-space retry capabilities.
- Synchronized workqueue teardown safely by atomically clearing PROTO_READY / PROTO_INIT under proto_lock prior to calling cancel_work_sync().
- Fixed a Use-After-Free (UAF) vulnerability in the teardown sequence by relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev).
- Added cancel_work_sync(&hu->init_ready) at the very beginning of hci_uart_tty_close() to serialize teardown against active asynchronous registration.
Changes in v6:
- Fixed missing `hu->proto_lock` write lock in hci_uart_init_work() error path to prevent race with readers (reported by Sashiko).
- Added disable_work_sync() instead of cancel_work_sync() for `hu->write_work` in hci_uart_init_work() and hci_uart_register_dev() error paths.
Changes in v5:
- Relocated disable_work_sync() to the very top of hci_uart_tty_close(),
before hci_uart_close(), to ensure no new work is submitted during device teardown.
Changes in v4:
- Adopted Luiz's suggestion to use disable_work_sync() instead of
cancel_work_sync() in close path to prevent new work submissions.
Changes in v3:
- Added 'Cc: stable' tag as requested by the stable bot.
Changes in v2:
- Added KASAN/ODEBUG crash trace.
drivers/bluetooth/hci_ldisc.c | 33 ++++++++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 275ea865bc29..cb56194daad1 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -194,7 +194,15 @@ void hci_uart_init_work(struct work_struct *work)
err = hci_register_dev(hu->hdev);
if (err < 0) {
BT_ERR("Can't register HCI device");
+
+ percpu_down_write(&hu->proto_lock);
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
+ percpu_up_write(&hu->proto_lock);
+
+ /* Safely cancel work after clearing flags */
+ cancel_work_sync(&hu->write_work);
+
+ /* Close protocol before freeing hdev */
hu->proto->close(hu);
hdev = hu->hdev;
hu->hdev = NULL;
@@ -263,8 +271,12 @@ static int hci_uart_open(struct hci_dev *hdev)
/* Close device */
static int hci_uart_close(struct hci_dev *hdev)
{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+
BT_DBG("hdev %p", hdev);
+ cancel_work_sync(&hu->write_work);
+
hci_uart_flush(hdev);
hdev->flush = NULL;
return 0;
@@ -540,6 +552,12 @@ static void hci_uart_tty_close(struct tty_struct *tty)
if (!hu)
return;
+ /* Wait for init_ready to finish to prevent registration races */
+ cancel_work_sync(&hu->init_ready);
+
+ /* Unconditionally cancel write_work BEFORE hci_uart_close() to prevent double-free */
+ cancel_work_sync(&hu->write_work);
+
hdev = hu->hdev;
if (hdev)
hci_uart_close(hdev);
@@ -549,15 +567,15 @@ static void hci_uart_tty_close(struct tty_struct *tty)
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
percpu_up_write(&hu->proto_lock);
- cancel_work_sync(&hu->init_ready);
- cancel_work_sync(&hu->write_work);
-
if (hdev) {
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
hci_unregister_dev(hdev);
- hci_free_dev(hdev);
}
+ /* Close protocol before freeing hdev */
hu->proto->close(hu);
+
+ if (hdev)
+ hci_free_dev(hdev);
}
clear_bit(HCI_UART_PROTO_SET, &hu->flags);
@@ -625,11 +643,12 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
* tty caller
*/
hu->proto->recv(hu, data, count);
- percpu_up_read(&hu->proto_lock);
if (hu->hdev)
hu->hdev->stat.byte_rx += count;
+ percpu_up_read(&hu->proto_lock);
+
tty_unthrottle(tty);
}
@@ -695,6 +714,10 @@ static int hci_uart_register_dev(struct hci_uart *hu)
percpu_down_write(&hu->proto_lock);
clear_bit(HCI_UART_PROTO_INIT, &hu->flags);
percpu_up_write(&hu->proto_lock);
+ /* Cancel work after clearing flags */
+ cancel_work_sync(&hu->write_work);
+
+ /* Close protocol before freeing hdev */
hu->proto->close(hu);
hu->hdev = NULL;
hci_free_dev(hdev);
--
2.34.1
^ 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