diff options
author | Tom Lendacky <thomas.lendacky@amd.com> | 2014-06-05 11:17:57 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2014-06-20 09:26:14 -0400 |
commit | c4f4b325e9c885b11901174158d5e1ff4b19a189 (patch) | |
tree | 5dd00e9be91a839fc563f8d035f792833afbbbae /drivers/crypto | |
parent | 1ad348f4510f57163e4790ad202c81908d223edc (diff) |
crypto: ccp - Add platform device support for arm64
Add support for the CCP on arm64 as a platform device.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/Kconfig | 2 | ||||
-rw-r--r-- | drivers/crypto/ccp/Makefile | 5 | ||||
-rw-r--r-- | drivers/crypto/ccp/ccp-dev.c | 34 | ||||
-rw-r--r-- | drivers/crypto/ccp/ccp-dev.h | 7 | ||||
-rw-r--r-- | drivers/crypto/ccp/ccp-platform.c | 224 |
5 files changed, 270 insertions, 2 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 02f177aeb16c..30756bd1a8c4 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig | |||
@@ -391,7 +391,7 @@ config CRYPTO_DEV_ATMEL_SHA | |||
391 | 391 | ||
392 | config CRYPTO_DEV_CCP | 392 | config CRYPTO_DEV_CCP |
393 | bool "Support for AMD Cryptographic Coprocessor" | 393 | bool "Support for AMD Cryptographic Coprocessor" |
394 | depends on X86 && PCI | 394 | depends on (X86 && PCI) || ARM64 |
395 | default n | 395 | default n |
396 | help | 396 | help |
397 | The AMD Cryptographic Coprocessor provides hardware support | 397 | The AMD Cryptographic Coprocessor provides hardware support |
diff --git a/drivers/crypto/ccp/Makefile b/drivers/crypto/ccp/Makefile index d3505a018720..7f592d8d07bb 100644 --- a/drivers/crypto/ccp/Makefile +++ b/drivers/crypto/ccp/Makefile | |||
@@ -1,6 +1,11 @@ | |||
1 | obj-$(CONFIG_CRYPTO_DEV_CCP_DD) += ccp.o | 1 | obj-$(CONFIG_CRYPTO_DEV_CCP_DD) += ccp.o |
2 | ccp-objs := ccp-dev.o ccp-ops.o | 2 | ccp-objs := ccp-dev.o ccp-ops.o |
3 | ifdef CONFIG_X86 | ||
3 | ccp-objs += ccp-pci.o | 4 | ccp-objs += ccp-pci.o |
5 | endif | ||
6 | ifdef CONFIG_ARM64 | ||
7 | ccp-objs += ccp-platform.o | ||
8 | endif | ||
4 | 9 | ||
5 | obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o | 10 | obj-$(CONFIG_CRYPTO_DEV_CCP_CRYPTO) += ccp-crypto.o |
6 | ccp-crypto-objs := ccp-crypto-main.o \ | 11 | ccp-crypto-objs := ccp-crypto-main.o \ |
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index 2c7816149b01..fa1ab10f960f 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c | |||
@@ -20,7 +20,9 @@ | |||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/hw_random.h> | 21 | #include <linux/hw_random.h> |
22 | #include <linux/cpu.h> | 22 | #include <linux/cpu.h> |
23 | #ifdef CONFIG_X86 | ||
23 | #include <asm/cpu_device_id.h> | 24 | #include <asm/cpu_device_id.h> |
25 | #endif | ||
24 | #include <linux/ccp.h> | 26 | #include <linux/ccp.h> |
25 | 27 | ||
26 | #include "ccp-dev.h" | 28 | #include "ccp-dev.h" |
@@ -360,6 +362,12 @@ int ccp_init(struct ccp_device *ccp) | |||
360 | /* Build queue interrupt mask (two interrupts per queue) */ | 362 | /* Build queue interrupt mask (two interrupts per queue) */ |
361 | qim |= cmd_q->int_ok | cmd_q->int_err; | 363 | qim |= cmd_q->int_ok | cmd_q->int_err; |
362 | 364 | ||
365 | #ifdef CONFIG_ARM64 | ||
366 | /* For arm64 set the recommended queue cache settings */ | ||
367 | iowrite32(CACHE_WB_NO_ALLOC, ccp->io_regs + CMD_Q_CACHE_BASE + | ||
368 | (CMD_Q_CACHE_INC * i)); | ||
369 | #endif | ||
370 | |||
363 | dev_dbg(dev, "queue #%u available\n", i); | 371 | dev_dbg(dev, "queue #%u available\n", i); |
364 | } | 372 | } |
365 | if (ccp->cmd_q_count == 0) { | 373 | if (ccp->cmd_q_count == 0) { |
@@ -558,12 +566,15 @@ bool ccp_queues_suspended(struct ccp_device *ccp) | |||
558 | } | 566 | } |
559 | #endif | 567 | #endif |
560 | 568 | ||
569 | #ifdef CONFIG_X86 | ||
561 | static const struct x86_cpu_id ccp_support[] = { | 570 | static const struct x86_cpu_id ccp_support[] = { |
562 | { X86_VENDOR_AMD, 22, }, | 571 | { X86_VENDOR_AMD, 22, }, |
563 | }; | 572 | }; |
573 | #endif | ||
564 | 574 | ||
565 | static int __init ccp_mod_init(void) | 575 | static int __init ccp_mod_init(void) |
566 | { | 576 | { |
577 | #ifdef CONFIG_X86 | ||
567 | struct cpuinfo_x86 *cpuinfo = &boot_cpu_data; | 578 | struct cpuinfo_x86 *cpuinfo = &boot_cpu_data; |
568 | int ret; | 579 | int ret; |
569 | 580 | ||
@@ -589,12 +600,30 @@ static int __init ccp_mod_init(void) | |||
589 | 600 | ||
590 | break; | 601 | break; |
591 | } | 602 | } |
603 | #endif | ||
604 | |||
605 | #ifdef CONFIG_ARM64 | ||
606 | int ret; | ||
607 | |||
608 | ret = ccp_platform_init(); | ||
609 | if (ret) | ||
610 | return ret; | ||
611 | |||
612 | /* Don't leave the driver loaded if init failed */ | ||
613 | if (!ccp_get_device()) { | ||
614 | ccp_platform_exit(); | ||
615 | return -ENODEV; | ||
616 | } | ||
617 | |||
618 | return 0; | ||
619 | #endif | ||
592 | 620 | ||
593 | return -ENODEV; | 621 | return -ENODEV; |
594 | } | 622 | } |
595 | 623 | ||
596 | static void __exit ccp_mod_exit(void) | 624 | static void __exit ccp_mod_exit(void) |
597 | { | 625 | { |
626 | #ifdef CONFIG_X86 | ||
598 | struct cpuinfo_x86 *cpuinfo = &boot_cpu_data; | 627 | struct cpuinfo_x86 *cpuinfo = &boot_cpu_data; |
599 | 628 | ||
600 | switch (cpuinfo->x86) { | 629 | switch (cpuinfo->x86) { |
@@ -602,6 +631,11 @@ static void __exit ccp_mod_exit(void) | |||
602 | ccp_pci_exit(); | 631 | ccp_pci_exit(); |
603 | break; | 632 | break; |
604 | } | 633 | } |
634 | #endif | ||
635 | |||
636 | #ifdef CONFIG_ARM64 | ||
637 | ccp_platform_exit(); | ||
638 | #endif | ||
605 | } | 639 | } |
606 | 640 | ||
607 | module_init(ccp_mod_init); | 641 | module_init(ccp_mod_init); |
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 72bf1536b653..1c5651b09506 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h | |||
@@ -30,6 +30,8 @@ | |||
30 | 30 | ||
31 | #define TRNG_RETRIES 10 | 31 | #define TRNG_RETRIES 10 |
32 | 32 | ||
33 | #define CACHE_WB_NO_ALLOC 0xb7 | ||
34 | |||
33 | 35 | ||
34 | /****** Register Mappings ******/ | 36 | /****** Register Mappings ******/ |
35 | #define Q_MASK_REG 0x000 | 37 | #define Q_MASK_REG 0x000 |
@@ -48,7 +50,7 @@ | |||
48 | #define CMD_Q_INT_STATUS_BASE 0x214 | 50 | #define CMD_Q_INT_STATUS_BASE 0x214 |
49 | #define CMD_Q_STATUS_INCR 0x20 | 51 | #define CMD_Q_STATUS_INCR 0x20 |
50 | 52 | ||
51 | #define CMD_Q_CACHE 0x228 | 53 | #define CMD_Q_CACHE_BASE 0x228 |
52 | #define CMD_Q_CACHE_INC 0x20 | 54 | #define CMD_Q_CACHE_INC 0x20 |
53 | 55 | ||
54 | #define CMD_Q_ERROR(__qs) ((__qs) & 0x0000003f); | 56 | #define CMD_Q_ERROR(__qs) ((__qs) & 0x0000003f); |
@@ -259,6 +261,9 @@ struct ccp_device { | |||
259 | int ccp_pci_init(void); | 261 | int ccp_pci_init(void); |
260 | void ccp_pci_exit(void); | 262 | void ccp_pci_exit(void); |
261 | 263 | ||
264 | int ccp_platform_init(void); | ||
265 | void ccp_platform_exit(void); | ||
266 | |||
262 | struct ccp_device *ccp_alloc_struct(struct device *dev); | 267 | struct ccp_device *ccp_alloc_struct(struct device *dev); |
263 | int ccp_init(struct ccp_device *ccp); | 268 | int ccp_init(struct ccp_device *ccp); |
264 | void ccp_destroy(struct ccp_device *ccp); | 269 | void ccp_destroy(struct ccp_device *ccp); |
diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c new file mode 100644 index 000000000000..65e58291c668 --- /dev/null +++ b/drivers/crypto/ccp/ccp-platform.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * AMD Cryptographic Coprocessor (CCP) driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Advanced Micro Devices, Inc. | ||
5 | * | ||
6 | * Author: Tom Lendacky <thomas.lendacky@amd.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/dma-mapping.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/ccp.h> | ||
25 | |||
26 | #include "ccp-dev.h" | ||
27 | |||
28 | |||
29 | static int ccp_get_irq(struct ccp_device *ccp) | ||
30 | { | ||
31 | struct device *dev = ccp->dev; | ||
32 | struct platform_device *pdev = container_of(dev, | ||
33 | struct platform_device, dev); | ||
34 | int ret; | ||
35 | |||
36 | ret = platform_get_irq(pdev, 0); | ||
37 | if (ret < 0) | ||
38 | return ret; | ||
39 | |||
40 | ccp->irq = ret; | ||
41 | ret = request_irq(ccp->irq, ccp_irq_handler, 0, "ccp", dev); | ||
42 | if (ret) { | ||
43 | dev_notice(dev, "unable to allocate IRQ (%d)\n", ret); | ||
44 | return ret; | ||
45 | } | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static int ccp_get_irqs(struct ccp_device *ccp) | ||
51 | { | ||
52 | struct device *dev = ccp->dev; | ||
53 | int ret; | ||
54 | |||
55 | ret = ccp_get_irq(ccp); | ||
56 | if (!ret) | ||
57 | return 0; | ||
58 | |||
59 | /* Couldn't get an interrupt */ | ||
60 | dev_notice(dev, "could not enable interrupts (%d)\n", ret); | ||
61 | |||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | static void ccp_free_irqs(struct ccp_device *ccp) | ||
66 | { | ||
67 | struct device *dev = ccp->dev; | ||
68 | |||
69 | free_irq(ccp->irq, dev); | ||
70 | } | ||
71 | |||
72 | static struct resource *ccp_find_mmio_area(struct ccp_device *ccp) | ||
73 | { | ||
74 | struct device *dev = ccp->dev; | ||
75 | struct platform_device *pdev = container_of(dev, | ||
76 | struct platform_device, dev); | ||
77 | struct resource *ior; | ||
78 | |||
79 | ior = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
80 | if (ior && (resource_size(ior) >= 0x800)) | ||
81 | return ior; | ||
82 | |||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | static int ccp_platform_probe(struct platform_device *pdev) | ||
87 | { | ||
88 | struct ccp_device *ccp; | ||
89 | struct device *dev = &pdev->dev; | ||
90 | struct resource *ior; | ||
91 | int ret; | ||
92 | |||
93 | ret = -ENOMEM; | ||
94 | ccp = ccp_alloc_struct(dev); | ||
95 | if (!ccp) | ||
96 | goto e_err; | ||
97 | |||
98 | ccp->dev_specific = NULL; | ||
99 | ccp->get_irq = ccp_get_irqs; | ||
100 | ccp->free_irq = ccp_free_irqs; | ||
101 | |||
102 | ior = ccp_find_mmio_area(ccp); | ||
103 | ccp->io_map = devm_ioremap_resource(dev, ior); | ||
104 | if (IS_ERR(ccp->io_map)) { | ||
105 | ret = PTR_ERR(ccp->io_map); | ||
106 | goto e_free; | ||
107 | } | ||
108 | ccp->io_regs = ccp->io_map; | ||
109 | |||
110 | if (!dev->dma_mask) | ||
111 | dev->dma_mask = &dev->coherent_dma_mask; | ||
112 | *(dev->dma_mask) = DMA_BIT_MASK(48); | ||
113 | dev->coherent_dma_mask = DMA_BIT_MASK(48); | ||
114 | |||
115 | dev_set_drvdata(dev, ccp); | ||
116 | |||
117 | ret = ccp_init(ccp); | ||
118 | if (ret) | ||
119 | goto e_free; | ||
120 | |||
121 | dev_notice(dev, "enabled\n"); | ||
122 | |||
123 | return 0; | ||
124 | |||
125 | e_free: | ||
126 | kfree(ccp); | ||
127 | |||
128 | e_err: | ||
129 | dev_notice(dev, "initialization failed\n"); | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static int ccp_platform_remove(struct platform_device *pdev) | ||
134 | { | ||
135 | struct device *dev = &pdev->dev; | ||
136 | struct ccp_device *ccp = dev_get_drvdata(dev); | ||
137 | |||
138 | ccp_destroy(ccp); | ||
139 | |||
140 | kfree(ccp); | ||
141 | |||
142 | dev_notice(dev, "disabled\n"); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | #ifdef CONFIG_PM | ||
148 | static int ccp_platform_suspend(struct platform_device *pdev, | ||
149 | pm_message_t state) | ||
150 | { | ||
151 | struct device *dev = &pdev->dev; | ||
152 | struct ccp_device *ccp = dev_get_drvdata(dev); | ||
153 | unsigned long flags; | ||
154 | unsigned int i; | ||
155 | |||
156 | spin_lock_irqsave(&ccp->cmd_lock, flags); | ||
157 | |||
158 | ccp->suspending = 1; | ||
159 | |||
160 | /* Wake all the queue kthreads to prepare for suspend */ | ||
161 | for (i = 0; i < ccp->cmd_q_count; i++) | ||
162 | wake_up_process(ccp->cmd_q[i].kthread); | ||
163 | |||
164 | spin_unlock_irqrestore(&ccp->cmd_lock, flags); | ||
165 | |||
166 | /* Wait for all queue kthreads to say they're done */ | ||
167 | while (!ccp_queues_suspended(ccp)) | ||
168 | wait_event_interruptible(ccp->suspend_queue, | ||
169 | ccp_queues_suspended(ccp)); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int ccp_platform_resume(struct platform_device *pdev) | ||
175 | { | ||
176 | struct device *dev = &pdev->dev; | ||
177 | struct ccp_device *ccp = dev_get_drvdata(dev); | ||
178 | unsigned long flags; | ||
179 | unsigned int i; | ||
180 | |||
181 | spin_lock_irqsave(&ccp->cmd_lock, flags); | ||
182 | |||
183 | ccp->suspending = 0; | ||
184 | |||
185 | /* Wake up all the kthreads */ | ||
186 | for (i = 0; i < ccp->cmd_q_count; i++) { | ||
187 | ccp->cmd_q[i].suspended = 0; | ||
188 | wake_up_process(ccp->cmd_q[i].kthread); | ||
189 | } | ||
190 | |||
191 | spin_unlock_irqrestore(&ccp->cmd_lock, flags); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | #endif | ||
196 | |||
197 | static const struct of_device_id ccp_platform_ids[] = { | ||
198 | { .compatible = "amd,ccp-seattle-v1a" }, | ||
199 | { }, | ||
200 | }; | ||
201 | |||
202 | static struct platform_driver ccp_platform_driver = { | ||
203 | .driver = { | ||
204 | .name = "AMD Cryptographic Coprocessor", | ||
205 | .owner = THIS_MODULE, | ||
206 | .of_match_table = ccp_platform_ids, | ||
207 | }, | ||
208 | .probe = ccp_platform_probe, | ||
209 | .remove = ccp_platform_remove, | ||
210 | #ifdef CONFIG_PM | ||
211 | .suspend = ccp_platform_suspend, | ||
212 | .resume = ccp_platform_resume, | ||
213 | #endif | ||
214 | }; | ||
215 | |||
216 | int ccp_platform_init(void) | ||
217 | { | ||
218 | return platform_driver_register(&ccp_platform_driver); | ||
219 | } | ||
220 | |||
221 | void ccp_platform_exit(void) | ||
222 | { | ||
223 | platform_driver_unregister(&ccp_platform_driver); | ||
224 | } | ||