.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * AMD Cryptographic Coprocessor (CCP) driver |
---|
3 | 4 | * |
---|
4 | | - * Copyright (C) 2013,2017 Advanced Micro Devices, Inc. |
---|
| 5 | + * Copyright (C) 2013,2019 Advanced Micro Devices, Inc. |
---|
5 | 6 | * |
---|
6 | 7 | * Author: Tom Lendacky <thomas.lendacky@amd.com> |
---|
7 | 8 | * Author: Gary R Hook <gary.hook@amd.com> |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License version 2 as |
---|
11 | | - * published by the Free Software Foundation. |
---|
12 | 9 | */ |
---|
13 | 10 | |
---|
| 11 | +#include <linux/module.h> |
---|
14 | 12 | #include <linux/kernel.h> |
---|
15 | 13 | #include <linux/kthread.h> |
---|
16 | 14 | #include <linux/sched.h> |
---|
.. | .. |
---|
22 | 20 | #include <linux/delay.h> |
---|
23 | 21 | #include <linux/hw_random.h> |
---|
24 | 22 | #include <linux/cpu.h> |
---|
| 23 | +#include <linux/atomic.h> |
---|
25 | 24 | #ifdef CONFIG_X86 |
---|
26 | 25 | #include <asm/cpu_device_id.h> |
---|
27 | 26 | #endif |
---|
28 | 27 | #include <linux/ccp.h> |
---|
29 | 28 | |
---|
30 | 29 | #include "ccp-dev.h" |
---|
| 30 | + |
---|
| 31 | +#define MAX_CCPS 32 |
---|
| 32 | + |
---|
| 33 | +/* Limit CCP use to a specifed number of queues per device */ |
---|
| 34 | +static unsigned int nqueues = 0; |
---|
| 35 | +module_param(nqueues, uint, 0444); |
---|
| 36 | +MODULE_PARM_DESC(nqueues, "Number of queues per CCP (minimum 1; default: all available)"); |
---|
| 37 | + |
---|
| 38 | +/* Limit the maximum number of configured CCPs */ |
---|
| 39 | +static atomic_t dev_count = ATOMIC_INIT(0); |
---|
| 40 | +static unsigned int max_devs = MAX_CCPS; |
---|
| 41 | +module_param(max_devs, uint, 0444); |
---|
| 42 | +MODULE_PARM_DESC(max_devs, "Maximum number of CCPs to enable (default: all; 0 disables all CCPs)"); |
---|
31 | 43 | |
---|
32 | 44 | struct ccp_tasklet_data { |
---|
33 | 45 | struct completion completion; |
---|
.. | .. |
---|
519 | 531 | return len; |
---|
520 | 532 | } |
---|
521 | 533 | |
---|
522 | | -#ifdef CONFIG_PM |
---|
523 | 534 | bool ccp_queues_suspended(struct ccp_device *ccp) |
---|
524 | 535 | { |
---|
525 | 536 | unsigned int suspended = 0; |
---|
.. | .. |
---|
537 | 548 | return ccp->cmd_q_count == suspended; |
---|
538 | 549 | } |
---|
539 | 550 | |
---|
540 | | -int ccp_dev_suspend(struct sp_device *sp, pm_message_t state) |
---|
| 551 | +int ccp_dev_suspend(struct sp_device *sp) |
---|
541 | 552 | { |
---|
542 | 553 | struct ccp_device *ccp = sp->ccp_data; |
---|
543 | 554 | unsigned long flags; |
---|
.. | .. |
---|
589 | 600 | |
---|
590 | 601 | return 0; |
---|
591 | 602 | } |
---|
592 | | -#endif |
---|
593 | 603 | |
---|
594 | 604 | int ccp_dev_init(struct sp_device *sp) |
---|
595 | 605 | { |
---|
.. | .. |
---|
597 | 607 | struct ccp_device *ccp; |
---|
598 | 608 | int ret; |
---|
599 | 609 | |
---|
| 610 | + /* |
---|
| 611 | + * Check how many we have so far, and stop after reaching |
---|
| 612 | + * that number |
---|
| 613 | + */ |
---|
| 614 | + if (atomic_inc_return(&dev_count) > max_devs) |
---|
| 615 | + return 0; /* don't fail the load */ |
---|
| 616 | + |
---|
600 | 617 | ret = -ENOMEM; |
---|
601 | 618 | ccp = ccp_alloc_struct(sp); |
---|
602 | 619 | if (!ccp) |
---|
603 | 620 | goto e_err; |
---|
604 | 621 | sp->ccp_data = ccp; |
---|
| 622 | + |
---|
| 623 | + if (!nqueues || (nqueues > MAX_HW_QUEUES)) |
---|
| 624 | + ccp->max_q_count = MAX_HW_QUEUES; |
---|
| 625 | + else |
---|
| 626 | + ccp->max_q_count = nqueues; |
---|
605 | 627 | |
---|
606 | 628 | ccp->vdata = (struct ccp_vdata *)sp->dev_vdata->ccp_vdata; |
---|
607 | 629 | if (!ccp->vdata || !ccp->vdata->version) { |
---|
.. | .. |
---|
617 | 639 | ccp->vdata->setup(ccp); |
---|
618 | 640 | |
---|
619 | 641 | ret = ccp->vdata->perform->init(ccp); |
---|
620 | | - if (ret) |
---|
| 642 | + if (ret) { |
---|
| 643 | + /* A positive number means that the device cannot be initialized, |
---|
| 644 | + * but no additional message is required. |
---|
| 645 | + */ |
---|
| 646 | + if (ret > 0) |
---|
| 647 | + goto e_quiet; |
---|
| 648 | + |
---|
| 649 | + /* An unexpected problem occurred, and should be reported in the log */ |
---|
621 | 650 | goto e_err; |
---|
| 651 | + } |
---|
622 | 652 | |
---|
623 | 653 | dev_notice(dev, "ccp enabled\n"); |
---|
624 | 654 | |
---|
625 | 655 | return 0; |
---|
626 | 656 | |
---|
627 | 657 | e_err: |
---|
628 | | - sp->ccp_data = NULL; |
---|
629 | | - |
---|
630 | 658 | dev_notice(dev, "ccp initialization failed\n"); |
---|
631 | 659 | |
---|
| 660 | +e_quiet: |
---|
| 661 | + sp->ccp_data = NULL; |
---|
| 662 | + |
---|
632 | 663 | return ret; |
---|
633 | 664 | } |
---|
634 | 665 | |
---|