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
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use anyhow::{ensure, Result};
|
use anyhow::{bail, ensure, Result};
|
||||||
use tokio::{fs::File, io::AsyncWriteExt};
|
use tokio::fs::{self, File};
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
const POWER1_CAP_PATH: &str = "/sys/class/hwmon/hwmon5/power1_cap";
|
use crate::path;
|
||||||
const POWER2_CAP_PATH: &str = "/sys/class/hwmon/hwmon5/power2_cap";
|
|
||||||
|
const GPU_HWMON_PREFIX: &str = "/sys/class/drm/card0/device/hwmon";
|
||||||
|
|
||||||
const GPU_PERFORMANCE_LEVEL_PATH: &str =
|
const GPU_PERFORMANCE_LEVEL_PATH: &str =
|
||||||
"/sys/class/drm/card0/device/power_dpm_force_performance_level";
|
"/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
|
// Returns false on error or out of range
|
||||||
ensure!((3..=15).contains(&limit), "Invalid limit");
|
ensure!((3..=15).contains(&limit), "Invalid limit");
|
||||||
|
|
||||||
let mut power1file = File::create(POWER1_CAP_PATH).await.inspect_err(|message| {
|
let mut dir = fs::read_dir(path(GPU_HWMON_PREFIX)).await?;
|
||||||
error!("Error opening sysfs power1_cap file for writing TDP limits {message}")
|
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 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
|
power1file
|
||||||
.write(data.as_bytes())
|
.write(data.as_bytes())
|
||||||
.await
|
.await
|
||||||
.inspect_err(|message| error!("Error writing to power1_cap file: {message}"))?;
|
.inspect_err(|message| error!("Error writing to power1_cap file: {message}"))?;
|
||||||
power2file
|
|
||||||
.write(data.as_bytes())
|
if let Ok(mut power2file) = File::create(base.join("power2_cap")).await {
|
||||||
.await
|
power2file
|
||||||
.inspect_err(|message| error!("Error writing to power2_cap file: {message}"))?;
|
.write(data.as_bytes())
|
||||||
|
.await
|
||||||
|
.inspect_err(|message| error!("Error writing to power2_cap file: {message}"))?;
|
||||||
|
}
|
||||||
Ok(())
|
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