@@ -14,14 +14,15 @@ use amdgpu_sysfs::{
1414 CommitHandle , GpuHandle , PerformanceLevel , PowerLevelKind , PowerLevels ,
1515 } ,
1616 hw_mon:: { FanControlMethod , HwMon } ,
17+ sysfs:: SysFS ,
1718} ;
1819use anyhow:: { anyhow, Context } ;
1920use futures:: { future:: LocalBoxFuture , FutureExt } ;
2021use lact_schema:: {
2122 ClocksInfo , ClockspeedStats , DeviceInfo , DeviceStats , DrmInfo , FanStats , IntelDrmInfo ,
2223 LinkInfo , PmfwInfo , PowerState , PowerStates , PowerStats , VoltageStats , VramStats ,
2324} ;
24- use libdrm_amdgpu_sys:: AMDGPU :: { ThrottleStatus , ThrottlerBit } ;
25+ use libdrm_amdgpu_sys:: AMDGPU :: { GpuMetrics , ThrottleStatus , ThrottlerBit } ;
2526use libdrm_amdgpu_sys:: { LibDrmAmdgpu , AMDGPU :: SENSOR_INFO :: SENSOR_TYPE } ;
2627use std:: {
2728 cell:: RefCell ,
@@ -102,6 +103,12 @@ impl AmdGpuController {
102103
103104 // Use PMFW curve functionality for static speed when it is available
104105 if let Ok ( current_curve) = self . handle . get_fan_curve ( ) {
106+ if let Ok ( true ) = self . handle . get_fan_zero_rpm_enable ( ) {
107+ if let Err ( err) = self . handle . set_fan_zero_rpm_enable ( false ) {
108+ error ! ( "could not disable zero RPM mode for static fan control: {err}" ) ;
109+ }
110+ }
111+
105112 let allowed_ranges = current_curve. allowed_ranges . clone ( ) . ok_or_else ( || {
106113 anyhow ! ( "The GPU does not allow setting custom fan values (is overdrive enabled?)" )
107114 } ) ?;
@@ -606,6 +613,9 @@ impl GpuController for AmdGpuController {
606613 }
607614
608615 fn get_stats ( & self , gpu_config : Option < & config:: Gpu > ) -> DeviceStats {
616+ let metrics = GpuMetrics :: get_from_sysfs_path ( self . handle . get_path ( ) ) . ok ( ) ;
617+ let metrics = metrics. as_ref ( ) ;
618+
609619 let fan_settings = gpu_config. and_then ( |config| config. fan_control_settings . as_ref ( ) ) ;
610620 DeviceStats {
611621 fan : FanStats {
@@ -615,10 +625,18 @@ impl GpuController for AmdGpuController {
615625 curve : fan_settings. map ( |settings| settings. curve . 0 . clone ( ) ) ,
616626 spindown_delay_ms : fan_settings. and_then ( |settings| settings. spindown_delay_ms ) ,
617627 change_threshold : fan_settings. and_then ( |settings| settings. change_threshold ) ,
618- speed_current : self . hw_mon_and_then ( HwMon :: get_fan_current) ,
628+ speed_current : self . hw_mon_and_then ( HwMon :: get_fan_current) . or_else ( || {
629+ metrics
630+ . and_then ( MetricsInfo :: get_current_fan_speed)
631+ . map ( u32:: from)
632+ } ) ,
619633 speed_max : self . hw_mon_and_then ( HwMon :: get_fan_max) ,
620634 speed_min : self . hw_mon_and_then ( HwMon :: get_fan_min) ,
621- pwm_current : self . hw_mon_and_then ( HwMon :: get_fan_pwm) ,
635+ pwm_current : self . hw_mon_and_then ( HwMon :: get_fan_pwm) . or_else ( || {
636+ metrics
637+ . and_then ( MetricsInfo :: get_fan_pwm)
638+ . and_then ( |pwm| u8:: try_from ( pwm) . ok ( ) )
639+ } ) ,
622640 pmfw_info : PmfwInfo {
623641 acoustic_limit : self . handle . get_fan_acoustic_limit ( ) . ok ( ) ,
624642 acoustic_target : self . handle . get_fan_acoustic_target ( ) . ok ( ) ,
@@ -667,11 +685,32 @@ impl GpuController for AmdGpuController {
667685 }
668686 }
669687
670- fn get_clocks_info ( & self ) -> anyhow:: Result < ClocksInfo > {
671- let clocks_table = self
688+ fn get_clocks_info ( & self , gpu_config : Option < & config :: Gpu > ) -> anyhow:: Result < ClocksInfo > {
689+ let mut clocks_table = self
672690 . handle
673691 . get_clocks_table ( )
674692 . context ( "Clocks table not available" ) ?;
693+
694+ if let ClocksTableGen :: Vega20 ( table) = & mut clocks_table {
695+ // Workaround for RDNA4 not reporting current SCLK offset in the original format:
696+ // https://github.com/ilya-zlobintsev/LACT/issues/485#issuecomment-2712502906
697+ if table. rdna4_sclk_offset_workaround {
698+ // The values present in the old clocks table format for the current slck offset are rubbish,
699+ // we should report the configured value instead
700+ let offset = gpu_config
701+ . and_then ( |config| {
702+ config
703+ . clocks_configuration
704+ . gpu_clock_offsets
705+ . get ( & 0 )
706+ . copied ( )
707+ } )
708+ . unwrap_or ( 0 ) ;
709+
710+ table. sclk_offset = Some ( offset) ;
711+ }
712+ }
713+
675714 Ok ( clocks_table. into ( ) )
676715 }
677716
@@ -836,7 +875,7 @@ impl GpuController for AmdGpuController {
836875 commit_handles. push ( handle) ;
837876 }
838877 Err ( err) => {
839- error ! ( "custom clock settings are present but will be ignored, but could not get clocks table: {err}" ) ;
878+ error ! ( "custom clock settings are present but will be ignored, could not get clocks table: {err}" ) ;
840879 }
841880 }
842881 }
@@ -969,30 +1008,36 @@ impl GpuController for AmdGpuController {
9691008
9701009 // Unlike the other PMFW options, zero rpm should be functional with a custom curve
9711010 if let Some ( zero_rpm) = config. pmfw_options . zero_rpm {
972- let current_zero_rpm = self
973- . handle
974- . get_fan_zero_rpm_enable ( )
975- . context ( "Could not get zero RPM mode" ) ?;
976- if current_zero_rpm != zero_rpm {
977- let commit_handle = self
978- . handle
979- . set_fan_zero_rpm_enable ( zero_rpm)
980- . context ( "Could not set zero RPM mode" ) ?;
981- commit_handles. push ( commit_handle) ;
1011+ match self . handle . get_fan_zero_rpm_enable ( ) {
1012+ Ok ( current_zero_rpm) => {
1013+ if current_zero_rpm != zero_rpm {
1014+ let commit_handle = self
1015+ . handle
1016+ . set_fan_zero_rpm_enable ( zero_rpm)
1017+ . context ( "Could not set zero RPM mode" ) ?;
1018+ commit_handles. push ( commit_handle) ;
1019+ }
1020+ }
1021+ Err ( err) => {
1022+ error ! ( "zero RPM is present in the config, but not available on the GPU: {err}" ) ;
1023+ }
9821024 }
9831025 }
9841026
9851027 if let Some ( zero_rpm_threshold) = config. pmfw_options . zero_rpm_threshold {
986- let current_threshold = self
987- . handle
988- . get_fan_zero_rpm_stop_temperature ( )
989- . context ( "Could not get zero RPM temperature" ) ?;
990- if current_threshold. current != zero_rpm_threshold {
991- let commit_handle = self
992- . handle
993- . set_fan_zero_rpm_stop_temperature ( zero_rpm_threshold)
994- . context ( "Could not set zero RPM temperature" ) ?;
995- commit_handles. push ( commit_handle) ;
1028+ match self . handle . get_fan_zero_rpm_stop_temperature ( ) {
1029+ Ok ( current_threshold) => {
1030+ if current_threshold. current != zero_rpm_threshold {
1031+ let commit_handle = self
1032+ . handle
1033+ . set_fan_zero_rpm_stop_temperature ( zero_rpm_threshold)
1034+ . context ( "Could not set zero RPM temperature" ) ?;
1035+ commit_handles. push ( commit_handle) ;
1036+ }
1037+ }
1038+ Err ( err) => {
1039+ error ! ( "zero RPM threshold is present in the config, but not available on the GPU: {err}" ) ;
1040+ }
9961041 }
9971042 }
9981043
@@ -1073,6 +1118,10 @@ impl ClocksConfiguration {
10731118 Some ( offset) => table. set_voltage_offset ( offset) ?,
10741119 None => table. voltage_offset = None ,
10751120 }
1121+
1122+ if let Some ( offset) = self . gpu_clock_offsets . get ( & 0 ) {
1123+ table. sclk_offset = Some ( * offset) ;
1124+ }
10761125 }
10771126
10781127 if let Some ( min_clockspeed) = self . min_core_clock {
0 commit comments