On 10-Jun-26 5:39 PM, Priya Hosur wrote:
Replace the simple exact-match loop in emit_clk_levels with a
two-pass approach: the first pass checks whether the current
frequency matches any DPM level exactly and also tracks the closest
level by absolute frequency difference. The second pass emits the
levels, marking the exact match if found, otherwise the closest
level.
The SMU reports time-filtered average frequencies that often do not
match any DPM table entry exactly. Without this fallback, MCLK,
FCLK and other clocks show DPM levels but never display the *
marker, breaking userspace tools that rely on it to identify the
active frequency.
Also uses reverse DPM index for SMU_MCLK since MemPstateTable
stores levels high-to-low.
Signed-off-by: Priya Hosur <[email protected]>
---
.../drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c | 46 ++++++++++++++++---
1 file changed, 39 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
index c203e828cce4..b113cf2b26fa 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
@@ -1195,14 +1195,46 @@ static int smu_v14_0_0_emit_clk_levels(struct
smu_context *smu,
if (ret)
return ret;
- for (i = 0; i < count; i++) {
- idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i;
- ret = smu_v14_0_common_get_dpm_freq_by_index(smu, clk_type,
idx, &value);
- if (ret)
- return ret;
+ /*
+ * Try exact match first. If the SMU reports a time-averaged
+ * frequency that doesn't match any DPM level exactly, fall
+ * back to marking the closest DPM level.
+ */
+ {
+ int closest_idx = 0;
+ uint32_t closest_diff = U32_MAX;
+ bool exact_match = false;
+
+ for (i = 0; i < count; i++) {
+ idx = (clk_type == SMU_MCLK) ? (count - i - 1)
: i;
+ ret = smu_v14_0_common_get_dpm_freq_by_index(smu,
clk_type, idx, &value);
+ if (ret)
+ return ret;
+
+ if (cur_value == value)
+ exact_match = true;
What about closest_idx = i; and break here? You may also break the loop
if new_diff > closest_diff
Thanks,
Lijo
+
+ if (abs((int)cur_value - (int)value) <
closest_diff) {
+ closest_diff = abs((int)cur_value -
(int)value);
+ closest_idx = i;
+ }
+ }
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
- cur_value == value ? "*" : "");
+ for (i = 0; i < count; i++) {
+ idx = (clk_type == SMU_MCLK) ? (count - i - 1)
: i;
+ ret = smu_v14_0_common_get_dpm_freq_by_index(smu,
clk_type, idx, &value);
+ if (ret)
+ return ret;
+
+ if (exact_match)
+ size += sysfs_emit_at(buf, size, "%d: %uMhz
%s\n",
+ i, value,
+ cur_value == value ? "*" :
"");
+ else
+ size += sysfs_emit_at(buf, size, "%d: %uMhz
%s\n",
+ i, value,
+ i == closest_idx ? "*" :
"");
+ }
}
break;
case SMU_DCEFCLK: