Skip to content

Commit 7aa46b0

Browse files
authored
Merge pull request #461 from wedsonaf/power
rust: add a power management module.
2 parents a7653d2 + a287816 commit 7aa46b0

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

rust/helpers.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,12 @@ int rust_helper_security_binder_transfer_file(struct task_struct *from,
212212
}
213213
EXPORT_SYMBOL_GPL(rust_helper_security_binder_transfer_file);
214214

215+
void *rust_helper_dev_get_drvdata(struct device *dev)
216+
{
217+
return dev_get_drvdata(dev);
218+
}
219+
EXPORT_SYMBOL_GPL(rust_helper_dev_get_drvdata);
220+
215221
/* We use bindgen's --size_t-is-usize option to bind the C size_t type
216222
* as the Rust usize type, so we can use it in contexts where Rust
217223
* expects a usize like slice (array) indices. usize is defined to be

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub mod file;
4848
pub mod file_operations;
4949
pub mod miscdev;
5050
pub mod pages;
51+
pub mod power;
5152
pub mod security;
5253
pub mod str;
5354
pub mod task;

rust/kernel/power.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Power management interfaces.
4+
//!
5+
//! C header: [`include/linux/pm.h`](../../../../include/linux/pm.h)
6+
7+
use crate::{bindings, c_types, from_kernel_result, sync::Ref, types::PointerWrapper, Result};
8+
use core::{marker::PhantomData, ops::Deref};
9+
10+
extern "C" {
11+
#[allow(improper_ctypes)]
12+
fn rust_helper_dev_get_drvdata(dev: *mut bindings::device) -> *mut c_types::c_void;
13+
}
14+
15+
/// Corresponds to the kernel's `struct dev_pm_ops`.
16+
///
17+
/// It is meant to be implemented by drivers that support power-management operations.
18+
pub trait Operations: Sync + Send + Sized {
19+
/// The type of the context data stored by the driver on each device.
20+
type Data: PointerWrapper + Sync + Send = Ref<Self>;
21+
22+
/// Called before the system goes into a sleep state.
23+
fn suspend(_data: &<<Self::Data as PointerWrapper>::Borrowed as Deref>::Target) -> Result {
24+
Ok(())
25+
}
26+
27+
/// Called after the system comes back from a sleep state.
28+
fn resume(_data: &<<Self::Data as PointerWrapper>::Borrowed as Deref>::Target) -> Result {
29+
Ok(())
30+
}
31+
32+
/// Called before creating a hibernation image.
33+
fn freeze(_data: &<<Self::Data as PointerWrapper>::Borrowed as Deref>::Target) -> Result {
34+
Ok(())
35+
}
36+
37+
/// Called after the system is restored from a hibernation image.
38+
fn restore(_data: &<<Self::Data as PointerWrapper>::Borrowed as Deref>::Target) -> Result {
39+
Ok(())
40+
}
41+
}
42+
43+
macro_rules! pm_callback {
44+
($callback:ident, $method:ident) => {
45+
unsafe extern "C" fn $callback<T: Operations>(
46+
dev: *mut bindings::device,
47+
) -> c_types::c_int {
48+
from_kernel_result! {
49+
// SAFETY: `dev` is valid as it was passed in by the C portion.
50+
let ptr = unsafe { rust_helper_dev_get_drvdata(dev) };
51+
// SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came
52+
// from a previous call to `T::Data::into_pointer`.
53+
let data = unsafe { T::Data::borrow(ptr) };
54+
T::$method(data.deref())?;
55+
Ok(0)
56+
}
57+
}
58+
};
59+
}
60+
61+
pm_callback!(suspend_callback, suspend);
62+
pm_callback!(resume_callback, resume);
63+
pm_callback!(freeze_callback, freeze);
64+
pm_callback!(restore_callback, restore);
65+
66+
pub(crate) struct OpsTable<T: Operations>(PhantomData<*const T>);
67+
68+
impl<T: Operations> OpsTable<T> {
69+
const VTABLE: bindings::dev_pm_ops = bindings::dev_pm_ops {
70+
prepare: None,
71+
complete: None,
72+
suspend: Some(suspend_callback::<T>),
73+
resume: Some(resume_callback::<T>),
74+
freeze: Some(freeze_callback::<T>),
75+
thaw: None,
76+
poweroff: None,
77+
restore: Some(restore_callback::<T>),
78+
suspend_late: None,
79+
resume_early: None,
80+
freeze_late: None,
81+
thaw_early: None,
82+
poweroff_late: None,
83+
restore_early: None,
84+
suspend_noirq: None,
85+
resume_noirq: None,
86+
freeze_noirq: None,
87+
thaw_noirq: None,
88+
poweroff_noirq: None,
89+
restore_noirq: None,
90+
runtime_suspend: None,
91+
runtime_resume: None,
92+
runtime_idle: None,
93+
};
94+
95+
/// Builds an instance of `struct dev_pm_ops`.
96+
///
97+
/// # Safety
98+
///
99+
/// The caller must ensure that `dev_get_drvdata` will result in a value returned by
100+
/// [`T::Data::into_pointer`].
101+
pub(crate) const unsafe fn build() -> &'static bindings::dev_pm_ops {
102+
&Self::VTABLE
103+
}
104+
}
105+
106+
/// Implements the [`Operations`] trait as no-ops.
107+
///
108+
/// This is useful when one doesn't want to provide the implementation of any power-manager related
109+
/// operation.
110+
pub struct NoOperations<T: PointerWrapper>(PhantomData<T>);
111+
112+
impl<T: PointerWrapper + Send + Sync> Operations for NoOperations<T> {
113+
type Data = T;
114+
}
115+
116+
// SAFETY: `NoOperation` provides no functionality, it is safe to send a reference to it to
117+
// different threads.
118+
unsafe impl<T: PointerWrapper> Sync for NoOperations<T> {}
119+
120+
// SAFETY: `NoOperation` provides no functionality, it is safe to send it to different threads.
121+
unsafe impl<T: PointerWrapper> Send for NoOperations<T> {}

0 commit comments

Comments
 (0)