[PATCH v3 4/4] platform/x86/amd/hsmp: Document and expose client telemetry table in UAPI
From: Muralidhara M K
Date: Wed Aug 19 2026 - 03:33:15 EST
The client models return the Ryzen Master SMC telemetry table, which
the driver copies out without interpreting. Add the Telemetry Table RM
layout, reported as table version 5 by
HSMP_CLIENT_GET_METRICS_TABLE_VER, as struct declarations in the UAPI
header, so userspace has one authoritative, kernel-doc'd definition of
the byte layout instead of decoding it by hand.
Point amd_hsmp.rst at struct hsmp_telemetry_table_rm rather than
duplicating the layout in prose. The Public PPR for the model in use
remains the reference for units and encodings, which are firmware
defined.
Verified byte-for-byte, field by field, against AMD's internal metrics
table header, and end-to-end against a live snapshot pulled off Family
1Ah client hardware: driver-reported table size, struct sizeof(), and
field offsets all agree.
Signed-off-by: Muralidhara M K <muralidhara.mk@xxxxxxx>
---
Documentation/arch/x86/amd_hsmp.rst | 14 ++
arch/x86/include/uapi/asm/amd_hsmp.h | 263 +++++++++++++++++++++++++++
2 files changed, 277 insertions(+)
diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst
index b95f09945193..c483c68dcfad 100644
--- a/Documentation/arch/x86/amd_hsmp.rst
+++ b/Documentation/arch/x86/amd_hsmp.rst
@@ -221,9 +221,23 @@ 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, ``HSMP_CLIENT_GET_METRICS_TABLE`` (05h)
+returns the Ryzen Master SMC telemetry table, table version 5 as
+reported by ``HSMP_CLIENT_GET_METRICS_TABLE_VER`` (04h). This is the
+Telemetry Table RM layout, defined as ``struct hsmp_telemetry_table_rm``
+in amd_hsmp.h. The driver copies the table out without interpreting it.
+
+See the telemetry table chapter of the AMD Public PPR for the model in
+use for the units and encodings of its fields.
+
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
diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
index 00ca7855ca00..3b549fd65c6d 100644
--- a/arch/x86/include/uapi/asm/amd_hsmp.h
+++ b/arch/x86/include/uapi/asm/amd_hsmp.h
@@ -799,4 +799,267 @@ enum hsmp_client_message_ids {
HSMP_CLIENT_MSG_ID_MAX,
};
+#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
+
+/*
+ * Firmware lays out this table packed to a 4-byte boundary, so __u64
+ * members here only need 4-byte alignment rather than the usual 8. Without
+ * this, the compiler's natural 8-byte alignment would insert padding
+ * firmware never put there, shifting every field after the first
+ * misaligned __u64 off its real offset.
+ */
+#pragma pack(push, 4)
+
+/*
+ * struct hsmp_telemetry_table_rm_iod - I/O die counters for RM telemetry.
+ *
+ * Accumulator (*_acc) fields are monotonic counters; consumers derive
+ * deltas across two snapshots and normalise by accumulation_counter.
+ */
+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];
+
+ __u64 npu_temp_acc;
+ __u64 df_pstate_residency_acc[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE];
+ __u32 cclk_fboost;
+
+ /* PMF */
+ __u32 pmf_fast_apu_ppt_limit;
+ __u64 pmf_fast_apu_ppt_value_acc;
+ __u32 pmf_fast_apu_ppt_residency_acc;
+
+ __u32 pmf_slow_apu_ppt_limit;
+ __u64 pmf_slow_apu_ppt_value_acc;
+ __u32 pmf_slow_apu_ppt_residency_acc;
+
+ __u32 pmf_fast_spm_limit;
+ __u64 pmf_fast_spm_value_acc;
+ __u32 pmf_fast_spm_residency_acc;
+
+ __u32 pmf_slow_spm_limit;
+ __u64 pmf_slow_spm_value_acc;
+ __u32 pmf_slow_spm_residency_acc;
+
+ __u32 spare3[5];
+};
+
+/*
+ * struct hsmp_telemetry_table_rm_ccx - Per-CCX core counters for RM telemetry.
+ *
+ * Arrays are sized for the maximum cores per CCX; use the
+ * cclk_core_enabled[] mask in struct hsmp_telemetry_table_rm_iod to tell
+ * which entries 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.
+ *
+ * Layout of the table returned by HSMP_CLIENT_GET_METRICS_TABLE on the
+ * Family 1Ah client (Models 80h-8Fh and E0h-E3h), reported as table
+ * version 5 by HSMP_CLIENT_GET_METRICS_TABLE_VER. Units are
+ * firmware-defined; see the AMD HSMP/Ryzen Master SMC spec. Spare
+ * fields are firmware padding and must be preserved.
+ */
+struct hsmp_telemetry_table_rm {
+ struct hsmp_telemetry_table_rm_iod iod;
+ struct hsmp_telemetry_table_rm_ccx ccx[HSMP_TELEMETRY_RM_MAX_CCX];
+};
+
+#pragma pack(pop)
+
#endif /*_ASM_X86_AMD_HSMP_H_*/
--
2.34.1