@@ -71,6 +71,25 @@ Note: lseek() is not supported as entire metrics table is read.
Metrics table definitions will be documented as part of Public PPR.
The same is defined in the amd_hsmp.h header.
+2. HSMP telemetry sysfs files
+
+Following sysfs file are available at /sys/devices/platform/AMDI0097:0X/.
+
+* c0_residency_input : percentage of cores in C0 state
+* prochot_status : reports 1 if socket is in prochot, 0 otherwhile
+* smu_fw_version : SMU firmware version
+* protocol_version : HSMP interface version
+* ddr_max_bw : theoretical maximum ddr bw in GB/s
+* ddr_utilised_bw_input: current utilized ddr bw in GB/s
+* ddr_utilised_bw_perc_input(%): Percentage of current utilized ddr bw
+* mclk_input : memory clock in MHz
+* fclk_input: fabric clock in MHz
+* clk_fmax : max frequency of socket in MHz
+* clk_fmin : min frequency of socket in MHz
+* cclk_freq_limit_input : core clock frequency limit per socket in MHz
+* pwr_current_active_freq_limit: current active frequency limit of socket in MHz
+* pwr_current_active_freq_limit_source: source of current active frequency limit
+
ACPI device object format
=========================
The ACPI object format expected from the amd_hsmp driver
@@ -36,6 +36,11 @@
static struct hsmp_plat_device *hsmp_pdev;
+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)
{
@@ -243,6 +248,226 @@ static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj,
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 sysfs_emit(buf, "%u\n", data);
+
+ return ret;
+}
+
+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;
+ u16 mbw;
+
+ ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
+ if (!ret) {
+ mbw = data >> 20;
+ return sysfs_emit(buf, "%u\n", mbw);
+ }
+
+ return ret;
+}
+
+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;
+ u16 ubw;
+
+ ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
+ if (!ret) {
+ ubw = (data >> 8) & GENMASK(12, 0);
+ return sysfs_emit(buf, "%u\n", ubw);
+ }
+
+ return ret;
+}
+
+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;
+ u8 perc;
+
+ ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
+ if (!ret) {
+ perc = data & GENMASK(7, 0);
+ return sysfs_emit(buf, "%u\n", perc);
+ }
+
+ return ret;
+}
+
+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;
+ u8 major;
+ u8 minor;
+ u8 debug;
+ int ret;
+
+ ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
+ if (!ret) {
+ major = data >> 16 & GENMASK(7, 0);
+ minor = data >> 8 & GENMASK(7, 0);
+ debug = data & GENMASK(7, 0);
+ return sysfs_emit(buf, "%u.%u.%u\n", major, minor, debug);
+ }
+ return ret;
+}
+
+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 sysfs_emit(buf, "%u\n", data[0]);
+
+ return ret;
+}
+
+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 sysfs_emit(buf, "%u\n", data[1]);
+
+ return ret;
+}
+
+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;
+ u16 fmax;
+ int ret;
+
+ ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
+ if (!ret) {
+ fmax = (data >> 16) & GENMASK(15, 0);
+ return sysfs_emit(buf, "%u\n", fmax);
+ }
+
+ return ret;
+}
+
+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;
+ u16 fmin;
+ int ret;
+
+ ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
+ if (!ret) {
+ fmin = data & GENMASK(15, 0);
+ return sysfs_emit(buf, "%u\n", fmin);
+ }
+
+ return ret;
+}
+
+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);
+ u16 freq_limit;
+ u32 data;
+ int ret;
+
+ ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1);
+ if (!ret) {
+ freq_limit = data >> 16 & GENMASK(15, 0);
+ return sysfs_emit(buf, "%u\n", freq_limit);
+ }
+
+ return ret;
+}
+
+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);
+ u32 index = 0;
+ 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) {
+ src_ind = data & GENMASK(15, 0);
+ while (src_ind != 0 && index < ARRAY_SIZE(freqlimit_srcnames)) {
+ if ((src_ind & 1) == 1)
+ len += sysfs_emit_at(buf, len, "%s ", freqlimit_srcnames[index]);
+ index += 1;
+ src_ind = src_ind >> 1;
+ }
+ len += sysfs_emit_at(buf, len, "\n");
+ return len;
+ }
+
+ return ret;
+}
+
static int init_acpi(struct device *dev)
{
u16 sock_ind;
@@ -280,6 +505,7 @@ static int init_acpi(struct device *dev)
if (ret)
dev_err(dev, "Failed to init metric table\n");
}
+ dev_set_drvdata(dev, &hsmp_pdev->sock[sock_ind]);
return ret;
}
@@ -295,9 +521,52 @@ static const struct bin_attribute *hsmp_attr_list[] = {
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_new = 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[] = {
@@ -229,6 +229,27 @@ int hsmp_send_message(struct hsmp_message *msg)
}
EXPORT_SYMBOL_NS_GPL(hsmp_send_message, "AMD_HSMP");
+int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 n)
+{
+ struct hsmp_message msg = { 0 };
+ int ret;
+ int i;
+
+ if (!data)
+ return -EINVAL;
+ msg.msg_id = msg_id;
+ msg.sock_ind = sock_ind;
+ msg.response_sz = n;
+
+ ret = hsmp_send_message(&msg);
+ if (!ret) {
+ for (i = 0; i < n; i++)
+ data[i] = msg.args[i];
+ }
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(hsmp_msg_get_nargs, "AMD_HSMP");
+
int hsmp_test(u16 sock_ind, u32 value)
{
struct hsmp_message msg = { 0 };
@@ -75,4 +75,5 @@ int hsmp_get_tbl_dram_base(u16 sock_ind);
ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size);
struct hsmp_plat_device *get_hsmp_pdev(void);
int hsmp_create_sensor(struct device *dev, struct hsmp_plat_device *pdev);
+int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 n);
#endif /* HSMP_H */