* [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh
@ 2026-05-17 15:12 Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 1/7] platform/x86/amd/hsmp: Add new HSMP messages " Muralidhara M K
` (6 more replies)
0 siblings, 7 replies; 19+ messages in thread
From: Muralidhara M K @ 2026-05-17 15:12 UTC (permalink / raw)
To: ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel, Muralidhara M K
Hi,
This series adds AMD HSMP (Host System Management Port) support for
Family 1Ah, Model 50h-5Fh processors (HSMP protocol version 7) on top
of the existing platform/x86/amd/hsmp driver.
Highlights:
- New HSMP messages for Family 1Ah Model 50h-5Fh: PC6/CC6 control,
CCD power, Tdelta, SVI3 VR temperature, DIMM sideband, Floor/SDPS
limit control and an "enabled HSMP commands" capability query.
- UAPI structures (hsmp_metric_table_zen6 and friends) describing
the per-IOD/per-CCD metric table layout for protocol version 7.
- response_sz validation is unified to a single upper-bound check
so older userspace built against an earlier descriptor table
keeps working as new response words are added on newer platforms.
- Metric-table region size is sourced from firmware (args[2] of
HSMP_GET_METRIC_TABLE_DRAM_ADDR) rather than hard-coded to
sizeof(struct hsmp_metric_table), so the driver can map and
validate the larger ~13 KB protocol-version-7 layout (and any
future growth) without further code changes.
- Concurrent metric-table reads on the same socket are serialized
with a per-socket mutex managed via scoped guard(mutex), so two
simultaneous readers can no longer interleave the SMU refresh
command and the memcpy_fromio() and produce a torn snapshot.
Changes in v3:
- Switched the method of reading the metric table from the binary
sysfs attribute (metrics_bin) to a character-device IOCTL
(HSMP_IOCTL_GET_TELEMETRY_DATA on /dev/hsmp), as suggested during
the v2 review. The sysfs binary attribute is capped at PAGE_SIZE
(4 KB) on the standard read path, which cannot accommodate the
~13 KB hsmp_metric_table_zen6 layout used on Family 1Ah Model
50h-5Fh; the IOCTL has no such cap and works for both the
existing protocol-version-6 table and the new protocol-version-7
table. Userspace sizes its buffer using the matching UAPI struct
(hsmp_metric_table or hsmp_metric_table_zen6) and the kernel
rejects any size that disagrees with the firmware-reported table
size with -EINVAL, so a short copy can never silently truncate
the snapshot.
- The metrics_bin sysfs attribute is dropped from the ACPI driver
path (AMDI0097) in favour of the new IOCTL. This is an ABI change
for ACPI-driver users: userspace must now read telemetry via
HSMP_IOCTL_GET_TELEMETRY_DATA on /dev/hsmp. The non-ACPI plat.c
path (Family 1Ah Model 0h-Fh, fixed at protocol version 6) is
intentionally left untouched and its per-socket metrics_bin
remains available for existing tooling on those systems.
- The proto_ver gate that enables metric-table discovery in
init_acpi() is widened from "== HSMP_PROTO_VER6" to
">= HSMP_PROTO_VER6" so hsmp_get_tbl_dram_base() runs on
protocol version 7 (and any future compatible version).
- Per-socket metric_tbl_lock is now initialised with
devm_mutex_init() and taken via scoped guard(mutex) in
hsmp_metric_tbl_read(), instead of an open-coded
mutex_init()/mutex_destroy() pair.
Link to v2:
https://lore.kernel.org/platform-driver-x86/20260427155129.545327-1-muralidhara.mk@amd.com/T/#m9f1a19ba6e037e5a7f30441620f2fe4b2c3cf0fa
Thanks,
Murali
Muralidhara M K (6):
platform/x86/amd/hsmp: Add UAPI structures for Family 1Ah Model
50h-5Fh metrics table
platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound
check
platform/x86/amd/hsmp: Source metric-table size from firmware
platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table
reads
platform/x86/amd/hsmp: Drop ACPI sysfs metrics_bin in favour of the
IOCTL
platform/x86/amd/hsmp: Make metric table read locking use guard(mutex)
Suma Hegde (1):
platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model
50h-5Fh
arch/x86/include/uapi/asm/amd_hsmp.h | 278 +++++++++++++++++++++++++--
drivers/platform/x86/amd/hsmp/acpi.c | 34 +---
drivers/platform/x86/amd/hsmp/hsmp.c | 125 ++++++++++--
drivers/platform/x86/amd/hsmp/hsmp.h | 6 +-
4 files changed, 373 insertions(+), 70 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 1/7] platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model 50h-5Fh
2026-05-17 15:12 [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh Muralidhara M K
@ 2026-05-17 15:12 ` Muralidhara M K
2026-05-22 11:49 ` Ilpo Järvinen
2026-05-17 15:12 ` [PATCH v3 2/7] platform/x86/amd/hsmp: Add UAPI structures for Family 1Ah Model 50h-5Fh metrics table Muralidhara M K
` (5 subsequent siblings)
6 siblings, 1 reply; 19+ messages in thread
From: Muralidhara M K @ 2026-05-17 15:12 UTC (permalink / raw)
To: ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, Suma Hegde, Muralidhara M K,
Muthusamy Ramalingam
From: Suma Hegde <suma.hegde@amd.com>
The new messages extend the HSMP interface to provide finer control over
power states and system monitoring capabilities.
Power state control:
- Get/Set PC6 and CC6 enable/disable control (0x29, 0x2A)
Power and thermal monitoring:
- Get CCD power consumption reading (0x34)
- Get Thermal delta (Tdelta) reading (0x35)
- Get SVI3 VR controller temperature (0x36)
DIMM sideband operations:
- Get/Set DIMM sideband data(0x33, 0x39)
Power management:
- Get/Set Floor limit control (0x38)
- Get/Set SDPS limit control (0x3A)
System capabilities:
- Get enabled HSMP commands (0x37)
Bump driver version to 2.6.
Reviewed-by: Muralidhara M K <muralidhara.mk@amd.com>
Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Suma Hegde <suma.hegde@amd.com>
---
Changes v1->v3: None
arch/x86/include/uapi/asm/amd_hsmp.h | 142 +++++++++++++++++++++++----
drivers/platform/x86/amd/hsmp/hsmp.h | 2 +-
2 files changed, 126 insertions(+), 18 deletions(-)
diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
index 92d8f256d096..603d62f8d4da 100644
--- a/arch/x86/include/uapi/asm/amd_hsmp.h
+++ b/arch/x86/include/uapi/asm/amd_hsmp.h
@@ -53,9 +53,19 @@ enum hsmp_message_ids {
HSMP_SET_XGMI_PSTATE_RANGE, /* 26h Set xGMI P-state range */
HSMP_CPU_RAIL_ISO_FREQ_POLICY, /* 27h Get/Set Cpu Iso frequency policy */
HSMP_DFC_ENABLE_CTRL, /* 28h Enable/Disable DF C-state */
+ HSMP_PC6_ENABLE, /* 29h Get/Set PC6 enable/disable status */
+ HSMP_CC6_ENABLE, /* 2Ah Get/Set CC6 enable/disable status */
HSMP_GET_RAPL_UNITS = 0x30, /* 30h Get scaling factor for energy */
HSMP_GET_RAPL_CORE_COUNTER, /* 31h Get core energy counter value */
HSMP_GET_RAPL_PACKAGE_COUNTER, /* 32h Get package energy counter value */
+ HSMP_DIMM_SB_RD, /* 33h Get data from a specified device on the DIMM */
+ HSMP_READ_CCD_POWER, /* 34h Get the average power consumed by CCD */
+ HSMP_READ_TDELTA, /* 35h Get thermal solution behaviour */
+ HSMP_GET_SVI3_VR_CTRL_TEMP, /* 36h Get temperature of SVI3 VR controller rails */
+ HSMP_GET_ENABLED_HSMP_CMDS, /* 37h Get/Set supported HSMP commands */
+ HSMP_SET_GET_FLOOR_LIMIT, /* 38h Get/Set supported Floor limit commands */
+ HSMP_DIMM_SB_WR, /* 39h Set data to a specified device on the DIMM */
+ HSMP_SDPS_LIMIT, /* 3Ah Get/Set SDPS limit */
HSMP_MSG_ID_MAX,
};
@@ -170,16 +180,18 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
{0, 1, HSMP_GET},
/*
- * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0
- * input: args[0] = min link width[15:8] + max link width[7:0]
+ * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0/1
+ * input: args[0] = set/get XGMI Link width[31] + min link width[15:8] + max link width[7:0]
+ * output: args[0] = current min link width[15:8] + current max link width[7:0]
*/
- {1, 0, HSMP_SET},
+ {1, 1, HSMP_SET_GET},
/*
- * HSMP_SET_DF_PSTATE, num_args = 1, response_sz = 0
- * input: args[0] = df pstate[7:0]
+ * HSMP_SET_DF_PSTATE, num_args = 1, response_sz = 0/1
+ * input: args[0] = set/get df pstate[31] + df pstate[7:0]
+ * output: args[0] = APB enabled/disabled[8] + current df pstate[7:0]
*/
- {1, 0, HSMP_SET},
+ {1, 1, HSMP_SET_GET},
/* HSMP_SET_AUTO_DF_PSTATE, num_args = 0, response_sz = 0 */
{0, 0, HSMP_SET},
@@ -305,16 +317,18 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
{1, 1, HSMP_SET},
/*
- * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0
- * input: args[0] = power efficiency mode[2:0]
+ * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0/1
+ * input: args[0] = set/get power mode[31] + power efficiency mode[2:0]
+ * output: args[0] = current power efficiency mode[2:0]
*/
{1, 1, HSMP_SET_GET},
/*
- * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0
- * input: args[0] = min df pstate[15:8] + max df pstate[7:0]
+ * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0/1
+ * input: args[0] = set/get DF P-state range[31] + min df pstate[15:8] + max df pstate[7:0]
+ * output: args[0] = min df pstate[15:8] + max df pstate[7:0]
*/
- {1, 0, HSMP_SET},
+ {1, 1, HSMP_SET_GET},
/*
* HSMP_GET_METRIC_TABLE_VER, num_args = 0, response_sz = 1
@@ -335,10 +349,12 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
{0, 2, HSMP_GET},
/*
- * HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0
- * input: args[0] = min xGMI p-state[15:8] + max xGMI p-state[7:0]
+ * HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0/1
+ * input: args[0] = set/get XGMI pstate range[31] + min xGMI p-state[15:8] +
+ * max xGMI p-state[7:0]
+ * output: args[0] = min xGMI p-state[15:8] + max xGMI p-state[7:0]
*/
- {1, 0, HSMP_SET},
+ {1, 1, HSMP_SET_GET},
/*
* HSMP_CPU_RAIL_ISO_FREQ_POLICY, num_args = 1, response_sz = 1
@@ -355,9 +371,21 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
*/
{1, 1, HSMP_SET_GET},
- /* RESERVED(0x29-0x2f) */
- {0, 0, HSMP_RSVD},
- {0, 0, HSMP_RSVD},
+ /*
+ * HSMP_PC6_ENABLE, num_args = 1, response_sz = 0/1
+ * input: args[0] = set/get PC6 control[31] + disable/enable PC6[0]
+ * output: args[0] = current PC6 control status[0]
+ */
+ {1, 1, HSMP_SET_GET},
+
+ /*
+ * HSMP_CC6_ENABLE, num_args = 1, response_sz = 0/1
+ * input: args[0] = set/get CC6 control[31] + disable/enable CC6[0]
+ * output: args[0] = current CC6 control status[0]
+ */
+ {1, 1, HSMP_SET_GET},
+
+ /* RESERVED(0x2B-0x2F) */
{0, 0, HSMP_RSVD},
{0, 0, HSMP_RSVD},
{0, 0, HSMP_RSVD},
@@ -385,6 +413,86 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
*/
{0, 2, HSMP_GET},
+ /*
+ * HSMP_DIMM_SB_RD, num_args = 1, response_sz = 1
+ * input: args[0] =
+ * Register space[23]
+ * Register offset in given reg space[22:12]
+ * LID of device[11:8]
+ * DIMM address[7:0]
+ * output: args[0] = [3:0] Read data byte
+ */
+ {1, 1, HSMP_GET},
+
+ /*
+ * HSMP_READ_CCD_POWER, num_args = 1, response_sz = 1
+ * input: args[0] = apic id of core[15:0]
+ * output: args[0] = CCD power(mWatts)[31:0]
+ */
+ {1, 1, HSMP_GET},
+
+ /*
+ * HSMP_READ_TDELTA, num_args = 0, response_sz = 1
+ * input: None
+ * output: args[0] = thermal behaviour[31:0]
+ */
+ {0, 1, HSMP_GET},
+
+ /*
+ * HSMP_GET_SVI3_VR_CTRL_TEMP, num_args = 1, response_sz = 1
+ * input: args[0] = SVI3 rail index[3:1] + Read SVI3 temperature data[0]
+ * output: args[0] = SVI3 rail index[30:28] + SVI3 rail temperature(degree C)[27:0]
+ */
+ {1, 1, HSMP_GET},
+
+ /*
+ * HSMP_GET_ENABLED_HSMP_CMDS, num_args = 1, response_sz = 3
+ * input: args[0] = HSMP command mask[0]
+ * output: status of HSMP command = args[0], args[1], args[2]
+ */
+ {1, 3, HSMP_GET},
+
+ /*
+ * HSMP_SET_GET_FLOOR_LIMIT, num_args = 1, response_sz = 1
+ * input: args[0] =
+ * Set or Get[31:30]
+ * Set the Floor frequency per core = 00
+ * Set the Floor frequency for all cores = 01
+ * Get the Floor frequency of a core = 10
+ * Get the Effective Floor frequency per core = 11
+ * Reserved[29:28]
+ * Apic id / Reserved[27:16]
+ * args[27:16] is reserved if args[31:30] = 01
+ * Floor frequency limit / Reserved[15:0]
+ * if args[31] = 0, Floor frequency limit, else reserved
+ *
+ * output: args[0] =
+ * Effective Floor frequency limit(MHz) / None / Floor frequency limit[15:0]
+ * Effective Floor frequency if input args[31:30] = 11
+ * None if input args[31] = 0
+ * Floor frequency limit (MHz)[15:0] if args[31:30] = 10
+ */
+ {1, 1, HSMP_SET_GET},
+
+ /*
+ * HSMP_DIMM_SB_WR, num_args = 1, response_sz = 0
+ * input: args[0] =
+ * Write Data[31:24]
+ * Register space[23]
+ * Register offset in given reg space[22:12]
+ * LID of device[11:8]
+ * DIMM address[7:0]
+ * output: None
+ */
+ {1, 0, HSMP_SET},
+
+ /*
+ * HSMP_SDPS_LIMIT, num_args = 1, response_sz = 1
+ * input: args[0] = Set/Get[31] + SDPS Limit[30:0]
+ * output: args[0] = SDPS Limit[30:0]
+ */
+ {1, 1, HSMP_SET_GET},
+
};
/* Metrics table (supported only with proto version 6) */
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
index 0509a442eaae..b153527e0a0d 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.h
+++ b/drivers/platform/x86/amd/hsmp/hsmp.h
@@ -27,7 +27,7 @@
#define HSMP_DEVNODE_NAME "hsmp"
#define ACPI_HSMP_DEVICE_HID "AMDI0097"
-#define DRIVER_VERSION "2.5"
+#define DRIVER_VERSION "2.6"
struct hsmp_mbaddr_info {
u32 base_addr;
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 2/7] platform/x86/amd/hsmp: Add UAPI structures for Family 1Ah Model 50h-5Fh metrics table
2026-05-17 15:12 [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 1/7] platform/x86/amd/hsmp: Add new HSMP messages " Muralidhara M K
@ 2026-05-17 15:12 ` Muralidhara M K
2026-05-22 11:09 ` Ilpo Järvinen
2026-05-17 15:12 ` [PATCH v3 3/7] platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound check Muralidhara M K
` (4 subsequent siblings)
6 siblings, 1 reply; 19+ messages in thread
From: Muralidhara M K @ 2026-05-17 15:12 UTC (permalink / raw)
To: ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Suma Hegde,
Muthusamy Ramalingam
Define the UAPI structures hsmp_metric_table_zen6_iod,
hsmp_metric_table_zen6_ccd and the top-level hsmp_metric_table_zen6
to describe the per-IOD and per-CCD metrics layout for AMD Family 1Ah
Model 50h-5Fh processors (HSMP protocol version 7). These structures
allow userspace tools to interpret the raw metric table binary exposed
through the HSMP character device.
Driver enablement for protocol version 7 is added in a follow-up patch.
Reviewed-by: Suma Hegde <suma.hegde@amd.com>
Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
---
Changes:
v1->v2: Split the change
v2->v3: Move proto version check to seperate patch
arch/x86/include/uapi/asm/amd_hsmp.h | 88 ++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
index 603d62f8d4da..da3e3bbfa33e 100644
--- a/arch/x86/include/uapi/asm/amd_hsmp.h
+++ b/arch/x86/include/uapi/asm/amd_hsmp.h
@@ -575,6 +575,94 @@ struct hsmp_metric_table {
__u32 gfxclk_frequency[8];
};
+#define F1A_M50_M5F_MAX_CORES_PER_CCD_32 32
+#define F1A_M50_M5F_MAX_FREQ_TABLE_SIZE 4
+#define F1A_M50_M5F_MAX_XGMI 8
+#define F1A_M50_M5F_MAX_PCIE 8
+#define F1A_M50_M5F_MAX_CCD 8
+
+/* Metrics table (supported only with proto version 7) */
+struct hsmp_metric_table_zen6_iod {
+ __u32 num_active_ccds;
+ __u32 accumulation_counter;
+
+ /* TEMPERATURE */
+ __u64 max_socket_temperature_acc;
+
+ /* POWER */
+ __u32 socket_power_limit;
+ __u32 max_socket_power_limit;
+ __u64 socket_power_acc;
+ __u64 core_power_acc;
+ __u64 uncore_power_acc;
+
+ /* ENERGY */
+ __u64 timestamp;
+ __u64 socket_energy_acc;
+ __u64 core_energy_acc;
+ __u64 uncore_energy_acc;
+
+ /* FREQUENCY */
+ __u64 fclk_frequency_acc;
+ __u64 uclk_frequency_acc;
+ __u64 ddr_rate_acc;
+ __u64 lclk_frequency_acc[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
+
+ /* FREQUENCY RANGE */
+ __u32 fclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
+ __u32 uclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
+ __u32 ddr_rate_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
+ __u32 max_df_pstate_range;
+ __u32 min_df_pstate_range;
+ __u32 lclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
+ __u32 max_lclk_dpm_range;
+ __u32 min_lclk_dpm_range;
+
+ /* XGMI */
+ __u64 xgmi_bit_rate[F1A_M50_M5F_MAX_XGMI];
+ __u64 xgmi_read_bandwidth[F1A_M50_M5F_MAX_XGMI];
+ __u64 xgmi_write_bandwidth[F1A_M50_M5F_MAX_XGMI];
+
+ /* ACTIVITY */
+ __u64 socket_c0_residency_acc;
+ __u64 socket_df_cstate_residency_acc;
+ __u64 dram_read_bandwidth_acc;
+ __u64 dram_write_bandwidth_acc;
+ __u32 max_dram_bandwidth;
+ __u64 pcie_bandwidth_acc[F1A_M50_M5F_MAX_PCIE];
+
+ /* THROTTLERS */
+ __u32 prochot_residency_acc;
+ __u32 ppt_residency_acc;
+ __u32 thm_residency_acc;
+ __u32 vrhot_residency_acc;
+ __u32 cpu_tdc_residency_acc;
+ __u32 soc_tdc_residency_acc;
+ __u32 io_mem_tdc_residency_acc;
+ __u32 fit_residency_acc;
+};
+
+struct hsmp_metric_table_zen6_ccd {
+ __u32 core_apicid_of_thread0[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
+ __u64 core_c0[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
+ __u64 core_cc1[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
+ __u64 core_cc6[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
+ __u64 core_frequency[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
+ __u64 core_frequency_effective[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
+ __u64 core_power[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
+};
+
+/*
+ * Metrics table for Family 0x1A, Models 0x50 to 0x5F, table version 0x00700000
+ *
+ * Future processors within the same family and model may support a
+ * variable number of CCDs and cores
+ */
+struct hsmp_metric_table_zen6 {
+ struct hsmp_metric_table_zen6_iod iod;
+ struct hsmp_metric_table_zen6_ccd ccd[F1A_M50_M5F_MAX_CCD];
+};
+
/* Reset to default packing */
#pragma pack()
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 3/7] platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound check
2026-05-17 15:12 [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 1/7] platform/x86/amd/hsmp: Add new HSMP messages " Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 2/7] platform/x86/amd/hsmp: Add UAPI structures for Family 1Ah Model 50h-5Fh metrics table Muralidhara M K
@ 2026-05-17 15:12 ` Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 4/7] platform/x86/amd/hsmp: Source metric-table size from firmware Muralidhara M K
` (3 subsequent siblings)
6 siblings, 0 replies; 19+ messages in thread
From: Muralidhara M K @ 2026-05-17 15:12 UTC (permalink / raw)
To: ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Suma Hegde,
Muthusamy Ramalingam
The original validate_message() enforced a strict equality check
(response_sz != table.response_sz) for HSMP_SET and HSMP_GET messages,
while only HSMP_SET_GET messages used a relaxed upper-bound check.
As HSMP protocol versions increase, existing message IDs may gain
additional response arguments on newer platforms. The strict equality
check rejects older userspace callers that were compiled against an
earlier hsmp_msg_desc_table[] and request fewer response words than the
current table defines, breaking backward compatibility unnecessarily.
Replace the per-type branching with a single upper-bound check for all
message types. This allows older userspace to request fewer response
words while still rejecting any request that exceeds the hardware
capability defined in the descriptor table.
Reviewed-by: Suma Hegde <suma.hegde@amd.com>
Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
---
Changes:
v1->v2: New
v2->v3: None
drivers/platform/x86/amd/hsmp/hsmp.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
index 631ffc0978d1..9bad58fef304 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.c
+++ b/drivers/platform/x86/amd/hsmp/hsmp.c
@@ -182,20 +182,15 @@ static int validate_message(struct hsmp_message *msg)
return -EINVAL;
/*
- * Some older HSMP SET messages are updated to add GET in the same message.
- * In these messages, GET returns the current value and SET also returns
- * the successfully set value. To support this GET and SET in same message
- * while maintaining backward compatibility for the HSMP users,
- * hsmp_msg_desc_table[] indicates only maximum allowed response_sz.
+ * As the HSMP protocol evolves, newer platforms may define more
+ * response arguments for existing messages. Use an upper-bound
+ * check so that older userspace callers requesting fewer response
+ * words than what the current hsmp_msg_desc_table[] defines are
+ * still accepted, while rejecting requests that exceed the
+ * hardware capability.
*/
- if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET) {
- if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz)
- return -EINVAL;
- } else {
- /* only HSMP_SET or HSMP_GET messages go through this strict check */
- if (msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz)
- return -EINVAL;
- }
+ if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz)
+ return -EINVAL;
return 0;
}
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 4/7] platform/x86/amd/hsmp: Source metric-table size from firmware
2026-05-17 15:12 [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh Muralidhara M K
` (2 preceding siblings ...)
2026-05-17 15:12 ` [PATCH v3 3/7] platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound check Muralidhara M K
@ 2026-05-17 15:12 ` Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 5/7] platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table reads Muralidhara M K
` (2 subsequent siblings)
6 siblings, 0 replies; 19+ messages in thread
From: Muralidhara M K @ 2026-05-17 15:12 UTC (permalink / raw)
To: ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Muthusamy Ramalingam
The driver currently hard-codes the metric-table region size to
sizeof(struct hsmp_metric_table) when it ioremaps the DRAM region
returned by HSMP_GET_METRIC_TABLE_DRAM_ADDR and when it validates
buffer sizes in hsmp_metric_tbl_read(). That layout is fixed for
HSMP protocol version 6, but Family 1Ah Model 50h-5Fh uses the larger
struct hsmp_metric_table_zen6 (~13 KB), and future processors are
expected to grow the table further.
Pick up the table size from firmware instead:
- Bump the hsmp_msg_desc_table[] entry for
HSMP_GET_METRIC_TABLE_DRAM_ADDR from response_sz = 2 to 3 so
msg.args[2] is read back. SMU on Family 1Ah Model 50h and
later populates args[2] with the DRAM region size in bytes;
older firmware leaves it as 0.
- Add size_t hsmp_table_size to struct hsmp_plat_device, holding
the metric-table size discovered at probe time.
- In hsmp_get_tbl_dram_base(), set hsmp_pdev.hsmp_table_size to
msg.args[2] when firmware reports a non-zero value, and fall
back to sizeof(struct hsmp_metric_table) otherwise. Use the
same value for the devm_ioremap() of the DRAM region so the
full firmware-reported window is mapped.
- In hsmp_metric_tbl_read(), validate the caller-supplied buffer
size against hsmp_pdev.hsmp_table_size instead of the
hard-coded sizeof(struct hsmp_metric_table).
Behaviour is unchanged on existing protocol-version-6 hardware:
firmware returns 0 in args[2], the driver falls back to
sizeof(struct hsmp_metric_table), and both the ioremap and the
size check produce the same result as before.
The ioctl interface added later in this series uses
hsmp_pdev.hsmp_table_size to size its kernel buffer, validate the
userspace request, and copy out the full firmware-reported region
for protocol-version-7 (and future) layouts that exceed the
standard sysfs PAGE_SIZE read cap.
Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
---
Changes:
v1->v2: New
v2->v3: None
arch/x86/include/uapi/asm/amd_hsmp.h | 5 +++--
drivers/platform/x86/amd/hsmp/hsmp.c | 11 ++++++++---
drivers/platform/x86/amd/hsmp/hsmp.h | 1 +
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
index da3e3bbfa33e..b86bbc929395 100644
--- a/arch/x86/include/uapi/asm/amd_hsmp.h
+++ b/arch/x86/include/uapi/asm/amd_hsmp.h
@@ -342,11 +342,12 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
{0, 0, HSMP_GET},
/*
- * HSMP_GET_METRIC_TABLE_DRAM_ADDR, num_args = 0, response_sz = 2
+ * HSMP_GET_METRIC_TABLE_DRAM_ADDR, num_args = 0, response_sz = 3
* output: args[0] = lower 32 bits of the address
* output: args[1] = upper 32 bits of the address
+ * output: args[2] = DRAM region size in bytes
*/
- {0, 2, HSMP_GET},
+ {0, 3, HSMP_GET},
/*
* HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0/1
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
index 9bad58fef304..cf9392f99298 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.c
+++ b/drivers/platform/x86/amd/hsmp/hsmp.c
@@ -356,8 +356,7 @@ ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size)
return -ENOMEM;
}
- /* Do not support lseek(), also don't allow more than the size of metric table */
- if (size != sizeof(struct hsmp_metric_table)) {
+ if (size != hsmp_pdev.hsmp_table_size) {
dev_err(sock->dev, "Wrong buffer size\n");
return -EINVAL;
}
@@ -398,8 +397,14 @@ int hsmp_get_tbl_dram_base(u16 sock_ind)
dev_err(sock->dev, "Invalid DRAM address for metric table\n");
return -ENOMEM;
}
+ /* SMU returns table size from Family 1Ah Model 50h and forward */
+ if (msg.args[2])
+ hsmp_pdev.hsmp_table_size = msg.args[2];
+ else
+ hsmp_pdev.hsmp_table_size = sizeof(struct hsmp_metric_table);
+
sock->metric_tbl_addr = devm_ioremap(sock->dev, dram_addr,
- sizeof(struct hsmp_metric_table));
+ hsmp_pdev.hsmp_table_size);
if (!sock->metric_tbl_addr) {
dev_err(sock->dev, "Failed to ioremap metric table addr\n");
return -ENOMEM;
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
index b153527e0a0d..e7f051475728 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.h
+++ b/drivers/platform/x86/amd/hsmp/hsmp.h
@@ -55,6 +55,7 @@ struct hsmp_plat_device {
u32 proto_ver;
u16 num_sockets;
bool is_probed;
+ size_t hsmp_table_size;
};
int hsmp_cache_proto_ver(u16 sock_ind);
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 5/7] platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table reads
2026-05-17 15:12 [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh Muralidhara M K
` (3 preceding siblings ...)
2026-05-17 15:12 ` [PATCH v3 4/7] platform/x86/amd/hsmp: Source metric-table size from firmware Muralidhara M K
@ 2026-05-17 15:12 ` Muralidhara M K
2026-05-22 11:04 ` Ilpo Järvinen
2026-05-17 15:12 ` [PATCH v3 6/7] platform/x86/amd/hsmp: Drop ACPI sysfs metrics_bin in favour of the IOCTL Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 7/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex) Muralidhara M K
6 siblings, 1 reply; 19+ messages in thread
From: Muralidhara M K @ 2026-05-17 15:12 UTC (permalink / raw)
To: ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Muthusamy Ramalingam
The metric table for Family 1Ah Model 50h-5Fh
(struct hsmp_metric_table_zen6) is approximately 13 KB, exceeding the
PAGE_SIZE (4 KB) cap imposed on the standard sysfs binary attribute
read path. Rather than introduce new sysfs infrastructure to support
binary attributes larger than PAGE_SIZE, expose the metric table
through the existing HSMP character device using a new ioctl.
Add struct hsmp_telemetry_data and HSMP_IOCTL_GET_TELEMETRY_DATA to
the UAPI header. The request structure carries the socket index, the
required buffer size and a __u64-encoded user pointer to the
destination buffer, so the same layout works for 32-bit and 64-bit
callers. Fields are ordered with the __u64 user pointer first so all
members fall on their natural alignment under #pragma pack(4), giving
a tight 16-byte struct with no implicit padding; the trailing
reserved __u16 is documented as "set to zero" so future kernels can
attach meaning to it. Userspace sizes its buffer using the matching
UAPI metric table struct (hsmp_metric_table or hsmp_metric_table_zen6)
for the running platform; sizes that disagree with the firmware-
reported table size are rejected with -EINVAL so a short copy can
never silently truncate the snapshot.
Dispatch hsmp_ioctl() on the ioctl command, route HSMP_IOCTL_CMD to
the existing message handler (factored out as hsmp_ioctl_msg()) and
HSMP_IOCTL_GET_TELEMETRY_DATA to a new hsmp_ioctl_get_telemetry()
helper. The new helper validates the request, allocates a kernel
bounce buffer with kvmalloc() so it can hold the full table even
when it exceeds a single page (zeroing is skipped because the buffer
is overwritten in full by memcpy_fromio()), calls hsmp_metric_tbl_read()
to refresh and copy the table from the SMU DRAM region (under the
per-socket mutex introduced in a follow-up patch), and copies the
table to userspace. Unknown ioctl commands now return -ENOTTY instead
of falling through.
Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
---
Changes:
v1->v2: New patch based on bin sysfs
v2->v3: Replace with IOCTL method
arch/x86/include/uapi/asm/amd_hsmp.h | 43 ++++++++++++++
drivers/platform/x86/amd/hsmp/hsmp.c | 85 +++++++++++++++++++++++++++-
2 files changed, 127 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
index b86bbc929395..3d085298dd52 100644
--- a/arch/x86/include/uapi/asm/amd_hsmp.h
+++ b/arch/x86/include/uapi/asm/amd_hsmp.h
@@ -664,6 +664,40 @@ struct hsmp_metric_table_zen6 {
struct hsmp_metric_table_zen6_ccd ccd[F1A_M50_M5F_MAX_CCD];
};
+/**
+ * struct hsmp_telemetry_data - Request descriptor for HSMP telemetry IOCTL
+ * @buf: Input. Userspace pointer (encoded as __u64 to keep the layout
+ * stable between 32-bit and 64-bit callers) to the destination
+ * buffer that receives the metric table.
+ * @size: Input. Size in bytes of the buffer pointed to by @buf. Must
+ * match the firmware-reported metric table size for the running
+ * HSMP protocol version (see below); any other value results in
+ * -EINVAL. The kernel does not write this field back.
+ * @sock_ind: Input. Socket index from which the metric table is read.
+ * @reserved: Reserved for future use. Callers should set this to zero;
+ * future kernels may begin interpreting the field, so passing
+ * a non-zero value today is not forwards compatible.
+ *
+ * Placing @buf first lets all fields fall on their natural alignment under
+ * the surrounding #pragma pack(4), so the struct is a tight 16 bytes with
+ * the same wire layout on 32-bit and 64-bit userspace.
+ *
+ * The exact metric table layout depends on the HSMP protocol version reported
+ * by the firmware:
+ * - Protocol version 6 -> struct hsmp_metric_table
+ * - Protocol version 7 -> struct hsmp_metric_table_zen6
+ *
+ * Userspace queries the protocol version (e.g. via the protocol_version sysfs
+ * attribute) and uses sizeof() on the matching UAPI structure for both @size
+ * and the allocation backing @buf.
+ */
+struct hsmp_telemetry_data {
+ __u64 buf;
+ __u32 size;
+ __u16 sock_ind;
+ __u16 reserved;
+};
+
/* Reset to default packing */
#pragma pack()
@@ -671,4 +705,13 @@ struct hsmp_metric_table_zen6 {
#define HSMP_BASE_IOCTL_NR 0xF8
#define HSMP_IOCTL_CMD _IOWR(HSMP_BASE_IOCTL_NR, 0, struct hsmp_message)
+/*
+ * Fetch the firmware metric (telemetry) table for a given socket via the
+ * HSMP character device. This avoids the PAGE_SIZE limitation of the
+ * sysfs binary attribute path for tables larger than one page (such as the
+ * ~13 KB hsmp_metric_table_zen6 used on Family 1Ah Model 50h-5Fh).
+ */
+#define HSMP_IOCTL_GET_TELEMETRY_DATA \
+ _IOWR(HSMP_BASE_IOCTL_NR, 1, struct hsmp_telemetry_data)
+
#endif /*_ASM_X86_AMD_HSMP_H_*/
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
index cf9392f99298..3a02d683dea0 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.c
+++ b/drivers/platform/x86/amd/hsmp/hsmp.c
@@ -13,7 +13,9 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/semaphore.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
+#include <linux/uaccess.h>
#include "hsmp.h"
@@ -287,7 +289,7 @@ static bool is_get_msg(struct hsmp_message *msg)
return false;
}
-long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+static long hsmp_ioctl_msg(struct file *fp, unsigned long arg)
{
int __user *arguser = (int __user *)arg;
struct hsmp_message msg = { 0 };
@@ -343,6 +345,87 @@ long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
return 0;
}
+/*
+ * Fetch the firmware metric (telemetry) table for the requested socket and
+ * copy it to the userspace buffer described by the request.
+ *
+ * The metric table size is variable across HSMP protocol versions and on
+ * Family 1Ah Model 50h-5Fh exceeds PAGE_SIZE. Userspace must therefore
+ * supply a buffer at least the firmware-reported size in bytes.
+ */
+static long hsmp_ioctl_get_telemetry(struct file *fp, unsigned long arg)
+{
+ void __user *arguser = (void __user *)arg;
+ struct hsmp_telemetry_data req;
+ struct hsmp_socket *sock;
+ void __user *user_buf;
+ size_t tbl_size;
+ void *kbuf;
+ int ret;
+
+ /* Telemetry data is read-only; require read access on the fd. */
+ if (!(fp->f_mode & FMODE_READ))
+ return -EPERM;
+
+ if (copy_from_user(&req, arguser, sizeof(req)))
+ return -EFAULT;
+
+ if (!hsmp_pdev.sock || req.sock_ind >= hsmp_pdev.num_sockets)
+ return -ENODEV;
+
+ tbl_size = hsmp_pdev.hsmp_table_size;
+ if (!tbl_size)
+ return -ENODEV;
+
+ /*
+ * Userspace must size its buffer using the appropriate UAPI metric
+ * table struct for the running protocol version. Reject mismatched
+ * sizes so we never silently truncate or short-write.
+ */
+ if (req.size != tbl_size)
+ return -EINVAL;
+
+ sock = &hsmp_pdev.sock[req.sock_ind];
+ if (!sock->metric_tbl_addr)
+ return -ENODEV;
+
+ user_buf = u64_to_user_ptr(req.buf);
+
+ /*
+ * The bounce buffer is overwritten in full by memcpy_fromio() inside
+ * hsmp_metric_tbl_read(); use kvmalloc() to avoid the zeroing cost of
+ * kvzalloc() on the ~13 KB allocation done on every ioctl call.
+ */
+ kbuf = kvmalloc(tbl_size, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ ret = hsmp_metric_tbl_read(sock, kbuf, tbl_size);
+ if (ret < 0)
+ goto out;
+
+ if (copy_to_user(user_buf, kbuf, tbl_size))
+ ret = -EFAULT;
+ else
+ ret = 0;
+
+out:
+ kvfree(kbuf);
+ return ret;
+}
+
+long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case HSMP_IOCTL_CMD:
+ return hsmp_ioctl_msg(fp, arg);
+ case HSMP_IOCTL_GET_TELEMETRY_DATA:
+ return hsmp_ioctl_get_telemetry(fp, arg);
+ default:
+ return -ENOTTY;
+ }
+}
+
ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size)
{
struct hsmp_message msg = { 0 };
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 6/7] platform/x86/amd/hsmp: Drop ACPI sysfs metrics_bin in favour of the IOCTL
2026-05-17 15:12 [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh Muralidhara M K
` (4 preceding siblings ...)
2026-05-17 15:12 ` [PATCH v3 5/7] platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table reads Muralidhara M K
@ 2026-05-17 15:12 ` Muralidhara M K
2026-05-22 11:44 ` Ilpo Järvinen
2026-05-17 15:12 ` [PATCH v3 7/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex) Muralidhara M K
6 siblings, 1 reply; 19+ messages in thread
From: Muralidhara M K @ 2026-05-17 15:12 UTC (permalink / raw)
To: ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Muthusamy Ramalingam
The HSMP_IOCTL_GET_TELEMETRY_DATA character-device ioctl introduced in
the previous patch is now the canonical interface for reading the
metric table on the ACPI driver path. Unlike the metrics_bin sysfs
binary attribute, the ioctl is not constrained by PAGE_SIZE, so it
works for the ~13 KB hsmp_metric_table_zen6 layout used on Family 1Ah
Model 50h-5Fh as well as for the existing hsmp_metric_table layout
used on protocol version 6.
Drop the metrics_bin bin_attribute from the ACPI hsmp_attr_grp.
Widen the remaining proto_ver gate in init_acpi() from
'== HSMP_PROTO_VER6' to '>= HSMP_PROTO_VER6' so
hsmp_get_tbl_dram_base() is invoked on protocol version 7
(Family 1Ah Model 50h-5Fh) and any future protocol version that
retains a compatible per-socket metric table. This populates
sock->metric_tbl_addr and hsmp_pdev.hsmp_table_size, which the ioctl
handler requires.
This is an ABI change for users of the ACPI driver:
/sys/bus/platform/devices/AMDI0097:*/metrics_bin no longer exists.
Userspace must read telemetry through the HSMP_IOCTL_GET_TELEMETRY_DATA
ioctl on /dev/hsmp instead, sizing its buffer using the matching UAPI
metric table struct. The non-ACPI plat.c path is intentionally left
unchanged: it covers Family 1Ah Model 0h-Fh hardware that is fixed at
protocol version 6, and its per-socket metrics_bin remains available
for existing userspace tooling on those systems.
Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
---
Changes:
v1->v3: Remove bin attributes
drivers/platform/x86/amd/hsmp/acpi.c | 34 +---------------------------
1 file changed, 1 insertion(+), 33 deletions(-)
diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
index 97ed71593bdf..49765fefe1fb 100644
--- a/drivers/platform/x86/amd/hsmp/acpi.c
+++ b/drivers/platform/x86/amd/hsmp/acpi.c
@@ -231,25 +231,6 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind)
return hsmp_read_acpi_dsd(sock);
}
-static ssize_t hsmp_metric_tbl_acpi_read(struct file *filp, struct kobject *kobj,
- const struct bin_attribute *bin_attr, char *buf,
- loff_t off, size_t count)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct hsmp_socket *sock = dev_get_drvdata(dev);
-
- return hsmp_metric_tbl_read(sock, buf, count);
-}
-
-static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
- const struct bin_attribute *battr, int id)
-{
- if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6)
- return battr->attr.mode;
-
- return 0;
-}
-
static umode_t hsmp_is_sock_dev_attr_visible(struct kobject *kobj,
struct attribute *attr, int id)
{
@@ -491,7 +472,7 @@ static int init_acpi(struct device *dev)
return ret;
}
- if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) {
+ if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) {
ret = hsmp_get_tbl_dram_base(sock_ind);
if (ret)
dev_info(dev, "Failed to init metric table\n");
@@ -506,17 +487,6 @@ static int init_acpi(struct device *dev)
return 0;
}
-static const struct bin_attribute hsmp_metric_tbl_attr = {
- .attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444},
- .read = hsmp_metric_tbl_acpi_read,
- .size = sizeof(struct hsmp_metric_table),
-};
-
-static const struct bin_attribute *hsmp_attr_list[] = {
- &hsmp_metric_tbl_attr,
- NULL
-};
-
#define HSMP_DEV_ATTR(_name, _msg_id, _show, _mode) \
static struct hsmp_sys_attr hattr_##_name = { \
.dattr = __ATTR(_name, _mode, _show, NULL), \
@@ -559,9 +529,7 @@ static struct attribute *hsmp_dev_attr_list[] = {
};
static const struct attribute_group hsmp_attr_grp = {
- .bin_attrs = hsmp_attr_list,
.attrs = hsmp_dev_attr_list,
- .is_bin_visible = hsmp_is_sock_attr_visible,
.is_visible = hsmp_is_sock_dev_attr_visible,
};
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 7/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex)
2026-05-17 15:12 [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh Muralidhara M K
` (5 preceding siblings ...)
2026-05-17 15:12 ` [PATCH v3 6/7] platform/x86/amd/hsmp: Drop ACPI sysfs metrics_bin in favour of the IOCTL Muralidhara M K
@ 2026-05-17 15:12 ` Muralidhara M K
2026-05-22 10:55 ` Ilpo Järvinen
6 siblings, 1 reply; 19+ messages in thread
From: Muralidhara M K @ 2026-05-17 15:12 UTC (permalink / raw)
To: ilpo.jarvinen
Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Muthusamy Ramalingam
Add a per-socket mutex (metric_tbl_lock) to serialize concurrent reads
on the metric table. Without serialization, two simultaneous
readers could interleave the SMU refresh command and the
memcpy_fromio(), producing a torn (mixed old/new) snapshot.
Use scoped guard(mutex) in hsmp_metric_tbl_read() so the lock is
automatically released on all return paths. Initialize the mutex with
devm_mutex_init() in hsmp_get_tbl_dram_base() and return an error if
initialization fails, avoiding manual mutex_destroy() cleanup paths.
Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
---
Changes:
v1->v2: Add lock
v2->v3: Replace mutex_init to devm_mutex_init call
drivers/platform/x86/amd/hsmp/hsmp.c | 8 ++++++++
drivers/platform/x86/amd/hsmp/hsmp.h | 3 +++
2 files changed, 11 insertions(+)
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
index 3a02d683dea0..2fec897a95be 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.c
+++ b/drivers/platform/x86/amd/hsmp/hsmp.c
@@ -447,6 +447,7 @@ ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size)
msg.msg_id = HSMP_GET_METRIC_TABLE;
msg.sock_ind = sock->sock_ind;
+ guard(mutex)(&sock->metric_tbl_lock);
ret = hsmp_send_message(&msg);
if (ret)
return ret;
@@ -492,6 +493,13 @@ int hsmp_get_tbl_dram_base(u16 sock_ind)
dev_err(sock->dev, "Failed to ioremap metric table addr\n");
return -ENOMEM;
}
+
+ ret = devm_mutex_init(sock->dev, &sock->metric_tbl_lock);
+ if (ret) {
+ dev_err(sock->dev, "Failed to initialize metric table lock\n");
+ return ret;
+ }
+
return 0;
}
EXPORT_SYMBOL_NS_GPL(hsmp_get_tbl_dram_base, "AMD_HSMP");
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
index e7f051475728..f7b1cbf19932 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.h
+++ b/drivers/platform/x86/amd/hsmp/hsmp.h
@@ -15,6 +15,7 @@
#include <linux/hwmon.h>
#include <linux/kconfig.h>
#include <linux/miscdevice.h>
+#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/semaphore.h>
#include <linux/sysfs.h>
@@ -41,6 +42,8 @@ struct hsmp_socket {
struct bin_attribute hsmp_attr;
struct hsmp_mbaddr_info mbinfo;
void __iomem *metric_tbl_addr;
+ /* Serializes concurrent metric table refreshes from the sysfs path */
+ struct mutex metric_tbl_lock;
void __iomem *virt_base_addr;
struct semaphore hsmp_sem;
char name[HSMP_ATTR_GRP_NAME_SIZE];
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 7/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex)
2026-05-17 15:12 ` [PATCH v3 7/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex) Muralidhara M K
@ 2026-05-22 10:55 ` Ilpo Järvinen
2026-05-26 10:02 ` M K, Muralidhara
0 siblings, 1 reply; 19+ messages in thread
From: Ilpo Järvinen @ 2026-05-22 10:55 UTC (permalink / raw)
To: Muralidhara M K; +Cc: platform-driver-x86, LKML, Muthusamy Ramalingam
On Sun, 17 May 2026, Muralidhara M K wrote:
> Add a per-socket mutex (metric_tbl_lock) to serialize concurrent reads
> on the metric table. Without serialization, two simultaneous
> readers could interleave the SMU refresh command and the
> memcpy_fromio(), producing a torn (mixed old/new) snapshot.
>
> Use scoped guard(mutex) in hsmp_metric_tbl_read() so the lock is
> automatically released on all return paths. Initialize the mutex with
> devm_mutex_init() in hsmp_get_tbl_dram_base() and return an error if
> initialization fails, avoiding manual mutex_destroy() cleanup paths.
>
> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
> ---
> Changes:
> v1->v2: Add lock
> v2->v3: Replace mutex_init to devm_mutex_init call
>
> drivers/platform/x86/amd/hsmp/hsmp.c | 8 ++++++++
> drivers/platform/x86/amd/hsmp/hsmp.h | 3 +++
> 2 files changed, 11 insertions(+)
>
> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
> index 3a02d683dea0..2fec897a95be 100644
> --- a/drivers/platform/x86/amd/hsmp/hsmp.c
> +++ b/drivers/platform/x86/amd/hsmp/hsmp.c
> @@ -447,6 +447,7 @@ ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size)
> msg.msg_id = HSMP_GET_METRIC_TABLE;
> msg.sock_ind = sock->sock_ind;
>
> + guard(mutex)(&sock->metric_tbl_lock);
> ret = hsmp_send_message(&msg);
> if (ret)
> return ret;
> @@ -492,6 +493,13 @@ int hsmp_get_tbl_dram_base(u16 sock_ind)
> dev_err(sock->dev, "Failed to ioremap metric table addr\n");
> return -ENOMEM;
> }
> +
> + ret = devm_mutex_init(sock->dev, &sock->metric_tbl_lock);
> + if (ret) {
> + dev_err(sock->dev, "Failed to initialize metric table lock\n");
> + return ret;
> + }
Sashiko notes a potential problem with this failing and that not resulting
in a probe fail, which leaves the mutex uninitialized.
But the mutex could be initialized earlier to avoid the problem I think.
> +
> return 0;
> }
> EXPORT_SYMBOL_NS_GPL(hsmp_get_tbl_dram_base, "AMD_HSMP");
> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
> index e7f051475728..f7b1cbf19932 100644
> --- a/drivers/platform/x86/amd/hsmp/hsmp.h
> +++ b/drivers/platform/x86/amd/hsmp/hsmp.h
> @@ -15,6 +15,7 @@
> #include <linux/hwmon.h>
> #include <linux/kconfig.h>
> #include <linux/miscdevice.h>
> +#include <linux/mutex.h>
> #include <linux/pci.h>
> #include <linux/semaphore.h>
> #include <linux/sysfs.h>
> @@ -41,6 +42,8 @@ struct hsmp_socket {
> struct bin_attribute hsmp_attr;
> struct hsmp_mbaddr_info mbinfo;
> void __iomem *metric_tbl_addr;
> + /* Serializes concurrent metric table refreshes from the sysfs path */
> + struct mutex metric_tbl_lock;
> void __iomem *virt_base_addr;
> struct semaphore hsmp_sem;
> char name[HSMP_ATTR_GRP_NAME_SIZE];
>
--
i.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 5/7] platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table reads
2026-05-17 15:12 ` [PATCH v3 5/7] platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table reads Muralidhara M K
@ 2026-05-22 11:04 ` Ilpo Järvinen
2026-05-22 11:27 ` Ilpo Järvinen
2026-05-26 9:43 ` M K, Muralidhara
0 siblings, 2 replies; 19+ messages in thread
From: Ilpo Järvinen @ 2026-05-22 11:04 UTC (permalink / raw)
To: Muralidhara M K; +Cc: platform-driver-x86, LKML, Muthusamy Ramalingam
On Sun, 17 May 2026, Muralidhara M K wrote:
> The metric table for Family 1Ah Model 50h-5Fh
> (struct hsmp_metric_table_zen6) is approximately 13 KB, exceeding the
> PAGE_SIZE (4 KB) cap imposed on the standard sysfs binary attribute
> read path. Rather than introduce new sysfs infrastructure to support
> binary attributes larger than PAGE_SIZE, expose the metric table
> through the existing HSMP character device using a new ioctl.
>
> Add struct hsmp_telemetry_data and HSMP_IOCTL_GET_TELEMETRY_DATA to
> the UAPI header. The request structure carries the socket index, the
> required buffer size and a __u64-encoded user pointer to the
> destination buffer, so the same layout works for 32-bit and 64-bit
> callers. Fields are ordered with the __u64 user pointer first so all
> members fall on their natural alignment under #pragma pack(4), giving
> a tight 16-byte struct with no implicit padding; the trailing
> reserved __u16 is documented as "set to zero" so future kernels can
> attach meaning to it. Userspace sizes its buffer using the matching
> UAPI metric table struct (hsmp_metric_table or hsmp_metric_table_zen6)
> for the running platform; sizes that disagree with the firmware-
> reported table size are rejected with -EINVAL so a short copy can
> never silently truncate the snapshot.
>
> Dispatch hsmp_ioctl() on the ioctl command, route HSMP_IOCTL_CMD to
> the existing message handler (factored out as hsmp_ioctl_msg()) and
> HSMP_IOCTL_GET_TELEMETRY_DATA to a new hsmp_ioctl_get_telemetry()
> helper. The new helper validates the request, allocates a kernel
> bounce buffer with kvmalloc() so it can hold the full table even
> when it exceeds a single page (zeroing is skipped because the buffer
> is overwritten in full by memcpy_fromio()), calls hsmp_metric_tbl_read()
> to refresh and copy the table from the SMU DRAM region (under the
> per-socket mutex introduced in a follow-up patch), and copies the
> table to userspace. Unknown ioctl commands now return -ENOTTY instead
> of falling through.
>
> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
> ---
> Changes:
> v1->v2: New patch based on bin sysfs
> v2->v3: Replace with IOCTL method
>
> arch/x86/include/uapi/asm/amd_hsmp.h | 43 ++++++++++++++
> drivers/platform/x86/amd/hsmp/hsmp.c | 85 +++++++++++++++++++++++++++-
> 2 files changed, 127 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
> index b86bbc929395..3d085298dd52 100644
> --- a/arch/x86/include/uapi/asm/amd_hsmp.h
> +++ b/arch/x86/include/uapi/asm/amd_hsmp.h
> @@ -664,6 +664,40 @@ struct hsmp_metric_table_zen6 {
> struct hsmp_metric_table_zen6_ccd ccd[F1A_M50_M5F_MAX_CCD];
> };
>
> +/**
> + * struct hsmp_telemetry_data - Request descriptor for HSMP telemetry IOCTL
> + * @buf: Input. Userspace pointer (encoded as __u64 to keep the layout
> + * stable between 32-bit and 64-bit callers) to the destination
> + * buffer that receives the metric table.
> + * @size: Input. Size in bytes of the buffer pointed to by @buf. Must
> + * match the firmware-reported metric table size for the running
> + * HSMP protocol version (see below); any other value results in
> + * -EINVAL. The kernel does not write this field back.
> + * @sock_ind: Input. Socket index from which the metric table is read.
> + * @reserved: Reserved for future use. Callers should set this to zero;
> + * future kernels may begin interpreting the field, so passing
> + * a non-zero value today is not forwards compatible.
> + *
> + * Placing @buf first lets all fields fall on their natural alignment under
> + * the surrounding #pragma pack(4), so the struct is a tight 16 bytes with
> + * the same wire layout on 32-bit and 64-bit userspace.
> + *
> + * The exact metric table layout depends on the HSMP protocol version reported
> + * by the firmware:
> + * - Protocol version 6 -> struct hsmp_metric_table
> + * - Protocol version 7 -> struct hsmp_metric_table_zen6
> + *
> + * Userspace queries the protocol version (e.g. via the protocol_version sysfs
> + * attribute) and uses sizeof() on the matching UAPI structure for both @size
> + * and the allocation backing @buf.
> + */
> +struct hsmp_telemetry_data {
> + __u64 buf;
> + __u32 size;
> + __u16 sock_ind;
> + __u16 reserved;
> +};
> +
> /* Reset to default packing */
> #pragma pack()
>
> @@ -671,4 +705,13 @@ struct hsmp_metric_table_zen6 {
> #define HSMP_BASE_IOCTL_NR 0xF8
> #define HSMP_IOCTL_CMD _IOWR(HSMP_BASE_IOCTL_NR, 0, struct hsmp_message)
>
> +/*
> + * Fetch the firmware metric (telemetry) table for a given socket via the
> + * HSMP character device. This avoids the PAGE_SIZE limitation of the
> + * sysfs binary attribute path for tables larger than one page (such as the
> + * ~13 KB hsmp_metric_table_zen6 used on Family 1Ah Model 50h-5Fh).
> + */
> +#define HSMP_IOCTL_GET_TELEMETRY_DATA \
> + _IOWR(HSMP_BASE_IOCTL_NR, 1, struct hsmp_telemetry_data)
> +
> #endif /*_ASM_X86_AMD_HSMP_H_*/
> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
> index cf9392f99298..3a02d683dea0 100644
> --- a/drivers/platform/x86/amd/hsmp/hsmp.c
> +++ b/drivers/platform/x86/amd/hsmp/hsmp.c
> @@ -13,7 +13,9 @@
> #include <linux/delay.h>
> #include <linux/device.h>
> #include <linux/semaphore.h>
> +#include <linux/slab.h>
> #include <linux/sysfs.h>
> +#include <linux/uaccess.h>
>
> #include "hsmp.h"
>
> @@ -287,7 +289,7 @@ static bool is_get_msg(struct hsmp_message *msg)
> return false;
> }
>
> -long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> +static long hsmp_ioctl_msg(struct file *fp, unsigned long arg)
> {
> int __user *arguser = (int __user *)arg;
> struct hsmp_message msg = { 0 };
> @@ -343,6 +345,87 @@ long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> return 0;
> }
>
> +/*
> + * Fetch the firmware metric (telemetry) table for the requested socket and
> + * copy it to the userspace buffer described by the request.
> + *
> + * The metric table size is variable across HSMP protocol versions and on
> + * Family 1Ah Model 50h-5Fh exceeds PAGE_SIZE. Userspace must therefore
> + * supply a buffer at least the firmware-reported size in bytes.
> + */
> +static long hsmp_ioctl_get_telemetry(struct file *fp, unsigned long arg)
> +{
> + void __user *arguser = (void __user *)arg;
> + struct hsmp_telemetry_data req;
> + struct hsmp_socket *sock;
> + void __user *user_buf;
> + size_t tbl_size;
> + void *kbuf;
> + int ret;
> +
> + /* Telemetry data is read-only; require read access on the fd. */
> + if (!(fp->f_mode & FMODE_READ))
> + return -EPERM;
> +
> + if (copy_from_user(&req, arguser, sizeof(req)))
> + return -EFAULT;
> +
> + if (!hsmp_pdev.sock || req.sock_ind >= hsmp_pdev.num_sockets)
Sashiko warns userspace can use this as a speculation device so it needs
to be protected.
Please also address the req.reserved check mentioned by it with -EINVAL so
it can actually be used safely in future.
> + return -ENODEV;
> +
> + tbl_size = hsmp_pdev.hsmp_table_size;
> + if (!tbl_size)
> + return -ENODEV;
> +
> + /*
> + * Userspace must size its buffer using the appropriate UAPI metric
> + * table struct for the running protocol version. Reject mismatched
> + * sizes so we never silently truncate or short-write.
> + */
> + if (req.size != tbl_size)
> + return -EINVAL;
> +
> + sock = &hsmp_pdev.sock[req.sock_ind];
> + if (!sock->metric_tbl_addr)
> + return -ENODEV;
> +
> + user_buf = u64_to_user_ptr(req.buf);
> +
> + /*
> + * The bounce buffer is overwritten in full by memcpy_fromio() inside
> + * hsmp_metric_tbl_read(); use kvmalloc() to avoid the zeroing cost of
> + * kvzalloc() on the ~13 KB allocation done on every ioctl call.
> + */
> + kbuf = kvmalloc(tbl_size, GFP_KERNEL);
> + if (!kbuf)
> + return -ENOMEM;
> +
> + ret = hsmp_metric_tbl_read(sock, kbuf, tbl_size);
> + if (ret < 0)
> + goto out;
> +
> + if (copy_to_user(user_buf, kbuf, tbl_size))
> + ret = -EFAULT;
> + else
> + ret = 0;
> +
> +out:
> + kvfree(kbuf);
> + return ret;
> +}
> +
> +long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> +{
> + switch (cmd) {
> + case HSMP_IOCTL_CMD:
> + return hsmp_ioctl_msg(fp, arg);
> + case HSMP_IOCTL_GET_TELEMETRY_DATA:
> + return hsmp_ioctl_get_telemetry(fp, arg);
> + default:
> + return -ENOTTY;
> + }
> +}
> +
> ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size)
> {
> struct hsmp_message msg = { 0 };
>
--
i.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 2/7] platform/x86/amd/hsmp: Add UAPI structures for Family 1Ah Model 50h-5Fh metrics table
2026-05-17 15:12 ` [PATCH v3 2/7] platform/x86/amd/hsmp: Add UAPI structures for Family 1Ah Model 50h-5Fh metrics table Muralidhara M K
@ 2026-05-22 11:09 ` Ilpo Järvinen
2026-05-26 9:36 ` M K, Muralidhara
0 siblings, 1 reply; 19+ messages in thread
From: Ilpo Järvinen @ 2026-05-22 11:09 UTC (permalink / raw)
To: Muralidhara M K
Cc: platform-driver-x86, LKML, Suma Hegde, Muthusamy Ramalingam
On Sun, 17 May 2026, Muralidhara M K wrote:
> Define the UAPI structures hsmp_metric_table_zen6_iod,
> hsmp_metric_table_zen6_ccd and the top-level hsmp_metric_table_zen6
> to describe the per-IOD and per-CCD metrics layout for AMD Family 1Ah
> Model 50h-5Fh processors (HSMP protocol version 7). These structures
> allow userspace tools to interpret the raw metric table binary exposed
> through the HSMP character device.
>
> Driver enablement for protocol version 7 is added in a follow-up patch.
>
> Reviewed-by: Suma Hegde <suma.hegde@amd.com>
> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
> ---
> Changes:
> v1->v2: Split the change
> v2->v3: Move proto version check to seperate patch
>
> arch/x86/include/uapi/asm/amd_hsmp.h | 88 ++++++++++++++++++++++++++++
> 1 file changed, 88 insertions(+)
>
> diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
> index 603d62f8d4da..da3e3bbfa33e 100644
> --- a/arch/x86/include/uapi/asm/amd_hsmp.h
> +++ b/arch/x86/include/uapi/asm/amd_hsmp.h
> @@ -575,6 +575,94 @@ struct hsmp_metric_table {
> __u32 gfxclk_frequency[8];
> };
>
> +#define F1A_M50_M5F_MAX_CORES_PER_CCD_32 32
> +#define F1A_M50_M5F_MAX_FREQ_TABLE_SIZE 4
> +#define F1A_M50_M5F_MAX_XGMI 8
> +#define F1A_M50_M5F_MAX_PCIE 8
> +#define F1A_M50_M5F_MAX_CCD 8
Should have a prefix.
> +
> +/* Metrics table (supported only with proto version 7) */
> +struct hsmp_metric_table_zen6_iod {
> + __u32 num_active_ccds;
> + __u32 accumulation_counter;
> +
> + /* TEMPERATURE */
> + __u64 max_socket_temperature_acc;
> +
> + /* POWER */
> + __u32 socket_power_limit;
> + __u32 max_socket_power_limit;
> + __u64 socket_power_acc;
> + __u64 core_power_acc;
> + __u64 uncore_power_acc;
> +
> + /* ENERGY */
> + __u64 timestamp;
> + __u64 socket_energy_acc;
> + __u64 core_energy_acc;
> + __u64 uncore_energy_acc;
> +
> + /* FREQUENCY */
> + __u64 fclk_frequency_acc;
> + __u64 uclk_frequency_acc;
> + __u64 ddr_rate_acc;
> + __u64 lclk_frequency_acc[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
> +
> + /* FREQUENCY RANGE */
> + __u32 fclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
> + __u32 uclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
> + __u32 ddr_rate_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
> + __u32 max_df_pstate_range;
> + __u32 min_df_pstate_range;
> + __u32 lclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
> + __u32 max_lclk_dpm_range;
> + __u32 min_lclk_dpm_range;
> +
> + /* XGMI */
> + __u64 xgmi_bit_rate[F1A_M50_M5F_MAX_XGMI];
> + __u64 xgmi_read_bandwidth[F1A_M50_M5F_MAX_XGMI];
> + __u64 xgmi_write_bandwidth[F1A_M50_M5F_MAX_XGMI];
> +
> + /* ACTIVITY */
> + __u64 socket_c0_residency_acc;
> + __u64 socket_df_cstate_residency_acc;
> + __u64 dram_read_bandwidth_acc;
> + __u64 dram_write_bandwidth_acc;
> + __u32 max_dram_bandwidth;
> + __u64 pcie_bandwidth_acc[F1A_M50_M5F_MAX_PCIE];
> +
> + /* THROTTLERS */
> + __u32 prochot_residency_acc;
> + __u32 ppt_residency_acc;
> + __u32 thm_residency_acc;
> + __u32 vrhot_residency_acc;
> + __u32 cpu_tdc_residency_acc;
> + __u32 soc_tdc_residency_acc;
> + __u32 io_mem_tdc_residency_acc;
> + __u32 fit_residency_acc;
> +};
> +
> +struct hsmp_metric_table_zen6_ccd {
> + __u32 core_apicid_of_thread0[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
> + __u64 core_c0[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
> + __u64 core_cc1[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
> + __u64 core_cc6[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
> + __u64 core_frequency[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
> + __u64 core_frequency_effective[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
> + __u64 core_power[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
> +};
> +
> +/*
> + * Metrics table for Family 0x1A, Models 0x50 to 0x5F, table version 0x00700000
> + *
> + * Future processors within the same family and model may support a
> + * variable number of CCDs and cores
How is the correct number of CCDs then known?
If it's through num_active_ccds, I question if hsmp_metric_table_zen6
struct hierarchy is correct as then something under iod seems to
determine how to interpret the ccd[] array.
> + */
> +struct hsmp_metric_table_zen6 {
> + struct hsmp_metric_table_zen6_iod iod;
> + struct hsmp_metric_table_zen6_ccd ccd[F1A_M50_M5F_MAX_CCD];
> +};
> +
> /* Reset to default packing */
> #pragma pack()
>
>
--
i.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 5/7] platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table reads
2026-05-22 11:04 ` Ilpo Järvinen
@ 2026-05-22 11:27 ` Ilpo Järvinen
2026-05-26 9:43 ` M K, Muralidhara
1 sibling, 0 replies; 19+ messages in thread
From: Ilpo Järvinen @ 2026-05-22 11:27 UTC (permalink / raw)
To: Muralidhara M K; +Cc: platform-driver-x86, LKML, Muthusamy Ramalingam
[-- Attachment #1: Type: text/plain, Size: 9724 bytes --]
On Fri, 22 May 2026, Ilpo Järvinen wrote:
> On Sun, 17 May 2026, Muralidhara M K wrote:
>
> > The metric table for Family 1Ah Model 50h-5Fh
> > (struct hsmp_metric_table_zen6) is approximately 13 KB, exceeding the
> > PAGE_SIZE (4 KB) cap imposed on the standard sysfs binary attribute
> > read path. Rather than introduce new sysfs infrastructure to support
> > binary attributes larger than PAGE_SIZE, expose the metric table
> > through the existing HSMP character device using a new ioctl.
> >
> > Add struct hsmp_telemetry_data and HSMP_IOCTL_GET_TELEMETRY_DATA to
> > the UAPI header. The request structure carries the socket index, the
> > required buffer size and a __u64-encoded user pointer to the
> > destination buffer, so the same layout works for 32-bit and 64-bit
> > callers. Fields are ordered with the __u64 user pointer first so all
> > members fall on their natural alignment under #pragma pack(4), giving
> > a tight 16-byte struct with no implicit padding; the trailing
> > reserved __u16 is documented as "set to zero" so future kernels can
> > attach meaning to it. Userspace sizes its buffer using the matching
> > UAPI metric table struct (hsmp_metric_table or hsmp_metric_table_zen6)
> > for the running platform; sizes that disagree with the firmware-
> > reported table size are rejected with -EINVAL so a short copy can
> > never silently truncate the snapshot.
> >
> > Dispatch hsmp_ioctl() on the ioctl command, route HSMP_IOCTL_CMD to
> > the existing message handler (factored out as hsmp_ioctl_msg()) and
> > HSMP_IOCTL_GET_TELEMETRY_DATA to a new hsmp_ioctl_get_telemetry()
> > helper. The new helper validates the request, allocates a kernel
> > bounce buffer with kvmalloc() so it can hold the full table even
> > when it exceeds a single page (zeroing is skipped because the buffer
> > is overwritten in full by memcpy_fromio()), calls hsmp_metric_tbl_read()
> > to refresh and copy the table from the SMU DRAM region (under the
> > per-socket mutex introduced in a follow-up patch), and copies the
> > table to userspace. Unknown ioctl commands now return -ENOTTY instead
> > of falling through.
> >
> > Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> > Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> > Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
> > ---
> > Changes:
> > v1->v2: New patch based on bin sysfs
> > v2->v3: Replace with IOCTL method
> >
> > arch/x86/include/uapi/asm/amd_hsmp.h | 43 ++++++++++++++
> > drivers/platform/x86/amd/hsmp/hsmp.c | 85 +++++++++++++++++++++++++++-
> > 2 files changed, 127 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
> > index b86bbc929395..3d085298dd52 100644
> > --- a/arch/x86/include/uapi/asm/amd_hsmp.h
> > +++ b/arch/x86/include/uapi/asm/amd_hsmp.h
> > @@ -664,6 +664,40 @@ struct hsmp_metric_table_zen6 {
> > struct hsmp_metric_table_zen6_ccd ccd[F1A_M50_M5F_MAX_CCD];
> > };
> >
> > +/**
> > + * struct hsmp_telemetry_data - Request descriptor for HSMP telemetry IOCTL
> > + * @buf: Input. Userspace pointer (encoded as __u64 to keep the layout
> > + * stable between 32-bit and 64-bit callers) to the destination
> > + * buffer that receives the metric table.
> > + * @size: Input. Size in bytes of the buffer pointed to by @buf. Must
> > + * match the firmware-reported metric table size for the running
> > + * HSMP protocol version (see below); any other value results in
> > + * -EINVAL. The kernel does not write this field back.
> > + * @sock_ind: Input. Socket index from which the metric table is read.
> > + * @reserved: Reserved for future use. Callers should set this to zero;
> > + * future kernels may begin interpreting the field, so passing
> > + * a non-zero value today is not forwards compatible.
> > + *
> > + * Placing @buf first lets all fields fall on their natural alignment under
> > + * the surrounding #pragma pack(4), so the struct is a tight 16 bytes with
> > + * the same wire layout on 32-bit and 64-bit userspace.
> > + *
> > + * The exact metric table layout depends on the HSMP protocol version reported
> > + * by the firmware:
> > + * - Protocol version 6 -> struct hsmp_metric_table
> > + * - Protocol version 7 -> struct hsmp_metric_table_zen6
> > + *
> > + * Userspace queries the protocol version (e.g. via the protocol_version sysfs
> > + * attribute) and uses sizeof() on the matching UAPI structure for both @size
> > + * and the allocation backing @buf.
> > + */
> > +struct hsmp_telemetry_data {
> > + __u64 buf;
> > + __u32 size;
> > + __u16 sock_ind;
> > + __u16 reserved;
> > +};
> > +
> > /* Reset to default packing */
> > #pragma pack()
> >
> > @@ -671,4 +705,13 @@ struct hsmp_metric_table_zen6 {
> > #define HSMP_BASE_IOCTL_NR 0xF8
> > #define HSMP_IOCTL_CMD _IOWR(HSMP_BASE_IOCTL_NR, 0, struct hsmp_message)
> >
> > +/*
> > + * Fetch the firmware metric (telemetry) table for a given socket via the
> > + * HSMP character device. This avoids the PAGE_SIZE limitation of the
> > + * sysfs binary attribute path for tables larger than one page (such as the
> > + * ~13 KB hsmp_metric_table_zen6 used on Family 1Ah Model 50h-5Fh).
> > + */
> > +#define HSMP_IOCTL_GET_TELEMETRY_DATA \
> > + _IOWR(HSMP_BASE_IOCTL_NR, 1, struct hsmp_telemetry_data)
> > +
> > #endif /*_ASM_X86_AMD_HSMP_H_*/
> > diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
> > index cf9392f99298..3a02d683dea0 100644
> > --- a/drivers/platform/x86/amd/hsmp/hsmp.c
> > +++ b/drivers/platform/x86/amd/hsmp/hsmp.c
> > @@ -13,7 +13,9 @@
> > #include <linux/delay.h>
> > #include <linux/device.h>
> > #include <linux/semaphore.h>
> > +#include <linux/slab.h>
> > #include <linux/sysfs.h>
> > +#include <linux/uaccess.h>
> >
> > #include "hsmp.h"
> >
> > @@ -287,7 +289,7 @@ static bool is_get_msg(struct hsmp_message *msg)
> > return false;
> > }
> >
> > -long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> > +static long hsmp_ioctl_msg(struct file *fp, unsigned long arg)
> > {
> > int __user *arguser = (int __user *)arg;
> > struct hsmp_message msg = { 0 };
> > @@ -343,6 +345,87 @@ long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> > return 0;
> > }
> >
> > +/*
> > + * Fetch the firmware metric (telemetry) table for the requested socket and
> > + * copy it to the userspace buffer described by the request.
> > + *
> > + * The metric table size is variable across HSMP protocol versions and on
> > + * Family 1Ah Model 50h-5Fh exceeds PAGE_SIZE. Userspace must therefore
> > + * supply a buffer at least the firmware-reported size in bytes.
> > + */
> > +static long hsmp_ioctl_get_telemetry(struct file *fp, unsigned long arg)
> > +{
> > + void __user *arguser = (void __user *)arg;
> > + struct hsmp_telemetry_data req;
> > + struct hsmp_socket *sock;
> > + void __user *user_buf;
> > + size_t tbl_size;
> > + void *kbuf;
> > + int ret;
> > +
> > + /* Telemetry data is read-only; require read access on the fd. */
> > + if (!(fp->f_mode & FMODE_READ))
> > + return -EPERM;
> > +
> > + if (copy_from_user(&req, arguser, sizeof(req)))
> > + return -EFAULT;
> > +
> > + if (!hsmp_pdev.sock || req.sock_ind >= hsmp_pdev.num_sockets)
>
> Sashiko warns userspace can use this as a speculation device so it needs
> to be protected.
Hi again,
While looking at the other patches, I also noticed hsmp_ioctl() has a
similar userspace driver check (in pre-existing code):
if (msg.msg_id < HSMP_TEST || msg.msg_id >= HSMP_MSG_ID_MAX)
--
i.
> Please also address the req.reserved check mentioned by it with -EINVAL so
> it can actually be used safely in future.
>
> > + return -ENODEV;
> > +
> > + tbl_size = hsmp_pdev.hsmp_table_size;
> > + if (!tbl_size)
> > + return -ENODEV;
> > +
> > + /*
> > + * Userspace must size its buffer using the appropriate UAPI metric
> > + * table struct for the running protocol version. Reject mismatched
> > + * sizes so we never silently truncate or short-write.
> > + */
> > + if (req.size != tbl_size)
> > + return -EINVAL;
> > +
> > + sock = &hsmp_pdev.sock[req.sock_ind];
> > + if (!sock->metric_tbl_addr)
> > + return -ENODEV;
> > +
> > + user_buf = u64_to_user_ptr(req.buf);
> > +
> > + /*
> > + * The bounce buffer is overwritten in full by memcpy_fromio() inside
> > + * hsmp_metric_tbl_read(); use kvmalloc() to avoid the zeroing cost of
> > + * kvzalloc() on the ~13 KB allocation done on every ioctl call.
> > + */
> > + kbuf = kvmalloc(tbl_size, GFP_KERNEL);
> > + if (!kbuf)
> > + return -ENOMEM;
> > +
> > + ret = hsmp_metric_tbl_read(sock, kbuf, tbl_size);
> > + if (ret < 0)
> > + goto out;
> > +
> > + if (copy_to_user(user_buf, kbuf, tbl_size))
> > + ret = -EFAULT;
> > + else
> > + ret = 0;
> > +
> > +out:
> > + kvfree(kbuf);
> > + return ret;
> > +}
> > +
> > +long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> > +{
> > + switch (cmd) {
> > + case HSMP_IOCTL_CMD:
> > + return hsmp_ioctl_msg(fp, arg);
> > + case HSMP_IOCTL_GET_TELEMETRY_DATA:
> > + return hsmp_ioctl_get_telemetry(fp, arg);
> > + default:
> > + return -ENOTTY;
> > + }
> > +}
> > +
> > ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size)
> > {
> > struct hsmp_message msg = { 0 };
> >
>
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 6/7] platform/x86/amd/hsmp: Drop ACPI sysfs metrics_bin in favour of the IOCTL
2026-05-17 15:12 ` [PATCH v3 6/7] platform/x86/amd/hsmp: Drop ACPI sysfs metrics_bin in favour of the IOCTL Muralidhara M K
@ 2026-05-22 11:44 ` Ilpo Järvinen
2026-05-26 9:59 ` M K, Muralidhara
0 siblings, 1 reply; 19+ messages in thread
From: Ilpo Järvinen @ 2026-05-22 11:44 UTC (permalink / raw)
To: Muralidhara M K; +Cc: platform-driver-x86, LKML, Muthusamy Ramalingam
On Sun, 17 May 2026, Muralidhara M K wrote:
> The HSMP_IOCTL_GET_TELEMETRY_DATA character-device ioctl introduced in
> the previous patch is now the canonical interface for reading the
> metric table on the ACPI driver path. Unlike the metrics_bin sysfs
> binary attribute, the ioctl is not constrained by PAGE_SIZE, so it
> works for the ~13 KB hsmp_metric_table_zen6 layout
This was only a secondary reason from moving away from sysfs files? The
main cause for moving to misc device according to my impression was that
you wanted to prevent partial reads which are always possible with files.
> used on Family 1Ah
> Model 50h-5Fh as well as for the existing hsmp_metric_table layout
> used on protocol version 6.
> Drop the metrics_bin bin_attribute from the ACPI hsmp_attr_grp.
> Widen the remaining proto_ver gate in init_acpi() from
> '== HSMP_PROTO_VER6' to '>= HSMP_PROTO_VER6' so
> hsmp_get_tbl_dram_base() is invoked on protocol version 7
> (Family 1Ah Model 50h-5Fh) and any future protocol version that
> retains a compatible per-socket metric table. This populates
> sock->metric_tbl_addr and hsmp_pdev.hsmp_table_size, which the ioctl
> handler requires.
These are two logically separate changes so they should not be in the same
patch (but you'll likely need to alter the drop patch anyway, see below).
> This is an ABI change for users of the ACPI driver:
> /sys/bus/platform/devices/AMDI0097:*/metrics_bin no longer exists.
> Userspace must read telemetry through the HSMP_IOCTL_GET_TELEMETRY_DATA
> ioctl on /dev/hsmp instead, sizing its buffer using the matching UAPI
> metric table struct.
I might not be entirely following what's the extent of removal here but it
looks too extensive to me. The number 1 rule is that we cannot take away
existing and working ABI without properly deprecating it first.
You don't have to make it work with version 7 and can return error in
that case as it has never worked. But with version 6, things shouls be
left as is until properly deprecated. You may consider adding a warning
print too to warn about the deprecation and point towards the new way.
This interface probably never was documented in Documentation/ABI where
such deprecations are usually marked... oh well, maybe we need to add
a simple entry for this ABI there to follow the usual deprecation path.
--
i.
> The non-ACPI plat.c path is intentionally left
> unchanged: it covers Family 1Ah Model 0h-Fh hardware that is fixed at
> protocol version 6, and its per-socket metrics_bin remains available
> for existing userspace tooling on those systems.
>
> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
> ---
> Changes:
> v1->v3: Remove bin attributes
>
> drivers/platform/x86/amd/hsmp/acpi.c | 34 +---------------------------
> 1 file changed, 1 insertion(+), 33 deletions(-)
>
> diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
> index 97ed71593bdf..49765fefe1fb 100644
> --- a/drivers/platform/x86/amd/hsmp/acpi.c
> +++ b/drivers/platform/x86/amd/hsmp/acpi.c
> @@ -231,25 +231,6 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind)
> return hsmp_read_acpi_dsd(sock);
> }
>
> -static ssize_t hsmp_metric_tbl_acpi_read(struct file *filp, struct kobject *kobj,
> - const struct bin_attribute *bin_attr, char *buf,
> - loff_t off, size_t count)
> -{
> - struct device *dev = container_of(kobj, struct device, kobj);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> -
> - return hsmp_metric_tbl_read(sock, buf, count);
> -}
> -
> -static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
> - const struct bin_attribute *battr, int id)
> -{
> - if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6)
> - return battr->attr.mode;
> -
> - return 0;
> -}
> -
> static umode_t hsmp_is_sock_dev_attr_visible(struct kobject *kobj,
> struct attribute *attr, int id)
> {
> @@ -491,7 +472,7 @@ static int init_acpi(struct device *dev)
> return ret;
> }
>
> - if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) {
> + if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) {
> ret = hsmp_get_tbl_dram_base(sock_ind);
> if (ret)
> dev_info(dev, "Failed to init metric table\n");
> @@ -506,17 +487,6 @@ static int init_acpi(struct device *dev)
> return 0;
> }
>
> -static const struct bin_attribute hsmp_metric_tbl_attr = {
> - .attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444},
> - .read = hsmp_metric_tbl_acpi_read,
> - .size = sizeof(struct hsmp_metric_table),
> -};
> -
> -static const struct bin_attribute *hsmp_attr_list[] = {
> - &hsmp_metric_tbl_attr,
> - NULL
> -};
> -
> #define HSMP_DEV_ATTR(_name, _msg_id, _show, _mode) \
> static struct hsmp_sys_attr hattr_##_name = { \
> .dattr = __ATTR(_name, _mode, _show, NULL), \
> @@ -559,9 +529,7 @@ static struct attribute *hsmp_dev_attr_list[] = {
> };
>
> static const struct attribute_group hsmp_attr_grp = {
> - .bin_attrs = hsmp_attr_list,
> .attrs = hsmp_dev_attr_list,
> - .is_bin_visible = hsmp_is_sock_attr_visible,
> .is_visible = hsmp_is_sock_dev_attr_visible,
> };
>
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model 50h-5Fh
2026-05-17 15:12 ` [PATCH v3 1/7] platform/x86/amd/hsmp: Add new HSMP messages " Muralidhara M K
@ 2026-05-22 11:49 ` Ilpo Järvinen
2026-05-26 9:21 ` M K, Muralidhara
0 siblings, 1 reply; 19+ messages in thread
From: Ilpo Järvinen @ 2026-05-22 11:49 UTC (permalink / raw)
To: Muralidhara M K
Cc: platform-driver-x86, LKML, Suma Hegde, Muthusamy Ramalingam
On Sun, 17 May 2026, Muralidhara M K wrote:
> From: Suma Hegde <suma.hegde@amd.com>
>
> The new messages extend the HSMP interface to provide finer control over
> power states and system monitoring capabilities.
>
> Power state control:
> - Get/Set PC6 and CC6 enable/disable control (0x29, 0x2A)
>
> Power and thermal monitoring:
> - Get CCD power consumption reading (0x34)
> - Get Thermal delta (Tdelta) reading (0x35)
> - Get SVI3 VR controller temperature (0x36)
>
> DIMM sideband operations:
> - Get/Set DIMM sideband data(0x33, 0x39)
>
> Power management:
> - Get/Set Floor limit control (0x38)
> - Get/Set SDPS limit control (0x3A)
>
> System capabilities:
> - Get enabled HSMP commands (0x37)
As you change the existing entries, how does the old stuff handle the
newly allowed commands (which were previously blocked due to
hsmp_msg_desc_table[])? It would be good to explain in the changelog why
it's safe to do.
--
i.
> Bump driver version to 2.6.
>
> Reviewed-by: Muralidhara M K <muralidhara.mk@amd.com>
> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
> Signed-off-by: Suma Hegde <suma.hegde@amd.com>
> ---
> Changes v1->v3: None
>
> arch/x86/include/uapi/asm/amd_hsmp.h | 142 +++++++++++++++++++++++----
> drivers/platform/x86/amd/hsmp/hsmp.h | 2 +-
> 2 files changed, 126 insertions(+), 18 deletions(-)
>
> diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
> index 92d8f256d096..603d62f8d4da 100644
> --- a/arch/x86/include/uapi/asm/amd_hsmp.h
> +++ b/arch/x86/include/uapi/asm/amd_hsmp.h
> @@ -53,9 +53,19 @@ enum hsmp_message_ids {
> HSMP_SET_XGMI_PSTATE_RANGE, /* 26h Set xGMI P-state range */
> HSMP_CPU_RAIL_ISO_FREQ_POLICY, /* 27h Get/Set Cpu Iso frequency policy */
> HSMP_DFC_ENABLE_CTRL, /* 28h Enable/Disable DF C-state */
> + HSMP_PC6_ENABLE, /* 29h Get/Set PC6 enable/disable status */
> + HSMP_CC6_ENABLE, /* 2Ah Get/Set CC6 enable/disable status */
> HSMP_GET_RAPL_UNITS = 0x30, /* 30h Get scaling factor for energy */
> HSMP_GET_RAPL_CORE_COUNTER, /* 31h Get core energy counter value */
> HSMP_GET_RAPL_PACKAGE_COUNTER, /* 32h Get package energy counter value */
> + HSMP_DIMM_SB_RD, /* 33h Get data from a specified device on the DIMM */
> + HSMP_READ_CCD_POWER, /* 34h Get the average power consumed by CCD */
> + HSMP_READ_TDELTA, /* 35h Get thermal solution behaviour */
> + HSMP_GET_SVI3_VR_CTRL_TEMP, /* 36h Get temperature of SVI3 VR controller rails */
> + HSMP_GET_ENABLED_HSMP_CMDS, /* 37h Get/Set supported HSMP commands */
> + HSMP_SET_GET_FLOOR_LIMIT, /* 38h Get/Set supported Floor limit commands */
> + HSMP_DIMM_SB_WR, /* 39h Set data to a specified device on the DIMM */
> + HSMP_SDPS_LIMIT, /* 3Ah Get/Set SDPS limit */
> HSMP_MSG_ID_MAX,
> };
>
> @@ -170,16 +180,18 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
> {0, 1, HSMP_GET},
>
> /*
> - * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0
> - * input: args[0] = min link width[15:8] + max link width[7:0]
> + * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0/1
> + * input: args[0] = set/get XGMI Link width[31] + min link width[15:8] + max link width[7:0]
> + * output: args[0] = current min link width[15:8] + current max link width[7:0]
> */
> - {1, 0, HSMP_SET},
> + {1, 1, HSMP_SET_GET},
>
> /*
> - * HSMP_SET_DF_PSTATE, num_args = 1, response_sz = 0
> - * input: args[0] = df pstate[7:0]
> + * HSMP_SET_DF_PSTATE, num_args = 1, response_sz = 0/1
> + * input: args[0] = set/get df pstate[31] + df pstate[7:0]
> + * output: args[0] = APB enabled/disabled[8] + current df pstate[7:0]
> */
> - {1, 0, HSMP_SET},
> + {1, 1, HSMP_SET_GET},
>
> /* HSMP_SET_AUTO_DF_PSTATE, num_args = 0, response_sz = 0 */
> {0, 0, HSMP_SET},
> @@ -305,16 +317,18 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
> {1, 1, HSMP_SET},
>
> /*
> - * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0
> - * input: args[0] = power efficiency mode[2:0]
> + * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0/1
> + * input: args[0] = set/get power mode[31] + power efficiency mode[2:0]
> + * output: args[0] = current power efficiency mode[2:0]
> */
> {1, 1, HSMP_SET_GET},
>
> /*
> - * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0
> - * input: args[0] = min df pstate[15:8] + max df pstate[7:0]
> + * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0/1
> + * input: args[0] = set/get DF P-state range[31] + min df pstate[15:8] + max df pstate[7:0]
> + * output: args[0] = min df pstate[15:8] + max df pstate[7:0]
> */
> - {1, 0, HSMP_SET},
> + {1, 1, HSMP_SET_GET},
>
> /*
> * HSMP_GET_METRIC_TABLE_VER, num_args = 0, response_sz = 1
> @@ -335,10 +349,12 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
> {0, 2, HSMP_GET},
>
> /*
> - * HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0
> - * input: args[0] = min xGMI p-state[15:8] + max xGMI p-state[7:0]
> + * HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0/1
> + * input: args[0] = set/get XGMI pstate range[31] + min xGMI p-state[15:8] +
> + * max xGMI p-state[7:0]
> + * output: args[0] = min xGMI p-state[15:8] + max xGMI p-state[7:0]
> */
> - {1, 0, HSMP_SET},
> + {1, 1, HSMP_SET_GET},
>
> /*
> * HSMP_CPU_RAIL_ISO_FREQ_POLICY, num_args = 1, response_sz = 1
> @@ -355,9 +371,21 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
> */
> {1, 1, HSMP_SET_GET},
>
> - /* RESERVED(0x29-0x2f) */
> - {0, 0, HSMP_RSVD},
> - {0, 0, HSMP_RSVD},
> + /*
> + * HSMP_PC6_ENABLE, num_args = 1, response_sz = 0/1
> + * input: args[0] = set/get PC6 control[31] + disable/enable PC6[0]
> + * output: args[0] = current PC6 control status[0]
> + */
> + {1, 1, HSMP_SET_GET},
> +
> + /*
> + * HSMP_CC6_ENABLE, num_args = 1, response_sz = 0/1
> + * input: args[0] = set/get CC6 control[31] + disable/enable CC6[0]
> + * output: args[0] = current CC6 control status[0]
> + */
> + {1, 1, HSMP_SET_GET},
> +
> + /* RESERVED(0x2B-0x2F) */
> {0, 0, HSMP_RSVD},
> {0, 0, HSMP_RSVD},
> {0, 0, HSMP_RSVD},
> @@ -385,6 +413,86 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
> */
> {0, 2, HSMP_GET},
>
> + /*
> + * HSMP_DIMM_SB_RD, num_args = 1, response_sz = 1
> + * input: args[0] =
> + * Register space[23]
> + * Register offset in given reg space[22:12]
> + * LID of device[11:8]
> + * DIMM address[7:0]
> + * output: args[0] = [3:0] Read data byte
> + */
> + {1, 1, HSMP_GET},
> +
> + /*
> + * HSMP_READ_CCD_POWER, num_args = 1, response_sz = 1
> + * input: args[0] = apic id of core[15:0]
> + * output: args[0] = CCD power(mWatts)[31:0]
> + */
> + {1, 1, HSMP_GET},
> +
> + /*
> + * HSMP_READ_TDELTA, num_args = 0, response_sz = 1
> + * input: None
> + * output: args[0] = thermal behaviour[31:0]
> + */
> + {0, 1, HSMP_GET},
> +
> + /*
> + * HSMP_GET_SVI3_VR_CTRL_TEMP, num_args = 1, response_sz = 1
> + * input: args[0] = SVI3 rail index[3:1] + Read SVI3 temperature data[0]
> + * output: args[0] = SVI3 rail index[30:28] + SVI3 rail temperature(degree C)[27:0]
> + */
> + {1, 1, HSMP_GET},
> +
> + /*
> + * HSMP_GET_ENABLED_HSMP_CMDS, num_args = 1, response_sz = 3
> + * input: args[0] = HSMP command mask[0]
> + * output: status of HSMP command = args[0], args[1], args[2]
> + */
> + {1, 3, HSMP_GET},
> +
> + /*
> + * HSMP_SET_GET_FLOOR_LIMIT, num_args = 1, response_sz = 1
> + * input: args[0] =
> + * Set or Get[31:30]
> + * Set the Floor frequency per core = 00
> + * Set the Floor frequency for all cores = 01
> + * Get the Floor frequency of a core = 10
> + * Get the Effective Floor frequency per core = 11
> + * Reserved[29:28]
> + * Apic id / Reserved[27:16]
> + * args[27:16] is reserved if args[31:30] = 01
> + * Floor frequency limit / Reserved[15:0]
> + * if args[31] = 0, Floor frequency limit, else reserved
> + *
> + * output: args[0] =
> + * Effective Floor frequency limit(MHz) / None / Floor frequency limit[15:0]
> + * Effective Floor frequency if input args[31:30] = 11
> + * None if input args[31] = 0
> + * Floor frequency limit (MHz)[15:0] if args[31:30] = 10
> + */
> + {1, 1, HSMP_SET_GET},
> +
> + /*
> + * HSMP_DIMM_SB_WR, num_args = 1, response_sz = 0
> + * input: args[0] =
> + * Write Data[31:24]
> + * Register space[23]
> + * Register offset in given reg space[22:12]
> + * LID of device[11:8]
> + * DIMM address[7:0]
> + * output: None
> + */
> + {1, 0, HSMP_SET},
> +
> + /*
> + * HSMP_SDPS_LIMIT, num_args = 1, response_sz = 1
> + * input: args[0] = Set/Get[31] + SDPS Limit[30:0]
> + * output: args[0] = SDPS Limit[30:0]
> + */
> + {1, 1, HSMP_SET_GET},
> +
> };
>
> /* Metrics table (supported only with proto version 6) */
> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
> index 0509a442eaae..b153527e0a0d 100644
> --- a/drivers/platform/x86/amd/hsmp/hsmp.h
> +++ b/drivers/platform/x86/amd/hsmp/hsmp.h
> @@ -27,7 +27,7 @@
> #define HSMP_DEVNODE_NAME "hsmp"
> #define ACPI_HSMP_DEVICE_HID "AMDI0097"
>
> -#define DRIVER_VERSION "2.5"
> +#define DRIVER_VERSION "2.6"
>
> struct hsmp_mbaddr_info {
> u32 base_addr;
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model 50h-5Fh
2026-05-22 11:49 ` Ilpo Järvinen
@ 2026-05-26 9:21 ` M K, Muralidhara
0 siblings, 0 replies; 19+ messages in thread
From: M K, Muralidhara @ 2026-05-26 9:21 UTC (permalink / raw)
To: Ilpo Järvinen, Muralidhara M K
Cc: platform-driver-x86, LKML, Suma Hegde, Muthusamy Ramalingam
On 5/22/2026 5:19 PM, Ilpo Järvinen wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> On Sun, 17 May 2026, Muralidhara M K wrote:
>
>> From: Suma Hegde <suma.hegde@amd.com>
>>
>> The new messages extend the HSMP interface to provide finer control over
>> power states and system monitoring capabilities.
>>
>> Power state control:
>> - Get/Set PC6 and CC6 enable/disable control (0x29, 0x2A)
>>
>> Power and thermal monitoring:
>> - Get CCD power consumption reading (0x34)
>> - Get Thermal delta (Tdelta) reading (0x35)
>> - Get SVI3 VR controller temperature (0x36)
>>
>> DIMM sideband operations:
>> - Get/Set DIMM sideband data(0x33, 0x39)
>>
>> Power management:
>> - Get/Set Floor limit control (0x38)
>> - Get/Set SDPS limit control (0x3A)
>>
>> System capabilities:
>> - Get enabled HSMP commands (0x37)
>
> As you change the existing entries, how does the old stuff handle the
> newly allowed commands (which were previously blocked due to
> hsmp_msg_desc_table[])? It would be good to explain in the changelog why
> it's safe to do.
>
These HSMP message IDs are newly introduced for the Venice platform
(Family 1Ah, Models 50h-5Fh) and subsequent platforms. These commands
are not available on earlier platforms. This information I will document
in the changelog.
> --
> i.
>
>> Bump driver version to 2.6.
>>
>> Reviewed-by: Muralidhara M K <muralidhara.mk@amd.com>
>> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Suma Hegde <suma.hegde@amd.com>
>> ---
>> Changes v1->v3: None
>>
>> arch/x86/include/uapi/asm/amd_hsmp.h | 142 +++++++++++++++++++++++----
>> drivers/platform/x86/amd/hsmp/hsmp.h | 2 +-
>> 2 files changed, 126 insertions(+), 18 deletions(-)
>>
>> diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
>> index 92d8f256d096..603d62f8d4da 100644
>> --- a/arch/x86/include/uapi/asm/amd_hsmp.h
>> +++ b/arch/x86/include/uapi/asm/amd_hsmp.h
>> @@ -53,9 +53,19 @@ enum hsmp_message_ids {
>> HSMP_SET_XGMI_PSTATE_RANGE, /* 26h Set xGMI P-state range */
>> HSMP_CPU_RAIL_ISO_FREQ_POLICY, /* 27h Get/Set Cpu Iso frequency policy */
>> HSMP_DFC_ENABLE_CTRL, /* 28h Enable/Disable DF C-state */
>> + HSMP_PC6_ENABLE, /* 29h Get/Set PC6 enable/disable status */
>> + HSMP_CC6_ENABLE, /* 2Ah Get/Set CC6 enable/disable status */
>> HSMP_GET_RAPL_UNITS = 0x30, /* 30h Get scaling factor for energy */
>> HSMP_GET_RAPL_CORE_COUNTER, /* 31h Get core energy counter value */
>> HSMP_GET_RAPL_PACKAGE_COUNTER, /* 32h Get package energy counter value */
>> + HSMP_DIMM_SB_RD, /* 33h Get data from a specified device on the DIMM */
>> + HSMP_READ_CCD_POWER, /* 34h Get the average power consumed by CCD */
>> + HSMP_READ_TDELTA, /* 35h Get thermal solution behaviour */
>> + HSMP_GET_SVI3_VR_CTRL_TEMP, /* 36h Get temperature of SVI3 VR controller rails */
>> + HSMP_GET_ENABLED_HSMP_CMDS, /* 37h Get/Set supported HSMP commands */
>> + HSMP_SET_GET_FLOOR_LIMIT, /* 38h Get/Set supported Floor limit commands */
>> + HSMP_DIMM_SB_WR, /* 39h Set data to a specified device on the DIMM */
>> + HSMP_SDPS_LIMIT, /* 3Ah Get/Set SDPS limit */
>> HSMP_MSG_ID_MAX,
>> };
>>
>> @@ -170,16 +180,18 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
>> {0, 1, HSMP_GET},
>>
>> /*
>> - * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0
>> - * input: args[0] = min link width[15:8] + max link width[7:0]
>> + * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0/1
>> + * input: args[0] = set/get XGMI Link width[31] + min link width[15:8] + max link width[7:0]
>> + * output: args[0] = current min link width[15:8] + current max link width[7:0]
>> */
>> - {1, 0, HSMP_SET},
>> + {1, 1, HSMP_SET_GET},
>>
>> /*
>> - * HSMP_SET_DF_PSTATE, num_args = 1, response_sz = 0
>> - * input: args[0] = df pstate[7:0]
>> + * HSMP_SET_DF_PSTATE, num_args = 1, response_sz = 0/1
>> + * input: args[0] = set/get df pstate[31] + df pstate[7:0]
>> + * output: args[0] = APB enabled/disabled[8] + current df pstate[7:0]
>> */
>> - {1, 0, HSMP_SET},
>> + {1, 1, HSMP_SET_GET},
>>
>> /* HSMP_SET_AUTO_DF_PSTATE, num_args = 0, response_sz = 0 */
>> {0, 0, HSMP_SET},
>> @@ -305,16 +317,18 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
>> {1, 1, HSMP_SET},
>>
>> /*
>> - * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0
>> - * input: args[0] = power efficiency mode[2:0]
>> + * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0/1
>> + * input: args[0] = set/get power mode[31] + power efficiency mode[2:0]
>> + * output: args[0] = current power efficiency mode[2:0]
>> */
>> {1, 1, HSMP_SET_GET},
>>
>> /*
>> - * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0
>> - * input: args[0] = min df pstate[15:8] + max df pstate[7:0]
>> + * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0/1
>> + * input: args[0] = set/get DF P-state range[31] + min df pstate[15:8] + max df pstate[7:0]
>> + * output: args[0] = min df pstate[15:8] + max df pstate[7:0]
>> */
>> - {1, 0, HSMP_SET},
>> + {1, 1, HSMP_SET_GET},
>>
>> /*
>> * HSMP_GET_METRIC_TABLE_VER, num_args = 0, response_sz = 1
>> @@ -335,10 +349,12 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
>> {0, 2, HSMP_GET},
>>
>> /*
>> - * HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0
>> - * input: args[0] = min xGMI p-state[15:8] + max xGMI p-state[7:0]
>> + * HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0/1
>> + * input: args[0] = set/get XGMI pstate range[31] + min xGMI p-state[15:8] +
>> + * max xGMI p-state[7:0]
>> + * output: args[0] = min xGMI p-state[15:8] + max xGMI p-state[7:0]
>> */
>> - {1, 0, HSMP_SET},
>> + {1, 1, HSMP_SET_GET},
>>
>> /*
>> * HSMP_CPU_RAIL_ISO_FREQ_POLICY, num_args = 1, response_sz = 1
>> @@ -355,9 +371,21 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
>> */
>> {1, 1, HSMP_SET_GET},
>>
>> - /* RESERVED(0x29-0x2f) */
>> - {0, 0, HSMP_RSVD},
>> - {0, 0, HSMP_RSVD},
>> + /*
>> + * HSMP_PC6_ENABLE, num_args = 1, response_sz = 0/1
>> + * input: args[0] = set/get PC6 control[31] + disable/enable PC6[0]
>> + * output: args[0] = current PC6 control status[0]
>> + */
>> + {1, 1, HSMP_SET_GET},
>> +
>> + /*
>> + * HSMP_CC6_ENABLE, num_args = 1, response_sz = 0/1
>> + * input: args[0] = set/get CC6 control[31] + disable/enable CC6[0]
>> + * output: args[0] = current CC6 control status[0]
>> + */
>> + {1, 1, HSMP_SET_GET},
>> +
>> + /* RESERVED(0x2B-0x2F) */
>> {0, 0, HSMP_RSVD},
>> {0, 0, HSMP_RSVD},
>> {0, 0, HSMP_RSVD},
>> @@ -385,6 +413,86 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[]
>> */
>> {0, 2, HSMP_GET},
>>
>> + /*
>> + * HSMP_DIMM_SB_RD, num_args = 1, response_sz = 1
>> + * input: args[0] =
>> + * Register space[23]
>> + * Register offset in given reg space[22:12]
>> + * LID of device[11:8]
>> + * DIMM address[7:0]
>> + * output: args[0] = [3:0] Read data byte
>> + */
>> + {1, 1, HSMP_GET},
>> +
>> + /*
>> + * HSMP_READ_CCD_POWER, num_args = 1, response_sz = 1
>> + * input: args[0] = apic id of core[15:0]
>> + * output: args[0] = CCD power(mWatts)[31:0]
>> + */
>> + {1, 1, HSMP_GET},
>> +
>> + /*
>> + * HSMP_READ_TDELTA, num_args = 0, response_sz = 1
>> + * input: None
>> + * output: args[0] = thermal behaviour[31:0]
>> + */
>> + {0, 1, HSMP_GET},
>> +
>> + /*
>> + * HSMP_GET_SVI3_VR_CTRL_TEMP, num_args = 1, response_sz = 1
>> + * input: args[0] = SVI3 rail index[3:1] + Read SVI3 temperature data[0]
>> + * output: args[0] = SVI3 rail index[30:28] + SVI3 rail temperature(degree C)[27:0]
>> + */
>> + {1, 1, HSMP_GET},
>> +
>> + /*
>> + * HSMP_GET_ENABLED_HSMP_CMDS, num_args = 1, response_sz = 3
>> + * input: args[0] = HSMP command mask[0]
>> + * output: status of HSMP command = args[0], args[1], args[2]
>> + */
>> + {1, 3, HSMP_GET},
>> +
>> + /*
>> + * HSMP_SET_GET_FLOOR_LIMIT, num_args = 1, response_sz = 1
>> + * input: args[0] =
>> + * Set or Get[31:30]
>> + * Set the Floor frequency per core = 00
>> + * Set the Floor frequency for all cores = 01
>> + * Get the Floor frequency of a core = 10
>> + * Get the Effective Floor frequency per core = 11
>> + * Reserved[29:28]
>> + * Apic id / Reserved[27:16]
>> + * args[27:16] is reserved if args[31:30] = 01
>> + * Floor frequency limit / Reserved[15:0]
>> + * if args[31] = 0, Floor frequency limit, else reserved
>> + *
>> + * output: args[0] =
>> + * Effective Floor frequency limit(MHz) / None / Floor frequency limit[15:0]
>> + * Effective Floor frequency if input args[31:30] = 11
>> + * None if input args[31] = 0
>> + * Floor frequency limit (MHz)[15:0] if args[31:30] = 10
>> + */
>> + {1, 1, HSMP_SET_GET},
>> +
>> + /*
>> + * HSMP_DIMM_SB_WR, num_args = 1, response_sz = 0
>> + * input: args[0] =
>> + * Write Data[31:24]
>> + * Register space[23]
>> + * Register offset in given reg space[22:12]
>> + * LID of device[11:8]
>> + * DIMM address[7:0]
>> + * output: None
>> + */
>> + {1, 0, HSMP_SET},
>> +
>> + /*
>> + * HSMP_SDPS_LIMIT, num_args = 1, response_sz = 1
>> + * input: args[0] = Set/Get[31] + SDPS Limit[30:0]
>> + * output: args[0] = SDPS Limit[30:0]
>> + */
>> + {1, 1, HSMP_SET_GET},
>> +
>> };
>>
>> /* Metrics table (supported only with proto version 6) */
>> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
>> index 0509a442eaae..b153527e0a0d 100644
>> --- a/drivers/platform/x86/amd/hsmp/hsmp.h
>> +++ b/drivers/platform/x86/amd/hsmp/hsmp.h
>> @@ -27,7 +27,7 @@
>> #define HSMP_DEVNODE_NAME "hsmp"
>> #define ACPI_HSMP_DEVICE_HID "AMDI0097"
>>
>> -#define DRIVER_VERSION "2.5"
>> +#define DRIVER_VERSION "2.6"
>>
>> struct hsmp_mbaddr_info {
>> u32 base_addr;
>>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 2/7] platform/x86/amd/hsmp: Add UAPI structures for Family 1Ah Model 50h-5Fh metrics table
2026-05-22 11:09 ` Ilpo Järvinen
@ 2026-05-26 9:36 ` M K, Muralidhara
0 siblings, 0 replies; 19+ messages in thread
From: M K, Muralidhara @ 2026-05-26 9:36 UTC (permalink / raw)
To: Ilpo Järvinen, Muralidhara M K
Cc: platform-driver-x86, LKML, Suma Hegde, Muthusamy Ramalingam
On 5/22/2026 4:39 PM, Ilpo Järvinen wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> On Sun, 17 May 2026, Muralidhara M K wrote:
>
>> Define the UAPI structures hsmp_metric_table_zen6_iod,
>> hsmp_metric_table_zen6_ccd and the top-level hsmp_metric_table_zen6
>> to describe the per-IOD and per-CCD metrics layout for AMD Family 1Ah
>> Model 50h-5Fh processors (HSMP protocol version 7). These structures
>> allow userspace tools to interpret the raw metric table binary exposed
>> through the HSMP character device.
>>
>> Driver enablement for protocol version 7 is added in a follow-up patch.
>>
>> Reviewed-by: Suma Hegde <suma.hegde@amd.com>
>> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
>> ---
>> Changes:
>> v1->v2: Split the change
>> v2->v3: Move proto version check to seperate patch
>>
>> arch/x86/include/uapi/asm/amd_hsmp.h | 88 ++++++++++++++++++++++++++++
>> 1 file changed, 88 insertions(+)
>>
>> diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
>> index 603d62f8d4da..da3e3bbfa33e 100644
>> --- a/arch/x86/include/uapi/asm/amd_hsmp.h
>> +++ b/arch/x86/include/uapi/asm/amd_hsmp.h
>> @@ -575,6 +575,94 @@ struct hsmp_metric_table {
>> __u32 gfxclk_frequency[8];
>> };
>>
>> +#define F1A_M50_M5F_MAX_CORES_PER_CCD_32 32
>> +#define F1A_M50_M5F_MAX_FREQ_TABLE_SIZE 4
>> +#define F1A_M50_M5F_MAX_XGMI 8
>> +#define F1A_M50_M5F_MAX_PCIE 8
>> +#define F1A_M50_M5F_MAX_CCD 8
>
> Should have a prefix.
Sure will add HSMP prefix.
>
>> +
>> +/* Metrics table (supported only with proto version 7) */
>> +struct hsmp_metric_table_zen6_iod {
>> + __u32 num_active_ccds;
>> + __u32 accumulation_counter;
>> +
>> + /* TEMPERATURE */
>> + __u64 max_socket_temperature_acc;
>> +
>> + /* POWER */
>> + __u32 socket_power_limit;
>> + __u32 max_socket_power_limit;
>> + __u64 socket_power_acc;
>> + __u64 core_power_acc;
>> + __u64 uncore_power_acc;
>> +
>> + /* ENERGY */
>> + __u64 timestamp;
>> + __u64 socket_energy_acc;
>> + __u64 core_energy_acc;
>> + __u64 uncore_energy_acc;
>> +
>> + /* FREQUENCY */
>> + __u64 fclk_frequency_acc;
>> + __u64 uclk_frequency_acc;
>> + __u64 ddr_rate_acc;
>> + __u64 lclk_frequency_acc[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
>> +
>> + /* FREQUENCY RANGE */
>> + __u32 fclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
>> + __u32 uclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
>> + __u32 ddr_rate_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
>> + __u32 max_df_pstate_range;
>> + __u32 min_df_pstate_range;
>> + __u32 lclk_frequency_table[F1A_M50_M5F_MAX_FREQ_TABLE_SIZE];
>> + __u32 max_lclk_dpm_range;
>> + __u32 min_lclk_dpm_range;
>> +
>> + /* XGMI */
>> + __u64 xgmi_bit_rate[F1A_M50_M5F_MAX_XGMI];
>> + __u64 xgmi_read_bandwidth[F1A_M50_M5F_MAX_XGMI];
>> + __u64 xgmi_write_bandwidth[F1A_M50_M5F_MAX_XGMI];
>> +
>> + /* ACTIVITY */
>> + __u64 socket_c0_residency_acc;
>> + __u64 socket_df_cstate_residency_acc;
>> + __u64 dram_read_bandwidth_acc;
>> + __u64 dram_write_bandwidth_acc;
>> + __u32 max_dram_bandwidth;
>> + __u64 pcie_bandwidth_acc[F1A_M50_M5F_MAX_PCIE];
>> +
>> + /* THROTTLERS */
>> + __u32 prochot_residency_acc;
>> + __u32 ppt_residency_acc;
>> + __u32 thm_residency_acc;
>> + __u32 vrhot_residency_acc;
>> + __u32 cpu_tdc_residency_acc;
>> + __u32 soc_tdc_residency_acc;
>> + __u32 io_mem_tdc_residency_acc;
>> + __u32 fit_residency_acc;
>> +};
>> +
>> +struct hsmp_metric_table_zen6_ccd {
>> + __u32 core_apicid_of_thread0[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
>> + __u64 core_c0[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
>> + __u64 core_cc1[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
>> + __u64 core_cc6[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
>> + __u64 core_frequency[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
>> + __u64 core_frequency_effective[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
>> + __u64 core_power[F1A_M50_M5F_MAX_CORES_PER_CCD_32];
>> +};
>> +
>> +/*
>> + * Metrics table for Family 0x1A, Models 0x50 to 0x5F, table version 0x00700000
>> + *
>> + * Future processors within the same family and model may support a
>> + * variable number of CCDs and cores
>
> How is the correct number of CCDs then known?
>
> If it's through num_active_ccds, I question if hsmp_metric_table_zen6
> struct hierarchy is correct as then something under iod seems to
> determine how to interpret the ccd[] array.
>
For metrics table version 0x00700000, the maximum number of supported
CCDs is 8.
In scenarios where CCDs are disabled or unavailable, the
"num_active_ccds" variable within the IOD array indicates the number of
valid CCDs in the ccd[] array.
>> + */
>> +struct hsmp_metric_table_zen6 {
>> + struct hsmp_metric_table_zen6_iod iod;
>> + struct hsmp_metric_table_zen6_ccd ccd[F1A_M50_M5F_MAX_CCD];
>> +};
>> +
>> /* Reset to default packing */
>> #pragma pack()
>>
>>
>
> --
> i.
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 5/7] platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table reads
2026-05-22 11:04 ` Ilpo Järvinen
2026-05-22 11:27 ` Ilpo Järvinen
@ 2026-05-26 9:43 ` M K, Muralidhara
1 sibling, 0 replies; 19+ messages in thread
From: M K, Muralidhara @ 2026-05-26 9:43 UTC (permalink / raw)
To: Ilpo Järvinen, Muralidhara M K
Cc: platform-driver-x86, LKML, Muthusamy Ramalingam
On 5/22/2026 4:34 PM, Ilpo Järvinen wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> On Sun, 17 May 2026, Muralidhara M K wrote:
>
>> The metric table for Family 1Ah Model 50h-5Fh
>> (struct hsmp_metric_table_zen6) is approximately 13 KB, exceeding the
>> PAGE_SIZE (4 KB) cap imposed on the standard sysfs binary attribute
>> read path. Rather than introduce new sysfs infrastructure to support
>> binary attributes larger than PAGE_SIZE, expose the metric table
>> through the existing HSMP character device using a new ioctl.
>>
>> Add struct hsmp_telemetry_data and HSMP_IOCTL_GET_TELEMETRY_DATA to
>> the UAPI header. The request structure carries the socket index, the
>> required buffer size and a __u64-encoded user pointer to the
>> destination buffer, so the same layout works for 32-bit and 64-bit
>> callers. Fields are ordered with the __u64 user pointer first so all
>> members fall on their natural alignment under #pragma pack(4), giving
>> a tight 16-byte struct with no implicit padding; the trailing
>> reserved __u16 is documented as "set to zero" so future kernels can
>> attach meaning to it. Userspace sizes its buffer using the matching
>> UAPI metric table struct (hsmp_metric_table or hsmp_metric_table_zen6)
>> for the running platform; sizes that disagree with the firmware-
>> reported table size are rejected with -EINVAL so a short copy can
>> never silently truncate the snapshot.
>>
>> Dispatch hsmp_ioctl() on the ioctl command, route HSMP_IOCTL_CMD to
>> the existing message handler (factored out as hsmp_ioctl_msg()) and
>> HSMP_IOCTL_GET_TELEMETRY_DATA to a new hsmp_ioctl_get_telemetry()
>> helper. The new helper validates the request, allocates a kernel
>> bounce buffer with kvmalloc() so it can hold the full table even
>> when it exceeds a single page (zeroing is skipped because the buffer
>> is overwritten in full by memcpy_fromio()), calls hsmp_metric_tbl_read()
>> to refresh and copy the table from the SMU DRAM region (under the
>> per-socket mutex introduced in a follow-up patch), and copies the
>> table to userspace. Unknown ioctl commands now return -ENOTTY instead
>> of falling through.
>>
>> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
>> ---
>> Changes:
>> v1->v2: New patch based on bin sysfs
>> v2->v3: Replace with IOCTL method
>>
>> arch/x86/include/uapi/asm/amd_hsmp.h | 43 ++++++++++++++
>> drivers/platform/x86/amd/hsmp/hsmp.c | 85 +++++++++++++++++++++++++++-
>> 2 files changed, 127 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h
>> index b86bbc929395..3d085298dd52 100644
>> --- a/arch/x86/include/uapi/asm/amd_hsmp.h
>> +++ b/arch/x86/include/uapi/asm/amd_hsmp.h
>> @@ -664,6 +664,40 @@ struct hsmp_metric_table_zen6 {
>> struct hsmp_metric_table_zen6_ccd ccd[F1A_M50_M5F_MAX_CCD];
>> };
>>
>> +/**
>> + * struct hsmp_telemetry_data - Request descriptor for HSMP telemetry IOCTL
>> + * @buf: Input. Userspace pointer (encoded as __u64 to keep the layout
>> + * stable between 32-bit and 64-bit callers) to the destination
>> + * buffer that receives the metric table.
>> + * @size: Input. Size in bytes of the buffer pointed to by @buf. Must
>> + * match the firmware-reported metric table size for the running
>> + * HSMP protocol version (see below); any other value results in
>> + * -EINVAL. The kernel does not write this field back.
>> + * @sock_ind: Input. Socket index from which the metric table is read.
>> + * @reserved: Reserved for future use. Callers should set this to zero;
>> + * future kernels may begin interpreting the field, so passing
>> + * a non-zero value today is not forwards compatible.
>> + *
>> + * Placing @buf first lets all fields fall on their natural alignment under
>> + * the surrounding #pragma pack(4), so the struct is a tight 16 bytes with
>> + * the same wire layout on 32-bit and 64-bit userspace.
>> + *
>> + * The exact metric table layout depends on the HSMP protocol version reported
>> + * by the firmware:
>> + * - Protocol version 6 -> struct hsmp_metric_table
>> + * - Protocol version 7 -> struct hsmp_metric_table_zen6
>> + *
>> + * Userspace queries the protocol version (e.g. via the protocol_version sysfs
>> + * attribute) and uses sizeof() on the matching UAPI structure for both @size
>> + * and the allocation backing @buf.
>> + */
>> +struct hsmp_telemetry_data {
>> + __u64 buf;
>> + __u32 size;
>> + __u16 sock_ind;
>> + __u16 reserved;
>> +};
>> +
>> /* Reset to default packing */
>> #pragma pack()
>>
>> @@ -671,4 +705,13 @@ struct hsmp_metric_table_zen6 {
>> #define HSMP_BASE_IOCTL_NR 0xF8
>> #define HSMP_IOCTL_CMD _IOWR(HSMP_BASE_IOCTL_NR, 0, struct hsmp_message)
>>
>> +/*
>> + * Fetch the firmware metric (telemetry) table for a given socket via the
>> + * HSMP character device. This avoids the PAGE_SIZE limitation of the
>> + * sysfs binary attribute path for tables larger than one page (such as the
>> + * ~13 KB hsmp_metric_table_zen6 used on Family 1Ah Model 50h-5Fh).
>> + */
>> +#define HSMP_IOCTL_GET_TELEMETRY_DATA \
>> + _IOWR(HSMP_BASE_IOCTL_NR, 1, struct hsmp_telemetry_data)
>> +
>> #endif /*_ASM_X86_AMD_HSMP_H_*/
>> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
>> index cf9392f99298..3a02d683dea0 100644
>> --- a/drivers/platform/x86/amd/hsmp/hsmp.c
>> +++ b/drivers/platform/x86/amd/hsmp/hsmp.c
>> @@ -13,7 +13,9 @@
>> #include <linux/delay.h>
>> #include <linux/device.h>
>> #include <linux/semaphore.h>
>> +#include <linux/slab.h>
>> #include <linux/sysfs.h>
>> +#include <linux/uaccess.h>
>>
>> #include "hsmp.h"
>>
>> @@ -287,7 +289,7 @@ static bool is_get_msg(struct hsmp_message *msg)
>> return false;
>> }
>>
>> -long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
>> +static long hsmp_ioctl_msg(struct file *fp, unsigned long arg)
>> {
>> int __user *arguser = (int __user *)arg;
>> struct hsmp_message msg = { 0 };
>> @@ -343,6 +345,87 @@ long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
>> return 0;
>> }
>>
>> +/*
>> + * Fetch the firmware metric (telemetry) table for the requested socket and
>> + * copy it to the userspace buffer described by the request.
>> + *
>> + * The metric table size is variable across HSMP protocol versions and on
>> + * Family 1Ah Model 50h-5Fh exceeds PAGE_SIZE. Userspace must therefore
>> + * supply a buffer at least the firmware-reported size in bytes.
>> + */
>> +static long hsmp_ioctl_get_telemetry(struct file *fp, unsigned long arg)
>> +{
>> + void __user *arguser = (void __user *)arg;
>> + struct hsmp_telemetry_data req;
>> + struct hsmp_socket *sock;
>> + void __user *user_buf;
>> + size_t tbl_size;
>> + void *kbuf;
>> + int ret;
>> +
>> + /* Telemetry data is read-only; require read access on the fd. */
>> + if (!(fp->f_mode & FMODE_READ))
>> + return -EPERM;
>> +
>> + if (copy_from_user(&req, arguser, sizeof(req)))
>> + return -EFAULT;
>> +
>> + if (!hsmp_pdev.sock || req.sock_ind >= hsmp_pdev.num_sockets)
>
> Sashiko warns userspace can use this as a speculation device so it needs
> to be protected.
>
Will check.
> Please also address the req.reserved check mentioned by it with -EINVAL so
> it can actually be used safely in future.
Thanks. I will add a check for "req.reserved"
>
>> + return -ENODEV;
>> +
>> + tbl_size = hsmp_pdev.hsmp_table_size;
>> + if (!tbl_size)
>> + return -ENODEV;
>> +
>> + /*
>> + * Userspace must size its buffer using the appropriate UAPI metric
>> + * table struct for the running protocol version. Reject mismatched
>> + * sizes so we never silently truncate or short-write.
>> + */
>> + if (req.size != tbl_size)
>> + return -EINVAL;
>> +
>> + sock = &hsmp_pdev.sock[req.sock_ind];
>> + if (!sock->metric_tbl_addr)
>> + return -ENODEV;
>> +
>> + user_buf = u64_to_user_ptr(req.buf);
>> +
>> + /*
>> + * The bounce buffer is overwritten in full by memcpy_fromio() inside
>> + * hsmp_metric_tbl_read(); use kvmalloc() to avoid the zeroing cost of
>> + * kvzalloc() on the ~13 KB allocation done on every ioctl call.
>> + */
>> + kbuf = kvmalloc(tbl_size, GFP_KERNEL);
>> + if (!kbuf)
>> + return -ENOMEM;
>> +
>> + ret = hsmp_metric_tbl_read(sock, kbuf, tbl_size);
>> + if (ret < 0)
>> + goto out;
>> +
>> + if (copy_to_user(user_buf, kbuf, tbl_size))
>> + ret = -EFAULT;
>> + else
>> + ret = 0;
>> +
>> +out:
>> + kvfree(kbuf);
>> + return ret;
>> +}
>> +
>> +long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
>> +{
>> + switch (cmd) {
>> + case HSMP_IOCTL_CMD:
>> + return hsmp_ioctl_msg(fp, arg);
>> + case HSMP_IOCTL_GET_TELEMETRY_DATA:
>> + return hsmp_ioctl_get_telemetry(fp, arg);
>> + default:
>> + return -ENOTTY;
>> + }
>> +}
>> +
>> ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size)
>> {
>> struct hsmp_message msg = { 0 };
>>
>
> --
> i.
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 6/7] platform/x86/amd/hsmp: Drop ACPI sysfs metrics_bin in favour of the IOCTL
2026-05-22 11:44 ` Ilpo Järvinen
@ 2026-05-26 9:59 ` M K, Muralidhara
0 siblings, 0 replies; 19+ messages in thread
From: M K, Muralidhara @ 2026-05-26 9:59 UTC (permalink / raw)
To: Ilpo Järvinen, Muralidhara M K
Cc: platform-driver-x86, LKML, Muthusamy Ramalingam
On 5/22/2026 5:14 PM, Ilpo Järvinen wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> On Sun, 17 May 2026, Muralidhara M K wrote:
>
>> The HSMP_IOCTL_GET_TELEMETRY_DATA character-device ioctl introduced in
>> the previous patch is now the canonical interface for reading the
>> metric table on the ACPI driver path. Unlike the metrics_bin sysfs
>> binary attribute, the ioctl is not constrained by PAGE_SIZE, so it
>> works for the ~13 KB hsmp_metric_table_zen6 layout
>
> This was only a secondary reason from moving away from sysfs files? The
> main cause for moving to misc device according to my impression was that
> you wanted to prevent partial reads which are always possible with files.
>
Sure I will update the changelog to document the rationale for moving
away from sysfs files.
>> used on Family 1Ah
>> Model 50h-5Fh as well as for the existing hsmp_metric_table layout
>> used on protocol version 6.
>
>
>
>> Drop the metrics_bin bin_attribute from the ACPI hsmp_attr_grp.
>
>> Widen the remaining proto_ver gate in init_acpi() from
>> '== HSMP_PROTO_VER6' to '>= HSMP_PROTO_VER6' so
>> hsmp_get_tbl_dram_base() is invoked on protocol version 7
>> (Family 1Ah Model 50h-5Fh) and any future protocol version that
>> retains a compatible per-socket metric table. This populates
>> sock->metric_tbl_addr and hsmp_pdev.hsmp_table_size, which the ioctl
>> handler requires.
>
> These are two logically separate changes so they should not be in the same
> patch (but you'll likely need to alter the drop patch anyway, see below).
>
Ya Understood. I will make this change as a separate patch.
>> This is an ABI change for users of the ACPI driver:
>> /sys/bus/platform/devices/AMDI0097:*/metrics_bin no longer exists.
>> Userspace must read telemetry through the HSMP_IOCTL_GET_TELEMETRY_DATA
>> ioctl on /dev/hsmp instead, sizing its buffer using the matching UAPI
>> metric table struct.
>
> I might not be entirely following what's the extent of removal here but it
> looks too extensive to me. The number 1 rule is that we cannot take away
> existing and working ABI without properly deprecating it first.
>
> You don't have to make it work with version 7 and can return error in
> that case as it has never worked. But with version 6, things shouls be
> left as is until properly deprecated. You may consider adding a warning
> print too to warn about the deprecation and point towards the new way.
>
I will review and ensure that an appropriate error is returned if sysfs
is not supported for a particular version.
> This interface probably never was documented in Documentation/ABI where
> such deprecations are usually marked... oh well, maybe we need to add
> a simple entry for this ABI there to follow the usual deprecation path.
>
> --
> i.
>
>> The non-ACPI plat.c path is intentionally left
>> unchanged: it covers Family 1Ah Model 0h-Fh hardware that is fixed at
>> protocol version 6, and its per-socket metrics_bin remains available
>> for existing userspace tooling on those systems.
>>
>> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
>> ---
>> Changes:
>> v1->v3: Remove bin attributes
>>
>> drivers/platform/x86/amd/hsmp/acpi.c | 34 +---------------------------
>> 1 file changed, 1 insertion(+), 33 deletions(-)
>>
>> diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
>> index 97ed71593bdf..49765fefe1fb 100644
>> --- a/drivers/platform/x86/amd/hsmp/acpi.c
>> +++ b/drivers/platform/x86/amd/hsmp/acpi.c
>> @@ -231,25 +231,6 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind)
>> return hsmp_read_acpi_dsd(sock);
>> }
>>
>> -static ssize_t hsmp_metric_tbl_acpi_read(struct file *filp, struct kobject *kobj,
>> - const struct bin_attribute *bin_attr, char *buf,
>> - loff_t off, size_t count)
>> -{
>> - struct device *dev = container_of(kobj, struct device, kobj);
>> - struct hsmp_socket *sock = dev_get_drvdata(dev);
>> -
>> - return hsmp_metric_tbl_read(sock, buf, count);
>> -}
>> -
>> -static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
>> - const struct bin_attribute *battr, int id)
>> -{
>> - if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6)
>> - return battr->attr.mode;
>> -
>> - return 0;
>> -}
>> -
>> static umode_t hsmp_is_sock_dev_attr_visible(struct kobject *kobj,
>> struct attribute *attr, int id)
>> {
>> @@ -491,7 +472,7 @@ static int init_acpi(struct device *dev)
>> return ret;
>> }
>>
>> - if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) {
>> + if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) {
>> ret = hsmp_get_tbl_dram_base(sock_ind);
>> if (ret)
>> dev_info(dev, "Failed to init metric table\n");
>> @@ -506,17 +487,6 @@ static int init_acpi(struct device *dev)
>> return 0;
>> }
>>
>> -static const struct bin_attribute hsmp_metric_tbl_attr = {
>> - .attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444},
>> - .read = hsmp_metric_tbl_acpi_read,
>> - .size = sizeof(struct hsmp_metric_table),
>> -};
>> -
>> -static const struct bin_attribute *hsmp_attr_list[] = {
>> - &hsmp_metric_tbl_attr,
>> - NULL
>> -};
>> -
>> #define HSMP_DEV_ATTR(_name, _msg_id, _show, _mode) \
>> static struct hsmp_sys_attr hattr_##_name = { \
>> .dattr = __ATTR(_name, _mode, _show, NULL), \
>> @@ -559,9 +529,7 @@ static struct attribute *hsmp_dev_attr_list[] = {
>> };
>>
>> static const struct attribute_group hsmp_attr_grp = {
>> - .bin_attrs = hsmp_attr_list,
>> .attrs = hsmp_dev_attr_list,
>> - .is_bin_visible = hsmp_is_sock_attr_visible,
>> .is_visible = hsmp_is_sock_dev_attr_visible,
>> };
>>
>>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 7/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex)
2026-05-22 10:55 ` Ilpo Järvinen
@ 2026-05-26 10:02 ` M K, Muralidhara
0 siblings, 0 replies; 19+ messages in thread
From: M K, Muralidhara @ 2026-05-26 10:02 UTC (permalink / raw)
To: Ilpo Järvinen, Muralidhara M K
Cc: platform-driver-x86, LKML, Muthusamy Ramalingam
On 5/22/2026 4:25 PM, Ilpo Järvinen wrote:
> Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
>
>
> On Sun, 17 May 2026, Muralidhara M K wrote:
>
>> Add a per-socket mutex (metric_tbl_lock) to serialize concurrent reads
>> on the metric table. Without serialization, two simultaneous
>> readers could interleave the SMU refresh command and the
>> memcpy_fromio(), producing a torn (mixed old/new) snapshot.
>>
>> Use scoped guard(mutex) in hsmp_metric_tbl_read() so the lock is
>> automatically released on all return paths. Initialize the mutex with
>> devm_mutex_init() in hsmp_get_tbl_dram_base() and return an error if
>> initialization fails, avoiding manual mutex_destroy() cleanup paths.
>>
>> Co-developed-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muthusamy Ramalingam <muthusamy.ramalingam@amd.com>
>> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
>> ---
>> Changes:
>> v1->v2: Add lock
>> v2->v3: Replace mutex_init to devm_mutex_init call
>>
>> drivers/platform/x86/amd/hsmp/hsmp.c | 8 ++++++++
>> drivers/platform/x86/amd/hsmp/hsmp.h | 3 +++
>> 2 files changed, 11 insertions(+)
>>
>> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
>> index 3a02d683dea0..2fec897a95be 100644
>> --- a/drivers/platform/x86/amd/hsmp/hsmp.c
>> +++ b/drivers/platform/x86/amd/hsmp/hsmp.c
>> @@ -447,6 +447,7 @@ ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size)
>> msg.msg_id = HSMP_GET_METRIC_TABLE;
>> msg.sock_ind = sock->sock_ind;
>>
>> + guard(mutex)(&sock->metric_tbl_lock);
>> ret = hsmp_send_message(&msg);
>> if (ret)
>> return ret;
>> @@ -492,6 +493,13 @@ int hsmp_get_tbl_dram_base(u16 sock_ind)
>> dev_err(sock->dev, "Failed to ioremap metric table addr\n");
>> return -ENOMEM;
>> }
>> +
>> + ret = devm_mutex_init(sock->dev, &sock->metric_tbl_lock);
>> + if (ret) {
>> + dev_err(sock->dev, "Failed to initialize metric table lock\n");
>> + return ret;
>> + }
>
> Sashiko notes a potential problem with this failing and that not resulting
> in a probe fail, which leaves the mutex uninitialized.
>
> But the mutex could be initialized earlier to avoid the problem I think.
>
In the v2 series, you suggested using devm_mutex_init(). However, I will
test it and initialize it earlier if required.
>> +
>> return 0;
>> }
>> EXPORT_SYMBOL_NS_GPL(hsmp_get_tbl_dram_base, "AMD_HSMP");
>> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
>> index e7f051475728..f7b1cbf19932 100644
>> --- a/drivers/platform/x86/amd/hsmp/hsmp.h
>> +++ b/drivers/platform/x86/amd/hsmp/hsmp.h
>> @@ -15,6 +15,7 @@
>> #include <linux/hwmon.h>
>> #include <linux/kconfig.h>
>> #include <linux/miscdevice.h>
>> +#include <linux/mutex.h>
>> #include <linux/pci.h>
>> #include <linux/semaphore.h>
>> #include <linux/sysfs.h>
>> @@ -41,6 +42,8 @@ struct hsmp_socket {
>> struct bin_attribute hsmp_attr;
>> struct hsmp_mbaddr_info mbinfo;
>> void __iomem *metric_tbl_addr;
>> + /* Serializes concurrent metric table refreshes from the sysfs path */
>> + struct mutex metric_tbl_lock;
>> void __iomem *virt_base_addr;
>> struct semaphore hsmp_sem;
>> char name[HSMP_ATTR_GRP_NAME_SIZE];
>>
>
> --
> i.
>
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-05-26 10:02 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-17 15:12 [PATCH v3 0/7] platform/x86/amd/hsmp: Add support for Family 1Ah, Model 50h-5Fh Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 1/7] platform/x86/amd/hsmp: Add new HSMP messages " Muralidhara M K
2026-05-22 11:49 ` Ilpo Järvinen
2026-05-26 9:21 ` M K, Muralidhara
2026-05-17 15:12 ` [PATCH v3 2/7] platform/x86/amd/hsmp: Add UAPI structures for Family 1Ah Model 50h-5Fh metrics table Muralidhara M K
2026-05-22 11:09 ` Ilpo Järvinen
2026-05-26 9:36 ` M K, Muralidhara
2026-05-17 15:12 ` [PATCH v3 3/7] platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound check Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 4/7] platform/x86/amd/hsmp: Source metric-table size from firmware Muralidhara M K
2026-05-17 15:12 ` [PATCH v3 5/7] platform/x86/amd/hsmp: Add IOCTL_GET_TELEMETRY_DATA for metric table reads Muralidhara M K
2026-05-22 11:04 ` Ilpo Järvinen
2026-05-22 11:27 ` Ilpo Järvinen
2026-05-26 9:43 ` M K, Muralidhara
2026-05-17 15:12 ` [PATCH v3 6/7] platform/x86/amd/hsmp: Drop ACPI sysfs metrics_bin in favour of the IOCTL Muralidhara M K
2026-05-22 11:44 ` Ilpo Järvinen
2026-05-26 9:59 ` M K, Muralidhara
2026-05-17 15:12 ` [PATCH v3 7/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex) Muralidhara M K
2026-05-22 10:55 ` Ilpo Järvinen
2026-05-26 10:02 ` M K, Muralidhara
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome