SmuMetrics_t has no DclkFrequency field but DCLK and VCLK have
separate DPM clock tables with different frequencies at each level.

Introduce smu_v14_0_0_find_clk_level(), a shared helper that
finds the closest DPM level for a given target frequency in a
frequency array.

For METRICS_AVERAGE_DCLK, use the helper to find the DPM level
whose VCLK frequency matches the reported VclkFrequency and
return the DCLK frequency at that same level index, since both
clocks share the same level count (VcnClkLevelsEnabled /
Vcn0ClkLevelsEnabled).

The original code returned 0 for METRICS_AVERAGE_DCLK, which broke
the active-level marker in pp_dpm_dclk entirely.

Signed-off-by: Priya Hosur <[email protected]>
---
 .../drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c  | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)

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 2fe006de927a..b206a4d0376b 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
@@ -260,6 +260,35 @@ static int smu_v14_0_0_system_features_control(struct 
smu_context *smu, bool en)
        return ret;
 }
 
+/**
+ * smu_v14_0_0_find_clk_level - find the closest DPM level for a frequency
+ * @freqs: array of frequencies (one per DPM level)
+ * @count: number of valid entries in @freqs
+ * @target: the frequency to match
+ *
+ * Returns the index of the DPM level whose frequency is closest to @target.
+ * If an exact match exists it is preferred; otherwise the nearest level by
+ * absolute difference is returned.
+ */
+static uint8_t smu_v14_0_0_find_clk_level(const uint32_t *freqs, uint8_t count,
+                                          uint32_t target)
+{
+       uint8_t i, closest = 0;
+       uint32_t best_diff = U32_MAX;
+
+       for (i = 0; i < count; i++) {
+               uint32_t diff = abs((int)target - (int)freqs[i]);
+
+               if (diff < best_diff) {
+                       best_diff = diff;
+                       closest = i;
+               }
+               if (freqs[i] == target)
+                       return i;
+       }
+       return closest;
+}
+
 static int smu_v14_0_0_get_smu_metrics_data(struct smu_context *smu,
                                            MetricsMember_t member,
                                            uint32_t *value)
@@ -284,7 +313,30 @@ static int smu_v14_0_0_get_smu_metrics_data(struct 
smu_context *smu,
                *value = metrics->VclkFrequency;
                break;
        case METRICS_AVERAGE_DCLK:
+               /*
+                * SmuMetrics_t has no DclkFrequency field.  DCLK and VCLK
+                * share the same DPM level count, so find the DPM level
+                * whose VCLK matches the reported VclkFrequency and return
+                * the DCLK frequency at that level.
+                */
                *value = 0;
+               if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(14, 
0, 1)) {
+                       DpmClocks_t_v14_0_1 *clk_table = 
smu->smu_table.clocks_table;
+                       uint8_t lvl = smu_v14_0_0_find_clk_level(
+                                       clk_table->VClocks0,
+                                       clk_table->Vcn0ClkLevelsEnabled,
+                                       metrics->VclkFrequency);
+
+                       *value = clk_table->DClocks0[lvl];
+               } else {
+                       DpmClocks_t *clk_table = smu->smu_table.clocks_table;
+                       uint8_t lvl = smu_v14_0_0_find_clk_level(
+                                       clk_table->VClocks,
+                                       clk_table->VcnClkLevelsEnabled,
+                                       metrics->VclkFrequency);
+
+                       *value = clk_table->DClocks[lvl];
+               }
                break;
        case METRICS_AVERAGE_UCLK:
                *value = metrics->MemclkFrequency;
-- 
2.43.0

Reply via email to