From: Danilo Krummrich <dakr@kernel.org>
To: Viresh Kumar <viresh.kumar@linaro.org>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>,
"Miguel Ojeda" <miguel.ojeda.sandonis@gmail.com>,
"Danilo Krummrich" <dakr@redhat.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
linux-pm@vger.kernel.org,
"Vincent Guittot" <vincent.guittot@linaro.org>,
"Stephen Boyd" <sboyd@kernel.org>, "Nishanth Menon" <nm@ti.com>,
rust-for-linux@vger.kernel.org,
"Manos Pitsidianakis" <manos.pitsidianakis@linaro.org>,
"Erik Schilling" <erik.schilling@linaro.org>,
"Alex Bennée" <alex.bennee@linaro.org>,
"Joakim Bech" <joakim.bech@linaro.org>,
"Rob Herring" <robh@kernel.org>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH V8 12/14] rust: Extend cpufreq bindings for driver registration
Date: Thu, 6 Feb 2025 13:04:21 +0100 [thread overview]
Message-ID: <Z6SlRZouQ-nPH2EP@pollux> (raw)
In-Reply-To: <5860ff88ff81d09838f7786507ec47a33cf16158.1738832119.git.viresh.kumar@linaro.org>
On Thu, Feb 06, 2025 at 02:58:33PM +0530, Viresh Kumar wrote:
> This extends the cpufreq bindings with bindings for registering a
> driver.
>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
> rust/kernel/cpufreq.rs | 475 ++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 473 insertions(+), 2 deletions(-)
>
> diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
> index 63ea816017c0..f92259d339d3 100644
> --- a/rust/kernel/cpufreq.rs
> +++ b/rust/kernel/cpufreq.rs
> @@ -9,14 +9,17 @@
> use crate::{
> bindings, clk, cpumask,
> device::Device,
> - error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR},
> + devres::Devres,
> + error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR},
> prelude::*,
> types::ForeignOwnable,
> };
>
> use core::{
> + cell::UnsafeCell,
> + marker::PhantomData,
> pin::Pin,
> - ptr::self,
> + ptr::{self, addr_of_mut},
> };
>
> use macros::vtable;
> @@ -579,3 +582,471 @@ fn register_em(_policy: &mut Policy) {
> build_error!(VTABLE_DEFAULT_ERROR)
> }
> }
> +
> +/// Registration of a cpufreq driver.
> +pub struct Registration<T: Driver> {
> + drv: KBox<UnsafeCell<bindings::cpufreq_driver>>,
> + _p: PhantomData<T>,
> +}
> +
> +// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
> +// or CPUs, so it is safe to share it.
> +unsafe impl<T: Driver> Sync for Registration<T> {}
> +
> +#[allow(clippy::non_send_fields_in_send_ty)]
> +// SAFETY: Registration with and unregistration from the cpufreq subsystem can happen from any
> +// thread. Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is
> +// okay to move `Registration` to different threads.
> +unsafe impl<T: Driver> Send for Registration<T> {}
> +
> +impl<T: Driver> Registration<T> {
> + /// Registers a cpufreq driver with the rest of the kernel.
> + pub fn new(name: &'static CStr, data: T::Data, flags: u16, boost: bool) -> Result<Self> {
> + let mut drv = KBox::new(
> + UnsafeCell::new(bindings::cpufreq_driver::default()),
> + GFP_KERNEL,
> + )?;
> + let drv_ref = drv.get_mut();
> +
> + // Account for the trailing null character.
> + let len = name.len() + 1;
> + if len > drv_ref.name.len() {
> + return Err(EINVAL);
> + };
> +
> + // SAFETY: `name` is a valid Cstr, and we are copying it to an array of equal or larger
> + // size.
> + let name = unsafe { &*(name.as_bytes_with_nul() as *const [u8]) };
> + drv_ref.name[..len].copy_from_slice(name);
> +
> + drv_ref.boost_enabled = boost;
> + drv_ref.flags = flags;
> +
> + // Allocate an array of 3 pointers to be passed to the C code.
> + let mut attr = KBox::new([ptr::null_mut(); 3], GFP_KERNEL)?;
> + let mut next = 0;
> +
> + // SAFETY: The C code returns a valid pointer here, which is again passed to the C code in
> + // an array.
> + attr[next] =
> + unsafe { addr_of_mut!(bindings::cpufreq_freq_attr_scaling_available_freqs) as *mut _ };
> + next += 1;
> +
> + if boost {
> + // SAFETY: The C code returns a valid pointer here, which is again passed to the C code
> + // in an array.
> + attr[next] =
> + unsafe { addr_of_mut!(bindings::cpufreq_freq_attr_scaling_boost_freqs) as *mut _ };
> + next += 1;
> + }
> + attr[next] = ptr::null_mut();
> +
> + // Pass the ownership of the memory block to the C code. This will be freed when
> + // the [`Registration`] object goes out of scope.
> + drv_ref.attr = KBox::leak(attr) as *mut _;
I think this should be KBox::into_raw() instead.
> +
> + // Initialize mandatory callbacks.
> + drv_ref.init = Some(Self::init_callback);
> + drv_ref.verify = Some(Self::verify_callback);
> +
> + // Initialize optional callbacks.
> + drv_ref.setpolicy = if T::HAS_SETPOLICY {
> + Some(Self::setpolicy_callback)
> + } else {
> + None
> + };
> + drv_ref.target = if T::HAS_TARGET {
> + Some(Self::target_callback)
> + } else {
> + None
> + };
> + drv_ref.target_index = if T::HAS_TARGET_INDEX {
> + Some(Self::target_index_callback)
> + } else {
> + None
> + };
> + drv_ref.fast_switch = if T::HAS_FAST_SWITCH {
> + Some(Self::fast_switch_callback)
> + } else {
> + None
> + };
> + drv_ref.adjust_perf = if T::HAS_ADJUST_PERF {
> + Some(Self::adjust_perf_callback)
> + } else {
> + None
> + };
> + drv_ref.get_intermediate = if T::HAS_GET_INTERMEDIATE {
> + Some(Self::get_intermediate_callback)
> + } else {
> + None
> + };
> + drv_ref.target_intermediate = if T::HAS_TARGET_INTERMEDIATE {
> + Some(Self::target_intermediate_callback)
> + } else {
> + None
> + };
> + drv_ref.get = if T::HAS_GET {
> + Some(Self::get_callback)
> + } else {
> + None
> + };
> + drv_ref.update_limits = if T::HAS_UPDATE_LIMITS {
> + Some(Self::update_limits_callback)
> + } else {
> + None
> + };
> + drv_ref.bios_limit = if T::HAS_BIOS_LIMIT {
> + Some(Self::bios_limit_callback)
> + } else {
> + None
> + };
> + drv_ref.online = if T::HAS_ONLINE {
> + Some(Self::online_callback)
> + } else {
> + None
> + };
> + drv_ref.offline = if T::HAS_OFFLINE {
> + Some(Self::offline_callback)
> + } else {
> + None
> + };
> + drv_ref.exit = if T::HAS_EXIT {
> + Some(Self::exit_callback)
> + } else {
> + None
> + };
> + drv_ref.suspend = if T::HAS_SUSPEND {
> + Some(Self::suspend_callback)
> + } else {
> + None
> + };
> + drv_ref.resume = if T::HAS_RESUME {
> + Some(Self::resume_callback)
> + } else {
> + None
> + };
> + drv_ref.ready = if T::HAS_READY {
> + Some(Self::ready_callback)
> + } else {
> + None
> + };
> + drv_ref.set_boost = if T::HAS_SET_BOOST {
> + Some(Self::set_boost_callback)
> + } else {
> + None
> + };
> + drv_ref.register_em = if T::HAS_REGISTER_EM {
> + Some(Self::register_em_callback)
> + } else {
> + None
> + };
> +
> + // Set driver data before registering the driver, as the cpufreq core may call few
> + // callbacks before `cpufreq_register_driver()` returns.
> + Self::set_data(drv_ref, data)?;
> +
> + // SAFETY: It is safe to register the driver with the cpufreq core in the C code.
> + to_result(unsafe { bindings::cpufreq_register_driver(drv_ref) })?;
> +
> + Ok(Self {
> + drv,
> + _p: PhantomData,
> + })
> + }
...
> +// cpufreq driver callbacks.
> +impl<T: Driver> Registration<T> {
> + // Policy's init callback.
> + extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> core::ffi::c_int {
I suggest to convert all the ffi types to kernel::ffi::*.
> + from_result(|| {
> + // SAFETY: `ptr` is valid by the contract with the C code. `policy` is alive only for
> + // the duration of this call, so it is guaranteed to remain alive for the lifetime of
> + // `ptr`.
> + let mut policy = unsafe { Policy::from_raw_policy(ptr) };
> +
> + let data = T::init(&mut policy)?;
> + policy.set_data(data)?;
> + Ok(0)
> + })
> + }
...
> +impl<T: Driver> Drop for Registration<T> {
> + // Removes the registration from the kernel if it has completed successfully before.
> + fn drop(&mut self) {
> + pr_info!("Registration dropped\n");
This should be dropped.
> + let drv = self.drv.get_mut();
> +
> + // SAFETY: The driver was earlier registered from `new()`.
> + unsafe { bindings::cpufreq_unregister_driver(drv) };
> +
> + // Free the previously leaked memory to the C code.
> + if !drv.attr.is_null() {
> + // SAFETY: The pointer was earlier initialized from the result of `KBox::leak`.
Box::leak() returns a mutable reference, whereas Box::into_raw() returns a raw
pointer for exactly this purpose.
Now that I think of it, maybe Box::leak() should even be removed, since it
almost never makes any sense in the kernel.
> + unsafe { drop(KBox::from_raw(drv.attr)) };
This could just be
let _ = unsafe { KBox::from_raw(drv.attr) };
At least drop() should not be within the unsafe block.
> + }
> +
> + // Free data
> + drop(self.clear_data());
No need for drop(), but I also don't mind to be explicit.
> + }
> +}
> --
> 2.31.1.272.g89b43f80a514
>
>
next prev parent reply other threads:[~2025-02-06 12:04 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-06 9:28 [PATCH V8 00/14] Rust bindings for cpufreq and OPP core + sample driver Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 01/14] rust: macros: enable use of hyphens in module names Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 02/14] cpufreq: Use enum for cpufreq flags that use BIT() Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 03/14] rust: cpu: Add from_cpu() Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 04/14] rust: Add cpumask helpers Viresh Kumar
2025-02-11 0:02 ` Yury Norov
2025-02-11 4:29 ` Viresh Kumar
2025-02-11 16:24 ` Yury Norov
2025-02-11 16:49 ` Jason Gunthorpe
2025-02-11 17:27 ` Danilo Krummrich
2025-02-11 21:37 ` Miguel Ojeda
2025-02-14 2:20 ` Yury Norov
2025-02-14 3:36 ` Viresh Kumar
2025-02-14 17:56 ` Miguel Ojeda
2025-02-14 19:11 ` Jason Gunthorpe
2025-02-14 20:24 ` Miguel Ojeda
2025-02-14 21:06 ` Jason Gunthorpe
2025-02-14 22:36 ` Miguel Ojeda
2025-02-15 9:55 ` Andreas Hindborg
2025-02-17 9:45 ` Philipp Stanner
2025-02-14 20:58 ` Miguel Ojeda
2025-02-12 7:34 ` Viresh Kumar
2025-02-15 10:16 ` Andreas Hindborg
2025-02-06 9:28 ` [PATCH V8 05/14] rust: Add bindings for cpumask Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 06/14] rust: Add bare minimal bindings for clk framework Viresh Kumar
2025-02-06 11:49 ` Danilo Krummrich
2025-02-06 11:52 ` Danilo Krummrich
2025-02-06 20:05 ` Stephen Boyd
2025-02-06 23:11 ` Danilo Krummrich
2025-02-07 9:24 ` Viresh Kumar
2025-02-07 10:43 ` Viresh Kumar
2025-02-07 17:19 ` Danilo Krummrich
2025-02-10 8:06 ` Viresh Kumar
2025-02-10 22:07 ` Stephen Boyd
2025-02-17 12:19 ` Daniel Almeida
2025-02-21 6:35 ` Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 07/14] rust: Add initial bindings for OPP framework Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 08/14] rust: Extend OPP bindings for the OPP table Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 09/14] rust: Extend OPP bindings for the configuration options Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 10/14] rust: Add initial bindings for cpufreq framework Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 11/14] rust: Extend cpufreq bindings for policy and driver ops Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 12/14] rust: Extend cpufreq bindings for driver registration Viresh Kumar
2025-02-06 12:04 ` Danilo Krummrich [this message]
2025-02-06 12:06 ` Alice Ryhl
2025-02-07 9:15 ` Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 13/14] rust: Extend OPP bindings with CPU frequency table Viresh Kumar
2025-02-06 9:28 ` [PATCH V8 14/14] cpufreq: Add Rust based cpufreq-dt driver Viresh Kumar
2025-02-06 11:45 ` [PATCH V8 00/14] Rust bindings for cpufreq and OPP core + sample driver Danilo Krummrich
2025-02-07 7:15 ` Viresh Kumar
2025-02-07 11:07 ` Miguel Ojeda
2025-02-10 8:06 ` Viresh Kumar
2025-02-17 8:39 ` Miguel Ojeda
2025-02-17 10:18 ` Viresh Kumar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Z6SlRZouQ-nPH2EP@pollux \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alex.bennee@linaro.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@redhat.com \
--cc=erik.schilling@linaro.org \
--cc=gary@garyguo.net \
--cc=joakim.bech@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=manos.pitsidianakis@linaro.org \
--cc=miguel.ojeda.sandonis@gmail.com \
--cc=nm@ti.com \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=robh@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sboyd@kernel.org \
--cc=tmgross@umich.edu \
--cc=vincent.guittot@linaro.org \
--cc=viresh.kumar@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.