drm/amd/powerplay: honor hw limit on fetching metrics data
authorEvan Quan <evan.quan@amd.com>
Mon, 13 May 2019 09:31:03 +0000 (17:31 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 24 May 2019 17:20:59 +0000 (12:20 -0500)
Request too frequently may get corrupt data.

Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Feifei Xu <Feifei.Xu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
drivers/gpu/drm/amd/powerplay/smu_v11_0.c

index 3a9c253..2cb4cc2 100644 (file)
@@ -403,6 +403,9 @@ struct smu_context
        uint32_t default_power_profile_mode;
 
        uint32_t smc_if_version;
+
+       unsigned long metrics_time;
+       void *metrics_table;
 };
 
 struct pptable_funcs {
index cd36c42..c139f5f 100644 (file)
@@ -369,6 +369,13 @@ static int smu_v11_0_init_power(struct smu_context *smu)
                return -ENOMEM;
        smu_power->power_context_size = sizeof(struct smu_11_0_dpm_context);
 
+       smu->metrics_time = 0;
+       smu->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+       if (!smu->metrics_table) {
+               kfree(smu_power->power_context);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -379,7 +386,9 @@ static int smu_v11_0_fini_power(struct smu_context *smu)
        if (!smu_power->power_context || smu_power->power_context_size == 0)
                return -EINVAL;
 
+       kfree(smu->metrics_table);
        kfree(smu_power->power_context);
+       smu->metrics_table = NULL;
        smu_power->power_context = NULL;
        smu_power->power_context_size = 0;
 
@@ -1093,6 +1102,26 @@ static int smu_v11_0_start_thermal_control(struct smu_context *smu)
        return ret;
 }
 
+static int smu_v11_0_get_metrics_table(struct smu_context *smu,
+               SmuMetrics_t *metrics_table)
+{
+       int ret = 0;
+
+       if (!smu->metrics_time || time_after(jiffies, smu->metrics_time + HZ / 1000)) {
+               ret = smu_update_table(smu, TABLE_SMU_METRICS,
+                               (void *)metrics_table, false);
+               if (ret) {
+                       pr_info("Failed to export SMU metrics table!\n");
+                       return ret;
+               }
+               memcpy(smu->metrics_table, metrics_table, sizeof(SmuMetrics_t));
+               smu->metrics_time = jiffies;
+       } else
+               memcpy(metrics_table, smu->metrics_table, sizeof(SmuMetrics_t));
+
+       return ret;
+}
+
 static int smu_v11_0_get_current_activity_percent(struct smu_context *smu,
                                                  uint32_t *value)
 {
@@ -1102,7 +1131,7 @@ static int smu_v11_0_get_current_activity_percent(struct smu_context *smu,
        if (!value)
                return -EINVAL;
 
-       ret = smu_update_table(smu, TABLE_SMU_METRICS, (void *)&metrics, false);
+       ret = smu_v11_0_get_metrics_table(smu, &metrics);
        if (ret)
                return ret;
 
@@ -1139,7 +1168,7 @@ static int smu_v11_0_get_gpu_power(struct smu_context *smu, uint32_t *value)
        if (!value)
                return -EINVAL;
 
-       ret = smu_update_table(smu, TABLE_SMU_METRICS, (void *)&metrics, false);
+       ret = smu_v11_0_get_metrics_table(smu, &metrics);
        if (ret)
                return ret;