1
2
3
4
5
6
7#include <crypto/aes.h>
8#include <crypto/scatterwalk.h>
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/of_device.h>
12#include <linux/scatterlist.h>
13#include <linux/spinlock.h>
14#include <linux/firmware/xlnx-zynqmp.h>
15
16#define ZYNQMP_AES_QUEUE_LENGTH 1
17#define ZYNQMP_AES_IV_SIZE 12
18#define ZYNQMP_AES_GCM_SIZE 16
19#define ZYNQMP_AES_KEY_SIZE 32
20
21#define ZYNQMP_AES_DECRYPT 0
22#define ZYNQMP_AES_ENCRYPT 1
23
24#define ZYNQMP_AES_KUP_KEY 0
25
26#define ZYNQMP_AES_GCM_TAG_MISMATCH_ERR 0x01
27#define ZYNQMP_AES_SIZE_ERR 0x06
28#define ZYNQMP_AES_WRONG_KEY_SRC_ERR 0x13
29#define ZYNQMP_AES_PUF_NOT_PROGRAMMED 0xE300
30
31#define ZYNQMP_AES_BLOCKSIZE 0x04
32
33struct zynqmp_aes_dev {
34 struct list_head list;
35 struct device *dev;
36
37 spinlock_t lock;
38 struct crypto_queue queue;
39};
40
41struct zynqmp_aes_op {
42 struct zynqmp_aes_dev *dd;
43 void *src;
44 void *dst;
45 int len;
46 u8 key[ZYNQMP_AES_KEY_SIZE];
47 u8 *iv;
48 u32 keylen;
49 u32 keytype;
50};
51
52struct zynqmp_aes_data {
53 u64 src;
54 u64 iv;
55 u64 key;
56 u64 dst;
57 u64 size;
58 u64 optype;
59 u64 keysrc;
60};
61
62struct zynqmp_aes_drv {
63 struct list_head dev_list;
64
65 spinlock_t lock;
66};
67
68static struct zynqmp_aes_drv zynqmp_aes = {
69 .dev_list = LIST_HEAD_INIT(zynqmp_aes.dev_list),
70 .lock = __SPIN_LOCK_UNLOCKED(zynqmp_aes.lock),
71};
72
73static const struct zynqmp_eemi_ops *eemi_ops;
74
75static struct zynqmp_aes_dev *zynqmp_aes_find_dev(struct zynqmp_aes_op *ctx)
76{
77 struct zynqmp_aes_dev *aes_dd = NULL;
78 struct zynqmp_aes_dev *tmp;
79
80 spin_lock_bh(&zynqmp_aes.lock);
81 if (!ctx->dd) {
82 list_for_each_entry(tmp, &zynqmp_aes.dev_list, list) {
83 aes_dd = tmp;
84 break;
85 }
86 ctx->dd = aes_dd;
87 } else {
88 aes_dd = ctx->dd;
89 }
90 spin_unlock_bh(&zynqmp_aes.lock);
91
92 return aes_dd;
93}
94
95static int zynqmp_setkey_blk(struct crypto_tfm *tfm, const u8 *key,
96 unsigned int len)
97{
98 struct zynqmp_aes_op *op = crypto_tfm_ctx(tfm);
99
100 op->keylen = len;
101 memcpy(op->key, key, len);
102
103 return 0;
104}
105
106static int zynqmp_setkeytype(struct crypto_tfm *tfm, const u8 *keytype,
107 unsigned int len)
108{
109 struct zynqmp_aes_op *op = crypto_tfm_ctx(tfm);
110
111 op->keytype = (u32)(*keytype);
112
113 return 0;
114}
115
116static int zynqmp_aes_xcrypt(struct blkcipher_desc *desc,
117 struct scatterlist *dst,
118 struct scatterlist *src,
119 unsigned int nbytes,
120 unsigned int flags)
121{
122 struct zynqmp_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
123 struct zynqmp_aes_dev *dd = zynqmp_aes_find_dev(op);
124 int err, ret, copy_bytes, src_data = 0, dst_data = 0;
125 dma_addr_t dma_addr, dma_addr_buf;
126 struct zynqmp_aes_data *abuf;
127 struct blkcipher_walk walk;
128 unsigned int data_size;
129 size_t dma_size;
130 char *kbuf;
131
132 if (!eemi_ops->aes)
133 return -ENOTSUPP;
134
135 if (op->keytype == ZYNQMP_AES_KUP_KEY)
136 dma_size = nbytes + ZYNQMP_AES_KEY_SIZE
137 + ZYNQMP_AES_IV_SIZE;
138 else
139 dma_size = nbytes + ZYNQMP_AES_IV_SIZE;
140
141 kbuf = dma_alloc_coherent(dd->dev, dma_size, &dma_addr, GFP_KERNEL);
142 if (!kbuf)
143 return -ENOMEM;
144
145 abuf = dma_alloc_coherent(dd->dev, sizeof(struct zynqmp_aes_data),
146 &dma_addr_buf, GFP_KERNEL);
147 if (!abuf) {
148 dma_free_coherent(dd->dev, dma_size, kbuf, dma_addr);
149 return -ENOMEM;
150 }
151
152 data_size = nbytes;
153 blkcipher_walk_init(&walk, dst, src, data_size);
154 err = blkcipher_walk_virt(desc, &walk);
155 op->iv = walk.iv;
156
157 while ((nbytes = walk.nbytes)) {
158 op->src = walk.src.virt.addr;
159 memcpy(kbuf + src_data, op->src, nbytes);
160 src_data = src_data + nbytes;
161 nbytes &= (ZYNQMP_AES_BLOCKSIZE - 1);
162 err = blkcipher_walk_done(desc, &walk, nbytes);
163 }
164 memcpy(kbuf + data_size, op->iv, ZYNQMP_AES_IV_SIZE);
165 abuf->src = dma_addr;
166 abuf->dst = dma_addr;
167 abuf->iv = abuf->src + data_size;
168 abuf->size = data_size - ZYNQMP_AES_GCM_SIZE;
169 abuf->optype = flags;
170 abuf->keysrc = op->keytype;
171
172 if (op->keytype == ZYNQMP_AES_KUP_KEY) {
173 memcpy(kbuf + data_size + ZYNQMP_AES_IV_SIZE,
174 op->key, ZYNQMP_AES_KEY_SIZE);
175
176 abuf->key = abuf->src + data_size + ZYNQMP_AES_IV_SIZE;
177 } else {
178 abuf->key = 0;
179 }
180 eemi_ops->aes(dma_addr_buf, &ret);
181
182 if (ret != 0) {
183 switch (ret) {
184 case ZYNQMP_AES_GCM_TAG_MISMATCH_ERR:
185 dev_err(dd->dev, "ERROR: Gcm Tag mismatch\n\r");
186 break;
187 case ZYNQMP_AES_SIZE_ERR:
188 dev_err(dd->dev, "ERROR : Non word aligned data\n\r");
189 break;
190 case ZYNQMP_AES_WRONG_KEY_SRC_ERR:
191 dev_err(dd->dev, "ERROR: Wrong KeySrc, enable secure mode\n\r");
192 break;
193 case ZYNQMP_AES_PUF_NOT_PROGRAMMED:
194 dev_err(dd->dev, "ERROR: PUF is not registered\r\n");
195 break;
196 default:
197 dev_err(dd->dev, "ERROR: Invalid");
198 break;
199 }
200 goto END;
201 }
202 if (flags)
203 copy_bytes = data_size;
204 else
205 copy_bytes = data_size - ZYNQMP_AES_GCM_SIZE;
206
207 blkcipher_walk_init(&walk, dst, src, copy_bytes);
208 err = blkcipher_walk_virt(desc, &walk);
209
210 while ((nbytes = walk.nbytes)) {
211 memcpy(walk.dst.virt.addr, kbuf + dst_data, nbytes);
212 dst_data = dst_data + nbytes;
213 nbytes &= (ZYNQMP_AES_BLOCKSIZE - 1);
214 err = blkcipher_walk_done(desc, &walk, nbytes);
215 }
216END:
217 dma_free_coherent(dd->dev, dma_size, kbuf, dma_addr);
218 dma_free_coherent(dd->dev, sizeof(struct zynqmp_aes_data),
219 abuf, dma_addr_buf);
220 return err;
221}
222
223static int zynqmp_aes_decrypt(struct blkcipher_desc *desc,
224 struct scatterlist *dst,
225 struct scatterlist *src,
226 unsigned int nbytes)
227{
228 return zynqmp_aes_xcrypt(desc, dst, src, nbytes, ZYNQMP_AES_DECRYPT);
229}
230
231static int zynqmp_aes_encrypt(struct blkcipher_desc *desc,
232 struct scatterlist *dst,
233 struct scatterlist *src,
234 unsigned int nbytes)
235{
236 return zynqmp_aes_xcrypt(desc, dst, src, nbytes, ZYNQMP_AES_ENCRYPT);
237}
238
239static struct crypto_alg zynqmp_alg = {
240 .cra_name = "xilinx-zynqmp-aes",
241 .cra_driver_name = "zynqmp-aes",
242 .cra_priority = 400,
243 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
244 CRYPTO_ALG_KERN_DRIVER_ONLY,
245 .cra_blocksize = ZYNQMP_AES_BLOCKSIZE,
246 .cra_ctxsize = sizeof(struct zynqmp_aes_op),
247 .cra_alignmask = 15,
248 .cra_type = &crypto_blkcipher_type,
249 .cra_module = THIS_MODULE,
250 .cra_u = {
251 .blkcipher = {
252 .min_keysize = 0,
253 .max_keysize = ZYNQMP_AES_KEY_SIZE,
254 .setkey = zynqmp_setkey_blk,
255 .setkeytype = zynqmp_setkeytype,
256 .encrypt = zynqmp_aes_encrypt,
257 .decrypt = zynqmp_aes_decrypt,
258 .ivsize = ZYNQMP_AES_IV_SIZE,
259 }
260 }
261};
262
263static const struct of_device_id zynqmp_aes_dt_ids[] = {
264 { .compatible = "xlnx,zynqmp-aes" },
265 { }
266};
267MODULE_DEVICE_TABLE(of, zynqmp_aes_dt_ids);
268
269static int zynqmp_aes_probe(struct platform_device *pdev)
270{
271 struct zynqmp_aes_dev *aes_dd;
272 struct device *dev = &pdev->dev;
273 int ret;
274
275 eemi_ops = zynqmp_pm_get_eemi_ops();
276 if (IS_ERR(eemi_ops))
277 return PTR_ERR(eemi_ops);
278
279 aes_dd = devm_kzalloc(dev, sizeof(*aes_dd), GFP_KERNEL);
280 if (!aes_dd)
281 return -ENOMEM;
282
283 aes_dd->dev = dev;
284 platform_set_drvdata(pdev, aes_dd);
285
286 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(44));
287 if (ret < 0) {
288 dev_err(dev, "no usable DMA configuration");
289 return ret;
290 }
291
292 INIT_LIST_HEAD(&aes_dd->list);
293 crypto_init_queue(&aes_dd->queue, ZYNQMP_AES_QUEUE_LENGTH);
294 list_add_tail(&aes_dd->list, &zynqmp_aes.dev_list);
295
296 ret = crypto_register_alg(&zynqmp_alg);
297 if (ret)
298 goto err_algs;
299
300 dev_info(dev, "AES Successfully Registered\n\r");
301 return 0;
302
303err_algs:
304 list_del(&aes_dd->list);
305 dev_err(dev, "initialization failed.\n");
306
307 return ret;
308}
309
310static int zynqmp_aes_remove(struct platform_device *pdev)
311{
312 struct zynqmp_aes_dev *aes_dd;
313
314 aes_dd = platform_get_drvdata(pdev);
315 if (!aes_dd)
316 return -ENODEV;
317 list_del(&aes_dd->list);
318 crypto_unregister_alg(&zynqmp_alg);
319 return 0;
320}
321
322static struct platform_driver xilinx_aes_driver = {
323 .probe = zynqmp_aes_probe,
324 .remove = zynqmp_aes_remove,
325 .driver = {
326 .name = "zynqmp_aes",
327 .of_match_table = of_match_ptr(zynqmp_aes_dt_ids),
328 },
329};
330
331module_platform_driver(xilinx_aes_driver);
332
333MODULE_DESCRIPTION("Xilinx ZynqMP AES hw acceleration support.");
334MODULE_LICENSE("GPL v2");
335MODULE_AUTHOR("Nava kishore Manne <nava.manne@xilinx.com>");
336MODULE_AUTHOR("Kalyani Akula <kalyani.akula@xilinx.com>");
337