summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/pm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/pm')
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_dpm.c48
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_pm.c176
-rw-r--r--drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h7
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c17
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c21
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c7
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c38
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c11
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c755
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c446
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c80
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c85
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c761
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c7
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c5
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c7
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h25
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c25
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c280
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h117
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h38
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_metrics.h230
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h7
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h17
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h24
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h15
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h17
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c75
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c104
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c131
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c107
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c177
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c93
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c117
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c132
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c147
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c809
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h31
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c132
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c108
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c153
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c140
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c110
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c538
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h13
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c157
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c140
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h13
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_internal.h4
58 files changed, 3909 insertions, 2823 deletions
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index f76ba6753551..ce526db4d24a 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -508,7 +508,7 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
amdgpu_dpm_notify_ac_dc(adev);
if (is_support_sw_smu(adev))
- smu_set_ac_dc(adev->powerplay.pp_handle);
+ smu_set_ac_dc(adev->powerplay.pp_handle, true);
mutex_unlock(&adev->pm.mutex);
}
@@ -1183,20 +1183,36 @@ int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev,
return ret;
}
-int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table)
+static bool amdgpu_dpm_is_pp_table_allowed(struct amdgpu_device *adev)
+{
+ return !amdgpu_sriov_vf(adev) &&
+ !(adev->flags & AMD_IS_APU) &&
+ !adev->scpm_enabled;
+}
+
+int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table,
+ size_t size)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ char *pptable = NULL;
int ret = 0;
- if (!table)
+ if ((!table && size) || (table && !size))
return -EINVAL;
- if (amdgpu_sriov_vf(adev) || !pp_funcs->get_pp_table || adev->scpm_enabled)
+ if (!amdgpu_dpm_is_pp_table_allowed(adev) ||
+ !pp_funcs->get_pp_table)
return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);
ret = pp_funcs->get_pp_table(adev->powerplay.pp_handle,
- table);
+ &pptable);
+ if (ret > 0 && !pptable) {
+ ret = -EINVAL;
+ } else if (ret > 0 && table) {
+ ret = min_t(size_t, ret, size);
+ memcpy(table, pptable, ret);
+ }
mutex_unlock(&adev->pm.mutex);
return ret;
@@ -1426,17 +1442,23 @@ int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
return ret;
}
-int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table)
+ssize_t amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void *buf,
+ size_t size)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- int ret = 0;
+ void *table;
+ ssize_t ret;
if (!pp_funcs->get_gpu_metrics)
return 0;
mutex_lock(&adev->pm.mutex);
ret = pp_funcs->get_gpu_metrics(adev->powerplay.pp_handle,
- table);
+ &table);
+ if (ret > 0) {
+ ret = min_t(ssize_t, ret, size);
+ memcpy(buf, table, ret);
+ }
mutex_unlock(&adev->pm.mutex);
return ret;
@@ -1703,7 +1725,8 @@ int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
if (!buf || !size)
return -EINVAL;
- if (amdgpu_sriov_vf(adev) || !pp_funcs->set_pp_table || adev->scpm_enabled)
+ if (!amdgpu_dpm_is_pp_table_allowed(adev) ||
+ !pp_funcs->set_pp_table)
return -EOPNOTSUPP;
mutex_lock(&adev->pm.mutex);
@@ -2110,10 +2133,3 @@ ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
return ret;
}
-
-const struct ras_smu_drv *amdgpu_dpm_get_ras_smu_driver(struct amdgpu_device *adev)
-{
- void *pp_handle = adev->powerplay.pp_handle;
-
- return smu_get_ras_smu_driver(pp_handle);
-}
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index 97da01aff76c..c0e677328af5 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -34,6 +34,7 @@
#include <linux/nospec.h>
#include <linux/pm_runtime.h>
#include <linux/string_choices.h>
+#include <linux/units.h>
#include <asm/processor.h>
#define MAX_NUM_OF_FEATURES_PER_SUBSET 8
@@ -41,8 +42,6 @@
#define DEVICE_ATTR_IS(_name) (attr_id == device_attr_id__##_name)
-#define power_2_mwatt(power) (((power) >> 8) * 1000 + ((power) & 0xff))
-
struct od_attribute {
struct kobj_attribute attribute;
struct list_head entry;
@@ -100,6 +99,37 @@ const char * const amdgpu_pp_profile_name[] = {
"UNCAPPED",
};
+static int amdgpu_pm_parse_long_params(char *str, long *params,
+ uint32_t max_params,
+ uint32_t *num_params)
+{
+ const char delimiter[] = { ' ', '\n', '\0' };
+ uint32_t count = 0;
+ char *sub_str;
+ int ret;
+
+ if (!params || !num_params)
+ return -EINVAL;
+
+ while ((sub_str = strsep(&str, delimiter)) != NULL) {
+ if (strlen(sub_str) == 0)
+ continue;
+ if (count >= max_params)
+ return -EINVAL;
+ ret = kstrtol(sub_str, 0, &params[count]);
+ if (ret)
+ return -EINVAL;
+ count++;
+ if (!str)
+ break;
+ while (isspace(*str))
+ str++;
+ }
+ *num_params = count;
+
+ return 0;
+}
+
/**
* amdgpu_pm_dev_state_check - Check if device can be accessed.
* @adev: Target device.
@@ -564,25 +594,19 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- char *table = NULL;
int size, ret;
ret = amdgpu_pm_get_access_if_active(adev);
if (ret)
return ret;
- size = amdgpu_dpm_get_pp_table(adev, &table);
+ size = amdgpu_dpm_get_pp_table(adev, buf, PAGE_SIZE - 1);
amdgpu_pm_put_access(adev);
if (size <= 0)
return size;
- if (size >= PAGE_SIZE)
- size = PAGE_SIZE - 1;
-
- memcpy(buf, table, size);
-
return size;
}
@@ -769,8 +793,6 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
long parameter[64];
char buf_cpy[128];
char *tmp_str;
- char *sub_str;
- const char delimiter[3] = {' ', '\n', '\0'};
uint32_t type;
if (count > 127 || count == 0)
@@ -805,22 +827,10 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev,
tmp_str++;
while (isspace(*++tmp_str));
- while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) {
- if (strlen(sub_str) == 0)
- continue;
- if (parameter_size >= ARRAY_SIZE(parameter))
- return -EINVAL;
- ret = kstrtol(sub_str, 0, &parameter[parameter_size]);
- if (ret)
- return -EINVAL;
- parameter_size++;
-
- if (!tmp_str)
- break;
-
- while (isspace(*tmp_str))
- tmp_str++;
- }
+ ret = amdgpu_pm_parse_long_params(
+ tmp_str, parameter, ARRAY_SIZE(parameter), &parameter_size);
+ if (ret)
+ return ret;
ret = amdgpu_pm_get_access(adev);
if (ret < 0)
@@ -1393,11 +1403,9 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
struct amdgpu_device *adev = drm_to_adev(ddev);
uint32_t parameter_size = 0;
long parameter[64];
- char *sub_str, buf_cpy[128];
- char *tmp_str;
+ char buf_cpy[128];
char tmp[2];
long int profile_mode = 0;
- const char delimiter[3] = {' ', '\n', '\0'};
/* Reject empty/whitespace strings - fuzzing found this is not validated */
if (count == 0 || sysfs_streq(buf, ""))
@@ -1415,19 +1423,11 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev,
while (isspace(*buf))
buf++;
strscpy(buf_cpy, buf, sizeof(buf_cpy));
- tmp_str = buf_cpy;
- while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) {
- if (strlen(sub_str) == 0)
- continue;
- ret = kstrtol(sub_str, 0, &parameter[parameter_size]);
- if (ret)
- return -EINVAL;
- parameter_size++;
- if (!tmp_str)
- break;
- while (isspace(*tmp_str))
- tmp_str++;
- }
+ ret = amdgpu_pm_parse_long_params(buf_cpy, parameter,
+ ARRAY_SIZE(parameter) - 1,
+ &parameter_size);
+ if (ret)
+ return ret;
}
parameter[parameter_size] = profile_mode;
@@ -1780,7 +1780,6 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- void *gpu_metrics;
ssize_t size = 0;
int ret;
@@ -1788,15 +1787,10 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
if (ret)
return ret;
- size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics);
+ size = amdgpu_dpm_get_gpu_metrics(adev, buf, PAGE_SIZE - 1);
if (size <= 0)
goto out;
- if (size >= PAGE_SIZE)
- size = PAGE_SIZE - 1;
-
- memcpy(buf, gpu_metrics, size);
-
out:
amdgpu_pm_put_access(adev);
@@ -2029,6 +2023,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
gc_ver == IP_VERSION(11, 0, 1) ||
gc_ver == IP_VERSION(11, 0, 4) ||
gc_ver == IP_VERSION(11, 5, 0) ||
+ gc_ver == IP_VERSION(11, 5, 1) ||
gc_ver == IP_VERSION(11, 0, 2) ||
gc_ver == IP_VERSION(11, 0, 3) ||
amdgpu_is_multi_aid(adev)))
@@ -2037,7 +2032,8 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
if (!((gc_ver == IP_VERSION(10, 3, 1) ||
gc_ver == IP_VERSION(10, 3, 0) ||
gc_ver == IP_VERSION(11, 0, 2) ||
- gc_ver == IP_VERSION(11, 0, 3)) && adev->vcn.num_vcn_inst >= 2))
+ gc_ver == IP_VERSION(11, 0, 3) ||
+ gc_ver == IP_VERSION(11, 5, 1)) && adev->vcn.num_vcn_inst >= 2))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_dpm_dclk)) {
if (!(gc_ver == IP_VERSION(10, 3, 1) ||
@@ -2050,6 +2046,7 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
gc_ver == IP_VERSION(11, 0, 1) ||
gc_ver == IP_VERSION(11, 0, 4) ||
gc_ver == IP_VERSION(11, 5, 0) ||
+ gc_ver == IP_VERSION(11, 5, 1) ||
gc_ver == IP_VERSION(11, 0, 2) ||
gc_ver == IP_VERSION(11, 0, 3) ||
amdgpu_is_multi_aid(adev)))
@@ -2058,7 +2055,8 @@ static int pp_dpm_clk_default_attr_update(struct amdgpu_device *adev, struct amd
if (!((gc_ver == IP_VERSION(10, 3, 1) ||
gc_ver == IP_VERSION(10, 3, 0) ||
gc_ver == IP_VERSION(11, 0, 2) ||
- gc_ver == IP_VERSION(11, 0, 3)) && adev->vcn.num_vcn_inst >= 2))
+ gc_ver == IP_VERSION(11, 0, 3) ||
+ gc_ver == IP_VERSION(11, 5, 1)) && adev->vcn.num_vcn_inst >= 2))
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_dpm_pcie)) {
if (amdgpu_is_multi_aid(adev))
@@ -2726,10 +2724,9 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
*states = ATTR_STATE_UNSUPPORTED;
} else if (DEVICE_ATTR_IS(pp_table)) {
int ret;
- char *tmp = NULL;
- ret = amdgpu_dpm_get_pp_table(adev, &tmp);
- if (ret == -EOPNOTSUPP || !tmp)
+ ret = amdgpu_dpm_get_pp_table(adev, NULL, 0);
+ if (ret <= 0)
*states = ATTR_STATE_UNSUPPORTED;
else
*states = ATTR_STATE_SUPPORTED;
@@ -3364,7 +3361,7 @@ static int amdgpu_hwmon_get_power(struct device *dev,
return r;
/* convert to microwatts */
- return power_2_mwatt(query) * 1000;
+ return query * 1000;
}
static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev,
@@ -3958,18 +3955,14 @@ out_pm_put:
return size;
}
-static int parse_input_od_command_lines(const char *buf,
- size_t count,
- u32 *type,
- long *params,
- size_t params_max,
+static int parse_input_od_command_lines(const char *buf, size_t count,
+ u32 *type, long *params,
+ uint32_t max_params,
uint32_t *num_of_params)
{
- const char delimiter[3] = {' ', '\n', '\0'};
uint32_t parameter_size = 0;
char buf_cpy[128] = {0};
- char *tmp_str, *sub_str;
- int ret;
+ char *tmp_str;
if (count > sizeof(buf_cpy) - 1)
return -EINVAL;
@@ -3994,28 +3987,8 @@ static int parse_input_od_command_lines(const char *buf,
break;
}
- while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) {
- if (strlen(sub_str) == 0)
- continue;
-
- if (parameter_size >= params_max)
- return -EINVAL;
-
- ret = kstrtol(sub_str, 0, &params[parameter_size]);
- if (ret)
- return -EINVAL;
- parameter_size++;
-
- if (!tmp_str)
- break;
-
- while (isspace(*tmp_str))
- tmp_str++;
- }
-
- *num_of_params = parameter_size;
-
- return 0;
+ return amdgpu_pm_parse_long_params(tmp_str, params, max_params,
+ num_of_params);
}
static int
@@ -4028,10 +4001,7 @@ amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev,
long parameter[64];
int ret;
- ret = parse_input_od_command_lines(in_buf,
- count,
- &cmd_type,
- parameter,
+ ret = parse_input_od_command_lines(in_buf, count, &cmd_type, parameter,
ARRAY_SIZE(parameter),
&parameter_size);
if (ret)
@@ -4907,9 +4877,8 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
{
uint32_t mp1_ver = amdgpu_ip_version(adev, MP1_HWIP, 0);
uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
- uint32_t value, mwatt, centiwatt;
uint64_t value64 = 0;
- uint32_t query = 0;
+ uint32_t value;
int size;
/* GPU Clocks */
@@ -4930,25 +4899,22 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
seq_printf(m, "\t%u mV (VDDGFX)\n", value);
if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *)&value, &size))
seq_printf(m, "\t%u mV (VDDNB)\n", value);
- size = sizeof(uint32_t);
- if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) {
- mwatt = power_2_mwatt(query);
- centiwatt = DIV_ROUND_CLOSEST(mwatt, 10);
+ if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&value, &size)) {
if (adev->flags & AMD_IS_APU)
- seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", centiwatt / 100, centiwatt % 100);
+ seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n",
+ (u32)(value / MILLIWATT_PER_WATT), (u32)(value % MILLIWATT_PER_WATT) / 10);
else
- seq_printf(m, "\t%u.%02u W (average SoC)\n", centiwatt / 100, centiwatt % 100);
+ seq_printf(m, "\t%u.%02u W (average SoC)\n",
+ (u32)(value / MILLIWATT_PER_WATT), (u32)(value % MILLIWATT_PER_WATT) / 10);
}
- size = sizeof(uint32_t);
- if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) {
- mwatt = power_2_mwatt(query);
- centiwatt = DIV_ROUND_CLOSEST(mwatt, 10);
+ if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&value, &size)) {
if (adev->flags & AMD_IS_APU)
- seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", centiwatt / 100, centiwatt % 100);
+ seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n",
+ (u32)(value / MILLIWATT_PER_WATT), (u32)(value % MILLIWATT_PER_WATT) / 10);
else
- seq_printf(m, "\t%u.%02u W (current SoC)\n", centiwatt / 100, centiwatt % 100);
+ seq_printf(m, "\t%u.%02u W (current SoC)\n",
+ (u32)(value / MILLIWATT_PER_WATT), (u32)(value % MILLIWATT_PER_WATT) / 10);
}
- size = sizeof(value);
seq_printf(m, "\n");
/* GPU Temp */
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index aa3f427819a0..8e8a052e1d53 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -487,7 +487,8 @@ int amdgpu_dpm_get_pp_num_states(struct amdgpu_device *adev,
int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev,
enum amd_pp_task task_id,
enum amd_pm_state_type *user_state);
-int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table);
+int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table,
+ size_t size);
int amdgpu_dpm_set_fine_grain_clk_vol(struct amdgpu_device *adev,
uint32_t type,
long *input,
@@ -517,7 +518,8 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev,
char *buf);
int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
long *input, uint32_t size);
-int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table);
+ssize_t amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void *buf,
+ size_t size);
ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
void *table);
ssize_t amdgpu_dpm_get_temp_metrics(struct amdgpu_device *adev,
@@ -612,6 +614,5 @@ int amdgpu_dpm_reset_vcn(struct amdgpu_device *adev, uint32_t inst_mask);
bool amdgpu_dpm_reset_vcn_is_supported(struct amdgpu_device *adev);
bool amdgpu_dpm_is_temp_metrics_supported(struct amdgpu_device *adev,
enum smu_temp_metric_type type);
-const struct ras_smu_drv *amdgpu_dpm_get_ras_smu_driver(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
index 8079da7c5335..012227c70600 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
@@ -3892,13 +3892,16 @@ static void si_notify_hw_of_powersource(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- /* Check if the platform already manages the AC/DC switch via dedicated GPIO. */
- if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
- return;
-
- /* The SMU automatically notices DC, but needs to be notified when switching to AC. */
- if (adev->pm.ac_power)
+ /*
+ * Check if the platform already manages the AC/DC switch via dedicated GPIO.
+ * Otherwise SMU automatically notices DC, but needs to be notified of AC.
+ */
+ if (adev->pm.ac_power &&
+ (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC))
amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_RunningOnAC);
+
+ /* Recompute clocks with updated max_limits. */
+ amdgpu_legacy_dpm_compute_clocks(adev);
}
static PPSMC_Result si_send_msg_to_smc_with_parameter(struct amdgpu_device *adev,
@@ -7689,7 +7692,7 @@ static int si_dpm_process_interrupt(struct amdgpu_device *adev,
break;
}
- if (queue_thermal)
+ if (queue_thermal && amdgpu_dpm)
schedule_work(&adev->pm.dpm.thermal.work);
return 0;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
index 6f5c27bdc1e9..7c70e228a5ba 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
@@ -660,25 +660,20 @@ static int amd_powerplay_reset(void *handle)
static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
{
struct pp_hwmgr *hwmgr = handle;
+ void *hardcode_pp_table;
int ret = -ENOMEM;
- if (!hwmgr || !hwmgr->pm_en)
- return -EINVAL;
-
- if (size > hwmgr->soft_pp_table_size)
+ if (!hwmgr || !hwmgr->pm_en || !buf || !size || size > U32_MAX)
return -EINVAL;
- if (!hwmgr->hardcode_pp_table) {
- hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table,
- hwmgr->soft_pp_table_size,
- GFP_KERNEL);
- if (!hwmgr->hardcode_pp_table)
- return ret;
- }
-
- memcpy(hwmgr->hardcode_pp_table, buf, size);
+ hardcode_pp_table = kmemdup(buf, size, GFP_KERNEL);
+ if (!hardcode_pp_table)
+ return ret;
+ kfree(hwmgr->hardcode_pp_table);
+ hwmgr->hardcode_pp_table = hardcode_pp_table;
hwmgr->soft_pp_table = hwmgr->hardcode_pp_table;
+ hwmgr->soft_pp_table_size = size;
ret = amd_powerplay_reset(handle);
if (ret)
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
index 1d6e30269d56..4d553be56396 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
@@ -106,11 +106,8 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr)
hwmgr->od_enabled = false;
switch (hwmgr->chip_id) {
case CHIP_BONAIRE:
- /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM
- * R7 260X cards with old MC ucode: MCLK DPM is unstable
- */
- if (adev->pdev->subsystem_vendor == 0x106B ||
- adev->pdev->device == 0x6658) {
+ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM */
+ if (adev->pdev->subsystem_vendor == 0x106B) {
dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC");
adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK;
hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
index ce166a7f8e42..4b796d60b03d 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
@@ -46,16 +46,22 @@ union voltage_object_info {
static int atomctrl_retrieve_ac_timing(
uint8_t index,
ATOM_INIT_REG_BLOCK *reg_block,
+ u8 *table_end,
pp_atomctrl_mc_reg_table *table)
{
uint32_t i, j;
+ u16 stride = le16_to_cpu(reg_block->usRegDataBlkSize);
uint8_t tmem_id;
ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize));
uint8_t num_ranges = 0;
- while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
+ if (stride < sizeof(uint32_t))
+ return -EINVAL;
+
+ while ((uint8_t *)reg_data + sizeof(uint32_t) <= table_end &&
+ *(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) {
tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
@@ -67,6 +73,10 @@ static int atomctrl_retrieve_ac_timing(
for (i = 0, j = 1; i < table->last; i++) {
if ((table->mc_reg_address[i].uc_pre_reg_data &
LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
+ if ((uint8_t *)reg_data +
+ (j + 1) * sizeof(uint32_t) > table_end)
+ return -EINVAL;
+
table->mc_reg_table_entry[num_ranges].mc_data[i] =
(uint32_t)*((uint32_t *)reg_data + j);
j++;
@@ -81,11 +91,13 @@ static int atomctrl_retrieve_ac_timing(
}
reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
- ((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ;
+ ((uint8_t *)reg_data + stride);
}
- PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK),
- "Invalid VramInfo table.", return -1);
+ if ((uint8_t *)reg_data + sizeof(uint32_t) > table_end ||
+ *(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK)
+ return -EINVAL;
+
table->num_entries = num_ranges;
return 0;
@@ -136,6 +148,7 @@ int atomctrl_initialize_mc_reg_table(
{
ATOM_VRAM_INFO_HEADER_V2_1 *vram_info;
ATOM_INIT_REG_BLOCK *reg_block;
+ u8 *table_end;
int result = 0;
u8 frev, crev;
u16 size;
@@ -157,6 +170,7 @@ int atomctrl_initialize_mc_reg_table(
}
if (0 == result) {
+ table_end = (uint8_t *)vram_info + size;
reg_block = (ATOM_INIT_REG_BLOCK *)
((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
result = atomctrl_set_mc_reg_address_table(reg_block, table);
@@ -164,7 +178,7 @@ int atomctrl_initialize_mc_reg_table(
if (0 == result) {
result = atomctrl_retrieve_ac_timing(module_index,
- reg_block, table);
+ reg_block, table_end, table);
}
return result;
@@ -177,6 +191,7 @@ int atomctrl_initialize_mc_reg_table_v2_2(
{
ATOM_VRAM_INFO_HEADER_V2_2 *vram_info;
ATOM_INIT_REG_BLOCK *reg_block;
+ u8 *table_end;
int result = 0;
u8 frev, crev;
u16 size;
@@ -198,6 +213,7 @@ int atomctrl_initialize_mc_reg_table_v2_2(
}
if (0 == result) {
+ table_end = (uint8_t *)vram_info + size;
reg_block = (ATOM_INIT_REG_BLOCK *)
((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
result = atomctrl_set_mc_reg_address_table(reg_block, table);
@@ -205,7 +221,7 @@ int atomctrl_initialize_mc_reg_table_v2_2(
if (0 == result) {
result = atomctrl_retrieve_ac_timing(module_index,
- reg_block, table);
+ reg_block, table_end, table);
}
return result;
@@ -268,15 +284,21 @@ static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3(
unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]);
uint8_t *start = (uint8_t *)voltage_object_info_table;
- while (offset < size) {
+ while (offset + sizeof(ATOM_VOLTAGE_OBJECT_HEADER_V3) <= size) {
const ATOM_VOLTAGE_OBJECT_V3 *voltage_object =
(const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
+ u16 obj_size;
+
+ obj_size = le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
+ if (obj_size < sizeof(voltage_object->asGpioVoltageObj.sHeader) ||
+ offset + obj_size > size)
+ break;
if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType &&
voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode)
return voltage_object;
- offset += le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
+ offset += obj_size;
}
return NULL;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
index 6120f14caab0..69aee8661d1e 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
@@ -36,16 +36,21 @@ static const union atom_voltage_object_v4 *pp_atomfwctrl_lookup_voltage_type_v4(
offsetof(struct atom_voltage_objects_info_v4_1, voltage_object[0]);
unsigned long start = (unsigned long)voltage_object_info_table;
- while (offset < size) {
+ while (offset + sizeof(struct atom_voltage_object_header_v4) <= size) {
const union atom_voltage_object_v4 *voltage_object =
(const union atom_voltage_object_v4 *)(start + offset);
+ u16 obj_size;
+
+ obj_size = le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size);
+ if (obj_size < sizeof(voltage_object->gpio_voltage_obj.header) ||
+ offset + obj_size > size)
+ break;
if (voltage_type == voltage_object->gpio_voltage_obj.header.voltage_type &&
voltage_mode == voltage_object->gpio_voltage_obj.header.voltage_mode)
return voltage_object;
- offset += le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size);
-
+ offset += obj_size;
}
return NULL;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
index 6fcca65bd7d4..c5673077c895 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
@@ -150,6 +150,368 @@ static const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
return table_address;
}
+static bool tonga_pp_table_has_space(struct pp_hwmgr *hwmgr, size_t offset,
+ size_t size)
+{
+ size_t table_size = hwmgr->soft_pp_table_size;
+
+ return offset <= table_size && size <= table_size - offset;
+}
+
+static int get_tonga_subtable(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ u16 table_offset, size_t table_size, const void **table)
+{
+ PP_ASSERT_WITH_CODE((table_offset != 0),
+ "Invalid PowerPlay Table!", return -1);
+ PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *table = (const void *)(((unsigned long)powerplay_table) + table_offset);
+
+ return 0;
+}
+
+static int validate_tonga_table_entries(struct pp_hwmgr *hwmgr,
+ u16 table_offset, size_t entries_offset,
+ u8 num_entries, size_t entry_size)
+{
+ size_t table_size;
+
+ PP_ASSERT_WITH_CODE((num_entries != 0),
+ "Invalid PowerPlay Table!", return -1);
+
+ table_size = entries_offset + num_entries * entry_size;
+ PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ return 0;
+}
+
+static int get_tonga_voltage_lookup_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ u16 table_offset, uint32_t max_levels,
+ const ATOM_Tonga_Voltage_Lookup_Table **lookup_table)
+{
+ const ATOM_Tonga_Voltage_Lookup_Table *table;
+ size_t table_size;
+ int ret;
+
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ PP_ASSERT_WITH_CODE((table->ucNumEntries != 0 &&
+ table->ucNumEntries <= max_levels),
+ "Invalid PowerPlay Table!", return -1);
+
+ table_size = offsetof(ATOM_Tonga_Voltage_Lookup_Table, entries) +
+ table->ucNumEntries * sizeof(ATOM_Tonga_Voltage_Lookup_Record);
+ PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *lookup_table = table;
+
+ return 0;
+}
+
+static int get_tonga_mclk_dependency_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Tonga_MCLK_Dependency_Table **mclk_dep_table)
+{
+ const ATOM_Tonga_MCLK_Dependency_Table *table;
+ u16 table_offset;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usMclkDependencyTableOffset);
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ ret = validate_tonga_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Tonga_MCLK_Dependency_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Tonga_MCLK_Dependency_Record));
+ if (ret)
+ return ret;
+
+ *mclk_dep_table = table;
+
+ return 0;
+}
+
+static int get_tonga_mm_dependency_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Tonga_MM_Dependency_Table **mm_dep_table)
+{
+ const ATOM_Tonga_MM_Dependency_Table *table;
+ u16 table_offset;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usMMDependencyTableOffset);
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ ret = validate_tonga_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Tonga_MM_Dependency_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Tonga_MM_Dependency_Record));
+ if (ret)
+ return ret;
+
+ *mm_dep_table = table;
+
+ return 0;
+}
+
+static int get_tonga_sclk_dependency_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const PPTable_Generic_SubTable_Header **sclk_dep_table)
+{
+ const PPTable_Generic_SubTable_Header *header;
+ u16 table_offset;
+ size_t entries_offset;
+ size_t entry_size;
+ u8 num_entries;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usSclkDependencyTableOffset);
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*header), (const void **)&header);
+ if (ret)
+ return ret;
+
+ if (header->ucRevId < 1) {
+ const ATOM_Tonga_SCLK_Dependency_Table *table =
+ (const ATOM_Tonga_SCLK_Dependency_Table *)header;
+
+ entries_offset = offsetof(ATOM_Tonga_SCLK_Dependency_Table, entries);
+ entry_size = sizeof(ATOM_Tonga_SCLK_Dependency_Record);
+ num_entries = table->ucNumEntries;
+ } else {
+ const ATOM_Polaris_SCLK_Dependency_Table *table =
+ (const ATOM_Polaris_SCLK_Dependency_Table *)header;
+
+ entries_offset = offsetof(ATOM_Polaris_SCLK_Dependency_Table, entries);
+ entry_size = sizeof(ATOM_Polaris_SCLK_Dependency_Record);
+ num_entries = table->ucNumEntries;
+ }
+
+ ret = validate_tonga_table_entries(hwmgr, table_offset, entries_offset,
+ num_entries, entry_size);
+ if (ret)
+ return ret;
+
+ *sclk_dep_table = header;
+
+ return 0;
+}
+
+static int get_tonga_pcie_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const PPTable_Generic_SubTable_Header **pcie_table)
+{
+ const PPTable_Generic_SubTable_Header *header;
+ u16 table_offset;
+ size_t entries_offset;
+ size_t entry_size;
+ u8 num_entries;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usPCIETableOffset);
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*header), (const void **)&header);
+ if (ret)
+ return ret;
+
+ if (header->ucRevId < 1) {
+ const ATOM_Tonga_PCIE_Table *table =
+ (const ATOM_Tonga_PCIE_Table *)header;
+
+ entries_offset = offsetof(ATOM_Tonga_PCIE_Table, entries);
+ entry_size = sizeof(ATOM_Tonga_PCIE_Record);
+ num_entries = table->ucNumEntries;
+ } else {
+ const ATOM_Polaris10_PCIE_Table *table =
+ (const ATOM_Polaris10_PCIE_Table *)header;
+
+ entries_offset = offsetof(ATOM_Polaris10_PCIE_Table, entries);
+ entry_size = sizeof(ATOM_Polaris10_PCIE_Record);
+ num_entries = table->ucNumEntries;
+ }
+
+ ret = validate_tonga_table_entries(hwmgr, table_offset, entries_offset,
+ num_entries, entry_size);
+ if (ret)
+ return ret;
+
+ *pcie_table = header;
+
+ return 0;
+}
+
+static int get_tonga_hard_limit_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Tonga_Hard_Limit_Table **hard_limit_table)
+{
+ const ATOM_Tonga_Hard_Limit_Table *table;
+ u16 table_offset;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usHardLimitTableOffset);
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ ret = validate_tonga_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Tonga_Hard_Limit_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Tonga_Hard_Limit_Record));
+ if (ret)
+ return ret;
+
+ *hard_limit_table = table;
+
+ return 0;
+}
+
+static int get_tonga_thermal_controller_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Tonga_Thermal_Controller **thermal_controller)
+{
+ u16 table_offset;
+
+ table_offset = le16_to_cpu(powerplay_table->usThermalControllerOffset);
+
+ return get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(**thermal_controller),
+ (const void **)thermal_controller);
+}
+
+static int get_tonga_fan_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const PPTable_Generic_SubTable_Header **fan_table)
+{
+ const PPTable_Generic_SubTable_Header *header;
+ u16 table_offset;
+ size_t table_size;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usFanTableOffset);
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*header), (const void **)&header);
+ if (ret)
+ return ret;
+
+ if (header->ucRevId < 8)
+ table_size = sizeof(ATOM_Tonga_Fan_Table);
+ else if (header->ucRevId == 8)
+ table_size = sizeof(ATOM_Fiji_Fan_Table);
+ else
+ table_size = sizeof(ATOM_Polaris_Fan_Table);
+
+ PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *fan_table = header;
+
+ return 0;
+}
+
+static int get_tonga_power_tune_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const PPTable_Generic_SubTable_Header **power_tune_table)
+{
+ const PPTable_Generic_SubTable_Header *header;
+ u16 table_offset;
+ size_t table_size;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usPowerTuneTableOffset);
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*header), (const void **)&header);
+ if (ret)
+ return ret;
+
+ if (header->ucRevId < 3)
+ table_size = sizeof(ATOM_Tonga_PowerTune_Table);
+ else if (header->ucRevId < 4)
+ table_size = sizeof(ATOM_Fiji_PowerTune_Table);
+ else
+ table_size = sizeof(ATOM_Polaris_PowerTune_Table);
+
+ PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *power_tune_table = header;
+
+ return 0;
+}
+
+static int get_tonga_ppm_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Tonga_PPM_Table **ppm_table)
+{
+ u16 table_offset;
+
+ table_offset = le16_to_cpu(powerplay_table->usPPMTableOffset);
+
+ return get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(**ppm_table), (const void **)ppm_table);
+}
+
+static int get_tonga_gpio_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Tonga_GPIO_Table **gpio_table)
+{
+ u16 table_offset;
+
+ table_offset = le16_to_cpu(powerplay_table->usGPIOTableOffset);
+
+ return get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(**gpio_table), (const void **)gpio_table);
+}
+
+static int get_tonga_vce_state_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Tonga_VCE_State_Table **vce_state_table)
+{
+ const ATOM_Tonga_VCE_State_Table *table;
+ u16 table_offset;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usVCEStateTableOffset);
+ ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ ret = validate_tonga_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Tonga_VCE_State_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Tonga_VCE_State_Record));
+ if (ret)
+ return ret;
+
+ *vce_state_table = table;
+
+ return 0;
+}
+
static int get_vddc_lookup_table(
struct pp_hwmgr *hwmgr,
phm_ppt_v1_voltage_lookup_table **lookup_table,
@@ -158,6 +520,7 @@ static int get_vddc_lookup_table(
)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_voltage_lookup_table *table;
phm_ppt_v1_voltage_lookup_record *record;
ATOM_Tonga_Voltage_Lookup_Record *atom_record;
@@ -165,13 +528,22 @@ static int get_vddc_lookup_table(
PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
"Invalid CAC Leakage PowerPlay Table!", return 1);
- table = kzalloc_flex(*table, entries, max_levels);
+ num_entries = min_t(uint32_t, vddc_lookup_pp_tables->ucNumEntries,
+ min_t(uint32_t, max_levels,
+ pp_entries_max(hwmgr, vddc_lookup_pp_tables,
+ sizeof(*vddc_lookup_pp_tables),
+ sizeof(ATOM_Tonga_Voltage_Lookup_Record))));
+ if (num_entries < vddc_lookup_pp_tables->ucNumEntries)
+ pr_warn("amdgpu: VddcLookup table: clamping ucNumEntries %u -> %u\n",
+ vddc_lookup_pp_tables->ucNumEntries, num_entries);
+
+ table = kzalloc_flex(*table, entries, num_entries);
if (!table)
return -ENOMEM;
- table->count = vddc_lookup_pp_tables->ucNumEntries;
+ table->count = num_entries;
- for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
phm_ppt_v1_voltage_lookup_record,
entries, table, i);
@@ -198,7 +570,7 @@ static int get_vddc_lookup_table(
*/
static int get_platform_power_management_table(
struct pp_hwmgr *hwmgr,
- ATOM_Tonga_PPM_Table *atom_ppm_table)
+ const ATOM_Tonga_PPM_Table *atom_ppm_table)
{
struct phm_ppm_table *ptr = kzalloc_obj(*ptr);
struct phm_ppt_v1_information *pp_table_information =
@@ -246,7 +618,7 @@ static int init_dpm_2_parameters(
{
int result = 0;
struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
- ATOM_Tonga_PPM_Table *atom_ppm_table;
+ const ATOM_Tonga_PPM_Table *atom_ppm_table;
uint32_t disable_ppm = 0;
uint32_t disable_power_control = 0;
@@ -275,30 +647,39 @@ static int init_dpm_2_parameters(
}
if (0 != powerplay_table->usVddcLookupTableOffset) {
- const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable =
- (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
-
- result = get_vddc_lookup_table(hwmgr,
- &pp_table_information->vddc_lookup_table, pVddcCACTable, 16);
+ const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable;
+
+ result = get_tonga_voltage_lookup_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usVddcLookupTableOffset),
+ 16, &pVddcCACTable);
+ if (!result)
+ result = get_vddc_lookup_table(hwmgr,
+ &pp_table_information->vddc_lookup_table,
+ pVddcCACTable, 16);
}
- if (0 != powerplay_table->usVddgfxLookupTableOffset) {
- const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable =
- (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset));
+ if (!result && 0 != powerplay_table->usVddgfxLookupTableOffset) {
+ const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable;
- result = get_vddc_lookup_table(hwmgr,
- &pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16);
+ result = get_tonga_voltage_lookup_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset),
+ 16, &pVddgfxCACTable);
+ if (!result)
+ result = get_vddc_lookup_table(hwmgr,
+ &pp_table_information->vddgfx_lookup_table,
+ pVddgfxCACTable, 16);
}
disable_ppm = 0;
if (0 == disable_ppm) {
- atom_ppm_table = (ATOM_Tonga_PPM_Table *)
- (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset));
-
if (0 != powerplay_table->usPPMTableOffset) {
- if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) {
+ int ret;
+
+ ret = get_tonga_ppm_table(hwmgr, powerplay_table,
+ &atom_ppm_table);
+ if (!ret &&
+ get_platform_power_management_table(hwmgr,
+ atom_ppm_table) == 0) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_EnablePlatformPowerManagement);
}
@@ -363,6 +744,7 @@ static int get_mclk_voltage_dependency_table(
)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_clock_voltage_dependency_table *mclk_table;
phm_ppt_v1_clock_voltage_dependency_record *mclk_table_record;
ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record;
@@ -370,14 +752,21 @@ static int get_mclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- mclk_table = kzalloc_flex(*mclk_table, entries,
- mclk_dep_table->ucNumEntries);
+ num_entries = min_t(uint32_t, mclk_dep_table->ucNumEntries,
+ pp_entries_max(hwmgr, mclk_dep_table,
+ sizeof(*mclk_dep_table),
+ sizeof(ATOM_Tonga_MCLK_Dependency_Record)));
+ if (num_entries < mclk_dep_table->ucNumEntries)
+ pr_warn("amdgpu: MCLK dependency table: clamping ucNumEntries %u -> %u\n",
+ mclk_dep_table->ucNumEntries, num_entries);
+
+ mclk_table = kzalloc_flex(*mclk_table, entries, num_entries);
if (!mclk_table)
return -ENOMEM;
- mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
+ mclk_table->count = num_entries;
- for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
mclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
phm_ppt_v1_clock_voltage_dependency_record,
entries, mclk_table, i);
@@ -403,6 +792,7 @@ static int get_sclk_voltage_dependency_table(
)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_clock_voltage_dependency_table *sclk_table;
phm_ppt_v1_clock_voltage_dependency_record *sclk_table_record;
@@ -414,14 +804,21 @@ static int get_sclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- sclk_table = kzalloc_flex(*sclk_table, entries,
- tonga_table->ucNumEntries);
+ num_entries = min_t(uint32_t, tonga_table->ucNumEntries,
+ pp_entries_max(hwmgr, tonga_table,
+ sizeof(*tonga_table),
+ sizeof(ATOM_Tonga_SCLK_Dependency_Record)));
+ if (num_entries < tonga_table->ucNumEntries)
+ pr_warn("amdgpu: Tonga SCLK dependency table: clamping ucNumEntries %u -> %u\n",
+ tonga_table->ucNumEntries, num_entries);
+
+ sclk_table = kzalloc_flex(*sclk_table, entries, num_entries);
if (!sclk_table)
return -ENOMEM;
- sclk_table->count = (uint32_t)tonga_table->ucNumEntries;
+ sclk_table->count = num_entries;
- for (i = 0; i < tonga_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_SCLK_Dependency_Record,
entries, tonga_table, i);
@@ -443,14 +840,21 @@ static int get_sclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- sclk_table = kzalloc_flex(*sclk_table, entries,
- polaris_table->ucNumEntries);
+ num_entries = min_t(uint32_t, polaris_table->ucNumEntries,
+ pp_entries_max(hwmgr, polaris_table,
+ sizeof(*polaris_table),
+ sizeof(ATOM_Polaris_SCLK_Dependency_Record)));
+ if (num_entries < polaris_table->ucNumEntries)
+ pr_warn("amdgpu: Polaris SCLK dependency table: clamping ucNumEntries %u -> %u\n",
+ polaris_table->ucNumEntries, num_entries);
+
+ sclk_table = kzalloc_flex(*sclk_table, entries, num_entries);
if (!sclk_table)
return -ENOMEM;
- sclk_table->count = (uint32_t)polaris_table->ucNumEntries;
+ sclk_table->count = num_entries;
- for (i = 0; i < polaris_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Polaris_SCLK_Dependency_Record,
entries, polaris_table, i);
@@ -715,20 +1119,29 @@ static int get_mm_clock_voltage_table(
)
{
uint32_t i;
+ uint32_t num_entries;
const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record;
phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
phm_ppt_v1_mm_clock_voltage_dependency_record *mm_table_record;
PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- mm_table = kzalloc_flex(*mm_table, entries,
- mm_dependency_table->ucNumEntries);
+
+ num_entries = min_t(uint32_t, mm_dependency_table->ucNumEntries,
+ pp_entries_max(hwmgr, mm_dependency_table,
+ sizeof(*mm_dependency_table),
+ sizeof(ATOM_Tonga_MM_Dependency_Record)));
+ if (num_entries < mm_dependency_table->ucNumEntries)
+ pr_warn("amdgpu: MM dependency table: clamping ucNumEntries %u -> %u\n",
+ mm_dependency_table->ucNumEntries, num_entries);
+
+ mm_table = kzalloc_flex(*mm_table, entries, num_entries);
if (!mm_table)
return -ENOMEM;
- mm_table->count = mm_dependency_table->ucNumEntries;
+ mm_table->count = num_entries;
- for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
mm_dependency_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_MM_Dependency_Record,
entries, mm_dependency_table, i);
@@ -789,28 +1202,13 @@ static int init_clock_voltage_dependency(
int result = 0;
struct phm_ppt_v1_information *pp_table_information =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
-
- const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table =
- (const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
- const PPTable_Generic_SubTable_Header *pPowerTuneTable =
- (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
- const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
- (const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
- const PPTable_Generic_SubTable_Header *sclk_dep_table =
- (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
- const ATOM_Tonga_Hard_Limit_Table *pHardLimits =
- (const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usHardLimitTableOffset));
- const PPTable_Generic_SubTable_Header *pcie_table =
- (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usPCIETableOffset));
- const ATOM_Tonga_GPIO_Table *gpio_table =
- (const ATOM_Tonga_GPIO_Table *)(((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usGPIOTableOffset));
+ const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table;
+ const PPTable_Generic_SubTable_Header *pPowerTuneTable;
+ const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table;
+ const PPTable_Generic_SubTable_Header *sclk_dep_table;
+ const ATOM_Tonga_Hard_Limit_Table *pHardLimits;
+ const PPTable_Generic_SubTable_Header *pcie_table;
+ const ATOM_Tonga_GPIO_Table *gpio_table;
pp_table_information->vdd_dep_on_sclk = NULL;
pp_table_information->vdd_dep_on_mclk = NULL;
@@ -818,29 +1216,58 @@ static int init_clock_voltage_dependency(
pp_table_information->pcie_table = NULL;
pp_table_information->gpio_table = NULL;
- if (powerplay_table->usMMDependencyTableOffset != 0)
- result = get_mm_clock_voltage_table(hwmgr,
- &pp_table_information->mm_dep_table, mm_dependency_table);
+ if (powerplay_table->usMMDependencyTableOffset != 0) {
+ result = get_tonga_mm_dependency_table(hwmgr, powerplay_table,
+ &mm_dependency_table);
+ if (!result)
+ result = get_mm_clock_voltage_table(hwmgr,
+ &pp_table_information->mm_dep_table,
+ mm_dependency_table);
+ }
- if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0)
- result = get_cac_tdp_table(hwmgr,
- &pp_table_information->cac_dtp_table, pPowerTuneTable);
+ if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0) {
+ result = get_tonga_power_tune_table(hwmgr, powerplay_table,
+ &pPowerTuneTable);
+ if (!result)
+ result = get_cac_tdp_table(hwmgr,
+ &pp_table_information->cac_dtp_table,
+ pPowerTuneTable);
+ }
- if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0)
- result = get_sclk_voltage_dependency_table(hwmgr,
- &pp_table_information->vdd_dep_on_sclk, sclk_dep_table);
+ if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0) {
+ result = get_tonga_sclk_dependency_table(hwmgr, powerplay_table,
+ &sclk_dep_table);
+ if (!result)
+ result = get_sclk_voltage_dependency_table(hwmgr,
+ &pp_table_information->vdd_dep_on_sclk,
+ sclk_dep_table);
+ }
- if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0)
- result = get_mclk_voltage_dependency_table(hwmgr,
- &pp_table_information->vdd_dep_on_mclk, mclk_dep_table);
+ if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0) {
+ result = get_tonga_mclk_dependency_table(hwmgr, powerplay_table,
+ &mclk_dep_table);
+ if (!result)
+ result = get_mclk_voltage_dependency_table(hwmgr,
+ &pp_table_information->vdd_dep_on_mclk,
+ mclk_dep_table);
+ }
- if (result == 0 && powerplay_table->usPCIETableOffset != 0)
- result = get_pcie_table(hwmgr,
- &pp_table_information->pcie_table, pcie_table);
+ if (result == 0 && powerplay_table->usPCIETableOffset != 0) {
+ result = get_tonga_pcie_table(hwmgr, powerplay_table,
+ &pcie_table);
+ if (!result)
+ result = get_pcie_table(hwmgr,
+ &pp_table_information->pcie_table, pcie_table);
+ }
- if (result == 0 && powerplay_table->usHardLimitTableOffset != 0)
- result = get_hard_limits(hwmgr,
- &pp_table_information->max_clock_voltage_on_dc, pHardLimits);
+ if (result == 0 && powerplay_table->usHardLimitTableOffset != 0) {
+ result = get_tonga_hard_limit_table(hwmgr, powerplay_table,
+ &pHardLimits);
+ if (!result)
+ result = get_hard_limits(hwmgr,
+ &pp_table_information->max_clock_voltage_on_dc,
+ pHardLimits);
+ }
hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
pp_table_information->max_clock_voltage_on_dc.sclk;
@@ -861,9 +1288,13 @@ static int init_clock_voltage_dependency(
result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values,
pp_table_information->vdd_dep_on_sclk);
- if (!result && gpio_table)
- result = get_gpio_table(hwmgr, &pp_table_information->gpio_table,
- gpio_table);
+ if (!result && powerplay_table->usGPIOTableOffset) {
+ result = get_tonga_gpio_table(hwmgr, powerplay_table,
+ &gpio_table);
+ if (!result)
+ result = get_gpio_table(hwmgr,
+ &pp_table_information->gpio_table, gpio_table);
+ }
return result;
}
@@ -908,14 +1339,17 @@ static int init_thermal_controller(
)
{
const PPTable_Generic_SubTable_Header *fan_table;
- ATOM_Tonga_Thermal_Controller *thermal_controller;
+ const ATOM_Tonga_Thermal_Controller *thermal_controller;
+ int ret;
- thermal_controller = (ATOM_Tonga_Thermal_Controller *)
- (((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usThermalControllerOffset));
PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset),
"Thermal controller table not set!", return -1);
+ ret = get_tonga_thermal_controller_table(hwmgr, powerplay_table,
+ &thermal_controller);
+ if (ret)
+ return ret;
+
hwmgr->thermal_controller.ucType = thermal_controller->ucType;
hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
@@ -943,12 +1377,13 @@ static int init_thermal_controller(
return 0;
}
- fan_table = (const PPTable_Generic_SubTable_Header *)
- (((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usFanTableOffset));
-
PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset),
"Fan table not set!", return -1);
+
+ ret = get_tonga_fan_table(hwmgr, powerplay_table, &fan_table);
+ if (ret)
+ return ret;
+
PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId),
"Unsupported fan table format!", return -1);
@@ -1104,21 +1539,24 @@ static int init_thermal_controller(
}
/**
- * check_powerplay_tables - Private Function used during initialization.
- * Inspect the PowerPlay table for obvious signs of corruption.
+ * get_tonga_state_array - Get the Tonga state array from the PowerPlay table.
* @hwmgr: Pointer to the hardware manager.
* @powerplay_table: Pointer to the PowerPlay Table.
- * Exception: 2 if the powerplay table is incorrect.
+ * @state_array: Pointer to the returned Tonga state array.
+ *
+ * Return: 0 on success, negative error code on failure.
*/
-static int check_powerplay_tables(
- struct pp_hwmgr *hwmgr,
- const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
- )
+static int get_tonga_state_array(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Tonga_State_Array **state_array)
{
const ATOM_Tonga_State_Array *state_arrays;
+ u16 state_array_offset;
+ size_t state_array_size;
+ size_t table_size = hwmgr->soft_pp_table_size;
- state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usStateArrayOffset));
+ PP_ASSERT_WITH_CODE((table_size >= sizeof(*powerplay_table)),
+ "Invalid PowerPlay Table!", return -1);
PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <=
powerplay_table->sHeader.ucTableFormatRevision),
@@ -1127,12 +1565,34 @@ static int check_powerplay_tables(
"State table is not set!", return -1);
PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize),
"Invalid PowerPlay Table!", return -1);
+
+ state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset);
+ PP_ASSERT_WITH_CODE((state_array_offset <=
+ table_size - sizeof(*state_arrays)),
+ "Invalid PowerPlay Table!", return -1);
+
+ state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) +
+ state_array_offset);
PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
+ state_array_size = struct_size(state_arrays, entries, state_arrays->ucNumEntries);
+ PP_ASSERT_WITH_CODE((state_array_size <= table_size - state_array_offset),
+ "Invalid PowerPlay Table!", return -1);
+
+ *state_array = state_arrays;
+
return 0;
}
+static int check_powerplay_tables(struct pp_hwmgr *hwmgr,
+ const ATOM_Tonga_POWERPLAYTABLE *powerplay_table)
+{
+ const ATOM_Tonga_State_Array *state_arrays;
+
+ return get_tonga_state_array(hwmgr, powerplay_table, &state_arrays);
+}
+
static int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr)
{
int result = 0;
@@ -1236,17 +1696,16 @@ const struct pp_table_func pptable_v1_0_funcs = {
int get_number_of_powerplay_table_entries_v1_0(struct pp_hwmgr *hwmgr)
{
- ATOM_Tonga_State_Array const *state_arrays;
+ const ATOM_Tonga_State_Array *state_arrays;
const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+ int result;
PP_ASSERT_WITH_CODE((NULL != pp_table),
"Missing PowerPlay Table!", return -1);
- PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >=
- ATOM_Tonga_TABLE_REVISION_TONGA),
- "Incorrect PowerPlay table revision!", return -1);
- state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
- le16_to_cpu(pp_table->usStateArrayOffset));
+ result = get_tonga_state_array(hwmgr, pp_table, &state_arrays);
+ PP_ASSERT_WITH_CODE((result == 0),
+ "Invalid PowerPlay Table State Array.", return result);
return (uint32_t)(state_arrays->ucNumEntries);
}
@@ -1287,13 +1746,15 @@ static int ppt_get_num_of_vce_state_table_entries_v1_0(struct pp_hwmgr *hwmgr)
{
const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
const ATOM_Tonga_VCE_State_Table *vce_state_table;
+ int ret;
if (pp_table == NULL)
return 0;
- vce_state_table = (void *)pp_table +
- le16_to_cpu(pp_table->usVCEStateTableOffset);
+ ret = get_tonga_vce_state_table(hwmgr, pp_table, &vce_state_table);
+ if (ret)
+ return 0;
return vce_state_table->ucNumEntries;
}
@@ -1302,18 +1763,39 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i
struct amd_vce_state *vce_state, void **clock_info, uint32_t *flag)
{
const ATOM_Tonga_VCE_State_Record *vce_state_record;
- ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record;
+ ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record = NULL;
+ ATOM_Polaris_SCLK_Dependency_Record *polaris_sclk_dep_record = NULL;
ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record;
ATOM_Tonga_MM_Dependency_Record *mm_dep_record;
const ATOM_Tonga_POWERPLAYTABLE *pptable = get_powerplay_table(hwmgr);
- const ATOM_Tonga_VCE_State_Table *vce_state_table = (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pptable)
- + le16_to_cpu(pptable->usVCEStateTableOffset));
- const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table = (ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long)pptable)
- + le16_to_cpu(pptable->usSclkDependencyTableOffset));
- const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = (ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long)pptable)
- + le16_to_cpu(pptable->usMclkDependencyTableOffset));
- const ATOM_Tonga_MM_Dependency_Table *mm_dep_table = (ATOM_Tonga_MM_Dependency_Table *)(((unsigned long)pptable)
- + le16_to_cpu(pptable->usMMDependencyTableOffset));
+ const ATOM_Tonga_VCE_State_Table *vce_state_table;
+ const PPTable_Generic_SubTable_Header *sclk_dep_table_header;
+ const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table;
+ const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table;
+ const ATOM_Tonga_MM_Dependency_Table *mm_dep_table;
+ int ret;
+
+ if (!pptable)
+ return -EINVAL;
+
+ ret = get_tonga_vce_state_table(hwmgr, pptable, &vce_state_table);
+ if (ret)
+ return ret;
+
+ ret = get_tonga_sclk_dependency_table(hwmgr, pptable,
+ &sclk_dep_table_header);
+ if (ret)
+ return ret;
+ sclk_dep_table = (const ATOM_Tonga_SCLK_Dependency_Table *)
+ sclk_dep_table_header;
+
+ ret = get_tonga_mclk_dependency_table(hwmgr, pptable, &mclk_dep_table);
+ if (ret)
+ return ret;
+
+ ret = get_tonga_mm_dependency_table(hwmgr, pptable, &mm_dep_table);
+ if (ret)
+ return ret;
PP_ASSERT_WITH_CODE((i < vce_state_table->ucNumEntries),
"Requested state entry ID is out of range!",
@@ -1322,10 +1804,27 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i
vce_state_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_VCE_State_Record,
entries, vce_state_table, i);
- sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
- ATOM_Tonga_SCLK_Dependency_Record,
- entries, sclk_dep_table,
- vce_state_record->ucSCLKIndex);
+ PP_ASSERT_WITH_CODE((vce_state_record->ucSCLKIndex <
+ sclk_dep_table->ucNumEntries),
+ "Invalid PowerPlay Table!", return -EINVAL);
+ PP_ASSERT_WITH_CODE((vce_state_record->ucVCEClockIndex <
+ mm_dep_table->ucNumEntries),
+ "Invalid PowerPlay Table!", return -EINVAL);
+ PP_ASSERT_WITH_CODE((mclk_dep_table->ucNumEntries != 0),
+ "Invalid PowerPlay Table!", return -EINVAL);
+
+ if (sclk_dep_table_header->ucRevId < 1)
+ sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+ ATOM_Tonga_SCLK_Dependency_Record,
+ entries, sclk_dep_table,
+ vce_state_record->ucSCLKIndex);
+ else
+ polaris_sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
+ ATOM_Polaris_SCLK_Dependency_Record,
+ entries,
+ (ATOM_Polaris_SCLK_Dependency_Table *)
+ sclk_dep_table_header,
+ vce_state_record->ucSCLKIndex);
mm_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_MM_Dependency_Record,
entries, mm_dep_table,
@@ -1334,7 +1833,10 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i
vce_state->evclk = le32_to_cpu(mm_dep_record->ulEClk);
vce_state->ecclk = le32_to_cpu(mm_dep_record->ulEClk);
- vce_state->sclk = le32_to_cpu(sclk_dep_record->ulSclk);
+ if (sclk_dep_record)
+ vce_state->sclk = le32_to_cpu(sclk_dep_record->ulSclk);
+ else
+ vce_state->sclk = le32_to_cpu(polaris_sclk_dep_record->ulSclk);
if (vce_state_record->ucMCLKIndex >= mclk_dep_table->ucNumEntries)
mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
@@ -1377,15 +1879,11 @@ int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr,
if (pp_table->sHeader.ucTableFormatRevision >=
ATOM_Tonga_TABLE_REVISION_TONGA) {
- state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
- le16_to_cpu(pp_table->usStateArrayOffset));
-
- PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset),
- "Invalid PowerPlay Table State Array Offset.", return -1);
- PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
- "Invalid PowerPlay Table State Array.", return -1);
- PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
- "Invalid PowerPlay Table State Array Entry.", return -1);
+ result = get_tonga_state_array(hwmgr, pp_table, &state_arrays);
+ PP_ASSERT_WITH_CODE((result == 0),
+ "Invalid PowerPlay Table State Array.", return result);
+ PP_ASSERT_WITH_CODE((entry_index < state_arrays->ucNumEntries),
+ "Invalid PowerPlay Table State Array Entry.", return -1);
state_entry = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_State, entries,
@@ -1411,4 +1909,3 @@ int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr,
return result;
}
-
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
index bfd8fbb0b49d..56926eec6820 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c
@@ -47,26 +47,53 @@
#define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6
+static bool pp_table_has_space(struct pp_hwmgr *hwmgr, size_t offset,
+ size_t size)
+{
+ size_t table_size = hwmgr->soft_pp_table_size;
+
+ return offset <= table_size && size <= table_size - offset;
+}
+
+static const ATOM_PPLIB_EXTENDEDHEADER *
+get_extended_header(struct pp_hwmgr *hwmgr,
+ const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
+ size_t min_size)
+{
+ const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3;
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
+ u16 offset;
+
+ if (le16_to_cpu(powerplay_table->usTableSize) <
+ sizeof(ATOM_PPLIB_POWERPLAYTABLE3) ||
+ !pp_table_has_space(hwmgr, 0, sizeof(ATOM_PPLIB_POWERPLAYTABLE3)))
+ return NULL;
+
+ powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
+ offset = le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset);
+ if (!offset || !pp_table_has_space(hwmgr, offset,
+ sizeof(extended_header->usSize)))
+ return NULL;
+
+ extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *)
+ (((unsigned long)powerplay_table) + offset);
+ if (le16_to_cpu(extended_header->usSize) < min_size ||
+ !pp_table_has_space(hwmgr, offset, min_size))
+ return NULL;
+
+ return extended_header;
+}
+
static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr,
const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
{
uint16_t vce_table_offset = 0;
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
- if (le16_to_cpu(powerplay_table->usTableSize) >=
- sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
- const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
- (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
-
- if (powerplay_table3->usExtendendedHeaderOffset > 0) {
- const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
- (const ATOM_PPLIB_EXTENDEDHEADER *)
- (((unsigned long)powerplay_table3) +
- le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
- if (le16_to_cpu(extended_header->usSize) >=
- SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2)
- vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset);
- }
- }
+ extended_header = get_extended_header(hwmgr, powerplay_table,
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2);
+ if (extended_header)
+ vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset);
return vce_table_offset;
}
@@ -93,7 +120,14 @@ static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr,
if (table_offset > 0) {
const VCEClockInfoArray *p = (const VCEClockInfoArray *)
(((unsigned long) powerplay_table) + table_offset);
- table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo);
+ size_t size;
+
+ if (!pp_table_has_space(hwmgr, table_offset, sizeof(p->ucNumEntries)))
+ return 0;
+
+ size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo);
+ if (pp_table_has_space(hwmgr, table_offset, size))
+ table_size = size;
}
return table_size;
@@ -104,10 +138,13 @@ static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr,
{
uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
powerplay_table);
+ u16 table_size;
- if (table_offset > 0)
- return table_offset + get_vce_clock_info_array_size(hwmgr,
- powerplay_table);
+ if (table_offset > 0) {
+ table_size = get_vce_clock_info_array_size(hwmgr, powerplay_table);
+ if (table_size)
+ return table_offset + table_size;
+ }
return 0;
}
@@ -121,8 +158,15 @@ static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr,
if (table_offset > 0) {
const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable =
(const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset);
+ size_t size;
- table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record);
+ if (!pp_table_has_space(hwmgr, table_offset, sizeof(ptable->numEntries)))
+ return 0;
+
+ size = sizeof(uint8_t) +
+ ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record);
+ if (pp_table_has_space(hwmgr, table_offset, size))
+ table_size = size;
}
return table_size;
}
@@ -130,9 +174,13 @@ static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr,
static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
{
uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
+ u16 table_size;
- if (table_offset > 0)
- return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table);
+ if (table_offset > 0) {
+ table_size = get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table);
+ if (table_size)
+ return table_offset + table_size;
+ }
return 0;
}
@@ -143,8 +191,12 @@ static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table(
{
uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table);
- if (table_offset > 0)
- return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset);
+ if (table_offset > 0) {
+ if (pp_table_has_space(hwmgr, table_offset,
+ sizeof(((ATOM_PPLIB_VCE_State_Table *)0)->numEntries)))
+ return (const ATOM_PPLIB_VCE_State_Table *)
+ (((unsigned long)powerplay_table) + table_offset);
+ }
return NULL;
}
@@ -153,21 +205,13 @@ static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr,
const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
{
uint16_t uvd_table_offset = 0;
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
+
+ extended_header = get_extended_header(hwmgr, powerplay_table,
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3);
+ if (extended_header)
+ uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset);
- if (le16_to_cpu(powerplay_table->usTableSize) >=
- sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
- const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
- (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
- if (powerplay_table3->usExtendendedHeaderOffset > 0) {
- const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
- (const ATOM_PPLIB_EXTENDEDHEADER *)
- (((unsigned long)powerplay_table3) +
- le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
- if (le16_to_cpu(extended_header->usSize) >=
- SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3)
- uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset);
- }
- }
return uvd_table_offset;
}
@@ -193,8 +237,14 @@ static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr,
const UVDClockInfoArray *p = (const UVDClockInfoArray *)
(((unsigned long) powerplay_table)
+ table_offset);
- table_size = sizeof(UCHAR) +
- p->ucNumEntries * sizeof(UVDClockInfo);
+ size_t size;
+
+ if (!pp_table_has_space(hwmgr, table_offset, sizeof(p->ucNumEntries)))
+ return 0;
+
+ size = sizeof(UCHAR) + p->ucNumEntries * sizeof(UVDClockInfo);
+ if (pp_table_has_space(hwmgr, table_offset, size))
+ table_size = size;
}
return table_size;
@@ -206,10 +256,13 @@ static uint16_t get_uvd_clock_voltage_limit_table_offset(
{
uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
powerplay_table);
+ u16 table_size;
- if (table_offset > 0)
- return table_offset +
- get_uvd_clock_info_array_size(hwmgr, powerplay_table);
+ if (table_offset > 0) {
+ table_size = get_uvd_clock_info_array_size(hwmgr, powerplay_table);
+ if (table_size)
+ return table_offset + table_size;
+ }
return 0;
}
@@ -218,21 +271,12 @@ static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr,
const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
{
uint16_t samu_table_offset = 0;
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
- if (le16_to_cpu(powerplay_table->usTableSize) >=
- sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
- const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
- (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
- if (powerplay_table3->usExtendendedHeaderOffset > 0) {
- const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
- (const ATOM_PPLIB_EXTENDEDHEADER *)
- (((unsigned long)powerplay_table3) +
- le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
- if (le16_to_cpu(extended_header->usSize) >=
- SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4)
- samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset);
- }
- }
+ extended_header = get_extended_header(hwmgr, powerplay_table,
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4);
+ if (extended_header)
+ samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset);
return samu_table_offset;
}
@@ -254,21 +298,12 @@ static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr,
const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
{
uint16_t acp_table_offset = 0;
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
- if (le16_to_cpu(powerplay_table->usTableSize) >=
- sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
- const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
- (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
- if (powerplay_table3->usExtendendedHeaderOffset > 0) {
- const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
- (const ATOM_PPLIB_EXTENDEDHEADER *)
- (((unsigned long)powerplay_table3) +
- le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
- if (le16_to_cpu(pExtendedHeader->usSize) >=
- SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6)
- acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset);
- }
- }
+ extended_header = get_extended_header(hwmgr, powerplay_table,
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6);
+ if (extended_header)
+ acp_table_offset = le16_to_cpu(extended_header->usACPTableOffset);
return acp_table_offset;
}
@@ -290,21 +325,12 @@ static uint16_t get_cacp_tdp_table_offset(
const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
{
uint16_t cacTdpTableOffset = 0;
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
- if (le16_to_cpu(powerplay_table->usTableSize) >=
- sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
- const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
- (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
- if (powerplay_table3->usExtendendedHeaderOffset > 0) {
- const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
- (const ATOM_PPLIB_EXTENDEDHEADER *)
- (((unsigned long)powerplay_table3) +
- le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
- if (le16_to_cpu(pExtendedHeader->usSize) >=
- SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7)
- cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset);
- }
- }
+ extended_header = get_extended_header(hwmgr, powerplay_table,
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7);
+ if (extended_header)
+ cacTdpTableOffset = le16_to_cpu(extended_header->usPowerTuneTableOffset);
return cacTdpTableOffset;
}
@@ -341,22 +367,13 @@ static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr,
const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
{
uint16_t sclk_vdd_gfx_table_offset = 0;
+ const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
- if (le16_to_cpu(powerplay_table->usTableSize) >=
- sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
- const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
- (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
- if (powerplay_table3->usExtendendedHeaderOffset > 0) {
- const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
- (const ATOM_PPLIB_EXTENDEDHEADER *)
- (((unsigned long)powerplay_table3) +
- le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
- if (le16_to_cpu(pExtendedHeader->usSize) >=
- SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8)
- sclk_vdd_gfx_table_offset =
- le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset);
- }
- }
+ extended_header = get_extended_header(hwmgr, powerplay_table,
+ SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8);
+ if (extended_header)
+ sclk_vdd_gfx_table_offset =
+ le16_to_cpu(extended_header->usSclkVddgfxTableOffset);
return sclk_vdd_gfx_table_offset;
}
@@ -769,20 +786,37 @@ static ULONG size_of_entry_v2(ULONG num_dpm_levels)
}
static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
+ struct pp_hwmgr *hwmgr,
const StateArray * pstate_arrays,
+ u16 state_array_offset,
ULONG entry_index)
{
ULONG i;
const ATOM_PPLIB_STATE_V2 *pstate;
+ size_t entry_offset;
+ size_t entry_size;
+
+ if (entry_index >= pstate_arrays->ucNumEntries)
+ return NULL;
+ entry_offset = state_array_offset + sizeof(pstate_arrays->ucNumEntries);
pstate = pstate_arrays->states;
- if (entry_index <= pstate_arrays->ucNumEntries) {
- for (i = 0; i < entry_index; i++)
- pstate = (ATOM_PPLIB_STATE_V2 *)(
- (unsigned long)pstate +
- size_of_entry_v2(pstate->ucNumDPMLevels));
+ for (i = 0; i <= entry_index; i++) {
+ if (!pp_table_has_space(hwmgr, entry_offset, sizeof(*pstate)))
+ return NULL;
+
+ entry_size = size_of_entry_v2(pstate->ucNumDPMLevels);
+ if (!pp_table_has_space(hwmgr, entry_offset, entry_size))
+ return NULL;
+
+ if (i == entry_index)
+ return pstate;
+
+ entry_offset += entry_size;
+ pstate = (ATOM_PPLIB_STATE_V2 *)((unsigned long)pstate + entry_size);
}
- return pstate;
+
+ return NULL;
}
static const unsigned char soft_dummy_pp_table[] = {
@@ -850,6 +884,8 @@ int pp_tables_get_response_times(struct pp_hwmgr *hwmgr,
PP_ASSERT_WITH_CODE(NULL != powerplay_tab,
"Missing PowerPlay Table!", return -EINVAL);
+ PP_ASSERT_WITH_CODE(pp_table_has_space(hwmgr, 0, sizeof(*powerplay_tab)),
+ "Invalid PowerPlay Table!", return -EINVAL);
*vol_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usVoltageTime);
*bb_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usBackbiasTime);
@@ -862,13 +898,21 @@ int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
{
const StateArray *pstate_arrays;
const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
+ u16 state_array_offset;
if (powerplay_table == NULL)
return -1;
+ if (!pp_table_has_space(hwmgr, 0, sizeof(*powerplay_table)))
+ return -1;
if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
+ state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset);
+ if (!pp_table_has_space(hwmgr, state_array_offset,
+ sizeof(pstate_arrays->ucNumEntries)))
+ return -1;
+
pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usStateArrayOffset));
+ state_array_offset);
*num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries);
} else
@@ -895,49 +939,128 @@ int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
const NonClockInfoArray *pnon_clock_arrays;
const ATOM_PPLIB_STATE *pstate_entry;
+ u16 state_array_offset;
+ u16 clock_info_array_offset;
+ u16 non_clock_info_array_offset;
+ size_t clock_info_offset;
+ size_t non_clock_info_offset;
+ size_t state_entry_offset;
if (powerplay_table == NULL)
return -1;
+ if (!pp_table_has_space(hwmgr, 0, sizeof(*powerplay_table)))
+ return -1;
ps->classification.bios_index = entry_index;
if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
+ state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset);
+ if (!pp_table_has_space(hwmgr, state_array_offset,
+ sizeof(pstate_arrays->ucNumEntries)))
+ return -1;
+
pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usStateArrayOffset));
+ state_array_offset);
+
+ if (entry_index >= pstate_arrays->ucNumEntries)
+ return -1;
- if (entry_index > pstate_arrays->ucNumEntries)
+ pstate_entry_v2 = get_state_entry_v2(hwmgr, pstate_arrays,
+ state_array_offset,
+ entry_index);
+ if (!pstate_entry_v2)
+ return -1;
+
+ clock_info_array_offset =
+ le16_to_cpu(powerplay_table->usClockInfoArrayOffset);
+ if (!pp_table_has_space(hwmgr, clock_info_array_offset,
+ sizeof(*pclock_arrays)))
return -1;
- pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index);
pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
+ clock_info_array_offset);
+ if (!pclock_arrays->ucEntrySize)
+ return -1;
+
+ non_clock_info_array_offset =
+ le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset);
+ if (!pp_table_has_space(hwmgr, non_clock_info_array_offset,
+ sizeof(*pnon_clock_arrays)))
+ return -1;
pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset));
+ non_clock_info_array_offset);
+ if (!pnon_clock_arrays->ucEntrySize ||
+ pnon_clock_arrays->ucEntrySize < ATOM_PPLIB_NONCLOCKINFO_VER1 ||
+ (pnon_clock_arrays->ucEntrySize > ATOM_PPLIB_NONCLOCKINFO_VER1 &&
+ pnon_clock_arrays->ucEntrySize < ATOM_PPLIB_NONCLOCKINFO_VER2) ||
+ pstate_entry_v2->nonClockInfoIndex >= pnon_clock_arrays->ucNumEntries)
+ return -1;
+ non_clock_info_offset = non_clock_info_array_offset +
+ offsetof(NonClockInfoArray, nonClockInfo) +
+ pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize;
+ if (!pp_table_has_space(hwmgr, non_clock_info_offset,
+ pnon_clock_arrays->ucEntrySize))
+ return -1;
pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) +
(pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize));
result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info);
for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) {
- const void *pclock_info = (const void *)(
- (unsigned long)(pclock_arrays->clockInfo) +
- (pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize));
+ const void *pclock_info;
+
+ if (pstate_entry_v2->clockInfoIndex[i] >=
+ pclock_arrays->ucNumEntries)
+ return -1;
+
+ clock_info_offset = clock_info_array_offset +
+ offsetof(ClockInfoArray, clockInfo) +
+ pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize;
+ if (!pp_table_has_space(hwmgr, clock_info_offset,
+ pclock_arrays->ucEntrySize))
+ return -1;
+
+ pclock_info = (const void *)
+ ((unsigned long)(pclock_arrays->clockInfo) +
+ (pstate_entry_v2->clockInfoIndex[i] *
+ pclock_arrays->ucEntrySize));
res = func(hwmgr, &ps->hardware, i, pclock_info);
if ((0 == result) && (0 != res))
result = res;
}
} else {
- if (entry_index > powerplay_table->ucNumStates)
+ if (entry_index >= powerplay_table->ucNumStates ||
+ !powerplay_table->ucStateEntrySize ||
+ !powerplay_table->ucNonClockSize ||
+ powerplay_table->ucNonClockSize < ATOM_PPLIB_NONCLOCKINFO_VER1 ||
+ (powerplay_table->ucNonClockSize > ATOM_PPLIB_NONCLOCKINFO_VER1 &&
+ powerplay_table->ucNonClockSize < ATOM_PPLIB_NONCLOCKINFO_VER2) ||
+ !powerplay_table->ucClockInfoSize)
+ return -1;
+
+ state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset);
+ state_entry_offset = state_array_offset +
+ entry_index * powerplay_table->ucStateEntrySize;
+ if (!pp_table_has_space(hwmgr, state_entry_offset,
+ powerplay_table->ucStateEntrySize))
return -1;
pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table +
- le16_to_cpu(powerplay_table->usStateArrayOffset) +
+ state_array_offset +
entry_index * powerplay_table->ucStateEntrySize);
+ non_clock_info_array_offset =
+ le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset);
+ non_clock_info_offset = non_clock_info_array_offset +
+ pstate_entry->ucNonClockStateIndex * powerplay_table->ucNonClockSize;
+ if (!pp_table_has_space(hwmgr, non_clock_info_offset,
+ powerplay_table->ucNonClockSize))
+ return -1;
+
pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
- le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
+ non_clock_info_array_offset +
pstate_entry->ucNonClockStateIndex *
powerplay_table->ucNonClockSize);
@@ -946,12 +1069,23 @@ int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
pnon_clock_info);
for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
- const void *pclock_info = (const void *)((unsigned long)powerplay_table +
- le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
+ const void *pclock_info;
+
+ clock_info_array_offset =
+ le16_to_cpu(powerplay_table->usClockInfoArrayOffset);
+ clock_info_offset = clock_info_array_offset +
+ pstate_entry->ucClockStateIndices[i] *
+ powerplay_table->ucClockInfoSize;
+ if (!pp_table_has_space(hwmgr, clock_info_offset,
+ powerplay_table->ucClockInfoSize))
+ return -1;
+
+ pclock_info = (const void *)((unsigned long)powerplay_table +
+ clock_info_array_offset +
pstate_entry->ucClockStateIndices[i] *
powerplay_table->ucClockInfoSize);
- int res = func(hwmgr, &ps->hardware, i, pclock_info);
+ res = func(hwmgr, &ps->hardware, i, pclock_info);
if ((0 == result) && (0 != res))
result = res;
@@ -1661,21 +1795,70 @@ static int get_vce_state_table_entry(struct pp_hwmgr *hwmgr,
unsigned long *flag)
{
const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
+ const ATOM_PPLIB_VCE_State_Table *vce_state_table;
+ const ATOM_PPLIB_VCE_State_Record *record;
+ const VCEClockInfoArray *vce_clock_info_array;
+ const VCEClockInfo *vce_clock_info;
+ const ClockInfoArray *clock_arrays;
+ u16 vce_state_table_offset;
+ u16 vce_clock_info_array_offset;
+ u16 clock_info_array_offset;
+ unsigned long clockInfoIndex;
+ size_t record_offset;
+ size_t vce_clock_info_offset;
+ size_t clock_info_offset;
+
+ if (!powerplay_table || !pp_table_has_space(hwmgr, 0, sizeof(*powerplay_table)))
+ return -1;
- const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table);
+ vce_state_table_offset = get_vce_state_table_offset(hwmgr, powerplay_table);
+ vce_state_table = get_vce_state_table(hwmgr, powerplay_table);
+ if (!vce_state_table || i >= vce_state_table->numEntries)
+ return -1;
+
+ record_offset = vce_state_table_offset +
+ offsetof(ATOM_PPLIB_VCE_State_Table, entries) +
+ i * sizeof(*record);
+ if (!pp_table_has_space(hwmgr, record_offset, sizeof(*record)))
+ return -1;
+
+ record = &vce_state_table->entries[i];
+
+ vce_clock_info_array_offset =
+ get_vce_clock_info_array_offset(hwmgr, powerplay_table);
+ if (!pp_table_has_space(hwmgr, vce_clock_info_array_offset,
+ sizeof(vce_clock_info_array->ucNumEntries)))
+ return -1;
- unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table);
+ vce_clock_info_array = (const VCEClockInfoArray *)
+ (((unsigned long)powerplay_table) + vce_clock_info_array_offset);
+ if (record->ucVCEClockInfoIndex >= vce_clock_info_array->ucNumEntries)
+ return -1;
- const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset);
+ vce_clock_info_offset = vce_clock_info_array_offset +
+ offsetof(VCEClockInfoArray, entries) +
+ record->ucVCEClockInfoIndex * sizeof(*vce_clock_info);
+ if (!pp_table_has_space(hwmgr, vce_clock_info_offset, sizeof(*vce_clock_info)))
+ return -1;
- const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
+ vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex];
- const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i];
+ clock_info_array_offset = le16_to_cpu(powerplay_table->usClockInfoArrayOffset);
+ if (!pp_table_has_space(hwmgr, clock_info_array_offset,
+ sizeof(*clock_arrays)))
+ return -1;
- const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex];
+ clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
+ clock_info_array_offset);
+ clockInfoIndex = record->ucClockInfoIndex & 0x3F;
+ if (!clock_arrays->ucEntrySize || clockInfoIndex >= clock_arrays->ucNumEntries)
+ return -1;
- unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F;
+ clock_info_offset = clock_info_array_offset +
+ offsetof(ClockInfoArray, clockInfo) +
+ clockInfoIndex * clock_arrays->ucEntrySize;
+ if (!pp_table_has_space(hwmgr, clock_info_offset, clock_arrays->ucEntrySize))
+ return -1;
*flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX);
@@ -1699,6 +1882,10 @@ static int pp_tables_initialize(struct pp_hwmgr *hwmgr)
hwmgr->need_pp_table_upload = true;
powerplay_table = get_powerplay_table(hwmgr);
+ PP_ASSERT_WITH_CODE((powerplay_table),
+ "Missing PowerPlay Table!", return -1);
+ PP_ASSERT_WITH_CODE(pp_table_has_space(hwmgr, 0, sizeof(*powerplay_table)),
+ "Invalid PowerPlay Table!", return -1);
result = init_powerplay_tables(hwmgr, powerplay_table);
@@ -1801,4 +1988,3 @@ const struct pp_table_func pptable_funcs = {
.pptable_get_vce_state_table_entry =
get_vce_state_table_entry,
};
-
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
index 95bf187f02a5..bdf1e489369e 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
@@ -2216,12 +2216,24 @@ static int smu7_patch_voltage_dependency_tables_with_lookup_table(
if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) {
for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) {
voltage_id = sclk_table->entries[entry_id].vddInd;
+ if (voltage_id >= table_info->vddgfx_lookup_table->count) {
+ pr_err("amdgpu: sclk[%u] vddgfx index %u out of bounds (%u)\n",
+ entry_id, voltage_id,
+ table_info->vddgfx_lookup_table->count);
+ return -EINVAL;
+ }
sclk_table->entries[entry_id].vddgfx =
table_info->vddgfx_lookup_table->entries[voltage_id].us_vdd;
}
} else {
for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) {
voltage_id = sclk_table->entries[entry_id].vddInd;
+ if (voltage_id >= table_info->vddc_lookup_table->count) {
+ pr_err("amdgpu: sclk[%u] vddc index %u out of bounds (%u)\n",
+ entry_id, voltage_id,
+ table_info->vddc_lookup_table->count);
+ return -EINVAL;
+ }
sclk_table->entries[entry_id].vddc =
table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
}
@@ -2229,12 +2241,24 @@ static int smu7_patch_voltage_dependency_tables_with_lookup_table(
for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
voltage_id = mclk_table->entries[entry_id].vddInd;
+ if (voltage_id >= table_info->vddc_lookup_table->count) {
+ pr_err("amdgpu: mclk[%u] vddc index %u out of bounds (%u)\n",
+ entry_id, voltage_id,
+ table_info->vddc_lookup_table->count);
+ return -EINVAL;
+ }
mclk_table->entries[entry_id].vddc =
table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
}
for (entry_id = 0; entry_id < mm_table->count; ++entry_id) {
voltage_id = mm_table->entries[entry_id].vddcInd;
+ if (voltage_id >= table_info->vddc_lookup_table->count) {
+ pr_err("amdgpu: mm[%u] vddc index %u out of bounds (%u)\n",
+ entry_id, voltage_id,
+ table_info->vddc_lookup_table->count);
+ return -EINVAL;
+ }
mm_table->entries[entry_id].vddc =
table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
}
@@ -2964,7 +2988,7 @@ static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *
if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE))
return 0;
- table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL);
+ table = kzalloc_flex(*table, entries, 4);
if (!table)
return -ENOMEM;
@@ -4062,7 +4086,7 @@ static int smu7_get_gpu_power(struct pp_hwmgr *hwmgr, u32 *query)
(adev->asic_type != CHIP_FIJI) &&
(adev->asic_type != CHIP_TONGA)) {
smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetCurrPkgPwr, 0, &tmp);
- *query = tmp;
+ *query = PP_PWR_Q24_8_TO_MW(tmp);
if (tmp != 0)
return 0;
@@ -4081,7 +4105,7 @@ static int smu7_get_gpu_power(struct pp_hwmgr *hwmgr, u32 *query)
if (tmp != 0)
break;
}
- *query = tmp;
+ *query = PP_PWR_Q24_8_TO_MW(tmp);
return 0;
}
@@ -5648,23 +5672,29 @@ static int smu7_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
}
for (i = 0; i < size; i += 3) {
- if (i + 3 > size || input[i] >= podn_dpm_table_in_backend->num_of_pl) {
- pr_info("invalid clock voltage input \n");
- return 0;
+ if (i + 3 > size) {
+ pr_info("truncated clock/voltage input\n");
+ return -EINVAL;
}
- input_level = input[i];
- input_clk = input[i+1] * 100;
- input_vol = input[i+2];
-
- if (smu7_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) {
- podn_dpm_table_in_backend->entries[input_level].clock = input_clk;
- podn_vdd_dep_in_backend->entries[input_level].clk = input_clk;
- podn_dpm_table_in_backend->entries[input_level].vddc = input_vol;
- podn_vdd_dep_in_backend->entries[input_level].vddc = input_vol;
- podn_vdd_dep_in_backend->entries[input_level].vddgfx = input_vol;
- } else {
+ if (input[i] < 0 || input[i] >= podn_dpm_table_in_backend->num_of_pl) {
+ pr_info("invalid clock/voltage level\n");
return -EINVAL;
}
+ input_clk = input[i + 1] * 100;
+ input_vol = input[i + 2];
+ if (!smu7_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol))
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += 3) {
+ input_level = input[i];
+ input_clk = input[i + 1] * 100;
+ input_vol = input[i + 2];
+ podn_dpm_table_in_backend->entries[input_level].clock = input_clk;
+ podn_vdd_dep_in_backend->entries[input_level].clk = input_clk;
+ podn_dpm_table_in_backend->entries[input_level].vddc = input_vol;
+ podn_vdd_dep_in_backend->entries[input_level].vddc = input_vol;
+ podn_vdd_dep_in_backend->entries[input_level].vddgfx = input_vol;
}
return 0;
@@ -5857,15 +5887,19 @@ static int smu7_power_off_asic(struct pp_hwmgr *hwmgr)
static void smu7_notify_ac_dc(struct pp_hwmgr *hwmgr)
{
struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- /* Check if the platform already manages the AC/DC switch via dedicated GPIO. */
- if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+ /*
+ * Check if the platform already manages the AC/DC switch via dedicated GPIO.
+ * Otherwise SMU automatically notices DC, but needs to be notified of AC.
+ */
+ if (adev->pm.ac_power &&
+ phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_AutomaticDCTransition))
- return;
-
- /* The SMU automatically notices DC, but needs to be notified when switching to AC. */
- if (adev->pm.ac_power)
smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunningOnAC, NULL);
+
+ /* Recompute clocks with updated max_limits. */
+ pp_funcs->pm_compute_clocks(adev->powerplay.pp_handle);
}
static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
index 4b92b52aba2b..05b1e69116fd 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
@@ -685,10 +685,18 @@ static int vega10_patch_voltage_dependency_tables_with_lookup_table(
case 3: vdt = table_info->vdd_dep_on_pixclk; break;
case 4: vdt = table_info->vdd_dep_on_dispclk; break;
case 5: vdt = table_info->vdd_dep_on_phyclk; break;
+ default:
+ continue;
}
for (entry_id = 0; entry_id < vdt->count; entry_id++) {
voltage_id = vdt->entries[entry_id].vddInd;
+ if (voltage_id >= table_info->vddc_lookup_table->count) {
+ pr_err("amdgpu: clk_dep[%u][%u] vddc index %u out of bounds (%u)\n",
+ i, entry_id, voltage_id,
+ table_info->vddc_lookup_table->count);
+ return -EINVAL;
+ }
vdt->entries[entry_id].vddc =
table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
}
@@ -696,23 +704,48 @@ static int vega10_patch_voltage_dependency_tables_with_lookup_table(
for (entry_id = 0; entry_id < mm_table->count; ++entry_id) {
voltage_id = mm_table->entries[entry_id].vddcInd;
+ if (voltage_id >= table_info->vddc_lookup_table->count) {
+ pr_err("amdgpu: mm[%u] vddc index %u out of bounds (%u)\n",
+ entry_id, voltage_id,
+ table_info->vddc_lookup_table->count);
+ return -EINVAL;
+ }
mm_table->entries[entry_id].vddc =
table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
}
for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) {
voltage_id = mclk_table->entries[entry_id].vddInd;
+ if (voltage_id >= table_info->vddc_lookup_table->count) {
+ pr_err("amdgpu: mclk[%u] vddc index %u out of bounds (%u)\n",
+ entry_id, voltage_id,
+ table_info->vddc_lookup_table->count);
+ return -EINVAL;
+ }
mclk_table->entries[entry_id].vddc =
table_info->vddc_lookup_table->entries[voltage_id].us_vdd;
+
voltage_id = mclk_table->entries[entry_id].vddciInd;
+ if (voltage_id >= table_info->vddci_lookup_table->count) {
+ pr_err("amdgpu: mclk[%u] vddci index %u out of bounds (%u)\n",
+ entry_id, voltage_id,
+ table_info->vddci_lookup_table->count);
+ return -EINVAL;
+ }
mclk_table->entries[entry_id].vddci =
table_info->vddci_lookup_table->entries[voltage_id].us_vdd;
+
voltage_id = mclk_table->entries[entry_id].mvddInd;
+ if (voltage_id >= table_info->vddmem_lookup_table->count) {
+ pr_err("amdgpu: mclk[%u] vddmem index %u out of bounds (%u)\n",
+ entry_id, voltage_id,
+ table_info->vddmem_lookup_table->count);
+ return -EINVAL;
+ }
mclk_table->entries[entry_id].mvdd =
table_info->vddmem_lookup_table->entries[voltage_id].us_vdd;
}
-
return 0;
}
@@ -3934,8 +3967,8 @@ static int vega10_get_gpu_power(struct pp_hwmgr *hwmgr,
if (ret)
return ret;
- /* SMC returning actual watts, keep consistent with legacy asics, low 8 bit as 8 fractional bits */
- *query = value << 8;
+ /* SMC returns whole Watts, while power sensors use milliwatts. */
+ *query = value * MILLIWATT_PER_WATT;
return 0;
}
@@ -5215,6 +5248,11 @@ static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, ui
uint8_t min_active_level;
uint32_t power_profile_mode = input[size];
+ if (power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
+ pr_err("Invalid power profile mode %u\n", power_profile_mode);
+ return -EINVAL;
+ }
+
if (power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
if (size != 0 && size != 4)
return -EINVAL;
@@ -5230,6 +5268,10 @@ static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, ui
return -EINVAL;
}
+ if ((input[0] & ~0xFF) || (input[1] & ~0xFF) ||
+ (input[2] & ~0xFF) || (input[3] & ~0xFF))
+ return -EINVAL;
+
data->custom_profile_mode[0] = busy_set_point = input[0];
data->custom_profile_mode[1] = FPS = input[1];
data->custom_profile_mode[2] = use_rlc_busy = input[2];
@@ -5454,11 +5496,9 @@ static int vega10_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
if (PP_OD_EDIT_SCLK_VDDC_TABLE == type) {
dpm_table = &data->dpm_table.gfx_table;
podn_vdd_dep_table = &data->odn_dpm_table.vdd_dep_on_sclk;
- data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
} else if (PP_OD_EDIT_MCLK_VDDC_TABLE == type) {
dpm_table = &data->dpm_table.mem_table;
podn_vdd_dep_table = &data->odn_dpm_table.vdd_dep_on_mclk;
- data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
} else if (PP_OD_RESTORE_DEFAULT_TABLE == type) {
memcpy(&(data->dpm_table), &(data->golden_dpm_table), sizeof(struct vega10_dpm_table));
vega10_odn_initial_default_setting(hwmgr);
@@ -5476,21 +5516,32 @@ static int vega10_odn_edit_dpm_table(struct pp_hwmgr *hwmgr,
}
for (i = 0; i < size; i += 3) {
- if (i + 3 > size || input[i] >= podn_vdd_dep_table->count) {
- pr_info("invalid clock voltage input\n");
- return 0;
+ if (i + 3 > size) {
+ pr_info("truncated clock/voltage input\n");
+ return -EINVAL;
}
- input_level = input[i];
- input_clk = input[i+1] * 100;
- input_vol = input[i+2];
-
- if (vega10_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) {
- dpm_table->dpm_levels[input_level].value = input_clk;
- podn_vdd_dep_table->entries[input_level].clk = input_clk;
- podn_vdd_dep_table->entries[input_level].vddc = input_vol;
- } else {
+ if (input[i] < 0 || input[i] >= podn_vdd_dep_table->count) {
+ pr_info("invalid clock/voltage level\n");
return -EINVAL;
}
+ input_clk = input[i + 1] * 100;
+ input_vol = input[i + 2];
+ if (!vega10_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol))
+ return -EINVAL;
+ }
+
+ if (type == PP_OD_EDIT_SCLK_VDDC_TABLE)
+ data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
+ else
+ data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
+
+ for (i = 0; i < size; i += 3) {
+ input_level = input[i];
+ input_clk = input[i + 1] * 100;
+ input_vol = input[i + 2];
+ dpm_table->dpm_levels[input_level].value = input_clk;
+ podn_vdd_dep_table->entries[input_level].clk = input_clk;
+ podn_vdd_dep_table->entries[input_level].vddc = input_vol;
}
vega10_odn_update_soc_table(hwmgr, type);
return 0;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
index 052d139584fd..62b1e068f90d 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
@@ -63,14 +63,57 @@ static const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
return table_address;
}
-static int check_powerplay_tables(
- struct pp_hwmgr *hwmgr,
- const ATOM_Vega10_POWERPLAYTABLE *powerplay_table)
+static bool vega10_pp_table_has_space(struct pp_hwmgr *hwmgr, size_t offset,
+ size_t size)
+{
+ size_t table_size = hwmgr->soft_pp_table_size;
+
+ return offset <= table_size && size <= table_size - offset;
+}
+
+static int get_vega10_subtable(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ u16 table_offset, size_t table_size, const void **table)
+{
+ PP_ASSERT_WITH_CODE((table_offset != 0),
+ "Invalid PowerPlay Table!", return -1);
+ PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *table = (const void *)(((unsigned long)powerplay_table) + table_offset);
+
+ return 0;
+}
+
+static int validate_vega10_table_entries(struct pp_hwmgr *hwmgr,
+ u16 table_offset, size_t entries_offset,
+ u8 num_entries, size_t entry_size)
+{
+ size_t table_size;
+
+ PP_ASSERT_WITH_CODE((num_entries != 0),
+ "Invalid PowerPlay Table!", return -1);
+
+ table_size = entries_offset + num_entries * entry_size;
+ PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ return 0;
+}
+
+static int get_vega10_state_array(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Vega10_State_Array **state_array)
{
const ATOM_Vega10_State_Array *state_arrays;
+ u16 state_array_offset;
+ size_t state_array_size;
+ size_t table_size = hwmgr->soft_pp_table_size;
- state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usStateArrayOffset));
+ PP_ASSERT_WITH_CODE((table_size >= sizeof(*powerplay_table)),
+ "Invalid PowerPlay Table!", return -1);
PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >=
ATOM_Vega10_TABLE_REVISION_VEGA10),
@@ -79,12 +122,321 @@ static int check_powerplay_tables(
"State table is not set!", return -1);
PP_ASSERT_WITH_CODE(powerplay_table->sHeader.structuresize > 0,
"Invalid PowerPlay Table!", return -1);
+
+ state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset);
+ PP_ASSERT_WITH_CODE((state_array_offset <=
+ table_size - sizeof(*state_arrays)),
+ "Invalid PowerPlay Table!", return -1);
+
+ state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)powerplay_table) +
+ state_array_offset);
PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0,
"Invalid PowerPlay Table!", return -1);
+ state_array_size = struct_size(state_arrays, states, state_arrays->ucNumEntries);
+ PP_ASSERT_WITH_CODE((state_array_size <= table_size - state_array_offset),
+ "Invalid PowerPlay Table!", return -1);
+
+ *state_array = state_arrays;
+
return 0;
}
+static int get_vega10_gfxclk_dependency_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Vega10_GFXCLK_Dependency_Table **gfxclk_dep_table)
+{
+ const ATOM_Vega10_GFXCLK_Dependency_Table *table;
+ u16 table_offset;
+ size_t table_size;
+ size_t entry_size;
+
+ table_offset = le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset);
+ if (!table_offset)
+ return -EINVAL;
+
+ PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset,
+ sizeof(*table))),
+ "Invalid PowerPlay Table!", return -1);
+
+ table = (const ATOM_Vega10_GFXCLK_Dependency_Table *)
+ (((unsigned long)powerplay_table) + table_offset);
+ PP_ASSERT_WITH_CODE((table->ucNumEntries != 0),
+ "Invalid PowerPlay Table!", return -1);
+
+ if (table->ucRevId == 0)
+ entry_size = sizeof(ATOM_Vega10_GFXCLK_Dependency_Record);
+ else if (table->ucRevId == 1)
+ entry_size = sizeof(ATOM_Vega10_GFXCLK_Dependency_Record_V2);
+ else
+ PP_ASSERT_WITH_CODE(false,
+ "Unsupported GFXClockDependencyTable Revision!",
+ return -EINVAL);
+
+ table_size = offsetof(ATOM_Vega10_GFXCLK_Dependency_Table, entries) +
+ table->ucNumEntries * entry_size;
+ PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *gfxclk_dep_table = table;
+
+ return 0;
+}
+
+static int get_vega10_clk_dependency_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ u16 table_offset,
+ const ATOM_Vega10_SOCCLK_Dependency_Table **clk_dep_table)
+{
+ const ATOM_Vega10_SOCCLK_Dependency_Table *table;
+ int ret;
+
+ ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ ret = validate_vega10_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Vega10_SOCCLK_Dependency_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Vega10_CLK_Dependency_Record));
+ if (ret)
+ return ret;
+
+ *clk_dep_table = table;
+
+ return 0;
+}
+
+static int get_vega10_mclk_dependency_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Vega10_MCLK_Dependency_Table **mclk_dep_table)
+{
+ const ATOM_Vega10_MCLK_Dependency_Table *table;
+ u16 table_offset;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usMclkDependencyTableOffset);
+ ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ ret = validate_vega10_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Vega10_MCLK_Dependency_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Vega10_MCLK_Dependency_Record));
+ if (ret)
+ return ret;
+
+ *mclk_dep_table = table;
+
+ return 0;
+}
+
+static int get_vega10_mm_dependency_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Vega10_MM_Dependency_Table **mm_dep_table)
+{
+ const ATOM_Vega10_MM_Dependency_Table *table;
+ u16 table_offset;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usMMDependencyTableOffset);
+ ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ ret = validate_vega10_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Vega10_MM_Dependency_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Vega10_MM_Dependency_Record));
+ if (ret)
+ return ret;
+
+ *mm_dep_table = table;
+
+ return 0;
+}
+
+static int get_vega10_pcie_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const Vega10_PPTable_Generic_SubTable_Header **pcie_table)
+{
+ const ATOM_Vega10_PCIE_Table *table;
+ u16 table_offset;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usPCIETableOffset);
+ ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ if (!table->ucNumEntries) {
+ *pcie_table = (const Vega10_PPTable_Generic_SubTable_Header *)table;
+ return 0;
+ }
+
+ ret = validate_vega10_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Vega10_PCIE_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Vega10_PCIE_Record));
+ if (ret)
+ return ret;
+
+ *pcie_table = (const Vega10_PPTable_Generic_SubTable_Header *)table;
+
+ return 0;
+}
+
+static int get_vega10_hard_limit_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Vega10_Hard_Limit_Table **hard_limit_table)
+{
+ const ATOM_Vega10_Hard_Limit_Table *table;
+ u16 table_offset;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usHardLimitTableOffset);
+ ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ ret = validate_vega10_table_entries(hwmgr, table_offset,
+ offsetof(ATOM_Vega10_Hard_Limit_Table,
+ entries),
+ table->ucNumEntries,
+ sizeof(ATOM_Vega10_Hard_Limit_Record));
+ if (ret)
+ return ret;
+
+ *hard_limit_table = table;
+
+ return 0;
+}
+
+static int get_vega10_thermal_controller_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const ATOM_Vega10_Thermal_Controller **thermal_controller)
+{
+ u16 table_offset;
+
+ table_offset = le16_to_cpu(powerplay_table->usThermalControllerOffset);
+
+ return get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(**thermal_controller),
+ (const void **)thermal_controller);
+}
+
+static int get_vega10_fan_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const Vega10_PPTable_Generic_SubTable_Header **fan_table)
+{
+ const Vega10_PPTable_Generic_SubTable_Header *header;
+ u16 table_offset;
+ size_t table_size;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usFanTableOffset);
+ ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*header), (const void **)&header);
+ if (ret)
+ return ret;
+
+ if (header->ucRevId == 10)
+ table_size = sizeof(ATOM_Vega10_Fan_Table);
+ else if (header->ucRevId == 0xb)
+ table_size = sizeof(ATOM_Vega10_Fan_Table_V2);
+ else if (header->ucRevId > 0xb)
+ table_size = sizeof(ATOM_Vega10_Fan_Table_V3);
+ else
+ table_size = sizeof(*header);
+
+ PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *fan_table = header;
+
+ return 0;
+}
+
+static int get_vega10_power_tune_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ const Vega10_PPTable_Generic_SubTable_Header **power_tune_table)
+{
+ const Vega10_PPTable_Generic_SubTable_Header *header;
+ u16 table_offset;
+ size_t table_size;
+ int ret;
+
+ table_offset = le16_to_cpu(powerplay_table->usPowerTuneTableOffset);
+ ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*header), (const void **)&header);
+ if (ret)
+ return ret;
+
+ if (header->ucRevId == 5)
+ table_size = sizeof(ATOM_Vega10_PowerTune_Table);
+ else if (header->ucRevId == 6)
+ table_size = sizeof(ATOM_Vega10_PowerTune_Table_V2);
+ else
+ table_size = sizeof(ATOM_Vega10_PowerTune_Table_V3);
+
+ PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *power_tune_table = header;
+
+ return 0;
+}
+
+static int get_vega10_voltage_lookup_table(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
+ u16 table_offset, uint32_t max_levels,
+ const ATOM_Vega10_Voltage_Lookup_Table **lookup_table)
+{
+ const ATOM_Vega10_Voltage_Lookup_Table *table;
+ size_t table_size;
+ int ret;
+
+ ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset,
+ sizeof(*table), (const void **)&table);
+ if (ret)
+ return ret;
+
+ PP_ASSERT_WITH_CODE((table->ucNumEntries != 0 &&
+ table->ucNumEntries <= max_levels),
+ "Invalid PowerPlay Table!", return -1);
+
+ table_size = offsetof(ATOM_Vega10_Voltage_Lookup_Table, entries) +
+ table->ucNumEntries * sizeof(ATOM_Vega10_Voltage_Lookup_Record);
+ PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset,
+ table_size)),
+ "Invalid PowerPlay Table!", return -1);
+
+ *lookup_table = table;
+
+ return 0;
+}
+
+static int check_powerplay_tables(struct pp_hwmgr *hwmgr,
+ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table)
+{
+ const ATOM_Vega10_State_Array *state_arrays;
+
+ return get_vega10_state_array(hwmgr, powerplay_table, &state_arrays);
+}
+
static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
{
set_hw_cap(
@@ -124,14 +476,16 @@ static int init_thermal_controller(
const ATOM_Vega10_Fan_Table *fan_table_v1;
const ATOM_Vega10_Fan_Table_V2 *fan_table_v2;
const ATOM_Vega10_Fan_Table_V3 *fan_table_v3;
-
- thermal_controller = (ATOM_Vega10_Thermal_Controller *)
- (((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usThermalControllerOffset));
+ int ret;
PP_ASSERT_WITH_CODE((powerplay_table->usThermalControllerOffset != 0),
"Thermal controller table not set!", return -EINVAL);
+ ret = get_vega10_thermal_controller_table(hwmgr, powerplay_table,
+ &thermal_controller);
+ if (ret)
+ return ret;
+
hwmgr->thermal_controller.ucType = thermal_controller->ucType;
hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
@@ -160,9 +514,9 @@ static int init_thermal_controller(
if (!powerplay_table->usFanTableOffset)
return 0;
- header = (const Vega10_PPTable_Generic_SubTable_Header *)
- (((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usFanTableOffset));
+ ret = get_vega10_fan_table(hwmgr, powerplay_table, &header);
+ if (ret)
+ return ret;
if (header->ucRevId == 10) {
fan_table_v1 = (ATOM_Vega10_Fan_Table *)header;
@@ -307,12 +661,15 @@ static int init_over_drive_limits(
struct pp_hwmgr *hwmgr,
const ATOM_Vega10_POWERPLAYTABLE *powerplay_table)
{
- const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table =
- (const ATOM_Vega10_GFXCLK_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset));
+ const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table;
bool is_acg_enabled = false;
ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_v2;
+ int ret;
+
+ ret = get_vega10_gfxclk_dependency_table(hwmgr, powerplay_table,
+ &gfxclk_dep_table);
+ if (ret)
+ return ret;
if (gfxclk_dep_table->ucRevId == 1) {
patom_record_v2 =
@@ -344,20 +701,28 @@ static int get_mm_clock_voltage_table(
const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table)
{
uint32_t i;
+ uint32_t num_entries;
const ATOM_Vega10_MM_Dependency_Record *mm_dependency_record;
phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
PP_ASSERT_WITH_CODE((mm_dependency_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
- mm_table = kzalloc_flex(*mm_table, entries,
- mm_dependency_table->ucNumEntries);
+ num_entries = min_t(uint32_t, mm_dependency_table->ucNumEntries,
+ pp_entries_max(hwmgr, mm_dependency_table,
+ sizeof(*mm_dependency_table),
+ sizeof(ATOM_Vega10_MM_Dependency_Record)));
+ if (num_entries < mm_dependency_table->ucNumEntries)
+ pr_warn("amdgpu: Vega10 MM dependency table: clamping ucNumEntries %u -> %u\n",
+ mm_dependency_table->ucNumEntries, num_entries);
+
+ mm_table = kzalloc_flex(*mm_table, entries, num_entries);
if (!mm_table)
return -ENOMEM;
- mm_table->count = mm_dependency_table->ucNumEntries;
+ mm_table->count = num_entries;
- for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
mm_dependency_record = &mm_dependency_table->entries[i];
mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd;
mm_table->entries[i].samclock =
@@ -568,19 +933,27 @@ static int get_socclk_voltage_dependency_table(
const ATOM_Vega10_SOCCLK_Dependency_Table *clk_dep_table)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_clock_voltage_dependency_table *clk_table;
PP_ASSERT_WITH_CODE(clk_dep_table->ucNumEntries,
"Invalid PowerPlay Table!", return -1);
- clk_table = kzalloc_flex(*clk_table, entries,
- clk_dep_table->ucNumEntries);
+ num_entries = min_t(uint32_t, clk_dep_table->ucNumEntries,
+ pp_entries_max(hwmgr, clk_dep_table,
+ sizeof(*clk_dep_table),
+ sizeof(ATOM_Vega10_CLK_Dependency_Record)));
+ if (num_entries < clk_dep_table->ucNumEntries)
+ pr_warn("amdgpu: Vega10 SOCCLK dependency table: clamping ucNumEntries %u -> %u\n",
+ clk_dep_table->ucNumEntries, num_entries);
+
+ clk_table = kzalloc_flex(*clk_table, entries, num_entries);
if (!clk_table)
return -ENOMEM;
- clk_table->count = (uint32_t)clk_dep_table->ucNumEntries;
+ clk_table->count = num_entries;
- for (i = 0; i < clk_dep_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
clk_table->entries[i].vddInd =
clk_dep_table->entries[i].ucVddInd;
clk_table->entries[i].clk =
@@ -598,19 +971,27 @@ static int get_mclk_voltage_dependency_table(
const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_clock_voltage_dependency_table *mclk_table;
PP_ASSERT_WITH_CODE(mclk_dep_table->ucNumEntries,
"Invalid PowerPlay Table!", return -1);
- mclk_table = kzalloc_flex(*mclk_table, entries,
- mclk_dep_table->ucNumEntries);
+ num_entries = min_t(uint32_t, mclk_dep_table->ucNumEntries,
+ pp_entries_max(hwmgr, mclk_dep_table,
+ sizeof(*mclk_dep_table),
+ sizeof(ATOM_Vega10_MCLK_Dependency_Record)));
+ if (num_entries < mclk_dep_table->ucNumEntries)
+ pr_warn("amdgpu: Vega10 MCLK dependency table: clamping ucNumEntries %u -> %u\n",
+ mclk_dep_table->ucNumEntries, num_entries);
+
+ mclk_table = kzalloc_flex(*mclk_table, entries, num_entries);
if (!mclk_table)
return -ENOMEM;
- mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
+ mclk_table->count = num_entries;
- for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
mclk_table->entries[i].vddInd =
mclk_dep_table->entries[i].ucVddInd;
mclk_table->entries[i].vddciInd =
@@ -633,6 +1014,7 @@ static int get_gfxclk_voltage_dependency_table(
const ATOM_Vega10_GFXCLK_Dependency_Table *clk_dep_table)
{
uint32_t i;
+ uint32_t num_entries;
struct phm_ppt_v1_clock_voltage_dependency_table
*clk_table;
ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_v2;
@@ -640,15 +1022,34 @@ static int get_gfxclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
- clk_table = kzalloc_flex(*clk_table, entries,
- clk_dep_table->ucNumEntries);
+ if (clk_dep_table->ucRevId == 0) {
+ num_entries = min_t(uint32_t, clk_dep_table->ucNumEntries,
+ pp_entries_max(hwmgr, clk_dep_table,
+ sizeof(*clk_dep_table),
+ sizeof(ATOM_Vega10_GFXCLK_Dependency_Record)));
+ } else if (clk_dep_table->ucRevId == 1) {
+ num_entries = min_t(uint32_t, clk_dep_table->ucNumEntries,
+ pp_entries_max(hwmgr, clk_dep_table,
+ sizeof(*clk_dep_table),
+ sizeof(ATOM_Vega10_GFXCLK_Dependency_Record_V2)));
+ } else {
+ PP_ASSERT_WITH_CODE(false,
+ "Unsupported GFXClockDependencyTable Revision!",
+ return -EINVAL);
+ }
+
+ if (num_entries < clk_dep_table->ucNumEntries)
+ pr_warn("amdgpu: Vega10 GFXCLK dependency table: clamping ucNumEntries %u -> %u\n",
+ clk_dep_table->ucNumEntries, num_entries);
+
+ clk_table = kzalloc_flex(*clk_table, entries, num_entries);
if (!clk_table)
return -ENOMEM;
- clk_table->count = clk_dep_table->ucNumEntries;
+ clk_table->count = num_entries;
if (clk_dep_table->ucRevId == 0) {
- for (i = 0; i < clk_table->count; i++) {
+ for (i = 0; i < num_entries; i++) {
clk_table->entries[i].vddInd =
clk_dep_table->entries[i].ucVddInd;
clk_table->entries[i].clk =
@@ -661,9 +1062,9 @@ static int get_gfxclk_voltage_dependency_table(
clk_table->entries[i].sclk_offset =
le16_to_cpu(clk_dep_table->entries[i].usAVFSOffset);
}
- } else if (clk_dep_table->ucRevId == 1) {
+ } else {
patom_record_v2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)clk_dep_table->entries;
- for (i = 0; i < clk_table->count; i++) {
+ for (i = 0; i < num_entries; i++) {
clk_table->entries[i].vddInd =
patom_record_v2->ucVddInd;
clk_table->entries[i].clk =
@@ -677,11 +1078,6 @@ static int get_gfxclk_voltage_dependency_table(
le16_to_cpu(patom_record_v2->usAVFSOffset);
patom_record_v2++;
}
- } else {
- kfree(clk_table);
- PP_ASSERT_WITH_CODE(false,
- "Unsupported GFXClockDependencyTable Revision!",
- return -EINVAL);
}
*pp_vega10_clk_dep_table = clk_table;
@@ -696,20 +1092,28 @@ static int get_pix_clk_voltage_dependency_table(
const ATOM_Vega10_PIXCLK_Dependency_Table *clk_dep_table)
{
uint32_t i;
+ uint32_t num_entries;
struct phm_ppt_v1_clock_voltage_dependency_table
*clk_table;
PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
- clk_table = kzalloc_flex(*clk_table, entries,
- clk_dep_table->ucNumEntries);
+ num_entries = min_t(uint32_t, clk_dep_table->ucNumEntries,
+ pp_entries_max(hwmgr, clk_dep_table,
+ sizeof(*clk_dep_table),
+ sizeof(ATOM_Vega10_CLK_Dependency_Record)));
+ if (num_entries < clk_dep_table->ucNumEntries)
+ pr_warn("amdgpu: Vega10 PIXCLK dependency table: clamping ucNumEntries %u -> %u\n",
+ clk_dep_table->ucNumEntries, num_entries);
+
+ clk_table = kzalloc_flex(*clk_table, entries, num_entries);
if (!clk_table)
return -ENOMEM;
- clk_table->count = clk_dep_table->ucNumEntries;
+ clk_table->count = num_entries;
- for (i = 0; i < clk_table->count; i++) {
+ for (i = 0; i < num_entries; i++) {
clk_table->entries[i].vddInd =
clk_dep_table->entries[i].ucVddInd;
clk_table->entries[i].clk =
@@ -728,6 +1132,7 @@ static int get_dcefclk_voltage_dependency_table(
const ATOM_Vega10_DCEFCLK_Dependency_Table *clk_dep_table)
{
uint32_t i;
+ uint32_t safe_entries;
uint8_t num_entries;
struct phm_ppt_v1_clock_voltage_dependency_table
*clk_table;
@@ -738,6 +1143,14 @@ static int get_dcefclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -1);
+ safe_entries = min_t(uint32_t, clk_dep_table->ucNumEntries,
+ pp_entries_max(hwmgr, clk_dep_table,
+ sizeof(*clk_dep_table),
+ sizeof(ATOM_Vega10_CLK_Dependency_Record)));
+ if (safe_entries < clk_dep_table->ucNumEntries)
+ pr_warn("amdgpu: Vega10 DCEFCLK dependency table: clamping ucNumEntries %u -> %u\n",
+ clk_dep_table->ucNumEntries, safe_entries);
+
/*
* workaround needed to add another DPM level for pioneer cards
* as VBIOS is locked down.
@@ -747,12 +1160,12 @@ static int get_dcefclk_voltage_dependency_table(
dev_id = adev->pdev->device;
rev_id = adev->pdev->revision;
- if (dev_id == 0x6863 && rev_id == 0 &&
- clk_dep_table->entries[clk_dep_table->ucNumEntries - 1].ulClk < 90000)
- num_entries = clk_dep_table->ucNumEntries + 1 > NUM_DSPCLK_LEVELS ?
- NUM_DSPCLK_LEVELS : clk_dep_table->ucNumEntries + 1;
+ if (dev_id == 0x6863 && rev_id == 0 && safe_entries > 0 &&
+ clk_dep_table->entries[safe_entries - 1].ulClk < 90000)
+ num_entries = safe_entries + 1 > NUM_DSPCLK_LEVELS ?
+ NUM_DSPCLK_LEVELS : safe_entries + 1;
else
- num_entries = clk_dep_table->ucNumEntries;
+ num_entries = safe_entries;
clk_table = kzalloc_flex(*clk_table, entries, num_entries);
@@ -761,7 +1174,7 @@ static int get_dcefclk_voltage_dependency_table(
clk_table->count = (uint32_t)num_entries;
- for (i = 0; i < clk_dep_table->ucNumEntries; i++) {
+ for (i = 0; i < safe_entries; i++) {
clk_table->entries[i].vddInd =
clk_dep_table->entries[i].ucVddInd;
clk_table->entries[i].clk =
@@ -873,51 +1286,13 @@ static int init_powerplay_extended_tables(
int result = 0;
struct phm_ppt_v2_information *pp_table_info =
(struct phm_ppt_v2_information *)(hwmgr->pptable);
-
- const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table =
- (const ATOM_Vega10_MM_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
- const Vega10_PPTable_Generic_SubTable_Header *power_tune_table =
- (const Vega10_PPTable_Generic_SubTable_Header *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
- const ATOM_Vega10_SOCCLK_Dependency_Table *socclk_dep_table =
- (const ATOM_Vega10_SOCCLK_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset));
- const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table =
- (const ATOM_Vega10_GFXCLK_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset));
- const ATOM_Vega10_DCEFCLK_Dependency_Table *dcefclk_dep_table =
- (const ATOM_Vega10_DCEFCLK_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usDcefclkDependencyTableOffset));
- const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table =
- (const ATOM_Vega10_MCLK_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
- const ATOM_Vega10_Hard_Limit_Table *hard_limits =
- (const ATOM_Vega10_Hard_Limit_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usHardLimitTableOffset));
- const Vega10_PPTable_Generic_SubTable_Header *pcie_table =
- (const Vega10_PPTable_Generic_SubTable_Header *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usPCIETableOffset));
- const ATOM_Vega10_PIXCLK_Dependency_Table *pixclk_dep_table =
- (const ATOM_Vega10_PIXCLK_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usPixclkDependencyTableOffset));
- const ATOM_Vega10_PHYCLK_Dependency_Table *phyclk_dep_table =
- (const ATOM_Vega10_PHYCLK_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usPhyClkDependencyTableOffset));
- const ATOM_Vega10_DISPCLK_Dependency_Table *dispclk_dep_table =
- (const ATOM_Vega10_DISPCLK_Dependency_Table *)
- (((unsigned long) powerplay_table) +
- le16_to_cpu(powerplay_table->usDispClkDependencyTableOffset));
+ const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table;
+ const Vega10_PPTable_Generic_SubTable_Header *power_tune_table;
+ const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table;
+ const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table;
+ const ATOM_Vega10_Hard_Limit_Table *hard_limits;
+ const Vega10_PPTable_Generic_SubTable_Header *pcie_table;
+ const ATOM_Vega10_SOCCLK_Dependency_Table *clk_dep_table;
pp_table_info->vdd_dep_on_socclk = NULL;
pp_table_info->vdd_dep_on_sclk = NULL;
@@ -929,63 +1304,114 @@ static int init_powerplay_extended_tables(
pp_table_info->vdd_dep_on_phyclk = NULL;
pp_table_info->vdd_dep_on_dispclk = NULL;
- if (powerplay_table->usMMDependencyTableOffset)
- result = get_mm_clock_voltage_table(hwmgr,
+ if (powerplay_table->usMMDependencyTableOffset) {
+ result = get_vega10_mm_dependency_table(hwmgr, powerplay_table,
+ &mm_dependency_table);
+ if (!result)
+ result = get_mm_clock_voltage_table(hwmgr,
&pp_table_info->mm_dep_table,
mm_dependency_table);
+ }
- if (!result && powerplay_table->usPowerTuneTableOffset)
- result = get_tdp_table(hwmgr,
+ if (!result && powerplay_table->usPowerTuneTableOffset) {
+ result = get_vega10_power_tune_table(hwmgr, powerplay_table,
+ &power_tune_table);
+ if (!result)
+ result = get_tdp_table(hwmgr,
&pp_table_info->tdp_table,
power_tune_table);
+ }
- if (!result && powerplay_table->usSocclkDependencyTableOffset)
- result = get_socclk_voltage_dependency_table(hwmgr,
+ if (!result && powerplay_table->usSocclkDependencyTableOffset) {
+ result = get_vega10_clk_dependency_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset),
+ &clk_dep_table);
+ if (!result)
+ result = get_socclk_voltage_dependency_table(hwmgr,
&pp_table_info->vdd_dep_on_socclk,
- socclk_dep_table);
+ (const ATOM_Vega10_SOCCLK_Dependency_Table *)
+ clk_dep_table);
+ }
- if (!result && powerplay_table->usGfxclkDependencyTableOffset)
- result = get_gfxclk_voltage_dependency_table(hwmgr,
- &pp_table_info->vdd_dep_on_sclk,
- gfxclk_dep_table);
+ if (!result && powerplay_table->usGfxclkDependencyTableOffset) {
+ result = get_vega10_gfxclk_dependency_table(hwmgr,
+ powerplay_table, &gfxclk_dep_table);
+ if (!result)
+ result = get_gfxclk_voltage_dependency_table(hwmgr,
+ &pp_table_info->vdd_dep_on_sclk,
+ gfxclk_dep_table);
+ }
- if (!result && powerplay_table->usPixclkDependencyTableOffset)
- result = get_pix_clk_voltage_dependency_table(hwmgr,
+ if (!result && powerplay_table->usPixclkDependencyTableOffset) {
+ result = get_vega10_clk_dependency_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usPixclkDependencyTableOffset),
+ &clk_dep_table);
+ if (!result)
+ result = get_pix_clk_voltage_dependency_table(hwmgr,
&pp_table_info->vdd_dep_on_pixclk,
(const ATOM_Vega10_PIXCLK_Dependency_Table *)
- pixclk_dep_table);
+ clk_dep_table);
+ }
- if (!result && powerplay_table->usPhyClkDependencyTableOffset)
- result = get_pix_clk_voltage_dependency_table(hwmgr,
+ if (!result && powerplay_table->usPhyClkDependencyTableOffset) {
+ result = get_vega10_clk_dependency_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usPhyClkDependencyTableOffset),
+ &clk_dep_table);
+ if (!result)
+ result = get_pix_clk_voltage_dependency_table(hwmgr,
&pp_table_info->vdd_dep_on_phyclk,
(const ATOM_Vega10_PIXCLK_Dependency_Table *)
- phyclk_dep_table);
+ clk_dep_table);
+ }
- if (!result && powerplay_table->usDispClkDependencyTableOffset)
- result = get_pix_clk_voltage_dependency_table(hwmgr,
+ if (!result && powerplay_table->usDispClkDependencyTableOffset) {
+ result = get_vega10_clk_dependency_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usDispClkDependencyTableOffset),
+ &clk_dep_table);
+ if (!result)
+ result = get_pix_clk_voltage_dependency_table(hwmgr,
&pp_table_info->vdd_dep_on_dispclk,
(const ATOM_Vega10_PIXCLK_Dependency_Table *)
- dispclk_dep_table);
+ clk_dep_table);
+ }
- if (!result && powerplay_table->usDcefclkDependencyTableOffset)
- result = get_dcefclk_voltage_dependency_table(hwmgr,
+ if (!result && powerplay_table->usDcefclkDependencyTableOffset) {
+ result = get_vega10_clk_dependency_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usDcefclkDependencyTableOffset),
+ &clk_dep_table);
+ if (!result)
+ result = get_dcefclk_voltage_dependency_table(hwmgr,
&pp_table_info->vdd_dep_on_dcefclk,
- dcefclk_dep_table);
+ (const ATOM_Vega10_DCEFCLK_Dependency_Table *)
+ clk_dep_table);
+ }
- if (!result && powerplay_table->usMclkDependencyTableOffset)
- result = get_mclk_voltage_dependency_table(hwmgr,
+ if (!result && powerplay_table->usMclkDependencyTableOffset) {
+ result = get_vega10_mclk_dependency_table(hwmgr, powerplay_table,
+ &mclk_dep_table);
+ if (!result)
+ result = get_mclk_voltage_dependency_table(hwmgr,
&pp_table_info->vdd_dep_on_mclk,
mclk_dep_table);
+ }
- if (!result && powerplay_table->usPCIETableOffset)
- result = get_pcie_table(hwmgr,
+ if (!result && powerplay_table->usPCIETableOffset) {
+ result = get_vega10_pcie_table(hwmgr, powerplay_table,
+ &pcie_table);
+ if (!result)
+ result = get_pcie_table(hwmgr,
&pp_table_info->pcie_table,
pcie_table);
+ }
- if (!result && powerplay_table->usHardLimitTableOffset)
- result = get_hard_limits(hwmgr,
+ if (!result && powerplay_table->usHardLimitTableOffset) {
+ result = get_vega10_hard_limit_table(hwmgr, powerplay_table,
+ &hard_limits);
+ if (!result)
+ result = get_hard_limits(hwmgr,
&pp_table_info->max_clock_voltage_on_dc,
hard_limits);
+ }
hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
pp_table_info->max_clock_voltage_on_dc.sclk;
@@ -1034,18 +1460,28 @@ static int get_vddc_lookup_table(
uint32_t max_levels)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_voltage_lookup_table *table;
PP_ASSERT_WITH_CODE((vddc_lookup_pp_tables->ucNumEntries != 0),
"Invalid SOC_VDDD Lookup Table!", return 1);
- table = kzalloc_flex(*table, entries, max_levels);
+ num_entries = min_t(uint32_t, vddc_lookup_pp_tables->ucNumEntries,
+ min_t(uint32_t, max_levels,
+ pp_entries_max(hwmgr, vddc_lookup_pp_tables,
+ sizeof(*vddc_lookup_pp_tables),
+ sizeof(ATOM_Vega10_Voltage_Lookup_Record))));
+ if (num_entries < vddc_lookup_pp_tables->ucNumEntries)
+ pr_warn("amdgpu: Vega10 VddcLookup table: clamping ucNumEntries %u -> %u\n",
+ vddc_lookup_pp_tables->ucNumEntries, num_entries);
+
+ table = kzalloc_flex(*table, entries, num_entries);
if (!table)
return -ENOMEM;
- table->count = vddc_lookup_pp_tables->ucNumEntries;
+ table->count = num_entries;
- for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++)
+ for (i = 0; i < num_entries; i++)
table->entries[i].us_vdd =
le16_to_cpu(vddc_lookup_pp_tables->entries[i].usVdd);
@@ -1113,30 +1549,39 @@ static int init_dpm_2_parameters(
}
if (powerplay_table->usVddcLookupTableOffset) {
- const ATOM_Vega10_Voltage_Lookup_Table *vddc_table =
- (ATOM_Vega10_Voltage_Lookup_Table *)
- (((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
- result = get_vddc_lookup_table(hwmgr,
- &pp_table_info->vddc_lookup_table, vddc_table, 8);
+ const ATOM_Vega10_Voltage_Lookup_Table *vddc_table;
+
+ result = get_vega10_voltage_lookup_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usVddcLookupTableOffset),
+ 8, &vddc_table);
+ if (!result)
+ result = get_vddc_lookup_table(hwmgr,
+ &pp_table_info->vddc_lookup_table,
+ vddc_table, 8);
}
- if (powerplay_table->usVddmemLookupTableOffset) {
- const ATOM_Vega10_Voltage_Lookup_Table *vdd_mem_table =
- (ATOM_Vega10_Voltage_Lookup_Table *)
- (((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usVddmemLookupTableOffset));
- result = get_vddc_lookup_table(hwmgr,
- &pp_table_info->vddmem_lookup_table, vdd_mem_table, 4);
+ if (!result && powerplay_table->usVddmemLookupTableOffset) {
+ const ATOM_Vega10_Voltage_Lookup_Table *vdd_mem_table;
+
+ result = get_vega10_voltage_lookup_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usVddmemLookupTableOffset),
+ 4, &vdd_mem_table);
+ if (!result)
+ result = get_vddc_lookup_table(hwmgr,
+ &pp_table_info->vddmem_lookup_table,
+ vdd_mem_table, 4);
}
- if (powerplay_table->usVddciLookupTableOffset) {
- const ATOM_Vega10_Voltage_Lookup_Table *vddci_table =
- (ATOM_Vega10_Voltage_Lookup_Table *)
- (((unsigned long)powerplay_table) +
- le16_to_cpu(powerplay_table->usVddciLookupTableOffset));
- result = get_vddc_lookup_table(hwmgr,
- &pp_table_info->vddci_lookup_table, vddci_table, 4);
+ if (!result && powerplay_table->usVddciLookupTableOffset) {
+ const ATOM_Vega10_Voltage_Lookup_Table *vddci_table;
+
+ result = get_vega10_voltage_lookup_table(hwmgr, powerplay_table,
+ le16_to_cpu(powerplay_table->usVddciLookupTableOffset),
+ 4, &vddci_table);
+ if (!result)
+ result = get_vddc_lookup_table(hwmgr,
+ &pp_table_info->vddci_lookup_table,
+ vddci_table, 4);
}
return result;
@@ -1247,15 +1692,14 @@ int vega10_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr)
{
const ATOM_Vega10_State_Array *state_arrays;
const ATOM_Vega10_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
+ int result;
PP_ASSERT_WITH_CODE((pp_table != NULL),
"Missing PowerPlay Table!", return -1);
- PP_ASSERT_WITH_CODE((pp_table->sHeader.format_revision >=
- ATOM_Vega10_TABLE_REVISION_VEGA10),
- "Incorrect PowerPlay table revision!", return -1);
- state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)pp_table) +
- le16_to_cpu(pp_table->usStateArrayOffset));
+ result = get_vega10_state_array(hwmgr, pp_table, &state_arrays);
+ PP_ASSERT_WITH_CODE((result == 0),
+ "Invalid PowerPlay Table State Array.", return result);
return (uint32_t)(state_arrays->ucNumEntries);
}
@@ -1306,17 +1750,11 @@ int vega10_get_powerplay_table_entry(struct pp_hwmgr *hwmgr,
if (pp_table->sHeader.format_revision >=
ATOM_Vega10_TABLE_REVISION_VEGA10) {
- state_arrays = (ATOM_Vega10_State_Array *)
- (((unsigned long)pp_table) +
- le16_to_cpu(pp_table->usStateArrayOffset));
-
- PP_ASSERT_WITH_CODE(pp_table->usStateArrayOffset > 0,
- "Invalid PowerPlay Table State Array Offset.",
- return -1);
- PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0,
+ result = get_vega10_state_array(hwmgr, pp_table, &state_arrays);
+ PP_ASSERT_WITH_CODE((result == 0),
"Invalid PowerPlay Table State Array.",
- return -1);
- PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
+ return result);
+ PP_ASSERT_WITH_CODE((entry_index < state_arrays->ucNumEntries),
"Invalid PowerPlay Table State Array Entry.",
return -1);
@@ -1358,4 +1796,3 @@ int vega10_baco_set_cap(struct pp_hwmgr *hwmgr)
PHM_PlatformCaps_BACO);
return result;
}
-
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
index 69a9074058ce..b466b08e4a67 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
@@ -1419,7 +1419,7 @@ static int vega12_get_gpu_power(struct pp_hwmgr *hwmgr, uint32_t *query)
if (ret)
return ret;
- *query = metrics_table.CurrSocketPower << 8;
+ *query = metrics_table.CurrSocketPower * MILLIWATT_PER_WATT;
return ret;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
index 55e13f376039..dcb9c749eba3 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
@@ -64,6 +64,13 @@ static int check_powerplay_tables(
struct pp_hwmgr *hwmgr,
const ATOM_Vega12_POWERPLAYTABLE *powerplay_table)
{
+ size_t smc_pptable_size =
+ offsetofend(ATOM_Vega12_POWERPLAYTABLE, smcPPTable);
+ size_t table_size = hwmgr->soft_pp_table_size;
+
+ PP_ASSERT_WITH_CODE((table_size >= smc_pptable_size),
+ "Invalid PowerPlay Table!", return -1);
+
PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >=
ATOM_VEGA12_TABLE_REVISION_VEGA12),
"Unsupported PPTable format!", return -1);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
index 7b8f4c1b80eb..e9c194056e32 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
@@ -2154,12 +2154,13 @@ static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, int idx,
switch (idx) {
case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
if (hwmgr->smu_version == 0x282e00)
- *query = metrics_table.AverageSocketPower << 8;
+ *query = metrics_table.AverageSocketPower *
+ MILLIWATT_PER_WATT;
else
ret = -EOPNOTSUPP;
break;
case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
- *query = metrics_table.CurrSocketPower << 8;
+ *query = metrics_table.CurrSocketPower * MILLIWATT_PER_WATT;
break;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
index 36cb7aa80d07..a0c884c2341d 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
@@ -66,6 +66,13 @@ static int check_powerplay_tables(
struct pp_hwmgr *hwmgr,
const ATOM_Vega20_POWERPLAYTABLE *powerplay_table)
{
+ size_t smc_pptable_size =
+ offsetofend(ATOM_Vega20_POWERPLAYTABLE, smcPPTable);
+ size_t table_size = hwmgr->soft_pp_table_size;
+
+ PP_ASSERT_WITH_CODE((table_size >= smc_pptable_size),
+ "Invalid PowerPlay Table!", return -1);
+
PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >=
ATOM_VEGA20_TABLE_REVISION_VEGA20),
"Unsupported PPTable format!", return -1);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
index ca71efaa1656..448246cc52cc 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
@@ -35,6 +35,11 @@ struct pp_hwmgr;
struct phm_fan_speed_info;
struct pp_atomctrl_voltage_table;
+/* Decode legacy unsigned Q24.8 watts to internal milliwatts. */
+#define PP_PWR_Q24_8_TO_MW(power) \
+ DIV_ROUND_CLOSEST_ULL((u64)(power) * MILLIWATT_PER_WATT, \
+ BIT(8))
+
#define VOLTAGE_SCALE 4
#define VOLTAGE_VID_OFFSET_SCALE1 625
#define VOLTAGE_VID_OFFSET_SCALE2 100
@@ -829,4 +834,24 @@ int smu8_init_function_pointers(struct pp_hwmgr *hwmgr);
int vega12_hwmgr_init(struct pp_hwmgr *hwmgr);
int vega20_hwmgr_init(struct pp_hwmgr *hwmgr);
+static inline uint32_t pp_entries_max(const struct pp_hwmgr *hwmgr,
+ const void *sub_table,
+ size_t hdr_size, size_t rec_size)
+{
+ const char *pp_start = hwmgr->soft_pp_table;
+ const char *pp_end = pp_start + hwmgr->soft_pp_table_size;
+ const char *entries = (const char *)sub_table + hdr_size;
+
+ if (!hwmgr->hardcode_pp_table) {
+ struct amdgpu_device *adev = hwmgr->adev;
+ const char *bios_end = (const char *)adev->bios + adev->bios_size;
+
+ if (pp_end > bios_end)
+ return 0;
+ }
+ if (!rec_size || entries >= pp_end)
+ return 0;
+ return (uint32_t)((pp_end - entries) / rec_size);
+}
+
#endif /* _HWMGR_H_ */
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c
index 3e0068a6aeb2..45504ac3a31d 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu7_smumgr.c
@@ -134,14 +134,6 @@ int smu7_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
PHM_WAIT_FIELD_UNEQUAL(hwmgr, SMC_RESP_0, SMC_RESP, 0);
- ret = PHM_READ_FIELD(hwmgr->device, SMC_RESP_0, SMC_RESP);
-
- if (ret == 0xFE)
- dev_dbg(adev->dev, "last message was not supported\n");
- else if (ret != 1)
- dev_info(adev->dev,
- "\nlast message was failed ret is %d\n", ret);
-
cgs_write_register(hwmgr->device, mmSMC_RESP_0, 0);
cgs_write_register(hwmgr->device, mmSMC_MESSAGE_0, msg);
@@ -149,13 +141,16 @@ int smu7_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
ret = PHM_READ_FIELD(hwmgr->device, SMC_RESP_0, SMC_RESP);
- if (ret == 0xFE)
- dev_dbg(adev->dev, "message %x was not supported\n", msg);
- else if (ret != 1)
- dev_dbg(adev->dev,
- "failed to send message %x ret is %d \n", msg, ret);
-
- return 0;
+ switch (ret) {
+ case 1:
+ return 0;
+ case 0xFE:
+ dev_dbg(adev->dev, "SMU message %#x was not supported\n", msg);
+ return -EOPNOTSUPP;
+ default:
+ dev_info(adev->dev, "SMU message %#x failed: response is %d\n", msg, ret);
+ return ret != 0xFFFF ? -EIO : -ENXIO;
+ }
}
int smu7_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 208a2fba6d40..cca32f74abf0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -28,6 +28,7 @@
#include <linux/reboot.h>
#include "amdgpu.h"
+#include "amdgpu_reset.h"
#include "amdgpu_smu.h"
#include "smu_internal.h"
#include "atom.h"
@@ -70,7 +71,7 @@ static int smu_handle_task(struct smu_context *smu,
static int smu_reset(struct smu_context *smu);
static int smu_set_fan_speed_pwm(void *handle, u32 speed);
static int smu_set_fan_control_mode(void *handle, u32 value);
-static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit);
+static int smu_set_ppt_limit(void *handle, uint32_t limit_type, uint32_t limit);
static int smu_set_fan_speed_rpm(void *handle, uint32_t speed);
static int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled);
static int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state);
@@ -488,13 +489,52 @@ static void smu_set_user_clk_dependencies(struct smu_context *smu, enum smu_clk_
return;
}
+static void smu_restore_ppt_limits(struct smu_context *smu,
+ bool restore_defaults)
+{
+ enum smu_power_src_type power_source;
+ struct smu_ppt_limit_range *range;
+ uint32_t restore_mask;
+ uint32_t limit;
+ int i, ret;
+
+ power_source = smu->adev->pm.ac_power ?
+ SMU_POWER_SOURCE_AC : SMU_POWER_SOURCE_DC;
+ restore_mask = smu->user_dpm_profile.ppt_limit_user_mask[power_source] &
+ smu->ppt_limits.supported_mask;
+ if (!restore_mask && !restore_defaults)
+ return;
+
+ smu->user_dpm_profile.flags |= SMU_DPM_USER_PROFILE_RESTORE;
+
+ for (i = SMU_PPT_LIMIT_PPT0; i < SMU_LIMIT_TYPE_COUNT; i++) {
+ if (!(smu->ppt_limits.supported_mask & BIT(i)))
+ continue;
+
+ if (restore_mask & BIT(i)) {
+ limit = smu->user_dpm_profile.ppt_limits[power_source][i];
+ } else if (restore_defaults) {
+ range = &smu->ppt_limits.range[power_source][i];
+ limit = range->default_value;
+ } else {
+ continue;
+ }
+
+ ret = smu_set_ppt_limit(smu, i, limit);
+ if (ret)
+ dev_err(smu->adev->dev,
+ "Failed to restore PPT%d limit: %d\n", i, ret);
+ }
+
+ smu->user_dpm_profile.flags &= ~SMU_DPM_USER_PROFILE_RESTORE;
+}
+
/**
* smu_restore_dpm_user_profile - reinstate user dpm profile
*
* @smu: smu_context pointer
*
- * Restore the saved user power configurations include power limit,
- * clock frequencies, fan control mode and fan speed.
+ * Restore saved user clock frequencies and fan settings.
*/
static void smu_restore_dpm_user_profile(struct smu_context *smu)
{
@@ -510,16 +550,6 @@ static void smu_restore_dpm_user_profile(struct smu_context *smu)
/* Enable restore flag */
smu->user_dpm_profile.flags |= SMU_DPM_USER_PROFILE_RESTORE;
- /* set the user dpm power limits */
- for (int i = SMU_DEFAULT_PPT_LIMIT; i < SMU_LIMIT_TYPE_COUNT; i++) {
- if (!smu->user_dpm_profile.power_limits[i])
- continue;
- ret = smu_set_power_limit(smu, i,
- smu->user_dpm_profile.power_limits[i]);
- if (ret)
- dev_err(smu->adev->dev, "Failed to set %d power limit value\n", i);
- }
-
/* set the user dpm clock configurations */
if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
enum smu_clk_type clk_type;
@@ -591,17 +621,13 @@ static int smu_get_power_num_states(void *handle,
return 0;
}
-bool is_support_sw_smu(struct amdgpu_device *adev)
+void amdgpu_smu_early_init(struct amdgpu_device *adev)
{
/* vega20 is 11.0.2, but it's supported via the powerplay code */
- if (adev->asic_type == CHIP_VEGA20)
- return false;
-
- if ((amdgpu_ip_version(adev, MP1_HWIP, 0) >= IP_VERSION(11, 0, 0)) &&
- amdgpu_device_ip_is_valid(adev, AMD_IP_BLOCK_TYPE_SMC))
- return true;
-
- return false;
+ adev->is_sw_smu = adev->asic_type != CHIP_VEGA20 &&
+ (amdgpu_ip_version(adev, MP1_HWIP, 0) >=
+ IP_VERSION(11, 0, 0) &&
+ amdgpu_device_ip_is_valid(adev, AMD_IP_BLOCK_TYPE_SMC));
}
bool is_support_cclk_dpm(struct amdgpu_device *adev)
@@ -667,27 +693,31 @@ static int smu_sys_set_pp_table(void *handle,
{
struct smu_context *smu = handle;
struct smu_table_context *smu_table = &smu->smu_table;
- ATOM_COMMON_TABLE_HEADER *header = (ATOM_COMMON_TABLE_HEADER *)buf;
+ ATOM_COMMON_TABLE_HEADER *header;
+ void *hardcode_pptable;
int ret = 0;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
+ if (!buf || size < sizeof(*header))
+ return -EINVAL;
+
+ header = (ATOM_COMMON_TABLE_HEADER *)buf;
if (header->usStructureSize != size) {
dev_err(smu->adev->dev, "pp table size not matched !\n");
return -EIO;
}
- if (!smu_table->hardcode_pptable || smu_table->power_play_table_size < size) {
- kfree(smu_table->hardcode_pptable);
- smu_table->hardcode_pptable = kzalloc(size, GFP_KERNEL);
- if (!smu_table->hardcode_pptable)
- return -ENOMEM;
- }
+ hardcode_pptable = kmemdup(buf, size, GFP_KERNEL);
+ if (!hardcode_pptable)
+ return -ENOMEM;
- memcpy(smu_table->hardcode_pptable, buf, size);
+ kfree(smu_table->hardcode_pptable);
+ smu_table->hardcode_pptable = hardcode_pptable;
smu_table->power_play_table = smu_table->hardcode_pptable;
smu_table->power_play_table_size = size;
+ memset(&smu->ppt_limits, 0, sizeof(smu->ppt_limits));
/*
* Special hw_fini action(for Navi1x, the DPMs disablement will be
@@ -802,6 +832,7 @@ static int smu_set_funcs(struct amdgpu_device *adev)
break;
case IP_VERSION(15, 0, 0):
case IP_VERSION(15, 0, 5):
+ case IP_VERSION(15, 0, 9):
smu_v15_0_0_set_ppt_funcs(smu);
break;
case IP_VERSION(15, 0, 8):
@@ -929,7 +960,7 @@ static int smu_late_init(struct amdgpu_ip_block *ip_block)
* is unnecessary.
*/
adev->pm.ac_power = power_supply_is_system_supplied() > 0;
- smu_set_ac_dc(smu);
+ smu_set_ac_dc(smu, false);
if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 1)) ||
(amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 3)))
@@ -949,16 +980,6 @@ static int smu_late_init(struct amdgpu_ip_block *ip_block)
return ret;
}
- ret = smu_get_asic_power_limits(smu,
- &smu->current_power_limit,
- &smu->default_power_limit,
- &smu->max_power_limit,
- &smu->min_power_limit);
- if (ret) {
- dev_err(adev->dev, "Failed to get asic power limits!\n");
- return ret;
- }
-
if (!amdgpu_sriov_vf(adev))
smu_get_unique_id(smu);
@@ -974,6 +995,8 @@ static int smu_late_init(struct amdgpu_ip_block *ip_block)
return ret;
}
+ if (adev->in_suspend || amdgpu_reset_in_recovery(adev))
+ smu_restore_ppt_limits(smu, false);
smu_restore_dpm_user_profile(smu);
return 0;
@@ -1366,6 +1389,14 @@ static void smu_feature_cap_init(struct smu_context *smu)
bitmap_zero(fea_cap->cap_map, SMU_FEATURE_CAP_ID__COUNT);
}
+static int smu_set_power_dep(struct smu_context *smu, bool enable)
+{
+ if (!smu->ppt_funcs->set_power_dep)
+ return 0;
+
+ return smu->ppt_funcs->set_power_dep(smu, enable);
+}
+
static int smu_sw_init(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
@@ -1427,6 +1458,8 @@ static int smu_sw_init(struct amdgpu_ip_block *ip_block)
if (!smu->ppt_funcs->get_fan_control_mode)
smu->adev->pm.no_fan = true;
+ smu_set_power_dep(smu, true);
+
return 0;
}
@@ -1449,6 +1482,8 @@ static int smu_sw_fini(struct amdgpu_ip_block *ip_block)
smu_fini_microcode(smu);
+ smu_set_power_dep(smu, false);
+
return 0;
}
@@ -2739,7 +2774,7 @@ static int smu_set_watermarks_for_clock_ranges(void *handle,
return smu_set_watermarks_table(smu, clock_ranges);
}
-int smu_set_ac_dc(struct smu_context *smu)
+int smu_set_ac_dc(struct smu_context *smu, bool restore_ppt_policy)
{
int ret = 0;
@@ -2747,17 +2782,22 @@ int smu_set_ac_dc(struct smu_context *smu)
return -EOPNOTSUPP;
/* controlled by firmware */
- if (smu->dc_controlled_by_gpio)
- return 0;
+ if (!smu->dc_controlled_by_gpio) {
+ ret = smu_set_power_source(smu,
+ smu->adev->pm.ac_power ?
+ SMU_POWER_SOURCE_AC :
+ SMU_POWER_SOURCE_DC);
+ if (ret) {
+ dev_err(smu->adev->dev, "Failed to switch to %s mode!\n",
+ smu->adev->pm.ac_power ? "AC" : "DC");
+ return ret;
+ }
+ }
- ret = smu_set_power_source(smu,
- smu->adev->pm.ac_power ? SMU_POWER_SOURCE_AC :
- SMU_POWER_SOURCE_DC);
- if (ret)
- dev_err(smu->adev->dev, "Failed to switch to %s mode!\n",
- smu->adev->pm.ac_power ? "AC" : "DC");
+ if (restore_ppt_policy)
+ smu_restore_ppt_limits(smu, true);
- return ret;
+ return 0;
}
const struct amd_ip_funcs smu_ip_funcs = {
@@ -2772,7 +2812,6 @@ const struct amd_ip_funcs smu_ip_funcs = {
.suspend = smu_suspend,
.resume = smu_resume,
.is_idle = NULL,
- .check_soft_reset = NULL,
.wait_for_idle = NULL,
.soft_reset = NULL,
.set_clockgating_state = smu_set_clockgating_state,
@@ -2819,17 +2858,6 @@ const struct amdgpu_ip_block_version smu_v15_0_ip_block = {
.funcs = &smu_ip_funcs,
};
-const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle)
-{
- struct smu_context *smu = (struct smu_context *)handle;
- const struct ras_smu_drv *tmp = NULL;
- int ret;
-
- ret = smu_get_ras_smu_drv(smu, &tmp);
-
- return ret ? NULL : tmp;
-}
-
static int smu_load_microcode(void *handle)
{
struct smu_context *smu = handle;
@@ -2900,7 +2928,7 @@ static int smu_set_fan_speed_rpm(void *handle, uint32_t speed)
}
/**
- * smu_get_power_limit - Request one of the SMU Power Limits
+ * smu_get_ppt_limit - Request one of the SMU PPT limits
*
* @handle: pointer to smu context
* @limit: requested limit is written back to this variable
@@ -2909,13 +2937,13 @@ static int smu_set_fan_speed_rpm(void *handle, uint32_t speed)
* Return: 0 on success, <0 on error
*
*/
-int smu_get_power_limit(void *handle,
+int smu_get_ppt_limit(void *handle,
uint32_t *limit,
enum pp_power_limit_level pp_limit_level,
enum pp_power_type pp_power_type)
{
struct smu_context *smu = handle;
- struct amdgpu_device *adev = smu->adev;
+ enum smu_power_src_type power_source;
enum smu_ppt_limit_level limit_level;
uint32_t limit_type;
int ret = 0;
@@ -2926,9 +2954,12 @@ int smu_get_power_limit(void *handle,
if (!limit)
return -EINVAL;
+ power_source = smu->adev->pm.ac_power ?
+ SMU_POWER_SOURCE_AC : SMU_POWER_SOURCE_DC;
+
switch (pp_power_type) {
case PP_PWR_TYPE_SUSTAINED:
- limit_type = SMU_DEFAULT_PPT_LIMIT;
+ limit_type = SMU_SLOW_PPT_LIMIT;
break;
case PP_PWR_TYPE_FAST:
limit_type = SMU_FAST_PPT_LIMIT;
@@ -2954,75 +2985,78 @@ int smu_get_power_limit(void *handle,
return -EOPNOTSUPP;
}
- if (limit_type != SMU_DEFAULT_PPT_LIMIT) {
- if (smu->ppt_funcs->get_ppt_limit)
- ret = smu->ppt_funcs->get_ppt_limit(smu, limit, limit_type, limit_level);
- else
- return -EOPNOTSUPP;
- } else {
- switch (limit_level) {
- case SMU_PPT_LIMIT_CURRENT:
- switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
- case IP_VERSION(13, 0, 2):
- case IP_VERSION(13, 0, 6):
- case IP_VERSION(13, 0, 12):
- case IP_VERSION(13, 0, 14):
- case IP_VERSION(11, 0, 7):
- case IP_VERSION(11, 0, 11):
- case IP_VERSION(11, 0, 12):
- case IP_VERSION(11, 0, 13):
- case IP_VERSION(15, 0, 8):
- ret = smu_get_asic_power_limits(smu,
- &smu->current_power_limit,
- NULL, NULL, NULL);
- break;
- default:
- break;
- }
- *limit = smu->current_power_limit;
- break;
- case SMU_PPT_LIMIT_DEFAULT:
- *limit = smu->default_power_limit;
- break;
- case SMU_PPT_LIMIT_MAX:
- *limit = smu->max_power_limit;
- break;
- case SMU_PPT_LIMIT_MIN:
- *limit = smu->min_power_limit;
- break;
- default:
- return -EINVAL;
- }
+ if (!(smu->ppt_limits.supported_mask & BIT(limit_type)))
+ return -EOPNOTSUPP;
+
+ switch (limit_level) {
+ case SMU_PPT_LIMIT_CURRENT:
+ ret = smu_get_asic_ppt_limit(smu, limit_type, limit);
+ break;
+ case SMU_PPT_LIMIT_DEFAULT:
+ *limit = smu->ppt_limits.range[power_source][limit_type].default_value;
+ break;
+ case SMU_PPT_LIMIT_MAX:
+ *limit = smu->od_enabled ?
+ smu->ppt_limits.range[power_source][limit_type].od_max :
+ smu->ppt_limits.range[power_source][limit_type].max;
+ break;
+ case SMU_PPT_LIMIT_MIN:
+ *limit = smu->od_enabled ?
+ smu->ppt_limits.range[power_source][limit_type].od_min :
+ smu->ppt_limits.range[power_source][limit_type].min;
+ break;
+ default:
+ return -EINVAL;
}
return ret;
}
-static int smu_set_power_limit(void *handle, uint32_t limit_type, uint32_t limit)
+static int smu_set_ppt_limit(void *handle, uint32_t limit_type, uint32_t limit)
{
struct smu_context *smu = handle;
+ enum smu_power_src_type power_source;
+ struct smu_ppt_limit_range *range;
+ uint32_t min_limit, max_limit;
int ret = 0;
if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
return -EOPNOTSUPP;
+ if (limit_type >= SMU_LIMIT_TYPE_COUNT)
+ return -EINVAL;
- if (limit_type == SMU_DEFAULT_PPT_LIMIT) {
- if (!limit)
- limit = smu->current_power_limit;
- if ((limit > smu->max_power_limit) || (limit < smu->min_power_limit)) {
- dev_err(smu->adev->dev,
- "New power limit (%d) is out of range [%d,%d]\n",
- limit, smu->min_power_limit, smu->max_power_limit);
- return -EINVAL;
- }
- }
+ power_source = smu->adev->pm.ac_power ?
+ SMU_POWER_SOURCE_AC : SMU_POWER_SOURCE_DC;
+ range = &smu->ppt_limits.range[power_source][limit_type];
+ min_limit = smu->od_enabled ? range->od_min : range->min;
+ max_limit = smu->od_enabled ? range->od_max : range->max;
+
+ if (!(smu->ppt_limits.supported_mask & BIT(limit_type)))
+ return -EOPNOTSUPP;
- if (smu->ppt_funcs->set_power_limit) {
- ret = smu->ppt_funcs->set_power_limit(smu, limit_type, limit);
+ if (limit_type == SMU_DEFAULT_PPT_LIMIT && !limit) {
+ ret = smu_get_asic_ppt_limit(smu, limit_type, &limit);
if (ret)
return ret;
- if (!(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE))
- smu->user_dpm_profile.power_limits[limit_type] = limit;
+ }
+
+ if (limit > max_limit || limit < min_limit) {
+ dev_err(smu->adev->dev,
+ "New PPT limit (%d) is out of range [%d,%d]\n",
+ limit, min_limit, max_limit);
+ return -EINVAL;
+ }
+
+ if (!smu->ppt_funcs->set_ppt_limit)
+ return -EOPNOTSUPP;
+
+ ret = smu->ppt_funcs->set_ppt_limit(smu, limit_type, limit);
+ if (ret)
+ return ret;
+ if (!(smu->user_dpm_profile.flags & SMU_DPM_USER_PROFILE_RESTORE)) {
+ smu->user_dpm_profile.ppt_limits[power_source][limit_type] = limit;
+ smu->user_dpm_profile.ppt_limit_user_mask[power_source] |=
+ BIT(limit_type);
}
return 0;
@@ -3970,8 +4004,8 @@ static const struct amd_pm_funcs swsmu_pm_funcs = {
.dispatch_tasks = smu_handle_dpm_task,
.load_firmware = smu_load_microcode,
.set_powergating_by_smu = smu_dpm_set_power_gate,
- .set_power_limit = smu_set_power_limit,
- .get_power_limit = smu_get_power_limit,
+ .set_power_limit = smu_set_ppt_limit,
+ .get_power_limit = smu_get_ppt_limit,
.get_power_profile_mode = smu_get_power_profile_mode,
.set_power_profile_mode = smu_set_power_profile_mode,
.odn_edit_dpm_table = smu_od_edit_dpm_table,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index d76e0b005308..3ec65630ab99 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -34,7 +34,7 @@
#define SMU_THERMAL_MINIMUM_ALERT_TEMP 0
#define SMU_THERMAL_MAXIMUM_ALERT_TEMP 255
-#define SMU_TEMPERATURE_UNITS_PER_CENTIGRADES 1000
+#define SMU_TEMPERATURE_UNITS_PER_CENTIGRADES MILLIDEGREE_PER_DEGREE
#define SMU_FW_NAME_LEN 0x24
#define SMU_DPM_USER_PROFILE_RESTORE (1 << 0)
@@ -212,9 +212,12 @@ enum smu_power_src_type {
};
enum smu_ppt_limit_type {
- SMU_DEFAULT_PPT_LIMIT = 0,
- SMU_FAST_PPT_LIMIT,
+ SMU_PPT_LIMIT_PPT0 = 0,
+ SMU_PPT_LIMIT_PPT1,
SMU_LIMIT_TYPE_COUNT,
+ SMU_DEFAULT_PPT_LIMIT = SMU_PPT_LIMIT_PPT0,
+ SMU_SLOW_PPT_LIMIT = SMU_PPT_LIMIT_PPT0,
+ SMU_FAST_PPT_LIMIT = SMU_PPT_LIMIT_PPT1,
};
enum smu_ppt_limit_level {
@@ -224,6 +227,20 @@ enum smu_ppt_limit_level {
SMU_PPT_LIMIT_MAX,
};
+struct smu_ppt_limit_range {
+ uint32_t default_value;
+ uint32_t min;
+ uint32_t max;
+ uint32_t od_min;
+ uint32_t od_max;
+};
+
+struct smu_ppt_limit_context {
+ struct smu_ppt_limit_range
+ range[SMU_POWER_SOURCE_COUNT][SMU_LIMIT_TYPE_COUNT];
+ uint32_t supported_mask;
+};
+
enum smu_memory_pool_size {
SMU_MEMORY_POOL_SIZE_ZERO = 0,
SMU_MEMORY_POOL_SIZE_256_MB = 0x10000000,
@@ -234,7 +251,8 @@ enum smu_memory_pool_size {
struct smu_user_dpm_profile {
uint32_t fan_mode;
- uint32_t power_limits[SMU_LIMIT_TYPE_COUNT];
+ uint32_t ppt_limits[SMU_POWER_SOURCE_COUNT][SMU_LIMIT_TYPE_COUNT];
+ uint32_t ppt_limit_user_mask[SMU_POWER_SOURCE_COUNT];
uint32_t fan_speed_pwm;
uint32_t fan_speed_rpm;
uint32_t flags;
@@ -719,10 +737,7 @@ struct smu_context {
uint32_t pstate_mclk;
bool od_enabled;
- uint32_t current_power_limit;
- uint32_t default_power_limit;
- uint32_t max_power_limit;
- uint32_t min_power_limit;
+ struct smu_ppt_limit_context ppt_limits;
/* soft pptable */
uint32_t ppt_offset_bytes;
@@ -749,6 +764,9 @@ struct smu_context {
bool pm_enabled;
bool is_apu;
+ /* Power dependency link from an integrated xHCI controller to the GPU */
+ struct device_link *usb_power_link;
+
uint32_t smc_driver_if_version;
uint32_t smc_fw_if_version;
uint32_t smc_fw_version;
@@ -849,8 +867,6 @@ struct pptable_funcs {
*/
int (*set_default_dpm_table)(struct smu_context *smu);
- int (*set_power_state)(struct smu_context *smu);
-
/**
* @populate_umd_state_clk: Populate the UMD power state table with
* defaults.
@@ -904,16 +920,6 @@ struct pptable_funcs {
pp_clock_levels_with_latency
*clocks);
/**
- * @get_clock_by_type_with_voltage: Get the speed and voltage of a clock
- * domain.
- */
- int (*get_clock_by_type_with_voltage)(struct smu_context *smu,
- enum amd_pp_clock_type type,
- struct
- pp_clock_levels_with_voltage
- *clocks);
-
- /**
* @get_power_profile_mode: Print all power profile modes to
* buffer. Star current mode.
*/
@@ -1054,19 +1060,11 @@ struct pptable_funcs {
int (*display_disable_memory_clock_switch)(struct smu_context *smu, bool disable_memory_clock_switch);
/**
- * @get_power_limit: Get the device's power limits.
- */
- int (*get_power_limit)(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit);
-
- /**
- * @get_ppt_limit: Get the device's ppt limits.
+ * @get_ppt_limit: Get the effective runtime PPT0 or PPT1 limit.
*/
- int (*get_ppt_limit)(struct smu_context *smu, uint32_t *ppt_limit,
- enum smu_ppt_limit_type limit_type, enum smu_ppt_limit_level limit_level);
+ int (*get_ppt_limit)(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *current_ppt_limit);
/**
* @set_df_cstate: Set data fabric cstate.
@@ -1254,11 +1252,11 @@ struct pptable_funcs {
int (*notify_display_change)(struct smu_context *smu);
/**
- * @set_power_limit: Set power limit in watts.
+ * @set_ppt_limit: Set the PPT0 or PPT1 limit in watts.
*/
- int (*set_power_limit)(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit);
+ int (*set_ppt_limit)(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit);
/**
* @init_max_sustainable_clocks: Populate max sustainable clock speed
@@ -1345,7 +1343,7 @@ struct pptable_funcs {
u32 (*set_gfx_off_residency)(struct smu_context *smu, bool start);
/**
- * @get_gfx_off_residency: Average GFXOFF residency % during the logging interval
+ * @get_gfx_off_residency: Live GFXOFF residency percentage
*/
u32 (*get_gfx_off_residency)(struct smu_context *smu, uint32_t *residency);
@@ -1355,11 +1353,6 @@ struct pptable_funcs {
int (*register_irq_handler)(struct smu_context *smu);
/**
- * @set_azalia_d3_pme: Wake the audio decode engine from d3 sleep.
- */
- int (*set_azalia_d3_pme)(struct smu_context *smu);
-
- /**
* @get_max_sustainable_clocks_by_dc: Get a copy of the max sustainable
* clock speeds table.
*
@@ -1376,18 +1369,6 @@ struct pptable_funcs {
int (*get_bamaco_support)(struct smu_context *smu);
/**
- * @baco_get_state: Get the current BACO state.
- *
- * Return: Current BACO state.
- */
- enum smu_baco_state (*baco_get_state)(struct smu_context *smu);
-
- /**
- * @baco_set_state: Enter/exit BACO.
- */
- int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state);
-
- /**
* @baco_enter: Enter BACO.
*/
int (*baco_enter)(struct smu_context *smu);
@@ -1648,12 +1629,13 @@ struct pptable_funcs {
int (*ras_send_msg)(struct smu_context *smu,
enum smu_message_type msg, uint32_t param, uint32_t *read_arg);
-
/**
- * @get_ras_smu_drv: Get RAS smu driver interface
- * Return: ras_smu_drv *
+ * @set_power_dep: Create or destroy a power dependency link
+ * from an integrated xHCI controller to the GPU so that the GPU is
+ * resumed before the USB controller during PM resume. @enable is true
+ * to create the link and false to tear it down.
*/
- int (*get_ras_smu_drv)(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv);
+ int (*set_power_dep)(struct smu_context *smu, bool enable);
};
typedef enum {
@@ -1940,10 +1922,10 @@ smu_driver_table_update_cache_time(struct smu_context *smu,
}
#if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4)
-int smu_get_power_limit(void *handle,
- uint32_t *limit,
- enum pp_power_limit_level pp_limit_level,
- enum pp_power_type pp_power_type);
+int smu_get_ppt_limit(void *handle,
+ uint32_t *limit,
+ enum pp_power_limit_level pp_limit_level,
+ enum pp_power_type pp_power_type);
bool smu_mode1_reset_is_support(struct smu_context *smu);
bool smu_link_reset_is_support(struct smu_context *smu);
@@ -1952,7 +1934,13 @@ int smu_link_reset(struct smu_context *smu);
extern const struct amd_ip_funcs smu_ip_funcs;
-bool is_support_sw_smu(struct amdgpu_device *adev);
+void amdgpu_smu_early_init(struct amdgpu_device *adev);
+
+static inline bool is_support_sw_smu(struct amdgpu_device *adev)
+{
+ return adev->is_sw_smu;
+}
+
bool is_support_cclk_dpm(struct amdgpu_device *adev);
int smu_write_watermarks_table(struct smu_context *smu);
@@ -1964,7 +1952,7 @@ int smu_set_soft_freq_range(struct smu_context *smu, enum pp_clock_type clk_type
int smu_set_gfx_power_up_by_imu(struct smu_context *smu);
-int smu_set_ac_dc(struct smu_context *smu);
+int smu_set_ac_dc(struct smu_context *smu, bool restore_ppt_policy);
int smu_set_xgmi_plpd_mode(struct smu_context *smu,
enum pp_xgmi_plpd_mode mode);
@@ -1995,7 +1983,6 @@ int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type,
int level);
ssize_t smu_get_pm_policy_info(struct smu_context *smu,
enum pp_pm_policy p_type, char *sysbuf);
-const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle);
int amdgpu_smu_ras_send_msg(struct amdgpu_device *adev, enum smu_message_type msg,
uint32_t param, uint32_t *readarg);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h
index 47ddf533b08f..a5d3e8d88860 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu15_driver_if_v15_0_0.h
@@ -144,6 +144,44 @@ typedef struct {
uint32_t MaxGfxClk;
} DpmClocks_t;
+//Freq in MHz
+//Voltage in milli volts with 2 fractional bits
+typedef struct {
+ uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS];
+ uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS];
+ uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS];
+ uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS];
+
+ uint32_t VPEClocks[NUM_VPE_DPM_LEVELS];
+ uint32_t FclkClocks_Freq[NUM_FCLK_DPM_LEVELS];
+ uint32_t FclkClocks_Voltage[NUM_FCLK_DPM_LEVELS];
+ uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS];
+ MemPstateTable_t MemPstateTable[NUM_MEM_PSTATE_LEVELS];
+
+ uint8_t NumDcfClkLevelsEnabled;
+ uint8_t NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk
+ uint8_t NumSocClkLevelsEnabled;
+
+ uint8_t VpeClkLevelsEnabled;
+
+ uint8_t NumMemPstatesEnabled;
+ uint8_t NumFclkLevelsEnabled;
+ uint8_t Spare1;
+ uint8_t Spare2;
+
+ uint8_t Spare3;
+ uint8_t Spare4;
+ uint8_t Spare5[2];
+
+ uint32_t MinGfxClk;
+ uint32_t MaxGfxClk;
+
+ uint32_t Spare6[8];
+ uint32_t Spare7[8];
+ uint32_t Spare8[8];
+ uint32_t Spare9[8];
+} DpmClocks_t_v15_0_5;
+
typedef struct {
uint16_t CoreFrequency[16]; //Target core frequency [MHz]
uint16_t CorePower[16]; //CAC calculated core power [mW]
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h
index 7471e2df2828..4206514765cd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v11_5_ppsmc.h
@@ -110,8 +110,10 @@
#define PPSMC_MSG_GetSlowPPTLimit 0x4C
#define PPSMC_MSG_GetGfxOffStatus 0x50
#define PPSMC_MSG_GetGfxOffEntryCount 0x51
-#define PPSMC_MSG_LogGfxOffResidency 0x52
-#define PPSMC_Message_Count 0x53
+#define PPSMC_MSG_GfxOffResidencyLogReadSample 0x52
+#define PPSMC_MSG_StopGfxOffResidencyLogging 0x53
+#define PPSMC_MSG_StartGfxOffResidencyLogging 0x56
+#define PPSMC_Message_Count 0x57
//Argument for PPSMC_MSG_GfxDeviceDriverReset
enum {
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_metrics.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_metrics.h
new file mode 100644
index 000000000000..698c08875760
--- /dev/null
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_metrics.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __SMU_V15_0_0_METRICS_H__
+#define __SMU_V15_0_0_METRICS_H__
+
+#define METRICS_TABLE_VERSION 0x04
+#define NUM_MAX_CORES 12
+#define NUM_CLK_DPM_LEVELS 8
+#define METRIC_CORE_TYPE_MAX 4
+#define METRIC_CCX_MAX 4
+
+/* Variable Type | Description */
+#pragma pack(push, 4)
+typedef struct {
+uint32_t AccumulationCounter;
+
+/*SET_VOLTAGES */
+uint64_t VDDCR_SetVoltage; /* Acc Float (V) */
+uint64_t VDDCR_SOC_SetVoltage; /* Acc Float (V) */
+uint64_t VDDCR_NPU_SetVoltage; /* Acc Float (V) */
+uint64_t VDDCR_LP_SetVoltage; /* Acc Float (V) */
+uint64_t VDDCR_GFX_SetVoltage; /* Acc Float (V) */
+uint64_t VDD_MISC_SetVoltage; /* Acc Float (V) */
+
+/*TELEMETRY_VOLTAGES */
+uint64_t VDDCR_TelemetryVoltage; /* Acc Float (V) */
+uint64_t VDDCR_SOC_TelemetryVoltage; /* Acc Float (V) */
+uint64_t VDDCR_NPU_TelemetryVoltage; /* Acc Float (V) */
+uint64_t VDDCR_LP_TelemetryVoltage; /* Acc Float (V) */
+uint64_t VDDCR_GFX_TelemetryVoltage; /* Acc Float (V) */
+uint64_t VDD_MISC_TelemetryVoltage; /* Acc Float (V) */
+
+/*TELEMETRY_POWERS */
+uint64_t VDDCR_TelemetryPower; /* Acc Float (W) */
+uint64_t VDDCR_SOC_TelemetryPower; /* Acc Float (W) */
+uint64_t VDDCR_NPU_TelemetryPower; /* Acc Float (W) */
+uint64_t VDDCR_LP_TelemetryPower; /* Acc Float (W) */
+uint64_t VDDCR_GFX_TelemetryPower; /* Acc Float (W) */
+uint64_t VDD_MISC_TelemetryPower; /* Acc Float (W) */
+
+/*THROTTLERS */
+uint32_t fPPT_FusedLimit; /* Inst Float (W) */
+uint32_t fPPT_MaxIrmLimit; /* Inst Float (W) */
+uint32_t fPPT_MaxPboLimit; /* Inst Float (W) */
+uint32_t fPPT_Limit; /* Inst Float (W) */
+uint64_t fPPT_ValueAcc; /* Acc Int (W) */
+uint32_t fPPT_ResidencyAcc; /* Acc Float */
+
+uint32_t sPPT_FusedLimit; /* Inst Float (W) */
+uint32_t sPPT_MaxIrmLimit; /* Inst Float (W) */
+uint32_t sPPT_MaxPboLimit; /* Inst Float (W) */
+uint32_t sPPT_Limit; /* Inst Float (W) */
+uint64_t sPPT_ValueAcc; /* Acc Int (W) */
+uint32_t sPPT_ResidencyAcc; /* Acc Float */
+
+uint32_t SPL_FusedLimit; /* Inst Float (W) */
+uint32_t SPL_MaxIrmLimit; /* Inst Float (W) */
+uint32_t SPL_MaxPboLimit; /* Inst Float (W) */
+uint32_t SPL_Limit; /* Inst Float (W) */
+uint64_t SPL_ValueAcc; /* Acc Int (W) */
+uint32_t SPL_ResidencyAcc; /* Acc Float */
+
+uint32_t TDC_VDDCR_FusedLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_MaxIrmLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_MaxPboLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_Limit; /* Inst Float (A) */
+uint64_t TDC_VDDCR_ValueAcc; /* Acc Int (A) */
+uint32_t TDC_VDDCR_ResidencyAcc; /* Acc Float */
+
+uint32_t TDC_VDDCR_SOC_FusedLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_SOC_MaxIrmLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_SOC_MaxPboLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_SOC_Limit; /* Inst Float (A) */
+uint64_t TDC_VDDCR_SOC_ValueAcc; /* Acc Int (A) */
+uint32_t TDC_VDDCR_SOC_ResidencyAcc; /* Acc Float */
+
+uint32_t TDC_VDDCR_NPU_FusedLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_NPU_MaxIrmLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_NPU_MaxPboLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_NPU_Limit; /* Inst Float (A) */
+uint64_t TDC_VDDCR_NPU_ValueAcc; /* Acc Int (A) */
+uint32_t TDC_VDDCR_NPU_ResidencyAcc; /* Acc Float */
+
+uint32_t TDC_VDDCR_LP_FusedLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_LP_MaxIrmLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_LP_MaxPboLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_LP_Limit; /* Inst Float (A) */
+uint64_t TDC_VDDCR_LP_ValueAcc; /* Acc Int (A) */
+uint32_t TDC_VDDCR_LP_ResidencyAcc; /* Acc Float */
+
+uint32_t TDC_VDDCR_GFX_FusedLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_GFX_MaxIrmLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_GFX_MaxPboLimit; /* Inst Float (A) */
+uint32_t TDC_VDDCR_GFX_Limit; /* Inst Float (A) */
+uint64_t TDC_VDDCR_GFX_ValueAcc; /* Acc Int (A) */
+uint32_t TDC_VDDCR_GFX_ResidencyAcc; /* Acc Float */
+
+uint32_t EDC_VDDCR_FusedLimit; /* Inst Float (A) */
+uint32_t EDC_VDDCR_MaxIrmLimit; /* Inst Float (A) */
+uint32_t EDC_VDDCR_MaxPboLimit; /* Inst Float (A) */
+uint32_t EDC_VDDCR_Limit; /* Inst Float (A) */
+
+uint32_t THM_FusedLimit; /* Inst Float (C) */
+uint32_t THM_Limit; /* Inst Float (C) */
+uint64_t THM_ValueAcc; /* Acc Float (C) */
+uint32_t THM_ResidencyAcc; /* Acc Float */
+uint32_t PROCHOT_ResidencyAcc; /* Acc Float */
+uint64_t GFX_TempAcc; /* Acc Float (C) */
+uint64_t SOC_TempAcc; /* Acc Float (C) */
+uint32_t P3T_FusedLimit; /* Inst Float (W) */
+uint64_t P3T_ValueAcc; /* Acc Float (W) */
+
+/*POWER */
+uint64_t SystemPowerAcc; /* Acc Float (W) */
+uint64_t ApuPowerAcc; /* Acc Float (W) */
+uint64_t dGpuPowerAcc; /* Acc Float (W) */
+uint64_t NpuPowerAcc; /* Acc Float (W) */
+
+/*FREQUENCIES */
+uint64_t FclkFreqEffAcc; /* Acc Float (MHz) */
+uint64_t MemclkFreqEffAcc; /* Acc Float (MHz) */
+uint64_t LclkFreqEffAcc; /* Acc Float (MHz) */
+uint64_t GfxclkFreqEffAcc; /* Acc Float (MHz) */
+uint64_t SocclkFreqEffAcc; /* Acc Float (MHz) */
+uint64_t VclkFreqEffAcc; /* Acc Float (MHz) */
+uint64_t VpeclkFreqEffAcc; /* Acc Float (MHz) */
+uint64_t AieclkFreqEffAcc; /* Acc Float (MHz) */
+uint64_t NpuhclkFreqEffAcc; /* Acc Float (MHz) */
+/*BANDWIDTH */
+uint64_t DramReadBandwidth; /* Acc Float (GB/sec) */
+uint64_t DramWriteBandwidth; /* Acc Float (GB/sec) */
+
+/*ACTIVITY MONITORS */
+uint64_t GfxBusyAcc; /* Acc Float (%) */
+uint64_t VcnBusyAcc; /* Acc Float (%) */
+uint64_t NpuBusyAcc[3]; /* Acc Float (%) */
+
+/*STT */
+uint32_t STT_MinLimit; /* Inst Float (W) */
+uint64_t STT_APU_HotSpotTempAcc; /* Acc Float (C) */
+uint64_t STT_HS2_HotSpotTempAcc; /* Acc Float (C) */
+uint32_t STT_APU_Temp_Limit; /* Inst Float (C) */
+uint64_t STT_APU_SkinTempAcc; /* Acc Float (C) */
+
+/*RESIDENCIES */
+uint64_t CpuOffResidency_CCX0; /* Acc Float (%) */
+uint64_t CpuOffResidency_CCX1; /* Acc Float (%) */
+uint64_t CpuOffResidency_CCX2; /* Acc Float (%) */
+uint64_t CpuOffResidency_CCX3; /* Acc Float (%) */
+
+/*DFPSTATES */
+uint32_t FclkFreqTable[NUM_CLK_DPM_LEVELS]; /* Inst Int (MHz) */
+uint32_t UclkFreqTable[NUM_CLK_DPM_LEVELS]; /* Inst Int (MHz) */
+uint32_t DdrRateTable[NUM_CLK_DPM_LEVELS]; /* Inst Int (MT/s) */
+uint8_t DfPstate_Source[NUM_CLK_DPM_LEVELS]; /* Inst Int */
+
+/*SYSTEM */
+uint8_t GfxDisabled; /* Inst Int */
+uint8_t spare2[3];
+uint32_t GfxClk_Fmax; /* Inst Float (GHz) */
+uint8_t CClk_CoreFuseEnable[METRIC_CORE_TYPE_MAX][NUM_MAX_CORES]; /* Inst Int */
+uint8_t CClk_CoreEnabled[METRIC_CORE_TYPE_MAX][NUM_MAX_CORES]; /* Inst Int */
+uint32_t CClk_Fmax[METRIC_CORE_TYPE_MAX][NUM_MAX_CORES]; /* Inst Float (GHz) */
+
+/*OVERCLOCK CAPABLE */
+uint8_t CpuPreciseAndDirectOverClockingCapable; /* Inst Int */
+uint8_t GfxPreciseAndDirectOverClockingCapable; /* Inst Int */
+uint8_t PboBasicOverClockingCapable; /* Inst Int */
+uint8_t PboAdvancedOverClockingCapable; /* Inst Int */
+uint8_t PboNitroOverClockingCapable; /* Inst Int */
+uint8_t MemoryAndFabricOverClockingCapable; /* Inst Int */
+uint8_t MiscOverClockingCapable; /* Inst Int */
+uint8_t ExtremeColdOverclockingCapable; /* Inst Int */
+uint8_t DownConfigControlCapable; /* Inst Int */
+uint8_t spare0[3];
+
+/*OVERCLOCK STATUS */
+uint32_t FIT_LimitScalar; /* Inst Float */
+uint8_t LN2Enabled; /* Inst Int */
+uint8_t CpuPreciseAndDirectOcEnabled; /* Inst Int */
+uint8_t GfxPreciseAndDirectOcEnabled; /* Inst Int */
+uint8_t spare1[2];
+int8_t PsmGuardband[5][5][3]; /* Inst Int */
+int32_t CorePowerLimitOffset; /* Inst Float (W) */
+uint32_t MaxFreqOffset[5]; /* Inst Float (GHz) */
+
+uint64_t NpuTempAcc; /* Acc Float (C) */
+uint64_t DfPStateResidencyAcc[NUM_CLK_DPM_LEVELS]; /* Acc Int (%) */
+uint32_t CClk_Fboost; /* Inst Float (GHz) */
+uint32_t spare3[5];
+} MetricsTable_IOD_t;
+
+typedef struct {
+uint64_t Core_C0[NUM_MAX_CORES]; /* Acc Float (%) */
+uint64_t Core_CC6[NUM_MAX_CORES]; /* Acc Float (%) */
+uint64_t Core_FREQ[NUM_MAX_CORES]; /* Acc Float (GHz) */
+uint64_t Core_FREQEFF[NUM_MAX_CORES]; /* Acc Float (GHz) */
+uint64_t Core_TEMP[NUM_MAX_CORES]; /* Acc Float (C) */
+uint64_t Core_POWER[NUM_MAX_CORES]; /* Acc Float (W) */
+} MetricsTable_CCX_t;
+
+typedef struct {
+MetricsTable_IOD_t IOD;
+MetricsTable_CCX_t CCX[METRIC_CCX_MAX];
+} MetricsTable_t;
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h
index bf216f83e689..9f627b5fef5b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h
@@ -100,7 +100,10 @@
#define PPSMC_MSG_DisableLSdma 0x1F ///< Disable LSDMA
#define PPSMC_MSG_SetSoftMaxVpe 0x20 ///<
#define PPSMC_MSG_SetSoftMinVpe 0x21 ///<
-#define PPSMC_Message_Count 0x22 ///< Total number of PPSMC messages
+#define PPSMC_MSG_GetMetricsTableVersion 0x22
+#define PPSMC_MSG_GetMetricsTableLogSample 0x23
+#define PPSMC_MSG_GetMetricsTableLogDramAddr 0x24
+#define PPSMC_Message_Count 0x25 ///< Total number of PPSMC messages
/** @}*/
/**
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
index 636ff90923d9..d6675b4ee9be 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
@@ -252,7 +252,9 @@
__SMU_DUMMY_MAP(DriverMode2Reset), \
__SMU_DUMMY_MAP(GetGfxOffStatus), \
__SMU_DUMMY_MAP(GetGfxOffEntryCount), \
- __SMU_DUMMY_MAP(LogGfxOffResidency), \
+ __SMU_DUMMY_MAP(StartGfxOffResidencyLogging), \
+ __SMU_DUMMY_MAP(GfxOffResidencyLogReadSample), \
+ __SMU_DUMMY_MAP(StopGfxOffResidencyLogging), \
__SMU_DUMMY_MAP(SetNumBadMemoryPagesRetired), \
__SMU_DUMMY_MAP(SetBadMemoryPagesRetiredFlagsPerChannel), \
__SMU_DUMMY_MAP(AllowGpo), \
@@ -295,6 +297,9 @@
__SMU_DUMMY_MAP(GetSmartShiftStatus), \
__SMU_DUMMY_MAP(EnableLSdma), \
__SMU_DUMMY_MAP(DisableLSdma), \
+ __SMU_DUMMY_MAP(GetMetricsTableVersion), \
+ __SMU_DUMMY_MAP(GetMetricsTableLogSample), \
+ __SMU_DUMMY_MAP(GetMetricsTableLogDramAddr), \
__SMU_DUMMY_MAP(InitializeGfx), \
__SMU_DUMMY_MAP(SetSoftMaxFclk), \
__SMU_DUMMY_MAP(SetSoftMaxGl2clk), \
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
index dd94e8a9e218..9f20c631d2b7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h
@@ -108,10 +108,6 @@ struct smu_11_5_power_context {
uint32_t power_source;
uint8_t in_power_limit_boost_mode;
enum smu_11_0_power_state power_state;
-
- uint32_t current_fast_ppt_limit;
- uint32_t default_fast_ppt_limit;
- uint32_t max_fast_ppt_limit;
};
#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3)
@@ -151,12 +147,13 @@ int smu_v11_0_set_allowed_mask(struct smu_context *smu);
int smu_v11_0_notify_display_change(struct smu_context *smu);
-int smu_v11_0_get_current_power_limit(struct smu_context *smu,
- uint32_t *power_limit);
+int smu_v11_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit);
-int smu_v11_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit);
+int smu_v11_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit);
int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu);
@@ -199,8 +196,6 @@ int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable);
int smu_v11_0_register_irq_handler(struct smu_context *smu);
-int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu);
-
int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu,
struct pp_smu_nv_clock_table *max_clocks);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
index 89bbda0670ef..ffff02489c3e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
@@ -55,6 +55,13 @@
#define SMUQ10_TO_UINT(x) ((x) >> 10)
#define SMUQ10_FRAC(x) ((x) & 0x3ff)
#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200))
+/* Convert Q10 watts to milliwatts, preserving the fractional part */
+#define SMUQ10_TO_MILLIWATT(x) (SMUQ10_TO_UINT(x) * MILLIWATT_PER_WATT + \
+ ((SMUQ10_FRAC(x) * MILLIWATT_PER_WATT) >> 10))
+/* Convert Q10 degrees Celsius to millidegrees, preserving the fractional part */
+#define SMUQ10_TO_MILLICELSIUS(x) \
+ (SMUQ10_TO_UINT(x) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES + \
+ ((SMUQ10_FRAC(x) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES) >> 10))
#define SMU_V13_SOFT_FREQ_ROUND(x) ((x) + 1)
extern const int pmfw_decoded_link_speed[5];
@@ -145,12 +152,13 @@ int smu_v13_0_set_allowed_mask(struct smu_context *smu);
int smu_v13_0_notify_display_change(struct smu_context *smu);
-int smu_v13_0_get_current_power_limit(struct smu_context *smu,
- uint32_t *power_limit);
+int smu_v13_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit);
-int smu_v13_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit);
+int smu_v13_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit);
int smu_v13_0_init_max_sustainable_clocks(struct smu_context *smu);
@@ -180,8 +188,6 @@ int smu_v13_0_gfx_off_control(struct smu_context *smu, bool enable);
int smu_v13_0_register_irq_handler(struct smu_context *smu);
-int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu);
-
int smu_v13_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu,
struct pp_smu_nv_clock_table *max_clocks);
@@ -255,10 +261,6 @@ void smu_v13_0_init_msg_ctl(struct smu_context *smu,
int smu_v13_0_mode1_reset(struct smu_context *smu);
-int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu,
- void **table,
- uint32_t *size,
- uint32_t pptable_id);
int smu_v13_0_update_pcie_parameters(struct smu_context *smu,
uint8_t pcie_gen_cap,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
index 4eb40ff8aff2..dc222f3b3655 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h
@@ -132,12 +132,13 @@ int smu_v14_0_set_allowed_mask(struct smu_context *smu);
int smu_v14_0_notify_display_change(struct smu_context *smu);
-int smu_v14_0_get_current_power_limit(struct smu_context *smu,
- uint32_t *power_limit);
+int smu_v14_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit);
-int smu_v14_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit);
+int smu_v14_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit);
int smu_v14_0_gfx_off_control(struct smu_context *smu, bool enable);
@@ -203,10 +204,6 @@ int smu_v14_0_set_gfx_power_up_by_imu(struct smu_context *smu);
int smu_v14_0_set_default_dpm_tables(struct smu_context *smu);
-int smu_v14_0_get_pptable_from_firmware(struct smu_context *smu,
- void **table,
- uint32_t *size,
- uint32_t pptable_id);
int smu_v14_0_od_edit_dpm_table(struct smu_context *smu,
enum PP_OD_DPM_TABLE_COMMAND type,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h
index e6fd8be2cc4a..ec96dc775485 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h
@@ -26,7 +26,7 @@
#include "amdgpu_smu.h"
#define SMU15_DRIVER_IF_VERSION_INV 0xFFFFFFFF
-#define SMU15_DRIVER_IF_VERSION_SMU_V15_0 0x7
+#define SMU15_DRIVER_IF_VERSION_SMU_V15_0 0x9
#define FEATURE_MASK(feature) (1ULL << feature)
@@ -142,12 +142,13 @@ int smu_v15_0_set_allowed_mask(struct smu_context *smu);
int smu_v15_0_notify_display_change(struct smu_context *smu);
-int smu_v15_0_get_current_power_limit(struct smu_context *smu,
- uint32_t *power_limit);
+int smu_v15_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit);
-int smu_v15_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit);
+int smu_v15_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit);
int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable);
@@ -211,10 +212,6 @@ int smu_v15_0_deep_sleep_control(struct smu_context *smu,
int smu_v15_0_set_gfx_power_up_by_imu(struct smu_context *smu);
-int smu_v15_0_get_pptable_from_firmware(struct smu_context *smu,
- void **table,
- uint32_t *size,
- uint32_t pptable_id);
int smu_v15_0_od_edit_dpm_table(struct smu_context *smu,
enum PP_OD_DPM_TABLE_COMMAND type,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
index 54d3dba7d354..edb0393505ba 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
@@ -67,6 +67,8 @@
#define SMU11_DRIVER_IF_VERSION_ARCT 0x17
+static int arcturus_init_ppt_limits(struct smu_context *smu);
+
static const struct smu_feature_bits arcturus_dpm_features = {
.bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT),
SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
@@ -544,7 +546,7 @@ static int arcturus_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
- return ret;
+ return arcturus_init_ppt_limits(smu);
}
static int arcturus_run_btc(struct smu_context *smu)
@@ -658,7 +660,7 @@ static int arcturus_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->VcnActivityPercentage;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
@@ -1259,37 +1261,42 @@ static int arcturus_get_fan_parameters(struct smu_context *smu)
return 0;
}
-static int arcturus_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int arcturus_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
+{
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
+
+ return smu_v11_0_get_ppt_limit(smu, limit_type, ppt_limit);
+}
+
+static int arcturus_init_ppt_limits(struct smu_context *smu)
{
PPTable_t *pptable = smu->smu_table.driver_pptable;
- uint32_t power_limit;
+ uint32_t default_limit;
+ int i;
- if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
- /* the last hope to figure out the ppt limit */
- if (!pptable) {
- dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
- return -EINVAL;
- }
- power_limit =
- pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
+ if (!pptable) {
+ dev_err(smu->adev->dev,
+ "Cannot get PPT limit due to pptable missing!");
+ return -EINVAL;
}
- if (current_power_limit)
- *current_power_limit = power_limit;
- if (default_power_limit)
- *default_power_limit = power_limit;
- if (max_power_limit)
- *max_power_limit = power_limit;
- /*
- * No lower bound is imposed on the limit. Any unreasonable limit set
- * will result in frequent throttling.
- */
- if (min_power_limit)
- *min_power_limit = 0;
+ default_limit = pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
+
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ default_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max =
+ default_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min = 0;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ default_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min = 0;
+ }
+
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
return 0;
}
@@ -1466,9 +1473,10 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu,
return -ENOMEM;
}
if (custom_params && custom_params_max_idx) {
- if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT)
- return -EINVAL;
- if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)
+ if (!smu_cmn_custom_params_count_valid(custom_params_max_idx,
+ ARCTURUS_CUSTOM_PARAMS_COUNT) ||
+ !smu_cmn_custom_params_clock_valid(custom_params[0],
+ ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT))
return -EINVAL;
idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT;
smu->custom_profile_params[idx] = 1;
@@ -1890,7 +1898,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
.get_power_profile_mode = arcturus_get_power_profile_mode,
.set_power_profile_mode = arcturus_set_power_profile_mode,
.set_performance_level = arcturus_set_performance_level,
- .get_power_limit = arcturus_get_power_limit,
+ .get_ppt_limit = arcturus_get_ppt_limit,
.is_dpm_running = arcturus_is_dpm_running,
.dpm_set_vcn_enable = arcturus_dpm_set_vcn_enable,
.i2c_init = arcturus_i2c_control_init,
@@ -1919,7 +1927,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
.feature_is_enabled = smu_cmn_feature_is_enabled,
.disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception,
.notify_display_change = NULL,
- .set_power_limit = smu_v11_0_set_power_limit,
+ .set_ppt_limit = smu_v11_0_set_ppt_limit,
.init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks,
.enable_thermal_alert = smu_v11_0_enable_thermal_alert,
.disable_thermal_alert = smu_v11_0_disable_thermal_alert,
@@ -1932,7 +1940,6 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
.set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
.gfx_off_control = smu_v11_0_gfx_off_control,
.register_irq_handler = smu_v11_0_register_irq_handler,
- .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme,
.get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc,
.get_bamaco_support = smu_v11_0_get_bamaco_support,
.baco_enter = smu_v11_0_baco_enter,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
index e6e009df9840..bb9620666dae 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/cyan_skillfish_ppt.c
@@ -158,12 +158,10 @@ cyan_skillfish_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->Current.MemclkFrequency;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->Current.CurrentSocketPower << 8) /
- 1000;
+ *value = metrics->Current.CurrentSocketPower;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = (metrics->Average.CurrentSocketPower << 8) /
- 1000;
+ *value = metrics->Average.CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->Current.GfxTemperature / 100 *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index cd0457e13f54..f8ca5eb9adc6 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -58,6 +58,8 @@
#undef pr_info
#undef pr_debug
+static int navi10_init_ppt_limits(struct smu_context *smu);
+
static const struct smu_feature_bits navi10_dpm_features = {
.bits = {
SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT),
@@ -488,7 +490,7 @@ static int navi10_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
- return ret;
+ return navi10_init_ppt_limits(smu);
}
static int navi10_tables_init(struct smu_context *smu)
@@ -602,7 +604,7 @@ static int navi10_get_legacy_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
@@ -691,7 +693,7 @@ static int navi10_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
@@ -777,7 +779,7 @@ static int navi12_get_legacy_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
@@ -866,7 +868,7 @@ static int navi12_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->TemperatureEdge *
@@ -1843,9 +1845,10 @@ static int navi10_set_power_profile_mode(struct smu_context *smu,
return -ENOMEM;
}
if (custom_params && custom_params_max_idx) {
- if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT)
- return -EINVAL;
- if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)
+ if (!smu_cmn_custom_params_count_valid(custom_params_max_idx,
+ NAVI10_CUSTOM_PARAMS_COUNT) ||
+ !smu_cmn_custom_params_clock_valid(custom_params[0],
+ NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT))
return -EINVAL;
idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT;
smu->custom_profile_params[idx] = 1;
@@ -2133,57 +2136,61 @@ static int navi10_display_disable_memory_clock_switch(struct smu_context *smu,
return ret;
}
-static int navi10_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int navi10_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
+{
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
+
+ return smu_v11_0_get_ppt_limit(smu, limit_type, ppt_limit);
+}
+
+static int navi10_init_ppt_limits(struct smu_context *smu)
{
struct smu_11_0_powerplay_table *powerplay_table =
(struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
PPTable_t *pptable = smu->smu_table.driver_pptable;
- uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
+ uint32_t default_limit[SMU_POWER_SOURCE_COUNT];
+ uint32_t od_percent_upper = 0, od_percent_lower = 0;
+ int i;
- if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
- /* the last hope to figure out the ppt limit */
- if (!pptable) {
- dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
- return -EINVAL;
- }
- power_limit =
- pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
- }
-
- if (current_power_limit)
- *current_power_limit = power_limit;
- if (default_power_limit)
- *default_power_limit = power_limit;
-
- if (powerplay_table) {
- if (smu->od_enabled &&
- navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
- od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
- od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
- } else if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
- od_percent_upper = 0;
- od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
- }
+ if (!pptable) {
+ dev_err(smu->adev->dev,
+ "Cannot get PPT limit due to pptable missing!");
+ return -EINVAL;
}
- dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, power_limit);
+ default_limit[SMU_POWER_SOURCE_AC] =
+ pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
+ default_limit[SMU_POWER_SOURCE_DC] =
+ pptable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
- if (max_power_limit) {
- *max_power_limit = power_limit * (100 + od_percent_upper);
- *max_power_limit /= 100;
+ if (powerplay_table &&
+ navi10_od_feature_is_supported(od_settings,
+ SMU_11_0_ODCAP_POWER_LIMIT)) {
+ od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[
+ SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+ od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[
+ SMU_11_0_ODSETTING_POWERPERCENTAGE]);
}
- if (min_power_limit) {
- *min_power_limit = power_limit * (100 - od_percent_lower);
- *min_power_limit /= 100;
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ default_limit[i];
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max =
+ default_limit[i];
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min =
+ default_limit[i] * (100 - od_percent_lower) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ default_limit[i] * (100 + od_percent_upper) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min =
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min;
}
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
+
return 0;
}
@@ -3300,7 +3307,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.set_performance_level = smu_v11_0_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,
+ .get_ppt_limit = navi10_get_ppt_limit,
.update_pcie_parameters = navi10_update_pcie_parameters,
.init_microcode = smu_v11_0_init_microcode,
.load_microcode = smu_v11_0_load_microcode,
@@ -3324,7 +3331,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.feature_is_enabled = smu_cmn_feature_is_enabled,
.disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception,
.notify_display_change = smu_v11_0_notify_display_change,
- .set_power_limit = smu_v11_0_set_power_limit,
+ .set_ppt_limit = smu_v11_0_set_ppt_limit,
.init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks,
.enable_thermal_alert = smu_v11_0_enable_thermal_alert,
.disable_thermal_alert = smu_v11_0_disable_thermal_alert,
@@ -3337,7 +3344,6 @@ static const struct pptable_funcs navi10_ppt_funcs = {
.set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
.gfx_off_control = smu_v11_0_gfx_off_control,
.register_irq_handler = smu_v11_0_register_irq_handler,
- .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme,
.get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc,
.get_bamaco_support = smu_v11_0_get_bamaco_support,
.baco_enter = navi10_baco_enter,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
index f799e489b481..b42897e7c066 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
@@ -60,6 +60,8 @@
#undef pr_info
#undef pr_debug
+static int sienna_cichlid_init_ppt_limits(struct smu_context *smu);
+
static const struct smu_feature_bits sienna_cichlid_dpm_features = {
.bits = {
SMU_FEATURE_BIT_INIT(FEATURE_DPM_PREFETCHER_BIT),
@@ -524,7 +526,11 @@ static int sienna_cichlid_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
- return sienna_cichlid_patch_pptable_quirk(smu);
+ ret = sienna_cichlid_patch_pptable_quirk(smu);
+ if (ret)
+ return ret;
+
+ return sienna_cichlid_init_ppt_limits(smu);
}
static int sienna_cichlid_tables_init(struct smu_context *smu)
@@ -624,53 +630,58 @@ static bool sienna_cichlid_is_od_feature_supported(struct smu_11_0_7_overdrive_t
return od_table->cap[cap];
}
-static int sienna_cichlid_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int sienna_cichlid_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
+{
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
+
+ return smu_v11_0_get_ppt_limit(smu, limit_type, ppt_limit);
+}
+
+static int sienna_cichlid_init_ppt_limits(struct smu_context *smu)
{
struct smu_11_0_7_powerplay_table *powerplay_table =
(struct smu_11_0_7_powerplay_table *)smu->smu_table.power_play_table;
struct smu_11_0_7_overdrive_table *od_settings = smu->od_settings;
- uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
- uint16_t *table_member;
-
- GET_PPTABLE_MEMBER(SocketPowerLimitAc, &table_member);
+ uint32_t default_limit[SMU_POWER_SOURCE_COUNT];
+ uint32_t od_percent_upper = 0, od_percent_lower = 0;
+ uint16_t *ppt_limit_ac, *ppt_limit_dc;
+ int i;
- if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
- power_limit =
- table_member[PPT_THROTTLER_PPT0];
- }
+ GET_PPTABLE_MEMBER(SocketPowerLimitAc, &ppt_limit_ac);
+ GET_PPTABLE_MEMBER(SocketPowerLimitDc, &ppt_limit_dc);
- if (current_power_limit)
- *current_power_limit = power_limit;
- if (default_power_limit)
- *default_power_limit = power_limit;
+ default_limit[SMU_POWER_SOURCE_AC] =
+ ppt_limit_ac[PPT_THROTTLER_PPT0];
+ default_limit[SMU_POWER_SOURCE_DC] =
+ ppt_limit_dc[PPT_THROTTLER_PPT0];
- if (powerplay_table) {
- if (smu->od_enabled &&
- sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_POWER_LIMIT)) {
- od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
- od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
- } else if ((sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_POWER_LIMIT))) {
- od_percent_upper = 0;
- od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
- }
+ if (powerplay_table &&
+ sienna_cichlid_is_od_feature_supported(od_settings,
+ SMU_11_0_7_ODCAP_POWER_LIMIT)) {
+ od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[
+ SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
+ od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[
+ SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
}
- dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, power_limit);
-
- if (max_power_limit) {
- *max_power_limit = power_limit * (100 + od_percent_upper);
- *max_power_limit /= 100;
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ default_limit[i];
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max =
+ default_limit[i];
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min =
+ default_limit[i] * (100 - od_percent_lower) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ default_limit[i] * (100 + od_percent_upper) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min =
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min;
}
- if (min_power_limit) {
- *min_power_limit = power_limit * (100 - od_percent_lower);
- *min_power_limit /= 100;
- }
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
+
return 0;
}
@@ -683,22 +694,29 @@ static void sienna_cichlid_get_smartshift_power_percentage(struct smu_context *s
&(((SmuMetricsExternal_t *)(smu_table->metrics_table))->SmuMetrics_V4);
uint16_t powerRatio = 0;
uint16_t apu_power_limit = 0;
- uint16_t dgpu_power_limit = 0;
+ uint16_t dgpu_ppt_limit = 0;
uint32_t apu_boost = 0;
uint32_t dgpu_boost = 0;
- uint32_t cur_power_limit;
+ uint32_t cur_ppt_limit;
+ enum smu_power_src_type power_source;
if (metrics_v4->ApuSTAPMSmartShiftLimit != 0) {
- sienna_cichlid_get_power_limit(smu, &cur_power_limit, NULL, NULL, NULL);
+ if (sienna_cichlid_get_ppt_limit(smu, SMU_PPT_LIMIT_PPT0,
+ &cur_ppt_limit)) {
+ power_source = smu->adev->pm.ac_power ?
+ SMU_POWER_SOURCE_AC : SMU_POWER_SOURCE_DC;
+ cur_ppt_limit = smu->ppt_limits.range[power_source]
+ [SMU_PPT_LIMIT_PPT0].default_value;
+ }
apu_power_limit = metrics_v4->ApuSTAPMLimit;
- dgpu_power_limit = cur_power_limit;
+ dgpu_ppt_limit = cur_ppt_limit;
powerRatio = (((apu_power_limit +
- dgpu_power_limit) * 100) /
+ dgpu_ppt_limit) * 100) /
metrics_v4->ApuSTAPMSmartShiftLimit);
if (powerRatio > 100) {
apu_power_limit = (apu_power_limit * 100) /
powerRatio;
- dgpu_power_limit = (dgpu_power_limit * 100) /
+ dgpu_ppt_limit = (dgpu_ppt_limit * 100) /
powerRatio;
}
if (metrics_v4->AverageApuSocketPower > apu_power_limit &&
@@ -710,11 +728,11 @@ static void sienna_cichlid_get_smartshift_power_percentage(struct smu_context *s
apu_boost = 100;
}
- if (metrics_v4->AverageSocketPower > dgpu_power_limit &&
- dgpu_power_limit != 0) {
+ if (metrics_v4->AverageSocketPower > dgpu_ppt_limit &&
+ dgpu_ppt_limit != 0) {
dgpu_boost = ((metrics_v4->AverageSocketPower -
- dgpu_power_limit) * 100) /
- dgpu_power_limit;
+ dgpu_ppt_limit) * 100) /
+ dgpu_ppt_limit;
if (dgpu_boost > 100)
dgpu_boost = 100;
}
@@ -855,9 +873,10 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
metrics->AverageUclkActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = use_metrics_v3 ? metrics_v3->AverageSocketPower << 8 :
- use_metrics_v2 ? metrics_v2->AverageSocketPower << 8 :
- metrics->AverageSocketPower << 8;
+ *value = use_metrics_v3 ? metrics_v3->AverageSocketPower :
+ use_metrics_v2 ? metrics_v2->AverageSocketPower :
+ metrics->AverageSocketPower;
+ *value *= MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = (use_metrics_v3 ? metrics_v3->TemperatureEdge :
@@ -1755,9 +1774,10 @@ static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu,
return -ENOMEM;
}
if (custom_params && custom_params_max_idx) {
- if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT)
- return -EINVAL;
- if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)
+ if (!smu_cmn_custom_params_count_valid(custom_params_max_idx,
+ SIENNA_CICHLID_CUSTOM_PARAMS_COUNT) ||
+ !smu_cmn_custom_params_clock_valid(custom_params[0],
+ SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT))
return -EINVAL;
idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT;
smu->custom_profile_params[idx] = 1;
@@ -3107,7 +3127,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.set_performance_level = smu_v11_0_set_performance_level,
.get_thermal_temperature_range = sienna_cichlid_get_thermal_temperature_range,
.display_disable_memory_clock_switch = sienna_cichlid_display_disable_memory_clock_switch,
- .get_power_limit = sienna_cichlid_get_power_limit,
+ .get_ppt_limit = sienna_cichlid_get_ppt_limit,
.update_pcie_parameters = sienna_cichlid_update_pcie_parameters,
.init_microcode = smu_v11_0_init_microcode,
.load_microcode = smu_v11_0_load_microcode,
@@ -3131,7 +3151,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.feature_is_enabled = smu_cmn_feature_is_enabled,
.disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception,
.notify_display_change = NULL,
- .set_power_limit = smu_v11_0_set_power_limit,
+ .set_ppt_limit = smu_v11_0_set_ppt_limit,
.init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks,
.enable_thermal_alert = smu_v11_0_enable_thermal_alert,
.disable_thermal_alert = smu_v11_0_disable_thermal_alert,
@@ -3144,7 +3164,6 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
.set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
.gfx_off_control = smu_v11_0_gfx_off_control,
.register_irq_handler = smu_v11_0_register_irq_handler,
- .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme,
.get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc,
.get_bamaco_support = smu_v11_0_get_bamaco_support,
.baco_enter = sienna_cichlid_baco_enter,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
index d68ceee16d8f..f0b2e7da67b1 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
@@ -192,81 +192,22 @@ int smu_v11_0_check_fw_status(struct smu_context *smu)
return -EIO;
}
-static int smu_v11_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t ppt_offset_bytes;
- const struct smc_firmware_header_v2_0 *v2;
-
- v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data;
-
- ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes);
- *size = le32_to_cpu(v2->ppt_size_bytes);
- *table = (uint8_t *)v2 + ppt_offset_bytes;
-
- return 0;
-}
-
-static int smu_v11_0_set_pptable_v2_1(struct smu_context *smu, void **table,
- uint32_t *size, uint32_t pptable_id)
-{
- struct amdgpu_device *adev = smu->adev;
- const struct smc_firmware_header_v2_1 *v2_1;
- struct smc_soft_pptable_entry *entries;
- uint32_t pptable_count = 0;
- int i = 0;
-
- v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data;
- entries = (struct smc_soft_pptable_entry *)
- ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset));
- pptable_count = le32_to_cpu(v2_1->pptable_count);
- for (i = 0; i < pptable_count; i++) {
- if (le32_to_cpu(entries[i].id) == pptable_id) {
- *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes));
- *size = le32_to_cpu(entries[i].ppt_size_bytes);
- break;
- }
- }
-
- if (i == pptable_count)
- return -EINVAL;
-
- return 0;
-}
-
int smu_v11_0_setup_pptable(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- const struct smc_firmware_header_v1_0 *hdr;
- int ret, index;
- uint32_t size = 0;
uint16_t atom_table_size;
uint8_t frev, crev;
+ uint32_t size = 0;
+ int ret, index;
void *table;
- uint16_t version_major, version_minor;
-
- if (!amdgpu_sriov_vf(adev)) {
- hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
- version_major = le16_to_cpu(hdr->header.header_version_major);
- version_minor = le16_to_cpu(hdr->header.header_version_minor);
- if (version_major == 2 && smu->smu_table.boot_values.pp_table_id > 0) {
- dev_info(adev->dev, "use driver provided pptable %d\n", smu->smu_table.boot_values.pp_table_id);
- switch (version_minor) {
- case 0:
- ret = smu_v11_0_set_pptable_v2_0(smu, &table, &size);
- break;
- case 1:
- ret = smu_v11_0_set_pptable_v2_1(smu, &table, &size,
- smu->smu_table.boot_values.pp_table_id);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret)
- return ret;
- goto out;
- }
+
+ if (!amdgpu_sriov_vf(adev) &&
+ smu->smu_table.boot_values.pp_table_id > 0) {
+ ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size,
+ smu->smu_table.boot_values.pp_table_id);
+ if (ret)
+ return ret;
+ goto out;
}
dev_info(adev->dev, "use vbios provided pptable\n");
@@ -829,14 +770,17 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu)
return 0;
}
-int smu_v11_0_get_current_power_limit(struct smu_context *smu,
- uint32_t *power_limit)
+int smu_v11_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
{
int power_src;
int ret = 0;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT))
return -EINVAL;
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
power_src = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_PWR,
@@ -853,26 +797,26 @@ int smu_v11_0_get_current_power_limit(struct smu_context *smu,
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_GetPptLimit,
(0 << 24) | (power_src << 16),
- power_limit);
+ ppt_limit);
if (ret)
dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
return ret;
}
-int smu_v11_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+int smu_v11_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
int power_src;
int ret = 0;
uint32_t limit_param;
- if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
return -EINVAL;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
- dev_err(smu->adev->dev, "Setting new power limit is not supported!\n");
+ dev_err(smu->adev->dev, "Setting new PPT limit is not supported!\n");
return -EOPNOTSUPP;
}
@@ -894,12 +838,10 @@ int smu_v11_0_set_power_limit(struct smu_context *smu,
limit_param |= (power_src) << 16;
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit_param, NULL);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__);
+ dev_err(smu->adev->dev, "[%s] Set PPT limit failed!\n", __func__);
return ret;
}
- smu->current_power_limit = limit;
-
return 0;
}
@@ -1476,11 +1418,6 @@ int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu,
return 0;
}
-int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu)
-{
- return smu_cmn_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME, NULL);
-}
-
int smu_v11_0_baco_set_armd3_sequence(struct smu_context *smu,
enum smu_baco_seq baco_seq)
{
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
index 016a5c893fee..b38bc49c43dd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
@@ -58,6 +58,8 @@
#define SMUIO_GFX_MISC_CNTL__SMU_GFX_cold_vs_gfxoff_MASK 0x00000001L
#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK 0x00000006L
+static int vangogh_init_ppt_limits(struct smu_context *smu);
+
static const struct smu_feature_bits vangogh_dpm_features = {
.bits = {
SMU_FEATURE_BIT_INIT(FEATURE_CCLK_DPM_BIT),
@@ -72,6 +74,12 @@ static const struct smu_feature_bits vangogh_dpm_features = {
}
};
+/*
+ * SMU support new GFXOFF residency log interface since version 4.63.62.00,
+ * use this to get live readings of GFXOFF residency
+ */
+#define SUPPORT_LIVE_RESIDENCY_MSG_VERSION 0x043f3e00
+
static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0),
MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 0),
@@ -142,7 +150,9 @@ static struct cmn2asic_msg_mapping vangogh_message_map[SMU_MSG_MAX_COUNT] = {
MSG_MAP(GetSlowPPTLimit, PPSMC_MSG_GetSlowPPTLimit, 0),
MSG_MAP(GetGfxOffStatus, PPSMC_MSG_GetGfxOffStatus, 0),
MSG_MAP(GetGfxOffEntryCount, PPSMC_MSG_GetGfxOffEntryCount, 0),
- MSG_MAP(LogGfxOffResidency, PPSMC_MSG_LogGfxOffResidency, 0),
+ MSG_MAP(StartGfxOffResidencyLogging, PPSMC_MSG_StartGfxOffResidencyLogging, 0),
+ MSG_MAP(GfxOffResidencyLogReadSample, PPSMC_MSG_GfxOffResidencyLogReadSample, 0),
+ MSG_MAP(StopGfxOffResidencyLogging, PPSMC_MSG_StopGfxOffResidencyLogging, 0),
};
static struct cmn2asic_mapping vangogh_feature_mask_map[SMU_FEATURE_COUNT] = {
@@ -310,8 +320,7 @@ static int vangogh_get_legacy_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity / 100;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = (metrics->CurrentSocketPower << 8) /
- 1000 ;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
@@ -379,12 +388,10 @@ static int vangogh_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->Current.UvdActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = (metrics->Average.CurrentSocketPower << 8) /
- 1000;
+ *value = metrics->Average.CurrentSocketPower;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->Current.CurrentSocketPower << 8) /
- 1000;
+ *value = metrics->Current.CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->Current.GfxTemperature / 100 *
@@ -2238,6 +2245,10 @@ static int vangogh_post_smu_init(struct smu_context *smu)
if (adev->in_s0ix)
return 0;
+ ret = vangogh_init_ppt_limits(smu);
+ if (ret)
+ return ret;
+
/* allow message will be sent after enable message on Vangogh*/
if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) &&
(adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) {
@@ -2317,91 +2328,75 @@ static u32 vangogh_get_gfxoff_status(struct smu_context *smu)
return gfxoff_status;
}
-static int vangogh_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int vangogh_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
{
- struct smu_11_5_power_context *power_context = smu->smu_power.power_context;
- uint32_t ppt_limit;
- int ret = 0;
+ enum smu_message_type msg;
+ uint32_t raw_limit;
+ int ret;
if (smu->adev->pm.fw_version < 0x43f1e00)
- return ret;
+ return -EOPNOTSUPP;
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetSlowPPTLimit, &ppt_limit);
- if (ret) {
- dev_err(smu->adev->dev, "Get slow PPT limit failed!\n");
- return ret;
- }
- /* convert from milliwatt to watt */
- if (current_power_limit)
- *current_power_limit = ppt_limit / 1000;
- if (default_power_limit)
- *default_power_limit = ppt_limit / 1000;
- if (max_power_limit)
- *max_power_limit = 29;
- if (min_power_limit)
- *min_power_limit = 0;
-
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPPTLimit, &ppt_limit);
+ msg = limit_type == SMU_PPT_LIMIT_PPT1 ?
+ SMU_MSG_GetFastPPTLimit : SMU_MSG_GetSlowPPTLimit;
+ ret = smu_cmn_send_smc_msg(smu, msg, &raw_limit);
if (ret) {
- dev_err(smu->adev->dev, "Get fast PPT limit failed!\n");
+ dev_err(smu->adev->dev, "Get PPT%d limit failed!\n",
+ limit_type);
return ret;
}
- /* convert from milliwatt to watt */
- power_context->current_fast_ppt_limit =
- power_context->default_fast_ppt_limit = ppt_limit / 1000;
- power_context->max_fast_ppt_limit = 30;
- return ret;
+ *ppt_limit = raw_limit / 1000;
+
+ return 0;
}
-static int vangogh_get_ppt_limit(struct smu_context *smu,
- uint32_t *ppt_limit,
- enum smu_ppt_limit_type type,
- enum smu_ppt_limit_level level)
+static int vangogh_init_ppt_limits(struct smu_context *smu)
{
- struct smu_11_5_power_context *power_context = smu->smu_power.power_context;
+ struct smu_ppt_limit_range *range;
+ uint32_t default_limit;
+ int i, j, ret;
- if (!power_context)
- return -EOPNOTSUPP;
+ if (smu->adev->pm.fw_version < 0x43f1e00)
+ return 0;
- if (type == SMU_FAST_PPT_LIMIT) {
- switch (level) {
- case SMU_PPT_LIMIT_MAX:
- *ppt_limit = power_context->max_fast_ppt_limit;
- break;
- case SMU_PPT_LIMIT_CURRENT:
- *ppt_limit = power_context->current_fast_ppt_limit;
- break;
- case SMU_PPT_LIMIT_DEFAULT:
- *ppt_limit = power_context->default_fast_ppt_limit;
- break;
- default:
- break;
+ for (i = SMU_PPT_LIMIT_PPT0; i < SMU_LIMIT_TYPE_COUNT; i++) {
+ if (smu->ppt_limits.supported_mask & BIT(i))
+ continue;
+
+ ret = vangogh_get_ppt_limit(smu, i, &default_limit);
+ if (ret)
+ return ret;
+
+ for (j = SMU_POWER_SOURCE_AC; j < SMU_POWER_SOURCE_COUNT; j++) {
+ range = &smu->ppt_limits.range[j][i];
+ range->default_value = default_limit;
+ range->min = 0;
+ range->max = i == SMU_PPT_LIMIT_PPT1 ? 30 : 29;
+ range->od_min = range->min;
+ range->od_max = range->max;
}
+ smu->ppt_limits.supported_mask |= BIT(i);
}
return 0;
}
-static int vangogh_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t ppt_limit)
+static int vangogh_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t ppt_limit)
{
- struct smu_11_5_power_context *power_context =
- smu->smu_power.power_context;
int ret = 0;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
- dev_err(smu->adev->dev, "Setting new power limit is not supported!\n");
+ dev_err(smu->adev->dev, "Setting new PPT limit is not supported!\n");
return -EOPNOTSUPP;
}
switch (limit_type) {
- case SMU_DEFAULT_PPT_LIMIT:
+ case SMU_SLOW_PPT_LIMIT:
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetSlowPPTLimit,
ppt_limit * 1000, /* convert from watt to milliwatt */
@@ -2409,16 +2404,8 @@ static int vangogh_set_power_limit(struct smu_context *smu,
if (ret)
return ret;
- smu->current_power_limit = ppt_limit;
break;
case SMU_FAST_PPT_LIMIT:
- if (ppt_limit > power_context->max_fast_ppt_limit) {
- dev_err(smu->adev->dev,
- "New power limit (%d) is over the max allowed %d\n",
- ppt_limit, power_context->max_fast_ppt_limit);
- return ret;
- }
-
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_SetFastPPTLimit,
ppt_limit * 1000, /* convert from watt to milliwatt */
@@ -2426,7 +2413,6 @@ static int vangogh_set_power_limit(struct smu_context *smu,
if (ret)
return ret;
- power_context->current_fast_ppt_limit = ppt_limit;
break;
default:
return -EINVAL;
@@ -2449,19 +2435,32 @@ static int vangogh_set_power_limit(struct smu_context *smu,
static u32 vangogh_set_gfxoff_residency(struct smu_context *smu, bool start)
{
int ret = 0;
- u32 residency;
struct amdgpu_device *adev = smu->adev;
if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
return 0;
- ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_LogGfxOffResidency,
- start, &residency);
- if (ret)
- return ret;
+ if (smu->smc_fw_version < SUPPORT_LIVE_RESIDENCY_MSG_VERSION) {
+ u32 residency;
- if (!start)
- adev->gfx.gfx_off_residency = residency;
+ ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxOffResidencyLogReadSample,
+ start, &residency);
+ if (ret)
+ return ret;
+
+ if (!start)
+ adev->gfx.gfx_off_residency = residency;
+ } else {
+ if (start) {
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_StartGfxOffResidencyLogging, NULL);
+ if (ret)
+ return ret;
+ } else {
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_StopGfxOffResidencyLogging, NULL);
+ if (ret)
+ return ret;
+ }
+ }
return ret;
}
@@ -2478,11 +2477,20 @@ static u32 vangogh_set_gfxoff_residency(struct smu_context *smu, bool start)
*/
static u32 vangogh_get_gfxoff_residency(struct smu_context *smu, uint32_t *residency)
{
+ int ret = 0;
struct amdgpu_device *adev = smu->adev;
- *residency = adev->gfx.gfx_off_residency;
+ if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
+ return 0;
- return 0;
+ if (smu->smc_fw_version < SUPPORT_LIVE_RESIDENCY_MSG_VERSION) {
+ *residency = adev->gfx.gfx_off_residency;
+ } else {
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GfxOffResidencyLogReadSample,
+ residency);
+ }
+
+ return ret;
}
/**
@@ -2550,8 +2558,7 @@ static const struct pptable_funcs vangogh_ppt_funcs = {
.get_gfx_off_residency = vangogh_get_gfxoff_residency,
.set_gfx_off_residency = vangogh_set_gfxoff_residency,
.get_ppt_limit = vangogh_get_ppt_limit,
- .get_power_limit = vangogh_get_power_limit,
- .set_power_limit = vangogh_set_power_limit,
+ .set_ppt_limit = vangogh_set_ppt_limit,
.get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values,
};
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
index 75335da224c7..0ec17c1054c0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
@@ -1215,9 +1215,10 @@ static int renoir_get_smu_metrics_data(struct smu_context *smu,
((amdgpu_ip_version(adev, MP1_HWIP, 0) ==
IP_VERSION(12, 0, 0)) &&
(adev->pm.fw_version >= 0x373200)))
- *value = metrics->CurrentSocketPower << 8;
+ *value = metrics->CurrentSocketPower *
+ MILLIWATT_PER_WATT;
else
- *value = (metrics->CurrentSocketPower << 8) / 1000;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = (metrics->GfxTemperature / 100) *
@@ -1444,7 +1445,6 @@ static int renoir_get_enabled_mask(struct smu_context *smu,
}
static const struct pptable_funcs renoir_ppt_funcs = {
- .set_power_state = NULL,
.emit_clk_levels = renoir_emit_clk_levels,
.get_current_power_state = renoir_get_current_power_state,
.dpm_set_vcn_enable = renoir_dpm_set_vcn_enable,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
index 9d8b1227388f..1b1ffe19d002 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
@@ -61,6 +61,9 @@
[smu_feature] = {1, (aldebaran_feature)}
#define FEATURE_MASK(feature) (1ULL << feature)
+
+static int aldebaran_init_ppt_limits(struct smu_context *smu);
+
static const struct smu_feature_bits aldebaran_dpm_features = {
.bits = {
SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATIONS),
@@ -537,7 +540,7 @@ static int aldebaran_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
- return ret;
+ return aldebaran_init_ppt_limits(smu);
}
static bool aldebaran_is_primary(struct smu_context *smu)
@@ -677,7 +680,8 @@ static int aldebaran_get_smu_metrics_data(struct smu_context *smu,
case METRICS_AVERAGE_SOCKETPOWER:
/* Valid power data is available only from primary die */
if (aldebaran_is_primary(smu))
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower *
+ MILLIWATT_PER_WATT;
else
ret = -EOPNOTSUPP;
break;
@@ -1110,28 +1114,17 @@ static int aldebaran_read_sensor(struct smu_context *smu,
return ret;
}
-static int aldebaran_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int aldebaran_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
{
- PPTable_t *pptable = smu->smu_table.driver_pptable;
- uint32_t power_limit = 0;
int ret;
- if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
- if (current_power_limit)
- *current_power_limit = 0;
- if (default_power_limit)
- *default_power_limit = 0;
- if (max_power_limit)
- *max_power_limit = 0;
- if (min_power_limit)
- *min_power_limit = 0;
- dev_warn(smu->adev->dev,
- "PPT feature is not enabled, power values can't be fetched.");
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
+ if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
+ *ppt_limit = 0;
return 0;
}
@@ -1140,42 +1133,47 @@ static int aldebaran_get_power_limit(struct smu_context *smu,
*/
if (aldebaran_is_primary(smu)) {
ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit,
- &power_limit);
-
- if (ret) {
- /* the last hope to figure out the ppt limit */
- if (!pptable) {
- dev_err(smu->adev->dev,
- "Cannot get PPT limit due to pptable missing!");
- return -EINVAL;
- }
- power_limit = pptable->PptLimit;
- }
+ ppt_limit);
+ if (ret)
+ return ret;
+ } else {
+ *ppt_limit = 0;
}
- if (current_power_limit)
- *current_power_limit = power_limit;
- if (default_power_limit)
- *default_power_limit = power_limit;
+ return 0;
+}
+
+static int aldebaran_init_ppt_limits(struct smu_context *smu)
+{
+ PPTable_t *pptable = smu->smu_table.driver_pptable;
+ int i;
+
+ if (!pptable)
+ return -EINVAL;
- if (max_power_limit) {
- if (pptable)
- *max_power_limit = pptable->PptLimit;
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ pptable->PptLimit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min = 0;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max =
+ pptable->PptLimit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min = 0;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ pptable->PptLimit;
}
- if (min_power_limit)
- *min_power_limit = 0;
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
return 0;
}
-static int aldebaran_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+static int aldebaran_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
- /* Power limit can be set only through primary die */
+ /* PPT limit can be set only through primary die */
if (aldebaran_is_primary(smu))
- return smu_v13_0_set_power_limit(smu, limit_type, limit);
+ return smu_v13_0_set_ppt_limit(smu, limit_type, limit);
return -EINVAL;
}
@@ -1975,7 +1973,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = {
.force_clk_levels = aldebaran_force_clk_levels,
.read_sensor = aldebaran_read_sensor,
.set_performance_level = aldebaran_set_performance_level,
- .get_power_limit = aldebaran_get_power_limit,
+ .get_ppt_limit = aldebaran_get_ppt_limit,
.is_dpm_running = aldebaran_is_dpm_running,
.get_unique_id = aldebaran_get_unique_id,
.init_microcode = smu_v13_0_init_microcode,
@@ -1998,13 +1996,12 @@ static const struct pptable_funcs aldebaran_ppt_funcs = {
.get_enabled_mask = smu_cmn_get_enabled_mask,
.feature_is_enabled = smu_cmn_feature_is_enabled,
.disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception,
- .set_power_limit = aldebaran_set_power_limit,
+ .set_ppt_limit = aldebaran_set_ppt_limit,
.init_max_sustainable_clocks = smu_v13_0_init_max_sustainable_clocks,
.enable_thermal_alert = smu_v13_0_enable_thermal_alert,
.disable_thermal_alert = smu_v13_0_disable_thermal_alert,
.set_xgmi_pstate = smu_v13_0_set_xgmi_pstate,
.register_irq_handler = smu_v13_0_register_irq_handler,
- .set_azalia_d3_pme = smu_v13_0_set_azalia_d3_pme,
.get_max_sustainable_clocks_by_dc = smu_v13_0_get_max_sustainable_clocks_by_dc,
.get_bamaco_support = aldebaran_get_bamaco_support,
.get_dpm_ultimate_freq = aldebaran_get_dpm_ultimate_freq,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
index be9a7a32de99..c4b2fe60da62 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
@@ -218,7 +218,7 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu)
if (!pptable_id)
return 0;
- ret = smu_v13_0_get_pptable_from_firmware(smu, &table, &size, pptable_id);
+ ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id);
if (ret)
return ret;
@@ -258,48 +258,6 @@ int smu_v13_0_check_fw_status(struct smu_context *smu)
return -EIO;
}
-static int smu_v13_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t ppt_offset_bytes;
- const struct smc_firmware_header_v2_0 *v2;
-
- v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data;
-
- ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes);
- *size = le32_to_cpu(v2->ppt_size_bytes);
- *table = (uint8_t *)v2 + ppt_offset_bytes;
-
- return 0;
-}
-
-static int smu_v13_0_set_pptable_v2_1(struct smu_context *smu, void **table,
- uint32_t *size, uint32_t pptable_id)
-{
- struct amdgpu_device *adev = smu->adev;
- const struct smc_firmware_header_v2_1 *v2_1;
- struct smc_soft_pptable_entry *entries;
- uint32_t pptable_count = 0;
- int i = 0;
-
- v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data;
- entries = (struct smc_soft_pptable_entry *)
- ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset));
- pptable_count = le32_to_cpu(v2_1->pptable_count);
- for (i = 0; i < pptable_count; i++) {
- if (le32_to_cpu(entries[i].id) == pptable_id) {
- *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes));
- *size = le32_to_cpu(entries[i].ppt_size_bytes);
- break;
- }
- }
-
- if (i == pptable_count)
- return -EINVAL;
-
- return 0;
-}
-
static int smu_v13_0_get_pptable_from_vbios(struct smu_context *smu, void **table, uint32_t *size)
{
struct amdgpu_device *adev = smu->adev;
@@ -322,45 +280,6 @@ static int smu_v13_0_get_pptable_from_vbios(struct smu_context *smu, void **tabl
return 0;
}
-int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu,
- void **table,
- uint32_t *size,
- uint32_t pptable_id)
-{
- const struct smc_firmware_header_v1_0 *hdr;
- struct amdgpu_device *adev = smu->adev;
- uint16_t version_major, version_minor;
- int ret;
-
- hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
- if (!hdr)
- return -EINVAL;
-
- dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id);
-
- version_major = le16_to_cpu(hdr->header.header_version_major);
- version_minor = le16_to_cpu(hdr->header.header_version_minor);
- if (version_major != 2) {
- dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n",
- version_major, version_minor);
- return -EINVAL;
- }
-
- switch (version_minor) {
- case 0:
- ret = smu_v13_0_set_pptable_v2_0(smu, table, size);
- break;
- case 1:
- ret = smu_v13_0_set_pptable_v2_1(smu, table, size, pptable_id);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
int smu_v13_0_setup_pptable(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -380,7 +299,7 @@ int smu_v13_0_setup_pptable(struct smu_context *smu)
if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1))
ret = smu_v13_0_get_pptable_from_vbios(smu, &table, &size);
else
- ret = smu_v13_0_get_pptable_from_firmware(smu, &table, &size, pptable_id);
+ ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id);
if (ret)
return ret;
@@ -896,14 +815,17 @@ int smu_v13_0_init_max_sustainable_clocks(struct smu_context *smu)
return 0;
}
-int smu_v13_0_get_current_power_limit(struct smu_context *smu,
- uint32_t *power_limit)
+int smu_v13_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
{
int power_src;
int ret = 0;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT))
return -EINVAL;
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
power_src = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_PWR,
@@ -916,35 +838,33 @@ int smu_v13_0_get_current_power_limit(struct smu_context *smu,
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_GetPptLimit,
power_src << 16,
- power_limit);
+ ppt_limit);
if (ret)
dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
return ret;
}
-int smu_v13_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+int smu_v13_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
int ret = 0;
- if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
return -EINVAL;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
- dev_err(smu->adev->dev, "Setting new power limit is not supported!\n");
+ dev_err(smu->adev->dev, "Setting new PPT limit is not supported!\n");
return -EOPNOTSUPP;
}
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit, NULL);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__);
+ dev_err(smu->adev->dev, "[%s] Set PPT limit failed!\n", __func__);
return ret;
}
- smu->current_power_limit = limit;
-
return 0;
}
@@ -1401,15 +1321,6 @@ int smu_v13_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu,
return 0;
}
-int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu)
-{
- int ret = 0;
-
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME, NULL);
-
- return ret;
-}
-
static int smu_v13_0_wait_for_reset_complete(struct smu_context *smu,
uint64_t event_arg)
{
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index acbd7046d8a5..6e741ec4a71e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -62,6 +62,7 @@
static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
int od_feature_bit,
int32_t *min, int32_t *max);
+static int smu_v13_0_0_init_ppt_limits(struct smu_context *smu);
static const struct smu_feature_bits smu_v13_0_0_dpm_features = {
.bits = {
@@ -467,7 +468,7 @@ static int smu_v13_0_0_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
- return ret;
+ return smu_v13_0_0_init_ppt_limits(smu);
}
static int smu_v13_0_0_tables_init(struct smu_context *smu)
@@ -807,7 +808,7 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->AvgTemperature[TEMP_EDGE] *
@@ -2389,58 +2390,71 @@ static int smu_v13_0_0_enable_mgpu_fan_boost(struct smu_context *smu)
NULL);
}
-static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int smu_v13_0_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
+{
+ OverDriveTableExternal_t od_table;
+ int ret;
+
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
+
+ ret = smu_v13_0_get_ppt_limit(smu, limit_type, ppt_limit);
+ if (ret)
+ return ret;
+
+ ret = smu_v13_0_0_get_overdrive_table(smu, &od_table);
+ if (ret)
+ return ret;
+
+ if (od_table.OverDriveTable.Ppt > 0)
+ *ppt_limit = *ppt_limit *
+ (100 + od_table.OverDriveTable.Ppt) / 100;
+
+ return 0;
+}
+
+static int smu_v13_0_0_init_ppt_limits(struct smu_context *smu)
{
struct smu_table_context *table_context = &smu->smu_table;
struct smu_13_0_0_powerplay_table *powerplay_table =
(struct smu_13_0_0_powerplay_table *)table_context->power_play_table;
PPTable_t *pptable = table_context->driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- uint32_t pp_limit = smu->adev->pm.ac_power ?
- skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
- skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
- uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
- uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit);
- uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit);
uint32_t od_percent_upper = 0, od_percent_lower = 0;
- int ret;
-
- if (current_power_limit) {
- ret = smu_v13_0_get_current_power_limit(smu, current_power_limit);
- if (ret)
- *current_power_limit = pp_limit;
- }
+ uint32_t pp_limit, msg_limit, min_limit, max_limit;
+ int i;
- if (default_power_limit)
- *default_power_limit = pp_limit;
-
- if (powerplay_table) {
- if (smu->od_enabled &&
- smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
- od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
- od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
- } else if (smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
- od_percent_upper = 0;
- od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
- }
+ if (powerplay_table &&
+ smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
+ od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[
+ SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
+ od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[
+ SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
}
- dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, pp_limit);
-
- if (max_power_limit) {
- *max_power_limit = max_limit * (100 + od_percent_upper);
- *max_power_limit /= 100;
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ pp_limit = i == SMU_POWER_SOURCE_AC ?
+ skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
+ skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][i];
+ min_limit = min(pp_limit, msg_limit);
+ max_limit = max(pp_limit, msg_limit);
+
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ pp_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max =
+ max_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min =
+ min_limit * (100 - od_percent_lower) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ max_limit * (100 + od_percent_upper) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min =
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min;
}
- if (min_power_limit) {
- *min_power_limit = min_limit * (100 - od_percent_lower);
- *min_power_limit /= 100;
- }
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
return 0;
}
@@ -2619,9 +2633,10 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
return -ENOMEM;
}
if (custom_params && custom_params_max_idx) {
- if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT)
- return -EINVAL;
- if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)
+ if (!smu_cmn_custom_params_count_valid(custom_params_max_idx,
+ SMU_13_0_0_CUSTOM_PARAMS_COUNT) ||
+ !smu_cmn_custom_params_clock_valid(custom_params[0],
+ SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT))
return -EINVAL;
idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT;
smu->custom_profile_params[idx] = 1;
@@ -3030,23 +3045,29 @@ static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu)
}
}
-static int smu_v13_0_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+static int smu_v13_0_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
PPTable_t *pptable = smu->smu_table.driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+ uint32_t msg_limit = skutable->MsgLimits.Power
+ [PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)table_context->overdrive_table;
+ OverDriveTableExternal_t current_od_table;
int ret = 0;
- if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
return -EINVAL;
if (limit <= msg_limit) {
- if (smu->current_power_limit > msg_limit) {
+ ret = smu_v13_0_0_get_overdrive_table(smu, &current_od_table);
+ if (ret)
+ return ret;
+
+ if (current_od_table.OverDriveTable.Ppt) {
od_table->OverDriveTable.Ppt = 0;
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
@@ -3056,9 +3077,9 @@ static int smu_v13_0_0_set_power_limit(struct smu_context *smu,
return ret;
}
}
- return smu_v13_0_set_power_limit(smu, limit_type, limit);
+ return smu_v13_0_set_ppt_limit(smu, limit_type, limit);
} else if (smu->od_enabled) {
- ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit);
+ ret = smu_v13_0_set_ppt_limit(smu, limit_type, msg_limit);
if (ret)
return ret;
@@ -3071,7 +3092,6 @@ static int smu_v13_0_0_set_power_limit(struct smu_context *smu,
return ret;
}
- smu->current_power_limit = limit;
} else {
return -EINVAL;
}
@@ -3214,8 +3234,8 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
.get_fan_control_mode = smu_v13_0_get_fan_control_mode,
.set_fan_control_mode = smu_v13_0_set_fan_control_mode,
.enable_mgpu_fan_boost = smu_v13_0_0_enable_mgpu_fan_boost,
- .get_power_limit = smu_v13_0_0_get_power_limit,
- .set_power_limit = smu_v13_0_0_set_power_limit,
+ .get_ppt_limit = smu_v13_0_0_get_ppt_limit,
+ .set_ppt_limit = smu_v13_0_0_set_ppt_limit,
.set_power_source = smu_v13_0_set_power_source,
.get_power_profile_mode = smu_v13_0_0_get_power_profile_mode,
.set_power_profile_mode = smu_v13_0_0_set_power_profile_mode,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
index fe929bd89058..0033453f27e5 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
@@ -434,22 +434,19 @@ int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu,
*value = SMUQ10_ROUND(metrics->DramBandwidthUtilization);
break;
case METRICS_CURR_SOCKETPOWER:
- *value = SMUQ10_ROUND(metrics->SocketPower) << 8;
+ *value = SMUQ10_TO_MILLIWATT(metrics->SocketPower);
break;
case METRICS_TEMPERATURE_HOTSPOT:
- *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxSocketTemperature);
break;
case METRICS_TEMPERATURE_MEM:
- *value = SMUQ10_ROUND(metrics->MaxHbmTemperature) *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxHbmTemperature);
break;
/* This is the max of all VRs and not just SOC VR.
* No need to define another data type for the same.
*/
case METRICS_TEMPERATURE_VRSOC:
- *value = SMUQ10_ROUND(metrics->MaxVrTemperature) *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxVrTemperature);
break;
default:
*value = UINT_MAX;
@@ -1017,139 +1014,3 @@ const struct smu_temp_funcs smu_v13_0_12_temp_funcs = {
.temp_metrics_is_supported = smu_v13_0_12_is_temp_metrics_supported,
.get_temp_metrics = smu_v13_0_12_get_temp_metrics,
};
-
-static int smu_v13_0_12_get_ras_table_version(struct amdgpu_device *adev,
- uint32_t *table_version)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
-
- return smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetRASTableVersion, 0, table_version);
-}
-
-static int smu_v13_0_12_get_badpage_count(struct amdgpu_device *adev, uint32_t *count,
- uint32_t timeout)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- uint64_t end, now;
- int ret = 0;
-
- now = (uint64_t)ktime_to_ms(ktime_get());
- end = now + timeout;
- do {
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetBadPageCount, 0, count);
- /* eeprom is not ready */
- if (ret != -EBUSY)
- return ret;
- mdelay(10);
- now = (uint64_t)ktime_to_ms(ktime_get());
- } while (now < end);
-
- dev_err(adev->dev,
- "smu get bad page count timeout!\n");
- return ret;
-}
-
-static int smu_v13_0_12_set_timestamp(struct amdgpu_device *adev, uint64_t timestamp)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
-
- return smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_SetTimestamp, (uint32_t)timestamp, 0);
-}
-
-static int smu_v13_0_12_get_timestamp(struct amdgpu_device *adev,
- uint16_t index, uint64_t *timestamp)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- uint32_t temp;
- int ret;
-
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetTimestamp, index, &temp);
- if (!ret)
- *timestamp = temp;
-
- return ret;
-}
-
-static int smu_v13_0_12_get_badpage_ipid(struct amdgpu_device *adev,
- uint16_t index, uint64_t *ipid)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- uint32_t temp_arg, temp_ipid_lo, temp_ipid_high;
- int ret;
-
- temp_arg = index | (1 << 16);
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetBadPageIpid, temp_arg, &temp_ipid_lo);
- if (ret)
- return ret;
-
- temp_arg = index | (2 << 16);
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetBadPageIpid, temp_arg, &temp_ipid_high);
- if (!ret)
- *ipid = (uint64_t)temp_ipid_high << 32 | temp_ipid_lo;
- return ret;
-}
-
-static int smu_v13_0_12_erase_ras_table(struct amdgpu_device *adev,
- uint32_t *result)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
-
- return smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_EraseRasTable, 0, result);
-}
-
-static int smu_v13_0_12_get_badpage_mca_addr(struct amdgpu_device *adev,
- uint16_t index, uint64_t *mca_addr)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- uint32_t temp_arg, temp_addr_lo, temp_addr_high;
- int ret;
-
- temp_arg = index | (1 << 16);
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetBadPageMcaAddr, temp_arg, &temp_addr_lo);
- if (ret)
- return ret;
-
- temp_arg = index | (2 << 16);
- ret = smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_GetBadPageMcaAddr, temp_arg, &temp_addr_high);
- if (!ret)
- *mca_addr = (uint64_t)temp_addr_high << 32 | temp_addr_lo;
- return ret;
-}
-
-static const struct ras_eeprom_smu_funcs smu_v13_0_12_eeprom_smu_funcs = {
- .get_ras_table_version = smu_v13_0_12_get_ras_table_version,
- .get_badpage_count = smu_v13_0_12_get_badpage_count,
- .get_badpage_mca_addr = smu_v13_0_12_get_badpage_mca_addr,
- .set_timestamp = smu_v13_0_12_set_timestamp,
- .get_timestamp = smu_v13_0_12_get_timestamp,
- .get_badpage_ipid = smu_v13_0_12_get_badpage_ipid,
- .erase_ras_table = smu_v13_0_12_erase_ras_table,
-};
-
-static void smu_v13_0_12_ras_smu_feature_flags(struct amdgpu_device *adev, uint64_t *flags)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
-
- if (!flags)
- return;
-
- *flags = 0ULL;
-
- if (smu_v13_0_6_cap_supported(smu, SMU_CAP(RAS_EEPROM)))
- *flags |= RAS_SMU_FEATURE_BIT__RAS_EEPROM;
-
-}
-
-const struct ras_smu_drv smu_v13_0_12_ras_smu_drv = {
- .smu_eeprom_funcs = &smu_v13_0_12_eeprom_smu_funcs,
- .ras_smu_feature_flags = smu_v13_0_12_ras_smu_feature_flags,
-};
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
index ba91bf590eed..a9d558f5b739 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
@@ -338,10 +338,10 @@ static int smu_v13_0_4_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity / 100;
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = (metrics->AverageSocketPower << 8) / 1000;
+ *value = metrics->AverageSocketPower;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->CurrentSocketPower << 8) / 1000;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
index 27372a60e83d..f95b15af436d 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
@@ -295,7 +295,7 @@ static int smu_v13_0_5_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity / 100;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->CurrentSocketPower << 8) / 1000;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
index b12388134489..84c02e6d9673 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
@@ -44,8 +44,6 @@
#include "amdgpu_xgmi.h"
#include <linux/pci.h>
#include "amdgpu_ras.h"
-#include "amdgpu_mca.h"
-#include "amdgpu_aca.h"
#include "smu_cmn.h"
#include "mp/mp_13_0_6_offset.h"
#include "mp/mp_13_0_6_sh_mask.h"
@@ -76,6 +74,9 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_14.bin");
[smu_feature] = { 1, (smu_13_0_6_feature) }
#define FEATURE_MASK(feature) (1ULL << feature)
+
+static int smu_v13_0_6_init_ppt_limits(struct smu_context *smu);
+
static const struct smu_feature_bits smu_v13_0_6_dpm_features = {
.bits = {
SMU_FEATURE_BIT_INIT(FEATURE_DATA_CALCULATION),
@@ -99,25 +100,6 @@ static const struct smu_feature_bits smu_v13_0_6_dpm_features = {
#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xE0
#define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0x5
#define LINK_SPEED_MAX 4
-#define MCA_BANK_IPID(_ip, _hwid, _type) \
- [AMDGPU_MCA_IP_##_ip] = { .hwid = _hwid, .mcatype = _type, }
-
-struct mca_bank_ipid {
- enum amdgpu_mca_ip ip;
- uint16_t hwid;
- uint16_t mcatype;
-};
-
-struct mca_ras_info {
- enum amdgpu_ras_block blkid;
- enum amdgpu_mca_ip ip;
- int *err_code_array;
- int err_code_count;
- int (*get_err_count)(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count);
- bool (*bank_is_valid)(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry);
-};
#define P2S_TABLE_ID_A 0x50325341
#define P2S_TABLE_ID_X 0x50325358
@@ -1171,7 +1153,7 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu)
}
}
- return 0;
+ return smu_v13_0_6_init_ppt_limits(smu);
}
static int smu_v13_0_6_setup_pptable(struct smu_context *smu)
@@ -1321,22 +1303,19 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu,
*value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, version));
break;
case METRICS_CURR_SOCKETPOWER:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, version)) << 8;
+ *value = SMUQ10_TO_MILLIWATT(GET_METRIC_FIELD(SocketPower, version));
break;
case METRICS_TEMPERATURE_HOTSPOT:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, version)) *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(GET_METRIC_FIELD(MaxSocketTemperature, version));
break;
case METRICS_TEMPERATURE_MEM:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, version)) *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(GET_METRIC_FIELD(MaxHbmTemperature, version));
break;
/* This is the max of all VRs and not just SOC VR.
* No need to define another data type for the same.
*/
case METRICS_TEMPERATURE_VRSOC:
- *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, version)) *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(GET_METRIC_FIELD(MaxVrTemperature, version));
break;
default:
*value = UINT_MAX;
@@ -1719,54 +1698,82 @@ static int smu_v13_0_6_read_sensor(struct smu_context *smu,
return ret;
}
-static int smu_v13_0_6_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int smu_v13_0_6_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
{
- struct smu_table_context *smu_table = &smu->smu_table;
- struct PPTable_t *pptable =
- (struct PPTable_t *)smu_table->driver_pptable;
- uint32_t power_limit = 0;
int ret;
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit, &power_limit);
-
+ if (limit_type == SMU_PPT_LIMIT_PPT1) {
+ if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)))
+ return -EOPNOTSUPP;
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit,
+ ppt_limit);
+ } else {
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit,
+ ppt_limit);
+ }
if (ret) {
dev_err(smu->adev->dev, "Couldn't get PPT limit");
return -EINVAL;
}
- if (current_power_limit)
- *current_power_limit = power_limit;
- if (default_power_limit)
- *default_power_limit = pptable->MaxSocketPowerLimit;
+ return 0;
+}
+
+static int smu_v13_0_6_init_ppt_limits(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ struct PPTable_t *pptable =
+ (struct PPTable_t *)smu_table->driver_pptable;
+ int i;
- if (max_power_limit) {
- *max_power_limit = pptable->MaxSocketPowerLimit;
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ pptable->MaxSocketPowerLimit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max =
+ pptable->MaxSocketPowerLimit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min = 0;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ pptable->MaxSocketPowerLimit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min = 0;
+ }
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
+
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT))) {
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].default_value =
+ pptable->PPT1Default;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].max =
+ pptable->PPT1Max;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].min =
+ pptable->PPT1Min;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].od_max =
+ pptable->PPT1Max;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].od_min =
+ pptable->PPT1Min;
+ }
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT1);
}
- if (min_power_limit)
- *min_power_limit = 0;
return 0;
}
-static int smu_v13_0_6_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+static int smu_v13_0_6_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct PPTable_t *pptable =
(struct PPTable_t *)smu_table->driver_pptable;
int ret;
- if (limit_type == SMU_FAST_PPT_LIMIT) {
+ if (limit_type == SMU_PPT_LIMIT_PPT1) {
if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)))
return -EOPNOTSUPP;
if (limit > pptable->PPT1Max || limit < pptable->PPT1Min) {
dev_err(smu->adev->dev,
- "New power limit (%d) should be between min %d max %d\n",
+ "New PPT limit (%d) should be between min %d max %d\n",
limit, pptable->PPT1Min, pptable->PPT1Max);
return -EINVAL;
}
@@ -1777,43 +1784,7 @@ static int smu_v13_0_6_set_power_limit(struct smu_context *smu,
return ret;
}
- return smu_v13_0_set_power_limit(smu, limit_type, limit);
-}
-
-static int smu_v13_0_6_get_ppt_limit(struct smu_context *smu,
- uint32_t *ppt_limit,
- enum smu_ppt_limit_type type,
- enum smu_ppt_limit_level level)
-{
- struct smu_table_context *smu_table = &smu->smu_table;
- struct PPTable_t *pptable =
- (struct PPTable_t *)smu_table->driver_pptable;
- int ret = 0;
-
- if (type == SMU_FAST_PPT_LIMIT) {
- if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(FAST_PPT)))
- return -EOPNOTSUPP;
- switch (level) {
- case SMU_PPT_LIMIT_MAX:
- *ppt_limit = pptable->PPT1Max;
- break;
- case SMU_PPT_LIMIT_CURRENT:
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit, ppt_limit);
- if (ret)
- dev_err(smu->adev->dev, "Get fast PPT limit failed!\n");
- break;
- case SMU_PPT_LIMIT_DEFAULT:
- *ppt_limit = pptable->PPT1Default;
- break;
- case SMU_PPT_LIMIT_MIN:
- *ppt_limit = pptable->PPT1Min;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return ret;
- }
- return -EOPNOTSUPP;
+ return smu_v13_0_set_ppt_limit(smu, limit_type, limit);
}
static int smu_v13_0_6_irq_process(struct amdgpu_device *adev,
@@ -1943,17 +1914,6 @@ static int smu_v13_0_6_notify_unload(struct smu_context *smu)
return 0;
}
-static int smu_v13_0_6_mca_set_debug_mode(struct smu_context *smu, bool enable)
-{
- /* NOTE: this ClearMcaOnRead message is only supported for smu version 85.72.0 or higher */
- if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(MCA_DEBUG_MODE)))
- return 0;
-
- return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ClearMcaOnRead,
- enable ? 0 : ClearMcaOnRead_UE_FLAG_MASK | ClearMcaOnRead_CE_POLL_MASK,
- NULL);
-}
-
static int smu_v13_0_6_system_features_control(struct smu_context *smu,
bool enable)
{
@@ -3299,651 +3259,12 @@ static int smu_v13_0_6_post_init(struct smu_context *smu)
return 0;
}
-static int mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
-
- return smu_v13_0_6_mca_set_debug_mode(smu, enable);
-}
-
-static int smu_v13_0_6_get_valid_mca_count(struct smu_context *smu, enum amdgpu_mca_error_type type, uint32_t *count)
-{
- uint32_t msg;
- int ret;
-
- if (!count)
- return -EINVAL;
-
- switch (type) {
- case AMDGPU_MCA_ERROR_TYPE_UE:
- msg = SMU_MSG_QueryValidMcaCount;
- break;
- case AMDGPU_MCA_ERROR_TYPE_CE:
- msg = SMU_MSG_QueryValidMcaCeCount;
- break;
- default:
- return -EINVAL;
- }
-
- ret = smu_cmn_send_smc_msg(smu, msg, count);
- if (ret) {
- *count = 0;
- return ret;
- }
-
- return 0;
-}
-
-static int __smu_v13_0_6_mca_dump_bank(struct smu_context *smu, enum amdgpu_mca_error_type type,
- int idx, int offset, uint32_t *val)
-{
- uint32_t msg, param;
-
- switch (type) {
- case AMDGPU_MCA_ERROR_TYPE_UE:
- msg = SMU_MSG_McaBankDumpDW;
- break;
- case AMDGPU_MCA_ERROR_TYPE_CE:
- msg = SMU_MSG_McaBankCeDumpDW;
- break;
- default:
- return -EINVAL;
- }
-
- param = ((idx & 0xffff) << 16) | (offset & 0xfffc);
-
- return smu_cmn_send_smc_msg_with_param(smu, msg, param, val);
-}
-
-static int smu_v13_0_6_mca_dump_bank(struct smu_context *smu, enum amdgpu_mca_error_type type,
- int idx, int offset, uint32_t *val, int count)
-{
- int ret, i;
-
- if (!val)
- return -EINVAL;
-
- for (i = 0; i < count; i++) {
- ret = __smu_v13_0_6_mca_dump_bank(smu, type, idx, offset + (i << 2), &val[i]);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static const struct mca_bank_ipid smu_v13_0_6_mca_ipid_table[AMDGPU_MCA_IP_COUNT] = {
- MCA_BANK_IPID(UMC, 0x96, 0x0),
- MCA_BANK_IPID(SMU, 0x01, 0x1),
- MCA_BANK_IPID(MP5, 0x01, 0x2),
- MCA_BANK_IPID(PCS_XGMI, 0x50, 0x0),
-};
-
-static void mca_bank_entry_info_decode(struct mca_bank_entry *entry, struct mca_bank_info *info)
-{
- u64 ipid = entry->regs[MCA_REG_IDX_IPID];
- u32 instidhi, instid;
-
- /* NOTE: All MCA IPID register share the same format,
- * so the driver can share the MCMP1 register header file.
- * */
-
- info->hwid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, HardwareID);
- info->mcatype = REG_GET_FIELD(ipid, MCMP1_IPIDT0, McaType);
-
- /*
- * Unfied DieID Format: SAASS. A:AID, S:Socket.
- * Unfied DieID[4] = InstanceId[0]
- * Unfied DieID[0:3] = InstanceIdHi[0:3]
- */
- instidhi = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdHi);
- instid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdLo);
- info->aid = ((instidhi >> 2) & 0x03);
- info->socket_id = ((instid & 0x1) << 2) | (instidhi & 0x03);
-}
-
-static int mca_bank_read_reg(struct amdgpu_device *adev, enum amdgpu_mca_error_type type,
- int idx, int reg_idx, uint64_t *val)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- uint32_t data[2] = {0, 0};
- int ret;
-
- if (!val || reg_idx >= MCA_REG_IDX_COUNT)
- return -EINVAL;
-
- ret = smu_v13_0_6_mca_dump_bank(smu, type, idx, reg_idx * 8, data, ARRAY_SIZE(data));
- if (ret)
- return ret;
-
- *val = (uint64_t)data[1] << 32 | data[0];
-
- dev_dbg(adev->dev, "mca read bank reg: type:%s, index: %d, reg_idx: %d, val: 0x%016llx\n",
- type == AMDGPU_MCA_ERROR_TYPE_UE ? "UE" : "CE", idx, reg_idx, *val);
-
- return 0;
-}
-
-static int mca_get_mca_entry(struct amdgpu_device *adev, enum amdgpu_mca_error_type type,
- int idx, struct mca_bank_entry *entry)
-{
- int i, ret;
-
- /* NOTE: populated all mca register by default */
- for (i = 0; i < ARRAY_SIZE(entry->regs); i++) {
- ret = mca_bank_read_reg(adev, type, idx, i, &entry->regs[i]);
- if (ret)
- return ret;
- }
-
- entry->idx = idx;
- entry->type = type;
-
- mca_bank_entry_info_decode(entry, &entry->info);
-
- return 0;
-}
-
-static int mca_decode_ipid_to_hwip(uint64_t val)
-{
- const struct mca_bank_ipid *ipid;
- uint16_t hwid, mcatype;
- int i;
-
- hwid = REG_GET_FIELD(val, MCMP1_IPIDT0, HardwareID);
- mcatype = REG_GET_FIELD(val, MCMP1_IPIDT0, McaType);
-
- for (i = 0; i < ARRAY_SIZE(smu_v13_0_6_mca_ipid_table); i++) {
- ipid = &smu_v13_0_6_mca_ipid_table[i];
-
- if (!ipid->hwid)
- continue;
-
- if (ipid->hwid == hwid && ipid->mcatype == mcatype)
- return i;
- }
-
- return AMDGPU_MCA_IP_UNKNOW;
-}
-
-static int mca_umc_mca_get_err_count(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count)
-{
- uint64_t status0;
- uint32_t ext_error_code;
- uint32_t odecc_err_cnt;
-
- status0 = entry->regs[MCA_REG_IDX_STATUS];
- ext_error_code = MCA_REG__STATUS__ERRORCODEEXT(status0);
- odecc_err_cnt = MCA_REG__MISC0__ERRCNT(entry->regs[MCA_REG_IDX_MISC0]);
-
- if (!REG_GET_FIELD(status0, MCMP1_STATUST0, Val)) {
- *count = 0;
- return 0;
- }
-
- if (umc_v12_0_is_deferred_error(adev, status0) ||
- umc_v12_0_is_uncorrectable_error(adev, status0) ||
- umc_v12_0_is_correctable_error(adev, status0))
- *count = (ext_error_code == 0) ? odecc_err_cnt : 1;
-
- amdgpu_umc_update_ecc_status(adev,
- entry->regs[MCA_REG_IDX_STATUS],
- entry->regs[MCA_REG_IDX_IPID],
- entry->regs[MCA_REG_IDX_ADDR]);
-
- return 0;
-}
-
-static int mca_pcs_xgmi_mca_get_err_count(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry,
- uint32_t *count)
-{
- u32 ext_error_code;
- u32 err_cnt;
-
- ext_error_code = MCA_REG__STATUS__ERRORCODEEXT(entry->regs[MCA_REG_IDX_STATUS]);
- err_cnt = MCA_REG__MISC0__ERRCNT(entry->regs[MCA_REG_IDX_MISC0]);
-
- if (type == AMDGPU_MCA_ERROR_TYPE_UE &&
- (ext_error_code == 0 || ext_error_code == 9))
- *count = err_cnt;
- else if (type == AMDGPU_MCA_ERROR_TYPE_CE && ext_error_code == 6)
- *count = err_cnt;
-
- return 0;
-}
-
-static bool mca_smu_check_error_code(struct amdgpu_device *adev, const struct mca_ras_info *mca_ras,
- uint32_t errcode)
-{
- int i;
-
- if (!mca_ras->err_code_count || !mca_ras->err_code_array)
- return true;
-
- for (i = 0; i < mca_ras->err_code_count; i++) {
- if (errcode == mca_ras->err_code_array[i])
- return true;
- }
-
- return false;
-}
-
-static int mca_gfx_mca_get_err_count(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count)
-{
- uint64_t status0, misc0;
-
- status0 = entry->regs[MCA_REG_IDX_STATUS];
- if (!REG_GET_FIELD(status0, MCMP1_STATUST0, Val)) {
- *count = 0;
- return 0;
- }
-
- if (type == AMDGPU_MCA_ERROR_TYPE_UE &&
- REG_GET_FIELD(status0, MCMP1_STATUST0, UC) == 1 &&
- REG_GET_FIELD(status0, MCMP1_STATUST0, PCC) == 1) {
- *count = 1;
- return 0;
- } else {
- misc0 = entry->regs[MCA_REG_IDX_MISC0];
- *count = REG_GET_FIELD(misc0, MCMP1_MISC0T0, ErrCnt);
- }
-
- return 0;
-}
-
-static int mca_smu_mca_get_err_count(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count)
-{
- uint64_t status0, misc0;
-
- status0 = entry->regs[MCA_REG_IDX_STATUS];
- if (!REG_GET_FIELD(status0, MCMP1_STATUST0, Val)) {
- *count = 0;
- return 0;
- }
-
- if (type == AMDGPU_MCA_ERROR_TYPE_UE &&
- REG_GET_FIELD(status0, MCMP1_STATUST0, UC) == 1 &&
- REG_GET_FIELD(status0, MCMP1_STATUST0, PCC) == 1) {
- if (count)
- *count = 1;
- return 0;
- }
-
- misc0 = entry->regs[MCA_REG_IDX_MISC0];
- *count = REG_GET_FIELD(misc0, MCMP1_MISC0T0, ErrCnt);
-
- return 0;
-}
-
-static bool mca_gfx_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry)
-{
- uint32_t instlo;
-
- instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo);
- instlo &= GENMASK(31, 1);
- switch (instlo) {
- case 0x36430400: /* SMNAID XCD 0 */
- case 0x38430400: /* SMNAID XCD 1 */
- case 0x40430400: /* SMNXCD XCD 0, NOTE: FIXME: fix this error later */
- return true;
- default:
- return false;
- }
-
- return false;
-};
-
-static bool mca_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- uint32_t errcode, instlo;
-
- instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo);
- instlo &= GENMASK(31, 1);
- if (instlo != 0x03b30400)
- return false;
-
- if (smu_v13_0_6_cap_supported(smu, SMU_CAP(ACA_SYND))) {
- errcode = MCA_REG__SYND__ERRORINFORMATION(entry->regs[MCA_REG_IDX_SYND]);
- errcode &= 0xff;
- } else {
- errcode = REG_GET_FIELD(entry->regs[MCA_REG_IDX_STATUS], MCMP1_STATUST0, ErrorCode);
- }
-
- return mca_smu_check_error_code(adev, mca_ras, errcode);
-}
-
-static int sdma_err_codes[] = { CODE_SDMA0, CODE_SDMA1, CODE_SDMA2, CODE_SDMA3 };
-static int mmhub_err_codes[] = {
- CODE_DAGB0, CODE_DAGB0 + 1, CODE_DAGB0 + 2, CODE_DAGB0 + 3, CODE_DAGB0 + 4, /* DAGB0-4 */
- CODE_EA0, CODE_EA0 + 1, CODE_EA0 + 2, CODE_EA0 + 3, CODE_EA0 + 4, /* MMEA0-4*/
- CODE_VML2, CODE_VML2_WALKER, CODE_MMCANE,
-};
-
-static int vcn_err_codes[] = {
- CODE_VIDD, CODE_VIDV,
-};
-static int jpeg_err_codes[] = {
- CODE_JPEG0S, CODE_JPEG0D, CODE_JPEG1S, CODE_JPEG1D,
- CODE_JPEG2S, CODE_JPEG2D, CODE_JPEG3S, CODE_JPEG3D,
- CODE_JPEG4S, CODE_JPEG4D, CODE_JPEG5S, CODE_JPEG5D,
- CODE_JPEG6S, CODE_JPEG6D, CODE_JPEG7S, CODE_JPEG7D,
-};
-
-static const struct mca_ras_info mca_ras_table[] = {
- {
- .blkid = AMDGPU_RAS_BLOCK__UMC,
- .ip = AMDGPU_MCA_IP_UMC,
- .get_err_count = mca_umc_mca_get_err_count,
- }, {
- .blkid = AMDGPU_RAS_BLOCK__GFX,
- .ip = AMDGPU_MCA_IP_SMU,
- .get_err_count = mca_gfx_mca_get_err_count,
- .bank_is_valid = mca_gfx_smu_bank_is_valid,
- }, {
- .blkid = AMDGPU_RAS_BLOCK__SDMA,
- .ip = AMDGPU_MCA_IP_SMU,
- .err_code_array = sdma_err_codes,
- .err_code_count = ARRAY_SIZE(sdma_err_codes),
- .get_err_count = mca_smu_mca_get_err_count,
- .bank_is_valid = mca_smu_bank_is_valid,
- }, {
- .blkid = AMDGPU_RAS_BLOCK__MMHUB,
- .ip = AMDGPU_MCA_IP_SMU,
- .err_code_array = mmhub_err_codes,
- .err_code_count = ARRAY_SIZE(mmhub_err_codes),
- .get_err_count = mca_smu_mca_get_err_count,
- .bank_is_valid = mca_smu_bank_is_valid,
- }, {
- .blkid = AMDGPU_RAS_BLOCK__XGMI_WAFL,
- .ip = AMDGPU_MCA_IP_PCS_XGMI,
- .get_err_count = mca_pcs_xgmi_mca_get_err_count,
- }, {
- .blkid = AMDGPU_RAS_BLOCK__VCN,
- .ip = AMDGPU_MCA_IP_SMU,
- .err_code_array = vcn_err_codes,
- .err_code_count = ARRAY_SIZE(vcn_err_codes),
- .get_err_count = mca_smu_mca_get_err_count,
- .bank_is_valid = mca_smu_bank_is_valid,
- }, {
- .blkid = AMDGPU_RAS_BLOCK__JPEG,
- .ip = AMDGPU_MCA_IP_SMU,
- .err_code_array = jpeg_err_codes,
- .err_code_count = ARRAY_SIZE(jpeg_err_codes),
- .get_err_count = mca_smu_mca_get_err_count,
- .bank_is_valid = mca_smu_bank_is_valid,
- },
-};
-
-static const struct mca_ras_info *mca_get_mca_ras_info(struct amdgpu_device *adev, enum amdgpu_ras_block blkid)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mca_ras_table); i++) {
- if (mca_ras_table[i].blkid == blkid)
- return &mca_ras_table[i];
- }
-
- return NULL;
-}
-
-static int mca_get_valid_mca_count(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, uint32_t *count)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- int ret;
-
- switch (type) {
- case AMDGPU_MCA_ERROR_TYPE_UE:
- case AMDGPU_MCA_ERROR_TYPE_CE:
- ret = smu_v13_0_6_get_valid_mca_count(smu, type, count);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static bool mca_bank_is_valid(struct amdgpu_device *adev, const struct mca_ras_info *mca_ras,
- enum amdgpu_mca_error_type type, struct mca_bank_entry *entry)
-{
- if (mca_decode_ipid_to_hwip(entry->regs[MCA_REG_IDX_IPID]) != mca_ras->ip)
- return false;
-
- if (mca_ras->bank_is_valid)
- return mca_ras->bank_is_valid(mca_ras, adev, type, entry);
-
- return true;
-}
-
-static int mca_smu_parse_mca_error_count(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type,
- struct mca_bank_entry *entry, uint32_t *count)
-{
- const struct mca_ras_info *mca_ras;
-
- if (!entry || !count)
- return -EINVAL;
-
- mca_ras = mca_get_mca_ras_info(adev, blk);
- if (!mca_ras)
- return -EOPNOTSUPP;
-
- if (!mca_bank_is_valid(adev, mca_ras, type, entry)) {
- *count = 0;
- return 0;
- }
-
- return mca_ras->get_err_count(mca_ras, adev, type, entry, count);
-}
-
-static int mca_smu_get_mca_entry(struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, int idx, struct mca_bank_entry *entry)
-{
- return mca_get_mca_entry(adev, type, idx, entry);
-}
-
-static int mca_smu_get_valid_mca_count(struct amdgpu_device *adev,
- enum amdgpu_mca_error_type type, uint32_t *count)
-{
- return mca_get_valid_mca_count(adev, type, count);
-}
-
-static const struct amdgpu_mca_smu_funcs smu_v13_0_6_mca_smu_funcs = {
- .max_ue_count = 12,
- .max_ce_count = 12,
- .mca_set_debug_mode = mca_smu_set_debug_mode,
- .mca_parse_mca_error_count = mca_smu_parse_mca_error_count,
- .mca_get_mca_entry = mca_smu_get_mca_entry,
- .mca_get_valid_mca_count = mca_smu_get_valid_mca_count,
-};
-
-static int aca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
-
- return smu_v13_0_6_mca_set_debug_mode(smu, enable);
-}
-
-static int smu_v13_0_6_get_valid_aca_count(struct smu_context *smu, enum aca_smu_type type, u32 *count)
-{
- uint32_t msg;
- int ret;
-
- if (!count)
- return -EINVAL;
-
- switch (type) {
- case ACA_SMU_TYPE_UE:
- msg = SMU_MSG_QueryValidMcaCount;
- break;
- case ACA_SMU_TYPE_CE:
- msg = SMU_MSG_QueryValidMcaCeCount;
- break;
- default:
- return -EINVAL;
- }
-
- ret = smu_cmn_send_smc_msg(smu, msg, count);
- if (ret) {
- *count = 0;
- return ret;
- }
-
- return 0;
-}
-
-static int aca_smu_get_valid_aca_count(struct amdgpu_device *adev,
- enum aca_smu_type type, u32 *count)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- int ret;
-
- switch (type) {
- case ACA_SMU_TYPE_UE:
- case ACA_SMU_TYPE_CE:
- ret = smu_v13_0_6_get_valid_aca_count(smu, type, count);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int __smu_v13_0_6_aca_bank_dump(struct smu_context *smu, enum aca_smu_type type,
- int idx, int offset, u32 *val)
-{
- uint32_t msg, param;
-
- switch (type) {
- case ACA_SMU_TYPE_UE:
- msg = SMU_MSG_McaBankDumpDW;
- break;
- case ACA_SMU_TYPE_CE:
- msg = SMU_MSG_McaBankCeDumpDW;
- break;
- default:
- return -EINVAL;
- }
-
- param = ((idx & 0xffff) << 16) | (offset & 0xfffc);
-
- return smu_cmn_send_smc_msg_with_param(smu, msg, param, (uint32_t *)val);
-}
-
-static int smu_v13_0_6_aca_bank_dump(struct smu_context *smu, enum aca_smu_type type,
- int idx, int offset, u32 *val, int count)
-{
- int ret, i;
-
- if (!val)
- return -EINVAL;
-
- for (i = 0; i < count; i++) {
- ret = __smu_v13_0_6_aca_bank_dump(smu, type, idx, offset + (i << 2), &val[i]);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int aca_bank_read_reg(struct amdgpu_device *adev, enum aca_smu_type type,
- int idx, int reg_idx, u64 *val)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- u32 data[2] = {0, 0};
- int ret;
-
- if (!val || reg_idx >= ACA_REG_IDX_COUNT)
- return -EINVAL;
-
- ret = smu_v13_0_6_aca_bank_dump(smu, type, idx, reg_idx * 8, data, ARRAY_SIZE(data));
- if (ret)
- return ret;
-
- *val = (u64)data[1] << 32 | data[0];
-
- dev_dbg(adev->dev, "mca read bank reg: type:%s, index: %d, reg_idx: %d, val: 0x%016llx\n",
- type == ACA_SMU_TYPE_UE ? "UE" : "CE", idx, reg_idx, *val);
-
- return 0;
-}
-
-static int aca_smu_get_valid_aca_bank(struct amdgpu_device *adev,
- enum aca_smu_type type, int idx, struct aca_bank *bank)
-{
- int i, ret, count;
-
- count = min_t(int, 16, ARRAY_SIZE(bank->regs));
- for (i = 0; i < count; i++) {
- ret = aca_bank_read_reg(adev, type, idx, i, &bank->regs[i]);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int aca_smu_parse_error_code(struct amdgpu_device *adev, struct aca_bank *bank)
-{
- struct smu_context *smu = adev->powerplay.pp_handle;
- int error_code;
-
- if (smu_v13_0_6_cap_supported(smu, SMU_CAP(ACA_SYND)))
- error_code = ACA_REG__SYND__ERRORINFORMATION(bank->regs[ACA_REG_IDX_SYND]);
- else
- error_code = ACA_REG__STATUS__ERRORCODE(bank->regs[ACA_REG_IDX_STATUS]);
-
- return error_code & 0xff;
-}
-
-static const struct aca_smu_funcs smu_v13_0_6_aca_smu_funcs = {
- .max_ue_bank_count = 12,
- .max_ce_bank_count = 12,
- .set_debug_mode = aca_smu_set_debug_mode,
- .get_valid_aca_count = aca_smu_get_valid_aca_count,
- .get_valid_aca_bank = aca_smu_get_valid_aca_bank,
- .parse_error_code = aca_smu_parse_error_code,
-};
-
static void smu_v13_0_6_set_temp_funcs(struct smu_context *smu)
{
smu->smu_temp.temp_funcs = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)
== IP_VERSION(13, 0, 12)) ? &smu_v13_0_12_temp_funcs : NULL;
}
-static int smu_v13_0_6_get_ras_smu_drv(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv)
-{
- if (!ras_smu_drv)
- return -EINVAL;
-
- if (amdgpu_sriov_vf(smu->adev))
- return -EOPNOTSUPP;
-
- if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_HROM_EN_BIT))
- smu_v13_0_6_cap_set(smu, SMU_CAP(RAS_EEPROM));
-
- switch (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)) {
- case IP_VERSION(13, 0, 12):
- *ras_smu_drv = &smu_v13_0_12_ras_smu_drv;
- break;
- default:
- *ras_smu_drv = NULL;
- break;
- }
-
- return 0;
-}
-
static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
/* init dpm */
.init_allowed_features = smu_v13_0_6_init_allowed_features,
@@ -3954,7 +3275,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
.force_clk_levels = smu_v13_0_6_force_clk_levels,
.read_sensor = smu_v13_0_6_read_sensor,
.set_performance_level = smu_v13_0_6_set_performance_level,
- .get_power_limit = smu_v13_0_6_get_power_limit,
+ .get_ppt_limit = smu_v13_0_6_get_ppt_limit,
.is_dpm_running = smu_v13_0_6_is_dpm_running,
.get_unique_id = smu_v13_0_6_get_unique_id,
.init_microcode = smu_v13_0_6_init_microcode,
@@ -3972,8 +3293,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
.system_features_control = smu_v13_0_6_system_features_control,
.get_enabled_mask = smu_v13_0_6_get_enabled_mask,
.feature_is_enabled = smu_cmn_feature_is_enabled,
- .set_power_limit = smu_v13_0_6_set_power_limit,
- .get_ppt_limit = smu_v13_0_6_get_ppt_limit,
+ .set_ppt_limit = smu_v13_0_6_set_ppt_limit,
.set_xgmi_pstate = smu_v13_0_set_xgmi_pstate,
.register_irq_handler = smu_v13_0_6_register_irq_handler,
.enable_thermal_alert = smu_v13_0_enable_thermal_alert,
@@ -4002,7 +3322,6 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
.dpm_reset_vcn = smu_v13_0_6_reset_vcn,
.post_init = smu_v13_0_6_post_init,
.ras_send_msg = smu_v13_0_6_ras_send_msg,
- .get_ras_smu_drv = smu_v13_0_6_get_ras_smu_drv,
};
void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu)
@@ -4020,7 +3339,5 @@ void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu)
smu->smc_fw_caps |= SMU_FW_CAP_RAS_PRI;
smu_v13_0_init_msg_ctl(smu, message_map);
smu_v13_0_6_set_temp_funcs(smu);
- amdgpu_mca_smu_init_funcs(smu->adev, &smu_v13_0_6_mca_smu_funcs);
- amdgpu_aca_set_smu_funcs(smu->adev, &smu_v13_0_6_aca_smu_funcs);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
index a150fc88902c..6554780afff7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
@@ -117,7 +117,6 @@ int smu_v13_0_12_get_system_power(struct smu_context *smu,
extern const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[];
extern const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[];
extern const struct smu_temp_funcs smu_v13_0_12_temp_funcs;
-extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv;
#if defined(SWSMU_CODE_LAYER_L2)
#include "smu_cmn.h"
@@ -145,15 +144,15 @@ extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv;
SMU_SCALAR(SMU_MATTR(ACCUMULATION_COUNTER), SMU_MUNIT(NONE), \
SMU_MTYPE(U64), accumulation_counter); \
SMU_SCALAR(SMU_MATTR(PROCHOT_RESIDENCY_ACC), SMU_MUNIT(NONE), \
- SMU_MTYPE(U32), prochot_residency_acc); \
+ SMU_MTYPE(U64), prochot_residency_acc); \
SMU_SCALAR(SMU_MATTR(PPT_RESIDENCY_ACC), SMU_MUNIT(NONE), \
- SMU_MTYPE(U32), ppt_residency_acc); \
+ SMU_MTYPE(U64), ppt_residency_acc); \
SMU_SCALAR(SMU_MATTR(SOCKET_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
- SMU_MTYPE(U32), socket_thm_residency_acc); \
+ SMU_MTYPE(U64), socket_thm_residency_acc); \
SMU_SCALAR(SMU_MATTR(VR_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
- SMU_MTYPE(U32), vr_thm_residency_acc); \
+ SMU_MTYPE(U64), vr_thm_residency_acc); \
SMU_SCALAR(SMU_MATTR(HBM_THM_RESIDENCY_ACC), SMU_MUNIT(NONE), \
- SMU_MTYPE(U32), hbm_thm_residency_acc); \
+ SMU_MTYPE(U64), hbm_thm_residency_acc); \
SMU_SCALAR(SMU_MATTR(GFXCLK_LOCK_STATUS), SMU_MUNIT(NONE), \
SMU_MTYPE(U32), gfxclk_lock_status); \
SMU_SCALAR(SMU_MATTR(PCIE_LINK_WIDTH), SMU_MUNIT(NONE), \
@@ -164,11 +163,11 @@ extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv;
SMU_MTYPE(U16), xgmi_link_width); \
SMU_SCALAR(SMU_MATTR(XGMI_LINK_SPEED), SMU_MUNIT(SPEED_1), \
SMU_MTYPE(U16), xgmi_link_speed); \
- SMU_SCALAR(SMU_MATTR(GFX_ACTIVITY_ACC), SMU_MUNIT(PERCENT), \
- SMU_MTYPE(U32), gfx_activity_acc); \
- SMU_SCALAR(SMU_MATTR(MEM_ACTIVITY_ACC), SMU_MUNIT(PERCENT), \
- SMU_MTYPE(U32), mem_activity_acc); \
- SMU_SCALAR(SMU_MATTR(PCIE_BANDWIDTH_ACC), SMU_MUNIT(PERCENT), \
+ SMU_SCALAR(SMU_MATTR(GFX_ACTIVITY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), gfx_activity_acc); \
+ SMU_SCALAR(SMU_MATTR(MEM_ACTIVITY_ACC), SMU_MUNIT(NONE), \
+ SMU_MTYPE(U64), mem_activity_acc); \
+ SMU_SCALAR(SMU_MATTR(PCIE_BANDWIDTH_ACC), SMU_MUNIT(NONE), \
SMU_MTYPE(U64), pcie_bandwidth_acc); \
SMU_SCALAR(SMU_MATTR(PCIE_BANDWIDTH_INST), SMU_MUNIT(BW_1), \
SMU_MTYPE(U64), pcie_bandwidth_inst); \
@@ -179,9 +178,9 @@ extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv;
SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_ROVER_COUNT_ACC), SMU_MUNIT(NONE), \
SMU_MTYPE(U64), pcie_replay_rover_count_acc); \
SMU_SCALAR(SMU_MATTR(PCIE_NAK_SENT_COUNT_ACC), SMU_MUNIT(NONE), \
- SMU_MTYPE(U32), pcie_nak_sent_count_acc); \
+ SMU_MTYPE(U64), pcie_nak_sent_count_acc); \
SMU_SCALAR(SMU_MATTR(PCIE_NAK_RCVD_COUNT_ACC), SMU_MUNIT(NONE), \
- SMU_MTYPE(U32), pcie_nak_rcvd_count_acc); \
+ SMU_MTYPE(U64), pcie_nak_rcvd_count_acc); \
SMU_ARRAY(SMU_MATTR(XGMI_READ_DATA_ACC), SMU_MUNIT(DATA_1), \
SMU_MTYPE(U64), xgmi_read_data_acc, \
SMU_13_0_6_NUM_XGMI_LINKS); \
@@ -204,7 +203,7 @@ extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv;
SMU_SCALAR(SMU_MATTR(CURRENT_UCLK), SMU_MUNIT(CLOCK_1), \
SMU_MTYPE(U16), current_uclk); \
SMU_SCALAR(SMU_MATTR(PCIE_LC_PERF_OTHER_END_RECOVERY), \
- SMU_MUNIT(NONE), SMU_MTYPE(U32), \
+ SMU_MUNIT(NONE), SMU_MTYPE(U64), \
pcie_lc_perf_other_end_recovery); \
SMU_ARRAY(SMU_MATTR(GFX_BUSY_INST), SMU_MUNIT(PERCENT), \
SMU_MTYPE(U32), gfx_busy_inst, SMU_13_0_6_MAX_XCC); \
@@ -212,7 +211,7 @@ extern const struct ras_smu_drv smu_v13_0_12_ras_smu_drv;
jpeg_busy, SMU_13_0_6_MAX_JPEG); \
SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \
vcn_busy, SMU_13_0_6_MAX_VCN); \
- SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(PERCENT), SMU_MTYPE(U64), \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(NONE), SMU_MTYPE(U64), \
gfx_busy_acc, SMU_13_0_6_MAX_XCC); \
SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \
SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \
@@ -257,7 +256,7 @@ void smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table,
jpeg_busy, SMU_13_0_6_MAX_JPEG); \
SMU_ARRAY(SMU_MATTR(VCN_BUSY), SMU_MUNIT(PERCENT), SMU_MTYPE(U16), \
vcn_busy, SMU_13_0_6_MAX_VCN); \
- SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(PERCENT), SMU_MTYPE(U64), \
+ SMU_ARRAY(SMU_MATTR(GFX_BUSY_ACC), SMU_MUNIT(NONE), SMU_MTYPE(U64), \
gfx_busy_acc, SMU_13_0_6_MAX_XCC); \
SMU_ARRAY(SMU_MATTR(GFX_BELOW_HOST_LIMIT_PPT_ACC), SMU_MUNIT(NONE), \
SMU_MTYPE(U64), gfx_below_host_limit_ppt_acc, \
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index 42c9ceeb4f7d..b94ae43586df 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -62,6 +62,7 @@
static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
int od_feature_bit,
int32_t *min, int32_t *max);
+static int smu_v13_0_7_init_ppt_limits(struct smu_context *smu);
static const struct smu_feature_bits smu_v13_0_7_dpm_features = {
.bits = {
@@ -503,7 +504,7 @@ static int smu_v13_0_7_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
- return ret;
+ return smu_v13_0_7_init_ppt_limits(smu);
}
static int smu_v13_0_7_tables_init(struct smu_context *smu)
@@ -817,7 +818,7 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu,
*value = smu_safe_u16_nn(metrics->AverageUclkActivity);
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->AvgTemperature[TEMP_EDGE] *
@@ -2371,58 +2372,71 @@ static int smu_v13_0_7_enable_mgpu_fan_boost(struct smu_context *smu)
NULL);
}
-static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int smu_v13_0_7_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
+{
+ OverDriveTableExternal_t od_table;
+ int ret;
+
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
+
+ ret = smu_v13_0_get_ppt_limit(smu, limit_type, ppt_limit);
+ if (ret)
+ return ret;
+
+ ret = smu_v13_0_7_get_overdrive_table(smu, &od_table);
+ if (ret)
+ return ret;
+
+ if (od_table.OverDriveTable.Ppt > 0)
+ *ppt_limit = *ppt_limit *
+ (100 + od_table.OverDriveTable.Ppt) / 100;
+
+ return 0;
+}
+
+static int smu_v13_0_7_init_ppt_limits(struct smu_context *smu)
{
struct smu_table_context *table_context = &smu->smu_table;
struct smu_13_0_7_powerplay_table *powerplay_table =
(struct smu_13_0_7_powerplay_table *)table_context->power_play_table;
PPTable_t *pptable = table_context->driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- uint32_t pp_limit = smu->adev->pm.ac_power ?
- skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
- skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
- uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
- uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit);
- uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit);
uint32_t od_percent_upper = 0, od_percent_lower = 0;
- int ret;
+ uint32_t pp_limit, msg_limit, min_limit, max_limit;
+ int i;
- if (current_power_limit) {
- ret = smu_v13_0_get_current_power_limit(smu, current_power_limit);
- if (ret)
- *current_power_limit = pp_limit;
+ if (powerplay_table &&
+ smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
+ od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[
+ SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
+ od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[
+ SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
}
- if (default_power_limit)
- *default_power_limit = pp_limit;
-
- if (powerplay_table) {
- if (smu->od_enabled &&
- (smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT))) {
- od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
- od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
- } else if (smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
- od_percent_upper = 0;
- od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
- }
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ pp_limit = i == SMU_POWER_SOURCE_AC ?
+ skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
+ skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][i];
+ min_limit = min(pp_limit, msg_limit);
+ max_limit = max(pp_limit, msg_limit);
+
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ pp_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max =
+ max_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min =
+ min_limit * (100 - od_percent_lower) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ max_limit * (100 + od_percent_upper) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min =
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min;
}
- dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, pp_limit);
-
- if (max_power_limit) {
- *max_power_limit = max_limit * (100 + od_percent_upper);
- *max_power_limit /= 100;
- }
-
- if (min_power_limit) {
- *min_power_limit = min_limit * (100 - od_percent_lower);
- *min_power_limit /= 100;
- }
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
return 0;
}
@@ -2574,9 +2588,10 @@ static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu,
return -ENOMEM;
}
if (custom_params && custom_params_max_idx) {
- if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT)
- return -EINVAL;
- if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)
+ if (!smu_cmn_custom_params_count_valid(custom_params_max_idx,
+ SMU_13_0_7_CUSTOM_PARAMS_COUNT) ||
+ !smu_cmn_custom_params_clock_valid(custom_params[0],
+ SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT))
return -EINVAL;
idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT;
smu->custom_profile_params[idx] = 1;
@@ -2650,23 +2665,29 @@ static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu)
return smu->smc_fw_version > 0x00524600;
}
-static int smu_v13_0_7_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+static int smu_v13_0_7_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
PPTable_t *pptable = smu->smu_table.driver_pptable;
SkuTable_t *skutable = &pptable->SkuTable;
- uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+ uint32_t msg_limit = skutable->MsgLimits.Power
+ [PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)table_context->overdrive_table;
+ OverDriveTableExternal_t current_od_table;
int ret = 0;
- if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
return -EINVAL;
if (limit <= msg_limit) {
- if (smu->current_power_limit > msg_limit) {
+ ret = smu_v13_0_7_get_overdrive_table(smu, &current_od_table);
+ if (ret)
+ return ret;
+
+ if (current_od_table.OverDriveTable.Ppt) {
od_table->OverDriveTable.Ppt = 0;
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
@@ -2676,9 +2697,9 @@ static int smu_v13_0_7_set_power_limit(struct smu_context *smu,
return ret;
}
}
- return smu_v13_0_set_power_limit(smu, limit_type, limit);
+ return smu_v13_0_set_ppt_limit(smu, limit_type, limit);
} else if (smu->od_enabled) {
- ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit);
+ ret = smu_v13_0_set_ppt_limit(smu, limit_type, msg_limit);
if (ret)
return ret;
@@ -2691,7 +2712,6 @@ static int smu_v13_0_7_set_power_limit(struct smu_context *smu,
return ret;
}
- smu->current_power_limit = limit;
} else {
return -EINVAL;
}
@@ -2860,8 +2880,8 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = {
.get_fan_control_mode = smu_v13_0_get_fan_control_mode,
.set_fan_control_mode = smu_v13_0_set_fan_control_mode,
.enable_mgpu_fan_boost = smu_v13_0_7_enable_mgpu_fan_boost,
- .get_power_limit = smu_v13_0_7_get_power_limit,
- .set_power_limit = smu_v13_0_7_set_power_limit,
+ .get_ppt_limit = smu_v13_0_7_get_ppt_limit,
+ .set_ppt_limit = smu_v13_0_7_set_ppt_limit,
.set_power_source = smu_v13_0_set_power_source,
.get_power_profile_mode = smu_v13_0_7_get_power_profile_mode,
.set_power_profile_mode = smu_v13_0_7_set_power_profile_mode,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
index 7bf88ffd311b..edc3fedca9f8 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
@@ -372,7 +372,7 @@ static int yellow_carp_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->UvdActivity / 100;
break;
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->CurrentSocketPower << 8) / 1000;
+ *value = metrics->CurrentSocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
index d0a8df1aa6b6..80dac277d1ae 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
@@ -194,7 +194,7 @@ int smu_v14_0_init_pptable_microcode(struct smu_context *smu)
if (!pptable_id)
return 0;
- ret = smu_v14_0_get_pptable_from_firmware(smu, &table, &size, pptable_id);
+ ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id);
if (ret)
return ret;
@@ -229,48 +229,6 @@ int smu_v14_0_check_fw_status(struct smu_context *smu)
return -EIO;
}
-static int smu_v14_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t ppt_offset_bytes;
- const struct smc_firmware_header_v2_0 *v2;
-
- v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data;
-
- ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes);
- *size = le32_to_cpu(v2->ppt_size_bytes);
- *table = (uint8_t *)v2 + ppt_offset_bytes;
-
- return 0;
-}
-
-static int smu_v14_0_set_pptable_v2_1(struct smu_context *smu, void **table,
- uint32_t *size, uint32_t pptable_id)
-{
- struct amdgpu_device *adev = smu->adev;
- const struct smc_firmware_header_v2_1 *v2_1;
- struct smc_soft_pptable_entry *entries;
- uint32_t pptable_count = 0;
- int i = 0;
-
- v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data;
- entries = (struct smc_soft_pptable_entry *)
- ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset));
- pptable_count = le32_to_cpu(v2_1->pptable_count);
- for (i = 0; i < pptable_count; i++) {
- if (le32_to_cpu(entries[i].id) == pptable_id) {
- *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes));
- *size = le32_to_cpu(entries[i].ppt_size_bytes);
- break;
- }
- }
-
- if (i == pptable_count)
- return -EINVAL;
-
- return 0;
-}
-
static int smu_v14_0_get_pptable_from_vbios(struct smu_context *smu, void **table, uint32_t *size)
{
struct amdgpu_device *adev = smu->adev;
@@ -293,45 +251,6 @@ static int smu_v14_0_get_pptable_from_vbios(struct smu_context *smu, void **tabl
return 0;
}
-int smu_v14_0_get_pptable_from_firmware(struct smu_context *smu,
- void **table,
- uint32_t *size,
- uint32_t pptable_id)
-{
- const struct smc_firmware_header_v1_0 *hdr;
- struct amdgpu_device *adev = smu->adev;
- uint16_t version_major, version_minor;
- int ret;
-
- hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
- if (!hdr)
- return -EINVAL;
-
- dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id);
-
- version_major = le16_to_cpu(hdr->header.header_version_major);
- version_minor = le16_to_cpu(hdr->header.header_version_minor);
- if (version_major != 2) {
- dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n",
- version_major, version_minor);
- return -EINVAL;
- }
-
- switch (version_minor) {
- case 0:
- ret = smu_v14_0_set_pptable_v2_0(smu, table, size);
- break;
- case 1:
- ret = smu_v14_0_set_pptable_v2_1(smu, table, size, pptable_id);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
int smu_v14_0_setup_pptable(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -351,7 +270,7 @@ int smu_v14_0_setup_pptable(struct smu_context *smu)
if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1))
ret = smu_v14_0_get_pptable_from_vbios(smu, &table, &size);
else
- ret = smu_v14_0_get_pptable_from_firmware(smu, &table, &size, pptable_id);
+ ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id);
if (ret)
return ret;
@@ -748,14 +667,17 @@ int smu_v14_0_notify_display_change(struct smu_context *smu)
return ret;
}
-int smu_v14_0_get_current_power_limit(struct smu_context *smu,
- uint32_t *power_limit)
+int smu_v14_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
{
int power_src;
int ret = 0;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT))
return -EINVAL;
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
power_src = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_PWR,
@@ -768,35 +690,33 @@ int smu_v14_0_get_current_power_limit(struct smu_context *smu,
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_GetPptLimit,
power_src << 16,
- power_limit);
+ ppt_limit);
if (ret)
dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
return ret;
}
-int smu_v14_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+int smu_v14_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
int ret = 0;
- if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
return -EINVAL;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
- dev_err(smu->adev->dev, "Setting new power limit is not supported!\n");
+ dev_err(smu->adev->dev, "Setting new PPT limit is not supported!\n");
return -EOPNOTSUPP;
}
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit, NULL);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__);
+ dev_err(smu->adev->dev, "[%s] Set PPT limit failed!\n", __func__);
return ret;
}
- smu->current_power_limit = limit;
-
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
index 75719c47a41e..c83c58d5a2e2 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c
@@ -260,6 +260,35 @@ static int smu_v14_0_0_system_features_control(struct smu_context *smu, bool en)
return ret;
}
+/**
+ * smu_v14_0_0_find_clk_level - find the closest DPM level for a frequency
+ * @freqs: array of frequencies (one per DPM level)
+ * @count: number of valid entries in @freqs
+ * @target: the frequency to match
+ *
+ * Returns the index of the DPM level whose frequency is closest to @target.
+ * If an exact match exists it is preferred; otherwise the nearest level by
+ * absolute difference is returned.
+ */
+static uint8_t smu_v14_0_0_find_clk_level(const uint32_t *freqs, uint8_t count,
+ uint32_t target)
+{
+ uint8_t i, closest = 0;
+ uint32_t best_diff = U32_MAX;
+
+ for (i = 0; i < count; i++) {
+ uint32_t diff = abs((int)target - (int)freqs[i]);
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ closest = i;
+ }
+ if (freqs[i] == target)
+ return i;
+ }
+ return closest;
+}
+
static int smu_v14_0_0_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
@@ -284,7 +313,30 @@ static int smu_v14_0_0_get_smu_metrics_data(struct smu_context *smu,
*value = metrics->VclkFrequency;
break;
case METRICS_AVERAGE_DCLK:
+ /*
+ * SmuMetrics_t has no DclkFrequency field. DCLK and VCLK
+ * share the same DPM level count, so find the DPM level
+ * whose VCLK matches the reported VclkFrequency and return
+ * the DCLK frequency at that level.
+ */
*value = 0;
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(14, 0, 1)) {
+ DpmClocks_t_v14_0_1 *clk_table = smu->smu_table.clocks_table;
+ uint8_t lvl = smu_v14_0_0_find_clk_level(
+ clk_table->VClocks0,
+ clk_table->Vcn0ClkLevelsEnabled,
+ metrics->VclkFrequency);
+
+ *value = clk_table->DClocks0[lvl];
+ } else {
+ DpmClocks_t *clk_table = smu->smu_table.clocks_table;
+ uint8_t lvl = smu_v14_0_0_find_clk_level(
+ clk_table->VClocks,
+ clk_table->VcnClkLevelsEnabled,
+ metrics->VclkFrequency);
+
+ *value = clk_table->DClocks[lvl];
+ }
break;
case METRICS_AVERAGE_UCLK:
*value = metrics->MemclkFrequency;
@@ -312,8 +364,7 @@ static int smu_v14_0_0_get_smu_metrics_data(struct smu_context *smu,
break;
case METRICS_AVERAGE_SOCKETPOWER:
case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->SocketPower / 1000 << 8) +
- (metrics->SocketPower % 1000 / 10);
+ *value = metrics->SocketPower;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->GfxTemperature / 100 *
@@ -683,6 +734,11 @@ static int smu_v14_0_1_get_dpm_freq_by_index(struct smu_context *smu,
return -EINVAL;
*freq = clk_table->FclkClocks_Freq[dpm_level];
break;
+ case SMU_DCEFCLK:
+ if (dpm_level >= clk_table->NumDcfClkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->DcfClocks[dpm_level];
+ break;
default:
return -EINVAL;
}
@@ -727,6 +783,11 @@ static int smu_v14_0_0_get_dpm_freq_by_index(struct smu_context *smu,
return -EINVAL;
*freq = clk_table->FclkClocks_Freq[dpm_level];
break;
+ case SMU_DCEFCLK:
+ if (dpm_level >= clk_table->NumDcfClkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->DcfClocks[dpm_level];
+ break;
default:
return -EINVAL;
}
@@ -1090,6 +1151,9 @@ static int smu_v14_0_1_get_dpm_level_count(struct smu_context *smu,
case SMU_FCLK:
*count = clk_table->NumFclkLevelsEnabled;
break;
+ case SMU_DCEFCLK:
+ *count = clk_table->NumDcfClkLevelsEnabled;
+ break;
default:
break;
}
@@ -1119,6 +1183,9 @@ static int smu_v14_0_0_get_dpm_level_count(struct smu_context *smu,
case SMU_FCLK:
*count = clk_table->NumFclkLevelsEnabled;
break;
+ case SMU_DCEFCLK:
+ *count = clk_table->NumDcfClkLevelsEnabled;
+ break;
default:
break;
}
@@ -1175,14 +1242,41 @@ static int smu_v14_0_0_emit_clk_levels(struct smu_context *smu,
if (ret)
return ret;
+ /*
+ * Build a frequency table and use find_clk_level() to
+ * locate the closest DPM level. The SMU often reports
+ * time-averaged frequencies that do not match any DPM
+ * entry exactly.
+ */
+ {
+ uint32_t freqs[NUM_SOCCLK_DPM_LEVELS];
+ int active;
+
+ for (i = 0; i < count; i++) {
+ idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i;
+ ret = smu_v14_0_common_get_dpm_freq_by_index(smu, clk_type, idx, &freqs[i]);
+ if (ret)
+ return ret;
+ }
+
+ active = smu_v14_0_0_find_clk_level(freqs, count, cur_value);
+
+ for (i = 0; i < count; i++)
+ size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n",
+ i, freqs[i],
+ i == active ? "*" : "");
+ }
+ break;
+ case SMU_DCEFCLK:
+ ret = smu_v14_0_common_get_dpm_level_count(smu, clk_type, &count);
+ if (ret)
+ return ret;
+
for (i = 0; i < count; i++) {
- idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i;
- ret = smu_v14_0_common_get_dpm_freq_by_index(smu, clk_type, idx, &value);
+ ret = smu_v14_0_common_get_dpm_freq_by_index(smu, clk_type, i, &value);
if (ret)
return ret;
-
- size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
- cur_value == value ? "*" : "");
+ size += sysfs_emit_at(buf, size, "%d: %uMhz\n", i, value);
}
break;
case SMU_GFXCLK:
@@ -1701,6 +1795,50 @@ static int smu_v14_0_0_restore_user_od_settings(struct smu_context *smu)
return 0;
}
+/*
+ * Link any xHCI controller sharing the GPU's PCIe root port as a consumer
+ * of the GPU so the GPU resumes first, avoiding an xHCI resume race.
+ */
+static int smu_v14_0_0_set_power_dep(struct smu_context *smu, bool enable)
+{
+ struct amdgpu_device *adev = smu->adev;
+ struct pci_dev *gpu_pdev = adev->pdev;
+ struct pci_dev *root_port, *usb_pdev = NULL;
+ struct device_link *link;
+
+ if (!enable) {
+ if (smu->usb_power_link) {
+ device_link_del(smu->usb_power_link);
+ smu->usb_power_link = NULL;
+ }
+ return 0;
+ }
+
+ root_port = pcie_find_root_port(gpu_pdev);
+ while ((usb_pdev = pci_get_class(PCI_CLASS_SERIAL_USB_XHCI, usb_pdev))) {
+ struct pci_dev *usb_root;
+
+ usb_root = pcie_find_root_port(usb_pdev);
+ if (usb_root != root_port)
+ continue;
+
+ /* Create device link: USB (consumer) depends on GPU (supplier) */
+ link = device_link_add(&usb_pdev->dev, &gpu_pdev->dev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
+ if (link) {
+ smu->usb_power_link = link;
+ drm_info(adev_to_drm(adev), "USB controller %s D0 power state depends on %s\n",
+ pci_name(usb_pdev), pci_name(gpu_pdev));
+ /* Only create one link for the first USB controller found */
+ break;
+ }
+ }
+
+ pci_dev_put(usb_pdev);
+
+ return 0;
+}
+
static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
.check_fw_status = smu_v14_0_check_fw_status,
.check_fw_version = smu_cmn_check_fw_version,
@@ -1734,6 +1872,7 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = {
.dpm_set_umsch_mm_enable = smu_v14_0_0_set_umsch_mm_enable,
.get_dpm_clock_table = smu_v14_0_common_get_dpm_table,
.set_mall_enable = smu_v14_0_common_set_mall_enable,
+ .set_power_dep = smu_v14_0_0_set_power_dep,
};
static void smu_v14_0_0_init_msg_ctl(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index fdc1456b885c..56a5c11bc196 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -59,6 +59,9 @@
static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
int od_feature_bit,
int32_t *min, int32_t *max);
+static int smu_v14_0_2_init_ppt_limits(struct smu_context *smu);
+static int smu_v14_0_2_get_overdrive_table(struct smu_context *smu,
+ OverDriveTableExternal_t *od_table);
static const struct smu_feature_bits smu_v14_0_2_dpm_features = {
.bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
@@ -370,7 +373,7 @@ static int smu_v14_0_2_setup_pptable(struct smu_context *smu)
if (ret)
return ret;
- return ret;
+ return smu_v14_0_2_init_ppt_limits(smu);
}
static int smu_v14_0_2_tables_init(struct smu_context *smu)
@@ -695,7 +698,7 @@ static int smu_v14_0_2_get_smu_metrics_data(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
break;
case METRICS_AVERAGE_SOCKETPOWER:
- *value = metrics->AverageSocketPower << 8;
+ *value = metrics->AverageSocketPower * MILLIWATT_PER_WATT;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->AvgTemperature[TEMP_EDGE] *
@@ -1610,11 +1613,32 @@ static int smu_v14_0_2_get_fan_speed_rpm(struct smu_context *smu,
speed);
}
-static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int smu_v14_0_2_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
+{
+ OverDriveTableExternal_t od_table;
+ int ret;
+
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
+
+ ret = smu_v14_0_get_ppt_limit(smu, limit_type, ppt_limit);
+ if (ret)
+ return ret;
+
+ ret = smu_v14_0_2_get_overdrive_table(smu, &od_table);
+ if (ret)
+ return ret;
+
+ if (od_table.OverDriveTable.Ppt > 0)
+ *ppt_limit = *ppt_limit *
+ (100 + od_table.OverDriveTable.Ppt) / 100;
+
+ return 0;
+}
+
+static int smu_v14_0_2_init_ppt_limits(struct smu_context *smu)
{
struct smu_table_context *table_context = &smu->smu_table;
struct smu_14_0_2_powerplay_table *powerplay_table =
@@ -1622,42 +1646,36 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
PPTable_t *pptable = table_context->driver_pptable;
CustomSkuTable_t *skutable = &pptable->CustomSkuTable;
int16_t od_percent_upper = 0, od_percent_lower = 0;
- uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
- uint32_t power_limit;
-
- if (smu_v14_0_get_current_power_limit(smu, &power_limit))
- power_limit = smu->adev->pm.ac_power ?
- skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
- skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
-
- if (current_power_limit)
- *current_power_limit = power_limit;
- if (default_power_limit)
- *default_power_limit = power_limit;
-
- if (powerplay_table) {
- if (smu->od_enabled &&
- smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
- od_percent_upper = pptable->SkuTable.OverDriveLimitsBasicMax.Ppt;
- od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt;
- } else if (smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
- od_percent_upper = 0;
- od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt;
- }
- }
-
- dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
- od_percent_upper, od_percent_lower, power_limit);
-
- if (max_power_limit) {
- *max_power_limit = msg_limit * (100 + od_percent_upper);
- *max_power_limit /= 100;
- }
-
- if (min_power_limit) {
- *min_power_limit = power_limit * (100 + od_percent_lower);
- *min_power_limit /= 100;
- }
+ uint32_t pp_limit, msg_limit, min_limit, max_limit;
+ int i;
+
+ if (powerplay_table &&
+ smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
+ od_percent_upper = pptable->SkuTable.OverDriveLimitsBasicMax.Ppt;
+ od_percent_lower = pptable->SkuTable.OverDriveLimitsBasicMin.Ppt;
+ }
+
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ pp_limit = i == SMU_POWER_SOURCE_AC ?
+ skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
+ skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+ msg_limit = pptable->SkuTable.MsgLimits.Power
+ [PPT_THROTTLER_PPT0][i];
+ min_limit = min(pp_limit, msg_limit);
+ max_limit = max(pp_limit, msg_limit);
+
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ pp_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max = max_limit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min =
+ min_limit * (100 + od_percent_lower) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ max_limit * (100 + od_percent_upper) / 100;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min =
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min;
+ }
+
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
return 0;
}
@@ -1828,9 +1846,10 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu,
return -ENOMEM;
}
if (custom_params && custom_params_max_idx) {
- if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT)
- return -EINVAL;
- if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)
+ if (!smu_cmn_custom_params_count_valid(custom_params_max_idx,
+ SMU_14_0_2_CUSTOM_PARAMS_COUNT) ||
+ !smu_cmn_custom_params_clock_valid(custom_params[0],
+ SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT))
return -EINVAL;
idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT;
smu->custom_profile_params[idx] = 1;
@@ -2784,22 +2803,28 @@ static int smu_v14_0_2_od_edit_dpm_table(struct smu_context *smu,
return ret;
}
-static int smu_v14_0_2_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+static int smu_v14_0_2_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
PPTable_t *pptable = smu->smu_table.driver_pptable;
- uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+ uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power
+ [PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
struct smu_table_context *table_context = &smu->smu_table;
OverDriveTableExternal_t *od_table =
(OverDriveTableExternal_t *)table_context->overdrive_table;
+ OverDriveTableExternal_t current_od_table;
int ret = 0;
- if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
return -EINVAL;
if (limit <= msg_limit) {
- if (smu->current_power_limit > msg_limit) {
+ ret = smu_v14_0_2_get_overdrive_table(smu, &current_od_table);
+ if (ret)
+ return ret;
+
+ if (current_od_table.OverDriveTable.Ppt) {
od_table->OverDriveTable.Ppt = 0;
od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT;
@@ -2809,9 +2834,9 @@ static int smu_v14_0_2_set_power_limit(struct smu_context *smu,
return ret;
}
}
- return smu_v14_0_set_power_limit(smu, limit_type, limit);
+ return smu_v14_0_set_ppt_limit(smu, limit_type, limit);
} else if (smu->od_enabled) {
- ret = smu_v14_0_set_power_limit(smu, limit_type, msg_limit);
+ ret = smu_v14_0_set_ppt_limit(smu, limit_type, msg_limit);
if (ret)
return ret;
@@ -2824,7 +2849,6 @@ static int smu_v14_0_2_set_power_limit(struct smu_context *smu,
return ret;
}
- smu->current_power_limit = limit;
} else {
return -EINVAL;
}
@@ -2878,8 +2902,8 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
.get_unique_id = smu_v14_0_2_get_unique_id,
.get_fan_speed_pwm = smu_v14_0_2_get_fan_speed_pwm,
.get_fan_speed_rpm = smu_v14_0_2_get_fan_speed_rpm,
- .get_power_limit = smu_v14_0_2_get_power_limit,
- .set_power_limit = smu_v14_0_2_set_power_limit,
+ .get_ppt_limit = smu_v14_0_2_get_ppt_limit,
+ .set_ppt_limit = smu_v14_0_2_set_ppt_limit,
.get_power_profile_mode = smu_v14_0_2_get_power_profile_mode,
.set_power_profile_mode = smu_v14_0_2_set_power_profile_mode,
.run_btc = smu_v14_0_run_btc,
@@ -2889,8 +2913,6 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
.deep_sleep_control = smu_v14_0_deep_sleep_control,
.gfx_ulv_control = smu_v14_0_gfx_ulv_control,
.get_bamaco_support = smu_v14_0_get_bamaco_support,
- .baco_get_state = smu_v14_0_baco_get_state,
- .baco_set_state = smu_v14_0_baco_set_state,
.baco_enter = smu_v14_0_2_baco_enter,
.baco_exit = smu_v14_0_2_baco_exit,
.mode1_reset_is_support = smu_v14_0_2_is_mode1_reset_supported,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
index a1318409e4b5..4c0236196de4 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c
@@ -174,7 +174,7 @@ int smu_v15_0_init_pptable_microcode(struct smu_context *smu)
if (!pptable_id)
return 0;
- ret = smu_v15_0_get_pptable_from_firmware(smu, &table, &size, pptable_id);
+ ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id);
if (ret)
return ret;
@@ -207,48 +207,6 @@ int smu_v15_0_check_fw_status(struct smu_context *smu)
return -EIO;
}
-static int smu_v15_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
-{
- struct amdgpu_device *adev = smu->adev;
- uint32_t ppt_offset_bytes;
- const struct smc_firmware_header_v2_0 *v2;
-
- v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data;
-
- ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes);
- *size = le32_to_cpu(v2->ppt_size_bytes);
- *table = (uint8_t *)v2 + ppt_offset_bytes;
-
- return 0;
-}
-
-static int smu_v15_0_set_pptable_v2_1(struct smu_context *smu, void **table,
- uint32_t *size, uint32_t pptable_id)
-{
- struct amdgpu_device *adev = smu->adev;
- const struct smc_firmware_header_v2_1 *v2_1;
- struct smc_soft_pptable_entry *entries;
- uint32_t pptable_count = 0;
- int i = 0;
-
- v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data;
- entries = (struct smc_soft_pptable_entry *)
- ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset));
- pptable_count = le32_to_cpu(v2_1->pptable_count);
- for (i = 0; i < pptable_count; i++) {
- if (le32_to_cpu(entries[i].id) == pptable_id) {
- *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes));
- *size = le32_to_cpu(entries[i].ppt_size_bytes);
- break;
- }
- }
-
- if (i == pptable_count)
- return -EINVAL;
-
- return 0;
-}
-
static int smu_v15_0_get_pptable_from_vbios(struct smu_context *smu, void **table, uint32_t *size)
{
struct amdgpu_device *adev = smu->adev;
@@ -271,45 +229,6 @@ static int smu_v15_0_get_pptable_from_vbios(struct smu_context *smu, void **tabl
return 0;
}
-int smu_v15_0_get_pptable_from_firmware(struct smu_context *smu,
- void **table,
- uint32_t *size,
- uint32_t pptable_id)
-{
- const struct smc_firmware_header_v1_0 *hdr;
- struct amdgpu_device *adev = smu->adev;
- uint16_t version_major, version_minor;
- int ret;
-
- hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data;
- if (!hdr)
- return -EINVAL;
-
- dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id);
-
- version_major = le16_to_cpu(hdr->header.header_version_major);
- version_minor = le16_to_cpu(hdr->header.header_version_minor);
- if (version_major != 2) {
- dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n",
- version_major, version_minor);
- return -EINVAL;
- }
-
- switch (version_minor) {
- case 0:
- ret = smu_v15_0_set_pptable_v2_0(smu, table, size);
- break;
- case 1:
- ret = smu_v15_0_set_pptable_v2_1(smu, table, size, pptable_id);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
int smu_v15_0_setup_pptable(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -329,7 +248,7 @@ int smu_v15_0_setup_pptable(struct smu_context *smu)
if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1))
ret = smu_v15_0_get_pptable_from_vbios(smu, &table, &size);
else
- ret = smu_v15_0_get_pptable_from_firmware(smu, &table, &size, pptable_id);
+ ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id);
if (ret)
return ret;
@@ -664,6 +583,8 @@ int smu_v15_0_gfx_off_control(struct smu_context *smu, bool enable)
switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
case IP_VERSION(15, 0, 0):
+ case IP_VERSION(15, 0, 5):
+ case IP_VERSION(15, 0, 9):
if (!(adev->pm.pp_feature & PP_GFXOFF_MASK))
return 0;
if (enable)
@@ -698,14 +619,17 @@ int smu_v15_0_notify_display_change(struct smu_context *smu)
return ret;
}
-int smu_v15_0_get_current_power_limit(struct smu_context *smu,
- uint32_t *power_limit)
+int smu_v15_0_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
{
int power_src;
int ret = 0;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT))
return -EINVAL;
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
+ return -EOPNOTSUPP;
power_src = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_PWR,
@@ -718,35 +642,33 @@ int smu_v15_0_get_current_power_limit(struct smu_context *smu,
ret = smu_cmn_send_smc_msg_with_param(smu,
SMU_MSG_GetPptLimit,
power_src << 16,
- power_limit);
+ ppt_limit);
if (ret)
dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__);
return ret;
}
-int smu_v15_0_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+int smu_v15_0_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
int ret = 0;
- if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+ if (limit_type != SMU_PPT_LIMIT_PPT0)
return -EINVAL;
if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) {
- dev_err(smu->adev->dev, "Setting new power limit is not supported!\n");
+ dev_err(smu->adev->dev, "Setting new PPT limit is not supported!\n");
return -EOPNOTSUPP;
}
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, limit, NULL);
if (ret) {
- dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__);
+ dev_err(smu->adev->dev, "[%s] Set PPT limit failed!\n", __func__);
return ret;
}
- smu->current_power_limit = limit;
-
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
index a214ddbd4c86..cbfeb9736e6c 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
@@ -33,6 +33,9 @@
#include "smu_v15_0_0_pmfw.h"
#include "smu_cmn.h"
+#include <linux/overflow.h>
+#include <linux/math64.h>
+
/*
* DO NOT use these for err/warn/info/debug messages.
* Use dev_err, dev_warn, dev_info and dev_dbg instead.
@@ -119,6 +122,9 @@ static struct cmn2asic_msg_mapping smu_v15_0_0_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(DisableLSdma, PPSMC_MSG_DisableLSdma, 1),
MSG_MAP(SetSoftMaxVpe, PPSMC_MSG_SetSoftMaxVpe, 1),
MSG_MAP(SetSoftMinVpe, PPSMC_MSG_SetSoftMinVpe, 1),
+ MSG_MAP(GetMetricsTableVersion, PPSMC_MSG_GetMetricsTableVersion, 1),
+ MSG_MAP(GetMetricsTableLogSample, PPSMC_MSG_GetMetricsTableLogSample, 1),
+ MSG_MAP(GetMetricsTableLogDramAddr, PPSMC_MSG_GetMetricsTableLogDramAddr, 1),
};
static struct cmn2asic_mapping smu_v15_0_0_feature_mask_map[SMU_FEATURE_COUNT] = {
@@ -160,25 +166,52 @@ static struct cmn2asic_mapping smu_v15_0_0_table_map[SMU_TABLE_COUNT] = {
TAB_MAP_VALID(DPMCLOCKS),
};
+static int smu_v15_0_0_get_metrics_table_dram_addr(struct smu_context *smu,
+ SMU_15_0_0_MetricsInfo_t *metrics_info)
+{
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+ struct smu_msg_args args = {
+ .msg = SMU_MSG_GetMetricsTableLogDramAddr,
+ .num_args = 0,
+ .num_out_args = 3,
+ };
+ int ret;
+
+ ret = ctl->ops->send_msg(ctl, &args);
+ if (ret)
+ return ret;
+
+ metrics_info->addr = ((uint64_t)args.out_args[1] << 32) | args.out_args[0];
+ metrics_info->table_size = args.out_args[2];
+
+ metrics_info->cpu_addr = ioremap_wc(metrics_info->addr,
+ metrics_info->table_size);
+ if (!metrics_info->cpu_addr)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int smu_v15_0_0_init_smc_tables(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ SMU_15_0_0_MetricsInfo_t *metrics_info;
int ret;
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
+ SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t_v15_0_5),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
- smu_table->metrics_table = kzalloc_obj(SmuMetrics_t);
+ smu_table->metrics_table = kzalloc_obj(SMU_15_0_0_MetricsInfo_t);
if (!smu_table->metrics_table)
goto err0_out;
smu_table->metrics_time = 0;
- smu_table->clocks_table = kzalloc_obj(DpmClocks_t);
+ smu_table->clocks_table = kzalloc_obj(DpmClocks_t_v15_0_5);
if (!smu_table->clocks_table)
goto err1_out;
@@ -192,8 +225,16 @@ static int smu_v15_0_0_init_smc_tables(struct smu_context *smu)
if (ret)
goto err3_out;
+ metrics_info = (SMU_15_0_0_MetricsInfo_t *)smu_table->metrics_table;
+
+ ret = smu_v15_0_0_get_metrics_table_dram_addr(smu, metrics_info);
+ if (ret)
+ goto err4_out;
+
return 0;
+err4_out:
+ smu_driver_table_fini(smu, SMU_DRIVER_TABLE_GPU_METRICS);
err3_out:
kfree(smu_table->watermarks_table);
err2_out:
@@ -207,6 +248,14 @@ err0_out:
static int smu_v15_0_0_fini_smc_tables(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
+ SMU_15_0_0_MetricsInfo_t *metrics_info = smu_table->metrics_table;
+
+ if (metrics_info) {
+ if (metrics_info->cpu_addr) {
+ iounmap(metrics_info->cpu_addr);
+ metrics_info->cpu_addr = NULL;
+ }
+ }
kfree(smu_table->clocks_table);
smu_table->clocks_table = NULL;
@@ -299,7 +348,7 @@ static int smu_v15_0_0_set_default_dpm_tables(struct smu_context *smu)
smu_table->clocks_table, false);
}
-static int smu_v15_0_0_get_metrics_table(struct smu_context *smu,
+static int smu_v15_0_0_get_gpu_metrics_table(struct smu_context *smu,
void *metrics_table,
bool bypass_cache)
{
@@ -329,115 +378,161 @@ static int smu_v15_0_0_get_metrics_table(struct smu_context *smu,
return 0;
}
+/*
+ * Fetch a fresh metrics sample into the inactive buffer.
+ * Returns 0 if a new sample was copied, 1 if the cached sample is still
+ * fresh (nothing copied), or a negative errno on failure.
+ */
+static int smu_v15_0_0_get_metrics_table(struct smu_context *smu,
+ SMU_15_0_0_MetricsInfo_t *metrics_info)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ void __iomem *cpu_addr = metrics_info->cpu_addr;
+ struct smu_msg_ctl *ctl = &smu->msg_ctl;
+ struct smu_msg_args args = {0};
+ size_t table_size = metrics_info->table_size;
+ int ret;
+
+ if (smu_table->metrics_time &&
+ !time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1)))
+ return 1;
+
+ if (!cpu_addr)
+ return -ENOMEM;
+
+ args.msg = SMU_MSG_GetMetricsTableLogSample;
+ args.num_args = 0;
+ args.num_out_args = 0;
+
+ ret = ctl->ops->send_msg(ctl, &args);
+ if (ret)
+ return ret;
+
+ /* best to flush before copy */
+ amdgpu_hdp_invalidate(smu->adev, NULL);
+ if (table_size <= sizeof(MetricsTable_t))
+ memcpy_fromio(&metrics_info->metrics[!metrics_info->active_idx],
+ cpu_addr, table_size);
+ else
+ memcpy_fromio(&metrics_info->metrics[!metrics_info->active_idx],
+ cpu_addr, sizeof(MetricsTable_t));
+
+ metrics_info->active_idx = !metrics_info->active_idx;
+ smu_table->metrics_time = jiffies;
+
+ return 0;
+}
+
+/*
+ * Accumulators monotonically increase and roll over at their type width.
+ * Use the kernel wrapping_sub() API to compute the delta so the subtraction
+ * wraps modulo 2^n (correct across a single rollover) without tripping any
+ * wrap-around sanitizers.
+ */
+static void smu_v15_0_0_compute_all_metrics(
+ uint32_t *avg_metric,
+ MetricsTable_t *prev,
+ MetricsTable_t *curr)
+{
+ uint64_t counter, val;
+ uint32_t mw;
+ MetricsTable_IOD_t *p = &prev->IOD;
+ MetricsTable_IOD_t *c = &curr->IOD;
+
+ counter = wrapping_sub(u32, c->AccumulationCounter, p->AccumulationCounter);
+ if (!counter)
+ return;
+
+ /* Accumulator-based clock frequencies (fixed-point /1024) */
+ val = wrapping_sub(u64, c->GfxclkFreqEffAcc, p->GfxclkFreqEffAcc);
+ avg_metric[METRICS_AVERAGE_GFXCLK] = div_u64(div64_u64(val, counter), 1024);
+
+ val = wrapping_sub(u64, c->SocclkFreqEffAcc, p->SocclkFreqEffAcc);
+ avg_metric[METRICS_AVERAGE_SOCCLK] = div_u64(div64_u64(val, counter), 1024);
+
+ val = wrapping_sub(u64, c->VclkFreqEffAcc, p->VclkFreqEffAcc);
+ avg_metric[METRICS_AVERAGE_VCLK] = div_u64(div64_u64(val, counter), 1024);
+
+ val = wrapping_sub(u64, c->MemclkFreqEffAcc, p->MemclkFreqEffAcc);
+ avg_metric[METRICS_AVERAGE_UCLK] = div_u64(div64_u64(val, counter), 1024);
+
+ val = wrapping_sub(u64, c->FclkFreqEffAcc, p->FclkFreqEffAcc);
+ avg_metric[METRICS_AVERAGE_FCLK] = div_u64(div64_u64(val, counter), 1024);
+
+ val = wrapping_sub(u64, c->NpuhclkFreqEffAcc, p->NpuhclkFreqEffAcc);
+ avg_metric[METRICS_AVERAGE_NPUCLK] = div_u64(div64_u64(val, counter), 1024);
+
+ /* Activity (fixed-point /1024) */
+ val = wrapping_sub(u64, c->GfxBusyAcc, p->GfxBusyAcc);
+ avg_metric[METRICS_AVERAGE_GFXACTIVITY] = div_u64(div64_u64(val, counter), 1024);
+
+ val = wrapping_sub(u64, c->VcnBusyAcc, p->VcnBusyAcc);
+ avg_metric[METRICS_AVERAGE_VCNACTIVITY] = div_u64(div64_u64(val, counter), 1024);
+
+ /*
+ * Power: accumulator holds a 1024x fixed-point value in Watts.
+ * Average it into milliwatts, which is the unit expected by
+ * power sensor consumers (hwmon/debugfs).
+ */
+ val = wrapping_sub(u64, c->ApuPowerAcc, p->ApuPowerAcc);
+ mw = div_u64(div64_u64(val, counter) * 1000, 1024);
+ avg_metric[METRICS_AVERAGE_SOCKETPOWER] = mw;
+
+ val = wrapping_sub(u64, c->SystemPowerAcc, p->SystemPowerAcc);
+ mw = div_u64(div64_u64(val, counter) * 1000, 1024);
+ avg_metric[METRICS_CURR_SOCKETPOWER] = mw;
+
+ /*
+ * Temperature: accumulator holds a 1024x fixed-point value in
+ * Celsius. Descale by 1024 and convert to millidegrees C as the
+ * hwmon/sysfs consumers expect (temp*_input is in millidegrees).
+ */
+ val = wrapping_sub(u64, c->GFX_TempAcc, p->GFX_TempAcc);
+ avg_metric[METRICS_TEMPERATURE_VRGFX] =
+ div_u64(div64_u64(val, counter) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES, 1024);
+
+ val = wrapping_sub(u64, c->STT_APU_HotSpotTempAcc, p->STT_APU_HotSpotTempAcc);
+ avg_metric[METRICS_TEMPERATURE_HOTSPOT] =
+ div_u64(div64_u64(val, counter) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES, 1024);
+
+ /* Voltage: accumulator holds a 1024x fixed-point value in Volts;
+ * convert to millivolts for the hwmon/sysfs consumers.
+ */
+ val = wrapping_sub(u64, c->VDDCR_GFX_TelemetryVoltage, p->VDDCR_GFX_TelemetryVoltage);
+ avg_metric[METRICS_VOLTAGE_VDDGFX] = div_u64(div64_u64(val, counter) * 1000, 1024);
+
+ val = wrapping_sub(u64, c->VDDCR_SOC_TelemetryVoltage, p->VDDCR_SOC_TelemetryVoltage);
+ avg_metric[METRICS_VOLTAGE_VDDSOC] = div_u64(div64_u64(val, counter) * 1000, 1024);
+}
+
static int smu_v15_0_0_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
{
struct smu_table_context *smu_table = &smu->smu_table;
+ SMU_15_0_0_MetricsInfo_t *metrics_info =
+ (SMU_15_0_0_MetricsInfo_t *)smu_table->metrics_table;
+ int ret;
- SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
- int ret = 0;
+ if (member >= ARRAY_SIZE(metrics_info->avg_metric))
+ return -EINVAL;
- ret = smu_v15_0_0_get_metrics_table(smu, NULL, false);
- if (ret)
+ ret = smu_v15_0_0_get_metrics_table(smu, metrics_info);
+ if (ret < 0)
return ret;
- switch (member) {
- case METRICS_AVERAGE_GFXCLK:
- *value = metrics->GfxclkFrequency;
- break;
- case METRICS_AVERAGE_SOCCLK:
- *value = metrics->SocclkFrequency;
- break;
- case METRICS_AVERAGE_VCLK:
- *value = metrics->VclkFrequency;
- break;
- case METRICS_AVERAGE_DCLK:
- *value = 0;
- break;
- case METRICS_AVERAGE_UCLK:
- *value = metrics->MemclkFrequency;
- break;
- case METRICS_AVERAGE_FCLK:
- *value = metrics->FclkFrequency;
- break;
- case METRICS_AVERAGE_VPECLK:
- *value = metrics->VpeclkFrequency;
- break;
- case METRICS_AVERAGE_NPUCLK:
- *value = metrics->NpuclkFrequency;
- break;
- case METRICS_AVERAGE_GFXACTIVITY:
- if ((smu->smc_fw_version > 0x5d4600))
- *value = metrics->GfxActivity;
- else
- *value = metrics->GfxActivity / 100;
- break;
- case METRICS_AVERAGE_VCNACTIVITY:
- *value = metrics->VcnActivity / 100;
- break;
- case METRICS_AVERAGE_SOCKETPOWER:
- case METRICS_CURR_SOCKETPOWER:
- *value = (metrics->SocketPower / 1000 << 8) +
- (metrics->SocketPower % 1000 / 10);
- break;
- case METRICS_TEMPERATURE_EDGE:
- *value = metrics->GfxTemperature / 100 *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
- break;
- case METRICS_TEMPERATURE_HOTSPOT:
- *value = metrics->SocTemperature / 100 *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
- break;
- case METRICS_THROTTLER_RESIDENCY_PROCHOT:
- *value = metrics->ThrottleResidency_PROCHOT;
- break;
- case METRICS_THROTTLER_RESIDENCY_SPL:
- *value = metrics->ThrottleResidency_SPL;
- break;
- case METRICS_THROTTLER_RESIDENCY_FPPT:
- *value = metrics->ThrottleResidency_FPPT;
- break;
- case METRICS_THROTTLER_RESIDENCY_SPPT:
- *value = metrics->ThrottleResidency_SPPT;
- break;
- case METRICS_THROTTLER_RESIDENCY_THM_SOC:
- *value = metrics->ThrottleResidency_THM_SOC;
- break;
- case METRICS_VOLTAGE_VDDGFX:
- *value = 0;
- break;
- case METRICS_VOLTAGE_VDDSOC:
- *value = 0;
- break;
- case METRICS_SS_APU_SHARE:
- /* return the percentage of APU power with respect to APU's power limit.
- * percentage is reported, this isn't boost value. Smartshift power
- * boost/shift is only when the percentage is more than 100.
- */
- if (metrics->StapmOpnLimit > 0)
- *value = (metrics->ApuPower * 100) / metrics->StapmOpnLimit;
- else
- *value = 0;
- break;
- case METRICS_SS_DGPU_SHARE:
- /* return the percentage of dGPU power with respect to dGPU's power limit.
- * percentage is reported, this isn't boost value. Smartshift power
- * boost/shift is only when the percentage is more than 100.
- */
- if ((metrics->dGpuPower > 0) &&
- (metrics->StapmCurrentLimit > metrics->StapmOpnLimit))
- *value = (metrics->dGpuPower * 100) /
- (metrics->StapmCurrentLimit - metrics->StapmOpnLimit);
- else
- *value = 0;
- break;
- default:
- *value = UINT_MAX;
- break;
- }
+ if (ret == 0 &&
+ metrics_info->metrics[metrics_info->active_idx].IOD.AccumulationCounter !=
+ metrics_info->metrics[!metrics_info->active_idx].IOD.AccumulationCounter) {
+ /* New sample: active_idx already points to the latest sample. */
+ smu_v15_0_0_compute_all_metrics(metrics_info->avg_metric,
+ &metrics_info->metrics[!metrics_info->active_idx],
+ &metrics_info->metrics[metrics_info->active_idx]);
+ }
- return ret;
+ *value = metrics_info->avg_metric[member];
+
+ return 0;
}
static int smu_v15_0_0_read_sensor(struct smu_context *smu,
@@ -474,9 +569,9 @@ static int smu_v15_0_0_read_sensor(struct smu_context *smu,
(uint32_t *)data);
*size = 4;
break;
- case AMDGPU_PP_SENSOR_EDGE_TEMP:
+ case AMDGPU_PP_SENSOR_GPU_TEMP:
ret = smu_v15_0_0_get_smu_metrics_data(smu,
- METRICS_TEMPERATURE_EDGE,
+ METRICS_TEMPERATURE_VRGFX,
(uint32_t *)data);
*size = 4;
break;
@@ -512,18 +607,6 @@ static int smu_v15_0_0_read_sensor(struct smu_context *smu,
(uint32_t *)data);
*size = 4;
break;
- case AMDGPU_PP_SENSOR_SS_APU_SHARE:
- ret = smu_v15_0_0_get_smu_metrics_data(smu,
- METRICS_SS_APU_SHARE,
- (uint32_t *)data);
- *size = 4;
- break;
- case AMDGPU_PP_SENSOR_SS_DGPU_SHARE:
- ret = smu_v15_0_0_get_smu_metrics_data(smu,
- METRICS_SS_DGPU_SHARE,
- (uint32_t *)data);
- *size = 4;
- break;
default:
ret = -EOPNOTSUPP;
break;
@@ -634,7 +717,7 @@ static ssize_t smu_v15_0_0_get_gpu_metrics(struct smu_context *smu,
SmuMetrics_t metrics;
int ret = 0;
- ret = smu_v15_0_0_get_metrics_table(smu, &metrics, false);
+ ret = smu_v15_0_0_get_gpu_metrics_table(smu, &metrics, false);
if (ret)
return ret;
@@ -752,11 +835,48 @@ static int smu_v15_0_0_get_dpm_freq_by_index(struct smu_context *smu,
return 0;
}
+static int smu_v15_0_5_get_dpm_freq_by_index(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t dpm_level,
+ uint32_t *freq)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+
+ if (!clk_table || clk_type >= SMU_CLK_COUNT)
+ return -EINVAL;
+
+ switch (clk_type) {
+ case SMU_SOCCLK:
+ if (dpm_level >= clk_table->NumSocClkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->SocClocks[dpm_level];
+ break;
+ case SMU_UCLK:
+ case SMU_MCLK:
+ if (dpm_level >= clk_table->NumMemPstatesEnabled)
+ return -EINVAL;
+ *freq = clk_table->MemPstateTable[dpm_level].MemClk;
+ break;
+ case SMU_FCLK:
+ if (dpm_level >= clk_table->NumFclkLevelsEnabled)
+ return -EINVAL;
+ *freq = clk_table->FclkClocks_Freq[dpm_level];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int smu_v15_0_common_get_dpm_freq_by_index(struct smu_context *smu,
enum smu_clk_type clk_type,
uint32_t dpm_level,
uint32_t *freq)
{
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_get_dpm_freq_by_index(smu, clk_type, dpm_level, freq);
+ else
smu_v15_0_0_get_dpm_freq_by_index(smu, clk_type, dpm_level, freq);
return 0;
@@ -907,12 +1027,116 @@ failed:
return ret;
}
+static int smu_v15_0_5_get_dpm_ultimate_freq(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *min,
+ uint32_t *max)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+ uint32_t clock_limit;
+ uint32_t max_dpm_level, min_dpm_level;
+ int ret = 0;
+
+ if (!smu_v15_0_0_clk_dpm_is_enabled(smu, clk_type)) {
+ switch (clk_type) {
+ case SMU_MCLK:
+ case SMU_UCLK:
+ clock_limit = smu->smu_table.boot_values.uclk;
+ break;
+ case SMU_FCLK:
+ clock_limit = smu->smu_table.boot_values.fclk;
+ break;
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ clock_limit = smu->smu_table.boot_values.gfxclk;
+ break;
+ case SMU_SOCCLK:
+ clock_limit = smu->smu_table.boot_values.socclk;
+ break;
+ default:
+ clock_limit = 0;
+ break;
+ }
+
+ /* clock in Mhz unit */
+ if (min)
+ *min = clock_limit / 100;
+ if (max)
+ *max = clock_limit / 100;
+
+ return 0;
+ }
+
+ if (max) {
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ *max = clk_table->MaxGfxClk;
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
+ max_dpm_level = 0;
+ break;
+ case SMU_FCLK:
+ max_dpm_level = clk_table->NumFclkLevelsEnabled - 1;
+ break;
+ case SMU_SOCCLK:
+ max_dpm_level = clk_table->NumSocClkLevelsEnabled - 1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type,
+ max_dpm_level, max);
+ if (ret)
+ goto failed;
+ }
+ }
+
+ if (min) {
+ switch (clk_type) {
+ case SMU_GFXCLK:
+ case SMU_SCLK:
+ *min = clk_table->MinGfxClk;
+ break;
+ case SMU_MCLK:
+ case SMU_UCLK:
+ min_dpm_level = clk_table->NumMemPstatesEnabled - 1;
+ break;
+ case SMU_FCLK:
+ min_dpm_level = 0;
+ break;
+ case SMU_SOCCLK:
+ min_dpm_level = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ if (clk_type != SMU_GFXCLK && clk_type != SMU_SCLK) {
+ ret = smu_v15_0_common_get_dpm_freq_by_index(smu, clk_type,
+ min_dpm_level, min);
+ if (ret)
+ goto failed;
+ }
+ }
+
+failed:
+ return ret;
+}
+
static int smu_v15_0_common_get_dpm_ultimate_freq(struct smu_context *smu,
enum smu_clk_type clk_type,
uint32_t *min,
uint32_t *max)
{
- if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_get_dpm_ultimate_freq(smu, clk_type, min, max);
+ else if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
smu_v15_0_0_get_dpm_ultimate_freq(smu, clk_type, min, max);
return 0;
@@ -986,11 +1210,36 @@ static int smu_v15_0_0_get_dpm_level_count(struct smu_context *smu,
return 0;
}
+static int smu_v15_0_5_get_dpm_level_count(struct smu_context *smu,
+ enum smu_clk_type clk_type,
+ uint32_t *count)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+
+ switch (clk_type) {
+ case SMU_SOCCLK:
+ *count = clk_table->NumSocClkLevelsEnabled;
+ break;
+ case SMU_MCLK:
+ *count = clk_table->NumMemPstatesEnabled;
+ break;
+ case SMU_FCLK:
+ *count = clk_table->NumFclkLevelsEnabled;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int smu_v15_0_common_get_dpm_level_count(struct smu_context *smu,
enum smu_clk_type clk_type,
uint32_t *count)
{
- if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_get_dpm_level_count(smu, clk_type, count);
+ else if (clk_type != SMU_VCLK1 && clk_type != SMU_DCLK1)
smu_v15_0_0_get_dpm_level_count(smu, clk_type, count);
return 0;
@@ -1177,7 +1426,8 @@ static int smu_v15_0_common_get_dpm_profile_freq(struct smu_context *smu,
smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_SOCCLK, NULL, &clk_limit);
break;
case SMU_FCLK:
- if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 0))
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 0) ||
+ amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 9))
smu_v15_0_common_get_dpm_ultimate_freq(smu, SMU_FCLK, NULL, &clk_limit);
else
clk_limit = SMU_15_0_UMD_PSTATE_FCLK;
@@ -1362,9 +1612,24 @@ static int smu_v15_0_0_set_fine_grain_gfx_freq_parameters(struct smu_context *sm
return 0;
}
+static int smu_v15_0_5_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+
+ smu->gfx_default_hard_min_freq = clk_table->MinGfxClk;
+ smu->gfx_default_soft_max_freq = clk_table->MaxGfxClk;
+ smu->gfx_actual_hard_min_freq = 0;
+ smu->gfx_actual_soft_max_freq = 0;
+
+ return 0;
+}
+
static int smu_v15_0_common_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
{
- smu_v15_0_0_set_fine_grain_gfx_freq_parameters(smu);
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_set_fine_grain_gfx_freq_parameters(smu);
+ else
+ smu_v15_0_0_set_fine_grain_gfx_freq_parameters(smu);
return 0;
}
@@ -1404,9 +1669,36 @@ static int smu_v15_0_0_get_dpm_table(struct smu_context *smu, struct dpm_clocks
return 0;
}
+static int smu_v15_0_5_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table)
+{
+ DpmClocks_t_v15_0_5 *clk_table = smu->smu_table.clocks_table;
+ uint8_t idx;
+
+ /*
+ * Only the Clock information of SOC and
+ * VPE is copied to provide VPE DPM settings for use.
+ */
+ for (idx = 0; idx < NUM_SOCCLK_DPM_LEVELS; idx++) {
+ clock_table->SocClocks[idx].Freq =
+ (idx < clk_table->NumSocClkLevelsEnabled) ? clk_table->SocClocks[idx]:0;
+ clock_table->SocClocks[idx].Vol = 0;
+ }
+
+ for (idx = 0; idx < NUM_VPE_DPM_LEVELS; idx++) {
+ clock_table->VPEClocks[idx].Freq =
+ (idx < clk_table->VpeClkLevelsEnabled) ? clk_table->VPEClocks[idx]:0;
+ clock_table->VPEClocks[idx].Vol = 0;
+ }
+
+ return 0;
+}
+
static int smu_v15_0_common_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table)
{
- smu_v15_0_0_get_dpm_table(smu, clock_table);
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(15, 0, 5))
+ smu_v15_0_5_get_dpm_table(smu, clock_table);
+ else
+ smu_v15_0_0_get_dpm_table(smu, clock_table);
return 0;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h
index 8365b9fea77e..8471ba1a353e 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h
@@ -23,6 +23,19 @@
#ifndef __SMU_V15_0_0_PPT_H__
#define __SMU_V15_0_0_PPT_H__
+#include "amdgpu_smu.h"
+
+#include "pmfw_if/smu_v15_0_0_metrics.h"
+
+typedef struct {
+ MetricsTable_t metrics[2];
+ bool active_idx;
+ uint32_t table_size;
+ uint64_t addr;
+ void __iomem *cpu_addr;
+ uint32_t avg_metric[METRICS_AVERAGE_NPUCLK+1];
+} SMU_15_0_0_MetricsInfo_t;
+
extern void smu_v15_0_0_set_ppt_funcs(struct smu_context *smu);
#endif \ No newline at end of file
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c
index 2105a1d7bb34..4f820db5f8dd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.c
@@ -55,6 +55,13 @@
#define SMUQ10_TO_UINT(x) ((x) >> 10)
#define SMUQ10_FRAC(x) ((x) & 0x3ff)
#define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200))
+/* Convert Q10 watts to milliwatts, preserving the fractional part */
+#define SMUQ10_TO_MILLIWATT(x) (SMUQ10_TO_UINT(x) * MILLIWATT_PER_WATT + \
+ ((SMUQ10_FRAC(x) * MILLIWATT_PER_WATT) >> 10))
+/* Convert Q10 degrees Celsius to millidegrees, preserving the fractional part */
+#define SMUQ10_TO_MILLICELSIUS(x) \
+ (SMUQ10_TO_UINT(x) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES + \
+ ((SMUQ10_FRAC(x) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES) >> 10))
#define hbm_stack_mask_valid(umc_mask) \
(((umc_mask) & 0xF) == 0xF)
@@ -72,6 +79,8 @@
#define FEATURE_MASK(feature) (1ULL << feature)
+static int smu_v15_0_8_init_ppt_limits(struct smu_context *smu);
+
static const struct smu_feature_bits smu_v15_0_8_dpm_features = {
.bits = { SMU_FEATURE_BIT_INIT(FEATURE_ID_DATA_CALCULATION),
SMU_FEATURE_BIT_INIT(FEATURE_ID_DPM_GFXCLK),
@@ -213,7 +222,7 @@ static int smu_v15_0_8_tables_init(struct smu_context *smu)
smu_table->metrics_time = 0;
- driver_pptable = kzalloc(sizeof(PPTable_t), GFP_KERNEL);
+ driver_pptable = kzalloc_obj(PPTable_t);
if (!driver_pptable)
return -ENOMEM;
@@ -411,11 +420,10 @@ static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu,
*value = SMUQ10_ROUND(metrics->DramBandwidthUtilization);
break;
case METRICS_CURR_SOCKETPOWER:
- *value = SMUQ10_ROUND(metrics->SocketPower) << 8;
+ *value = SMUQ10_TO_MILLIWATT(metrics->SocketPower);
break;
case METRICS_TEMPERATURE_HOTSPOT:
- *value = SMUQ10_ROUND(metrics->MaxSocketTemperature) *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxSocketTemperature);
break;
case METRICS_TEMPERATURE_MEM:
{
@@ -433,19 +441,18 @@ static int smu_v15_0_8_get_smu_metrics_data(struct smu_context *smu,
if (!hbm_stack_mask_valid(mask))
continue;
- temp = SMUQ10_ROUND(metrics->HbmTemperature[stack_idx]);
+ temp = metrics->HbmTemperature[stack_idx];
if (temp > max_hbm_temp)
max_hbm_temp = temp;
}
}
- *value = max_hbm_temp * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(max_hbm_temp);
break;
}
/* This is the max of all VRs and not just SOC VR.
*/
case METRICS_TEMPERATURE_VRSOC:
- *value = SMUQ10_ROUND(metrics->MaxVrTemperature) *
- SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+ *value = SMUQ10_TO_MILLICELSIUS(metrics->MaxVrTemperature);
break;
default:
*value = UINT_MAX;
@@ -1019,7 +1026,7 @@ static int smu_v15_0_8_fru_get_product_info(struct smu_context *smu,
struct amdgpu_device *adev = smu->adev;
if (!adev->fru_info) {
- adev->fru_info = kzalloc(sizeof(*adev->fru_info), GFP_KERNEL);
+ adev->fru_info = kzalloc_obj(*adev->fru_info);
if (!adev->fru_info)
return -ENOMEM;
}
@@ -1152,7 +1159,7 @@ static int smu_v15_0_8_set_default_dpm_table(struct smu_context *smu)
if (ret)
return ret;
- return 0;
+ return smu_v15_0_8_init_ppt_limits(smu);
}
static int smu_v15_0_8_irq_process(struct amdgpu_device *adev,
@@ -1766,12 +1773,17 @@ static ssize_t smu_v15_0_8_get_gpu_metrics(struct smu_context *smu, void **table
idx++;
}
- /* Per-VCN clocks */
+ /* Per-VCN clocks and busy */
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
inst = GET_INST(VCN, i);
if (inst >= 0) {
gpu_metrics->current_vclk0[i] = SMUQ10_ROUND(metrics->VclkFrequency[inst]);
gpu_metrics->current_dclk0[i] = SMUQ10_ROUND(metrics->DclkFrequency[inst]);
+ gpu_metrics->vcn_busy[i] = SMUQ10_ROUND(metrics->VcnBusy[inst]);
+ for (j = 0; j < NUM_JPEG_RINGS_FW; ++j)
+ gpu_metrics->jpeg_busy[(i * NUM_JPEG_RINGS_FW) + j] =
+ SMUQ10_ROUND(metrics->JpegBusy[(inst * NUM_JPEG_RINGS_FW)
+ + j]);
}
}
@@ -1842,34 +1854,59 @@ static void smu_v15_0_8_get_unique_id(struct smu_context *smu)
adev->unique_id = pptable->PublicSerialNumberMID;
}
-static int smu_v15_0_8_get_power_limit(struct smu_context *smu,
- uint32_t *current_power_limit,
- uint32_t *default_power_limit,
- uint32_t *max_power_limit,
- uint32_t *min_power_limit)
+static int smu_v15_0_8_get_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t *ppt_limit)
{
- struct smu_table_context *smu_table = &smu->smu_table;
- PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
- uint32_t power_limit = 0;
int ret;
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit, &power_limit);
+ if (limit_type == SMU_PPT_LIMIT_PPT1)
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit,
+ ppt_limit);
+ else
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetPptLimit,
+ ppt_limit);
if (ret) {
dev_err(smu->adev->dev, "Couldn't get PPT limit");
return -EINVAL;
}
- if (current_power_limit)
- *current_power_limit = power_limit;
-
- if (default_power_limit)
- *default_power_limit = pptable->MaxSocketPowerLimit;
-
- if (max_power_limit)
- *max_power_limit = pptable->MaxSocketPowerLimit;
+ return 0;
+}
- if (min_power_limit)
- *min_power_limit = 0;
+static int smu_v15_0_8_init_ppt_limits(struct smu_context *smu)
+{
+ struct smu_table_context *smu_table = &smu->smu_table;
+ PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
+ int i;
+
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].default_value =
+ pptable->MaxSocketPowerLimit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].max =
+ pptable->MaxSocketPowerLimit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].min = 0;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_max =
+ pptable->MaxSocketPowerLimit;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT0].od_min = 0;
+ }
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT0);
+
+ if (pptable->PPT1Max) {
+ for (i = SMU_POWER_SOURCE_AC; i < SMU_POWER_SOURCE_COUNT; i++) {
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].default_value =
+ pptable->PPT1Default;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].max =
+ pptable->PPT1Max;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].min =
+ pptable->PPT1Min;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].od_max =
+ pptable->PPT1Max;
+ smu->ppt_limits.range[i][SMU_PPT_LIMIT_PPT1].od_min =
+ pptable->PPT1Min;
+ }
+ smu->ppt_limits.supported_mask |= BIT(SMU_PPT_LIMIT_PPT1);
+ }
return 0;
}
@@ -1914,7 +1951,7 @@ static int smu_v15_0_8_set_performance_level(struct smu_context *smu,
struct smu_dpm_table *gfx_table = &dpm_context->dpm_tables.gfx_table;
struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table;
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
- int ret;
+ int ret = 0;
switch (level) {
case AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM:
@@ -1955,9 +1992,6 @@ static int smu_v15_0_8_set_performance_level(struct smu_context *smu,
SMU_DPM_TABLE_MAX(uclk_table);
}
- if (ret)
- goto out;
-
smu_cmn_reset_custom_level(smu);
break;
@@ -2207,15 +2241,15 @@ static int smu_v15_0_8_get_thermal_temperature_range(struct smu_context *smu,
return 0;
}
-static int smu_v15_0_8_set_power_limit(struct smu_context *smu,
- enum smu_ppt_limit_type limit_type,
- uint32_t limit)
+static int smu_v15_0_8_set_ppt_limit(struct smu_context *smu,
+ enum smu_ppt_limit_type limit_type,
+ uint32_t limit)
{
struct smu_table_context *smu_table = &smu->smu_table;
PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
int ret;
- if (limit_type == SMU_FAST_PPT_LIMIT) {
+ if (limit_type == SMU_PPT_LIMIT_PPT1) {
if (!pptable->PPT1Max)
return -EOPNOTSUPP;
@@ -2234,49 +2268,7 @@ static int smu_v15_0_8_set_power_limit(struct smu_context *smu,
return ret;
}
- return smu_v15_0_set_power_limit(smu, limit_type, limit);
-}
-
-static int smu_v15_0_8_get_ppt_limit(struct smu_context *smu,
- uint32_t *ppt_limit,
- enum smu_ppt_limit_type type,
- enum smu_ppt_limit_level level)
-{
- struct smu_table_context *smu_table = &smu->smu_table;
- PPTable_t *pptable = (PPTable_t *)smu_table->driver_pptable;
- int ret = 0;
-
- if (!ppt_limit)
- return -EINVAL;
-
- if (type == SMU_FAST_PPT_LIMIT) {
- if (!pptable->PPT1Max)
- return -EOPNOTSUPP;
-
- switch (level) {
- case SMU_PPT_LIMIT_MAX:
- *ppt_limit = pptable->PPT1Max;
- break;
- case SMU_PPT_LIMIT_CURRENT:
- ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetFastPptLimit,
- ppt_limit);
- if (ret)
- dev_err(smu->adev->dev,
- "Get fast PPT limit failed!\n");
- break;
- case SMU_PPT_LIMIT_DEFAULT:
- *ppt_limit = pptable->PPT1Default;
- break;
- case SMU_PPT_LIMIT_MIN:
- *ppt_limit = pptable->PPT1Min;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return ret;
- }
-
- return -EOPNOTSUPP;
+ return smu_v15_0_set_ppt_limit(smu, limit_type, limit);
}
static uint32_t smu_v15_0_8_get_throttler_status(struct smu_context *smu)
@@ -2373,9 +2365,8 @@ static const struct pptable_funcs smu_v15_0_8_ppt_funcs = {
.get_dpm_ultimate_freq = smu_v15_0_8_get_dpm_ultimate_freq,
.get_gpu_metrics = smu_v15_0_8_get_gpu_metrics,
.get_unique_id = smu_v15_0_8_get_unique_id,
- .get_power_limit = smu_v15_0_8_get_power_limit,
- .set_power_limit = smu_v15_0_8_set_power_limit,
.get_ppt_limit = smu_v15_0_8_get_ppt_limit,
+ .set_ppt_limit = smu_v15_0_8_set_ppt_limit,
.emit_clk_levels = smu_v15_0_8_emit_clk_levels,
.read_sensor = smu_v15_0_8_read_sensor,
.populate_umd_state_clk = smu_v15_0_8_populate_umd_state_clk,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h
index 4dfc40aaffcb..46fce0a79c21 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_8_ppt.h
@@ -125,7 +125,7 @@ typedef struct {
SMU_ARRAY(SMU_MATTR(PCIE_BANDWIDTH_ACC), SMU_MUNIT(NONE), \
SMU_MTYPE(U64), pcie_bandwidth_acc, SMU_15_0_8_MAX_MID); \
SMU_ARRAY(SMU_MATTR(PCIE_BANDWIDTH_INST), SMU_MUNIT(BW_1), \
- SMU_MTYPE(U32), pcie_bandwidth_inst, SMU_15_0_8_MAX_MID); \
+ SMU_MTYPE(U64), pcie_bandwidth_inst, SMU_15_0_8_MAX_MID); \
SMU_SCALAR(SMU_MATTR(PCIE_L0_TO_RECOV_COUNT_ACC), SMU_MUNIT(NONE), \
SMU_MTYPE(U64), pcie_l0_to_recov_count_acc); \
SMU_SCALAR(SMU_MATTR(PCIE_REPLAY_COUNT_ACC), SMU_MUNIT(NONE), \
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index d365f06ac1ac..2bd3ea17e789 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1544,3 +1544,143 @@ int smu_cmn_dpm_pcie_width_idx(int width)
return ret;
}
+
+static int smu_cmn_get_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size)
+{
+ const struct smc_firmware_header_v2_0 *v2;
+ struct amdgpu_device *adev = smu->adev;
+ size_t fw_size = adev->pm.fw->size;
+ uint32_t ppt_offset_bytes;
+ uint32_t ppt_size_bytes;
+
+ if (fw_size < sizeof(*v2)) {
+ dev_err(adev->dev,
+ "SMC firmware too small for v2.0 header: %zu < %zu\n",
+ fw_size, sizeof(*v2));
+ return -EINVAL;
+ }
+
+ v2 = (const struct smc_firmware_header_v2_0 *)adev->pm.fw->data;
+
+ ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes);
+ ppt_size_bytes = le32_to_cpu(v2->ppt_size_bytes);
+
+ if (ppt_offset_bytes > fw_size ||
+ ppt_size_bytes > fw_size - ppt_offset_bytes) {
+ dev_err(adev->dev,
+ "pptable v2.0 exceeds firmware binary: offset %u + size %u > %zu\n",
+ ppt_offset_bytes, ppt_size_bytes, fw_size);
+ return -EINVAL;
+ }
+
+ *size = ppt_size_bytes;
+ *table = (uint8_t *)v2 + ppt_offset_bytes;
+
+ return 0;
+}
+
+static int smu_cmn_get_pptable_v2_1(struct smu_context *smu, void **table,
+ uint32_t *size, uint32_t pptable_id)
+{
+ const struct smc_firmware_header_v2_1 *v2_1;
+ struct amdgpu_device *adev = smu->adev;
+ struct smc_soft_pptable_entry *entries;
+ size_t fw_size = adev->pm.fw->size;
+ uint32_t pptable_entry_offset;
+ uint32_t ppt_offset_bytes;
+ uint32_t ppt_size_bytes;
+ uint32_t pptable_count;
+ int i;
+
+ if (fw_size < sizeof(*v2_1)) {
+ dev_err(adev->dev,
+ "SMC firmware too small for v2.1 header: %zu < %zu\n",
+ fw_size, sizeof(*v2_1));
+ return -EINVAL;
+ }
+
+ v2_1 = (const struct smc_firmware_header_v2_1 *)adev->pm.fw->data;
+
+ pptable_entry_offset = le32_to_cpu(v2_1->pptable_entry_offset);
+ pptable_count = le32_to_cpu(v2_1->pptable_count);
+
+ if (pptable_entry_offset > fw_size ||
+ pptable_count > (fw_size - pptable_entry_offset) / sizeof(*entries)) {
+ dev_err(adev->dev,
+ "pptable v2.1 entry array exceeds firmware binary: offset %u, count %u\n",
+ pptable_entry_offset, pptable_count);
+ return -EINVAL;
+ }
+
+ entries = (struct smc_soft_pptable_entry *)
+ ((uint8_t *)v2_1 + pptable_entry_offset);
+
+ for (i = 0; i < pptable_count; i++) {
+ if (le32_to_cpu(entries[i].id) != pptable_id)
+ continue;
+
+ ppt_offset_bytes = le32_to_cpu(entries[i].ppt_offset_bytes);
+ ppt_size_bytes = le32_to_cpu(entries[i].ppt_size_bytes);
+
+ if (ppt_offset_bytes > fw_size ||
+ ppt_size_bytes > fw_size - ppt_offset_bytes) {
+ dev_err(adev->dev,
+ "pptable entry %d exceeds firmware binary: offset %u + size %u > %zu\n",
+ i, ppt_offset_bytes, ppt_size_bytes, fw_size);
+ return -EINVAL;
+ }
+
+ *table = (uint8_t *)v2_1 + ppt_offset_bytes;
+ *size = ppt_size_bytes;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * smu_cmn_get_pptable_from_firmware - locate the soft pptable embedded in the
+ * SMC firmware binary.
+ * @smu: SMU context
+ * @table: on success, set to the start of the pptable within the firmware
+ * blob
+ * @size: on success, set to the pptable size in bytes
+ * @pptable_id: the entry ID to search for (used only for v2.1 binaries)
+ *
+ * Reads the firmware header version and dispatches to the appropriate v2.x
+ * parser. Only major version 2 is supported; minor version selects between
+ * the single-entry (v2.0) and multi-entry directory (v2.1) layouts.
+ *
+ * Return: 0 on success, -EINVAL for an unsupported version or if the
+ * requested pptable cannot be found or exceeds the binary bounds.
+ */
+int smu_cmn_get_pptable_from_firmware(struct smu_context *smu, void **table,
+ uint32_t *size, uint32_t pptable_id)
+{
+ const struct smc_firmware_header_v1_0 *hdr;
+ struct amdgpu_device *adev = smu->adev;
+ uint16_t version_major, version_minor;
+
+ hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data;
+ if (!hdr)
+ return -EINVAL;
+
+ dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id);
+
+ version_major = le16_to_cpu(hdr->header.header_version_major);
+ version_minor = le16_to_cpu(hdr->header.header_version_minor);
+ if (version_major != 2) {
+ dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n",
+ version_major, version_minor);
+ return -EINVAL;
+ }
+
+ switch (version_minor) {
+ case 0:
+ return smu_cmn_get_pptable_v2_0(smu, table, size);
+ case 1:
+ return smu_cmn_get_pptable_v2_1(smu, table, size, pptable_id);
+ default:
+ return -EINVAL;
+ }
+}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index 0e119965ce13..ae6742f5298f 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -113,6 +113,16 @@ static inline int pcie_gen_to_speed(uint32_t gen)
return ((gen == 0) ? link_speed[0] : link_speed[gen - 1]);
}
+static inline bool smu_cmn_custom_params_count_valid(u32 max_idx, u32 params_count)
+{
+ return max_idx == params_count;
+}
+
+static inline bool smu_cmn_custom_params_clock_valid(long clock_idx, long clock_count)
+{
+ return clock_idx >= 0 && clock_idx < clock_count;
+}
+
int smu_cmn_send_smc_msg_with_param(struct smu_context *smu,
enum smu_message_type msg,
uint32_t param,
@@ -239,6 +249,9 @@ int smu_cmn_dpm_pcie_gen_idx(int gen);
int smu_cmn_dpm_pcie_width_idx(int width);
int smu_cmn_check_fw_version(struct smu_context *smu);
+int smu_cmn_get_pptable_from_firmware(struct smu_context *smu, void **table,
+ uint32_t *size, uint32_t pptable_id);
+
/*SMU gpu metrics */
/* Attribute ID mapping */
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
index 24848da90234..6244f8895668 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h
@@ -82,7 +82,8 @@
#define smu_i2c_fini(smu) smu_ppt_funcs(i2c_fini, 0, smu)
#define smu_get_unique_id(smu) smu_ppt_funcs(get_unique_id, 0, smu)
#define smu_log_thermal_throttling(smu) smu_ppt_funcs(log_thermal_throttling_event, 0, smu)
-#define smu_get_asic_power_limits(smu, current, default, max, min) smu_ppt_funcs(get_power_limit, 0, smu, current, default, max, min)
+#define smu_get_asic_ppt_limit(smu, type, current) \
+ smu_ppt_funcs(get_ppt_limit, -EOPNOTSUPP, smu, type, current)
#define smu_get_pp_feature_mask(smu, buf) smu_ppt_funcs(get_pp_feature_mask, 0, smu, buf)
#define smu_set_pp_feature_mask(smu, new_mask) smu_ppt_funcs(set_pp_feature_mask, 0, smu, new_mask)
#define smu_gfx_ulv_control(smu, enablement) smu_ppt_funcs(gfx_ulv_control, 0, smu, enablement)
@@ -98,7 +99,6 @@
#define smu_is_asic_wbrf_supported(smu) smu_ppt_funcs(is_asic_wbrf_supported, false, smu)
#define smu_enable_uclk_shadow(smu, enable) smu_ppt_funcs(enable_uclk_shadow, 0, smu, enable)
#define smu_set_wbrf_exclusion_ranges(smu, freq_band_range) smu_ppt_funcs(set_wbrf_exclusion_ranges, -EOPNOTSUPP, smu, freq_band_range)
-#define smu_get_ras_smu_drv(smu, ras_smu_drv) smu_ppt_funcs(get_ras_smu_drv, -EOPNOTSUPP, smu, ras_smu_drv)
#endif
#endif