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