From 500fde964ca8692602220bfcdfb3607eae06fcb6 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Mon, 2 Jan 2023 18:47:14 -0500 Subject: [PATCH] Implement RyzenAdj driver for AMD --- backend/src/settings/generic/cpu.rs | 4 +- backend/src/settings/generic/gpu.rs | 26 ++-- backend/src/settings/generic_amd/cpu.rs | 5 +- backend/src/settings/generic_amd/gpu.rs | 153 +++++++++++++++++++++++- backend/src/state/generic/gpu.rs | 16 +++ backend/src/state/generic/mod.rs | 3 + backend/src/state/mod.rs | 1 + 7 files changed, 189 insertions(+), 19 deletions(-) create mode 100644 backend/src/state/generic/gpu.rs create mode 100644 backend/src/state/generic/mod.rs diff --git a/backend/src/settings/generic/cpu.rs b/backend/src/settings/generic/cpu.rs index fcf90c9..a2fe995 100644 --- a/backend/src/settings/generic/cpu.rs +++ b/backend/src/settings/generic/cpu.rs @@ -169,12 +169,12 @@ pub struct Cpu { state: crate::state::steam_deck::Cpu, } -impl Cpu { +/*impl Cpu { #[inline] pub fn index(&self) -> usize { self.index } -} +}*/ impl AsRef for Cpu { #[inline] diff --git a/backend/src/settings/generic/gpu.rs b/backend/src/settings/generic/gpu.rs index aa1a111..7e658a4 100644 --- a/backend/src/settings/generic/gpu.rs +++ b/backend/src/settings/generic/gpu.rs @@ -9,10 +9,10 @@ use crate::persist::GpuJson; #[derive(Debug, Clone)] pub struct Gpu { - slow_memory: bool, - fast_ppt: Option, - slow_ppt: Option, - clock_limits: Option>, + pub slow_memory: bool, + pub fast_ppt: Option, + pub slow_ppt: Option, + pub clock_limits: Option>, limits: GenericGpuLimit, } @@ -101,11 +101,11 @@ impl TGpu for Gpu { } fn ppt(&mut self, fast: Option, slow: Option) { - if self.limits.fast_ppt.is_some() { - self.fast_ppt = fast; + if let Some(fast_lims) = &self.limits.fast_ppt { + self.fast_ppt = fast.map(|x| x.clamp(fast_lims.min, fast_lims.max)); } - if self.limits.slow_ppt.is_some() { - self.slow_ppt = slow; + if let Some(slow_lims) = &self.limits.slow_ppt { + self.slow_ppt = slow.map(|x| x.clamp(slow_lims.min, slow_lims.max)); } } @@ -114,8 +114,14 @@ impl TGpu for Gpu { } fn clock_limits(&mut self, limits: Option>) { - if self.limits.clock_min.is_some() && self.limits.clock_max.is_some() { - self.clock_limits = limits; + if let Some(clock_min) = &self.limits.clock_min { + if let Some(clock_max) = &self.limits.clock_max { + self.clock_limits = limits.map(|mut x| { + x.min = x.min.clamp(clock_min.min, clock_min.max); + x.max = x.max.clamp(clock_max.max, clock_max.max); + x + }); + } } } diff --git a/backend/src/settings/generic_amd/cpu.rs b/backend/src/settings/generic_amd/cpu.rs index e698c72..74f5c5b 100644 --- a/backend/src/settings/generic_amd/cpu.rs +++ b/backend/src/settings/generic_amd/cpu.rs @@ -123,8 +123,9 @@ impl TCpu for Cpu { self.generic.get_governor() } - fn clock_limits(&mut self, limits: Option>) { - self.generic.clock_limits(limits) + fn clock_limits(&mut self, _limits: Option>) { + //self.generic.clock_limits(limits) + // TODO: support this } fn get_clock_limits(&self) -> Option<&MinMax> { diff --git a/backend/src/settings/generic_amd/gpu.rs b/backend/src/settings/generic_amd/gpu.rs index 8c9654c..ca4dffe 100644 --- a/backend/src/settings/generic_amd/gpu.rs +++ b/backend/src/settings/generic_amd/gpu.rs @@ -1,39 +1,182 @@ +use std::sync::Mutex; +use ryzenadj_rs::RyzenAccess; + use crate::persist::GpuJson; use crate::settings::MinMax; use crate::settings::generic::Gpu as GenericGpu; -use crate::settings::{OnResume, OnSet, SettingError}; +use crate::settings::{OnResume, OnSet, SettingError, SettingVariant}; use crate::settings::TGpu; +fn ryzen_adj_or_log() -> Option> { + match RyzenAccess::new() { + Ok(x) => Some(Mutex::new(x)), + Err(e) => { + log::error!("RyzenAdj init error: {}", e); + None + } + } +} + #[derive(Debug)] pub struct Gpu { generic: GenericGpu, + implementor: Option>, + state: crate::state::generic::Gpu, // NOTE this is re-used for simplicity } impl Gpu { pub fn from_limits(limits: limits_core::json::GenericGpuLimit) -> Self { Self { generic: GenericGpu::from_limits(limits), + implementor: ryzen_adj_or_log(), + state: Default::default(), } } pub fn from_json_and_limits(other: GpuJson, version: u64, limits: limits_core::json::GenericGpuLimit) -> Self { Self { generic: GenericGpu::from_json_and_limits(other, version, limits), + implementor: ryzen_adj_or_log(), + state: Default::default(), } } + + fn set_all(&mut self) -> Result<(), SettingError> { + let mutex = match &self.implementor { + Some(x) => x, + None => { + return Err(SettingError { + msg: "RyzenAdj unavailable".to_owned(), + setting: SettingVariant::Gpu, + }); + } + }; + let lock = match mutex.lock() { + Ok(x) => x, + Err(e) => { + return Err(SettingError { + msg: format!("RyzenAdj lock acquire failed: {}", e), + setting: SettingVariant::Gpu, + }); + } + }; + if let Some(fast_ppt) = &self.generic.fast_ppt { + if self.state.old_fast_ppt.is_none() { + self.state.old_fast_ppt = Some(lock.get_fast_value() as _); + } + lock.set_fast_limit(*fast_ppt as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_fast_limit({}) err: {}", *fast_ppt, e), + setting: SettingVariant::Gpu, + })?; + } else if let Some(fast_ppt) = &self.state.old_fast_ppt { + lock.set_fast_limit(*fast_ppt as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_fast_limit({}) err: {}", *fast_ppt, e), + setting: SettingVariant::Gpu, + })?; + self.state.old_fast_ppt = None; + } + if let Some(slow_ppt) = &self.generic.slow_ppt { + if self.state.old_slow_ppt.is_none() { + self.state.old_slow_ppt = Some(lock.get_slow_value() as _); + } + lock.set_slow_limit(*slow_ppt as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_slow_limit({}) err: {}", *slow_ppt, e), + setting: SettingVariant::Gpu, + })?; + } else if let Some(slow_ppt) = &self.state.old_slow_ppt { + lock.set_slow_limit(*slow_ppt as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_slow_limit({}) err: {}", *slow_ppt, e), + setting: SettingVariant::Gpu, + })?; + self.state.old_slow_ppt = None; + } + if let Some(clock_limits) = &self.generic.clock_limits { + self.state.clock_limits_set = true; + lock.set_max_gfxclk_freq(clock_limits.max as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_max_gfxclk_freq({}) err: {}", clock_limits.max, e), + setting: SettingVariant::Gpu, + })?; + lock.set_min_gfxclk_freq(clock_limits.min as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_min_gfxclk_freq({}) err: {}", clock_limits.min, e), + setting: SettingVariant::Gpu, + })?; + } else if self.state.clock_limits_set { + self.state.clock_limits_set = false; + let limits = self.generic.limits(); + if let Some(min_limits) = limits.clock_min_limits { + if let Some(max_limits) = limits.clock_max_limits { + lock.set_max_gfxclk_freq(max_limits.max as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_max_gfxclk_freq({}) err: {}", max_limits.max, e), + setting: SettingVariant::Gpu, + })?; + lock.set_min_gfxclk_freq(min_limits.min as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_min_gfxclk_freq({}) err: {}", min_limits.min, e), + setting: SettingVariant::Gpu, + })?; + } + } + } + Ok(()) + } + + fn resume_all(&self) -> Result<(), SettingError> { + // like set_all() but without updating state + // -- assumption: state is already up to date + let mutex = match &self.implementor { + Some(x) => x, + None => { + return Err(SettingError { + msg: "RyzenAdj unavailable".to_owned(), + setting: SettingVariant::Gpu, + }); + } + }; + let lock = match mutex.lock() { + Ok(x) => x, + Err(e) => { + return Err(SettingError { + msg: format!("RyzenAdj lock acquire failed: {}", e), + setting: SettingVariant::Gpu, + }); + } + }; + if let Some(fast_ppt) = &self.generic.fast_ppt { + lock.set_fast_limit(*fast_ppt as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_fast_limit({}) err: {}", *fast_ppt, e), + setting: SettingVariant::Gpu, + })?; + } + if let Some(slow_ppt) = &self.generic.slow_ppt { + lock.set_slow_limit(*slow_ppt as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_slow_limit({}) err: {}", *slow_ppt, e), + setting: SettingVariant::Gpu, + })?; + } + if let Some(clock_limits) = &self.generic.clock_limits { + lock.set_max_gfxclk_freq(clock_limits.max as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_max_gfxclk_freq({}) err: {}", clock_limits.max, e), + setting: SettingVariant::Gpu, + })?; + lock.set_min_gfxclk_freq(clock_limits.min as _).map_err(|e| SettingError { + msg: format!("RyzenAdj set_min_gfxclk_freq({}) err: {}", clock_limits.min, e), + setting: SettingVariant::Gpu, + })?; + } + Ok(()) + } } impl OnResume for Gpu { fn on_resume(&self) -> Result<(), SettingError> { - self.generic.on_resume() - // TODO + self.generic.on_resume()?; + self.resume_all() } } impl OnSet for Gpu { fn on_set(&mut self) -> Result<(), SettingError> { - self.generic.on_set() - // TODO + self.generic.on_set()?; + self.set_all() } } diff --git a/backend/src/state/generic/gpu.rs b/backend/src/state/generic/gpu.rs new file mode 100644 index 0000000..51e0909 --- /dev/null +++ b/backend/src/state/generic/gpu.rs @@ -0,0 +1,16 @@ +#[derive(Debug, Clone)] +pub struct Gpu { + pub clock_limits_set: bool, + pub old_fast_ppt: Option, + pub old_slow_ppt: Option, +} + +impl std::default::Default for Gpu { + fn default() -> Self { + Self { + clock_limits_set: false, + old_fast_ppt: None, + old_slow_ppt: None, + } + } +} diff --git a/backend/src/state/generic/mod.rs b/backend/src/state/generic/mod.rs new file mode 100644 index 0000000..d91c88c --- /dev/null +++ b/backend/src/state/generic/mod.rs @@ -0,0 +1,3 @@ +mod gpu; + +pub use gpu::Gpu; diff --git a/backend/src/state/mod.rs b/backend/src/state/mod.rs index 72ca58f..570de60 100644 --- a/backend/src/state/mod.rs +++ b/backend/src/state/mod.rs @@ -1,6 +1,7 @@ mod error; mod traits; +pub mod generic; pub mod steam_deck; pub use error::StateError;