Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform/x86/amd/hsmp: acpi: Add sysfs files to display HSMP telemetry

Make frequently fetched telemetry available via sysfs. These parameters
do not fit in hwmon sensor model, hence make them available via sysfs.

Create following sysfs files per acpi device node.
* c0_residency_input
* prochot_status
* smu_fw_version
* protocol_version
* ddr_max_bw(GB/s)
* ddr_utilised_bw_input(GB/s)
* ddr_utilised_bw_perc_input(%)
* mclk_input(MHz)
* fclk_input(MHz)
* clk_fmax(MHz)
* clk_fmin(MHz)
* cclk_freq_limit_input(MHz)
* pwr_current_active_freq_limit(MHz)
* pwr_current_active_freq_limit_source

Signed-off-by: Suma Hegde <suma.hegde@amd.com>
Reviewed-by: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20250506101542.200811-3-suma.hegde@amd.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

authored by

Suma Hegde and committed by
Ilpo Järvinen
511a4a5e 92c025db

+308
+22
Documentation/arch/x86/amd_hsmp.rst
··· 71 71 Metrics table definitions will be documented as part of Public PPR. 72 72 The same is defined in the amd_hsmp.h header. 73 73 74 + 2. HSMP telemetry sysfs files 75 + 76 + Following sysfs files are available at /sys/devices/platform/AMDI0097:0X/. 77 + 78 + * c0_residency_input: Percentage of cores in C0 state. 79 + * prochot_status: Reports 1 if the processor is at thermal threshold value, 80 + 0 otherwise. 81 + * smu_fw_version: SMU firmware version. 82 + * protocol_version: HSMP interface version. 83 + * ddr_max_bw: Theoretical maximum DDR bandwidth in GB/s. 84 + * ddr_utilised_bw_input: Current utilized DDR bandwidth in GB/s. 85 + * ddr_utilised_bw_perc_input(%): Percentage of current utilized DDR bandwidth. 86 + * mclk_input: Memory clock in MHz. 87 + * fclk_input: Fabric clock in MHz. 88 + * clk_fmax: Maximum frequency of socket in MHz. 89 + * clk_fmin: Minimum frequency of socket in MHz. 90 + * cclk_freq_limit_input: Core clock frequency limit per socket in MHz. 91 + * pwr_current_active_freq_limit: Current active frequency limit of socket 92 + in MHz. 93 + * pwr_current_active_freq_limit_source: Source of current active frequency 94 + limit. 95 + 74 96 ACPI device object format 75 97 ========================= 76 98 The ACPI object format expected from the amd_hsmp driver
+262
drivers/platform/x86/amd/hsmp/acpi.c
··· 12 12 #include <asm/amd_hsmp.h> 13 13 14 14 #include <linux/acpi.h> 15 + #include <linux/array_size.h> 16 + #include <linux/bits.h> 17 + #include <linux/bitfield.h> 15 18 #include <linux/device.h> 16 19 #include <linux/dev_printk.h> 17 20 #include <linux/ioport.h> ··· 38 35 #define MSG_RESPOFF_STR "MsgRspOffset" 39 36 40 37 static struct hsmp_plat_device *hsmp_pdev; 38 + 39 + struct hsmp_sys_attr { 40 + struct device_attribute dattr; 41 + u32 msg_id; 42 + }; 41 43 42 44 static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset, 43 45 u32 *value, bool write) ··· 251 243 return 0; 252 244 } 253 245 246 + static umode_t hsmp_is_sock_dev_attr_visible(struct kobject *kobj, 247 + struct attribute *attr, int id) 248 + { 249 + return attr->mode; 250 + } 251 + 252 + #define to_hsmp_sys_attr(_attr) container_of(_attr, struct hsmp_sys_attr, dattr) 253 + 254 + static ssize_t hsmp_msg_resp32_show(struct device *dev, struct device_attribute *attr, 255 + char *buf) 256 + { 257 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 258 + struct hsmp_socket *sock = dev_get_drvdata(dev); 259 + u32 data; 260 + int ret; 261 + 262 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 263 + if (ret) 264 + return ret; 265 + 266 + return sysfs_emit(buf, "%u\n", data); 267 + } 268 + 269 + #define DDR_MAX_BW_MASK GENMASK(31, 20) 270 + #define DDR_UTIL_BW_MASK GENMASK(19, 8) 271 + #define DDR_UTIL_BW_PERC_MASK GENMASK(7, 0) 272 + #define FW_VER_MAJOR_MASK GENMASK(23, 16) 273 + #define FW_VER_MINOR_MASK GENMASK(15, 8) 274 + #define FW_VER_DEBUG_MASK GENMASK(7, 0) 275 + #define FMAX_MASK GENMASK(31, 16) 276 + #define FMIN_MASK GENMASK(15, 0) 277 + #define FREQ_LIMIT_MASK GENMASK(31, 16) 278 + #define FREQ_SRC_IND_MASK GENMASK(15, 0) 279 + 280 + static ssize_t hsmp_ddr_max_bw_show(struct device *dev, struct device_attribute *attr, 281 + char *buf) 282 + { 283 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 284 + struct hsmp_socket *sock = dev_get_drvdata(dev); 285 + u32 data; 286 + int ret; 287 + 288 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 289 + if (ret) 290 + return ret; 291 + 292 + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_MAX_BW_MASK, data)); 293 + } 294 + 295 + static ssize_t hsmp_ddr_util_bw_show(struct device *dev, struct device_attribute *attr, 296 + char *buf) 297 + { 298 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 299 + struct hsmp_socket *sock = dev_get_drvdata(dev); 300 + u32 data; 301 + int ret; 302 + 303 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 304 + if (ret) 305 + return ret; 306 + 307 + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_UTIL_BW_MASK, data)); 308 + } 309 + 310 + static ssize_t hsmp_ddr_util_bw_perc_show(struct device *dev, struct device_attribute *attr, 311 + char *buf) 312 + { 313 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 314 + struct hsmp_socket *sock = dev_get_drvdata(dev); 315 + u32 data; 316 + int ret; 317 + 318 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 319 + if (ret) 320 + return ret; 321 + 322 + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_UTIL_BW_PERC_MASK, data)); 323 + } 324 + 325 + static ssize_t hsmp_msg_fw_ver_show(struct device *dev, struct device_attribute *attr, 326 + char *buf) 327 + { 328 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 329 + struct hsmp_socket *sock = dev_get_drvdata(dev); 330 + u32 data; 331 + int ret; 332 + 333 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 334 + if (ret) 335 + return ret; 336 + 337 + return sysfs_emit(buf, "%lu.%lu.%lu\n", 338 + FIELD_GET(FW_VER_MAJOR_MASK, data), 339 + FIELD_GET(FW_VER_MINOR_MASK, data), 340 + FIELD_GET(FW_VER_DEBUG_MASK, data)); 341 + } 342 + 343 + static ssize_t hsmp_fclk_show(struct device *dev, struct device_attribute *attr, 344 + char *buf) 345 + { 346 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 347 + struct hsmp_socket *sock = dev_get_drvdata(dev); 348 + u32 data[2]; 349 + int ret; 350 + 351 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, data, 2); 352 + if (ret) 353 + return ret; 354 + 355 + return sysfs_emit(buf, "%u\n", data[0]); 356 + } 357 + 358 + static ssize_t hsmp_mclk_show(struct device *dev, struct device_attribute *attr, 359 + char *buf) 360 + { 361 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 362 + struct hsmp_socket *sock = dev_get_drvdata(dev); 363 + u32 data[2]; 364 + int ret; 365 + 366 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, data, 2); 367 + if (ret) 368 + return ret; 369 + 370 + return sysfs_emit(buf, "%u\n", data[1]); 371 + } 372 + 373 + static ssize_t hsmp_clk_fmax_show(struct device *dev, struct device_attribute *attr, 374 + char *buf) 375 + { 376 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 377 + struct hsmp_socket *sock = dev_get_drvdata(dev); 378 + u32 data; 379 + int ret; 380 + 381 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 382 + if (ret) 383 + return ret; 384 + 385 + return sysfs_emit(buf, "%lu\n", FIELD_GET(FMAX_MASK, data)); 386 + } 387 + 388 + static ssize_t hsmp_clk_fmin_show(struct device *dev, struct device_attribute *attr, 389 + char *buf) 390 + { 391 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 392 + struct hsmp_socket *sock = dev_get_drvdata(dev); 393 + u32 data; 394 + int ret; 395 + 396 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 397 + if (ret) 398 + return ret; 399 + 400 + return sysfs_emit(buf, "%lu\n", FIELD_GET(FMIN_MASK, data)); 401 + } 402 + 403 + static ssize_t hsmp_freq_limit_show(struct device *dev, struct device_attribute *attr, 404 + char *buf) 405 + { 406 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 407 + struct hsmp_socket *sock = dev_get_drvdata(dev); 408 + u32 data; 409 + int ret; 410 + 411 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 412 + if (ret) 413 + return ret; 414 + 415 + return sysfs_emit(buf, "%lu\n", FIELD_GET(FREQ_LIMIT_MASK, data)); 416 + } 417 + 418 + static const char * const freqlimit_srcnames[] = { 419 + "cHTC-Active", 420 + "PROCHOT", 421 + "TDC limit", 422 + "PPT Limit", 423 + "OPN Max", 424 + "Reliability Limit", 425 + "APML Agent", 426 + "HSMP Agent", 427 + }; 428 + 429 + static ssize_t hsmp_freq_limit_source_show(struct device *dev, struct device_attribute *attr, 430 + char *buf) 431 + { 432 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 433 + struct hsmp_socket *sock = dev_get_drvdata(dev); 434 + unsigned int index; 435 + int len = 0; 436 + u16 src_ind; 437 + u32 data; 438 + int ret; 439 + 440 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 441 + if (ret) 442 + return ret; 443 + 444 + src_ind = FIELD_GET(FREQ_SRC_IND_MASK, data); 445 + for (index = 0; index < ARRAY_SIZE(freqlimit_srcnames); index++) { 446 + if (!src_ind) 447 + break; 448 + if (src_ind & 1) 449 + len += sysfs_emit_at(buf, len, "%s\n", freqlimit_srcnames[index]); 450 + src_ind >>= 1; 451 + } 452 + return len; 453 + } 454 + 254 455 static int init_acpi(struct device *dev) 255 456 { 256 457 u16 sock_ind; ··· 502 285 if (ret) 503 286 dev_err(dev, "Failed to register HSMP sensors with hwmon\n"); 504 287 288 + dev_set_drvdata(dev, &hsmp_pdev->sock[sock_ind]); 289 + 505 290 return ret; 506 291 } 507 292 ··· 518 299 NULL 519 300 }; 520 301 302 + #define HSMP_DEV_ATTR(_name, _msg_id, _show, _mode) \ 303 + static struct hsmp_sys_attr hattr_##_name = { \ 304 + .dattr = __ATTR(_name, _mode, _show, NULL), \ 305 + .msg_id = _msg_id, \ 306 + } 307 + 308 + HSMP_DEV_ATTR(c0_residency_input, HSMP_GET_C0_PERCENT, hsmp_msg_resp32_show, 0444); 309 + HSMP_DEV_ATTR(prochot_status, HSMP_GET_PROC_HOT, hsmp_msg_resp32_show, 0444); 310 + HSMP_DEV_ATTR(smu_fw_version, HSMP_GET_SMU_VER, hsmp_msg_fw_ver_show, 0444); 311 + HSMP_DEV_ATTR(protocol_version, HSMP_GET_PROTO_VER, hsmp_msg_resp32_show, 0444); 312 + HSMP_DEV_ATTR(cclk_freq_limit_input, HSMP_GET_CCLK_THROTTLE_LIMIT, hsmp_msg_resp32_show, 0444); 313 + HSMP_DEV_ATTR(ddr_max_bw, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_max_bw_show, 0444); 314 + HSMP_DEV_ATTR(ddr_utilised_bw_input, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_util_bw_show, 0444); 315 + HSMP_DEV_ATTR(ddr_utilised_bw_perc_input, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_util_bw_perc_show, 0444); 316 + HSMP_DEV_ATTR(fclk_input, HSMP_GET_FCLK_MCLK, hsmp_fclk_show, 0444); 317 + HSMP_DEV_ATTR(mclk_input, HSMP_GET_FCLK_MCLK, hsmp_mclk_show, 0444); 318 + HSMP_DEV_ATTR(clk_fmax, HSMP_GET_SOCKET_FMAX_FMIN, hsmp_clk_fmax_show, 0444); 319 + HSMP_DEV_ATTR(clk_fmin, HSMP_GET_SOCKET_FMAX_FMIN, hsmp_clk_fmin_show, 0444); 320 + HSMP_DEV_ATTR(pwr_current_active_freq_limit, HSMP_GET_SOCKET_FREQ_LIMIT, 321 + hsmp_freq_limit_show, 0444); 322 + HSMP_DEV_ATTR(pwr_current_active_freq_limit_source, HSMP_GET_SOCKET_FREQ_LIMIT, 323 + hsmp_freq_limit_source_show, 0444); 324 + 325 + static struct attribute *hsmp_dev_attr_list[] = { 326 + &hattr_c0_residency_input.dattr.attr, 327 + &hattr_prochot_status.dattr.attr, 328 + &hattr_smu_fw_version.dattr.attr, 329 + &hattr_protocol_version.dattr.attr, 330 + &hattr_cclk_freq_limit_input.dattr.attr, 331 + &hattr_ddr_max_bw.dattr.attr, 332 + &hattr_ddr_utilised_bw_input.dattr.attr, 333 + &hattr_ddr_utilised_bw_perc_input.dattr.attr, 334 + &hattr_fclk_input.dattr.attr, 335 + &hattr_mclk_input.dattr.attr, 336 + &hattr_clk_fmax.dattr.attr, 337 + &hattr_clk_fmin.dattr.attr, 338 + &hattr_pwr_current_active_freq_limit.dattr.attr, 339 + &hattr_pwr_current_active_freq_limit_source.dattr.attr, 340 + NULL 341 + }; 342 + 521 343 static const struct attribute_group hsmp_attr_grp = { 522 344 .bin_attrs_new = hsmp_attr_list, 345 + .attrs = hsmp_dev_attr_list, 523 346 .is_bin_visible = hsmp_is_sock_attr_visible, 347 + .is_visible = hsmp_is_sock_dev_attr_visible, 524 348 }; 525 349 526 350 static const struct attribute_group *hsmp_groups[] = {
+23
drivers/platform/x86/amd/hsmp/hsmp.c
··· 228 228 } 229 229 EXPORT_SYMBOL_NS_GPL(hsmp_send_message, "AMD_HSMP"); 230 230 231 + int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 num_args) 232 + { 233 + struct hsmp_message msg = {}; 234 + unsigned int i; 235 + int ret; 236 + 237 + if (!data) 238 + return -EINVAL; 239 + msg.msg_id = msg_id; 240 + msg.sock_ind = sock_ind; 241 + msg.response_sz = num_args; 242 + 243 + ret = hsmp_send_message(&msg); 244 + if (ret) 245 + return ret; 246 + 247 + for (i = 0; i < num_args; i++) 248 + data[i] = msg.args[i]; 249 + 250 + return 0; 251 + } 252 + EXPORT_SYMBOL_NS_GPL(hsmp_msg_get_nargs, "AMD_HSMP"); 253 + 231 254 int hsmp_test(u16 sock_ind, u32 value) 232 255 { 233 256 struct hsmp_message msg = { 0 };
+1
drivers/platform/x86/amd/hsmp/hsmp.h
··· 69 69 #else 70 70 static inline int hsmp_create_sensor(struct device *dev, u16 sock_ind) { return 0; } 71 71 #endif 72 + int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 num_args); 72 73 #endif /* HSMP_H */