mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-08 07:30:36 -04:00
power: Add Lenovo WMI-based TDP limiting
This commit is contained in:
parent
a3125be955
commit
6086e23cc8
2 changed files with 85 additions and 0 deletions
|
@ -1,3 +1,6 @@
|
|||
[performance_profile]
|
||||
platform_profile_name = "lenovo-wmi-gamezone"
|
||||
suggested_default = "custom"
|
||||
|
||||
[tdp_limit]
|
||||
method = "lenovo_wmi"
|
||||
|
|
82
src/power.rs
82
src/power.rs
|
@ -93,11 +93,15 @@ pub enum CPUScalingGovernor {
|
|||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum TdpLimitingMethod {
|
||||
GpuHwmon,
|
||||
LenovoWmi,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct GpuHwmonTdpLimitManager {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct LenovoWmiTdpLimitManager {}
|
||||
|
||||
#[async_trait]
|
||||
pub(crate) trait TdpLimitManager: Send + Sync {
|
||||
async fn get_tdp_limit(&self) -> Result<u32>;
|
||||
|
@ -113,6 +117,7 @@ pub(crate) async fn tdp_limit_manager() -> Result<Box<dyn TdpLimitManager>> {
|
|||
.ok_or(anyhow!("No TDP limit configured"))?;
|
||||
|
||||
Ok(match config.method {
|
||||
TdpLimitingMethod::LenovoWmi => Box::new(LenovoWmiTdpLimitManager {}),
|
||||
TdpLimitingMethod::GpuHwmon => Box::new(GpuHwmonTdpLimitManager {}),
|
||||
})
|
||||
}
|
||||
|
@ -451,6 +456,83 @@ impl TdpLimitManager for GpuHwmonTdpLimitManager {
|
|||
}
|
||||
}
|
||||
|
||||
impl LenovoWmiTdpLimitManager {
|
||||
const PREFIX: &str = "/sys/class/firmware-attributes/lenovo-wmi-other-0/attributes";
|
||||
const SPL_SUFFIX: &str = "ppt_pl1_spl";
|
||||
const SPPT_SUFFIX: &str = "ppt_pl2_sppt";
|
||||
const FPPT_SUFFIX: &str = "ppt_pl3_fppt";
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TdpLimitManager for LenovoWmiTdpLimitManager {
|
||||
async fn get_tdp_limit(&self) -> Result<u32> {
|
||||
let config = platform_config().await?;
|
||||
if let Some(config) = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.performance_profile.as_ref())
|
||||
{
|
||||
ensure!(
|
||||
get_platform_profile(&config.platform_profile_name).await? == "custom",
|
||||
"TDP limiting not active"
|
||||
);
|
||||
}
|
||||
let base = path(Self::PREFIX);
|
||||
|
||||
fs::read_to_string(base.join(Self::SPL_SUFFIX).join("current_value"))
|
||||
.await
|
||||
.map_err(|message| anyhow!("Error reading sysfs: {message}"))?
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("Error parsing value: {e}"))
|
||||
}
|
||||
|
||||
async fn set_tdp_limit(&self, limit: u32) -> Result<()> {
|
||||
ensure!(
|
||||
self.get_tdp_limit_range().await?.contains(&limit),
|
||||
"Invalid limit"
|
||||
);
|
||||
|
||||
let limit = limit.to_string();
|
||||
let base = path(Self::PREFIX);
|
||||
write_synced(
|
||||
base.join(Self::SPL_SUFFIX).join("current_value"),
|
||||
limit.as_bytes(),
|
||||
)
|
||||
.await
|
||||
.inspect_err(|message| error!("Error writing to sysfs file: {message}"))?;
|
||||
write_synced(
|
||||
base.join(Self::SPPT_SUFFIX).join("current_value"),
|
||||
limit.as_bytes(),
|
||||
)
|
||||
.await
|
||||
.inspect_err(|message| error!("Error writing to sysfs file: {message}"))?;
|
||||
write_synced(
|
||||
base.join(Self::FPPT_SUFFIX).join("current_value"),
|
||||
limit.as_bytes(),
|
||||
)
|
||||
.await
|
||||
.inspect_err(|message| error!("Error writing to sysfs file: {message}"))
|
||||
}
|
||||
|
||||
async fn get_tdp_limit_range(&self) -> Result<RangeInclusive<u32>> {
|
||||
let base = path(Self::PREFIX).join(Self::SPL_SUFFIX);
|
||||
|
||||
let min: u32 = fs::read_to_string(base.join("min_value"))
|
||||
.await
|
||||
.map_err(|message| anyhow!("Error reading sysfs: {message}"))?
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("Error parsing value: {e}"))?;
|
||||
let max: u32 = fs::read_to_string(base.join("max_value"))
|
||||
.await
|
||||
.map_err(|message| anyhow!("Error reading sysfs: {message}"))?
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| anyhow!("Error parsing value: {e}"))?;
|
||||
Ok(min..=max)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_max_charge_level() -> Result<i32> {
|
||||
let config = platform_config().await?;
|
||||
let config = config
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue