From 1dc0acca8e759d36a803da977a18e8df40c4cf3a Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Fri, 30 Dec 2022 23:27:22 -0500 Subject: [PATCH] Combine SD advance mode back into regular SD driver, implement custom clock file support --- backend/limits_core/Cargo.lock | 89 ++++ backend/limits_core/src/json/base.rs | 17 + backend/limits_core/src/json/conditions.rs | 4 +- backend/limits_srv/pt_limits.json | 21 + backend/src/settings/detect/auto_detect.rs | 12 +- backend/src/settings/driver.rs | 5 +- backend/src/settings/mod.rs | 1 - backend/src/settings/steam_deck/battery.rs | 41 +- backend/src/settings/steam_deck/cpu.rs | 74 ++-- backend/src/settings/steam_deck/gpu.rs | 77 ++-- backend/src/settings/steam_deck/mod.rs | 1 + backend/src/settings/steam_deck/oc_limits.rs | 115 +++++ backend/src/settings/steam_deck_adv/cpu.rs | 428 ------------------- backend/src/settings/steam_deck_adv/gpu.rs | 310 -------------- backend/src/settings/steam_deck_adv/mod.rs | 7 - 15 files changed, 318 insertions(+), 884 deletions(-) create mode 100644 backend/limits_core/Cargo.lock create mode 100644 backend/src/settings/steam_deck/oc_limits.rs delete mode 100644 backend/src/settings/steam_deck_adv/cpu.rs delete mode 100644 backend/src/settings/steam_deck_adv/gpu.rs delete mode 100644 backend/src/settings/steam_deck_adv/mod.rs diff --git a/backend/limits_core/Cargo.lock b/backend/limits_core/Cargo.lock new file mode 100644 index 0000000..9eb5c72 --- /dev/null +++ b/backend/limits_core/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "limits_core" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" diff --git a/backend/limits_core/src/json/base.rs b/backend/limits_core/src/json/base.rs index c25e5de..6e77b71 100644 --- a/backend/limits_core/src/json/base.rs +++ b/backend/limits_core/src/json/base.rs @@ -14,6 +14,21 @@ impl Default for Base { fn default() -> Self { Base { configs: vec![ + super::Config { + name: "Steam Deck Custom".to_owned(), + conditions: super::Conditions { + dmi: None, + cpuinfo: Some("model name\t: AMD Custom APU 0405\n".to_owned()), + os: None, + command: None, + file_exists: Some("./pt_oc.json".into()), + }, + limits: vec![ + super::Limits::Cpu(super::CpuLimit::SteamDeckAdvance), + super::Limits::Gpu(super::GpuLimit::SteamDeckAdvance), + super::Limits::Battery(super::BatteryLimit::SteamDeckAdvance), + ] + }, super::Config { name: "Steam Deck".to_owned(), conditions: super::Conditions { @@ -21,6 +36,7 @@ impl Default for Base { cpuinfo: Some("model name\t: AMD Custom APU 0405\n".to_owned()), os: None, command: None, + file_exists: None, }, limits: vec![ super::Limits::Cpu(super::CpuLimit::SteamDeck), @@ -35,6 +51,7 @@ impl Default for Base { cpuinfo: None, os: None, command: None, + file_exists: None, }, limits: vec![ super::Limits::Cpu(super::CpuLimit::Unknown), diff --git a/backend/limits_core/src/json/conditions.rs b/backend/limits_core/src/json/conditions.rs index 2016cb9..e584c4a 100644 --- a/backend/limits_core/src/json/conditions.rs +++ b/backend/limits_core/src/json/conditions.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -/// Conditions under which a config applies +/// Conditions under which a config applies (ANDed together) #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Conditions { /// Regex pattern for dmidecode output @@ -11,6 +11,8 @@ pub struct Conditions { pub os: Option, /// Custom command to run, where an exit code of 0 means a successful match pub command: Option, + /// Check if file exists + pub file_exists: Option, } impl Conditions { diff --git a/backend/limits_srv/pt_limits.json b/backend/limits_srv/pt_limits.json index 4dcef89..7a4143a 100644 --- a/backend/limits_srv/pt_limits.json +++ b/backend/limits_srv/pt_limits.json @@ -1,5 +1,26 @@ { "configs": [ + { + "name": "Steam Deck Custom", + "conditions": { + "cpuinfo": "model name\t: AMD Custom APU 0405\n", + "file_exists": "./pt_oc.json" + }, + "limits": [ + { + "limits": "Cpu", + "target": "SteamDeck" + }, + { + "limits": "Gpu", + "target": "SteamDeck" + }, + { + "limits": "Battery", + "target": "SteamDeck" + } + ] + }, { "name": "Steam Deck", "conditions": { diff --git a/backend/src/settings/detect/auto_detect.rs b/backend/src/settings/detect/auto_detect.rs index 18a6fd2..5306d78 100644 --- a/backend/src/settings/detect/auto_detect.rs +++ b/backend/src/settings/detect/auto_detect.rs @@ -84,6 +84,10 @@ pub fn auto_detect0(settings_opt: Option, json_path: std::path::Pa Err(e) => log::warn!("Ignoring bash limits error: {}", e), } } + if let Some(file_exists) = &conditions.file_exists { + let exists = std::path::Path::new(file_exists).exists(); + matches &= exists; + } } if matches { if let Some(settings) = &settings_opt { @@ -92,7 +96,7 @@ pub fn auto_detect0(settings_opt: Option, json_path: std::path::Pa Limits::Cpu(cpus) => { let cpu_driver: Box = match cpus { CpuLimit::SteamDeck => Box::new(crate::settings::steam_deck::Cpus::from_json(settings.cpus.clone(), settings.version)), - CpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck_adv::Cpus::from_json(settings.cpus.clone(), settings.version)), + CpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck::Cpus::from_json(settings.cpus.clone(), settings.version)), CpuLimit::Generic(x) => Box::new(crate::settings::generic::Cpus::from_json_and_limits(settings.cpus.clone(), settings.version, x)), CpuLimit::Unknown => Box::new(crate::settings::unknown::Cpus::from_json(settings.cpus.clone(), settings.version)), }; @@ -101,7 +105,7 @@ pub fn auto_detect0(settings_opt: Option, json_path: std::path::Pa Limits::Gpu(gpu) => { let driver: Box = match gpu { GpuLimit::SteamDeck => Box::new(crate::settings::steam_deck::Gpu::from_json(settings.gpu.clone(), settings.version)), - GpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck_adv::Gpu::from_json(settings.gpu.clone(), settings.version)), + GpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck::Gpu::from_json(settings.gpu.clone(), settings.version)), GpuLimit::Generic(x) => Box::new(crate::settings::generic::Gpu::from_json_and_limits(settings.gpu.clone(), settings.version, x)), GpuLimit::Unknown => Box::new(crate::settings::unknown::Gpu::from_json(settings.gpu.clone(), settings.version)), }; @@ -124,7 +128,7 @@ pub fn auto_detect0(settings_opt: Option, json_path: std::path::Pa Limits::Cpu(cpus) => { let cpu_driver: Box = match cpus { CpuLimit::SteamDeck => Box::new(crate::settings::steam_deck::Cpus::system_default()), - CpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck_adv::Cpus::system_default()), + CpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck::Cpus::system_default()), CpuLimit::Generic(x) => Box::new(crate::settings::generic::Cpus::from_limits(x)), CpuLimit::Unknown => Box::new(crate::settings::unknown::Cpus::system_default()), }; @@ -133,7 +137,7 @@ pub fn auto_detect0(settings_opt: Option, json_path: std::path::Pa Limits::Gpu(gpu) => { let driver: Box = match gpu { GpuLimit::SteamDeck => Box::new(crate::settings::steam_deck::Gpu::system_default()), - GpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck_adv::Gpu::system_default()), + GpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck::Gpu::system_default()), GpuLimit::Generic(x) => Box::new(crate::settings::generic::Gpu::from_limits(x)), GpuLimit::Unknown => Box::new(crate::settings::unknown::Gpu::system_default()), }; diff --git a/backend/src/settings/driver.rs b/backend/src/settings/driver.rs index b637da4..e1d1b0e 100644 --- a/backend/src/settings/driver.rs +++ b/backend/src/settings/driver.rs @@ -40,6 +40,7 @@ impl Driver { gpu: Box::new(super::steam_deck::Gpu::from_json(settings.gpu, settings.version)), battery: Box::new(super::steam_deck::Battery::from_json(settings.battery, settings.version)), }), + // There's nothing special about SteamDeckAdvance, it just appears different DriverJson::SteamDeckAdvance => Ok(Self { general: Box::new(General { persistent: settings.persistent, @@ -47,8 +48,8 @@ impl Driver { name: settings.name, driver: DriverJson::SteamDeckAdvance, }), - cpus: Box::new(super::steam_deck_adv::Cpus::from_json(settings.cpus, settings.version)), - gpu: Box::new(super::steam_deck_adv::Gpu::from_json(settings.gpu, settings.version)), + cpus: Box::new(super::steam_deck::Cpus::from_json(settings.cpus, settings.version)), + gpu: Box::new(super::steam_deck::Gpu::from_json(settings.gpu, settings.version)), battery: Box::new(super::steam_deck::Battery::from_json(settings.battery, settings.version)), }), DriverJson::Generic => Ok(Self { diff --git a/backend/src/settings/mod.rs b/backend/src/settings/mod.rs index 68e5bd7..22a591f 100644 --- a/backend/src/settings/mod.rs +++ b/backend/src/settings/mod.rs @@ -7,7 +7,6 @@ mod traits; pub mod generic; pub mod steam_deck; -pub mod steam_deck_adv; pub mod unknown; pub use detect::{auto_detect0, auto_detect_provider, limits_worker::spawn as limits_worker_spawn}; diff --git a/backend/src/settings/steam_deck/battery.rs b/backend/src/settings/steam_deck/battery.rs index 13fe425..3732bee 100644 --- a/backend/src/settings/steam_deck/battery.rs +++ b/backend/src/settings/steam_deck/battery.rs @@ -1,15 +1,17 @@ use std::convert::Into; use crate::api::RangeLimit; -use crate::settings::{OnResume, OnSet, SettingError, SettingsRange}; +use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::TBattery; use crate::persist::BatteryJson; use super::util::ChargeMode; +use super::oc_limits::{BatteryLimits, OverclockLimits}; #[derive(Debug, Clone)] pub struct Battery { pub charge_rate: Option, pub charge_mode: Option, + limits: BatteryLimits, state: crate::state::steam_deck::Battery, } @@ -24,15 +26,18 @@ const BATTERY_CHARGE_DESIGN_PATH: &str = "/sys/class/hwmon/hwmon2/device/charge_ impl Battery { #[inline] pub fn from_json(other: BatteryJson, version: u64) -> Self { + let oc_limits = OverclockLimits::load_or_default().battery; match version { 0 => Self { charge_rate: other.charge_rate, charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(), + limits: oc_limits, state: crate::state::steam_deck::Battery::default(), }, _ => Self { charge_rate: other.charge_rate, charge_mode: other.charge_mode.map(|x| Self::str_to_charge_mode(&x)).flatten(), + limits: oc_limits, state: crate::state::steam_deck::Battery::default(), }, } @@ -68,7 +73,7 @@ impl Battery { )?; } else if self.state.charge_rate_set { self.state.charge_rate_set = false; - usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, Self::max().charge_rate.unwrap()).map_err( + usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, self.limits.charge_rate.max).map_err( |e| SettingError { msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e), setting: crate::settings::SettingVariant::Battery, @@ -96,10 +101,8 @@ impl Battery { } fn clamp_all(&mut self) { - let min = Self::min(); - let max = Self::max(); if let Some(charge_rate) = &mut self.charge_rate { - *charge_rate = (*charge_rate).clamp(min.charge_rate.unwrap(), max.charge_rate.unwrap()); + *charge_rate = (*charge_rate).clamp(self.limits.charge_rate.min, self.limits.charge_rate.max); } } @@ -181,9 +184,11 @@ impl Battery { } pub fn system_default() -> Self { + let oc_limits = OverclockLimits::load_or_default().battery; Self { charge_rate: None, charge_mode: None, + limits: oc_limits, state: crate::state::steam_deck::Battery::default(), } } @@ -212,34 +217,12 @@ impl OnResume for Battery { } } -impl SettingsRange for Battery { - #[inline] - fn max() -> Self { - Self { - charge_rate: Some(2500), - charge_mode: None, - state: crate::state::steam_deck::Battery::default(), - } - } - - #[inline] - fn min() -> Self { - Self { - charge_rate: Some(250), - charge_mode: None, - state: crate::state::steam_deck::Battery::default(), - } - } -} - impl TBattery for Battery { fn limits(&self) -> crate::api::BatteryLimits { - let max = Self::max(); - let min = Self::min(); crate::api::BatteryLimits { charge_current: Some(RangeLimit{ - min: min.charge_rate.unwrap(), - max: max.charge_rate.unwrap(), + min: self.limits.charge_rate.min, + max: self.limits.charge_rate.max }), charge_current_step: 50, charge_modes: vec!["normal".to_owned(), "discharge".to_owned(), "idle".to_owned()], diff --git a/backend/src/settings/steam_deck/cpu.rs b/backend/src/settings/steam_deck/cpu.rs index 35f498b..9b78d62 100644 --- a/backend/src/settings/steam_deck/cpu.rs +++ b/backend/src/settings/steam_deck/cpu.rs @@ -2,9 +2,10 @@ use std::convert::Into; use crate::api::RangeLimit; use crate::settings::MinMax; -use crate::settings::{OnResume, OnSet, SettingError, SettingsRange}; +use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::{TCpus, TCpu}; use crate::persist::CpuJson; +use super::oc_limits::{OverclockLimits, CpusLimits, CpuLimits}; const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present"; const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control"; @@ -14,6 +15,8 @@ pub struct Cpus { pub cpus: Vec, pub smt: bool, pub smt_capable: bool, + #[allow(dead_code)] // in case this may be useful in the future + pub(super) limits: CpusLimits, } impl OnSet for Cpus { @@ -81,28 +84,32 @@ impl Cpus { } pub fn system_default() -> Self { + let oc_limits = OverclockLimits::load_or_default().cpus; if let Some(max_cpu) = Self::cpu_count() { let mut sys_cpus = Vec::with_capacity(max_cpu); for i in 0..max_cpu { - sys_cpus.push(Cpu::from_sys(i)); + sys_cpus.push(Cpu::from_sys(i, oc_limits.cpus.get(i).map(|x| x.to_owned()).unwrap_or_default())); } let (smt_status, can_smt) = Self::system_smt_capabilities(); Self { cpus: sys_cpus, smt: smt_status, smt_capable: can_smt, + limits: oc_limits, } } else { Self { cpus: vec![], smt: false, smt_capable: false, + limits: oc_limits, } } } #[inline] pub fn from_json(mut other: Vec, version: u64) -> Self { + let oc_limits = OverclockLimits::load_or_default().cpus; let (_, can_smt) = Self::system_smt_capabilities(); let mut result = Vec::with_capacity(other.len()); let max_cpus = Self::cpu_count(); @@ -113,7 +120,7 @@ impl Cpus { break; } } - result.push(Cpu::from_json(cpu, version, i)); + result.push(Cpu::from_json(cpu, version, i, oc_limits.cpus.get(i).map(|x| x.to_owned()).unwrap_or_default())); } if let Some(max_cpus) = max_cpus { if result.len() != max_cpus { @@ -127,6 +134,7 @@ impl Cpus { cpus: result, smt: true, smt_capable: can_smt, + limits: oc_limits, } } } @@ -166,6 +174,7 @@ pub struct Cpu { pub online: bool, pub clock_limits: Option>, pub governor: String, + limits: CpuLimits, index: usize, state: crate::state::steam_deck::Cpu, } @@ -175,12 +184,13 @@ const CPU_FORCE_LIMITS_PATH: &str = "/sys/class/drm/card0/device/power_dpm_force impl Cpu { #[inline] - pub fn from_json(other: CpuJson, version: u64, i: usize) -> Self { + fn from_json(other: CpuJson, version: u64, i: usize, oc_limits: CpuLimits) -> Self { match version { 0 => Self { online: other.online, clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)), governor: other.governor, + limits: oc_limits, index: i, state: crate::state::steam_deck::Cpu::default(), }, @@ -188,6 +198,7 @@ impl Cpu { online: other.online, clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)), governor: other.governor, + limits: oc_limits, index: i, state: crate::state::steam_deck::Cpu::default(), }, @@ -250,7 +261,7 @@ impl Cpu { // disable manual clock limits log::debug!("Setting CPU {} to default clockspeed", self.index); // max clock - let payload_max = format!("p {} 1 {}\n", self.index / 2, Self::max().clock_limits.unwrap().max); + let payload_max = format!("p {} 1 {}\n", self.index / 2, self.limits.clock_max.max); usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_max).map_err( |e| SettingError { msg: format!( @@ -261,7 +272,7 @@ impl Cpu { }, )?; // min clock - let payload_min = format!("p {} 0 {}\n", self.index / 2, Self::min().clock_limits.unwrap().min); + let payload_min = format!("p {} 0 {}\n", self.index / 2, self.limits.clock_min.min); usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_min).map_err( |e| SettingError { msg: format!( @@ -297,41 +308,33 @@ impl Cpu { } fn clamp_all(&mut self) { - let min = Self::min(); - let max = Self::max(); if let Some(clock_limits) = &mut self.clock_limits { - let max_boost = max.clock_limits.as_ref().unwrap(); - let min_boost = min.clock_limits.as_ref().unwrap(); - clock_limits.min = clock_limits.min.clamp(min_boost.min, max_boost.min); - clock_limits.max = clock_limits.max.clamp(min_boost.max, max_boost.max); + clock_limits.min = clock_limits.min.clamp(self.limits.clock_min.min, self.limits.clock_min.max); + clock_limits.max = clock_limits.max.clamp(self.limits.clock_max.min, self.limits.clock_max.max); } } - fn from_sys(cpu_index: usize) -> Self { + fn from_sys(cpu_index: usize, oc_limits: CpuLimits) -> Self { Self { online: usdpl_back::api::files::read_single(cpu_online_path(cpu_index)).unwrap_or(1u8) != 0, clock_limits: None, governor: usdpl_back::api::files::read_single(cpu_governor_path(cpu_index)) .unwrap_or("schedutil".to_owned()), + limits: oc_limits, index: cpu_index, state: crate::state::steam_deck::Cpu::default(), } } fn limits(&self) -> crate::api::CpuLimits { - let max = Self::max(); - let max_clocks = max.clock_limits.unwrap(); - - let min = Self::min(); - let min_clocks = min.clock_limits.unwrap(); crate::api::CpuLimits { clock_min_limits: Some(RangeLimit { - min: min_clocks.min, - max: max_clocks.min + min: self.limits.clock_min.min, + max: self.limits.clock_min.max }), clock_max_limits: Some(RangeLimit { - min: min_clocks.max, - max: max_clocks.max + min: self.limits.clock_max.min, + max: self.limits.clock_max.max }), clock_step: 100, governors: self.governors(), @@ -404,33 +407,6 @@ impl TCpu for Cpu { } } -impl SettingsRange for Cpu { - #[inline] - fn max() -> Self { - Self { - online: true, - clock_limits: Some(MinMax { - max: 3500, - min: 3500, - }), - governor: "schedutil".to_owned(), - index: usize::MAX, - state: crate::state::steam_deck::Cpu::default(), - } - } - - #[inline] - fn min() -> Self { - Self { - online: false, - clock_limits: Some(MinMax { max: 500, min: 1400 }), - governor: "schedutil".to_owned(), - index: usize::MIN, - state: crate::state::steam_deck::Cpu::default(), - } - } -} - #[inline] fn cpu_online_path(index: usize) -> String { format!("/sys/devices/system/cpu/cpu{}/online", index) diff --git a/backend/src/settings/steam_deck/gpu.rs b/backend/src/settings/steam_deck/gpu.rs index 59827fe..99fce9c 100644 --- a/backend/src/settings/steam_deck/gpu.rs +++ b/backend/src/settings/steam_deck/gpu.rs @@ -2,9 +2,10 @@ use std::convert::Into; use crate::api::RangeLimit; use crate::settings::MinMax; -use crate::settings::{OnResume, OnSet, SettingError, SettingsRange}; +use crate::settings::{OnResume, OnSet, SettingError}; use crate::settings::TGpu; use crate::persist::GpuJson; +use super::oc_limits::{OverclockLimits, GpuLimits}; const SLOW_PPT: u8 = 1; const FAST_PPT: u8 = 2; @@ -15,6 +16,7 @@ pub struct Gpu { pub slow_ppt: Option, pub clock_limits: Option>, pub slow_memory: bool, + limits: GpuLimits, state: crate::state::steam_deck::Gpu, } @@ -26,12 +28,14 @@ const GPU_MEMORY_DOWNCLOCK_PATH: &str = "/sys/class/drm/card0/device/pp_dpm_fclk impl Gpu { #[inline] pub fn from_json(other: GpuJson, version: u64) -> Self { + let oc_limits = OverclockLimits::load_or_default().gpu; match version { 0 => Self { fast_ppt: other.fast_ppt, slow_ppt: other.slow_ppt, clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)), slow_memory: other.slow_memory, + limits: oc_limits, state: crate::state::steam_deck::Gpu::default(), }, _ => Self { @@ -39,6 +43,7 @@ impl Gpu { slow_ppt: other.slow_ppt, clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)), slow_memory: other.slow_memory, + limits: oc_limits, state: crate::state::steam_deck::Gpu::default(), }, } @@ -120,7 +125,7 @@ impl Gpu { self.state.clock_limits_set = false; // disable manual clock limits // max clock - let payload_max = format!("s 1 {}\n", Self::max().clock_limits.unwrap().max); + let payload_max = format!("s 1 {}\n", self.limits.clock_max.max); usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_max).map_err( |e| SettingError { msg: format!( @@ -131,7 +136,7 @@ impl Gpu { }, )?; // min clock - let payload_min = format!("s 0 {}\n", Self::min().clock_limits.unwrap().min); + let payload_min = format!("s 0 {}\n", self.limits.clock_min.min); usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_min).map_err( |e| SettingError { msg: format!( @@ -154,34 +159,32 @@ impl Gpu { } fn clamp_all(&mut self) { - let min = Self::min(); - let max = Self::max(); if let Some(fast_ppt) = &mut self.fast_ppt { *fast_ppt = (*fast_ppt).clamp( - *min.fast_ppt.as_ref().unwrap(), - *max.fast_ppt.as_ref().unwrap(), + self.limits.fast_ppt.min, + self.limits.fast_ppt.max, ); } if let Some(slow_ppt) = &mut self.slow_ppt { *slow_ppt = (*slow_ppt).clamp( - *min.slow_ppt.as_ref().unwrap(), - *max.slow_ppt.as_ref().unwrap(), + self.limits.slow_ppt.min, + self.limits.slow_ppt.max, ); } if let Some(clock_limits) = &mut self.clock_limits { - let max_boost = max.clock_limits.as_ref().unwrap(); - let min_boost = min.clock_limits.as_ref().unwrap(); - clock_limits.min = clock_limits.min.clamp(min_boost.min, max_boost.min); - clock_limits.max = clock_limits.max.clamp(min_boost.max, max_boost.max); + clock_limits.min = clock_limits.min.clamp(self.limits.clock_min.min, self.limits.clock_min.max); + clock_limits.max = clock_limits.max.clamp(self.limits.clock_max.min, self.limits.clock_max.max); } } pub fn system_default() -> Self { + let oc_limits = OverclockLimits::load_or_default().gpu; Self { fast_ppt: None, slow_ppt: None, clock_limits: None, slow_memory: false, + limits: oc_limits, state: crate::state::steam_deck::Gpu::default(), } } @@ -214,62 +217,30 @@ impl OnResume for Gpu { } } -impl SettingsRange for Gpu { - #[inline] - fn max() -> Self { - Self { - fast_ppt: Some(30_000_000), - slow_ppt: Some(29_000_000), - clock_limits: Some(MinMax { - min: 1600, - max: 1600, - }), - slow_memory: false, - state: crate::state::steam_deck::Gpu::default(), - } - } - - #[inline] - fn min() -> Self { - Self { - fast_ppt: Some(0), - slow_ppt: Some(1000000), - clock_limits: Some(MinMax { min: 200, max: 200 }), - slow_memory: true, - state: crate::state::steam_deck::Gpu::default(), - } - } -} - const PPT_DIVISOR: u64 = 1_000_000; impl TGpu for Gpu { fn limits(&self) -> crate::api::GpuLimits { - let max = Self::max(); - let max_clock_limits = max.clock_limits.unwrap(); - - let min = Self::min(); - let min_clock_limits = min.clock_limits.unwrap(); crate::api::GpuLimits { fast_ppt_limits: Some(RangeLimit { - min: min.fast_ppt.unwrap() / PPT_DIVISOR, - max: max.fast_ppt.unwrap() / PPT_DIVISOR, + min: self.limits.fast_ppt.min / PPT_DIVISOR, + max: self.limits.fast_ppt.max / PPT_DIVISOR, }), slow_ppt_limits: Some(RangeLimit { - min: min.slow_ppt.unwrap() / PPT_DIVISOR, - max: max.slow_ppt.unwrap() / PPT_DIVISOR, + min: self.limits.slow_ppt.min / PPT_DIVISOR, + max: self.limits.slow_ppt.max / PPT_DIVISOR, }), ppt_step: 1, tdp_limits: None, tdp_boost_limits: None, tdp_step: 42, clock_min_limits: Some(RangeLimit { - min: min_clock_limits.min, - max: max_clock_limits.max, + min: self.limits.clock_min.min, + max: self.limits.clock_min.max, }), clock_max_limits: Some(RangeLimit { - min: min_clock_limits.min, - max: max_clock_limits.max, + min: self.limits.clock_max.min, + max: self.limits.clock_max.max, }), clock_step: 100, memory_control_capable: true, diff --git a/backend/src/settings/steam_deck/mod.rs b/backend/src/settings/steam_deck/mod.rs index fb836a1..9c325b6 100644 --- a/backend/src/settings/steam_deck/mod.rs +++ b/backend/src/settings/steam_deck/mod.rs @@ -1,6 +1,7 @@ mod battery; mod cpu; mod gpu; +mod oc_limits; mod util; pub use battery::Battery; diff --git a/backend/src/settings/steam_deck/oc_limits.rs b/backend/src/settings/steam_deck/oc_limits.rs new file mode 100644 index 0000000..f81bde1 --- /dev/null +++ b/backend/src/settings/steam_deck/oc_limits.rs @@ -0,0 +1,115 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub(super) struct MinMaxLimits { + pub min: T, + pub max: T, +} + +const OC_LIMITS_FILEPATH: &str = "./pt_oc.json"; + +#[derive(Serialize, Deserialize, Debug)] +pub(super) struct OverclockLimits { + pub battery: BatteryLimits, + pub cpus: CpusLimits, + pub gpu: GpuLimits, +} + +impl Default for OverclockLimits { + fn default() -> Self { + Self { + battery: BatteryLimits::default(), + cpus: CpusLimits::default(), + gpu: GpuLimits::default(), + } + } +} + +impl OverclockLimits { + pub fn load_or_default() -> Self { + let path = std::path::Path::new(OC_LIMITS_FILEPATH); + if path.exists() { + log::info!("Steam Deck limits file {} found", path.display()); + let mut file = match std::fs::File::open(&path) { + Ok(f) => f, + Err(e) => { + log::warn!("Steam Deck limits file {} err: {} (using default fallback)", path.display(), e); + return Self::default(); + }, + }; + match serde_json::from_reader(&mut file) { + Ok(result) => { + log::debug!("Steam Deck limits file {} successfully loaded", path.display()); + result + }, + Err(e) => { + log::warn!("Steam Deck limits file {} json err: {} (using default fallback)", path.display(), e); + Self::default() + } + } + } else { + log::info!("Steam Deck limits file {} not found (using default fallback)", path.display()); + Self::default() + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub(super) struct BatteryLimits { + pub charge_rate: MinMaxLimits, +} + +impl Default for BatteryLimits { + fn default() -> Self { + Self { + charge_rate: MinMaxLimits { min: 250, max: 2500 }, + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub(super) struct CpusLimits { + pub cpus: Vec, +} + +impl Default for CpusLimits { + fn default() -> Self { + Self { + cpus: [(); 8].iter().map(|_| CpuLimits::default()).collect() + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub(super) struct CpuLimits { + pub clock_min: MinMaxLimits, + pub clock_max: MinMaxLimits, +} + +impl Default for CpuLimits { + fn default() -> Self { + Self { + clock_min: MinMaxLimits { min: 1400, max: 3500 }, + clock_max: MinMaxLimits { min: 500, max: 3500 } + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub(super) struct GpuLimits { + pub fast_ppt: MinMaxLimits, + pub slow_ppt: MinMaxLimits, + pub clock_min: MinMaxLimits, + pub clock_max: MinMaxLimits, +} + +impl Default for GpuLimits { + fn default() -> Self { + Self { + fast_ppt: MinMaxLimits { min: 1000000, max: 30_000_000 }, + slow_ppt: MinMaxLimits { min: 1000000, max: 29_000_000 }, + clock_min: MinMaxLimits { min: 200, max: 1600 }, + clock_max: MinMaxLimits { min: 200, max: 1600 } + } + } +} diff --git a/backend/src/settings/steam_deck_adv/cpu.rs b/backend/src/settings/steam_deck_adv/cpu.rs deleted file mode 100644 index 50e4f49..0000000 --- a/backend/src/settings/steam_deck_adv/cpu.rs +++ /dev/null @@ -1,428 +0,0 @@ -use std::convert::Into; - -use crate::api::RangeLimit; -use crate::settings::MinMax; -use crate::settings::{OnResume, OnSet, SettingError, SettingsRange}; -use crate::settings::{TCpus, TCpu}; -use crate::persist::CpuJson; - -const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present"; -const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control"; - -#[derive(Debug, Clone)] -pub struct Cpus { - pub cpus: Vec, - pub smt: bool, - pub smt_capable: bool, -} - -impl OnSet for Cpus { - fn on_set(&mut self) -> Result<(), SettingError> { - if self.smt_capable { - // toggle SMT - if self.smt { - usdpl_back::api::files::write_single(CPU_SMT_PATH, "on").map_err(|e| { - SettingError { - msg: format!( - "Failed to write `on` to `{}`: {}", - CPU_SMT_PATH, e - ), - setting: crate::settings::SettingVariant::Cpu, - } - })?; - } else { - usdpl_back::api::files::write_single(CPU_SMT_PATH, "off").map_err(|e| { - SettingError { - msg: format!( - "Failed to write `off` to `{}`: {}", - CPU_SMT_PATH, e - ), - setting: crate::settings::SettingVariant::Cpu, - } - })?; - } - } - for (i, cpu) in self.cpus.as_mut_slice().iter_mut().enumerate() { - cpu.state.do_set_online = self.smt || i % 2 == 0; - cpu.on_set()?; - } - Ok(()) - } -} - -impl OnResume for Cpus { - fn on_resume(&self) -> Result<(), SettingError> { - for cpu in &self.cpus { - cpu.on_resume()?; - } - Ok(()) - } -} - -impl Cpus { - pub fn cpu_count() -> Option { - let mut data: String = usdpl_back::api::files::read_single(CPU_PRESENT_PATH) - .unwrap_or_else(|_| "0-7".to_string() /* Steam Deck's default */); - if let Some(dash_index) = data.find('-') { - let data = data.split_off(dash_index + 1); - if let Ok(max_cpu) = data.parse::() { - return Some(max_cpu + 1); - } - } - log::warn!("Failed to parse CPU info from kernel, is Tux evil?"); - None - } - - fn system_smt_capabilities() -> (bool, bool) { - match usdpl_back::api::files::read_single::<_, String, _>(CPU_SMT_PATH) { - Ok(val) => (val.trim().to_lowercase() == "on", true), - Err(_) => (false, false) - } - } - - pub fn system_default() -> Self { - if let Some(max_cpu) = Self::cpu_count() { - let mut sys_cpus = Vec::with_capacity(max_cpu); - for i in 0..max_cpu { - sys_cpus.push(Cpu::from_sys(i)); - } - let (smt_status, can_smt) = Self::system_smt_capabilities(); - Self { - cpus: sys_cpus, - smt: smt_status, - smt_capable: can_smt, - } - } else { - Self { - cpus: vec![], - smt: false, - smt_capable: false, - } - } - } - - #[inline] - pub fn from_json(mut other: Vec, version: u64) -> Self { - let (_, can_smt) = Self::system_smt_capabilities(); - let mut result = Vec::with_capacity(other.len()); - let max_cpus = Self::cpu_count(); - for (i, cpu) in other.drain(..).enumerate() { - // prevent having more CPUs than available - if let Some(max_cpus) = max_cpus { - if i == max_cpus { - break; - } - } - result.push(Cpu::from_json(cpu, version, i)); - } - if let Some(max_cpus) = max_cpus { - if result.len() != max_cpus { - let mut sys_cpus = Cpus::system_default(); - for i in result.len()..sys_cpus.cpus.len() { - result.push(sys_cpus.cpus.remove(i)); - } - } - } - Self { - cpus: result, - smt: true, - smt_capable: can_smt, - } - } -} - -impl TCpus for Cpus { - fn limits(&self) -> crate::api::CpusLimits { - crate::api::CpusLimits { - cpus: self.cpus.iter().map(|x| x.limits()).collect(), - count: self.cpus.len(), - smt_capable: self.smt_capable, - } - } - - fn json(&self) -> Vec { - self.cpus.iter().map(|x| x.to_owned().into()).collect() - } - - fn cpus(&mut self) -> Vec<&mut dyn TCpu> { - self.cpus.iter_mut().map(|x| x as &mut dyn TCpu).collect() - } - - fn len(&self) -> usize { - self.cpus.len() - } - - fn smt(&mut self) -> &'_ mut bool { - &mut self.smt - } - - fn provider(&self) -> crate::persist::DriverJson { - crate::persist::DriverJson::SteamDeckAdvance - } -} - -#[derive(Debug, Clone)] -pub struct Cpu { - pub online: bool, - pub clock_limits: Option>, - pub governor: String, - index: usize, - state: crate::state::steam_deck::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] - pub fn from_json(other: CpuJson, version: u64, i: usize) -> Self { - match version { - 0 => Self { - online: other.online, - clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)), - governor: other.governor, - index: i, - state: crate::state::steam_deck::Cpu::default(), - }, - _ => Self { - online: other.online, - clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)), - governor: other.governor, - index: i, - state: crate::state::steam_deck::Cpu::default(), - }, - } - } - - fn set_all(&mut self) -> Result<(), SettingError> { - // set cpu online/offline - if self.index != 0 && self.state.do_set_online { // cpu0 cannot be disabled - let online_path = cpu_online_path(self.index); - usdpl_back::api::files::write_single(&online_path, self.online as u8).map_err(|e| { - SettingError { - msg: format!("Failed to write to `{}`: {}", &online_path, e), - setting: crate::settings::SettingVariant::Cpu, - } - })?; - } - // 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| { - SettingError { - msg: format!( - "Failed to write `manual` to `{}`: {}", - CPU_FORCE_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Cpu, - } - })?; - } - if let Some(clock_limits) = &self.clock_limits { - log::debug!("Setting CPU {} (min, max) clockspeed to ({}, {})", self.index, clock_limits.min, clock_limits.max); - self.state.clock_limits_set = true; - // max clock - let payload_max = format!("p {} 1 {}\n", self.index / 2, clock_limits.max); - usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_max).map_err( - |e| SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &payload_max, CPU_CLOCK_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Cpu, - }, - )?; - // min clock - let payload_min = format!("p {} 0 {}\n", self.index / 2, clock_limits.min); - usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_min).map_err( - |e| SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &payload_min, CPU_CLOCK_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Cpu, - }, - )?; - } else if self.state.clock_limits_set || self.state.is_resuming { - self.state.clock_limits_set = false; - // disable manual clock limits - log::debug!("Setting CPU {} to default clockspeed", self.index); - // max clock - let payload_max = format!("p {} 1 {}\n", self.index / 2, Self::max().clock_limits.unwrap().max); - usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_max).map_err( - |e| SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &payload_max, CPU_CLOCK_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Cpu, - }, - )?; - // min clock - let payload_min = format!("p {} 0 {}\n", self.index / 2, Self::min().clock_limits.unwrap().min); - usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_min).map_err( - |e| SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &payload_min, CPU_CLOCK_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Cpu, - }, - )?; - } - // commit changes - usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, "c\n").map_err(|e| { - SettingError { - msg: format!("Failed to write `c` to `{}`: {}", CPU_CLOCK_LIMITS_PATH, e), - setting: crate::settings::SettingVariant::Cpu, - } - })?; - - // set governor - if self.index == 0 || self.online { - let governor_path = cpu_governor_path(self.index); - usdpl_back::api::files::write_single(&governor_path, &self.governor).map_err(|e| { - SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &self.governor, &governor_path, e - ), - setting: crate::settings::SettingVariant::Cpu, - } - })?; - } - Ok(()) - } - - fn clamp_all(&mut self) { - let min = Self::min(); - let max = Self::max(); - if let Some(clock_limits) = &mut self.clock_limits { - let max_boost = max.clock_limits.as_ref().unwrap(); - let min_boost = min.clock_limits.as_ref().unwrap(); - clock_limits.min = clock_limits.min.clamp(min_boost.min, max_boost.min); - clock_limits.max = clock_limits.max.clamp(min_boost.max, max_boost.max); - } - } - - fn from_sys(cpu_index: usize) -> Self { - Self { - online: usdpl_back::api::files::read_single(cpu_online_path(cpu_index)).unwrap_or(1u8) != 0, - clock_limits: None, - governor: usdpl_back::api::files::read_single(cpu_governor_path(cpu_index)) - .unwrap_or("schedutil".to_owned()), - index: cpu_index, - state: crate::state::steam_deck::Cpu::default(), - } - } - - fn limits(&self) -> crate::api::CpuLimits { - let max = Self::max(); - let max_clocks = max.clock_limits.unwrap(); - - let min = Self::min(); - let min_clocks = min.clock_limits.unwrap(); - crate::api::CpuLimits { - clock_min_limits: Some(RangeLimit { - min: min_clocks.min, - max: max_clocks.min - }), - clock_max_limits: Some(RangeLimit { - min: min_clocks.max, - max: max_clocks.max - }), - clock_step: 100, - governors: vec![], // TODO - } - } -} - -impl Into for Cpu { - #[inline] - fn into(self) -> CpuJson { - CpuJson { - online: self.online, - clock_limits: self.clock_limits.map(|x| x.into()), - governor: self.governor, - } - } -} - -impl OnSet for Cpu { - fn on_set(&mut self) -> Result<(), SettingError> { - self.clamp_all(); - self.set_all() - } -} - -impl OnResume for Cpu { - fn on_resume(&self) -> Result<(), SettingError> { - let mut copy = self.clone(); - copy.state.is_resuming = true; - copy.set_all() - } -} - -impl TCpu for Cpu { - fn online(&mut self) -> &mut bool { - &mut self.online - } - - fn governor(&mut self, governor: String) { - self.governor = governor; - } - - fn get_governor(&self) -> &'_ str { - &self.governor - } - - fn clock_limits(&mut self, limits: Option>) { - self.clock_limits = limits; - } - - fn get_clock_limits(&self) -> Option<&MinMax> { - self.clock_limits.as_ref() - } -} - -impl SettingsRange for Cpu { - #[inline] - fn max() -> Self { - Self { - online: true, - clock_limits: Some(MinMax { - max: 3500, - min: 3500, - }), - governor: "schedutil".to_owned(), - index: usize::MAX, - state: crate::state::steam_deck::Cpu::default(), - } - } - - #[inline] - fn min() -> Self { - Self { - online: false, - clock_limits: Some(MinMax { max: 500, min: 1400 }), - governor: "schedutil".to_owned(), - index: usize::MIN, - state: crate::state::steam_deck::Cpu::default(), - } - } -} - -#[inline] -fn cpu_online_path(index: usize) -> String { - format!("/sys/devices/system/cpu/cpu{}/online", index) -} - -#[inline] -fn cpu_governor_path(index: usize) -> String { - format!( - "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_governor", - index - ) -} diff --git a/backend/src/settings/steam_deck_adv/gpu.rs b/backend/src/settings/steam_deck_adv/gpu.rs deleted file mode 100644 index 7ae25b8..0000000 --- a/backend/src/settings/steam_deck_adv/gpu.rs +++ /dev/null @@ -1,310 +0,0 @@ -use std::convert::Into; - -use crate::api::RangeLimit; -use crate::settings::MinMax; -use crate::settings::{OnResume, OnSet, SettingError, SettingsRange}; -use crate::settings::TGpu; -use crate::persist::GpuJson; - -const SLOW_PPT: u8 = 1; -const FAST_PPT: u8 = 2; - -#[derive(Debug, Clone)] -pub struct Gpu { - pub fast_ppt: Option, - pub slow_ppt: Option, - pub clock_limits: Option>, - pub slow_memory: bool, - state: crate::state::steam_deck::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 { - #[inline] - pub fn from_json(other: GpuJson, version: u64) -> Self { - match version { - 0 => Self { - fast_ppt: other.fast_ppt, - slow_ppt: other.slow_ppt, - clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)), - slow_memory: other.slow_memory, - state: crate::state::steam_deck::Gpu::default(), - }, - _ => Self { - fast_ppt: other.fast_ppt, - slow_ppt: other.slow_ppt, - clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)), - slow_memory: other.slow_memory, - state: crate::state::steam_deck::Gpu::default(), - }, - } - } - - fn set_all(&mut self) -> Result<(), SettingError> { - // set fast PPT - if let Some(fast_ppt) = &self.fast_ppt { - let fast_ppt_path = gpu_power_path(FAST_PPT); - usdpl_back::api::files::write_single(&fast_ppt_path, fast_ppt).map_err(|e| { - SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - fast_ppt, &fast_ppt_path, e - ), - setting: crate::settings::SettingVariant::Gpu, - } - })?; - } - // set slow PPT - if let Some(slow_ppt) = &self.slow_ppt { - let slow_ppt_path = gpu_power_path(SLOW_PPT); - usdpl_back::api::files::write_single(&slow_ppt_path, slow_ppt).map_err(|e| { - SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - slow_ppt, &slow_ppt_path, e - ), - setting: crate::settings::SettingVariant::Gpu, - } - })?; - } - // 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| { - 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?) - usdpl_back::api::files::write_single(GPU_MEMORY_DOWNCLOCK_PATH, self.slow_memory as u8) - .map_err(|e| SettingError { - msg: format!("Failed to write to `{}`: {}", GPU_MEMORY_DOWNCLOCK_PATH, e), - setting: crate::settings::SettingVariant::Gpu, - })?; - if let Some(clock_limits) = &self.clock_limits { - // set clock limits - self.state.clock_limits_set = true; - // max clock - let payload_max = format!("s 1 {}\n", clock_limits.max); - usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_max).map_err( - |e| SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &payload_max, GPU_CLOCK_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Gpu, - }, - )?; - // min clock - let payload_min = format!("s 0 {}\n", clock_limits.min); - usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_min).map_err( - |e| SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &payload_min, GPU_CLOCK_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Gpu, - }, - )?; - } else if self.state.clock_limits_set || self.state.is_resuming { - self.state.clock_limits_set = false; - // disable manual clock limits - // max clock - let payload_max = format!("s 1 {}\n", Self::max().clock_limits.unwrap().max); - usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_max).map_err( - |e| SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &payload_max, GPU_CLOCK_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Gpu, - }, - )?; - // min clock - let payload_min = format!("s 0 {}\n", Self::min().clock_limits.unwrap().min); - usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_min).map_err( - |e| SettingError { - msg: format!( - "Failed to write `{}` to `{}`: {}", - &payload_min, GPU_CLOCK_LIMITS_PATH, e - ), - setting: crate::settings::SettingVariant::Gpu, - }, - )?; - } - // commit changes - usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").map_err(|e| { - SettingError { - msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e), - setting: crate::settings::SettingVariant::Gpu, - } - })?; - - Ok(()) - } - - fn clamp_all(&mut self) { - let min = Self::min(); - let max = Self::max(); - if let Some(fast_ppt) = &mut self.fast_ppt { - *fast_ppt = (*fast_ppt).clamp( - *min.fast_ppt.as_ref().unwrap(), - *max.fast_ppt.as_ref().unwrap(), - ); - } - if let Some(slow_ppt) = &mut self.slow_ppt { - *slow_ppt = (*slow_ppt).clamp( - *min.slow_ppt.as_ref().unwrap(), - *max.slow_ppt.as_ref().unwrap(), - ); - } - if let Some(clock_limits) = &mut self.clock_limits { - let max_boost = max.clock_limits.as_ref().unwrap(); - let min_boost = min.clock_limits.as_ref().unwrap(); - clock_limits.min = clock_limits.min.clamp(min_boost.min, max_boost.min); - clock_limits.max = clock_limits.max.clamp(min_boost.max, max_boost.max); - } - } - - pub fn system_default() -> Self { - Self { - fast_ppt: None, - slow_ppt: None, - clock_limits: None, - slow_memory: false, - state: crate::state::steam_deck::Gpu::default(), - } - } -} - -impl Into for Gpu { - #[inline] - fn into(self) -> GpuJson { - GpuJson { - fast_ppt: self.fast_ppt, - slow_ppt: self.slow_ppt, - clock_limits: self.clock_limits.map(|x| x.into()), - slow_memory: self.slow_memory, - } - } -} - -impl OnSet for Gpu { - fn on_set(&mut self) -> Result<(), SettingError> { - self.clamp_all(); - self.set_all() - } -} - -impl OnResume for Gpu { - fn on_resume(&self) -> Result<(), SettingError> { - let mut copy = self.clone(); - copy.state.is_resuming = true; - copy.set_all() - } -} - -impl SettingsRange for Gpu { - #[inline] - fn max() -> Self { - Self { - fast_ppt: Some(30_000_000), - slow_ppt: Some(29_000_000), - clock_limits: Some(MinMax { - min: 1600, - max: 1600, - }), - slow_memory: false, - state: crate::state::steam_deck::Gpu::default(), - } - } - - #[inline] - fn min() -> Self { - Self { - fast_ppt: Some(0), - slow_ppt: Some(1000000), - clock_limits: Some(MinMax { min: 200, max: 200 }), - slow_memory: true, - state: crate::state::steam_deck::Gpu::default(), - } - } -} - -impl TGpu for Gpu { - fn limits(&self) -> crate::api::GpuLimits { - let max = Self::max(); - let max_clock_limits = max.clock_limits.unwrap(); - - let min = Self::min(); - let min_clock_limits = min.clock_limits.unwrap(); - crate::api::GpuLimits { - fast_ppt_limits: Some(RangeLimit { - min: min.fast_ppt.unwrap(), - max: max.fast_ppt.unwrap(), - }), - slow_ppt_limits: Some(RangeLimit { - min: min.slow_ppt.unwrap(), - max: max.slow_ppt.unwrap(), - }), - ppt_step: 1_000_000, - tdp_limits: None, - tdp_boost_limits: None, - tdp_step: 42, - clock_min_limits: Some(RangeLimit { - min: min_clock_limits.min, - max: max_clock_limits.max, - }), - clock_max_limits: Some(RangeLimit { - min: min_clock_limits.min, - max: max_clock_limits.max, - }), - clock_step: 100, - memory_control_capable: true, - } - } - - fn json(&self) -> crate::persist::GpuJson { - self.clone().into() - } - - fn ppt(&mut self, fast: Option, slow: Option) { - self.fast_ppt = fast; - self.slow_ppt = slow; - } - - fn get_ppt(&self) -> (Option, Option) { - (self.fast_ppt, self.slow_ppt) - } - - fn clock_limits(&mut self, limits: Option>) { - self.clock_limits = limits; - } - - fn get_clock_limits(&self) -> Option<&MinMax> { - self.clock_limits.as_ref() - } - - fn slow_memory(&mut self) -> &mut bool { - &mut self.slow_memory - } - - fn provider(&self) -> crate::persist::DriverJson { - crate::persist::DriverJson::SteamDeckAdvance - } -} - -#[inline] -fn gpu_power_path(power_number: u8) -> String { - format!("/sys/class/hwmon/hwmon4/power{}_cap", power_number) -} diff --git a/backend/src/settings/steam_deck_adv/mod.rs b/backend/src/settings/steam_deck_adv/mod.rs deleted file mode 100644 index 4a6bb90..0000000 --- a/backend/src/settings/steam_deck_adv/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//mod battery; -mod cpu; -mod gpu; - -//pub use battery::Battery; -pub use cpu::{Cpu, Cpus}; -pub use gpu::Gpu;