Rework smu_v15_0_0_get_gpu_metrics() to derive values from the raw
accumulator double-buffer instead of the firmware-computed SmuMetrics_t
snapshot:

- Add SMU_V15_IOD_AVG()/SMU_V15_CCX_AVG() helpers: wrapping_sub() delta
  over the sampling window, scaled by the caller's unit factor, then
  descaled from 1024x fixed-point with >>10 (scale before shift to keep
  sub-unit precision); typeof() preserves each field's width.
- Reuse the same macro in smu_v15_0_0_compute_all_metrics(), dropping
  the open-coded div_u64(..., 1024) boilerplate.
- Drop the unused smu_v15_0_0_get_gpu_metrics_table() helper and the
  SMU_TABLE_SMU_METRICS allocation.

Signed-off-by: Shubhankar Milind Sardeshpande 
<[email protected]>
Assisted-by: Claude:claude-opus-4.8
---
 .../inc/pmfw_if/smu15_driver_if_v15_0_0.h     |  46 ---
 .../drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c  | 282 +++++++++---------
 2 files changed, 140 insertions(+), 188 deletions(-)

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 a5d3e8d88860..94932d8f3e61 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
@@ -182,52 +182,6 @@ typedef struct {
        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]
-  uint16_t CoreTemperature[16];        //TSEN measured core temperature 
[centi-C]
-  uint16_t GfxTemperature;             //TSEN measured GFX temperature 
[centi-C]
-  uint16_t SocTemperature;             //TSEN measured SOC temperature 
[centi-C]
-  uint16_t StapmOpnLimit;              //Maximum IRM defined STAPM power limit 
[mW]
-  uint16_t StapmCurrentLimit;          //Time filtered STAPM power limit [mW]
-  uint16_t InfrastructureCpuMaxFreq;   //CCLK frequency limit enforced on 
classic cores [MHz]
-  uint16_t InfrastructureGfxMaxFreq;   //GFXCLK frequency limit enforced on 
GFX [MHz]
-  uint16_t SkinTemp;                   //Maximum skin temperature reported by 
APU and HS2 chassis sensors [centi-C]
-  uint16_t GfxclkFrequency;            //Time filtered target GFXCLK frequency 
[MHz]
-  uint16_t FclkFrequency;              //Time filtered target FCLK frequency 
[MHz]
-  uint16_t GfxActivity;                //Time filtered GFX busy % [0-100]
-  uint16_t SocclkFrequency;            //Time filtered target SOCCLK frequency 
[MHz]
-  uint16_t VclkFrequency;              //Time filtered target VCLK frequency 
[MHz]
-  uint16_t VcnActivity;                //Time filtered VCN busy % [0-100]
-  uint16_t VpeclkFrequency;            //Time filtered target VPECLK frequency 
[MHz]
-  uint16_t NpuclkFrequency;            //Time filtered target NPUCLK frequency 
[MHz]
-  uint16_t NpuBusy[8];                 //Time filtered NPU per-column busy % 
[0-100]
-  uint16_t DRAMReads;                  //Time filtered DRAM read bandwidth 
[MB/sec]
-  uint16_t DRAMWrites;                 //Time filtered DRAM write bandwidth 
[MB/sec]
-  uint16_t CoreC0Residency[16];        //Time filtered per-core C0 residency % 
[0-100]
-  uint16_t NpuPower;                   //Time filtered NPU power [mW]
-  uint32_t ApuPower;                   //Time filtered APU power [mW]
-  uint32_t GfxPower;                   //Time filtered GFX power [mW]
-  uint32_t dGpuPower;                  //Time filtered dGPU power [mW]
-  uint32_t SocketPower;                //Time filtered power used for 
PPT/STAPM [APU+dGPU] [mW]
-  uint32_t AllCorePower;               //Time filtered sum of core power 
across all cores in the socket [mW]
-  uint32_t FilterAlphaValue;           //Metrics table alpha filter time 
constant [us]
-  uint32_t MetricsCounter;             //Counter that is incremented on every 
metrics table update [PM_TIMER cycles]
-  uint16_t MemclkFrequency;            //Time filtered target MEMCLK frequency 
[MHz]
-  uint16_t AieclkFrequency;            //Time filtered target AIECLK frequency 
[MHz]
-  uint16_t NpuReads;                   //Time filtered NPU read bandwidth 
[MB/sec]
-  uint16_t NpuWrites;                  //Time filtered NPU write bandwidth 
[MB/sec]
-  uint32_t ThrottleResidency_PROCHOT;  //Counter that is incremented on every 
metrics table update when PROCHOT was engaged [PM_TIMER cycles]
-  uint32_t ThrottleResidency_SPL;      //Counter that is incremented on every 
metrics table update when SPL was engaged [PM_TIMER cycles]
-  uint32_t ThrottleResidency_FPPT;     //Counter that is incremented on every 
metrics table update when fast PPT was engaged [PM_TIMER cycles]
-  uint32_t ThrottleResidency_SPPT;     //Counter that is incremented on every 
metrics table update when slow PPT was engaged [PM_TIMER cycles]
-  uint32_t ThrottleResidency_THM_VDD;  //Counter that is incremented on every 
metrics table update when VDD thermal throttling was engaged [PM_TIMER cycles]
-  uint32_t ThrottleResidency_THM_SOC;  //Counter that is incremented on every 
metrics table update when SOC thermal throttling was engaged [PM_TIMER cycles]
-  uint16_t Psys;                       //Time filtered Psys power [mW]
-  uint16_t spare1;
-  uint32_t spare[6];
-} SmuMetrics_t;
-
 //ISP tile definitions
 typedef enum {
   TILE_XTILE = 0,         //ONO0
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 12fe2bc0488e..2bcd20072583 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
@@ -203,8 +203,6 @@ static int smu_v15_0_0_init_smc_tables(struct smu_context 
*smu)
                PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
        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(SMU_15_0_0_MetricsInfo_t);
        if (!smu_table->metrics_table)
@@ -348,36 +346,6 @@ 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_gpu_metrics_table(struct smu_context *smu,
-                                                       void *metrics_table,
-                                                       bool bypass_cache)
-{
-       struct smu_table_context *smu_table = &smu->smu_table;
-       uint32_t table_size =
-                       smu_table->tables[SMU_TABLE_SMU_METRICS].size;
-       int ret;
-
-       if (bypass_cache ||
-               !smu_table->metrics_time ||
-               time_after(jiffies, smu_table->metrics_time + 
msecs_to_jiffies(1))) {
-               ret = smu_v15_0_0_update_table(smu,
-                                               SMU_TABLE_SMU_METRICS,
-                                               0,
-                                               smu_table->metrics_table,
-                                               false);
-               if (ret) {
-                       dev_info(smu->adev->dev, "Failed to export SMU15_0_0 
metrics table!\n");
-                       return ret;
-               }
-               smu_table->metrics_time = jiffies;
-       }
-
-       if (metrics_table)
-               memcpy(metrics_table, smu_table->metrics_table, table_size);
-
-       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
@@ -424,85 +392,74 @@ static int smu_v15_0_0_get_metrics_table(struct 
smu_context *smu,
 }
 
 /*
- * 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.
+ * All accumulators below are 1024x fixed-point values in their native unit.
+ * The average over the sampling window is (curr - prev) / AccumulationCounter,
+ * still 1024x fixed-point. We multiply by @scale first (to preserve the
+ * sub-unit fractional bits the scaled unit needs) and only then descale by
+ * 1024 with a >>10 shift. wrapping_sub() handles a single accumulator rollover
+ * without tripping wrap sanitizers; typeof() keeps the modular subtraction at
+ * the field's real width (the *_ResidencyAcc fields are u32, the rest u64).
+ *
+ * @scale folds in the unit conversion the consumer expects:
+ *   1    -> native unit  (MHz, %)
+ *   1000 -> W->mW, GHz->MHz, GB/s->MB/s, V->mV
+ *   100  -> C->centi-C
+ */
+#define SMU_V15_IOD_AVG(field, scale)                                          
\
+       ((uint32_t)((div64_u64(wrapping_sub(typeof(c->field),                   
\
+                                           c->field, p->field),                
\
+                              counter) * (scale)) >> 10))
+#define SMU_V15_CCX_AVG(field, scale)                                          
\
+       ((uint32_t)((div64_u64(wrapping_sub(typeof(curr->CCX[ccx].field[core]), 
\
+                                           curr->CCX[ccx].field[core],         
\
+                                           prev->CCX[ccx].field[core]),        
\
+                              counter) * (scale)) >> 10))
+
+/*
+ * Compute the windowed average of every sensor exposed through read_sensor and
+ * cache it in avg_metric[]. Units here follow the hwmon/sysfs sensor ABI
+ * (milli-C, mW, mV), which differs from the gpu_metrics scaling used in
+ * smu_v15_0_0_get_gpu_metrics(). SMU_V15_IOD_AVG() relies on the c, p and
+ * counter locals declared below.
  */
 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;
+       uint64_t counter;
 
        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);
+       /* Effective clocks: accumulator already in MHz. */
+       avg_metric[METRICS_AVERAGE_GFXCLK] = SMU_V15_IOD_AVG(GfxclkFreqEffAcc, 
1);
+       avg_metric[METRICS_AVERAGE_SOCCLK] = SMU_V15_IOD_AVG(SocclkFreqEffAcc, 
1);
+       avg_metric[METRICS_AVERAGE_VCLK] = SMU_V15_IOD_AVG(VclkFreqEffAcc, 1);
+       avg_metric[METRICS_AVERAGE_UCLK] = SMU_V15_IOD_AVG(MemclkFreqEffAcc, 1);
+       avg_metric[METRICS_AVERAGE_FCLK] = SMU_V15_IOD_AVG(FclkFreqEffAcc, 1);
+       avg_metric[METRICS_AVERAGE_NPUCLK] = SMU_V15_IOD_AVG(NpuhclkFreqEffAcc, 
1);
 
-       val = wrapping_sub(u64, c->VclkFreqEffAcc, p->VclkFreqEffAcc);
-       avg_metric[METRICS_AVERAGE_VCLK] = div_u64(div64_u64(val, counter), 
1024);
+       /* Activity: accumulator already in %. */
+       avg_metric[METRICS_AVERAGE_GFXACTIVITY] = SMU_V15_IOD_AVG(GfxBusyAcc, 
1);
+       avg_metric[METRICS_AVERAGE_VCNACTIVITY] = SMU_V15_IOD_AVG(VcnBusyAcc, 
1);
 
-       val = wrapping_sub(u64, c->MemclkFreqEffAcc, p->MemclkFreqEffAcc);
-       avg_metric[METRICS_AVERAGE_UCLK] = div_u64(div64_u64(val, counter), 
1024);
+       /* Power: accumulator in W -> mW (hwmon/debugfs). */
+       avg_metric[METRICS_AVERAGE_SOCKETPOWER] = SMU_V15_IOD_AVG(ApuPowerAcc, 
1000);
+       avg_metric[METRICS_CURR_SOCKETPOWER] = SMU_V15_IOD_AVG(SystemPowerAcc, 
1000);
 
-       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);
+       /* Temperature: accumulator in Celsius -> millidegrees C (temp*_input). 
*/
        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);
+               SMU_V15_IOD_AVG(GFX_TempAcc, 
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES);
        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);
+               SMU_V15_IOD_AVG(STT_APU_HotSpotTempAcc, 
SMU_TEMPERATURE_UNITS_PER_CENTIGRADES);
 
-       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);
+       /* Voltage: accumulator in Volts -> millivolts. */
+       avg_metric[METRICS_VOLTAGE_VDDGFX] = 
SMU_V15_IOD_AVG(VDDCR_GFX_TelemetryVoltage, 1000);
+       avg_metric[METRICS_VOLTAGE_VDDSOC] = 
SMU_V15_IOD_AVG(VDDCR_SOC_TelemetryVoltage, 1000);
 }
 
 static int smu_v15_0_0_get_smu_metrics_data(struct smu_context *smu,
@@ -714,61 +671,99 @@ static ssize_t smu_v15_0_0_get_gpu_metrics(struct 
smu_context *smu,
        struct gpu_metrics_v3_0 *gpu_metrics =
                (struct gpu_metrics_v3_0 *)smu_driver_table_ptr(
                        smu, SMU_DRIVER_TABLE_GPU_METRICS);
-       SmuMetrics_t metrics;
-       int ret = 0;
+       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;
+       uint32_t all_core_power = 0;
+       MetricsTable_IOD_t *p, *c;
+       MetricsTable_t *prev, *curr;
+       size_t i, ccx, core;
+       uint32_t coreclk;
+       uint64_t counter;
+       int ret;
 
-       ret = smu_v15_0_0_get_gpu_metrics_table(smu, &metrics, false);
-       if (ret)
+       /* Refresh the accumulator double-buffer (may reuse a cached sample). */
+       ret = smu_v15_0_0_get_metrics_table(smu, metrics_info);
+       if (ret < 0)
                return ret;
 
+       curr = &metrics_info->metrics[metrics_info->active_idx];
+       prev = &metrics_info->metrics[!metrics_info->active_idx];
+       c = &curr->IOD;
+       p = &prev->IOD;
+
        smu_cmn_init_soft_gpu_metrics(gpu_metrics, 3, 0);
 
-       gpu_metrics->temperature_gfx = metrics.GfxTemperature;
-       gpu_metrics->temperature_soc = metrics.SocTemperature;
-       memcpy(&gpu_metrics->temperature_core[0],
-               &metrics.CoreTemperature[0],
-               sizeof(uint16_t) * 16);
-       gpu_metrics->temperature_skin = metrics.SkinTemp;
-
-       gpu_metrics->average_gfx_activity = metrics.GfxActivity;
-       gpu_metrics->average_vcn_activity = metrics.VcnActivity;
-
-       memcpy(&gpu_metrics->average_core_c0_activity[0],
-               &metrics.CoreC0Residency[0],
-               sizeof(uint16_t) * 16);
-       gpu_metrics->average_dram_reads = metrics.DRAMReads;
-       gpu_metrics->average_dram_writes = metrics.DRAMWrites;
-
-       gpu_metrics->average_socket_power = metrics.SocketPower;
-       gpu_metrics->average_apu_power = metrics.ApuPower;
-       gpu_metrics->average_gfx_power = metrics.GfxPower;
-       gpu_metrics->average_dgpu_power = metrics.dGpuPower;
-       gpu_metrics->average_all_core_power = metrics.AllCorePower;
-       gpu_metrics->average_sys_power = metrics.Psys;
-       memcpy(&gpu_metrics->average_core_power[0],
-               &metrics.CorePower[0],
-               sizeof(uint16_t) * 16);
-
-       gpu_metrics->average_gfxclk_frequency = metrics.GfxclkFrequency;
-       gpu_metrics->average_socclk_frequency = metrics.SocclkFrequency;
-       gpu_metrics->average_vpeclk_frequency = metrics.VpeclkFrequency;
-       gpu_metrics->average_fclk_frequency = metrics.FclkFrequency;
-       gpu_metrics->average_vclk_frequency = metrics.VclkFrequency;
-       gpu_metrics->average_uclk_frequency = metrics.MemclkFrequency;
-
-       memcpy(&gpu_metrics->current_coreclk[0],
-               &metrics.CoreFrequency[0],
-               sizeof(uint16_t) * 16);
-       gpu_metrics->current_core_maxfreq = metrics.InfrastructureCpuMaxFreq;
-       gpu_metrics->current_gfx_maxfreq = metrics.InfrastructureGfxMaxFreq;
-
-       gpu_metrics->throttle_residency_prochot = 
metrics.ThrottleResidency_PROCHOT;
-       gpu_metrics->throttle_residency_spl = metrics.ThrottleResidency_SPL;
-       gpu_metrics->throttle_residency_fppt = metrics.ThrottleResidency_FPPT;
-       gpu_metrics->throttle_residency_sppt = metrics.ThrottleResidency_SPPT;
-       gpu_metrics->throttle_residency_thm_soc = 
metrics.ThrottleResidency_THM_SOC;
-
-       gpu_metrics->time_filter_alphavalue = metrics.FilterAlphaValue;
+       counter = wrapping_sub(u32, c->AccumulationCounter, 
p->AccumulationCounter);
+       if (counter) {
+               /* Temperatures: accumulator in Celsius -> centi-C. */
+               gpu_metrics->temperature_gfx = SMU_V15_IOD_AVG(GFX_TempAcc, 
100);
+               gpu_metrics->temperature_soc = SMU_V15_IOD_AVG(SOC_TempAcc, 
100);
+               gpu_metrics->temperature_skin = 
SMU_V15_IOD_AVG(STT_APU_SkinTempAcc, 100);
+
+               /* Activity: accumulator already in %. */
+               gpu_metrics->average_gfx_activity = SMU_V15_IOD_AVG(GfxBusyAcc, 
1);
+               gpu_metrics->average_vcn_activity = SMU_V15_IOD_AVG(VcnBusyAcc, 
1);
+
+               /* Bandwidth: accumulator in GB/s -> MB/s. */
+               gpu_metrics->average_dram_reads = 
SMU_V15_IOD_AVG(DramReadBandwidth, 1000);
+               gpu_metrics->average_dram_writes = 
SMU_V15_IOD_AVG(DramWriteBandwidth, 1000);
+
+               /* Power: accumulator in W -> mW. */
+               gpu_metrics->average_apu_power = SMU_V15_IOD_AVG(ApuPowerAcc, 
1000);
+               gpu_metrics->average_gfx_power = 
SMU_V15_IOD_AVG(VDDCR_GFX_TelemetryPower, 1000);
+               gpu_metrics->average_dgpu_power = SMU_V15_IOD_AVG(dGpuPowerAcc, 
1000);
+               gpu_metrics->average_sys_power = 
SMU_V15_IOD_AVG(SystemPowerAcc, 1000);
+               /* No dedicated socket accumulator: APU + dGPU, matching 
PPT/STAPM. */
+               gpu_metrics->average_socket_power =
+                       gpu_metrics->average_apu_power + 
gpu_metrics->average_dgpu_power;
+
+               /* Effective clocks: accumulator already in MHz. */
+               gpu_metrics->average_gfxclk_frequency = 
SMU_V15_IOD_AVG(GfxclkFreqEffAcc, 1);
+               gpu_metrics->average_socclk_frequency = 
SMU_V15_IOD_AVG(SocclkFreqEffAcc, 1);
+               gpu_metrics->average_vpeclk_frequency = 
SMU_V15_IOD_AVG(VpeclkFreqEffAcc, 1);
+               gpu_metrics->average_fclk_frequency = 
SMU_V15_IOD_AVG(FclkFreqEffAcc, 1);
+               gpu_metrics->average_vclk_frequency = 
SMU_V15_IOD_AVG(VclkFreqEffAcc, 1);
+               gpu_metrics->average_uclk_frequency = 
SMU_V15_IOD_AVG(MemclkFreqEffAcc, 1);
+
+               /* Per-core metrics: report only active cores (non-zero 
effective
+                * clock), flattening CCX-major into the 16 gpu_metrics slots.
+                */
+               i = 0;
+               for (ccx = 0; ccx < METRIC_CCX_MAX &&
+                             i < ARRAY_SIZE(gpu_metrics->current_coreclk); 
ccx++) {
+                       for (core = 0; core < NUM_MAX_CORES &&
+                                      i < 
ARRAY_SIZE(gpu_metrics->current_coreclk);
+                            core++) {
+                               /* Effective clock gates whether the core is 
active. */
+                               coreclk = SMU_V15_CCX_AVG(Core_FREQEFF, 1000);
+                               if (!coreclk)
+                                       continue;
+
+                               gpu_metrics->current_coreclk[i] = coreclk;
+                               gpu_metrics->temperature_core[i] =
+                                       SMU_V15_CCX_AVG(Core_TEMP, 100);
+                               gpu_metrics->average_core_c0_activity[i] =
+                                       SMU_V15_CCX_AVG(Core_C0, 1);
+                               gpu_metrics->average_core_power[i] =
+                                       SMU_V15_CCX_AVG(Core_POWER, 1000);
+                               all_core_power += 
gpu_metrics->average_core_power[i];
+                               i++;
+                       }
+               }
+               gpu_metrics->average_all_core_power = all_core_power;
+
+               /* Throttle residencies: accumulator in % (semantics differ from
+                * the PM_TIMER cycle counters exposed by the legacy metrics 
path).
+                */
+               gpu_metrics->throttle_residency_prochot =
+                       SMU_V15_IOD_AVG(PROCHOT_ResidencyAcc, 1);
+               gpu_metrics->throttle_residency_spl = 
SMU_V15_IOD_AVG(SPL_ResidencyAcc, 1);
+               gpu_metrics->throttle_residency_fppt = 
SMU_V15_IOD_AVG(fPPT_ResidencyAcc, 1);
+               gpu_metrics->throttle_residency_sppt = 
SMU_V15_IOD_AVG(sPPT_ResidencyAcc, 1);
+               gpu_metrics->throttle_residency_thm_soc = 
SMU_V15_IOD_AVG(THM_ResidencyAcc, 1);
+       }
+
        gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
 
        *table = (void *)gpu_metrics;
@@ -778,6 +773,9 @@ static ssize_t smu_v15_0_0_get_gpu_metrics(struct 
smu_context *smu,
        return sizeof(struct gpu_metrics_v3_0);
 }
 
+#undef SMU_V15_IOD_AVG
+#undef SMU_V15_CCX_AVG
+
 static int smu_v15_0_0_mode2_reset(struct smu_context *smu)
 {
        int ret;
-- 
2.43.0

Reply via email to