Only apply manual power_dpm_force_performance_level when actually necessary #87
This commit is contained in:
parent
69f6b800be
commit
27afa31520
4 changed files with 234 additions and 95 deletions
|
@ -6,6 +6,7 @@ use crate::settings::{OnResume, OnSet, SettingError};
|
|||
use crate::settings::{TCpus, TCpu};
|
||||
use crate::persist::CpuJson;
|
||||
use super::oc_limits::{OverclockLimits, CpusLimits, CpuLimits};
|
||||
use super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT;
|
||||
|
||||
const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present";
|
||||
const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control";
|
||||
|
@ -94,6 +95,7 @@ impl Cpus {
|
|||
}
|
||||
|
||||
pub fn system_default() -> Self {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.reset();
|
||||
let (oc_limits, is_default) = OverclockLimits::load_or_default();
|
||||
let oc_limits = oc_limits.cpus;
|
||||
let driver = if is_default { crate::persist::DriverJson::SteamDeck } else { crate::persist::DriverJson::SteamDeckAdvance };
|
||||
|
@ -123,6 +125,7 @@ impl Cpus {
|
|||
|
||||
#[inline]
|
||||
pub fn from_json(mut other: Vec<CpuJson>, version: u64) -> Self {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.reset();
|
||||
let (oc_limits, is_default) = OverclockLimits::load_or_default();
|
||||
let oc_limits = oc_limits.cpus;
|
||||
let driver = if is_default { crate::persist::DriverJson::SteamDeck } else { crate::persist::DriverJson::SteamDeckAdvance };
|
||||
|
@ -208,7 +211,6 @@ pub struct Cpu {
|
|||
}
|
||||
|
||||
const CPU_CLOCK_LIMITS_PATH: &str = "/sys/class/drm/card0/device/pp_od_clk_voltage";
|
||||
const CPU_FORCE_LIMITS_PATH: &str = "/sys/class/drm/card0/device/power_dpm_force_performance_level";
|
||||
|
||||
impl Cpu {
|
||||
#[inline]
|
||||
|
@ -237,21 +239,11 @@ impl Cpu {
|
|||
let mut errors = Vec::new();
|
||||
|
||||
// set clock limits
|
||||
log::debug!("Setting {} to manual", CPU_FORCE_LIMITS_PATH);
|
||||
let mode: String = usdpl_back::api::files::read_single(CPU_FORCE_LIMITS_PATH.to_owned()).unwrap();
|
||||
if mode != "manual" {
|
||||
// set manual control
|
||||
usdpl_back::api::files::write_single(CPU_FORCE_LIMITS_PATH, "manual").map_err(|e| {
|
||||
vec![SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `manual` to `{}`: {}",
|
||||
CPU_FORCE_LIMITS_PATH, e
|
||||
),
|
||||
setting: crate::settings::SettingVariant::Cpu,
|
||||
}]
|
||||
})?;
|
||||
}
|
||||
//log::debug!("Setting {} to manual", CPU_FORCE_LIMITS_PATH);
|
||||
//let mode: String = usdpl_back::api::files::read_single(CPU_FORCE_LIMITS_PATH.to_owned()).unwrap();
|
||||
if let Some(clock_limits) = &self.clock_limits {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_cpu(true, self.index);
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level()?;
|
||||
log::debug!("Setting CPU {} (min, max) clockspeed to ({}, {})", self.index, clock_limits.min, clock_limits.max);
|
||||
self.state.clock_limits_set = true;
|
||||
// max clock
|
||||
|
@ -277,8 +269,19 @@ impl Cpu {
|
|||
setting: crate::settings::SettingVariant::Cpu,
|
||||
},
|
||||
).unwrap_or_else(|e| errors.push(e));
|
||||
} else if self.state.clock_limits_set || (self.state.is_resuming && !self.limits.skip_resume_reclock) {
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, "c\n")
|
||||
.unwrap_or_else(|e| {
|
||||
errors.push(SettingError {
|
||||
msg: format!("Failed to write `c` to `{}`: {}", CPU_CLOCK_LIMITS_PATH, e),
|
||||
setting: crate::settings::SettingVariant::Cpu,
|
||||
});
|
||||
});
|
||||
} else if self.state.clock_limits_set ||
|
||||
(self.state.is_resuming && !self.limits.skip_resume_reclock)
|
||||
|| POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
|
||||
self.state.clock_limits_set = false;
|
||||
if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level()?;
|
||||
// disable manual clock limits
|
||||
log::debug!("Setting CPU {} to default clockspeed", self.index);
|
||||
// max clock
|
||||
|
@ -303,8 +306,6 @@ impl Cpu {
|
|||
setting: crate::settings::SettingVariant::Cpu,
|
||||
},
|
||||
).unwrap_or_else(|e| errors.push(e));
|
||||
}
|
||||
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, "c\n")
|
||||
.unwrap_or_else(|e| {
|
||||
errors.push(SettingError {
|
||||
|
@ -312,6 +313,10 @@ impl Cpu {
|
|||
setting: crate::settings::SettingVariant::Cpu,
|
||||
});
|
||||
});
|
||||
}
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_cpu(false, self.index);
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
}
|
||||
// commit changes (if no errors have already occured)
|
||||
if errors.is_empty() {
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, "c\n").map_err(|e| {
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::settings::{OnResume, OnSet, SettingError};
|
|||
use crate::settings::TGpu;
|
||||
use crate::persist::GpuJson;
|
||||
use super::oc_limits::{OverclockLimits, GpuLimits};
|
||||
use super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT;
|
||||
|
||||
const SLOW_PPT: u8 = 1;
|
||||
const FAST_PPT: u8 = 2;
|
||||
|
@ -23,7 +24,6 @@ pub struct Gpu {
|
|||
|
||||
// same as CPU
|
||||
const GPU_CLOCK_LIMITS_PATH: &str = "/sys/class/drm/card0/device/pp_od_clk_voltage";
|
||||
const GPU_FORCE_LIMITS_PATH: &str = "/sys/class/drm/card0/device/power_dpm_force_performance_level";
|
||||
const GPU_MEMORY_DOWNCLOCK_PATH: &str = "/sys/class/drm/card0/device/pp_dpm_fclk";
|
||||
|
||||
impl Gpu {
|
||||
|
@ -56,6 +56,8 @@ impl Gpu {
|
|||
fn set_clocks(&mut self) -> Result<(), Vec<SettingError>> {
|
||||
let mut errors = Vec::new();
|
||||
if let Some(clock_limits) = &self.clock_limits {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(true);
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level()?;
|
||||
// set clock limits
|
||||
self.state.clock_limits_set = true;
|
||||
// max clock
|
||||
|
@ -80,8 +82,18 @@ impl Gpu {
|
|||
setting: crate::settings::SettingVariant::Gpu,
|
||||
},
|
||||
).unwrap_or_else(|e| errors.push(e));
|
||||
} else if self.state.clock_limits_set || (self.state.is_resuming && !self.limits.skip_resume_reclock) {
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").unwrap_or_else(|e| {
|
||||
errors.push(SettingError {
|
||||
msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e),
|
||||
setting: crate::settings::SettingVariant::Gpu,
|
||||
})
|
||||
});
|
||||
} else if self.state.clock_limits_set ||
|
||||
(self.state.is_resuming && !self.limits.skip_resume_reclock)
|
||||
|| POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
|
||||
self.state.clock_limits_set = false;
|
||||
if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level()?;
|
||||
// disable manual clock limits
|
||||
// max clock
|
||||
let payload_max = format!("s 1 {}\n", self.limits.clock_max.max);
|
||||
|
@ -105,6 +117,15 @@ impl Gpu {
|
|||
setting: crate::settings::SettingVariant::Gpu,
|
||||
},
|
||||
).unwrap_or_else(|e| errors.push(e));
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").unwrap_or_else(|e| {
|
||||
errors.push(SettingError {
|
||||
msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e),
|
||||
setting: crate::settings::SettingVariant::Gpu,
|
||||
})
|
||||
});
|
||||
}
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(self.slow_memory);
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
}
|
||||
if errors.is_empty() {
|
||||
Ok(())
|
||||
|
@ -115,21 +136,10 @@ impl Gpu {
|
|||
|
||||
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
|
||||
let mut errors = Vec::new();
|
||||
// settings using force_performance_level
|
||||
let mode: String = usdpl_back::api::files::read_single(GPU_FORCE_LIMITS_PATH.to_owned()).unwrap();
|
||||
if mode != "manual" {
|
||||
// set manual control
|
||||
usdpl_back::api::files::write_single(GPU_FORCE_LIMITS_PATH, "manual").map_err(|e| {
|
||||
vec![SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `manual` to `{}`: {}",
|
||||
GPU_FORCE_LIMITS_PATH, e
|
||||
),
|
||||
setting: crate::settings::SettingVariant::Gpu,
|
||||
}]
|
||||
})?;
|
||||
}
|
||||
// enable/disable downclock of GPU memory (to 400Mhz?)
|
||||
if self.slow_memory {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(true);
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
usdpl_back::api::files::write_single(GPU_MEMORY_DOWNCLOCK_PATH, self.slow_memory as u8)
|
||||
.unwrap_or_else(|e| {
|
||||
errors.push(SettingError {
|
||||
|
@ -137,16 +147,31 @@ impl Gpu {
|
|||
setting: crate::settings::SettingVariant::Gpu,
|
||||
});
|
||||
});
|
||||
} else if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
|
||||
usdpl_back::api::files::write_single(GPU_MEMORY_DOWNCLOCK_PATH, self.slow_memory as u8)
|
||||
.unwrap_or_else(|e| {
|
||||
errors.push(SettingError {
|
||||
msg: format!("Failed to write to `{}`: {}", GPU_MEMORY_DOWNCLOCK_PATH, e),
|
||||
setting: crate::settings::SettingVariant::Gpu,
|
||||
});
|
||||
});
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(self.clock_limits.is_some());
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level().unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
}
|
||||
self.set_clocks()
|
||||
.unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
// commit changes (if no errors have already occured)
|
||||
if errors.is_empty() {
|
||||
if self.slow_memory || self.clock_limits.is_some() {
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").map_err(|e| {
|
||||
vec![SettingError {
|
||||
msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e),
|
||||
setting: crate::settings::SettingVariant::Gpu,
|
||||
}]
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ mod battery;
|
|||
mod cpu;
|
||||
mod gpu;
|
||||
mod oc_limits;
|
||||
mod power_dpm_force;
|
||||
mod util;
|
||||
|
||||
pub use battery::Battery;
|
||||
pub use cpu::{Cpu, Cpus};
|
||||
pub use gpu::Gpu;
|
||||
pub(self) use power_dpm_force::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT;
|
||||
|
||||
pub use util::flash_led;
|
||||
|
|
107
backend/src/settings/steam_deck/power_dpm_force.rs
Normal file
107
backend/src/settings/steam_deck/power_dpm_force.rs
Normal file
|
@ -0,0 +1,107 @@
|
|||
//! Be very careful when using this.
|
||||
//! This influences Steam Deck CPU and GPU driver behaviour,
|
||||
//! so familiarize yourself with those before messing with this functionality.
|
||||
//! Refer to https://docs.kernel.org/5.19/gpu/amdgpu/thermal.html for kernel stuff.
|
||||
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
use crate::settings::SettingError;
|
||||
|
||||
const DEFAULT_BITS: u64 = 0;
|
||||
|
||||
/// Global usage tracker for the sysfs file by the same name
|
||||
pub static POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT: PDFPLManager = PDFPLManager(AtomicU64::new(DEFAULT_BITS));
|
||||
|
||||
pub struct PDFPLManager(AtomicU64);
|
||||
|
||||
//const OVERRIDE_BIT: usize = 0;
|
||||
const GPU_BIT: usize = 1;
|
||||
const CPU_BITS_START: usize = 2;
|
||||
|
||||
const DPM_FORCE_LIMITS_PATH: &str = "/sys/class/drm/card0/device/power_dpm_force_performance_level";
|
||||
|
||||
impl PDFPLManager {
|
||||
#[inline]
|
||||
fn get(&self) -> u64 {
|
||||
self.0.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set(&self, val: u64) {
|
||||
self.0.store(val, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_bit(&self, val: bool, bit: usize) {
|
||||
let bitmask: u64 = !(1 << bit);
|
||||
let val: u64 = (val as u64) << bit;
|
||||
let new_val = (self.get() & bitmask) | val;
|
||||
self.set(new_val);
|
||||
}
|
||||
|
||||
pub fn set_gpu(&self, manual: bool) {
|
||||
self.set_bit(manual, GPU_BIT);
|
||||
}
|
||||
|
||||
pub fn set_cpu(&self, manual: bool, cpu: usize) {
|
||||
self.set_bit(manual, CPU_BITS_START + cpu);
|
||||
}
|
||||
|
||||
pub fn needs_manual(&self) -> bool {
|
||||
self.get() != 0
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
self.set(DEFAULT_BITS);
|
||||
}
|
||||
|
||||
pub fn enforce_level(&self) -> Result<(), Vec<SettingError>> {
|
||||
let needs = self.needs_manual();
|
||||
let mut errors = Vec::new();
|
||||
let mode: String = usdpl_back::api::files::read_single(DPM_FORCE_LIMITS_PATH.to_owned()).map_err(|e| {
|
||||
vec![SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `manual` to `{}`: {}",
|
||||
DPM_FORCE_LIMITS_PATH, e
|
||||
),
|
||||
setting: crate::settings::SettingVariant::General,
|
||||
}]
|
||||
})?;
|
||||
if mode != "manual" && needs {
|
||||
log::info!("Setting `{}` to manual", DPM_FORCE_LIMITS_PATH);
|
||||
// set manual control
|
||||
usdpl_back::api::files::write_single(DPM_FORCE_LIMITS_PATH, "manual").map_err(|e| {
|
||||
errors.push(SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `manual` to `{}`: {}",
|
||||
DPM_FORCE_LIMITS_PATH, e
|
||||
),
|
||||
setting: crate::settings::SettingVariant::General,
|
||||
})
|
||||
}).unwrap_or(());
|
||||
} else if mode != "auto" && !needs {
|
||||
log::info!("Setting `{}` to auto", DPM_FORCE_LIMITS_PATH);
|
||||
// unset manual control
|
||||
usdpl_back::api::files::write_single(DPM_FORCE_LIMITS_PATH, "auto").map_err(|e| {
|
||||
errors.push(SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `auto` to `{}`: {}",
|
||||
DPM_FORCE_LIMITS_PATH, e
|
||||
),
|
||||
setting: crate::settings::SettingVariant::General,
|
||||
})
|
||||
}).unwrap_or(());
|
||||
}
|
||||
if let Ok(mode_now) = usdpl_back::api::files::read_single::<_, String, _>(DPM_FORCE_LIMITS_PATH.to_owned()) {
|
||||
log::debug!("Mode for `{}` is now `{}`", DPM_FORCE_LIMITS_PATH, mode_now);
|
||||
} else {
|
||||
log::debug!("Error getting new mode for debugging purposes");
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue