diff --git a/backend/limits_core/src/json_v2/cpu_limit.rs b/backend/limits_core/src/json_v2/cpu_limit.rs index 99ed9fd..09f746a 100644 --- a/backend/limits_core/src/json_v2/cpu_limit.rs +++ b/backend/limits_core/src/json_v2/cpu_limit.rs @@ -10,6 +10,7 @@ pub enum CpuLimitType { #[serde(rename = "GabeBoySP", alias = "SteamDeckOLED")] SteamDeckOLED, ROGAlly, + MSIClaw, Generic, GenericAMD, Unknown, diff --git a/backend/limits_core/src/json_v2/gpu_limit.rs b/backend/limits_core/src/json_v2/gpu_limit.rs index 4f91ec7..633a55c 100644 --- a/backend/limits_core/src/json_v2/gpu_limit.rs +++ b/backend/limits_core/src/json_v2/gpu_limit.rs @@ -9,6 +9,7 @@ pub enum GpuLimitType { #[serde(rename = "GabeBoySP", alias = "SteamDeckOLED")] SteamDeckOLED, ROGAlly, + MSIClaw, Generic, GenericAMD, Unknown, diff --git a/backend/src/persist/driver.rs b/backend/src/persist/driver.rs index dafc60f..d5cd7f0 100644 --- a/backend/src/persist/driver.rs +++ b/backend/src/persist/driver.rs @@ -14,6 +14,8 @@ pub enum DriverJson { GenericAMD, #[serde(rename = "rog-ally")] ROGAlly, + #[serde(rename = "msi-claw")] + MSIClaw, #[serde(rename = "unknown")] Unknown, #[default] diff --git a/backend/src/settings/detect/auto_detect.rs b/backend/src/settings/detect/auto_detect.rs index 3a32ff7..b45bf6a 100644 --- a/backend/src/settings/detect/auto_detect.rs +++ b/backend/src/settings/detect/auto_detect.rs @@ -145,6 +145,13 @@ pub fn auto_detect0( relevant_limits.cpu.limits, ) ), + CpuLimitType::MSIClaw => Box::new( + crate::settings::msi_claw::Cpus::from_json_and_limits( + settings.cpus.clone(), + settings.version, + relevant_limits.cpu.limits, + ) + ), CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::< crate::settings::generic::Cpu, >::from_json_and_limits( @@ -199,6 +206,13 @@ pub fn auto_detect0( relevant_limits.gpu.limits, ) ), + GpuLimitType::MSIClaw => Box::new( + crate::settings::msi_claw::Gpu::from_json_and_limits( + settings.gpu.clone(), + settings.version, + relevant_limits.gpu.limits, + ) + ), GpuLimitType::Generic => { Box::new(crate::settings::generic::Gpu::from_json_and_limits( settings.gpu.clone(), @@ -287,6 +301,9 @@ pub fn auto_detect0( CpuLimitType::ROGAlly => Box::new( crate::settings::rog_ally::Cpus::from_limits(relevant_limits.cpu.limits) ), + CpuLimitType::MSIClaw => Box::new( + crate::settings::msi_claw::Cpus::from_limits(relevant_limits.cpu.limits) + ), CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::< crate::settings::generic::Cpu, >::from_limits( @@ -314,6 +331,9 @@ pub fn auto_detect0( GpuLimitType::ROGAlly => Box::new( crate::settings::rog_ally::Gpu::from_limits(relevant_limits.gpu.limits) ), + GpuLimitType::MSIClaw => Box::new( + crate::settings::msi_claw::Gpu::from_limits(relevant_limits.gpu.limits) + ), GpuLimitType::Generic => Box::new(crate::settings::generic::Gpu::from_limits( relevant_limits.gpu.limits, )), diff --git a/backend/src/settings/driver.rs b/backend/src/settings/driver.rs index caa21cc..88b17c6 100644 --- a/backend/src/settings/driver.rs +++ b/backend/src/settings/driver.rs @@ -39,6 +39,7 @@ pub fn maybe_do_button() { crate::settings::steam_deck::flash_led(); }, DriverJson::ROGAlly => log::info!("Roggle boggle smoggle flollop"), + DriverJson::MSIClaw => log::warn!("My condolences"), DriverJson::Generic | DriverJson::GenericAMD => { log::warn!("You need to come up with something fun on generic") } diff --git a/backend/src/settings/mod.rs b/backend/src/settings/mod.rs index 96ef472..1deae24 100644 --- a/backend/src/settings/mod.rs +++ b/backend/src/settings/mod.rs @@ -12,6 +12,7 @@ pub mod generic_amd; pub mod steam_deck; pub mod unknown; pub mod rog_ally; +pub mod msi_claw; pub use detect::{ auto_detect0, auto_detect_provider, get_dev_messages, diff --git a/backend/src/settings/msi_claw/cpu.rs b/backend/src/settings/msi_claw/cpu.rs new file mode 100644 index 0000000..0378c6d --- /dev/null +++ b/backend/src/settings/msi_claw/cpu.rs @@ -0,0 +1,155 @@ +use crate::persist::CpuJson; +use crate::settings::generic::{Cpu as GenericCpu, Cpus as GenericCpus, FromGenericCpuInfo}; +use crate::settings::MinMax; +use crate::settings::{OnResume, OnSet, SettingError}; +use crate::settings::{ProviderBuilder, TCpu, TCpus}; + +#[derive(Debug)] +pub struct Cpus { + generic: GenericCpus, +} + +impl ProviderBuilder, limits_core::json_v2::GenericCpusLimit> for Cpus { + fn from_limits(limits: limits_core::json_v2::GenericCpusLimit) -> Self { + Self { + generic: GenericCpus::from_limits(limits), + } + } + + fn from_json_and_limits( + other: Vec, + version: u64, + limits: limits_core::json_v2::GenericCpusLimit, + ) -> Self { + Self { + generic: GenericCpus::from_json_and_limits(other, version, limits), + } + } +} + +impl OnResume for Cpus { + fn on_resume(&self) -> Result<(), Vec> { + self.generic.on_resume() + // TODO + } +} + +impl OnSet for Cpus { + fn on_set(&mut self) -> Result<(), Vec> { + self.generic.on_set() + // TODO + } +} + +impl crate::settings::OnPowerEvent for Cpus {} + +impl crate::settings::OnLoad for Cpus { + fn on_load(&mut self) -> Result<(), Vec> { + Ok(()) + } +} + +impl crate::settings::OnUnload for Cpus { + fn on_unload(&mut self) -> Result<(), Vec> { + Ok(()) + } +} + +impl TCpus for Cpus { + fn limits(&self) -> crate::api::CpusLimits { + self.generic.limits() + } + + fn json(&self) -> Vec { + self.generic.json() // TODO + } + + fn cpus(&mut self) -> Vec<&mut dyn TCpu> { + self.generic.cpus() // TODO + } + + fn len(&self) -> usize { + self.generic.len() // TODO + } + + fn smt(&mut self) -> &'_ mut bool { + self.generic.smt() + } + + fn provider(&self) -> crate::persist::DriverJson { + crate::persist::DriverJson::GenericAMD + } +} + +#[derive(Debug)] +pub struct Cpu { + generic: GenericCpu, +} + +impl FromGenericCpuInfo for Cpu { + fn from_limits(cpu_index: usize, limits: limits_core::json_v2::GenericCpuLimit) -> Self { + let gen = GenericCpu::from_limits(cpu_index, limits.clone()); + Self { generic: gen } + } + + fn from_json_and_limits( + other: CpuJson, + version: u64, + cpu_index: usize, + limits: limits_core::json_v2::GenericCpuLimit, + ) -> Self { + let gen = GenericCpu::from_json_and_limits(other, version, cpu_index, limits); + Self { generic: gen } + } +} + +impl AsRef for Cpu { + fn as_ref(&self) -> &GenericCpu { + &self.generic + } +} + +impl AsMut for Cpu { + fn as_mut(&mut self) -> &mut GenericCpu { + &mut self.generic + } +} + +impl OnResume for Cpu { + fn on_resume(&self) -> Result<(), Vec> { + self.generic.on_resume() + // TODO + } +} + +impl OnSet for Cpu { + fn on_set(&mut self) -> Result<(), Vec> { + self.generic.on_set() + // TODO + } +} + +impl crate::settings::OnPowerEvent for Cpu {} + +impl TCpu for Cpu { + fn online(&mut self) -> &mut bool { + self.generic.online() + } + + fn governor(&mut self, governor: String) { + self.generic.governor(governor) + } + + fn get_governor(&self) -> &'_ str { + self.generic.get_governor() + } + + fn clock_limits(&mut self, _limits: Option>) { + //self.generic.clock_limits(limits) + // TODO: support this + } + + fn get_clock_limits(&self) -> Option> { + self.generic.get_clock_limits() + } +} diff --git a/backend/src/settings/msi_claw/gpu.rs b/backend/src/settings/msi_claw/gpu.rs new file mode 100644 index 0000000..bca31bc --- /dev/null +++ b/backend/src/settings/msi_claw/gpu.rs @@ -0,0 +1,287 @@ +use limits_core::json_v2::GenericGpuLimit; +//use sysfuss::{capability::attributes, BasicEntityPath, SysEntity}; +//use procbox::gpu::IntelGpu; // TODO + +use crate::api::RangeLimit; +use crate::persist::{GpuJson, MinMaxJson}; +use crate::settings::{min_max_from_json, MinMax}; +use crate::settings::{OnResume, OnSet, SettingError}; +use crate::settings::{ProviderBuilder, TGpu}; + +//#[derive(Clone)] +pub struct Gpu { + //gpu_impl: IntelGpu, + settings: GpuJson, + limits: GenericGpuLimit, +} + +impl Gpu { + /*fn find_badgpu(root: Option>) -> IntelGpu { + let root = crate::settings::util::root_or_default_sysfs(root); + let ent_path = match root.class( + "drm", + attributes( + crate::settings::util::CARD_NEEDS + .into_iter() + .map(|s| s.to_string()), + ), + ) { + Ok(iter) => { + let card = iter + .filter(|ent| if let Ok(name) = ent.name() { name.starts_with("card")} else { false }) + //.filter(|ent| super::util::card_also_has(ent, CARD_EXTENSIONS)) + .next() + .unwrap_or_else(|| { + log::error!("Failed to find ROG Ally gpu drm in sysfs (no results), using naive fallback"); + BasicEntityPath::new(root.as_ref().join("sys/class/drm/card1")) + }); + log::info!( + "Found ROG Ally gpu drm in sysfs: {}", + card.as_ref().display() + ); + card + } + Err(e) => { + log::error!( + "Failed to find ROG Ally gpu drm in sysfs ({}), using naive fallback", + e + ); + BasicEntityPath::new(root.as_ref().join("sys/class/drm/card1")) + } + }; + IntelGpu::new(ent_path) + }*/ +} + +impl core::fmt::Debug for Gpu { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("msi_claw::Gpu") + .field("limits", &self.limits) + //.field("settings", &self.settings) + //.field("gpu_impl", &self.gpu_impl) + .finish_non_exhaustive() + } +} + +impl ProviderBuilder for Gpu { + fn from_json_and_limits(persistent: GpuJson, _version: u64, limits: GenericGpuLimit) -> Self { + Self { + //gpu_impl: Self::find_badgpu(persistent.root.clone()), + settings: persistent, + limits, + } + } + + fn from_limits(limits: GenericGpuLimit) -> Self { + Self { + //gpu_impl: Self::find_badgpu(None::<&'static str>), + settings: GpuJson::default(), + limits, + } + } +} + +impl Into for Gpu { + #[inline] + fn into(self) -> GpuJson { + self.settings + } +} + +impl OnSet for Gpu { + fn on_set(&mut self) -> Result<(), Vec> { + // TODO + Ok(()) + } +} + +impl OnResume for Gpu { + fn on_resume(&self) -> Result<(), Vec> { + // TODO + Ok(()) + } +} + +impl crate::settings::OnPowerEvent for Gpu {} + +impl crate::settings::OnLoad for Gpu { + fn on_load(&mut self) -> Result<(), Vec> { + Ok(()) + } +} + +impl crate::settings::OnUnload for Gpu { + fn on_unload(&mut self) -> Result<(), Vec> { + Ok(()) + } +} + +impl TGpu for Gpu { + fn limits(&self) -> crate::api::GpuLimits { + crate::api::GpuLimits { + fast_ppt_limits: self + .limits + .fast_ppt + .clone() + .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15))) + .map(|mut x| { + if let Some(ppt_divisor) = self.limits.ppt_divisor { + x.min /= ppt_divisor; + x.max /= ppt_divisor; + x + } else { + x + } + }), + fast_ppt_default: { + let def = self + .limits + .fast_ppt_default + .or_else(|| self.limits.fast_ppt.and_then(|x| x.max)) + .unwrap_or(15); + if let Some(ppt_divisor) = self.limits.ppt_divisor { + def / ppt_divisor + } else { + def + } + }, + slow_ppt_limits: self + .limits + .slow_ppt + .clone() + .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15))) + .map(|mut x| { + if let Some(ppt_divisor) = self.limits.ppt_divisor { + x.min /= ppt_divisor; + x.max /= ppt_divisor; + x + } else { + x + } + }), + slow_ppt_default: { + let def = self + .limits + .slow_ppt_default + .or_else(|| self.limits.slow_ppt.and_then(|x| x.max)) + .unwrap_or(15); + if let Some(ppt_divisor) = self.limits.ppt_divisor { + def / ppt_divisor + } else { + def + } + }, + ppt_step: self.limits.ppt_step.unwrap_or(1), + tdp_limits: self + .limits + .tdp + .clone() + .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))), + tdp_boost_limits: self + .limits + .tdp_boost + .clone() + .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))), + tdp_step: self.limits.tdp_step.unwrap_or(42), + clock_min_limits: self + .limits + .clock_min + .clone() + .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(3_000))), + clock_max_limits: self + .limits + .clock_max + .clone() + .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(3_000))), + clock_step: self.limits.clock_step.unwrap_or(100), + memory_control: None, + memory_step: 100, + } + } + + fn json(&self) -> crate::persist::GpuJson { + self.settings.clone() + } + + fn ppt(&mut self, fast: Option, slow: Option) { + if let Some(fast_lims) = &self.limits.fast_ppt { + self.settings.fast_ppt = fast + .map(|x| { + if let Some(ppt_divisor) = self.limits.ppt_divisor { + x * ppt_divisor + } else { + x + } + }) + .map(|x| { + x.clamp( + fast_lims.min.unwrap_or(0), + fast_lims.max.unwrap_or(u64::MAX), + ) + }); + } + if let Some(slow_lims) = &self.limits.slow_ppt { + self.settings.slow_ppt = slow + .map(|x| { + if let Some(ppt_divisor) = self.limits.ppt_divisor { + x * ppt_divisor + } else { + x + } + }) + .map(|x| { + x.clamp( + slow_lims.min.unwrap_or(0), + slow_lims.max.unwrap_or(u64::MAX), + ) + }); + } + } + + fn get_ppt(&self) -> (Option, Option) { + ( + self.settings.fast_ppt.map(|x| { + if let Some(ppt_divisor) = self.limits.ppt_divisor { + x / ppt_divisor + } else { + x + } + }), + self.settings.slow_ppt.map(|x| { + if let Some(ppt_divisor) = self.limits.ppt_divisor { + x / ppt_divisor + } else { + x + } + }), + ) + } + + fn clock_limits(&mut self, limits: Option>) { + if let Some(clock_min) = &self.limits.clock_min { + if let Some(clock_max) = &self.limits.clock_max { + self.settings.clock_limits = limits.map(|x| { + MinMaxJson { + min: x.min.clamp(clock_min.min, clock_min.max), + max: x.max.clamp(clock_max.max, clock_max.max) + } + }); + } + } + } + + fn get_clock_limits(&self) -> Option> { + self.settings.clock_limits.clone().map(|mmj| min_max_from_json(mmj, 1)) + } + + fn memory_clock(&mut self, _speed: Option) {} + + fn get_memory_clock(&self) -> Option { + None + } + + fn provider(&self) -> crate::persist::DriverJson { + crate::persist::DriverJson::Generic + } +} + diff --git a/backend/src/settings/msi_claw/mod.rs b/backend/src/settings/msi_claw/mod.rs new file mode 100644 index 0000000..96f0bcb --- /dev/null +++ b/backend/src/settings/msi_claw/mod.rs @@ -0,0 +1,6 @@ +mod cpu; +mod gpu; +mod util; + +pub use cpu::Cpus; +pub use gpu::Gpu; diff --git a/backend/src/settings/msi_claw/util.rs b/backend/src/settings/msi_claw/util.rs new file mode 100644 index 0000000..e69de29