xref: /OK3568_Linux_fs/kernel/drivers/crypto/ccp/ccp-ops.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * AMD Cryptographic Coprocessor (CCP) driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2013-2019 Advanced Micro Devices, Inc.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Tom Lendacky <thomas.lendacky@amd.com>
8*4882a593Smuzhiyun  * Author: Gary R Hook <gary.hook@amd.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/dma-mapping.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <crypto/scatterwalk.h>
16*4882a593Smuzhiyun #include <crypto/des.h>
17*4882a593Smuzhiyun #include <linux/ccp.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include "ccp-dev.h"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* SHA initial context values */
22*4882a593Smuzhiyun static const __be32 ccp_sha1_init[SHA1_DIGEST_SIZE / sizeof(__be32)] = {
23*4882a593Smuzhiyun 	cpu_to_be32(SHA1_H0), cpu_to_be32(SHA1_H1),
24*4882a593Smuzhiyun 	cpu_to_be32(SHA1_H2), cpu_to_be32(SHA1_H3),
25*4882a593Smuzhiyun 	cpu_to_be32(SHA1_H4),
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static const __be32 ccp_sha224_init[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
29*4882a593Smuzhiyun 	cpu_to_be32(SHA224_H0), cpu_to_be32(SHA224_H1),
30*4882a593Smuzhiyun 	cpu_to_be32(SHA224_H2), cpu_to_be32(SHA224_H3),
31*4882a593Smuzhiyun 	cpu_to_be32(SHA224_H4), cpu_to_be32(SHA224_H5),
32*4882a593Smuzhiyun 	cpu_to_be32(SHA224_H6), cpu_to_be32(SHA224_H7),
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static const __be32 ccp_sha256_init[SHA256_DIGEST_SIZE / sizeof(__be32)] = {
36*4882a593Smuzhiyun 	cpu_to_be32(SHA256_H0), cpu_to_be32(SHA256_H1),
37*4882a593Smuzhiyun 	cpu_to_be32(SHA256_H2), cpu_to_be32(SHA256_H3),
38*4882a593Smuzhiyun 	cpu_to_be32(SHA256_H4), cpu_to_be32(SHA256_H5),
39*4882a593Smuzhiyun 	cpu_to_be32(SHA256_H6), cpu_to_be32(SHA256_H7),
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static const __be64 ccp_sha384_init[SHA512_DIGEST_SIZE / sizeof(__be64)] = {
43*4882a593Smuzhiyun 	cpu_to_be64(SHA384_H0), cpu_to_be64(SHA384_H1),
44*4882a593Smuzhiyun 	cpu_to_be64(SHA384_H2), cpu_to_be64(SHA384_H3),
45*4882a593Smuzhiyun 	cpu_to_be64(SHA384_H4), cpu_to_be64(SHA384_H5),
46*4882a593Smuzhiyun 	cpu_to_be64(SHA384_H6), cpu_to_be64(SHA384_H7),
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun static const __be64 ccp_sha512_init[SHA512_DIGEST_SIZE / sizeof(__be64)] = {
50*4882a593Smuzhiyun 	cpu_to_be64(SHA512_H0), cpu_to_be64(SHA512_H1),
51*4882a593Smuzhiyun 	cpu_to_be64(SHA512_H2), cpu_to_be64(SHA512_H3),
52*4882a593Smuzhiyun 	cpu_to_be64(SHA512_H4), cpu_to_be64(SHA512_H5),
53*4882a593Smuzhiyun 	cpu_to_be64(SHA512_H6), cpu_to_be64(SHA512_H7),
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define	CCP_NEW_JOBID(ccp)	((ccp->vdata->version == CCP_VERSION(3, 0)) ? \
57*4882a593Smuzhiyun 					ccp_gen_jobid(ccp) : 0)
58*4882a593Smuzhiyun 
ccp_gen_jobid(struct ccp_device * ccp)59*4882a593Smuzhiyun static u32 ccp_gen_jobid(struct ccp_device *ccp)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	return atomic_inc_return(&ccp->current_id) & CCP_JOBID_MASK;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
ccp_sg_free(struct ccp_sg_workarea * wa)64*4882a593Smuzhiyun static void ccp_sg_free(struct ccp_sg_workarea *wa)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	if (wa->dma_count)
67*4882a593Smuzhiyun 		dma_unmap_sg(wa->dma_dev, wa->dma_sg_head, wa->nents, wa->dma_dir);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	wa->dma_count = 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
ccp_init_sg_workarea(struct ccp_sg_workarea * wa,struct device * dev,struct scatterlist * sg,u64 len,enum dma_data_direction dma_dir)72*4882a593Smuzhiyun static int ccp_init_sg_workarea(struct ccp_sg_workarea *wa, struct device *dev,
73*4882a593Smuzhiyun 				struct scatterlist *sg, u64 len,
74*4882a593Smuzhiyun 				enum dma_data_direction dma_dir)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	memset(wa, 0, sizeof(*wa));
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	wa->sg = sg;
79*4882a593Smuzhiyun 	if (!sg)
80*4882a593Smuzhiyun 		return 0;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	wa->nents = sg_nents_for_len(sg, len);
83*4882a593Smuzhiyun 	if (wa->nents < 0)
84*4882a593Smuzhiyun 		return wa->nents;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	wa->bytes_left = len;
87*4882a593Smuzhiyun 	wa->sg_used = 0;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	if (len == 0)
90*4882a593Smuzhiyun 		return 0;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (dma_dir == DMA_NONE)
93*4882a593Smuzhiyun 		return 0;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	wa->dma_sg = sg;
96*4882a593Smuzhiyun 	wa->dma_sg_head = sg;
97*4882a593Smuzhiyun 	wa->dma_dev = dev;
98*4882a593Smuzhiyun 	wa->dma_dir = dma_dir;
99*4882a593Smuzhiyun 	wa->dma_count = dma_map_sg(dev, sg, wa->nents, dma_dir);
100*4882a593Smuzhiyun 	if (!wa->dma_count)
101*4882a593Smuzhiyun 		return -ENOMEM;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
ccp_update_sg_workarea(struct ccp_sg_workarea * wa,unsigned int len)106*4882a593Smuzhiyun static void ccp_update_sg_workarea(struct ccp_sg_workarea *wa, unsigned int len)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	unsigned int nbytes = min_t(u64, len, wa->bytes_left);
109*4882a593Smuzhiyun 	unsigned int sg_combined_len = 0;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	if (!wa->sg)
112*4882a593Smuzhiyun 		return;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	wa->sg_used += nbytes;
115*4882a593Smuzhiyun 	wa->bytes_left -= nbytes;
116*4882a593Smuzhiyun 	if (wa->sg_used == sg_dma_len(wa->dma_sg)) {
117*4882a593Smuzhiyun 		/* Advance to the next DMA scatterlist entry */
118*4882a593Smuzhiyun 		wa->dma_sg = sg_next(wa->dma_sg);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 		/* In the case that the DMA mapped scatterlist has entries
121*4882a593Smuzhiyun 		 * that have been merged, the non-DMA mapped scatterlist
122*4882a593Smuzhiyun 		 * must be advanced multiple times for each merged entry.
123*4882a593Smuzhiyun 		 * This ensures that the current non-DMA mapped entry
124*4882a593Smuzhiyun 		 * corresponds to the current DMA mapped entry.
125*4882a593Smuzhiyun 		 */
126*4882a593Smuzhiyun 		do {
127*4882a593Smuzhiyun 			sg_combined_len += wa->sg->length;
128*4882a593Smuzhiyun 			wa->sg = sg_next(wa->sg);
129*4882a593Smuzhiyun 		} while (wa->sg_used > sg_combined_len);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 		wa->sg_used = 0;
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
ccp_dm_free(struct ccp_dm_workarea * wa)135*4882a593Smuzhiyun static void ccp_dm_free(struct ccp_dm_workarea *wa)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	if (wa->length <= CCP_DMAPOOL_MAX_SIZE) {
138*4882a593Smuzhiyun 		if (wa->address)
139*4882a593Smuzhiyun 			dma_pool_free(wa->dma_pool, wa->address,
140*4882a593Smuzhiyun 				      wa->dma.address);
141*4882a593Smuzhiyun 	} else {
142*4882a593Smuzhiyun 		if (wa->dma.address)
143*4882a593Smuzhiyun 			dma_unmap_single(wa->dev, wa->dma.address, wa->length,
144*4882a593Smuzhiyun 					 wa->dma.dir);
145*4882a593Smuzhiyun 		kfree(wa->address);
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	wa->address = NULL;
149*4882a593Smuzhiyun 	wa->dma.address = 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
ccp_init_dm_workarea(struct ccp_dm_workarea * wa,struct ccp_cmd_queue * cmd_q,unsigned int len,enum dma_data_direction dir)152*4882a593Smuzhiyun static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa,
153*4882a593Smuzhiyun 				struct ccp_cmd_queue *cmd_q,
154*4882a593Smuzhiyun 				unsigned int len,
155*4882a593Smuzhiyun 				enum dma_data_direction dir)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	memset(wa, 0, sizeof(*wa));
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (!len)
160*4882a593Smuzhiyun 		return 0;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	wa->dev = cmd_q->ccp->dev;
163*4882a593Smuzhiyun 	wa->length = len;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (len <= CCP_DMAPOOL_MAX_SIZE) {
166*4882a593Smuzhiyun 		wa->dma_pool = cmd_q->dma_pool;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 		wa->address = dma_pool_zalloc(wa->dma_pool, GFP_KERNEL,
169*4882a593Smuzhiyun 					     &wa->dma.address);
170*4882a593Smuzhiyun 		if (!wa->address)
171*4882a593Smuzhiyun 			return -ENOMEM;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 		wa->dma.length = CCP_DMAPOOL_MAX_SIZE;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	} else {
176*4882a593Smuzhiyun 		wa->address = kzalloc(len, GFP_KERNEL);
177*4882a593Smuzhiyun 		if (!wa->address)
178*4882a593Smuzhiyun 			return -ENOMEM;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		wa->dma.address = dma_map_single(wa->dev, wa->address, len,
181*4882a593Smuzhiyun 						 dir);
182*4882a593Smuzhiyun 		if (dma_mapping_error(wa->dev, wa->dma.address))
183*4882a593Smuzhiyun 			return -ENOMEM;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 		wa->dma.length = len;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 	wa->dma.dir = dir;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
ccp_set_dm_area(struct ccp_dm_workarea * wa,unsigned int wa_offset,struct scatterlist * sg,unsigned int sg_offset,unsigned int len)192*4882a593Smuzhiyun static int ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
193*4882a593Smuzhiyun 			   struct scatterlist *sg, unsigned int sg_offset,
194*4882a593Smuzhiyun 			   unsigned int len)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	WARN_ON(!wa->address);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	if (len > (wa->length - wa_offset))
199*4882a593Smuzhiyun 		return -EINVAL;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
202*4882a593Smuzhiyun 				 0);
203*4882a593Smuzhiyun 	return 0;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
ccp_get_dm_area(struct ccp_dm_workarea * wa,unsigned int wa_offset,struct scatterlist * sg,unsigned int sg_offset,unsigned int len)206*4882a593Smuzhiyun static void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
207*4882a593Smuzhiyun 			    struct scatterlist *sg, unsigned int sg_offset,
208*4882a593Smuzhiyun 			    unsigned int len)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	WARN_ON(!wa->address);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
213*4882a593Smuzhiyun 				 1);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
ccp_reverse_set_dm_area(struct ccp_dm_workarea * wa,unsigned int wa_offset,struct scatterlist * sg,unsigned int sg_offset,unsigned int len)216*4882a593Smuzhiyun static int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa,
217*4882a593Smuzhiyun 				   unsigned int wa_offset,
218*4882a593Smuzhiyun 				   struct scatterlist *sg,
219*4882a593Smuzhiyun 				   unsigned int sg_offset,
220*4882a593Smuzhiyun 				   unsigned int len)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	u8 *p, *q;
223*4882a593Smuzhiyun 	int	rc;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	rc = ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len);
226*4882a593Smuzhiyun 	if (rc)
227*4882a593Smuzhiyun 		return rc;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	p = wa->address + wa_offset;
230*4882a593Smuzhiyun 	q = p + len - 1;
231*4882a593Smuzhiyun 	while (p < q) {
232*4882a593Smuzhiyun 		*p = *p ^ *q;
233*4882a593Smuzhiyun 		*q = *p ^ *q;
234*4882a593Smuzhiyun 		*p = *p ^ *q;
235*4882a593Smuzhiyun 		p++;
236*4882a593Smuzhiyun 		q--;
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 	return 0;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
ccp_reverse_get_dm_area(struct ccp_dm_workarea * wa,unsigned int wa_offset,struct scatterlist * sg,unsigned int sg_offset,unsigned int len)241*4882a593Smuzhiyun static void ccp_reverse_get_dm_area(struct ccp_dm_workarea *wa,
242*4882a593Smuzhiyun 				    unsigned int wa_offset,
243*4882a593Smuzhiyun 				    struct scatterlist *sg,
244*4882a593Smuzhiyun 				    unsigned int sg_offset,
245*4882a593Smuzhiyun 				    unsigned int len)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	u8 *p, *q;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	p = wa->address + wa_offset;
250*4882a593Smuzhiyun 	q = p + len - 1;
251*4882a593Smuzhiyun 	while (p < q) {
252*4882a593Smuzhiyun 		*p = *p ^ *q;
253*4882a593Smuzhiyun 		*q = *p ^ *q;
254*4882a593Smuzhiyun 		*p = *p ^ *q;
255*4882a593Smuzhiyun 		p++;
256*4882a593Smuzhiyun 		q--;
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	ccp_get_dm_area(wa, wa_offset, sg, sg_offset, len);
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
ccp_free_data(struct ccp_data * data,struct ccp_cmd_queue * cmd_q)262*4882a593Smuzhiyun static void ccp_free_data(struct ccp_data *data, struct ccp_cmd_queue *cmd_q)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	ccp_dm_free(&data->dm_wa);
265*4882a593Smuzhiyun 	ccp_sg_free(&data->sg_wa);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
ccp_init_data(struct ccp_data * data,struct ccp_cmd_queue * cmd_q,struct scatterlist * sg,u64 sg_len,unsigned int dm_len,enum dma_data_direction dir)268*4882a593Smuzhiyun static int ccp_init_data(struct ccp_data *data, struct ccp_cmd_queue *cmd_q,
269*4882a593Smuzhiyun 			 struct scatterlist *sg, u64 sg_len,
270*4882a593Smuzhiyun 			 unsigned int dm_len,
271*4882a593Smuzhiyun 			 enum dma_data_direction dir)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	int ret;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	memset(data, 0, sizeof(*data));
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	ret = ccp_init_sg_workarea(&data->sg_wa, cmd_q->ccp->dev, sg, sg_len,
278*4882a593Smuzhiyun 				   dir);
279*4882a593Smuzhiyun 	if (ret)
280*4882a593Smuzhiyun 		goto e_err;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&data->dm_wa, cmd_q, dm_len, dir);
283*4882a593Smuzhiyun 	if (ret)
284*4882a593Smuzhiyun 		goto e_err;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	return 0;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun e_err:
289*4882a593Smuzhiyun 	ccp_free_data(data, cmd_q);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	return ret;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
ccp_queue_buf(struct ccp_data * data,unsigned int from)294*4882a593Smuzhiyun static unsigned int ccp_queue_buf(struct ccp_data *data, unsigned int from)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct ccp_sg_workarea *sg_wa = &data->sg_wa;
297*4882a593Smuzhiyun 	struct ccp_dm_workarea *dm_wa = &data->dm_wa;
298*4882a593Smuzhiyun 	unsigned int buf_count, nbytes;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	/* Clear the buffer if setting it */
301*4882a593Smuzhiyun 	if (!from)
302*4882a593Smuzhiyun 		memset(dm_wa->address, 0, dm_wa->length);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	if (!sg_wa->sg)
305*4882a593Smuzhiyun 		return 0;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	/* Perform the copy operation
308*4882a593Smuzhiyun 	 *   nbytes will always be <= UINT_MAX because dm_wa->length is
309*4882a593Smuzhiyun 	 *   an unsigned int
310*4882a593Smuzhiyun 	 */
311*4882a593Smuzhiyun 	nbytes = min_t(u64, sg_wa->bytes_left, dm_wa->length);
312*4882a593Smuzhiyun 	scatterwalk_map_and_copy(dm_wa->address, sg_wa->sg, sg_wa->sg_used,
313*4882a593Smuzhiyun 				 nbytes, from);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	/* Update the structures and generate the count */
316*4882a593Smuzhiyun 	buf_count = 0;
317*4882a593Smuzhiyun 	while (sg_wa->bytes_left && (buf_count < dm_wa->length)) {
318*4882a593Smuzhiyun 		nbytes = min(sg_dma_len(sg_wa->dma_sg) - sg_wa->sg_used,
319*4882a593Smuzhiyun 			     dm_wa->length - buf_count);
320*4882a593Smuzhiyun 		nbytes = min_t(u64, sg_wa->bytes_left, nbytes);
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 		buf_count += nbytes;
323*4882a593Smuzhiyun 		ccp_update_sg_workarea(sg_wa, nbytes);
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return buf_count;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
ccp_fill_queue_buf(struct ccp_data * data)329*4882a593Smuzhiyun static unsigned int ccp_fill_queue_buf(struct ccp_data *data)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	return ccp_queue_buf(data, 0);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
ccp_empty_queue_buf(struct ccp_data * data)334*4882a593Smuzhiyun static unsigned int ccp_empty_queue_buf(struct ccp_data *data)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	return ccp_queue_buf(data, 1);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
ccp_prepare_data(struct ccp_data * src,struct ccp_data * dst,struct ccp_op * op,unsigned int block_size,bool blocksize_op)339*4882a593Smuzhiyun static void ccp_prepare_data(struct ccp_data *src, struct ccp_data *dst,
340*4882a593Smuzhiyun 			     struct ccp_op *op, unsigned int block_size,
341*4882a593Smuzhiyun 			     bool blocksize_op)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	unsigned int sg_src_len, sg_dst_len, op_len;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	/* The CCP can only DMA from/to one address each per operation. This
346*4882a593Smuzhiyun 	 * requires that we find the smallest DMA area between the source
347*4882a593Smuzhiyun 	 * and destination. The resulting len values will always be <= UINT_MAX
348*4882a593Smuzhiyun 	 * because the dma length is an unsigned int.
349*4882a593Smuzhiyun 	 */
350*4882a593Smuzhiyun 	sg_src_len = sg_dma_len(src->sg_wa.dma_sg) - src->sg_wa.sg_used;
351*4882a593Smuzhiyun 	sg_src_len = min_t(u64, src->sg_wa.bytes_left, sg_src_len);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	if (dst) {
354*4882a593Smuzhiyun 		sg_dst_len = sg_dma_len(dst->sg_wa.dma_sg) - dst->sg_wa.sg_used;
355*4882a593Smuzhiyun 		sg_dst_len = min_t(u64, src->sg_wa.bytes_left, sg_dst_len);
356*4882a593Smuzhiyun 		op_len = min(sg_src_len, sg_dst_len);
357*4882a593Smuzhiyun 	} else {
358*4882a593Smuzhiyun 		op_len = sg_src_len;
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	/* The data operation length will be at least block_size in length
362*4882a593Smuzhiyun 	 * or the smaller of available sg room remaining for the source or
363*4882a593Smuzhiyun 	 * the destination
364*4882a593Smuzhiyun 	 */
365*4882a593Smuzhiyun 	op_len = max(op_len, block_size);
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	/* Unless we have to buffer data, there's no reason to wait */
368*4882a593Smuzhiyun 	op->soc = 0;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (sg_src_len < block_size) {
371*4882a593Smuzhiyun 		/* Not enough data in the sg element, so it
372*4882a593Smuzhiyun 		 * needs to be buffered into a blocksize chunk
373*4882a593Smuzhiyun 		 */
374*4882a593Smuzhiyun 		int cp_len = ccp_fill_queue_buf(src);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 		op->soc = 1;
377*4882a593Smuzhiyun 		op->src.u.dma.address = src->dm_wa.dma.address;
378*4882a593Smuzhiyun 		op->src.u.dma.offset = 0;
379*4882a593Smuzhiyun 		op->src.u.dma.length = (blocksize_op) ? block_size : cp_len;
380*4882a593Smuzhiyun 	} else {
381*4882a593Smuzhiyun 		/* Enough data in the sg element, but we need to
382*4882a593Smuzhiyun 		 * adjust for any previously copied data
383*4882a593Smuzhiyun 		 */
384*4882a593Smuzhiyun 		op->src.u.dma.address = sg_dma_address(src->sg_wa.dma_sg);
385*4882a593Smuzhiyun 		op->src.u.dma.offset = src->sg_wa.sg_used;
386*4882a593Smuzhiyun 		op->src.u.dma.length = op_len & ~(block_size - 1);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 		ccp_update_sg_workarea(&src->sg_wa, op->src.u.dma.length);
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	if (dst) {
392*4882a593Smuzhiyun 		if (sg_dst_len < block_size) {
393*4882a593Smuzhiyun 			/* Not enough room in the sg element or we're on the
394*4882a593Smuzhiyun 			 * last piece of data (when using padding), so the
395*4882a593Smuzhiyun 			 * output needs to be buffered into a blocksize chunk
396*4882a593Smuzhiyun 			 */
397*4882a593Smuzhiyun 			op->soc = 1;
398*4882a593Smuzhiyun 			op->dst.u.dma.address = dst->dm_wa.dma.address;
399*4882a593Smuzhiyun 			op->dst.u.dma.offset = 0;
400*4882a593Smuzhiyun 			op->dst.u.dma.length = op->src.u.dma.length;
401*4882a593Smuzhiyun 		} else {
402*4882a593Smuzhiyun 			/* Enough room in the sg element, but we need to
403*4882a593Smuzhiyun 			 * adjust for any previously used area
404*4882a593Smuzhiyun 			 */
405*4882a593Smuzhiyun 			op->dst.u.dma.address = sg_dma_address(dst->sg_wa.dma_sg);
406*4882a593Smuzhiyun 			op->dst.u.dma.offset = dst->sg_wa.sg_used;
407*4882a593Smuzhiyun 			op->dst.u.dma.length = op->src.u.dma.length;
408*4882a593Smuzhiyun 		}
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
ccp_process_data(struct ccp_data * src,struct ccp_data * dst,struct ccp_op * op)412*4882a593Smuzhiyun static void ccp_process_data(struct ccp_data *src, struct ccp_data *dst,
413*4882a593Smuzhiyun 			     struct ccp_op *op)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	op->init = 0;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	if (dst) {
418*4882a593Smuzhiyun 		if (op->dst.u.dma.address == dst->dm_wa.dma.address)
419*4882a593Smuzhiyun 			ccp_empty_queue_buf(dst);
420*4882a593Smuzhiyun 		else
421*4882a593Smuzhiyun 			ccp_update_sg_workarea(&dst->sg_wa,
422*4882a593Smuzhiyun 					       op->dst.u.dma.length);
423*4882a593Smuzhiyun 	}
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
ccp_copy_to_from_sb(struct ccp_cmd_queue * cmd_q,struct ccp_dm_workarea * wa,u32 jobid,u32 sb,u32 byte_swap,bool from)426*4882a593Smuzhiyun static int ccp_copy_to_from_sb(struct ccp_cmd_queue *cmd_q,
427*4882a593Smuzhiyun 			       struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
428*4882a593Smuzhiyun 			       u32 byte_swap, bool from)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun 	struct ccp_op op;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
435*4882a593Smuzhiyun 	op.jobid = jobid;
436*4882a593Smuzhiyun 	op.eom = 1;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	if (from) {
439*4882a593Smuzhiyun 		op.soc = 1;
440*4882a593Smuzhiyun 		op.src.type = CCP_MEMTYPE_SB;
441*4882a593Smuzhiyun 		op.src.u.sb = sb;
442*4882a593Smuzhiyun 		op.dst.type = CCP_MEMTYPE_SYSTEM;
443*4882a593Smuzhiyun 		op.dst.u.dma.address = wa->dma.address;
444*4882a593Smuzhiyun 		op.dst.u.dma.length = wa->length;
445*4882a593Smuzhiyun 	} else {
446*4882a593Smuzhiyun 		op.src.type = CCP_MEMTYPE_SYSTEM;
447*4882a593Smuzhiyun 		op.src.u.dma.address = wa->dma.address;
448*4882a593Smuzhiyun 		op.src.u.dma.length = wa->length;
449*4882a593Smuzhiyun 		op.dst.type = CCP_MEMTYPE_SB;
450*4882a593Smuzhiyun 		op.dst.u.sb = sb;
451*4882a593Smuzhiyun 	}
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	op.u.passthru.byte_swap = byte_swap;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	return cmd_q->ccp->vdata->perform->passthru(&op);
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun 
ccp_copy_to_sb(struct ccp_cmd_queue * cmd_q,struct ccp_dm_workarea * wa,u32 jobid,u32 sb,u32 byte_swap)458*4882a593Smuzhiyun static int ccp_copy_to_sb(struct ccp_cmd_queue *cmd_q,
459*4882a593Smuzhiyun 			  struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
460*4882a593Smuzhiyun 			  u32 byte_swap)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun 	return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, false);
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
ccp_copy_from_sb(struct ccp_cmd_queue * cmd_q,struct ccp_dm_workarea * wa,u32 jobid,u32 sb,u32 byte_swap)465*4882a593Smuzhiyun static int ccp_copy_from_sb(struct ccp_cmd_queue *cmd_q,
466*4882a593Smuzhiyun 			    struct ccp_dm_workarea *wa, u32 jobid, u32 sb,
467*4882a593Smuzhiyun 			    u32 byte_swap)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, true);
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_aes_cmac_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)473*4882a593Smuzhiyun ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct ccp_aes_engine *aes = &cmd->u.aes;
476*4882a593Smuzhiyun 	struct ccp_dm_workarea key, ctx;
477*4882a593Smuzhiyun 	struct ccp_data src;
478*4882a593Smuzhiyun 	struct ccp_op op;
479*4882a593Smuzhiyun 	unsigned int dm_offset;
480*4882a593Smuzhiyun 	int ret;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	if (!((aes->key_len == AES_KEYSIZE_128) ||
483*4882a593Smuzhiyun 	      (aes->key_len == AES_KEYSIZE_192) ||
484*4882a593Smuzhiyun 	      (aes->key_len == AES_KEYSIZE_256)))
485*4882a593Smuzhiyun 		return -EINVAL;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	if (aes->src_len & (AES_BLOCK_SIZE - 1))
488*4882a593Smuzhiyun 		return -EINVAL;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	if (aes->iv_len != AES_BLOCK_SIZE)
491*4882a593Smuzhiyun 		return -EINVAL;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	if (!aes->key || !aes->iv || !aes->src)
494*4882a593Smuzhiyun 		return -EINVAL;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (aes->cmac_final) {
497*4882a593Smuzhiyun 		if (aes->cmac_key_len != AES_BLOCK_SIZE)
498*4882a593Smuzhiyun 			return -EINVAL;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 		if (!aes->cmac_key)
501*4882a593Smuzhiyun 			return -EINVAL;
502*4882a593Smuzhiyun 	}
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	BUILD_BUG_ON(CCP_AES_KEY_SB_COUNT != 1);
505*4882a593Smuzhiyun 	BUILD_BUG_ON(CCP_AES_CTX_SB_COUNT != 1);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	ret = -EIO;
508*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
509*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
510*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
511*4882a593Smuzhiyun 	op.sb_key = cmd_q->sb_key;
512*4882a593Smuzhiyun 	op.sb_ctx = cmd_q->sb_ctx;
513*4882a593Smuzhiyun 	op.init = 1;
514*4882a593Smuzhiyun 	op.u.aes.type = aes->type;
515*4882a593Smuzhiyun 	op.u.aes.mode = aes->mode;
516*4882a593Smuzhiyun 	op.u.aes.action = aes->action;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	/* All supported key sizes fit in a single (32-byte) SB entry
519*4882a593Smuzhiyun 	 * and must be in little endian format. Use the 256-bit byte
520*4882a593Smuzhiyun 	 * swap passthru option to convert from big endian to little
521*4882a593Smuzhiyun 	 * endian.
522*4882a593Smuzhiyun 	 */
523*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&key, cmd_q,
524*4882a593Smuzhiyun 				   CCP_AES_KEY_SB_COUNT * CCP_SB_BYTES,
525*4882a593Smuzhiyun 				   DMA_TO_DEVICE);
526*4882a593Smuzhiyun 	if (ret)
527*4882a593Smuzhiyun 		return ret;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	dm_offset = CCP_SB_BYTES - aes->key_len;
530*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
531*4882a593Smuzhiyun 	if (ret)
532*4882a593Smuzhiyun 		goto e_key;
533*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
534*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
535*4882a593Smuzhiyun 	if (ret) {
536*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
537*4882a593Smuzhiyun 		goto e_key;
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	/* The AES context fits in a single (32-byte) SB entry and
541*4882a593Smuzhiyun 	 * must be in little endian format. Use the 256-bit byte swap
542*4882a593Smuzhiyun 	 * passthru option to convert from big endian to little endian.
543*4882a593Smuzhiyun 	 */
544*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&ctx, cmd_q,
545*4882a593Smuzhiyun 				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
546*4882a593Smuzhiyun 				   DMA_BIDIRECTIONAL);
547*4882a593Smuzhiyun 	if (ret)
548*4882a593Smuzhiyun 		goto e_key;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
551*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
552*4882a593Smuzhiyun 	if (ret)
553*4882a593Smuzhiyun 		goto e_ctx;
554*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
555*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
556*4882a593Smuzhiyun 	if (ret) {
557*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
558*4882a593Smuzhiyun 		goto e_ctx;
559*4882a593Smuzhiyun 	}
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	/* Send data to the CCP AES engine */
562*4882a593Smuzhiyun 	ret = ccp_init_data(&src, cmd_q, aes->src, aes->src_len,
563*4882a593Smuzhiyun 			    AES_BLOCK_SIZE, DMA_TO_DEVICE);
564*4882a593Smuzhiyun 	if (ret)
565*4882a593Smuzhiyun 		goto e_ctx;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	while (src.sg_wa.bytes_left) {
568*4882a593Smuzhiyun 		ccp_prepare_data(&src, NULL, &op, AES_BLOCK_SIZE, true);
569*4882a593Smuzhiyun 		if (aes->cmac_final && !src.sg_wa.bytes_left) {
570*4882a593Smuzhiyun 			op.eom = 1;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 			/* Push the K1/K2 key to the CCP now */
573*4882a593Smuzhiyun 			ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid,
574*4882a593Smuzhiyun 					       op.sb_ctx,
575*4882a593Smuzhiyun 					       CCP_PASSTHRU_BYTESWAP_256BIT);
576*4882a593Smuzhiyun 			if (ret) {
577*4882a593Smuzhiyun 				cmd->engine_error = cmd_q->cmd_error;
578*4882a593Smuzhiyun 				goto e_src;
579*4882a593Smuzhiyun 			}
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 			ret = ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
582*4882a593Smuzhiyun 					      aes->cmac_key_len);
583*4882a593Smuzhiyun 			if (ret)
584*4882a593Smuzhiyun 				goto e_src;
585*4882a593Smuzhiyun 			ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
586*4882a593Smuzhiyun 					     CCP_PASSTHRU_BYTESWAP_256BIT);
587*4882a593Smuzhiyun 			if (ret) {
588*4882a593Smuzhiyun 				cmd->engine_error = cmd_q->cmd_error;
589*4882a593Smuzhiyun 				goto e_src;
590*4882a593Smuzhiyun 			}
591*4882a593Smuzhiyun 		}
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 		ret = cmd_q->ccp->vdata->perform->aes(&op);
594*4882a593Smuzhiyun 		if (ret) {
595*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
596*4882a593Smuzhiyun 			goto e_src;
597*4882a593Smuzhiyun 		}
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 		ccp_process_data(&src, NULL, &op);
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	/* Retrieve the AES context - convert from LE to BE using
603*4882a593Smuzhiyun 	 * 32-byte (256-bit) byteswapping
604*4882a593Smuzhiyun 	 */
605*4882a593Smuzhiyun 	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
606*4882a593Smuzhiyun 			       CCP_PASSTHRU_BYTESWAP_256BIT);
607*4882a593Smuzhiyun 	if (ret) {
608*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
609*4882a593Smuzhiyun 		goto e_src;
610*4882a593Smuzhiyun 	}
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	/* ...but we only need AES_BLOCK_SIZE bytes */
613*4882a593Smuzhiyun 	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
614*4882a593Smuzhiyun 	ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun e_src:
617*4882a593Smuzhiyun 	ccp_free_data(&src, cmd_q);
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun e_ctx:
620*4882a593Smuzhiyun 	ccp_dm_free(&ctx);
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun e_key:
623*4882a593Smuzhiyun 	ccp_dm_free(&key);
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	return ret;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_aes_gcm_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)629*4882a593Smuzhiyun ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun 	struct ccp_aes_engine *aes = &cmd->u.aes;
632*4882a593Smuzhiyun 	struct ccp_dm_workarea key, ctx, final_wa, tag;
633*4882a593Smuzhiyun 	struct ccp_data src, dst;
634*4882a593Smuzhiyun 	struct ccp_data aad;
635*4882a593Smuzhiyun 	struct ccp_op op;
636*4882a593Smuzhiyun 	unsigned int dm_offset;
637*4882a593Smuzhiyun 	unsigned int authsize;
638*4882a593Smuzhiyun 	unsigned int jobid;
639*4882a593Smuzhiyun 	unsigned int ilen;
640*4882a593Smuzhiyun 	bool in_place = true; /* Default value */
641*4882a593Smuzhiyun 	__be64 *final;
642*4882a593Smuzhiyun 	int ret;
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	struct scatterlist *p_inp, sg_inp[2];
645*4882a593Smuzhiyun 	struct scatterlist *p_tag, sg_tag[2];
646*4882a593Smuzhiyun 	struct scatterlist *p_outp, sg_outp[2];
647*4882a593Smuzhiyun 	struct scatterlist *p_aad;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	if (!aes->iv)
650*4882a593Smuzhiyun 		return -EINVAL;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	if (!((aes->key_len == AES_KEYSIZE_128) ||
653*4882a593Smuzhiyun 		(aes->key_len == AES_KEYSIZE_192) ||
654*4882a593Smuzhiyun 		(aes->key_len == AES_KEYSIZE_256)))
655*4882a593Smuzhiyun 		return -EINVAL;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	if (!aes->key) /* Gotta have a key SGL */
658*4882a593Smuzhiyun 		return -EINVAL;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	/* Zero defaults to 16 bytes, the maximum size */
661*4882a593Smuzhiyun 	authsize = aes->authsize ? aes->authsize : AES_BLOCK_SIZE;
662*4882a593Smuzhiyun 	switch (authsize) {
663*4882a593Smuzhiyun 	case 16:
664*4882a593Smuzhiyun 	case 15:
665*4882a593Smuzhiyun 	case 14:
666*4882a593Smuzhiyun 	case 13:
667*4882a593Smuzhiyun 	case 12:
668*4882a593Smuzhiyun 	case 8:
669*4882a593Smuzhiyun 	case 4:
670*4882a593Smuzhiyun 		break;
671*4882a593Smuzhiyun 	default:
672*4882a593Smuzhiyun 		return -EINVAL;
673*4882a593Smuzhiyun 	}
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	/* First, decompose the source buffer into AAD & PT,
676*4882a593Smuzhiyun 	 * and the destination buffer into AAD, CT & tag, or
677*4882a593Smuzhiyun 	 * the input into CT & tag.
678*4882a593Smuzhiyun 	 * It is expected that the input and output SGs will
679*4882a593Smuzhiyun 	 * be valid, even if the AAD and input lengths are 0.
680*4882a593Smuzhiyun 	 */
681*4882a593Smuzhiyun 	p_aad = aes->src;
682*4882a593Smuzhiyun 	p_inp = scatterwalk_ffwd(sg_inp, aes->src, aes->aad_len);
683*4882a593Smuzhiyun 	p_outp = scatterwalk_ffwd(sg_outp, aes->dst, aes->aad_len);
684*4882a593Smuzhiyun 	if (aes->action == CCP_AES_ACTION_ENCRYPT) {
685*4882a593Smuzhiyun 		ilen = aes->src_len;
686*4882a593Smuzhiyun 		p_tag = scatterwalk_ffwd(sg_tag, p_outp, ilen);
687*4882a593Smuzhiyun 	} else {
688*4882a593Smuzhiyun 		/* Input length for decryption includes tag */
689*4882a593Smuzhiyun 		ilen = aes->src_len - authsize;
690*4882a593Smuzhiyun 		p_tag = scatterwalk_ffwd(sg_tag, p_inp, ilen);
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	jobid = CCP_NEW_JOBID(cmd_q->ccp);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
696*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
697*4882a593Smuzhiyun 	op.jobid = jobid;
698*4882a593Smuzhiyun 	op.sb_key = cmd_q->sb_key; /* Pre-allocated */
699*4882a593Smuzhiyun 	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
700*4882a593Smuzhiyun 	op.init = 1;
701*4882a593Smuzhiyun 	op.u.aes.type = aes->type;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	/* Copy the key to the LSB */
704*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&key, cmd_q,
705*4882a593Smuzhiyun 				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
706*4882a593Smuzhiyun 				   DMA_TO_DEVICE);
707*4882a593Smuzhiyun 	if (ret)
708*4882a593Smuzhiyun 		return ret;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	dm_offset = CCP_SB_BYTES - aes->key_len;
711*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
712*4882a593Smuzhiyun 	if (ret)
713*4882a593Smuzhiyun 		goto e_key;
714*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
715*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
716*4882a593Smuzhiyun 	if (ret) {
717*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
718*4882a593Smuzhiyun 		goto e_key;
719*4882a593Smuzhiyun 	}
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	/* Copy the context (IV) to the LSB.
722*4882a593Smuzhiyun 	 * There is an assumption here that the IV is 96 bits in length, plus
723*4882a593Smuzhiyun 	 * a nonce of 32 bits. If no IV is present, use a zeroed buffer.
724*4882a593Smuzhiyun 	 */
725*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&ctx, cmd_q,
726*4882a593Smuzhiyun 				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
727*4882a593Smuzhiyun 				   DMA_BIDIRECTIONAL);
728*4882a593Smuzhiyun 	if (ret)
729*4882a593Smuzhiyun 		goto e_key;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	dm_offset = CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES - aes->iv_len;
732*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
733*4882a593Smuzhiyun 	if (ret)
734*4882a593Smuzhiyun 		goto e_ctx;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
737*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
738*4882a593Smuzhiyun 	if (ret) {
739*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
740*4882a593Smuzhiyun 		goto e_ctx;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	op.init = 1;
744*4882a593Smuzhiyun 	if (aes->aad_len > 0) {
745*4882a593Smuzhiyun 		/* Step 1: Run a GHASH over the Additional Authenticated Data */
746*4882a593Smuzhiyun 		ret = ccp_init_data(&aad, cmd_q, p_aad, aes->aad_len,
747*4882a593Smuzhiyun 				    AES_BLOCK_SIZE,
748*4882a593Smuzhiyun 				    DMA_TO_DEVICE);
749*4882a593Smuzhiyun 		if (ret)
750*4882a593Smuzhiyun 			goto e_ctx;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 		op.u.aes.mode = CCP_AES_MODE_GHASH;
753*4882a593Smuzhiyun 		op.u.aes.action = CCP_AES_GHASHAAD;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 		while (aad.sg_wa.bytes_left) {
756*4882a593Smuzhiyun 			ccp_prepare_data(&aad, NULL, &op, AES_BLOCK_SIZE, true);
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 			ret = cmd_q->ccp->vdata->perform->aes(&op);
759*4882a593Smuzhiyun 			if (ret) {
760*4882a593Smuzhiyun 				cmd->engine_error = cmd_q->cmd_error;
761*4882a593Smuzhiyun 				goto e_aad;
762*4882a593Smuzhiyun 			}
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 			ccp_process_data(&aad, NULL, &op);
765*4882a593Smuzhiyun 			op.init = 0;
766*4882a593Smuzhiyun 		}
767*4882a593Smuzhiyun 	}
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	op.u.aes.mode = CCP_AES_MODE_GCTR;
770*4882a593Smuzhiyun 	op.u.aes.action = aes->action;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	if (ilen > 0) {
773*4882a593Smuzhiyun 		/* Step 2: Run a GCTR over the plaintext */
774*4882a593Smuzhiyun 		in_place = (sg_virt(p_inp) == sg_virt(p_outp)) ? true : false;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 		ret = ccp_init_data(&src, cmd_q, p_inp, ilen,
777*4882a593Smuzhiyun 				    AES_BLOCK_SIZE,
778*4882a593Smuzhiyun 				    in_place ? DMA_BIDIRECTIONAL
779*4882a593Smuzhiyun 					     : DMA_TO_DEVICE);
780*4882a593Smuzhiyun 		if (ret)
781*4882a593Smuzhiyun 			goto e_aad;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 		if (in_place) {
784*4882a593Smuzhiyun 			dst = src;
785*4882a593Smuzhiyun 		} else {
786*4882a593Smuzhiyun 			ret = ccp_init_data(&dst, cmd_q, p_outp, ilen,
787*4882a593Smuzhiyun 					    AES_BLOCK_SIZE, DMA_FROM_DEVICE);
788*4882a593Smuzhiyun 			if (ret)
789*4882a593Smuzhiyun 				goto e_src;
790*4882a593Smuzhiyun 		}
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 		op.soc = 0;
793*4882a593Smuzhiyun 		op.eom = 0;
794*4882a593Smuzhiyun 		op.init = 1;
795*4882a593Smuzhiyun 		while (src.sg_wa.bytes_left) {
796*4882a593Smuzhiyun 			ccp_prepare_data(&src, &dst, &op, AES_BLOCK_SIZE, true);
797*4882a593Smuzhiyun 			if (!src.sg_wa.bytes_left) {
798*4882a593Smuzhiyun 				unsigned int nbytes = ilen % AES_BLOCK_SIZE;
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 				if (nbytes) {
801*4882a593Smuzhiyun 					op.eom = 1;
802*4882a593Smuzhiyun 					op.u.aes.size = (nbytes * 8) - 1;
803*4882a593Smuzhiyun 				}
804*4882a593Smuzhiyun 			}
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 			ret = cmd_q->ccp->vdata->perform->aes(&op);
807*4882a593Smuzhiyun 			if (ret) {
808*4882a593Smuzhiyun 				cmd->engine_error = cmd_q->cmd_error;
809*4882a593Smuzhiyun 				goto e_dst;
810*4882a593Smuzhiyun 			}
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 			ccp_process_data(&src, &dst, &op);
813*4882a593Smuzhiyun 			op.init = 0;
814*4882a593Smuzhiyun 		}
815*4882a593Smuzhiyun 	}
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	/* Step 3: Update the IV portion of the context with the original IV */
818*4882a593Smuzhiyun 	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
819*4882a593Smuzhiyun 			       CCP_PASSTHRU_BYTESWAP_256BIT);
820*4882a593Smuzhiyun 	if (ret) {
821*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
822*4882a593Smuzhiyun 		goto e_dst;
823*4882a593Smuzhiyun 	}
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
826*4882a593Smuzhiyun 	if (ret)
827*4882a593Smuzhiyun 		goto e_dst;
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
830*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
831*4882a593Smuzhiyun 	if (ret) {
832*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
833*4882a593Smuzhiyun 		goto e_dst;
834*4882a593Smuzhiyun 	}
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	/* Step 4: Concatenate the lengths of the AAD and source, and
837*4882a593Smuzhiyun 	 * hash that 16 byte buffer.
838*4882a593Smuzhiyun 	 */
839*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&final_wa, cmd_q, AES_BLOCK_SIZE,
840*4882a593Smuzhiyun 				   DMA_BIDIRECTIONAL);
841*4882a593Smuzhiyun 	if (ret)
842*4882a593Smuzhiyun 		goto e_dst;
843*4882a593Smuzhiyun 	final = (__be64 *)final_wa.address;
844*4882a593Smuzhiyun 	final[0] = cpu_to_be64(aes->aad_len * 8);
845*4882a593Smuzhiyun 	final[1] = cpu_to_be64(ilen * 8);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
848*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
849*4882a593Smuzhiyun 	op.jobid = jobid;
850*4882a593Smuzhiyun 	op.sb_key = cmd_q->sb_key; /* Pre-allocated */
851*4882a593Smuzhiyun 	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
852*4882a593Smuzhiyun 	op.init = 1;
853*4882a593Smuzhiyun 	op.u.aes.type = aes->type;
854*4882a593Smuzhiyun 	op.u.aes.mode = CCP_AES_MODE_GHASH;
855*4882a593Smuzhiyun 	op.u.aes.action = CCP_AES_GHASHFINAL;
856*4882a593Smuzhiyun 	op.src.type = CCP_MEMTYPE_SYSTEM;
857*4882a593Smuzhiyun 	op.src.u.dma.address = final_wa.dma.address;
858*4882a593Smuzhiyun 	op.src.u.dma.length = AES_BLOCK_SIZE;
859*4882a593Smuzhiyun 	op.dst.type = CCP_MEMTYPE_SYSTEM;
860*4882a593Smuzhiyun 	op.dst.u.dma.address = final_wa.dma.address;
861*4882a593Smuzhiyun 	op.dst.u.dma.length = AES_BLOCK_SIZE;
862*4882a593Smuzhiyun 	op.eom = 1;
863*4882a593Smuzhiyun 	op.u.aes.size = 0;
864*4882a593Smuzhiyun 	ret = cmd_q->ccp->vdata->perform->aes(&op);
865*4882a593Smuzhiyun 	if (ret)
866*4882a593Smuzhiyun 		goto e_final_wa;
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	if (aes->action == CCP_AES_ACTION_ENCRYPT) {
869*4882a593Smuzhiyun 		/* Put the ciphered tag after the ciphertext. */
870*4882a593Smuzhiyun 		ccp_get_dm_area(&final_wa, 0, p_tag, 0, authsize);
871*4882a593Smuzhiyun 	} else {
872*4882a593Smuzhiyun 		/* Does this ciphered tag match the input? */
873*4882a593Smuzhiyun 		ret = ccp_init_dm_workarea(&tag, cmd_q, authsize,
874*4882a593Smuzhiyun 					   DMA_BIDIRECTIONAL);
875*4882a593Smuzhiyun 		if (ret)
876*4882a593Smuzhiyun 			goto e_final_wa;
877*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&tag, 0, p_tag, 0, authsize);
878*4882a593Smuzhiyun 		if (ret) {
879*4882a593Smuzhiyun 			ccp_dm_free(&tag);
880*4882a593Smuzhiyun 			goto e_final_wa;
881*4882a593Smuzhiyun 		}
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 		ret = crypto_memneq(tag.address, final_wa.address,
884*4882a593Smuzhiyun 				    authsize) ? -EBADMSG : 0;
885*4882a593Smuzhiyun 		ccp_dm_free(&tag);
886*4882a593Smuzhiyun 	}
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun e_final_wa:
889*4882a593Smuzhiyun 	ccp_dm_free(&final_wa);
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun e_dst:
892*4882a593Smuzhiyun 	if (ilen > 0 && !in_place)
893*4882a593Smuzhiyun 		ccp_free_data(&dst, cmd_q);
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun e_src:
896*4882a593Smuzhiyun 	if (ilen > 0)
897*4882a593Smuzhiyun 		ccp_free_data(&src, cmd_q);
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun e_aad:
900*4882a593Smuzhiyun 	if (aes->aad_len)
901*4882a593Smuzhiyun 		ccp_free_data(&aad, cmd_q);
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun e_ctx:
904*4882a593Smuzhiyun 	ccp_dm_free(&ctx);
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun e_key:
907*4882a593Smuzhiyun 	ccp_dm_free(&key);
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	return ret;
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_aes_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)913*4882a593Smuzhiyun ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
914*4882a593Smuzhiyun {
915*4882a593Smuzhiyun 	struct ccp_aes_engine *aes = &cmd->u.aes;
916*4882a593Smuzhiyun 	struct ccp_dm_workarea key, ctx;
917*4882a593Smuzhiyun 	struct ccp_data src, dst;
918*4882a593Smuzhiyun 	struct ccp_op op;
919*4882a593Smuzhiyun 	unsigned int dm_offset;
920*4882a593Smuzhiyun 	bool in_place = false;
921*4882a593Smuzhiyun 	int ret;
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	if (!((aes->key_len == AES_KEYSIZE_128) ||
924*4882a593Smuzhiyun 	      (aes->key_len == AES_KEYSIZE_192) ||
925*4882a593Smuzhiyun 	      (aes->key_len == AES_KEYSIZE_256)))
926*4882a593Smuzhiyun 		return -EINVAL;
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	if (((aes->mode == CCP_AES_MODE_ECB) ||
929*4882a593Smuzhiyun 	     (aes->mode == CCP_AES_MODE_CBC)) &&
930*4882a593Smuzhiyun 	    (aes->src_len & (AES_BLOCK_SIZE - 1)))
931*4882a593Smuzhiyun 		return -EINVAL;
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	if (!aes->key || !aes->src || !aes->dst)
934*4882a593Smuzhiyun 		return -EINVAL;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	if (aes->mode != CCP_AES_MODE_ECB) {
937*4882a593Smuzhiyun 		if (aes->iv_len != AES_BLOCK_SIZE)
938*4882a593Smuzhiyun 			return -EINVAL;
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 		if (!aes->iv)
941*4882a593Smuzhiyun 			return -EINVAL;
942*4882a593Smuzhiyun 	}
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	BUILD_BUG_ON(CCP_AES_KEY_SB_COUNT != 1);
945*4882a593Smuzhiyun 	BUILD_BUG_ON(CCP_AES_CTX_SB_COUNT != 1);
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	ret = -EIO;
948*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
949*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
950*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
951*4882a593Smuzhiyun 	op.sb_key = cmd_q->sb_key;
952*4882a593Smuzhiyun 	op.sb_ctx = cmd_q->sb_ctx;
953*4882a593Smuzhiyun 	op.init = (aes->mode == CCP_AES_MODE_ECB) ? 0 : 1;
954*4882a593Smuzhiyun 	op.u.aes.type = aes->type;
955*4882a593Smuzhiyun 	op.u.aes.mode = aes->mode;
956*4882a593Smuzhiyun 	op.u.aes.action = aes->action;
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	/* All supported key sizes fit in a single (32-byte) SB entry
959*4882a593Smuzhiyun 	 * and must be in little endian format. Use the 256-bit byte
960*4882a593Smuzhiyun 	 * swap passthru option to convert from big endian to little
961*4882a593Smuzhiyun 	 * endian.
962*4882a593Smuzhiyun 	 */
963*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&key, cmd_q,
964*4882a593Smuzhiyun 				   CCP_AES_KEY_SB_COUNT * CCP_SB_BYTES,
965*4882a593Smuzhiyun 				   DMA_TO_DEVICE);
966*4882a593Smuzhiyun 	if (ret)
967*4882a593Smuzhiyun 		return ret;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	dm_offset = CCP_SB_BYTES - aes->key_len;
970*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
971*4882a593Smuzhiyun 	if (ret)
972*4882a593Smuzhiyun 		goto e_key;
973*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
974*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
975*4882a593Smuzhiyun 	if (ret) {
976*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
977*4882a593Smuzhiyun 		goto e_key;
978*4882a593Smuzhiyun 	}
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	/* The AES context fits in a single (32-byte) SB entry and
981*4882a593Smuzhiyun 	 * must be in little endian format. Use the 256-bit byte swap
982*4882a593Smuzhiyun 	 * passthru option to convert from big endian to little endian.
983*4882a593Smuzhiyun 	 */
984*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&ctx, cmd_q,
985*4882a593Smuzhiyun 				   CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES,
986*4882a593Smuzhiyun 				   DMA_BIDIRECTIONAL);
987*4882a593Smuzhiyun 	if (ret)
988*4882a593Smuzhiyun 		goto e_key;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	if (aes->mode != CCP_AES_MODE_ECB) {
991*4882a593Smuzhiyun 		/* Load the AES context - convert to LE */
992*4882a593Smuzhiyun 		dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
993*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
994*4882a593Smuzhiyun 		if (ret)
995*4882a593Smuzhiyun 			goto e_ctx;
996*4882a593Smuzhiyun 		ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
997*4882a593Smuzhiyun 				     CCP_PASSTHRU_BYTESWAP_256BIT);
998*4882a593Smuzhiyun 		if (ret) {
999*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1000*4882a593Smuzhiyun 			goto e_ctx;
1001*4882a593Smuzhiyun 		}
1002*4882a593Smuzhiyun 	}
1003*4882a593Smuzhiyun 	switch (aes->mode) {
1004*4882a593Smuzhiyun 	case CCP_AES_MODE_CFB: /* CFB128 only */
1005*4882a593Smuzhiyun 	case CCP_AES_MODE_CTR:
1006*4882a593Smuzhiyun 		op.u.aes.size = AES_BLOCK_SIZE * BITS_PER_BYTE - 1;
1007*4882a593Smuzhiyun 		break;
1008*4882a593Smuzhiyun 	default:
1009*4882a593Smuzhiyun 		op.u.aes.size = 0;
1010*4882a593Smuzhiyun 	}
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	/* Prepare the input and output data workareas. For in-place
1013*4882a593Smuzhiyun 	 * operations we need to set the dma direction to BIDIRECTIONAL
1014*4882a593Smuzhiyun 	 * and copy the src workarea to the dst workarea.
1015*4882a593Smuzhiyun 	 */
1016*4882a593Smuzhiyun 	if (sg_virt(aes->src) == sg_virt(aes->dst))
1017*4882a593Smuzhiyun 		in_place = true;
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 	ret = ccp_init_data(&src, cmd_q, aes->src, aes->src_len,
1020*4882a593Smuzhiyun 			    AES_BLOCK_SIZE,
1021*4882a593Smuzhiyun 			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
1022*4882a593Smuzhiyun 	if (ret)
1023*4882a593Smuzhiyun 		goto e_ctx;
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 	if (in_place) {
1026*4882a593Smuzhiyun 		dst = src;
1027*4882a593Smuzhiyun 	} else {
1028*4882a593Smuzhiyun 		ret = ccp_init_data(&dst, cmd_q, aes->dst, aes->src_len,
1029*4882a593Smuzhiyun 				    AES_BLOCK_SIZE, DMA_FROM_DEVICE);
1030*4882a593Smuzhiyun 		if (ret)
1031*4882a593Smuzhiyun 			goto e_src;
1032*4882a593Smuzhiyun 	}
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	/* Send data to the CCP AES engine */
1035*4882a593Smuzhiyun 	while (src.sg_wa.bytes_left) {
1036*4882a593Smuzhiyun 		ccp_prepare_data(&src, &dst, &op, AES_BLOCK_SIZE, true);
1037*4882a593Smuzhiyun 		if (!src.sg_wa.bytes_left) {
1038*4882a593Smuzhiyun 			op.eom = 1;
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 			/* Since we don't retrieve the AES context in ECB
1041*4882a593Smuzhiyun 			 * mode we have to wait for the operation to complete
1042*4882a593Smuzhiyun 			 * on the last piece of data
1043*4882a593Smuzhiyun 			 */
1044*4882a593Smuzhiyun 			if (aes->mode == CCP_AES_MODE_ECB)
1045*4882a593Smuzhiyun 				op.soc = 1;
1046*4882a593Smuzhiyun 		}
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 		ret = cmd_q->ccp->vdata->perform->aes(&op);
1049*4882a593Smuzhiyun 		if (ret) {
1050*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1051*4882a593Smuzhiyun 			goto e_dst;
1052*4882a593Smuzhiyun 		}
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 		ccp_process_data(&src, &dst, &op);
1055*4882a593Smuzhiyun 	}
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 	if (aes->mode != CCP_AES_MODE_ECB) {
1058*4882a593Smuzhiyun 		/* Retrieve the AES context - convert from LE to BE using
1059*4882a593Smuzhiyun 		 * 32-byte (256-bit) byteswapping
1060*4882a593Smuzhiyun 		 */
1061*4882a593Smuzhiyun 		ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
1062*4882a593Smuzhiyun 				       CCP_PASSTHRU_BYTESWAP_256BIT);
1063*4882a593Smuzhiyun 		if (ret) {
1064*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1065*4882a593Smuzhiyun 			goto e_dst;
1066*4882a593Smuzhiyun 		}
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 		/* ...but we only need AES_BLOCK_SIZE bytes */
1069*4882a593Smuzhiyun 		dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
1070*4882a593Smuzhiyun 		ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
1071*4882a593Smuzhiyun 	}
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun e_dst:
1074*4882a593Smuzhiyun 	if (!in_place)
1075*4882a593Smuzhiyun 		ccp_free_data(&dst, cmd_q);
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun e_src:
1078*4882a593Smuzhiyun 	ccp_free_data(&src, cmd_q);
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun e_ctx:
1081*4882a593Smuzhiyun 	ccp_dm_free(&ctx);
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun e_key:
1084*4882a593Smuzhiyun 	ccp_dm_free(&key);
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	return ret;
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_xts_aes_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)1090*4882a593Smuzhiyun ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
1091*4882a593Smuzhiyun {
1092*4882a593Smuzhiyun 	struct ccp_xts_aes_engine *xts = &cmd->u.xts;
1093*4882a593Smuzhiyun 	struct ccp_dm_workarea key, ctx;
1094*4882a593Smuzhiyun 	struct ccp_data src, dst;
1095*4882a593Smuzhiyun 	struct ccp_op op;
1096*4882a593Smuzhiyun 	unsigned int unit_size, dm_offset;
1097*4882a593Smuzhiyun 	bool in_place = false;
1098*4882a593Smuzhiyun 	unsigned int sb_count;
1099*4882a593Smuzhiyun 	enum ccp_aes_type aestype;
1100*4882a593Smuzhiyun 	int ret;
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	switch (xts->unit_size) {
1103*4882a593Smuzhiyun 	case CCP_XTS_AES_UNIT_SIZE_16:
1104*4882a593Smuzhiyun 		unit_size = 16;
1105*4882a593Smuzhiyun 		break;
1106*4882a593Smuzhiyun 	case CCP_XTS_AES_UNIT_SIZE_512:
1107*4882a593Smuzhiyun 		unit_size = 512;
1108*4882a593Smuzhiyun 		break;
1109*4882a593Smuzhiyun 	case CCP_XTS_AES_UNIT_SIZE_1024:
1110*4882a593Smuzhiyun 		unit_size = 1024;
1111*4882a593Smuzhiyun 		break;
1112*4882a593Smuzhiyun 	case CCP_XTS_AES_UNIT_SIZE_2048:
1113*4882a593Smuzhiyun 		unit_size = 2048;
1114*4882a593Smuzhiyun 		break;
1115*4882a593Smuzhiyun 	case CCP_XTS_AES_UNIT_SIZE_4096:
1116*4882a593Smuzhiyun 		unit_size = 4096;
1117*4882a593Smuzhiyun 		break;
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 	default:
1120*4882a593Smuzhiyun 		return -EINVAL;
1121*4882a593Smuzhiyun 	}
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	if (xts->key_len == AES_KEYSIZE_128)
1124*4882a593Smuzhiyun 		aestype = CCP_AES_TYPE_128;
1125*4882a593Smuzhiyun 	else if (xts->key_len == AES_KEYSIZE_256)
1126*4882a593Smuzhiyun 		aestype = CCP_AES_TYPE_256;
1127*4882a593Smuzhiyun 	else
1128*4882a593Smuzhiyun 		return -EINVAL;
1129*4882a593Smuzhiyun 
1130*4882a593Smuzhiyun 	if (!xts->final && (xts->src_len & (AES_BLOCK_SIZE - 1)))
1131*4882a593Smuzhiyun 		return -EINVAL;
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 	if (xts->iv_len != AES_BLOCK_SIZE)
1134*4882a593Smuzhiyun 		return -EINVAL;
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 	if (!xts->key || !xts->iv || !xts->src || !xts->dst)
1137*4882a593Smuzhiyun 		return -EINVAL;
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	BUILD_BUG_ON(CCP_XTS_AES_KEY_SB_COUNT != 1);
1140*4882a593Smuzhiyun 	BUILD_BUG_ON(CCP_XTS_AES_CTX_SB_COUNT != 1);
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	ret = -EIO;
1143*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
1144*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
1145*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
1146*4882a593Smuzhiyun 	op.sb_key = cmd_q->sb_key;
1147*4882a593Smuzhiyun 	op.sb_ctx = cmd_q->sb_ctx;
1148*4882a593Smuzhiyun 	op.init = 1;
1149*4882a593Smuzhiyun 	op.u.xts.type = aestype;
1150*4882a593Smuzhiyun 	op.u.xts.action = xts->action;
1151*4882a593Smuzhiyun 	op.u.xts.unit_size = xts->unit_size;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	/* A version 3 device only supports 128-bit keys, which fits into a
1154*4882a593Smuzhiyun 	 * single SB entry. A version 5 device uses a 512-bit vector, so two
1155*4882a593Smuzhiyun 	 * SB entries.
1156*4882a593Smuzhiyun 	 */
1157*4882a593Smuzhiyun 	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
1158*4882a593Smuzhiyun 		sb_count = CCP_XTS_AES_KEY_SB_COUNT;
1159*4882a593Smuzhiyun 	else
1160*4882a593Smuzhiyun 		sb_count = CCP5_XTS_AES_KEY_SB_COUNT;
1161*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&key, cmd_q,
1162*4882a593Smuzhiyun 				   sb_count * CCP_SB_BYTES,
1163*4882a593Smuzhiyun 				   DMA_TO_DEVICE);
1164*4882a593Smuzhiyun 	if (ret)
1165*4882a593Smuzhiyun 		return ret;
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) {
1168*4882a593Smuzhiyun 		/* All supported key sizes must be in little endian format.
1169*4882a593Smuzhiyun 		 * Use the 256-bit byte swap passthru option to convert from
1170*4882a593Smuzhiyun 		 * big endian to little endian.
1171*4882a593Smuzhiyun 		 */
1172*4882a593Smuzhiyun 		dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
1173*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
1174*4882a593Smuzhiyun 		if (ret)
1175*4882a593Smuzhiyun 			goto e_key;
1176*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
1177*4882a593Smuzhiyun 		if (ret)
1178*4882a593Smuzhiyun 			goto e_key;
1179*4882a593Smuzhiyun 	} else {
1180*4882a593Smuzhiyun 		/* Version 5 CCPs use a 512-bit space for the key: each portion
1181*4882a593Smuzhiyun 		 * occupies 256 bits, or one entire slot, and is zero-padded.
1182*4882a593Smuzhiyun 		 */
1183*4882a593Smuzhiyun 		unsigned int pad;
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 		dm_offset = CCP_SB_BYTES;
1186*4882a593Smuzhiyun 		pad = dm_offset - xts->key_len;
1187*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
1188*4882a593Smuzhiyun 		if (ret)
1189*4882a593Smuzhiyun 			goto e_key;
1190*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&key, dm_offset + pad, xts->key,
1191*4882a593Smuzhiyun 				      xts->key_len, xts->key_len);
1192*4882a593Smuzhiyun 		if (ret)
1193*4882a593Smuzhiyun 			goto e_key;
1194*4882a593Smuzhiyun 	}
1195*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
1196*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
1197*4882a593Smuzhiyun 	if (ret) {
1198*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
1199*4882a593Smuzhiyun 		goto e_key;
1200*4882a593Smuzhiyun 	}
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	/* The AES context fits in a single (32-byte) SB entry and
1203*4882a593Smuzhiyun 	 * for XTS is already in little endian format so no byte swapping
1204*4882a593Smuzhiyun 	 * is needed.
1205*4882a593Smuzhiyun 	 */
1206*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&ctx, cmd_q,
1207*4882a593Smuzhiyun 				   CCP_XTS_AES_CTX_SB_COUNT * CCP_SB_BYTES,
1208*4882a593Smuzhiyun 				   DMA_BIDIRECTIONAL);
1209*4882a593Smuzhiyun 	if (ret)
1210*4882a593Smuzhiyun 		goto e_key;
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
1213*4882a593Smuzhiyun 	if (ret)
1214*4882a593Smuzhiyun 		goto e_ctx;
1215*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
1216*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_NOOP);
1217*4882a593Smuzhiyun 	if (ret) {
1218*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
1219*4882a593Smuzhiyun 		goto e_ctx;
1220*4882a593Smuzhiyun 	}
1221*4882a593Smuzhiyun 
1222*4882a593Smuzhiyun 	/* Prepare the input and output data workareas. For in-place
1223*4882a593Smuzhiyun 	 * operations we need to set the dma direction to BIDIRECTIONAL
1224*4882a593Smuzhiyun 	 * and copy the src workarea to the dst workarea.
1225*4882a593Smuzhiyun 	 */
1226*4882a593Smuzhiyun 	if (sg_virt(xts->src) == sg_virt(xts->dst))
1227*4882a593Smuzhiyun 		in_place = true;
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun 	ret = ccp_init_data(&src, cmd_q, xts->src, xts->src_len,
1230*4882a593Smuzhiyun 			    unit_size,
1231*4882a593Smuzhiyun 			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
1232*4882a593Smuzhiyun 	if (ret)
1233*4882a593Smuzhiyun 		goto e_ctx;
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 	if (in_place) {
1236*4882a593Smuzhiyun 		dst = src;
1237*4882a593Smuzhiyun 	} else {
1238*4882a593Smuzhiyun 		ret = ccp_init_data(&dst, cmd_q, xts->dst, xts->src_len,
1239*4882a593Smuzhiyun 				    unit_size, DMA_FROM_DEVICE);
1240*4882a593Smuzhiyun 		if (ret)
1241*4882a593Smuzhiyun 			goto e_src;
1242*4882a593Smuzhiyun 	}
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	/* Send data to the CCP AES engine */
1245*4882a593Smuzhiyun 	while (src.sg_wa.bytes_left) {
1246*4882a593Smuzhiyun 		ccp_prepare_data(&src, &dst, &op, unit_size, true);
1247*4882a593Smuzhiyun 		if (!src.sg_wa.bytes_left)
1248*4882a593Smuzhiyun 			op.eom = 1;
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 		ret = cmd_q->ccp->vdata->perform->xts_aes(&op);
1251*4882a593Smuzhiyun 		if (ret) {
1252*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1253*4882a593Smuzhiyun 			goto e_dst;
1254*4882a593Smuzhiyun 		}
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 		ccp_process_data(&src, &dst, &op);
1257*4882a593Smuzhiyun 	}
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 	/* Retrieve the AES context - convert from LE to BE using
1260*4882a593Smuzhiyun 	 * 32-byte (256-bit) byteswapping
1261*4882a593Smuzhiyun 	 */
1262*4882a593Smuzhiyun 	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
1263*4882a593Smuzhiyun 			       CCP_PASSTHRU_BYTESWAP_256BIT);
1264*4882a593Smuzhiyun 	if (ret) {
1265*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
1266*4882a593Smuzhiyun 		goto e_dst;
1267*4882a593Smuzhiyun 	}
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 	/* ...but we only need AES_BLOCK_SIZE bytes */
1270*4882a593Smuzhiyun 	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
1271*4882a593Smuzhiyun 	ccp_get_dm_area(&ctx, dm_offset, xts->iv, 0, xts->iv_len);
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun e_dst:
1274*4882a593Smuzhiyun 	if (!in_place)
1275*4882a593Smuzhiyun 		ccp_free_data(&dst, cmd_q);
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun e_src:
1278*4882a593Smuzhiyun 	ccp_free_data(&src, cmd_q);
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun e_ctx:
1281*4882a593Smuzhiyun 	ccp_dm_free(&ctx);
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun e_key:
1284*4882a593Smuzhiyun 	ccp_dm_free(&key);
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	return ret;
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_des3_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)1290*4882a593Smuzhiyun ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
1291*4882a593Smuzhiyun {
1292*4882a593Smuzhiyun 	struct ccp_des3_engine *des3 = &cmd->u.des3;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	struct ccp_dm_workarea key, ctx;
1295*4882a593Smuzhiyun 	struct ccp_data src, dst;
1296*4882a593Smuzhiyun 	struct ccp_op op;
1297*4882a593Smuzhiyun 	unsigned int dm_offset;
1298*4882a593Smuzhiyun 	unsigned int len_singlekey;
1299*4882a593Smuzhiyun 	bool in_place = false;
1300*4882a593Smuzhiyun 	int ret;
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 	/* Error checks */
1303*4882a593Smuzhiyun 	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0))
1304*4882a593Smuzhiyun 		return -EINVAL;
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	if (!cmd_q->ccp->vdata->perform->des3)
1307*4882a593Smuzhiyun 		return -EINVAL;
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	if (des3->key_len != DES3_EDE_KEY_SIZE)
1310*4882a593Smuzhiyun 		return -EINVAL;
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun 	if (((des3->mode == CCP_DES3_MODE_ECB) ||
1313*4882a593Smuzhiyun 		(des3->mode == CCP_DES3_MODE_CBC)) &&
1314*4882a593Smuzhiyun 		(des3->src_len & (DES3_EDE_BLOCK_SIZE - 1)))
1315*4882a593Smuzhiyun 		return -EINVAL;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	if (!des3->key || !des3->src || !des3->dst)
1318*4882a593Smuzhiyun 		return -EINVAL;
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	if (des3->mode != CCP_DES3_MODE_ECB) {
1321*4882a593Smuzhiyun 		if (des3->iv_len != DES3_EDE_BLOCK_SIZE)
1322*4882a593Smuzhiyun 			return -EINVAL;
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 		if (!des3->iv)
1325*4882a593Smuzhiyun 			return -EINVAL;
1326*4882a593Smuzhiyun 	}
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 	/* Zero out all the fields of the command desc */
1329*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 	/* Set up the Function field */
1332*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
1333*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
1334*4882a593Smuzhiyun 	op.sb_key = cmd_q->sb_key;
1335*4882a593Smuzhiyun 
1336*4882a593Smuzhiyun 	op.init = (des3->mode == CCP_DES3_MODE_ECB) ? 0 : 1;
1337*4882a593Smuzhiyun 	op.u.des3.type = des3->type;
1338*4882a593Smuzhiyun 	op.u.des3.mode = des3->mode;
1339*4882a593Smuzhiyun 	op.u.des3.action = des3->action;
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun 	/*
1342*4882a593Smuzhiyun 	 * All supported key sizes fit in a single (32-byte) KSB entry and
1343*4882a593Smuzhiyun 	 * (like AES) must be in little endian format. Use the 256-bit byte
1344*4882a593Smuzhiyun 	 * swap passthru option to convert from big endian to little endian.
1345*4882a593Smuzhiyun 	 */
1346*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&key, cmd_q,
1347*4882a593Smuzhiyun 				   CCP_DES3_KEY_SB_COUNT * CCP_SB_BYTES,
1348*4882a593Smuzhiyun 				   DMA_TO_DEVICE);
1349*4882a593Smuzhiyun 	if (ret)
1350*4882a593Smuzhiyun 		return ret;
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	/*
1353*4882a593Smuzhiyun 	 * The contents of the key triplet are in the reverse order of what
1354*4882a593Smuzhiyun 	 * is required by the engine. Copy the 3 pieces individually to put
1355*4882a593Smuzhiyun 	 * them where they belong.
1356*4882a593Smuzhiyun 	 */
1357*4882a593Smuzhiyun 	dm_offset = CCP_SB_BYTES - des3->key_len; /* Basic offset */
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	len_singlekey = des3->key_len / 3;
1360*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey,
1361*4882a593Smuzhiyun 			      des3->key, 0, len_singlekey);
1362*4882a593Smuzhiyun 	if (ret)
1363*4882a593Smuzhiyun 		goto e_key;
1364*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&key, dm_offset + len_singlekey,
1365*4882a593Smuzhiyun 			      des3->key, len_singlekey, len_singlekey);
1366*4882a593Smuzhiyun 	if (ret)
1367*4882a593Smuzhiyun 		goto e_key;
1368*4882a593Smuzhiyun 	ret = ccp_set_dm_area(&key, dm_offset,
1369*4882a593Smuzhiyun 			      des3->key, 2 * len_singlekey, len_singlekey);
1370*4882a593Smuzhiyun 	if (ret)
1371*4882a593Smuzhiyun 		goto e_key;
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	/* Copy the key to the SB */
1374*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
1375*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
1376*4882a593Smuzhiyun 	if (ret) {
1377*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
1378*4882a593Smuzhiyun 		goto e_key;
1379*4882a593Smuzhiyun 	}
1380*4882a593Smuzhiyun 
1381*4882a593Smuzhiyun 	/*
1382*4882a593Smuzhiyun 	 * The DES3 context fits in a single (32-byte) KSB entry and
1383*4882a593Smuzhiyun 	 * must be in little endian format. Use the 256-bit byte swap
1384*4882a593Smuzhiyun 	 * passthru option to convert from big endian to little endian.
1385*4882a593Smuzhiyun 	 */
1386*4882a593Smuzhiyun 	if (des3->mode != CCP_DES3_MODE_ECB) {
1387*4882a593Smuzhiyun 		op.sb_ctx = cmd_q->sb_ctx;
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 		ret = ccp_init_dm_workarea(&ctx, cmd_q,
1390*4882a593Smuzhiyun 					   CCP_DES3_CTX_SB_COUNT * CCP_SB_BYTES,
1391*4882a593Smuzhiyun 					   DMA_BIDIRECTIONAL);
1392*4882a593Smuzhiyun 		if (ret)
1393*4882a593Smuzhiyun 			goto e_key;
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 		/* Load the context into the LSB */
1396*4882a593Smuzhiyun 		dm_offset = CCP_SB_BYTES - des3->iv_len;
1397*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0,
1398*4882a593Smuzhiyun 				      des3->iv_len);
1399*4882a593Smuzhiyun 		if (ret)
1400*4882a593Smuzhiyun 			goto e_ctx;
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 		ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
1403*4882a593Smuzhiyun 				     CCP_PASSTHRU_BYTESWAP_256BIT);
1404*4882a593Smuzhiyun 		if (ret) {
1405*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1406*4882a593Smuzhiyun 			goto e_ctx;
1407*4882a593Smuzhiyun 		}
1408*4882a593Smuzhiyun 	}
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 	/*
1411*4882a593Smuzhiyun 	 * Prepare the input and output data workareas. For in-place
1412*4882a593Smuzhiyun 	 * operations we need to set the dma direction to BIDIRECTIONAL
1413*4882a593Smuzhiyun 	 * and copy the src workarea to the dst workarea.
1414*4882a593Smuzhiyun 	 */
1415*4882a593Smuzhiyun 	if (sg_virt(des3->src) == sg_virt(des3->dst))
1416*4882a593Smuzhiyun 		in_place = true;
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun 	ret = ccp_init_data(&src, cmd_q, des3->src, des3->src_len,
1419*4882a593Smuzhiyun 			DES3_EDE_BLOCK_SIZE,
1420*4882a593Smuzhiyun 			in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
1421*4882a593Smuzhiyun 	if (ret)
1422*4882a593Smuzhiyun 		goto e_ctx;
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 	if (in_place)
1425*4882a593Smuzhiyun 		dst = src;
1426*4882a593Smuzhiyun 	else {
1427*4882a593Smuzhiyun 		ret = ccp_init_data(&dst, cmd_q, des3->dst, des3->src_len,
1428*4882a593Smuzhiyun 				DES3_EDE_BLOCK_SIZE, DMA_FROM_DEVICE);
1429*4882a593Smuzhiyun 		if (ret)
1430*4882a593Smuzhiyun 			goto e_src;
1431*4882a593Smuzhiyun 	}
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 	/* Send data to the CCP DES3 engine */
1434*4882a593Smuzhiyun 	while (src.sg_wa.bytes_left) {
1435*4882a593Smuzhiyun 		ccp_prepare_data(&src, &dst, &op, DES3_EDE_BLOCK_SIZE, true);
1436*4882a593Smuzhiyun 		if (!src.sg_wa.bytes_left) {
1437*4882a593Smuzhiyun 			op.eom = 1;
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 			/* Since we don't retrieve the context in ECB mode
1440*4882a593Smuzhiyun 			 * we have to wait for the operation to complete
1441*4882a593Smuzhiyun 			 * on the last piece of data
1442*4882a593Smuzhiyun 			 */
1443*4882a593Smuzhiyun 			op.soc = 0;
1444*4882a593Smuzhiyun 		}
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 		ret = cmd_q->ccp->vdata->perform->des3(&op);
1447*4882a593Smuzhiyun 		if (ret) {
1448*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1449*4882a593Smuzhiyun 			goto e_dst;
1450*4882a593Smuzhiyun 		}
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun 		ccp_process_data(&src, &dst, &op);
1453*4882a593Smuzhiyun 	}
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	if (des3->mode != CCP_DES3_MODE_ECB) {
1456*4882a593Smuzhiyun 		/* Retrieve the context and make BE */
1457*4882a593Smuzhiyun 		ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
1458*4882a593Smuzhiyun 				       CCP_PASSTHRU_BYTESWAP_256BIT);
1459*4882a593Smuzhiyun 		if (ret) {
1460*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1461*4882a593Smuzhiyun 			goto e_dst;
1462*4882a593Smuzhiyun 		}
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 		/* ...but we only need the last DES3_EDE_BLOCK_SIZE bytes */
1465*4882a593Smuzhiyun 		ccp_get_dm_area(&ctx, dm_offset, des3->iv, 0,
1466*4882a593Smuzhiyun 				DES3_EDE_BLOCK_SIZE);
1467*4882a593Smuzhiyun 	}
1468*4882a593Smuzhiyun e_dst:
1469*4882a593Smuzhiyun 	if (!in_place)
1470*4882a593Smuzhiyun 		ccp_free_data(&dst, cmd_q);
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun e_src:
1473*4882a593Smuzhiyun 	ccp_free_data(&src, cmd_q);
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun e_ctx:
1476*4882a593Smuzhiyun 	if (des3->mode != CCP_DES3_MODE_ECB)
1477*4882a593Smuzhiyun 		ccp_dm_free(&ctx);
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun e_key:
1480*4882a593Smuzhiyun 	ccp_dm_free(&key);
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun 	return ret;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_sha_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)1486*4882a593Smuzhiyun ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
1487*4882a593Smuzhiyun {
1488*4882a593Smuzhiyun 	struct ccp_sha_engine *sha = &cmd->u.sha;
1489*4882a593Smuzhiyun 	struct ccp_dm_workarea ctx;
1490*4882a593Smuzhiyun 	struct ccp_data src;
1491*4882a593Smuzhiyun 	struct ccp_op op;
1492*4882a593Smuzhiyun 	unsigned int ioffset, ooffset;
1493*4882a593Smuzhiyun 	unsigned int digest_size;
1494*4882a593Smuzhiyun 	int sb_count;
1495*4882a593Smuzhiyun 	const void *init;
1496*4882a593Smuzhiyun 	u64 block_size;
1497*4882a593Smuzhiyun 	int ctx_size;
1498*4882a593Smuzhiyun 	int ret;
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun 	switch (sha->type) {
1501*4882a593Smuzhiyun 	case CCP_SHA_TYPE_1:
1502*4882a593Smuzhiyun 		if (sha->ctx_len < SHA1_DIGEST_SIZE)
1503*4882a593Smuzhiyun 			return -EINVAL;
1504*4882a593Smuzhiyun 		block_size = SHA1_BLOCK_SIZE;
1505*4882a593Smuzhiyun 		break;
1506*4882a593Smuzhiyun 	case CCP_SHA_TYPE_224:
1507*4882a593Smuzhiyun 		if (sha->ctx_len < SHA224_DIGEST_SIZE)
1508*4882a593Smuzhiyun 			return -EINVAL;
1509*4882a593Smuzhiyun 		block_size = SHA224_BLOCK_SIZE;
1510*4882a593Smuzhiyun 		break;
1511*4882a593Smuzhiyun 	case CCP_SHA_TYPE_256:
1512*4882a593Smuzhiyun 		if (sha->ctx_len < SHA256_DIGEST_SIZE)
1513*4882a593Smuzhiyun 			return -EINVAL;
1514*4882a593Smuzhiyun 		block_size = SHA256_BLOCK_SIZE;
1515*4882a593Smuzhiyun 		break;
1516*4882a593Smuzhiyun 	case CCP_SHA_TYPE_384:
1517*4882a593Smuzhiyun 		if (cmd_q->ccp->vdata->version < CCP_VERSION(4, 0)
1518*4882a593Smuzhiyun 		    || sha->ctx_len < SHA384_DIGEST_SIZE)
1519*4882a593Smuzhiyun 			return -EINVAL;
1520*4882a593Smuzhiyun 		block_size = SHA384_BLOCK_SIZE;
1521*4882a593Smuzhiyun 		break;
1522*4882a593Smuzhiyun 	case CCP_SHA_TYPE_512:
1523*4882a593Smuzhiyun 		if (cmd_q->ccp->vdata->version < CCP_VERSION(4, 0)
1524*4882a593Smuzhiyun 		    || sha->ctx_len < SHA512_DIGEST_SIZE)
1525*4882a593Smuzhiyun 			return -EINVAL;
1526*4882a593Smuzhiyun 		block_size = SHA512_BLOCK_SIZE;
1527*4882a593Smuzhiyun 		break;
1528*4882a593Smuzhiyun 	default:
1529*4882a593Smuzhiyun 		return -EINVAL;
1530*4882a593Smuzhiyun 	}
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 	if (!sha->ctx)
1533*4882a593Smuzhiyun 		return -EINVAL;
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun 	if (!sha->final && (sha->src_len & (block_size - 1)))
1536*4882a593Smuzhiyun 		return -EINVAL;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	/* The version 3 device can't handle zero-length input */
1539*4882a593Smuzhiyun 	if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) {
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 		if (!sha->src_len) {
1542*4882a593Smuzhiyun 			unsigned int digest_len;
1543*4882a593Smuzhiyun 			const u8 *sha_zero;
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 			/* Not final, just return */
1546*4882a593Smuzhiyun 			if (!sha->final)
1547*4882a593Smuzhiyun 				return 0;
1548*4882a593Smuzhiyun 
1549*4882a593Smuzhiyun 			/* CCP can't do a zero length sha operation so the
1550*4882a593Smuzhiyun 			 * caller must buffer the data.
1551*4882a593Smuzhiyun 			 */
1552*4882a593Smuzhiyun 			if (sha->msg_bits)
1553*4882a593Smuzhiyun 				return -EINVAL;
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun 			/* The CCP cannot perform zero-length sha operations
1556*4882a593Smuzhiyun 			 * so the caller is required to buffer data for the
1557*4882a593Smuzhiyun 			 * final operation. However, a sha operation for a
1558*4882a593Smuzhiyun 			 * message with a total length of zero is valid so
1559*4882a593Smuzhiyun 			 * known values are required to supply the result.
1560*4882a593Smuzhiyun 			 */
1561*4882a593Smuzhiyun 			switch (sha->type) {
1562*4882a593Smuzhiyun 			case CCP_SHA_TYPE_1:
1563*4882a593Smuzhiyun 				sha_zero = sha1_zero_message_hash;
1564*4882a593Smuzhiyun 				digest_len = SHA1_DIGEST_SIZE;
1565*4882a593Smuzhiyun 				break;
1566*4882a593Smuzhiyun 			case CCP_SHA_TYPE_224:
1567*4882a593Smuzhiyun 				sha_zero = sha224_zero_message_hash;
1568*4882a593Smuzhiyun 				digest_len = SHA224_DIGEST_SIZE;
1569*4882a593Smuzhiyun 				break;
1570*4882a593Smuzhiyun 			case CCP_SHA_TYPE_256:
1571*4882a593Smuzhiyun 				sha_zero = sha256_zero_message_hash;
1572*4882a593Smuzhiyun 				digest_len = SHA256_DIGEST_SIZE;
1573*4882a593Smuzhiyun 				break;
1574*4882a593Smuzhiyun 			default:
1575*4882a593Smuzhiyun 				return -EINVAL;
1576*4882a593Smuzhiyun 			}
1577*4882a593Smuzhiyun 
1578*4882a593Smuzhiyun 			scatterwalk_map_and_copy((void *)sha_zero, sha->ctx, 0,
1579*4882a593Smuzhiyun 						 digest_len, 1);
1580*4882a593Smuzhiyun 
1581*4882a593Smuzhiyun 			return 0;
1582*4882a593Smuzhiyun 		}
1583*4882a593Smuzhiyun 	}
1584*4882a593Smuzhiyun 
1585*4882a593Smuzhiyun 	/* Set variables used throughout */
1586*4882a593Smuzhiyun 	switch (sha->type) {
1587*4882a593Smuzhiyun 	case CCP_SHA_TYPE_1:
1588*4882a593Smuzhiyun 		digest_size = SHA1_DIGEST_SIZE;
1589*4882a593Smuzhiyun 		init = (void *) ccp_sha1_init;
1590*4882a593Smuzhiyun 		ctx_size = SHA1_DIGEST_SIZE;
1591*4882a593Smuzhiyun 		sb_count = 1;
1592*4882a593Smuzhiyun 		if (cmd_q->ccp->vdata->version != CCP_VERSION(3, 0))
1593*4882a593Smuzhiyun 			ooffset = ioffset = CCP_SB_BYTES - SHA1_DIGEST_SIZE;
1594*4882a593Smuzhiyun 		else
1595*4882a593Smuzhiyun 			ooffset = ioffset = 0;
1596*4882a593Smuzhiyun 		break;
1597*4882a593Smuzhiyun 	case CCP_SHA_TYPE_224:
1598*4882a593Smuzhiyun 		digest_size = SHA224_DIGEST_SIZE;
1599*4882a593Smuzhiyun 		init = (void *) ccp_sha224_init;
1600*4882a593Smuzhiyun 		ctx_size = SHA256_DIGEST_SIZE;
1601*4882a593Smuzhiyun 		sb_count = 1;
1602*4882a593Smuzhiyun 		ioffset = 0;
1603*4882a593Smuzhiyun 		if (cmd_q->ccp->vdata->version != CCP_VERSION(3, 0))
1604*4882a593Smuzhiyun 			ooffset = CCP_SB_BYTES - SHA224_DIGEST_SIZE;
1605*4882a593Smuzhiyun 		else
1606*4882a593Smuzhiyun 			ooffset = 0;
1607*4882a593Smuzhiyun 		break;
1608*4882a593Smuzhiyun 	case CCP_SHA_TYPE_256:
1609*4882a593Smuzhiyun 		digest_size = SHA256_DIGEST_SIZE;
1610*4882a593Smuzhiyun 		init = (void *) ccp_sha256_init;
1611*4882a593Smuzhiyun 		ctx_size = SHA256_DIGEST_SIZE;
1612*4882a593Smuzhiyun 		sb_count = 1;
1613*4882a593Smuzhiyun 		ooffset = ioffset = 0;
1614*4882a593Smuzhiyun 		break;
1615*4882a593Smuzhiyun 	case CCP_SHA_TYPE_384:
1616*4882a593Smuzhiyun 		digest_size = SHA384_DIGEST_SIZE;
1617*4882a593Smuzhiyun 		init = (void *) ccp_sha384_init;
1618*4882a593Smuzhiyun 		ctx_size = SHA512_DIGEST_SIZE;
1619*4882a593Smuzhiyun 		sb_count = 2;
1620*4882a593Smuzhiyun 		ioffset = 0;
1621*4882a593Smuzhiyun 		ooffset = 2 * CCP_SB_BYTES - SHA384_DIGEST_SIZE;
1622*4882a593Smuzhiyun 		break;
1623*4882a593Smuzhiyun 	case CCP_SHA_TYPE_512:
1624*4882a593Smuzhiyun 		digest_size = SHA512_DIGEST_SIZE;
1625*4882a593Smuzhiyun 		init = (void *) ccp_sha512_init;
1626*4882a593Smuzhiyun 		ctx_size = SHA512_DIGEST_SIZE;
1627*4882a593Smuzhiyun 		sb_count = 2;
1628*4882a593Smuzhiyun 		ooffset = ioffset = 0;
1629*4882a593Smuzhiyun 		break;
1630*4882a593Smuzhiyun 	default:
1631*4882a593Smuzhiyun 		ret = -EINVAL;
1632*4882a593Smuzhiyun 		goto e_data;
1633*4882a593Smuzhiyun 	}
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	/* For zero-length plaintext the src pointer is ignored;
1636*4882a593Smuzhiyun 	 * otherwise both parts must be valid
1637*4882a593Smuzhiyun 	 */
1638*4882a593Smuzhiyun 	if (sha->src_len && !sha->src)
1639*4882a593Smuzhiyun 		return -EINVAL;
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
1642*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
1643*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
1644*4882a593Smuzhiyun 	op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
1645*4882a593Smuzhiyun 	op.u.sha.type = sha->type;
1646*4882a593Smuzhiyun 	op.u.sha.msg_bits = sha->msg_bits;
1647*4882a593Smuzhiyun 
1648*4882a593Smuzhiyun 	/* For SHA1/224/256 the context fits in a single (32-byte) SB entry;
1649*4882a593Smuzhiyun 	 * SHA384/512 require 2 adjacent SB slots, with the right half in the
1650*4882a593Smuzhiyun 	 * first slot, and the left half in the second. Each portion must then
1651*4882a593Smuzhiyun 	 * be in little endian format: use the 256-bit byte swap option.
1652*4882a593Smuzhiyun 	 */
1653*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&ctx, cmd_q, sb_count * CCP_SB_BYTES,
1654*4882a593Smuzhiyun 				   DMA_BIDIRECTIONAL);
1655*4882a593Smuzhiyun 	if (ret)
1656*4882a593Smuzhiyun 		return ret;
1657*4882a593Smuzhiyun 	if (sha->first) {
1658*4882a593Smuzhiyun 		switch (sha->type) {
1659*4882a593Smuzhiyun 		case CCP_SHA_TYPE_1:
1660*4882a593Smuzhiyun 		case CCP_SHA_TYPE_224:
1661*4882a593Smuzhiyun 		case CCP_SHA_TYPE_256:
1662*4882a593Smuzhiyun 			memcpy(ctx.address + ioffset, init, ctx_size);
1663*4882a593Smuzhiyun 			break;
1664*4882a593Smuzhiyun 		case CCP_SHA_TYPE_384:
1665*4882a593Smuzhiyun 		case CCP_SHA_TYPE_512:
1666*4882a593Smuzhiyun 			memcpy(ctx.address + ctx_size / 2, init,
1667*4882a593Smuzhiyun 			       ctx_size / 2);
1668*4882a593Smuzhiyun 			memcpy(ctx.address, init + ctx_size / 2,
1669*4882a593Smuzhiyun 			       ctx_size / 2);
1670*4882a593Smuzhiyun 			break;
1671*4882a593Smuzhiyun 		default:
1672*4882a593Smuzhiyun 			ret = -EINVAL;
1673*4882a593Smuzhiyun 			goto e_ctx;
1674*4882a593Smuzhiyun 		}
1675*4882a593Smuzhiyun 	} else {
1676*4882a593Smuzhiyun 		/* Restore the context */
1677*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
1678*4882a593Smuzhiyun 				      sb_count * CCP_SB_BYTES);
1679*4882a593Smuzhiyun 		if (ret)
1680*4882a593Smuzhiyun 			goto e_ctx;
1681*4882a593Smuzhiyun 	}
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun 	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
1684*4882a593Smuzhiyun 			     CCP_PASSTHRU_BYTESWAP_256BIT);
1685*4882a593Smuzhiyun 	if (ret) {
1686*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
1687*4882a593Smuzhiyun 		goto e_ctx;
1688*4882a593Smuzhiyun 	}
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 	if (sha->src) {
1691*4882a593Smuzhiyun 		/* Send data to the CCP SHA engine; block_size is set above */
1692*4882a593Smuzhiyun 		ret = ccp_init_data(&src, cmd_q, sha->src, sha->src_len,
1693*4882a593Smuzhiyun 				    block_size, DMA_TO_DEVICE);
1694*4882a593Smuzhiyun 		if (ret)
1695*4882a593Smuzhiyun 			goto e_ctx;
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 		while (src.sg_wa.bytes_left) {
1698*4882a593Smuzhiyun 			ccp_prepare_data(&src, NULL, &op, block_size, false);
1699*4882a593Smuzhiyun 			if (sha->final && !src.sg_wa.bytes_left)
1700*4882a593Smuzhiyun 				op.eom = 1;
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 			ret = cmd_q->ccp->vdata->perform->sha(&op);
1703*4882a593Smuzhiyun 			if (ret) {
1704*4882a593Smuzhiyun 				cmd->engine_error = cmd_q->cmd_error;
1705*4882a593Smuzhiyun 				goto e_data;
1706*4882a593Smuzhiyun 			}
1707*4882a593Smuzhiyun 
1708*4882a593Smuzhiyun 			ccp_process_data(&src, NULL, &op);
1709*4882a593Smuzhiyun 		}
1710*4882a593Smuzhiyun 	} else {
1711*4882a593Smuzhiyun 		op.eom = 1;
1712*4882a593Smuzhiyun 		ret = cmd_q->ccp->vdata->perform->sha(&op);
1713*4882a593Smuzhiyun 		if (ret) {
1714*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1715*4882a593Smuzhiyun 			goto e_data;
1716*4882a593Smuzhiyun 		}
1717*4882a593Smuzhiyun 	}
1718*4882a593Smuzhiyun 
1719*4882a593Smuzhiyun 	/* Retrieve the SHA context - convert from LE to BE using
1720*4882a593Smuzhiyun 	 * 32-byte (256-bit) byteswapping to BE
1721*4882a593Smuzhiyun 	 */
1722*4882a593Smuzhiyun 	ret = ccp_copy_from_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
1723*4882a593Smuzhiyun 			       CCP_PASSTHRU_BYTESWAP_256BIT);
1724*4882a593Smuzhiyun 	if (ret) {
1725*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
1726*4882a593Smuzhiyun 		goto e_data;
1727*4882a593Smuzhiyun 	}
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun 	if (sha->final) {
1730*4882a593Smuzhiyun 		/* Finishing up, so get the digest */
1731*4882a593Smuzhiyun 		switch (sha->type) {
1732*4882a593Smuzhiyun 		case CCP_SHA_TYPE_1:
1733*4882a593Smuzhiyun 		case CCP_SHA_TYPE_224:
1734*4882a593Smuzhiyun 		case CCP_SHA_TYPE_256:
1735*4882a593Smuzhiyun 			ccp_get_dm_area(&ctx, ooffset,
1736*4882a593Smuzhiyun 					sha->ctx, 0,
1737*4882a593Smuzhiyun 					digest_size);
1738*4882a593Smuzhiyun 			break;
1739*4882a593Smuzhiyun 		case CCP_SHA_TYPE_384:
1740*4882a593Smuzhiyun 		case CCP_SHA_TYPE_512:
1741*4882a593Smuzhiyun 			ccp_get_dm_area(&ctx, 0,
1742*4882a593Smuzhiyun 					sha->ctx, LSB_ITEM_SIZE - ooffset,
1743*4882a593Smuzhiyun 					LSB_ITEM_SIZE);
1744*4882a593Smuzhiyun 			ccp_get_dm_area(&ctx, LSB_ITEM_SIZE + ooffset,
1745*4882a593Smuzhiyun 					sha->ctx, 0,
1746*4882a593Smuzhiyun 					LSB_ITEM_SIZE - ooffset);
1747*4882a593Smuzhiyun 			break;
1748*4882a593Smuzhiyun 		default:
1749*4882a593Smuzhiyun 			ret = -EINVAL;
1750*4882a593Smuzhiyun 			goto e_data;
1751*4882a593Smuzhiyun 		}
1752*4882a593Smuzhiyun 	} else {
1753*4882a593Smuzhiyun 		/* Stash the context */
1754*4882a593Smuzhiyun 		ccp_get_dm_area(&ctx, 0, sha->ctx, 0,
1755*4882a593Smuzhiyun 				sb_count * CCP_SB_BYTES);
1756*4882a593Smuzhiyun 	}
1757*4882a593Smuzhiyun 
1758*4882a593Smuzhiyun 	if (sha->final && sha->opad) {
1759*4882a593Smuzhiyun 		/* HMAC operation, recursively perform final SHA */
1760*4882a593Smuzhiyun 		struct ccp_cmd hmac_cmd;
1761*4882a593Smuzhiyun 		struct scatterlist sg;
1762*4882a593Smuzhiyun 		u8 *hmac_buf;
1763*4882a593Smuzhiyun 
1764*4882a593Smuzhiyun 		if (sha->opad_len != block_size) {
1765*4882a593Smuzhiyun 			ret = -EINVAL;
1766*4882a593Smuzhiyun 			goto e_data;
1767*4882a593Smuzhiyun 		}
1768*4882a593Smuzhiyun 
1769*4882a593Smuzhiyun 		hmac_buf = kmalloc(block_size + digest_size, GFP_KERNEL);
1770*4882a593Smuzhiyun 		if (!hmac_buf) {
1771*4882a593Smuzhiyun 			ret = -ENOMEM;
1772*4882a593Smuzhiyun 			goto e_data;
1773*4882a593Smuzhiyun 		}
1774*4882a593Smuzhiyun 		sg_init_one(&sg, hmac_buf, block_size + digest_size);
1775*4882a593Smuzhiyun 
1776*4882a593Smuzhiyun 		scatterwalk_map_and_copy(hmac_buf, sha->opad, 0, block_size, 0);
1777*4882a593Smuzhiyun 		switch (sha->type) {
1778*4882a593Smuzhiyun 		case CCP_SHA_TYPE_1:
1779*4882a593Smuzhiyun 		case CCP_SHA_TYPE_224:
1780*4882a593Smuzhiyun 		case CCP_SHA_TYPE_256:
1781*4882a593Smuzhiyun 			memcpy(hmac_buf + block_size,
1782*4882a593Smuzhiyun 			       ctx.address + ooffset,
1783*4882a593Smuzhiyun 			       digest_size);
1784*4882a593Smuzhiyun 			break;
1785*4882a593Smuzhiyun 		case CCP_SHA_TYPE_384:
1786*4882a593Smuzhiyun 		case CCP_SHA_TYPE_512:
1787*4882a593Smuzhiyun 			memcpy(hmac_buf + block_size,
1788*4882a593Smuzhiyun 			       ctx.address + LSB_ITEM_SIZE + ooffset,
1789*4882a593Smuzhiyun 			       LSB_ITEM_SIZE);
1790*4882a593Smuzhiyun 			memcpy(hmac_buf + block_size +
1791*4882a593Smuzhiyun 			       (LSB_ITEM_SIZE - ooffset),
1792*4882a593Smuzhiyun 			       ctx.address,
1793*4882a593Smuzhiyun 			       LSB_ITEM_SIZE);
1794*4882a593Smuzhiyun 			break;
1795*4882a593Smuzhiyun 		default:
1796*4882a593Smuzhiyun 			kfree(hmac_buf);
1797*4882a593Smuzhiyun 			ret = -EINVAL;
1798*4882a593Smuzhiyun 			goto e_data;
1799*4882a593Smuzhiyun 		}
1800*4882a593Smuzhiyun 
1801*4882a593Smuzhiyun 		memset(&hmac_cmd, 0, sizeof(hmac_cmd));
1802*4882a593Smuzhiyun 		hmac_cmd.engine = CCP_ENGINE_SHA;
1803*4882a593Smuzhiyun 		hmac_cmd.u.sha.type = sha->type;
1804*4882a593Smuzhiyun 		hmac_cmd.u.sha.ctx = sha->ctx;
1805*4882a593Smuzhiyun 		hmac_cmd.u.sha.ctx_len = sha->ctx_len;
1806*4882a593Smuzhiyun 		hmac_cmd.u.sha.src = &sg;
1807*4882a593Smuzhiyun 		hmac_cmd.u.sha.src_len = block_size + digest_size;
1808*4882a593Smuzhiyun 		hmac_cmd.u.sha.opad = NULL;
1809*4882a593Smuzhiyun 		hmac_cmd.u.sha.opad_len = 0;
1810*4882a593Smuzhiyun 		hmac_cmd.u.sha.first = 1;
1811*4882a593Smuzhiyun 		hmac_cmd.u.sha.final = 1;
1812*4882a593Smuzhiyun 		hmac_cmd.u.sha.msg_bits = (block_size + digest_size) << 3;
1813*4882a593Smuzhiyun 
1814*4882a593Smuzhiyun 		ret = ccp_run_sha_cmd(cmd_q, &hmac_cmd);
1815*4882a593Smuzhiyun 		if (ret)
1816*4882a593Smuzhiyun 			cmd->engine_error = hmac_cmd.engine_error;
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun 		kfree(hmac_buf);
1819*4882a593Smuzhiyun 	}
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun e_data:
1822*4882a593Smuzhiyun 	if (sha->src)
1823*4882a593Smuzhiyun 		ccp_free_data(&src, cmd_q);
1824*4882a593Smuzhiyun 
1825*4882a593Smuzhiyun e_ctx:
1826*4882a593Smuzhiyun 	ccp_dm_free(&ctx);
1827*4882a593Smuzhiyun 
1828*4882a593Smuzhiyun 	return ret;
1829*4882a593Smuzhiyun }
1830*4882a593Smuzhiyun 
1831*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_rsa_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)1832*4882a593Smuzhiyun ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
1833*4882a593Smuzhiyun {
1834*4882a593Smuzhiyun 	struct ccp_rsa_engine *rsa = &cmd->u.rsa;
1835*4882a593Smuzhiyun 	struct ccp_dm_workarea exp, src, dst;
1836*4882a593Smuzhiyun 	struct ccp_op op;
1837*4882a593Smuzhiyun 	unsigned int sb_count, i_len, o_len;
1838*4882a593Smuzhiyun 	int ret;
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun 	/* Check against the maximum allowable size, in bits */
1841*4882a593Smuzhiyun 	if (rsa->key_size > cmd_q->ccp->vdata->rsamax)
1842*4882a593Smuzhiyun 		return -EINVAL;
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun 	if (!rsa->exp || !rsa->mod || !rsa->src || !rsa->dst)
1845*4882a593Smuzhiyun 		return -EINVAL;
1846*4882a593Smuzhiyun 
1847*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
1848*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
1849*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
1850*4882a593Smuzhiyun 
1851*4882a593Smuzhiyun 	/* The RSA modulus must precede the message being acted upon, so
1852*4882a593Smuzhiyun 	 * it must be copied to a DMA area where the message and the
1853*4882a593Smuzhiyun 	 * modulus can be concatenated.  Therefore the input buffer
1854*4882a593Smuzhiyun 	 * length required is twice the output buffer length (which
1855*4882a593Smuzhiyun 	 * must be a multiple of 256-bits).  Compute o_len, i_len in bytes.
1856*4882a593Smuzhiyun 	 * Buffer sizes must be a multiple of 32 bytes; rounding up may be
1857*4882a593Smuzhiyun 	 * required.
1858*4882a593Smuzhiyun 	 */
1859*4882a593Smuzhiyun 	o_len = 32 * ((rsa->key_size + 255) / 256);
1860*4882a593Smuzhiyun 	i_len = o_len * 2;
1861*4882a593Smuzhiyun 
1862*4882a593Smuzhiyun 	sb_count = 0;
1863*4882a593Smuzhiyun 	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) {
1864*4882a593Smuzhiyun 		/* sb_count is the number of storage block slots required
1865*4882a593Smuzhiyun 		 * for the modulus.
1866*4882a593Smuzhiyun 		 */
1867*4882a593Smuzhiyun 		sb_count = o_len / CCP_SB_BYTES;
1868*4882a593Smuzhiyun 		op.sb_key = cmd_q->ccp->vdata->perform->sballoc(cmd_q,
1869*4882a593Smuzhiyun 								sb_count);
1870*4882a593Smuzhiyun 		if (!op.sb_key)
1871*4882a593Smuzhiyun 			return -EIO;
1872*4882a593Smuzhiyun 	} else {
1873*4882a593Smuzhiyun 		/* A version 5 device allows a modulus size that will not fit
1874*4882a593Smuzhiyun 		 * in the LSB, so the command will transfer it from memory.
1875*4882a593Smuzhiyun 		 * Set the sb key to the default, even though it's not used.
1876*4882a593Smuzhiyun 		 */
1877*4882a593Smuzhiyun 		op.sb_key = cmd_q->sb_key;
1878*4882a593Smuzhiyun 	}
1879*4882a593Smuzhiyun 
1880*4882a593Smuzhiyun 	/* The RSA exponent must be in little endian format. Reverse its
1881*4882a593Smuzhiyun 	 * byte order.
1882*4882a593Smuzhiyun 	 */
1883*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&exp, cmd_q, o_len, DMA_TO_DEVICE);
1884*4882a593Smuzhiyun 	if (ret)
1885*4882a593Smuzhiyun 		goto e_sb;
1886*4882a593Smuzhiyun 
1887*4882a593Smuzhiyun 	ret = ccp_reverse_set_dm_area(&exp, 0, rsa->exp, 0, rsa->exp_len);
1888*4882a593Smuzhiyun 	if (ret)
1889*4882a593Smuzhiyun 		goto e_exp;
1890*4882a593Smuzhiyun 
1891*4882a593Smuzhiyun 	if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) {
1892*4882a593Smuzhiyun 		/* Copy the exponent to the local storage block, using
1893*4882a593Smuzhiyun 		 * as many 32-byte blocks as were allocated above. It's
1894*4882a593Smuzhiyun 		 * already little endian, so no further change is required.
1895*4882a593Smuzhiyun 		 */
1896*4882a593Smuzhiyun 		ret = ccp_copy_to_sb(cmd_q, &exp, op.jobid, op.sb_key,
1897*4882a593Smuzhiyun 				     CCP_PASSTHRU_BYTESWAP_NOOP);
1898*4882a593Smuzhiyun 		if (ret) {
1899*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
1900*4882a593Smuzhiyun 			goto e_exp;
1901*4882a593Smuzhiyun 		}
1902*4882a593Smuzhiyun 	} else {
1903*4882a593Smuzhiyun 		/* The exponent can be retrieved from memory via DMA. */
1904*4882a593Smuzhiyun 		op.exp.u.dma.address = exp.dma.address;
1905*4882a593Smuzhiyun 		op.exp.u.dma.offset = 0;
1906*4882a593Smuzhiyun 	}
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun 	/* Concatenate the modulus and the message. Both the modulus and
1909*4882a593Smuzhiyun 	 * the operands must be in little endian format.  Since the input
1910*4882a593Smuzhiyun 	 * is in big endian format it must be converted.
1911*4882a593Smuzhiyun 	 */
1912*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&src, cmd_q, i_len, DMA_TO_DEVICE);
1913*4882a593Smuzhiyun 	if (ret)
1914*4882a593Smuzhiyun 		goto e_exp;
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun 	ret = ccp_reverse_set_dm_area(&src, 0, rsa->mod, 0, rsa->mod_len);
1917*4882a593Smuzhiyun 	if (ret)
1918*4882a593Smuzhiyun 		goto e_src;
1919*4882a593Smuzhiyun 	ret = ccp_reverse_set_dm_area(&src, o_len, rsa->src, 0, rsa->src_len);
1920*4882a593Smuzhiyun 	if (ret)
1921*4882a593Smuzhiyun 		goto e_src;
1922*4882a593Smuzhiyun 
1923*4882a593Smuzhiyun 	/* Prepare the output area for the operation */
1924*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&dst, cmd_q, o_len, DMA_FROM_DEVICE);
1925*4882a593Smuzhiyun 	if (ret)
1926*4882a593Smuzhiyun 		goto e_src;
1927*4882a593Smuzhiyun 
1928*4882a593Smuzhiyun 	op.soc = 1;
1929*4882a593Smuzhiyun 	op.src.u.dma.address = src.dma.address;
1930*4882a593Smuzhiyun 	op.src.u.dma.offset = 0;
1931*4882a593Smuzhiyun 	op.src.u.dma.length = i_len;
1932*4882a593Smuzhiyun 	op.dst.u.dma.address = dst.dma.address;
1933*4882a593Smuzhiyun 	op.dst.u.dma.offset = 0;
1934*4882a593Smuzhiyun 	op.dst.u.dma.length = o_len;
1935*4882a593Smuzhiyun 
1936*4882a593Smuzhiyun 	op.u.rsa.mod_size = rsa->key_size;
1937*4882a593Smuzhiyun 	op.u.rsa.input_len = i_len;
1938*4882a593Smuzhiyun 
1939*4882a593Smuzhiyun 	ret = cmd_q->ccp->vdata->perform->rsa(&op);
1940*4882a593Smuzhiyun 	if (ret) {
1941*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
1942*4882a593Smuzhiyun 		goto e_dst;
1943*4882a593Smuzhiyun 	}
1944*4882a593Smuzhiyun 
1945*4882a593Smuzhiyun 	ccp_reverse_get_dm_area(&dst, 0, rsa->dst, 0, rsa->mod_len);
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun e_dst:
1948*4882a593Smuzhiyun 	ccp_dm_free(&dst);
1949*4882a593Smuzhiyun 
1950*4882a593Smuzhiyun e_src:
1951*4882a593Smuzhiyun 	ccp_dm_free(&src);
1952*4882a593Smuzhiyun 
1953*4882a593Smuzhiyun e_exp:
1954*4882a593Smuzhiyun 	ccp_dm_free(&exp);
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun e_sb:
1957*4882a593Smuzhiyun 	if (sb_count)
1958*4882a593Smuzhiyun 		cmd_q->ccp->vdata->perform->sbfree(cmd_q, op.sb_key, sb_count);
1959*4882a593Smuzhiyun 
1960*4882a593Smuzhiyun 	return ret;
1961*4882a593Smuzhiyun }
1962*4882a593Smuzhiyun 
1963*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_passthru_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)1964*4882a593Smuzhiyun ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
1965*4882a593Smuzhiyun {
1966*4882a593Smuzhiyun 	struct ccp_passthru_engine *pt = &cmd->u.passthru;
1967*4882a593Smuzhiyun 	struct ccp_dm_workarea mask;
1968*4882a593Smuzhiyun 	struct ccp_data src, dst;
1969*4882a593Smuzhiyun 	struct ccp_op op;
1970*4882a593Smuzhiyun 	bool in_place = false;
1971*4882a593Smuzhiyun 	unsigned int i;
1972*4882a593Smuzhiyun 	int ret = 0;
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun 	if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
1975*4882a593Smuzhiyun 		return -EINVAL;
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun 	if (!pt->src || !pt->dst)
1978*4882a593Smuzhiyun 		return -EINVAL;
1979*4882a593Smuzhiyun 
1980*4882a593Smuzhiyun 	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
1981*4882a593Smuzhiyun 		if (pt->mask_len != CCP_PASSTHRU_MASKSIZE)
1982*4882a593Smuzhiyun 			return -EINVAL;
1983*4882a593Smuzhiyun 		if (!pt->mask)
1984*4882a593Smuzhiyun 			return -EINVAL;
1985*4882a593Smuzhiyun 	}
1986*4882a593Smuzhiyun 
1987*4882a593Smuzhiyun 	BUILD_BUG_ON(CCP_PASSTHRU_SB_COUNT != 1);
1988*4882a593Smuzhiyun 
1989*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
1990*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
1991*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
1992*4882a593Smuzhiyun 
1993*4882a593Smuzhiyun 	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
1994*4882a593Smuzhiyun 		/* Load the mask */
1995*4882a593Smuzhiyun 		op.sb_key = cmd_q->sb_key;
1996*4882a593Smuzhiyun 
1997*4882a593Smuzhiyun 		ret = ccp_init_dm_workarea(&mask, cmd_q,
1998*4882a593Smuzhiyun 					   CCP_PASSTHRU_SB_COUNT *
1999*4882a593Smuzhiyun 					   CCP_SB_BYTES,
2000*4882a593Smuzhiyun 					   DMA_TO_DEVICE);
2001*4882a593Smuzhiyun 		if (ret)
2002*4882a593Smuzhiyun 			return ret;
2003*4882a593Smuzhiyun 
2004*4882a593Smuzhiyun 		ret = ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
2005*4882a593Smuzhiyun 		if (ret)
2006*4882a593Smuzhiyun 			goto e_mask;
2007*4882a593Smuzhiyun 		ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
2008*4882a593Smuzhiyun 				     CCP_PASSTHRU_BYTESWAP_NOOP);
2009*4882a593Smuzhiyun 		if (ret) {
2010*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
2011*4882a593Smuzhiyun 			goto e_mask;
2012*4882a593Smuzhiyun 		}
2013*4882a593Smuzhiyun 	}
2014*4882a593Smuzhiyun 
2015*4882a593Smuzhiyun 	/* Prepare the input and output data workareas. For in-place
2016*4882a593Smuzhiyun 	 * operations we need to set the dma direction to BIDIRECTIONAL
2017*4882a593Smuzhiyun 	 * and copy the src workarea to the dst workarea.
2018*4882a593Smuzhiyun 	 */
2019*4882a593Smuzhiyun 	if (sg_virt(pt->src) == sg_virt(pt->dst))
2020*4882a593Smuzhiyun 		in_place = true;
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun 	ret = ccp_init_data(&src, cmd_q, pt->src, pt->src_len,
2023*4882a593Smuzhiyun 			    CCP_PASSTHRU_MASKSIZE,
2024*4882a593Smuzhiyun 			    in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE);
2025*4882a593Smuzhiyun 	if (ret)
2026*4882a593Smuzhiyun 		goto e_mask;
2027*4882a593Smuzhiyun 
2028*4882a593Smuzhiyun 	if (in_place) {
2029*4882a593Smuzhiyun 		dst = src;
2030*4882a593Smuzhiyun 	} else {
2031*4882a593Smuzhiyun 		ret = ccp_init_data(&dst, cmd_q, pt->dst, pt->src_len,
2032*4882a593Smuzhiyun 				    CCP_PASSTHRU_MASKSIZE, DMA_FROM_DEVICE);
2033*4882a593Smuzhiyun 		if (ret)
2034*4882a593Smuzhiyun 			goto e_src;
2035*4882a593Smuzhiyun 	}
2036*4882a593Smuzhiyun 
2037*4882a593Smuzhiyun 	/* Send data to the CCP Passthru engine
2038*4882a593Smuzhiyun 	 *   Because the CCP engine works on a single source and destination
2039*4882a593Smuzhiyun 	 *   dma address at a time, each entry in the source scatterlist
2040*4882a593Smuzhiyun 	 *   (after the dma_map_sg call) must be less than or equal to the
2041*4882a593Smuzhiyun 	 *   (remaining) length in the destination scatterlist entry and the
2042*4882a593Smuzhiyun 	 *   length must be a multiple of CCP_PASSTHRU_BLOCKSIZE
2043*4882a593Smuzhiyun 	 */
2044*4882a593Smuzhiyun 	dst.sg_wa.sg_used = 0;
2045*4882a593Smuzhiyun 	for (i = 1; i <= src.sg_wa.dma_count; i++) {
2046*4882a593Smuzhiyun 		if (!dst.sg_wa.sg ||
2047*4882a593Smuzhiyun 		    (sg_dma_len(dst.sg_wa.sg) < sg_dma_len(src.sg_wa.sg))) {
2048*4882a593Smuzhiyun 			ret = -EINVAL;
2049*4882a593Smuzhiyun 			goto e_dst;
2050*4882a593Smuzhiyun 		}
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun 		if (i == src.sg_wa.dma_count) {
2053*4882a593Smuzhiyun 			op.eom = 1;
2054*4882a593Smuzhiyun 			op.soc = 1;
2055*4882a593Smuzhiyun 		}
2056*4882a593Smuzhiyun 
2057*4882a593Smuzhiyun 		op.src.type = CCP_MEMTYPE_SYSTEM;
2058*4882a593Smuzhiyun 		op.src.u.dma.address = sg_dma_address(src.sg_wa.sg);
2059*4882a593Smuzhiyun 		op.src.u.dma.offset = 0;
2060*4882a593Smuzhiyun 		op.src.u.dma.length = sg_dma_len(src.sg_wa.sg);
2061*4882a593Smuzhiyun 
2062*4882a593Smuzhiyun 		op.dst.type = CCP_MEMTYPE_SYSTEM;
2063*4882a593Smuzhiyun 		op.dst.u.dma.address = sg_dma_address(dst.sg_wa.sg);
2064*4882a593Smuzhiyun 		op.dst.u.dma.offset = dst.sg_wa.sg_used;
2065*4882a593Smuzhiyun 		op.dst.u.dma.length = op.src.u.dma.length;
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun 		ret = cmd_q->ccp->vdata->perform->passthru(&op);
2068*4882a593Smuzhiyun 		if (ret) {
2069*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
2070*4882a593Smuzhiyun 			goto e_dst;
2071*4882a593Smuzhiyun 		}
2072*4882a593Smuzhiyun 
2073*4882a593Smuzhiyun 		dst.sg_wa.sg_used += sg_dma_len(src.sg_wa.sg);
2074*4882a593Smuzhiyun 		if (dst.sg_wa.sg_used == sg_dma_len(dst.sg_wa.sg)) {
2075*4882a593Smuzhiyun 			dst.sg_wa.sg = sg_next(dst.sg_wa.sg);
2076*4882a593Smuzhiyun 			dst.sg_wa.sg_used = 0;
2077*4882a593Smuzhiyun 		}
2078*4882a593Smuzhiyun 		src.sg_wa.sg = sg_next(src.sg_wa.sg);
2079*4882a593Smuzhiyun 	}
2080*4882a593Smuzhiyun 
2081*4882a593Smuzhiyun e_dst:
2082*4882a593Smuzhiyun 	if (!in_place)
2083*4882a593Smuzhiyun 		ccp_free_data(&dst, cmd_q);
2084*4882a593Smuzhiyun 
2085*4882a593Smuzhiyun e_src:
2086*4882a593Smuzhiyun 	ccp_free_data(&src, cmd_q);
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun e_mask:
2089*4882a593Smuzhiyun 	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
2090*4882a593Smuzhiyun 		ccp_dm_free(&mask);
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 	return ret;
2093*4882a593Smuzhiyun }
2094*4882a593Smuzhiyun 
2095*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)2096*4882a593Smuzhiyun ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q,
2097*4882a593Smuzhiyun 				      struct ccp_cmd *cmd)
2098*4882a593Smuzhiyun {
2099*4882a593Smuzhiyun 	struct ccp_passthru_nomap_engine *pt = &cmd->u.passthru_nomap;
2100*4882a593Smuzhiyun 	struct ccp_dm_workarea mask;
2101*4882a593Smuzhiyun 	struct ccp_op op;
2102*4882a593Smuzhiyun 	int ret;
2103*4882a593Smuzhiyun 
2104*4882a593Smuzhiyun 	if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1)))
2105*4882a593Smuzhiyun 		return -EINVAL;
2106*4882a593Smuzhiyun 
2107*4882a593Smuzhiyun 	if (!pt->src_dma || !pt->dst_dma)
2108*4882a593Smuzhiyun 		return -EINVAL;
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun 	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
2111*4882a593Smuzhiyun 		if (pt->mask_len != CCP_PASSTHRU_MASKSIZE)
2112*4882a593Smuzhiyun 			return -EINVAL;
2113*4882a593Smuzhiyun 		if (!pt->mask)
2114*4882a593Smuzhiyun 			return -EINVAL;
2115*4882a593Smuzhiyun 	}
2116*4882a593Smuzhiyun 
2117*4882a593Smuzhiyun 	BUILD_BUG_ON(CCP_PASSTHRU_SB_COUNT != 1);
2118*4882a593Smuzhiyun 
2119*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
2120*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
2121*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
2122*4882a593Smuzhiyun 
2123*4882a593Smuzhiyun 	if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) {
2124*4882a593Smuzhiyun 		/* Load the mask */
2125*4882a593Smuzhiyun 		op.sb_key = cmd_q->sb_key;
2126*4882a593Smuzhiyun 
2127*4882a593Smuzhiyun 		mask.length = pt->mask_len;
2128*4882a593Smuzhiyun 		mask.dma.address = pt->mask;
2129*4882a593Smuzhiyun 		mask.dma.length = pt->mask_len;
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 		ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
2132*4882a593Smuzhiyun 				     CCP_PASSTHRU_BYTESWAP_NOOP);
2133*4882a593Smuzhiyun 		if (ret) {
2134*4882a593Smuzhiyun 			cmd->engine_error = cmd_q->cmd_error;
2135*4882a593Smuzhiyun 			return ret;
2136*4882a593Smuzhiyun 		}
2137*4882a593Smuzhiyun 	}
2138*4882a593Smuzhiyun 
2139*4882a593Smuzhiyun 	/* Send data to the CCP Passthru engine */
2140*4882a593Smuzhiyun 	op.eom = 1;
2141*4882a593Smuzhiyun 	op.soc = 1;
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	op.src.type = CCP_MEMTYPE_SYSTEM;
2144*4882a593Smuzhiyun 	op.src.u.dma.address = pt->src_dma;
2145*4882a593Smuzhiyun 	op.src.u.dma.offset = 0;
2146*4882a593Smuzhiyun 	op.src.u.dma.length = pt->src_len;
2147*4882a593Smuzhiyun 
2148*4882a593Smuzhiyun 	op.dst.type = CCP_MEMTYPE_SYSTEM;
2149*4882a593Smuzhiyun 	op.dst.u.dma.address = pt->dst_dma;
2150*4882a593Smuzhiyun 	op.dst.u.dma.offset = 0;
2151*4882a593Smuzhiyun 	op.dst.u.dma.length = pt->src_len;
2152*4882a593Smuzhiyun 
2153*4882a593Smuzhiyun 	ret = cmd_q->ccp->vdata->perform->passthru(&op);
2154*4882a593Smuzhiyun 	if (ret)
2155*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun 	return ret;
2158*4882a593Smuzhiyun }
2159*4882a593Smuzhiyun 
ccp_run_ecc_mm_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)2160*4882a593Smuzhiyun static int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
2161*4882a593Smuzhiyun {
2162*4882a593Smuzhiyun 	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
2163*4882a593Smuzhiyun 	struct ccp_dm_workarea src, dst;
2164*4882a593Smuzhiyun 	struct ccp_op op;
2165*4882a593Smuzhiyun 	int ret;
2166*4882a593Smuzhiyun 	u8 *save;
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun 	if (!ecc->u.mm.operand_1 ||
2169*4882a593Smuzhiyun 	    (ecc->u.mm.operand_1_len > CCP_ECC_MODULUS_BYTES))
2170*4882a593Smuzhiyun 		return -EINVAL;
2171*4882a593Smuzhiyun 
2172*4882a593Smuzhiyun 	if (ecc->function != CCP_ECC_FUNCTION_MINV_384BIT)
2173*4882a593Smuzhiyun 		if (!ecc->u.mm.operand_2 ||
2174*4882a593Smuzhiyun 		    (ecc->u.mm.operand_2_len > CCP_ECC_MODULUS_BYTES))
2175*4882a593Smuzhiyun 			return -EINVAL;
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun 	if (!ecc->u.mm.result ||
2178*4882a593Smuzhiyun 	    (ecc->u.mm.result_len < CCP_ECC_MODULUS_BYTES))
2179*4882a593Smuzhiyun 		return -EINVAL;
2180*4882a593Smuzhiyun 
2181*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
2182*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
2183*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
2184*4882a593Smuzhiyun 
2185*4882a593Smuzhiyun 	/* Concatenate the modulus and the operands. Both the modulus and
2186*4882a593Smuzhiyun 	 * the operands must be in little endian format.  Since the input
2187*4882a593Smuzhiyun 	 * is in big endian format it must be converted and placed in a
2188*4882a593Smuzhiyun 	 * fixed length buffer.
2189*4882a593Smuzhiyun 	 */
2190*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&src, cmd_q, CCP_ECC_SRC_BUF_SIZE,
2191*4882a593Smuzhiyun 				   DMA_TO_DEVICE);
2192*4882a593Smuzhiyun 	if (ret)
2193*4882a593Smuzhiyun 		return ret;
2194*4882a593Smuzhiyun 
2195*4882a593Smuzhiyun 	/* Save the workarea address since it is updated in order to perform
2196*4882a593Smuzhiyun 	 * the concatenation
2197*4882a593Smuzhiyun 	 */
2198*4882a593Smuzhiyun 	save = src.address;
2199*4882a593Smuzhiyun 
2200*4882a593Smuzhiyun 	/* Copy the ECC modulus */
2201*4882a593Smuzhiyun 	ret = ccp_reverse_set_dm_area(&src, 0, ecc->mod, 0, ecc->mod_len);
2202*4882a593Smuzhiyun 	if (ret)
2203*4882a593Smuzhiyun 		goto e_src;
2204*4882a593Smuzhiyun 	src.address += CCP_ECC_OPERAND_SIZE;
2205*4882a593Smuzhiyun 
2206*4882a593Smuzhiyun 	/* Copy the first operand */
2207*4882a593Smuzhiyun 	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.mm.operand_1, 0,
2208*4882a593Smuzhiyun 				      ecc->u.mm.operand_1_len);
2209*4882a593Smuzhiyun 	if (ret)
2210*4882a593Smuzhiyun 		goto e_src;
2211*4882a593Smuzhiyun 	src.address += CCP_ECC_OPERAND_SIZE;
2212*4882a593Smuzhiyun 
2213*4882a593Smuzhiyun 	if (ecc->function != CCP_ECC_FUNCTION_MINV_384BIT) {
2214*4882a593Smuzhiyun 		/* Copy the second operand */
2215*4882a593Smuzhiyun 		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.mm.operand_2, 0,
2216*4882a593Smuzhiyun 					      ecc->u.mm.operand_2_len);
2217*4882a593Smuzhiyun 		if (ret)
2218*4882a593Smuzhiyun 			goto e_src;
2219*4882a593Smuzhiyun 		src.address += CCP_ECC_OPERAND_SIZE;
2220*4882a593Smuzhiyun 	}
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun 	/* Restore the workarea address */
2223*4882a593Smuzhiyun 	src.address = save;
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun 	/* Prepare the output area for the operation */
2226*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&dst, cmd_q, CCP_ECC_DST_BUF_SIZE,
2227*4882a593Smuzhiyun 				   DMA_FROM_DEVICE);
2228*4882a593Smuzhiyun 	if (ret)
2229*4882a593Smuzhiyun 		goto e_src;
2230*4882a593Smuzhiyun 
2231*4882a593Smuzhiyun 	op.soc = 1;
2232*4882a593Smuzhiyun 	op.src.u.dma.address = src.dma.address;
2233*4882a593Smuzhiyun 	op.src.u.dma.offset = 0;
2234*4882a593Smuzhiyun 	op.src.u.dma.length = src.length;
2235*4882a593Smuzhiyun 	op.dst.u.dma.address = dst.dma.address;
2236*4882a593Smuzhiyun 	op.dst.u.dma.offset = 0;
2237*4882a593Smuzhiyun 	op.dst.u.dma.length = dst.length;
2238*4882a593Smuzhiyun 
2239*4882a593Smuzhiyun 	op.u.ecc.function = cmd->u.ecc.function;
2240*4882a593Smuzhiyun 
2241*4882a593Smuzhiyun 	ret = cmd_q->ccp->vdata->perform->ecc(&op);
2242*4882a593Smuzhiyun 	if (ret) {
2243*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
2244*4882a593Smuzhiyun 		goto e_dst;
2245*4882a593Smuzhiyun 	}
2246*4882a593Smuzhiyun 
2247*4882a593Smuzhiyun 	ecc->ecc_result = le16_to_cpup(
2248*4882a593Smuzhiyun 		(const __le16 *)(dst.address + CCP_ECC_RESULT_OFFSET));
2249*4882a593Smuzhiyun 	if (!(ecc->ecc_result & CCP_ECC_RESULT_SUCCESS)) {
2250*4882a593Smuzhiyun 		ret = -EIO;
2251*4882a593Smuzhiyun 		goto e_dst;
2252*4882a593Smuzhiyun 	}
2253*4882a593Smuzhiyun 
2254*4882a593Smuzhiyun 	/* Save the ECC result */
2255*4882a593Smuzhiyun 	ccp_reverse_get_dm_area(&dst, 0, ecc->u.mm.result, 0,
2256*4882a593Smuzhiyun 				CCP_ECC_MODULUS_BYTES);
2257*4882a593Smuzhiyun 
2258*4882a593Smuzhiyun e_dst:
2259*4882a593Smuzhiyun 	ccp_dm_free(&dst);
2260*4882a593Smuzhiyun 
2261*4882a593Smuzhiyun e_src:
2262*4882a593Smuzhiyun 	ccp_dm_free(&src);
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 	return ret;
2265*4882a593Smuzhiyun }
2266*4882a593Smuzhiyun 
ccp_run_ecc_pm_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)2267*4882a593Smuzhiyun static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
2268*4882a593Smuzhiyun {
2269*4882a593Smuzhiyun 	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
2270*4882a593Smuzhiyun 	struct ccp_dm_workarea src, dst;
2271*4882a593Smuzhiyun 	struct ccp_op op;
2272*4882a593Smuzhiyun 	int ret;
2273*4882a593Smuzhiyun 	u8 *save;
2274*4882a593Smuzhiyun 
2275*4882a593Smuzhiyun 	if (!ecc->u.pm.point_1.x ||
2276*4882a593Smuzhiyun 	    (ecc->u.pm.point_1.x_len > CCP_ECC_MODULUS_BYTES) ||
2277*4882a593Smuzhiyun 	    !ecc->u.pm.point_1.y ||
2278*4882a593Smuzhiyun 	    (ecc->u.pm.point_1.y_len > CCP_ECC_MODULUS_BYTES))
2279*4882a593Smuzhiyun 		return -EINVAL;
2280*4882a593Smuzhiyun 
2281*4882a593Smuzhiyun 	if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) {
2282*4882a593Smuzhiyun 		if (!ecc->u.pm.point_2.x ||
2283*4882a593Smuzhiyun 		    (ecc->u.pm.point_2.x_len > CCP_ECC_MODULUS_BYTES) ||
2284*4882a593Smuzhiyun 		    !ecc->u.pm.point_2.y ||
2285*4882a593Smuzhiyun 		    (ecc->u.pm.point_2.y_len > CCP_ECC_MODULUS_BYTES))
2286*4882a593Smuzhiyun 			return -EINVAL;
2287*4882a593Smuzhiyun 	} else {
2288*4882a593Smuzhiyun 		if (!ecc->u.pm.domain_a ||
2289*4882a593Smuzhiyun 		    (ecc->u.pm.domain_a_len > CCP_ECC_MODULUS_BYTES))
2290*4882a593Smuzhiyun 			return -EINVAL;
2291*4882a593Smuzhiyun 
2292*4882a593Smuzhiyun 		if (ecc->function == CCP_ECC_FUNCTION_PMUL_384BIT)
2293*4882a593Smuzhiyun 			if (!ecc->u.pm.scalar ||
2294*4882a593Smuzhiyun 			    (ecc->u.pm.scalar_len > CCP_ECC_MODULUS_BYTES))
2295*4882a593Smuzhiyun 				return -EINVAL;
2296*4882a593Smuzhiyun 	}
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 	if (!ecc->u.pm.result.x ||
2299*4882a593Smuzhiyun 	    (ecc->u.pm.result.x_len < CCP_ECC_MODULUS_BYTES) ||
2300*4882a593Smuzhiyun 	    !ecc->u.pm.result.y ||
2301*4882a593Smuzhiyun 	    (ecc->u.pm.result.y_len < CCP_ECC_MODULUS_BYTES))
2302*4882a593Smuzhiyun 		return -EINVAL;
2303*4882a593Smuzhiyun 
2304*4882a593Smuzhiyun 	memset(&op, 0, sizeof(op));
2305*4882a593Smuzhiyun 	op.cmd_q = cmd_q;
2306*4882a593Smuzhiyun 	op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
2307*4882a593Smuzhiyun 
2308*4882a593Smuzhiyun 	/* Concatenate the modulus and the operands. Both the modulus and
2309*4882a593Smuzhiyun 	 * the operands must be in little endian format.  Since the input
2310*4882a593Smuzhiyun 	 * is in big endian format it must be converted and placed in a
2311*4882a593Smuzhiyun 	 * fixed length buffer.
2312*4882a593Smuzhiyun 	 */
2313*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&src, cmd_q, CCP_ECC_SRC_BUF_SIZE,
2314*4882a593Smuzhiyun 				   DMA_TO_DEVICE);
2315*4882a593Smuzhiyun 	if (ret)
2316*4882a593Smuzhiyun 		return ret;
2317*4882a593Smuzhiyun 
2318*4882a593Smuzhiyun 	/* Save the workarea address since it is updated in order to perform
2319*4882a593Smuzhiyun 	 * the concatenation
2320*4882a593Smuzhiyun 	 */
2321*4882a593Smuzhiyun 	save = src.address;
2322*4882a593Smuzhiyun 
2323*4882a593Smuzhiyun 	/* Copy the ECC modulus */
2324*4882a593Smuzhiyun 	ret = ccp_reverse_set_dm_area(&src, 0, ecc->mod, 0, ecc->mod_len);
2325*4882a593Smuzhiyun 	if (ret)
2326*4882a593Smuzhiyun 		goto e_src;
2327*4882a593Smuzhiyun 	src.address += CCP_ECC_OPERAND_SIZE;
2328*4882a593Smuzhiyun 
2329*4882a593Smuzhiyun 	/* Copy the first point X and Y coordinate */
2330*4882a593Smuzhiyun 	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_1.x, 0,
2331*4882a593Smuzhiyun 				      ecc->u.pm.point_1.x_len);
2332*4882a593Smuzhiyun 	if (ret)
2333*4882a593Smuzhiyun 		goto e_src;
2334*4882a593Smuzhiyun 	src.address += CCP_ECC_OPERAND_SIZE;
2335*4882a593Smuzhiyun 	ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_1.y, 0,
2336*4882a593Smuzhiyun 				      ecc->u.pm.point_1.y_len);
2337*4882a593Smuzhiyun 	if (ret)
2338*4882a593Smuzhiyun 		goto e_src;
2339*4882a593Smuzhiyun 	src.address += CCP_ECC_OPERAND_SIZE;
2340*4882a593Smuzhiyun 
2341*4882a593Smuzhiyun 	/* Set the first point Z coordinate to 1 */
2342*4882a593Smuzhiyun 	*src.address = 0x01;
2343*4882a593Smuzhiyun 	src.address += CCP_ECC_OPERAND_SIZE;
2344*4882a593Smuzhiyun 
2345*4882a593Smuzhiyun 	if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) {
2346*4882a593Smuzhiyun 		/* Copy the second point X and Y coordinate */
2347*4882a593Smuzhiyun 		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_2.x, 0,
2348*4882a593Smuzhiyun 					      ecc->u.pm.point_2.x_len);
2349*4882a593Smuzhiyun 		if (ret)
2350*4882a593Smuzhiyun 			goto e_src;
2351*4882a593Smuzhiyun 		src.address += CCP_ECC_OPERAND_SIZE;
2352*4882a593Smuzhiyun 		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.point_2.y, 0,
2353*4882a593Smuzhiyun 					      ecc->u.pm.point_2.y_len);
2354*4882a593Smuzhiyun 		if (ret)
2355*4882a593Smuzhiyun 			goto e_src;
2356*4882a593Smuzhiyun 		src.address += CCP_ECC_OPERAND_SIZE;
2357*4882a593Smuzhiyun 
2358*4882a593Smuzhiyun 		/* Set the second point Z coordinate to 1 */
2359*4882a593Smuzhiyun 		*src.address = 0x01;
2360*4882a593Smuzhiyun 		src.address += CCP_ECC_OPERAND_SIZE;
2361*4882a593Smuzhiyun 	} else {
2362*4882a593Smuzhiyun 		/* Copy the Domain "a" parameter */
2363*4882a593Smuzhiyun 		ret = ccp_reverse_set_dm_area(&src, 0, ecc->u.pm.domain_a, 0,
2364*4882a593Smuzhiyun 					      ecc->u.pm.domain_a_len);
2365*4882a593Smuzhiyun 		if (ret)
2366*4882a593Smuzhiyun 			goto e_src;
2367*4882a593Smuzhiyun 		src.address += CCP_ECC_OPERAND_SIZE;
2368*4882a593Smuzhiyun 
2369*4882a593Smuzhiyun 		if (ecc->function == CCP_ECC_FUNCTION_PMUL_384BIT) {
2370*4882a593Smuzhiyun 			/* Copy the scalar value */
2371*4882a593Smuzhiyun 			ret = ccp_reverse_set_dm_area(&src, 0,
2372*4882a593Smuzhiyun 						      ecc->u.pm.scalar, 0,
2373*4882a593Smuzhiyun 						      ecc->u.pm.scalar_len);
2374*4882a593Smuzhiyun 			if (ret)
2375*4882a593Smuzhiyun 				goto e_src;
2376*4882a593Smuzhiyun 			src.address += CCP_ECC_OPERAND_SIZE;
2377*4882a593Smuzhiyun 		}
2378*4882a593Smuzhiyun 	}
2379*4882a593Smuzhiyun 
2380*4882a593Smuzhiyun 	/* Restore the workarea address */
2381*4882a593Smuzhiyun 	src.address = save;
2382*4882a593Smuzhiyun 
2383*4882a593Smuzhiyun 	/* Prepare the output area for the operation */
2384*4882a593Smuzhiyun 	ret = ccp_init_dm_workarea(&dst, cmd_q, CCP_ECC_DST_BUF_SIZE,
2385*4882a593Smuzhiyun 				   DMA_FROM_DEVICE);
2386*4882a593Smuzhiyun 	if (ret)
2387*4882a593Smuzhiyun 		goto e_src;
2388*4882a593Smuzhiyun 
2389*4882a593Smuzhiyun 	op.soc = 1;
2390*4882a593Smuzhiyun 	op.src.u.dma.address = src.dma.address;
2391*4882a593Smuzhiyun 	op.src.u.dma.offset = 0;
2392*4882a593Smuzhiyun 	op.src.u.dma.length = src.length;
2393*4882a593Smuzhiyun 	op.dst.u.dma.address = dst.dma.address;
2394*4882a593Smuzhiyun 	op.dst.u.dma.offset = 0;
2395*4882a593Smuzhiyun 	op.dst.u.dma.length = dst.length;
2396*4882a593Smuzhiyun 
2397*4882a593Smuzhiyun 	op.u.ecc.function = cmd->u.ecc.function;
2398*4882a593Smuzhiyun 
2399*4882a593Smuzhiyun 	ret = cmd_q->ccp->vdata->perform->ecc(&op);
2400*4882a593Smuzhiyun 	if (ret) {
2401*4882a593Smuzhiyun 		cmd->engine_error = cmd_q->cmd_error;
2402*4882a593Smuzhiyun 		goto e_dst;
2403*4882a593Smuzhiyun 	}
2404*4882a593Smuzhiyun 
2405*4882a593Smuzhiyun 	ecc->ecc_result = le16_to_cpup(
2406*4882a593Smuzhiyun 		(const __le16 *)(dst.address + CCP_ECC_RESULT_OFFSET));
2407*4882a593Smuzhiyun 	if (!(ecc->ecc_result & CCP_ECC_RESULT_SUCCESS)) {
2408*4882a593Smuzhiyun 		ret = -EIO;
2409*4882a593Smuzhiyun 		goto e_dst;
2410*4882a593Smuzhiyun 	}
2411*4882a593Smuzhiyun 
2412*4882a593Smuzhiyun 	/* Save the workarea address since it is updated as we walk through
2413*4882a593Smuzhiyun 	 * to copy the point math result
2414*4882a593Smuzhiyun 	 */
2415*4882a593Smuzhiyun 	save = dst.address;
2416*4882a593Smuzhiyun 
2417*4882a593Smuzhiyun 	/* Save the ECC result X and Y coordinates */
2418*4882a593Smuzhiyun 	ccp_reverse_get_dm_area(&dst, 0, ecc->u.pm.result.x, 0,
2419*4882a593Smuzhiyun 				CCP_ECC_MODULUS_BYTES);
2420*4882a593Smuzhiyun 	dst.address += CCP_ECC_OUTPUT_SIZE;
2421*4882a593Smuzhiyun 	ccp_reverse_get_dm_area(&dst, 0, ecc->u.pm.result.y, 0,
2422*4882a593Smuzhiyun 				CCP_ECC_MODULUS_BYTES);
2423*4882a593Smuzhiyun 	dst.address += CCP_ECC_OUTPUT_SIZE;
2424*4882a593Smuzhiyun 
2425*4882a593Smuzhiyun 	/* Restore the workarea address */
2426*4882a593Smuzhiyun 	dst.address = save;
2427*4882a593Smuzhiyun 
2428*4882a593Smuzhiyun e_dst:
2429*4882a593Smuzhiyun 	ccp_dm_free(&dst);
2430*4882a593Smuzhiyun 
2431*4882a593Smuzhiyun e_src:
2432*4882a593Smuzhiyun 	ccp_dm_free(&src);
2433*4882a593Smuzhiyun 
2434*4882a593Smuzhiyun 	return ret;
2435*4882a593Smuzhiyun }
2436*4882a593Smuzhiyun 
2437*4882a593Smuzhiyun static noinline_for_stack int
ccp_run_ecc_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)2438*4882a593Smuzhiyun ccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
2439*4882a593Smuzhiyun {
2440*4882a593Smuzhiyun 	struct ccp_ecc_engine *ecc = &cmd->u.ecc;
2441*4882a593Smuzhiyun 
2442*4882a593Smuzhiyun 	ecc->ecc_result = 0;
2443*4882a593Smuzhiyun 
2444*4882a593Smuzhiyun 	if (!ecc->mod ||
2445*4882a593Smuzhiyun 	    (ecc->mod_len > CCP_ECC_MODULUS_BYTES))
2446*4882a593Smuzhiyun 		return -EINVAL;
2447*4882a593Smuzhiyun 
2448*4882a593Smuzhiyun 	switch (ecc->function) {
2449*4882a593Smuzhiyun 	case CCP_ECC_FUNCTION_MMUL_384BIT:
2450*4882a593Smuzhiyun 	case CCP_ECC_FUNCTION_MADD_384BIT:
2451*4882a593Smuzhiyun 	case CCP_ECC_FUNCTION_MINV_384BIT:
2452*4882a593Smuzhiyun 		return ccp_run_ecc_mm_cmd(cmd_q, cmd);
2453*4882a593Smuzhiyun 
2454*4882a593Smuzhiyun 	case CCP_ECC_FUNCTION_PADD_384BIT:
2455*4882a593Smuzhiyun 	case CCP_ECC_FUNCTION_PMUL_384BIT:
2456*4882a593Smuzhiyun 	case CCP_ECC_FUNCTION_PDBL_384BIT:
2457*4882a593Smuzhiyun 		return ccp_run_ecc_pm_cmd(cmd_q, cmd);
2458*4882a593Smuzhiyun 
2459*4882a593Smuzhiyun 	default:
2460*4882a593Smuzhiyun 		return -EINVAL;
2461*4882a593Smuzhiyun 	}
2462*4882a593Smuzhiyun }
2463*4882a593Smuzhiyun 
ccp_run_cmd(struct ccp_cmd_queue * cmd_q,struct ccp_cmd * cmd)2464*4882a593Smuzhiyun int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
2465*4882a593Smuzhiyun {
2466*4882a593Smuzhiyun 	int ret;
2467*4882a593Smuzhiyun 
2468*4882a593Smuzhiyun 	cmd->engine_error = 0;
2469*4882a593Smuzhiyun 	cmd_q->cmd_error = 0;
2470*4882a593Smuzhiyun 	cmd_q->int_rcvd = 0;
2471*4882a593Smuzhiyun 	cmd_q->free_slots = cmd_q->ccp->vdata->perform->get_free_slots(cmd_q);
2472*4882a593Smuzhiyun 
2473*4882a593Smuzhiyun 	switch (cmd->engine) {
2474*4882a593Smuzhiyun 	case CCP_ENGINE_AES:
2475*4882a593Smuzhiyun 		switch (cmd->u.aes.mode) {
2476*4882a593Smuzhiyun 		case CCP_AES_MODE_CMAC:
2477*4882a593Smuzhiyun 			ret = ccp_run_aes_cmac_cmd(cmd_q, cmd);
2478*4882a593Smuzhiyun 			break;
2479*4882a593Smuzhiyun 		case CCP_AES_MODE_GCM:
2480*4882a593Smuzhiyun 			ret = ccp_run_aes_gcm_cmd(cmd_q, cmd);
2481*4882a593Smuzhiyun 			break;
2482*4882a593Smuzhiyun 		default:
2483*4882a593Smuzhiyun 			ret = ccp_run_aes_cmd(cmd_q, cmd);
2484*4882a593Smuzhiyun 			break;
2485*4882a593Smuzhiyun 		}
2486*4882a593Smuzhiyun 		break;
2487*4882a593Smuzhiyun 	case CCP_ENGINE_XTS_AES_128:
2488*4882a593Smuzhiyun 		ret = ccp_run_xts_aes_cmd(cmd_q, cmd);
2489*4882a593Smuzhiyun 		break;
2490*4882a593Smuzhiyun 	case CCP_ENGINE_DES3:
2491*4882a593Smuzhiyun 		ret = ccp_run_des3_cmd(cmd_q, cmd);
2492*4882a593Smuzhiyun 		break;
2493*4882a593Smuzhiyun 	case CCP_ENGINE_SHA:
2494*4882a593Smuzhiyun 		ret = ccp_run_sha_cmd(cmd_q, cmd);
2495*4882a593Smuzhiyun 		break;
2496*4882a593Smuzhiyun 	case CCP_ENGINE_RSA:
2497*4882a593Smuzhiyun 		ret = ccp_run_rsa_cmd(cmd_q, cmd);
2498*4882a593Smuzhiyun 		break;
2499*4882a593Smuzhiyun 	case CCP_ENGINE_PASSTHRU:
2500*4882a593Smuzhiyun 		if (cmd->flags & CCP_CMD_PASSTHRU_NO_DMA_MAP)
2501*4882a593Smuzhiyun 			ret = ccp_run_passthru_nomap_cmd(cmd_q, cmd);
2502*4882a593Smuzhiyun 		else
2503*4882a593Smuzhiyun 			ret = ccp_run_passthru_cmd(cmd_q, cmd);
2504*4882a593Smuzhiyun 		break;
2505*4882a593Smuzhiyun 	case CCP_ENGINE_ECC:
2506*4882a593Smuzhiyun 		ret = ccp_run_ecc_cmd(cmd_q, cmd);
2507*4882a593Smuzhiyun 		break;
2508*4882a593Smuzhiyun 	default:
2509*4882a593Smuzhiyun 		ret = -EINVAL;
2510*4882a593Smuzhiyun 	}
2511*4882a593Smuzhiyun 
2512*4882a593Smuzhiyun 	return ret;
2513*4882a593Smuzhiyun }
2514