From 3b8d3359c3b726bdc7dfaebfe83801802160604b Mon Sep 17 00:00:00 2001 From: Roman Makarov Date: Sat, 28 Feb 2026 09:59:27 +0100 Subject: [PATCH] feat: add support for nvidia acoustic target temp (#917) * upd nvml * wip * don't set target temp if none is provided and reset * refactor * naming * cache current init target temp in config for pseudo-reset * cleanup * fmt/tests * pass gpu config to cleanup * upd capture_initial_pmfw_values fix clippy warnings * remove redundant read * remove redundant config read * clean up * refactor reset_pmfw config lock * remove initial_target_temp from config * return reset_pmfw_settings back to intel * revert the flags override * remove diff noise * remove deprecated value from default config --- .gitignore | 3 +- .../src/server/gpu_controller/nvidia.rs | 68 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 415b3634..91d3afce 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ appimage-build/ pkg/output build/ .flatpak-builder/ -.vscode \ No newline at end of file +.vscode +.idea \ No newline at end of file diff --git a/lact-daemon/src/server/gpu_controller/nvidia.rs b/lact-daemon/src/server/gpu_controller/nvidia.rs index 52ee76e9..6f131880 100644 --- a/lact-daemon/src/server/gpu_controller/nvidia.rs +++ b/lact-daemon/src/server/gpu_controller/nvidia.rs @@ -10,7 +10,10 @@ use crate::{ vulkan::get_vulkan_info, }, }; -use amdgpu_sysfs::{gpu_handle::power_profile_mode::PowerProfileModesTable, hw_mon::Temperature}; +use amdgpu_sysfs::{ + gpu_handle::{fan_control::FanInfo, power_profile_mode::PowerProfileModesTable}, + hw_mon::Temperature, +}; use anyhow::{Context, anyhow, bail}; use driver::DriverHandle; use futures::{FutureExt, future::LocalBoxFuture, join}; @@ -53,6 +56,7 @@ pub struct NvidiaGpuController { nvapi: Option<&'static NvApi>, common: CommonControllerInfo, fan_control_handle: RefCell>, + initial_target_temp: Option, driver_handle: Option, nvapi_handle: Option, @@ -120,6 +124,10 @@ impl NvidiaGpuController { } }; + let target_temp = device + .temperature_threshold(TemperatureThreshold::AcousticCurr) + .ok(); + Ok(Self { nvml, nvapi, @@ -127,6 +135,7 @@ impl NvidiaGpuController { driver_handle, nvapi_handle, nvapi_thermals_mask, + initial_target_temp: target_temp, last_util_timestamp: Cell::new(None), fan_control_handle: RefCell::new(None), last_applied_offsets: RefCell::new(HashMap::new()), @@ -141,6 +150,24 @@ impl NvidiaGpuController { .expect("Can no longer get device") } + fn get_target_temp(&self) -> Option { + let device = self.device(); + let current = device + .temperature_threshold(TemperatureThreshold::AcousticCurr) + .ok()?; + let min = device + .temperature_threshold(TemperatureThreshold::AcousticMin) + .ok()?; + let max = device + .temperature_threshold(TemperatureThreshold::AcousticMax) + .ok()?; + + Some(FanInfo { + current, + allowed_range: Some((min, max)), + }) + } + async fn start_curve_fan_control_task( &self, curve: FanCurve, @@ -605,7 +632,10 @@ impl GpuController for NvidiaGpuController { pwm_max: fan_range.map(|(_, max)| (f64::from(max) * 2.55).round() as u32), pwm_min: fan_range.map(|(min, _)| (f64::from(min) * 2.55).round() as u32), temperature_range: None, - pmfw_info: PmfwInfo::default(), + pmfw_info: PmfwInfo { + target_temp: self.get_target_temp(), + ..Default::default() + }, }, power: PowerStats { average: None, @@ -748,7 +778,22 @@ impl GpuController for NvidiaGpuController { Err(anyhow!("Not supported on Nvidia")) } - fn reset_pmfw_settings(&self) {} + fn reset_pmfw_settings(&self) { + if let Some(initial) = self.initial_target_temp { + let device = self.device(); + if let Ok(current) = device.temperature_threshold(TemperatureThreshold::AcousticCurr) + && current != initial + { + debug!("resetting target temperature to {initial}"); + if let Err(err) = device.set_temperature_threshold( + TemperatureThreshold::AcousticCurr, + initial.cast_signed(), + ) { + warn!("Could not reset target temperature: {err:#}"); + } + } + } + } fn vbios_dump(&self) -> anyhow::Result> { Err(anyhow!("Not supported on Nvidia")) @@ -901,6 +946,23 @@ impl GpuController for NvidiaGpuController { .context("Could not reset fan control")?; } + if let Some(target_temp) = config.pmfw_options.target_temperature + && let Some(info) = self.get_target_temp() + && let Some((min, max)) = info.allowed_range + { + let target_temp = target_temp.clamp(min, max); + + if info.current != target_temp { + debug!("setting target temperature to {target_temp}"); + if let Err(err) = device.set_temperature_threshold( + TemperatureThreshold::AcousticCurr, + target_temp.cast_signed(), + ) { + warn!("Could not set target temperature: {err:#}"); + } + } + } + Ok(()) }) }