Skip to content

Commit 8f83549

Browse files
committed
rust: opp: Add initial abstractions for OPP framework
Introduce initial Rust abstractions for the Operating Performance Points (OPP) framework. This includes bindings for `struct dev_pm_opp` and `struct dev_pm_opp_data`, laying the groundwork for further OPP integration. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
1 parent 3accb57 commit 8f83549

File tree

4 files changed

+303
-0
lines changed

4 files changed

+303
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18165,6 +18165,7 @@ F: Documentation/devicetree/bindings/opp/
1816518165
F: Documentation/power/opp.rst
1816618166
F: drivers/opp/
1816718167
F: include/linux/pm_opp.h
18168+
F: rust/kernel/opp.rs
1816818169

1816918170
OPL4 DRIVER
1817018171
M: Clemens Ladisch <clemens@ladisch.de>

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/phy.h>
3131
#include <linux/pid_namespace.h>
3232
#include <linux/platform_device.h>
33+
#include <linux/pm_opp.h>
3334
#include <linux/poll.h>
3435
#include <linux/property.h>
3536
#include <linux/refcount.h>

rust/kernel/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ pub mod miscdevice;
6767
#[cfg(CONFIG_NET)]
6868
pub mod net;
6969
pub mod of;
70+
#[cfg(CONFIG_PM_OPP)]
71+
pub mod opp;
7072
pub mod page;
7173
#[cfg(CONFIG_PCI)]
7274
pub mod pci;

rust/kernel/opp.rs

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Operating performance points.
4+
//!
5+
//! This module provides rust abstractions for interacting with the OPP subsystem.
6+
//!
7+
//! C header: [`include/linux/pm_opp.h`](srctree/include/linux/pm_opp.h)
8+
//!
9+
//! Reference: <https://docs.kernel.org/power/opp.html>
10+
11+
use crate::{
12+
clk::Hertz,
13+
device::Device,
14+
error::{code::*, to_result, Result},
15+
ffi::c_ulong,
16+
types::{ARef, AlwaysRefCounted, Opaque},
17+
};
18+
19+
use core::ptr;
20+
21+
/// The voltage unit.
22+
///
23+
/// Represents voltage in microvolts, wrapping a [`c_ulong`] value.
24+
///
25+
/// ## Examples
26+
///
27+
/// ```
28+
/// use kernel::opp::MicroVolt;
29+
///
30+
/// let raw = 90500;
31+
/// let volt = MicroVolt(raw);
32+
///
33+
/// assert_eq!(usize::from(volt), raw);
34+
/// assert_eq!(volt, MicroVolt(raw));
35+
/// ```
36+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
37+
pub struct MicroVolt(pub c_ulong);
38+
39+
impl From<MicroVolt> for c_ulong {
40+
#[inline]
41+
fn from(volt: MicroVolt) -> Self {
42+
volt.0
43+
}
44+
}
45+
46+
/// The power unit.
47+
///
48+
/// Represents power in microwatts, wrapping a [`c_ulong`] value.
49+
///
50+
/// ## Examples
51+
///
52+
/// ```
53+
/// use kernel::opp::MicroWatt;
54+
///
55+
/// let raw = 1000000;
56+
/// let power = MicroWatt(raw);
57+
///
58+
/// assert_eq!(usize::from(power), raw);
59+
/// assert_eq!(power, MicroWatt(raw));
60+
/// ```
61+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
62+
pub struct MicroWatt(pub c_ulong);
63+
64+
impl From<MicroWatt> for c_ulong {
65+
#[inline]
66+
fn from(power: MicroWatt) -> Self {
67+
power.0
68+
}
69+
}
70+
71+
/// Handle for a dynamically created [`OPP`].
72+
///
73+
/// The associated [`OPP`] is automatically removed when the [`Token`] is dropped.
74+
///
75+
/// ## Examples
76+
///
77+
/// The following example demonstrates how to create an [`OPP`] dynamically.
78+
///
79+
/// ```
80+
/// use kernel::clk::Hertz;
81+
/// use kernel::device::Device;
82+
/// use kernel::error::Result;
83+
/// use kernel::opp::{Data, MicroVolt, Token};
84+
/// use kernel::types::ARef;
85+
///
86+
/// fn create_opp(dev: &ARef<Device>, freq: Hertz, volt: MicroVolt, level: u32) -> Result<Token> {
87+
/// let data = Data::new(freq, volt, level, false);
88+
///
89+
/// // OPP is removed once token goes out of scope.
90+
/// data.add_opp(dev)
91+
/// }
92+
/// ```
93+
pub struct Token {
94+
dev: ARef<Device>,
95+
freq: Hertz,
96+
}
97+
98+
impl Token {
99+
/// Dynamically adds an [`OPP`] and returns a [`Token`] that removes it on drop.
100+
fn new(dev: &ARef<Device>, mut data: Data) -> Result<Self> {
101+
// SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
102+
// requirements.
103+
to_result(unsafe { bindings::dev_pm_opp_add_dynamic(dev.as_raw(), &mut data.0) })?;
104+
Ok(Self {
105+
dev: dev.clone(),
106+
freq: data.freq(),
107+
})
108+
}
109+
}
110+
111+
impl Drop for Token {
112+
fn drop(&mut self) {
113+
// SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
114+
// requirements.
115+
unsafe { bindings::dev_pm_opp_remove(self.dev.as_raw(), self.freq.into()) };
116+
}
117+
}
118+
119+
/// OPP data.
120+
///
121+
/// Rust abstraction for the C `struct dev_pm_opp_data`, used to define operating performance
122+
/// points (OPPs) dynamically.
123+
///
124+
/// ## Examples
125+
///
126+
/// The following example demonstrates how to create an [`OPP`] with [`Data`].
127+
///
128+
/// ```
129+
/// use kernel::clk::Hertz;
130+
/// use kernel::device::Device;
131+
/// use kernel::error::Result;
132+
/// use kernel::opp::{Data, MicroVolt, Token};
133+
/// use kernel::types::ARef;
134+
///
135+
/// fn create_opp(dev: &ARef<Device>, freq: Hertz, volt: MicroVolt, level: u32) -> Result<Token> {
136+
/// let data = Data::new(freq, volt, level, false);
137+
///
138+
/// // OPP is removed once token goes out of scope.
139+
/// data.add_opp(dev)
140+
/// }
141+
/// ```
142+
#[repr(transparent)]
143+
pub struct Data(bindings::dev_pm_opp_data);
144+
145+
impl Data {
146+
/// Creates a new instance of [`Data`].
147+
///
148+
/// This can be used to define a dynamic OPP to be added to a device.
149+
pub fn new(freq: Hertz, volt: MicroVolt, level: u32, turbo: bool) -> Self {
150+
Self(bindings::dev_pm_opp_data {
151+
turbo,
152+
freq: freq.into(),
153+
u_volt: volt.into(),
154+
level,
155+
})
156+
}
157+
158+
/// Adds an [`OPP`] dynamically.
159+
///
160+
/// Returns a [`Token`] that ensures the OPP is automatically removed
161+
/// when it goes out of scope.
162+
#[inline]
163+
pub fn add_opp(self, dev: &ARef<Device>) -> Result<Token> {
164+
Token::new(dev, self)
165+
}
166+
167+
/// Returns the frequency associated with this OPP data.
168+
#[inline]
169+
fn freq(&self) -> Hertz {
170+
Hertz(self.0.freq)
171+
}
172+
}
173+
174+
/// A reference-counted Operating performance point (OPP).
175+
///
176+
/// Rust abstraction for the C `struct dev_pm_opp`.
177+
///
178+
/// # Invariants
179+
///
180+
/// The pointer stored in `Self` is non-null and valid for the lifetime of the [`OPP`].
181+
///
182+
/// Instances of this type are reference-counted. The reference count is incremented by the
183+
/// `dev_pm_opp_get` function and decremented by `dev_pm_opp_put`. The Rust type `ARef<OPP>`
184+
/// represents a pointer that owns a reference count on the [`OPP`].
185+
///
186+
/// A reference to the [`OPP`], &[`OPP`], isn't refcounted by the Rust code.
187+
#[repr(transparent)]
188+
pub struct OPP(Opaque<bindings::dev_pm_opp>);
189+
190+
/// SAFETY: It is okay to send the ownership of [`OPP`] across thread boundaries.
191+
unsafe impl Send for OPP {}
192+
193+
/// SAFETY: It is okay to access [`OPP`] through shared references from other threads because we're
194+
/// either accessing properties that don't change or that are properly synchronised by C code.
195+
unsafe impl Sync for OPP {}
196+
197+
/// SAFETY: The type invariants guarantee that [`OPP`] is always refcounted.
198+
unsafe impl AlwaysRefCounted for OPP {
199+
fn inc_ref(&self) {
200+
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
201+
unsafe { bindings::dev_pm_opp_get(self.0.get()) };
202+
}
203+
204+
unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
205+
// SAFETY: The safety requirements guarantee that the refcount is nonzero.
206+
unsafe { bindings::dev_pm_opp_put(obj.cast().as_ptr()) }
207+
}
208+
}
209+
210+
impl OPP {
211+
/// Creates an owned reference to a [`OPP`] from a valid pointer.
212+
///
213+
/// The refcount is incremented by the C code and will be decremented by `dec_ref` when the
214+
/// [`ARef`] object is dropped.
215+
///
216+
/// # Safety
217+
///
218+
/// The caller must ensure that `ptr` is valid and the refcount of the [`OPP`] is incremented.
219+
/// The caller must also ensure that it doesn't explicitly drop the refcount of the [`OPP`], as
220+
/// the returned [`ARef`] object takes over the refcount increment on the underlying object and
221+
/// the same will be dropped along with it.
222+
pub unsafe fn from_raw_opp_owned(ptr: *mut bindings::dev_pm_opp) -> Result<ARef<Self>> {
223+
let ptr = ptr::NonNull::new(ptr).ok_or(ENODEV)?;
224+
225+
// SAFETY: The safety requirements guarantee the validity of the pointer.
226+
//
227+
// INVARIANT: The reference-count is decremented when [`OPP`] goes out of scope.
228+
Ok(unsafe { ARef::from_raw(ptr.cast()) })
229+
}
230+
231+
/// Creates a reference to a [`OPP`] from a valid pointer.
232+
///
233+
/// The refcount is not updated by the Rust API unless the returned reference is converted to
234+
/// an [`ARef`] object.
235+
///
236+
/// # Safety
237+
///
238+
/// The caller must ensure that `ptr` is valid and remains valid for the duration of `'a`.
239+
#[inline]
240+
pub unsafe fn from_raw_opp<'a>(ptr: *mut bindings::dev_pm_opp) -> Result<&'a Self> {
241+
// SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the
242+
// duration of 'a. The cast is okay because [`OPP`] is `repr(transparent)`.
243+
Ok(unsafe { &*ptr.cast() })
244+
}
245+
246+
#[inline]
247+
fn as_raw(&self) -> *mut bindings::dev_pm_opp {
248+
self.0.get()
249+
}
250+
251+
/// Returns the frequency of an [`OPP`].
252+
pub fn freq(&self, index: Option<u32>) -> Hertz {
253+
let index = index.unwrap_or(0);
254+
255+
// SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
256+
// use it.
257+
Hertz(unsafe { bindings::dev_pm_opp_get_freq_indexed(self.as_raw(), index) })
258+
}
259+
260+
/// Returns the voltage of an [`OPP`].
261+
#[inline]
262+
pub fn voltage(&self) -> MicroVolt {
263+
// SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
264+
// use it.
265+
MicroVolt(unsafe { bindings::dev_pm_opp_get_voltage(self.as_raw()) })
266+
}
267+
268+
/// Returns the level of an [`OPP`].
269+
#[inline]
270+
pub fn level(&self) -> u32 {
271+
// SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
272+
// use it.
273+
unsafe { bindings::dev_pm_opp_get_level(self.as_raw()) }
274+
}
275+
276+
/// Returns the power of an [`OPP`].
277+
#[inline]
278+
pub fn power(&self) -> MicroWatt {
279+
// SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
280+
// use it.
281+
MicroWatt(unsafe { bindings::dev_pm_opp_get_power(self.as_raw()) })
282+
}
283+
284+
/// Returns the required pstate of an [`OPP`].
285+
#[inline]
286+
pub fn required_pstate(&self, index: u32) -> u32 {
287+
// SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
288+
// use it.
289+
unsafe { bindings::dev_pm_opp_get_required_pstate(self.as_raw(), index) }
290+
}
291+
292+
/// Returns true if the [`OPP`] is turbo.
293+
#[inline]
294+
pub fn is_turbo(&self) -> bool {
295+
// SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
296+
// use it.
297+
unsafe { bindings::dev_pm_opp_is_turbo(self.as_raw()) }
298+
}
299+
}

0 commit comments

Comments
 (0)