From fd3b87ff0232f46e1ad53a48609a3853c8757c6c Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 5 May 2026 17:23:08 +0200 Subject: rust: auxiliary: add registration data to auxiliary devices Add a registration_data pointer to struct auxiliary_device, allowing the registering (parent) driver to attach private data to the device at registration time and retrieve it later when called back by the auxiliary (child) driver. By tying the data to the device's registration, Rust drivers can bind the lifetime of device resources to it, since the auxiliary bus guarantees that the parent driver remains bound while the auxiliary device is bound. On the Rust side, Registration takes ownership of the data via ForeignOwnable. A TypeId is stored alongside the data for runtime type checking, making Device::registration_data() a safe method. Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20260505152400.3905096-3-dakr@kernel.org Signed-off-by: Danilo Krummrich --- samples/rust/rust_driver_auxiliary.rs | 40 ++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'samples') diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index 5c5a5105a3ff..319ef734c02b 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -17,8 +17,6 @@ use kernel::{ InPlaceModule, // }; -use core::any::TypeId; - const MODULE_NAME: &CStr = ::NAME; const AUXILIARY_NAME: &CStr = c"auxiliary"; @@ -49,13 +47,13 @@ impl auxiliary::Driver for AuxiliaryDriver { } } -#[pin_data] +struct Data { + index: u32, +} + struct ParentDriver { - private: TypeId, - #[pin] - _reg0: Devres, - #[pin] - _reg1: Devres, + _reg0: Devres>, + _reg1: Devres>, } kernel::pci_device_table!( @@ -71,10 +69,21 @@ impl pci::Driver for ParentDriver { const ID_TABLE: pci::IdTable = &PCI_TABLE; fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinInit { - try_pin_init!(Self { - private: TypeId::of::(), - _reg0 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME), - _reg1 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME), + Ok(Self { + _reg0: auxiliary::Registration::new( + pdev.as_ref(), + AUXILIARY_NAME, + 0, + MODULE_NAME, + Data { index: 0 }, + )?, + _reg1: auxiliary::Registration::new( + pdev.as_ref(), + AUXILIARY_NAME, + 1, + MODULE_NAME, + Data { index: 1 }, + )?, }) } } @@ -83,7 +92,8 @@ impl ParentDriver { fn connect(adev: &auxiliary::Device) -> Result { let dev = adev.parent(); let pdev: &pci::Device = dev.try_into()?; - let drvdata = dev.drvdata::()?; + + let data = adev.registration_data::()?; dev_info!( dev, @@ -95,8 +105,8 @@ impl ParentDriver { dev_info!( dev, - "We have access to the private data of {:?}.\n", - drvdata.private + "Connected to auxiliary device with index {}.\n", + data.index ); Ok(()) -- cgit v1.2.3 From 7fdffdda630ee61ae0e09ef8f1ace52bbf70e2b0 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:20:51 +0200 Subject: rust: driver: decouple driver private data from driver type Add a type Data<'bound> associated type to all bus driver traits, decoupling the driver's bus device private data type from the driver struct itself. In the context of adding a 'bound lifetime, making this an associated type has the advantage that it allows us to avoid a driver trait global lifetime and it avoids the need for ForLt for bus device private data; both of which make the subsequent implementation by buses much simpler. All existing drivers and doc examples set type Data = Self to preserve the current behavior. Reviewed-by: Alexandre Courbot Reviewed-by: Gary Guo Reviewed-by: Greg Kroah-Hartman Link: https://patch.msgid.link/20260525202921.124698-5-dakr@kernel.org Signed-off-by: Danilo Krummrich --- drivers/cpufreq/rcpufreq_dt.rs | 1 + drivers/gpu/drm/nova/driver.rs | 1 + drivers/gpu/drm/tyr/driver.rs | 1 + drivers/gpu/nova-core/driver.rs | 1 + drivers/pwm/pwm_th1520.rs | 1 + rust/kernel/auxiliary.rs | 18 +++++++++++------- rust/kernel/cpufreq.rs | 1 + rust/kernel/driver.rs | 24 ++++++++++++++---------- rust/kernel/i2c.rs | 32 ++++++++++++++++++-------------- rust/kernel/io/mem.rs | 2 ++ rust/kernel/pci.rs | 21 +++++++++++++-------- rust/kernel/platform.rs | 20 ++++++++++++-------- rust/kernel/usb.rs | 20 ++++++++++++-------- samples/rust/rust_debugfs.rs | 1 + samples/rust/rust_dma.rs | 1 + samples/rust/rust_driver_auxiliary.rs | 2 ++ samples/rust/rust_driver_i2c.rs | 1 + samples/rust/rust_driver_pci.rs | 1 + samples/rust/rust_driver_platform.rs | 1 + samples/rust/rust_driver_usb.rs | 1 + samples/rust/rust_i2c_client.rs | 1 + samples/rust/rust_soc.rs | 1 + 22 files changed, 98 insertions(+), 55 deletions(-) (limited to 'samples') diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index f17bf64c22e2..b7eeb2730eb0 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -201,6 +201,7 @@ kernel::of_device_table!( impl platform::Driver for CPUFreqDTDriver { type IdInfo = (); + type Data = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); fn probe( diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index b1af0a099551..08136ec0bccb 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -51,6 +51,7 @@ kernel::auxiliary_device_table!( impl auxiliary::Driver for NovaDriver { type IdInfo = (); + type Data = Self; const ID_TABLE: auxiliary::IdTable = &AUX_TABLE; fn probe(adev: &auxiliary::Device, _info: &Self::IdInfo) -> impl PinInit { diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index 279710b36a10..c81bf217743d 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -91,6 +91,7 @@ kernel::of_device_table!( impl platform::Driver for TyrPlatformDriverData { type IdInfo = (); + type Data = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); fn probe( diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 8fe484d357f6..699e27046c93 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -74,6 +74,7 @@ kernel::pci_device_table!( impl pci::Driver for NovaCore { type IdInfo = (); + type Data = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinInit { diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index ddd44a5ce497..07795910a0b5 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -316,6 +316,7 @@ kernel::of_device_table!( impl platform::Driver for Th1520PwmPlatformDriver { type IdInfo = (); + type Data = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); fn probe( diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 35b44d194f67..4e83f9e27d78 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -41,12 +41,12 @@ pub struct Adapter(T); // SAFETY: // - `bindings::auxiliary_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct auxiliary_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::auxiliary_driver; - type DriverData = T; + type DriverData<'bound> = T::Data; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -111,8 +111,8 @@ impl Adapter { // 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>`. - let data = unsafe { adev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>`. + let data = unsafe { adev.as_ref().drvdata_borrow::() }; T::unbind(adev, data); } @@ -202,13 +202,17 @@ pub trait Driver { /// type IdInfo: 'static = (); type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data: Send; + /// The table of device ids supported by the driver. const ID_TABLE: IdTable; /// Auxiliary driver probe. /// /// Called when an auxiliary device is matches a corresponding driver. - fn probe(dev: &Device, id_info: &Self::IdInfo) -> impl PinInit; + fn probe(dev: &Device, id_info: &Self::IdInfo) + -> impl PinInit; /// Auxiliary driver unbind. /// @@ -219,8 +223,8 @@ pub trait Driver { /// `&Device` or `&Device` reference. For instance, drivers may try to perform I/O /// operations to gracefully tear down the device. /// - /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &Device, this: Pin<&Self>) { + /// Otherwise, release operations for driver resources should be performed in `Drop`. + fn unbind(dev: &Device, this: Pin<&Self::Data>) { let _ = (dev, this); } } diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index d8d26870bea2..50dd2a2c3e81 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -888,6 +888,7 @@ pub trait Driver { /// /// impl platform::Driver for SampleDriver { /// type IdInfo = (); +/// type Data = Self; /// const OF_ID_TABLE: Option> = None; /// /// fn probe( diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index c8406dc4da60..5fd1cfd64e93 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -13,10 +13,13 @@ //! The main driver interface is defined by a bus specific driver trait. For instance: //! //! ```ignore -//! pub trait Driver: Send { +//! pub trait Driver { //! /// The type holding information about each device ID supported by the driver. //! type IdInfo: 'static; //! +//! /// The type of the driver's bus device private data. +//! type Data: Send; +//! //! /// The table of OF device ids supported by the driver. //! const OF_ID_TABLE: Option> = None; //! @@ -24,10 +27,11 @@ //! const ACPI_ID_TABLE: Option> = None; //! //! /// Driver probe. -//! fn probe(dev: &Device, id_info: &Self::IdInfo) -> impl PinInit; +//! fn probe(dev: &Device, id_info: &Self::IdInfo) +//! -> impl PinInit; //! //! /// Driver unbind (optional). -//! fn unbind(dev: &Device, this: Pin<&Self>) { +//! fn unbind(dev: &Device, this: Pin<&Self::Data>) { //! let _ = (dev, this); //! } //! } @@ -42,9 +46,9 @@ )] #![cfg_attr(CONFIG_PCI, doc = "* [`pci::Driver`](kernel::pci::Driver)")] //! -//! The `probe()` callback should return a `impl PinInit`, i.e. the driver's private -//! data. The bus abstraction should store the pointer in the corresponding bus device. The generic -//! [`Device`] infrastructure provides common helpers for this purpose on its +//! The `probe()` callback should return a `impl PinInit`, i.e. the driver's +//! private data. The bus abstraction should store the pointer in the corresponding bus device. The +//! generic [`Device`] infrastructure provides common helpers for this purpose on its //! [`Device`] implementation. //! //! All driver callbacks should provide a reference to the driver's private data. Once the driver @@ -118,8 +122,8 @@ pub unsafe trait DriverLayout { /// The specific driver type embedding a `struct device_driver`. type DriverType: Default; - /// The type of the driver's device private data. - type DriverData; + /// The type of the driver's bus device private data. + type DriverData<'bound>; /// Byte offset of the embedded `struct device_driver` within `DriverType`. /// @@ -193,8 +197,8 @@ impl Registration { // driver's device private data. // // SAFETY: By the safety requirements of the `Driver` trait, `T::DriverData` is the - // driver's device private data type. - drop(unsafe { dev.drvdata_obtain::() }); + // driver's bus device private data type. + drop(unsafe { dev.drvdata_obtain::>() }); } /// Attach generic `struct device_driver` callbacks. diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 4ccee4ba4f23..bfd081518615 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -93,12 +93,12 @@ pub struct Adapter(T); // SAFETY: // - `bindings::i2c_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct i2c_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::i2c_driver; - type DriverData = T; + type DriverData<'bound> = T::Data; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -176,8 +176,8 @@ impl Adapter { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `I2cClient::set_drvdata()` has been called - // and stored a `Pin>`. - let data = unsafe { idev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>`. + let data = unsafe { idev.as_ref().drvdata_borrow::() }; T::unbind(idev, data); } @@ -188,8 +188,8 @@ impl Adapter { // SAFETY: `shutdown_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>`. - let data = unsafe { idev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>`. + let data = unsafe { idev.as_ref().drvdata_borrow::() }; T::shutdown(idev, data); } @@ -294,6 +294,7 @@ macro_rules! module_i2c_driver { /// /// impl i2c::Driver for MyDriver { /// type IdInfo = (); +/// type Data = Self; /// const I2C_ID_TABLE: Option> = Some(&I2C_TABLE); /// const OF_ID_TABLE: Option> = Some(&OF_TABLE); /// const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); @@ -301,15 +302,15 @@ macro_rules! module_i2c_driver { /// fn probe( /// _idev: &i2c::I2cClient, /// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit { +/// ) -> impl PinInit { /// Err(ENODEV) /// } /// -/// fn shutdown(_idev: &i2c::I2cClient, this: Pin<&Self>) { +/// fn shutdown(_idev: &i2c::I2cClient, this: Pin<&Self::Data>) { /// } /// } ///``` -pub trait Driver: Send { +pub trait Driver { /// The type holding information about each device id supported by the driver. // TODO: Use `associated_type_defaults` once stabilized: // @@ -318,6 +319,9 @@ pub trait Driver: Send { // ``` type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data: Send; + /// The table of device ids supported by the driver. const I2C_ID_TABLE: Option> = None; @@ -334,7 +338,7 @@ pub trait Driver: Send { fn probe( dev: &I2cClient, id_info: Option<&Self::IdInfo>, - ) -> impl PinInit; + ) -> impl PinInit; /// I2C driver shutdown. /// @@ -346,8 +350,8 @@ pub trait Driver: Send { /// /// This callback is distinct from final resource cleanup, as the driver instance remains valid /// after it returns. Any deallocation or teardown of driver-owned resources should instead be - /// handled in `Self::drop`. - fn shutdown(dev: &I2cClient, this: Pin<&Self>) { + /// handled in `Drop`. + fn shutdown(dev: &I2cClient, this: Pin<&Self::Data>) { let _ = (dev, this); } @@ -360,8 +364,8 @@ pub trait Driver: Send { /// `&Device` or `&Device` reference. For instance, drivers may try to perform I/O /// operations to gracefully tear down the device. /// - /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &I2cClient, this: Pin<&Self>) { + /// Otherwise, release operations for driver resources should be performed in `Drop`. + fn unbind(dev: &I2cClient, this: Pin<&Self::Data>) { let _ = (dev, this); } } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 7dc78d547f7a..e136b676d372 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -62,6 +62,7 @@ impl<'a> IoRequest<'a> { /// /// impl platform::Driver for SampleDriver { /// # type IdInfo = (); + /// # type Data = Self; /// /// fn probe( /// pdev: &platform::Device, @@ -126,6 +127,7 @@ impl<'a> IoRequest<'a> { /// /// impl platform::Driver for SampleDriver { /// # type IdInfo = (); + /// # type Data = Self; /// /// fn probe( /// pdev: &platform::Device, diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 17a33819dc0a..c743f2abb62f 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -59,12 +59,12 @@ pub struct Adapter(T); // SAFETY: // - `bindings::pci_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct pci_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::pci_driver; - type DriverData = T; + type DriverData<'bound> = T::Data; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -129,8 +129,8 @@ impl Adapter { // 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>`. - let data = unsafe { pdev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>`. + let data = unsafe { pdev.as_ref().drvdata_borrow::() }; T::unbind(pdev, data); } @@ -279,6 +279,7 @@ macro_rules! pci_device_table { /// /// impl pci::Driver for MyDriver { /// type IdInfo = (); +/// type Data = Self; /// const ID_TABLE: pci::IdTable = &PCI_TABLE; /// /// fn probe( @@ -291,7 +292,7 @@ macro_rules! pci_device_table { ///``` /// Drivers must implement this trait in order to get a PCI driver registered. Please refer to the /// `Adapter` documentation for an example. -pub trait Driver: Send { +pub trait Driver { /// The type holding information about each device id supported by the driver. // TODO: Use `associated_type_defaults` once stabilized: // @@ -300,6 +301,9 @@ pub trait Driver: Send { // ``` type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data: Send; + /// The table of device ids supported by the driver. const ID_TABLE: IdTable; @@ -307,7 +311,8 @@ pub trait Driver: Send { /// /// Called when a new pci device is added or discovered. Implementers should /// attempt to initialize the device here. - fn probe(dev: &Device, id_info: &Self::IdInfo) -> impl PinInit; + fn probe(dev: &Device, id_info: &Self::IdInfo) + -> impl PinInit; /// PCI driver unbind. /// @@ -318,8 +323,8 @@ pub trait Driver: Send { /// `&Device` or `&Device` reference. For instance, drivers may try to perform I/O /// operations to gracefully tear down the device. /// - /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &Device, this: Pin<&Self>) { + /// Otherwise, release operations for driver resources should be performed in `Drop`. + fn unbind(dev: &Device, this: Pin<&Self::Data>) { let _ = (dev, this); } } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index c7a3dcdde3b1..975b22ffe5db 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -45,12 +45,12 @@ pub struct Adapter(T); // SAFETY: // - `bindings::platform_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct platform_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::platform_driver; - type DriverData = T; + type DriverData<'bound> = T::Data; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -117,8 +117,8 @@ impl Adapter { // 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>`. - let data = unsafe { pdev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>`. + let data = unsafe { pdev.as_ref().drvdata_borrow::() }; T::unbind(pdev, data); } @@ -192,6 +192,7 @@ macro_rules! module_platform_driver { /// /// impl platform::Driver for MyDriver { /// type IdInfo = (); +/// type Data = Self; /// const OF_ID_TABLE: Option> = Some(&OF_TABLE); /// const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); /// @@ -203,7 +204,7 @@ macro_rules! module_platform_driver { /// } /// } ///``` -pub trait Driver: Send { +pub trait Driver { /// The type holding driver private data about each device id supported by the driver. // TODO: Use associated_type_defaults once stabilized: // @@ -212,6 +213,9 @@ pub trait Driver: Send { // ``` type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data: Send; + /// The table of OF device ids supported by the driver. const OF_ID_TABLE: Option> = None; @@ -225,7 +229,7 @@ pub trait Driver: Send { fn probe( dev: &Device, id_info: Option<&Self::IdInfo>, - ) -> impl PinInit; + ) -> impl PinInit; /// Platform driver unbind. /// @@ -236,8 +240,8 @@ pub trait Driver: Send { /// `&Device` or `&Device` reference. For instance, drivers may try to perform I/O /// operations to gracefully tear down the device. /// - /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &Device, this: Pin<&Self>) { + /// Otherwise, release operations for driver resources should be performed in `Drop`. + fn unbind(dev: &Device, this: Pin<&Self::Data>) { let _ = (dev, this); } } diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 3f62da585281..88721970afcb 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -36,12 +36,12 @@ pub struct Adapter(T); // SAFETY: // - `bindings::usb_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `T::Data` is the type of the driver's device private data. // - `struct usb_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::usb_driver; - type DriverData = T; + type DriverData<'bound> = T::Data; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -109,8 +109,8 @@ impl Adapter { // SAFETY: `disconnect_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>`. - let data = unsafe { dev.drvdata_borrow::() }; + // and stored a `Pin>`. + let data = unsafe { dev.drvdata_borrow::() }; T::disconnect(intf, data); } @@ -287,23 +287,27 @@ macro_rules! usb_device_table { /// /// impl usb::Driver for MyDriver { /// type IdInfo = (); +/// type Data = Self; /// const ID_TABLE: usb::IdTable = &USB_TABLE; /// /// fn probe( /// _interface: &usb::Interface, /// _id: &usb::DeviceId, /// _info: &Self::IdInfo, -/// ) -> impl PinInit { +/// ) -> impl PinInit { /// Err(ENODEV) /// } /// -/// fn disconnect(_interface: &usb::Interface, _data: Pin<&Self>) {} +/// fn disconnect(_interface: &usb::Interface, _data: Pin<&Self::Data>) {} /// } ///``` pub trait Driver { /// The type holding information about each one of the device ids supported by the driver. type IdInfo: 'static; + /// The type of the driver's bus device private data. + type Data: Send; + /// The table of device ids supported by the driver. const ID_TABLE: IdTable; @@ -315,12 +319,12 @@ pub trait Driver { interface: &Interface, id: &DeviceId, id_info: &Self::IdInfo, - ) -> impl PinInit; + ) -> impl PinInit; /// USB driver disconnect. /// /// Called when the USB interface is about to be unbound from this driver. - fn disconnect(interface: &Interface, data: Pin<&Self>); + fn disconnect(interface: &Interface, data: Pin<&Self::Data>); } /// A USB interface. diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 0963efe19f93..478c4f693deb 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -117,6 +117,7 @@ kernel::acpi_device_table!( impl platform::Driver for RustDebugFs { type IdInfo = (); + type Data = Self; const OF_ID_TABLE: Option> = None; const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index 129bb4b39c04..e583c6b8390a 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -58,6 +58,7 @@ kernel::pci_device_table!( impl pci::Driver for DmaSampleDriver { type IdInfo = (); + type Data = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinInit { diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index 319ef734c02b..61d5bf2e8c0d 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -31,6 +31,7 @@ kernel::auxiliary_device_table!( impl auxiliary::Driver for AuxiliaryDriver { type IdInfo = (); + type Data = Self; const ID_TABLE: auxiliary::IdTable = &AUX_TABLE; @@ -65,6 +66,7 @@ kernel::pci_device_table!( impl pci::Driver for ParentDriver { type IdInfo = (); + type Data = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; diff --git a/samples/rust/rust_driver_i2c.rs b/samples/rust/rust_driver_i2c.rs index 6be79f9e9fb5..8269f1798611 100644 --- a/samples/rust/rust_driver_i2c.rs +++ b/samples/rust/rust_driver_i2c.rs @@ -35,6 +35,7 @@ kernel::of_device_table! { impl i2c::Driver for SampleDriver { type IdInfo = u32; + type Data = Self; const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); const I2C_ID_TABLE: Option> = Some(&I2C_TABLE); diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 47d3e84fab63..f43c6a660b39 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -140,6 +140,7 @@ impl SampleDriver { impl pci::Driver for SampleDriver { type IdInfo = TestIndex; + type Data = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index f2229d176fb9..6505902f8200 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -101,6 +101,7 @@ kernel::acpi_device_table!( impl platform::Driver for SampleDriver { type IdInfo = Info; + type Data = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs index ab72e99e1274..5942e4b01fd8 100644 --- a/samples/rust/rust_driver_usb.rs +++ b/samples/rust/rust_driver_usb.rs @@ -26,6 +26,7 @@ kernel::usb_device_table!( impl usb::Driver for SampleDriver { type IdInfo = (); + type Data = Self; const ID_TABLE: usb::IdTable = &USB_TABLE; fn probe( diff --git a/samples/rust/rust_i2c_client.rs b/samples/rust/rust_i2c_client.rs index 8d2c12e535b0..5956b647294d 100644 --- a/samples/rust/rust_i2c_client.rs +++ b/samples/rust/rust_i2c_client.rs @@ -106,6 +106,7 @@ const BOARD_INFO: i2c::I2cBoardInfo = impl platform::Driver for SampleDriver { type IdInfo = (); + type Data = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); diff --git a/samples/rust/rust_soc.rs b/samples/rust/rust_soc.rs index 8079c1c48416..a5e72582f4a2 100644 --- a/samples/rust/rust_soc.rs +++ b/samples/rust/rust_soc.rs @@ -37,6 +37,7 @@ kernel::acpi_device_table!( impl platform::Driver for SampleSocDriver { type IdInfo = (); + type Data = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); -- cgit v1.2.3 From 24799831d631239ff21ea1bf7feee832df48b81f Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:20:58 +0200 Subject: rust: device: make Core and CoreInternal lifetime-parameterized Device references in probe callbacks are scoped to the callback, not the full binding duration. Add a lifetime parameter to Core and CoreInternal to accurately represent this in the type system. Suggested-by: Gary Guo Reviewed-by: Greg Kroah-Hartman Reviewed-by: Alexandre Courbot Reviewed-by: Eliot Courtney Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260525202921.124698-12-dakr@kernel.org Signed-off-by: Danilo Krummrich --- drivers/cpufreq/rcpufreq_dt.rs | 2 +- drivers/gpu/drm/nova/driver.rs | 5 +++- drivers/gpu/drm/tyr/driver.rs | 2 +- drivers/gpu/nova-core/driver.rs | 4 +-- drivers/gpu/nova-core/gpu.rs | 2 +- drivers/pwm/pwm_th1520.rs | 2 +- rust/kernel/auxiliary.rs | 12 +++++---- rust/kernel/cpufreq.rs | 2 +- rust/kernel/device.rs | 49 +++++++++++++++++++++++++++-------- rust/kernel/devres.rs | 2 +- rust/kernel/dma.rs | 2 +- rust/kernel/driver.rs | 6 ++--- rust/kernel/i2c.rs | 16 ++++++------ rust/kernel/io/mem.rs | 4 +-- rust/kernel/pci.rs | 20 +++++++------- rust/kernel/pci/id.rs | 2 +- rust/kernel/platform.rs | 12 ++++----- rust/kernel/usb.rs | 16 ++++++------ samples/rust/rust_debugfs.rs | 4 +-- samples/rust/rust_dma.rs | 2 +- samples/rust/rust_driver_auxiliary.rs | 7 +++-- samples/rust/rust_driver_i2c.rs | 6 ++--- samples/rust/rust_driver_pci.rs | 4 +-- samples/rust/rust_driver_platform.rs | 2 +- samples/rust/rust_driver_usb.rs | 8 +++--- samples/rust/rust_i2c_client.rs | 4 +-- samples/rust/rust_soc.rs | 2 +- 27 files changed, 118 insertions(+), 81 deletions(-) (limited to 'samples') diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index b7eeb2730eb0..5e0b224f6699 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -205,7 +205,7 @@ impl platform::Driver for CPUFreqDTDriver { const OF_ID_TABLE: Option> = Some(&OF_TABLE); fn probe( - pdev: &platform::Device, + pdev: &platform::Device>, _id_info: Option<&Self::IdInfo>, ) -> impl PinInit { cpufreq::Registration::::new_foreign_owned(pdev.as_ref())?; diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index 08136ec0bccb..7605348af994 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -54,7 +54,10 @@ impl auxiliary::Driver for NovaDriver { type Data = Self; const ID_TABLE: auxiliary::IdTable = &AUX_TABLE; - fn probe(adev: &auxiliary::Device, _info: &Self::IdInfo) -> impl PinInit { + fn probe( + adev: &auxiliary::Device>, + _info: &Self::IdInfo, + ) -> impl PinInit { let data = try_pin_init!(NovaData { adev: adev.into() }); let drm = drm::Device::::new(adev.as_ref(), data)?; diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index c81bf217743d..001727f44fc8 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -95,7 +95,7 @@ impl platform::Driver for TyrPlatformDriverData { const OF_ID_TABLE: Option> = Some(&OF_TABLE); fn probe( - pdev: &platform::Device, + pdev: &platform::Device>, _info: Option<&Self::IdInfo>, ) -> impl PinInit { let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 699e27046c93..13c5ff15e87f 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -77,7 +77,7 @@ impl pci::Driver for NovaCore { type Data = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; - fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinInit { + fn probe(pdev: &pci::Device>, _info: &Self::IdInfo) -> impl PinInit { pin_init::pin_init_scope(move || { dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); @@ -109,7 +109,7 @@ impl pci::Driver for NovaCore { }) } - fn unbind(pdev: &pci::Device, this: Pin<&Self>) { + fn unbind(pdev: &pci::Device>, this: Pin<&Self>) { this.gpu.unbind(pdev.as_ref()); } } diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 0f6fe9a1b955..4ffb506342a9 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -278,7 +278,7 @@ impl Gpu { /// Called when the corresponding [`Device`](device::Device) is unbound. /// /// Note: This method must only be called from `Driver::unbind`. - pub(crate) fn unbind(&self, dev: &device::Device) { + pub(crate) fn unbind(&self, dev: &device::Device>) { kernel::warn_on!(self .bar .access(dev) diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index 07795910a0b5..df83a4a9a507 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -320,7 +320,7 @@ impl platform::Driver for Th1520PwmPlatformDriver { const OF_ID_TABLE: Option> = Some(&OF_TABLE); fn probe( - pdev: &platform::Device, + pdev: &platform::Device>, _id_info: Option<&Self::IdInfo>, ) -> impl PinInit { let dev = pdev.as_ref(); diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index df2c97423dcc..6d504b0933d5 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -87,7 +87,7 @@ impl Adapter { // `struct auxiliary_device`. // // INVARIANT: `adev` is valid for the duration of `probe_callback()`. - let adev = unsafe { &*adev.cast::>() }; + let adev = unsafe { &*adev.cast::>>() }; // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id` // and does not add additional invariants, so it's safe to transmute. @@ -107,7 +107,7 @@ impl Adapter { // `struct auxiliary_device`. // // INVARIANT: `adev` is valid for the duration of `remove_callback()`. - let adev = unsafe { &*adev.cast::>() }; + let adev = unsafe { &*adev.cast::>>() }; // 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 @@ -211,8 +211,10 @@ pub trait Driver { /// Auxiliary driver probe. /// /// Called when an auxiliary device is matches a corresponding driver. - fn probe(dev: &Device, id_info: &Self::IdInfo) - -> impl PinInit; + fn probe( + dev: &Device>, + id_info: &Self::IdInfo, + ) -> impl PinInit; /// Auxiliary driver unbind. /// @@ -224,7 +226,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Drop`. - fn unbind(dev: &Device, this: Pin<&Self::Data>) { + fn unbind(dev: &Device>, this: Pin<&Self::Data>) { let _ = (dev, this); } } diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 50dd2a2c3e81..0df518fa1d77 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -892,7 +892,7 @@ pub trait Driver { /// const OF_ID_TABLE: Option> = None; /// /// fn probe( -/// pdev: &platform::Device, +/// pdev: &platform::Device>, /// _id_info: Option<&Self::IdInfo>, /// ) -> impl PinInit { /// cpufreq::Registration::::new_foreign_owned(pdev.as_ref())?; diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index c4486f4b8c40..645afc49a27d 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -201,7 +201,7 @@ impl Device { } } -impl Device { +impl<'a> Device> { /// Store a pointer to the bound driver's private data. pub fn set_drvdata(&self, data: impl PinInit) -> Result { let data = KBox::pin_init(data, GFP_KERNEL)?; @@ -511,7 +511,7 @@ pub struct Normal; /// callback it appears in. It is intended to be used for synchronization purposes. Bus device /// implementations can implement methods for [`Device`], such that they can only be called /// from bus callbacks. -pub struct Core; +pub struct Core<'a>(PhantomData<&'a ()>); /// Semantically the same as [`Core`], but reserved for internal usage of the corresponding bus /// abstraction. @@ -522,7 +522,7 @@ pub struct Core; /// /// This context mainly exists to share generic [`Device`] infrastructure that should only be called /// from bus callbacks with bus abstractions, but without making them accessible for drivers. -pub struct CoreInternal; +pub struct CoreInternal<'a>(PhantomData<&'a ()>); /// The [`Bound`] context is the [`DeviceContext`] of a bus specific device when it is guaranteed to /// be bound to a driver. @@ -546,14 +546,14 @@ mod private { pub trait Sealed {} impl Sealed for super::Bound {} - impl Sealed for super::Core {} - impl Sealed for super::CoreInternal {} + impl<'a> Sealed for super::Core<'a> {} + impl<'a> Sealed for super::CoreInternal<'a> {} impl Sealed for super::Normal {} } impl DeviceContext for Bound {} -impl DeviceContext for Core {} -impl DeviceContext for CoreInternal {} +impl<'a> DeviceContext for Core<'a> {} +impl<'a> DeviceContext for CoreInternal<'a> {} impl DeviceContext for Normal {} impl AsRef> for Device { @@ -603,6 +603,22 @@ pub unsafe trait AsBusDevice: AsRef> { #[doc(hidden)] #[macro_export] macro_rules! __impl_device_context_deref { + (unsafe { $device:ident, <$lt:lifetime> $src:ty => $dst:ty }) => { + impl<$lt> ::core::ops::Deref for $device<$src> { + type Target = $device<$dst>; + + fn deref(&self) -> &Self::Target { + let ptr: *const Self = self; + + // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the + // safety requirement of the macro. + let ptr = ptr.cast::(); + + // SAFETY: `ptr` was derived from `&self`. + unsafe { &*ptr } + } + } + }; (unsafe { $device:ident, $src:ty => $dst:ty }) => { impl ::core::ops::Deref for $device<$src> { type Target = $device<$dst>; @@ -635,14 +651,14 @@ macro_rules! impl_device_context_deref { // `__impl_device_context_deref!`. ::kernel::__impl_device_context_deref!(unsafe { $device, - $crate::device::CoreInternal => $crate::device::Core + <'a> $crate::device::CoreInternal<'a> => $crate::device::Core<'a> }); // SAFETY: This macro has the exact same safety requirement as // `__impl_device_context_deref!`. ::kernel::__impl_device_context_deref!(unsafe { $device, - $crate::device::Core => $crate::device::Bound + <'a> $crate::device::Core<'a> => $crate::device::Bound }); // SAFETY: This macro has the exact same safety requirement as @@ -657,6 +673,13 @@ macro_rules! impl_device_context_deref { #[doc(hidden)] #[macro_export] macro_rules! __impl_device_context_into_aref { + (<$lt:lifetime> $src:ty, $device:tt) => { + impl<$lt> ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> { + fn from(dev: &$device<$src>) -> Self { + (&**dev).into() + } + } + }; ($src:ty, $device:tt) => { impl ::core::convert::From<&$device<$src>> for $crate::sync::aref::ARef<$device> { fn from(dev: &$device<$src>) -> Self { @@ -671,8 +694,12 @@ macro_rules! __impl_device_context_into_aref { #[macro_export] macro_rules! impl_device_context_into_aref { ($device:tt) => { - ::kernel::__impl_device_context_into_aref!($crate::device::CoreInternal, $device); - ::kernel::__impl_device_context_into_aref!($crate::device::Core, $device); + ::kernel::__impl_device_context_into_aref!( + <'a> $crate::device::CoreInternal<'a>, $device + ); + ::kernel::__impl_device_context_into_aref!( + <'a> $crate::device::Core<'a>, $device + ); ::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device); }; } diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 9e5f93aed20c..fd4633f977f6 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -304,7 +304,7 @@ impl Devres { /// pci, // /// }; /// - /// fn from_core(dev: &pci::Device, devres: Devres>) -> Result { + /// fn from_core(dev: &pci::Device>, devres: Devres>) -> Result { /// let bar = devres.access(dev.as_ref())?; /// /// let _ = bar.read32(0x0); diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 4995ee5dc689..8f97916e0688 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -47,7 +47,7 @@ pub type DmaAddress = bindings::dma_addr_t; /// where the underlying bus is DMA capable, such as: #[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")] /// * [`platform::Device`](::kernel::platform::Device) -pub trait Device: AsRef> { +pub trait Device<'a>: AsRef>> { /// Set up the device's DMA streaming addressing capabilities. /// /// This method is usually called once from `probe()` as soon as the device capabilities are diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index a95dafaa9d68..558fdef4a1c6 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -27,11 +27,11 @@ //! const ACPI_ID_TABLE: Option> = None; //! //! /// Driver probe. -//! fn probe(dev: &Device, id_info: &Self::IdInfo) +//! fn probe(dev: &Device>, id_info: &Self::IdInfo) //! -> impl PinInit; //! //! /// Driver unbind (optional). -//! fn unbind(dev: &Device, this: Pin<&Self::Data>) { +//! fn unbind(dev: &Device>, this: Pin<&Self::Data>) { //! let _ = (dev, this); //! } //! } @@ -191,7 +191,7 @@ impl Registration { // a `struct device`. // // INVARIANT: `dev` is valid for the duration of the `post_unbind_callback()`. - let dev = unsafe { &*dev.cast::>() }; + let dev = unsafe { &*dev.cast::>>() }; // `remove()` has been completed at this point; devres resources are still valid and will // be released after the driver's bus device private data is dropped. diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index bfd081518615..50feade0fb58 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -157,7 +157,7 @@ impl Adapter { // `struct i2c_client`. // // INVARIANT: `idev` is valid for the duration of `probe_callback()`. - let idev = unsafe { &*idev.cast::>() }; + let idev = unsafe { &*idev.cast::>>() }; let info = Self::i2c_id_info(idev).or_else(|| ::id_info(idev.as_ref())); @@ -172,7 +172,7 @@ impl Adapter { extern "C" fn remove_callback(idev: *mut bindings::i2c_client) { // SAFETY: `idev` is a valid pointer to a `struct i2c_client`. - let idev = unsafe { &*idev.cast::>() }; + let idev = unsafe { &*idev.cast::>>() }; // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `I2cClient::set_drvdata()` has been called @@ -184,7 +184,7 @@ impl Adapter { extern "C" fn shutdown_callback(idev: *mut bindings::i2c_client) { // SAFETY: `shutdown_callback` is only ever called for a valid `idev` - let idev = unsafe { &*idev.cast::>() }; + let idev = unsafe { &*idev.cast::>>() }; // SAFETY: `shutdown_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called @@ -300,13 +300,13 @@ macro_rules! module_i2c_driver { /// const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); /// /// fn probe( -/// _idev: &i2c::I2cClient, +/// _idev: &i2c::I2cClient>, /// _id_info: Option<&Self::IdInfo>, /// ) -> impl PinInit { /// Err(ENODEV) /// } /// -/// fn shutdown(_idev: &i2c::I2cClient, this: Pin<&Self::Data>) { +/// fn shutdown(_idev: &i2c::I2cClient>, this: Pin<&Self::Data>) { /// } /// } ///``` @@ -336,7 +336,7 @@ pub trait Driver { /// Called when a new i2c client is added or discovered. /// Implementers should attempt to initialize the client here. fn probe( - dev: &I2cClient, + dev: &I2cClient>, id_info: Option<&Self::IdInfo>, ) -> impl PinInit; @@ -351,7 +351,7 @@ pub trait Driver { /// This callback is distinct from final resource cleanup, as the driver instance remains valid /// after it returns. Any deallocation or teardown of driver-owned resources should instead be /// handled in `Drop`. - fn shutdown(dev: &I2cClient, this: Pin<&Self::Data>) { + fn shutdown(dev: &I2cClient>, this: Pin<&Self::Data>) { let _ = (dev, this); } @@ -365,7 +365,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Drop`. - fn unbind(dev: &I2cClient, this: Pin<&Self::Data>) { + fn unbind(dev: &I2cClient>, this: Pin<&Self::Data>) { let _ = (dev, this); } } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index e136b676d372..03d8745b5e1d 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -65,7 +65,7 @@ impl<'a> IoRequest<'a> { /// # type Data = Self; /// /// fn probe( - /// pdev: &platform::Device, + /// pdev: &platform::Device>, /// info: Option<&Self::IdInfo>, /// ) -> impl PinInit { /// let offset = 0; // Some offset. @@ -130,7 +130,7 @@ impl<'a> IoRequest<'a> { /// # type Data = Self; /// /// fn probe( - /// pdev: &platform::Device, + /// pdev: &platform::Device>, /// info: Option<&Self::IdInfo>, /// ) -> impl PinInit { /// let offset = 0; // Some offset. diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index d214a861375d..314ad9fefdb0 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -105,7 +105,7 @@ impl Adapter { // `struct pci_dev`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. - let pdev = unsafe { &*pdev.cast::>() }; + let pdev = unsafe { &*pdev.cast::>>() }; // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct pci_device_id` and // does not add additional invariants, so it's safe to transmute. @@ -125,7 +125,7 @@ impl Adapter { // `struct pci_dev`. // // INVARIANT: `pdev` is valid for the duration of `remove_callback()`. - let pdev = unsafe { &*pdev.cast::>() }; + let pdev = unsafe { &*pdev.cast::>>() }; // 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 @@ -283,7 +283,7 @@ macro_rules! pci_device_table { /// const ID_TABLE: pci::IdTable = &PCI_TABLE; /// /// fn probe( -/// _pdev: &pci::Device, +/// _pdev: &pci::Device>, /// _id_info: &Self::IdInfo, /// ) -> impl PinInit { /// Err(ENODEV) @@ -311,8 +311,10 @@ pub trait Driver { /// /// Called when a new pci device is added or discovered. Implementers should /// attempt to initialize the device here. - fn probe(dev: &Device, id_info: &Self::IdInfo) - -> impl PinInit; + fn probe( + dev: &Device>, + id_info: &Self::IdInfo, + ) -> impl PinInit; /// PCI driver unbind. /// @@ -324,7 +326,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Drop`. - fn unbind(dev: &Device, this: Pin<&Self::Data>) { + fn unbind(dev: &Device>, this: Pin<&Self::Data>) { let _ = (dev, this); } } @@ -359,7 +361,7 @@ impl Device { /// /// ``` /// # use kernel::{device::Core, pci::{self, Vendor}, prelude::*}; - /// fn log_device_info(pdev: &pci::Device) -> Result { + /// fn log_device_info(pdev: &pci::Device>) -> Result { /// // Get an instance of `Vendor`. /// let vendor = pdev.vendor_id(); /// dev_info!( @@ -450,7 +452,7 @@ impl Device { } } -impl Device { +impl<'a> Device> { /// Enable memory resources for this device. pub fn enable_device_mem(&self) -> Result { // SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`. @@ -476,7 +478,7 @@ unsafe impl device::AsBusDevice for Device kernel::impl_device_context_deref!(unsafe { Device }); kernel::impl_device_context_into_aref!(Device); -impl crate::dma::Device for Device {} +impl<'a> crate::dma::Device<'a> for Device> {} // SAFETY: Instances of `Device` are always reference-counted. unsafe impl crate::sync::aref::AlwaysRefCounted for Device { diff --git a/rust/kernel/pci/id.rs b/rust/kernel/pci/id.rs index 50005d176561..dbaf301666e7 100644 --- a/rust/kernel/pci/id.rs +++ b/rust/kernel/pci/id.rs @@ -19,7 +19,7 @@ use crate::{ /// /// ``` /// # use kernel::{device::Core, pci::{self, Class}, prelude::*}; -/// fn probe_device(pdev: &pci::Device) -> Result { +/// fn probe_device(pdev: &pci::Device>) -> Result { /// let pci_class = pdev.pci_class(); /// dev_info!( /// pdev, diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 106a5ed57ea6..257b7084338c 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -97,7 +97,7 @@ impl Adapter { // `struct platform_device`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. - let pdev = unsafe { &*pdev.cast::>() }; + let pdev = unsafe { &*pdev.cast::>>() }; let info = ::id_info(pdev.as_ref()); from_result(|| { @@ -113,7 +113,7 @@ impl Adapter { // `struct platform_device`. // // INVARIANT: `pdev` is valid for the duration of `remove_callback()`. - let pdev = unsafe { &*pdev.cast::>() }; + let pdev = unsafe { &*pdev.cast::>>() }; // 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 @@ -197,7 +197,7 @@ macro_rules! module_platform_driver { /// const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); /// /// fn probe( -/// _pdev: &platform::Device, +/// _pdev: &platform::Device>, /// _id_info: Option<&Self::IdInfo>, /// ) -> impl PinInit { /// Err(ENODEV) @@ -227,7 +227,7 @@ pub trait Driver { /// Called when a new platform device is added or discovered. /// Implementers should attempt to initialize the device here. fn probe( - dev: &Device, + dev: &Device>, id_info: Option<&Self::IdInfo>, ) -> impl PinInit; @@ -241,7 +241,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Drop`. - fn unbind(dev: &Device, this: Pin<&Self::Data>) { + fn unbind(dev: &Device>, this: Pin<&Self::Data>) { let _ = (dev, this); } } @@ -513,7 +513,7 @@ impl Device { kernel::impl_device_context_deref!(unsafe { Device }); kernel::impl_device_context_into_aref!(Device); -impl crate::dma::Device for Device {} +impl<'a> crate::dma::Device<'a> for Device> {} // SAFETY: Instances of `Device` are always reference-counted. unsafe impl crate::sync::aref::AlwaysRefCounted for Device { diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 6c917d8fa883..1dbb8387b463 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -82,7 +82,7 @@ impl Adapter { // `struct usb_interface` and `struct usb_device_id`. // // INVARIANT: `intf` is valid for the duration of `probe_callback()`. - let intf = unsafe { &*intf.cast::>() }; + let intf = unsafe { &*intf.cast::>>() }; from_result(|| { // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct usb_device_id` and @@ -92,7 +92,7 @@ impl Adapter { let info = T::ID_TABLE.info(id.index()); let data = T::probe(intf, id, info); - let dev: &device::Device = intf.as_ref(); + let dev: &device::Device> = intf.as_ref(); dev.set_drvdata(data)?; Ok(0) }) @@ -103,9 +103,9 @@ impl Adapter { // `struct usb_interface`. // // INVARIANT: `intf` is valid for the duration of `disconnect_callback()`. - let intf = unsafe { &*intf.cast::>() }; + let intf = unsafe { &*intf.cast::>>() }; - let dev: &device::Device = intf.as_ref(); + let dev: &device::Device> = intf.as_ref(); // SAFETY: `disconnect_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called @@ -291,14 +291,14 @@ macro_rules! usb_device_table { /// const ID_TABLE: usb::IdTable = &USB_TABLE; /// /// fn probe( -/// _interface: &usb::Interface, +/// _interface: &usb::Interface>, /// _id: &usb::DeviceId, /// _info: &Self::IdInfo, /// ) -> impl PinInit { /// Err(ENODEV) /// } /// -/// fn disconnect(_interface: &usb::Interface, _data: Pin<&Self::Data>) {} +/// fn disconnect(_interface: &usb::Interface>, _data: Pin<&Self::Data>) {} /// } ///``` pub trait Driver { @@ -316,7 +316,7 @@ pub trait Driver { /// Called when a new USB interface is bound to this driver. /// Implementers should attempt to initialize the interface here. fn probe( - interface: &Interface, + interface: &Interface>, id: &DeviceId, id_info: &Self::IdInfo, ) -> impl PinInit; @@ -324,7 +324,7 @@ pub trait Driver { /// USB driver disconnect. /// /// Called when the USB interface is about to be unbound from this driver. - fn disconnect(interface: &Interface, data: Pin<&Self::Data>); + fn disconnect(interface: &Interface>, data: Pin<&Self::Data>); } /// A USB interface. diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 478c4f693deb..37640ed33642 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -122,7 +122,7 @@ impl platform::Driver for RustDebugFs { const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); fn probe( - pdev: &platform::Device, + pdev: &platform::Device>, _info: Option<&Self::IdInfo>, ) -> impl PinInit { RustDebugFs::new(pdev).pin_chain(|this| { @@ -147,7 +147,7 @@ impl RustDebugFs { dir.read_write_file(c"pair", new_mutex!(Inner { x: 3, y: 10 })) } - fn new(pdev: &platform::Device) -> impl PinInit + '_ { + fn new<'a>(pdev: &'a platform::Device>) -> impl PinInit + 'a { let debugfs = Dir::new(c"sample_debugfs"); let dev = pdev.as_ref(); diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index e583c6b8390a..9a243e7c7298 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -61,7 +61,7 @@ impl pci::Driver for DmaSampleDriver { type Data = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; - fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinInit { + fn probe(pdev: &pci::Device>, _info: &Self::IdInfo) -> impl PinInit { pin_init::pin_init_scope(move || { dev_info!(pdev, "Probe DMA test driver.\n"); diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index 61d5bf2e8c0d..f0d419823f9a 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -35,7 +35,10 @@ impl auxiliary::Driver for AuxiliaryDriver { const ID_TABLE: auxiliary::IdTable = &AUX_TABLE; - fn probe(adev: &auxiliary::Device, _info: &Self::IdInfo) -> impl PinInit { + fn probe( + adev: &auxiliary::Device>, + _info: &Self::IdInfo, + ) -> impl PinInit { dev_info!( adev, "Probing auxiliary driver for auxiliary device with id={}\n", @@ -70,7 +73,7 @@ impl pci::Driver for ParentDriver { const ID_TABLE: pci::IdTable = &PCI_TABLE; - fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinInit { + fn probe(pdev: &pci::Device>, _info: &Self::IdInfo) -> impl PinInit { Ok(Self { _reg0: auxiliary::Registration::new( pdev.as_ref(), diff --git a/samples/rust/rust_driver_i2c.rs b/samples/rust/rust_driver_i2c.rs index 8269f1798611..171550ea0b6f 100644 --- a/samples/rust/rust_driver_i2c.rs +++ b/samples/rust/rust_driver_i2c.rs @@ -42,7 +42,7 @@ impl i2c::Driver for SampleDriver { const OF_ID_TABLE: Option> = Some(&OF_TABLE); fn probe( - idev: &i2c::I2cClient, + idev: &i2c::I2cClient>, info: Option<&Self::IdInfo>, ) -> impl PinInit { let dev = idev.as_ref(); @@ -56,11 +56,11 @@ impl i2c::Driver for SampleDriver { Ok(Self) } - fn shutdown(idev: &i2c::I2cClient, _this: Pin<&Self>) { + fn shutdown(idev: &i2c::I2cClient>, _this: Pin<&Self>) { dev_info!(idev.as_ref(), "Shutdown Rust I2C driver sample.\n"); } - fn unbind(idev: &i2c::I2cClient, _this: Pin<&Self>) { + fn unbind(idev: &i2c::I2cClient>, _this: Pin<&Self>) { dev_info!(idev.as_ref(), "Unbind Rust I2C driver sample.\n"); } } diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index f43c6a660b39..3106f766fd93 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -144,7 +144,7 @@ impl pci::Driver for SampleDriver { const ID_TABLE: pci::IdTable = &PCI_TABLE; - fn probe(pdev: &pci::Device, info: &Self::IdInfo) -> impl PinInit { + fn probe(pdev: &pci::Device>, info: &Self::IdInfo) -> impl PinInit { pin_init::pin_init_scope(move || { let vendor = pdev.vendor_id(); dev_dbg!( @@ -175,7 +175,7 @@ impl pci::Driver for SampleDriver { }) } - fn unbind(pdev: &pci::Device, this: Pin<&Self>) { + fn unbind(pdev: &pci::Device>, this: Pin<&Self>) { if let Ok(bar) = this.bar.access(pdev.as_ref()) { // Reset pci-testdev by writing a new test index. bar.write_reg(regs::TEST::zeroed().with_index(this.index)); diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index 6505902f8200..04d40f836275 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -106,7 +106,7 @@ impl platform::Driver for SampleDriver { const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); fn probe( - pdev: &platform::Device, + pdev: &platform::Device>, info: Option<&Self::IdInfo>, ) -> impl PinInit { let dev = pdev.as_ref(); diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs index 5942e4b01fd8..e900993335e9 100644 --- a/samples/rust/rust_driver_usb.rs +++ b/samples/rust/rust_driver_usb.rs @@ -30,18 +30,18 @@ impl usb::Driver for SampleDriver { const ID_TABLE: usb::IdTable = &USB_TABLE; fn probe( - intf: &usb::Interface, + intf: &usb::Interface>, _id: &usb::DeviceId, _info: &Self::IdInfo, ) -> impl PinInit { - let dev: &device::Device = intf.as_ref(); + let dev: &device::Device> = intf.as_ref(); dev_info!(dev, "Rust USB driver sample probed\n"); Ok(Self { _intf: intf.into() }) } - fn disconnect(intf: &usb::Interface, _data: Pin<&Self>) { - let dev: &device::Device = intf.as_ref(); + fn disconnect(intf: &usb::Interface>, _data: Pin<&Self>) { + let dev: &device::Device> = intf.as_ref(); dev_info!(dev, "Rust USB driver sample disconnected\n"); } } diff --git a/samples/rust/rust_i2c_client.rs b/samples/rust/rust_i2c_client.rs index 5956b647294d..3f273c754f86 100644 --- a/samples/rust/rust_i2c_client.rs +++ b/samples/rust/rust_i2c_client.rs @@ -111,7 +111,7 @@ impl platform::Driver for SampleDriver { const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); fn probe( - pdev: &platform::Device, + pdev: &platform::Device>, _info: Option<&Self::IdInfo>, ) -> impl PinInit { dev_info!( @@ -130,7 +130,7 @@ impl platform::Driver for SampleDriver { }) } - fn unbind(pdev: &platform::Device, _this: Pin<&Self>) { + fn unbind(pdev: &platform::Device>, _this: Pin<&Self>) { dev_info!( pdev.as_ref(), "Unbind Rust I2C Client registration sample.\n" diff --git a/samples/rust/rust_soc.rs b/samples/rust/rust_soc.rs index a5e72582f4a2..c466653491d2 100644 --- a/samples/rust/rust_soc.rs +++ b/samples/rust/rust_soc.rs @@ -42,7 +42,7 @@ impl platform::Driver for SampleSocDriver { const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); fn probe( - pdev: &platform::Device, + pdev: &platform::Device>, _info: Option<&Self::IdInfo>, ) -> impl PinInit { dev_dbg!(pdev, "Probe Rust SoC driver sample.\n"); -- cgit v1.2.3 From 16c2b8fdab7c0808ff36430b2f49569029a8f484 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:20:59 +0200 Subject: rust: pci: make Driver trait lifetime-parameterized Add a 'bound lifetime to the associated Data, changing type Data to type Data<'bound>. This allows the driver's bus device private data to capture the device / driver bound lifetime; device resources can be stored directly by reference rather than requiring Devres. The probe() and unbind() callbacks thus gain a 'bound lifetime parameter on the methods themselves; avoiding a global lifetime on the trait impl. Existing drivers set type Data<'bound> = Self, preserving the current behavior. Reviewed-by: Alexandre Courbot Reviewed-by: Greg Kroah-Hartman Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260525202921.124698-13-dakr@kernel.org Signed-off-by: Danilo Krummrich --- drivers/gpu/nova-core/driver.rs | 9 ++++++--- rust/kernel/pci.rs | 28 ++++++++++++++-------------- samples/rust/rust_dma.rs | 7 +++++-- samples/rust/rust_driver_auxiliary.rs | 7 +++++-- samples/rust/rust_driver_pci.rs | 7 +++++-- 5 files changed, 35 insertions(+), 23 deletions(-) (limited to 'samples') diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 13c5ff15e87f..6ad1a856694c 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -74,10 +74,13 @@ kernel::pci_device_table!( impl pci::Driver for NovaCore { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; - fn probe(pdev: &pci::Device>, _info: &Self::IdInfo) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound pci::Device>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { pin_init::pin_init_scope(move || { dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); @@ -109,7 +112,7 @@ impl pci::Driver for NovaCore { }) } - fn unbind(pdev: &pci::Device>, this: Pin<&Self>) { + fn unbind<'bound>(pdev: &'bound pci::Device>, this: Pin<&Self>) { this.gpu.unbind(pdev.as_ref()); } } diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 314ad9fefdb0..5071cae6543f 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -64,7 +64,7 @@ pub struct Adapter(T); // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::pci_driver; - type DriverData<'bound> = T::Data; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -129,8 +129,8 @@ impl Adapter { // 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>`. - let data = unsafe { pdev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>>`. + let data = unsafe { pdev.as_ref().drvdata_borrow::>() }; T::unbind(pdev, data); } @@ -279,13 +279,13 @@ macro_rules! pci_device_table { /// /// impl pci::Driver for MyDriver { /// type IdInfo = (); -/// type Data = Self; +/// type Data<'bound> = Self; /// const ID_TABLE: pci::IdTable = &PCI_TABLE; /// -/// fn probe( -/// _pdev: &pci::Device>, -/// _id_info: &Self::IdInfo, -/// ) -> impl PinInit { +/// fn probe<'bound>( +/// _pdev: &'bound pci::Device>, +/// _id_info: &'bound Self::IdInfo, +/// ) -> impl PinInit, Error> + 'bound { /// Err(ENODEV) /// } /// } @@ -302,7 +302,7 @@ pub trait Driver { type IdInfo: 'static; /// The type of the driver's bus device private data. - type Data: Send; + type Data<'bound>: Send + 'bound; /// The table of device ids supported by the driver. const ID_TABLE: IdTable; @@ -311,10 +311,10 @@ pub trait Driver { /// /// Called when a new pci device is added or discovered. Implementers should /// attempt to initialize the device here. - fn probe( - dev: &Device>, - id_info: &Self::IdInfo, - ) -> impl PinInit; + fn probe<'bound>( + dev: &'bound Device>, + id_info: &'bound Self::IdInfo, + ) -> impl PinInit, Error> + 'bound; /// PCI driver unbind. /// @@ -326,7 +326,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Drop`. - fn unbind(dev: &Device>, this: Pin<&Self::Data>) { + fn unbind<'bound>(dev: &'bound Device>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } } diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index 9a243e7c7298..c4d2d36602af 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -58,10 +58,13 @@ kernel::pci_device_table!( impl pci::Driver for DmaSampleDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; - fn probe(pdev: &pci::Device>, _info: &Self::IdInfo) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound pci::Device>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { pin_init::pin_init_scope(move || { dev_info!(pdev, "Probe DMA test driver.\n"); diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index f0d419823f9a..0e979f45cd68 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -69,11 +69,14 @@ kernel::pci_device_table!( impl pci::Driver for ParentDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; - fn probe(pdev: &pci::Device>, _info: &Self::IdInfo) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound pci::Device>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { Ok(Self { _reg0: auxiliary::Registration::new( pdev.as_ref(), diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 3106f766fd93..6791d98e1c79 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -140,11 +140,14 @@ impl SampleDriver { impl pci::Driver for SampleDriver { type IdInfo = TestIndex; - type Data = Self; + type Data<'bound> = Self; const ID_TABLE: pci::IdTable = &PCI_TABLE; - fn probe(pdev: &pci::Device>, info: &Self::IdInfo) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound pci::Device>, + info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { pin_init::pin_init_scope(move || { let vendor = pdev.vendor_id(); dev_dbg!( -- cgit v1.2.3 From 81fdc788144348f295cfaa4b1e1edf6c74441c15 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:21:00 +0200 Subject: rust: platform: make Driver trait lifetime-parameterized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a 'bound lifetime to the associated Data, changing type Data to type Data<'bound>. This allows the driver's bus device private data to capture the device / driver bound lifetime; device resources can be stored directly by reference rather than requiring Devres. The probe() and unbind() callbacks thus gain a 'bound lifetime parameter on the methods themselves; avoiding a global lifetime on the trait impl. Existing drivers set type Data<'bound> = Self, preserving the current behavior. Acked-by: Uwe Kleine-König Reviewed-by: Alexandre Courbot Reviewed-by: Greg Kroah-Hartman Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260525202921.124698-14-dakr@kernel.org Signed-off-by: Danilo Krummrich --- drivers/cpufreq/rcpufreq_dt.rs | 10 +++++----- drivers/gpu/drm/tyr/driver.rs | 10 +++++----- drivers/pwm/pwm_th1520.rs | 10 +++++----- rust/kernel/cpufreq.rs | 10 +++++----- rust/kernel/io/mem.rs | 20 ++++++++++---------- rust/kernel/platform.rs | 28 ++++++++++++++-------------- samples/rust/rust_debugfs.rs | 10 +++++----- samples/rust/rust_driver_platform.rs | 10 +++++----- samples/rust/rust_i2c_client.rs | 15 +++++++++------ samples/rust/rust_soc.rs | 10 +++++----- 10 files changed, 68 insertions(+), 65 deletions(-) (limited to 'samples') diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index 5e0b224f6699..10106fa13095 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -201,13 +201,13 @@ kernel::of_device_table!( impl platform::Driver for CPUFreqDTDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); - fn probe( - pdev: &platform::Device>, - _id_info: Option<&Self::IdInfo>, - ) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound platform::Device>, + _id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { cpufreq::Registration::::new_foreign_owned(pdev.as_ref())?; Ok(Self {}) } diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index 001727f44fc8..797f09e23a4c 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -91,13 +91,13 @@ kernel::of_device_table!( impl platform::Driver for TyrPlatformDriverData { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); - fn probe( - pdev: &platform::Device>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound platform::Device>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?; let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?; diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index df83a4a9a507..6c5b791f3153 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -316,13 +316,13 @@ kernel::of_device_table!( impl platform::Driver for Th1520PwmPlatformDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); - fn probe( - pdev: &platform::Device>, - _id_info: Option<&Self::IdInfo>, - ) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound platform::Device>, + _id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { let dev = pdev.as_ref(); let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 0df518fa1d77..d94c6cdbc45a 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -888,13 +888,13 @@ pub trait Driver { /// /// impl platform::Driver for SampleDriver { /// type IdInfo = (); -/// type Data = Self; +/// type Data<'bound> = Self; /// const OF_ID_TABLE: Option> = None; /// -/// fn probe( -/// pdev: &platform::Device>, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit { +/// fn probe<'bound>( +/// pdev: &'bound platform::Device>, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit + 'bound { /// cpufreq::Registration::::new_foreign_owned(pdev.as_ref())?; /// Ok(Self {}) /// } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 03d8745b5e1d..51ba347220ee 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -62,12 +62,12 @@ impl<'a> IoRequest<'a> { /// /// impl platform::Driver for SampleDriver { /// # type IdInfo = (); - /// # type Data = Self; + /// # type Data<'bound> = Self; /// - /// fn probe( - /// pdev: &platform::Device>, - /// info: Option<&Self::IdInfo>, - /// ) -> impl PinInit { + /// fn probe<'bound>( + /// pdev: &'bound platform::Device>, + /// info: Option<&'bound Self::IdInfo>, + /// ) -> impl PinInit + 'bound { /// let offset = 0; // Some offset. /// /// // If the size is known at compile time, use [`Self::iomap_sized`]. @@ -127,12 +127,12 @@ impl<'a> IoRequest<'a> { /// /// impl platform::Driver for SampleDriver { /// # type IdInfo = (); - /// # type Data = Self; + /// # type Data<'bound> = Self; /// - /// fn probe( - /// pdev: &platform::Device>, - /// info: Option<&Self::IdInfo>, - /// ) -> impl PinInit { + /// fn probe<'bound>( + /// pdev: &'bound platform::Device>, + /// info: Option<&'bound Self::IdInfo>, + /// ) -> impl PinInit + 'bound { /// let offset = 0; // Some offset. /// /// // Unlike [`Self::iomap_sized`], here the size of the memory region diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 257b7084338c..d8d48f60b0b9 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -50,7 +50,7 @@ pub struct Adapter(T); // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::platform_driver; - type DriverData<'bound> = T::Data; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -117,8 +117,8 @@ impl Adapter { // 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>`. - let data = unsafe { pdev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>>`. + let data = unsafe { pdev.as_ref().drvdata_borrow::>() }; T::unbind(pdev, data); } @@ -192,14 +192,14 @@ macro_rules! module_platform_driver { /// /// impl platform::Driver for MyDriver { /// type IdInfo = (); -/// type Data = Self; +/// type Data<'bound> = Self; /// const OF_ID_TABLE: Option> = Some(&OF_TABLE); /// const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); /// -/// fn probe( -/// _pdev: &platform::Device>, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit { +/// fn probe<'bound>( +/// _pdev: &'bound platform::Device>, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit, Error> + 'bound { /// Err(ENODEV) /// } /// } @@ -214,7 +214,7 @@ pub trait Driver { type IdInfo: 'static; /// The type of the driver's bus device private data. - type Data: Send; + type Data<'bound>: Send + 'bound; /// The table of OF device ids supported by the driver. const OF_ID_TABLE: Option> = None; @@ -226,10 +226,10 @@ pub trait Driver { /// /// Called when a new platform device is added or discovered. /// Implementers should attempt to initialize the device here. - fn probe( - dev: &Device>, - id_info: Option<&Self::IdInfo>, - ) -> impl PinInit; + fn probe<'bound>( + dev: &'bound Device>, + id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit, Error> + 'bound; /// Platform driver unbind. /// @@ -241,7 +241,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Drop`. - fn unbind(dev: &Device>, this: Pin<&Self::Data>) { + fn unbind<'bound>(dev: &'bound Device>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } } diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 37640ed33642..1f59e08aaa4b 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -117,14 +117,14 @@ kernel::acpi_device_table!( impl platform::Driver for RustDebugFs { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const OF_ID_TABLE: Option> = None; const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); - fn probe( - pdev: &platform::Device>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound platform::Device>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { RustDebugFs::new(pdev).pin_chain(|this| { this.counter.store(91, Relaxed); { diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs index 04d40f836275..ec0d6cac4f57 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -101,14 +101,14 @@ kernel::acpi_device_table!( impl platform::Driver for SampleDriver { type IdInfo = Info; - type Data = Self; + type Data<'bound> = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); - fn probe( - pdev: &platform::Device>, - info: Option<&Self::IdInfo>, - ) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound platform::Device>, + info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { let dev = pdev.as_ref(); dev_dbg!(dev, "Probe Rust Platform driver sample.\n"); diff --git a/samples/rust/rust_i2c_client.rs b/samples/rust/rust_i2c_client.rs index 3f273c754f86..2d876f4e3ee0 100644 --- a/samples/rust/rust_i2c_client.rs +++ b/samples/rust/rust_i2c_client.rs @@ -106,14 +106,14 @@ const BOARD_INFO: i2c::I2cBoardInfo = impl platform::Driver for SampleDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); - fn probe( - pdev: &platform::Device>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound platform::Device>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { dev_info!( pdev.as_ref(), "Probe Rust I2C Client registration sample.\n" @@ -130,7 +130,10 @@ impl platform::Driver for SampleDriver { }) } - fn unbind(pdev: &platform::Device>, _this: Pin<&Self>) { + fn unbind<'bound>( + pdev: &'bound platform::Device>, + _this: Pin<&Self::Data<'bound>>, + ) { dev_info!( pdev.as_ref(), "Unbind Rust I2C Client registration sample.\n" diff --git a/samples/rust/rust_soc.rs b/samples/rust/rust_soc.rs index c466653491d2..808d58200eb6 100644 --- a/samples/rust/rust_soc.rs +++ b/samples/rust/rust_soc.rs @@ -37,14 +37,14 @@ kernel::acpi_device_table!( impl platform::Driver for SampleSocDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const OF_ID_TABLE: Option> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); - fn probe( - pdev: &platform::Device>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit { + fn probe<'bound>( + pdev: &'bound platform::Device>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { dev_dbg!(pdev, "Probe Rust SoC driver sample.\n"); let pdev = pdev.into(); -- cgit v1.2.3 From 46f651d88662ef931555cd135f09382af206295a Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:21:01 +0200 Subject: rust: auxiliary: make Driver trait lifetime-parameterized Add a 'bound lifetime to the associated Data, changing type Data to type Data<'bound>. This allows the driver's bus device private data to capture the device / driver bound lifetime; device resources can be stored directly by reference rather than requiring Devres. The probe() and unbind() callbacks thus gain a 'bound lifetime parameter on the methods themselves; avoiding a global lifetime on the trait impl. Existing drivers set type Data<'bound> = Self, preserving the current behavior. Reviewed-by: Alexandre Courbot Reviewed-by: Greg Kroah-Hartman Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260525202921.124698-15-dakr@kernel.org Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/nova/driver.rs | 10 +++++----- rust/kernel/auxiliary.rs | 18 +++++++++--------- samples/rust/rust_driver_auxiliary.rs | 10 +++++----- 3 files changed, 19 insertions(+), 19 deletions(-) (limited to 'samples') diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index 7605348af994..aa08644012f7 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -51,13 +51,13 @@ kernel::auxiliary_device_table!( impl auxiliary::Driver for NovaDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const ID_TABLE: auxiliary::IdTable = &AUX_TABLE; - fn probe( - adev: &auxiliary::Device>, - _info: &Self::IdInfo, - ) -> impl PinInit { + fn probe<'bound>( + adev: &'bound auxiliary::Device>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { let data = try_pin_init!(NovaData { adev: adev.into() }); let drm = drm::Device::::new(adev.as_ref(), data)?; diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 6d504b0933d5..7a1b1a7b7ca6 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -46,7 +46,7 @@ pub struct Adapter(T); // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::auxiliary_driver; - type DriverData<'bound> = T::Data; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -111,8 +111,8 @@ impl Adapter { // 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>`. - let data = unsafe { adev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>>`. + let data = unsafe { adev.as_ref().drvdata_borrow::>() }; T::unbind(adev, data); } @@ -203,7 +203,7 @@ pub trait Driver { type IdInfo: 'static; /// The type of the driver's bus device private data. - type Data: Send; + type Data<'bound>: Send + 'bound; /// The table of device ids supported by the driver. const ID_TABLE: IdTable; @@ -211,10 +211,10 @@ pub trait Driver { /// Auxiliary driver probe. /// /// Called when an auxiliary device is matches a corresponding driver. - fn probe( - dev: &Device>, - id_info: &Self::IdInfo, - ) -> impl PinInit; + fn probe<'bound>( + dev: &'bound Device>, + id_info: &'bound Self::IdInfo, + ) -> impl PinInit, Error> + 'bound; /// Auxiliary driver unbind. /// @@ -226,7 +226,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Drop`. - fn unbind(dev: &Device>, this: Pin<&Self::Data>) { + fn unbind<'bound>(dev: &'bound Device>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } } diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index 0e979f45cd68..b30a4d5cdf8a 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -31,14 +31,14 @@ kernel::auxiliary_device_table!( impl auxiliary::Driver for AuxiliaryDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const ID_TABLE: auxiliary::IdTable = &AUX_TABLE; - fn probe( - adev: &auxiliary::Device>, - _info: &Self::IdInfo, - ) -> impl PinInit { + fn probe<'bound>( + adev: &'bound auxiliary::Device>, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { dev_info!( adev, "Probing auxiliary driver for auxiliary device with id={}\n", -- cgit v1.2.3 From a3f09f8e47c4262510c979b384d6f85d376d91f5 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:21:02 +0200 Subject: rust: usb: make Driver trait lifetime-parameterized Add a 'bound lifetime to the associated Data, changing type Data to type Data<'bound>. This allows the driver's bus device private data to capture the device / driver bound lifetime; device resources can be stored directly by reference rather than requiring Devres. The probe() and disconnect() callbacks thus gain a 'bound lifetime parameter on the methods themselves; avoiding a global lifetime on the trait impl. Existing drivers set type Data<'bound> = Self, preserving the current behavior. Reviewed-by: Alexandre Courbot Reviewed-by: Greg Kroah-Hartman Reviewed-by: Eliot Courtney Reviewed-by: Gary Guo Reviewed-by: Daniel Almeida Link: https://patch.msgid.link/20260525202921.124698-16-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/usb.rs | 37 ++++++++++++++++++++++--------------- samples/rust/rust_driver_usb.rs | 12 ++++++------ 2 files changed, 28 insertions(+), 21 deletions(-) (limited to 'samples') diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 1dbb8387b463..7aff0c82d0af 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -41,7 +41,7 @@ pub struct Adapter(T); // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::usb_driver; - type DriverData<'bound> = T::Data; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -109,8 +109,8 @@ impl Adapter { // SAFETY: `disconnect_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>`. - let data = unsafe { dev.drvdata_borrow::() }; + // and stored a `Pin>>`. + let data = unsafe { dev.drvdata_borrow::>() }; T::disconnect(intf, data); } @@ -287,18 +287,22 @@ macro_rules! usb_device_table { /// /// impl usb::Driver for MyDriver { /// type IdInfo = (); -/// type Data = Self; +/// type Data<'bound> = Self; /// const ID_TABLE: usb::IdTable = &USB_TABLE; /// -/// fn probe( -/// _interface: &usb::Interface>, +/// fn probe<'bound>( +/// _interface: &'bound usb::Interface>, /// _id: &usb::DeviceId, -/// _info: &Self::IdInfo, -/// ) -> impl PinInit { +/// _info: &'bound Self::IdInfo, +/// ) -> impl PinInit, Error> + 'bound { /// Err(ENODEV) /// } /// -/// fn disconnect(_interface: &usb::Interface>, _data: Pin<&Self::Data>) {} +/// fn disconnect<'bound>( +/// _interface: &'bound usb::Interface>, +/// _data: Pin<&Self::Data<'bound>>, +/// ) { +/// } /// } ///``` pub trait Driver { @@ -306,7 +310,7 @@ pub trait Driver { type IdInfo: 'static; /// The type of the driver's bus device private data. - type Data: Send; + type Data<'bound>: Send + 'bound; /// The table of device ids supported by the driver. const ID_TABLE: IdTable; @@ -315,16 +319,19 @@ pub trait Driver { /// /// Called when a new USB interface is bound to this driver. /// Implementers should attempt to initialize the interface here. - fn probe( - interface: &Interface>, + fn probe<'bound>( + interface: &'bound Interface>, id: &DeviceId, - id_info: &Self::IdInfo, - ) -> impl PinInit; + id_info: &'bound Self::IdInfo, + ) -> impl PinInit, Error> + 'bound; /// USB driver disconnect. /// /// Called when the USB interface is about to be unbound from this driver. - fn disconnect(interface: &Interface>, data: Pin<&Self::Data>); + fn disconnect<'bound>( + interface: &'bound Interface>, + data: Pin<&Self::Data<'bound>>, + ); } /// A USB interface. diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs index e900993335e9..02bd5085f9bc 100644 --- a/samples/rust/rust_driver_usb.rs +++ b/samples/rust/rust_driver_usb.rs @@ -26,21 +26,21 @@ kernel::usb_device_table!( impl usb::Driver for SampleDriver { type IdInfo = (); - type Data = Self; + type Data<'bound> = Self; const ID_TABLE: usb::IdTable = &USB_TABLE; - fn probe( - intf: &usb::Interface>, + fn probe<'bound>( + intf: &'bound usb::Interface>, _id: &usb::DeviceId, - _info: &Self::IdInfo, - ) -> impl PinInit { + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { let dev: &device::Device> = intf.as_ref(); dev_info!(dev, "Rust USB driver sample probed\n"); Ok(Self { _intf: intf.into() }) } - fn disconnect(intf: &usb::Interface>, _data: Pin<&Self>) { + fn disconnect<'bound>(intf: &'bound usb::Interface>, _data: Pin<&Self>) { let dev: &device::Device> = intf.as_ref(); dev_info!(dev, "Rust USB driver sample disconnected\n"); } -- cgit v1.2.3 From 71e6b6a80b5158323be56e0a776e9fa3cc77d061 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:21:03 +0200 Subject: rust: i2c: make Driver trait lifetime-parameterized Add a 'bound lifetime to the associated Data, changing type Data to type Data<'bound>. This allows the driver's bus device private data to capture the device / driver bound lifetime; device resources can be stored directly by reference rather than requiring Devres. The probe() and unbind() callbacks thus gain a 'bound lifetime parameter on the methods themselves; avoiding a global lifetime on the trait impl. Existing drivers set type Data<'bound> = Self, preserving the current behavior. Acked-by: Igor Korotin Reviewed-by: Alexandre Courbot Reviewed-by: Greg Kroah-Hartman Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260525202921.124698-17-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/i2c.rs | 39 +++++++++++++++++++++------------------ samples/rust/rust_driver_i2c.rs | 14 +++++++------- 2 files changed, 28 insertions(+), 25 deletions(-) (limited to 'samples') diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 50feade0fb58..6094d32652e3 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -98,7 +98,7 @@ pub struct Adapter(T); // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::i2c_driver; - type DriverData<'bound> = T::Data; + type DriverData<'bound> = T::Data<'bound>; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } @@ -176,8 +176,8 @@ impl Adapter { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `I2cClient::set_drvdata()` has been called - // and stored a `Pin>`. - let data = unsafe { idev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>>`. + let data = unsafe { idev.as_ref().drvdata_borrow::>() }; T::unbind(idev, data); } @@ -188,8 +188,8 @@ impl Adapter { // SAFETY: `shutdown_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>`. - let data = unsafe { idev.as_ref().drvdata_borrow::() }; + // and stored a `Pin>>`. + let data = unsafe { idev.as_ref().drvdata_borrow::>() }; T::shutdown(idev, data); } @@ -294,19 +294,22 @@ macro_rules! module_i2c_driver { /// /// impl i2c::Driver for MyDriver { /// type IdInfo = (); -/// type Data = Self; +/// type Data<'bound> = Self; /// const I2C_ID_TABLE: Option> = Some(&I2C_TABLE); /// const OF_ID_TABLE: Option> = Some(&OF_TABLE); /// const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); /// -/// fn probe( -/// _idev: &i2c::I2cClient>, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit { +/// fn probe<'bound>( +/// _idev: &'bound i2c::I2cClient>, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit, Error> + 'bound { /// Err(ENODEV) /// } /// -/// fn shutdown(_idev: &i2c::I2cClient>, this: Pin<&Self::Data>) { +/// fn shutdown<'bound>( +/// _idev: &'bound i2c::I2cClient>, +/// this: Pin<&Self::Data<'bound>>, +/// ) { /// } /// } ///``` @@ -320,7 +323,7 @@ pub trait Driver { type IdInfo: 'static; /// The type of the driver's bus device private data. - type Data: Send; + type Data<'bound>: Send + 'bound; /// The table of device ids supported by the driver. const I2C_ID_TABLE: Option> = None; @@ -335,10 +338,10 @@ pub trait Driver { /// /// Called when a new i2c client is added or discovered. /// Implementers should attempt to initialize the client here. - fn probe( - dev: &I2cClient>, - id_info: Option<&Self::IdInfo>, - ) -> impl PinInit; + fn probe<'bound>( + dev: &'bound I2cClient>, + id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit, Error> + 'bound; /// I2C driver shutdown. /// @@ -351,7 +354,7 @@ pub trait Driver { /// This callback is distinct from final resource cleanup, as the driver instance remains valid /// after it returns. Any deallocation or teardown of driver-owned resources should instead be /// handled in `Drop`. - fn shutdown(dev: &I2cClient>, this: Pin<&Self::Data>) { + fn shutdown<'bound>(dev: &'bound I2cClient>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } @@ -365,7 +368,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Drop`. - fn unbind(dev: &I2cClient>, this: Pin<&Self::Data>) { + fn unbind<'bound>(dev: &'bound I2cClient>, this: Pin<&Self::Data<'bound>>) { let _ = (dev, this); } } diff --git a/samples/rust/rust_driver_i2c.rs b/samples/rust/rust_driver_i2c.rs index 171550ea0b6f..ead8263a7d48 100644 --- a/samples/rust/rust_driver_i2c.rs +++ b/samples/rust/rust_driver_i2c.rs @@ -35,16 +35,16 @@ kernel::of_device_table! { impl i2c::Driver for SampleDriver { type IdInfo = u32; - type Data = Self; + type Data<'bound> = Self; const ACPI_ID_TABLE: Option> = Some(&ACPI_TABLE); const I2C_ID_TABLE: Option> = Some(&I2C_TABLE); const OF_ID_TABLE: Option> = Some(&OF_TABLE); - fn probe( - idev: &i2c::I2cClient>, - info: Option<&Self::IdInfo>, - ) -> impl PinInit { + fn probe<'bound>( + idev: &'bound i2c::I2cClient>, + info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { let dev = idev.as_ref(); dev_info!(dev, "Probe Rust I2C driver sample.\n"); @@ -56,11 +56,11 @@ impl i2c::Driver for SampleDriver { Ok(Self) } - fn shutdown(idev: &i2c::I2cClient>, _this: Pin<&Self>) { + fn shutdown<'bound>(idev: &'bound i2c::I2cClient>, _this: Pin<&Self>) { dev_info!(idev.as_ref(), "Shutdown Rust I2C driver sample.\n"); } - fn unbind(idev: &i2c::I2cClient>, _this: Pin<&Self>) { + fn unbind<'bound>(idev: &'bound i2c::I2cClient>, _this: Pin<&Self>) { dev_info!(idev.as_ref(), "Unbind Rust I2C driver sample.\n"); } } -- cgit v1.2.3 From 8ea0b6d5bef5e4f4637964c3b2cf732d9bf4f408 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:21:05 +0200 Subject: rust: pci: make Bar lifetime-parameterized Convert pci::Bar to pci::Bar<'a, SIZE>, storing &'a Device to tie the BAR mapping lifetime to the device. iomap_region_sized() now returns Result> directly instead of impl PinInit>, Error>. Since the lifetime ties the mapping to the device's bound state, callers no longer need Devres for the common case where the Bar lives in the driver's private data. Add Bar::into_devres() to consume the bar and register it as a device-managed resource, returning Devres>. The lifetime is erased to 'static because Devres guarantees the bar does not actually outlive the device -- access is revoked on unbind. Reviewed-by: Eliot Courtney Reviewed-by: Greg Kroah-Hartman Reviewed-by: Alexandre Courbot Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260525202921.124698-19-dakr@kernel.org Signed-off-by: Danilo Krummrich --- drivers/gpu/nova-core/driver.rs | 7 +++--- rust/kernel/devres.rs | 2 +- rust/kernel/pci/io.rs | 52 ++++++++++++++++++++++++----------------- samples/rust/rust_driver_pci.rs | 5 ++-- 4 files changed, 38 insertions(+), 28 deletions(-) (limited to 'samples') diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 6ad1a856694c..7dbec0470c26 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -45,7 +45,7 @@ const BAR0_SIZE: usize = SZ_16M; // DMA addresses. These systems should be quite rare. const GPU_DMA_BITS: u32 = 47; -pub(crate) type Bar0 = pci::Bar; +pub(crate) type Bar0 = pci::Bar<'static, BAR0_SIZE>; kernel::pci_device_table!( PCI_TABLE, @@ -92,8 +92,9 @@ impl pci::Driver for NovaCore { // other threads of execution. unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::())? }; - let bar = Arc::pin_init( - pdev.iomap_region_sized::(0, c"nova-core/bar0"), + let bar = Arc::new( + pdev.iomap_region_sized::(0, c"nova-core/bar0")? + .into_devres()?, GFP_KERNEL, )?; diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index fd4633f977f6..82cbd8b969fb 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -304,7 +304,7 @@ impl Devres { /// pci, // /// }; /// - /// fn from_core(dev: &pci::Device>, devres: Devres>) -> Result { + /// fn from_core(dev: &pci::Device>, devres: Devres>) -> Result { /// let bar = devres.access(dev.as_ref())?; /// /// let _ = bar.read32(0x0); diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index 3ce21482b079..0461e01aaa20 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -14,8 +14,7 @@ use crate::{ Mmio, MmioRaw, // }, - prelude::*, - sync::aref::ARef, // + prelude::*, // }; use core::{ marker::PhantomData, @@ -146,14 +145,18 @@ impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> { /// /// `Bar` always holds an `IoRaw` instance that holds a valid pointer to the start of the I/O /// memory mapped PCI BAR and its size. -pub struct Bar { - pdev: ARef, +pub struct Bar<'a, const SIZE: usize = 0> { + pdev: &'a Device, io: MmioRaw, num: i32, } -impl Bar { - pub(super) fn new(pdev: &Device, num: u32, name: &'static CStr) -> Result { +impl<'a, const SIZE: usize> Bar<'a, SIZE> { + pub(super) fn new( + pdev: &'a Device, + num: u32, + name: &'static CStr, + ) -> Result { let len = pdev.resource_len(num)?; if len == 0 { return Err(ENOMEM); @@ -196,11 +199,7 @@ impl Bar { } }; - Ok(Bar { - pdev: pdev.into(), - io, - num, - }) + Ok(Bar { pdev, io, num }) } /// # Safety @@ -219,11 +218,24 @@ impl Bar { fn release(&self) { // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`. - unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; + unsafe { Self::do_release(self.pdev, self.io.addr(), self.num) }; + } + + /// Consume the `Bar` and register it as a device-managed resource. + /// + /// The returned `Devres>` can outlive the original lifetime `'a`. Access + /// to the BAR is revoked when the device is unbound. + pub fn into_devres(self) -> Result>> { + // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `Bar` does not + // actually outlive the device -- access is revoked and the resource is released when the + // device is unbound. + let bar: Bar<'static, SIZE> = unsafe { core::mem::transmute(self) }; + let pdev = bar.pdev; + Devres::new(pdev.as_ref(), bar) } } -impl Bar { +impl Bar<'_> { #[inline] pub(super) fn index_is_valid(index: u32) -> bool { // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries. @@ -231,13 +243,13 @@ impl Bar { } } -impl Drop for Bar { +impl Drop for Bar<'_, SIZE> { fn drop(&mut self) { self.release(); } } -impl Deref for Bar { +impl Deref for Bar<'_, SIZE> { type Target = Mmio; fn deref(&self) -> &Self::Target { @@ -253,16 +265,12 @@ impl Device { &'a self, bar: u32, name: &'static CStr, - ) -> impl PinInit>, Error> + 'a { - Devres::new(self.as_ref(), Bar::::new(self, bar, name)) + ) -> Result> { + Bar::new(self, bar, name) } /// Maps an entire PCI BAR after performing a region-request on it. - pub fn iomap_region<'a>( - &'a self, - bar: u32, - name: &'static CStr, - ) -> impl PinInit, Error> + 'a { + pub fn iomap_region<'a>(&'a self, bar: u32, name: &'static CStr) -> Result> { self.iomap_region_sized::<0>(bar, name) } diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 6791d98e1c79..0353481b0690 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -45,7 +45,7 @@ mod regs { pub(super) const END: usize = 0x10; } -type Bar0 = pci::Bar<{ regs::END }>; +type Bar0 = pci::Bar<'static, { regs::END }>; #[derive(Copy, Clone, Debug)] struct TestIndex(u8); @@ -161,7 +161,8 @@ impl pci::Driver for SampleDriver { pdev.set_master(); Ok(try_pin_init!(Self { - bar <- pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci"), + bar: pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci")? + .into_devres()?, index: *info, _: { let bar = bar.access(pdev.as_ref())?; -- cgit v1.2.3 From e397d405c4c6117b4eeeeecb8170c17c604ee6cc Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:21:07 +0200 Subject: samples: rust: rust_driver_pci: use HRT lifetime for Bar Convert the sample driver to SampleDriver<'bound>, taking advantage of the lifetime-parameterized Driver trait. The driver struct holds &'bound pci::Device directly instead of ARef, and pci::Bar<'bound> directly instead of Devres. This removes PinnedDrop, pin_init_scope, and runtime revocation checks on BAR access. Reviewed-by: Eliot Courtney Reviewed-by: Greg Kroah-Hartman Reviewed-by: Alexandre Courbot Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260525202921.124698-21-dakr@kernel.org Signed-off-by: Danilo Krummrich --- samples/rust/rust_driver_pci.rs | 89 ++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 49 deletions(-) (limited to 'samples') diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs index 0353481b0690..1aa8197d8698 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -9,7 +9,6 @@ use kernel::{ Bound, Core, // }, - devres::Devres, io::{ register, register::Array, @@ -17,8 +16,7 @@ use kernel::{ }, num::Bounded, pci, - prelude::*, - sync::aref::ARef, // + prelude::*, // }; mod regs { @@ -45,7 +43,7 @@ mod regs { pub(super) const END: usize = 0x10; } -type Bar0 = pci::Bar<'static, { regs::END }>; +type Bar0<'bound> = pci::Bar<'bound, { regs::END }>; #[derive(Copy, Clone, Debug)] struct TestIndex(u8); @@ -66,14 +64,14 @@ impl TestIndex { const NO_EVENTFD: Self = Self(0); } -#[pin_data(PinnedDrop)] -struct SampleDriver { - pdev: ARef, - #[pin] - bar: Devres, +struct SampleDriverData<'bound> { + pdev: &'bound pci::Device, + bar: Bar0<'bound>, index: TestIndex, } +struct SampleDriver; + kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, @@ -84,8 +82,8 @@ kernel::pci_device_table!( )] ); -impl SampleDriver { - fn testdev(index: &TestIndex, bar: &Bar0) -> Result { +impl SampleDriverData<'_> { + fn testdev(index: &TestIndex, bar: &Bar0<'_>) -> Result { // Select the test. bar.write_reg(regs::TEST::zeroed().with_index(*index)); @@ -140,56 +138,49 @@ impl SampleDriver { impl pci::Driver for SampleDriver { type IdInfo = TestIndex; - type Data<'bound> = Self; + type Data<'bound> = SampleDriverData<'bound>; const ID_TABLE: pci::IdTable = &PCI_TABLE; fn probe<'bound>( pdev: &'bound pci::Device>, info: &'bound Self::IdInfo, - ) -> impl PinInit + 'bound { - pin_init::pin_init_scope(move || { - let vendor = pdev.vendor_id(); - dev_dbg!( - pdev, - "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", - vendor, - pdev.device_id() - ); - - pdev.enable_device_mem()?; - pdev.set_master(); - - Ok(try_pin_init!(Self { - bar: pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci")? - .into_devres()?, - index: *info, - _: { - let bar = bar.access(pdev.as_ref())?; - - dev_info!( - pdev, - "pci-testdev data-match count: {}\n", - Self::testdev(info, bar)? - ); - Self::config_space(pdev); - }, - pdev: pdev.into(), - })) + ) -> impl PinInit, Error> + 'bound { + let vendor = pdev.vendor_id(); + dev_dbg!( + pdev, + "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", + vendor, + pdev.device_id() + ); + + pdev.enable_device_mem()?; + pdev.set_master(); + + let bar = pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_driver_pci")?; + + dev_info!( + pdev, + "pci-testdev data-match count: {}\n", + SampleDriverData::testdev(info, &bar)? + ); + SampleDriverData::config_space(pdev); + + Ok(SampleDriverData { + pdev, + bar, + index: *info, }) } - fn unbind(pdev: &pci::Device>, this: Pin<&Self>) { - if let Ok(bar) = this.bar.access(pdev.as_ref()) { - // Reset pci-testdev by writing a new test index. - bar.write_reg(regs::TEST::zeroed().with_index(this.index)); - } + fn unbind<'bound>(_pdev: &'bound pci::Device>, this: Pin<&Self::Data<'bound>>) { + this.bar + .write_reg(regs::TEST::zeroed().with_index(this.index)); } } -#[pinned_drop] -impl PinnedDrop for SampleDriver { - fn drop(self: Pin<&mut Self>) { +impl Drop for SampleDriverData<'_> { + fn drop(&mut self) { dev_dbg!(self.pdev, "Remove Rust PCI driver sample.\n"); } } -- cgit v1.2.3 From 4555291ddae9abe2c40a7eae192b1976b07a1fad Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:21:10 +0200 Subject: rust: auxiliary: generalize Registration over ForLt Generalize Registration to Registration and Device::registration_data() to return Pin<&F::Of<'_>>. The stored 'static lifetime is shortened to the borrow lifetime of &self via ForLt::cast_ref; ForLt's covariance guarantee makes this sound. Reviewed-by: Greg Kroah-Hartman Reviewed-by: Alexandre Courbot Reviewed-by: Eliot Courtney Reviewed-by: Gary Guo Link: https://patch.msgid.link/20260525202921.124698-24-dakr@kernel.org [ Use PhantomData> instead of PhantomData<(fn(&'a ()) -> &'a (), F)>], which also gets us rid of #[allow(clippy::type_complexity)]. - Danilo ] Signed-off-by: Danilo Krummrich --- drivers/gpu/nova-core/driver.rs | 13 +++-- rust/kernel/auxiliary.rs | 107 ++++++++++++++++++++++++---------- samples/rust/rust_driver_auxiliary.rs | 19 +++--- 3 files changed, 95 insertions(+), 44 deletions(-) (limited to 'samples') diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index fa898fe5c893..d3f2245ba2e0 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -3,7 +3,6 @@ use kernel::{ auxiliary, device::Core, - devres::Devres, dma::Device, dma::DmaMask, pci, @@ -21,6 +20,7 @@ use kernel::{ }, Arc, }, + types::ForLt, }; use crate::gpu::Gpu; @@ -29,10 +29,11 @@ use crate::gpu::Gpu; static AUXILIARY_ID_COUNTER: Atomic = Atomic::new(0); #[pin_data] -pub(crate) struct NovaCore { +pub(crate) struct NovaCore<'bound> { #[pin] pub(crate) gpu: Gpu, - _reg: Devres>, + #[allow(clippy::type_complexity)] + _reg: auxiliary::Registration<'bound, ForLt!(())>, } pub(crate) struct NovaCoreDriver; @@ -76,13 +77,13 @@ kernel::pci_device_table!( impl pci::Driver for NovaCoreDriver { type IdInfo = (); - type Data<'bound> = NovaCore; + type Data<'bound> = NovaCore<'bound>; const ID_TABLE: pci::IdTable = &PCI_TABLE; fn probe<'bound>( pdev: &'bound pci::Device>, _info: &'bound Self::IdInfo, - ) -> impl PinInit + 'bound { + ) -> impl PinInit, Error> + 'bound { pin_init::pin_init_scope(move || { dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); @@ -115,7 +116,7 @@ impl pci::Driver for NovaCoreDriver { }) } - fn unbind<'bound>(pdev: &'bound pci::Device>, this: Pin<&NovaCore>) { + fn unbind<'bound>(pdev: &'bound pci::Device>, this: Pin<&Self::Data<'bound>>) { this.gpu.unbind(pdev.as_ref()); } } diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 7a1b1a7b7ca6..c42928d5a239 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -12,7 +12,7 @@ use crate::{ RawDeviceId, RawDeviceIdIndex, // }, - devres::Devres, + driver, error::{ from_result, @@ -20,6 +20,7 @@ use crate::{ }, prelude::*, types::{ + ForLt, ForeignOwnable, Opaque, // }, @@ -271,12 +272,16 @@ impl Device { /// Returns a pinned reference to the registration data set by the registering (parent) driver. /// - /// Returns [`EINVAL`] if `T` does not match the type used by the parent driver when calling + /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The returned + /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via + /// [`ForLt::cast_ref`]. + /// + /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling /// [`Registration::new()`]. /// /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was /// registered by a C driver. - pub fn registration_data(&self) -> Result> { + pub fn registration_data(&self) -> Result>> { // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`. let ptr = unsafe { (*self.as_raw()).registration_data_rust }; if ptr.is_null() { @@ -289,18 +294,23 @@ impl Device { // SAFETY: `ptr` is non-null and was set via `into_foreign()` in `Registration::new()`; // `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, so reading a `TypeId` - // at the start of the allocation is valid regardless of `T`. + // at the start of the allocation is valid regardless of `F`. let type_id = unsafe { ptr.cast::().read() }; - if type_id != TypeId::of::() { + if type_id != TypeId::of::() { return Err(EINVAL); } - // SAFETY: The `TypeId` check above confirms that the stored type is `T`; `ptr` remains - // valid until `Registration::drop()` calls `from_foreign()`. - let wrapper = unsafe { Pin::>>::borrow(ptr) }; + // SAFETY: The `TypeId` check above confirms that the stored type matches + // `F::Of<'static>`; `ptr` remains valid until `Registration::drop()` calls + // `from_foreign()`. + let wrapper = unsafe { Pin::>>>::borrow(ptr) }; // SAFETY: `data` is a structurally pinned field of `RegistrationData`. - Ok(unsafe { wrapper.map_unchecked(|w| &w.data) }) + let pinned: Pin<&F::Of<'_>> = unsafe { wrapper.map_unchecked(|w| &w.data) }; + + // SAFETY: The data was pinned when stored; `cast_ref` only shortens + // the lifetime, so the pinning guarantee is preserved. + Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) }) } } @@ -389,43 +399,60 @@ struct RegistrationData { /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device /// is unbound, the corresponding auxiliary device will be unregistered from the system. /// -/// The type parameter `T` is the type of the registration data owned by the registering (parent) -/// driver. It can be accessed by the auxiliary driver through -/// [`Device::registration_data()`]. +/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration +/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt). +/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`]. /// /// # Invariants /// /// `self.adev` always holds a valid pointer to an initialized and registered /// [`struct auxiliary_device`] whose `registration_data_rust` field points to a -/// valid `Pin>>`. -pub struct Registration { +/// valid `Pin>>>`. +pub struct Registration<'a, F: ForLt + 'static> { adev: NonNull, - _data: PhantomData, + _phantom: PhantomData>, } -impl Registration { +impl<'a, F: ForLt> Registration<'a, F> +where + for<'b> F::Of<'b>: Send + Sync, +{ /// Create and register a new auxiliary device with the given registration data. /// /// The `data` is owned by the registration and can be accessed through the auxiliary device /// via [`Device::registration_data()`]. - pub fn new( - parent: &device::Device, + /// + /// # Safety + /// + /// The caller must not `mem::forget()` the returned [`Registration`] or otherwise prevent its + /// [`Drop`] implementation from running, since the registration data may contain borrowed + /// references that become invalid after `'a` ends. + /// + /// If the registration data is `'static`, use the safe [`Registration::new()`] instead. + pub unsafe fn new_with_lt( + parent: &'a device::Device, name: &CStr, id: u32, modname: &CStr, - data: impl PinInit, - ) -> Result> + data: impl PinInit, E>, + ) -> Result where Error: From, { let data = KBox::pin_init::( try_pin_init!(RegistrationData { - type_id: TypeId::of::(), + type_id: TypeId::of::(), data <- data, }), GFP_KERNEL, )?; + // SAFETY: `'a` is invariant (via `Registration`'s `PhantomData`). Lifetimes do not + // affect layout, so RegistrationData> and RegistrationData> + // have identical representation. + let data: Pin>>> = + unsafe { core::mem::transmute(data) }; + let boxed: KBox> = KBox::zeroed(GFP_KERNEL)?; let adev = boxed.get(); @@ -455,7 +482,9 @@ impl Registration { if ret != 0 { // SAFETY: `registration_data` was set above via `into_foreign()`. drop(unsafe { - Pin::>>::from_foreign((*adev).registration_data_rust) + Pin::>>>::from_foreign( + (*adev).registration_data_rust, + ) }); // SAFETY: `adev` is guaranteed to be a valid pointer to a @@ -467,18 +496,36 @@ impl Registration { // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is // called, which happens in `Self::drop()`. - let reg = Self { + Ok(Self { // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated // successfully. adev: unsafe { NonNull::new_unchecked(adev) }, - _data: PhantomData, - }; + _phantom: PhantomData, + }) + } - Devres::new::(parent, reg) + /// Create and register a new auxiliary device with `'static` registration data. + /// + /// Safe variant of [`Registration::new_with_lt()`] for registration data that does not contain + /// borrowed references. + pub fn new( + parent: &'a device::Device, + name: &CStr, + id: u32, + modname: &CStr, + data: impl PinInit, E>, + ) -> Result + where + F::Of<'a>: 'static, + Error: From, + { + // SAFETY: `F::Of<'a>: 'static` guarantees the data contains no borrowed references, + // so forgetting the `Registration` cannot cause use-after-free. + unsafe { Self::new_with_lt(parent, name, id, modname, data) } } } -impl Drop for Registration { +impl Drop for Registration<'_, F> { fn drop(&mut self) { // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered // `struct auxiliary_device`. @@ -486,7 +533,7 @@ impl Drop for Registration { // SAFETY: `registration_data` was set in `new()` via `into_foreign()`. drop(unsafe { - Pin::>>::from_foreign( + Pin::>>>::from_foreign( (*self.adev.as_ptr()).registration_data_rust, ) }); @@ -500,7 +547,7 @@ impl Drop for Registration { } // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread. -unsafe impl Send for Registration {} +unsafe impl Send for Registration<'_, F> where for<'a> F::Of<'a>: Send {} // SAFETY: `Registration` does not expose any methods or fields that need synchronization. -unsafe impl Sync for Registration {} +unsafe impl Sync for Registration<'_, F> where for<'a> F::Of<'a>: Send {} diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index b30a4d5cdf8a..e3e811a14110 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -10,10 +10,10 @@ use kernel::{ Bound, Core, // }, - devres::Devres, driver, pci, prelude::*, + types::ForLt, InPlaceModule, // }; @@ -55,9 +55,12 @@ struct Data { index: u32, } -struct ParentDriver { - _reg0: Devres>, - _reg1: Devres>, +struct ParentDriver; + +#[allow(clippy::type_complexity)] +struct ParentData<'bound> { + _reg0: auxiliary::Registration<'bound, ForLt!(Data)>, + _reg1: auxiliary::Registration<'bound, ForLt!(Data)>, } kernel::pci_device_table!( @@ -69,15 +72,15 @@ kernel::pci_device_table!( impl pci::Driver for ParentDriver { type IdInfo = (); - type Data<'bound> = Self; + type Data<'bound> = ParentData<'bound>; const ID_TABLE: pci::IdTable = &PCI_TABLE; fn probe<'bound>( pdev: &'bound pci::Device>, _info: &'bound Self::IdInfo, - ) -> impl PinInit + 'bound { - Ok(Self { + ) -> impl PinInit, Error> + 'bound { + Ok(ParentData { _reg0: auxiliary::Registration::new( pdev.as_ref(), AUXILIARY_NAME, @@ -101,7 +104,7 @@ impl ParentDriver { let dev = adev.parent(); let pdev: &pci::Device = dev.try_into()?; - let data = adev.registration_data::()?; + let data = adev.registration_data::()?; dev_info!( dev, -- cgit v1.2.3 From d18f3646184fc805d213fc049fc3b5d9fb9a6a27 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 25 May 2026 22:21:11 +0200 Subject: samples: rust: rust_driver_auxiliary: showcase lifetime-bound registration data Make the Data struct lifetime-parameterized, storing a reference to the parent pci::Device. This demonstrates that registration data can hold device resources tied to the parent driver's lifetime. In connect(), retrieve the parent PCI device from the registration data rather than casting through adev.parent(). Reviewed-by: Eliot Courtney Reviewed-by: Gary Guo Reviewed-by: Greg Kroah-Hartman Reviewed-by: Alexandre Courbot Link: https://patch.msgid.link/20260525202921.124698-25-dakr@kernel.org Signed-off-by: Danilo Krummrich --- samples/rust/rust_driver_auxiliary.rs | 58 +++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 23 deletions(-) (limited to 'samples') diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs index e3e811a14110..2c1351040e45 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -51,16 +51,17 @@ impl auxiliary::Driver for AuxiliaryDriver { } } -struct Data { +struct Data<'bound> { index: u32, + parent: &'bound pci::Device, } struct ParentDriver; #[allow(clippy::type_complexity)] struct ParentData<'bound> { - _reg0: auxiliary::Registration<'bound, ForLt!(Data)>, - _reg1: auxiliary::Registration<'bound, ForLt!(Data)>, + _reg0: auxiliary::Registration<'bound, ForLt!(Data<'_>)>, + _reg1: auxiliary::Registration<'bound, ForLt!(Data<'_>)>, } kernel::pci_device_table!( @@ -81,33 +82,44 @@ impl pci::Driver for ParentDriver { _info: &'bound Self::IdInfo, ) -> impl PinInit, Error> + 'bound { Ok(ParentData { - _reg0: auxiliary::Registration::new( - pdev.as_ref(), - AUXILIARY_NAME, - 0, - MODULE_NAME, - Data { index: 0 }, - )?, - _reg1: auxiliary::Registration::new( - pdev.as_ref(), - AUXILIARY_NAME, - 1, - MODULE_NAME, - Data { index: 1 }, - )?, + // SAFETY: `ParentData` is the driver's private data, which is dropped when the + // device is unbound; i.e. `mem::forget()` is never called on it. + _reg0: unsafe { + auxiliary::Registration::new_with_lt( + pdev.as_ref(), + AUXILIARY_NAME, + 0, + MODULE_NAME, + Data { + index: 0, + parent: pdev, + }, + )? + }, + // SAFETY: See `_reg0` above. + _reg1: unsafe { + auxiliary::Registration::new_with_lt( + pdev.as_ref(), + AUXILIARY_NAME, + 1, + MODULE_NAME, + Data { + index: 1, + parent: pdev, + }, + )? + }, }) } } impl ParentDriver { fn connect(adev: &auxiliary::Device) -> Result { - let dev = adev.parent(); - let pdev: &pci::Device = dev.try_into()?; - - let data = adev.registration_data::()?; + let data = adev.registration_data::)>()?; + let pdev = data.parent; dev_info!( - dev, + pdev, "Connect auxiliary {} with parent: VendorID={}, DeviceID={:#x}\n", adev.id(), pdev.vendor_id(), @@ -115,7 +127,7 @@ impl ParentDriver { ); dev_info!( - dev, + pdev, "Connected to auxiliary device with index {}.\n", data.index ); -- cgit v1.2.3