drm/amd/pm: add support for new smu metrics table for vangogh

This patch is to add support for new smu metrics table for vangogh.
It will support new and legacy smu metrics table in the meanwhile.
New pmfw version is 4.63.36.00, and new smu interface version is #3.

v1: check smu pmfw version to determine to use new or legacy smu metrics
table

v2: check smu interface version to determine to use new or legacy smu
metrics table

v3: revise wrong symbol

Signed-off-by: Xiaojian Du <Xiaojian.Du@amd.com>
Reviewed-by: Kevin Wang <kevin1.wang@amd.com>
Reviewed-by: Huang Rui <ray.huang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Xiaojian Du 2021-04-09 16:19:43 +08:00 committed by Alex Deucher
parent f4994be248
commit 86c8236eec
1 changed files with 356 additions and 44 deletions

View File

@ -194,18 +194,34 @@ static int vangogh_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
struct amdgpu_device *adev = smu->adev;
uint32_t if_version;
uint32_t ret = 0;
ret = smu_cmn_get_smc_version(smu, &if_version, NULL);
if (ret) {
dev_err(adev->dev, "Failed to get smu if version!\n");
goto err0_out;
}
SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
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_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE,
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, sizeof(DpmActivityMonitorCoeffExt_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
if (if_version < 0x3) {
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_legacy_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_legacy_t), GFP_KERNEL);
} else {
SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
}
if (!smu_table->metrics_table)
goto err0_out;
smu_table->metrics_time = 0;
@ -235,13 +251,12 @@ err0_out:
return -ENOMEM;
}
static int vangogh_get_smu_metrics_data(struct smu_context *smu,
static int vangogh_get_legacy_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
{
struct smu_table_context *smu_table = &smu->smu_table;
SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
SmuMetrics_legacy_t *metrics = (SmuMetrics_legacy_t *)smu_table->metrics_table;
int ret = 0;
mutex_lock(&smu->metrics_lock);
@ -311,6 +326,103 @@ static int vangogh_get_smu_metrics_data(struct smu_context *smu,
return ret;
}
static int vangogh_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
{
struct smu_table_context *smu_table = &smu->smu_table;
SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
int ret = 0;
mutex_lock(&smu->metrics_lock);
ret = smu_cmn_get_metrics_table_locked(smu,
NULL,
false);
if (ret) {
mutex_unlock(&smu->metrics_lock);
return ret;
}
switch (member) {
case METRICS_AVERAGE_GFXCLK:
*value = metrics->Current.GfxclkFrequency;
break;
case METRICS_AVERAGE_SOCCLK:
*value = metrics->Current.SocclkFrequency;
break;
case METRICS_AVERAGE_VCLK:
*value = metrics->Current.VclkFrequency;
break;
case METRICS_AVERAGE_DCLK:
*value = metrics->Current.DclkFrequency;
break;
case METRICS_AVERAGE_UCLK:
*value = metrics->Current.MemclkFrequency;
break;
case METRICS_AVERAGE_GFXACTIVITY:
*value = metrics->Current.GfxActivity;
break;
case METRICS_AVERAGE_VCNACTIVITY:
*value = metrics->Current.UvdActivity;
break;
case METRICS_AVERAGE_SOCKETPOWER:
*value = (metrics->Current.CurrentSocketPower << 8) /
1000;
break;
case METRICS_TEMPERATURE_EDGE:
*value = metrics->Current.GfxTemperature / 100 *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
case METRICS_TEMPERATURE_HOTSPOT:
*value = metrics->Current.SocTemperature / 100 *
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
break;
case METRICS_THROTTLER_STATUS:
*value = metrics->Current.ThrottlerStatus;
break;
case METRICS_VOLTAGE_VDDGFX:
*value = metrics->Current.Voltage[2];
break;
case METRICS_VOLTAGE_VDDSOC:
*value = metrics->Current.Voltage[1];
break;
case METRICS_AVERAGE_CPUCLK:
memcpy(value, &metrics->Current.CoreFrequency[0],
smu->cpu_core_num * sizeof(uint16_t));
break;
default:
*value = UINT_MAX;
break;
}
mutex_unlock(&smu->metrics_lock);
return ret;
}
static int vangogh_common_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member,
uint32_t *value)
{
struct amdgpu_device *adev = smu->adev;
uint32_t if_version;
int ret = 0;
ret = smu_cmn_get_smc_version(smu, &if_version, NULL);
if (ret) {
dev_err(adev->dev, "Failed to get smu if version!\n");
return ret;
}
if (if_version < 0x3)
ret = vangogh_get_legacy_smu_metrics_data(smu, member, value);
else
ret = vangogh_get_smu_metrics_data(smu, member, value);
return ret;
}
static int vangogh_allocate_dpm_context(struct smu_context *smu)
{
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
@ -447,11 +559,11 @@ static int vangogh_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_typ
return 0;
}
static int vangogh_print_clk_levels(struct smu_context *smu,
static int vangogh_print_legacy_clk_levels(struct smu_context *smu,
enum smu_clk_type clk_type, char *buf)
{
DpmClocks_t *clk_table = smu->smu_table.clocks_table;
SmuMetrics_t metrics;
SmuMetrics_legacy_t metrics;
struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
int i, size = 0, ret = 0;
uint32_t cur_value = 0, value = 0, count = 0;
@ -546,6 +658,126 @@ static int vangogh_print_clk_levels(struct smu_context *smu,
return size;
}
static int vangogh_print_clk_levels(struct smu_context *smu,
enum smu_clk_type clk_type, char *buf)
{
DpmClocks_t *clk_table = smu->smu_table.clocks_table;
SmuMetrics_t metrics;
struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
int i, size = 0, ret = 0;
uint32_t cur_value = 0, value = 0, count = 0;
bool cur_value_match_level = false;
memset(&metrics, 0, sizeof(metrics));
ret = smu_cmn_get_metrics_table(smu, &metrics, false);
if (ret)
return ret;
switch (clk_type) {
case SMU_OD_SCLK:
if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
size = sprintf(buf, "%s:\n", "OD_SCLK");
size += sprintf(buf + size, "0: %10uMhz\n",
(smu->gfx_actual_hard_min_freq > 0) ? smu->gfx_actual_hard_min_freq : smu->gfx_default_hard_min_freq);
size += sprintf(buf + size, "1: %10uMhz\n",
(smu->gfx_actual_soft_max_freq > 0) ? smu->gfx_actual_soft_max_freq : smu->gfx_default_soft_max_freq);
}
break;
case SMU_OD_CCLK:
if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
size = sprintf(buf, "CCLK_RANGE in Core%d:\n", smu->cpu_core_id_select);
size += sprintf(buf + size, "0: %10uMhz\n",
(smu->cpu_actual_soft_min_freq > 0) ? smu->cpu_actual_soft_min_freq : smu->cpu_default_soft_min_freq);
size += sprintf(buf + size, "1: %10uMhz\n",
(smu->cpu_actual_soft_max_freq > 0) ? smu->cpu_actual_soft_max_freq : smu->cpu_default_soft_max_freq);
}
break;
case SMU_OD_RANGE:
if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) {
size = sprintf(buf, "%s:\n", "OD_RANGE");
size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
smu->gfx_default_hard_min_freq, smu->gfx_default_soft_max_freq);
size += sprintf(buf + size, "CCLK: %7uMhz %10uMhz\n",
smu->cpu_default_soft_min_freq, smu->cpu_default_soft_max_freq);
}
break;
case SMU_SOCCLK:
/* the level 3 ~ 6 of socclk use the same frequency for vangogh */
count = clk_table->NumSocClkLevelsEnabled;
cur_value = metrics.Current.SocclkFrequency;
break;
case SMU_VCLK:
count = clk_table->VcnClkLevelsEnabled;
cur_value = metrics.Current.VclkFrequency;
break;
case SMU_DCLK:
count = clk_table->VcnClkLevelsEnabled;
cur_value = metrics.Current.DclkFrequency;
break;
case SMU_MCLK:
count = clk_table->NumDfPstatesEnabled;
cur_value = metrics.Current.MemclkFrequency;
break;
case SMU_FCLK:
count = clk_table->NumDfPstatesEnabled;
ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetFclkFrequency, 0, &cur_value);
if (ret)
return ret;
break;
default:
break;
}
switch (clk_type) {
case SMU_SOCCLK:
case SMU_VCLK:
case SMU_DCLK:
case SMU_MCLK:
case SMU_FCLK:
for (i = 0; i < count; i++) {
ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value);
if (ret)
return ret;
if (!value)
continue;
size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
cur_value == value ? "*" : "");
if (cur_value == value)
cur_value_match_level = true;
}
if (!cur_value_match_level)
size += sprintf(buf + size, " %uMhz *\n", cur_value);
break;
default:
break;
}
return size;
}
static int vangogh_common_print_clk_levels(struct smu_context *smu,
enum smu_clk_type clk_type, char *buf)
{
struct amdgpu_device *adev = smu->adev;
uint32_t if_version;
int ret = 0;
ret = smu_cmn_get_smc_version(smu, &if_version, NULL);
if (ret) {
dev_err(adev->dev, "Failed to get smu if version!\n");
return ret;
}
if (if_version < 0x3)
ret = vangogh_print_legacy_clk_levels(smu, clk_type, buf);
else
ret = vangogh_print_clk_levels(smu, clk_type, buf);
return ret;
}
static int vangogh_get_profiling_clk_mask(struct smu_context *smu,
enum amd_dpm_forced_level level,
uint32_t *vclk_mask,
@ -1278,57 +1510,57 @@ static int vangogh_read_sensor(struct smu_context *smu,
mutex_lock(&smu->sensor_lock);
switch (sensor) {
case AMDGPU_PP_SENSOR_GPU_LOAD:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_AVERAGE_GFXACTIVITY,
(uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_GPU_POWER:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_AVERAGE_SOCKETPOWER,
(uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_EDGE_TEMP:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_TEMPERATURE_EDGE,
(uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_TEMPERATURE_HOTSPOT,
(uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_GFX_MCLK:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_AVERAGE_UCLK,
(uint32_t *)data);
*(uint32_t *)data *= 100;
*size = 4;
break;
case AMDGPU_PP_SENSOR_GFX_SCLK:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_AVERAGE_GFXCLK,
(uint32_t *)data);
*(uint32_t *)data *= 100;
*size = 4;
break;
case AMDGPU_PP_SENSOR_VDDGFX:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_VOLTAGE_VDDGFX,
(uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_VDDNB:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_VOLTAGE_VDDSOC,
(uint32_t *)data);
*size = 4;
break;
case AMDGPU_PP_SENSOR_CPU_CLK:
ret = vangogh_get_smu_metrics_data(smu,
ret = vangogh_common_get_smu_metrics_data(smu,
METRICS_AVERAGE_CPUCLK,
(uint32_t *)data);
*size = smu->cpu_core_num * sizeof(uint16_t);
@ -1402,6 +1634,60 @@ static int vangogh_set_watermarks_table(struct smu_context *smu,
return 0;
}
static ssize_t vangogh_get_legacy_gpu_metrics(struct smu_context *smu,
void **table)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v2_1 *gpu_metrics =
(struct gpu_metrics_v2_1 *)smu_table->gpu_metrics_table;
SmuMetrics_legacy_t metrics;
int ret = 0;
ret = smu_cmn_get_metrics_table(smu, &metrics, true);
if (ret)
return ret;
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1);
gpu_metrics->temperature_gfx = metrics.GfxTemperature;
gpu_metrics->temperature_soc = metrics.SocTemperature;
memcpy(&gpu_metrics->temperature_core[0],
&metrics.CoreTemperature[0],
sizeof(uint16_t) * 4);
gpu_metrics->temperature_l3[0] = metrics.L3Temperature[0];
gpu_metrics->average_gfx_activity = metrics.GfxActivity;
gpu_metrics->average_mm_activity = metrics.UvdActivity;
gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
gpu_metrics->average_cpu_power = metrics.Power[0];
gpu_metrics->average_soc_power = metrics.Power[1];
gpu_metrics->average_gfx_power = metrics.Power[2];
memcpy(&gpu_metrics->average_core_power[0],
&metrics.CorePower[0],
sizeof(uint16_t) * 4);
gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
gpu_metrics->average_dclk_frequency = metrics.DclkFrequency;
memcpy(&gpu_metrics->current_coreclk[0],
&metrics.CoreFrequency[0],
sizeof(uint16_t) * 4);
gpu_metrics->current_l3clk[0] = metrics.L3Frequency[0];
gpu_metrics->throttle_status = metrics.ThrottlerStatus;
gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
*table = (void *)gpu_metrics;
return sizeof(struct gpu_metrics_v2_1);
}
static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
void **table)
{
@ -1417,39 +1703,44 @@ static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 2, 1);
gpu_metrics->temperature_gfx = metrics.GfxTemperature;
gpu_metrics->temperature_soc = metrics.SocTemperature;
gpu_metrics->temperature_gfx = metrics.Current.GfxTemperature;
gpu_metrics->temperature_soc = metrics.Current.SocTemperature;
memcpy(&gpu_metrics->temperature_core[0],
&metrics.CoreTemperature[0],
sizeof(uint16_t) * 8);
gpu_metrics->temperature_l3[0] = metrics.L3Temperature[0];
gpu_metrics->temperature_l3[1] = metrics.L3Temperature[1];
&metrics.Current.CoreTemperature[0],
sizeof(uint16_t) * 4);
gpu_metrics->temperature_l3[0] = metrics.Current.L3Temperature[0];
gpu_metrics->average_gfx_activity = metrics.GfxActivity;
gpu_metrics->average_mm_activity = metrics.UvdActivity;
gpu_metrics->average_gfx_activity = metrics.Current.GfxActivity;
gpu_metrics->average_mm_activity = metrics.Current.UvdActivity;
gpu_metrics->average_socket_power = metrics.CurrentSocketPower;
gpu_metrics->average_cpu_power = metrics.Power[0];
gpu_metrics->average_soc_power = metrics.Power[1];
gpu_metrics->average_gfx_power = metrics.Power[2];
gpu_metrics->average_socket_power = metrics.Current.CurrentSocketPower;
gpu_metrics->average_cpu_power = metrics.Current.Power[0];
gpu_metrics->average_soc_power = metrics.Current.Power[1];
gpu_metrics->average_gfx_power = metrics.Current.Power[2];
memcpy(&gpu_metrics->average_core_power[0],
&metrics.CorePower[0],
sizeof(uint16_t) * 8);
&metrics.Average.CorePower[0],
sizeof(uint16_t) * 4);
gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
gpu_metrics->average_fclk_frequency = metrics.MemclkFrequency;
gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
gpu_metrics->average_dclk_frequency = metrics.DclkFrequency;
gpu_metrics->average_gfxclk_frequency = metrics.Average.GfxclkFrequency;
gpu_metrics->average_socclk_frequency = metrics.Average.SocclkFrequency;
gpu_metrics->average_uclk_frequency = metrics.Average.MemclkFrequency;
gpu_metrics->average_fclk_frequency = metrics.Average.MemclkFrequency;
gpu_metrics->average_vclk_frequency = metrics.Average.VclkFrequency;
gpu_metrics->average_dclk_frequency = metrics.Average.DclkFrequency;
gpu_metrics->current_gfxclk = metrics.Current.GfxclkFrequency;
gpu_metrics->current_socclk = metrics.Current.SocclkFrequency;
gpu_metrics->current_uclk = metrics.Current.MemclkFrequency;
gpu_metrics->current_fclk = metrics.Current.MemclkFrequency;
gpu_metrics->current_vclk = metrics.Current.VclkFrequency;
gpu_metrics->current_dclk = metrics.Current.DclkFrequency;
memcpy(&gpu_metrics->current_coreclk[0],
&metrics.CoreFrequency[0],
sizeof(uint16_t) * 8);
gpu_metrics->current_l3clk[0] = metrics.L3Frequency[0];
gpu_metrics->current_l3clk[1] = metrics.L3Frequency[1];
&metrics.Current.CoreFrequency[0],
sizeof(uint16_t) * 4);
gpu_metrics->current_l3clk[0] = metrics.Current.L3Frequency[0];
gpu_metrics->throttle_status = metrics.ThrottlerStatus;
gpu_metrics->throttle_status = metrics.Current.ThrottlerStatus;
gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
@ -1458,6 +1749,27 @@ static ssize_t vangogh_get_gpu_metrics(struct smu_context *smu,
return sizeof(struct gpu_metrics_v2_1);
}
static ssize_t vangogh_common_get_gpu_metrics(struct smu_context *smu,
void **table)
{
struct amdgpu_device *adev = smu->adev;
uint32_t if_version;
int ret = 0;
ret = smu_cmn_get_smc_version(smu, &if_version, NULL);
if (ret) {
dev_err(adev->dev, "Failed to get smu if version!\n");
return ret;
}
if (if_version < 0x3)
ret = vangogh_get_legacy_gpu_metrics(smu, table);
else
ret = vangogh_get_gpu_metrics(smu, table);
return ret;
}
static int vangogh_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type,
long input[], uint32_t size)
{
@ -1876,9 +2188,9 @@ static const struct pptable_funcs vangogh_ppt_funcs = {
.set_watermarks_table = vangogh_set_watermarks_table,
.set_driver_table_location = smu_v11_0_set_driver_table_location,
.interrupt_work = smu_v11_0_interrupt_work,
.get_gpu_metrics = vangogh_get_gpu_metrics,
.get_gpu_metrics = vangogh_common_get_gpu_metrics,
.od_edit_dpm_table = vangogh_od_edit_dpm_table,
.print_clk_levels = vangogh_print_clk_levels,
.print_clk_levels = vangogh_common_print_clk_levels,
.set_default_dpm_table = vangogh_set_default_dpm_tables,
.set_fine_grain_gfx_freq_parameters = vangogh_set_fine_grain_gfx_freq_parameters,
.system_features_control = vangogh_system_features_control,