aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGary R Hook <gary.hook@amd.com>2016-03-01 14:49:04 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2016-03-11 08:19:07 -0500
commit553d2374db0bb3f48bbd29bef7ba2a4d1a3f325d (patch)
tree1a32958d7359b5e46f7e7f613ac180e88eb8a0df
parent3f19ce2054541a6c663c8a5fcf52e7baa1c6c5f5 (diff)
crypto: ccp - Support for multiple CCPs
Enable management of >1 CCPs in a system. Each device will get a unique identifier, as well as uniquely named resources. Treat each CCP as an orthogonal unit and register resources individually. Signed-off-by: Gary R Hook <gary.hook@amd.com> Acked-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--drivers/crypto/ccp/ccp-dev.c113
-rw-r--r--drivers/crypto/ccp/ccp-dev.h9
-rw-r--r--drivers/crypto/ccp/ccp-pci.c7
-rw-r--r--drivers/crypto/ccp/ccp-platform.c4
4 files changed, 114 insertions, 19 deletions
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index 725c59016a36..dd71e673a109 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -16,6 +16,8 @@
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/spinlock.h> 18#include <linux/spinlock.h>
19#include <linux/rwlock_types.h>
20#include <linux/types.h>
19#include <linux/mutex.h> 21#include <linux/mutex.h>
20#include <linux/delay.h> 22#include <linux/delay.h>
21#include <linux/hw_random.h> 23#include <linux/hw_random.h>
@@ -37,20 +39,96 @@ struct ccp_tasklet_data {
37 struct ccp_cmd *cmd; 39 struct ccp_cmd *cmd;
38}; 40};
39 41
40static struct ccp_device *ccp_dev; 42/* List of CCPs, CCP count, read-write access lock, and access functions
41static inline struct ccp_device *ccp_get_device(void) 43 *
44 * Lock structure: get ccp_unit_lock for reading whenever we need to
45 * examine the CCP list. While holding it for reading we can acquire
46 * the RR lock to update the round-robin next-CCP pointer. The unit lock
47 * must be acquired before the RR lock.
48 *
49 * If the unit-lock is acquired for writing, we have total control over
50 * the list, so there's no value in getting the RR lock.
51 */
52static DEFINE_RWLOCK(ccp_unit_lock);
53static LIST_HEAD(ccp_units);
54
55/* Round-robin counter */
56static DEFINE_RWLOCK(ccp_rr_lock);
57static struct ccp_device *ccp_rr;
58
59/* Ever-increasing value to produce unique unit numbers */
60static atomic_t ccp_unit_ordinal;
61unsigned int ccp_increment_unit_ordinal(void)
42{ 62{
43 return ccp_dev; 63 return atomic_inc_return(&ccp_unit_ordinal);
44} 64}
45 65
66/*
67 * Put this CCP on the unit list, which makes it available
68 * for use.
69 */
46static inline void ccp_add_device(struct ccp_device *ccp) 70static inline void ccp_add_device(struct ccp_device *ccp)
47{ 71{
48 ccp_dev = ccp; 72 unsigned long flags;
73
74 write_lock_irqsave(&ccp_unit_lock, flags);
75 list_add_tail(&ccp->entry, &ccp_units);
76 if (!ccp_rr)
77 /* We already have the list lock (we're first) so this
78 * pointer can't change on us. Set its initial value.
79 */
80 ccp_rr = ccp;
81 write_unlock_irqrestore(&ccp_unit_lock, flags);
49} 82}
50 83
84/* Remove this unit from the list of devices. If the next device
85 * up for use is this one, adjust the pointer. If this is the last
86 * device, NULL the pointer.
87 */
51static inline void ccp_del_device(struct ccp_device *ccp) 88static inline void ccp_del_device(struct ccp_device *ccp)
52{ 89{
53 ccp_dev = NULL; 90 unsigned long flags;
91
92 write_lock_irqsave(&ccp_unit_lock, flags);
93 if (ccp_rr == ccp) {
94 /* ccp_unit_lock is read/write; any read access
95 * will be suspended while we make changes to the
96 * list and RR pointer.
97 */
98 if (list_is_last(&ccp_rr->entry, &ccp_units))
99 ccp_rr = list_first_entry(&ccp_units, struct ccp_device,
100 entry);
101 else
102 ccp_rr = list_next_entry(ccp_rr, entry);
103 }
104 list_del(&ccp->entry);
105 if (list_empty(&ccp_units))
106 ccp_rr = NULL;
107 write_unlock_irqrestore(&ccp_unit_lock, flags);
108}
109
110static struct ccp_device *ccp_get_device(void)
111{
112 unsigned long flags;
113 struct ccp_device *dp = NULL;
114
115 /* We round-robin through the unit list.
116 * The (ccp_rr) pointer refers to the next unit to use.
117 */
118 read_lock_irqsave(&ccp_unit_lock, flags);
119 if (!list_empty(&ccp_units)) {
120 write_lock_irqsave(&ccp_rr_lock, flags);
121 dp = ccp_rr;
122 if (list_is_last(&ccp_rr->entry, &ccp_units))
123 ccp_rr = list_first_entry(&ccp_units, struct ccp_device,
124 entry);
125 else
126 ccp_rr = list_next_entry(ccp_rr, entry);
127 write_unlock_irqrestore(&ccp_rr_lock, flags);
128 }
129 read_unlock_irqrestore(&ccp_unit_lock, flags);
130
131 return dp;
54} 132}
55 133
56/** 134/**
@@ -60,10 +138,14 @@ static inline void ccp_del_device(struct ccp_device *ccp)
60 */ 138 */
61int ccp_present(void) 139int ccp_present(void)
62{ 140{
63 if (ccp_get_device()) 141 unsigned long flags;
64 return 0; 142 int ret;
65 143
66 return -ENODEV; 144 read_lock_irqsave(&ccp_unit_lock, flags);
145 ret = list_empty(&ccp_units);
146 read_unlock_irqrestore(&ccp_unit_lock, flags);
147
148 return ret ? -ENODEV : 0;
67} 149}
68EXPORT_SYMBOL_GPL(ccp_present); 150EXPORT_SYMBOL_GPL(ccp_present);
69 151
@@ -309,6 +391,10 @@ struct ccp_device *ccp_alloc_struct(struct device *dev)
309 ccp->ksb_count = KSB_COUNT; 391 ccp->ksb_count = KSB_COUNT;
310 ccp->ksb_start = 0; 392 ccp->ksb_start = 0;
311 393
394 ccp->ord = ccp_increment_unit_ordinal();
395 snprintf(ccp->name, MAX_CCP_NAME_LEN, "ccp-%u", ccp->ord);
396 snprintf(ccp->rngname, MAX_CCP_NAME_LEN, "ccp-%u-rng", ccp->ord);
397
312 return ccp; 398 return ccp;
313} 399}
314 400
@@ -334,7 +420,8 @@ int ccp_init(struct ccp_device *ccp)
334 continue; 420 continue;
335 421
336 /* Allocate a dma pool for this queue */ 422 /* Allocate a dma pool for this queue */
337 snprintf(dma_pool_name, sizeof(dma_pool_name), "ccp_q%d", i); 423 snprintf(dma_pool_name, sizeof(dma_pool_name), "%s_q%d",
424 ccp->name, i);
338 dma_pool = dma_pool_create(dma_pool_name, dev, 425 dma_pool = dma_pool_create(dma_pool_name, dev,
339 CCP_DMAPOOL_MAX_SIZE, 426 CCP_DMAPOOL_MAX_SIZE,
340 CCP_DMAPOOL_ALIGN, 0); 427 CCP_DMAPOOL_ALIGN, 0);
@@ -416,7 +503,7 @@ int ccp_init(struct ccp_device *ccp)
416 cmd_q = &ccp->cmd_q[i]; 503 cmd_q = &ccp->cmd_q[i];
417 504
418 kthread = kthread_create(ccp_cmd_queue_thread, cmd_q, 505 kthread = kthread_create(ccp_cmd_queue_thread, cmd_q,
419 "ccp-q%u", cmd_q->id); 506 "%s-q%u", ccp->name, cmd_q->id);
420 if (IS_ERR(kthread)) { 507 if (IS_ERR(kthread)) {
421 dev_err(dev, "error creating queue thread (%ld)\n", 508 dev_err(dev, "error creating queue thread (%ld)\n",
422 PTR_ERR(kthread)); 509 PTR_ERR(kthread));
@@ -429,7 +516,7 @@ int ccp_init(struct ccp_device *ccp)
429 } 516 }
430 517
431 /* Register the RNG */ 518 /* Register the RNG */
432 ccp->hwrng.name = "ccp-rng"; 519 ccp->hwrng.name = ccp->rngname;
433 ccp->hwrng.read = ccp_trng_read; 520 ccp->hwrng.read = ccp_trng_read;
434 ret = hwrng_register(&ccp->hwrng); 521 ret = hwrng_register(&ccp->hwrng);
435 if (ret) { 522 if (ret) {
@@ -587,7 +674,7 @@ static int __init ccp_mod_init(void)
587 return ret; 674 return ret;
588 675
589 /* Don't leave the driver loaded if init failed */ 676 /* Don't leave the driver loaded if init failed */
590 if (!ccp_get_device()) { 677 if (ccp_present() != 0) {
591 ccp_pci_exit(); 678 ccp_pci_exit();
592 return -ENODEV; 679 return -ENODEV;
593 } 680 }
@@ -603,7 +690,7 @@ static int __init ccp_mod_init(void)
603 return ret; 690 return ret;
604 691
605 /* Don't leave the driver loaded if init failed */ 692 /* Don't leave the driver loaded if init failed */
606 if (!ccp_get_device()) { 693 if (ccp_present() != 0) {
607 ccp_platform_exit(); 694 ccp_platform_exit();
608 return -ENODEV; 695 return -ENODEV;
609 } 696 }
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h
index 6ff89031fb96..974dc055e0ab 100644
--- a/drivers/crypto/ccp/ccp-dev.h
+++ b/drivers/crypto/ccp/ccp-dev.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * AMD Cryptographic Coprocessor (CCP) driver 2 * AMD Cryptographic Coprocessor (CCP) driver
3 * 3 *
4 * Copyright (C) 2013 Advanced Micro Devices, Inc. 4 * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
5 * 5 *
6 * Author: Tom Lendacky <thomas.lendacky@amd.com> 6 * Author: Tom Lendacky <thomas.lendacky@amd.com>
7 * 7 *
@@ -23,6 +23,7 @@
23#include <linux/hw_random.h> 23#include <linux/hw_random.h>
24#include <linux/bitops.h> 24#include <linux/bitops.h>
25 25
26#define MAX_CCP_NAME_LEN 16
26#define MAX_DMAPOOL_NAME_LEN 32 27#define MAX_DMAPOOL_NAME_LEN 32
27 28
28#define MAX_HW_QUEUES 5 29#define MAX_HW_QUEUES 5
@@ -184,6 +185,12 @@ struct ccp_cmd_queue {
184} ____cacheline_aligned; 185} ____cacheline_aligned;
185 186
186struct ccp_device { 187struct ccp_device {
188 struct list_head entry;
189
190 unsigned int ord;
191 char name[MAX_CCP_NAME_LEN];
192 char rngname[MAX_CCP_NAME_LEN];
193
187 struct device *dev; 194 struct device *dev;
188 195
189 /* 196 /*
diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c
index 7690467c42f8..668e5154beb3 100644
--- a/drivers/crypto/ccp/ccp-pci.c
+++ b/drivers/crypto/ccp/ccp-pci.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * AMD Cryptographic Coprocessor (CCP) driver 2 * AMD Cryptographic Coprocessor (CCP) driver
3 * 3 *
4 * Copyright (C) 2013 Advanced Micro Devices, Inc. 4 * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
5 * 5 *
6 * Author: Tom Lendacky <thomas.lendacky@amd.com> 6 * Author: Tom Lendacky <thomas.lendacky@amd.com>
7 * 7 *
@@ -59,7 +59,8 @@ static int ccp_get_msix_irqs(struct ccp_device *ccp)
59 ccp_pci->msix_count = ret; 59 ccp_pci->msix_count = ret;
60 for (v = 0; v < ccp_pci->msix_count; v++) { 60 for (v = 0; v < ccp_pci->msix_count; v++) {
61 /* Set the interrupt names and request the irqs */ 61 /* Set the interrupt names and request the irqs */
62 snprintf(ccp_pci->msix[v].name, name_len, "ccp-%u", v); 62 snprintf(ccp_pci->msix[v].name, name_len, "%s-%u",
63 ccp->name, v);
63 ccp_pci->msix[v].vector = msix_entry[v].vector; 64 ccp_pci->msix[v].vector = msix_entry[v].vector;
64 ret = request_irq(ccp_pci->msix[v].vector, ccp_irq_handler, 65 ret = request_irq(ccp_pci->msix[v].vector, ccp_irq_handler,
65 0, ccp_pci->msix[v].name, dev); 66 0, ccp_pci->msix[v].name, dev);
@@ -94,7 +95,7 @@ static int ccp_get_msi_irq(struct ccp_device *ccp)
94 return ret; 95 return ret;
95 96
96 ccp->irq = pdev->irq; 97 ccp->irq = pdev->irq;
97 ret = request_irq(ccp->irq, ccp_irq_handler, 0, "ccp", dev); 98 ret = request_irq(ccp->irq, ccp_irq_handler, 0, ccp->name, dev);
98 if (ret) { 99 if (ret) {
99 dev_notice(dev, "unable to allocate MSI IRQ (%d)\n", ret); 100 dev_notice(dev, "unable to allocate MSI IRQ (%d)\n", ret);
100 goto e_msi; 101 goto e_msi;
diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c
index 66dd7c9d08c3..4331318b57b2 100644
--- a/drivers/crypto/ccp/ccp-platform.c
+++ b/drivers/crypto/ccp/ccp-platform.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * AMD Cryptographic Coprocessor (CCP) driver 2 * AMD Cryptographic Coprocessor (CCP) driver
3 * 3 *
4 * Copyright (C) 2014 Advanced Micro Devices, Inc. 4 * Copyright (C) 2014,2016 Advanced Micro Devices, Inc.
5 * 5 *
6 * Author: Tom Lendacky <thomas.lendacky@amd.com> 6 * Author: Tom Lendacky <thomas.lendacky@amd.com>
7 * 7 *
@@ -43,7 +43,7 @@ static int ccp_get_irq(struct ccp_device *ccp)
43 return ret; 43 return ret;
44 44
45 ccp->irq = ret; 45 ccp->irq = ret;
46 ret = request_irq(ccp->irq, ccp_irq_handler, 0, "ccp", dev); 46 ret = request_irq(ccp->irq, ccp_irq_handler, 0, ccp->name, dev);
47 if (ret) { 47 if (ret) {
48 dev_notice(dev, "unable to allocate IRQ (%d)\n", ret); 48 dev_notice(dev, "unable to allocate IRQ (%d)\n", ret);
49 return ret; 49 return ret;