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]
|
[performance_profile]
|
||||||
platform_profile_name = "lenovo-wmi-gamezone"
|
platform_profile_name = "lenovo-wmi-gamezone"
|
||||||
suggested_default = "custom"
|
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")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
pub enum TdpLimitingMethod {
|
pub enum TdpLimitingMethod {
|
||||||
GpuHwmon,
|
GpuHwmon,
|
||||||
|
LenovoWmi,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct GpuHwmonTdpLimitManager {}
|
pub(crate) struct GpuHwmonTdpLimitManager {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct LenovoWmiTdpLimitManager {}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub(crate) trait TdpLimitManager: Send + Sync {
|
pub(crate) trait TdpLimitManager: Send + Sync {
|
||||||
async fn get_tdp_limit(&self) -> Result<u32>;
|
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_or(anyhow!("No TDP limit configured"))?;
|
||||||
|
|
||||||
Ok(match config.method {
|
Ok(match config.method {
|
||||||
|
TdpLimitingMethod::LenovoWmi => Box::new(LenovoWmiTdpLimitManager {}),
|
||||||
TdpLimitingMethod::GpuHwmon => Box::new(GpuHwmonTdpLimitManager {}),
|
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> {
|
pub(crate) async fn get_max_charge_level() -> Result<i32> {
|
||||||
let config = platform_config().await?;
|
let config = platform_config().await?;
|
||||||
let config = config
|
let config = config
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue