drm/amdgpu/smu_v11: Unify and fix power limits
authorMatt Coffin <mcoffin13@gmail.com>
Mon, 11 Nov 2019 18:36:31 +0000 (11:36 -0700)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 11 Nov 2019 22:38:14 +0000 (17:38 -0500)
[Why]
On Navi10, and presumably arcterus, updating pp_table via sysfs would
not re-scale the maximum possible power limit one can set. On navi10,
the SMU code ignored the power percentage overdrive setting entirely,
and would not allow you to exceed the default power limit at all.

[How]
Adding a function to the SMU interface to get the pptable version of the
default power limit allows ASIC-specific code to provide the correct
maximum-settable power limit for the current pptable.

v3: fix spelling (Alex)

Reviewed-by: Evan Quan <evan.quan@amd.com>
Signed-off-by: Matt Coffin <mcoffin13@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h
drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_pptable.h
drivers/gpu/drm/amd/powerplay/navi10_ppt.c
drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drivers/gpu/drm/amd/powerplay/vega20_ppt.c

index 1e2da4d..57459a6 100644 (file)
@@ -1109,7 +1109,7 @@ static int smu_smc_table_hw_init(struct smu_context *smu,
                if (ret)
                        return ret;
 
-               ret = smu_get_power_limit(smu, &smu->default_power_limit, true, false);
+               ret = smu_get_power_limit(smu, &smu->default_power_limit, false, false);
                if (ret)
                        return ret;
        }
@@ -2511,3 +2511,13 @@ int smu_get_dpm_clock_table(struct smu_context *smu,
 
        return ret;
 }
+
+uint32_t smu_get_pptable_power_limit(struct smu_context *smu)
+{
+       uint32_t ret = 0;
+
+       if (smu->ppt_funcs->get_pptable_power_limit)
+               ret = smu->ppt_funcs->get_pptable_power_limit(smu);
+
+       return ret;
+}
index 3099ac2..58c7c4a 100644 (file)
@@ -1261,15 +1261,14 @@ arcturus_get_profiling_clk_mask(struct smu_context *smu,
 
 static int arcturus_get_power_limit(struct smu_context *smu,
                                     uint32_t *limit,
-                                    bool asic_default)
+                                    bool cap)
 {
        PPTable_t *pptable = smu->smu_table.driver_pptable;
        uint32_t asic_default_power_limit = 0;
        int ret = 0;
        int power_src;
 
-       if (!smu->default_power_limit ||
-           !smu->power_limit) {
+       if (!smu->power_limit) {
                if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
                        power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC);
                        if (power_src < 0)
@@ -1292,17 +1291,11 @@ static int arcturus_get_power_limit(struct smu_context *smu,
                                pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
                }
 
-               if (smu->od_enabled) {
-                       asic_default_power_limit *= (100 + smu->smu_table.TDPODLimit);
-                       asic_default_power_limit /= 100;
-               }
-
-               smu->default_power_limit = asic_default_power_limit;
                smu->power_limit = asic_default_power_limit;
        }
 
-       if (asic_default)
-               *limit = smu->default_power_limit;
+       if (cap)
+               *limit = smu_v11_0_get_max_power_limit(smu);
        else
                *limit = smu->power_limit;
 
@@ -2070,6 +2063,13 @@ static void arcturus_i2c_eeprom_control_fini(struct i2c_adapter *control)
        i2c_del_adapter(control);
 }
 
+static uint32_t arcturus_get_pptable_power_limit(struct smu_context *smu)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+
+       return pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
+}
+
 static const struct pptable_funcs arcturus_ppt_funcs = {
        /* translate smu index into arcturus specific index */
        .get_smu_msg_index = arcturus_get_smu_msg_index,
@@ -2160,6 +2160,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq,
        .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
        .override_pcie_parameters = smu_v11_0_override_pcie_parameters,
+       .get_pptable_power_limit = arcturus_get_pptable_power_limit,
 };
 
 void arcturus_set_ppt_funcs(struct smu_context *smu)
index 8120e75..999445c 100644 (file)
@@ -261,7 +261,6 @@ struct smu_table_context
        struct smu_table                *tables;
        struct smu_table                memory_pool;
        uint8_t                         thermal_controller_type;
-       uint16_t                        TDPODLimit;
 
        void                            *overdrive_table;
 };
@@ -548,6 +547,7 @@ struct pptable_funcs {
        int (*get_dpm_ultimate_freq)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max);
        int (*set_soft_freq_limited_range)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max);
        int (*override_pcie_parameters)(struct smu_context *smu);
+       uint32_t (*get_pptable_power_limit)(struct smu_context *smu);
 };
 
 int smu_load_microcode(struct smu_context *smu);
@@ -717,4 +717,6 @@ int smu_get_uclk_dpm_states(struct smu_context *smu,
 int smu_get_dpm_clock_table(struct smu_context *smu,
                            struct dpm_clocks *clock_table);
 
+uint32_t smu_get_pptable_power_limit(struct smu_context *smu);
+
 #endif
index 154b57a..0ba7a72 100644 (file)
@@ -252,4 +252,6 @@ int smu_v11_0_override_pcie_parameters(struct smu_context *smu);
 
 int smu_v11_0_set_default_od_settings(struct smu_context *smu, bool initialize, size_t overdrive_table_size);
 
+uint32_t smu_v11_0_get_max_power_limit(struct smu_context *smu);
+
 #endif
index 86cdc33..b2f96a1 100644 (file)
@@ -141,7 +141,9 @@ struct smu_11_0_powerplay_table
       struct smu_11_0_power_saving_clock_table      power_saving_clock;
       struct smu_11_0_overdrive_table               overdrive_table;
 
+#ifndef SMU_11_0_PARTIAL_PPTABLE
       PPTable_t smc_pptable;                        //PPTable_t in smu11_driver_if.h
+#endif
 } __attribute__((packed));
 
 #endif
index 4fbdf0e..36cf313 100644 (file)
@@ -1633,17 +1633,22 @@ static int navi10_display_disable_memory_clock_switch(struct smu_context *smu,
        return ret;
 }
 
+static uint32_t navi10_get_pptable_power_limit(struct smu_context *smu)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+       return pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
+}
+
 static int navi10_get_power_limit(struct smu_context *smu,
                                     uint32_t *limit,
-                                    bool asic_default)
+                                    bool cap)
 {
        PPTable_t *pptable = smu->smu_table.driver_pptable;
        uint32_t asic_default_power_limit = 0;
        int ret = 0;
        int power_src;
 
-       if (!smu->default_power_limit ||
-           !smu->power_limit) {
+       if (!smu->power_limit) {
                if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
                        power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC);
                        if (power_src < 0)
@@ -1666,17 +1671,11 @@ static int navi10_get_power_limit(struct smu_context *smu,
                                pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
                }
 
-               if (smu->od_enabled) {
-                       asic_default_power_limit *= (100 + smu->smu_table.TDPODLimit);
-                       asic_default_power_limit /= 100;
-               }
-
-               smu->default_power_limit = asic_default_power_limit;
                smu->power_limit = asic_default_power_limit;
        }
 
-       if (asic_default)
-               *limit = smu->default_power_limit;
+       if (cap)
+               *limit = smu_v11_0_get_max_power_limit(smu);
        else
                *limit = smu->power_limit;
 
@@ -2024,6 +2023,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .override_pcie_parameters = smu_v11_0_override_pcie_parameters,
        .set_default_od_settings = navi10_set_default_od_settings,
        .od_edit_dpm_table = navi10_od_edit_dpm_table,
+       .get_pptable_power_limit = navi10_get_pptable_power_limit,
 };
 
 void navi10_set_ppt_funcs(struct smu_context *smu)
index c4f67ee..fc9679e 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 
+#define SMU_11_0_PARTIAL_PPTABLE
+
 #include "pp_debug.h"
 #include "amdgpu.h"
 #include "amdgpu_smu.h"
@@ -31,6 +33,7 @@
 #include "atomfirmware.h"
 #include "amdgpu_atomfirmware.h"
 #include "smu_v11_0.h"
+#include "smu_v11_0_pptable.h"
 #include "soc15_common.h"
 #include "atom.h"
 #include "amd_pcie.h"
@@ -1045,13 +1048,44 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu)
        return 0;
 }
 
+uint32_t smu_v11_0_get_max_power_limit(struct smu_context *smu) {
+       uint32_t od_limit, max_power_limit;
+       struct smu_11_0_powerplay_table *powerplay_table = NULL;
+       struct smu_table_context *table_context = &smu->smu_table;
+       powerplay_table = table_context->power_play_table;
+
+       max_power_limit = smu_get_pptable_power_limit(smu);
+
+       if (!max_power_limit) {
+               // If we couldn't get the table limit, fall back on first-read value
+               if (!smu->default_power_limit)
+                       smu->default_power_limit = smu->power_limit;
+               max_power_limit = smu->default_power_limit;
+       }
+
+       if (smu->od_enabled) {
+               od_limit = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+
+               pr_debug("ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_limit, smu->default_power_limit);
+
+               max_power_limit *= (100 + od_limit);
+               max_power_limit /= 100;
+       }
+
+       return max_power_limit;
+}
+
 int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n)
 {
        int ret = 0;
+       uint32_t max_power_limit;
+
+       max_power_limit = smu_v11_0_get_max_power_limit(smu);
 
-       if (n > smu->default_power_limit) {
-               pr_err("New power limit is over the max allowed %d\n",
-                               smu->default_power_limit);
+       if (n > max_power_limit) {
+               pr_err("New power limit (%d) is over the max allowed %d\n",
+                               n,
+                               max_power_limit);
                return -EINVAL;
        }
 
index 5b21386..0b48928 100644 (file)
@@ -466,7 +466,6 @@ static int vega20_store_powerplay_table(struct smu_context *smu)
               sizeof(PPTable_t));
 
        table_context->thermal_controller_type = powerplay_table->ucThermalControllerType;
-       table_context->TDPODLimit = le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE]);
 
        return 0;
 }