public inbox for driver-core@lists.linux.dev
 help / color / mirror / Atom feed
* [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support
@ 2026-04-27 15:51 Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 1/7] platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model 50h-5Fh Muralidhara M K
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Muralidhara M K @ 2026-04-27 15:51 UTC (permalink / raw)
  To: ilpo.jarvinen, gregkh, rafael
  Cc: platform-driver-x86, linux-kernel, driver-core, Muralidhara M K

This series adds HSMP protocol version 7 support for AMD Family 1Ah
Model 50h-5Fh processors and replaces offset-based chunked reading
with a single read method for variable-sized metrics data larger than
4 KB, and addresses locking to allow concurrent reads safely.

The zen6 metric table (~13 KB) exceeds the PAGE_SIZE (4096 bytes) read
cap imposed by kernfs_file_read_iter().  Commit 3124eb1679b2 ("sysfs:
remove bin_attribute.size") cleared i_size for sysfs binary files,
which made kernfs_file_read_iter() fall back to PAGE_SIZE as the
maximum single-read length.  This means userspace gets a silently
truncated snapshot when reading the metric table via sysfs.

To solve this, the series introduces SYSFS_HUGE_BIN_FILE, a new sysfs
mode flag that routes binary attribute reads through the seq_file path
(seq_read_iter) instead of kernfs_file_read_iter().  The seq_file
buffer grows dynamically (doubling from PAGE_SIZE) and has no built-in
size cap, so it can serve arbitrarily large binary attributes in a
single read.

Additionally, the series retrieves the actual metric table size from
the SMU at init time (via args[2] of HSMP_GET_METRIC_TABLE_DRAM_ADDR)
rather than relying on a compiled-in sizeof(), and adds per-socket
mutex serialization for metric table reads using the scoped guard(mutex)
API.

Link: https://lore.kernel.org/platform-driver-x86/81915669-87e0-f06d-7a91-eaec41ecc0e1@linux.intel.com/T/#m28341c51bcf27862ef6615414b1970d3db279fd7

Patch breakdown:

  1/7  HSMP messages    - Define HSMP protocol v7 message IDs and
                          response sizes in the UAPI header.
  2/7  UAPI structs     - Add hsmp_metric_table_zen6 UAPI structures
                          and widen acpi.c proto_ver checks to >= VER6.
  3/7  response_sz      - Unify response_sz validation to an upper-bound
                          check, allowing HSMP_GET_METRIC_TABLE_DRAM_ADDR
                          to return 3 dwords (including table size).
  4/7  SYSFS_HUGE_BIN_FILE - Add the sysfs infrastructure: new flag,
                          seq_show callback, and kernfs_ops for binary
                          files larger than PAGE_SIZE.
  5/7  Dynamic size     - Read actual table size from SMU args[2] at
                          init time; use bin_size callback to report it
                          to sysfs.
  6/7  Read locking     - Add per-socket guard(mutex) serialization for
                          metric table reads to prevent torn snapshots.
  7/7  Wire it up       - Set SYSFS_HUGE_BIN_FILE mode on metric table
                          bin_attributes in both acpi.c and plat.c.

Build-tested each patch individually with W=1, zero warnings.
Tested on AMD Family 1Ah Model 50h platform with HSMP protocol v7.

Muralidhara M K (6):
  platform/x86/amd/hsmp: Add metrics table support for Family 1Ah Model
    50h-5Fh
  platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound
    check
  sysfs: Add SYSFS_HUGE_BIN_FILE flag for binary attributes larger than
    PAGE_SIZE
  platform/x86/amd/hsmp: Add dynamic table size for metric table
  platform/x86/amd/hsmp: Make metric table read locking use guard(mutex)
  platform/x86/amd/hsmp: Support SYSFS_HUGE_BIN_FILE for metric table
    reads

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 | 235 ++++++++++++++++++++++++---
 drivers/platform/x86/amd/hsmp/acpi.c |  14 +-
 drivers/platform/x86/amd/hsmp/hsmp.c |  36 ++--
 drivers/platform/x86/amd/hsmp/hsmp.h |   6 +-
 drivers/platform/x86/amd/hsmp/plat.c |  13 +-
 fs/sysfs/file.c                      |  45 +++++
 fs/sysfs/group.c                     |   8 +-
 include/linux/sysfs.h                |   1 +
 8 files changed, 312 insertions(+), 46 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/7] platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model 50h-5Fh
  2026-04-27 15:51 [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support Muralidhara M K
@ 2026-04-27 15:51 ` Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 2/7] platform/x86/amd/hsmp: Add metrics table support for Family 1Ah " Muralidhara M K
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Muralidhara M K @ 2026-04-27 15:51 UTC (permalink / raw)
  To: ilpo.jarvinen, gregkh, rafael
  Cc: platform-driver-x86, linux-kernel, driver-core, 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->v2: 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 related	[flat|nested] 9+ messages in thread

* [PATCH v2 2/7] platform/x86/amd/hsmp: Add metrics table support for Family 1Ah Model 50h-5Fh
  2026-04-27 15:51 [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 1/7] platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model 50h-5Fh Muralidhara M K
@ 2026-04-27 15:51 ` Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 3/7] platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound check Muralidhara M K
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Muralidhara M K @ 2026-04-27 15:51 UTC (permalink / raw)
  To: ilpo.jarvinen, gregkh, rafael
  Cc: platform-driver-x86, linux-kernel, driver-core, Muralidhara M K,
	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
via sysfs.

Widen the ACPI driver protocol version checks from
== HSMP_PROTO_VER6 to >= HSMP_PROTO_VER6 so the metric table
sysfs binary attribute is also created for protocol version 7 and
future versions.

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

 arch/x86/include/uapi/asm/amd_hsmp.h | 88 ++++++++++++++++++++++++++++
 drivers/platform/x86/amd/hsmp/acpi.c |  4 +-
 2 files changed, 90 insertions(+), 2 deletions(-)

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()
 
diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
index 97ed71593bdf..8044df862275 100644
--- a/drivers/platform/x86/amd/hsmp/acpi.c
+++ b/drivers/platform/x86/amd/hsmp/acpi.c
@@ -244,7 +244,7 @@ static ssize_t hsmp_metric_tbl_acpi_read(struct file *filp, struct kobject *kobj
 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)
+	if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6)
 		return battr->attr.mode;
 
 	return 0;
@@ -491,7 +491,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");
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 3/7] platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound check
  2026-04-27 15:51 [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 1/7] platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model 50h-5Fh Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 2/7] platform/x86/amd/hsmp: Add metrics table support for Family 1Ah " Muralidhara M K
@ 2026-04-27 15:51 ` Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 4/7] sysfs: Add SYSFS_HUGE_BIN_FILE flag for binary attributes larger than PAGE_SIZE Muralidhara M K
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Muralidhara M K @ 2026-04-27 15:51 UTC (permalink / raw)
  To: ilpo.jarvinen, gregkh, rafael
  Cc: platform-driver-x86, linux-kernel, driver-core, Muralidhara M K,
	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.

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>
---
Change v1->v2: New

 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 related	[flat|nested] 9+ messages in thread

* [PATCH v2 4/7] sysfs: Add SYSFS_HUGE_BIN_FILE flag for binary attributes larger than PAGE_SIZE
  2026-04-27 15:51 [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support Muralidhara M K
                   ` (2 preceding siblings ...)
  2026-04-27 15:51 ` [PATCH v2 3/7] platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound check Muralidhara M K
@ 2026-04-27 15:51 ` Muralidhara M K
  2026-04-28  7:20   ` K Prateek Nayak
  2026-04-27 15:51 ` [PATCH v2 5/7] platform/x86/amd/hsmp: Add dynamic table size for metric table Muralidhara M K
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 9+ messages in thread
From: Muralidhara M K @ 2026-04-27 15:51 UTC (permalink / raw)
  To: ilpo.jarvinen, gregkh, rafael
  Cc: platform-driver-x86, linux-kernel, driver-core, Muralidhara M K,
	Nayak K Prateek

Historically, sysfs read buffers were allocated with get_zeroed_page(),
limiting reads to PAGE_SIZE.  Commit 13c589d5b0ac ("sysfs: use seq_file
when reading regular files") transitioned regular (text) attribute reads
to seq_file, which can dynamically grow buffers beyond PAGE_SIZE.
However, the PAGE_SIZE limit was intentionally preserved for
compatibility.  When binary attribute handling was later unified into
the same codebase, the non-seq_file read path (kernfs_file_read_iter)
retained this PAGE_SIZE cap for binary files as well.

Drivers that expose binary attributes larger than PAGE_SIZE — such as
the AMD HSMP metric table (~13 KB) — cannot deliver the full content
in a single read() call through the existing path.

Introduce a new opt-in flag SYSFS_HUGE_BIN_FILE (040000) that drivers
can OR into their bin_attribute mode.  When set, sysfs selects a new
kernfs_ops (sysfs_bin_kfops_huge_file_ro) whose .seq_show callback
pipes the bin_attribute ->read() result through seq_file, allowing
reads of arbitrary size in one shot.  Existing binary attributes
without the flag continue using the legacy capped path.

Co-developed-by: Nayak K Prateek <kprateek.nayak@amd.com>
Signed-off-by: Nayak K Prateek <kprateek.nayak@amd.com>
Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
---
Changes v1->v2: New patch

 fs/sysfs/file.c       | 45 +++++++++++++++++++++++++++++++++++++++++++
 fs/sysfs/group.c      |  8 ++++----
 include/linux/sysfs.h |  1 +
 3 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 5709cede1d75..be42c3c1e056 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -38,6 +38,45 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
 	return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
 }
 
+/*
+ * Reads on huge sysfs bin files are handled through seq_file, which
+ * takes care of hairy details like buffering and seeking.  The
+ * following function pipes the bin_attribute ->read() result through
+ * seq_file so that reads larger than PAGE_SIZE work in one shot.
+ */
+static int sysfs_kf_huge_file_seq_show(struct seq_file *sf, void *v)
+{
+	struct kernfs_open_file *of = sf->private;
+	const struct bin_attribute *battr = of->kn->priv;
+	struct kobject *kobj = sysfs_file_kobj(of->kn);
+	loff_t size = file_inode(of->file)->i_size;
+	ssize_t count;
+	char *buf;
+
+	if (!battr->read)
+		return -EIO;
+
+	if (!size)
+		return -EIO;
+
+	/* acquire buffer and ensure that it's >= size */
+	count = seq_get_buf(sf, &buf);
+	if (count < size) {
+		seq_commit(sf, -1);
+		return 0;
+	}
+
+	memset(buf, 0, size);
+
+	count = battr->read(of->file, kobj, battr, buf, 0, size);
+	if (count < 0)
+		return count;
+
+	WARN_ON(count > size);
+	seq_commit(sf, min_t(ssize_t, count, size));
+	return 0;
+}
+
 /*
  * Reads on sysfs are handled through seq_file, which takes care of hairy
  * details like buffering and seeking.  The following function pipes
@@ -249,6 +288,10 @@ static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
 	.prealloc	= true,
 };
 
+static const struct kernfs_ops sysfs_bin_kfops_huge_file_ro = {
+	.seq_show	= sysfs_kf_huge_file_seq_show,
+};
+
 static const struct kernfs_ops sysfs_bin_kfops_ro = {
 	.read		= sysfs_kf_bin_read,
 };
@@ -333,6 +376,8 @@ int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
 		ops = &sysfs_bin_kfops_mmap;
 	else if (battr->read && battr->write)
 		ops = &sysfs_bin_kfops_rw;
+	else if (battr->read && (mode & SYSFS_HUGE_BIN_FILE))
+		ops = &sysfs_bin_kfops_huge_file_ro;
 	else if (battr->read)
 		ops = &sysfs_bin_kfops_ro;
 	else if (battr->write)
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index b3edae0578c0..2d0b01c00a97 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -74,11 +74,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 					continue;
 			}
 
-			WARN(mode & ~(SYSFS_PREALLOC | 0664),
+			WARN(mode & ~(SYSFS_PREALLOC | SYSFS_HUGE_BIN_FILE | 0664),
 			     "Attribute %s: Invalid permissions 0%o\n",
 			     (*attr)->name, mode);
 
-			mode &= SYSFS_PREALLOC | 0664;
+			mode &= SYSFS_PREALLOC | SYSFS_HUGE_BIN_FILE | 0664;
 			error = sysfs_add_file_mode_ns(parent, *attr, mode, uid,
 						       gid, NULL);
 			if (unlikely(error))
@@ -107,11 +107,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
 			if (grp->bin_size)
 				size = grp->bin_size(kobj, *bin_attr, i);
 
-			WARN(mode & ~(SYSFS_PREALLOC | 0664),
+			WARN(mode & ~(SYSFS_PREALLOC | SYSFS_HUGE_BIN_FILE | 0664),
 			     "Attribute %s: Invalid permissions 0%o\n",
 			     (*bin_attr)->attr.name, mode);
 
-			mode &= SYSFS_PREALLOC | 0664;
+			mode &= SYSFS_PREALLOC | SYSFS_HUGE_BIN_FILE | 0664;
 			error = sysfs_add_bin_file_mode_ns(parent, *bin_attr,
 							   mode, size, uid, gid,
 							   NULL);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index b1a3a1e6ad09..78f6c6252cf9 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -124,6 +124,7 @@ struct attribute_group {
 
 #define SYSFS_PREALLOC		010000
 #define SYSFS_GROUP_INVISIBLE	020000
+#define SYSFS_HUGE_BIN_FILE		040000
 
 /*
  * DEFINE_SYSFS_GROUP_VISIBLE(name):
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 5/7] platform/x86/amd/hsmp: Add dynamic table size for metric table
  2026-04-27 15:51 [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support Muralidhara M K
                   ` (3 preceding siblings ...)
  2026-04-27 15:51 ` [PATCH v2 4/7] sysfs: Add SYSFS_HUGE_BIN_FILE flag for binary attributes larger than PAGE_SIZE Muralidhara M K
@ 2026-04-27 15:51 ` Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 6/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex) Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 7/7] platform/x86/amd/hsmp: Support SYSFS_HUGE_BIN_FILE for metric table reads Muralidhara M K
  6 siblings, 0 replies; 9+ messages in thread
From: Muralidhara M K @ 2026-04-27 15:51 UTC (permalink / raw)
  To: ilpo.jarvinen, gregkh, rafael
  Cc: platform-driver-x86, linux-kernel, driver-core, Muralidhara M K,
	Muthusamy Ramalingam

Prepare the metric table infrastructure for supporting variable-sized
tables used by different processor families.

- Add hsmp_table_size to hsmp_plat_device for runtime table size
  configuration.
- Update the HSMP_GET_METRIC_TABLE_DRAM_ADDR message descriptor
  response_sz from 2 to 3 to read the new args[2] field that carries
  the DRAM region size in bytes.
- Use msg.args[2] from SMU to set hsmp_pdev.hsmp_table_size directly.
  For older firmware that does not populate args[2] (returns 0), fall
  back to sizeof(struct hsmp_metric_table) for backward compatibility.
- Use hsmp_pdev.hsmp_table_size for ioremap and size validation
  instead of hard-coding sizeof(struct hsmp_metric_table).
- Add a bin_size callback in both acpi.c and plat.c that returns
  hsmp_table_size, overriding the static bin_attribute .size at sysfs
  group registration time so that i_size reflects the actual table
  size reported by SMU.

This makes future processor support automatic as long as SMU reports
the correct DRAM size.

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

 arch/x86/include/uapi/asm/amd_hsmp.h |  5 +++--
 drivers/platform/x86/amd/hsmp/acpi.c |  7 +++++++
 drivers/platform/x86/amd/hsmp/hsmp.c | 10 +++++++---
 drivers/platform/x86/amd/hsmp/hsmp.h |  1 +
 drivers/platform/x86/amd/hsmp/plat.c |  7 +++++++
 5 files changed, 25 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/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
index 8044df862275..f3cfc99ef73d 100644
--- a/drivers/platform/x86/amd/hsmp/acpi.c
+++ b/drivers/platform/x86/amd/hsmp/acpi.c
@@ -250,6 +250,12 @@ static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
 	return 0;
 }
 
+static size_t hsmp_metric_tbl_bin_size(struct kobject *kobj,
+				       const struct bin_attribute *battr, int id)
+{
+	return hsmp_pdev->hsmp_table_size;
+}
+
 static umode_t hsmp_is_sock_dev_attr_visible(struct kobject *kobj,
 					     struct attribute *attr, int id)
 {
@@ -563,6 +569,7 @@ static const struct attribute_group hsmp_attr_grp = {
 	.attrs = hsmp_dev_attr_list,
 	.is_bin_visible = hsmp_is_sock_attr_visible,
 	.is_visible = hsmp_is_sock_dev_attr_visible,
+	.bin_size = hsmp_metric_tbl_bin_size,
 };
 
 static const struct attribute_group *hsmp_groups[] = {
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
index 9bad58fef304..d6e377078182 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,13 @@ 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);
diff --git a/drivers/platform/x86/amd/hsmp/plat.c b/drivers/platform/x86/amd/hsmp/plat.c
index e07f68575055..d8dd90dfeb4e 100644
--- a/drivers/platform/x86/amd/hsmp/plat.c
+++ b/drivers/platform/x86/amd/hsmp/plat.c
@@ -62,6 +62,12 @@ static ssize_t hsmp_metric_tbl_plat_read(struct file *filp, struct kobject *kobj
 	return hsmp_metric_tbl_read(sock, buf, count);
 }
 
+static size_t hsmp_metric_tbl_bin_size(struct kobject *kobj,
+				       const struct bin_attribute *battr, int id)
+{
+	return hsmp_pdev->hsmp_table_size;
+}
+
 static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
 					 const struct bin_attribute *battr, int id)
 {
@@ -114,6 +120,7 @@ HSMP_BIN_ATTR(7, *sock7_attr_list);
 static const struct attribute_group sock##index##_attr_grp = {	\
 	.bin_attrs = _list,					\
 	.is_bin_visible = hsmp_is_sock_attr_visible,		\
+	.bin_size = hsmp_metric_tbl_bin_size,			\
 	.name = #_name,						\
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 6/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex)
  2026-04-27 15:51 [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support Muralidhara M K
                   ` (4 preceding siblings ...)
  2026-04-27 15:51 ` [PATCH v2 5/7] platform/x86/amd/hsmp: Add dynamic table size for metric table Muralidhara M K
@ 2026-04-27 15:51 ` Muralidhara M K
  2026-04-27 15:51 ` [PATCH v2 7/7] platform/x86/amd/hsmp: Support SYSFS_HUGE_BIN_FILE for metric table reads Muralidhara M K
  6 siblings, 0 replies; 9+ messages in thread
From: Muralidhara M K @ 2026-04-27 15:51 UTC (permalink / raw)
  To: ilpo.jarvinen, gregkh, rafael
  Cc: platform-driver-x86, linux-kernel, driver-core, Muralidhara M K,
	Muthusamy Ramalingam

Add a per-socket mutex (metric_tbl_lock) to serialize concurrent
reads on the metric table sysfs file.  Without serialization, two
simultaneous readers could interleave the SMU refresh command and
the memcpy_fromio(), producing a torn (mixed old/new) snapshot.

Use the scoped guard(mutex) API from <linux/cleanup.h> so the lock
is automatically released when hsmp_metric_tbl_read() returns,
including on error 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: New patch

 drivers/platform/x86/amd/hsmp/hsmp.c | 5 +++++
 drivers/platform/x86/amd/hsmp/hsmp.h | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
index d6e377078182..49e7ed9981e9 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.c
+++ b/drivers/platform/x86/amd/hsmp/hsmp.c
@@ -10,7 +10,9 @@
 #include <asm/amd/hsmp.h>
 
 #include <linux/acpi.h>
+#include <linux/cleanup.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 #include <linux/device.h>
 #include <linux/semaphore.h>
 #include <linux/sysfs.h>
@@ -364,6 +366,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;
@@ -408,6 +411,8 @@ int hsmp_get_tbl_dram_base(u16 sock_ind)
 		dev_err(sock->dev, "Failed to ioremap metric table addr\n");
 		return -ENOMEM;
 	}
+
+	mutex_init(&sock->metric_tbl_lock);
 	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..038678b8ab0e 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.h
+++ b/drivers/platform/x86/amd/hsmp/hsmp.h
@@ -16,6 +16,7 @@
 #include <linux/kconfig.h>
 #include <linux/miscdevice.h>
 #include <linux/pci.h>
+#include <linux/mutex.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 reads */
+	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 related	[flat|nested] 9+ messages in thread

* [PATCH v2 7/7] platform/x86/amd/hsmp: Support SYSFS_HUGE_BIN_FILE for metric table reads
  2026-04-27 15:51 [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support Muralidhara M K
                   ` (5 preceding siblings ...)
  2026-04-27 15:51 ` [PATCH v2 6/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex) Muralidhara M K
@ 2026-04-27 15:51 ` Muralidhara M K
  6 siblings, 0 replies; 9+ messages in thread
From: Muralidhara M K @ 2026-04-27 15:51 UTC (permalink / raw)
  To: ilpo.jarvinen, gregkh, rafael
  Cc: platform-driver-x86, linux-kernel, driver-core, Muralidhara M K,
	Muthusamy Ramalingam

The metric table for Family 1Ah Model 50h-5Fh (hsmp_metric_table_zen6)
is approximately 13KB, exceeding the PAGE_SIZE (4KB) cap imposed by the
standard sysfs binary attribute read path.

Set the SYSFS_HUGE_BIN_FILE flag in the bin_attribute mode for the
metric table in both acpi.c and plat.c so that reads are routed through
seq_file, which dynamically grows its buffer to accommodate the full
table.  This lets userspace read the entire table in a single read()
call.

Drop the static .size initializer from the bin_attribute since the
bin_size callback (added in the previous patch) already provides the
runtime table size at sysfs group registration time.

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

 drivers/platform/x86/amd/hsmp/acpi.c | 3 +--
 drivers/platform/x86/amd/hsmp/plat.c | 6 ++++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
index f3cfc99ef73d..ea99625d0f36 100644
--- a/drivers/platform/x86/amd/hsmp/acpi.c
+++ b/drivers/platform/x86/amd/hsmp/acpi.c
@@ -513,9 +513,8 @@ static int init_acpi(struct device *dev)
 }
 
 static const struct bin_attribute  hsmp_metric_tbl_attr = {
-	.attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444},
+	.attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = SYSFS_HUGE_BIN_FILE | 0444},
 	.read = hsmp_metric_tbl_acpi_read,
-	.size = sizeof(struct hsmp_metric_table),
 };
 
 static const struct bin_attribute *hsmp_attr_list[] = {
diff --git a/drivers/platform/x86/amd/hsmp/plat.c b/drivers/platform/x86/amd/hsmp/plat.c
index d8dd90dfeb4e..625602a0d44c 100644
--- a/drivers/platform/x86/amd/hsmp/plat.c
+++ b/drivers/platform/x86/amd/hsmp/plat.c
@@ -97,10 +97,12 @@ static_assert(MAX_AMD_NUM_NODES == 8);
 
 #define HSMP_BIN_ATTR(index, _list)					\
 static const struct bin_attribute attr##index = {			\
-	.attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444},	\
+	.attr = {							\
+		.name = HSMP_METRICS_TABLE_NAME,			\
+		.mode = SYSFS_HUGE_BIN_FILE | 0444,				\
+	},								\
 	.private = (void *)index,					\
 	.read = hsmp_metric_tbl_plat_read,				\
-	.size = sizeof(struct hsmp_metric_table),			\
 };									\
 static const struct bin_attribute _list[] = {				\
 	&attr##index,							\
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 4/7] sysfs: Add SYSFS_HUGE_BIN_FILE flag for binary attributes larger than PAGE_SIZE
  2026-04-27 15:51 ` [PATCH v2 4/7] sysfs: Add SYSFS_HUGE_BIN_FILE flag for binary attributes larger than PAGE_SIZE Muralidhara M K
@ 2026-04-28  7:20   ` K Prateek Nayak
  0 siblings, 0 replies; 9+ messages in thread
From: K Prateek Nayak @ 2026-04-28  7:20 UTC (permalink / raw)
  To: Muralidhara M K, ilpo.jarvinen, gregkh, rafael, Danilo Krummrich
  Cc: platform-driver-x86, linux-kernel, driver-core

(+ Danilo for the sysfs bits)

Hello folks,

Please treat this patch as an RFC.

On 4/27/2026 9:21 PM, Muralidhara M K wrote:
> Historically, sysfs read buffers were allocated with get_zeroed_page(),
> limiting reads to PAGE_SIZE.  Commit 13c589d5b0ac ("sysfs: use seq_file
> when reading regular files") transitioned regular (text) attribute reads
> to seq_file, which can dynamically grow buffers beyond PAGE_SIZE.
> However, the PAGE_SIZE limit was intentionally preserved for
> compatibility.  When binary attribute handling was later unified into
> the same codebase, the non-seq_file read path (kernfs_file_read_iter)
> retained this PAGE_SIZE cap for binary files as well.
> 
> Drivers that expose binary attributes larger than PAGE_SIZE — such as
> the AMD HSMP metric table (~13 KB) — cannot deliver the full content
> in a single read() call through the existing path.

I have to add that neither of us are familiar with filesystems so our
assumptions might be a way off since we are out of our depths - we only
brought up what we could dig from the commit logs and by looking at the
implementation.

It looks like HSMP users want a sysfs way to read the *entire* metric
table in one go which has proved to be slightly harder to deliver with
the PAGE_SIZE limits in presence on concurrent readers.

Please forgive if this is not correct and if we have failed to uncover
a better approach for the same. We are all ears. (This should have been
ideally marked as an RFC; sorry for the oversight!)

> 
> Introduce a new opt-in flag SYSFS_HUGE_BIN_FILE (040000) that drivers
> can OR into their bin_attribute mode.  When set, sysfs selects a new
> kernfs_ops (sysfs_bin_kfops_huge_file_ro) whose .seq_show callback
> pipes the bin_attribute ->read() result through seq_file, allowing
> reads of arbitrary size in one shot.  Existing binary attributes
> without the flag continue using the legacy capped path.
> 
> Co-developed-by: Nayak K Prateek <kprateek.nayak@amd.com>
> Signed-off-by: Nayak K Prateek <kprateek.nayak@amd.com>
> Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com>
> ---
> Changes v1->v2: New patch
> 
>  fs/sysfs/file.c       | 45 +++++++++++++++++++++++++++++++++++++++++++
>  fs/sysfs/group.c      |  8 ++++----
>  include/linux/sysfs.h |  1 +
>  3 files changed, 50 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
> index 5709cede1d75..be42c3c1e056 100644
> --- a/fs/sysfs/file.c
> +++ b/fs/sysfs/file.c
> @@ -38,6 +38,45 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
>  	return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
>  }
>  
> +/*
> + * Reads on huge sysfs bin files are handled through seq_file, which
> + * takes care of hairy details like buffering and seeking.  The
> + * following function pipes the bin_attribute ->read() result through
> + * seq_file so that reads larger than PAGE_SIZE work in one shot.
> + */
> +static int sysfs_kf_huge_file_seq_show(struct seq_file *sf, void *v)
> +{
> +	struct kernfs_open_file *of = sf->private;
> +	const struct bin_attribute *battr = of->kn->priv;
> +	struct kobject *kobj = sysfs_file_kobj(of->kn);
> +	loff_t size = file_inode(of->file)->i_size;
> +	ssize_t count;
> +	char *buf;
> +
> +	if (!battr->read)
> +		return -EIO;
> +
> +	if (!size)
> +		return -EIO;
> +
> +	/* acquire buffer and ensure that it's >= size */
> +	count = seq_get_buf(sf, &buf);
> +	if (count < size) {
> +		seq_commit(sf, -1);
> +		return 0;
> +	}
> +
> +	memset(buf, 0, size);
> +
> +	count = battr->read(of->file, kobj, battr, buf, 0, size);
> +	if (count < 0)
> +		return count;
> +
> +	WARN_ON(count > size);
> +	seq_commit(sf, min_t(ssize_t, count, size));
> +	return 0;
> +}
> +
>  /*
>   * Reads on sysfs are handled through seq_file, which takes care of hairy
>   * details like buffering and seeking.  The following function pipes
> @@ -249,6 +288,10 @@ static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
>  	.prealloc	= true,
>  };
>  
> +static const struct kernfs_ops sysfs_bin_kfops_huge_file_ro = {
> +	.seq_show	= sysfs_kf_huge_file_seq_show,
> +};
> +
>  static const struct kernfs_ops sysfs_bin_kfops_ro = {
>  	.read		= sysfs_kf_bin_read,
>  };
> @@ -333,6 +376,8 @@ int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
>  		ops = &sysfs_bin_kfops_mmap;
>  	else if (battr->read && battr->write)
>  		ops = &sysfs_bin_kfops_rw;
> +	else if (battr->read && (mode & SYSFS_HUGE_BIN_FILE))
> +		ops = &sysfs_bin_kfops_huge_file_ro;
>  	else if (battr->read)
>  		ops = &sysfs_bin_kfops_ro;
>  	else if (battr->write)
> diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
> index b3edae0578c0..2d0b01c00a97 100644
> --- a/fs/sysfs/group.c
> +++ b/fs/sysfs/group.c
> @@ -74,11 +74,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>  					continue;
>  			}
>  
> -			WARN(mode & ~(SYSFS_PREALLOC | 0664),
> +			WARN(mode & ~(SYSFS_PREALLOC | SYSFS_HUGE_BIN_FILE | 0664),
>  			     "Attribute %s: Invalid permissions 0%o\n",
>  			     (*attr)->name, mode);
>  
> -			mode &= SYSFS_PREALLOC | 0664;
> +			mode &= SYSFS_PREALLOC | SYSFS_HUGE_BIN_FILE | 0664;

nit.

Since we would like the flags to only apply to bin files, we probably
don't need this hunk that allows for adding SYSFS_PREALLOC to plain
files.

>  			error = sysfs_add_file_mode_ns(parent, *attr, mode, uid,
>  						       gid, NULL);
>  			if (unlikely(error))
> @@ -107,11 +107,11 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
>  			if (grp->bin_size)
>  				size = grp->bin_size(kobj, *bin_attr, i);
>  
> -			WARN(mode & ~(SYSFS_PREALLOC | 0664),
> +			WARN(mode & ~(SYSFS_PREALLOC | SYSFS_HUGE_BIN_FILE | 0664),
>  			     "Attribute %s: Invalid permissions 0%o\n",
>  			     (*bin_attr)->attr.name, mode);
>  
> -			mode &= SYSFS_PREALLOC | 0664;
> +			mode &= SYSFS_PREALLOC | SYSFS_HUGE_BIN_FILE | 0664;
>  			error = sysfs_add_bin_file_mode_ns(parent, *bin_attr,
>  							   mode, size, uid, gid,
>  							   NULL);
> diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
> index b1a3a1e6ad09..78f6c6252cf9 100644
> --- a/include/linux/sysfs.h
> +++ b/include/linux/sysfs.h
> @@ -124,6 +124,7 @@ struct attribute_group {
>  
>  #define SYSFS_PREALLOC		010000
>  #define SYSFS_GROUP_INVISIBLE	020000
> +#define SYSFS_HUGE_BIN_FILE		040000
>  
>  /*
>   * DEFINE_SYSFS_GROUP_VISIBLE(name):

-- 
Thanks and Regards,
Prateek


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-04-28  7:20 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-27 15:51 [PATCH v2 0/7] AMD HSMP: metrics table improvements and Family 1Ah Model 50h-5Fh support Muralidhara M K
2026-04-27 15:51 ` [PATCH v2 1/7] platform/x86/amd/hsmp: Add new HSMP messages for Family 1Ah, Model 50h-5Fh Muralidhara M K
2026-04-27 15:51 ` [PATCH v2 2/7] platform/x86/amd/hsmp: Add metrics table support for Family 1Ah " Muralidhara M K
2026-04-27 15:51 ` [PATCH v2 3/7] platform/x86/amd/hsmp: Unify response_sz validation to an upper-bound check Muralidhara M K
2026-04-27 15:51 ` [PATCH v2 4/7] sysfs: Add SYSFS_HUGE_BIN_FILE flag for binary attributes larger than PAGE_SIZE Muralidhara M K
2026-04-28  7:20   ` K Prateek Nayak
2026-04-27 15:51 ` [PATCH v2 5/7] platform/x86/amd/hsmp: Add dynamic table size for metric table Muralidhara M K
2026-04-27 15:51 ` [PATCH v2 6/7] platform/x86/amd/hsmp: Make metric table read locking use guard(mutex) Muralidhara M K
2026-04-27 15:51 ` [PATCH v2 7/7] platform/x86/amd/hsmp: Support SYSFS_HUGE_BIN_FILE for metric table reads Muralidhara M K

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox