* Re: [PATCH] tty: n_tty: fix KCSAN data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl
From: Osama Abdelkader @ 2026-03-13 23:16 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jiri Slaby, Andy Shevchenko, Ilpo Järvinen, linux-kernel,
linux-serial, syzbot+80806cf7508e92c7cc86
In-Reply-To: <2026031211-scared-riches-6a52@gregkh>
On Thu, Mar 12, 2026 at 03:21:03PM +0100, Greg Kroah-Hartman wrote:
> On Wed, Feb 11, 2026 at 10:08:38PM +0100, Osama Abdelkader wrote:
> > n_tty_lookahead_flow_ctrl() accesses ldata->lookahead_count without
> > holding termios_rwsem, while reset_buffer_flags() in n_tty_flush_buffer()
> > resets it with exclusive termios_rwsem held. This causes a data race
> > reported by KCSAN when a PTY is closed while flush_to_ldisc is still
> > processing lookahead data.
>
> A data race of what exactly? lookahead_count?
yes, ldata->lookahead_count.
>
> > Fix by taking termios_rwsem (read) in n_tty_lookahead_flow_ctrl(),
> > consistent with __receive_buf() which also modifies lookahead_count
> > under the read lock.
>
> This feels wrong. I would like to see a LOT of testing and validation
> that this is correct before being able to take this patch. How was that
> done?
>
To clarify the reported race:
The race is on `ldata->lookahead_count` between:
1. `n_tty_lookahead_flow_ctrl()`, which does `lookahead_count += count`
from the `flush_to_ldisc()` workqueue path:
`flush_to_ldisc() -> lookahead_bufs() -> tty_port_default_lookahead_buf() -> n_tty_lookahead_flow_ctrl()`
2. `reset_buffer_flags()`, which does `lookahead_count = 0`
from `n_tty_flush_buffer()` under write `termios_rwsem`
(for example during PTY close / hangup).
`__receive_buf()` already accesses the same field under read `termios_rwsem`,
so this lookahead path was the remaining unlocked access to that state.
Because `n_tty_lookahead_flow_ctrl()` performs a read-modify-write (`+= count`),
`READ_ONCE()/WRITE_ONCE()` would still allow lost updates, so taking read
`termios_rwsem` there matches the existing writer-side protection.
I also ran the change with lockdep enabled and did not observe lockdep warnings
on PTY open/close stress.
> thanks,
>
> greg k-h
Thanks,
Osama
^ permalink raw reply
* Re: [PATCH] hvc/xen: Check console connection flag
From: Stefano Stabellini @ 2026-03-13 22:35 UTC (permalink / raw)
To: Jason Andryuk
Cc: Greg Kroah-Hartman, Jiri Slaby, Juergen Gross, Stefano Stabellini,
Oleksandr Tyshchenko, linuxppc-dev, linux-kernel, linux-serial,
xen-devel
In-Reply-To: <20260312173845.47235-1-jason.andryuk@amd.com>
On Thu, 11 Mar 2026, Jason Andryuk wrote:
> When the console out buffer is filled, __write_console() will return 0
> as it cannot send any data. domU_write_console() will then spin in
> `while (len)` as len doesn't decrement until xenconsoled attaches. This
> would block a domU and nullify the parallelism of Hyperlaunch until dom0
> userspace starts xenconsoled, which empties the buffer.
>
> Xen 4.21 added a connection field to the xen console page. This is set
> to XENCONSOLED_DISCONNECTED (1) when a domain is built, and xenconsoled
> will set it to XENCONSOLED_CONNECTED (0) when it connects.
It should be XENCONSOLE_DISCONNECTED
> Update the hvc_xen driver to check the field. When the field is
> disconnected, drop the write with -ENOTCONN. We only drop the write
> when the field is XENCONSOLED_DISCONNECTED (1) to try for maximum
> compatibility. The Xen toolstack has historically zero initialized the
> console, so it should see XENCONSOLED_CONNECTED (0) by default. If an
> implemenation used uninitialized memory, only checking for
> XENCONSOLED_DISCONNECTED could have the lowest chance of not connecting.
>
> This lets the hyperlaunched domU boot without stalling. Once dom0
> starts xenconsoled, xl console can be used to access the domU's hvc0.
>
> Update the console.h header to bring in the new field.
>
> Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
Aside from the minor comment on the commit message:
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
> ---
> drivers/tty/hvc/hvc_xen.c | 3 +++
> include/xen/interface/io/console.h | 13 +++++++++++++
> 2 files changed, 16 insertions(+)
>
> diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
> index 7f0b6262488c..c407592442cd 100644
> --- a/drivers/tty/hvc/hvc_xen.c
> +++ b/drivers/tty/hvc/hvc_xen.c
> @@ -139,6 +139,9 @@ static ssize_t domU_write_console(uint32_t vtermno, const u8 *data, size_t len)
> if (cons == NULL)
> return -EINVAL;
>
> + if (cons->intf->connection == XENCONSOLE_DISCONNECTED)
> + return -ENOTCONN;
> +
> /*
> * Make sure the whole buffer is emitted, polling if
> * necessary. We don't ever want to rely on the hvc daemon
> diff --git a/include/xen/interface/io/console.h b/include/xen/interface/io/console.h
> index cf17e89ed861..687949bdebb1 100644
> --- a/include/xen/interface/io/console.h
> +++ b/include/xen/interface/io/console.h
> @@ -19,6 +19,19 @@ struct xencons_interface {
> char out[2048];
> XENCONS_RING_IDX in_cons, in_prod;
> XENCONS_RING_IDX out_cons, out_prod;
> +/*
> + * Flag values signaling from backend to frontend whether the console is
> + * connected. i.e. Whether it will be serviced and emptied.
> + *
> + * The flag starts as disconnected.
> + */
> +#define XENCONSOLE_DISCONNECTED 1
> +/*
> + * The flag is set to connected when the backend connects and the console
> + * will be serviced.
> + */
> +#define XENCONSOLE_CONNECTED 0
> + uint8_t connection;
> };
>
> #endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
> --
> 2.34.1
>
^ permalink raw reply
* [PATCH] serial: 8250_fintek: Add support for F81214E
From: Ravi Rama @ 2026-03-13 19:47 UTC (permalink / raw)
To: linux-serial; +Cc: linux-kernel, jirislaby, gregkh, Ravi Rama
In-Reply-To: <CA+mnHaW481bx8nJBNkkgS+oB+=Y=+qeX+hP0q6ObULt8=ewr-g@mail.gmail.com>
The F81214E is a LPC/eSPI to 2 UART Super I/O chip.
Functionally, it is the same as the F81216E. The only difference
is that the F81216E has 4 UART ports, whereas the F81214E has 2
UART ports.
Signed-off-by: Ravi Rama <ravi.rama@nexthop.ai>
---
drivers/tty/serial/8250/8250_fintek.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
index b4461a89b8d0..976c5748905c 100644
--- a/drivers/tty/serial/8250/8250_fintek.c
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Probe for F81216A LPC to 4 UART
+ * Probe for F81216A LPC to 4 UART and F81214E LPC/eSPI to 2 UART
*
* Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S
*/
@@ -23,6 +23,7 @@
#define CHIP_ID_F81216AD 0x1602
#define CHIP_ID_F81216E 0x1617
#define CHIP_ID_F81216H 0x0501
+#define CHIP_ID_F81214E 0x1417
#define CHIP_ID_F81216 0x0802
#define VENDOR_ID1 0x23
#define VENDOR_ID1_VAL 0x19
@@ -161,6 +162,7 @@ static int fintek_8250_check_id(struct fintek_8250 *pdata)
case CHIP_ID_F81216AD:
case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
+ case CHIP_ID_F81214E:
case CHIP_ID_F81216:
break;
default:
@@ -185,6 +187,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
case CHIP_ID_F81216AD:
case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
+ case CHIP_ID_F81214E:
case CHIP_ID_F81216:
*min = F81216_LDN_LOW;
*max = F81216_LDN_HIGH;
@@ -255,6 +258,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
case CHIP_ID_F81216AD:
case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
+ case CHIP_ID_F81214E:
case CHIP_ID_F81216:
sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE,
IRQ_SHARE);
@@ -269,6 +273,7 @@ static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata)
switch (pdata->pid) {
case CHIP_ID_F81216E: /* 128Bytes FIFO */
case CHIP_ID_F81216H:
+ case CHIP_ID_F81214E:
case CHIP_ID_F81966:
case CHIP_ID_F81866:
sio_write_mask_reg(pdata, FIFO_CTRL,
@@ -304,6 +309,7 @@ static void fintek_8250_set_termios(struct uart_port *port,
switch (pdata->pid) {
case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
+ case CHIP_ID_F81214E:
reg = RS485;
break;
case CHIP_ID_F81966:
@@ -354,6 +360,7 @@ static void fintek_8250_set_termios_handler(struct uart_8250_port *uart)
switch (pdata->pid) {
case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
+ case CHIP_ID_F81214E:
case CHIP_ID_F81966:
case CHIP_ID_F81866:
uart->port.set_termios = fintek_8250_set_termios;
@@ -446,6 +453,7 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
break;
case CHIP_ID_F81216E: /* F81216E does not support RS485 delays */
+ case CHIP_ID_F81214E: /* F81214E does not support RS485 delays */
uart->port.rs485_config = fintek_8250_rs485_config;
uart->port.rs485_supported = fintek_8250_rs485_supported;
break;
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* Re: [PATCH] vt: keyboard: add NULL check for vc_cons[fg_console].d in kbd_keycode and kbd_rawcode
From: Daniel Hodges @ 2026-03-13 18:54 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Daniel Hodges, Jiri Slaby, linux-kernel, linux-serial,
syzbot+c3693b491545af43db87, syzbot+03f79366754268a0f20c
In-Reply-To: <2026031236-unfold-repurpose-52e6@gregkh>
On Thu, Mar 12, 2026 at 03:22:09PM +0100, Greg Kroah-Hartman wrote:
> On Sat, Feb 07, 2026 at 07:31:12PM -0500, Daniel Hodges wrote:
> > kbd_keycode() and kbd_rawcode() dereference vc_cons[fg_console].d
> > without checking if it is NULL. The foreground console should normally
> > always be allocated, but there could be a time during console setup or
> > teardown where this pointer could be NULL, leading to a general
> > protection fault.
> >
> > Syzkaller triggers this by injecting USB HID input events that reach
> > kbd_event() while the console state may not be fully consistent. The crash
> > manifests as a null-ptr-deref in __queue_work when put_queue() or
> > puts_queue() calls tty_flip_buffer_push() on the uninitialized vc port.
> >
> > Add a NULL check for vc at the start of both kbd_rawcode() and
> > kbd_keycode() to bail out early if the foreground console is not allocated.
> >
> > Reported-by: syzbot+c3693b491545af43db87@syzkaller.appspotmail.com
> > Closes: https://syzkaller.appspot.com/bug?extid=c3693b491545af43db87
> > Reported-by: syzbot+03f79366754268a0f20c@syzkaller.appspotmail.com
> > Closes: https://syzkaller.appspot.com/bug?extid=03f79366754268a0f20c
> > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> > Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> > ---
> > drivers/tty/vt/keyboard.c | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
> > index a2116e135a82..975830013d24 100644
> > --- a/drivers/tty/vt/keyboard.c
> > +++ b/drivers/tty/vt/keyboard.c
> > @@ -1389,6 +1389,9 @@ static void kbd_rawcode(unsigned char data)
> > {
> > struct vc_data *vc = vc_cons[fg_console].d;
> >
> > + if (!vc)
> > + return;
> > +
>
> What prevents vc from being NULL right after checking this?
Yeah, your right about that. I spent a bit of time to make a reproducer
using a kernel module and I think if RCU is used on vc_cons[].d it
should then be properly protected. Let me know if that sounds like a
reasonable approach and I can send a v2.
>
>
>
> > kbd = &kbd_table[vc->vc_num];
> > if (kbd->kbdmode == VC_RAW)
> > put_queue(vc, data);
> > @@ -1405,6 +1408,9 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
> > struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
> > int rc;
> >
> > + if (!vc)
> > + return;
>
> Same here, where is the locking?
>
> thanks,
>
> greg k-h
Same as above if this is protected with RCU I think that should work
properly.
-Daniel
^ permalink raw reply
* [PATCH v3 4/4] samples: rust: add Rust serial device bus sample device driver
From: Markus Probst @ 2026-03-13 18:12 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: <20260313-rust_serdev-v3-0-c9a3af214f7f@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>
---
samples/rust/Kconfig | 11 +++++
samples/rust/Makefile | 1 +
samples/rust/rust_driver_serdev.rs | 86 ++++++++++++++++++++++++++++++++++++++
3 files changed, 98 insertions(+)
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index c49ab9106345..a421470d2c52 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"
+ depends on SERIAL_DEV_BUS
+ 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..8cf3fb451b22
--- /dev/null
+++ b/samples/rust/rust_driver_serdev.rs
@@ -0,0 +1,86 @@
+// 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 = ();
+ 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(
+ sdev: &serdev::Device<Core>,
+ _info: Option<&Self::IdInfo>,
+ ) -> impl PinInit<Self, Error> {
+ 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(sdev: &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.52.0
^ permalink raw reply related
* [PATCH v3 2/4] serdev: add rust private data to serdev_device
From: Markus Probst @ 2026-03-13 18:12 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: <20260313-rust_serdev-v3-0-c9a3af214f7f@posteo.de>
Add rust private data to `struct serdev_device`, as it is required by the
rust abstraction added in the following commit
(rust: add basic serial device bus abstractions).
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
include/linux/serdev.h | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index 5654c58eb73c..c74c345d60ae 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -33,12 +33,14 @@ struct serdev_device_ops {
/**
* struct serdev_device - Basic representation of an serdev device
- * @dev: Driver model representation of the device.
- * @nr: Device number on serdev bus.
- * @ctrl: serdev controller managing this device.
- * @ops: Device operations.
- * @write_comp Completion used by serdev_device_write() internally
- * @write_lock Lock to serialize access when writing data
+ * @dev: Driver model representation of the device.
+ * @nr: Device number on serdev bus.
+ * @ctrl: serdev controller managing this device.
+ * @ops: Device operations.
+ * @write_comp: Completion used by serdev_device_write() internally
+ * @write_lock: Lock to serialize access when writing data
+ * @rust_private_data: Private data for the rust abstraction. This should
+ * not be used by the C drivers.
*/
struct serdev_device {
struct device dev;
@@ -47,6 +49,7 @@ struct serdev_device {
const struct serdev_device_ops *ops;
struct completion write_comp;
struct mutex write_lock;
+ void *rust_private_data;
};
static inline struct serdev_device *to_serdev_device(struct device *d)
--
2.52.0
^ permalink raw reply related
* [PATCH v3 1/4] rust: devres: return reference in `devres::register`
From: Markus Probst @ 2026-03-13 18:12 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: <20260313-rust_serdev-v3-0-c9a3af214f7f@posteo.de>
Return the reference to the initialized data in the `devres::register`
function.
This is needed in a following commit (rust: add basic serial device bus
abstractions).
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
rust/kernel/cpufreq.rs | 3 ++-
rust/kernel/devres.rs | 15 +++++++++++++--
rust/kernel/drm/driver.rs | 3 ++-
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index 76faa1ac8501..8cf86bb8e0f4 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -1051,7 +1051,8 @@ pub fn new_foreign_owned(dev: &Device<Bound>) -> Result
where
T: 'static,
{
- devres::register(dev, Self::new()?, GFP_KERNEL)
+ devres::register(dev, Self::new()?, GFP_KERNEL)?;
+ Ok(())
}
}
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 6afe196be42c..f882bace8601 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -326,15 +326,26 @@ fn register_foreign<P>(dev: &Device<Bound>, data: P) -> Result
/// }
///
/// fn from_bound_context(dev: &Device<Bound>) -> Result {
-/// devres::register(dev, Registration::new(), GFP_KERNEL)
+/// devres::register(dev, Registration::new(), GFP_KERNEL)?;
+/// Ok(())
/// }
/// ```
-pub fn register<T, E>(dev: &Device<Bound>, data: impl PinInit<T, E>, flags: Flags) -> Result
+pub fn register<'a, T, E>(
+ dev: &'a Device<Bound>,
+ data: impl PinInit<T, E>,
+ flags: Flags,
+) -> Result<&'a T>
where
T: Send + 'static,
Error: From<E>,
{
let data = KBox::pin_init(data, flags)?;
+ let data_ptr = &raw const *data;
+
register_foreign(dev, data)
+ // SAFETY: `dev` is valid for the lifetime of 'a. As long as there is a reference to
+ // `Device<Bound>`, it is guaranteed that the device is not unbound and data has not been
+ // dropped. Thus `data_ptr` is also valid for the lifetime of 'a.
+ .map(|()| unsafe { &*data_ptr })
}
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index e09f977b5b51..51e0c7e30cc2 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -145,7 +145,8 @@ pub fn new_foreign_owned(
let reg = Registration::<T>::new(drm, flags)?;
- devres::register(dev, reg, GFP_KERNEL)
+ devres::register(dev, reg, GFP_KERNEL)?;
+ Ok(())
}
/// Returns a reference to the `Device` instance for this registration.
--
2.52.0
^ permalink raw reply related
* [PATCH v3 3/4] rust: add basic serial device bus abstractions
From: Markus Probst @ 2026-03-13 18:12 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: <20260313-rust_serdev-v3-0-c9a3af214f7f@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>
---
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 | 536 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 569 insertions(+)
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 083cc44aa952..ab521ba42673 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -80,6 +80,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 a3c42e51f00a..9b87e9591cfd 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -53,6 +53,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 3da92f18f4ee..90635f44e171 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -140,6 +140,8 @@
pub mod scatterlist;
pub mod security;
pub mod seq_file;
+#[cfg(CONFIG_RUST_SERIAL_DEV_BUS_ABSTRACTIONS)]
+pub mod serdev;
pub mod sizes;
pub mod slice;
#[cfg(CONFIG_SOC_BUS)]
diff --git a/rust/kernel/serdev.rs b/rust/kernel/serdev.rs
new file mode 100644
index 000000000000..d9fea4bd4439
--- /dev/null
+++ b/rust/kernel/serdev.rs
@@ -0,0 +1,536 @@
+// 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,
+ devres,
+ driver,
+ error::{
+ from_result,
+ to_result,
+ VTABLE_DEFAULT_ERROR, //
+ },
+ of,
+ prelude::*,
+ sync::Completion,
+ time::{
+ msecs_to_jiffies,
+ Jiffies,
+ Msecs, //
+ },
+ types::{
+ AlwaysRefCounted,
+ Opaque, //
+ }, //
+};
+
+use core::{
+ cell::UnsafeCell,
+ marker::PhantomData,
+ mem::offset_of,
+ 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)`.
+// - `Drvdata<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 + 'static> driver::DriverLayout for Adapter<T> {
+ type DriverType = bindings::serdev_device_driver;
+ type DriverData = 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 + 'static> 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()) };
+ }
+}
+
+#[pin_data]
+struct PrivateData {
+ #[pin]
+ probe_complete: Completion,
+ error: UnsafeCell<bool>,
+}
+
+impl<T: Driver + 'static> 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 id_info = <Self as driver::Adapter>::id_info(sdev.as_ref());
+
+ from_result(|| {
+ let private_data = devres::register(
+ sdev.as_ref(),
+ try_pin_init!(PrivateData {
+ probe_complete <- Completion::new(),
+ error: false.into(),
+ }),
+ GFP_KERNEL,
+ )?;
+
+ // SAFETY: `sdev.as_raw()` is guaranteed to be a valid pointer to `serdev_device`.
+ unsafe {
+ (*sdev.as_raw()).rust_private_data =
+ (&raw const *private_data).cast::<c_void>().cast_mut()
+ };
+
+ // 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::devm_serdev_device_open(sdev.as_ref().as_raw(), sdev.as_raw())
+ })?;
+
+ let data = T::probe(sdev, id_info);
+ let result = sdev.as_ref().set_drvdata(data);
+
+ // SAFETY: We have exclusive access to `private_data.error`.
+ unsafe { *private_data.error.get() = result.is_err() };
+
+ private_data.probe_complete.complete_all();
+
+ result.map(|()| 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<T>>`.
+ let data = unsafe { sdev.as_ref().drvdata_borrow::<T>() };
+
+ T::unbind(sdev, data);
+ }
+
+ 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::CoreInternal>>() };
+
+ // SAFETY:
+ // - The serial device bus only ever calls the receive buf callback with a valid pointer to
+ // a `struct serdev_device`.
+ // - `receive_buf_callback` is only ever called after a successful call to
+ // `probe_callback`, hence it's guaranteed that `sdev.private_data` is a pointer
+ // to a valid `PrivateData`.
+ let private_data = unsafe { &*(*sdev.as_raw()).rust_private_data.cast::<PrivateData>() };
+
+ private_data.probe_complete.wait_for_completion();
+
+ // SAFETY: No one has exclusive access to `private_data.error`.
+ if unsafe { *private_data.error.get() } {
+ return length;
+ }
+
+ // 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<T>>`.
+ let data = unsafe { sdev.as_ref().drvdata_borrow::<T>() };
+
+ // 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, buf)
+ }
+}
+
+impl<T: Driver + 'static> 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 = ();
+/// 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(
+/// sdev: &serdev::Device<Core>,
+/// _id_info: Option<&Self::IdInfo>,
+/// ) -> impl PinInit<Self, Error> {
+/// sdev.set_baudrate(115200);
+/// sdev.write_all(b"Hello\n", serdev::Timeout::Max)?;
+/// Ok(MyDriver)
+/// }
+/// }
+///```
+#[vtable]
+pub trait Driver: Send {
+ /// 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 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(
+ sdev: &Device<device::Core>,
+ id_info: Option<&Self::IdInfo>,
+ ) -> impl PinInit<Self, Error>;
+
+ /// 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 `Self::drop`.
+ fn unbind(sdev: &Device<device::Core>, this: Pin<&Self>) {
+ 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(sdev: &Device<device::Bound>, this: Pin<&Self>, 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 {}
--
2.52.0
^ permalink raw reply related
* [PATCH v3 0/4] rust: add basic serial device bus abstractions
From: Markus Probst @ 2026-03-13 18:12 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).
@Rob: Are you willing to maintain these rust abstractions yourself,
as you are the expert on this subsystem, otherwise I would take care of
it with a "SERIAL DEVICE BUS [RUST]" section in the MAINTAINERS file. In
the second case, I assume you are going to pick those patches as-is into
your tree, after they have been reviewed?
Signed-off-by: Markus Probst <markus.probst@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 (4):
rust: devres: return reference in `devres::register`
serdev: add rust private data to serdev_device
rust: add basic serial device bus abstractions
samples: rust: add Rust serial device bus sample device driver
drivers/tty/serdev/Kconfig | 7 +
include/linux/serdev.h | 15 +-
rust/bindings/bindings_helper.h | 1 +
rust/helpers/helpers.c | 1 +
rust/helpers/serdev.c | 22 ++
rust/kernel/cpufreq.rs | 3 +-
rust/kernel/devres.rs | 15 +-
rust/kernel/drm/driver.rs | 3 +-
rust/kernel/lib.rs | 2 +
rust/kernel/serdev.rs | 536 +++++++++++++++++++++++++++++++++++++
samples/rust/Kconfig | 11 +
samples/rust/Makefile | 1 +
samples/rust/rust_driver_serdev.rs | 86 ++++++
13 files changed, 693 insertions(+), 10 deletions(-)
---
base-commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681
change-id: 20251217-rust_serdev-ee5481e9085c
^ permalink raw reply
* Re: [PATCH] hvc/xen: Check console connection flag
From: Jason Andryuk @ 2026-03-13 15:36 UTC (permalink / raw)
To: Andrew Cooper, Jiri Slaby, Greg Kroah-Hartman, Juergen Gross,
Stefano Stabellini, Oleksandr Tyshchenko
Cc: linuxppc-dev, linux-kernel, linux-serial, xen-devel
In-Reply-To: <ff1cce61-abb4-463d-adce-0e5fc0a326df@citrix.com>
On 2026-03-13 06:44, Andrew Cooper wrote:
> On 13/03/2026 8:33 am, Jiri Slaby wrote:
>> On 12. 03. 26, 18:38, Jason Andryuk wrote:
>>> --- a/include/xen/interface/io/console.h
>>> +++ b/include/xen/interface/io/console.h
>>> @@ -19,6 +19,19 @@ struct xencons_interface {
>>> char out[2048];
>>> XENCONS_RING_IDX in_cons, in_prod;
>>> XENCONS_RING_IDX out_cons, out_prod;
>>> +/*
>>> + * Flag values signaling from backend to frontend whether the
>>> console is
>>> + * connected. i.e. Whether it will be serviced and emptied.
>>> + *
>>> + * The flag starts as disconnected.
>>> + */
>>> +#define XENCONSOLE_DISCONNECTED 1
>>> +/*
>>> + * The flag is set to connected when the backend connects and the
>>> console
>>> + * will be serviced.
>>> + */
>>> +#define XENCONSOLE_CONNECTED 0
>>
>> This all should be an enum. And you can document it using kernel-doc
>> properly then.
>>
>>> + uint8_t connection;
>>
>> And type check as well.
>
> This is a non-Linux header file being re-sync'd with it's original source.
>
> It describes an ABI between VMs, where things like enum are forbidden.
Yes, it is as Andrew wrote. I included "Update the console.h header to
bring in the new field." in the commit message to try in indicate that.
"Sync console.h from the xen repo to bring in the new field." would
better explain its origin.
I only brought in the needed part. There is an emacs variable block
that is not synced for other headers. There is also an ifdef block for
XEN_WANT_FLEX_CONSOLE_RING that isn't used by linux, which I did not sync.
Thanks,
Jason
^ permalink raw reply
* Re: [PATCH] dt-bindings: serial: 8250: spacemit: fix clock property for K3 SoC
From: Yixun Lan @ 2026-03-13 13:24 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lubomir Rintel, devicetree, Guodong Xu, Yixun Lan
Cc: Conor Dooley, linux-kernel, linux-serial, linux-riscv, spacemit
In-Reply-To: <20260304-01-uart-clock-names-v1-1-338483f04a8b@kernel.org>
On Wed, 04 Mar 2026 07:19:39 +0000, Yixun Lan wrote:
> The UART of SpacemiT K3 SoC has same clock property as K1 generation which
> request two clock sources, fix the binding otherwise will get DT check
> warnings.
>
>
Applied, thanks!
[1/1] dt-bindings: serial: 8250: spacemit: fix clock property for K3 SoC
https://github.com/spacemit-com/linux/commit/606a6b8bca570aa4f838ddd410345a2937bd98eb
Best regards,
--
Yixun Lan <dlan@kernel.org>
^ permalink raw reply
* Re: [PATCH] hvc/xen: Check console connection flag
From: Andrew Cooper @ 2026-03-13 10:44 UTC (permalink / raw)
To: Jiri Slaby, Jason Andryuk, Greg Kroah-Hartman, Juergen Gross,
Stefano Stabellini, Oleksandr Tyshchenko
Cc: Andrew Cooper, linuxppc-dev, linux-kernel, linux-serial,
xen-devel
In-Reply-To: <8e5974b1-da6d-4718-9140-1f943cdd2404@kernel.org>
On 13/03/2026 8:33 am, Jiri Slaby wrote:
> On 12. 03. 26, 18:38, Jason Andryuk wrote:
>> --- a/include/xen/interface/io/console.h
>> +++ b/include/xen/interface/io/console.h
>> @@ -19,6 +19,19 @@ struct xencons_interface {
>> char out[2048];
>> XENCONS_RING_IDX in_cons, in_prod;
>> XENCONS_RING_IDX out_cons, out_prod;
>> +/*
>> + * Flag values signaling from backend to frontend whether the
>> console is
>> + * connected. i.e. Whether it will be serviced and emptied.
>> + *
>> + * The flag starts as disconnected.
>> + */
>> +#define XENCONSOLE_DISCONNECTED 1
>> +/*
>> + * The flag is set to connected when the backend connects and the
>> console
>> + * will be serviced.
>> + */
>> +#define XENCONSOLE_CONNECTED 0
>
> This all should be an enum. And you can document it using kernel-doc
> properly then.
>
>> + uint8_t connection;
>
> And type check as well.
This is a non-Linux header file being re-sync'd with it's original source.
It describes an ABI between VMs, where things like enum are forbidden.
~Andrew
^ permalink raw reply
* Re: [PATCH 0/3] vt: add modifier support to cursor and navigation keys
From: Greg Kroah-Hartman @ 2026-03-13 8:38 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: Jiri Slaby, Alexey Gladkov, linux-serial, linux-kernel
In-Reply-To: <2026031309-arena-obsessive-f68f@gregkh>
On Fri, Mar 13, 2026 at 08:11:31AM +0100, Greg Kroah-Hartman wrote:
> On Thu, Mar 12, 2026 at 02:56:05PM -0400, Nicolas Pitre wrote:
> > On Thu, 12 Mar 2026, Greg Kroah-Hartman wrote:
> >
> > > On Fri, Mar 06, 2026 at 01:26:56PM -0500, Nicolas Pitre wrote:
> > > > On Tue, 10 Feb 2026, Greg Kroah-Hartman wrote:
> > > >
> > > > > On Sun, Feb 08, 2026 at 11:22:27AM -0500, Nicolas Pitre wrote:
> > > > > > On Sun, 8 Feb 2026, Greg Kroah-Hartman wrote:
> > > > > >
> > > > > > > Argh, sorry, I saw this patch series too late for this merge window.
> > > > > > > I'll review it after -rc1 is out.
> > > > > >
> > > > > > Too bad.
> > > > > >
> > > > > > But please at least consider this one now
> > > > > > https://lkml.org/lkml/2026/1/27/1886
> > > > > > and queue it for the stable tree as well.
> > > > >
> > > > > Sorry, that slipped through as well, I'll grab it after -rc1 is out and
> > > > > get it backported to stable kernels.
> > > >
> > > > Ping. ;-)
> > >
> > > Sorry, am catching up now...
> >
> > Thanks, appreciated.
> >
> > Also please consider the patch fixing alt screen support linked above.
> > That one should go to stable afterwards.
>
> That is very odd, I don't have a copy of it anywhere locally, sorry
> about that. I'll queue it up later today. Thanks for reminding me!
Now applied. If I have missed anything else that is pending, please let
me know as my tty/serial patch queue is now empty.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH] hvc/xen: Check console connection flag
From: Jiri Slaby @ 2026-03-13 8:33 UTC (permalink / raw)
To: Jason Andryuk, Greg Kroah-Hartman, Juergen Gross,
Stefano Stabellini, Oleksandr Tyshchenko
Cc: linuxppc-dev, linux-kernel, linux-serial, xen-devel
In-Reply-To: <20260312173845.47235-1-jason.andryuk@amd.com>
On 12. 03. 26, 18:38, Jason Andryuk wrote:
> --- a/include/xen/interface/io/console.h
> +++ b/include/xen/interface/io/console.h
> @@ -19,6 +19,19 @@ struct xencons_interface {
> char out[2048];
> XENCONS_RING_IDX in_cons, in_prod;
> XENCONS_RING_IDX out_cons, out_prod;
> +/*
> + * Flag values signaling from backend to frontend whether the console is
> + * connected. i.e. Whether it will be serviced and emptied.
> + *
> + * The flag starts as disconnected.
> + */
> +#define XENCONSOLE_DISCONNECTED 1
> +/*
> + * The flag is set to connected when the backend connects and the console
> + * will be serviced.
> + */
> +#define XENCONSOLE_CONNECTED 0
This all should be an enum. And you can document it using kernel-doc
properly then.
> + uint8_t connection;
And type check as well.
thanks,
--
js
suse labs
^ permalink raw reply
* Re: [PATCH] serial: tegra: remove Kconfig dependency on APB DMA controller
From: Francesco Lavra @ 2026-03-13 7:56 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jiri Slaby, Andy Shevchenko, Kartik Rajput, Geert Uytterhoeven,
Wolfram Sang, Robert Marko, Thierry Bultel, Douglas Anderson,
linux-kernel, linux-serial
In-Reply-To: <2026031248-devalue-diabetic-51ed@gregkh>
On Thu, 2026-03-12 at 14:43 +0100, Greg Kroah-Hartman wrote:
> On Wed, Feb 25, 2026 at 12:35:53PM +0100, Francesco Lavra wrote:
> > Friendly ping
>
> Can you resend this, I don't have it around anymore, thanks.
I saw that it has been applied to the tty-testing branch already (thanks!),
anyway for reference the last version of the patch can be found at
https://patch.msgid.link/20260303111438.2691799-1-flavra@baylibre.com
^ permalink raw reply
* Re: [PATCH 0/3] vt: add modifier support to cursor and navigation keys
From: Greg Kroah-Hartman @ 2026-03-13 7:11 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: Jiri Slaby, Alexey Gladkov, linux-serial, linux-kernel
In-Reply-To: <69o09136-13nq-41sr-s3o8-s6sn68rq1s8o@syhkavp.arg>
On Thu, Mar 12, 2026 at 02:56:05PM -0400, Nicolas Pitre wrote:
> On Thu, 12 Mar 2026, Greg Kroah-Hartman wrote:
>
> > On Fri, Mar 06, 2026 at 01:26:56PM -0500, Nicolas Pitre wrote:
> > > On Tue, 10 Feb 2026, Greg Kroah-Hartman wrote:
> > >
> > > > On Sun, Feb 08, 2026 at 11:22:27AM -0500, Nicolas Pitre wrote:
> > > > > On Sun, 8 Feb 2026, Greg Kroah-Hartman wrote:
> > > > >
> > > > > > Argh, sorry, I saw this patch series too late for this merge window.
> > > > > > I'll review it after -rc1 is out.
> > > > >
> > > > > Too bad.
> > > > >
> > > > > But please at least consider this one now
> > > > > https://lkml.org/lkml/2026/1/27/1886
> > > > > and queue it for the stable tree as well.
> > > >
> > > > Sorry, that slipped through as well, I'll grab it after -rc1 is out and
> > > > get it backported to stable kernels.
> > >
> > > Ping. ;-)
> >
> > Sorry, am catching up now...
>
> Thanks, appreciated.
>
> Also please consider the patch fixing alt screen support linked above.
> That one should go to stable afterwards.
That is very odd, I don't have a copy of it anywhere locally, sorry
about that. I'll queue it up later today. Thanks for reminding me!
greg k-h
^ permalink raw reply
* Re: [PATCH] dt-bindings: serial: 8250: spacemit: fix clock property for K3 SoC
From: Greg Kroah-Hartman @ 2026-03-13 7:06 UTC (permalink / raw)
To: Yixun Lan
Cc: Yixun Lan, Jiri Slaby, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lubomir Rintel, devicetree, Guodong Xu,
Conor Dooley, linux-kernel, linux-serial, linux-riscv, spacemit
In-Reply-To: <20260313011910-GKL302167@kernel.org>
On Fri, Mar 13, 2026 at 09:19:10AM +0800, Yixun Lan wrote:
> Hi Greg,
>
> On 15:13 Thu 12 Mar , Greg Kroah-Hartman wrote:
> > On Tue, Mar 10, 2026 at 05:34:46PM +0800, Yixun Lan wrote:
> > > Hi Greg, Jiri,
> > >
> > > Do you mind if I taking this patch via SpacemiT's SoC tree? and if
> > > possible, it would be nice to have your Acks..
> > > (or either way works for me, if you grab it and merged via tty tree)
> > >
> > > On 07:19 Wed 04 Mar , Yixun Lan wrote:
> > > > The UART of SpacemiT K3 SoC has same clock property as K1 generation which
> > > > request two clock sources, fix the binding otherwise will get DT check
> > > > warnings.
> > > >
> > > > Fixes: b5024e804ee0 ("dt-bindings: serial: 8250: add SpacemiT K3 UART compatible")
> > > I would just drop the Fixes tag, as I think at the time of Gudong
> > > submitting the patch, the clock driver isn't ready, so he deliberatly
> > > removed this clock contraint and provided with a fixed clock frequency
> > > (the bindings match with DTS)
> > >
> > > https://github.com/torvalds/linux/blob/v7.0-rc3/arch/riscv/boot/dts/spacemit/k3.dtsi#L414
> >
> > You need to get a DT maintainer to review it before you can apply it.
> Ok, so Rob gave an Ack
>
> > If you want to take it through your tree once that happens, that's fine
> > with me.
> Thanks, so this imply an Ack, but could give an explict Acked-by?
> then I will proceed..
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
^ permalink raw reply
* Re: [PATCH] dt-bindings: serial: 8250: spacemit: fix clock property for K3 SoC
From: Yixun Lan @ 2026-03-13 1:19 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Yixun Lan, Jiri Slaby, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lubomir Rintel, devicetree, Guodong Xu,
Conor Dooley, linux-kernel, linux-serial, linux-riscv, spacemit
In-Reply-To: <2026031226-utter-spellbind-53bf@gregkh>
Hi Greg,
On 15:13 Thu 12 Mar , Greg Kroah-Hartman wrote:
> On Tue, Mar 10, 2026 at 05:34:46PM +0800, Yixun Lan wrote:
> > Hi Greg, Jiri,
> >
> > Do you mind if I taking this patch via SpacemiT's SoC tree? and if
> > possible, it would be nice to have your Acks..
> > (or either way works for me, if you grab it and merged via tty tree)
> >
> > On 07:19 Wed 04 Mar , Yixun Lan wrote:
> > > The UART of SpacemiT K3 SoC has same clock property as K1 generation which
> > > request two clock sources, fix the binding otherwise will get DT check
> > > warnings.
> > >
> > > Fixes: b5024e804ee0 ("dt-bindings: serial: 8250: add SpacemiT K3 UART compatible")
> > I would just drop the Fixes tag, as I think at the time of Gudong
> > submitting the patch, the clock driver isn't ready, so he deliberatly
> > removed this clock contraint and provided with a fixed clock frequency
> > (the bindings match with DTS)
> >
> > https://github.com/torvalds/linux/blob/v7.0-rc3/arch/riscv/boot/dts/spacemit/k3.dtsi#L414
>
> You need to get a DT maintainer to review it before you can apply it.
Ok, so Rob gave an Ack
> If you want to take it through your tree once that happens, that's fine
> with me.
Thanks, so this imply an Ack, but could give an explict Acked-by?
then I will proceed..
--
Yixun Lan (dlan)
^ permalink raw reply
* Re: [PATCH 3/4] arm64: dts: mediatek: add device-tree for Genio 720-EVK board
From: David Lechner @ 2026-03-13 0:26 UTC (permalink / raw)
To: Louis-Alexis Eyraud, Greg Kroah-Hartman, Jiri Slaby, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Sean Wang
Cc: kernel, linux-kernel, linux-serial, devicetree, linux-arm-kernel,
linux-mediatek
In-Reply-To: <20251203-add-mediatek-genio-520-720-evk-v1-3-df794b2a30ae@collabora.com>
On 12/3/25 7:59 AM, Louis-Alexis Eyraud wrote:
> Add support for MediaTek MT8189 SoC and its variants, and a device-tree
> for the basic hardware enablement of the Genio 720-EVK board, based on
> MT8391 SoC.
>
...
> + mmc0_default_pins: mmc0-default-pins {
> + pins-clk {
> + pinmux = <PINMUX_GPIO162__FUNC_MSDC0_CLK>;
> + drive-strength = <6>;
> + bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
> + };
> +
> + pins-cmd-dat {
> + pinmux = <PINMUX_GPIO166__FUNC_MSDC0_DAT0>,
> + <PINMUX_GPIO165__FUNC_MSDC0_DAT1>,
> + <PINMUX_GPIO164__FUNC_MSDC0_DAT2>,
> + <PINMUX_GPIO163__FUNC_MSDC0_DAT3>,
> + <PINMUX_GPIO159__FUNC_MSDC0_DAT4>,
> + <PINMUX_GPIO158__FUNC_MSDC0_DAT5>,
> + <PINMUX_GPIO157__FUNC_MSDC0_DAT6>,
> + <PINMUX_GPIO156__FUNC_MSDC0_DAT7>,
> + <PINMUX_GPIO161__FUNC_MSDC0_CMD>;
> + input-enable;
> + drive-strength = <6>;
> + bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
> + };
Should we also have pins-ds here to match mmc0-uhs-pins?
> +
> + pins-rst {
> + pinmux = <PINMUX_GPIO160__FUNC_MSDC0_RSTB>;
> + drive-strength = <6>;
> + bias-pull-up = <MTK_PUPD_SET_R1R0_00>;
> + };
> + };
> +
> + mmc0_uhs_pins: mmc0-uhs-pins {
> + pins-clk {
> + pinmux = <PINMUX_GPIO162__FUNC_MSDC0_CLK>;
> + drive-strength = <8>;
> + bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
> + };
> +
> + pins-cmd-dat {
> + pinmux = <PINMUX_GPIO166__FUNC_MSDC0_DAT0>,
> + <PINMUX_GPIO165__FUNC_MSDC0_DAT1>,
> + <PINMUX_GPIO164__FUNC_MSDC0_DAT2>,
> + <PINMUX_GPIO163__FUNC_MSDC0_DAT3>,
> + <PINMUX_GPIO159__FUNC_MSDC0_DAT4>,
> + <PINMUX_GPIO158__FUNC_MSDC0_DAT5>,
> + <PINMUX_GPIO157__FUNC_MSDC0_DAT6>,
> + <PINMUX_GPIO156__FUNC_MSDC0_DAT7>,
> + <PINMUX_GPIO161__FUNC_MSDC0_CMD>;
> + input-enable;
> + drive-strength = <8>;
> + bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
> + };
> +
> + pins-ds {
> + pinmux = <PINMUX_GPIO167__FUNC_MSDC0_DSL>;
> + drive-strength = <8>;
> + bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
> + };
> +
> + pins-rst {
> + pinmux = <PINMUX_GPIO160__FUNC_MSDC0_RSTB>;
> + bias-pull-up = <MTK_PUPD_SET_R1R0_00>;
> + };
> + };
> +
> + mmc1_default_pins: mmc1-default-pins {
> + pins-clk {
> + pinmux = <PINMUX_GPIO169__FUNC_MSDC1_CLK>;
> + drive-strength = <6>;
> + bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
> + };
> +
> + pins-cmd-dat {
> + pinmux = <PINMUX_GPIO170__FUNC_MSDC1_DAT0>,
> + <PINMUX_GPIO171__FUNC_MSDC1_DAT1>,
> + <PINMUX_GPIO172__FUNC_MSDC1_DAT2>,
> + <PINMUX_GPIO173__FUNC_MSDC1_DAT3>,
> + <PINMUX_GPIO168__FUNC_MSDC1_CMD>;
> + input-enable;
> + drive-strength = <6>;
> + bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
> + };
> +
> + pins-insert {
> + pinmux = <PINMUX_GPIO2__FUNC_GPIO2>;
> + bias-pull-up;
> + };
> + };
> +
> + mmc1_uhs_pins: mmc1-uhs-pins {
> + pins-clk {
> + pinmux = <PINMUX_GPIO169__FUNC_MSDC1_CLK>;
> + drive-strength = <8>;
> + bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
> + };
> +
> + pins-cmd-dat {
> + pinmux = <PINMUX_GPIO170__FUNC_MSDC1_DAT0>,
> + <PINMUX_GPIO171__FUNC_MSDC1_DAT1>,
> + <PINMUX_GPIO172__FUNC_MSDC1_DAT2>,
> + <PINMUX_GPIO173__FUNC_MSDC1_DAT3>,
> + <PINMUX_GPIO168__FUNC_MSDC1_CMD>;
> + input-enable;
> + drive-strength = <8>;
> + bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
> + };
Don't we also need pins-insert here? (to match mmc1-default-pins)
I was having trouble with the CD input pin not working in U-Boot
until I added it.
> + };
> +
^ permalink raw reply
* Re: [PATCH 0/3] vt: add modifier support to cursor and navigation keys
From: Nicolas Pitre @ 2026-03-12 18:56 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Jiri Slaby, Alexey Gladkov, linux-serial, linux-kernel
In-Reply-To: <2026031225-daylong-uselessly-1821@gregkh>
On Thu, 12 Mar 2026, Greg Kroah-Hartman wrote:
> On Fri, Mar 06, 2026 at 01:26:56PM -0500, Nicolas Pitre wrote:
> > On Tue, 10 Feb 2026, Greg Kroah-Hartman wrote:
> >
> > > On Sun, Feb 08, 2026 at 11:22:27AM -0500, Nicolas Pitre wrote:
> > > > On Sun, 8 Feb 2026, Greg Kroah-Hartman wrote:
> > > >
> > > > > Argh, sorry, I saw this patch series too late for this merge window.
> > > > > I'll review it after -rc1 is out.
> > > >
> > > > Too bad.
> > > >
> > > > But please at least consider this one now
> > > > https://lkml.org/lkml/2026/1/27/1886
> > > > and queue it for the stable tree as well.
> > >
> > > Sorry, that slipped through as well, I'll grab it after -rc1 is out and
> > > get it backported to stable kernels.
> >
> > Ping. ;-)
>
> Sorry, am catching up now...
Thanks, appreciated.
Also please consider the patch fixing alt screen support linked above.
That one should go to stable afterwards.
Nicolas
^ permalink raw reply
* [PATCH] hvc/xen: Check console connection flag
From: Jason Andryuk @ 2026-03-12 17:38 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Juergen Gross, Stefano Stabellini,
Oleksandr Tyshchenko
Cc: Jason Andryuk, linuxppc-dev, linux-kernel, linux-serial,
xen-devel
When the console out buffer is filled, __write_console() will return 0
as it cannot send any data. domU_write_console() will then spin in
`while (len)` as len doesn't decrement until xenconsoled attaches. This
would block a domU and nullify the parallelism of Hyperlaunch until dom0
userspace starts xenconsoled, which empties the buffer.
Xen 4.21 added a connection field to the xen console page. This is set
to XENCONSOLED_DISCONNECTED (1) when a domain is built, and xenconsoled
will set it to XENCONSOLED_CONNECTED (0) when it connects.
Update the hvc_xen driver to check the field. When the field is
disconnected, drop the write with -ENOTCONN. We only drop the write
when the field is XENCONSOLED_DISCONNECTED (1) to try for maximum
compatibility. The Xen toolstack has historically zero initialized the
console, so it should see XENCONSOLED_CONNECTED (0) by default. If an
implemenation used uninitialized memory, only checking for
XENCONSOLED_DISCONNECTED could have the lowest chance of not connecting.
This lets the hyperlaunched domU boot without stalling. Once dom0
starts xenconsoled, xl console can be used to access the domU's hvc0.
Update the console.h header to bring in the new field.
Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
---
drivers/tty/hvc/hvc_xen.c | 3 +++
include/xen/interface/io/console.h | 13 +++++++++++++
2 files changed, 16 insertions(+)
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 7f0b6262488c..c407592442cd 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -139,6 +139,9 @@ static ssize_t domU_write_console(uint32_t vtermno, const u8 *data, size_t len)
if (cons == NULL)
return -EINVAL;
+ if (cons->intf->connection == XENCONSOLE_DISCONNECTED)
+ return -ENOTCONN;
+
/*
* Make sure the whole buffer is emitted, polling if
* necessary. We don't ever want to rely on the hvc daemon
diff --git a/include/xen/interface/io/console.h b/include/xen/interface/io/console.h
index cf17e89ed861..687949bdebb1 100644
--- a/include/xen/interface/io/console.h
+++ b/include/xen/interface/io/console.h
@@ -19,6 +19,19 @@ struct xencons_interface {
char out[2048];
XENCONS_RING_IDX in_cons, in_prod;
XENCONS_RING_IDX out_cons, out_prod;
+/*
+ * Flag values signaling from backend to frontend whether the console is
+ * connected. i.e. Whether it will be serviced and emptied.
+ *
+ * The flag starts as disconnected.
+ */
+#define XENCONSOLE_DISCONNECTED 1
+/*
+ * The flag is set to connected when the backend connects and the console
+ * will be serviced.
+ */
+#define XENCONSOLE_CONNECTED 0
+ uint8_t connection;
};
#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v2] tty: vt/keyboard: Hoist and reuse variable in vt_do_kdgkb_ioctl
From: Greg Kroah-Hartman @ 2026-03-12 15:56 UTC (permalink / raw)
To: Thorsten Blum
Cc: Jiri Slaby, Alexey Gladkov, Nathan Chancellor, Myrrh Periwinkle,
Thomas Gleixner, linux-kernel, linux-serial
In-Reply-To: <6AD2F599-396F-42B5-B918-DC5A2CB7B64B@linux.dev>
On Thu, Mar 12, 2026 at 04:30:00PM +0100, Thorsten Blum wrote:
> On 12. Mar 2026, at 15:18, Greg Kroah-Hartman wrote:
> > On Mon, Mar 02, 2026 at 04:32:52PM +0100, Thorsten Blum wrote:
> >> Hoist 'len' and use it in both cases.
> >
> > Why? And what is "both cases"?
>
> To reuse 'len' in both switch cases (KDGKBSENT and KDSKBSENT) instead of
> defining 'len = sizeof(user_kdgkb->kb_string)' in KDGKBSENT and inlining
> sizeof(user_kdgkb->kb_string) in KDSKBSENT.
As the sizeof() turns into a static number, the code is a bit simpler
as-is, right?
And there's no real need to change this for the sake of changing it that
I can see.
> >> + /*
> >> + * Ownership transfer: vt_kdskbsent() returns a pointer
> >> + * that must be freed (new buffer, old buffer, or NULL).
> >> + */
> >> kbs = vt_kdskbsent(kbs, kb_func);
> >
> > That's fine, but what does it have to do with len?
>
> It's unrelated to 'len' and just a drive-by change while I was at it.
Which, by default, makes this patch impossible to accept :(
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v2] tty: vt/keyboard: Hoist and reuse variable in vt_do_kdgkb_ioctl
From: Thorsten Blum @ 2026-03-12 15:30 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jiri Slaby, Alexey Gladkov, Nathan Chancellor, Myrrh Periwinkle,
Thomas Gleixner, linux-kernel, linux-serial
In-Reply-To: <2026031255-rudder-amusable-1d10@gregkh>
On 12. Mar 2026, at 15:18, Greg Kroah-Hartman wrote:
> On Mon, Mar 02, 2026 at 04:32:52PM +0100, Thorsten Blum wrote:
>> Hoist 'len' and use it in both cases.
>
> Why? And what is "both cases"?
To reuse 'len' in both switch cases (KDGKBSENT and KDSKBSENT) instead of
defining 'len = sizeof(user_kdgkb->kb_string)' in KDGKBSENT and inlining
sizeof(user_kdgkb->kb_string) in KDSKBSENT.
>> Add a comment explaining why reassigning 'kbs' is intentional.
>>
>> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
>> ---
>> Changes in v2:
>> - Keep 'kbs' reassignment and add a comment why it's required (Jiri)
>> - Link to v1: https://lore.kernel.org/lkml/20260226123419.737669-1-thorsten.blum@linux.dev/
>> ---
>> drivers/tty/vt/keyboard.c | 14 ++++++++++----
>> 1 file changed, 10 insertions(+), 4 deletions(-)
>
> I feel you just made the code harder to understand, as you added
> complexity :(
Not sure how reusing a local variable adds complexity? Would renaming
'len' to 'kb_string_len' help?
>> guard(spinlock_irqsave)(&func_buf_lock);
>> +
>> + /*
>> + * Ownership transfer: vt_kdskbsent() returns a pointer
>> + * that must be freed (new buffer, old buffer, or NULL).
>> + */
>> kbs = vt_kdskbsent(kbs, kb_func);
>
> That's fine, but what does it have to do with len?
It's unrelated to 'len' and just a drive-by change while I was at it.
Thanks,
Thorsten
^ permalink raw reply
* Re: [PATCH] vt: Add boot param for setting default vt console
From: Greg Kroah-Hartman @ 2026-03-12 14:29 UTC (permalink / raw)
To: Adam Saponara; +Cc: Jiri Slaby, linux-kernel, linux-serial, linux-doc
In-Reply-To: <20260301214804.283484-1-as@php.net>
On Sun, Mar 01, 2026 at 04:48:04PM -0500, Adam Saponara wrote:
> Presently the default console is hard-coded to vt1.
>
> The param allows for setting a different default. The param defaults to 0
> (vt1), preserving the current behavior. It is clamped by the constants
> `(MIN|MAX)_NR_CONSOLES`. If set `>= MIN`, `con_init` will initialize that
> vt as well (a couple extra kilobytes heap for the `vc_data` and
> `vc_screenbuf` structs).
>
> Without this feature, users achieve the same effect with an init
> script[0][1][2][3]. This works but requires an extra `chvt(1)` which can
> race with user interaction and flicker the screen at login.
What user interaction races? I'm loath to change this as I've not seen
any bug reports for this. What changed to cause this issue?
And this is for the "odd" systems that want a graphical login, BUT still
want to default to the console? That's a very odd configuration, and I
think that we should just stick with the fix that we have for those that
want to do this as adding more boot parameters that we need to support
for forever feels like a bad idea.
sorry,
greg k-h
^ permalink raw reply
* Re: [PATCH] vt: keyboard: add NULL check for vc_cons[fg_console].d in kbd_keycode and kbd_rawcode
From: Greg Kroah-Hartman @ 2026-03-12 14:22 UTC (permalink / raw)
To: Daniel Hodges
Cc: Jiri Slaby, linux-kernel, linux-serial,
syzbot+c3693b491545af43db87, syzbot+03f79366754268a0f20c
In-Reply-To: <20260208003112.6040-1-git@danielhodges.dev>
On Sat, Feb 07, 2026 at 07:31:12PM -0500, Daniel Hodges wrote:
> kbd_keycode() and kbd_rawcode() dereference vc_cons[fg_console].d
> without checking if it is NULL. The foreground console should normally
> always be allocated, but there could be a time during console setup or
> teardown where this pointer could be NULL, leading to a general
> protection fault.
>
> Syzkaller triggers this by injecting USB HID input events that reach
> kbd_event() while the console state may not be fully consistent. The crash
> manifests as a null-ptr-deref in __queue_work when put_queue() or
> puts_queue() calls tty_flip_buffer_push() on the uninitialized vc port.
>
> Add a NULL check for vc at the start of both kbd_rawcode() and
> kbd_keycode() to bail out early if the foreground console is not allocated.
>
> Reported-by: syzbot+c3693b491545af43db87@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=c3693b491545af43db87
> Reported-by: syzbot+03f79366754268a0f20c@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=03f79366754268a0f20c
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> ---
> drivers/tty/vt/keyboard.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
> index a2116e135a82..975830013d24 100644
> --- a/drivers/tty/vt/keyboard.c
> +++ b/drivers/tty/vt/keyboard.c
> @@ -1389,6 +1389,9 @@ static void kbd_rawcode(unsigned char data)
> {
> struct vc_data *vc = vc_cons[fg_console].d;
>
> + if (!vc)
> + return;
> +
What prevents vc from being NULL right after checking this?
> kbd = &kbd_table[vc->vc_num];
> if (kbd->kbdmode == VC_RAW)
> put_queue(vc, data);
> @@ -1405,6 +1408,9 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
> struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
> int rc;
>
> + if (!vc)
> + return;
Same here, where is the locking?
thanks,
greg k-h
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox