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");