]> git.baikalelectronics.ru Git - kernel.git/commitdiff
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 1e2da4d37567496bf7e39edeb43923be7405efe2..57459a65eb44fc3cca5cd7d719681a573e3f70d4 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 3099ac256bd3d17a5869445b948fc7c6e38500b5..58c7c4a3053e2b8c55c9fb20654ee427ceaa2d98 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 8120e7587585d0f09d6435a00e0e64a1dca7037e..999445c5c010721700adaa48a31a1ed99d782c4e 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 154b57a4dbbb42da76e43a4f72e6139867f0685b..0ba7a7292bea9027bb9f3bcfa8021f39194ae483 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 86cdc3393eacf948e51b3348fcf29fe983f71995..b2f96a10112465f283add4d068ccab8fa630548a 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 4fbdf0e507f387ab2edbf4eafb836c8e29acb7c0..36cf313754e4991dd1fcbb401e8ae182ef107471 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 c4f67ee8840e646dd6cf5f70a817dc08d515e599..fc9679ea23680af0dd26bbaae723ac3890332e84 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 5b21386f558de256cb2581d4f67a4e3b53c72f4e..0b4892833808f11cd5d2855d893763113b0b160f 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;
 }