xref: /openbmc/linux/drivers/crypto/atmel-aes.c (revision b0cc7491)
1820684ccSTudor Ambarus // SPDX-License-Identifier: GPL-2.0
2bd3c7b5cSNicolas Royer /*
3bd3c7b5cSNicolas Royer  * Cryptographic API.
4bd3c7b5cSNicolas Royer  *
5bd3c7b5cSNicolas Royer  * Support for ATMEL AES HW acceleration.
6bd3c7b5cSNicolas Royer  *
7bd3c7b5cSNicolas Royer  * Copyright (c) 2012 Eukréa Electromatique - ATMEL
8bd3c7b5cSNicolas Royer  * Author: Nicolas Royer <nicolas@eukrea.com>
9bd3c7b5cSNicolas Royer  *
10bd3c7b5cSNicolas Royer  * Some ideas are from omap-aes.c driver.
11bd3c7b5cSNicolas Royer  */
12bd3c7b5cSNicolas Royer 
13bd3c7b5cSNicolas Royer 
14bd3c7b5cSNicolas Royer #include <linux/kernel.h>
15bd3c7b5cSNicolas Royer #include <linux/module.h>
16bd3c7b5cSNicolas Royer #include <linux/slab.h>
17bd3c7b5cSNicolas Royer #include <linux/err.h>
18bd3c7b5cSNicolas Royer #include <linux/clk.h>
19bd3c7b5cSNicolas Royer #include <linux/io.h>
20bd3c7b5cSNicolas Royer #include <linux/hw_random.h>
21bd3c7b5cSNicolas Royer #include <linux/platform_device.h>
22bd3c7b5cSNicolas Royer 
23bd3c7b5cSNicolas Royer #include <linux/device.h>
24b46f36c0STudor Ambarus #include <linux/dmaengine.h>
25bd3c7b5cSNicolas Royer #include <linux/init.h>
26bd3c7b5cSNicolas Royer #include <linux/errno.h>
27bd3c7b5cSNicolas Royer #include <linux/interrupt.h>
28bd3c7b5cSNicolas Royer #include <linux/irq.h>
29bd3c7b5cSNicolas Royer #include <linux/scatterlist.h>
30bd3c7b5cSNicolas Royer #include <linux/dma-mapping.h>
31*b0cc7491SRob Herring #include <linux/mod_devicetable.h>
32bd3c7b5cSNicolas Royer #include <linux/delay.h>
33bd3c7b5cSNicolas Royer #include <linux/crypto.h>
34bd3c7b5cSNicolas Royer #include <crypto/scatterwalk.h>
35bd3c7b5cSNicolas Royer #include <crypto/algapi.h>
36bd3c7b5cSNicolas Royer #include <crypto/aes.h>
37219d51c7SCorentin LABBE #include <crypto/gcm.h>
38d52db518SCyrille Pitchen #include <crypto/xts.h>
39d4419548SCyrille Pitchen #include <crypto/internal/aead.h>
407ada42d2SArd Biesheuvel #include <crypto/internal/skcipher.h>
41bd3c7b5cSNicolas Royer #include "atmel-aes-regs.h"
4289a82ef8SCyrille Pitchen #include "atmel-authenc.h"
43bd3c7b5cSNicolas Royer 
4488efd9a9SCyrille Pitchen #define ATMEL_AES_PRIORITY	300
4588efd9a9SCyrille Pitchen 
46bbe628edSCyrille Pitchen #define ATMEL_AES_BUFFER_ORDER	2
47bbe628edSCyrille Pitchen #define ATMEL_AES_BUFFER_SIZE	(PAGE_SIZE << ATMEL_AES_BUFFER_ORDER)
48bbe628edSCyrille Pitchen 
49bd3c7b5cSNicolas Royer #define CFB8_BLOCK_SIZE		1
50bd3c7b5cSNicolas Royer #define CFB16_BLOCK_SIZE	2
51bd3c7b5cSNicolas Royer #define CFB32_BLOCK_SIZE	4
52bd3c7b5cSNicolas Royer #define CFB64_BLOCK_SIZE	8
53bd3c7b5cSNicolas Royer 
54bbe628edSCyrille Pitchen #define SIZE_IN_WORDS(x)	((x) >> 2)
55bbe628edSCyrille Pitchen 
56bd3c7b5cSNicolas Royer /* AES flags */
57d4419548SCyrille Pitchen /* Reserve bits [18:16] [14:12] [1:0] for mode (same as for AES_MR) */
5877dacf5fSCyrille Pitchen #define AES_FLAGS_ENCRYPT	AES_MR_CYPHER_ENC
59d4419548SCyrille Pitchen #define AES_FLAGS_GTAGEN	AES_MR_GTAGEN
6077dacf5fSCyrille Pitchen #define AES_FLAGS_OPMODE_MASK	(AES_MR_OPMOD_MASK | AES_MR_CFBS_MASK)
6177dacf5fSCyrille Pitchen #define AES_FLAGS_ECB		AES_MR_OPMOD_ECB
6277dacf5fSCyrille Pitchen #define AES_FLAGS_CBC		AES_MR_OPMOD_CBC
6377dacf5fSCyrille Pitchen #define AES_FLAGS_OFB		AES_MR_OPMOD_OFB
6477dacf5fSCyrille Pitchen #define AES_FLAGS_CFB128	(AES_MR_OPMOD_CFB | AES_MR_CFBS_128b)
6577dacf5fSCyrille Pitchen #define AES_FLAGS_CFB64		(AES_MR_OPMOD_CFB | AES_MR_CFBS_64b)
6677dacf5fSCyrille Pitchen #define AES_FLAGS_CFB32		(AES_MR_OPMOD_CFB | AES_MR_CFBS_32b)
6777dacf5fSCyrille Pitchen #define AES_FLAGS_CFB16		(AES_MR_OPMOD_CFB | AES_MR_CFBS_16b)
6877dacf5fSCyrille Pitchen #define AES_FLAGS_CFB8		(AES_MR_OPMOD_CFB | AES_MR_CFBS_8b)
6977dacf5fSCyrille Pitchen #define AES_FLAGS_CTR		AES_MR_OPMOD_CTR
70d4419548SCyrille Pitchen #define AES_FLAGS_GCM		AES_MR_OPMOD_GCM
71d52db518SCyrille Pitchen #define AES_FLAGS_XTS		AES_MR_OPMOD_XTS
72bd3c7b5cSNicolas Royer 
7377dacf5fSCyrille Pitchen #define AES_FLAGS_MODE_MASK	(AES_FLAGS_OPMODE_MASK |	\
74d4419548SCyrille Pitchen 				 AES_FLAGS_ENCRYPT |		\
75d4419548SCyrille Pitchen 				 AES_FLAGS_GTAGEN)
7677dacf5fSCyrille Pitchen 
7777dacf5fSCyrille Pitchen #define AES_FLAGS_BUSY		BIT(3)
784537992bSCyrille Pitchen #define AES_FLAGS_DUMP_REG	BIT(4)
7989a82ef8SCyrille Pitchen #define AES_FLAGS_OWN_SHA	BIT(5)
8077dacf5fSCyrille Pitchen 
817a373fd7SRomain Izard #define AES_FLAGS_PERSISTENT	AES_FLAGS_BUSY
82bd3c7b5cSNicolas Royer 
83cadc4ab8SNicolas Royer #define ATMEL_AES_QUEUE_LENGTH	50
84bd3c7b5cSNicolas Royer 
85129f8bb6SCyrille Pitchen #define ATMEL_AES_DMA_THRESHOLD		256
86bd3c7b5cSNicolas Royer 
87bd3c7b5cSNicolas Royer 
88cadc4ab8SNicolas Royer struct atmel_aes_caps {
89cadc4ab8SNicolas Royer 	bool			has_dualbuff;
90cadc4ab8SNicolas Royer 	bool			has_cfb64;
91d4419548SCyrille Pitchen 	bool			has_gcm;
92d52db518SCyrille Pitchen 	bool			has_xts;
9389a82ef8SCyrille Pitchen 	bool			has_authenc;
94cadc4ab8SNicolas Royer 	u32			max_burst_size;
95cadc4ab8SNicolas Royer };
96cadc4ab8SNicolas Royer 
97bd3c7b5cSNicolas Royer struct atmel_aes_dev;
98bd3c7b5cSNicolas Royer 
99ccbf7298SCyrille Pitchen 
100ccbf7298SCyrille Pitchen typedef int (*atmel_aes_fn_t)(struct atmel_aes_dev *);
101ccbf7298SCyrille Pitchen 
102ccbf7298SCyrille Pitchen 
103ccbf7298SCyrille Pitchen struct atmel_aes_base_ctx {
104bd3c7b5cSNicolas Royer 	struct atmel_aes_dev	*dd;
105ccbf7298SCyrille Pitchen 	atmel_aes_fn_t		start;
106bd3c7b5cSNicolas Royer 	int			keylen;
107bd3c7b5cSNicolas Royer 	u32			key[AES_KEYSIZE_256 / sizeof(u32)];
108cadc4ab8SNicolas Royer 	u16			block_size;
10991308019SRomain Izard 	bool			is_aead;
110bd3c7b5cSNicolas Royer };
111bd3c7b5cSNicolas Royer 
112ccbf7298SCyrille Pitchen struct atmel_aes_ctx {
113ccbf7298SCyrille Pitchen 	struct atmel_aes_base_ctx	base;
114ccbf7298SCyrille Pitchen };
115ccbf7298SCyrille Pitchen 
116fcac8365SCyrille Pitchen struct atmel_aes_ctr_ctx {
117fcac8365SCyrille Pitchen 	struct atmel_aes_base_ctx	base;
118fcac8365SCyrille Pitchen 
11949c4cd80SBen Dooks (Codethink) 	__be32			iv[AES_BLOCK_SIZE / sizeof(u32)];
120fcac8365SCyrille Pitchen 	size_t			offset;
121fcac8365SCyrille Pitchen 	struct scatterlist	src[2];
122fcac8365SCyrille Pitchen 	struct scatterlist	dst[2];
1233907ccfaSTudor Ambarus 	u32			blocks;
124fcac8365SCyrille Pitchen };
125fcac8365SCyrille Pitchen 
126d4419548SCyrille Pitchen struct atmel_aes_gcm_ctx {
127d4419548SCyrille Pitchen 	struct atmel_aes_base_ctx	base;
128d4419548SCyrille Pitchen 
129d4419548SCyrille Pitchen 	struct scatterlist	src[2];
130d4419548SCyrille Pitchen 	struct scatterlist	dst[2];
131d4419548SCyrille Pitchen 
13249c4cd80SBen Dooks (Codethink) 	__be32			j0[AES_BLOCK_SIZE / sizeof(u32)];
133d4419548SCyrille Pitchen 	u32			tag[AES_BLOCK_SIZE / sizeof(u32)];
13449c4cd80SBen Dooks (Codethink) 	__be32			ghash[AES_BLOCK_SIZE / sizeof(u32)];
135d4419548SCyrille Pitchen 	size_t			textlen;
136d4419548SCyrille Pitchen 
13749c4cd80SBen Dooks (Codethink) 	const __be32		*ghash_in;
13849c4cd80SBen Dooks (Codethink) 	__be32			*ghash_out;
139d4419548SCyrille Pitchen 	atmel_aes_fn_t		ghash_resume;
140d4419548SCyrille Pitchen };
141d4419548SCyrille Pitchen 
142d52db518SCyrille Pitchen struct atmel_aes_xts_ctx {
143d52db518SCyrille Pitchen 	struct atmel_aes_base_ctx	base;
144d52db518SCyrille Pitchen 
145d52db518SCyrille Pitchen 	u32			key2[AES_KEYSIZE_256 / sizeof(u32)];
146bf2db8e7STudor Ambarus 	struct crypto_skcipher *fallback_tfm;
147d52db518SCyrille Pitchen };
148d52db518SCyrille Pitchen 
1491520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
15089a82ef8SCyrille Pitchen struct atmel_aes_authenc_ctx {
15189a82ef8SCyrille Pitchen 	struct atmel_aes_base_ctx	base;
15289a82ef8SCyrille Pitchen 	struct atmel_sha_authenc_ctx	*auth;
15389a82ef8SCyrille Pitchen };
15489a82ef8SCyrille Pitchen #endif
15589a82ef8SCyrille Pitchen 
156bd3c7b5cSNicolas Royer struct atmel_aes_reqctx {
157bd3c7b5cSNicolas Royer 	unsigned long		mode;
15857d8154fSTudor Ambarus 	u8			lastc[AES_BLOCK_SIZE];
159bf2db8e7STudor Ambarus 	struct skcipher_request fallback_req;
160bd3c7b5cSNicolas Royer };
161bd3c7b5cSNicolas Royer 
1621520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
16389a82ef8SCyrille Pitchen struct atmel_aes_authenc_reqctx {
16489a82ef8SCyrille Pitchen 	struct atmel_aes_reqctx	base;
16589a82ef8SCyrille Pitchen 
16689a82ef8SCyrille Pitchen 	struct scatterlist	src[2];
16789a82ef8SCyrille Pitchen 	struct scatterlist	dst[2];
16889a82ef8SCyrille Pitchen 	size_t			textlen;
16989a82ef8SCyrille Pitchen 	u32			digest[SHA512_DIGEST_SIZE / sizeof(u32)];
17089a82ef8SCyrille Pitchen 
17189a82ef8SCyrille Pitchen 	/* auth_req MUST be place last. */
17289a82ef8SCyrille Pitchen 	struct ahash_request	auth_req;
17389a82ef8SCyrille Pitchen };
17489a82ef8SCyrille Pitchen #endif
17589a82ef8SCyrille Pitchen 
176bd3c7b5cSNicolas Royer struct atmel_aes_dma {
177bd3c7b5cSNicolas Royer 	struct dma_chan		*chan;
178bbe628edSCyrille Pitchen 	struct scatterlist	*sg;
179bbe628edSCyrille Pitchen 	int			nents;
180bbe628edSCyrille Pitchen 	unsigned int		remainder;
181bbe628edSCyrille Pitchen 	unsigned int		sg_len;
182bd3c7b5cSNicolas Royer };
183bd3c7b5cSNicolas Royer 
184bd3c7b5cSNicolas Royer struct atmel_aes_dev {
185bd3c7b5cSNicolas Royer 	struct list_head	list;
186bd3c7b5cSNicolas Royer 	unsigned long		phys_base;
187bd3c7b5cSNicolas Royer 	void __iomem		*io_base;
188bd3c7b5cSNicolas Royer 
189ccbf7298SCyrille Pitchen 	struct crypto_async_request	*areq;
190ccbf7298SCyrille Pitchen 	struct atmel_aes_base_ctx	*ctx;
191ccbf7298SCyrille Pitchen 
19210f12c1bSCyrille Pitchen 	bool			is_async;
19310f12c1bSCyrille Pitchen 	atmel_aes_fn_t		resume;
194bbe628edSCyrille Pitchen 	atmel_aes_fn_t		cpu_transfer_complete;
19510f12c1bSCyrille Pitchen 
196bd3c7b5cSNicolas Royer 	struct device		*dev;
197bd3c7b5cSNicolas Royer 	struct clk		*iclk;
198bd3c7b5cSNicolas Royer 	int			irq;
199bd3c7b5cSNicolas Royer 
200bd3c7b5cSNicolas Royer 	unsigned long		flags;
201bd3c7b5cSNicolas Royer 
202bd3c7b5cSNicolas Royer 	spinlock_t		lock;
203bd3c7b5cSNicolas Royer 	struct crypto_queue	queue;
204bd3c7b5cSNicolas Royer 
205bd3c7b5cSNicolas Royer 	struct tasklet_struct	done_task;
206bd3c7b5cSNicolas Royer 	struct tasklet_struct	queue_task;
207bd3c7b5cSNicolas Royer 
208bd3c7b5cSNicolas Royer 	size_t			total;
209bbe628edSCyrille Pitchen 	size_t			datalen;
210bbe628edSCyrille Pitchen 	u32			*data;
211bd3c7b5cSNicolas Royer 
212bbe628edSCyrille Pitchen 	struct atmel_aes_dma	src;
213bbe628edSCyrille Pitchen 	struct atmel_aes_dma	dst;
214bd3c7b5cSNicolas Royer 
215cadc4ab8SNicolas Royer 	size_t			buflen;
216bbe628edSCyrille Pitchen 	void			*buf;
217bbe628edSCyrille Pitchen 	struct scatterlist	aligned_sg;
218bbe628edSCyrille Pitchen 	struct scatterlist	*real_dst;
219bd3c7b5cSNicolas Royer 
220cadc4ab8SNicolas Royer 	struct atmel_aes_caps	caps;
221cadc4ab8SNicolas Royer 
222bd3c7b5cSNicolas Royer 	u32			hw_version;
223bd3c7b5cSNicolas Royer };
224bd3c7b5cSNicolas Royer 
225bd3c7b5cSNicolas Royer struct atmel_aes_drv {
226bd3c7b5cSNicolas Royer 	struct list_head	dev_list;
227bd3c7b5cSNicolas Royer 	spinlock_t		lock;
228bd3c7b5cSNicolas Royer };
229bd3c7b5cSNicolas Royer 
230bd3c7b5cSNicolas Royer static struct atmel_aes_drv atmel_aes = {
231bd3c7b5cSNicolas Royer 	.dev_list = LIST_HEAD_INIT(atmel_aes.dev_list),
232bd3c7b5cSNicolas Royer 	.lock = __SPIN_LOCK_UNLOCKED(atmel_aes.lock),
233bd3c7b5cSNicolas Royer };
234bd3c7b5cSNicolas Royer 
2354537992bSCyrille Pitchen #ifdef VERBOSE_DEBUG
atmel_aes_reg_name(u32 offset,char * tmp,size_t sz)2364537992bSCyrille Pitchen static const char *atmel_aes_reg_name(u32 offset, char *tmp, size_t sz)
2374537992bSCyrille Pitchen {
2384537992bSCyrille Pitchen 	switch (offset) {
2394537992bSCyrille Pitchen 	case AES_CR:
2404537992bSCyrille Pitchen 		return "CR";
2414537992bSCyrille Pitchen 
2424537992bSCyrille Pitchen 	case AES_MR:
2434537992bSCyrille Pitchen 		return "MR";
2444537992bSCyrille Pitchen 
2454537992bSCyrille Pitchen 	case AES_ISR:
2464537992bSCyrille Pitchen 		return "ISR";
2474537992bSCyrille Pitchen 
2484537992bSCyrille Pitchen 	case AES_IMR:
2494537992bSCyrille Pitchen 		return "IMR";
2504537992bSCyrille Pitchen 
2514537992bSCyrille Pitchen 	case AES_IER:
2524537992bSCyrille Pitchen 		return "IER";
2534537992bSCyrille Pitchen 
2544537992bSCyrille Pitchen 	case AES_IDR:
2554537992bSCyrille Pitchen 		return "IDR";
2564537992bSCyrille Pitchen 
2574537992bSCyrille Pitchen 	case AES_KEYWR(0):
2584537992bSCyrille Pitchen 	case AES_KEYWR(1):
2594537992bSCyrille Pitchen 	case AES_KEYWR(2):
2604537992bSCyrille Pitchen 	case AES_KEYWR(3):
2614537992bSCyrille Pitchen 	case AES_KEYWR(4):
2624537992bSCyrille Pitchen 	case AES_KEYWR(5):
2634537992bSCyrille Pitchen 	case AES_KEYWR(6):
2644537992bSCyrille Pitchen 	case AES_KEYWR(7):
2654537992bSCyrille Pitchen 		snprintf(tmp, sz, "KEYWR[%u]", (offset - AES_KEYWR(0)) >> 2);
2664537992bSCyrille Pitchen 		break;
2674537992bSCyrille Pitchen 
2684537992bSCyrille Pitchen 	case AES_IDATAR(0):
2694537992bSCyrille Pitchen 	case AES_IDATAR(1):
2704537992bSCyrille Pitchen 	case AES_IDATAR(2):
2714537992bSCyrille Pitchen 	case AES_IDATAR(3):
2724537992bSCyrille Pitchen 		snprintf(tmp, sz, "IDATAR[%u]", (offset - AES_IDATAR(0)) >> 2);
2734537992bSCyrille Pitchen 		break;
2744537992bSCyrille Pitchen 
2754537992bSCyrille Pitchen 	case AES_ODATAR(0):
2764537992bSCyrille Pitchen 	case AES_ODATAR(1):
2774537992bSCyrille Pitchen 	case AES_ODATAR(2):
2784537992bSCyrille Pitchen 	case AES_ODATAR(3):
2794537992bSCyrille Pitchen 		snprintf(tmp, sz, "ODATAR[%u]", (offset - AES_ODATAR(0)) >> 2);
2804537992bSCyrille Pitchen 		break;
2814537992bSCyrille Pitchen 
2824537992bSCyrille Pitchen 	case AES_IVR(0):
2834537992bSCyrille Pitchen 	case AES_IVR(1):
2844537992bSCyrille Pitchen 	case AES_IVR(2):
2854537992bSCyrille Pitchen 	case AES_IVR(3):
2864537992bSCyrille Pitchen 		snprintf(tmp, sz, "IVR[%u]", (offset - AES_IVR(0)) >> 2);
2874537992bSCyrille Pitchen 		break;
2884537992bSCyrille Pitchen 
2894537992bSCyrille Pitchen 	case AES_AADLENR:
2904537992bSCyrille Pitchen 		return "AADLENR";
2914537992bSCyrille Pitchen 
2924537992bSCyrille Pitchen 	case AES_CLENR:
2934537992bSCyrille Pitchen 		return "CLENR";
2944537992bSCyrille Pitchen 
2954537992bSCyrille Pitchen 	case AES_GHASHR(0):
2964537992bSCyrille Pitchen 	case AES_GHASHR(1):
2974537992bSCyrille Pitchen 	case AES_GHASHR(2):
2984537992bSCyrille Pitchen 	case AES_GHASHR(3):
2994537992bSCyrille Pitchen 		snprintf(tmp, sz, "GHASHR[%u]", (offset - AES_GHASHR(0)) >> 2);
3004537992bSCyrille Pitchen 		break;
3014537992bSCyrille Pitchen 
3024537992bSCyrille Pitchen 	case AES_TAGR(0):
3034537992bSCyrille Pitchen 	case AES_TAGR(1):
3044537992bSCyrille Pitchen 	case AES_TAGR(2):
3054537992bSCyrille Pitchen 	case AES_TAGR(3):
3064537992bSCyrille Pitchen 		snprintf(tmp, sz, "TAGR[%u]", (offset - AES_TAGR(0)) >> 2);
3074537992bSCyrille Pitchen 		break;
3084537992bSCyrille Pitchen 
3094537992bSCyrille Pitchen 	case AES_CTRR:
3104537992bSCyrille Pitchen 		return "CTRR";
3114537992bSCyrille Pitchen 
3124537992bSCyrille Pitchen 	case AES_GCMHR(0):
3134537992bSCyrille Pitchen 	case AES_GCMHR(1):
3144537992bSCyrille Pitchen 	case AES_GCMHR(2):
3154537992bSCyrille Pitchen 	case AES_GCMHR(3):
3164537992bSCyrille Pitchen 		snprintf(tmp, sz, "GCMHR[%u]", (offset - AES_GCMHR(0)) >> 2);
317e31835adSHerbert Xu 		break;
3184537992bSCyrille Pitchen 
31989a82ef8SCyrille Pitchen 	case AES_EMR:
32089a82ef8SCyrille Pitchen 		return "EMR";
32189a82ef8SCyrille Pitchen 
322d52db518SCyrille Pitchen 	case AES_TWR(0):
323d52db518SCyrille Pitchen 	case AES_TWR(1):
324d52db518SCyrille Pitchen 	case AES_TWR(2):
325d52db518SCyrille Pitchen 	case AES_TWR(3):
326d52db518SCyrille Pitchen 		snprintf(tmp, sz, "TWR[%u]", (offset - AES_TWR(0)) >> 2);
327d52db518SCyrille Pitchen 		break;
328d52db518SCyrille Pitchen 
329d52db518SCyrille Pitchen 	case AES_ALPHAR(0):
330d52db518SCyrille Pitchen 	case AES_ALPHAR(1):
331d52db518SCyrille Pitchen 	case AES_ALPHAR(2):
332d52db518SCyrille Pitchen 	case AES_ALPHAR(3):
333d52db518SCyrille Pitchen 		snprintf(tmp, sz, "ALPHAR[%u]", (offset - AES_ALPHAR(0)) >> 2);
334d52db518SCyrille Pitchen 		break;
335d52db518SCyrille Pitchen 
3364537992bSCyrille Pitchen 	default:
3374537992bSCyrille Pitchen 		snprintf(tmp, sz, "0x%02x", offset);
3384537992bSCyrille Pitchen 		break;
3394537992bSCyrille Pitchen 	}
3404537992bSCyrille Pitchen 
3414537992bSCyrille Pitchen 	return tmp;
3424537992bSCyrille Pitchen }
3434537992bSCyrille Pitchen #endif /* VERBOSE_DEBUG */
3444537992bSCyrille Pitchen 
345e37a7e55SCyrille Pitchen /* Shared functions */
346cadc4ab8SNicolas Royer 
atmel_aes_read(struct atmel_aes_dev * dd,u32 offset)347bd3c7b5cSNicolas Royer static inline u32 atmel_aes_read(struct atmel_aes_dev *dd, u32 offset)
348bd3c7b5cSNicolas Royer {
3494537992bSCyrille Pitchen 	u32 value = readl_relaxed(dd->io_base + offset);
3504537992bSCyrille Pitchen 
3514537992bSCyrille Pitchen #ifdef VERBOSE_DEBUG
3524537992bSCyrille Pitchen 	if (dd->flags & AES_FLAGS_DUMP_REG) {
3534537992bSCyrille Pitchen 		char tmp[16];
3544537992bSCyrille Pitchen 
3554537992bSCyrille Pitchen 		dev_vdbg(dd->dev, "read 0x%08x from %s\n", value,
3564537992bSCyrille Pitchen 			 atmel_aes_reg_name(offset, tmp, sizeof(tmp)));
3574537992bSCyrille Pitchen 	}
3584537992bSCyrille Pitchen #endif /* VERBOSE_DEBUG */
3594537992bSCyrille Pitchen 
3604537992bSCyrille Pitchen 	return value;
361bd3c7b5cSNicolas Royer }
362bd3c7b5cSNicolas Royer 
atmel_aes_write(struct atmel_aes_dev * dd,u32 offset,u32 value)363bd3c7b5cSNicolas Royer static inline void atmel_aes_write(struct atmel_aes_dev *dd,
364bd3c7b5cSNicolas Royer 					u32 offset, u32 value)
365bd3c7b5cSNicolas Royer {
3664537992bSCyrille Pitchen #ifdef VERBOSE_DEBUG
3674537992bSCyrille Pitchen 	if (dd->flags & AES_FLAGS_DUMP_REG) {
3684537992bSCyrille Pitchen 		char tmp[16];
3694537992bSCyrille Pitchen 
3704537992bSCyrille Pitchen 		dev_vdbg(dd->dev, "write 0x%08x into %s\n", value,
371f709dc86SCyrille Pitchen 			 atmel_aes_reg_name(offset, tmp, sizeof(tmp)));
3724537992bSCyrille Pitchen 	}
3734537992bSCyrille Pitchen #endif /* VERBOSE_DEBUG */
3744537992bSCyrille Pitchen 
375bd3c7b5cSNicolas Royer 	writel_relaxed(value, dd->io_base + offset);
376bd3c7b5cSNicolas Royer }
377bd3c7b5cSNicolas Royer 
atmel_aes_read_n(struct atmel_aes_dev * dd,u32 offset,u32 * value,int count)378bd3c7b5cSNicolas Royer static void atmel_aes_read_n(struct atmel_aes_dev *dd, u32 offset,
379bd3c7b5cSNicolas Royer 					u32 *value, int count)
380bd3c7b5cSNicolas Royer {
381bd3c7b5cSNicolas Royer 	for (; count--; value++, offset += 4)
382bd3c7b5cSNicolas Royer 		*value = atmel_aes_read(dd, offset);
383bd3c7b5cSNicolas Royer }
384bd3c7b5cSNicolas Royer 
atmel_aes_write_n(struct atmel_aes_dev * dd,u32 offset,const u32 * value,int count)385bd3c7b5cSNicolas Royer static void atmel_aes_write_n(struct atmel_aes_dev *dd, u32 offset,
386c0b28d8cSCyrille Pitchen 			      const u32 *value, int count)
387bd3c7b5cSNicolas Royer {
388bd3c7b5cSNicolas Royer 	for (; count--; value++, offset += 4)
389bd3c7b5cSNicolas Royer 		atmel_aes_write(dd, offset, *value);
390bd3c7b5cSNicolas Royer }
391bd3c7b5cSNicolas Royer 
atmel_aes_read_block(struct atmel_aes_dev * dd,u32 offset,void * value)392bbe628edSCyrille Pitchen static inline void atmel_aes_read_block(struct atmel_aes_dev *dd, u32 offset,
39349c4cd80SBen Dooks (Codethink) 					void *value)
394bbe628edSCyrille Pitchen {
395bbe628edSCyrille Pitchen 	atmel_aes_read_n(dd, offset, value, SIZE_IN_WORDS(AES_BLOCK_SIZE));
396bbe628edSCyrille Pitchen }
397bbe628edSCyrille Pitchen 
atmel_aes_write_block(struct atmel_aes_dev * dd,u32 offset,const void * value)398bbe628edSCyrille Pitchen static inline void atmel_aes_write_block(struct atmel_aes_dev *dd, u32 offset,
39949c4cd80SBen Dooks (Codethink) 					 const void *value)
400bbe628edSCyrille Pitchen {
401bbe628edSCyrille Pitchen 	atmel_aes_write_n(dd, offset, value, SIZE_IN_WORDS(AES_BLOCK_SIZE));
402bbe628edSCyrille Pitchen }
403bbe628edSCyrille Pitchen 
atmel_aes_wait_for_data_ready(struct atmel_aes_dev * dd,atmel_aes_fn_t resume)404bbe628edSCyrille Pitchen static inline int atmel_aes_wait_for_data_ready(struct atmel_aes_dev *dd,
405bbe628edSCyrille Pitchen 						atmel_aes_fn_t resume)
406bbe628edSCyrille Pitchen {
407bbe628edSCyrille Pitchen 	u32 isr = atmel_aes_read(dd, AES_ISR);
408bbe628edSCyrille Pitchen 
409bbe628edSCyrille Pitchen 	if (unlikely(isr & AES_INT_DATARDY))
410bbe628edSCyrille Pitchen 		return resume(dd);
411bbe628edSCyrille Pitchen 
412bbe628edSCyrille Pitchen 	dd->resume = resume;
413bbe628edSCyrille Pitchen 	atmel_aes_write(dd, AES_IER, AES_INT_DATARDY);
414bbe628edSCyrille Pitchen 	return -EINPROGRESS;
415bbe628edSCyrille Pitchen }
416bbe628edSCyrille Pitchen 
atmel_aes_padlen(size_t len,size_t block_size)417bbe628edSCyrille Pitchen static inline size_t atmel_aes_padlen(size_t len, size_t block_size)
418bbe628edSCyrille Pitchen {
419bbe628edSCyrille Pitchen 	len &= block_size - 1;
420bbe628edSCyrille Pitchen 	return len ? block_size - len : 0;
421bbe628edSCyrille Pitchen }
422bbe628edSCyrille Pitchen 
atmel_aes_dev_alloc(struct atmel_aes_base_ctx * ctx)423ec2088b6STudor Ambarus static struct atmel_aes_dev *atmel_aes_dev_alloc(struct atmel_aes_base_ctx *ctx)
424bd3c7b5cSNicolas Royer {
425ec2088b6STudor Ambarus 	struct atmel_aes_dev *aes_dd;
426bd3c7b5cSNicolas Royer 
427bd3c7b5cSNicolas Royer 	spin_lock_bh(&atmel_aes.lock);
428ec2088b6STudor Ambarus 	/* One AES IP per SoC. */
429ec2088b6STudor Ambarus 	aes_dd = list_first_entry_or_null(&atmel_aes.dev_list,
430ec2088b6STudor Ambarus 					  struct atmel_aes_dev, list);
431bd3c7b5cSNicolas Royer 	spin_unlock_bh(&atmel_aes.lock);
432bd3c7b5cSNicolas Royer 	return aes_dd;
433bd3c7b5cSNicolas Royer }
434bd3c7b5cSNicolas Royer 
atmel_aes_hw_init(struct atmel_aes_dev * dd)435bd3c7b5cSNicolas Royer static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
436bd3c7b5cSNicolas Royer {
4379d83d299SLABBE Corentin 	int err;
4389d83d299SLABBE Corentin 
43949a20454SCyrille Pitchen 	err = clk_enable(dd->iclk);
4409d83d299SLABBE Corentin 	if (err)
4419d83d299SLABBE Corentin 		return err;
442bd3c7b5cSNicolas Royer 
443bd3c7b5cSNicolas Royer 	atmel_aes_write(dd, AES_CR, AES_CR_SWRST);
444cadc4ab8SNicolas Royer 	atmel_aes_write(dd, AES_MR, 0xE << AES_MR_CKEY_OFFSET);
445bd3c7b5cSNicolas Royer 
446bd3c7b5cSNicolas Royer 	return 0;
447bd3c7b5cSNicolas Royer }
448bd3c7b5cSNicolas Royer 
atmel_aes_get_version(struct atmel_aes_dev * dd)449cadc4ab8SNicolas Royer static inline unsigned int atmel_aes_get_version(struct atmel_aes_dev *dd)
450cadc4ab8SNicolas Royer {
451cadc4ab8SNicolas Royer 	return atmel_aes_read(dd, AES_HW_VERSION) & 0x00000fff;
452cadc4ab8SNicolas Royer }
453cadc4ab8SNicolas Royer 
atmel_aes_hw_version_init(struct atmel_aes_dev * dd)454aab0a39bSCyrille Pitchen static int atmel_aes_hw_version_init(struct atmel_aes_dev *dd)
455bd3c7b5cSNicolas Royer {
456aab0a39bSCyrille Pitchen 	int err;
457aab0a39bSCyrille Pitchen 
458aab0a39bSCyrille Pitchen 	err = atmel_aes_hw_init(dd);
459aab0a39bSCyrille Pitchen 	if (err)
460aab0a39bSCyrille Pitchen 		return err;
461bd3c7b5cSNicolas Royer 
462cadc4ab8SNicolas Royer 	dd->hw_version = atmel_aes_get_version(dd);
463cadc4ab8SNicolas Royer 
464aab0a39bSCyrille Pitchen 	dev_info(dd->dev, "version: 0x%x\n", dd->hw_version);
465bd3c7b5cSNicolas Royer 
46649a20454SCyrille Pitchen 	clk_disable(dd->iclk);
467aab0a39bSCyrille Pitchen 	return 0;
468bd3c7b5cSNicolas Royer }
469bd3c7b5cSNicolas Royer 
atmel_aes_set_mode(struct atmel_aes_dev * dd,const struct atmel_aes_reqctx * rctx)47077dacf5fSCyrille Pitchen static inline void atmel_aes_set_mode(struct atmel_aes_dev *dd,
47177dacf5fSCyrille Pitchen 				      const struct atmel_aes_reqctx *rctx)
47277dacf5fSCyrille Pitchen {
47377dacf5fSCyrille Pitchen 	/* Clear all but persistent flags and set request flags. */
47477dacf5fSCyrille Pitchen 	dd->flags = (dd->flags & AES_FLAGS_PERSISTENT) | rctx->mode;
47577dacf5fSCyrille Pitchen }
47677dacf5fSCyrille Pitchen 
atmel_aes_is_encrypt(const struct atmel_aes_dev * dd)477d4419548SCyrille Pitchen static inline bool atmel_aes_is_encrypt(const struct atmel_aes_dev *dd)
478d4419548SCyrille Pitchen {
479d4419548SCyrille Pitchen 	return (dd->flags & AES_FLAGS_ENCRYPT);
480d4419548SCyrille Pitchen }
481d4419548SCyrille Pitchen 
4821520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
48389a82ef8SCyrille Pitchen static void atmel_aes_authenc_complete(struct atmel_aes_dev *dd, int err);
48489a82ef8SCyrille Pitchen #endif
48589a82ef8SCyrille Pitchen 
atmel_aes_set_iv_as_last_ciphertext_block(struct atmel_aes_dev * dd)48686ef1dfcSTudor Ambarus static void atmel_aes_set_iv_as_last_ciphertext_block(struct atmel_aes_dev *dd)
48786ef1dfcSTudor Ambarus {
4887ada42d2SArd Biesheuvel 	struct skcipher_request *req = skcipher_request_cast(dd->areq);
4897ada42d2SArd Biesheuvel 	struct atmel_aes_reqctx *rctx = skcipher_request_ctx(req);
4907ada42d2SArd Biesheuvel 	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
4917ada42d2SArd Biesheuvel 	unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
49286ef1dfcSTudor Ambarus 
4937ada42d2SArd Biesheuvel 	if (req->cryptlen < ivsize)
49486ef1dfcSTudor Ambarus 		return;
49586ef1dfcSTudor Ambarus 
4962fbe4829SRyan Wanner 	if (rctx->mode & AES_FLAGS_ENCRYPT)
4977ada42d2SArd Biesheuvel 		scatterwalk_map_and_copy(req->iv, req->dst,
4987ada42d2SArd Biesheuvel 					 req->cryptlen - ivsize, ivsize, 0);
49986ef1dfcSTudor Ambarus 	else
5002fbe4829SRyan Wanner 		memcpy(req->iv, rctx->lastc, ivsize);
50186ef1dfcSTudor Ambarus }
50286ef1dfcSTudor Ambarus 
503371731ecSTudor Ambarus static inline struct atmel_aes_ctr_ctx *
atmel_aes_ctr_ctx_cast(struct atmel_aes_base_ctx * ctx)504371731ecSTudor Ambarus atmel_aes_ctr_ctx_cast(struct atmel_aes_base_ctx *ctx)
505371731ecSTudor Ambarus {
506371731ecSTudor Ambarus 	return container_of(ctx, struct atmel_aes_ctr_ctx, base);
507371731ecSTudor Ambarus }
508371731ecSTudor Ambarus 
atmel_aes_ctr_update_req_iv(struct atmel_aes_dev * dd)509371731ecSTudor Ambarus static void atmel_aes_ctr_update_req_iv(struct atmel_aes_dev *dd)
510371731ecSTudor Ambarus {
511371731ecSTudor Ambarus 	struct atmel_aes_ctr_ctx *ctx = atmel_aes_ctr_ctx_cast(dd->ctx);
512371731ecSTudor Ambarus 	struct skcipher_request *req = skcipher_request_cast(dd->areq);
513371731ecSTudor Ambarus 	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
514371731ecSTudor Ambarus 	unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
515371731ecSTudor Ambarus 	int i;
516371731ecSTudor Ambarus 
5173907ccfaSTudor Ambarus 	/*
5183907ccfaSTudor Ambarus 	 * The CTR transfer works in fragments of data of maximum 1 MByte
5193907ccfaSTudor Ambarus 	 * because of the 16 bit CTR counter embedded in the IP. When reaching
5203907ccfaSTudor Ambarus 	 * here, ctx->blocks contains the number of blocks of the last fragment
5213907ccfaSTudor Ambarus 	 * processed, there is no need to explicit cast it to u16.
5223907ccfaSTudor Ambarus 	 */
523371731ecSTudor Ambarus 	for (i = 0; i < ctx->blocks; i++)
524371731ecSTudor Ambarus 		crypto_inc((u8 *)ctx->iv, AES_BLOCK_SIZE);
525371731ecSTudor Ambarus 
526371731ecSTudor Ambarus 	memcpy(req->iv, ctx->iv, ivsize);
527371731ecSTudor Ambarus }
528371731ecSTudor Ambarus 
atmel_aes_complete(struct atmel_aes_dev * dd,int err)52910f12c1bSCyrille Pitchen static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err)
530bd3c7b5cSNicolas Royer {
531c65d1237STudor Ambarus 	struct skcipher_request *req = skcipher_request_cast(dd->areq);
532c65d1237STudor Ambarus 	struct atmel_aes_reqctx *rctx = skcipher_request_ctx(req);
533c65d1237STudor Ambarus 
5341520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
53591308019SRomain Izard 	if (dd->ctx->is_aead)
53689a82ef8SCyrille Pitchen 		atmel_aes_authenc_complete(dd, err);
53789a82ef8SCyrille Pitchen #endif
53889a82ef8SCyrille Pitchen 
53949a20454SCyrille Pitchen 	clk_disable(dd->iclk);
540bd3c7b5cSNicolas Royer 	dd->flags &= ~AES_FLAGS_BUSY;
541bd3c7b5cSNicolas Royer 
54227f4adf7STudor Ambarus 	if (!err && !dd->ctx->is_aead &&
543371731ecSTudor Ambarus 	    (rctx->mode & AES_FLAGS_OPMODE_MASK) != AES_FLAGS_ECB) {
544371731ecSTudor Ambarus 		if ((rctx->mode & AES_FLAGS_OPMODE_MASK) != AES_FLAGS_CTR)
54586ef1dfcSTudor Ambarus 			atmel_aes_set_iv_as_last_ciphertext_block(dd);
546371731ecSTudor Ambarus 		else
547371731ecSTudor Ambarus 			atmel_aes_ctr_update_req_iv(dd);
548371731ecSTudor Ambarus 	}
54991308019SRomain Izard 
55010f12c1bSCyrille Pitchen 	if (dd->is_async)
5517d19abdcSHerbert Xu 		crypto_request_complete(dd->areq, err);
55210f12c1bSCyrille Pitchen 
55310f12c1bSCyrille Pitchen 	tasklet_schedule(&dd->queue_task);
55410f12c1bSCyrille Pitchen 
55510f12c1bSCyrille Pitchen 	return err;
556bd3c7b5cSNicolas Royer }
557bd3c7b5cSNicolas Royer 
atmel_aes_write_ctrl_key(struct atmel_aes_dev * dd,bool use_dma,const __be32 * iv,const u32 * key,int keylen)558d52db518SCyrille Pitchen static void atmel_aes_write_ctrl_key(struct atmel_aes_dev *dd, bool use_dma,
55949c4cd80SBen Dooks (Codethink) 				     const __be32 *iv, const u32 *key, int keylen)
560e37a7e55SCyrille Pitchen {
561e37a7e55SCyrille Pitchen 	u32 valmr = 0;
562e37a7e55SCyrille Pitchen 
563e37a7e55SCyrille Pitchen 	/* MR register must be set before IV registers */
564d52db518SCyrille Pitchen 	if (keylen == AES_KEYSIZE_128)
565e37a7e55SCyrille Pitchen 		valmr |= AES_MR_KEYSIZE_128;
566d52db518SCyrille Pitchen 	else if (keylen == AES_KEYSIZE_192)
567e37a7e55SCyrille Pitchen 		valmr |= AES_MR_KEYSIZE_192;
568e37a7e55SCyrille Pitchen 	else
569e37a7e55SCyrille Pitchen 		valmr |= AES_MR_KEYSIZE_256;
570e37a7e55SCyrille Pitchen 
571e37a7e55SCyrille Pitchen 	valmr |= dd->flags & AES_FLAGS_MODE_MASK;
572e37a7e55SCyrille Pitchen 
573e37a7e55SCyrille Pitchen 	if (use_dma) {
574e37a7e55SCyrille Pitchen 		valmr |= AES_MR_SMOD_IDATAR0;
575e37a7e55SCyrille Pitchen 		if (dd->caps.has_dualbuff)
576e37a7e55SCyrille Pitchen 			valmr |= AES_MR_DUALBUFF;
577e37a7e55SCyrille Pitchen 	} else {
578e37a7e55SCyrille Pitchen 		valmr |= AES_MR_SMOD_AUTO;
579e37a7e55SCyrille Pitchen 	}
580e37a7e55SCyrille Pitchen 
581e37a7e55SCyrille Pitchen 	atmel_aes_write(dd, AES_MR, valmr);
582e37a7e55SCyrille Pitchen 
583d52db518SCyrille Pitchen 	atmel_aes_write_n(dd, AES_KEYWR(0), key, SIZE_IN_WORDS(keylen));
584e37a7e55SCyrille Pitchen 
585e37a7e55SCyrille Pitchen 	if (iv && (valmr & AES_MR_OPMOD_MASK) != AES_MR_OPMOD_ECB)
586e37a7e55SCyrille Pitchen 		atmel_aes_write_block(dd, AES_IVR(0), iv);
587e37a7e55SCyrille Pitchen }
588e37a7e55SCyrille Pitchen 
atmel_aes_write_ctrl(struct atmel_aes_dev * dd,bool use_dma,const __be32 * iv)589d52db518SCyrille Pitchen static inline void atmel_aes_write_ctrl(struct atmel_aes_dev *dd, bool use_dma,
59049c4cd80SBen Dooks (Codethink) 					const __be32 *iv)
591d52db518SCyrille Pitchen 
592d52db518SCyrille Pitchen {
593d52db518SCyrille Pitchen 	atmel_aes_write_ctrl_key(dd, use_dma, iv,
594d52db518SCyrille Pitchen 				 dd->ctx->key, dd->ctx->keylen);
595d52db518SCyrille Pitchen }
596bd3c7b5cSNicolas Royer 
597bbe628edSCyrille Pitchen /* CPU transfer */
598bbe628edSCyrille Pitchen 
atmel_aes_cpu_transfer(struct atmel_aes_dev * dd)599bbe628edSCyrille Pitchen static int atmel_aes_cpu_transfer(struct atmel_aes_dev *dd)
600bbe628edSCyrille Pitchen {
601bbe628edSCyrille Pitchen 	int err = 0;
602bbe628edSCyrille Pitchen 	u32 isr;
603bbe628edSCyrille Pitchen 
604bbe628edSCyrille Pitchen 	for (;;) {
605bbe628edSCyrille Pitchen 		atmel_aes_read_block(dd, AES_ODATAR(0), dd->data);
606bbe628edSCyrille Pitchen 		dd->data += 4;
607bbe628edSCyrille Pitchen 		dd->datalen -= AES_BLOCK_SIZE;
608bbe628edSCyrille Pitchen 
609bbe628edSCyrille Pitchen 		if (dd->datalen < AES_BLOCK_SIZE)
610bbe628edSCyrille Pitchen 			break;
611bbe628edSCyrille Pitchen 
612bbe628edSCyrille Pitchen 		atmel_aes_write_block(dd, AES_IDATAR(0), dd->data);
613bbe628edSCyrille Pitchen 
614bbe628edSCyrille Pitchen 		isr = atmel_aes_read(dd, AES_ISR);
615bbe628edSCyrille Pitchen 		if (!(isr & AES_INT_DATARDY)) {
616bbe628edSCyrille Pitchen 			dd->resume = atmel_aes_cpu_transfer;
617bbe628edSCyrille Pitchen 			atmel_aes_write(dd, AES_IER, AES_INT_DATARDY);
618bbe628edSCyrille Pitchen 			return -EINPROGRESS;
619bbe628edSCyrille Pitchen 		}
620bd3c7b5cSNicolas Royer 	}
621bd3c7b5cSNicolas Royer 
622bbe628edSCyrille Pitchen 	if (!sg_copy_from_buffer(dd->real_dst, sg_nents(dd->real_dst),
623bbe628edSCyrille Pitchen 				 dd->buf, dd->total))
624bbe628edSCyrille Pitchen 		err = -EINVAL;
625bbe628edSCyrille Pitchen 
626bbe628edSCyrille Pitchen 	if (err)
627bbe628edSCyrille Pitchen 		return atmel_aes_complete(dd, err);
628bbe628edSCyrille Pitchen 
629bbe628edSCyrille Pitchen 	return dd->cpu_transfer_complete(dd);
630bbe628edSCyrille Pitchen }
631bbe628edSCyrille Pitchen 
atmel_aes_cpu_start(struct atmel_aes_dev * dd,struct scatterlist * src,struct scatterlist * dst,size_t len,atmel_aes_fn_t resume)632bbe628edSCyrille Pitchen static int atmel_aes_cpu_start(struct atmel_aes_dev *dd,
633bbe628edSCyrille Pitchen 			       struct scatterlist *src,
634bbe628edSCyrille Pitchen 			       struct scatterlist *dst,
635bbe628edSCyrille Pitchen 			       size_t len,
636bbe628edSCyrille Pitchen 			       atmel_aes_fn_t resume)
637bd3c7b5cSNicolas Royer {
638bbe628edSCyrille Pitchen 	size_t padlen = atmel_aes_padlen(len, AES_BLOCK_SIZE);
639bbe628edSCyrille Pitchen 
640bbe628edSCyrille Pitchen 	if (unlikely(len == 0))
641bbe628edSCyrille Pitchen 		return -EINVAL;
642bbe628edSCyrille Pitchen 
643bbe628edSCyrille Pitchen 	sg_copy_to_buffer(src, sg_nents(src), dd->buf, len);
644bbe628edSCyrille Pitchen 
645bbe628edSCyrille Pitchen 	dd->total = len;
646bbe628edSCyrille Pitchen 	dd->real_dst = dst;
647bbe628edSCyrille Pitchen 	dd->cpu_transfer_complete = resume;
648bbe628edSCyrille Pitchen 	dd->datalen = len + padlen;
649bbe628edSCyrille Pitchen 	dd->data = (u32 *)dd->buf;
650bbe628edSCyrille Pitchen 	atmel_aes_write_block(dd, AES_IDATAR(0), dd->data);
651bbe628edSCyrille Pitchen 	return atmel_aes_wait_for_data_ready(dd, atmel_aes_cpu_transfer);
652bbe628edSCyrille Pitchen }
653bbe628edSCyrille Pitchen 
654bbe628edSCyrille Pitchen 
655bbe628edSCyrille Pitchen /* DMA transfer */
656bbe628edSCyrille Pitchen 
657bbe628edSCyrille Pitchen static void atmel_aes_dma_callback(void *data);
658bbe628edSCyrille Pitchen 
atmel_aes_check_aligned(struct atmel_aes_dev * dd,struct scatterlist * sg,size_t len,struct atmel_aes_dma * dma)659bbe628edSCyrille Pitchen static bool atmel_aes_check_aligned(struct atmel_aes_dev *dd,
660bbe628edSCyrille Pitchen 				    struct scatterlist *sg,
661bbe628edSCyrille Pitchen 				    size_t len,
662bbe628edSCyrille Pitchen 				    struct atmel_aes_dma *dma)
663bbe628edSCyrille Pitchen {
664bbe628edSCyrille Pitchen 	int nents;
665bbe628edSCyrille Pitchen 
666bbe628edSCyrille Pitchen 	if (!IS_ALIGNED(len, dd->ctx->block_size))
667bbe628edSCyrille Pitchen 		return false;
668bbe628edSCyrille Pitchen 
669bbe628edSCyrille Pitchen 	for (nents = 0; sg; sg = sg_next(sg), ++nents) {
670bbe628edSCyrille Pitchen 		if (!IS_ALIGNED(sg->offset, sizeof(u32)))
671bbe628edSCyrille Pitchen 			return false;
672bbe628edSCyrille Pitchen 
673bbe628edSCyrille Pitchen 		if (len <= sg->length) {
674bbe628edSCyrille Pitchen 			if (!IS_ALIGNED(len, dd->ctx->block_size))
675bbe628edSCyrille Pitchen 				return false;
676bbe628edSCyrille Pitchen 
677bbe628edSCyrille Pitchen 			dma->nents = nents+1;
678bbe628edSCyrille Pitchen 			dma->remainder = sg->length - len;
679bbe628edSCyrille Pitchen 			sg->length = len;
680bbe628edSCyrille Pitchen 			return true;
681bbe628edSCyrille Pitchen 		}
682bbe628edSCyrille Pitchen 
683bbe628edSCyrille Pitchen 		if (!IS_ALIGNED(sg->length, dd->ctx->block_size))
684bbe628edSCyrille Pitchen 			return false;
685bbe628edSCyrille Pitchen 
686bbe628edSCyrille Pitchen 		len -= sg->length;
687bbe628edSCyrille Pitchen 	}
688bbe628edSCyrille Pitchen 
689bbe628edSCyrille Pitchen 	return false;
690bbe628edSCyrille Pitchen }
691bbe628edSCyrille Pitchen 
atmel_aes_restore_sg(const struct atmel_aes_dma * dma)692bbe628edSCyrille Pitchen static inline void atmel_aes_restore_sg(const struct atmel_aes_dma *dma)
693bbe628edSCyrille Pitchen {
694bbe628edSCyrille Pitchen 	struct scatterlist *sg = dma->sg;
695bbe628edSCyrille Pitchen 	int nents = dma->nents;
696bbe628edSCyrille Pitchen 
697bbe628edSCyrille Pitchen 	if (!dma->remainder)
698bbe628edSCyrille Pitchen 		return;
699bbe628edSCyrille Pitchen 
700bbe628edSCyrille Pitchen 	while (--nents > 0 && sg)
701bbe628edSCyrille Pitchen 		sg = sg_next(sg);
702bbe628edSCyrille Pitchen 
703bbe628edSCyrille Pitchen 	if (!sg)
704bbe628edSCyrille Pitchen 		return;
705bbe628edSCyrille Pitchen 
706bbe628edSCyrille Pitchen 	sg->length += dma->remainder;
707bbe628edSCyrille Pitchen }
708bbe628edSCyrille Pitchen 
atmel_aes_map(struct atmel_aes_dev * dd,struct scatterlist * src,struct scatterlist * dst,size_t len)709bbe628edSCyrille Pitchen static int atmel_aes_map(struct atmel_aes_dev *dd,
710bbe628edSCyrille Pitchen 			 struct scatterlist *src,
711bbe628edSCyrille Pitchen 			 struct scatterlist *dst,
712bbe628edSCyrille Pitchen 			 size_t len)
713bbe628edSCyrille Pitchen {
714bbe628edSCyrille Pitchen 	bool src_aligned, dst_aligned;
715bbe628edSCyrille Pitchen 	size_t padlen;
716bbe628edSCyrille Pitchen 
717bbe628edSCyrille Pitchen 	dd->total = len;
718bbe628edSCyrille Pitchen 	dd->src.sg = src;
719bbe628edSCyrille Pitchen 	dd->dst.sg = dst;
720bbe628edSCyrille Pitchen 	dd->real_dst = dst;
721bbe628edSCyrille Pitchen 
722bbe628edSCyrille Pitchen 	src_aligned = atmel_aes_check_aligned(dd, src, len, &dd->src);
723bbe628edSCyrille Pitchen 	if (src == dst)
724bbe628edSCyrille Pitchen 		dst_aligned = src_aligned;
725bbe628edSCyrille Pitchen 	else
726bbe628edSCyrille Pitchen 		dst_aligned = atmel_aes_check_aligned(dd, dst, len, &dd->dst);
727bbe628edSCyrille Pitchen 	if (!src_aligned || !dst_aligned) {
728bbe628edSCyrille Pitchen 		padlen = atmel_aes_padlen(len, dd->ctx->block_size);
729bbe628edSCyrille Pitchen 
730bbe628edSCyrille Pitchen 		if (dd->buflen < len + padlen)
731bbe628edSCyrille Pitchen 			return -ENOMEM;
732bbe628edSCyrille Pitchen 
733bbe628edSCyrille Pitchen 		if (!src_aligned) {
734bbe628edSCyrille Pitchen 			sg_copy_to_buffer(src, sg_nents(src), dd->buf, len);
735bbe628edSCyrille Pitchen 			dd->src.sg = &dd->aligned_sg;
736bbe628edSCyrille Pitchen 			dd->src.nents = 1;
737bbe628edSCyrille Pitchen 			dd->src.remainder = 0;
738bbe628edSCyrille Pitchen 		}
739bbe628edSCyrille Pitchen 
740bbe628edSCyrille Pitchen 		if (!dst_aligned) {
741bbe628edSCyrille Pitchen 			dd->dst.sg = &dd->aligned_sg;
742bbe628edSCyrille Pitchen 			dd->dst.nents = 1;
743bbe628edSCyrille Pitchen 			dd->dst.remainder = 0;
744bbe628edSCyrille Pitchen 		}
745bbe628edSCyrille Pitchen 
746bbe628edSCyrille Pitchen 		sg_init_table(&dd->aligned_sg, 1);
747bbe628edSCyrille Pitchen 		sg_set_buf(&dd->aligned_sg, dd->buf, len + padlen);
748bbe628edSCyrille Pitchen 	}
749bbe628edSCyrille Pitchen 
750bbe628edSCyrille Pitchen 	if (dd->src.sg == dd->dst.sg) {
751bbe628edSCyrille Pitchen 		dd->src.sg_len = dma_map_sg(dd->dev, dd->src.sg, dd->src.nents,
752bbe628edSCyrille Pitchen 					    DMA_BIDIRECTIONAL);
753bbe628edSCyrille Pitchen 		dd->dst.sg_len = dd->src.sg_len;
754bbe628edSCyrille Pitchen 		if (!dd->src.sg_len)
755bbe628edSCyrille Pitchen 			return -EFAULT;
756bbe628edSCyrille Pitchen 	} else {
757bbe628edSCyrille Pitchen 		dd->src.sg_len = dma_map_sg(dd->dev, dd->src.sg, dd->src.nents,
758bbe628edSCyrille Pitchen 					    DMA_TO_DEVICE);
759bbe628edSCyrille Pitchen 		if (!dd->src.sg_len)
760bbe628edSCyrille Pitchen 			return -EFAULT;
761bbe628edSCyrille Pitchen 
762bbe628edSCyrille Pitchen 		dd->dst.sg_len = dma_map_sg(dd->dev, dd->dst.sg, dd->dst.nents,
763bbe628edSCyrille Pitchen 					    DMA_FROM_DEVICE);
764bbe628edSCyrille Pitchen 		if (!dd->dst.sg_len) {
765bbe628edSCyrille Pitchen 			dma_unmap_sg(dd->dev, dd->src.sg, dd->src.nents,
766bbe628edSCyrille Pitchen 				     DMA_TO_DEVICE);
767bbe628edSCyrille Pitchen 			return -EFAULT;
768bbe628edSCyrille Pitchen 		}
769bbe628edSCyrille Pitchen 	}
770bbe628edSCyrille Pitchen 
771bbe628edSCyrille Pitchen 	return 0;
772bbe628edSCyrille Pitchen }
773bbe628edSCyrille Pitchen 
atmel_aes_unmap(struct atmel_aes_dev * dd)774bbe628edSCyrille Pitchen static void atmel_aes_unmap(struct atmel_aes_dev *dd)
775bbe628edSCyrille Pitchen {
776bbe628edSCyrille Pitchen 	if (dd->src.sg == dd->dst.sg) {
777bbe628edSCyrille Pitchen 		dma_unmap_sg(dd->dev, dd->src.sg, dd->src.nents,
778bbe628edSCyrille Pitchen 			     DMA_BIDIRECTIONAL);
779bbe628edSCyrille Pitchen 
780bbe628edSCyrille Pitchen 		if (dd->src.sg != &dd->aligned_sg)
781bbe628edSCyrille Pitchen 			atmel_aes_restore_sg(&dd->src);
782bbe628edSCyrille Pitchen 	} else {
783bbe628edSCyrille Pitchen 		dma_unmap_sg(dd->dev, dd->dst.sg, dd->dst.nents,
784bbe628edSCyrille Pitchen 			     DMA_FROM_DEVICE);
785bbe628edSCyrille Pitchen 
786bbe628edSCyrille Pitchen 		if (dd->dst.sg != &dd->aligned_sg)
787bbe628edSCyrille Pitchen 			atmel_aes_restore_sg(&dd->dst);
788bbe628edSCyrille Pitchen 
789bbe628edSCyrille Pitchen 		dma_unmap_sg(dd->dev, dd->src.sg, dd->src.nents,
790bbe628edSCyrille Pitchen 			     DMA_TO_DEVICE);
791bbe628edSCyrille Pitchen 
792bbe628edSCyrille Pitchen 		if (dd->src.sg != &dd->aligned_sg)
793bbe628edSCyrille Pitchen 			atmel_aes_restore_sg(&dd->src);
794bbe628edSCyrille Pitchen 	}
795bbe628edSCyrille Pitchen 
796bbe628edSCyrille Pitchen 	if (dd->dst.sg == &dd->aligned_sg)
797bbe628edSCyrille Pitchen 		sg_copy_from_buffer(dd->real_dst, sg_nents(dd->real_dst),
798bbe628edSCyrille Pitchen 				    dd->buf, dd->total);
799bbe628edSCyrille Pitchen }
800bbe628edSCyrille Pitchen 
atmel_aes_dma_transfer_start(struct atmel_aes_dev * dd,enum dma_slave_buswidth addr_width,enum dma_transfer_direction dir,u32 maxburst)801bbe628edSCyrille Pitchen static int atmel_aes_dma_transfer_start(struct atmel_aes_dev *dd,
802bbe628edSCyrille Pitchen 					enum dma_slave_buswidth addr_width,
803bbe628edSCyrille Pitchen 					enum dma_transfer_direction dir,
804bbe628edSCyrille Pitchen 					u32 maxburst)
805bbe628edSCyrille Pitchen {
806bbe628edSCyrille Pitchen 	struct dma_async_tx_descriptor *desc;
807bbe628edSCyrille Pitchen 	struct dma_slave_config config;
808bbe628edSCyrille Pitchen 	dma_async_tx_callback callback;
809bbe628edSCyrille Pitchen 	struct atmel_aes_dma *dma;
810bbe628edSCyrille Pitchen 	int err;
811bbe628edSCyrille Pitchen 
812bbe628edSCyrille Pitchen 	memset(&config, 0, sizeof(config));
813bbe628edSCyrille Pitchen 	config.src_addr_width = addr_width;
814bbe628edSCyrille Pitchen 	config.dst_addr_width = addr_width;
815bbe628edSCyrille Pitchen 	config.src_maxburst = maxburst;
816bbe628edSCyrille Pitchen 	config.dst_maxburst = maxburst;
817bbe628edSCyrille Pitchen 
818bbe628edSCyrille Pitchen 	switch (dir) {
819bbe628edSCyrille Pitchen 	case DMA_MEM_TO_DEV:
820bbe628edSCyrille Pitchen 		dma = &dd->src;
821bbe628edSCyrille Pitchen 		callback = NULL;
822bbe628edSCyrille Pitchen 		config.dst_addr = dd->phys_base + AES_IDATAR(0);
823bbe628edSCyrille Pitchen 		break;
824bbe628edSCyrille Pitchen 
825bbe628edSCyrille Pitchen 	case DMA_DEV_TO_MEM:
826bbe628edSCyrille Pitchen 		dma = &dd->dst;
827bbe628edSCyrille Pitchen 		callback = atmel_aes_dma_callback;
828bbe628edSCyrille Pitchen 		config.src_addr = dd->phys_base + AES_ODATAR(0);
829bbe628edSCyrille Pitchen 		break;
830bbe628edSCyrille Pitchen 
831bbe628edSCyrille Pitchen 	default:
832bbe628edSCyrille Pitchen 		return -EINVAL;
833bbe628edSCyrille Pitchen 	}
834bbe628edSCyrille Pitchen 
835bbe628edSCyrille Pitchen 	err = dmaengine_slave_config(dma->chan, &config);
836bbe628edSCyrille Pitchen 	if (err)
837bbe628edSCyrille Pitchen 		return err;
838bbe628edSCyrille Pitchen 
839bbe628edSCyrille Pitchen 	desc = dmaengine_prep_slave_sg(dma->chan, dma->sg, dma->sg_len, dir,
840bbe628edSCyrille Pitchen 				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
841bbe628edSCyrille Pitchen 	if (!desc)
842bbe628edSCyrille Pitchen 		return -ENOMEM;
843bbe628edSCyrille Pitchen 
844bbe628edSCyrille Pitchen 	desc->callback = callback;
845bbe628edSCyrille Pitchen 	desc->callback_param = dd;
846bbe628edSCyrille Pitchen 	dmaengine_submit(desc);
847bbe628edSCyrille Pitchen 	dma_async_issue_pending(dma->chan);
848bbe628edSCyrille Pitchen 
849bbe628edSCyrille Pitchen 	return 0;
850bbe628edSCyrille Pitchen }
851bbe628edSCyrille Pitchen 
atmel_aes_dma_start(struct atmel_aes_dev * dd,struct scatterlist * src,struct scatterlist * dst,size_t len,atmel_aes_fn_t resume)852bbe628edSCyrille Pitchen static int atmel_aes_dma_start(struct atmel_aes_dev *dd,
853bbe628edSCyrille Pitchen 			       struct scatterlist *src,
854bbe628edSCyrille Pitchen 			       struct scatterlist *dst,
855bbe628edSCyrille Pitchen 			       size_t len,
856bbe628edSCyrille Pitchen 			       atmel_aes_fn_t resume)
857bbe628edSCyrille Pitchen {
85877dacf5fSCyrille Pitchen 	enum dma_slave_buswidth addr_width;
85977dacf5fSCyrille Pitchen 	u32 maxburst;
860bbe628edSCyrille Pitchen 	int err;
86177dacf5fSCyrille Pitchen 
86277dacf5fSCyrille Pitchen 	switch (dd->ctx->block_size) {
86377dacf5fSCyrille Pitchen 	case CFB8_BLOCK_SIZE:
86477dacf5fSCyrille Pitchen 		addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
86577dacf5fSCyrille Pitchen 		maxburst = 1;
86677dacf5fSCyrille Pitchen 		break;
86777dacf5fSCyrille Pitchen 
86877dacf5fSCyrille Pitchen 	case CFB16_BLOCK_SIZE:
86977dacf5fSCyrille Pitchen 		addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
87077dacf5fSCyrille Pitchen 		maxburst = 1;
87177dacf5fSCyrille Pitchen 		break;
87277dacf5fSCyrille Pitchen 
87377dacf5fSCyrille Pitchen 	case CFB32_BLOCK_SIZE:
87477dacf5fSCyrille Pitchen 	case CFB64_BLOCK_SIZE:
87577dacf5fSCyrille Pitchen 		addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
87677dacf5fSCyrille Pitchen 		maxburst = 1;
87777dacf5fSCyrille Pitchen 		break;
87877dacf5fSCyrille Pitchen 
87977dacf5fSCyrille Pitchen 	case AES_BLOCK_SIZE:
88077dacf5fSCyrille Pitchen 		addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
88177dacf5fSCyrille Pitchen 		maxburst = dd->caps.max_burst_size;
88277dacf5fSCyrille Pitchen 		break;
88377dacf5fSCyrille Pitchen 
88477dacf5fSCyrille Pitchen 	default:
885bbe628edSCyrille Pitchen 		err = -EINVAL;
886bbe628edSCyrille Pitchen 		goto exit;
88777dacf5fSCyrille Pitchen 	}
888bd3c7b5cSNicolas Royer 
889bbe628edSCyrille Pitchen 	err = atmel_aes_map(dd, src, dst, len);
890bbe628edSCyrille Pitchen 	if (err)
891bbe628edSCyrille Pitchen 		goto exit;
892bd3c7b5cSNicolas Royer 
893bbe628edSCyrille Pitchen 	dd->resume = resume;
894bd3c7b5cSNicolas Royer 
895bbe628edSCyrille Pitchen 	/* Set output DMA transfer first */
896bbe628edSCyrille Pitchen 	err = atmel_aes_dma_transfer_start(dd, addr_width, DMA_DEV_TO_MEM,
897bbe628edSCyrille Pitchen 					   maxburst);
898bbe628edSCyrille Pitchen 	if (err)
899bbe628edSCyrille Pitchen 		goto unmap;
900cadc4ab8SNicolas Royer 
901bbe628edSCyrille Pitchen 	/* Then set input DMA transfer */
902bbe628edSCyrille Pitchen 	err = atmel_aes_dma_transfer_start(dd, addr_width, DMA_MEM_TO_DEV,
903bbe628edSCyrille Pitchen 					   maxburst);
904bbe628edSCyrille Pitchen 	if (err)
905bbe628edSCyrille Pitchen 		goto output_transfer_stop;
906cadc4ab8SNicolas Royer 
90710f12c1bSCyrille Pitchen 	return -EINPROGRESS;
908bbe628edSCyrille Pitchen 
909bbe628edSCyrille Pitchen output_transfer_stop:
9100e693789STudor Ambarus 	dmaengine_terminate_sync(dd->dst.chan);
911bbe628edSCyrille Pitchen unmap:
912bbe628edSCyrille Pitchen 	atmel_aes_unmap(dd);
913bbe628edSCyrille Pitchen exit:
914bbe628edSCyrille Pitchen 	return atmel_aes_complete(dd, err);
915bd3c7b5cSNicolas Royer }
916bd3c7b5cSNicolas Royer 
atmel_aes_dma_callback(void * data)917bbe628edSCyrille Pitchen static void atmel_aes_dma_callback(void *data)
918bbe628edSCyrille Pitchen {
919bbe628edSCyrille Pitchen 	struct atmel_aes_dev *dd = data;
920bd3c7b5cSNicolas Royer 
9210e693789STudor Ambarus 	atmel_aes_unmap(dd);
922bbe628edSCyrille Pitchen 	dd->is_async = true;
923bbe628edSCyrille Pitchen 	(void)dd->resume(dd);
924bd3c7b5cSNicolas Royer }
925bd3c7b5cSNicolas Royer 
atmel_aes_handle_queue(struct atmel_aes_dev * dd,struct crypto_async_request * new_areq)926bd3c7b5cSNicolas Royer static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
927ccbf7298SCyrille Pitchen 				  struct crypto_async_request *new_areq)
928bd3c7b5cSNicolas Royer {
929ccbf7298SCyrille Pitchen 	struct crypto_async_request *areq, *backlog;
930ccbf7298SCyrille Pitchen 	struct atmel_aes_base_ctx *ctx;
931bd3c7b5cSNicolas Royer 	unsigned long flags;
932a1f613f1SCyrille Pitchen 	bool start_async;
933bd3c7b5cSNicolas Royer 	int err, ret = 0;
934bd3c7b5cSNicolas Royer 
935bd3c7b5cSNicolas Royer 	spin_lock_irqsave(&dd->lock, flags);
936ccbf7298SCyrille Pitchen 	if (new_areq)
937ccbf7298SCyrille Pitchen 		ret = crypto_enqueue_request(&dd->queue, new_areq);
938bd3c7b5cSNicolas Royer 	if (dd->flags & AES_FLAGS_BUSY) {
939bd3c7b5cSNicolas Royer 		spin_unlock_irqrestore(&dd->lock, flags);
940bd3c7b5cSNicolas Royer 		return ret;
941bd3c7b5cSNicolas Royer 	}
942bd3c7b5cSNicolas Royer 	backlog = crypto_get_backlog(&dd->queue);
943ccbf7298SCyrille Pitchen 	areq = crypto_dequeue_request(&dd->queue);
944ccbf7298SCyrille Pitchen 	if (areq)
945bd3c7b5cSNicolas Royer 		dd->flags |= AES_FLAGS_BUSY;
946bd3c7b5cSNicolas Royer 	spin_unlock_irqrestore(&dd->lock, flags);
947bd3c7b5cSNicolas Royer 
948ccbf7298SCyrille Pitchen 	if (!areq)
949bd3c7b5cSNicolas Royer 		return ret;
950bd3c7b5cSNicolas Royer 
951bd3c7b5cSNicolas Royer 	if (backlog)
9527d19abdcSHerbert Xu 		crypto_request_complete(backlog, -EINPROGRESS);
953bd3c7b5cSNicolas Royer 
954ccbf7298SCyrille Pitchen 	ctx = crypto_tfm_ctx(areq->tfm);
955ccbf7298SCyrille Pitchen 
956ccbf7298SCyrille Pitchen 	dd->areq = areq;
9576d48de65STudor Ambarus 	dd->ctx = ctx;
958a1f613f1SCyrille Pitchen 	start_async = (areq != new_areq);
959a1f613f1SCyrille Pitchen 	dd->is_async = start_async;
960ccbf7298SCyrille Pitchen 
961a1f613f1SCyrille Pitchen 	/* WARNING: ctx->start() MAY change dd->is_async. */
962ccbf7298SCyrille Pitchen 	err = ctx->start(dd);
963a1f613f1SCyrille Pitchen 	return (start_async) ? ret : err;
964ccbf7298SCyrille Pitchen }
965ccbf7298SCyrille Pitchen 
966e37a7e55SCyrille Pitchen 
967e37a7e55SCyrille Pitchen /* AES async block ciphers */
968e37a7e55SCyrille Pitchen 
atmel_aes_transfer_complete(struct atmel_aes_dev * dd)969bbe628edSCyrille Pitchen static int atmel_aes_transfer_complete(struct atmel_aes_dev *dd)
970bbe628edSCyrille Pitchen {
971bbe628edSCyrille Pitchen 	return atmel_aes_complete(dd, 0);
972bbe628edSCyrille Pitchen }
973bbe628edSCyrille Pitchen 
atmel_aes_start(struct atmel_aes_dev * dd)974ccbf7298SCyrille Pitchen static int atmel_aes_start(struct atmel_aes_dev *dd)
975ccbf7298SCyrille Pitchen {
9767ada42d2SArd Biesheuvel 	struct skcipher_request *req = skcipher_request_cast(dd->areq);
9777ada42d2SArd Biesheuvel 	struct atmel_aes_reqctx *rctx = skcipher_request_ctx(req);
9787ada42d2SArd Biesheuvel 	bool use_dma = (req->cryptlen >= ATMEL_AES_DMA_THRESHOLD ||
979bbe628edSCyrille Pitchen 			dd->ctx->block_size != AES_BLOCK_SIZE);
980ccbf7298SCyrille Pitchen 	int err;
981bd3c7b5cSNicolas Royer 
98277dacf5fSCyrille Pitchen 	atmel_aes_set_mode(dd, rctx);
983bd3c7b5cSNicolas Royer 
984cdfab4a7SCyrille Pitchen 	err = atmel_aes_hw_init(dd);
985bbe628edSCyrille Pitchen 	if (err)
986bbe628edSCyrille Pitchen 		return atmel_aes_complete(dd, err);
987bbe628edSCyrille Pitchen 
9887ada42d2SArd Biesheuvel 	atmel_aes_write_ctrl(dd, use_dma, (void *)req->iv);
989cdfab4a7SCyrille Pitchen 	if (use_dma)
9907ada42d2SArd Biesheuvel 		return atmel_aes_dma_start(dd, req->src, req->dst,
9917ada42d2SArd Biesheuvel 					   req->cryptlen,
992bbe628edSCyrille Pitchen 					   atmel_aes_transfer_complete);
993bd3c7b5cSNicolas Royer 
9947ada42d2SArd Biesheuvel 	return atmel_aes_cpu_start(dd, req->src, req->dst, req->cryptlen,
995bbe628edSCyrille Pitchen 				   atmel_aes_transfer_complete);
996bd3c7b5cSNicolas Royer }
997bd3c7b5cSNicolas Royer 
atmel_aes_ctr_transfer(struct atmel_aes_dev * dd)998fcac8365SCyrille Pitchen static int atmel_aes_ctr_transfer(struct atmel_aes_dev *dd)
999fcac8365SCyrille Pitchen {
1000fcac8365SCyrille Pitchen 	struct atmel_aes_ctr_ctx *ctx = atmel_aes_ctr_ctx_cast(dd->ctx);
10017ada42d2SArd Biesheuvel 	struct skcipher_request *req = skcipher_request_cast(dd->areq);
1002fcac8365SCyrille Pitchen 	struct scatterlist *src, *dst;
1003fcac8365SCyrille Pitchen 	size_t datalen;
1004781a08d9STudor Ambarus 	u32 ctr;
1005371731ecSTudor Ambarus 	u16 start, end;
1006fcac8365SCyrille Pitchen 	bool use_dma, fragmented = false;
1007fcac8365SCyrille Pitchen 
1008fcac8365SCyrille Pitchen 	/* Check for transfer completion. */
1009fcac8365SCyrille Pitchen 	ctx->offset += dd->total;
10107ada42d2SArd Biesheuvel 	if (ctx->offset >= req->cryptlen)
1011fcac8365SCyrille Pitchen 		return atmel_aes_transfer_complete(dd);
1012fcac8365SCyrille Pitchen 
1013fcac8365SCyrille Pitchen 	/* Compute data length. */
10147ada42d2SArd Biesheuvel 	datalen = req->cryptlen - ctx->offset;
1015371731ecSTudor Ambarus 	ctx->blocks = DIV_ROUND_UP(datalen, AES_BLOCK_SIZE);
1016fcac8365SCyrille Pitchen 	ctr = be32_to_cpu(ctx->iv[3]);
1017fcac8365SCyrille Pitchen 
1018fcac8365SCyrille Pitchen 	/* Check 16bit counter overflow. */
1019781a08d9STudor Ambarus 	start = ctr & 0xffff;
1020371731ecSTudor Ambarus 	end = start + ctx->blocks - 1;
1021fcac8365SCyrille Pitchen 
1022371731ecSTudor Ambarus 	if (ctx->blocks >> 16 || end < start) {
1023fcac8365SCyrille Pitchen 		ctr |= 0xffff;
1024fcac8365SCyrille Pitchen 		datalen = AES_BLOCK_SIZE * (0x10000 - start);
1025fcac8365SCyrille Pitchen 		fragmented = true;
1026fcac8365SCyrille Pitchen 	}
1027781a08d9STudor Ambarus 
1028fcac8365SCyrille Pitchen 	use_dma = (datalen >= ATMEL_AES_DMA_THRESHOLD);
1029fcac8365SCyrille Pitchen 
1030fcac8365SCyrille Pitchen 	/* Jump to offset. */
1031fcac8365SCyrille Pitchen 	src = scatterwalk_ffwd(ctx->src, req->src, ctx->offset);
1032fcac8365SCyrille Pitchen 	dst = ((req->src == req->dst) ? src :
1033fcac8365SCyrille Pitchen 	       scatterwalk_ffwd(ctx->dst, req->dst, ctx->offset));
1034fcac8365SCyrille Pitchen 
1035fcac8365SCyrille Pitchen 	/* Configure hardware. */
1036fcac8365SCyrille Pitchen 	atmel_aes_write_ctrl(dd, use_dma, ctx->iv);
1037fcac8365SCyrille Pitchen 	if (unlikely(fragmented)) {
1038fcac8365SCyrille Pitchen 		/*
1039fcac8365SCyrille Pitchen 		 * Increment the counter manually to cope with the hardware
1040fcac8365SCyrille Pitchen 		 * counter overflow.
1041fcac8365SCyrille Pitchen 		 */
1042fcac8365SCyrille Pitchen 		ctx->iv[3] = cpu_to_be32(ctr);
1043fcac8365SCyrille Pitchen 		crypto_inc((u8 *)ctx->iv, AES_BLOCK_SIZE);
1044fcac8365SCyrille Pitchen 	}
1045fcac8365SCyrille Pitchen 
1046fcac8365SCyrille Pitchen 	if (use_dma)
1047fcac8365SCyrille Pitchen 		return atmel_aes_dma_start(dd, src, dst, datalen,
1048fcac8365SCyrille Pitchen 					   atmel_aes_ctr_transfer);
1049fcac8365SCyrille Pitchen 
1050fcac8365SCyrille Pitchen 	return atmel_aes_cpu_start(dd, src, dst, datalen,
1051fcac8365SCyrille Pitchen 				   atmel_aes_ctr_transfer);
1052fcac8365SCyrille Pitchen }
1053fcac8365SCyrille Pitchen 
atmel_aes_ctr_start(struct atmel_aes_dev * dd)1054fcac8365SCyrille Pitchen static int atmel_aes_ctr_start(struct atmel_aes_dev *dd)
1055fcac8365SCyrille Pitchen {
1056fcac8365SCyrille Pitchen 	struct atmel_aes_ctr_ctx *ctx = atmel_aes_ctr_ctx_cast(dd->ctx);
10577ada42d2SArd Biesheuvel 	struct skcipher_request *req = skcipher_request_cast(dd->areq);
10587ada42d2SArd Biesheuvel 	struct atmel_aes_reqctx *rctx = skcipher_request_ctx(req);
1059fcac8365SCyrille Pitchen 	int err;
1060fcac8365SCyrille Pitchen 
1061fcac8365SCyrille Pitchen 	atmel_aes_set_mode(dd, rctx);
1062fcac8365SCyrille Pitchen 
1063fcac8365SCyrille Pitchen 	err = atmel_aes_hw_init(dd);
1064fcac8365SCyrille Pitchen 	if (err)
1065fcac8365SCyrille Pitchen 		return atmel_aes_complete(dd, err);
1066fcac8365SCyrille Pitchen 
10677ada42d2SArd Biesheuvel 	memcpy(ctx->iv, req->iv, AES_BLOCK_SIZE);
1068fcac8365SCyrille Pitchen 	ctx->offset = 0;
1069fcac8365SCyrille Pitchen 	dd->total = 0;
1070fcac8365SCyrille Pitchen 	return atmel_aes_ctr_transfer(dd);
1071fcac8365SCyrille Pitchen }
1072fcac8365SCyrille Pitchen 
atmel_aes_xts_fallback(struct skcipher_request * req,bool enc)1073bf2db8e7STudor Ambarus static int atmel_aes_xts_fallback(struct skcipher_request *req, bool enc)
1074bf2db8e7STudor Ambarus {
1075bf2db8e7STudor Ambarus 	struct atmel_aes_reqctx *rctx = skcipher_request_ctx(req);
1076bf2db8e7STudor Ambarus 	struct atmel_aes_xts_ctx *ctx = crypto_skcipher_ctx(
1077bf2db8e7STudor Ambarus 			crypto_skcipher_reqtfm(req));
1078bf2db8e7STudor Ambarus 
1079bf2db8e7STudor Ambarus 	skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
1080bf2db8e7STudor Ambarus 	skcipher_request_set_callback(&rctx->fallback_req, req->base.flags,
1081bf2db8e7STudor Ambarus 				      req->base.complete, req->base.data);
1082bf2db8e7STudor Ambarus 	skcipher_request_set_crypt(&rctx->fallback_req, req->src, req->dst,
1083bf2db8e7STudor Ambarus 				   req->cryptlen, req->iv);
1084bf2db8e7STudor Ambarus 
1085bf2db8e7STudor Ambarus 	return enc ? crypto_skcipher_encrypt(&rctx->fallback_req) :
1086bf2db8e7STudor Ambarus 		     crypto_skcipher_decrypt(&rctx->fallback_req);
1087bf2db8e7STudor Ambarus }
1088bf2db8e7STudor Ambarus 
atmel_aes_crypt(struct skcipher_request * req,unsigned long mode)10897ada42d2SArd Biesheuvel static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode)
1090bd3c7b5cSNicolas Royer {
10917ada42d2SArd Biesheuvel 	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
10927ada42d2SArd Biesheuvel 	struct atmel_aes_base_ctx *ctx = crypto_skcipher_ctx(skcipher);
1093afbac17eSCyrille Pitchen 	struct atmel_aes_reqctx *rctx;
1094534b32a8STudor Ambarus 	u32 opmode = mode & AES_FLAGS_OPMODE_MASK;
1095534b32a8STudor Ambarus 
1096bf2db8e7STudor Ambarus 	if (opmode == AES_FLAGS_XTS) {
1097bf2db8e7STudor Ambarus 		if (req->cryptlen < XTS_BLOCK_SIZE)
109826d769aeSTudor Ambarus 			return -EINVAL;
109926d769aeSTudor Ambarus 
1100bf2db8e7STudor Ambarus 		if (!IS_ALIGNED(req->cryptlen, XTS_BLOCK_SIZE))
1101bf2db8e7STudor Ambarus 			return atmel_aes_xts_fallback(req,
1102bf2db8e7STudor Ambarus 						      mode & AES_FLAGS_ENCRYPT);
1103bf2db8e7STudor Ambarus 	}
1104bf2db8e7STudor Ambarus 
11050d043359STudor Ambarus 	/*
11060d043359STudor Ambarus 	 * ECB, CBC, CFB, OFB or CTR mode require the plaintext and ciphertext
11070d043359STudor Ambarus 	 * to have a positve integer length.
11080d043359STudor Ambarus 	 */
11090d043359STudor Ambarus 	if (!req->cryptlen && opmode != AES_FLAGS_XTS)
11100d043359STudor Ambarus 		return 0;
11110d043359STudor Ambarus 
1112534b32a8STudor Ambarus 	if ((opmode == AES_FLAGS_ECB || opmode == AES_FLAGS_CBC) &&
1113534b32a8STudor Ambarus 	    !IS_ALIGNED(req->cryptlen, crypto_skcipher_blocksize(skcipher)))
1114534b32a8STudor Ambarus 		return -EINVAL;
1115bd3c7b5cSNicolas Royer 
111677dacf5fSCyrille Pitchen 	switch (mode & AES_FLAGS_OPMODE_MASK) {
111777dacf5fSCyrille Pitchen 	case AES_FLAGS_CFB8:
1118cadc4ab8SNicolas Royer 		ctx->block_size = CFB8_BLOCK_SIZE;
111977dacf5fSCyrille Pitchen 		break;
112077dacf5fSCyrille Pitchen 
112177dacf5fSCyrille Pitchen 	case AES_FLAGS_CFB16:
1122cadc4ab8SNicolas Royer 		ctx->block_size = CFB16_BLOCK_SIZE;
112377dacf5fSCyrille Pitchen 		break;
112477dacf5fSCyrille Pitchen 
112577dacf5fSCyrille Pitchen 	case AES_FLAGS_CFB32:
1126cadc4ab8SNicolas Royer 		ctx->block_size = CFB32_BLOCK_SIZE;
112777dacf5fSCyrille Pitchen 		break;
112877dacf5fSCyrille Pitchen 
112977dacf5fSCyrille Pitchen 	case AES_FLAGS_CFB64:
11309f84951fSLeilei Zhao 		ctx->block_size = CFB64_BLOCK_SIZE;
113177dacf5fSCyrille Pitchen 		break;
113277dacf5fSCyrille Pitchen 
113377dacf5fSCyrille Pitchen 	default:
1134cadc4ab8SNicolas Royer 		ctx->block_size = AES_BLOCK_SIZE;
113577dacf5fSCyrille Pitchen 		break;
1136cadc4ab8SNicolas Royer 	}
113791308019SRomain Izard 	ctx->is_aead = false;
1138bd3c7b5cSNicolas Royer 
11397ada42d2SArd Biesheuvel 	rctx = skcipher_request_ctx(req);
1140bd3c7b5cSNicolas Royer 	rctx->mode = mode;
1141bd3c7b5cSNicolas Royer 
1142534b32a8STudor Ambarus 	if (opmode != AES_FLAGS_ECB &&
11432fbe4829SRyan Wanner 	    !(mode & AES_FLAGS_ENCRYPT)) {
11447ada42d2SArd Biesheuvel 		unsigned int ivsize = crypto_skcipher_ivsize(skcipher);
114591308019SRomain Izard 
11467ada42d2SArd Biesheuvel 		if (req->cryptlen >= ivsize)
114791308019SRomain Izard 			scatterwalk_map_and_copy(rctx->lastc, req->src,
11487ada42d2SArd Biesheuvel 						 req->cryptlen - ivsize,
114986ef1dfcSTudor Ambarus 						 ivsize, 0);
115091308019SRomain Izard 	}
115191308019SRomain Izard 
1152ec2088b6STudor Ambarus 	return atmel_aes_handle_queue(ctx->dd, &req->base);
1153bd3c7b5cSNicolas Royer }
1154bd3c7b5cSNicolas Royer 
atmel_aes_setkey(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)11557ada42d2SArd Biesheuvel static int atmel_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
1156bd3c7b5cSNicolas Royer 			   unsigned int keylen)
1157bd3c7b5cSNicolas Royer {
11587ada42d2SArd Biesheuvel 	struct atmel_aes_base_ctx *ctx = crypto_skcipher_ctx(tfm);
1159bd3c7b5cSNicolas Royer 
1160afbac17eSCyrille Pitchen 	if (keylen != AES_KEYSIZE_128 &&
1161afbac17eSCyrille Pitchen 	    keylen != AES_KEYSIZE_192 &&
1162674f368aSEric Biggers 	    keylen != AES_KEYSIZE_256)
1163bd3c7b5cSNicolas Royer 		return -EINVAL;
1164bd3c7b5cSNicolas Royer 
1165bd3c7b5cSNicolas Royer 	memcpy(ctx->key, key, keylen);
1166bd3c7b5cSNicolas Royer 	ctx->keylen = keylen;
1167bd3c7b5cSNicolas Royer 
1168bd3c7b5cSNicolas Royer 	return 0;
1169bd3c7b5cSNicolas Royer }
1170bd3c7b5cSNicolas Royer 
atmel_aes_ecb_encrypt(struct skcipher_request * req)11717ada42d2SArd Biesheuvel static int atmel_aes_ecb_encrypt(struct skcipher_request *req)
1172bd3c7b5cSNicolas Royer {
117377dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_ECB | AES_FLAGS_ENCRYPT);
1174bd3c7b5cSNicolas Royer }
1175bd3c7b5cSNicolas Royer 
atmel_aes_ecb_decrypt(struct skcipher_request * req)11767ada42d2SArd Biesheuvel static int atmel_aes_ecb_decrypt(struct skcipher_request *req)
1177bd3c7b5cSNicolas Royer {
117877dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_ECB);
1179bd3c7b5cSNicolas Royer }
1180bd3c7b5cSNicolas Royer 
atmel_aes_cbc_encrypt(struct skcipher_request * req)11817ada42d2SArd Biesheuvel static int atmel_aes_cbc_encrypt(struct skcipher_request *req)
1182bd3c7b5cSNicolas Royer {
1183afbac17eSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CBC | AES_FLAGS_ENCRYPT);
1184bd3c7b5cSNicolas Royer }
1185bd3c7b5cSNicolas Royer 
atmel_aes_cbc_decrypt(struct skcipher_request * req)11867ada42d2SArd Biesheuvel static int atmel_aes_cbc_decrypt(struct skcipher_request *req)
1187bd3c7b5cSNicolas Royer {
1188afbac17eSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CBC);
1189bd3c7b5cSNicolas Royer }
1190bd3c7b5cSNicolas Royer 
atmel_aes_ofb_encrypt(struct skcipher_request * req)11917ada42d2SArd Biesheuvel static int atmel_aes_ofb_encrypt(struct skcipher_request *req)
1192bd3c7b5cSNicolas Royer {
1193afbac17eSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_OFB | AES_FLAGS_ENCRYPT);
1194bd3c7b5cSNicolas Royer }
1195bd3c7b5cSNicolas Royer 
atmel_aes_ofb_decrypt(struct skcipher_request * req)11967ada42d2SArd Biesheuvel static int atmel_aes_ofb_decrypt(struct skcipher_request *req)
1197bd3c7b5cSNicolas Royer {
1198afbac17eSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_OFB);
1199bd3c7b5cSNicolas Royer }
1200bd3c7b5cSNicolas Royer 
atmel_aes_cfb_encrypt(struct skcipher_request * req)12017ada42d2SArd Biesheuvel static int atmel_aes_cfb_encrypt(struct skcipher_request *req)
1202bd3c7b5cSNicolas Royer {
120377dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB128 | AES_FLAGS_ENCRYPT);
1204bd3c7b5cSNicolas Royer }
1205bd3c7b5cSNicolas Royer 
atmel_aes_cfb_decrypt(struct skcipher_request * req)12067ada42d2SArd Biesheuvel static int atmel_aes_cfb_decrypt(struct skcipher_request *req)
1207bd3c7b5cSNicolas Royer {
120877dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB128);
1209bd3c7b5cSNicolas Royer }
1210bd3c7b5cSNicolas Royer 
atmel_aes_cfb64_encrypt(struct skcipher_request * req)12117ada42d2SArd Biesheuvel static int atmel_aes_cfb64_encrypt(struct skcipher_request *req)
1212bd3c7b5cSNicolas Royer {
121377dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB64 | AES_FLAGS_ENCRYPT);
1214bd3c7b5cSNicolas Royer }
1215bd3c7b5cSNicolas Royer 
atmel_aes_cfb64_decrypt(struct skcipher_request * req)12167ada42d2SArd Biesheuvel static int atmel_aes_cfb64_decrypt(struct skcipher_request *req)
1217bd3c7b5cSNicolas Royer {
121877dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB64);
1219bd3c7b5cSNicolas Royer }
1220bd3c7b5cSNicolas Royer 
atmel_aes_cfb32_encrypt(struct skcipher_request * req)12217ada42d2SArd Biesheuvel static int atmel_aes_cfb32_encrypt(struct skcipher_request *req)
1222bd3c7b5cSNicolas Royer {
122377dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB32 | AES_FLAGS_ENCRYPT);
1224bd3c7b5cSNicolas Royer }
1225bd3c7b5cSNicolas Royer 
atmel_aes_cfb32_decrypt(struct skcipher_request * req)12267ada42d2SArd Biesheuvel static int atmel_aes_cfb32_decrypt(struct skcipher_request *req)
1227bd3c7b5cSNicolas Royer {
122877dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB32);
1229bd3c7b5cSNicolas Royer }
1230bd3c7b5cSNicolas Royer 
atmel_aes_cfb16_encrypt(struct skcipher_request * req)12317ada42d2SArd Biesheuvel static int atmel_aes_cfb16_encrypt(struct skcipher_request *req)
1232bd3c7b5cSNicolas Royer {
123377dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB16 | AES_FLAGS_ENCRYPT);
1234bd3c7b5cSNicolas Royer }
1235bd3c7b5cSNicolas Royer 
atmel_aes_cfb16_decrypt(struct skcipher_request * req)12367ada42d2SArd Biesheuvel static int atmel_aes_cfb16_decrypt(struct skcipher_request *req)
1237bd3c7b5cSNicolas Royer {
123877dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB16);
1239bd3c7b5cSNicolas Royer }
1240bd3c7b5cSNicolas Royer 
atmel_aes_cfb8_encrypt(struct skcipher_request * req)12417ada42d2SArd Biesheuvel static int atmel_aes_cfb8_encrypt(struct skcipher_request *req)
1242bd3c7b5cSNicolas Royer {
124377dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB8 | AES_FLAGS_ENCRYPT);
1244bd3c7b5cSNicolas Royer }
1245bd3c7b5cSNicolas Royer 
atmel_aes_cfb8_decrypt(struct skcipher_request * req)12467ada42d2SArd Biesheuvel static int atmel_aes_cfb8_decrypt(struct skcipher_request *req)
1247bd3c7b5cSNicolas Royer {
124877dacf5fSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CFB8);
1249bd3c7b5cSNicolas Royer }
1250bd3c7b5cSNicolas Royer 
atmel_aes_ctr_encrypt(struct skcipher_request * req)12517ada42d2SArd Biesheuvel static int atmel_aes_ctr_encrypt(struct skcipher_request *req)
1252bd3c7b5cSNicolas Royer {
1253afbac17eSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CTR | AES_FLAGS_ENCRYPT);
1254bd3c7b5cSNicolas Royer }
1255bd3c7b5cSNicolas Royer 
atmel_aes_ctr_decrypt(struct skcipher_request * req)12567ada42d2SArd Biesheuvel static int atmel_aes_ctr_decrypt(struct skcipher_request *req)
1257bd3c7b5cSNicolas Royer {
1258afbac17eSCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_CTR);
1259bd3c7b5cSNicolas Royer }
1260bd3c7b5cSNicolas Royer 
atmel_aes_init_tfm(struct crypto_skcipher * tfm)12617ada42d2SArd Biesheuvel static int atmel_aes_init_tfm(struct crypto_skcipher *tfm)
1262bd3c7b5cSNicolas Royer {
12637ada42d2SArd Biesheuvel 	struct atmel_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
1264ec2088b6STudor Ambarus 	struct atmel_aes_dev *dd;
1265ec2088b6STudor Ambarus 
1266ec2088b6STudor Ambarus 	dd = atmel_aes_dev_alloc(&ctx->base);
1267ec2088b6STudor Ambarus 	if (!dd)
1268ec2088b6STudor Ambarus 		return -ENODEV;
1269ccbf7298SCyrille Pitchen 
12707ada42d2SArd Biesheuvel 	crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx));
1271ec2088b6STudor Ambarus 	ctx->base.dd = dd;
1272ccbf7298SCyrille Pitchen 	ctx->base.start = atmel_aes_start;
1273bd3c7b5cSNicolas Royer 
1274bd3c7b5cSNicolas Royer 	return 0;
1275bd3c7b5cSNicolas Royer }
1276bd3c7b5cSNicolas Royer 
atmel_aes_ctr_init_tfm(struct crypto_skcipher * tfm)12777ada42d2SArd Biesheuvel static int atmel_aes_ctr_init_tfm(struct crypto_skcipher *tfm)
1278fcac8365SCyrille Pitchen {
12797ada42d2SArd Biesheuvel 	struct atmel_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
1280ec2088b6STudor Ambarus 	struct atmel_aes_dev *dd;
1281ec2088b6STudor Ambarus 
1282ec2088b6STudor Ambarus 	dd = atmel_aes_dev_alloc(&ctx->base);
1283ec2088b6STudor Ambarus 	if (!dd)
1284ec2088b6STudor Ambarus 		return -ENODEV;
1285fcac8365SCyrille Pitchen 
12867ada42d2SArd Biesheuvel 	crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx));
1287ec2088b6STudor Ambarus 	ctx->base.dd = dd;
1288fcac8365SCyrille Pitchen 	ctx->base.start = atmel_aes_ctr_start;
1289fcac8365SCyrille Pitchen 
1290fcac8365SCyrille Pitchen 	return 0;
1291fcac8365SCyrille Pitchen }
1292fcac8365SCyrille Pitchen 
12937ada42d2SArd Biesheuvel static struct skcipher_alg aes_algs[] = {
1294bd3c7b5cSNicolas Royer {
12957ada42d2SArd Biesheuvel 	.base.cra_name		= "ecb(aes)",
12967ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-ecb-aes",
12977ada42d2SArd Biesheuvel 	.base.cra_blocksize	= AES_BLOCK_SIZE,
12987ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctx),
12997ada42d2SArd Biesheuvel 
13007ada42d2SArd Biesheuvel 	.init			= atmel_aes_init_tfm,
1301bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1302bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1303bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1304bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_ecb_encrypt,
1305bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_ecb_decrypt,
1306bd3c7b5cSNicolas Royer },
1307bd3c7b5cSNicolas Royer {
13087ada42d2SArd Biesheuvel 	.base.cra_name		= "cbc(aes)",
13097ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-cbc-aes",
13107ada42d2SArd Biesheuvel 	.base.cra_blocksize	= AES_BLOCK_SIZE,
13117ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctx),
13127ada42d2SArd Biesheuvel 
13137ada42d2SArd Biesheuvel 	.init			= atmel_aes_init_tfm,
1314bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1315bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1316bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1317bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_cbc_encrypt,
1318bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_cbc_decrypt,
13197ada42d2SArd Biesheuvel 	.ivsize			= AES_BLOCK_SIZE,
1320bd3c7b5cSNicolas Royer },
1321bd3c7b5cSNicolas Royer {
13227ada42d2SArd Biesheuvel 	.base.cra_name		= "ofb(aes)",
13237ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-ofb-aes",
132476d579f2STudor Ambarus 	.base.cra_blocksize	= 1,
13257ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctx),
13267ada42d2SArd Biesheuvel 
13277ada42d2SArd Biesheuvel 	.init			= atmel_aes_init_tfm,
1328bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1329bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1330bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1331bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_ofb_encrypt,
1332bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_ofb_decrypt,
13337ada42d2SArd Biesheuvel 	.ivsize			= AES_BLOCK_SIZE,
1334bd3c7b5cSNicolas Royer },
1335bd3c7b5cSNicolas Royer {
13367ada42d2SArd Biesheuvel 	.base.cra_name		= "cfb(aes)",
13377ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-cfb-aes",
1338e93c6085SRyan Wanner 	.base.cra_blocksize	= 1,
13397ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctx),
13407ada42d2SArd Biesheuvel 
13417ada42d2SArd Biesheuvel 	.init			= atmel_aes_init_tfm,
1342bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1343bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1344bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1345bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_cfb_encrypt,
1346bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_cfb_decrypt,
13477ada42d2SArd Biesheuvel 	.ivsize			= AES_BLOCK_SIZE,
1348bd3c7b5cSNicolas Royer },
1349bd3c7b5cSNicolas Royer {
13507ada42d2SArd Biesheuvel 	.base.cra_name		= "cfb32(aes)",
13517ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-cfb32-aes",
13527ada42d2SArd Biesheuvel 	.base.cra_blocksize	= CFB32_BLOCK_SIZE,
13537ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctx),
13547ada42d2SArd Biesheuvel 
13557ada42d2SArd Biesheuvel 	.init			= atmel_aes_init_tfm,
1356bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1357bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1358bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1359bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_cfb32_encrypt,
1360bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_cfb32_decrypt,
13617ada42d2SArd Biesheuvel 	.ivsize			= AES_BLOCK_SIZE,
1362bd3c7b5cSNicolas Royer },
1363bd3c7b5cSNicolas Royer {
13647ada42d2SArd Biesheuvel 	.base.cra_name		= "cfb16(aes)",
13657ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-cfb16-aes",
13667ada42d2SArd Biesheuvel 	.base.cra_blocksize	= CFB16_BLOCK_SIZE,
13677ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctx),
13687ada42d2SArd Biesheuvel 
13697ada42d2SArd Biesheuvel 	.init			= atmel_aes_init_tfm,
1370bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1371bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1372bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1373bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_cfb16_encrypt,
1374bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_cfb16_decrypt,
13757ada42d2SArd Biesheuvel 	.ivsize			= AES_BLOCK_SIZE,
1376bd3c7b5cSNicolas Royer },
1377bd3c7b5cSNicolas Royer {
13787ada42d2SArd Biesheuvel 	.base.cra_name		= "cfb8(aes)",
13797ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-cfb8-aes",
13807ada42d2SArd Biesheuvel 	.base.cra_blocksize	= CFB8_BLOCK_SIZE,
13817ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctx),
13827ada42d2SArd Biesheuvel 
13837ada42d2SArd Biesheuvel 	.init			= atmel_aes_init_tfm,
1384bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1385bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1386bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1387bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_cfb8_encrypt,
1388bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_cfb8_decrypt,
13897ada42d2SArd Biesheuvel 	.ivsize			= AES_BLOCK_SIZE,
1390bd3c7b5cSNicolas Royer },
1391bd3c7b5cSNicolas Royer {
13927ada42d2SArd Biesheuvel 	.base.cra_name		= "ctr(aes)",
13937ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-ctr-aes",
13947ada42d2SArd Biesheuvel 	.base.cra_blocksize	= 1,
13957ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctr_ctx),
13967ada42d2SArd Biesheuvel 
13977ada42d2SArd Biesheuvel 	.init			= atmel_aes_ctr_init_tfm,
1398bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1399bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1400bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1401bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_ctr_encrypt,
1402bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_ctr_decrypt,
14037ada42d2SArd Biesheuvel 	.ivsize			= AES_BLOCK_SIZE,
1404bd3c7b5cSNicolas Royer },
1405bd3c7b5cSNicolas Royer };
1406bd3c7b5cSNicolas Royer 
14077ada42d2SArd Biesheuvel static struct skcipher_alg aes_cfb64_alg = {
14087ada42d2SArd Biesheuvel 	.base.cra_name		= "cfb64(aes)",
14097ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-cfb64-aes",
14107ada42d2SArd Biesheuvel 	.base.cra_blocksize	= CFB64_BLOCK_SIZE,
14117ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_ctx),
14127ada42d2SArd Biesheuvel 
14137ada42d2SArd Biesheuvel 	.init			= atmel_aes_init_tfm,
1414bd3c7b5cSNicolas Royer 	.min_keysize		= AES_MIN_KEY_SIZE,
1415bd3c7b5cSNicolas Royer 	.max_keysize		= AES_MAX_KEY_SIZE,
1416bd3c7b5cSNicolas Royer 	.setkey			= atmel_aes_setkey,
1417bd3c7b5cSNicolas Royer 	.encrypt		= atmel_aes_cfb64_encrypt,
1418bd3c7b5cSNicolas Royer 	.decrypt		= atmel_aes_cfb64_decrypt,
14197ada42d2SArd Biesheuvel 	.ivsize			= AES_BLOCK_SIZE,
1420bd3c7b5cSNicolas Royer };
1421bd3c7b5cSNicolas Royer 
1422e37a7e55SCyrille Pitchen 
1423d4419548SCyrille Pitchen /* gcm aead functions */
1424d4419548SCyrille Pitchen 
1425d4419548SCyrille Pitchen static int atmel_aes_gcm_ghash(struct atmel_aes_dev *dd,
1426d4419548SCyrille Pitchen 			       const u32 *data, size_t datalen,
142749c4cd80SBen Dooks (Codethink) 			       const __be32 *ghash_in, __be32 *ghash_out,
1428d4419548SCyrille Pitchen 			       atmel_aes_fn_t resume);
1429d4419548SCyrille Pitchen static int atmel_aes_gcm_ghash_init(struct atmel_aes_dev *dd);
1430d4419548SCyrille Pitchen static int atmel_aes_gcm_ghash_finalize(struct atmel_aes_dev *dd);
1431d4419548SCyrille Pitchen 
1432d4419548SCyrille Pitchen static int atmel_aes_gcm_start(struct atmel_aes_dev *dd);
1433d4419548SCyrille Pitchen static int atmel_aes_gcm_process(struct atmel_aes_dev *dd);
1434d4419548SCyrille Pitchen static int atmel_aes_gcm_length(struct atmel_aes_dev *dd);
1435d4419548SCyrille Pitchen static int atmel_aes_gcm_data(struct atmel_aes_dev *dd);
1436d4419548SCyrille Pitchen static int atmel_aes_gcm_tag_init(struct atmel_aes_dev *dd);
1437d4419548SCyrille Pitchen static int atmel_aes_gcm_tag(struct atmel_aes_dev *dd);
1438d4419548SCyrille Pitchen static int atmel_aes_gcm_finalize(struct atmel_aes_dev *dd);
1439d4419548SCyrille Pitchen 
1440d4419548SCyrille Pitchen static inline struct atmel_aes_gcm_ctx *
atmel_aes_gcm_ctx_cast(struct atmel_aes_base_ctx * ctx)1441d4419548SCyrille Pitchen atmel_aes_gcm_ctx_cast(struct atmel_aes_base_ctx *ctx)
1442d4419548SCyrille Pitchen {
1443d4419548SCyrille Pitchen 	return container_of(ctx, struct atmel_aes_gcm_ctx, base);
1444d4419548SCyrille Pitchen }
1445d4419548SCyrille Pitchen 
atmel_aes_gcm_ghash(struct atmel_aes_dev * dd,const u32 * data,size_t datalen,const __be32 * ghash_in,__be32 * ghash_out,atmel_aes_fn_t resume)1446d4419548SCyrille Pitchen static int atmel_aes_gcm_ghash(struct atmel_aes_dev *dd,
1447d4419548SCyrille Pitchen 			       const u32 *data, size_t datalen,
144849c4cd80SBen Dooks (Codethink) 			       const __be32 *ghash_in, __be32 *ghash_out,
1449d4419548SCyrille Pitchen 			       atmel_aes_fn_t resume)
1450d4419548SCyrille Pitchen {
1451d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1452d4419548SCyrille Pitchen 
1453d4419548SCyrille Pitchen 	dd->data = (u32 *)data;
1454d4419548SCyrille Pitchen 	dd->datalen = datalen;
1455d4419548SCyrille Pitchen 	ctx->ghash_in = ghash_in;
1456d4419548SCyrille Pitchen 	ctx->ghash_out = ghash_out;
1457d4419548SCyrille Pitchen 	ctx->ghash_resume = resume;
1458d4419548SCyrille Pitchen 
1459d4419548SCyrille Pitchen 	atmel_aes_write_ctrl(dd, false, NULL);
1460d4419548SCyrille Pitchen 	return atmel_aes_wait_for_data_ready(dd, atmel_aes_gcm_ghash_init);
1461d4419548SCyrille Pitchen }
1462d4419548SCyrille Pitchen 
atmel_aes_gcm_ghash_init(struct atmel_aes_dev * dd)1463d4419548SCyrille Pitchen static int atmel_aes_gcm_ghash_init(struct atmel_aes_dev *dd)
1464d4419548SCyrille Pitchen {
1465d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1466d4419548SCyrille Pitchen 
1467d4419548SCyrille Pitchen 	/* Set the data length. */
1468d4419548SCyrille Pitchen 	atmel_aes_write(dd, AES_AADLENR, dd->total);
1469d4419548SCyrille Pitchen 	atmel_aes_write(dd, AES_CLENR, 0);
1470d4419548SCyrille Pitchen 
1471d4419548SCyrille Pitchen 	/* If needed, overwrite the GCM Intermediate Hash Word Registers */
1472d4419548SCyrille Pitchen 	if (ctx->ghash_in)
1473d4419548SCyrille Pitchen 		atmel_aes_write_block(dd, AES_GHASHR(0), ctx->ghash_in);
1474d4419548SCyrille Pitchen 
1475d4419548SCyrille Pitchen 	return atmel_aes_gcm_ghash_finalize(dd);
1476d4419548SCyrille Pitchen }
1477d4419548SCyrille Pitchen 
atmel_aes_gcm_ghash_finalize(struct atmel_aes_dev * dd)1478d4419548SCyrille Pitchen static int atmel_aes_gcm_ghash_finalize(struct atmel_aes_dev *dd)
1479d4419548SCyrille Pitchen {
1480d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1481d4419548SCyrille Pitchen 	u32 isr;
1482d4419548SCyrille Pitchen 
1483d4419548SCyrille Pitchen 	/* Write data into the Input Data Registers. */
1484d4419548SCyrille Pitchen 	while (dd->datalen > 0) {
1485d4419548SCyrille Pitchen 		atmel_aes_write_block(dd, AES_IDATAR(0), dd->data);
1486d4419548SCyrille Pitchen 		dd->data += 4;
1487d4419548SCyrille Pitchen 		dd->datalen -= AES_BLOCK_SIZE;
1488d4419548SCyrille Pitchen 
1489d4419548SCyrille Pitchen 		isr = atmel_aes_read(dd, AES_ISR);
1490d4419548SCyrille Pitchen 		if (!(isr & AES_INT_DATARDY)) {
1491d4419548SCyrille Pitchen 			dd->resume = atmel_aes_gcm_ghash_finalize;
1492d4419548SCyrille Pitchen 			atmel_aes_write(dd, AES_IER, AES_INT_DATARDY);
1493d4419548SCyrille Pitchen 			return -EINPROGRESS;
1494d4419548SCyrille Pitchen 		}
1495d4419548SCyrille Pitchen 	}
1496d4419548SCyrille Pitchen 
1497d4419548SCyrille Pitchen 	/* Read the computed hash from GHASHRx. */
1498d4419548SCyrille Pitchen 	atmel_aes_read_block(dd, AES_GHASHR(0), ctx->ghash_out);
1499d4419548SCyrille Pitchen 
1500d4419548SCyrille Pitchen 	return ctx->ghash_resume(dd);
1501d4419548SCyrille Pitchen }
1502d4419548SCyrille Pitchen 
1503d4419548SCyrille Pitchen 
atmel_aes_gcm_start(struct atmel_aes_dev * dd)1504d4419548SCyrille Pitchen static int atmel_aes_gcm_start(struct atmel_aes_dev *dd)
1505d4419548SCyrille Pitchen {
1506d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1507d4419548SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
1508d4419548SCyrille Pitchen 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
1509d4419548SCyrille Pitchen 	struct atmel_aes_reqctx *rctx = aead_request_ctx(req);
1510d4419548SCyrille Pitchen 	size_t ivsize = crypto_aead_ivsize(tfm);
1511d4419548SCyrille Pitchen 	size_t datalen, padlen;
1512d4419548SCyrille Pitchen 	const void *iv = req->iv;
1513d4419548SCyrille Pitchen 	u8 *data = dd->buf;
1514d4419548SCyrille Pitchen 	int err;
1515d4419548SCyrille Pitchen 
1516d4419548SCyrille Pitchen 	atmel_aes_set_mode(dd, rctx);
1517d4419548SCyrille Pitchen 
1518d4419548SCyrille Pitchen 	err = atmel_aes_hw_init(dd);
1519d4419548SCyrille Pitchen 	if (err)
1520d4419548SCyrille Pitchen 		return atmel_aes_complete(dd, err);
1521d4419548SCyrille Pitchen 
1522219d51c7SCorentin LABBE 	if (likely(ivsize == GCM_AES_IV_SIZE)) {
1523d4419548SCyrille Pitchen 		memcpy(ctx->j0, iv, ivsize);
1524d4419548SCyrille Pitchen 		ctx->j0[3] = cpu_to_be32(1);
1525d4419548SCyrille Pitchen 		return atmel_aes_gcm_process(dd);
1526d4419548SCyrille Pitchen 	}
1527d4419548SCyrille Pitchen 
1528d4419548SCyrille Pitchen 	padlen = atmel_aes_padlen(ivsize, AES_BLOCK_SIZE);
1529d4419548SCyrille Pitchen 	datalen = ivsize + padlen + AES_BLOCK_SIZE;
1530d4419548SCyrille Pitchen 	if (datalen > dd->buflen)
1531d4419548SCyrille Pitchen 		return atmel_aes_complete(dd, -EINVAL);
1532d4419548SCyrille Pitchen 
1533d4419548SCyrille Pitchen 	memcpy(data, iv, ivsize);
1534d4419548SCyrille Pitchen 	memset(data + ivsize, 0, padlen + sizeof(u64));
153549c4cd80SBen Dooks (Codethink) 	((__be64 *)(data + datalen))[-1] = cpu_to_be64(ivsize * 8);
1536d4419548SCyrille Pitchen 
1537d4419548SCyrille Pitchen 	return atmel_aes_gcm_ghash(dd, (const u32 *)data, datalen,
1538d4419548SCyrille Pitchen 				   NULL, ctx->j0, atmel_aes_gcm_process);
1539d4419548SCyrille Pitchen }
1540d4419548SCyrille Pitchen 
atmel_aes_gcm_process(struct atmel_aes_dev * dd)1541d4419548SCyrille Pitchen static int atmel_aes_gcm_process(struct atmel_aes_dev *dd)
1542d4419548SCyrille Pitchen {
1543d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1544d4419548SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
1545d4419548SCyrille Pitchen 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
1546d4419548SCyrille Pitchen 	bool enc = atmel_aes_is_encrypt(dd);
1547d4419548SCyrille Pitchen 	u32 authsize;
1548d4419548SCyrille Pitchen 
1549d4419548SCyrille Pitchen 	/* Compute text length. */
1550d4419548SCyrille Pitchen 	authsize = crypto_aead_authsize(tfm);
1551d4419548SCyrille Pitchen 	ctx->textlen = req->cryptlen - (enc ? 0 : authsize);
1552d4419548SCyrille Pitchen 
1553d4419548SCyrille Pitchen 	/*
1554d4419548SCyrille Pitchen 	 * According to tcrypt test suite, the GCM Automatic Tag Generation
1555d4419548SCyrille Pitchen 	 * fails when both the message and its associated data are empty.
1556d4419548SCyrille Pitchen 	 */
1557d4419548SCyrille Pitchen 	if (likely(req->assoclen != 0 || ctx->textlen != 0))
1558d4419548SCyrille Pitchen 		dd->flags |= AES_FLAGS_GTAGEN;
1559d4419548SCyrille Pitchen 
1560d4419548SCyrille Pitchen 	atmel_aes_write_ctrl(dd, false, NULL);
1561d4419548SCyrille Pitchen 	return atmel_aes_wait_for_data_ready(dd, atmel_aes_gcm_length);
1562d4419548SCyrille Pitchen }
1563d4419548SCyrille Pitchen 
atmel_aes_gcm_length(struct atmel_aes_dev * dd)1564d4419548SCyrille Pitchen static int atmel_aes_gcm_length(struct atmel_aes_dev *dd)
1565d4419548SCyrille Pitchen {
1566d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1567d4419548SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
156849c4cd80SBen Dooks (Codethink) 	__be32 j0_lsw, *j0 = ctx->j0;
1569d4419548SCyrille Pitchen 	size_t padlen;
1570d4419548SCyrille Pitchen 
1571d4419548SCyrille Pitchen 	/* Write incr32(J0) into IV. */
1572d4419548SCyrille Pitchen 	j0_lsw = j0[3];
1573fb7c2f46SLiu Shixin 	be32_add_cpu(&j0[3], 1);
1574d4419548SCyrille Pitchen 	atmel_aes_write_block(dd, AES_IVR(0), j0);
1575d4419548SCyrille Pitchen 	j0[3] = j0_lsw;
1576d4419548SCyrille Pitchen 
1577d4419548SCyrille Pitchen 	/* Set aad and text lengths. */
1578d4419548SCyrille Pitchen 	atmel_aes_write(dd, AES_AADLENR, req->assoclen);
1579d4419548SCyrille Pitchen 	atmel_aes_write(dd, AES_CLENR, ctx->textlen);
1580d4419548SCyrille Pitchen 
1581d4419548SCyrille Pitchen 	/* Check whether AAD are present. */
1582d4419548SCyrille Pitchen 	if (unlikely(req->assoclen == 0)) {
1583d4419548SCyrille Pitchen 		dd->datalen = 0;
1584d4419548SCyrille Pitchen 		return atmel_aes_gcm_data(dd);
1585d4419548SCyrille Pitchen 	}
1586d4419548SCyrille Pitchen 
1587d4419548SCyrille Pitchen 	/* Copy assoc data and add padding. */
1588d4419548SCyrille Pitchen 	padlen = atmel_aes_padlen(req->assoclen, AES_BLOCK_SIZE);
1589d4419548SCyrille Pitchen 	if (unlikely(req->assoclen + padlen > dd->buflen))
1590d4419548SCyrille Pitchen 		return atmel_aes_complete(dd, -EINVAL);
1591d4419548SCyrille Pitchen 	sg_copy_to_buffer(req->src, sg_nents(req->src), dd->buf, req->assoclen);
1592d4419548SCyrille Pitchen 
1593d4419548SCyrille Pitchen 	/* Write assoc data into the Input Data register. */
1594d4419548SCyrille Pitchen 	dd->data = (u32 *)dd->buf;
1595d4419548SCyrille Pitchen 	dd->datalen = req->assoclen + padlen;
1596d4419548SCyrille Pitchen 	return atmel_aes_gcm_data(dd);
1597d4419548SCyrille Pitchen }
1598d4419548SCyrille Pitchen 
atmel_aes_gcm_data(struct atmel_aes_dev * dd)1599d4419548SCyrille Pitchen static int atmel_aes_gcm_data(struct atmel_aes_dev *dd)
1600d4419548SCyrille Pitchen {
1601d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1602d4419548SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
1603d4419548SCyrille Pitchen 	bool use_dma = (ctx->textlen >= ATMEL_AES_DMA_THRESHOLD);
1604d4419548SCyrille Pitchen 	struct scatterlist *src, *dst;
1605d4419548SCyrille Pitchen 	u32 isr, mr;
1606d4419548SCyrille Pitchen 
1607d4419548SCyrille Pitchen 	/* Write AAD first. */
1608d4419548SCyrille Pitchen 	while (dd->datalen > 0) {
1609d4419548SCyrille Pitchen 		atmel_aes_write_block(dd, AES_IDATAR(0), dd->data);
1610d4419548SCyrille Pitchen 		dd->data += 4;
1611d4419548SCyrille Pitchen 		dd->datalen -= AES_BLOCK_SIZE;
1612d4419548SCyrille Pitchen 
1613d4419548SCyrille Pitchen 		isr = atmel_aes_read(dd, AES_ISR);
1614d4419548SCyrille Pitchen 		if (!(isr & AES_INT_DATARDY)) {
1615d4419548SCyrille Pitchen 			dd->resume = atmel_aes_gcm_data;
1616d4419548SCyrille Pitchen 			atmel_aes_write(dd, AES_IER, AES_INT_DATARDY);
1617d4419548SCyrille Pitchen 			return -EINPROGRESS;
1618d4419548SCyrille Pitchen 		}
1619d4419548SCyrille Pitchen 	}
1620d4419548SCyrille Pitchen 
1621d4419548SCyrille Pitchen 	/* GMAC only. */
1622d4419548SCyrille Pitchen 	if (unlikely(ctx->textlen == 0))
1623d4419548SCyrille Pitchen 		return atmel_aes_gcm_tag_init(dd);
1624d4419548SCyrille Pitchen 
1625d4419548SCyrille Pitchen 	/* Prepare src and dst scatter lists to transfer cipher/plain texts */
1626d4419548SCyrille Pitchen 	src = scatterwalk_ffwd(ctx->src, req->src, req->assoclen);
1627d4419548SCyrille Pitchen 	dst = ((req->src == req->dst) ? src :
1628d4419548SCyrille Pitchen 	       scatterwalk_ffwd(ctx->dst, req->dst, req->assoclen));
1629d4419548SCyrille Pitchen 
1630d4419548SCyrille Pitchen 	if (use_dma) {
1631d4419548SCyrille Pitchen 		/* Update the Mode Register for DMA transfers. */
1632d4419548SCyrille Pitchen 		mr = atmel_aes_read(dd, AES_MR);
1633d4419548SCyrille Pitchen 		mr &= ~(AES_MR_SMOD_MASK | AES_MR_DUALBUFF);
1634d4419548SCyrille Pitchen 		mr |= AES_MR_SMOD_IDATAR0;
1635d4419548SCyrille Pitchen 		if (dd->caps.has_dualbuff)
1636d4419548SCyrille Pitchen 			mr |= AES_MR_DUALBUFF;
1637d4419548SCyrille Pitchen 		atmel_aes_write(dd, AES_MR, mr);
1638d4419548SCyrille Pitchen 
1639d4419548SCyrille Pitchen 		return atmel_aes_dma_start(dd, src, dst, ctx->textlen,
1640d4419548SCyrille Pitchen 					   atmel_aes_gcm_tag_init);
1641d4419548SCyrille Pitchen 	}
1642d4419548SCyrille Pitchen 
1643d4419548SCyrille Pitchen 	return atmel_aes_cpu_start(dd, src, dst, ctx->textlen,
1644d4419548SCyrille Pitchen 				   atmel_aes_gcm_tag_init);
1645d4419548SCyrille Pitchen }
1646d4419548SCyrille Pitchen 
atmel_aes_gcm_tag_init(struct atmel_aes_dev * dd)1647d4419548SCyrille Pitchen static int atmel_aes_gcm_tag_init(struct atmel_aes_dev *dd)
1648d4419548SCyrille Pitchen {
1649d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1650d4419548SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
165149c4cd80SBen Dooks (Codethink) 	__be64 *data = dd->buf;
1652d4419548SCyrille Pitchen 
1653d4419548SCyrille Pitchen 	if (likely(dd->flags & AES_FLAGS_GTAGEN)) {
1654d4419548SCyrille Pitchen 		if (!(atmel_aes_read(dd, AES_ISR) & AES_INT_TAGRDY)) {
1655d4419548SCyrille Pitchen 			dd->resume = atmel_aes_gcm_tag_init;
1656d4419548SCyrille Pitchen 			atmel_aes_write(dd, AES_IER, AES_INT_TAGRDY);
1657d4419548SCyrille Pitchen 			return -EINPROGRESS;
1658d4419548SCyrille Pitchen 		}
1659d4419548SCyrille Pitchen 
1660d4419548SCyrille Pitchen 		return atmel_aes_gcm_finalize(dd);
1661d4419548SCyrille Pitchen 	}
1662d4419548SCyrille Pitchen 
1663d4419548SCyrille Pitchen 	/* Read the GCM Intermediate Hash Word Registers. */
1664d4419548SCyrille Pitchen 	atmel_aes_read_block(dd, AES_GHASHR(0), ctx->ghash);
1665d4419548SCyrille Pitchen 
1666d4419548SCyrille Pitchen 	data[0] = cpu_to_be64(req->assoclen * 8);
1667d4419548SCyrille Pitchen 	data[1] = cpu_to_be64(ctx->textlen * 8);
1668d4419548SCyrille Pitchen 
1669d4419548SCyrille Pitchen 	return atmel_aes_gcm_ghash(dd, (const u32 *)data, AES_BLOCK_SIZE,
1670d4419548SCyrille Pitchen 				   ctx->ghash, ctx->ghash, atmel_aes_gcm_tag);
1671d4419548SCyrille Pitchen }
1672d4419548SCyrille Pitchen 
atmel_aes_gcm_tag(struct atmel_aes_dev * dd)1673d4419548SCyrille Pitchen static int atmel_aes_gcm_tag(struct atmel_aes_dev *dd)
1674d4419548SCyrille Pitchen {
1675d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1676d4419548SCyrille Pitchen 	unsigned long flags;
1677d4419548SCyrille Pitchen 
1678d4419548SCyrille Pitchen 	/*
1679d4419548SCyrille Pitchen 	 * Change mode to CTR to complete the tag generation.
1680d4419548SCyrille Pitchen 	 * Use J0 as Initialization Vector.
1681d4419548SCyrille Pitchen 	 */
1682d4419548SCyrille Pitchen 	flags = dd->flags;
1683d4419548SCyrille Pitchen 	dd->flags &= ~(AES_FLAGS_OPMODE_MASK | AES_FLAGS_GTAGEN);
1684d4419548SCyrille Pitchen 	dd->flags |= AES_FLAGS_CTR;
1685d4419548SCyrille Pitchen 	atmel_aes_write_ctrl(dd, false, ctx->j0);
1686d4419548SCyrille Pitchen 	dd->flags = flags;
1687d4419548SCyrille Pitchen 
1688d4419548SCyrille Pitchen 	atmel_aes_write_block(dd, AES_IDATAR(0), ctx->ghash);
1689d4419548SCyrille Pitchen 	return atmel_aes_wait_for_data_ready(dd, atmel_aes_gcm_finalize);
1690d4419548SCyrille Pitchen }
1691d4419548SCyrille Pitchen 
atmel_aes_gcm_finalize(struct atmel_aes_dev * dd)1692d4419548SCyrille Pitchen static int atmel_aes_gcm_finalize(struct atmel_aes_dev *dd)
1693d4419548SCyrille Pitchen {
1694d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = atmel_aes_gcm_ctx_cast(dd->ctx);
1695d4419548SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
1696d4419548SCyrille Pitchen 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
1697d4419548SCyrille Pitchen 	bool enc = atmel_aes_is_encrypt(dd);
1698d4419548SCyrille Pitchen 	u32 offset, authsize, itag[4], *otag = ctx->tag;
1699d4419548SCyrille Pitchen 	int err;
1700d4419548SCyrille Pitchen 
1701d4419548SCyrille Pitchen 	/* Read the computed tag. */
1702d4419548SCyrille Pitchen 	if (likely(dd->flags & AES_FLAGS_GTAGEN))
1703d4419548SCyrille Pitchen 		atmel_aes_read_block(dd, AES_TAGR(0), ctx->tag);
1704d4419548SCyrille Pitchen 	else
1705d4419548SCyrille Pitchen 		atmel_aes_read_block(dd, AES_ODATAR(0), ctx->tag);
1706d4419548SCyrille Pitchen 
1707d4419548SCyrille Pitchen 	offset = req->assoclen + ctx->textlen;
1708d4419548SCyrille Pitchen 	authsize = crypto_aead_authsize(tfm);
1709d4419548SCyrille Pitchen 	if (enc) {
1710d4419548SCyrille Pitchen 		scatterwalk_map_and_copy(otag, req->dst, offset, authsize, 1);
1711d4419548SCyrille Pitchen 		err = 0;
1712d4419548SCyrille Pitchen 	} else {
1713d4419548SCyrille Pitchen 		scatterwalk_map_and_copy(itag, req->src, offset, authsize, 0);
1714d4419548SCyrille Pitchen 		err = crypto_memneq(itag, otag, authsize) ? -EBADMSG : 0;
1715d4419548SCyrille Pitchen 	}
1716d4419548SCyrille Pitchen 
1717d4419548SCyrille Pitchen 	return atmel_aes_complete(dd, err);
1718d4419548SCyrille Pitchen }
1719d4419548SCyrille Pitchen 
atmel_aes_gcm_crypt(struct aead_request * req,unsigned long mode)1720d4419548SCyrille Pitchen static int atmel_aes_gcm_crypt(struct aead_request *req,
1721d4419548SCyrille Pitchen 			       unsigned long mode)
1722d4419548SCyrille Pitchen {
1723d4419548SCyrille Pitchen 	struct atmel_aes_base_ctx *ctx;
1724d4419548SCyrille Pitchen 	struct atmel_aes_reqctx *rctx;
1725d4419548SCyrille Pitchen 
1726d4419548SCyrille Pitchen 	ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
1727d4419548SCyrille Pitchen 	ctx->block_size = AES_BLOCK_SIZE;
172891308019SRomain Izard 	ctx->is_aead = true;
1729d4419548SCyrille Pitchen 
1730d4419548SCyrille Pitchen 	rctx = aead_request_ctx(req);
1731d4419548SCyrille Pitchen 	rctx->mode = AES_FLAGS_GCM | mode;
1732d4419548SCyrille Pitchen 
1733ec2088b6STudor Ambarus 	return atmel_aes_handle_queue(ctx->dd, &req->base);
1734d4419548SCyrille Pitchen }
1735d4419548SCyrille Pitchen 
atmel_aes_gcm_setkey(struct crypto_aead * tfm,const u8 * key,unsigned int keylen)1736d4419548SCyrille Pitchen static int atmel_aes_gcm_setkey(struct crypto_aead *tfm, const u8 *key,
1737d4419548SCyrille Pitchen 				unsigned int keylen)
1738d4419548SCyrille Pitchen {
1739d4419548SCyrille Pitchen 	struct atmel_aes_base_ctx *ctx = crypto_aead_ctx(tfm);
1740d4419548SCyrille Pitchen 
1741d4419548SCyrille Pitchen 	if (keylen != AES_KEYSIZE_256 &&
1742d4419548SCyrille Pitchen 	    keylen != AES_KEYSIZE_192 &&
1743674f368aSEric Biggers 	    keylen != AES_KEYSIZE_128)
1744d4419548SCyrille Pitchen 		return -EINVAL;
1745d4419548SCyrille Pitchen 
1746d4419548SCyrille Pitchen 	memcpy(ctx->key, key, keylen);
1747d4419548SCyrille Pitchen 	ctx->keylen = keylen;
1748d4419548SCyrille Pitchen 
1749d4419548SCyrille Pitchen 	return 0;
1750d4419548SCyrille Pitchen }
1751d4419548SCyrille Pitchen 
atmel_aes_gcm_setauthsize(struct crypto_aead * tfm,unsigned int authsize)1752d4419548SCyrille Pitchen static int atmel_aes_gcm_setauthsize(struct crypto_aead *tfm,
1753d4419548SCyrille Pitchen 				     unsigned int authsize)
1754d4419548SCyrille Pitchen {
17557db15aadSTudor Ambarus 	return crypto_gcm_check_authsize(authsize);
1756d4419548SCyrille Pitchen }
1757d4419548SCyrille Pitchen 
atmel_aes_gcm_encrypt(struct aead_request * req)1758d4419548SCyrille Pitchen static int atmel_aes_gcm_encrypt(struct aead_request *req)
1759d4419548SCyrille Pitchen {
1760d4419548SCyrille Pitchen 	return atmel_aes_gcm_crypt(req, AES_FLAGS_ENCRYPT);
1761d4419548SCyrille Pitchen }
1762d4419548SCyrille Pitchen 
atmel_aes_gcm_decrypt(struct aead_request * req)1763d4419548SCyrille Pitchen static int atmel_aes_gcm_decrypt(struct aead_request *req)
1764d4419548SCyrille Pitchen {
1765d4419548SCyrille Pitchen 	return atmel_aes_gcm_crypt(req, 0);
1766d4419548SCyrille Pitchen }
1767d4419548SCyrille Pitchen 
atmel_aes_gcm_init(struct crypto_aead * tfm)1768d4419548SCyrille Pitchen static int atmel_aes_gcm_init(struct crypto_aead *tfm)
1769d4419548SCyrille Pitchen {
1770d4419548SCyrille Pitchen 	struct atmel_aes_gcm_ctx *ctx = crypto_aead_ctx(tfm);
1771ec2088b6STudor Ambarus 	struct atmel_aes_dev *dd;
1772ec2088b6STudor Ambarus 
1773ec2088b6STudor Ambarus 	dd = atmel_aes_dev_alloc(&ctx->base);
1774ec2088b6STudor Ambarus 	if (!dd)
1775ec2088b6STudor Ambarus 		return -ENODEV;
1776d4419548SCyrille Pitchen 
1777d4419548SCyrille Pitchen 	crypto_aead_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx));
1778ec2088b6STudor Ambarus 	ctx->base.dd = dd;
1779d4419548SCyrille Pitchen 	ctx->base.start = atmel_aes_gcm_start;
1780d4419548SCyrille Pitchen 
1781d4419548SCyrille Pitchen 	return 0;
1782d4419548SCyrille Pitchen }
1783d4419548SCyrille Pitchen 
1784d4419548SCyrille Pitchen static struct aead_alg aes_gcm_alg = {
1785d4419548SCyrille Pitchen 	.setkey		= atmel_aes_gcm_setkey,
1786d4419548SCyrille Pitchen 	.setauthsize	= atmel_aes_gcm_setauthsize,
1787d4419548SCyrille Pitchen 	.encrypt	= atmel_aes_gcm_encrypt,
1788d4419548SCyrille Pitchen 	.decrypt	= atmel_aes_gcm_decrypt,
1789d4419548SCyrille Pitchen 	.init		= atmel_aes_gcm_init,
1790219d51c7SCorentin LABBE 	.ivsize		= GCM_AES_IV_SIZE,
1791d4419548SCyrille Pitchen 	.maxauthsize	= AES_BLOCK_SIZE,
1792d4419548SCyrille Pitchen 
1793d4419548SCyrille Pitchen 	.base = {
1794d4419548SCyrille Pitchen 		.cra_name		= "gcm(aes)",
1795d4419548SCyrille Pitchen 		.cra_driver_name	= "atmel-gcm-aes",
1796d4419548SCyrille Pitchen 		.cra_blocksize		= 1,
1797d4419548SCyrille Pitchen 		.cra_ctxsize		= sizeof(struct atmel_aes_gcm_ctx),
1798d4419548SCyrille Pitchen 	},
1799d4419548SCyrille Pitchen };
1800d4419548SCyrille Pitchen 
1801d4419548SCyrille Pitchen 
1802d52db518SCyrille Pitchen /* xts functions */
1803d52db518SCyrille Pitchen 
1804d52db518SCyrille Pitchen static inline struct atmel_aes_xts_ctx *
atmel_aes_xts_ctx_cast(struct atmel_aes_base_ctx * ctx)1805d52db518SCyrille Pitchen atmel_aes_xts_ctx_cast(struct atmel_aes_base_ctx *ctx)
1806d52db518SCyrille Pitchen {
1807d52db518SCyrille Pitchen 	return container_of(ctx, struct atmel_aes_xts_ctx, base);
1808d52db518SCyrille Pitchen }
1809d52db518SCyrille Pitchen 
1810d52db518SCyrille Pitchen static int atmel_aes_xts_process_data(struct atmel_aes_dev *dd);
1811d52db518SCyrille Pitchen 
atmel_aes_xts_start(struct atmel_aes_dev * dd)1812d52db518SCyrille Pitchen static int atmel_aes_xts_start(struct atmel_aes_dev *dd)
1813d52db518SCyrille Pitchen {
1814d52db518SCyrille Pitchen 	struct atmel_aes_xts_ctx *ctx = atmel_aes_xts_ctx_cast(dd->ctx);
18157ada42d2SArd Biesheuvel 	struct skcipher_request *req = skcipher_request_cast(dd->areq);
18167ada42d2SArd Biesheuvel 	struct atmel_aes_reqctx *rctx = skcipher_request_ctx(req);
1817d52db518SCyrille Pitchen 	unsigned long flags;
1818d52db518SCyrille Pitchen 	int err;
1819d52db518SCyrille Pitchen 
1820d52db518SCyrille Pitchen 	atmel_aes_set_mode(dd, rctx);
1821d52db518SCyrille Pitchen 
1822d52db518SCyrille Pitchen 	err = atmel_aes_hw_init(dd);
1823d52db518SCyrille Pitchen 	if (err)
1824d52db518SCyrille Pitchen 		return atmel_aes_complete(dd, err);
1825d52db518SCyrille Pitchen 
18267ada42d2SArd Biesheuvel 	/* Compute the tweak value from req->iv with ecb(aes). */
1827d52db518SCyrille Pitchen 	flags = dd->flags;
1828d52db518SCyrille Pitchen 	dd->flags &= ~AES_FLAGS_MODE_MASK;
1829d52db518SCyrille Pitchen 	dd->flags |= (AES_FLAGS_ECB | AES_FLAGS_ENCRYPT);
1830d52db518SCyrille Pitchen 	atmel_aes_write_ctrl_key(dd, false, NULL,
1831d52db518SCyrille Pitchen 				 ctx->key2, ctx->base.keylen);
1832d52db518SCyrille Pitchen 	dd->flags = flags;
1833d52db518SCyrille Pitchen 
18347ada42d2SArd Biesheuvel 	atmel_aes_write_block(dd, AES_IDATAR(0), req->iv);
1835d52db518SCyrille Pitchen 	return atmel_aes_wait_for_data_ready(dd, atmel_aes_xts_process_data);
1836d52db518SCyrille Pitchen }
1837d52db518SCyrille Pitchen 
atmel_aes_xts_process_data(struct atmel_aes_dev * dd)1838d52db518SCyrille Pitchen static int atmel_aes_xts_process_data(struct atmel_aes_dev *dd)
1839d52db518SCyrille Pitchen {
18407ada42d2SArd Biesheuvel 	struct skcipher_request *req = skcipher_request_cast(dd->areq);
18417ada42d2SArd Biesheuvel 	bool use_dma = (req->cryptlen >= ATMEL_AES_DMA_THRESHOLD);
1842d52db518SCyrille Pitchen 	u32 tweak[AES_BLOCK_SIZE / sizeof(u32)];
184349c4cd80SBen Dooks (Codethink) 	static const __le32 one[AES_BLOCK_SIZE / sizeof(u32)] = {cpu_to_le32(1), };
1844d52db518SCyrille Pitchen 	u8 *tweak_bytes = (u8 *)tweak;
1845d52db518SCyrille Pitchen 	int i;
1846d52db518SCyrille Pitchen 
1847d52db518SCyrille Pitchen 	/* Read the computed ciphered tweak value. */
1848d52db518SCyrille Pitchen 	atmel_aes_read_block(dd, AES_ODATAR(0), tweak);
1849d52db518SCyrille Pitchen 	/*
1850d52db518SCyrille Pitchen 	 * Hardware quirk:
1851d52db518SCyrille Pitchen 	 * the order of the ciphered tweak bytes need to be reversed before
1852d52db518SCyrille Pitchen 	 * writing them into the ODATARx registers.
1853d52db518SCyrille Pitchen 	 */
1854089015d3SSalah Triki 	for (i = 0; i < AES_BLOCK_SIZE/2; ++i)
1855089015d3SSalah Triki 		swap(tweak_bytes[i], tweak_bytes[AES_BLOCK_SIZE - 1 - i]);
1856d52db518SCyrille Pitchen 
1857d52db518SCyrille Pitchen 	/* Process the data. */
1858d52db518SCyrille Pitchen 	atmel_aes_write_ctrl(dd, use_dma, NULL);
1859d52db518SCyrille Pitchen 	atmel_aes_write_block(dd, AES_TWR(0), tweak);
1860d52db518SCyrille Pitchen 	atmel_aes_write_block(dd, AES_ALPHAR(0), one);
1861d52db518SCyrille Pitchen 	if (use_dma)
18627ada42d2SArd Biesheuvel 		return atmel_aes_dma_start(dd, req->src, req->dst,
18637ada42d2SArd Biesheuvel 					   req->cryptlen,
1864d52db518SCyrille Pitchen 					   atmel_aes_transfer_complete);
1865d52db518SCyrille Pitchen 
18667ada42d2SArd Biesheuvel 	return atmel_aes_cpu_start(dd, req->src, req->dst, req->cryptlen,
1867d52db518SCyrille Pitchen 				   atmel_aes_transfer_complete);
1868d52db518SCyrille Pitchen }
1869d52db518SCyrille Pitchen 
atmel_aes_xts_setkey(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)18707ada42d2SArd Biesheuvel static int atmel_aes_xts_setkey(struct crypto_skcipher *tfm, const u8 *key,
1871d52db518SCyrille Pitchen 				unsigned int keylen)
1872d52db518SCyrille Pitchen {
18737ada42d2SArd Biesheuvel 	struct atmel_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
1874d52db518SCyrille Pitchen 	int err;
1875d52db518SCyrille Pitchen 
18760ee43367SVladis Dronov 	err = xts_verify_key(tfm, key, keylen);
1877d52db518SCyrille Pitchen 	if (err)
1878d52db518SCyrille Pitchen 		return err;
1879d52db518SCyrille Pitchen 
1880bf2db8e7STudor Ambarus 	crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK);
1881bf2db8e7STudor Ambarus 	crypto_skcipher_set_flags(ctx->fallback_tfm, tfm->base.crt_flags &
1882bf2db8e7STudor Ambarus 				  CRYPTO_TFM_REQ_MASK);
1883bf2db8e7STudor Ambarus 	err = crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen);
1884bf2db8e7STudor Ambarus 	if (err)
1885bf2db8e7STudor Ambarus 		return err;
1886bf2db8e7STudor Ambarus 
1887d52db518SCyrille Pitchen 	memcpy(ctx->base.key, key, keylen/2);
1888d52db518SCyrille Pitchen 	memcpy(ctx->key2, key + keylen/2, keylen/2);
1889d52db518SCyrille Pitchen 	ctx->base.keylen = keylen/2;
1890d52db518SCyrille Pitchen 
1891d52db518SCyrille Pitchen 	return 0;
1892d52db518SCyrille Pitchen }
1893d52db518SCyrille Pitchen 
atmel_aes_xts_encrypt(struct skcipher_request * req)18947ada42d2SArd Biesheuvel static int atmel_aes_xts_encrypt(struct skcipher_request *req)
1895d52db518SCyrille Pitchen {
1896d52db518SCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_XTS | AES_FLAGS_ENCRYPT);
1897d52db518SCyrille Pitchen }
1898d52db518SCyrille Pitchen 
atmel_aes_xts_decrypt(struct skcipher_request * req)18997ada42d2SArd Biesheuvel static int atmel_aes_xts_decrypt(struct skcipher_request *req)
1900d52db518SCyrille Pitchen {
1901d52db518SCyrille Pitchen 	return atmel_aes_crypt(req, AES_FLAGS_XTS);
1902d52db518SCyrille Pitchen }
1903d52db518SCyrille Pitchen 
atmel_aes_xts_init_tfm(struct crypto_skcipher * tfm)19047ada42d2SArd Biesheuvel static int atmel_aes_xts_init_tfm(struct crypto_skcipher *tfm)
1905d52db518SCyrille Pitchen {
19067ada42d2SArd Biesheuvel 	struct atmel_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
1907ec2088b6STudor Ambarus 	struct atmel_aes_dev *dd;
1908bf2db8e7STudor Ambarus 	const char *tfm_name = crypto_tfm_alg_name(&tfm->base);
1909d52db518SCyrille Pitchen 
1910ec2088b6STudor Ambarus 	dd = atmel_aes_dev_alloc(&ctx->base);
1911ec2088b6STudor Ambarus 	if (!dd)
1912ec2088b6STudor Ambarus 		return -ENODEV;
1913ec2088b6STudor Ambarus 
1914bf2db8e7STudor Ambarus 	ctx->fallback_tfm = crypto_alloc_skcipher(tfm_name, 0,
1915bf2db8e7STudor Ambarus 						  CRYPTO_ALG_NEED_FALLBACK);
1916bf2db8e7STudor Ambarus 	if (IS_ERR(ctx->fallback_tfm))
1917bf2db8e7STudor Ambarus 		return PTR_ERR(ctx->fallback_tfm);
1918bf2db8e7STudor Ambarus 
1919bf2db8e7STudor Ambarus 	crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx) +
1920bf2db8e7STudor Ambarus 				    crypto_skcipher_reqsize(ctx->fallback_tfm));
1921ec2088b6STudor Ambarus 	ctx->base.dd = dd;
1922d52db518SCyrille Pitchen 	ctx->base.start = atmel_aes_xts_start;
1923d52db518SCyrille Pitchen 
1924d52db518SCyrille Pitchen 	return 0;
1925d52db518SCyrille Pitchen }
1926d52db518SCyrille Pitchen 
atmel_aes_xts_exit_tfm(struct crypto_skcipher * tfm)1927bf2db8e7STudor Ambarus static void atmel_aes_xts_exit_tfm(struct crypto_skcipher *tfm)
1928bf2db8e7STudor Ambarus {
1929bf2db8e7STudor Ambarus 	struct atmel_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
1930bf2db8e7STudor Ambarus 
1931bf2db8e7STudor Ambarus 	crypto_free_skcipher(ctx->fallback_tfm);
1932bf2db8e7STudor Ambarus }
1933bf2db8e7STudor Ambarus 
19347ada42d2SArd Biesheuvel static struct skcipher_alg aes_xts_alg = {
19357ada42d2SArd Biesheuvel 	.base.cra_name		= "xts(aes)",
19367ada42d2SArd Biesheuvel 	.base.cra_driver_name	= "atmel-xts-aes",
19377ada42d2SArd Biesheuvel 	.base.cra_blocksize	= AES_BLOCK_SIZE,
19387ada42d2SArd Biesheuvel 	.base.cra_ctxsize	= sizeof(struct atmel_aes_xts_ctx),
1939bf2db8e7STudor Ambarus 	.base.cra_flags		= CRYPTO_ALG_NEED_FALLBACK,
19407ada42d2SArd Biesheuvel 
1941d52db518SCyrille Pitchen 	.min_keysize		= 2 * AES_MIN_KEY_SIZE,
1942d52db518SCyrille Pitchen 	.max_keysize		= 2 * AES_MAX_KEY_SIZE,
1943d52db518SCyrille Pitchen 	.ivsize			= AES_BLOCK_SIZE,
1944d52db518SCyrille Pitchen 	.setkey			= atmel_aes_xts_setkey,
1945d52db518SCyrille Pitchen 	.encrypt		= atmel_aes_xts_encrypt,
1946d52db518SCyrille Pitchen 	.decrypt		= atmel_aes_xts_decrypt,
19477ada42d2SArd Biesheuvel 	.init			= atmel_aes_xts_init_tfm,
1948bf2db8e7STudor Ambarus 	.exit			= atmel_aes_xts_exit_tfm,
1949d52db518SCyrille Pitchen };
1950d52db518SCyrille Pitchen 
19511520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
195289a82ef8SCyrille Pitchen /* authenc aead functions */
195389a82ef8SCyrille Pitchen 
195489a82ef8SCyrille Pitchen static int atmel_aes_authenc_start(struct atmel_aes_dev *dd);
195589a82ef8SCyrille Pitchen static int atmel_aes_authenc_init(struct atmel_aes_dev *dd, int err,
195689a82ef8SCyrille Pitchen 				  bool is_async);
195789a82ef8SCyrille Pitchen static int atmel_aes_authenc_transfer(struct atmel_aes_dev *dd, int err,
195889a82ef8SCyrille Pitchen 				      bool is_async);
195989a82ef8SCyrille Pitchen static int atmel_aes_authenc_digest(struct atmel_aes_dev *dd);
196089a82ef8SCyrille Pitchen static int atmel_aes_authenc_final(struct atmel_aes_dev *dd, int err,
196189a82ef8SCyrille Pitchen 				   bool is_async);
196289a82ef8SCyrille Pitchen 
atmel_aes_authenc_complete(struct atmel_aes_dev * dd,int err)196389a82ef8SCyrille Pitchen static void atmel_aes_authenc_complete(struct atmel_aes_dev *dd, int err)
196489a82ef8SCyrille Pitchen {
196589a82ef8SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
196689a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
196789a82ef8SCyrille Pitchen 
196889a82ef8SCyrille Pitchen 	if (err && (dd->flags & AES_FLAGS_OWN_SHA))
196989a82ef8SCyrille Pitchen 		atmel_sha_authenc_abort(&rctx->auth_req);
197089a82ef8SCyrille Pitchen 	dd->flags &= ~AES_FLAGS_OWN_SHA;
197189a82ef8SCyrille Pitchen }
197289a82ef8SCyrille Pitchen 
atmel_aes_authenc_start(struct atmel_aes_dev * dd)197389a82ef8SCyrille Pitchen static int atmel_aes_authenc_start(struct atmel_aes_dev *dd)
197489a82ef8SCyrille Pitchen {
197589a82ef8SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
197689a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
197789a82ef8SCyrille Pitchen 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
197889a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm);
197989a82ef8SCyrille Pitchen 	int err;
198089a82ef8SCyrille Pitchen 
198189a82ef8SCyrille Pitchen 	atmel_aes_set_mode(dd, &rctx->base);
198289a82ef8SCyrille Pitchen 
198389a82ef8SCyrille Pitchen 	err = atmel_aes_hw_init(dd);
198489a82ef8SCyrille Pitchen 	if (err)
198589a82ef8SCyrille Pitchen 		return atmel_aes_complete(dd, err);
198689a82ef8SCyrille Pitchen 
198789a82ef8SCyrille Pitchen 	return atmel_sha_authenc_schedule(&rctx->auth_req, ctx->auth,
198889a82ef8SCyrille Pitchen 					  atmel_aes_authenc_init, dd);
198989a82ef8SCyrille Pitchen }
199089a82ef8SCyrille Pitchen 
atmel_aes_authenc_init(struct atmel_aes_dev * dd,int err,bool is_async)199189a82ef8SCyrille Pitchen static int atmel_aes_authenc_init(struct atmel_aes_dev *dd, int err,
199289a82ef8SCyrille Pitchen 				  bool is_async)
199389a82ef8SCyrille Pitchen {
199489a82ef8SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
199589a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
199689a82ef8SCyrille Pitchen 
199789a82ef8SCyrille Pitchen 	if (is_async)
199889a82ef8SCyrille Pitchen 		dd->is_async = true;
199989a82ef8SCyrille Pitchen 	if (err)
200089a82ef8SCyrille Pitchen 		return atmel_aes_complete(dd, err);
200189a82ef8SCyrille Pitchen 
200289a82ef8SCyrille Pitchen 	/* If here, we've got the ownership of the SHA device. */
200389a82ef8SCyrille Pitchen 	dd->flags |= AES_FLAGS_OWN_SHA;
200489a82ef8SCyrille Pitchen 
200589a82ef8SCyrille Pitchen 	/* Configure the SHA device. */
200689a82ef8SCyrille Pitchen 	return atmel_sha_authenc_init(&rctx->auth_req,
200789a82ef8SCyrille Pitchen 				      req->src, req->assoclen,
200889a82ef8SCyrille Pitchen 				      rctx->textlen,
200989a82ef8SCyrille Pitchen 				      atmel_aes_authenc_transfer, dd);
201089a82ef8SCyrille Pitchen }
201189a82ef8SCyrille Pitchen 
atmel_aes_authenc_transfer(struct atmel_aes_dev * dd,int err,bool is_async)201289a82ef8SCyrille Pitchen static int atmel_aes_authenc_transfer(struct atmel_aes_dev *dd, int err,
201389a82ef8SCyrille Pitchen 				      bool is_async)
201489a82ef8SCyrille Pitchen {
201589a82ef8SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
201689a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
201789a82ef8SCyrille Pitchen 	bool enc = atmel_aes_is_encrypt(dd);
201889a82ef8SCyrille Pitchen 	struct scatterlist *src, *dst;
2019427e6e3aSHerbert Xu 	__be32 iv[AES_BLOCK_SIZE / sizeof(u32)];
202089a82ef8SCyrille Pitchen 	u32 emr;
202189a82ef8SCyrille Pitchen 
202289a82ef8SCyrille Pitchen 	if (is_async)
202389a82ef8SCyrille Pitchen 		dd->is_async = true;
202489a82ef8SCyrille Pitchen 	if (err)
202589a82ef8SCyrille Pitchen 		return atmel_aes_complete(dd, err);
202689a82ef8SCyrille Pitchen 
202789a82ef8SCyrille Pitchen 	/* Prepare src and dst scatter-lists to transfer cipher/plain texts. */
202889a82ef8SCyrille Pitchen 	src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen);
202989a82ef8SCyrille Pitchen 	dst = src;
203089a82ef8SCyrille Pitchen 
203189a82ef8SCyrille Pitchen 	if (req->src != req->dst)
203289a82ef8SCyrille Pitchen 		dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen);
203389a82ef8SCyrille Pitchen 
203489a82ef8SCyrille Pitchen 	/* Configure the AES device. */
203589a82ef8SCyrille Pitchen 	memcpy(iv, req->iv, sizeof(iv));
203689a82ef8SCyrille Pitchen 
203789a82ef8SCyrille Pitchen 	/*
203889a82ef8SCyrille Pitchen 	 * Here we always set the 2nd parameter of atmel_aes_write_ctrl() to
203989a82ef8SCyrille Pitchen 	 * 'true' even if the data transfer is actually performed by the CPU (so
204089a82ef8SCyrille Pitchen 	 * not by the DMA) because we must force the AES_MR_SMOD bitfield to the
204189a82ef8SCyrille Pitchen 	 * value AES_MR_SMOD_IDATAR0. Indeed, both AES_MR_SMOD and SHA_MR_SMOD
204289a82ef8SCyrille Pitchen 	 * must be set to *_MR_SMOD_IDATAR0.
204389a82ef8SCyrille Pitchen 	 */
204489a82ef8SCyrille Pitchen 	atmel_aes_write_ctrl(dd, true, iv);
204589a82ef8SCyrille Pitchen 	emr = AES_EMR_PLIPEN;
204689a82ef8SCyrille Pitchen 	if (!enc)
204789a82ef8SCyrille Pitchen 		emr |= AES_EMR_PLIPD;
204889a82ef8SCyrille Pitchen 	atmel_aes_write(dd, AES_EMR, emr);
204989a82ef8SCyrille Pitchen 
205089a82ef8SCyrille Pitchen 	/* Transfer data. */
205189a82ef8SCyrille Pitchen 	return atmel_aes_dma_start(dd, src, dst, rctx->textlen,
205289a82ef8SCyrille Pitchen 				   atmel_aes_authenc_digest);
205389a82ef8SCyrille Pitchen }
205489a82ef8SCyrille Pitchen 
atmel_aes_authenc_digest(struct atmel_aes_dev * dd)205589a82ef8SCyrille Pitchen static int atmel_aes_authenc_digest(struct atmel_aes_dev *dd)
205689a82ef8SCyrille Pitchen {
205789a82ef8SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
205889a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
205989a82ef8SCyrille Pitchen 
206089a82ef8SCyrille Pitchen 	/* atmel_sha_authenc_final() releases the SHA device. */
206189a82ef8SCyrille Pitchen 	dd->flags &= ~AES_FLAGS_OWN_SHA;
206289a82ef8SCyrille Pitchen 	return atmel_sha_authenc_final(&rctx->auth_req,
206389a82ef8SCyrille Pitchen 				       rctx->digest, sizeof(rctx->digest),
206489a82ef8SCyrille Pitchen 				       atmel_aes_authenc_final, dd);
206589a82ef8SCyrille Pitchen }
206689a82ef8SCyrille Pitchen 
atmel_aes_authenc_final(struct atmel_aes_dev * dd,int err,bool is_async)206789a82ef8SCyrille Pitchen static int atmel_aes_authenc_final(struct atmel_aes_dev *dd, int err,
206889a82ef8SCyrille Pitchen 				   bool is_async)
206989a82ef8SCyrille Pitchen {
207089a82ef8SCyrille Pitchen 	struct aead_request *req = aead_request_cast(dd->areq);
207189a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
207289a82ef8SCyrille Pitchen 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
207389a82ef8SCyrille Pitchen 	bool enc = atmel_aes_is_encrypt(dd);
207489a82ef8SCyrille Pitchen 	u32 idigest[SHA512_DIGEST_SIZE / sizeof(u32)], *odigest = rctx->digest;
207589a82ef8SCyrille Pitchen 	u32 offs, authsize;
207689a82ef8SCyrille Pitchen 
207789a82ef8SCyrille Pitchen 	if (is_async)
207889a82ef8SCyrille Pitchen 		dd->is_async = true;
207989a82ef8SCyrille Pitchen 	if (err)
208089a82ef8SCyrille Pitchen 		goto complete;
208189a82ef8SCyrille Pitchen 
208289a82ef8SCyrille Pitchen 	offs = req->assoclen + rctx->textlen;
208389a82ef8SCyrille Pitchen 	authsize = crypto_aead_authsize(tfm);
208489a82ef8SCyrille Pitchen 	if (enc) {
208589a82ef8SCyrille Pitchen 		scatterwalk_map_and_copy(odigest, req->dst, offs, authsize, 1);
208689a82ef8SCyrille Pitchen 	} else {
208789a82ef8SCyrille Pitchen 		scatterwalk_map_and_copy(idigest, req->src, offs, authsize, 0);
208889a82ef8SCyrille Pitchen 		if (crypto_memneq(idigest, odigest, authsize))
208989a82ef8SCyrille Pitchen 			err = -EBADMSG;
209089a82ef8SCyrille Pitchen 	}
209189a82ef8SCyrille Pitchen 
209289a82ef8SCyrille Pitchen complete:
209389a82ef8SCyrille Pitchen 	return atmel_aes_complete(dd, err);
209489a82ef8SCyrille Pitchen }
209589a82ef8SCyrille Pitchen 
atmel_aes_authenc_setkey(struct crypto_aead * tfm,const u8 * key,unsigned int keylen)209689a82ef8SCyrille Pitchen static int atmel_aes_authenc_setkey(struct crypto_aead *tfm, const u8 *key,
209789a82ef8SCyrille Pitchen 				    unsigned int keylen)
209889a82ef8SCyrille Pitchen {
209989a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm);
210089a82ef8SCyrille Pitchen 	struct crypto_authenc_keys keys;
210189a82ef8SCyrille Pitchen 	int err;
210289a82ef8SCyrille Pitchen 
210389a82ef8SCyrille Pitchen 	if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
210489a82ef8SCyrille Pitchen 		goto badkey;
210589a82ef8SCyrille Pitchen 
210689a82ef8SCyrille Pitchen 	if (keys.enckeylen > sizeof(ctx->base.key))
210789a82ef8SCyrille Pitchen 		goto badkey;
210889a82ef8SCyrille Pitchen 
210989a82ef8SCyrille Pitchen 	/* Save auth key. */
211089a82ef8SCyrille Pitchen 	err = atmel_sha_authenc_setkey(ctx->auth,
211189a82ef8SCyrille Pitchen 				       keys.authkey, keys.authkeylen,
2112af5034e8SEric Biggers 				       crypto_aead_get_flags(tfm));
211389a82ef8SCyrille Pitchen 	if (err) {
211489a82ef8SCyrille Pitchen 		memzero_explicit(&keys, sizeof(keys));
211589a82ef8SCyrille Pitchen 		return err;
211689a82ef8SCyrille Pitchen 	}
211789a82ef8SCyrille Pitchen 
211889a82ef8SCyrille Pitchen 	/* Save enc key. */
211989a82ef8SCyrille Pitchen 	ctx->base.keylen = keys.enckeylen;
212089a82ef8SCyrille Pitchen 	memcpy(ctx->base.key, keys.enckey, keys.enckeylen);
212189a82ef8SCyrille Pitchen 
212289a82ef8SCyrille Pitchen 	memzero_explicit(&keys, sizeof(keys));
212389a82ef8SCyrille Pitchen 	return 0;
212489a82ef8SCyrille Pitchen 
212589a82ef8SCyrille Pitchen badkey:
21265d804a51SAntoine Tenart 	memzero_explicit(&keys, sizeof(keys));
212789a82ef8SCyrille Pitchen 	return -EINVAL;
212889a82ef8SCyrille Pitchen }
212989a82ef8SCyrille Pitchen 
atmel_aes_authenc_init_tfm(struct crypto_aead * tfm,unsigned long auth_mode)213089a82ef8SCyrille Pitchen static int atmel_aes_authenc_init_tfm(struct crypto_aead *tfm,
213189a82ef8SCyrille Pitchen 				      unsigned long auth_mode)
213289a82ef8SCyrille Pitchen {
213389a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm);
213489a82ef8SCyrille Pitchen 	unsigned int auth_reqsize = atmel_sha_authenc_get_reqsize();
2135ec2088b6STudor Ambarus 	struct atmel_aes_dev *dd;
2136ec2088b6STudor Ambarus 
2137ec2088b6STudor Ambarus 	dd = atmel_aes_dev_alloc(&ctx->base);
2138ec2088b6STudor Ambarus 	if (!dd)
2139ec2088b6STudor Ambarus 		return -ENODEV;
214089a82ef8SCyrille Pitchen 
214189a82ef8SCyrille Pitchen 	ctx->auth = atmel_sha_authenc_spawn(auth_mode);
214289a82ef8SCyrille Pitchen 	if (IS_ERR(ctx->auth))
214389a82ef8SCyrille Pitchen 		return PTR_ERR(ctx->auth);
214489a82ef8SCyrille Pitchen 
214589a82ef8SCyrille Pitchen 	crypto_aead_set_reqsize(tfm, (sizeof(struct atmel_aes_authenc_reqctx) +
214689a82ef8SCyrille Pitchen 				      auth_reqsize));
2147ec2088b6STudor Ambarus 	ctx->base.dd = dd;
214889a82ef8SCyrille Pitchen 	ctx->base.start = atmel_aes_authenc_start;
214989a82ef8SCyrille Pitchen 
215089a82ef8SCyrille Pitchen 	return 0;
215189a82ef8SCyrille Pitchen }
215289a82ef8SCyrille Pitchen 
atmel_aes_authenc_hmac_sha1_init_tfm(struct crypto_aead * tfm)215389a82ef8SCyrille Pitchen static int atmel_aes_authenc_hmac_sha1_init_tfm(struct crypto_aead *tfm)
215489a82ef8SCyrille Pitchen {
215589a82ef8SCyrille Pitchen 	return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA1);
215689a82ef8SCyrille Pitchen }
215789a82ef8SCyrille Pitchen 
atmel_aes_authenc_hmac_sha224_init_tfm(struct crypto_aead * tfm)215889a82ef8SCyrille Pitchen static int atmel_aes_authenc_hmac_sha224_init_tfm(struct crypto_aead *tfm)
215989a82ef8SCyrille Pitchen {
216089a82ef8SCyrille Pitchen 	return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA224);
216189a82ef8SCyrille Pitchen }
216289a82ef8SCyrille Pitchen 
atmel_aes_authenc_hmac_sha256_init_tfm(struct crypto_aead * tfm)216389a82ef8SCyrille Pitchen static int atmel_aes_authenc_hmac_sha256_init_tfm(struct crypto_aead *tfm)
216489a82ef8SCyrille Pitchen {
216589a82ef8SCyrille Pitchen 	return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA256);
216689a82ef8SCyrille Pitchen }
216789a82ef8SCyrille Pitchen 
atmel_aes_authenc_hmac_sha384_init_tfm(struct crypto_aead * tfm)216889a82ef8SCyrille Pitchen static int atmel_aes_authenc_hmac_sha384_init_tfm(struct crypto_aead *tfm)
216989a82ef8SCyrille Pitchen {
217089a82ef8SCyrille Pitchen 	return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA384);
217189a82ef8SCyrille Pitchen }
217289a82ef8SCyrille Pitchen 
atmel_aes_authenc_hmac_sha512_init_tfm(struct crypto_aead * tfm)217389a82ef8SCyrille Pitchen static int atmel_aes_authenc_hmac_sha512_init_tfm(struct crypto_aead *tfm)
217489a82ef8SCyrille Pitchen {
217589a82ef8SCyrille Pitchen 	return atmel_aes_authenc_init_tfm(tfm, SHA_FLAGS_HMAC_SHA512);
217689a82ef8SCyrille Pitchen }
217789a82ef8SCyrille Pitchen 
atmel_aes_authenc_exit_tfm(struct crypto_aead * tfm)217889a82ef8SCyrille Pitchen static void atmel_aes_authenc_exit_tfm(struct crypto_aead *tfm)
217989a82ef8SCyrille Pitchen {
218089a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm);
218189a82ef8SCyrille Pitchen 
218289a82ef8SCyrille Pitchen 	atmel_sha_authenc_free(ctx->auth);
218389a82ef8SCyrille Pitchen }
218489a82ef8SCyrille Pitchen 
atmel_aes_authenc_crypt(struct aead_request * req,unsigned long mode)218589a82ef8SCyrille Pitchen static int atmel_aes_authenc_crypt(struct aead_request *req,
218689a82ef8SCyrille Pitchen 				   unsigned long mode)
218789a82ef8SCyrille Pitchen {
218889a82ef8SCyrille Pitchen 	struct atmel_aes_authenc_reqctx *rctx = aead_request_ctx(req);
218989a82ef8SCyrille Pitchen 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
219089a82ef8SCyrille Pitchen 	struct atmel_aes_base_ctx *ctx = crypto_aead_ctx(tfm);
219189a82ef8SCyrille Pitchen 	u32 authsize = crypto_aead_authsize(tfm);
219289a82ef8SCyrille Pitchen 	bool enc = (mode & AES_FLAGS_ENCRYPT);
219389a82ef8SCyrille Pitchen 
219489a82ef8SCyrille Pitchen 	/* Compute text length. */
219589a82ef8SCyrille Pitchen 	if (!enc && req->cryptlen < authsize)
219689a82ef8SCyrille Pitchen 		return -EINVAL;
219789a82ef8SCyrille Pitchen 	rctx->textlen = req->cryptlen - (enc ? 0 : authsize);
219889a82ef8SCyrille Pitchen 
219989a82ef8SCyrille Pitchen 	/*
220089a82ef8SCyrille Pitchen 	 * Currently, empty messages are not supported yet:
220189a82ef8SCyrille Pitchen 	 * the SHA auto-padding can be used only on non-empty messages.
220289a82ef8SCyrille Pitchen 	 * Hence a special case needs to be implemented for empty message.
220389a82ef8SCyrille Pitchen 	 */
220489a82ef8SCyrille Pitchen 	if (!rctx->textlen && !req->assoclen)
220589a82ef8SCyrille Pitchen 		return -EINVAL;
220689a82ef8SCyrille Pitchen 
220789a82ef8SCyrille Pitchen 	rctx->base.mode = mode;
220889a82ef8SCyrille Pitchen 	ctx->block_size = AES_BLOCK_SIZE;
220991308019SRomain Izard 	ctx->is_aead = true;
221089a82ef8SCyrille Pitchen 
2211ec2088b6STudor Ambarus 	return atmel_aes_handle_queue(ctx->dd, &req->base);
221289a82ef8SCyrille Pitchen }
221389a82ef8SCyrille Pitchen 
atmel_aes_authenc_cbc_aes_encrypt(struct aead_request * req)221489a82ef8SCyrille Pitchen static int atmel_aes_authenc_cbc_aes_encrypt(struct aead_request *req)
221589a82ef8SCyrille Pitchen {
221689a82ef8SCyrille Pitchen 	return atmel_aes_authenc_crypt(req, AES_FLAGS_CBC | AES_FLAGS_ENCRYPT);
221789a82ef8SCyrille Pitchen }
221889a82ef8SCyrille Pitchen 
atmel_aes_authenc_cbc_aes_decrypt(struct aead_request * req)221989a82ef8SCyrille Pitchen static int atmel_aes_authenc_cbc_aes_decrypt(struct aead_request *req)
222089a82ef8SCyrille Pitchen {
222189a82ef8SCyrille Pitchen 	return atmel_aes_authenc_crypt(req, AES_FLAGS_CBC);
222289a82ef8SCyrille Pitchen }
222389a82ef8SCyrille Pitchen 
222489a82ef8SCyrille Pitchen static struct aead_alg aes_authenc_algs[] = {
222589a82ef8SCyrille Pitchen {
222689a82ef8SCyrille Pitchen 	.setkey		= atmel_aes_authenc_setkey,
222789a82ef8SCyrille Pitchen 	.encrypt	= atmel_aes_authenc_cbc_aes_encrypt,
222889a82ef8SCyrille Pitchen 	.decrypt	= atmel_aes_authenc_cbc_aes_decrypt,
222989a82ef8SCyrille Pitchen 	.init		= atmel_aes_authenc_hmac_sha1_init_tfm,
223089a82ef8SCyrille Pitchen 	.exit		= atmel_aes_authenc_exit_tfm,
223189a82ef8SCyrille Pitchen 	.ivsize		= AES_BLOCK_SIZE,
223289a82ef8SCyrille Pitchen 	.maxauthsize	= SHA1_DIGEST_SIZE,
223389a82ef8SCyrille Pitchen 
223489a82ef8SCyrille Pitchen 	.base = {
223589a82ef8SCyrille Pitchen 		.cra_name		= "authenc(hmac(sha1),cbc(aes))",
223689a82ef8SCyrille Pitchen 		.cra_driver_name	= "atmel-authenc-hmac-sha1-cbc-aes",
223789a82ef8SCyrille Pitchen 		.cra_blocksize		= AES_BLOCK_SIZE,
223889a82ef8SCyrille Pitchen 		.cra_ctxsize		= sizeof(struct atmel_aes_authenc_ctx),
223989a82ef8SCyrille Pitchen 	},
224089a82ef8SCyrille Pitchen },
224189a82ef8SCyrille Pitchen {
224289a82ef8SCyrille Pitchen 	.setkey		= atmel_aes_authenc_setkey,
224389a82ef8SCyrille Pitchen 	.encrypt	= atmel_aes_authenc_cbc_aes_encrypt,
224489a82ef8SCyrille Pitchen 	.decrypt	= atmel_aes_authenc_cbc_aes_decrypt,
224589a82ef8SCyrille Pitchen 	.init		= atmel_aes_authenc_hmac_sha224_init_tfm,
224689a82ef8SCyrille Pitchen 	.exit		= atmel_aes_authenc_exit_tfm,
224789a82ef8SCyrille Pitchen 	.ivsize		= AES_BLOCK_SIZE,
224889a82ef8SCyrille Pitchen 	.maxauthsize	= SHA224_DIGEST_SIZE,
224989a82ef8SCyrille Pitchen 
225089a82ef8SCyrille Pitchen 	.base = {
225189a82ef8SCyrille Pitchen 		.cra_name		= "authenc(hmac(sha224),cbc(aes))",
225289a82ef8SCyrille Pitchen 		.cra_driver_name	= "atmel-authenc-hmac-sha224-cbc-aes",
225389a82ef8SCyrille Pitchen 		.cra_blocksize		= AES_BLOCK_SIZE,
225489a82ef8SCyrille Pitchen 		.cra_ctxsize		= sizeof(struct atmel_aes_authenc_ctx),
225589a82ef8SCyrille Pitchen 	},
225689a82ef8SCyrille Pitchen },
225789a82ef8SCyrille Pitchen {
225889a82ef8SCyrille Pitchen 	.setkey		= atmel_aes_authenc_setkey,
225989a82ef8SCyrille Pitchen 	.encrypt	= atmel_aes_authenc_cbc_aes_encrypt,
226089a82ef8SCyrille Pitchen 	.decrypt	= atmel_aes_authenc_cbc_aes_decrypt,
226189a82ef8SCyrille Pitchen 	.init		= atmel_aes_authenc_hmac_sha256_init_tfm,
226289a82ef8SCyrille Pitchen 	.exit		= atmel_aes_authenc_exit_tfm,
226389a82ef8SCyrille Pitchen 	.ivsize		= AES_BLOCK_SIZE,
226489a82ef8SCyrille Pitchen 	.maxauthsize	= SHA256_DIGEST_SIZE,
226589a82ef8SCyrille Pitchen 
226689a82ef8SCyrille Pitchen 	.base = {
226789a82ef8SCyrille Pitchen 		.cra_name		= "authenc(hmac(sha256),cbc(aes))",
226889a82ef8SCyrille Pitchen 		.cra_driver_name	= "atmel-authenc-hmac-sha256-cbc-aes",
226989a82ef8SCyrille Pitchen 		.cra_blocksize		= AES_BLOCK_SIZE,
227089a82ef8SCyrille Pitchen 		.cra_ctxsize		= sizeof(struct atmel_aes_authenc_ctx),
227189a82ef8SCyrille Pitchen 	},
227289a82ef8SCyrille Pitchen },
227389a82ef8SCyrille Pitchen {
227489a82ef8SCyrille Pitchen 	.setkey		= atmel_aes_authenc_setkey,
227589a82ef8SCyrille Pitchen 	.encrypt	= atmel_aes_authenc_cbc_aes_encrypt,
227689a82ef8SCyrille Pitchen 	.decrypt	= atmel_aes_authenc_cbc_aes_decrypt,
227789a82ef8SCyrille Pitchen 	.init		= atmel_aes_authenc_hmac_sha384_init_tfm,
227889a82ef8SCyrille Pitchen 	.exit		= atmel_aes_authenc_exit_tfm,
227989a82ef8SCyrille Pitchen 	.ivsize		= AES_BLOCK_SIZE,
228089a82ef8SCyrille Pitchen 	.maxauthsize	= SHA384_DIGEST_SIZE,
228189a82ef8SCyrille Pitchen 
228289a82ef8SCyrille Pitchen 	.base = {
228389a82ef8SCyrille Pitchen 		.cra_name		= "authenc(hmac(sha384),cbc(aes))",
228489a82ef8SCyrille Pitchen 		.cra_driver_name	= "atmel-authenc-hmac-sha384-cbc-aes",
228589a82ef8SCyrille Pitchen 		.cra_blocksize		= AES_BLOCK_SIZE,
228689a82ef8SCyrille Pitchen 		.cra_ctxsize		= sizeof(struct atmel_aes_authenc_ctx),
228789a82ef8SCyrille Pitchen 	},
228889a82ef8SCyrille Pitchen },
228989a82ef8SCyrille Pitchen {
229089a82ef8SCyrille Pitchen 	.setkey		= atmel_aes_authenc_setkey,
229189a82ef8SCyrille Pitchen 	.encrypt	= atmel_aes_authenc_cbc_aes_encrypt,
229289a82ef8SCyrille Pitchen 	.decrypt	= atmel_aes_authenc_cbc_aes_decrypt,
229389a82ef8SCyrille Pitchen 	.init		= atmel_aes_authenc_hmac_sha512_init_tfm,
229489a82ef8SCyrille Pitchen 	.exit		= atmel_aes_authenc_exit_tfm,
229589a82ef8SCyrille Pitchen 	.ivsize		= AES_BLOCK_SIZE,
229689a82ef8SCyrille Pitchen 	.maxauthsize	= SHA512_DIGEST_SIZE,
229789a82ef8SCyrille Pitchen 
229889a82ef8SCyrille Pitchen 	.base = {
229989a82ef8SCyrille Pitchen 		.cra_name		= "authenc(hmac(sha512),cbc(aes))",
230089a82ef8SCyrille Pitchen 		.cra_driver_name	= "atmel-authenc-hmac-sha512-cbc-aes",
230189a82ef8SCyrille Pitchen 		.cra_blocksize		= AES_BLOCK_SIZE,
230289a82ef8SCyrille Pitchen 		.cra_ctxsize		= sizeof(struct atmel_aes_authenc_ctx),
230389a82ef8SCyrille Pitchen 	},
230489a82ef8SCyrille Pitchen },
230589a82ef8SCyrille Pitchen };
230689a82ef8SCyrille Pitchen #endif /* CONFIG_CRYPTO_DEV_ATMEL_AUTHENC */
2307d52db518SCyrille Pitchen 
2308e37a7e55SCyrille Pitchen /* Probe functions */
2309e37a7e55SCyrille Pitchen 
atmel_aes_buff_init(struct atmel_aes_dev * dd)2310e37a7e55SCyrille Pitchen static int atmel_aes_buff_init(struct atmel_aes_dev *dd)
2311e37a7e55SCyrille Pitchen {
2312e37a7e55SCyrille Pitchen 	dd->buf = (void *)__get_free_pages(GFP_KERNEL, ATMEL_AES_BUFFER_ORDER);
2313e37a7e55SCyrille Pitchen 	dd->buflen = ATMEL_AES_BUFFER_SIZE;
2314e37a7e55SCyrille Pitchen 	dd->buflen &= ~(AES_BLOCK_SIZE - 1);
2315e37a7e55SCyrille Pitchen 
2316e37a7e55SCyrille Pitchen 	if (!dd->buf) {
2317e37a7e55SCyrille Pitchen 		dev_err(dd->dev, "unable to alloc pages.\n");
2318e37a7e55SCyrille Pitchen 		return -ENOMEM;
2319e37a7e55SCyrille Pitchen 	}
2320e37a7e55SCyrille Pitchen 
2321e37a7e55SCyrille Pitchen 	return 0;
2322e37a7e55SCyrille Pitchen }
2323e37a7e55SCyrille Pitchen 
atmel_aes_buff_cleanup(struct atmel_aes_dev * dd)2324e37a7e55SCyrille Pitchen static void atmel_aes_buff_cleanup(struct atmel_aes_dev *dd)
2325e37a7e55SCyrille Pitchen {
2326e37a7e55SCyrille Pitchen 	free_page((unsigned long)dd->buf);
2327e37a7e55SCyrille Pitchen }
2328e37a7e55SCyrille Pitchen 
atmel_aes_dma_init(struct atmel_aes_dev * dd)2329827a98dfSTudor Ambarus static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
2330e37a7e55SCyrille Pitchen {
233162f72cbdSPeter Ujfalusi 	int ret;
2332e37a7e55SCyrille Pitchen 
2333e37a7e55SCyrille Pitchen 	/* Try to grab 2 DMA channels */
233462f72cbdSPeter Ujfalusi 	dd->src.chan = dma_request_chan(dd->dev, "tx");
233562f72cbdSPeter Ujfalusi 	if (IS_ERR(dd->src.chan)) {
233662f72cbdSPeter Ujfalusi 		ret = PTR_ERR(dd->src.chan);
2337e37a7e55SCyrille Pitchen 		goto err_dma_in;
233862f72cbdSPeter Ujfalusi 	}
2339e37a7e55SCyrille Pitchen 
234062f72cbdSPeter Ujfalusi 	dd->dst.chan = dma_request_chan(dd->dev, "rx");
234162f72cbdSPeter Ujfalusi 	if (IS_ERR(dd->dst.chan)) {
234262f72cbdSPeter Ujfalusi 		ret = PTR_ERR(dd->dst.chan);
2343e37a7e55SCyrille Pitchen 		goto err_dma_out;
234462f72cbdSPeter Ujfalusi 	}
2345e37a7e55SCyrille Pitchen 
2346e37a7e55SCyrille Pitchen 	return 0;
2347e37a7e55SCyrille Pitchen 
2348e37a7e55SCyrille Pitchen err_dma_out:
2349e37a7e55SCyrille Pitchen 	dma_release_channel(dd->src.chan);
2350e37a7e55SCyrille Pitchen err_dma_in:
2351e9ce6aeeSTudor Ambarus 	dev_err(dd->dev, "no DMA channel available\n");
235262f72cbdSPeter Ujfalusi 	return ret;
2353e37a7e55SCyrille Pitchen }
2354e37a7e55SCyrille Pitchen 
atmel_aes_dma_cleanup(struct atmel_aes_dev * dd)2355e37a7e55SCyrille Pitchen static void atmel_aes_dma_cleanup(struct atmel_aes_dev *dd)
2356e37a7e55SCyrille Pitchen {
2357e37a7e55SCyrille Pitchen 	dma_release_channel(dd->dst.chan);
2358e37a7e55SCyrille Pitchen 	dma_release_channel(dd->src.chan);
2359e37a7e55SCyrille Pitchen }
2360e37a7e55SCyrille Pitchen 
atmel_aes_queue_task(unsigned long data)2361bd3c7b5cSNicolas Royer static void atmel_aes_queue_task(unsigned long data)
2362bd3c7b5cSNicolas Royer {
2363bd3c7b5cSNicolas Royer 	struct atmel_aes_dev *dd = (struct atmel_aes_dev *)data;
2364bd3c7b5cSNicolas Royer 
2365bd3c7b5cSNicolas Royer 	atmel_aes_handle_queue(dd, NULL);
2366bd3c7b5cSNicolas Royer }
2367bd3c7b5cSNicolas Royer 
atmel_aes_done_task(unsigned long data)2368bd3c7b5cSNicolas Royer static void atmel_aes_done_task(unsigned long data)
2369bd3c7b5cSNicolas Royer {
2370bd3c7b5cSNicolas Royer 	struct atmel_aes_dev *dd = (struct atmel_aes_dev *)data;
2371bd3c7b5cSNicolas Royer 
237210f12c1bSCyrille Pitchen 	dd->is_async = true;
237310f12c1bSCyrille Pitchen 	(void)dd->resume(dd);
2374bd3c7b5cSNicolas Royer }
2375bd3c7b5cSNicolas Royer 
atmel_aes_irq(int irq,void * dev_id)2376bd3c7b5cSNicolas Royer static irqreturn_t atmel_aes_irq(int irq, void *dev_id)
2377bd3c7b5cSNicolas Royer {
2378bd3c7b5cSNicolas Royer 	struct atmel_aes_dev *aes_dd = dev_id;
2379bd3c7b5cSNicolas Royer 	u32 reg;
2380bd3c7b5cSNicolas Royer 
2381bd3c7b5cSNicolas Royer 	reg = atmel_aes_read(aes_dd, AES_ISR);
2382bd3c7b5cSNicolas Royer 	if (reg & atmel_aes_read(aes_dd, AES_IMR)) {
2383bd3c7b5cSNicolas Royer 		atmel_aes_write(aes_dd, AES_IDR, reg);
2384bd3c7b5cSNicolas Royer 		if (AES_FLAGS_BUSY & aes_dd->flags)
2385bd3c7b5cSNicolas Royer 			tasklet_schedule(&aes_dd->done_task);
2386bd3c7b5cSNicolas Royer 		else
2387bd3c7b5cSNicolas Royer 			dev_warn(aes_dd->dev, "AES interrupt when no active requests.\n");
2388bd3c7b5cSNicolas Royer 		return IRQ_HANDLED;
2389bd3c7b5cSNicolas Royer 	}
2390bd3c7b5cSNicolas Royer 
2391bd3c7b5cSNicolas Royer 	return IRQ_NONE;
2392bd3c7b5cSNicolas Royer }
2393bd3c7b5cSNicolas Royer 
atmel_aes_unregister_algs(struct atmel_aes_dev * dd)2394bd3c7b5cSNicolas Royer static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
2395bd3c7b5cSNicolas Royer {
2396bd3c7b5cSNicolas Royer 	int i;
2397bd3c7b5cSNicolas Royer 
23981520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
239989a82ef8SCyrille Pitchen 	if (dd->caps.has_authenc)
240089a82ef8SCyrille Pitchen 		for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++)
240189a82ef8SCyrille Pitchen 			crypto_unregister_aead(&aes_authenc_algs[i]);
240289a82ef8SCyrille Pitchen #endif
240389a82ef8SCyrille Pitchen 
2404d52db518SCyrille Pitchen 	if (dd->caps.has_xts)
24057ada42d2SArd Biesheuvel 		crypto_unregister_skcipher(&aes_xts_alg);
2406d52db518SCyrille Pitchen 
2407d4419548SCyrille Pitchen 	if (dd->caps.has_gcm)
2408d4419548SCyrille Pitchen 		crypto_unregister_aead(&aes_gcm_alg);
2409d4419548SCyrille Pitchen 
2410cadc4ab8SNicolas Royer 	if (dd->caps.has_cfb64)
24117ada42d2SArd Biesheuvel 		crypto_unregister_skcipher(&aes_cfb64_alg);
2412924a8bc7SCyrille Pitchen 
2413924a8bc7SCyrille Pitchen 	for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
24147ada42d2SArd Biesheuvel 		crypto_unregister_skcipher(&aes_algs[i]);
2415bd3c7b5cSNicolas Royer }
2416bd3c7b5cSNicolas Royer 
atmel_aes_crypto_alg_init(struct crypto_alg * alg)2417aebe5bd7STudor Ambarus static void atmel_aes_crypto_alg_init(struct crypto_alg *alg)
2418aebe5bd7STudor Ambarus {
2419bf2db8e7STudor Ambarus 	alg->cra_flags |= CRYPTO_ALG_ASYNC;
2420aebe5bd7STudor Ambarus 	alg->cra_alignmask = 0xf;
2421aebe5bd7STudor Ambarus 	alg->cra_priority = ATMEL_AES_PRIORITY;
2422aebe5bd7STudor Ambarus 	alg->cra_module = THIS_MODULE;
2423aebe5bd7STudor Ambarus }
2424aebe5bd7STudor Ambarus 
atmel_aes_register_algs(struct atmel_aes_dev * dd)2425bd3c7b5cSNicolas Royer static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
2426bd3c7b5cSNicolas Royer {
2427bd3c7b5cSNicolas Royer 	int err, i, j;
2428bd3c7b5cSNicolas Royer 
2429bd3c7b5cSNicolas Royer 	for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
2430aebe5bd7STudor Ambarus 		atmel_aes_crypto_alg_init(&aes_algs[i].base);
2431aebe5bd7STudor Ambarus 
24327ada42d2SArd Biesheuvel 		err = crypto_register_skcipher(&aes_algs[i]);
2433bd3c7b5cSNicolas Royer 		if (err)
2434bd3c7b5cSNicolas Royer 			goto err_aes_algs;
2435bd3c7b5cSNicolas Royer 	}
2436bd3c7b5cSNicolas Royer 
2437cadc4ab8SNicolas Royer 	if (dd->caps.has_cfb64) {
2438aebe5bd7STudor Ambarus 		atmel_aes_crypto_alg_init(&aes_cfb64_alg.base);
2439aebe5bd7STudor Ambarus 
24407ada42d2SArd Biesheuvel 		err = crypto_register_skcipher(&aes_cfb64_alg);
2441bd3c7b5cSNicolas Royer 		if (err)
2442bd3c7b5cSNicolas Royer 			goto err_aes_cfb64_alg;
2443bd3c7b5cSNicolas Royer 	}
2444bd3c7b5cSNicolas Royer 
2445d4419548SCyrille Pitchen 	if (dd->caps.has_gcm) {
2446aebe5bd7STudor Ambarus 		atmel_aes_crypto_alg_init(&aes_gcm_alg.base);
2447aebe5bd7STudor Ambarus 
2448d4419548SCyrille Pitchen 		err = crypto_register_aead(&aes_gcm_alg);
2449d4419548SCyrille Pitchen 		if (err)
2450d4419548SCyrille Pitchen 			goto err_aes_gcm_alg;
2451d4419548SCyrille Pitchen 	}
2452d4419548SCyrille Pitchen 
2453d52db518SCyrille Pitchen 	if (dd->caps.has_xts) {
2454aebe5bd7STudor Ambarus 		atmel_aes_crypto_alg_init(&aes_xts_alg.base);
2455aebe5bd7STudor Ambarus 
24567ada42d2SArd Biesheuvel 		err = crypto_register_skcipher(&aes_xts_alg);
2457d52db518SCyrille Pitchen 		if (err)
2458d52db518SCyrille Pitchen 			goto err_aes_xts_alg;
2459d52db518SCyrille Pitchen 	}
2460d52db518SCyrille Pitchen 
24611520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
246289a82ef8SCyrille Pitchen 	if (dd->caps.has_authenc) {
246389a82ef8SCyrille Pitchen 		for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++) {
2464aebe5bd7STudor Ambarus 			atmel_aes_crypto_alg_init(&aes_authenc_algs[i].base);
2465aebe5bd7STudor Ambarus 
246689a82ef8SCyrille Pitchen 			err = crypto_register_aead(&aes_authenc_algs[i]);
246789a82ef8SCyrille Pitchen 			if (err)
246889a82ef8SCyrille Pitchen 				goto err_aes_authenc_alg;
246989a82ef8SCyrille Pitchen 		}
247089a82ef8SCyrille Pitchen 	}
247189a82ef8SCyrille Pitchen #endif
247289a82ef8SCyrille Pitchen 
2473bd3c7b5cSNicolas Royer 	return 0;
2474bd3c7b5cSNicolas Royer 
24751520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
247689a82ef8SCyrille Pitchen 	/* i = ARRAY_SIZE(aes_authenc_algs); */
247789a82ef8SCyrille Pitchen err_aes_authenc_alg:
247889a82ef8SCyrille Pitchen 	for (j = 0; j < i; j++)
247989a82ef8SCyrille Pitchen 		crypto_unregister_aead(&aes_authenc_algs[j]);
24807ada42d2SArd Biesheuvel 	crypto_unregister_skcipher(&aes_xts_alg);
248189a82ef8SCyrille Pitchen #endif
2482d52db518SCyrille Pitchen err_aes_xts_alg:
2483d52db518SCyrille Pitchen 	crypto_unregister_aead(&aes_gcm_alg);
2484d4419548SCyrille Pitchen err_aes_gcm_alg:
24857ada42d2SArd Biesheuvel 	crypto_unregister_skcipher(&aes_cfb64_alg);
2486bd3c7b5cSNicolas Royer err_aes_cfb64_alg:
2487bd3c7b5cSNicolas Royer 	i = ARRAY_SIZE(aes_algs);
2488bd3c7b5cSNicolas Royer err_aes_algs:
2489bd3c7b5cSNicolas Royer 	for (j = 0; j < i; j++)
24907ada42d2SArd Biesheuvel 		crypto_unregister_skcipher(&aes_algs[j]);
2491bd3c7b5cSNicolas Royer 
2492bd3c7b5cSNicolas Royer 	return err;
2493bd3c7b5cSNicolas Royer }
2494bd3c7b5cSNicolas Royer 
atmel_aes_get_cap(struct atmel_aes_dev * dd)2495cadc4ab8SNicolas Royer static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
2496cadc4ab8SNicolas Royer {
2497cadc4ab8SNicolas Royer 	dd->caps.has_dualbuff = 0;
2498cadc4ab8SNicolas Royer 	dd->caps.has_cfb64 = 0;
2499d4419548SCyrille Pitchen 	dd->caps.has_gcm = 0;
2500d52db518SCyrille Pitchen 	dd->caps.has_xts = 0;
250189a82ef8SCyrille Pitchen 	dd->caps.has_authenc = 0;
2502cadc4ab8SNicolas Royer 	dd->caps.max_burst_size = 1;
2503cadc4ab8SNicolas Royer 
2504cadc4ab8SNicolas Royer 	/* keep only major version number */
2505cadc4ab8SNicolas Royer 	switch (dd->hw_version & 0xff0) {
250616d20a08SKavyasree Kotagiri 	case 0x700:
25074838c519SSergiu Moga 	case 0x600:
2508973e209dSLeilei Zhao 	case 0x500:
2509973e209dSLeilei Zhao 		dd->caps.has_dualbuff = 1;
2510973e209dSLeilei Zhao 		dd->caps.has_cfb64 = 1;
2511d4419548SCyrille Pitchen 		dd->caps.has_gcm = 1;
2512d52db518SCyrille Pitchen 		dd->caps.has_xts = 1;
251389a82ef8SCyrille Pitchen 		dd->caps.has_authenc = 1;
2514973e209dSLeilei Zhao 		dd->caps.max_burst_size = 4;
2515973e209dSLeilei Zhao 		break;
2516cf1f0d12SLeilei Zhao 	case 0x200:
2517cf1f0d12SLeilei Zhao 		dd->caps.has_dualbuff = 1;
2518cf1f0d12SLeilei Zhao 		dd->caps.has_cfb64 = 1;
2519d4419548SCyrille Pitchen 		dd->caps.has_gcm = 1;
2520cf1f0d12SLeilei Zhao 		dd->caps.max_burst_size = 4;
2521cf1f0d12SLeilei Zhao 		break;
2522cadc4ab8SNicolas Royer 	case 0x130:
2523cadc4ab8SNicolas Royer 		dd->caps.has_dualbuff = 1;
2524cadc4ab8SNicolas Royer 		dd->caps.has_cfb64 = 1;
2525cadc4ab8SNicolas Royer 		dd->caps.max_burst_size = 4;
2526cadc4ab8SNicolas Royer 		break;
2527cadc4ab8SNicolas Royer 	case 0x120:
2528cadc4ab8SNicolas Royer 		break;
2529cadc4ab8SNicolas Royer 	default:
2530cadc4ab8SNicolas Royer 		dev_warn(dd->dev,
2531cadc4ab8SNicolas Royer 				"Unmanaged aes version, set minimum capabilities\n");
2532cadc4ab8SNicolas Royer 		break;
2533cadc4ab8SNicolas Royer 	}
2534cadc4ab8SNicolas Royer }
2535cadc4ab8SNicolas Royer 
2536be943c7dSNicolas Ferre static const struct of_device_id atmel_aes_dt_ids[] = {
2537be943c7dSNicolas Ferre 	{ .compatible = "atmel,at91sam9g46-aes" },
2538be943c7dSNicolas Ferre 	{ /* sentinel */ }
2539be943c7dSNicolas Ferre };
2540be943c7dSNicolas Ferre MODULE_DEVICE_TABLE(of, atmel_aes_dt_ids);
2541be943c7dSNicolas Ferre 
atmel_aes_probe(struct platform_device * pdev)254249cfe4dbSGreg Kroah-Hartman static int atmel_aes_probe(struct platform_device *pdev)
2543bd3c7b5cSNicolas Royer {
2544bd3c7b5cSNicolas Royer 	struct atmel_aes_dev *aes_dd;
2545bd3c7b5cSNicolas Royer 	struct device *dev = &pdev->dev;
2546bd3c7b5cSNicolas Royer 	struct resource *aes_res;
2547bd3c7b5cSNicolas Royer 	int err;
2548bd3c7b5cSNicolas Royer 
2549b0e8b341SLABBE Corentin 	aes_dd = devm_kzalloc(&pdev->dev, sizeof(*aes_dd), GFP_KERNEL);
2550c9063a02STudor Ambarus 	if (!aes_dd)
2551c9063a02STudor Ambarus 		return -ENOMEM;
2552bd3c7b5cSNicolas Royer 
2553bd3c7b5cSNicolas Royer 	aes_dd->dev = dev;
2554bd3c7b5cSNicolas Royer 
2555bd3c7b5cSNicolas Royer 	platform_set_drvdata(pdev, aes_dd);
2556bd3c7b5cSNicolas Royer 
2557bd3c7b5cSNicolas Royer 	INIT_LIST_HEAD(&aes_dd->list);
25588a10eb8dSLeilei Zhao 	spin_lock_init(&aes_dd->lock);
2559bd3c7b5cSNicolas Royer 
2560bd3c7b5cSNicolas Royer 	tasklet_init(&aes_dd->done_task, atmel_aes_done_task,
2561bd3c7b5cSNicolas Royer 					(unsigned long)aes_dd);
2562bd3c7b5cSNicolas Royer 	tasklet_init(&aes_dd->queue_task, atmel_aes_queue_task,
2563bd3c7b5cSNicolas Royer 					(unsigned long)aes_dd);
2564bd3c7b5cSNicolas Royer 
2565bd3c7b5cSNicolas Royer 	crypto_init_queue(&aes_dd->queue, ATMEL_AES_QUEUE_LENGTH);
2566bd3c7b5cSNicolas Royer 
25673aaafe05SYangtao Li 	aes_dd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &aes_res);
25683aaafe05SYangtao Li 	if (IS_ERR(aes_dd->io_base)) {
25693aaafe05SYangtao Li 		err = PTR_ERR(aes_dd->io_base);
2570e7836518STudor Ambarus 		goto err_tasklet_kill;
2571bd3c7b5cSNicolas Royer 	}
2572bd3c7b5cSNicolas Royer 	aes_dd->phys_base = aes_res->start;
2573bd3c7b5cSNicolas Royer 
2574bd3c7b5cSNicolas Royer 	/* Get the IRQ */
2575bd3c7b5cSNicolas Royer 	aes_dd->irq = platform_get_irq(pdev,  0);
2576bd3c7b5cSNicolas Royer 	if (aes_dd->irq < 0) {
2577bd3c7b5cSNicolas Royer 		err = aes_dd->irq;
2578e7836518STudor Ambarus 		goto err_tasklet_kill;
2579bd3c7b5cSNicolas Royer 	}
2580bd3c7b5cSNicolas Royer 
2581b0e8b341SLABBE Corentin 	err = devm_request_irq(&pdev->dev, aes_dd->irq, atmel_aes_irq,
2582b0e8b341SLABBE Corentin 			       IRQF_SHARED, "atmel-aes", aes_dd);
2583bd3c7b5cSNicolas Royer 	if (err) {
2584bd3c7b5cSNicolas Royer 		dev_err(dev, "unable to request aes irq.\n");
2585e7836518STudor Ambarus 		goto err_tasklet_kill;
2586bd3c7b5cSNicolas Royer 	}
2587bd3c7b5cSNicolas Royer 
2588bd3c7b5cSNicolas Royer 	/* Initializing the clock */
2589b0e8b341SLABBE Corentin 	aes_dd->iclk = devm_clk_get(&pdev->dev, "aes_clk");
2590bd3c7b5cSNicolas Royer 	if (IS_ERR(aes_dd->iclk)) {
2591be208356SColin Ian King 		dev_err(dev, "clock initialization failed.\n");
2592bd3c7b5cSNicolas Royer 		err = PTR_ERR(aes_dd->iclk);
2593e7836518STudor Ambarus 		goto err_tasklet_kill;
2594bd3c7b5cSNicolas Royer 	}
2595bd3c7b5cSNicolas Royer 
259649a20454SCyrille Pitchen 	err = clk_prepare(aes_dd->iclk);
2597aab0a39bSCyrille Pitchen 	if (err)
2598e7836518STudor Ambarus 		goto err_tasklet_kill;
2599cadc4ab8SNicolas Royer 
260049a20454SCyrille Pitchen 	err = atmel_aes_hw_version_init(aes_dd);
260149a20454SCyrille Pitchen 	if (err)
2602e7836518STudor Ambarus 		goto err_iclk_unprepare;
260349a20454SCyrille Pitchen 
2604cadc4ab8SNicolas Royer 	atmel_aes_get_cap(aes_dd);
2605cadc4ab8SNicolas Royer 
26061520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC)
260789a82ef8SCyrille Pitchen 	if (aes_dd->caps.has_authenc && !atmel_sha_authenc_is_ready()) {
260889a82ef8SCyrille Pitchen 		err = -EPROBE_DEFER;
2609e7836518STudor Ambarus 		goto err_iclk_unprepare;
261089a82ef8SCyrille Pitchen 	}
261189a82ef8SCyrille Pitchen #endif
261289a82ef8SCyrille Pitchen 
2613cadc4ab8SNicolas Royer 	err = atmel_aes_buff_init(aes_dd);
2614cadc4ab8SNicolas Royer 	if (err)
2615e7836518STudor Ambarus 		goto err_iclk_unprepare;
2616cadc4ab8SNicolas Royer 
2617827a98dfSTudor Ambarus 	err = atmel_aes_dma_init(aes_dd);
2618bd3c7b5cSNicolas Royer 	if (err)
2619e7836518STudor Ambarus 		goto err_buff_cleanup;
2620bd3c7b5cSNicolas Royer 
2621bd3c7b5cSNicolas Royer 	spin_lock(&atmel_aes.lock);
2622bd3c7b5cSNicolas Royer 	list_add_tail(&aes_dd->list, &atmel_aes.dev_list);
2623bd3c7b5cSNicolas Royer 	spin_unlock(&atmel_aes.lock);
2624bd3c7b5cSNicolas Royer 
2625bd3c7b5cSNicolas Royer 	err = atmel_aes_register_algs(aes_dd);
2626bd3c7b5cSNicolas Royer 	if (err)
2627bd3c7b5cSNicolas Royer 		goto err_algs;
2628bd3c7b5cSNicolas Royer 
2629be943c7dSNicolas Ferre 	dev_info(dev, "Atmel AES - Using %s, %s for DMA transfers\n",
2630bbe628edSCyrille Pitchen 			dma_chan_name(aes_dd->src.chan),
2631bbe628edSCyrille Pitchen 			dma_chan_name(aes_dd->dst.chan));
2632bd3c7b5cSNicolas Royer 
2633bd3c7b5cSNicolas Royer 	return 0;
2634bd3c7b5cSNicolas Royer 
2635bd3c7b5cSNicolas Royer err_algs:
2636bd3c7b5cSNicolas Royer 	spin_lock(&atmel_aes.lock);
2637bd3c7b5cSNicolas Royer 	list_del(&aes_dd->list);
2638bd3c7b5cSNicolas Royer 	spin_unlock(&atmel_aes.lock);
2639bd3c7b5cSNicolas Royer 	atmel_aes_dma_cleanup(aes_dd);
2640e7836518STudor Ambarus err_buff_cleanup:
2641cadc4ab8SNicolas Royer 	atmel_aes_buff_cleanup(aes_dd);
2642e7836518STudor Ambarus err_iclk_unprepare:
264349a20454SCyrille Pitchen 	clk_unprepare(aes_dd->iclk);
2644e7836518STudor Ambarus err_tasklet_kill:
2645bd3c7b5cSNicolas Royer 	tasklet_kill(&aes_dd->done_task);
2646bd3c7b5cSNicolas Royer 	tasklet_kill(&aes_dd->queue_task);
2647bd3c7b5cSNicolas Royer 
2648bd3c7b5cSNicolas Royer 	return err;
2649bd3c7b5cSNicolas Royer }
2650bd3c7b5cSNicolas Royer 
atmel_aes_remove(struct platform_device * pdev)265149cfe4dbSGreg Kroah-Hartman static int atmel_aes_remove(struct platform_device *pdev)
2652bd3c7b5cSNicolas Royer {
2653fc783341SWei Yongjun 	struct atmel_aes_dev *aes_dd;
2654bd3c7b5cSNicolas Royer 
2655bd3c7b5cSNicolas Royer 	aes_dd = platform_get_drvdata(pdev);
26564fdcabb8SUwe Kleine-König 
2657bd3c7b5cSNicolas Royer 	spin_lock(&atmel_aes.lock);
2658bd3c7b5cSNicolas Royer 	list_del(&aes_dd->list);
2659bd3c7b5cSNicolas Royer 	spin_unlock(&atmel_aes.lock);
2660bd3c7b5cSNicolas Royer 
2661bd3c7b5cSNicolas Royer 	atmel_aes_unregister_algs(aes_dd);
2662bd3c7b5cSNicolas Royer 
2663bd3c7b5cSNicolas Royer 	tasklet_kill(&aes_dd->done_task);
2664bd3c7b5cSNicolas Royer 	tasklet_kill(&aes_dd->queue_task);
2665bd3c7b5cSNicolas Royer 
2666bd3c7b5cSNicolas Royer 	atmel_aes_dma_cleanup(aes_dd);
26672a377828SCyrille Pitchen 	atmel_aes_buff_cleanup(aes_dd);
2668bd3c7b5cSNicolas Royer 
266949a20454SCyrille Pitchen 	clk_unprepare(aes_dd->iclk);
267049a20454SCyrille Pitchen 
2671bd3c7b5cSNicolas Royer 	return 0;
2672bd3c7b5cSNicolas Royer }
2673bd3c7b5cSNicolas Royer 
2674bd3c7b5cSNicolas Royer static struct platform_driver atmel_aes_driver = {
2675bd3c7b5cSNicolas Royer 	.probe		= atmel_aes_probe,
267649cfe4dbSGreg Kroah-Hartman 	.remove		= atmel_aes_remove,
2677bd3c7b5cSNicolas Royer 	.driver		= {
2678bd3c7b5cSNicolas Royer 		.name	= "atmel_aes",
2679*b0cc7491SRob Herring 		.of_match_table = atmel_aes_dt_ids,
2680bd3c7b5cSNicolas Royer 	},
2681bd3c7b5cSNicolas Royer };
2682bd3c7b5cSNicolas Royer 
2683bd3c7b5cSNicolas Royer module_platform_driver(atmel_aes_driver);
2684bd3c7b5cSNicolas Royer 
2685bd3c7b5cSNicolas Royer MODULE_DESCRIPTION("Atmel AES hw acceleration support.");
2686bd3c7b5cSNicolas Royer MODULE_LICENSE("GPL v2");
2687bd3c7b5cSNicolas Royer MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
2688