mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-13 01:41:59 -04:00
power: Redo hwmon handling
This commit is contained in:
parent
6e3ac42e8e
commit
27493c647d
1 changed files with 97 additions and 16 deletions
113
src/power.rs
113
src/power.rs
|
@ -5,12 +5,14 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
use anyhow::{ensure, Result};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
use anyhow::{bail, ensure, Result};
|
||||
use tokio::fs::{self, File};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tracing::error;
|
||||
|
||||
const POWER1_CAP_PATH: &str = "/sys/class/hwmon/hwmon5/power1_cap";
|
||||
const POWER2_CAP_PATH: &str = "/sys/class/hwmon/hwmon5/power2_cap";
|
||||
use crate::path;
|
||||
|
||||
const GPU_HWMON_PREFIX: &str = "/sys/class/drm/card0/device/hwmon";
|
||||
|
||||
const GPU_PERFORMANCE_LEVEL_PATH: &str =
|
||||
"/sys/class/drm/card0/device/power_dpm_force_performance_level";
|
||||
|
@ -70,23 +72,102 @@ pub async fn set_tdp_limit(limit: i32) -> Result<()> {
|
|||
// Returns false on error or out of range
|
||||
ensure!((3..=15).contains(&limit), "Invalid limit");
|
||||
|
||||
let mut power1file = File::create(POWER1_CAP_PATH).await.inspect_err(|message| {
|
||||
error!("Error opening sysfs power1_cap file for writing TDP limits {message}")
|
||||
})?;
|
||||
let mut dir = fs::read_dir(path(GPU_HWMON_PREFIX)).await?;
|
||||
let base = loop {
|
||||
let base = match dir.next_entry().await? {
|
||||
Some(entry) => entry.path(),
|
||||
None => bail!("hwmon not found"),
|
||||
};
|
||||
if fs::try_exists(base.join("power1_cap")).await? {
|
||||
break base;
|
||||
}
|
||||
};
|
||||
|
||||
let mut power2file = File::create(POWER2_CAP_PATH).await.inspect_err(|message| {
|
||||
error!("Error opening sysfs power2_cap file for wtriting TDP limits {message}")
|
||||
})?;
|
||||
|
||||
// Now write the value * 1,000,000
|
||||
let data = format!("{limit}000000");
|
||||
|
||||
let mut power1file = File::create(base.join("power1_cap"))
|
||||
.await
|
||||
.inspect_err(|message| {
|
||||
error!("Error opening sysfs power1_cap file for writing TDP limits {message}")
|
||||
})?;
|
||||
power1file
|
||||
.write(data.as_bytes())
|
||||
.await
|
||||
.inspect_err(|message| error!("Error writing to power1_cap file: {message}"))?;
|
||||
power2file
|
||||
.write(data.as_bytes())
|
||||
.await
|
||||
.inspect_err(|message| error!("Error writing to power2_cap file: {message}"))?;
|
||||
|
||||
if let Ok(mut power2file) = File::create(base.join("power2_cap")).await {
|
||||
power2file
|
||||
.write(data.as_bytes())
|
||||
.await
|
||||
.inspect_err(|message| error!("Error writing to power2_cap file: {message}"))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::testing;
|
||||
use anyhow::anyhow;
|
||||
use tokio::fs::{create_dir_all, read_to_string, remove_dir, write};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_set_tdp_limit() {
|
||||
let h = testing::start();
|
||||
|
||||
assert_eq!(
|
||||
set_tdp_limit(2).await.unwrap_err().to_string(),
|
||||
anyhow!("Invalid limit").to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
set_tdp_limit(20).await.unwrap_err().to_string(),
|
||||
anyhow!("Invalid limit").to_string()
|
||||
);
|
||||
assert!(set_tdp_limit(10).await.is_err());
|
||||
|
||||
let hwmon = path(GPU_HWMON_PREFIX);
|
||||
create_dir_all(hwmon.as_path())
|
||||
.await
|
||||
.expect("create_dir_all");
|
||||
assert_eq!(
|
||||
set_tdp_limit(10).await.unwrap_err().to_string(),
|
||||
anyhow!("hwmon not found").to_string()
|
||||
);
|
||||
|
||||
let hwmon = hwmon.join("hwmon5");
|
||||
create_dir_all(hwmon.join("power1_cap"))
|
||||
.await
|
||||
.expect("create_dir_all");
|
||||
create_dir_all(hwmon.join("power2_cap"))
|
||||
.await
|
||||
.expect("create_dir_all");
|
||||
assert_eq!(
|
||||
set_tdp_limit(10).await.unwrap_err().to_string(),
|
||||
anyhow!("Is a directory (os error 21)").to_string()
|
||||
);
|
||||
|
||||
remove_dir(hwmon.join("power1_cap"))
|
||||
.await
|
||||
.expect("remove_dir");
|
||||
write(hwmon.join("power1_cap"), "0").await.expect("write");
|
||||
assert!(set_tdp_limit(10).await.is_ok());
|
||||
let power1_cap = read_to_string(hwmon.join("power1_cap"))
|
||||
.await
|
||||
.expect("power1_cap");
|
||||
assert_eq!(power1_cap, "10000000");
|
||||
|
||||
remove_dir(hwmon.join("power2_cap"))
|
||||
.await
|
||||
.expect("remove_dir");
|
||||
write(hwmon.join("power2_cap"), "0").await.expect("write");
|
||||
assert!(set_tdp_limit(15).await.is_ok());
|
||||
let power1_cap = read_to_string(hwmon.join("power1_cap"))
|
||||
.await
|
||||
.expect("power1_cap");
|
||||
assert_eq!(power1_cap, "15000000");
|
||||
let power2_cap = read_to_string(hwmon.join("power2_cap"))
|
||||
.await
|
||||
.expect("power2_cap");
|
||||
assert_eq!(power2_cap, "15000000");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue