From: Carlos Bilbao <carlos.bilbao.osdev@gmail.com>
To: Erwan Velu <erwanaliasr1@gmail.com>, platform-driver-x86@vger.kernel.org
Cc: "Naveen Krishna Chatradhi" <naveenkrishna.chatradhi@amd.com>,
"Carlos Bilbao" <carlos.bilbao@kernel.org>,
"Hans de Goede" <hansg@kernel.org>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/4] platform/x86/amd/hsmp: Move per-socket sysfs attributes to common code
Date: Sun, 1 Nov 2026 18:38:24 -0800 [thread overview]
Message-ID: <af99559a-d37d-4745-b7b1-69ceac2978ed@gmail.com> (raw)
In-Reply-To: <20261007125908.321186-2-erwanaliasr1@gmail.com>
On 10/7/26 05:59, Erwan Velu wrote:
> From: Erwan Velu <e.velu@criteo.com>
>
> The per-socket telemetry attributes (c0_residency_input, ddr_max_bw,
> pwr_current_active_freq_limit, ...) are implemented in acpi.c, so only
> the ACPI driver can expose them, although they are plain HSMP messages
> the platform driver can send as well.
>
> Move them to a new sysfs.c in hsmp_common and export the attribute
> groups as hsmp_sock_groups, so they can be shared by both drivers. The
> ACPI driver keeps exposing them on its socket devices via dev_groups.
>
> No functional change.
>
> Assisted-by: claude-opus-5-5
> Signed-off-by: Erwan Velu <e.velu@criteo.com>
Acked-by: Carlos Bilbao <carlos.bilbao@kernel.org>
> ---
> drivers/platform/x86/amd/hsmp/Makefile | 2 +-
> drivers/platform/x86/amd/hsmp/acpi.c | 321 +----------------------
> drivers/platform/x86/amd/hsmp/hsmp.h | 1 +
> drivers/platform/x86/amd/hsmp/sysfs.c | 338 +++++++++++++++++++++++++
> 4 files changed, 341 insertions(+), 321 deletions(-)
> create mode 100644 drivers/platform/x86/amd/hsmp/sysfs.c
>
> diff --git a/drivers/platform/x86/amd/hsmp/Makefile b/drivers/platform/x86/amd/hsmp/Makefile
> index ce8342e71f50..21fc1d185550 100644
> --- a/drivers/platform/x86/amd/hsmp/Makefile
> +++ b/drivers/platform/x86/amd/hsmp/Makefile
> @@ -5,7 +5,7 @@
> #
>
> obj-$(CONFIG_AMD_HSMP) += hsmp_common.o
> -hsmp_common-y := hsmp.o
> +hsmp_common-y := hsmp.o sysfs.o
> hsmp_common-$(CONFIG_HWMON) += hwmon.o
> obj-$(CONFIG_AMD_HSMP_PLAT) += amd_hsmp.o
> amd_hsmp-y := plat.o
> diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
> index ddd7a04ee753..d76979baffa8 100644
> --- a/drivers/platform/x86/amd/hsmp/acpi.c
> +++ b/drivers/platform/x86/amd/hsmp/acpi.c
> @@ -12,9 +12,6 @@
> #include <asm/amd/hsmp.h>
>
> #include <linux/acpi.h>
> -#include <linux/array_size.h>
> -#include <linux/bits.h>
> -#include <linux/bitfield.h>
> #include <linux/cleanup.h>
> #include <linux/device.h>
> #include <linux/dev_printk.h>
> @@ -27,7 +24,6 @@
> #include <linux/rwsem.h>
> #include <linux/slab.h>
> #include <linux/string.h>
> -#include <linux/sysfs.h>
> #include <linux/topology.h>
> #include <linux/uuid.h>
>
> @@ -55,11 +51,6 @@ static struct hsmp_plat_device *hsmp_pdev;
> */
> static struct kref hsmp_acpi_sock_kref;
>
> -struct hsmp_sys_attr {
> - struct device_attribute dattr;
> - u32 msg_id;
> -};
> -
> static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset,
> u32 *value, bool write)
> {
> @@ -270,252 +261,6 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind)
> return 0;
> }
>
> -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);
> -
> - /*
> - * metrics_bin is a sysfs binary attribute and is capped at PAGE_SIZE.
> - * It can therefore only carry the protocol version 6 metric table
> - * (struct hsmp_metric_table). The larger tables defined from protocol
> - * version 7 onwards do not fit; userspace on those systems must read
> - * the snapshot through HSMP_IOCTL_GET_TELEMETRY_DATA on /dev/hsmp.
> - * Surface the unsupported case here as -EOPNOTSUPP rather than
> - * silently truncating the snapshot.
> - */
> - if (hsmp_pdev->proto_ver != HSMP_PROTO_VER6)
> - return -EOPNOTSUPP;
> -
> - 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)
> -{
> - /*
> - * Keep metrics_bin visible on protocol version 7 and later as well,
> - * so that userspace which expects the file to exist gets a clear
> - * -EOPNOTSUPP from the read handler instead of -ENOENT, and is
> - * pointed at HSMP_IOCTL_GET_TELEMETRY_DATA as the supported path.
> - */
> - 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)
> -{
> - return attr->mode;
> -}
> -
> -#define to_hsmp_sys_attr(_attr) container_of(_attr, struct hsmp_sys_attr, dattr)
> -
> -static ssize_t hsmp_msg_resp32_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%u\n", data);
> -}
> -
> -#define DDR_MAX_BW_MASK GENMASK(31, 20)
> -#define DDR_UTIL_BW_MASK GENMASK(19, 8)
> -#define DDR_UTIL_BW_PERC_MASK GENMASK(7, 0)
> -#define FW_VER_MAJOR_MASK GENMASK(23, 16)
> -#define FW_VER_MINOR_MASK GENMASK(15, 8)
> -#define FW_VER_DEBUG_MASK GENMASK(7, 0)
> -#define FMAX_MASK GENMASK(31, 16)
> -#define FMIN_MASK GENMASK(15, 0)
> -#define FREQ_LIMIT_MASK GENMASK(31, 16)
> -#define FREQ_SRC_IND_MASK GENMASK(15, 0)
> -
> -static ssize_t hsmp_ddr_max_bw_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_MAX_BW_MASK, data));
> -}
> -
> -static ssize_t hsmp_ddr_util_bw_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_UTIL_BW_MASK, data));
> -}
> -
> -static ssize_t hsmp_ddr_util_bw_perc_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_UTIL_BW_PERC_MASK, data));
> -}
> -
> -static ssize_t hsmp_msg_fw_ver_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%lu.%lu.%lu\n",
> - FIELD_GET(FW_VER_MAJOR_MASK, data),
> - FIELD_GET(FW_VER_MINOR_MASK, data),
> - FIELD_GET(FW_VER_DEBUG_MASK, data));
> -}
> -
> -static ssize_t hsmp_fclk_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data[2];
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, data, 2);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%u\n", data[0]);
> -}
> -
> -static ssize_t hsmp_mclk_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data[2];
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, data, 2);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%u\n", data[1]);
> -}
> -
> -static ssize_t hsmp_clk_fmax_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%lu\n", FIELD_GET(FMAX_MASK, data));
> -}
> -
> -static ssize_t hsmp_clk_fmin_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%lu\n", FIELD_GET(FMIN_MASK, data));
> -}
> -
> -static ssize_t hsmp_freq_limit_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - return sysfs_emit(buf, "%lu\n", FIELD_GET(FREQ_LIMIT_MASK, data));
> -}
> -
> -static const char * const freqlimit_srcnames[] = {
> - "cHTC-Active",
> - "PROCHOT",
> - "TDC limit",
> - "PPT Limit",
> - "OPN Max",
> - "Reliability Limit",
> - "APML Agent",
> - "HSMP Agent",
> -};
> -
> -static ssize_t hsmp_freq_limit_source_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> -{
> - struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> - struct hsmp_socket *sock = dev_get_drvdata(dev);
> - unsigned int index;
> - int len = 0;
> - u16 src_ind;
> - u32 data;
> - int ret;
> -
> - ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> - if (ret)
> - return ret;
> -
> - src_ind = FIELD_GET(FREQ_SRC_IND_MASK, data);
> - for (index = 0; index < ARRAY_SIZE(freqlimit_srcnames); index++) {
> - if (!src_ind)
> - break;
> - if (src_ind & 1)
> - len += sysfs_emit_at(buf, len, "%s\n", freqlimit_srcnames[index]);
> - src_ind >>= 1;
> - }
> - return len;
> -}
> -
> /*
> * Bring up one ACPI HSMP socket: parse its ACPI table, run the mailbox
> * handshake and register its sysfs/hwmon interfaces.
> @@ -572,70 +317,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), \
> - .msg_id = _msg_id, \
> -}
> -
> -HSMP_DEV_ATTR(c0_residency_input, HSMP_GET_C0_PERCENT, hsmp_msg_resp32_show, 0444);
> -HSMP_DEV_ATTR(prochot_status, HSMP_GET_PROC_HOT, hsmp_msg_resp32_show, 0444);
> -HSMP_DEV_ATTR(smu_fw_version, HSMP_GET_SMU_VER, hsmp_msg_fw_ver_show, 0444);
> -HSMP_DEV_ATTR(protocol_version, HSMP_GET_PROTO_VER, hsmp_msg_resp32_show, 0444);
> -HSMP_DEV_ATTR(cclk_freq_limit_input, HSMP_GET_CCLK_THROTTLE_LIMIT, hsmp_msg_resp32_show, 0444);
> -HSMP_DEV_ATTR(ddr_max_bw, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_max_bw_show, 0444);
> -HSMP_DEV_ATTR(ddr_utilised_bw_input, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_util_bw_show, 0444);
> -HSMP_DEV_ATTR(ddr_utilised_bw_perc_input, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_util_bw_perc_show, 0444);
> -HSMP_DEV_ATTR(fclk_input, HSMP_GET_FCLK_MCLK, hsmp_fclk_show, 0444);
> -HSMP_DEV_ATTR(mclk_input, HSMP_GET_FCLK_MCLK, hsmp_mclk_show, 0444);
> -HSMP_DEV_ATTR(clk_fmax, HSMP_GET_SOCKET_FMAX_FMIN, hsmp_clk_fmax_show, 0444);
> -HSMP_DEV_ATTR(clk_fmin, HSMP_GET_SOCKET_FMAX_FMIN, hsmp_clk_fmin_show, 0444);
> -HSMP_DEV_ATTR(pwr_current_active_freq_limit, HSMP_GET_SOCKET_FREQ_LIMIT,
> - hsmp_freq_limit_show, 0444);
> -HSMP_DEV_ATTR(pwr_current_active_freq_limit_source, HSMP_GET_SOCKET_FREQ_LIMIT,
> - hsmp_freq_limit_source_show, 0444);
> -
> -static struct attribute *hsmp_dev_attr_list[] = {
> - &hattr_c0_residency_input.dattr.attr,
> - &hattr_prochot_status.dattr.attr,
> - &hattr_smu_fw_version.dattr.attr,
> - &hattr_protocol_version.dattr.attr,
> - &hattr_cclk_freq_limit_input.dattr.attr,
> - &hattr_ddr_max_bw.dattr.attr,
> - &hattr_ddr_utilised_bw_input.dattr.attr,
> - &hattr_ddr_utilised_bw_perc_input.dattr.attr,
> - &hattr_fclk_input.dattr.attr,
> - &hattr_mclk_input.dattr.attr,
> - &hattr_clk_fmax.dattr.attr,
> - &hattr_clk_fmin.dattr.attr,
> - &hattr_pwr_current_active_freq_limit.dattr.attr,
> - &hattr_pwr_current_active_freq_limit_source.dattr.attr,
> - NULL
> -};
> -
> -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,
> -};
> -
> -static const struct attribute_group *hsmp_groups[] = {
> - &hsmp_attr_grp,
> - NULL
> -};
> -
> static const struct acpi_device_id amd_hsmp_acpi_ids[] = {
> {ACPI_HSMP_DEVICE_HID, 0},
> {}
> @@ -793,7 +474,7 @@ static struct platform_driver amd_hsmp_driver = {
> .driver = {
> .name = DRIVER_NAME,
> .acpi_match_table = amd_hsmp_acpi_ids,
> - .dev_groups = hsmp_groups,
> + .dev_groups = hsmp_sock_groups,
> },
> };
>
> diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h
> index 8dbff16a87b1..692721e2e6d3 100644
> --- a/drivers/platform/x86/amd/hsmp/hsmp.h
> +++ b/drivers/platform/x86/amd/hsmp/hsmp.h
> @@ -80,6 +80,7 @@ int hsmp_create_sensor(struct device *dev, u16 sock_ind);
> static inline int hsmp_create_sensor(struct device *dev, u16 sock_ind) { return 0; }
> #endif
> int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 num_args);
> +extern const struct attribute_group *hsmp_sock_groups[];
>
> /*
> * Gates the HSMP data plane: hsmp_send_message() takes it for read; probe and
> diff --git a/drivers/platform/x86/amd/hsmp/sysfs.c b/drivers/platform/x86/amd/hsmp/sysfs.c
> new file mode 100644
> index 000000000000..b1db3b4d77b9
> --- /dev/null
> +++ b/drivers/platform/x86/amd/hsmp/sysfs.c
> @@ -0,0 +1,338 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * AMD HSMP sysfs support
> + * Copyright (c) 2024, AMD.
> + * All Rights Reserved.
> + *
> + * This file provides the per-socket sysfs attributes of the HSMP interface.
> + */
> +
> +#include <asm/amd/hsmp.h>
> +
> +#include <linux/array_size.h>
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/device.h>
> +#include <linux/sysfs.h>
> +
> +#include "hsmp.h"
> +
> +struct hsmp_sys_attr {
> + struct device_attribute dattr;
> + u32 msg_id;
> +};
> +
> +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);
> +
> + /*
> + * metrics_bin is a sysfs binary attribute and is capped at PAGE_SIZE.
> + * It can therefore only carry the protocol version 6 metric table
> + * (struct hsmp_metric_table). The larger tables defined from protocol
> + * version 7 onwards do not fit; userspace on those systems must read
> + * the snapshot through HSMP_IOCTL_GET_TELEMETRY_DATA on /dev/hsmp.
> + * Surface the unsupported case here as -EOPNOTSUPP rather than
> + * silently truncating the snapshot.
> + */
> + if (get_hsmp_pdev()->proto_ver != HSMP_PROTO_VER6)
> + return -EOPNOTSUPP;
> +
> + 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)
> +{
> + /*
> + * Keep metrics_bin visible on protocol version 7 and later as well,
> + * so that userspace which expects the file to exist gets a clear
> + * -EOPNOTSUPP from the read handler instead of -ENOENT, and is
> + * pointed at HSMP_IOCTL_GET_TELEMETRY_DATA as the supported path.
> + */
> + if (get_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)
> +{
> + return attr->mode;
> +}
> +
> +#define to_hsmp_sys_attr(_attr) container_of(_attr, struct hsmp_sys_attr, dattr)
> +
> +static ssize_t hsmp_msg_resp32_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%u\n", data);
> +}
> +
> +#define DDR_MAX_BW_MASK GENMASK(31, 20)
> +#define DDR_UTIL_BW_MASK GENMASK(19, 8)
> +#define DDR_UTIL_BW_PERC_MASK GENMASK(7, 0)
> +#define FW_VER_MAJOR_MASK GENMASK(23, 16)
> +#define FW_VER_MINOR_MASK GENMASK(15, 8)
> +#define FW_VER_DEBUG_MASK GENMASK(7, 0)
> +#define FMAX_MASK GENMASK(31, 16)
> +#define FMIN_MASK GENMASK(15, 0)
> +#define FREQ_LIMIT_MASK GENMASK(31, 16)
> +#define FREQ_SRC_IND_MASK GENMASK(15, 0)
> +
> +static ssize_t hsmp_ddr_max_bw_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_MAX_BW_MASK, data));
> +}
> +
> +static ssize_t hsmp_ddr_util_bw_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_UTIL_BW_MASK, data));
> +}
> +
> +static ssize_t hsmp_ddr_util_bw_perc_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_UTIL_BW_PERC_MASK, data));
> +}
> +
> +static ssize_t hsmp_msg_fw_ver_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%lu.%lu.%lu\n",
> + FIELD_GET(FW_VER_MAJOR_MASK, data),
> + FIELD_GET(FW_VER_MINOR_MASK, data),
> + FIELD_GET(FW_VER_DEBUG_MASK, data));
> +}
> +
> +static ssize_t hsmp_fclk_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data[2];
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, data, 2);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%u\n", data[0]);
> +}
> +
> +static ssize_t hsmp_mclk_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data[2];
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, data, 2);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%u\n", data[1]);
> +}
> +
> +static ssize_t hsmp_clk_fmax_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%lu\n", FIELD_GET(FMAX_MASK, data));
> +}
> +
> +static ssize_t hsmp_clk_fmin_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%lu\n", FIELD_GET(FMIN_MASK, data));
> +}
> +
> +static ssize_t hsmp_freq_limit_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%lu\n", FIELD_GET(FREQ_LIMIT_MASK, data));
> +}
> +
> +static const char * const freqlimit_srcnames[] = {
> + "cHTC-Active",
> + "PROCHOT",
> + "TDC limit",
> + "PPT Limit",
> + "OPN Max",
> + "Reliability Limit",
> + "APML Agent",
> + "HSMP Agent",
> +};
> +
> +static ssize_t hsmp_freq_limit_source_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr);
> + struct hsmp_socket *sock = dev_get_drvdata(dev);
> + unsigned int index;
> + int len = 0;
> + u16 src_ind;
> + u32 data;
> + int ret;
> +
> + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
> + if (ret)
> + return ret;
> +
> + src_ind = FIELD_GET(FREQ_SRC_IND_MASK, data);
> + for (index = 0; index < ARRAY_SIZE(freqlimit_srcnames); index++) {
> + if (!src_ind)
> + break;
> + if (src_ind & 1)
> + len += sysfs_emit_at(buf, len, "%s\n", freqlimit_srcnames[index]);
> + src_ind >>= 1;
> + }
> + return len;
> +}
> +
> +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), \
> + .msg_id = _msg_id, \
> +}
> +
> +HSMP_DEV_ATTR(c0_residency_input, HSMP_GET_C0_PERCENT, hsmp_msg_resp32_show, 0444);
> +HSMP_DEV_ATTR(prochot_status, HSMP_GET_PROC_HOT, hsmp_msg_resp32_show, 0444);
> +HSMP_DEV_ATTR(smu_fw_version, HSMP_GET_SMU_VER, hsmp_msg_fw_ver_show, 0444);
> +HSMP_DEV_ATTR(protocol_version, HSMP_GET_PROTO_VER, hsmp_msg_resp32_show, 0444);
> +HSMP_DEV_ATTR(cclk_freq_limit_input, HSMP_GET_CCLK_THROTTLE_LIMIT, hsmp_msg_resp32_show, 0444);
> +HSMP_DEV_ATTR(ddr_max_bw, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_max_bw_show, 0444);
> +HSMP_DEV_ATTR(ddr_utilised_bw_input, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_util_bw_show, 0444);
> +HSMP_DEV_ATTR(ddr_utilised_bw_perc_input, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_util_bw_perc_show, 0444);
> +HSMP_DEV_ATTR(fclk_input, HSMP_GET_FCLK_MCLK, hsmp_fclk_show, 0444);
> +HSMP_DEV_ATTR(mclk_input, HSMP_GET_FCLK_MCLK, hsmp_mclk_show, 0444);
> +HSMP_DEV_ATTR(clk_fmax, HSMP_GET_SOCKET_FMAX_FMIN, hsmp_clk_fmax_show, 0444);
> +HSMP_DEV_ATTR(clk_fmin, HSMP_GET_SOCKET_FMAX_FMIN, hsmp_clk_fmin_show, 0444);
> +HSMP_DEV_ATTR(pwr_current_active_freq_limit, HSMP_GET_SOCKET_FREQ_LIMIT,
> + hsmp_freq_limit_show, 0444);
> +HSMP_DEV_ATTR(pwr_current_active_freq_limit_source, HSMP_GET_SOCKET_FREQ_LIMIT,
> + hsmp_freq_limit_source_show, 0444);
> +
> +static struct attribute *hsmp_dev_attr_list[] = {
> + &hattr_c0_residency_input.dattr.attr,
> + &hattr_prochot_status.dattr.attr,
> + &hattr_smu_fw_version.dattr.attr,
> + &hattr_protocol_version.dattr.attr,
> + &hattr_cclk_freq_limit_input.dattr.attr,
> + &hattr_ddr_max_bw.dattr.attr,
> + &hattr_ddr_utilised_bw_input.dattr.attr,
> + &hattr_ddr_utilised_bw_perc_input.dattr.attr,
> + &hattr_fclk_input.dattr.attr,
> + &hattr_mclk_input.dattr.attr,
> + &hattr_clk_fmax.dattr.attr,
> + &hattr_clk_fmin.dattr.attr,
> + &hattr_pwr_current_active_freq_limit.dattr.attr,
> + &hattr_pwr_current_active_freq_limit_source.dattr.attr,
> + NULL
> +};
> +
> +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,
> +};
> +
> +/*
> + * Per-socket attribute groups. Every show/read handler expects the drvdata of
> + * the device carrying the group to be the struct hsmp_socket it reports on.
> + */
> +const struct attribute_group *hsmp_sock_groups[] = {
> + &hsmp_attr_grp,
> + NULL
> +};
> +EXPORT_SYMBOL_NS_GPL(hsmp_sock_groups, "AMD_HSMP");
next prev parent reply other threads:[~2026-11-02 2:38 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 12:59 [PATCH 0/4] platform/x86/amd/hsmp: Unify per-socket sysfs metrics Erwan Velu
2026-10-07 12:59 ` [PATCH 1/4] platform/x86/amd/hsmp: Move per-socket sysfs attributes to common code Erwan Velu
2026-11-02 2:38 ` Carlos Bilbao [this message]
2026-10-07 12:59 ` [PATCH 2/4] platform/x86/amd/hsmp: Add /sys/devices/amd_hsmp socket devices Erwan Velu
2026-10-16 11:02 ` Ilpo Järvinen
2026-11-02 2:57 ` Carlos Bilbao
2026-10-07 12:59 ` [PATCH 3/4] platform/x86/amd/hsmp: Expose socket attributes from the platform driver Erwan Velu
2026-10-07 12:59 ` [PATCH 4/4] platform/x86/amd/hsmp: Add pwr_current_active_freq_limit_source_raw Erwan Velu
2026-11-02 2:41 ` Carlos Bilbao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=af99559a-d37d-4745-b7b1-69ceac2978ed@gmail.com \
--to=carlos.bilbao.osdev@gmail.com \
--cc=carlos.bilbao@kernel.org \
--cc=erwanaliasr1@gmail.com \
--cc=hansg@kernel.org \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=naveenkrishna.chatradhi@amd.com \
--cc=platform-driver-x86@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®