if (ret)
return ret;
- ret = smu_get_power_limit(smu, &smu->default_power_limit, false);
+ ret = smu_get_power_limit(smu, &smu->default_power_limit, true);
if (ret)
return ret;
}
return 0;
}
+static int arcturus_get_power_limit(struct smu_context *smu,
+ uint32_t *limit,
+ bool asic_default)
+{
+ PPTable_t *pptable = smu->smu_table.driver_pptable;
+ uint32_t asic_default_power_limit;
+ int ret = 0;
+ int power_src;
+
+ if (!smu->default_power_limit ||
+ !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)
+ return -EINVAL;
+
+ ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
+ power_src << 16);
+ if (ret) {
+ pr_err("[%s] get PPT limit failed!", __func__);
+ return ret;
+ }
+ smu_read_smc_arg(smu, &asic_default_power_limit);
+ } else {
+ /* the last hope to figure out the ppt limit */
+ if (!pptable) {
+ pr_err("Cannot get PPT limit due to pptable missing!");
+ return -EINVAL;
+ }
+ asic_default_power_limit =
+ 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;
+ else
+ *limit = smu->power_limit;
+
+ return 0;
+}
+
static void arcturus_dump_pptable(struct smu_context *smu)
{
struct smu_table_context *table_context = &smu->smu_table;
.get_profiling_clk_mask = arcturus_get_profiling_clk_mask,
/* debug (internal used) */
.dump_pptable = arcturus_dump_pptable,
+ .get_power_limit = arcturus_get_power_limit,
};
void arcturus_set_ppt_funcs(struct smu_context *smu)
int (*set_performance_level)(struct smu_context *smu, enum amd_dpm_forced_level level);
int (*display_disable_memory_clock_switch)(struct smu_context *smu, bool disable_memory_clock_switch);
void (*dump_pptable)(struct smu_context *smu);
+ int (*get_power_limit)(struct smu_context *smu, uint32_t *limit, bool asic_default);
};
struct smu_funcs
int (*set_allowed_mask)(struct smu_context *smu);
int (*get_enabled_mask)(struct smu_context *smu, uint32_t *feature_mask, uint32_t num);
int (*notify_display_change)(struct smu_context *smu);
- int (*get_power_limit)(struct smu_context *smu, uint32_t *limit, bool def);
int (*set_power_limit)(struct smu_context *smu, uint32_t n);
int (*get_current_clk_freq)(struct smu_context *smu, enum smu_clk_type clk_id, uint32_t *value);
int (*init_max_sustainable_clocks)(struct smu_context *smu);
#define smu_set_default_od8_settings(smu) \
((smu)->ppt_funcs->set_default_od8_settings ? (smu)->ppt_funcs->set_default_od8_settings((smu)) : 0)
#define smu_get_power_limit(smu, limit, def) \
- ((smu)->funcs->get_power_limit ? (smu)->funcs->get_power_limit((smu), (limit), (def)) : 0)
+ ((smu)->ppt_funcs->get_power_limit ? (smu)->ppt_funcs->get_power_limit((smu), (limit), (def)) : 0)
#define smu_set_power_limit(smu, limit) \
((smu)->funcs->set_power_limit ? (smu)->funcs->set_power_limit((smu), (limit)) : 0)
#define smu_get_current_clk_freq(smu, clk_id, value) \
return ret;
}
+static int navi10_get_power_limit(struct smu_context *smu,
+ uint32_t *limit,
+ bool asic_default)
+{
+ PPTable_t *pptable = smu->smu_table.driver_pptable;
+ uint32_t asic_default_power_limit;
+ int ret = 0;
+ int power_src;
+
+ if (!smu->default_power_limit ||
+ !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)
+ return -EINVAL;
+
+ ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
+ power_src << 16);
+ if (ret) {
+ pr_err("[%s] get PPT limit failed!", __func__);
+ return ret;
+ }
+ smu_read_smc_arg(smu, &asic_default_power_limit);
+ } else {
+ /* the last hope to figure out the ppt limit */
+ if (!pptable) {
+ pr_err("Cannot get PPT limit due to pptable missing!");
+ return -EINVAL;
+ }
+ asic_default_power_limit =
+ 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;
+ else
+ *limit = smu->power_limit;
+
+ return 0;
+}
+
static const struct pptable_funcs navi10_ppt_funcs = {
.tables_init = navi10_tables_init,
.alloc_dpm_context = navi10_allocate_dpm_context,
.set_performance_level = navi10_set_performance_level,
.get_thermal_temperature_range = navi10_get_thermal_temperature_range,
.display_disable_memory_clock_switch = navi10_display_disable_memory_clock_switch,
+ .get_power_limit = navi10_get_power_limit,
};
void navi10_set_ppt_funcs(struct smu_context *smu)
return 0;
}
-static int smu_v11_0_get_power_limit(struct smu_context *smu,
- uint32_t *limit,
- bool get_default)
+static int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n)
{
int ret = 0;
- int power_src;
- power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC);
- if (power_src < 0)
+ if (n > smu->default_power_limit) {
+ pr_err("New power limit is over the max allowed %d\n",
+ smu->default_power_limit);
return -EINVAL;
-
- if (get_default) {
- mutex_lock(&smu->mutex);
- *limit = smu->default_power_limit;
- if (smu->od_enabled) {
- *limit *= (100 + smu->smu_table.TDPODLimit);
- *limit /= 100;
- }
- mutex_unlock(&smu->mutex);
- } else {
- ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
- power_src << 16);
- if (ret) {
- pr_err("[%s] get PPT limit failed!", __func__);
- return ret;
- }
- smu_read_smc_arg(smu, limit);
- smu->power_limit = *limit;
}
- return ret;
-}
-
-static int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n)
-{
- uint32_t max_power_limit;
- int ret = 0;
-
if (n == 0)
n = smu->default_power_limit;
- max_power_limit = smu->default_power_limit;
-
- if (smu->od_enabled) {
- max_power_limit *= (100 + smu->smu_table.TDPODLimit);
- max_power_limit /= 100;
+ if (!smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
+ pr_err("Setting new power limit is not supported!\n");
+ return -EOPNOTSUPP;
}
- if (n > max_power_limit)
- return -EINVAL;
- if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT))
- ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n);
+ ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n);
if (ret) {
- pr_err("[%s] Set power limit Failed!", __func__);
+ pr_err("[%s] Set power limit Failed!\n", __func__);
return ret;
}
+ smu->power_limit = n;
- return ret;
+ return 0;
}
static int smu_v11_0_get_current_clk_freq(struct smu_context *smu,
.get_enabled_mask = smu_v11_0_get_enabled_mask,
.system_features_control = smu_v11_0_system_features_control,
.notify_display_change = smu_v11_0_notify_display_change,
- .get_power_limit = smu_v11_0_get_power_limit,
.set_power_limit = smu_v11_0_set_power_limit,
.get_current_clk_freq = smu_v11_0_get_current_clk_freq,
.init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks,