[PATCH v2 4/4] Documentation/arch/x86/amd_hsmp: Document the client telemetry table

Muralidhara M K <[email protected]> Fri, 31 Jul 2026 21:45:16 +0530
Newsgroups org.kernel.vger.platform-driver-x86,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The client models return the Ryzen Master SMC telemetry table, and the
driver copies it out without interpreting it. Document the Telemetry
Table RM layout, which HSMP_CLIENT_GET_METRICS_TABLE_VER reports as
version 5, so that a tool can decode a snapshot from this file.

Carry the RM layout as the structure declarations themselves - the array
size defines, the per-IOD counters, the per-CCX core counters and the
top-level table - rather than as a paraphrase of them, so the file states
the byte layout a decoder has to follow. The Public PPR for the model in
use stays the reference for the units and encodings, which are firmware
defined.

Signed-off-by: Muralidhara M K <[email protected]>
---
 Documentation/arch/x86/amd_hsmp.rst | 277 ++++++++++++++++++++++++++++
 1 file changed, 277 insertions(+)

diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst
index b95f09945193..cf6faba6aa44 100644
--- a/Documentation/arch/x86/amd_hsmp.rst
+++ b/Documentation/arch/x86/amd_hsmp.rst
@@ -221,9 +221,286 @@ The following IOCTLs are defined:
   ``sizeof(struct hsmp_metric_table)``.  Later version metrics table
   layout is documented in the Public PPR.
 
+  The Family 1Ah client models carry their own telemetry table instead,
+  described in `Family 1Ah client telemetry table`_ below.
+
 The ioctl would return a non-zero on failure; you can read errno to see
 what happened. The transaction returns 0 on success.
 
+Family 1Ah client telemetry table
+=================================
+On the Family 1Ah client models the table returned by
+``HSMP_CLIENT_GET_METRICS_TABLE`` (05h) uses the Ryzen Master SMC
+telemetry layout.  Table version 5, as reported by
+``HSMP_CLIENT_GET_METRICS_TABLE_VER`` (04h), is the Telemetry Table RM
+layout below.  ``HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR`` (06h) returns
+the DRAM address the SMU writes the table to, and 05h asks it to refill
+that region.  The driver issues both and copies the table out without
+interpreting it.
+
+Use the telemetry table chapter of the AMD Public PPR for the model in
+use as the authoritative reference.
+
+Telemetry Table RM layout::
+
+    /*
+     * Telemetry Table RM (Ryzen Master SMC, F1A Models 80h-8Fh and
+     * E0h-E3h client)
+     *
+     * Layout returned by HSMP_CLIENT_GET_METRICS_TABLE: the SMU writes the
+     * table into DRAM at the address reported by
+     * HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR and the driver returns it
+     * through the HSMP_IOCTL_GET_TELEMETRY_DATA ioctl.  The structure
+     * mirrors the RM spec published with the AMD HSMP telemetry sample
+     * application.
+     * Field grouping (SET VOLTAGES, TELEMETRY VOLTAGES, ... ) matches the
+     * SMU spec; accumulator (*_acc) fields are monotonic counters from
+     * which consumers derive deltas across two snapshots.  Units are
+     * firmware-defined (typically mW for power, milli-degC for temperature,
+     * MHz for frequency); see the AMD HSMP/Ryzen Master SMC spec for exact
+     * unit definitions.
+     *
+     * The composition is:
+     *   struct hsmp_telemetry_table_rm
+     *     +-- struct hsmp_telemetry_table_rm_iod   iod;
+     *     +-- struct hsmp_telemetry_table_rm_ccx   ccx[HSMP_TELEMETRY_RM_MAX_CCX];
+     *
+     * Spare fields are explicit firmware padding and must be preserved to
+     * maintain the on-the-wire byte layout.
+     */
+    #define HSMP_TELEMETRY_RM_MAX_CCX               4
+    #define HSMP_TELEMETRY_RM_CORES_PER_CCX         12
+    #define HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE       8
+    #define HSMP_TELEMETRY_RM_NPU_BUSY_DOMAINS      3
+    #define HSMP_TELEMETRY_RM_OC_DOMAINS            5
+    #define HSMP_TELEMETRY_RM_OC_SUBDOMAINS         5
+    #define HSMP_TELEMETRY_RM_OC_GUARDBANDS         3
+
+    /**
+     * struct hsmp_telemetry_table_rm_iod - I/O die counters for RM telemetry.
+     *
+     * Populated once per SMU telemetry sample.  Accumulator (*_acc) fields
+     * are monotonic; consumers compute deltas across two snapshots and
+     * normalise by accumulation_counter.  Per-rail limit fields report the
+     * currently active limit in firmware-defined units.
+     */
+    struct hsmp_telemetry_table_rm_iod {
+            __u32 accumulation_counter;
+
+            /* SET VOLTAGES */
+            __u64 vddcr_set_voltage;
+            __u64 vddcr_soc_set_voltage;
+            __u64 vddcr_npu_set_voltage;
+            __u64 vddcr_lp_set_voltage;
+            __u64 vddcr_gfx_set_voltage;
+            __u64 vdd_misc_set_voltage;
+
+            /* TELEMETRY VOLTAGES */
+            __u64 vddcr_telemetry_voltage;
+            __u64 vddcr_soc_telemetry_voltage;
+            __u64 vddcr_npu_telemetry_voltage;
+            __u64 vddcr_lp_telemetry_voltage;
+            __u64 vddcr_gfx_telemetry_voltage;
+            __u64 vdd_misc_telemetry_voltage;
+
+            /* TELEMETRY POWERS */
+            __u64 vddcr_telemetry_power;
+            __u64 vddcr_soc_telemetry_power;
+            __u64 vddcr_npu_telemetry_power;
+            __u64 vddcr_lp_telemetry_power;
+            __u64 vddcr_gfx_telemetry_power;
+            __u64 vdd_misc_telemetry_power;
+
+            /* THROTTLERS - FAST PPT */
+            __u32 fppt_fused_limit;
+            __u32 fppt_max_irm_limit;
+            __u32 fppt_max_pbo_limit;
+            __u32 fppt_limit;
+            __u64 fppt_value_acc;
+            __u32 fppt_residency_acc;
+
+            /* THROTTLERS - SLOW PPT */
+            __u32 sppt_fused_limit;
+            __u32 sppt_max_irm_limit;
+            __u32 sppt_max_pbo_limit;
+            __u32 sppt_limit;
+            __u64 sppt_value_acc;
+            __u32 sppt_residency_acc;
+
+            /* THROTTLERS - SPL */
+            __u32 spl_fused_limit;
+            __u32 spl_max_irm_limit;
+            __u32 spl_max_pbo_limit;
+            __u32 spl_limit;
+            __u64 spl_value_acc;
+            __u32 spl_residency_acc;
+
+            /* THROTTLERS - TDC VDDCR */
+            __u32 tdc_vddcr_fused_limit;
+            __u32 tdc_vddcr_max_irm_limit;
+            __u32 tdc_vddcr_max_pbo_limit;
+            __u32 tdc_vddcr_limit;
+            __u64 tdc_vddcr_value_acc;
+            __u32 tdc_vddcr_residency_acc;
+
+            /* THROTTLERS - TDC VDDCR SOC */
+            __u32 tdc_vddcr_soc_fused_limit;
+            __u32 tdc_vddcr_soc_max_irm_limit;
+            __u32 tdc_vddcr_soc_max_pbo_limit;
+            __u32 tdc_vddcr_soc_limit;
+            __u64 tdc_vddcr_soc_value_acc;
+            __u32 tdc_vddcr_soc_residency_acc;
+
+            /* THROTTLERS - TDC VDDCR NPU */
+            __u32 tdc_vddcr_npu_fused_limit;
+            __u32 tdc_vddcr_npu_max_irm_limit;
+            __u32 tdc_vddcr_npu_max_pbo_limit;
+            __u32 tdc_vddcr_npu_limit;
+            __u64 tdc_vddcr_npu_value_acc;
+            __u32 tdc_vddcr_npu_residency_acc;
+
+            /* THROTTLERS - TDC VDDCR LP */
+            __u32 tdc_vddcr_lp_fused_limit;
+            __u32 tdc_vddcr_lp_max_irm_limit;
+            __u32 tdc_vddcr_lp_max_pbo_limit;
+            __u32 tdc_vddcr_lp_limit;
+            __u64 tdc_vddcr_lp_value_acc;
+            __u32 tdc_vddcr_lp_residency_acc;
+
+            /* THROTTLERS - TDC VDDCR GFX */
+            __u32 tdc_vddcr_gfx_fused_limit;
+            __u32 tdc_vddcr_gfx_max_irm_limit;
+            __u32 tdc_vddcr_gfx_max_pbo_limit;
+            __u32 tdc_vddcr_gfx_limit;
+            __u64 tdc_vddcr_gfx_value_acc;
+            __u32 tdc_vddcr_gfx_residency_acc;
+
+            /* THROTTLERS - EDC VDDCR */
+            __u32 edc_vddcr_fused_limit;
+            __u32 edc_vddcr_max_irm_limit;
+            __u32 edc_vddcr_max_pbo_limit;
+            __u32 edc_vddcr_limit;
+
+            /* THROTTLERS - THERMAL */
+            __u32 thm_fused_limit;
+            __u32 thm_limit;
+            __u64 thm_value_acc;
+            __u32 thm_residency_acc;
+            __u32 prochot_residency_acc;
+            __u64 gfx_temp_acc;
+            __u64 soc_temp_acc;
+            __u32 p3t_fused_limit;
+            __u64 p3t_value_acc;
+
+            /* POWER */
+            __u64 system_power_acc;
+            __u64 apu_power_acc;
+            __u64 dgpu_power_acc;
+            __u64 npu_power_acc;
+
+            /* FREQUENCIES */
+            __u64 fclk_freq_eff_acc;
+            __u64 memclk_freq_eff_acc;
+            __u64 lclk_freq_eff_acc;
+            __u64 gfxclk_freq_eff_acc;
+            __u64 socclk_freq_eff_acc;
+            __u64 vclk_freq_eff_acc;
+            __u64 vpeclk_freq_eff_acc;
+            __u64 aieclk_freq_eff_acc;
+            __u64 npuhclk_freq_eff_acc;
+
+            /* BANDWIDTH */
+            __u64 dram_read_bandwidth;
+            __u64 dram_write_bandwidth;
+
+            /* ACTIVITY MONITORS */
+            __u64 gfx_busy_acc;
+            __u64 vcn_busy_acc;
+            __u64 npu_busy_acc[HSMP_TELEMETRY_RM_NPU_BUSY_DOMAINS];
+
+            /* STT (Skin Temperature Tracking) */
+            __u32 stt_min_limit;
+            __u64 stt_apu_hot_spot_temp_acc;
+            __u64 stt_hs2_hot_spot_temp_acc;
+            __u32 stt_apu_temp_limit;
+            __u64 stt_apu_skin_temp_acc;
+
+            /* RESIDENCIES - per-CCX CPU off */
+            __u64 cpu_off_residency[HSMP_TELEMETRY_RM_MAX_CCX];
+
+            /* DF P-STATES */
+            __u32 fclk_freq_table[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE];
+            __u32 uclk_freq_table[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE];
+            __u32 ddr_rate_table[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE];
+            __u8  df_pstate_source[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE];
+
+            /* SYSTEM */
+            __u8  gfx_disabled;
+            __u8  spare2[3];
+            __u32 gfxclk_fmax;
+            __u8  cclk_core_fuse_enable[HSMP_TELEMETRY_RM_MAX_CCX][HSMP_TELEMETRY_RM_CORES_PER_CCX];
+            __u8  cclk_core_enabled[HSMP_TELEMETRY_RM_MAX_CCX][HSMP_TELEMETRY_RM_CORES_PER_CCX];
+            __u32 cclk_fmax[HSMP_TELEMETRY_RM_MAX_CCX][HSMP_TELEMETRY_RM_CORES_PER_CCX];
+
+            /* OVERCLOCK CAPABLE */
+            __u8  cpu_precise_and_direct_oc_capable;
+            __u8  gfx_precise_and_direct_oc_capable;
+            __u8  pbo_basic_oc_capable;
+            __u8  pbo_advanced_oc_capable;
+            __u8  pbo_nitro_oc_capable;
+            __u8  memory_and_fabric_oc_capable;
+            __u8  misc_oc_capable;
+            __u8  extreme_cold_oc_capable;
+            __u8  down_config_control_capable;
+            __u8  spare0[3];
+
+            /* OVERCLOCK STATUS */
+            __u32 fit_limit_scalar;
+            __u8  ln2_enabled;
+            __u8  cpu_precise_and_direct_oc_enabled;
+            __u8  gfx_precise_and_direct_oc_enabled;
+            __u8  spare1[2];
+            __s8  psm_guardband[HSMP_TELEMETRY_RM_OC_DOMAINS]
+                               [HSMP_TELEMETRY_RM_OC_SUBDOMAINS]
+                               [HSMP_TELEMETRY_RM_OC_GUARDBANDS];
+            __s32 core_power_limit_offset;
+            __u32 max_freq_offset[HSMP_TELEMETRY_RM_OC_DOMAINS];
+    };
+
+    /**
+     * struct hsmp_telemetry_table_rm_ccx - Per-CCX core counters for RM telemetry.
+     *
+     * Each CCX exposes per-core monotonic counters for residency, frequency,
+     * temperature and power.  Arrays are sized for the maximum cores per
+     * CCX; entries past the actual enabled-core count are zero-padded by
+     * the SMU.  Use the cclk_core_enabled[] mask in struct
+     * hsmp_telemetry_table_rm_iod to determine which lanes are valid.
+     */
+    struct hsmp_telemetry_table_rm_ccx {
+            __u64 core_c0[HSMP_TELEMETRY_RM_CORES_PER_CCX];
+            __u64 core_cc6[HSMP_TELEMETRY_RM_CORES_PER_CCX];
+            __u64 core_freq[HSMP_TELEMETRY_RM_CORES_PER_CCX];
+            __u64 core_freq_eff[HSMP_TELEMETRY_RM_CORES_PER_CCX];
+            __u64 core_temp[HSMP_TELEMETRY_RM_CORES_PER_CCX];
+            __u64 core_power[HSMP_TELEMETRY_RM_CORES_PER_CCX];
+    };
+
+    /**
+     * struct hsmp_telemetry_table_rm - Top-level RM telemetry table.
+     * @iod:      I/O die counters and per-rail/per-throttler/SYSTEM telemetry.
+     * @ccx:      Per-CCX core counters, one entry per CCX.
+     *
+     * Returned by the SMU at the DRAM address obtained from
+     * HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR after a successful
+     * HSMP_CLIENT_GET_METRICS_TABLE request.  The on-wire layout is fixed
+     * at the RM spec; future revisions will be exposed via a different
+     * table version and a sibling struct.
+     */
+    struct hsmp_telemetry_table_rm {
+            struct hsmp_telemetry_table_rm_iod iod;
+            struct hsmp_telemetry_table_rm_ccx ccx[HSMP_TELEMETRY_RM_MAX_CCX];
+    };
+
 More details on the interface and message definitions can be found in chapter
 "7 Host System Management Port (HSMP)" of the respective family/model PPR
 eg: https://docs.amd.com/v/u/en-US/55898_B1_pub_0_50
-- 
2.34.1