[PATCH 28/30] drm/amd/powerplay: make power limit retrieval as asic specific

Alex Deucher alexdeucher at gmail.com
Mon Jul 29 20:15:06 UTC 2019


From: Evan Quan <evan.quan at amd.com>

The power limit retrieval should be done per asic. Since we may
need to lookup in the pptable and that's really asic specific.

Signed-off-by: Evan Quan <evan.quan at amd.com>
Reviewed-by: Kenneth Feng <kenneth.feng at amd.com>
Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
 drivers/gpu/drm/amd/powerplay/amdgpu_smu.c    |  2 +-
 drivers/gpu/drm/amd/powerplay/arcturus_ppt.c  | 51 +++++++++++++++++
 .../gpu/drm/amd/powerplay/inc/amdgpu_smu.h    |  4 +-
 drivers/gpu/drm/amd/powerplay/navi10_ppt.c    | 51 +++++++++++++++++
 drivers/gpu/drm/amd/powerplay/smu_v11_0.c     | 55 ++++---------------
 5 files changed, 116 insertions(+), 47 deletions(-)

diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
index 3f615d4624c7..330cc3258e61 100644
--- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
@@ -1136,7 +1136,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, false);
+		ret = smu_get_power_limit(smu, &smu->default_power_limit, true);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
index c67a9914ce7b..9360f5a25b69 100644
--- a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c
@@ -1323,6 +1323,56 @@ arcturus_get_profiling_clk_mask(struct smu_context *smu,
 	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;
@@ -1788,6 +1838,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
 	.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)
diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
index 519aeac706a5..093e70fe684d 100644
--- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
@@ -447,6 +447,7 @@ struct pptable_funcs {
 	int (*set_default_od_settings)(struct smu_context *smu, bool initialize);
 	int (*set_performance_level)(struct smu_context *smu, enum amd_dpm_forced_level level);
 	void (*dump_pptable)(struct smu_context *smu);
+	int (*get_power_limit)(struct smu_context *smu, uint32_t *limit, bool asic_default);
 };
 
 struct smu_funcs
@@ -479,7 +480,6 @@ 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);
@@ -608,7 +608,7 @@ struct smu_funcs
 #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) \
diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
index 01d534c8442e..efcedeb8d883 100644
--- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c
@@ -1484,6 +1484,56 @@ static int navi10_get_thermal_temperature_range(struct smu_context *smu,
 	return 0;
 }
 
+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,
@@ -1520,6 +1570,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
 	.get_uclk_dpm_states = navi10_get_uclk_dpm_states,
 	.set_performance_level = navi10_set_performance_level,
 	.get_thermal_temperature_range = navi10_get_thermal_temperature_range,
+	.get_power_limit = navi10_get_power_limit,
 };
 
 void navi10_set_ppt_funcs(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c
index caf02ea4a481..7f03ca401d97 100644
--- a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c
+++ b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c
@@ -1012,64 +1012,32 @@ static int smu_v11_0_init_max_sustainable_clocks(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,
@@ -1742,7 +1710,6 @@ static const struct smu_funcs smu_v11_0_funcs = {
 	.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,
-- 
2.20.1



More information about the amd-gfx mailing list