[PATCH v3 2/3] rust: platform: wire runtime PM callbacks
Beata Michalska <[email protected]>
| Newsgroups | org.kernel.vger.rust-for-linux,dev.linux.lists.driver-core,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm |
|---|---|
| Message-ID | <[email protected]> |
Allow platform drivers to provide Rust runtime PM callbacks by exposing typed `dev_pm_ops` through the platform driver trait and installing them via the generated `platform_driver`. Add a platform-specific constructor for `pm::DevPMOps` that ties the PM callbacks to `platform::Adapter<T>` and requires callbacks to use a bound platform device. This keeps the unsafe generic PM ops constructor internal while letting platform drivers opt into runtime PM without affecting drivers that do not use it. The platform glue only wires the callback table into the C driver model; ownership of the callback payload and runtime PM teardown remain with the pm module. Signed-off-by: Beata Michalska <[email protected]> --- rust/kernel/platform.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 9b362e0495d3..3da2a5ed4857 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -72,6 +72,10 @@ unsafe fn register( None => core::ptr::null(), }; + let pm_ops = T::dev_pm_ops() + .map(|ops| ops.as_raw()) + .unwrap_or(core::ptr::null()); + // SAFETY: It's safe to set the fields of `struct platform_driver` on initialization. unsafe { (*pdrv.get()).driver.name = name.as_char_ptr(); @@ -79,6 +83,7 @@ unsafe fn register( (*pdrv.get()).remove = Some(Self::remove_callback); (*pdrv.get()).driver.of_match_table = of_table; (*pdrv.get()).driver.acpi_match_table = acpi_table; + (*pdrv.get()).driver.pm = pm_ops; } // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. @@ -195,6 +200,7 @@ macro_rules! module_platform_driver { /// impl platform::Driver for MyDriver { /// type IdInfo = (); /// type Data<'bound> = Self; +/// /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); /// const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE); /// @@ -224,6 +230,14 @@ pub trait Driver { /// The table of ACPI device ids supported by the driver. const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None; + /// Provides driver's PM callbacks, if any. + fn dev_pm_ops() -> Option<crate::pm::DevPMOps<Adapter<Self>, Self>> + where + Self: Sized, + { + None + } + /// Platform driver probe. /// /// Called when a new platform device is added or discovered. @@ -571,3 +585,19 @@ unsafe impl Sync for Device {} // SAFETY: Same as `Device<Normal>` -- the underlying `struct platform_device` is the same; // `Bound` is a zero-sized type-state marker that does not affect thread safety. unsafe impl Sync for Device<device::Bound> {} + +#[allow(clippy::new_without_default)] +impl<T> crate::pm::DevPMOps<Adapter<T>, T> +where + T: Driver + crate::pm::PMOps<Adapter<T>, DeviceType = Device<device::Bound>>, +{ + /// Creates a platform driver's runtime PM callbacks for `T`. + /// + /// This constructor is available only when `T` is a platform driver and + /// its runtime PM callbacks accept a bound platform device. + pub const fn new() -> Self { + // SAFETY: `Adapter<T>` is the platform bus adapter for `T`, and the + // bound above forces PM callbacks to receive a platform bound device. + unsafe { crate::pm::DevPMOps::new_unchecked() } + } +} -- 2.43.0