Make platform::Driver take a lifetime parameter 'bound that ties device resources to the binding scope.
Internally, Adapter<T: Driver> becomes Adapter<F: ForLt> with a bound for<'bound> F::Of<'bound>: Driver<'bound>; module_platform_driver! wraps the driver type in ForLt!() so drivers don't have to. Acked-by: Uwe Kleine-König <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]> --- drivers/cpufreq/rcpufreq_dt.rs | 10 +-- drivers/gpu/drm/tyr/driver.rs | 10 +-- drivers/pwm/pwm_th1520.rs | 10 +-- rust/kernel/cpufreq.rs | 8 +-- rust/kernel/driver.rs | 9 ++- rust/kernel/io/mem.rs | 16 ++--- rust/kernel/platform.rs | 93 ++++++++++++++++++---------- samples/rust/rust_debugfs.rs | 10 +-- samples/rust/rust_driver_platform.rs | 12 ++-- samples/rust/rust_i2c_client.rs | 12 ++-- samples/rust/rust_soc.rs | 12 ++-- 11 files changed, 117 insertions(+), 85 deletions(-) diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index f17bf64c22e2..f0ad2d115cf3 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -195,18 +195,18 @@ fn register_em(policy: &mut cpufreq::Policy) { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - <CPUFreqDTDriver as platform::Driver>::IdInfo, + <CPUFreqDTDriver as platform::Driver<'_>>::IdInfo, [(of::DeviceId::new(c"operating-points-v2"), ())] ); -impl platform::Driver for CPUFreqDTDriver { +impl<'bound> platform::Driver<'bound> for CPUFreqDTDriver { type IdInfo = (); const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); fn probe( - pdev: &platform::Device<Core>, - _id_info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + pdev: &'bound platform::Device<Core>, + _id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { cpufreq::Registration::<CPUFreqDTDriver>::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 279710b36a10..96d83605e4b9 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -82,21 +82,21 @@ fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - <TyrPlatformDriverData as platform::Driver>::IdInfo, + <TyrPlatformDriverData as platform::Driver<'_>>::IdInfo, [ (of::DeviceId::new(c"rockchip,rk3588-mali"), ()), (of::DeviceId::new(c"arm,mali-valhall-csf"), ()) ] ); -impl platform::Driver for TyrPlatformDriverData { +impl<'bound> platform::Driver<'bound> for TyrPlatformDriverData { type IdInfo = (); const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); fn probe( - pdev: &platform::Device<Core>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + pdev: &'bound platform::Device<Core>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + '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 ddd44a5ce497..a7831b4ebe00 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -310,18 +310,18 @@ fn drop(self: Pin<&mut Self>) { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - <Th1520PwmPlatformDriver as platform::Driver>::IdInfo, + <Th1520PwmPlatformDriver as platform::Driver<'_>>::IdInfo, [(of::DeviceId::new(c"thead,th1520-pwm"), ())] ); -impl platform::Driver for Th1520PwmPlatformDriver { +impl<'bound> platform::Driver<'bound> for Th1520PwmPlatformDriver { type IdInfo = (); const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); fn probe( - pdev: &platform::Device<Core>, - _id_info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + pdev: &'bound platform::Device<Core>, + _id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + '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 d8d26870bea2..ac59cdfd633c 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -886,14 +886,14 @@ fn register_em(_policy: &mut Policy) { /// } /// } /// -/// impl platform::Driver for SampleDriver { +/// impl<'a> platform::Driver<'a> for SampleDriver { /// type IdInfo = (); /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; /// /// fn probe( -/// pdev: &platform::Device<Core>, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit<Self, Error> { +/// pdev: &'a platform::Device<Core>, +/// _id_info: Option<&'a Self::IdInfo>, +/// ) -> impl PinInit<Self, Error> + 'a { /// cpufreq::Registration::<SampleDriver>::new_foreign_owned(pdev.as_ref())?; /// Ok(Self {}) /// } diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index e462535f545d..7c5148772697 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -13,7 +13,7 @@ //! The main driver interface is defined by a bus specific driver trait. For instance: //! //! ```ignore -//! pub trait Driver: Send { +//! pub trait Driver<'bound>: Send { //! /// The type holding information about each device ID supported by the driver. //! type IdInfo: 'static; //! @@ -24,10 +24,13 @@ //! const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None; //! //! /// Driver probe. -//! fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> impl PinInit<Self, Error>; +//! fn probe( +//! dev: &'bound Device<device::Core>, +//! id_info: &'bound Self::IdInfo, +//! ) -> impl PinInit<Self, Error> + 'bound; //! //! /// Driver unbind (optional). -//! fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { +//! fn unbind(dev: &'bound Device<device::Core>, this: Pin<&'bound Self>) { //! let _ = (dev, this); //! } //! } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 7dc78d547f7a..fd5292df5870 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -60,13 +60,13 @@ pub(crate) unsafe fn new(device: &'a Device<Bound>, resource: &'a Resource) -> S /// }; /// struct SampleDriver; /// - /// impl platform::Driver for SampleDriver { + /// impl<'bound> platform::Driver<'bound> for SampleDriver { /// # type IdInfo = (); /// /// fn probe( - /// pdev: &platform::Device<Core>, - /// info: Option<&Self::IdInfo>, - /// ) -> impl PinInit<Self, Error> { + /// pdev: &'bound platform::Device<Core>, + /// info: Option<&'bound Self::IdInfo>, + /// ) -> impl PinInit<Self, Error> + 'bound { /// let offset = 0; // Some offset. /// /// // If the size is known at compile time, use [`Self::iomap_sized`]. @@ -124,13 +124,13 @@ pub fn iomap_exclusive_sized<const SIZE: usize>( /// }; /// struct SampleDriver; /// - /// impl platform::Driver for SampleDriver { + /// impl<'bound> platform::Driver<'bound> for SampleDriver { /// # type IdInfo = (); /// /// fn probe( - /// pdev: &platform::Device<Core>, - /// info: Option<&Self::IdInfo>, - /// ) -> impl PinInit<Self, Error> { + /// pdev: &'bound platform::Device<Core>, + /// info: Option<&'bound Self::IdInfo>, + /// ) -> impl PinInit<Self, Error> + '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 aec26307ae68..9959364429b5 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -44,33 +44,46 @@ }; /// An adapter for the registration of platform drivers. -pub struct Adapter<T: Driver>(T); +/// +/// `F` is a [`ForLt`](trait@ForLt) type that maps lifetimes to the driver's device +/// private data type, i.e. `F::Of<'bound>` is the driver struct +/// parameterized by `'bound`. The macro `module_platform_driver!` +/// generates this automatically via `ForLt!()`. +pub struct Adapter<F>(PhantomData<F>); // SAFETY: // - `bindings::platform_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `F::Of<'static>` is the stored 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<T: Driver + 'static> driver::DriverLayout for Adapter<T> { +unsafe impl<F> driver::DriverLayout for Adapter<F> +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ type DriverType = bindings::platform_driver; - type DriverData = ForLt!(T); + type DriverData = F; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { +unsafe impl<F> driver::RegistrationOps for Adapter<F> +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ unsafe fn register( pdrv: &Opaque<Self::DriverType>, name: &'static CStr, module: &'static ThisModule, ) -> Result { - let of_table = match T::OF_ID_TABLE { + let of_table = match <F::Of<'static> as Driver<'static>>::OF_ID_TABLE { Some(table) => table.as_ptr(), None => core::ptr::null(), }; - let acpi_table = match T::ACPI_ID_TABLE { + let acpi_table = match <F::Of<'static> as Driver<'static>>::ACPI_ID_TABLE { Some(table) => table.as_ptr(), None => core::ptr::null(), }; @@ -94,19 +107,23 @@ unsafe fn unregister(pdrv: &Opaque<Self::DriverType>) { } } -impl<T: Driver + 'static> Adapter<T> { +impl<F> Adapter<F> +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ffi::c_int { // SAFETY: The platform bus only ever calls the probe callback with a valid pointer to a // `struct platform_device`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback()`. let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; - let info = <Self as driver::Adapter<'_>>::id_info(pdev.as_ref()); from_result(|| { - let data = T::probe(pdev, info); + let info = <Self as driver::Adapter<'_>>::id_info(pdev.as_ref()); + let data = <F::Of<'_> as Driver<'_>>::probe(pdev, info); - pdev.as_ref().set_drvdata::<ForLt!(T)>(data)?; + pdev.as_ref().set_drvdata::<F>(data)?; Ok(0) }) } @@ -119,28 +136,34 @@ extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() }; // SAFETY: `remove_callback` is only ever called after a successful call to - // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called - // and stored a `Pin<KBox<T>>`. - let data = unsafe { pdev.as_ref().drvdata_borrow::<ForLt!(T)>() }; + // `probe_callback`, hence it's guaranteed that drvdata has been set. + let data = unsafe { pdev.as_ref().drvdata_borrow::<F>() }; - T::unbind(pdev, data); + <F::Of<'_> as Driver<'_>>::unbind(pdev, data); } } -impl<'bound, T: Driver + 'static> driver::Adapter<'bound> for Adapter<T> { - type IdInfo = T::IdInfo; +impl<'bound, F> driver::Adapter<'bound> for Adapter<F> +where + F: ForLt + 'static, + for<'b> F::Of<'b>: Driver<'b>, +{ + type IdInfo = <F::Of<'bound> as Driver<'bound>>::IdInfo; fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> { - T::OF_ID_TABLE + <F::Of<'bound> as Driver<'bound>>::OF_ID_TABLE } fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>> { - T::ACPI_ID_TABLE + <F::Of<'bound> as Driver<'bound>>::ACPI_ID_TABLE } } /// Declares a kernel module that exposes a single platform driver. /// +/// The `type` field accepts a driver type, optionally with a lifetime placeholder `'_` for +/// lifetime-parameterized drivers. The macro wraps it in [`ForLt!`] automatically. +/// /// # Examples /// /// ```ignore @@ -152,10 +175,16 @@ fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>> { /// license: "GPL v2", /// } /// ``` +/// +/// [`ForLt!`]: macro@ForLt +/// [`ForLt`]: trait@ForLt #[macro_export] macro_rules! module_platform_driver { - ($($f:tt)*) => { - $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* }); + (type: $type:ty, $($rest:tt)*) => { + $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { + type: $crate::types::ForLt!($type), + $($rest)* + }); }; } @@ -178,7 +207,7 @@ macro_rules! module_platform_driver { /// kernel::of_device_table!( /// OF_TABLE, /// MODULE_OF_TABLE, -/// <MyDriver as platform::Driver>::IdInfo, +/// <MyDriver as platform::Driver<'_>>::IdInfo, /// [ /// (of::DeviceId::new(c"test,device"), ()) /// ] @@ -187,26 +216,26 @@ macro_rules! module_platform_driver { /// kernel::acpi_device_table!( /// ACPI_TABLE, /// MODULE_ACPI_TABLE, -/// <MyDriver as platform::Driver>::IdInfo, +/// <MyDriver as platform::Driver<'_>>::IdInfo, /// [ /// (acpi::DeviceId::new(c"LNUXBEEF"), ()) /// ] /// ); /// -/// impl platform::Driver for MyDriver { +/// impl<'bound> platform::Driver<'bound> for MyDriver { /// type IdInfo = (); /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); /// const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); /// /// fn probe( -/// _pdev: &platform::Device<Core>, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit<Self, Error> { +/// _pdev: &'bound platform::Device<Core>, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit<Self, Error> + 'bound { /// Err(ENODEV) /// } /// } ///``` -pub trait Driver: Send { +pub trait Driver<'bound>: Send { /// The type holding driver private data about each device id supported by the driver. // TODO: Use associated_type_defaults once stabilized: // @@ -226,9 +255,9 @@ pub trait Driver: Send { /// Called when a new platform device is added or discovered. /// Implementers should attempt to initialize the device here. fn probe( - dev: &Device<device::Core>, - id_info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error>; + dev: &'bound Device<device::Core>, + id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound; /// Platform driver unbind. /// @@ -240,7 +269,7 @@ fn probe( /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be performed in `Self::drop`. - fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) { + fn unbind(dev: &'bound Device<device::Core>, this: Pin<&'bound Self>) { let _ = (dev, this); } } diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 0963efe19f93..ca73c0ef4a79 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -111,19 +111,19 @@ fn from_str(s: &str) -> Result<Self> { kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, - <RustDebugFs as platform::Driver>::IdInfo, + <RustDebugFs as platform::Driver<'_>>::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), ())] ); -impl platform::Driver for RustDebugFs { +impl<'bound> platform::Driver<'bound> for RustDebugFs { type IdInfo = (); const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None; const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); fn probe( - pdev: &platform::Device<Core>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + pdev: &'bound platform::Device<Core>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + '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 f2229d176fb9..5b7037eb4b3f 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -88,26 +88,26 @@ struct SampleDriver { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - <SampleDriver as platform::Driver>::IdInfo, + <SampleDriver as platform::Driver<'_>>::IdInfo, [(of::DeviceId::new(c"test,rust-device"), Info(42))] ); kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, - <SampleDriver as platform::Driver>::IdInfo, + <SampleDriver as platform::Driver<'_>>::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), Info(0))] ); -impl platform::Driver for SampleDriver { +impl<'bound> platform::Driver<'bound> for SampleDriver { type IdInfo = Info; const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); fn probe( - pdev: &platform::Device<Core>, - info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + pdev: &'bound platform::Device<Core>, + info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + '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 8d2c12e535b0..e21595a4376e 100644 --- a/samples/rust/rust_i2c_client.rs +++ b/samples/rust/rust_i2c_client.rs @@ -88,14 +88,14 @@ struct SampleDriver { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - <SampleDriver as platform::Driver>::IdInfo, + <SampleDriver as platform::Driver<'_>>::IdInfo, [(of::DeviceId::new(c"test,rust-device"), ())] ); kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, - <SampleDriver as platform::Driver>::IdInfo, + <SampleDriver as platform::Driver<'_>>::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), ())] ); @@ -104,15 +104,15 @@ struct SampleDriver { const BOARD_INFO: i2c::I2cBoardInfo = i2c::I2cBoardInfo::new(c"rust_driver_i2c", SAMPLE_I2C_CLIENT_ADDR); -impl platform::Driver for SampleDriver { +impl<'bound> platform::Driver<'bound> for SampleDriver { type IdInfo = (); const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); fn probe( - pdev: &platform::Device<device::Core>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + pdev: &'bound platform::Device<device::Core>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { dev_info!( pdev.as_ref(), "Probe Rust I2C Client registration sample.\n" diff --git a/samples/rust/rust_soc.rs b/samples/rust/rust_soc.rs index 8079c1c48416..356d093bc8dd 100644 --- a/samples/rust/rust_soc.rs +++ b/samples/rust/rust_soc.rs @@ -24,26 +24,26 @@ struct SampleSocDriver { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - <SampleSocDriver as platform::Driver>::IdInfo, + <SampleSocDriver as platform::Driver<'_>>::IdInfo, [(of::DeviceId::new(c"test,rust-device"), ())] ); kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, - <SampleSocDriver as platform::Driver>::IdInfo, + <SampleSocDriver as platform::Driver<'_>>::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), ())] ); -impl platform::Driver for SampleSocDriver { +impl<'bound> platform::Driver<'bound> for SampleSocDriver { type IdInfo = (); const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); fn probe( - pdev: &platform::Device<Core>, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit<Self, Error> { + pdev: &'bound platform::Device<Core>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit<Self, Error> + 'bound { dev_dbg!(pdev, "Probe Rust SoC driver sample.\n"); let pdev = pdev.into(); -- 2.54.0
