Replace the legacy SMU table-copy metrics path with a DRAM-mapped accumulator-based approach for SMU v15.0.0:
- Add MSG_MAP entries for GetMetricsTableVersion, GetMetricsTableLogSample, and GetMetricsTableLogDramAddr messages. - Introduce SMU_15_0_0_MetricsInfo_t wrapping MetricsTable_t with cached address, table size, and pre-computed average metrics. - Add smu_v15_0_0_get_metrics_table() which obtains the DRAM address from the SMU, ioremaps it, and copies the metrics snapshot. - Add smu_v15_0_0_compute_all_metrics() to derive averaged clocks, activity, power, and temperature from accumulator deltas between consecutive samples. - Rework smu_v15_0_0_get_smu_metrics_data() to use the new accumulator-diff path, replacing the per-member switch statement with a single lookup into pre-computed avg_metric[]. - Rename the old smu_v15_0_0_get_metrics_table() to smu_v15_0_0_get_gpu_metrics_table(), preserving it for the gpu_metrics v3.0 export path. Signed-off-by: Pratik Vishwakarma <[email protected]> Signed-off-by: Suresh Guttula <[email protected]> Signed-off-by: Kanala Ramalingeswara Reddy <[email protected]> Signed-off-by: Shubhankar Milind Sardeshpande <[email protected]> --- .../pm/swsmu/inc/pmfw_if/smu_v15_0_0_ppsmc.h | 5 +- drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h | 3 + .../drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c | 246 +++++++++++------- .../drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h | 14 + 4 files changed, 166 insertions(+), 102 deletions(-) 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..e1b92d2dbc59 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -295,6 +295,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/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c index bb8d09e73c7d..d2ae631b6b27 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 @@ -119,6 +119,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] = { @@ -173,7 +176,7 @@ static int smu_v15_0_0_init_smc_tables(struct smu_context *smu) 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; @@ -299,7 +302,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 +332,156 @@ static int smu_v15_0_0_get_metrics_table(struct smu_context *smu, return 0; } + +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 = NULL; + struct smu_msg_ctl *ctl = &smu->msg_ctl; + struct smu_msg_args args = {0}; + int table_size = metrics_info->table_size; + uint64_t addr = metrics_info->addr; + int ret; + + if (smu_table->metrics_time && + !time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) + return 0; + + if (addr == 0) { + struct smu_msg_args args = { + .msg = SMU_MSG_GetMetricsTableLogDramAddr, + .num_args = 0, + .num_out_args = 3, + }; + + ret = ctl->ops->send_msg(ctl, &args); + + if (ret) + return ret; + + addr = ((uint64_t)args.out_args[1] << 32) | args.out_args[0]; + table_size = args.out_args[2]; + metrics_info->addr = addr; + metrics_info->table_size = table_size; + } + + cpu_addr = ioremap_wc(addr, table_size); + 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) { + amdgpu_hdp_invalidate(smu->adev, NULL);//best to flush before copy + if (table_size <= sizeof(MetricsTable_t)) + memcpy(&metrics_info->metrics, cpu_addr, table_size); + else + memcpy(&metrics_info->metrics, cpu_addr, sizeof(MetricsTable_t)); + } + iounmap(cpu_addr); + return ret; +} + +#define get_diff_count(a, b) \ + (a > b ? ((MAX_UINT32 - a) + b + 1) : (b - a)) +#define get_diff_val(a, b) \ + (a > b ? ((MAX_UINT64 - a) + b + 1) : (b - a)) + +static void smu_v15_0_0_compute_all_metrics( + SMU_15_0_0_MetricsInfo_t *prev, + SMU_15_0_0_MetricsInfo_t *curr) +{ + uint64_t counter, val; + MetricsTable_IOD_t *p = &prev->metrics.IOD; + MetricsTable_IOD_t *c = &curr->metrics.IOD; + + counter = get_diff_count(p->AccumulationCounter, c->AccumulationCounter); + if (!counter) + return; + + /* Accumulator-based clock frequencies (fixed-point /1024) */ + val = get_diff_val(p->GfxclkFreqEffAcc, c->GfxclkFreqEffAcc); + curr->avg_metric[METRICS_AVERAGE_GFXCLK] = (val / counter) / 1024; + + val = get_diff_val(p->SocclkFreqEffAcc, c->SocclkFreqEffAcc); + curr->avg_metric[METRICS_AVERAGE_SOCCLK] = (val / counter) / 1024; + + val = get_diff_val(p->VclkFreqEffAcc, c->VclkFreqEffAcc); + curr->avg_metric[METRICS_AVERAGE_VCLK] = (val / counter) / 1024; + + curr->avg_metric[METRICS_AVERAGE_DCLK] = 0; + + val = get_diff_val(p->MemclkFreqEffAcc, c->MemclkFreqEffAcc); + curr->avg_metric[METRICS_AVERAGE_UCLK] = (val / counter) / 1024; + + val = get_diff_val(p->FclkFreqEffAcc, c->FclkFreqEffAcc); + curr->avg_metric[METRICS_AVERAGE_FCLK] = (val / counter) / 1024; + + val = get_diff_val(p->NpuhclkFreqEffAcc, c->NpuhclkFreqEffAcc); + curr->avg_metric[METRICS_AVERAGE_NPUCLK] = (val / counter) / 1024; + + /* Activity (fixed-point /1024) */ + val = get_diff_val(p->GfxBusyAcc, c->GfxBusyAcc); + curr->avg_metric[METRICS_AVERAGE_GFXACTIVITY] = (val / counter) / 1024; + + val = get_diff_val(p->VcnBusyAcc, c->VcnBusyAcc); + curr->avg_metric[METRICS_AVERAGE_VCNACTIVITY] = (val / counter) / 1024; + + /* Power (fixed-point /1024) */ + val = get_diff_val(p->ApuPowerAcc, c->ApuPowerAcc); + curr->avg_metric[METRICS_AVERAGE_SOCKETPOWER] = (val / counter) / 1024; + + val = get_diff_val(p->SystemPowerAcc, c->SystemPowerAcc); + curr->avg_metric[METRICS_CURR_SOCKETPOWER] = (val / counter) / 1024; + + /* Temperature */ + val = get_diff_val(p->GFX_TempAcc, c->GFX_TempAcc); + curr->avg_metric[METRICS_TEMPERATURE_EDGE] = val / counter; + + /* Static zero values */ + curr->avg_metric[METRICS_VOLTAGE_VDDGFX] = 0; + curr->avg_metric[METRICS_VOLTAGE_VDDSOC] = 0; +} + 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; - SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; - int ret = 0; + SMU_15_0_0_MetricsInfo_t *prev_metrics; + SMU_15_0_0_MetricsInfo_t *curr_metrics; + int ret; - ret = smu_v15_0_0_get_metrics_table(smu, NULL, false); - if (ret) + prev_metrics = kzalloc(sizeof(SMU_15_0_0_MetricsInfo_t), GFP_KERNEL); + if (!prev_metrics) + return -ENOMEM; + + memcpy(prev_metrics, smu_table->metrics_table, + sizeof(SMU_15_0_0_MetricsInfo_t)); + ret = smu_v15_0_0_get_metrics_table(smu, + (SMU_15_0_0_MetricsInfo_t *)smu_table->metrics_table); + if (ret) { + kfree(prev_metrics); 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; + curr_metrics = (SMU_15_0_0_MetricsInfo_t *)smu_table->metrics_table; + + if (prev_metrics->metrics.IOD.AccumulationCounter != + curr_metrics->metrics.IOD.AccumulationCounter) { + /* New sample: compute all accumulator-based metrics at once */ + smu_v15_0_0_compute_all_metrics(prev_metrics, curr_metrics); } - return ret; + *value = curr_metrics->avg_metric[member]; + + kfree(prev_metrics); + return 0; } static int smu_v15_0_0_read_sensor(struct smu_context *smu, @@ -634,7 +678,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; 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..a80d9b2ab633 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,20 @@ #ifndef __SMU_V15_0_0_PPT_H__ #define __SMU_V15_0_0_PPT_H__ +#include "amdgpu_smu.h" + +#define MAX_UINT32 0x00000000FFFFFFFF +#define MAX_UINT64 0xFFFFFFFFFFFFFFFF + +#include "pmfw_if/smu_v15_0_0_metrics.h" + +typedef struct { + MetricsTable_t metrics; + uint32_t table_size; + uint64_t 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 -- 2.43.0
