Re: [PATCH V5 2/2] drm/amd/pm/smu15: switch SMU v15.0.0 to DRAM-based accumulator metrics

"Lazar, Lijo" <[email protected]> Mon, 27 Jul 2026 21:11:16 +0530
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>

On 27-Jul-26 9:03 PM, Shubhankar Milind Sardeshpande wrote:
> Replace the legacy SMU table-copy metrics path with a DRAM-mapped,
> accumulator-based approach for SMU v15.0.0, using a ping-pong buffer
> to compute averaged metrics from deltas between consecutive samples.
> 
> - Add GetMetricsTableVersion, GetMetricsTableLogSample and
>    GetMetricsTableLogDramAddr messages and their MSG_MAP entries.
> - Introduce SMU_15_0_0_MetricsInfo_t holding two MetricsTable_t
>    buffers, the mapped DRAM address, table size and pre-computed
>    avg_metric[] values.
> - Resolve and ioremap_wc() the firmware log DRAM address once in
>    init_smc_tables(); iounmap() it in fini_smc_tables().
> - Fetch samples into the inactive buffer, compute averaged clocks,
>    activity, power and temperature via wrapping_sub() accumulator
>    deltas, then swap the active index.
> - Rename the old get_metrics_table() to get_gpu_metrics_table() for
>    the gpu_metrics v3.0 export path.
> - Move AMDGPU_PP_SENSOR_SS_APU_SHARE, AMDGPU_PP_SENSOR_SS_DGPU_SHARE
>    to default case since they are not supported.
> 
> Co-developed-by: Pratik Vishwakarma <[email protected]>
> Signed-off-by: Pratik Vishwakarma <[email protected]>
> Co-developed-by: Suresh Guttula <[email protected]>
> Signed-off-by: Suresh Guttula <[email protected]>
> Co-developed-by: Kanala Ramalingeswara Reddy <[email protected]>
> Signed-off-by: Kanala Ramalingeswara Reddy <[email protected]>
> Signed-off-by: Shubhankar Milind Sardeshpande <[email protected]>
> ---

Series is -

Reviewed-by: Lijo Lazar <[email protected]>

Thanks,
Lijo

>   .../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  | 293 +++++++++++-------
>   .../drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.h  |  13 +
>   4 files changed, 199 insertions(+), 115 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 acf03838d49d..d6675b4ee9be 100644
> --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
> +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
> @@ -297,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/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
> index faa7d661f3bf..9da411bf2ad9 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,8 @@
>   #include "smu_v15_0_0_pmfw.h"
>   #include "smu_cmn.h"
>   
> +#include <linux/overflow.h>
> +
>   /*
>    * DO NOT use these for err/warn/info/debug messages.
>    * Use dev_err, dev_warn, dev_info and dev_dbg instead.
> @@ -119,6 +121,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,10 +165,37 @@ 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),
> @@ -173,7 +205,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;
> @@ -192,8 +224,18 @@ 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;
> +
> +	if (metrics_info->addr == 0) {
> +		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 +249,14 @@ static int smu_v15_0_0_init_smc_tables(struct smu_context *smu)
>   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 +349,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 +379,142 @@ 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};
> +	int 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(&metrics_info->metrics[!metrics_info->active_idx],
> +		       cpu_addr, table_size);
> +	else
> +		memcpy(&metrics_info->metrics[!metrics_info->active_idx],
> +		       cpu_addr, sizeof(MetricsTable_t));
> +
> +	metrics_info->active_idx = !metrics_info->active_idx;
> +
> +	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;
> +	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] = (val / counter) / 1024;
> +
> +	val = wrapping_sub(u64, c->SocclkFreqEffAcc, p->SocclkFreqEffAcc);
> +	avg_metric[METRICS_AVERAGE_SOCCLK] = (val / counter) / 1024;
> +
> +	val = wrapping_sub(u64, c->VclkFreqEffAcc, p->VclkFreqEffAcc);
> +	avg_metric[METRICS_AVERAGE_VCLK] = (val / counter) / 1024;
> +
> +	val = wrapping_sub(u64, c->MemclkFreqEffAcc, p->MemclkFreqEffAcc);
> +	avg_metric[METRICS_AVERAGE_UCLK] = (val / counter) / 1024;
> +
> +	val = wrapping_sub(u64, c->FclkFreqEffAcc, p->FclkFreqEffAcc);
> +	avg_metric[METRICS_AVERAGE_FCLK] = (val / counter) / 1024;
> +
> +	val = wrapping_sub(u64, c->NpuhclkFreqEffAcc, p->NpuhclkFreqEffAcc);
> +	avg_metric[METRICS_AVERAGE_NPUCLK] = (val / counter) / 1024;
> +
> +	/* Activity (fixed-point /1024) */
> +	val = wrapping_sub(u64, c->GfxBusyAcc, p->GfxBusyAcc);
> +	avg_metric[METRICS_AVERAGE_GFXACTIVITY] = (val / counter) / 1024;
> +
> +	val = wrapping_sub(u64, c->VcnBusyAcc, p->VcnBusyAcc);
> +	avg_metric[METRICS_AVERAGE_VCNACTIVITY] = (val / counter) / 1024;
> +
> +	/* Power (fixed-point /1024) */
> +	val = wrapping_sub(u64, c->ApuPowerAcc, p->ApuPowerAcc);
> +	avg_metric[METRICS_AVERAGE_SOCKETPOWER] = (val / counter) / 1024;
> +
> +	val = wrapping_sub(u64, c->SystemPowerAcc, p->SystemPowerAcc);
> +	avg_metric[METRICS_CURR_SOCKETPOWER] = (val / counter) / 1024;
> +
> +	/* Temperature */
> +	val = wrapping_sub(u64, c->GFX_TempAcc, p->GFX_TempAcc);
> +	avg_metric[METRICS_TEMPERATURE_EDGE] = val / counter;
> +
> +	val = wrapping_sub(u64, c->STT_APU_HotSpotTempAcc, p->STT_APU_HotSpotTempAcc);
> +	avg_metric[METRICS_TEMPERATURE_HOTSPOT] = val / counter;
> +
> +	/* Voltage(mV) */
> +	val = wrapping_sub(u64, c->VDDCR_GFX_TelemetryVoltage, p->VDDCR_GFX_TelemetryVoltage);
> +		avg_metric[METRICS_VOLTAGE_VDDGFX] = (val / counter) / 1000;
> +
> +	val = wrapping_sub(u64, c->VDDCR_SOC_TelemetryVoltage, p->VDDCR_SOC_TelemetryVoltage);
> +		avg_metric[METRICS_VOLTAGE_VDDSOC] = (val / counter) / 1000;
> +}
> +
>   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;
> -
> -	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,
> @@ -512,18 +589,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 +699,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..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