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
This commit is contained in:
Roman Makarov
2026-02-28 10:59:27 +02:00
committed by GitHub
parent 9c8983bc20
commit 3b8d3359c3
2 changed files with 67 additions and 4 deletions
+2 -1
View File
@@ -8,4 +8,5 @@ appimage-build/
pkg/output
build/
.flatpak-builder/
.vscode
.vscode
.idea
@@ -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<Option<FanControlHandle>>,
initial_target_temp: Option<u32>,
driver_handle: Option<DriverHandle>,
nvapi_handle: Option<NvPhysicalGpuHandle>,
@@ -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<FanInfo> {
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<Vec<u8>> {
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(())
})
}