diff mbox series

[V2,2/2] rust: Add basic bindings for clk APIs

Message ID a0a1ba4e27c3a0d9e38c677611eb88027e463287.1740118863.git.viresh.kumar@linaro.org (mailing list archive)
State Changes Requested, archived
Headers show
Series rust: Add basic clock bindings | expand

Commit Message

Viresh Kumar Feb. 21, 2025, 6:33 a.m. UTC
Add initial bindings for the clk APIs. These provide the minimal
functionality needed for common use cases, making them straightforward
to introduce in the first iteration.

These will be used by Rust based cpufreq / OPP layers to begin with.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 MAINTAINERS        |   1 +
 rust/kernel/clk.rs | 104 +++++++++++++++++++++++++++++++++++++++++++++
 rust/kernel/lib.rs |   1 +
 3 files changed, 106 insertions(+)
 create mode 100644 rust/kernel/clk.rs

Comments

Daniel Almeida Feb. 21, 2025, 1:30 p.m. UTC | #1
Hi Viresh, thank you for working on this.


> On 21 Feb 2025, at 03:33, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> 
> Add initial bindings for the clk APIs. These provide the minimal
> functionality needed for common use cases, making them straightforward
> to introduce in the first iteration.
> 
> These will be used by Rust based cpufreq / OPP layers to begin with.
> 
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
> MAINTAINERS        |   1 +
> rust/kernel/clk.rs | 104 +++++++++++++++++++++++++++++++++++++++++++++
> rust/kernel/lib.rs |   1 +
> 3 files changed, 106 insertions(+)
> create mode 100644 rust/kernel/clk.rs
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 726110d3c988..96e2574f41c0 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -5779,6 +5779,7 @@ F: include/linux/clk-pr*
> F: include/linux/clk/
> F: include/linux/of_clk.h
> F: rust/helpers/clk.c
> +F: rust/kernel/clk.rs
> X: drivers/clk/clkdev.c
> 
> COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3)
> diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
> new file mode 100644
> index 000000000000..c212cd3167e1
> --- /dev/null
> +++ b/rust/kernel/clk.rs
> @@ -0,0 +1,104 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Clock abstractions.
> +//!
> +//! C header: [`include/linux/clk.h`](srctree/include/linux/clk.h)
> +
> +use crate::{
> +    bindings,
> +    device::Device,
> +    error::{from_err_ptr, to_result, Result},
> +    prelude::*,
> +};
> +
> +use core::ptr;
> +
> +/// A simple implementation of `struct clk` from the C code.
> +#[repr(transparent)]
> +pub struct Clk(*mut bindings::clk);

> +
> +impl Clk {
> +    /// Creates `Clk` instance for a device and a connection id.
> +    pub fn new(dev: &Device, name: Option<&CStr>) -> Result<Self> {
> +        let con_id = if let Some(name) = name {
> +            name.as_ptr() as *const _
> +        } else {
> +            ptr::null()
> +        };
> +
> +        // SAFETY: It is safe to call `clk_get()`, on a device pointer earlier received from the C
> +        // code.
> +        Ok(Self(from_err_ptr(unsafe {
> +            bindings::clk_get(dev.as_raw(), con_id)
> +        })?))
> +    }
> +
> +    /// Obtain the raw `struct clk *`.
> +    pub fn as_raw(&self) -> *mut bindings::clk {
> +        self.0
> +    }
> +
> +    /// Clock enable.
> +    pub fn enable(&self) -> Result<()> {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.
> +        to_result(unsafe { bindings::clk_enable(self.0) })
> +    }
> +
> +    /// Clock disable.
> +    pub fn disable(&self) {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.
> +        unsafe { bindings::clk_disable(self.0) };
> +    }
> +
> +    /// Clock prepare.
> +    pub fn prepare(&self) -> Result<()> {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.
> +        to_result(unsafe { bindings::clk_prepare(self.0) })
> +    }
> +
> +    /// Clock unprepare.
> +    pub fn unprepare(&self) {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.
> +        unsafe { bindings::clk_unprepare(self.0) };
> +    }
> +
> +    /// Clock prepare enable.
> +    pub fn prepare_enable(&self) -> Result<()> {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.
> +        to_result(unsafe { bindings::clk_prepare_enable(self.0) })
> +    }
> +
> +    /// Clock disable unprepare.
> +    pub fn disable_unprepare(&self) {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.
> +        unsafe { bindings::clk_disable_unprepare(self.0) };
> +    }
> +
> +    /// Clock get rate.
> +    pub fn rate(&self) -> usize {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.
> +        unsafe { bindings::clk_get_rate(self.0) }
> +    }
> +
> +    /// Clock set rate.
> +    pub fn set_rate(&self, rate: usize) -> Result<()> {

It might be worth it to add a type here to make it clear what in what unit is `rate` expressed as.

Something like:

pub struct Hertz(pub u32);

pub fn set_rate(&self, rate: Hertz);

Assuming `rate` is in Hertz.


> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.
> +        to_result(unsafe { bindings::clk_set_rate(self.0, rate) })
> +    }
> +}
> +
> +impl Drop for Clk {
> +    fn drop(&mut self) {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // relinquish it now.
> +        unsafe { bindings::clk_put(self.0) };
> +    }
> +}
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 496ed32b0911..324b86f127a0 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -40,6 +40,7 @@
> pub mod block;
> #[doc(hidden)]
> pub mod build_assert;
> +pub mod clk;
> pub mod cred;
> pub mod device;
> pub mod device_id;
> -- 
> 2.31.1.272.g89b43f80a514
> 
> 


This is working fine on Tyr, so:

Tested-by: Daniel Almeida <daniel.almeida@collabora.com>

With the minor change above:

Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Danilo Krummrich Feb. 21, 2025, 1:56 p.m. UTC | #2
On Fri, Feb 21, 2025 at 12:03:39PM +0530, Viresh Kumar wrote:
> +/// A simple implementation of `struct clk` from the C code.
> +#[repr(transparent)]
> +pub struct Clk(*mut bindings::clk);

I remember that Stephen explained that NULL is valid value for struct clk. As a
consequence, all functions implemented for `Clk` have to consider this.

I wonder if it could make sense to have a transparent wrapper type
`MaybeNull<T>` (analogous to `NonNull<T>`) to make this fact more obvious for
cases like this?

> +
> +impl Clk {
> +    /// Creates `Clk` instance for a device and a connection id.
> +    pub fn new(dev: &Device, name: Option<&CStr>) -> Result<Self> {
> +        let con_id = if let Some(name) = name {
> +            name.as_ptr() as *const _
> +        } else {
> +            ptr::null()
> +        };
> +
> +        // SAFETY: It is safe to call `clk_get()`, on a device pointer earlier received from the C
> +        // code.
> +        Ok(Self(from_err_ptr(unsafe {
> +            bindings::clk_get(dev.as_raw(), con_id)
> +        })?))
> +    }
> +
> +    /// Obtain the raw `struct clk *`.
> +    pub fn as_raw(&self) -> *mut bindings::clk {
> +        self.0
> +    }
> +
> +    /// Clock enable.
> +    pub fn enable(&self) -> Result<()> {
> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> +        // use it now.

This is not true.

1. There is no type invariant documented for `Clk`.
2. The pointer contained in an instance of `Clk` may be NULL, hence `self` does
   not necessarily own a reference.

The same applies for all other functions in this implementation.
Daniel Almeida Feb. 21, 2025, 2:29 p.m. UTC | #3
> On 21 Feb 2025, at 10:56, Danilo Krummrich <dakr@kernel.org> wrote:
> 
> On Fri, Feb 21, 2025 at 12:03:39PM +0530, Viresh Kumar wrote:
>> +/// A simple implementation of `struct clk` from the C code.
>> +#[repr(transparent)]
>> +pub struct Clk(*mut bindings::clk);
> 
> I remember that Stephen explained that NULL is valid value for struct clk. As a
> consequence, all functions implemented for `Clk` have to consider this.

I am a bit confused here. If NULL is valid, then why should we have to specifically
consider that in the functions? No functions so far explicitly dereferences that value,
they only pass it to the clk framework.

Or are you referring to the safety comments only? In which case I do agree (sorry for
the oversight by the way)

> 
> I wonder if it could make sense to have a transparent wrapper type
> `MaybeNull<T>` (analogous to `NonNull<T>`) to make this fact more obvious for
> cases like this?

MaybeNull<T> sounds nice.

> 
>> +
>> +impl Clk {
>> +    /// Creates `Clk` instance for a device and a connection id.
>> +    pub fn new(dev: &Device, name: Option<&CStr>) -> Result<Self> {
>> +        let con_id = if let Some(name) = name {
>> +            name.as_ptr() as *const _
>> +        } else {
>> +            ptr::null()
>> +        };
>> +
>> +        // SAFETY: It is safe to call `clk_get()`, on a device pointer earlier received from the C
>> +        // code.
>> +        Ok(Self(from_err_ptr(unsafe {
>> +            bindings::clk_get(dev.as_raw(), con_id)
>> +        })?))
>> +    }
>> +
>> +    /// Obtain the raw `struct clk *`.
>> +    pub fn as_raw(&self) -> *mut bindings::clk {
>> +        self.0
>> +    }
>> +
>> +    /// Clock enable.
>> +    pub fn enable(&self) -> Result<()> {
>> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
>> +        // use it now.
> 
> This is not true.
> 
> 1. There is no type invariant documented for `Clk`.
> 2. The pointer contained in an instance of `Clk` may be NULL, hence `self` does
>   not necessarily own a reference.

> 
> The same applies for all other functions in this implementation.
>
Daniel Almeida Feb. 21, 2025, 2:42 p.m. UTC | #4
> +
> +use crate::{
> +    bindings,
> +    device::Device,
> +    error::{from_err_ptr, to_result, Result},
> +    prelude::*,
> +};
> +
> +use core::ptr;
> +
> +/// A simple implementation of `struct clk` from the C code.
> +#[repr(transparent)]
> +pub struct Clk(*mut bindings::clk);
> +
> +impl Clk {
> +    /// Creates `Clk` instance for a device and a connection id.
> +    pub fn new(dev: &Device, name: Option<&CStr>) -> Result<Self> {
> +        let con_id = if let Some(name) = name {
> +            name.as_ptr() as *const _
> +        } else {
> +            ptr::null()
> +        };

Viresh, one thing I forgot to comment. Maybe it’s better if we keep the
`get` nomenclature here instead of `new`.

This is to make clear that nothing is getting spawned. A reference to a system
resource is (potentially) being returned instead.

This would also mean refactoring the docs for this function.

— Daniel
Danilo Krummrich Feb. 21, 2025, 2:47 p.m. UTC | #5
On Fri, Feb 21, 2025 at 11:29:21AM -0300, Daniel Almeida wrote:
> 
> 
> > On 21 Feb 2025, at 10:56, Danilo Krummrich <dakr@kernel.org> wrote:
> > 
> > On Fri, Feb 21, 2025 at 12:03:39PM +0530, Viresh Kumar wrote:
> >> +/// A simple implementation of `struct clk` from the C code.
> >> +#[repr(transparent)]
> >> +pub struct Clk(*mut bindings::clk);
> > 
> > I remember that Stephen explained that NULL is valid value for struct clk. As a
> > consequence, all functions implemented for `Clk` have to consider this.
> 
> I am a bit confused here. If NULL is valid, then why should we have to specifically
> consider that in the functions? No functions so far explicitly dereferences that value,
> they only pass it to the clk framework.

This was badly phrased, the current implementation does not need to consider it
indeed. What I meant is that we have to consider it potentially. Especially,
when adding new functionality later on. For instance, when accessing fields of
struct clk directly. Maybe this only becomes relevant once we write a clk driver
itself in Rust, but still.

> 
> Or are you referring to the safety comments only? In which case I do agree (sorry for
> the oversight by the way)
> 
> > 
> > I wonder if it could make sense to have a transparent wrapper type
> > `MaybeNull<T>` (analogous to `NonNull<T>`) to make this fact more obvious for
> > cases like this?
> 
> MaybeNull<T> sounds nice.

Yeah, it's probably the correct thing to do, to make things obvious.

> 
> > 
> >> +
> >> +impl Clk {
> >> +    /// Creates `Clk` instance for a device and a connection id.
> >> +    pub fn new(dev: &Device, name: Option<&CStr>) -> Result<Self> {
> >> +        let con_id = if let Some(name) = name {
> >> +            name.as_ptr() as *const _
> >> +        } else {
> >> +            ptr::null()
> >> +        };
> >> +
> >> +        // SAFETY: It is safe to call `clk_get()`, on a device pointer earlier received from the C
> >> +        // code.
> >> +        Ok(Self(from_err_ptr(unsafe {
> >> +            bindings::clk_get(dev.as_raw(), con_id)
> >> +        })?))
> >> +    }
> >> +
> >> +    /// Obtain the raw `struct clk *`.
> >> +    pub fn as_raw(&self) -> *mut bindings::clk {
> >> +        self.0
> >> +    }
> >> +
> >> +    /// Clock enable.
> >> +    pub fn enable(&self) -> Result<()> {
> >> +        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
> >> +        // use it now.
> > 
> > This is not true.
> > 
> > 1. There is no type invariant documented for `Clk`.
> > 2. The pointer contained in an instance of `Clk` may be NULL, hence `self` does
> >   not necessarily own a reference.
> 
> > 
> > The same applies for all other functions in this implementation.
> > 
> 
>
Sebastian Reichel Feb. 21, 2025, 3:28 p.m. UTC | #6
Hi,

On Fri, Feb 21, 2025 at 03:47:57PM +0100, Danilo Krummrich wrote:
> On Fri, Feb 21, 2025 at 11:29:21AM -0300, Daniel Almeida wrote:
> > > On 21 Feb 2025, at 10:56, Danilo Krummrich <dakr@kernel.org> wrote:
> > > On Fri, Feb 21, 2025 at 12:03:39PM +0530, Viresh Kumar wrote:
> > >> +/// A simple implementation of `struct clk` from the C code.
> > >> +#[repr(transparent)]
> > >> +pub struct Clk(*mut bindings::clk);
> > > 
> > > I remember that Stephen explained that NULL is valid value for struct clk. As a
> > > consequence, all functions implemented for `Clk` have to consider this.
> > 
> > I am a bit confused here. If NULL is valid, then why should we have to specifically
> > consider that in the functions? No functions so far explicitly dereferences that value,
> > they only pass it to the clk framework.
> 
> This was badly phrased, the current implementation does not need to consider it
> indeed. What I meant is that we have to consider it potentially. Especially,
> when adding new functionality later on. For instance, when accessing fields of
> struct clk directly. 

Just a drive-by comment - the current implementation will never have
a NULL clock anyways. That is only returned by the clk_get functions
with the _optional() suffix. You are right now only using clk_get(),
which will instead returns ERR_PTR(-ENOENT).

> Maybe this only becomes relevant once we write a clk driver itself
> in Rust, but still.

For a clock provider implementation you will mainly use 'struct
clk_hw', which is different from 'struct clk'.

Greetings,

-- Sebastian
Rob Herring (Arm) Feb. 21, 2025, 9:59 p.m. UTC | #7
On Fri, Feb 21, 2025 at 04:28:18PM +0100, Sebastian Reichel wrote:
> Hi,
> 
> On Fri, Feb 21, 2025 at 03:47:57PM +0100, Danilo Krummrich wrote:
> > On Fri, Feb 21, 2025 at 11:29:21AM -0300, Daniel Almeida wrote:
> > > > On 21 Feb 2025, at 10:56, Danilo Krummrich <dakr@kernel.org> wrote:
> > > > On Fri, Feb 21, 2025 at 12:03:39PM +0530, Viresh Kumar wrote:
> > > >> +/// A simple implementation of `struct clk` from the C code.
> > > >> +#[repr(transparent)]
> > > >> +pub struct Clk(*mut bindings::clk);
> > > > 
> > > > I remember that Stephen explained that NULL is valid value for struct clk. As a
> > > > consequence, all functions implemented for `Clk` have to consider this.
> > > 
> > > I am a bit confused here. If NULL is valid, then why should we have to specifically
> > > consider that in the functions? No functions so far explicitly dereferences that value,
> > > they only pass it to the clk framework.
> > 
> > This was badly phrased, the current implementation does not need to consider it
> > indeed. What I meant is that we have to consider it potentially. Especially,
> > when adding new functionality later on. For instance, when accessing fields of
> > struct clk directly. 
> 
> Just a drive-by comment - the current implementation will never have
> a NULL clock anyways. That is only returned by the clk_get functions
> with the _optional() suffix. You are right now only using clk_get(),
> which will instead returns ERR_PTR(-ENOENT).

It would be nice to handle the optional case from the start. Otherwise, 
driver writers handle optional or not optional themselves. The not 
optional case is typically some form of error message duplicated in 
every driver.

Every foo_get() needs foo_get_optional(), so let's figure out the rust 
way to handle this once for everyone.

Rob
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 726110d3c988..96e2574f41c0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5779,6 +5779,7 @@  F:	include/linux/clk-pr*
 F:	include/linux/clk/
 F:	include/linux/of_clk.h
 F:	rust/helpers/clk.c
+F:	rust/kernel/clk.rs
 X:	drivers/clk/clkdev.c
 
 COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3)
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
new file mode 100644
index 000000000000..c212cd3167e1
--- /dev/null
+++ b/rust/kernel/clk.rs
@@ -0,0 +1,104 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+//! Clock abstractions.
+//!
+//! C header: [`include/linux/clk.h`](srctree/include/linux/clk.h)
+
+use crate::{
+    bindings,
+    device::Device,
+    error::{from_err_ptr, to_result, Result},
+    prelude::*,
+};
+
+use core::ptr;
+
+/// A simple implementation of `struct clk` from the C code.
+#[repr(transparent)]
+pub struct Clk(*mut bindings::clk);
+
+impl Clk {
+    /// Creates `Clk` instance for a device and a connection id.
+    pub fn new(dev: &Device, name: Option<&CStr>) -> Result<Self> {
+        let con_id = if let Some(name) = name {
+            name.as_ptr() as *const _
+        } else {
+            ptr::null()
+        };
+
+        // SAFETY: It is safe to call `clk_get()`, on a device pointer earlier received from the C
+        // code.
+        Ok(Self(from_err_ptr(unsafe {
+            bindings::clk_get(dev.as_raw(), con_id)
+        })?))
+    }
+
+    /// Obtain the raw `struct clk *`.
+    pub fn as_raw(&self) -> *mut bindings::clk {
+        self.0
+    }
+
+    /// Clock enable.
+    pub fn enable(&self) -> Result<()> {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // use it now.
+        to_result(unsafe { bindings::clk_enable(self.0) })
+    }
+
+    /// Clock disable.
+    pub fn disable(&self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // use it now.
+        unsafe { bindings::clk_disable(self.0) };
+    }
+
+    /// Clock prepare.
+    pub fn prepare(&self) -> Result<()> {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // use it now.
+        to_result(unsafe { bindings::clk_prepare(self.0) })
+    }
+
+    /// Clock unprepare.
+    pub fn unprepare(&self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // use it now.
+        unsafe { bindings::clk_unprepare(self.0) };
+    }
+
+    /// Clock prepare enable.
+    pub fn prepare_enable(&self) -> Result<()> {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // use it now.
+        to_result(unsafe { bindings::clk_prepare_enable(self.0) })
+    }
+
+    /// Clock disable unprepare.
+    pub fn disable_unprepare(&self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // use it now.
+        unsafe { bindings::clk_disable_unprepare(self.0) };
+    }
+
+    /// Clock get rate.
+    pub fn rate(&self) -> usize {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // use it now.
+        unsafe { bindings::clk_get_rate(self.0) }
+    }
+
+    /// Clock set rate.
+    pub fn set_rate(&self, rate: usize) -> Result<()> {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // use it now.
+        to_result(unsafe { bindings::clk_set_rate(self.0, rate) })
+    }
+}
+
+impl Drop for Clk {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
+        // relinquish it now.
+        unsafe { bindings::clk_put(self.0) };
+    }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 496ed32b0911..324b86f127a0 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -40,6 +40,7 @@ 
 pub mod block;
 #[doc(hidden)]
 pub mod build_assert;
+pub mod clk;
 pub mod cred;
 pub mod device;
 pub mod device_id;