[PATCH 2/2] drm/amd/pm/smu15: switch to DRAM-based accumulator metrics for SMU v15.0.0 using the newly added metrics table

Shubhankar Milind Sardeshpande <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.