On 10-Jun-26 11:53 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 | 53 ++++++++++++++++---
1 file changed, 46 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 1be8d1a8da19..c01c71acbe3f 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
@@ -1190,14 +1190,53 @@ 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;
+ uint32_t diff;
+ 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) {
+ closest_idx = i;
+ exact_match = true;
+ break;
+ }
+
+ diff = abs((int)cur_value - (int)value);
+ if (diff < closest_diff) {
+ closest_diff = diff;
+ closest_idx = i;
+ } else if (diff > closest_diff) {
+ break;
+ }
+ }
- 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)
exact_match is redundant now. It only needs closest_idx check.
Thanks,
Lijo
+ 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: