Linux Serial subsystem development
 help / color / mirror / Atom feed
* [PATCH] vc_screen: fix null-ptr-deref in vcs_notifier() during concurrent vcs_write
From: Yi Yang @ 2026-06-04  6:07 UTC (permalink / raw)
  To: gregkh, jirislaby, kees, linux, george.kennedy
  Cc: linux-kernel, linux-serial, lujialin4, yiyang13

A KASAN null-ptr-deref was observed in vcs_notifier():

BUG: KASAN: null-ptr-deref in vcs_notifier+0x98/0x130
Read of size 2 at addr qmp_cmd_name: qmp_capabilities, arguments: {}

The issue is a race condition in vcs_write(). When the console_lock is
temporarily dropped (to copy data from userspace), the vc_data pointer
obtained from vcs_vc() may become stale. After re-acquiring the lock,
vcs_vc() is called again to re-validate the pointer. If the vc has been
deallocated in the meantime, vcs_vc() returns NULL, and the while loop
breaks (with written > 0). However, after the loop, vcs_scr_updated(vc)
is still called with the now-NULL vc pointer, leading to a null pointer
dereference in the notifier chain (vcs_notifier dereferences param->vc).

Fix this by adding a NULL check for vc before calling vcs_scr_updated().

Fixes: 8fb9ea65c9d1 ("vc_screen: reload load of struct vc_data pointer in vcs_write() to avoid UAF")
Cc: stable@vger.kernel.org
Signed-off-by: Yi Yang <yiyang13@huawei.com>
---
 drivers/tty/vt/vc_screen.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 4d2d46c95fef..7d40eacc21b3 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -686,7 +686,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 	}
 	*ppos += written;
 	ret = written;
-	if (written)
+	if (written && vc)
 		vcs_scr_updated(vc);
 
 	return ret;
-- 
2.25.1


^ permalink raw reply related

* [PATCH] serial: 8250_pci: fix -Winitializer-overrides for Brainboxes UC-260/271/701/756 entries
From: Rosen Penev @ 2026-06-03 23:26 UTC (permalink / raw)
  To: linux-serial
  Cc: Greg Kroah-Hartman, Jiri Slaby, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt,
	open list:TTY LAYER AND SERIAL DRIVERS,
	open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b

PCI_VDEVICE() expands to set .class=0 and .class_mask=0, but the Brainboxes UC-260/271/701/756 entries immediately override those fields. This causes a build error with clang -Werror,-Winitializer-overrides.

Fix by expanding PCI_VDEVICE() manually, omitting the trailing .class/.class_mask zeroes so each field is set exactly once.

Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/tty/serial/8250/8250_pci.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 3e5bc9e8d269..0513f4b3c093 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -5394,12 +5394,14 @@ static const struct pci_device_id serial_pci_tbl[] = {
 	 * Brainboxes UC-260/271/701/756
 	 */
 	{
-		PCI_VDEVICE(INTASHIELD, 0x0D21),
+		.vendor = PCI_VENDOR_ID_INTASHIELD, .device = 0x0D21,
+		.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
 		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
 		.class_mask = 0xffff00,
 		.driver_data = pbn_b2_4_115200,
 	}, {
-		PCI_VDEVICE(INTASHIELD, 0x0E34),
+		.vendor = PCI_VENDOR_ID_INTASHIELD, .device = 0x0E34,
+		.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
 		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
 		.class_mask = 0xffff00,
 		.driver_data = pbn_b2_4_115200,
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH 2/3] serial: mxs-auart: use devm resources for iomem and GPIO IRQs
From: Frank Li @ 2026-06-03 18:48 UTC (permalink / raw)
  To: Rosen Penev
  Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam,
	open list:TTY LAYER AND SERIAL DRIVERS,
	open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260603025857.287148-3-rosenp@gmail.com>

On Tue, Jun 02, 2026 at 07:58:56PM -0700, Rosen Penev wrote:
> Replace platform_get_resource + ioremap with
> devm_platform_get_and_ioremap_resource and convert GPIO IRQ
> request_irq/free_irq to devm_request_irq. This eliminates the
> mxs_auart_free_gpio_irq function and its call sites, and the
> out_iounmap error label. Simplify the remove function accordingly.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
>  drivers/tty/serial/mxs-auart.c | 55 ++++++++--------------------------
>  1 file changed, 12 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> index 1390fa000a5b..4499e3206e85 100644
> --- a/drivers/tty/serial/mxs-auart.c
> +++ b/drivers/tty/serial/mxs-auart.c
> @@ -1517,15 +1517,6 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
>  	return 0;
>  }
>
> -static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s)
> -{
> -	enum mctrl_gpio_idx i;
> -
> -	for (i = 0; i < UART_GPIO_MAX; i++)
> -		if (s->gpio_irq[i] >= 0)
> -			free_irq(s->gpio_irq[i], s);
> -}
> -
>  static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
>  {
>  	int *irq = s->gpio_irq;
> @@ -1537,21 +1528,13 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
>  			continue;
>
>  		irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
> -		err = request_irq(irq[i], mxs_auart_irq_handle,
> -				IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
> +		err = devm_request_irq(s->dev, irq[i], mxs_auart_irq_handle,
> +				       IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
>  		if (err)
>  			dev_err(s->dev, "%s - Can't get %d irq\n",
>  				__func__, irq[i]);
>  	}
>
> -	/*
> -	 * If something went wrong, rollback.
> -	 * Be careful: i may be unsigned.
> -	 */
> -	while (err && (i-- > 0))
> -		if (irq[i] >= 0)
> -			free_irq(irq[i], s);
> -
>  	return err;
>  }
>
> @@ -1586,7 +1569,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>
> -	s->devtype = (enum mxs_auart_type)of_device_get_match_data(&pdev->dev);
> +	s->devtype = (unsigned long)of_device_get_match_data(&pdev->dev);

This change need seperate patch

Frank
>
>  	ret = mxs_get_clks(s, pdev);
>  	if (ret)
> @@ -1596,18 +1579,12 @@ static int mxs_auart_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>
> -	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	if (!r) {
> -		ret = -ENXIO;
> +	s->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
> +	if (IS_ERR(s->port.membase)) {
> +		ret = PTR_ERR(s->port.membase);
>  		goto out_disable_clk;
>  	}
> -
>  	s->port.mapbase = r->start;
> -	s->port.membase = ioremap(r->start, resource_size(r));
> -	if (!s->port.membase) {
> -		ret = -ENOMEM;
> -		goto out_disable_clk;
> -	}
>  	s->port.ops = &mxs_auart_ops;
>  	s->port.iotype = UPIO_MEM;
>  	s->port.fifosize = MXS_AUART_FIFO_SIZE;
> @@ -1622,21 +1599,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
>  	irq = platform_get_irq(pdev, 0);
>  	if (irq < 0) {
>  		ret = irq;
> -		goto out_iounmap;
> +		goto out_disable_clk;
>  	}
>
>  	s->port.irq = irq;
>  	ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
>  			       dev_name(&pdev->dev), s);
>  	if (ret)
> -		goto out_iounmap;
> +		goto out_disable_clk;
>
>  	platform_set_drvdata(pdev, s);
>
>  	ret = mxs_auart_init_gpios(s, &pdev->dev);
>  	if (ret) {
>  		dev_err(&pdev->dev, "Failed to initialize GPIOs.\n");
> -		goto out_iounmap;
> +		goto out_disable_clk;
>  	}
>
>  	/*
> @@ -1644,7 +1621,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
>  	 */
>  	ret = mxs_auart_request_gpio_irq(s);
>  	if (ret)
> -		goto out_iounmap;
> +		goto out_disable_clk;
>
>  	auart_port[s->port.line] = s;
>
> @@ -1667,11 +1644,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
>  	return 0;
>
>  out_free_qpio_irq:
> -	mxs_auart_free_gpio_irq(s);
> -	auart_port[pdev->id] = NULL;
> -
> -out_iounmap:
> -	iounmap(s->port.membase);
> +	auart_port[s->port.line] = NULL;
>
>  out_disable_clk:
>  	clk_disable_unprepare(s->clk);
> @@ -1683,11 +1656,7 @@ static void mxs_auart_remove(struct platform_device *pdev)
>  	struct mxs_auart_port *s = platform_get_drvdata(pdev);
>
>  	uart_remove_one_port(&auart_driver, &s->port);
> -	auart_port[pdev->id] = NULL;
> -	mxs_auart_free_gpio_irq(s);
> -	iounmap(s->port.membase);
> -	if (is_asm9260_auart(s))
> -		clk_disable_unprepare(s->clk);
> +	auart_port[s->port.line] = NULL;
>  }
>
>  static struct platform_driver mxs_auart_driver = {
> --
> 2.54.0
>

^ permalink raw reply

* Re: [PATCH 1/3] serial: mxs-auart: rework clock handling in mxs_get_clks and probe
From: Frank Li @ 2026-06-03 18:45 UTC (permalink / raw)
  To: Rosen Penev
  Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam,
	open list:TTY LAYER AND SERIAL DRIVERS,
	open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260603025857.287148-2-rosenp@gmail.com>

On Tue, Jun 02, 2026 at 07:58:55PM -0700, Rosen Penev wrote:
> Use devm_clk_get_enabled for the AHB clock so its enable/disable
> lifetime is managed by the driver model. Move the mod clock
> (clk) prepare_enable out of mxs_get_clks and into probe so that
> clk_set_rate is called while the clock is still disabled, avoiding
> CLK_SET_RATE_GATE failures. Clean up the error labels accordingly.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
>  drivers/tty/serial/mxs-auart.c | 47 ++++++++++++----------------------
>  1 file changed, 17 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> index 697318dbb146..1390fa000a5b 100644
> --- a/drivers/tty/serial/mxs-auart.c
> +++ b/drivers/tty/serial/mxs-auart.c
> @@ -1470,34 +1470,22 @@ static int mxs_get_clks(struct mxs_auart_port *s,
>  		return PTR_ERR(s->clk);
>  	}
>
> -	s->clk_ahb = devm_clk_get(s->dev, "ahb");
> +	s->clk_ahb = devm_clk_get_enabled(s->dev, "ahb");
>  	if (IS_ERR(s->clk_ahb)) {
>  		dev_err(s->dev, "Failed to get \"ahb\" clk\n");
>  		return PTR_ERR(s->clk_ahb);
>  	}
>
> -	err = clk_prepare_enable(s->clk_ahb);
> -	if (err) {
> -		dev_err(s->dev, "Failed to enable ahb_clk!\n");
> -		return err;
> -	}
> -
> +	/*
> +	 * Set mod clock rate while it is still disabled so
> +	 * CLK_SET_RATE_GATE does not cause clk_set_rate to fail.
> +	 * The mod clock will be enabled in mxs_auart_startup()
> +	 * and in probe after mxs_get_clks returns.
> +	 */
>  	err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb));
> -	if (err) {
> +	if (err)
>  		dev_err(s->dev, "Failed to set rate!\n");
> -		goto disable_clk_ahb;
> -	}
>
> -	err = clk_prepare_enable(s->clk);
> -	if (err) {
> -		dev_err(s->dev, "Failed to enable clk!\n");
> -		goto disable_clk_ahb;
> -	}
> -
> -	return 0;
> -
> -disable_clk_ahb:
> -	clk_disable_unprepare(s->clk_ahb);
>  	return err;
>  }
>
> @@ -1604,17 +1592,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>
> +	ret = clk_prepare_enable(s->clk);
> +	if (ret)
> +		return ret;
> +

why not direct enable clock when get?
	s->clk = devm_clk_get(s->dev, "mod");

Frank
>  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	if (!r) {
>  		ret = -ENXIO;
> -		goto out_disable_clks;
> +		goto out_disable_clk;
>  	}
>
>  	s->port.mapbase = r->start;
>  	s->port.membase = ioremap(r->start, resource_size(r));
>  	if (!s->port.membase) {
>  		ret = -ENOMEM;
> -		goto out_disable_clks;
> +		goto out_disable_clk;
>  	}
>  	s->port.ops = &mxs_auart_ops;
>  	s->port.iotype = UPIO_MEM;
> @@ -1681,11 +1673,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
>  out_iounmap:
>  	iounmap(s->port.membase);
>
> -out_disable_clks:
> -	if (is_asm9260_auart(s)) {
> -		clk_disable_unprepare(s->clk);
> -		clk_disable_unprepare(s->clk_ahb);
> -	}
> +out_disable_clk:
> +	clk_disable_unprepare(s->clk);
>  	return ret;
>  }
>
> @@ -1697,10 +1686,8 @@ static void mxs_auart_remove(struct platform_device *pdev)
>  	auart_port[pdev->id] = NULL;
>  	mxs_auart_free_gpio_irq(s);
>  	iounmap(s->port.membase);
> -	if (is_asm9260_auart(s)) {
> +	if (is_asm9260_auart(s))
>  		clk_disable_unprepare(s->clk);
> -		clk_disable_unprepare(s->clk_ahb);
> -	}
>  }
>
>  static struct platform_driver mxs_auart_driver = {
> --
> 2.54.0
>

^ permalink raw reply

* [PATCH v12 3/3] MAINTAINERS: serdev: Add self for serdev
From: Markus Probst via B4 Relay @ 2026-06-03 15:56 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst
In-Reply-To: <20260603-rust_serdev-v12-0-3400ffb88b12@posteo.de>

From: Markus Probst <markus.probst@posteo.de>

Rob mentioned he needs to find someone else to maintain serdev.

Link: https://lore.kernel.org/rust-for-linux/20260430195858.GA1650658-robh@kernel.org/
Link: https://lore.kernel.org/rust-for-linux/da85ceb81f51079d4a8248a1ffde6a27d2ef24ad.camel@posteo.de/
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
 MAINTAINERS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 3b995cb6e902..200f0ab09f9b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24271,7 +24271,7 @@ F:	drivers/iio/chemical/sps30_i2c.c
 F:	drivers/iio/chemical/sps30_serial.c
 
 SERIAL DEVICE BUS
-M:	Rob Herring <robh@kernel.org>
+M:	Markus Probst <markus.probst@posteo.de>
 L:	linux-serial@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/serial/serial.yaml

-- 
2.53.0



^ permalink raw reply related

* [PATCH v12 2/3] samples: rust: add Rust serial device bus sample device driver
From: Markus Probst via B4 Relay @ 2026-06-03 15:56 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst
In-Reply-To: <20260603-rust_serdev-v12-0-3400ffb88b12@posteo.de>

From: Markus Probst <markus.probst@posteo.de>

Add a sample Rust serial device bus device driver illustrating the usage
of the serial device bus abstractions.

This drivers probes through either a match of device / driver name or a
match within the OF ID table.

Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
 MAINTAINERS                        |  1 +
 samples/rust/Kconfig               | 11 +++++
 samples/rust/Makefile              |  1 +
 samples/rust/rust_driver_serdev.rs | 91 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 104 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d21be30a2d9d..3b995cb6e902 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24279,6 +24279,7 @@ F:	drivers/tty/serdev/
 F:	include/linux/serdev.h
 F:	rust/helpers/serdev.c
 F:	rust/kernel/serdev.rs
+F:	samples/rust/rust_driver_serdev.rs
 
 SERIAL IR RECEIVER
 M:	Sean Young <sean@mess.org>
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index c49ab9106345..31d62533ef25 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -161,6 +161,17 @@ config SAMPLE_RUST_DRIVER_AUXILIARY
 
 	  If unsure, say N.
 
+config SAMPLE_RUST_DRIVER_SERDEV
+	tristate "Serial Device Bus Device Driver"
+	select RUST_SERIAL_DEV_BUS_ABSTRACTIONS
+	help
+	  This option builds the Rust serial device bus driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_driver_serdev.
+
+	  If unsure, say N.
+
 config SAMPLE_RUST_SOC
 	tristate "SoC Driver"
 	select SOC_BUS
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 6c0aaa58cccc..b986b681cde5 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM)	+= rust_driver_platform.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_USB)		+= rust_driver_usb.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX)		+= rust_driver_faux.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY)	+= rust_driver_auxiliary.o
+obj-$(CONFIG_SAMPLE_RUST_DRIVER_SERDEV)		+= rust_driver_serdev.o
 obj-$(CONFIG_SAMPLE_RUST_CONFIGFS)		+= rust_configfs.o
 obj-$(CONFIG_SAMPLE_RUST_SOC)			+= rust_soc.o
 
diff --git a/samples/rust/rust_driver_serdev.rs b/samples/rust/rust_driver_serdev.rs
new file mode 100644
index 000000000000..824affbf6593
--- /dev/null
+++ b/samples/rust/rust_driver_serdev.rs
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust Serial device bus device driver sample.
+
+use kernel::{
+    acpi,
+    device::{
+        Bound,
+        Core, //
+    },
+    of,
+    prelude::*,
+    serdev,
+    sync::aref::ARef, //
+};
+
+struct SampleDriver {
+    sdev: ARef<serdev::Device>,
+}
+
+kernel::of_device_table!(
+    OF_TABLE,
+    MODULE_OF_TABLE,
+    <SampleDriver as serdev::Driver>::IdInfo,
+    [(of::DeviceId::new(c"test,rust_driver_serdev"), ())]
+);
+
+kernel::acpi_device_table!(
+    ACPI_TABLE,
+    MODULE_ACPI_TABLE,
+    <SampleDriver as serdev::Driver>::IdInfo,
+    [(acpi::DeviceId::new(c"LNUXBEEF"), ())]
+);
+
+#[vtable]
+impl serdev::Driver for SampleDriver {
+    type IdInfo = ();
+    type Data<'bound> = Self;
+    const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
+    const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
+
+    fn probe<'bound>(
+        sdev: &'bound serdev::Device<Core<'_>>,
+        _info: Option<&'bound Self::IdInfo>,
+    ) -> impl PinInit<Self, Error> + 'bound {
+        let dev = sdev.as_ref();
+
+        dev_dbg!(dev, "Probe Rust Serial device bus device driver sample.\n");
+
+        if sdev
+            .set_baudrate(
+                dev.fwnode()
+                    .and_then(|fwnode| fwnode.property_read(c"baudrate").optional())
+                    .unwrap_or(115200),
+            )
+            .is_err()
+        {
+            return Err(EINVAL);
+        }
+        sdev.set_flow_control(false);
+        sdev.set_parity(serdev::Parity::None)?;
+
+        Ok(Self { sdev: sdev.into() })
+    }
+
+    fn receive<'bound>(
+        sdev: &'bound serdev::Device<Bound>,
+        _this: Pin<&Self>,
+        data: &[u8],
+    ) -> usize {
+        let _ = sdev.write_all(data, serdev::Timeout::Max);
+        data.len()
+    }
+}
+
+impl Drop for SampleDriver {
+    fn drop(&mut self) {
+        dev_dbg!(
+            self.sdev.as_ref(),
+            "Remove Rust Serial device bus device driver sample.\n"
+        );
+    }
+}
+
+kernel::module_serdev_device_driver! {
+    type: SampleDriver,
+    name: "rust_driver_serdev",
+    authors: ["Markus Probst"],
+    description: "Rust Serial device bus device driver",
+    license: "GPL v2",
+}

-- 
2.53.0



^ permalink raw reply related

* [PATCH v12 1/3] rust: add basic serial device bus abstractions
From: Markus Probst via B4 Relay @ 2026-06-03 15:56 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst
In-Reply-To: <20260603-rust_serdev-v12-0-3400ffb88b12@posteo.de>

From: Markus Probst <markus.probst@posteo.de>

Implement the basic serial device bus abstractions required to write a
serial device bus device driver with or without the need for initial device
data. This includes the following data structures:

The `serdev::Driver` trait represents the interface to the driver.

The `serdev::Device` abstraction represents a `struct serdev_device`.

In order to provide the Serdev specific parts to a generic
`driver::Registration` the `driver::RegistrationOps` trait is
implemented by `serdev::Adapter`.

Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
 MAINTAINERS                     |   2 +
 drivers/tty/serdev/Kconfig      |   7 +
 rust/bindings/bindings_helper.h |   1 +
 rust/helpers/helpers.c          |   1 +
 rust/helpers/serdev.c           |  22 ++
 rust/kernel/lib.rs              |   2 +
 rust/kernel/serdev.rs           | 590 ++++++++++++++++++++++++++++++++++++++++
 7 files changed, 625 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1a5508df3f44..d21be30a2d9d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24277,6 +24277,8 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/serial/serial.yaml
 F:	drivers/tty/serdev/
 F:	include/linux/serdev.h
+F:	rust/helpers/serdev.c
+F:	rust/kernel/serdev.rs
 
 SERIAL IR RECEIVER
 M:	Sean Young <sean@mess.org>
diff --git a/drivers/tty/serdev/Kconfig b/drivers/tty/serdev/Kconfig
index 46ae732bfc68..e6dfe949ad01 100644
--- a/drivers/tty/serdev/Kconfig
+++ b/drivers/tty/serdev/Kconfig
@@ -9,6 +9,13 @@ menuconfig SERIAL_DEV_BUS
 
 	  Note that you typically also want to enable TTY port controller support.
 
+config RUST_SERIAL_DEV_BUS_ABSTRACTIONS
+	bool "Rust Serial device bus abstractions"
+	depends on RUST
+	select SERIAL_DEV_BUS
+	help
+	  This enables the Rust abstraction for the serial device bus API.
+
 if SERIAL_DEV_BUS
 
 config SERIAL_DEV_CTRL_TTYPORT
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 446dbeaf0866..4e42635b8607 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -84,6 +84,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/sched.h>
 #include <linux/security.h>
+#include <linux/serdev.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 #include <linux/task_work.h>
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 38b34518eff1..2fb8506a748a 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -86,6 +86,7 @@
 #include "regulator.c"
 #include "scatterlist.c"
 #include "security.c"
+#include "serdev.c"
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
diff --git a/rust/helpers/serdev.c b/rust/helpers/serdev.c
new file mode 100644
index 000000000000..c52b78ca3fc7
--- /dev/null
+++ b/rust/helpers/serdev.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/serdev.h>
+
+__rust_helper
+void rust_helper_serdev_device_driver_unregister(struct serdev_device_driver *sdrv)
+{
+	serdev_device_driver_unregister(sdrv);
+}
+
+__rust_helper
+void rust_helper_serdev_device_put(struct serdev_device *serdev)
+{
+	serdev_device_put(serdev);
+}
+
+__rust_helper
+void rust_helper_serdev_device_set_client_ops(struct serdev_device *serdev,
+					      const struct serdev_device_ops *ops)
+{
+	serdev_device_set_client_ops(serdev, ops);
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index b72b2fbe046d..83bc2c312241 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -118,6 +118,8 @@
 pub mod scatterlist;
 pub mod security;
 pub mod seq_file;
+#[cfg(CONFIG_RUST_SERIAL_DEV_BUS_ABSTRACTIONS)]
+pub mod serdev;
 pub mod sizes;
 #[cfg(CONFIG_SOC_BUS)]
 pub mod soc;
diff --git a/rust/kernel/serdev.rs b/rust/kernel/serdev.rs
new file mode 100644
index 000000000000..ab5d6446b091
--- /dev/null
+++ b/rust/kernel/serdev.rs
@@ -0,0 +1,590 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Abstractions for the serial device bus.
+//!
+//! C header: [`include/linux/serdev.h`](srctree/include/linux/serdev.h)
+
+use crate::{
+    acpi,
+    device,
+    driver,
+    error::{
+        from_result,
+        to_result,
+        VTABLE_DEFAULT_ERROR, //
+    },
+    new_mutex,
+    of,
+    prelude::*,
+    sync::{
+        aref::AlwaysRefCounted,
+        Mutex, //
+    },
+    time::{
+        msecs_to_jiffies,
+        Jiffies,
+        Msecs, //
+    },
+    types::{
+        Opaque,
+        ScopeGuard, //
+    }, //
+};
+
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::{offset_of, MaybeUninit},
+    num::NonZero,
+    ptr::NonNull, //
+};
+
+/// Parity bit to use with a serial device.
+#[repr(u32)]
+pub enum Parity {
+    /// No parity bit.
+    None = bindings::serdev_parity_SERDEV_PARITY_NONE,
+    /// Even partiy.
+    Even = bindings::serdev_parity_SERDEV_PARITY_EVEN,
+    /// Odd parity.
+    Odd = bindings::serdev_parity_SERDEV_PARITY_ODD,
+}
+
+/// Timeout in Jiffies.
+pub enum Timeout {
+    /// Wait for a specific amount of [`Jiffies`].
+    Jiffies(NonZero<Jiffies>),
+    /// Wait for a specific amount of [`Msecs`].
+    Milliseconds(NonZero<Msecs>),
+    /// Wait as long as possible.
+    ///
+    /// This is equivalent to [`kernel::task::MAX_SCHEDULE_TIMEOUT`].
+    Max,
+}
+
+impl Timeout {
+    fn into_jiffies(self) -> isize {
+        match self {
+            Self::Jiffies(value) => value.get().try_into().unwrap_or_default(),
+            Self::Milliseconds(value) => {
+                msecs_to_jiffies(value.get()).try_into().unwrap_or_default()
+            }
+            Self::Max => 0,
+        }
+    }
+}
+
+/// An adapter for the registration of serial device bus device drivers.
+pub struct Adapter<T: Driver>(T);
+
+// SAFETY:
+// - `bindings::serdev_device_driver` is a C type declared as `repr(C)`.
+// - `PrivateData<'bound, T>` is the type of the driver's device private data.
+// - `struct serdev_device_driver` embeds a `struct device_driver`.
+// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`.
+unsafe impl<T: Driver> driver::DriverLayout for Adapter<T> {
+    type DriverType = bindings::serdev_device_driver;
+    type DriverData<'bound> = PrivateData<'bound, T>;
+    const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver);
+}
+
+// SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if
+// a preceding call to `register` has been successful.
+unsafe impl<T: Driver> driver::RegistrationOps for Adapter<T> {
+    unsafe fn register(
+        sdrv: &Opaque<Self::DriverType>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        let of_table = match T::OF_ID_TABLE {
+            Some(table) => table.as_ptr(),
+            None => core::ptr::null(),
+        };
+
+        let acpi_table = match T::ACPI_ID_TABLE {
+            Some(table) => table.as_ptr(),
+            None => core::ptr::null(),
+        };
+
+        // SAFETY: It's safe to set the fields of `struct serdev_device_driver` on initialization.
+        unsafe {
+            (*sdrv.get()).driver.name = name.as_char_ptr();
+            (*sdrv.get()).probe = Some(Self::probe_callback);
+            (*sdrv.get()).remove = Some(Self::remove_callback);
+            (*sdrv.get()).driver.of_match_table = of_table;
+            (*sdrv.get()).driver.acpi_match_table = acpi_table;
+        }
+
+        // SAFETY: `sdrv` is guaranteed to be a valid `DriverType`.
+        to_result(unsafe { bindings::__serdev_device_driver_register(sdrv.get(), module.0) })
+    }
+
+    unsafe fn unregister(sdrv: &Opaque<Self::DriverType>) {
+        // SAFETY: `sdrv` is guaranteed to be a valid `DriverType`.
+        unsafe { bindings::serdev_device_driver_unregister(sdrv.get()) };
+    }
+}
+
+#[doc(hidden)]
+#[pin_data(PinnedDrop)]
+pub struct PrivateData<'bound, T: Driver> {
+    sdev: &'bound Device<device::Bound>,
+    #[pin]
+    driver: UnsafeCell<MaybeUninit<T::Data<'bound>>>,
+    open: UnsafeCell<bool>,
+    #[pin]
+    active: Mutex<bool>,
+}
+
+#[pinned_drop]
+impl<T: Driver> PinnedDrop for PrivateData<'_, T> {
+    fn drop(self: Pin<&mut Self>) {
+        let mut active = self.active.lock();
+        if *active {
+            // SAFETY:
+            // - We have exclusive access to `self.driver`.
+            // - `self.driver` is guaranteed to be initialized.
+            unsafe { (*self.driver.get()).assume_init_drop() };
+            *active = false;
+        }
+
+        // SAFETY: We have exclusive access to `self.open`.
+        if unsafe { *self.open.get() } {
+            // SAFETY: `self.sdev.as_raw()` is guaranteed to be a pointer to a valid
+            // `struct serdev_device`.
+            unsafe { bindings::serdev_device_close(self.sdev.as_raw()) };
+        }
+    }
+}
+
+impl<T: Driver> Adapter<T> {
+    const OPS: &'static bindings::serdev_device_ops = &bindings::serdev_device_ops {
+        receive_buf: if T::HAS_RECEIVE {
+            Some(Self::receive_buf_callback)
+        } else {
+            None
+        },
+        write_wakeup: Some(bindings::serdev_device_write_wakeup),
+    };
+
+    extern "C" fn probe_callback(sdev: *mut bindings::serdev_device) -> kernel::ffi::c_int {
+        // SAFETY: The serial device bus only ever calls the probe callback with a valid pointer to
+        // a `struct serdev_device`.
+        //
+        // INVARIANT: `sdev` is valid for the duration of `probe_callback()`.
+        let sdev = unsafe { &*sdev.cast::<Device<device::CoreInternal<'_>>>() };
+        let info = <Self as driver::Adapter>::id_info(sdev.as_ref());
+
+        from_result(|| {
+            sdev.as_ref().set_drvdata(try_pin_init!(PrivateData::<T> {
+                sdev: &**sdev,
+                driver: MaybeUninit::<T::Data<'_>>::zeroed().into(),
+                open: false.into(),
+                active <- new_mutex!(false),
+            }))?;
+            // SAFETY: We just set drvdata to `PrivateData<'_, T>`.
+            let private_data = unsafe { sdev.as_ref().drvdata_borrow::<PrivateData<'_, T>>() };
+            let private_data = ScopeGuard::new_with_data(private_data, |_| {
+                // SAFETY: We just set drvdata to `PrivateData<'_, T>`.
+                drop(unsafe { sdev.as_ref().drvdata_obtain::<PrivateData<'_, T>>() });
+            });
+            let mut active = private_data.active.lock();
+
+            // SAFETY: `sdev.as_raw()` is guaranteed to be a valid pointer to `serdev_device`.
+            unsafe { bindings::serdev_device_set_client_ops(sdev.as_raw(), Self::OPS) };
+
+            // SAFETY: The serial device bus only ever calls the probe callback with a valid pointer
+            // to a `serdev_device`.
+            to_result(unsafe { bindings::serdev_device_open(sdev.as_raw()) })?;
+
+            // SAFETY: We have exclusive access to `private_data.open`.
+            unsafe { *private_data.open.get() = true };
+
+            let data = T::probe(sdev, info);
+
+            // SAFETY: We have exclusive access to `private_data.driver`.
+            let driver = unsafe { &mut *private_data.driver.get() };
+            // SAFETY:
+            // - `driver.as_mut_ptr()` is a valid pointer to uninitialized data.
+            // - `private_data.driver` is pinned.
+            let result = unsafe { data.__pinned_init(driver.as_mut_ptr()) };
+
+            *active = result.is_ok();
+
+            drop(active);
+
+            result.map(|()| {
+                private_data.dismiss();
+                0
+            })
+        })
+    }
+
+    extern "C" fn remove_callback(sdev: *mut bindings::serdev_device) {
+        // SAFETY: The serial device bus only ever calls the remove callback with a valid pointer
+        // to a `struct serdev_device`.
+        //
+        // INVARIANT: `sdev` is valid for the duration of `remove_callback()`.
+        let sdev = unsafe { &*sdev.cast::<Device<device::CoreInternal<'_>>>() };
+
+        // SAFETY: `remove_callback` is only ever called after a successful call to
+        // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called
+        // and stored a `Pin<KBox<PrivateData<'_, T>>>`.
+        let private_data = unsafe { sdev.as_ref().drvdata_borrow::<PrivateData<'_, T>>() };
+
+        // SAFETY: No one has exclusive access to `private_data.driver`.
+        let data = unsafe { &*private_data.driver.get() };
+        // SAFETY:
+        // - `private_data.driver` is pinned.
+        // - `remove_callback` is only ever called after a successful call to `probe_callback`,
+        //   hence it's guaranteed that `private_data.driver` was initialized.
+        let data_pinned = unsafe { Pin::new_unchecked(data.assume_init_ref()) };
+
+        T::unbind(sdev, data_pinned);
+    }
+
+    extern "C" fn receive_buf_callback(
+        sdev: *mut bindings::serdev_device,
+        buf: *const u8,
+        length: usize,
+    ) -> usize {
+        // SAFETY: The serial device bus only ever calls the receive buf callback with a valid
+        // pointer to a `struct serdev_device`.
+        //
+        // INVARIANT: `sdev` is valid for the duration of `receive_buf_callback()`.
+        let sdev = unsafe { &*sdev.cast::<Device<device::BoundInternal>>() };
+
+        // SAFETY: `receive_buf_callback` is only ever called after a successful call to
+        // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called
+        // and stored a `Pin<KBox<PrivateData<'_, T>>>`.
+        let private_data = unsafe { sdev.as_ref().drvdata_borrow::<PrivateData<'_, T>>() };
+        let active = private_data.active.lock();
+
+        if !*active {
+            return length;
+        }
+
+        // SAFETY: No one has exclusive access to `private_data.driver`.
+        let data = unsafe { &*private_data.driver.get() };
+        // SAFETY:
+        // - `private_data.driver` is pinned.
+        // - `receive_buf_callback` is only ever called after a successful call to `probe_callback`,
+        //   hence it's guaranteed that `private_data.driver` was initialized.
+        let data_pinned = unsafe { Pin::new_unchecked(data.assume_init_ref()) };
+
+        // SAFETY: `buf` is guaranteed to be non-null and has the size of `length`.
+        let buf = unsafe { core::slice::from_raw_parts(buf, length) };
+
+        T::receive(sdev, data_pinned, buf)
+    }
+}
+
+impl<T: Driver> driver::Adapter for Adapter<T> {
+    type IdInfo = T::IdInfo;
+
+    fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> {
+        T::OF_ID_TABLE
+    }
+
+    fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>> {
+        T::ACPI_ID_TABLE
+    }
+}
+
+/// Declares a kernel module that exposes a single serial device bus device driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// kernel::module_serdev_device_driver! {
+///     type: MyDriver,
+///     name: "Module name",
+///     authors: ["Author name"],
+///     description: "Description",
+///     license: "GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_serdev_device_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::serdev::Adapter<T>, { $($f)* });
+    };
+}
+
+/// The serial device bus device driver trait.
+///
+/// Drivers must implement this trait in order to get a serial device bus device driver registered.
+///
+/// # Examples
+///
+///```
+/// # use kernel::{
+///     acpi,
+///     bindings,
+///     device::{
+///         Bound,
+///         Core, //
+///     },
+///     of,
+///     serdev, //
+/// };
+///
+/// struct MyDriver;
+///
+/// kernel::of_device_table!(
+///     OF_TABLE,
+///     MODULE_OF_TABLE,
+///     <MyDriver as serdev::Driver>::IdInfo,
+///     [
+///         (of::DeviceId::new(c"test,device"), ())
+///     ]
+/// );
+///
+/// kernel::acpi_device_table!(
+///     ACPI_TABLE,
+///     MODULE_ACPI_TABLE,
+///     <MyDriver as serdev::Driver>::IdInfo,
+///     [
+///         (acpi::DeviceId::new(c"LNUXBEEF"), ())
+///     ]
+/// );
+///
+/// #[vtable]
+/// impl serdev::Driver for MyDriver {
+///     type IdInfo = ();
+///     type Data<'bound> = Self;
+///     const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
+///     const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
+///
+///     fn probe<'bound>(
+///         sdev: &'bound serdev::Device<Core<'_>>,
+///         _id_info: Option<&'bound Self::IdInfo>,
+///     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
+///         sdev.set_baudrate(115200);
+///         sdev.write_all(b"Hello\n", serdev::Timeout::Max)?;
+///         Ok(MyDriver)
+///     }
+/// }
+///```
+#[vtable]
+pub trait Driver {
+    /// The type holding driver private data about each device id supported by the driver.
+    // TODO: Use associated_type_defaults once stabilized:
+    //
+    // ```
+    // type IdInfo: 'static = ();
+    // ```
+    type IdInfo: 'static;
+
+    /// The type of the driver's bus device private data.
+    type Data<'bound>: Send + 'bound;
+
+    /// The table of OF device ids supported by the driver.
+    const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
+
+    /// The table of ACPI device ids supported by the driver.
+    const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None;
+
+    /// Serial device bus device driver probe.
+    ///
+    /// Called when a new serial device bus device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe<'bound>(
+        sdev: &'bound Device<device::Core<'_>>,
+        id_info: Option<&'bound Self::IdInfo>,
+    ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
+
+    /// Serial device bus device driver unbind.
+    ///
+    /// Called when a [`Device`] is unbound from its bound [`Driver`]. Implementing this callback
+    /// is optional.
+    ///
+    /// This callback serves as a place for drivers to perform teardown operations that require a
+    /// `&Device<Core>` or `&Device<Bound>` reference. For instance.
+    ///
+    /// Otherwise, release operations for driver resources should be performed in `Drop`.
+    fn unbind<'bound>(sdev: &'bound Device<device::Core<'_>>, this: Pin<&Self::Data<'bound>>) {
+        let _ = (sdev, this);
+    }
+
+    /// Serial device bus device data receive callback.
+    ///
+    /// Called when data got received from device.
+    ///
+    /// Returns the number of bytes accepted.
+    fn receive<'bound>(
+        sdev: &'bound Device<device::Bound>,
+        this: Pin<&Self::Data<'bound>>,
+        data: &[u8],
+    ) -> usize {
+        let _ = (sdev, this, data);
+        build_error!(VTABLE_DEFAULT_ERROR)
+    }
+}
+
+/// The serial device bus device representation.
+///
+/// This structure represents the Rust abstraction for a C `struct serdev_device`. The
+/// implementation abstracts the usage of an already existing C `struct serdev_device` within Rust
+/// code that we get passed from the C side.
+///
+/// # Invariants
+///
+/// A [`Device`] instance represents a valid `struct serdev_device` created by the C portion of
+/// the kernel.
+#[repr(transparent)]
+pub struct Device<Ctx: device::DeviceContext = device::Normal>(
+    Opaque<bindings::serdev_device>,
+    PhantomData<Ctx>,
+);
+
+impl<Ctx: device::DeviceContext> Device<Ctx> {
+    fn as_raw(&self) -> *mut bindings::serdev_device {
+        self.0.get()
+    }
+}
+
+impl Device<device::Bound> {
+    /// Set the baudrate in bits per second.
+    ///
+    /// Common baudrates are 115200, 9600, 19200, 57600, 4800.
+    ///
+    /// Use [`Device::write_flush`] before calling this if you have written data prior to this call.
+    pub fn set_baudrate(&self, speed: u32) -> Result<(), u32> {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        let ret = unsafe { bindings::serdev_device_set_baudrate(self.as_raw(), speed) };
+        if ret == speed {
+            Ok(())
+        } else {
+            Err(ret)
+        }
+    }
+
+    /// Set if flow control should be enabled.
+    ///
+    /// Use [`Device::write_flush`] before calling this if you have written data prior to this call.
+    pub fn set_flow_control(&self, enable: bool) {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        unsafe { bindings::serdev_device_set_flow_control(self.as_raw(), enable) };
+    }
+
+    /// Set parity to use.
+    ///
+    /// Use [`Device::write_flush`] before calling this if you have written data prior to this call.
+    pub fn set_parity(&self, parity: Parity) -> Result {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        to_result(unsafe { bindings::serdev_device_set_parity(self.as_raw(), parity as u32) })
+    }
+
+    /// Write data to the serial device until the controller has accepted all the data or has
+    /// been interrupted by a timeout or signal.
+    ///
+    /// Note that any accepted data has only been buffered by the controller. Use
+    /// [`Device::wait_until_sent`] to make sure the controller write buffer has actually been
+    /// emptied.
+    ///
+    /// Returns the number of bytes written (less than `data.len()` if interrupted).
+    /// [`kernel::error::code::ETIMEDOUT`] or [`kernel::error::code::ERESTARTSYS`] if interrupted
+    /// before any bytes were written.
+    pub fn write_all(&self, data: &[u8], timeout: Timeout) -> Result<usize> {
+        // SAFETY:
+        // - `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        // - `data.as_ptr()` is guaranteed to be a valid array pointer with the size of
+        //   `data.len()`.
+        let ret = unsafe {
+            bindings::serdev_device_write(
+                self.as_raw(),
+                data.as_ptr(),
+                data.len(),
+                timeout.into_jiffies(),
+            )
+        };
+        // CAST: negative return values are guaranteed to be between `-MAX_ERRNO` and `-1`,
+        // which always fit into a `i32`.
+        to_result(ret as i32).map(|()| ret.unsigned_abs())
+    }
+
+    /// Write data to the serial device.
+    ///
+    /// If you want to write until the controller has accepted all the data, use
+    /// [`Device::write_all`].
+    ///
+    /// Note that any accepted data has only been buffered by the controller. Use
+    /// [ Device::wait_until_sent`] to make sure the controller write buffer has actually been
+    /// emptied.
+    ///
+    /// Returns the number of bytes written (less than `data.len()` if not enough room in the
+    /// write buffer).
+    pub fn write(&self, data: &[u8]) -> Result<u32> {
+        // SAFETY:
+        // - `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        // - `data.as_ptr()` is guaranteed to be a valid array pointer with the size of
+        //   `data.len()`.
+        let ret =
+            unsafe { bindings::serdev_device_write_buf(self.as_raw(), data.as_ptr(), data.len()) };
+
+        to_result(ret as i32).map(|()| ret.unsigned_abs())
+    }
+
+    /// Send data to the serial device immediately.
+    ///
+    /// Note that this doesn't guarantee that the data has been transmitted.
+    /// Use [`Device::wait_until_sent`] for this purpose.
+    pub fn write_flush(&self) {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        unsafe { bindings::serdev_device_write_flush(self.as_raw()) };
+    }
+
+    /// Wait for the data to be sent.
+    ///
+    /// After this function, the write buffer of the controller should be empty.
+    pub fn wait_until_sent(&self, timeout: Timeout) {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        unsafe { bindings::serdev_device_wait_until_sent(self.as_raw(), timeout.into_jiffies()) };
+    }
+}
+
+// SAFETY: `serdev::Device` is a transparent wrapper of `struct serdev_device`.
+// The offset is guaranteed to point to a valid device field inside `serdev::Device`.
+unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> {
+    const OFFSET: usize = offset_of!(bindings::serdev_device, dev);
+}
+
+// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
+// argument.
+kernel::impl_device_context_deref!(unsafe { Device });
+kernel::impl_device_context_into_aref!(Device);
+
+// SAFETY: Instances of `Device` are always reference-counted.
+unsafe impl AlwaysRefCounted for Device {
+    fn inc_ref(&self) {
+        self.as_ref().inc_ref();
+    }
+
+    unsafe fn dec_ref(obj: NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is non-zero.
+        unsafe { bindings::serdev_device_put(obj.cast().as_ptr()) }
+    }
+}
+
+impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
+    fn as_ref(&self) -> &device::Device<Ctx> {
+        // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
+        // `struct serdev_device`.
+        let dev = unsafe { &raw mut (*self.as_raw()).dev };
+
+        // SAFETY: `dev` points to a valid `struct device`.
+        unsafe { device::Device::from_raw(dev) }
+    }
+}
+
+// SAFETY: A `Device` is always reference-counted and can be released from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` can be shared among threads because all methods of `Device`
+// (i.e. `Device<Normal>) are thread safe.
+unsafe impl Sync for Device {}
+
+// SAFETY: Same as `Device<Normal>` -- the underlying `struct serdev_device` is the same;
+// `Bound` is a zero-sized type-state marker that does not affect thread safety.
+unsafe impl Sync for Device<device::Bound> {}

-- 
2.53.0



^ permalink raw reply related

* [PATCH v12 0/3] rust: add basic serial device bus abstractions
From: Markus Probst via B4 Relay @ 2026-06-03 15:56 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst

This patch series adds the serdev device bus rust abstraction into the
kernel.

This abstraction will be used by a driver,
which targets the MCU devices in Synology devices.

Kari Argillander also messaged me, stating that he wants to write a
watchdog driver with this abstraction (needing initial device data).

This series depends on [1] and [2].

[1]
https://lore.kernel.org/rust-for-linux/20260525202921.124698-1-dakr@kernel.org/
[2] https://lore.kernel.org/rust-for-linux/20260530132736.3298549-1-dakr@kernel.org/

Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
Changes in v12:
- fix CoreInternal instead of BoundInternal
- Link to v11: https://patch.msgid.link/20260531-rust_serdev-v11-0-dee8e0d830f1@posteo.de

Changes in v11:
- redo changes from v9 with the following fixes:
  - fix memory leak on probe failure
  - fix possible access of dropped drvdata from receive_buf
- Link to v10: https://patch.msgid.link/20260530-rust_serdev-v10-0-65d1d5db876c@posteo.de

Changes in v10:
- revert everything from v9, except BoundInternal
- use mutex to ensure receive_buf won't be called on a dropped drvdata.
- Link to v9: https://patch.msgid.link/20260530-rust_serdev-v9-0-f8b5fccb49c3@posteo.de

Changes in v9:
- make use of BoundInternal
- use PrivateData wrapper and drop rust_private_data field
- use non-devm version of serdev_device_open
- Link to v8: https://patch.msgid.link/20260530-rust_serdev-v8-0-2a95f1da22a7@posteo.de

Changes in v8:
- adapted to driver-lifetime v5 patch series
- add MAINTAINERS file patch
- Link to v7: https://patch.msgid.link/20260429-rust_serdev-v7-0-0d89c791b5c8@posteo.de

Changes in v7:
- adapted to driver-lifetime patch series
- Link to v6: https://patch.msgid.link/20260427-rust_serdev-v6-0-173798d5e1a3@posteo.de

Changes in v6:
- rebased onto v7.1-rc1
- Link to v5: https://patch.msgid.link/20260420-rust_serdev-v5-0-57e8ba0519f3@posteo.de

Changes in v5:
- fix typo in documentation
- Link to v4: https://lore.kernel.org/r/20260411-rust_serdev-v4-0-845e960c6627@posteo.de

Changes in v4:
- fixed not selecting rust serdev abstraction in sample
- Link to v3: https://lore.kernel.org/r/20260313-rust_serdev-v3-0-c9a3af214f7f@posteo.de

Changes in v3:
- fix vertical import style
- add Kconfig entry for the rust abstraction
- fix documentation in include/linux/serdev.h
- rename private_data to rust_private_data
- fix `complete_all` <-> `wait_for_completion` typo
- move drvdata_borrow call after the completion
- Link to v2: https://lore.kernel.org/r/20260306-rust_serdev-v2-0-e9b23b42b255@posteo.de

Changes in v2:
- fix documentation in `serdev::Driver::write` and
  `serdev::Driver::write_all`
- remove use of `dev_info` in probe from the sample
- remove `properties_parse` from the sample
- add optional `baudrate` property to the sample
- remove 1. patch
- remove `TryFrom<&device::Device<Ctx>> for &serdev::Device<Ctx>`
  implementation
- fix import style
- add patch to return reference in `devres::register` to fix safety
  issue
- add patch to add private data to serdev_device, to fix
  `Device.drvdata()` from failing
- simplify abstraction by removing ability to receive the initial
  transmission. It may be added later in a separate patch series if
  needed.
- Link to v1: https://lore.kernel.org/r/20251220-rust_serdev-v1-0-e44645767621@posteo.de

---
Markus Probst (3):
      rust: add basic serial device bus abstractions
      samples: rust: add Rust serial device bus sample device driver
      MAINTAINERS: serdev: Add self for serdev

 MAINTAINERS                        |   5 +-
 drivers/tty/serdev/Kconfig         |   7 +
 rust/bindings/bindings_helper.h    |   1 +
 rust/helpers/helpers.c             |   1 +
 rust/helpers/serdev.c              |  22 ++
 rust/kernel/lib.rs                 |   2 +
 rust/kernel/serdev.rs              | 590 +++++++++++++++++++++++++++++++++++++
 samples/rust/Kconfig               |  11 +
 samples/rust/Makefile              |   1 +
 samples/rust/rust_driver_serdev.rs |  91 ++++++
 10 files changed, 730 insertions(+), 1 deletion(-)
---
base-commit: 3bc831df9ee16fceee851872315161377ca1417d
change-id: 20251217-rust_serdev-ee5481e9085c
prerequisite-message-id: 20260505152400.3905096-1-dakr@kernel.org
prerequisite-patch-id: d2aebf69b153c039bbed1d0ed26906708fd22534
prerequisite-patch-id: 84b28da2f5de20fc1785095c647b2ffc35d969a5
prerequisite-patch-id: 67318671a5eed5fb4ad23a450f1cf0e442bf8ca2
prerequisite-message-id: 20260525202921.124698-1-dakr@kernel.org
prerequisite-patch-id: b84db329d4372a175cb8d49e4e88c3eecf7eb228
prerequisite-patch-id: 2c30303f409cc8288cc87e241920219f5ddd8390
prerequisite-patch-id: 4e4f0ad370d763ad00b0f75b91fa216f2cc95953
prerequisite-patch-id: 5bcd6b37f3498feebda275dfef78136eba34004e
prerequisite-patch-id: 872b0982f3e5e7d1698d9df3b325e4cd27b27789
prerequisite-patch-id: 3a3c7749e017d9335f58497404d1350e96caf471
prerequisite-patch-id: 3526c9154f581497a11465b936d83ef61a875454
prerequisite-patch-id: 65d8c757b52475c2acc7d22ddc92cd3f0152b55d
prerequisite-patch-id: 4bd31f1414d5248dc080884caadf5f21684a8427
prerequisite-patch-id: 7beadbb0da3e589ed86d12f512d1c83427dd82b4
prerequisite-patch-id: 12cd0f67ffd27347f90c065db491945908206b7f
prerequisite-patch-id: 4642e31f66331f6c3b579377111ea733dbb3a11c
prerequisite-patch-id: 52d67b40b4396c741e2222d6a5bc7927abcb77aa
prerequisite-patch-id: 74ca82ff26cf9c7a993757c87db8be62006e820f
prerequisite-patch-id: 466fb9fa7febbffd8ef51b311c7d9893c11fc0f0
prerequisite-patch-id: e515cd98b06e26721cbbe6a4fbacd251d0073b63
prerequisite-patch-id: 8dc8e75d9f6499a554ef7e474bbacdbf3660a9f2
prerequisite-patch-id: 5fdb9f71dca2f44dd293760a60db125b770f1f55
prerequisite-patch-id: c766a24c2d5064f5ec09daada0b8e8fba862d3aa
prerequisite-patch-id: b768f6456d35fa7a80c015e34bbdba6082dbd593
prerequisite-patch-id: 6a8b17234f12f7084e6e2ce843a7031b0a891ce4
prerequisite-patch-id: 98b2deb9e60c1f28f90c5ee34fd608aaa9fd9420
prerequisite-patch-id: 774b29be66e641ee50cedb4704cf49d8b9fabf50
prerequisite-patch-id: cf95dc936cfc4b3a7a363435a51a48d9009645b3
prerequisite-message-id: 20260530132736.3298549-1-dakr@kernel.org
prerequisite-patch-id: 310c6bee038ca3909a8e5e58ec12b74f7189b869
prerequisite-patch-id: 92812c3d42b29504838e6dc66c307ff5c035bb5e



^ permalink raw reply

* Re: [PATCH v3] serial: 8250_pci: Consistently define pci_device_ids using named initializers
From: Andy Shevchenko @ 2026-06-03 14:00 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Greg Kroah-Hartman, Jiri Slaby, Markus Schneider-Pargmann,
	linux-serial, linux-kernel
In-Reply-To: <aiANetMk3rkR0SyW@monoceros>

On Wed, Jun 03, 2026 at 01:21:40PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> On Wed, Jun 03, 2026 at 11:43:14AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > On Wed, Jun 03, 2026 at 09:24:34AM +0300, Andy Shevchenko wrote:
> > > On Wed, Jun 03, 2026 at 08:12:38AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > > > On Tue, Jun 02, 2026 at 10:20:56PM +0200, Andy Shevchenko wrote:
> > > > > This patch broke the build.
> > > > > 
> > > > > drivers/tty/serial/8250/8250_pci.c:5398:12: error: initializer overrides prior initialization of this subobject [-Werror,-Winitializer-overrides]
> > > > >  5398 |                 .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
> > > > >       |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > > > > include/linux/pci_ids.h:74:45: note: expanded from macro 'PCI_CLASS_COMMUNICATION_MULTISERIAL'
> > > > >    74 | #define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
> > > > > 
> > > > > and so on...
> > > > 
> > > > Oh, it works fine for me with clang 19.1.7, gcc 11.3.0, gcc 12.4.0, gcc
> > > > 13.3.0, gcc 14.2.0 and gcc 15.2.0, but I agree it's a bit obscure
> > > > because .class and .class_mask are specified twice; once by PCI_VDEVICE
> > > > and once explicitly.
> > > 
> > > > Which compiler are you using that breaks here? I guess I might have
> > > > broken more drivers this way, so it would be great to have a setup to
> > > > reproduce your issue.
> > > 
> > > My make command:
> > > 
> > > 	make LLVM=-19 W=1 C=1 CF=-D__CHECK_ENDIAN__ ...
> > > 
> > > The line the above error is from is from your patch.
> > 
> > OK, I can reproduce with that cmdline, thanks. Expect a patch in a
> > moment.
> 
> The pity is that an x86 allmodconfig fails to build for different
> reasons with W=1, so I cannot easily use that to check for other drivers
> that got that same clash between PCI_VDEVICE + explicit .class assignment :-\
> 
> I'll experiment a bit about how to identify those, maybe I'll have grep
> over all my patches ...

You don't need to build the whole kernel for that, build subsystem by subsystem
where gigantic patches from you were applied.

Example:
$ make LLVM=-19 W=1 C=1 CF=-D__CHECK_ENDIAN__ -j64 CONFIG_COMPILE_TEST=y allmodconfig -- drivers/tty/serial/8250/


-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* Re: [PATCH v2 2/3] serial: 8250: dispatch SysRq character in serial8250_handle_irq()
From: Maciej W. Rozycki @ 2026-06-03 12:26 UTC (permalink / raw)
  To: Jacques Nilo
  Cc: Greg Kroah-Hartman, Jiri Slaby, Ilpo Järvinen,
	Andy Shevchenko, linux-serial, linux-kernel, stable
In-Reply-To: <52692ae6c3501f7940347cef364ad7fcacaab7e5.1778675349.git.jnilo@free.fr>

On Wed, 13 May 2026, Jacques Nilo wrote:

> Switch to the new guard(uart_port_lock_check_sysrq_irqsave), whose
> destructor is the sysrq-aware unlock helper, restoring the pre-split
> behaviour. Update the Context: comment on serial8250_handle_irq_locked()
> so future HW-specific 8250 wrappers know to use the same guard or the
> explicit sysrq-aware unlock.

Tested-by: Maciej W. Rozycki <macro@orcam.me.uk>

  Maciej

^ permalink raw reply

* Re: [PATCH v2 1/3] serial: core: introduce guard(uart_port_lock_check_sysrq_irqsave)
From: Maciej W. Rozycki @ 2026-06-03 12:26 UTC (permalink / raw)
  To: Jacques Nilo
  Cc: Greg Kroah-Hartman, Jiri Slaby, Ilpo Järvinen,
	Andy Shevchenko, linux-serial, linux-kernel, stable
In-Reply-To: <3849af4bc55d5d2a424fa850844e94d641b2f8a6.1778675349.git.jnilo@free.fr>

On Wed, 13 May 2026, Jacques Nilo wrote:

> Add a dedicated guard(uart_port_lock_check_sysrq_irqsave) variant
> whose destructor is the sysrq-aware unlock helper. The lock side is
> identical to uart_port_lock_irqsave -- only the unlock-time behaviour
> differs. Callers that may capture SysRq characters must use
> guard(uart_port_lock_check_sysrq_irqsave); the existing
> guard(uart_port_lock_irqsave) keeps its current plain-unlock semantics
> for the many callers that do not process RX.

Tested-by: Maciej W. Rozycki <macro@orcam.me.uk>

  Maciej

^ permalink raw reply

* Re: [PATCH v2 0/3] serial: 8250: fix BREAK+SysRq dispatch on guard()-locked IRQ handlers
From: Maciej W. Rozycki @ 2026-06-03 12:26 UTC (permalink / raw)
  To: Jacques Nilo
  Cc: Greg Kroah-Hartman, Jiri Slaby, Ilpo Järvinen,
	Andy Shevchenko, linux-serial, linux-kernel, stable
In-Reply-To: <cover.1778675349.git.jnilo@free.fr>

On Wed, 13 May 2026, Jacques Nilo wrote:

> This series fixes a silent regression where a SysRq character entered as
> BREAK + key on the serial console is consumed by the kernel but never
> dispatched to handle_sysrq(). Same description as v1 [1].

 Thanks for the report and working on a fix.  This issue hit me hard last 
week when chasing a bug with one of my systems where my debug hacks caused 
me to become unable to become root and reboot the system properly.  To my 
surprise I was unable to access any of the magic SysRq features either and 
consequently I had to power-cycle the system remotely via a PDU (it's some 
1600km/1000mi away).  I've now verified that 1/3 and 2/3 bring the feature 
back with patched 7.0.0 and said x86 PC.  No way to verify 3/3 though.

  Maciej

^ permalink raw reply

* Open source social media project from Salzburg
From: Dogan Karaarslan @ 2026-06-03 12:00 UTC (permalink / raw)
  To: linux-serial

Hello,

I found your contact through GitHub.

I’m a developer based in Salzburg, and I’ve created an open source social media project focused on communities and meaningful connections.

I’d love to share it with you. If you like the idea of an open source social media project, I would really appreciate it if you could take a look and maybe star the repository.

I’ve put a lot of heart into this project, so any kind of support, feedback, contribution, or simply sharing it would mean a lot to me.

Here is the project:
https://github.com/dogankaraarslan1/ciaorelated

Thank you for your time.

Best regards,
Dogan Karaarslan

^ permalink raw reply

* Re: [PATCH] serial: 8250_pci: Don't specify conflicting values to pci_device_id members
From: Uwe Kleine-König (The Capable Hub) @ 2026-06-03 11:22 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Greg Kroah-Hartman, Jiri Slaby, Florian Eckert,
	Martin Roukala (né Peres), Kees Cook, linux-kernel,
	linux-serial
In-Reply-To: <aiAHR3y3RZtl7L_p@ashevche-desk.local>

[-- Attachment #1: Type: text/plain, Size: 1681 bytes --]

Hello Andy,

On Wed, Jun 03, 2026 at 01:51:51PM +0300, Andy Shevchenko wrote:
> On Wed, Jun 03, 2026 at 01:45:37PM +0300, Andy Shevchenko wrote:
> > On Wed, Jun 03, 2026 at 11:56:16AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > > The PCI_VDEVICE macro assigns 0 to .class and .class_mask to allow the
> > > next value in the initializer to define the value for .driver_data.
> > > 
> > > So the construct
> > > 
> > > 	{
> > > 		PCI_VDEVICE(INTASHIELD, 0x0D21),
> > > 		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
> > > 		.class_mask = 0xffff00,
> > > 		.driver_data = pbn_b2_4_115200,
> > > 	},
> > > 
> > > introduced in commit 44e55f1f3088 ("serial: 8250_pci: Consistently
> > > define pci_device_ids using named initializers") has conflicting
> > > assignments. In only some configurations (i.e. W=1 for me) that makes
> > > the compiler unhappy.
> > > 
> > > So convert the two affected items to PCI_DEVICE which doesn't have that
> > > hidden assigment to .class and .class_mask.
> > 
> > Reported-by? Closes?
> > 
> > > Fixes: 44e55f1f3088 ("serial: 8250_pci: Consistently define pci_device_ids using named initializers")
> > > Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> > 
> > I will test it right away.
> 
> Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Closes: https://lore.kernel.org/linux-serial/ah_5qVKOf8LXG1Xo@ashevche-desk.local/T/#ma6eab90ca801b4292639f5c255a89b4033b33d21
> Tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Thanks for the quick confirmation and also for providing the footers
that I should have added already.

Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH v3] serial: 8250_pci: Consistently define pci_device_ids using named initializers
From: Uwe Kleine-König (The Capable Hub) @ 2026-06-03 11:21 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Greg Kroah-Hartman, Jiri Slaby, Markus Schneider-Pargmann,
	linux-serial, linux-kernel
In-Reply-To: <ah_2rD9UPEYu78mv@monoceros>

[-- Attachment #1: Type: text/plain, Size: 1936 bytes --]

Hello Andy,

On Wed, Jun 03, 2026 at 11:43:14AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> On Wed, Jun 03, 2026 at 09:24:34AM +0300, Andy Shevchenko wrote:
> > On Wed, Jun 03, 2026 at 08:12:38AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > > On Tue, Jun 02, 2026 at 10:20:56PM +0200, Andy Shevchenko wrote:
> > > > This patch broke the build.
> > > > 
> > > > drivers/tty/serial/8250/8250_pci.c:5398:12: error: initializer overrides prior initialization of this subobject [-Werror,-Winitializer-overrides]
> > > >  5398 |                 .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
> > > >       |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > > > include/linux/pci_ids.h:74:45: note: expanded from macro 'PCI_CLASS_COMMUNICATION_MULTISERIAL'
> > > >    74 | #define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
> > > > 
> > > > and so on...
> > > 
> > > Oh, it works fine for me with clang 19.1.7, gcc 11.3.0, gcc 12.4.0, gcc
> > > 13.3.0, gcc 14.2.0 and gcc 15.2.0, but I agree it's a bit obscure
> > > because .class and .class_mask are specified twice; once by PCI_VDEVICE
> > > and once explicitly.
> > 
> > > Which compiler are you using that breaks here? I guess I might have
> > > broken more drivers this way, so it would be great to have a setup to
> > > reproduce your issue.
> > 
> > My make command:
> > 
> > 	make LLVM=-19 W=1 C=1 CF=-D__CHECK_ENDIAN__ ...
> > 
> > The line the above error is from is from your patch.
> 
> OK, I can reproduce with that cmdline, thanks. Expect a patch in a
> moment.

The pity is that an x86 allmodconfig fails to build for different
reasons with W=1, so I cannot easily use that to check for other drivers
that got that same clash between PCI_VDEVICE + explicit .class assignment :-\

I'll experiment a bit about how to identify those, maybe I'll have grep
over all my patches ...

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH] serial: 8250_pci: Don't specify conflicting values to pci_device_id members
From: Andy Shevchenko @ 2026-06-03 10:51 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Greg Kroah-Hartman, Jiri Slaby, Florian Eckert,
	Martin Roukala (né Peres), Kees Cook, linux-kernel,
	linux-serial
In-Reply-To: <aiAFzfU4jsB2iAXi@ashevche-desk.local>

On Wed, Jun 03, 2026 at 01:45:37PM +0300, Andy Shevchenko wrote:
> On Wed, Jun 03, 2026 at 11:56:16AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > The PCI_VDEVICE macro assigns 0 to .class and .class_mask to allow the
> > next value in the initializer to define the value for .driver_data.
> > 
> > So the construct
> > 
> > 	{
> > 		PCI_VDEVICE(INTASHIELD, 0x0D21),
> > 		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
> > 		.class_mask = 0xffff00,
> > 		.driver_data = pbn_b2_4_115200,
> > 	},
> > 
> > introduced in commit 44e55f1f3088 ("serial: 8250_pci: Consistently
> > define pci_device_ids using named initializers") has conflicting
> > assignments. In only some configurations (i.e. W=1 for me) that makes
> > the compiler unhappy.
> > 
> > So convert the two affected items to PCI_DEVICE which doesn't have that
> > hidden assigment to .class and .class_mask.
> 
> Reported-by? Closes?
> 
> > Fixes: 44e55f1f3088 ("serial: 8250_pci: Consistently define pci_device_ids using named initializers")
> > Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> 
> I will test it right away.

Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Closes: https://lore.kernel.org/linux-serial/ah_5qVKOf8LXG1Xo@ashevche-desk.local/T/#ma6eab90ca801b4292639f5c255a89b4033b33d21
Tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* Re: [PATCH] serial: 8250_pci: Don't specify conflicting values to pci_device_id members
From: Andy Shevchenko @ 2026-06-03 10:45 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Greg Kroah-Hartman, Jiri Slaby, Florian Eckert,
	Martin Roukala (né Peres), Kees Cook, linux-kernel,
	linux-serial
In-Reply-To: <20260603095616.937968-2-u.kleine-koenig@baylibre.com>

On Wed, Jun 03, 2026 at 11:56:16AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> The PCI_VDEVICE macro assigns 0 to .class and .class_mask to allow the
> next value in the initializer to define the value for .driver_data.
> 
> So the construct
> 
> 	{
> 		PCI_VDEVICE(INTASHIELD, 0x0D21),
> 		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
> 		.class_mask = 0xffff00,
> 		.driver_data = pbn_b2_4_115200,
> 	},
> 
> introduced in commit 44e55f1f3088 ("serial: 8250_pci: Consistently
> define pci_device_ids using named initializers") has conflicting
> assignments. In only some configurations (i.e. W=1 for me) that makes
> the compiler unhappy.
> 
> So convert the two affected items to PCI_DEVICE which doesn't have that
> hidden assigment to .class and .class_mask.

Reported-by? Closes?

> Fixes: 44e55f1f3088 ("serial: 8250_pci: Consistently define pci_device_ids using named initializers")
> Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>

I will test it right away.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [PATCH] serial: 8250_pci: Don't specify conflicting values to pci_device_id members
From: Uwe Kleine-König (The Capable Hub) @ 2026-06-03  9:56 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Andy Shevchenko
  Cc: Florian Eckert, Martin Roukala (né Peres), Kees Cook,
	linux-kernel, linux-serial

The PCI_VDEVICE macro assigns 0 to .class and .class_mask to allow the
next value in the initializer to define the value for .driver_data.

So the construct

	{
		PCI_VDEVICE(INTASHIELD, 0x0D21),
		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
		.class_mask = 0xffff00,
		.driver_data = pbn_b2_4_115200,
	},

introduced in commit 44e55f1f3088 ("serial: 8250_pci: Consistently
define pci_device_ids using named initializers") has conflicting
assignments. In only some configurations (i.e. W=1 for me) that makes
the compiler unhappy.

So convert the two affected items to PCI_DEVICE which doesn't have that
hidden assigment to .class and .class_mask.

Fixes: 44e55f1f3088 ("serial: 8250_pci: Consistently define pci_device_ids using named initializers")
Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
---
 drivers/tty/serial/8250/8250_pci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 3e5bc9e8d269..58b4e525bdb6 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -5394,12 +5394,12 @@ static const struct pci_device_id serial_pci_tbl[] = {
 	 * Brainboxes UC-260/271/701/756
 	 */
 	{
-		PCI_VDEVICE(INTASHIELD, 0x0D21),
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0D21),
 		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
 		.class_mask = 0xffff00,
 		.driver_data = pbn_b2_4_115200,
 	}, {
-		PCI_VDEVICE(INTASHIELD, 0x0E34),
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0E34),
 		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
 		.class_mask = 0xffff00,
 		.driver_data = pbn_b2_4_115200,

base-commit: 44e55f1f3088e4a471a943fbcf087ea7783a0199
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH v3] serial: 8250_pci: Consistently define pci_device_ids using named initializers
From: Andy Shevchenko @ 2026-06-03  9:53 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Greg Kroah-Hartman, Jiri Slaby, Markus Schneider-Pargmann,
	linux-serial, linux-kernel
In-Reply-To: <ah_2rD9UPEYu78mv@monoceros>

On Wed, Jun 03, 2026 at 11:43:11AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> On Wed, Jun 03, 2026 at 09:24:34AM +0300, Andy Shevchenko wrote:
> > On Wed, Jun 03, 2026 at 08:12:38AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > > On Tue, Jun 02, 2026 at 10:20:56PM +0200, Andy Shevchenko wrote:
> > > > This patch broke the build.
> > > > 
> > > > drivers/tty/serial/8250/8250_pci.c:5398:12: error: initializer overrides prior initialization of this subobject [-Werror,-Winitializer-overrides]
> > > >  5398 |                 .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
> > > >       |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > > > include/linux/pci_ids.h:74:45: note: expanded from macro 'PCI_CLASS_COMMUNICATION_MULTISERIAL'
> > > >    74 | #define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
> > > > 
> > > > and so on...
> > > 
> > > Oh, it works fine for me with clang 19.1.7, gcc 11.3.0, gcc 12.4.0, gcc
> > > 13.3.0, gcc 14.2.0 and gcc 15.2.0, but I agree it's a bit obscure
> > > because .class and .class_mask are specified twice; once by PCI_VDEVICE
> > > and once explicitly.
> > 
> > > Which compiler are you using that breaks here? I guess I might have
> > > broken more drivers this way, so it would be great to have a setup to
> > > reproduce your issue.
> > 
> > My make command:
> > 
> > 	make LLVM=-19 W=1 C=1 CF=-D__CHECK_ENDIAN__ ...
> > 
> > The line the above error is from is from your patch.
> 
> OK, I can reproduce with that cmdline, thanks. Expect a patch in a
> moment.

Thanks, will be glad to test ASAP.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* Re: [PATCH v3] serial: 8250_pci: Consistently define pci_device_ids using named initializers
From: Uwe Kleine-König (The Capable Hub) @ 2026-06-03  9:43 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Greg Kroah-Hartman, Jiri Slaby, Markus Schneider-Pargmann,
	linux-serial, linux-kernel
In-Reply-To: <ah_Iovpb8N2OTucV@ashevche-desk.local>

[-- Attachment #1: Type: text/plain, Size: 2055 bytes --]

Hello Andy,

On Wed, Jun 03, 2026 at 09:24:34AM +0300, Andy Shevchenko wrote:
> On Wed, Jun 03, 2026 at 08:12:38AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > On Tue, Jun 02, 2026 at 10:20:56PM +0200, Andy Shevchenko wrote:
> > > This patch broke the build.
> > > 
> > > drivers/tty/serial/8250/8250_pci.c:5398:12: error: initializer overrides prior initialization of this subobject [-Werror,-Winitializer-overrides]
> > >  5398 |                 .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
> > >       |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > > include/linux/pci_ids.h:74:45: note: expanded from macro 'PCI_CLASS_COMMUNICATION_MULTISERIAL'
> > >    74 | #define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
> > > 
> > > and so on...
> > 
> > Oh, it works fine for me with clang 19.1.7, gcc 11.3.0, gcc 12.4.0, gcc
> > 13.3.0, gcc 14.2.0 and gcc 15.2.0, but I agree it's a bit obscure
> > because .class and .class_mask are specified twice; once by PCI_VDEVICE
> > and once explicitly.
> 
> > Which compiler are you using that breaks here? I guess I might have
> > broken more drivers this way, so it would be great to have a setup to
> > reproduce your issue.
> 
> My make command:
> 
> 	make LLVM=-19 W=1 C=1 CF=-D__CHECK_ENDIAN__ ...
> 
> The line the above error is from is from your patch.

OK, I can reproduce with that cmdline, thanks. Expect a patch in a
moment.
 
> > Once all the initializer are converted to named initialisation, we
> > should definitively drop the assignment to .class and .class_mask in
> > PCI_VDEVICE, but that doesn't work yet.
> 
> Please, address the build issue first. I'm surprised the LKP hadn't complained
> on that (yet?). Note, that all redefinitions like this are broken and need to
> be addressed.

Full ack, I didn't want to say that dropping the assignments in
PCI_VDEVICE are the way to fix this issue, but only that it's a
surprising thing in it that should be fixed as soon as possible (i.e.
not now).

Thanks
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* [tty:tty-testing] BUILD SUCCESS b586d69177b5fc92450a5f37a3bb1ce50aa87e39
From: kernel test robot @ 2026-06-03  8:09 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-serial

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
branch HEAD: b586d69177b5fc92450a5f37a3bb1ce50aa87e39  Merge tag 'v7.1-rc6' into tty-next

elapsed time: 2056m

configs tested: 208
configs skipped: 13

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.2.0
alpha                            allyesconfig    gcc-15.2.0
alpha                               defconfig    gcc-15.2.0
arc                              allmodconfig    gcc-15.2.0
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    gcc-15.2.0
arc                                 defconfig    gcc-15.2.0
arc                   randconfig-001-20260602    gcc-11.5.0
arc                   randconfig-002-20260602    gcc-14.3.0
arm                               allnoconfig    clang-23
arm                              allyesconfig    gcc-15.2.0
arm                                 defconfig    clang-23
arm                   randconfig-001-20260602    gcc-11.5.0
arm                   randconfig-002-20260602    gcc-8.5.0
arm                   randconfig-003-20260602    gcc-10.5.0
arm                   randconfig-004-20260602    clang-23
arm64                            allmodconfig    clang-19
arm64                             allnoconfig    gcc-15.2.0
arm64                               defconfig    gcc-15.2.0
arm64                          randconfig-001    gcc-8.5.0
arm64                 randconfig-001-20260602    gcc-14.3.0
arm64                          randconfig-002    gcc-14.3.0
arm64                 randconfig-002-20260602    gcc-15.2.0
arm64                          randconfig-003    clang-23
arm64                 randconfig-003-20260602    clang-23
arm64                          randconfig-004    clang-23
arm64                 randconfig-004-20260602    clang-23
csky                              allnoconfig    gcc-15.2.0
csky                                defconfig    gcc-15.2.0
csky                           randconfig-001    gcc-10.5.0
csky                  randconfig-001-20260602    gcc-12.5.0
csky                           randconfig-002    gcc-10.5.0
csky                  randconfig-002-20260602    gcc-14.3.0
hexagon                           allnoconfig    clang-23
hexagon                             defconfig    clang-23
hexagon                        randconfig-001    clang-17
hexagon               randconfig-001-20260602    clang-23
hexagon                        randconfig-002    clang-23
hexagon               randconfig-002-20260602    clang-23
i386                             allmodconfig    gcc-14
i386                              allnoconfig    gcc-14
i386                             allyesconfig    gcc-14
i386                 buildonly-randconfig-001    gcc-14
i386        buildonly-randconfig-001-20260602    clang-20
i386                 buildonly-randconfig-002    clang-20
i386        buildonly-randconfig-002-20260602    gcc-13
i386                 buildonly-randconfig-003    clang-20
i386        buildonly-randconfig-003-20260602    clang-20
i386                 buildonly-randconfig-004    gcc-14
i386        buildonly-randconfig-004-20260602    gcc-14
i386                 buildonly-randconfig-005    gcc-14
i386        buildonly-randconfig-005-20260602    clang-20
i386                 buildonly-randconfig-006    gcc-14
i386        buildonly-randconfig-006-20260602    clang-20
i386                                defconfig    clang-20
i386                           randconfig-001    clang-20
i386                  randconfig-001-20260602    clang-20
i386                  randconfig-001-20260603    gcc-14
i386                           randconfig-002    gcc-14
i386                  randconfig-002-20260602    clang-20
i386                  randconfig-002-20260603    gcc-14
i386                           randconfig-003    gcc-14
i386                  randconfig-003-20260603    gcc-14
i386                           randconfig-004    clang-20
i386                  randconfig-004-20260602    clang-20
i386                  randconfig-004-20260603    gcc-14
i386                           randconfig-005    gcc-14
i386                  randconfig-005-20260602    clang-20
i386                  randconfig-005-20260603    clang-20
i386                           randconfig-006    gcc-14
i386                  randconfig-006-20260602    clang-20
i386                  randconfig-006-20260603    gcc-12
i386                           randconfig-007    gcc-14
i386                  randconfig-007-20260602    gcc-14
i386                  randconfig-007-20260603    clang-20
i386                  randconfig-011-20260602    gcc-14
i386                  randconfig-012-20260602    clang-20
i386                  randconfig-013-20260602    clang-20
i386                  randconfig-014-20260602    gcc-14
i386                  randconfig-015-20260602    gcc-14
i386                  randconfig-016-20260602    clang-20
i386                  randconfig-017-20260602    gcc-14
loongarch                        allmodconfig    clang-19
loongarch                         allnoconfig    clang-23
loongarch                           defconfig    clang-19
loongarch                      randconfig-001    clang-18
loongarch             randconfig-001-20260602    clang-23
loongarch                      randconfig-002    gcc-13.4.0
loongarch             randconfig-002-20260602    gcc-16.1.0
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    gcc-15.2.0
m68k                                defconfig    gcc-15.2.0
microblaze                        allnoconfig    gcc-15.2.0
microblaze                       allyesconfig    gcc-15.2.0
microblaze                          defconfig    gcc-15.2.0
mips                             allmodconfig    gcc-15.2.0
mips                              allnoconfig    gcc-15.2.0
mips                             allyesconfig    gcc-15.2.0
nios2                            allmodconfig    gcc-11.5.0
nios2                             allnoconfig    gcc-11.5.0
nios2                               defconfig    gcc-11.5.0
nios2                          randconfig-001    gcc-11.5.0
nios2                 randconfig-001-20260602    gcc-8.5.0
nios2                          randconfig-002    gcc-11.5.0
nios2                 randconfig-002-20260602    gcc-11.5.0
openrisc                         allmodconfig    gcc-15.2.0
openrisc                          allnoconfig    gcc-15.2.0
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    gcc-15.2.0
parisc                           allyesconfig    gcc-15.2.0
parisc                              defconfig    gcc-15.2.0
parisc                         randconfig-001    gcc-13.4.0
parisc                randconfig-001-20260602    gcc-12.5.0
parisc                         randconfig-002    gcc-8.5.0
parisc                randconfig-002-20260602    gcc-8.5.0
parisc64                            defconfig    gcc-15.2.0
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    gcc-15.2.0
powerpc                      arches_defconfig    gcc-15.2.0
powerpc                        randconfig-001    gcc-13.4.0
powerpc               randconfig-001-20260602    clang-23
powerpc                        randconfig-002    gcc-10.5.0
powerpc               randconfig-002-20260602    gcc-8.5.0
powerpc64                      randconfig-001    clang-17
powerpc64             randconfig-001-20260602    clang-23
powerpc64                      randconfig-002    clang-23
powerpc64             randconfig-002-20260602    gcc-8.5.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    gcc-15.2.0
riscv                            allyesconfig    clang-16
riscv                               defconfig    clang-23
riscv                 randconfig-001-20260602    gcc-13.4.0
riscv                 randconfig-002-20260602    clang-23
s390                             allmodconfig    clang-18
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
s390                                defconfig    clang-23
s390                  randconfig-001-20260602    gcc-10.5.0
s390                  randconfig-002-20260602    gcc-8.5.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    gcc-15.2.0
sh                               allyesconfig    gcc-15.2.0
sh                                  defconfig    gcc-15.2.0
sh                    randconfig-001-20260602    gcc-11.5.0
sh                    randconfig-002-20260602    gcc-16.1.0
sparc                             allnoconfig    gcc-15.2.0
sparc                               defconfig    gcc-15.2.0
sparc                 randconfig-001-20260602    gcc-12.5.0
sparc                 randconfig-001-20260603    gcc-8.5.0
sparc                 randconfig-002-20260602    gcc-12.5.0
sparc                 randconfig-002-20260603    gcc-16.1.0
sparc64                          allmodconfig    clang-23
sparc64                             defconfig    clang-20
sparc64               randconfig-001-20260602    gcc-8.5.0
sparc64               randconfig-001-20260603    clang-23
sparc64               randconfig-002-20260602    clang-20
sparc64               randconfig-002-20260603    clang-20
um                               allmodconfig    clang-19
um                                allnoconfig    clang-23
um                               allyesconfig    gcc-14
um                                  defconfig    clang-23
um                             i386_defconfig    gcc-14
um                    randconfig-001-20260602    gcc-14
um                    randconfig-001-20260603    gcc-14
um                    randconfig-002-20260602    clang-23
um                    randconfig-002-20260603    gcc-14
um                           x86_64_defconfig    clang-23
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260602    gcc-14
x86_64      buildonly-randconfig-002-20260602    clang-20
x86_64      buildonly-randconfig-003-20260602    gcc-14
x86_64      buildonly-randconfig-004-20260602    clang-20
x86_64      buildonly-randconfig-005-20260602    gcc-14
x86_64      buildonly-randconfig-006-20260602    gcc-14
x86_64                              defconfig    gcc-14
x86_64                randconfig-001-20260602    clang-20
x86_64                randconfig-002-20260602    clang-20
x86_64                randconfig-003-20260602    gcc-12
x86_64                randconfig-004-20260602    gcc-14
x86_64                randconfig-005-20260602    clang-20
x86_64                randconfig-006-20260602    clang-20
x86_64                         randconfig-011    gcc-14
x86_64                randconfig-011-20260602    clang-20
x86_64                         randconfig-012    gcc-14
x86_64                randconfig-012-20260602    clang-20
x86_64                         randconfig-013    clang-20
x86_64                randconfig-013-20260602    clang-20
x86_64                         randconfig-014    gcc-14
x86_64                randconfig-014-20260602    gcc-13
x86_64                         randconfig-015    gcc-14
x86_64                randconfig-015-20260602    clang-20
x86_64                         randconfig-016    clang-20
x86_64                randconfig-016-20260602    clang-20
x86_64                randconfig-071-20260602    clang-20
x86_64                randconfig-072-20260602    clang-20
x86_64                randconfig-073-20260602    gcc-14
x86_64                randconfig-074-20260602    gcc-14
x86_64                randconfig-075-20260602    clang-20
x86_64                randconfig-076-20260602    clang-20
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    gcc-15.2.0
xtensa                randconfig-001-20260603    gcc-9.5.0
xtensa                randconfig-002-20260602    gcc-14.3.0
xtensa                randconfig-002-20260603    gcc-15.2.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH v3] serial: 8250: Clear CON_PRINTBUFFER on port re-registration
From: Fushuai Wang @ 2026-06-03  6:56 UTC (permalink / raw)
  To: fushuai.wang
  Cc: alan, andy.shevchenko, gregkh, ilpo.jarvinen, jackzxcui1989,
	jirislaby, kees, linux-kernel, linux-serial, osama.abdelkader,
	sean, wangfushuai
In-Reply-To: <20260522101042.21976-1-fushuai.wang@linux.dev>

> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
> index a428e88938eb..5419f1d22d47 100644
> --- a/drivers/tty/serial/8250/8250_core.c
> +++ b/drivers/tty/serial/8250/8250_core.c
> @@ -716,8 +716,12 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
>  	if (uart->port.type == PORT_8250_CIR)
>  		return -ENODEV;
>  
> -	if (uart->port.dev)
> +	if (uart->port.dev) {
> +		if (uart_console(&uart->port))
> +			uart->port.cons->flags &= ~CON_PRINTBUFFER;
> +
>  		uart_remove_one_port(&serial8250_reg, &uart->port);
> +	}
>  
>  	uart->port.ctrl_id	= up->port.ctrl_id;
>  	uart->port.port_id	= up->port.port_id;

ping.

-- 
Regards,
WANG

^ permalink raw reply

* Re: [PATCH v3] serial: 8250_pci: Consistently define pci_device_ids using named initializers
From: Andy Shevchenko @ 2026-06-03  6:24 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Greg Kroah-Hartman, Jiri Slaby, Markus Schneider-Pargmann,
	linux-serial, linux-kernel
In-Reply-To: <ah_DFCQH9e47qBp7@monoceros>

On Wed, Jun 03, 2026 at 08:12:38AM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> On Tue, Jun 02, 2026 at 10:20:56PM +0200, Andy Shevchenko wrote:
> > On Tue, Apr 28, 2026 at 04:40:33PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > > ... and PCI device helpers.
> > > 
> > > The various struct pci_device_id were defined using a mixture of
> > > initialization by position and by name. Some use the PCI device helpers
> > > (like PCI_DEVICE and PCI_DEVICE_SUB) and others don't.
> > > 
> > > Consistently use named initializers, drop assignments of 0 by position
> > > for .class and .class_mask and use the PCI device helpers. Also use
> > > consistent line-breaks and positioning for opening and closing curly
> > > braces.
> > > 
> > > The secret plan is to make struct pci_device_id::driver_data an
> > > anonymous union (similar to
> > > https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/)
> > > and that requires named initializers. But it's also a nice cleanup on
> > > its own.
> > > 
> > > This patch doesn't change the compiled result; this was verified using
> > > an allmodconfig with several things disabled that make reproducible
> > > builds harder on x86 and arm64.
> > 
> > This patch broke the build.
> > 
> > drivers/tty/serial/8250/8250_pci.c:5398:12: error: initializer overrides prior initialization of this subobject [-Werror,-Winitializer-overrides]
> >  5398 |                 .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
> >       |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > include/linux/pci_ids.h:74:45: note: expanded from macro 'PCI_CLASS_COMMUNICATION_MULTISERIAL'
> >    74 | #define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
> > 
> > and so on...
> 
> Oh, it works fine for me with clang 19.1.7, gcc 11.3.0, gcc 12.4.0, gcc
> 13.3.0, gcc 14.2.0 and gcc 15.2.0, but I agree it's a bit obscure
> because .class and .class_mask are specified twice; once by PCI_VDEVICE
> and once explicitly.

> Which compiler are you using that breaks here? I guess I might have
> broken more drivers this way, so it would be great to have a setup to
> reproduce your issue.

My make command:

	make LLVM=-19 W=1 C=1 CF=-D__CHECK_ENDIAN__ ...

The line the above error is from is from your patch.

> Once all the initializer are converted to named initialisation, we
> should definitively drop the assignment to .class and .class_mask in
> PCI_VDEVICE, but that doesn't work yet.

Please, address the build issue first. I'm surprised the LKP hadn't complained
on that (yet?). Note, that all redefinitions like this are broken and need to
be addressed.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* Re: [PATCH v3] serial: 8250_pci: Consistently define pci_device_ids using named initializers
From: Uwe Kleine-König (The Capable Hub) @ 2026-06-03  6:12 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Greg Kroah-Hartman, Jiri Slaby, Markus Schneider-Pargmann,
	linux-serial, linux-kernel
In-Reply-To: <ah87KOm0nfAyvr4c@black.igk.intel.com>

[-- Attachment #1: Type: text/plain, Size: 2242 bytes --]

On Tue, Jun 02, 2026 at 10:20:56PM +0200, Andy Shevchenko wrote:
> On Tue, Apr 28, 2026 at 04:40:33PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > ... and PCI device helpers.
> > 
> > The various struct pci_device_id were defined using a mixture of
> > initialization by position and by name. Some use the PCI device helpers
> > (like PCI_DEVICE and PCI_DEVICE_SUB) and others don't.
> > 
> > Consistently use named initializers, drop assignments of 0 by position
> > for .class and .class_mask and use the PCI device helpers. Also use
> > consistent line-breaks and positioning for opening and closing curly
> > braces.
> > 
> > The secret plan is to make struct pci_device_id::driver_data an
> > anonymous union (similar to
> > https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/)
> > and that requires named initializers. But it's also a nice cleanup on
> > its own.
> > 
> > This patch doesn't change the compiled result; this was verified using
> > an allmodconfig with several things disabled that make reproducible
> > builds harder on x86 and arm64.
> 
> This patch broke the build.
> 
> drivers/tty/serial/8250/8250_pci.c:5398:12: error: initializer overrides prior initialization of this subobject [-Werror,-Winitializer-overrides]
>  5398 |                 .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
>       |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> include/linux/pci_ids.h:74:45: note: expanded from macro 'PCI_CLASS_COMMUNICATION_MULTISERIAL'
>    74 | #define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
> 
> and so on...

Oh, it works fine for me with clang 19.1.7, gcc 11.3.0, gcc 12.4.0, gcc
13.3.0, gcc 14.2.0 and gcc 15.2.0, but I agree it's a bit obscure
because .class and .class_mask are specified twice; once by PCI_VDEVICE
and once explicitly.

Which compiler are you using that breaks here? I guess I might have
broken more drivers this way, so it would be great to have a setup to
reproduce your issue.

Once all the initializer are converted to named initialisation, we
should definitively drop the assignment to .class and .class_mask in
PCI_VDEVICE, but that doesn't work yet.

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH] tty: vt: hold tty reference for keyboard callbacks
From: Jiri Slaby @ 2026-06-03  6:12 UTC (permalink / raw)
  To: Morduan Zang, Greg Kroah-Hartman
  Cc: linux-kernel, linux-serial, syzkaller-bugs,
	syzbot+2932e8970a6398db95c3, Zhan Jun
In-Reply-To: <5186FF3C10B2F8A0+20260602061539.1500845-1-zhangdandan@uniontech.com>

On 02. 06. 26, 8:15, Morduan Zang wrote:
> From: Zhan Jun <zhanjun@uniontech.com>
> 
> syzbot reported a use-after-free in stop_tty() when the VT
> keyboard path handles the hold key.
> 
> The keyboard event path reads vc->port.tty under kbd_event_lock,
> but con_shutdown() clears the pointer under console_lock and the tty
> can be released after the final close. The keyboard lock therefore
> does not protect the tty lifetime.
> 
> Let the VT port own a tty reference by using tty_port_tty_set() when
> installing and shutting down the console tty. Use tty_port_tty_get()
> in the keyboard paths before dereferencing vc->port.tty and drop the
> reference after the last use.
> 
> Reported-by: syzbot+2932e8970a6398db95c3@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/all/6a1dde0d.bd48a97d.14881d.0005.GAE@google.com/
> Signed-off-by: Zhan Jun <zhanjun@uniontech.com>
> ---
>   drivers/tty/vt/keyboard.c | 17 ++++++++++++-----
>   drivers/tty/vt/vt.c       |  4 ++--
>   2 files changed, 14 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
> index dfdea0842149..19f8df9706ee 100644
> --- a/drivers/tty/vt/keyboard.c
> +++ b/drivers/tty/vt/keyboard.c
> @@ -509,9 +509,13 @@ static void fn_show_ptregs(struct vc_data *vc)
>   
>   static void fn_hold(struct vc_data *vc)
>   {
> -	struct tty_struct *tty = vc->port.tty;
> +	struct tty_struct *tty;
> +
> +	if (rep)
> +		return;
>   
> -	if (rep || !tty)
> +	tty = tty_port_tty_get(&vc->port);

We have guards (tty_port_tty) and you should use those.

thanks,
-- 
js
suse labs

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox