hsmp.c (8e75dff56e003cdd38643024c4f5f8ba227100c8) | hsmp.c (7d3135d16356f1f0adda7e76d4a747f618263db4) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * AMD HSMP Platform Driver 4 * Copyright (c) 2022, AMD. 5 * All Rights Reserved. 6 * 7 * This file provides a device implementation for HSMP interface 8 */ 9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 12#include <asm/amd_hsmp.h> 13#include <asm/amd_nb.h> 14 15#include <linux/acpi.h> 16#include <linux/delay.h> 17#include <linux/device.h> | 1// SPDX-License-Identifier: GPL-2.0 2/* 3 * AMD HSMP Platform Driver 4 * Copyright (c) 2022, AMD. 5 * All Rights Reserved. 6 * 7 * This file provides a device implementation for HSMP interface 8 */ 9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 12#include <asm/amd_hsmp.h> 13#include <asm/amd_nb.h> 14 15#include <linux/acpi.h> 16#include <linux/delay.h> 17#include <linux/device.h> |
18#include <linux/module.h> 19#include <linux/platform_device.h> | |
20#include <linux/semaphore.h> 21#include <linux/sysfs.h> 22 23#include "hsmp.h" 24 | 18#include <linux/semaphore.h> 19#include <linux/sysfs.h> 20 21#include "hsmp.h" 22 |
25#define DRIVER_NAME "amd_hsmp" 26#define DRIVER_VERSION "2.2" 27#define ACPI_HSMP_DEVICE_HID "AMDI0097" 28 | |
29/* HSMP Status / Error codes */ 30#define HSMP_STATUS_NOT_READY 0x00 31#define HSMP_STATUS_OK 0x01 32#define HSMP_ERR_INVALID_MSG 0xFE 33#define HSMP_ERR_INVALID_INPUT 0xFF 34 35/* Timeout in millsec */ 36#define HSMP_MSG_TIMEOUT 100 37#define HSMP_SHORT_SLEEP 1 38 39#define HSMP_WR true 40#define HSMP_RD false 41 | 23/* HSMP Status / Error codes */ 24#define HSMP_STATUS_NOT_READY 0x00 25#define HSMP_STATUS_OK 0x01 26#define HSMP_ERR_INVALID_MSG 0xFE 27#define HSMP_ERR_INVALID_INPUT 0xFF 28 29/* Timeout in millsec */ 30#define HSMP_MSG_TIMEOUT 100 31#define HSMP_SHORT_SLEEP 1 32 33#define HSMP_WR true 34#define HSMP_RD false 35 |
36#define DRIVER_VERSION "2.3" 37 |
|
42struct hsmp_plat_device hsmp_pdev; | 38struct hsmp_plat_device hsmp_pdev; |
39EXPORT_SYMBOL_GPL(hsmp_pdev); |
|
43 44/* 45 * Send a message to the HSMP port via PCI-e config space registers 46 * or by writing to MMIO space. 47 * 48 * The caller is expected to zero out any unused arguments. 49 * If a response is expected, the number of response words should be greater than 0. 50 * --- 171 unchanged lines hidden (view full) --- 222 dev_err(hsmp_pdev.sock[sock_ind].dev, 223 "Socket %d test message failed, Expected 0x%08X, received 0x%08X\n", 224 sock_ind, (value + 1), msg.args[0]); 225 return -EBADE; 226 } 227 228 return ret; 229} | 40 41/* 42 * Send a message to the HSMP port via PCI-e config space registers 43 * or by writing to MMIO space. 44 * 45 * The caller is expected to zero out any unused arguments. 46 * If a response is expected, the number of response words should be greater than 0. 47 * --- 171 unchanged lines hidden (view full) --- 219 dev_err(hsmp_pdev.sock[sock_ind].dev, 220 "Socket %d test message failed, Expected 0x%08X, received 0x%08X\n", 221 sock_ind, (value + 1), msg.args[0]); 222 return -EBADE; 223 } 224 225 return ret; 226} |
227EXPORT_SYMBOL_GPL(hsmp_test); |
|
230 | 228 |
231static long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) | 229long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) |
232{ 233 int __user *arguser = (int __user *)arg; 234 struct hsmp_message msg = { 0 }; 235 int ret; 236 237 if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message))) 238 return -EFAULT; 239 --- 39 unchanged lines hidden (view full) --- 279 /* Copy results back to user for get/monitor commands */ 280 if (copy_to_user(arguser, &msg, sizeof(struct hsmp_message))) 281 return -EFAULT; 282 } 283 284 return 0; 285} 286 | 230{ 231 int __user *arguser = (int __user *)arg; 232 struct hsmp_message msg = { 0 }; 233 int ret; 234 235 if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message))) 236 return -EFAULT; 237 --- 39 unchanged lines hidden (view full) --- 277 /* Copy results back to user for get/monitor commands */ 278 if (copy_to_user(arguser, &msg, sizeof(struct hsmp_message))) 279 return -EFAULT; 280 } 281 282 return 0; 283} 284 |
287static const struct file_operations hsmp_fops = { 288 .owner = THIS_MODULE, 289 .unlocked_ioctl = hsmp_ioctl, 290 .compat_ioctl = hsmp_ioctl, 291}; 292 | |
293ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj, 294 struct bin_attribute *bin_attr, char *buf, 295 loff_t off, size_t count) 296{ 297 struct hsmp_socket *sock = bin_attr->private; 298 struct hsmp_message msg = { 0 }; 299 int ret; 300 --- 11 unchanged lines hidden (view full) --- 312 313 ret = hsmp_send_message(&msg); 314 if (ret) 315 return ret; 316 memcpy_fromio(buf, sock->metric_tbl_addr, bin_attr->size); 317 318 return bin_attr->size; 319} | 285ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj, 286 struct bin_attribute *bin_attr, char *buf, 287 loff_t off, size_t count) 288{ 289 struct hsmp_socket *sock = bin_attr->private; 290 struct hsmp_message msg = { 0 }; 291 int ret; 292 --- 11 unchanged lines hidden (view full) --- 304 305 ret = hsmp_send_message(&msg); 306 if (ret) 307 return ret; 308 memcpy_fromio(buf, sock->metric_tbl_addr, bin_attr->size); 309 310 return bin_attr->size; 311} |
312EXPORT_SYMBOL_GPL(hsmp_metric_tbl_read); |
|
320 321static int hsmp_get_tbl_dram_base(u16 sock_ind) 322{ 323 struct hsmp_socket *sock = &hsmp_pdev.sock[sock_ind]; 324 struct hsmp_message msg = { 0 }; 325 phys_addr_t dram_addr; 326 int ret; 327 --- 26 unchanged lines hidden (view full) --- 354umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, 355 struct bin_attribute *battr, int id) 356{ 357 if (hsmp_pdev.proto_ver == HSMP_PROTO_VER6) 358 return battr->attr.mode; 359 else 360 return 0; 361} | 313 314static int hsmp_get_tbl_dram_base(u16 sock_ind) 315{ 316 struct hsmp_socket *sock = &hsmp_pdev.sock[sock_ind]; 317 struct hsmp_message msg = { 0 }; 318 phys_addr_t dram_addr; 319 int ret; 320 --- 26 unchanged lines hidden (view full) --- 347umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, 348 struct bin_attribute *battr, int id) 349{ 350 if (hsmp_pdev.proto_ver == HSMP_PROTO_VER6) 351 return battr->attr.mode; 352 else 353 return 0; 354} |
355EXPORT_SYMBOL_GPL(hsmp_is_sock_attr_visible); |
|
362 363static int hsmp_init_metric_tbl_bin_attr(struct bin_attribute **hattrs, u16 sock_ind) 364{ 365 struct bin_attribute *hattr = &hsmp_pdev.sock[sock_ind].hsmp_attr; 366 367 sysfs_bin_attr_init(hattr); 368 hattr->attr.name = HSMP_METRICS_TABLE_NAME; 369 hattr->attr.mode = 0444; --- 22 unchanged lines hidden (view full) --- 392 GFP_KERNEL); 393 if (!hsmp_bin_attrs) 394 return -ENOMEM; 395 396 attr_grp->bin_attrs = hsmp_bin_attrs; 397 398 return hsmp_init_metric_tbl_bin_attr(hsmp_bin_attrs, sock_ind); 399} | 356 357static int hsmp_init_metric_tbl_bin_attr(struct bin_attribute **hattrs, u16 sock_ind) 358{ 359 struct bin_attribute *hattr = &hsmp_pdev.sock[sock_ind].hsmp_attr; 360 361 sysfs_bin_attr_init(hattr); 362 hattr->attr.name = HSMP_METRICS_TABLE_NAME; 363 hattr->attr.mode = 0444; --- 22 unchanged lines hidden (view full) --- 386 GFP_KERNEL); 387 if (!hsmp_bin_attrs) 388 return -ENOMEM; 389 390 attr_grp->bin_attrs = hsmp_bin_attrs; 391 392 return hsmp_init_metric_tbl_bin_attr(hsmp_bin_attrs, sock_ind); 393} |
394EXPORT_SYMBOL_GPL(hsmp_create_attr_list); |
|
400 401int hsmp_cache_proto_ver(u16 sock_ind) 402{ 403 struct hsmp_message msg = { 0 }; 404 int ret; 405 406 msg.msg_id = HSMP_GET_PROTO_VER; 407 msg.sock_ind = sock_ind; 408 msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; 409 410 ret = hsmp_send_message(&msg); 411 if (!ret) 412 hsmp_pdev.proto_ver = msg.args[0]; 413 414 return ret; 415} | 395 396int hsmp_cache_proto_ver(u16 sock_ind) 397{ 398 struct hsmp_message msg = { 0 }; 399 int ret; 400 401 msg.msg_id = HSMP_GET_PROTO_VER; 402 msg.sock_ind = sock_ind; 403 msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; 404 405 ret = hsmp_send_message(&msg); 406 if (!ret) 407 hsmp_pdev.proto_ver = msg.args[0]; 408 409 return ret; 410} |
411EXPORT_SYMBOL_GPL(hsmp_cache_proto_ver); |
|
416 | 412 |
417static const struct acpi_device_id amd_hsmp_acpi_ids[] = { 418 {ACPI_HSMP_DEVICE_HID, 0}, 419 {} | 413static const struct file_operations hsmp_fops = { 414 .owner = THIS_MODULE, 415 .unlocked_ioctl = hsmp_ioctl, 416 .compat_ioctl = hsmp_ioctl, |
420}; | 417}; |
421MODULE_DEVICE_TABLE(acpi, amd_hsmp_acpi_ids); | |
422 | 418 |
423static bool check_acpi_support(struct device *dev) | 419int hsmp_misc_register(struct device *dev) |
424{ | 420{ |
425 struct acpi_device *adev = ACPI_COMPANION(dev); | 421 hsmp_pdev.mdev.name = HSMP_CDEV_NAME; 422 hsmp_pdev.mdev.minor = MISC_DYNAMIC_MINOR; 423 hsmp_pdev.mdev.fops = &hsmp_fops; 424 hsmp_pdev.mdev.parent = dev; 425 hsmp_pdev.mdev.nodename = HSMP_DEVNODE_NAME; 426 hsmp_pdev.mdev.mode = 0644; |
426 | 427 |
427 if (adev && !acpi_match_device_ids(adev, amd_hsmp_acpi_ids)) 428 return true; 429 430 return false; | 428 return misc_register(&hsmp_pdev.mdev); |
431} | 429} |
430EXPORT_SYMBOL_GPL(hsmp_misc_register); |
|
432 | 431 |
433static int hsmp_pltdrv_probe(struct platform_device *pdev) | 432void hsmp_misc_deregister(void) |
434{ | 433{ |
435 int ret; 436 437 /* 438 * On ACPI supported BIOS, there is an ACPI HSMP device added for 439 * each socket, so the per socket probing, but the memory allocated for 440 * sockets should be contiguous to access it as an array, 441 * Hence allocate memory for all the sockets at once instead of allocating 442 * on each probe. 443 */ 444 if (!hsmp_pdev.is_probed) { 445 hsmp_pdev.sock = devm_kcalloc(&pdev->dev, hsmp_pdev.num_sockets, 446 sizeof(*hsmp_pdev.sock), 447 GFP_KERNEL); 448 if (!hsmp_pdev.sock) 449 return -ENOMEM; 450 } 451 if (check_acpi_support(&pdev->dev)) { 452 ret = init_acpi(&pdev->dev); 453 if (ret) { 454 dev_err(&pdev->dev, "Failed to init HSMP mailbox\n"); 455 return ret; 456 } 457 ret = hsmp_create_acpi_sysfs_if(&pdev->dev); 458 if (ret) 459 dev_err(&pdev->dev, "Failed to create HSMP sysfs interface\n"); 460 } else { 461 ret = init_platform_device(&pdev->dev); 462 if (ret) { 463 dev_err(&pdev->dev, "Failed to init HSMP mailbox\n"); 464 return ret; 465 } 466 ret = hsmp_create_non_acpi_sysfs_if(&pdev->dev); 467 if (ret) 468 dev_err(&pdev->dev, "Failed to create HSMP sysfs interface\n"); 469 } 470 471 if (!hsmp_pdev.is_probed) { 472 hsmp_pdev.mdev.name = HSMP_CDEV_NAME; 473 hsmp_pdev.mdev.minor = MISC_DYNAMIC_MINOR; 474 hsmp_pdev.mdev.fops = &hsmp_fops; 475 hsmp_pdev.mdev.parent = &pdev->dev; 476 hsmp_pdev.mdev.nodename = HSMP_DEVNODE_NAME; 477 hsmp_pdev.mdev.mode = 0644; 478 479 ret = misc_register(&hsmp_pdev.mdev); 480 if (ret) 481 return ret; 482 483 hsmp_pdev.is_probed = true; 484 } 485 486 return 0; 487 | 434 misc_deregister(&hsmp_pdev.mdev); |
488} | 435} |
436EXPORT_SYMBOL_GPL(hsmp_misc_deregister); |
|
489 | 437 |
490static void hsmp_pltdrv_remove(struct platform_device *pdev) 491{ 492 /* 493 * We register only one misc_device even on multi socket system. 494 * So, deregister should happen only once. 495 */ 496 if (hsmp_pdev.is_probed) { 497 misc_deregister(&hsmp_pdev.mdev); 498 hsmp_pdev.is_probed = false; 499 } 500} 501 502static struct platform_driver amd_hsmp_driver = { 503 .probe = hsmp_pltdrv_probe, 504 .remove = hsmp_pltdrv_remove, 505 .driver = { 506 .name = DRIVER_NAME, 507 .acpi_match_table = amd_hsmp_acpi_ids, 508 }, 509}; 510 511static struct platform_device *amd_hsmp_platdev; 512 513static int hsmp_plat_dev_register(void) 514{ 515 int ret; 516 517 amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE); 518 if (!amd_hsmp_platdev) 519 return -ENOMEM; 520 521 ret = platform_device_add(amd_hsmp_platdev); 522 if (ret) 523 platform_device_put(amd_hsmp_platdev); 524 525 return ret; 526} 527 528/* 529 * This check is only needed for backward compatibility of previous platforms. 530 * All new platforms are expected to support ACPI based probing. 531 */ 532static bool legacy_hsmp_support(void) 533{ 534 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 535 return false; 536 537 switch (boot_cpu_data.x86) { 538 case 0x19: 539 switch (boot_cpu_data.x86_model) { 540 case 0x00 ... 0x1F: 541 case 0x30 ... 0x3F: 542 case 0x90 ... 0x9F: 543 case 0xA0 ... 0xAF: 544 return true; 545 default: 546 return false; 547 } 548 case 0x1A: 549 switch (boot_cpu_data.x86_model) { 550 case 0x00 ... 0x1F: 551 return true; 552 default: 553 return false; 554 } 555 default: 556 return false; 557 } 558 559 return false; 560} 561 562static int __init hsmp_plt_init(void) 563{ 564 int ret = -ENODEV; 565 566 /* 567 * amd_nb_num() returns number of SMN/DF interfaces present in the system 568 * if we have N SMN/DF interfaces that ideally means N sockets 569 */ 570 hsmp_pdev.num_sockets = amd_nb_num(); 571 if (hsmp_pdev.num_sockets == 0 || hsmp_pdev.num_sockets > MAX_AMD_SOCKETS) 572 return ret; 573 574 ret = platform_driver_register(&amd_hsmp_driver); 575 if (ret) 576 return ret; 577 578 if (!hsmp_pdev.is_acpi_device) { 579 if (legacy_hsmp_support()) { 580 /* Not ACPI device, but supports HSMP, register a plat_dev */ 581 ret = hsmp_plat_dev_register(); 582 } else { 583 /* Not ACPI, Does not support HSMP */ 584 pr_info("HSMP is not supported on Family:%x model:%x\n", 585 boot_cpu_data.x86, boot_cpu_data.x86_model); 586 ret = -ENODEV; 587 } 588 if (ret) 589 platform_driver_unregister(&amd_hsmp_driver); 590 } 591 592 return ret; 593} 594 595static void __exit hsmp_plt_exit(void) 596{ 597 platform_device_unregister(amd_hsmp_platdev); 598 platform_driver_unregister(&amd_hsmp_driver); 599} 600 601device_initcall(hsmp_plt_init); 602module_exit(hsmp_plt_exit); 603 604MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver"); | 438MODULE_DESCRIPTION("AMD HSMP Common driver"); |
605MODULE_VERSION(DRIVER_VERSION); | 439MODULE_VERSION(DRIVER_VERSION); |
606MODULE_LICENSE("GPL v2"); | 440MODULE_LICENSE("GPL"); |