Re: [PATCH] drm/amd/pm: compute SMU v15.0.0 gpu_metrics from accumulator table
"Lazar, Lijo" <[email protected]> Mon, 10 Aug 2026 09:13:42 +0530
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
On 07-Aug-26 5:56 PM, Shubhankar Milind Sardeshpande wrote: > 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 A couple of nits below - Reviewed-by: Lijo Lazar <[email protected]> > --- > .../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 Better name as it as Q10 -> https://en.wikipedia.org/wiki/Q_(number_format) > + * 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) CoreAvg may be a better name. For readability, pass ccx/core also as arguments. \ > + ((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; The name gives the impression that it's average of all core powers (all_core_power / total_num_cores). Currently, it is the sum of of all core powers. Thanks, Lijo > + > + /* 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;