xref: /OK3568_Linux_fs/kernel/drivers/crypto/ccp/ccp-dev-v3.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,2017 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/module.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/kthread.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/ccp.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "ccp-dev.h"
18*4882a593Smuzhiyun 
ccp_alloc_ksb(struct ccp_cmd_queue * cmd_q,unsigned int count)19*4882a593Smuzhiyun static u32 ccp_alloc_ksb(struct ccp_cmd_queue *cmd_q, unsigned int count)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	int start;
22*4882a593Smuzhiyun 	struct ccp_device *ccp = cmd_q->ccp;
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 	for (;;) {
25*4882a593Smuzhiyun 		mutex_lock(&ccp->sb_mutex);
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun 		start = (u32)bitmap_find_next_zero_area(ccp->sb,
28*4882a593Smuzhiyun 							ccp->sb_count,
29*4882a593Smuzhiyun 							ccp->sb_start,
30*4882a593Smuzhiyun 							count, 0);
31*4882a593Smuzhiyun 		if (start <= ccp->sb_count) {
32*4882a593Smuzhiyun 			bitmap_set(ccp->sb, start, count);
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 			mutex_unlock(&ccp->sb_mutex);
35*4882a593Smuzhiyun 			break;
36*4882a593Smuzhiyun 		}
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 		ccp->sb_avail = 0;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 		mutex_unlock(&ccp->sb_mutex);
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 		/* Wait for KSB entries to become available */
43*4882a593Smuzhiyun 		if (wait_event_interruptible(ccp->sb_queue, ccp->sb_avail))
44*4882a593Smuzhiyun 			return 0;
45*4882a593Smuzhiyun 	}
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	return KSB_START + start;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
ccp_free_ksb(struct ccp_cmd_queue * cmd_q,unsigned int start,unsigned int count)50*4882a593Smuzhiyun static void ccp_free_ksb(struct ccp_cmd_queue *cmd_q, unsigned int start,
51*4882a593Smuzhiyun 			 unsigned int count)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	struct ccp_device *ccp = cmd_q->ccp;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	if (!start)
56*4882a593Smuzhiyun 		return;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	mutex_lock(&ccp->sb_mutex);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	bitmap_clear(ccp->sb, start - KSB_START, count);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	ccp->sb_avail = 1;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	mutex_unlock(&ccp->sb_mutex);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	wake_up_interruptible_all(&ccp->sb_queue);
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun 
ccp_get_free_slots(struct ccp_cmd_queue * cmd_q)69*4882a593Smuzhiyun static unsigned int ccp_get_free_slots(struct ccp_cmd_queue *cmd_q)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	return CMD_Q_DEPTH(ioread32(cmd_q->reg_status));
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
ccp_do_cmd(struct ccp_op * op,u32 * cr,unsigned int cr_count)74*4882a593Smuzhiyun static int ccp_do_cmd(struct ccp_op *op, u32 *cr, unsigned int cr_count)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	struct ccp_cmd_queue *cmd_q = op->cmd_q;
77*4882a593Smuzhiyun 	struct ccp_device *ccp = cmd_q->ccp;
78*4882a593Smuzhiyun 	void __iomem *cr_addr;
79*4882a593Smuzhiyun 	u32 cr0, cmd;
80*4882a593Smuzhiyun 	unsigned int i;
81*4882a593Smuzhiyun 	int ret = 0;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	/* We could read a status register to see how many free slots
84*4882a593Smuzhiyun 	 * are actually available, but reading that register resets it
85*4882a593Smuzhiyun 	 * and you could lose some error information.
86*4882a593Smuzhiyun 	 */
87*4882a593Smuzhiyun 	cmd_q->free_slots--;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	cr0 = (cmd_q->id << REQ0_CMD_Q_SHIFT)
90*4882a593Smuzhiyun 	      | (op->jobid << REQ0_JOBID_SHIFT)
91*4882a593Smuzhiyun 	      | REQ0_WAIT_FOR_WRITE;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (op->soc)
94*4882a593Smuzhiyun 		cr0 |= REQ0_STOP_ON_COMPLETE
95*4882a593Smuzhiyun 		       | REQ0_INT_ON_COMPLETE;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	if (op->ioc || !cmd_q->free_slots)
98*4882a593Smuzhiyun 		cr0 |= REQ0_INT_ON_COMPLETE;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	/* Start at CMD_REQ1 */
101*4882a593Smuzhiyun 	cr_addr = ccp->io_regs + CMD_REQ0 + CMD_REQ_INCR;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	mutex_lock(&ccp->req_mutex);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* Write CMD_REQ1 through CMD_REQx first */
106*4882a593Smuzhiyun 	for (i = 0; i < cr_count; i++, cr_addr += CMD_REQ_INCR)
107*4882a593Smuzhiyun 		iowrite32(*(cr + i), cr_addr);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	/* Tell the CCP to start */
110*4882a593Smuzhiyun 	wmb();
111*4882a593Smuzhiyun 	iowrite32(cr0, ccp->io_regs + CMD_REQ0);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	mutex_unlock(&ccp->req_mutex);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if (cr0 & REQ0_INT_ON_COMPLETE) {
116*4882a593Smuzhiyun 		/* Wait for the job to complete */
117*4882a593Smuzhiyun 		ret = wait_event_interruptible(cmd_q->int_queue,
118*4882a593Smuzhiyun 					       cmd_q->int_rcvd);
119*4882a593Smuzhiyun 		if (ret || cmd_q->cmd_error) {
120*4882a593Smuzhiyun 			/* On error delete all related jobs from the queue */
121*4882a593Smuzhiyun 			cmd = (cmd_q->id << DEL_Q_ID_SHIFT)
122*4882a593Smuzhiyun 			      | op->jobid;
123*4882a593Smuzhiyun 			if (cmd_q->cmd_error)
124*4882a593Smuzhiyun 				ccp_log_error(cmd_q->ccp,
125*4882a593Smuzhiyun 					      cmd_q->cmd_error);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 			iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 			if (!ret)
130*4882a593Smuzhiyun 				ret = -EIO;
131*4882a593Smuzhiyun 		} else if (op->soc) {
132*4882a593Smuzhiyun 			/* Delete just head job from the queue on SoC */
133*4882a593Smuzhiyun 			cmd = DEL_Q_ACTIVE
134*4882a593Smuzhiyun 			      | (cmd_q->id << DEL_Q_ID_SHIFT)
135*4882a593Smuzhiyun 			      | op->jobid;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 			iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB);
138*4882a593Smuzhiyun 		}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 		cmd_q->free_slots = CMD_Q_DEPTH(cmd_q->q_status);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 		cmd_q->int_rcvd = 0;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return ret;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
ccp_perform_aes(struct ccp_op * op)148*4882a593Smuzhiyun static int ccp_perform_aes(struct ccp_op *op)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	u32 cr[6];
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/* Fill out the register contents for REQ1 through REQ6 */
153*4882a593Smuzhiyun 	cr[0] = (CCP_ENGINE_AES << REQ1_ENGINE_SHIFT)
154*4882a593Smuzhiyun 		| (op->u.aes.type << REQ1_AES_TYPE_SHIFT)
155*4882a593Smuzhiyun 		| (op->u.aes.mode << REQ1_AES_MODE_SHIFT)
156*4882a593Smuzhiyun 		| (op->u.aes.action << REQ1_AES_ACTION_SHIFT)
157*4882a593Smuzhiyun 		| (op->sb_key << REQ1_KEY_KSB_SHIFT);
158*4882a593Smuzhiyun 	cr[1] = op->src.u.dma.length - 1;
159*4882a593Smuzhiyun 	cr[2] = ccp_addr_lo(&op->src.u.dma);
160*4882a593Smuzhiyun 	cr[3] = (op->sb_ctx << REQ4_KSB_SHIFT)
161*4882a593Smuzhiyun 		| (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
162*4882a593Smuzhiyun 		| ccp_addr_hi(&op->src.u.dma);
163*4882a593Smuzhiyun 	cr[4] = ccp_addr_lo(&op->dst.u.dma);
164*4882a593Smuzhiyun 	cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
165*4882a593Smuzhiyun 		| ccp_addr_hi(&op->dst.u.dma);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	if (op->u.aes.mode == CCP_AES_MODE_CFB)
168*4882a593Smuzhiyun 		cr[0] |= ((0x7f) << REQ1_AES_CFB_SIZE_SHIFT);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (op->eom)
171*4882a593Smuzhiyun 		cr[0] |= REQ1_EOM;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	if (op->init)
174*4882a593Smuzhiyun 		cr[0] |= REQ1_INIT;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
ccp_perform_xts_aes(struct ccp_op * op)179*4882a593Smuzhiyun static int ccp_perform_xts_aes(struct ccp_op *op)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	u32 cr[6];
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	/* Fill out the register contents for REQ1 through REQ6 */
184*4882a593Smuzhiyun 	cr[0] = (CCP_ENGINE_XTS_AES_128 << REQ1_ENGINE_SHIFT)
185*4882a593Smuzhiyun 		| (op->u.xts.action << REQ1_AES_ACTION_SHIFT)
186*4882a593Smuzhiyun 		| (op->u.xts.unit_size << REQ1_XTS_AES_SIZE_SHIFT)
187*4882a593Smuzhiyun 		| (op->sb_key << REQ1_KEY_KSB_SHIFT);
188*4882a593Smuzhiyun 	cr[1] = op->src.u.dma.length - 1;
189*4882a593Smuzhiyun 	cr[2] = ccp_addr_lo(&op->src.u.dma);
190*4882a593Smuzhiyun 	cr[3] = (op->sb_ctx << REQ4_KSB_SHIFT)
191*4882a593Smuzhiyun 		| (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
192*4882a593Smuzhiyun 		| ccp_addr_hi(&op->src.u.dma);
193*4882a593Smuzhiyun 	cr[4] = ccp_addr_lo(&op->dst.u.dma);
194*4882a593Smuzhiyun 	cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
195*4882a593Smuzhiyun 		| ccp_addr_hi(&op->dst.u.dma);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	if (op->eom)
198*4882a593Smuzhiyun 		cr[0] |= REQ1_EOM;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (op->init)
201*4882a593Smuzhiyun 		cr[0] |= REQ1_INIT;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
ccp_perform_sha(struct ccp_op * op)206*4882a593Smuzhiyun static int ccp_perform_sha(struct ccp_op *op)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	u32 cr[6];
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* Fill out the register contents for REQ1 through REQ6 */
211*4882a593Smuzhiyun 	cr[0] = (CCP_ENGINE_SHA << REQ1_ENGINE_SHIFT)
212*4882a593Smuzhiyun 		| (op->u.sha.type << REQ1_SHA_TYPE_SHIFT)
213*4882a593Smuzhiyun 		| REQ1_INIT;
214*4882a593Smuzhiyun 	cr[1] = op->src.u.dma.length - 1;
215*4882a593Smuzhiyun 	cr[2] = ccp_addr_lo(&op->src.u.dma);
216*4882a593Smuzhiyun 	cr[3] = (op->sb_ctx << REQ4_KSB_SHIFT)
217*4882a593Smuzhiyun 		| (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
218*4882a593Smuzhiyun 		| ccp_addr_hi(&op->src.u.dma);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	if (op->eom) {
221*4882a593Smuzhiyun 		cr[0] |= REQ1_EOM;
222*4882a593Smuzhiyun 		cr[4] = lower_32_bits(op->u.sha.msg_bits);
223*4882a593Smuzhiyun 		cr[5] = upper_32_bits(op->u.sha.msg_bits);
224*4882a593Smuzhiyun 	} else {
225*4882a593Smuzhiyun 		cr[4] = 0;
226*4882a593Smuzhiyun 		cr[5] = 0;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
ccp_perform_rsa(struct ccp_op * op)232*4882a593Smuzhiyun static int ccp_perform_rsa(struct ccp_op *op)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	u32 cr[6];
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	/* Fill out the register contents for REQ1 through REQ6 */
237*4882a593Smuzhiyun 	cr[0] = (CCP_ENGINE_RSA << REQ1_ENGINE_SHIFT)
238*4882a593Smuzhiyun 		| (op->u.rsa.mod_size << REQ1_RSA_MOD_SIZE_SHIFT)
239*4882a593Smuzhiyun 		| (op->sb_key << REQ1_KEY_KSB_SHIFT)
240*4882a593Smuzhiyun 		| REQ1_EOM;
241*4882a593Smuzhiyun 	cr[1] = op->u.rsa.input_len - 1;
242*4882a593Smuzhiyun 	cr[2] = ccp_addr_lo(&op->src.u.dma);
243*4882a593Smuzhiyun 	cr[3] = (op->sb_ctx << REQ4_KSB_SHIFT)
244*4882a593Smuzhiyun 		| (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
245*4882a593Smuzhiyun 		| ccp_addr_hi(&op->src.u.dma);
246*4882a593Smuzhiyun 	cr[4] = ccp_addr_lo(&op->dst.u.dma);
247*4882a593Smuzhiyun 	cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
248*4882a593Smuzhiyun 		| ccp_addr_hi(&op->dst.u.dma);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
ccp_perform_passthru(struct ccp_op * op)253*4882a593Smuzhiyun static int ccp_perform_passthru(struct ccp_op *op)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun 	u32 cr[6];
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	/* Fill out the register contents for REQ1 through REQ6 */
258*4882a593Smuzhiyun 	cr[0] = (CCP_ENGINE_PASSTHRU << REQ1_ENGINE_SHIFT)
259*4882a593Smuzhiyun 		| (op->u.passthru.bit_mod << REQ1_PT_BW_SHIFT)
260*4882a593Smuzhiyun 		| (op->u.passthru.byte_swap << REQ1_PT_BS_SHIFT);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	if (op->src.type == CCP_MEMTYPE_SYSTEM)
263*4882a593Smuzhiyun 		cr[1] = op->src.u.dma.length - 1;
264*4882a593Smuzhiyun 	else
265*4882a593Smuzhiyun 		cr[1] = op->dst.u.dma.length - 1;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (op->src.type == CCP_MEMTYPE_SYSTEM) {
268*4882a593Smuzhiyun 		cr[2] = ccp_addr_lo(&op->src.u.dma);
269*4882a593Smuzhiyun 		cr[3] = (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
270*4882a593Smuzhiyun 			| ccp_addr_hi(&op->src.u.dma);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 		if (op->u.passthru.bit_mod != CCP_PASSTHRU_BITWISE_NOOP)
273*4882a593Smuzhiyun 			cr[3] |= (op->sb_key << REQ4_KSB_SHIFT);
274*4882a593Smuzhiyun 	} else {
275*4882a593Smuzhiyun 		cr[2] = op->src.u.sb * CCP_SB_BYTES;
276*4882a593Smuzhiyun 		cr[3] = (CCP_MEMTYPE_SB << REQ4_MEMTYPE_SHIFT);
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	if (op->dst.type == CCP_MEMTYPE_SYSTEM) {
280*4882a593Smuzhiyun 		cr[4] = ccp_addr_lo(&op->dst.u.dma);
281*4882a593Smuzhiyun 		cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
282*4882a593Smuzhiyun 			| ccp_addr_hi(&op->dst.u.dma);
283*4882a593Smuzhiyun 	} else {
284*4882a593Smuzhiyun 		cr[4] = op->dst.u.sb * CCP_SB_BYTES;
285*4882a593Smuzhiyun 		cr[5] = (CCP_MEMTYPE_SB << REQ6_MEMTYPE_SHIFT);
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	if (op->eom)
289*4882a593Smuzhiyun 		cr[0] |= REQ1_EOM;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
ccp_perform_ecc(struct ccp_op * op)294*4882a593Smuzhiyun static int ccp_perform_ecc(struct ccp_op *op)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	u32 cr[6];
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	/* Fill out the register contents for REQ1 through REQ6 */
299*4882a593Smuzhiyun 	cr[0] = REQ1_ECC_AFFINE_CONVERT
300*4882a593Smuzhiyun 		| (CCP_ENGINE_ECC << REQ1_ENGINE_SHIFT)
301*4882a593Smuzhiyun 		| (op->u.ecc.function << REQ1_ECC_FUNCTION_SHIFT)
302*4882a593Smuzhiyun 		| REQ1_EOM;
303*4882a593Smuzhiyun 	cr[1] = op->src.u.dma.length - 1;
304*4882a593Smuzhiyun 	cr[2] = ccp_addr_lo(&op->src.u.dma);
305*4882a593Smuzhiyun 	cr[3] = (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT)
306*4882a593Smuzhiyun 		| ccp_addr_hi(&op->src.u.dma);
307*4882a593Smuzhiyun 	cr[4] = ccp_addr_lo(&op->dst.u.dma);
308*4882a593Smuzhiyun 	cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT)
309*4882a593Smuzhiyun 		| ccp_addr_hi(&op->dst.u.dma);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	return ccp_do_cmd(op, cr, ARRAY_SIZE(cr));
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
ccp_disable_queue_interrupts(struct ccp_device * ccp)314*4882a593Smuzhiyun static void ccp_disable_queue_interrupts(struct ccp_device *ccp)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun 	iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
ccp_enable_queue_interrupts(struct ccp_device * ccp)319*4882a593Smuzhiyun static void ccp_enable_queue_interrupts(struct ccp_device *ccp)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	iowrite32(ccp->qim, ccp->io_regs + IRQ_MASK_REG);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
ccp_irq_bh(unsigned long data)324*4882a593Smuzhiyun static void ccp_irq_bh(unsigned long data)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	struct ccp_device *ccp = (struct ccp_device *)data;
327*4882a593Smuzhiyun 	struct ccp_cmd_queue *cmd_q;
328*4882a593Smuzhiyun 	u32 q_int, status;
329*4882a593Smuzhiyun 	unsigned int i;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	status = ioread32(ccp->io_regs + IRQ_STATUS_REG);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	for (i = 0; i < ccp->cmd_q_count; i++) {
334*4882a593Smuzhiyun 		cmd_q = &ccp->cmd_q[i];
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 		q_int = status & (cmd_q->int_ok | cmd_q->int_err);
337*4882a593Smuzhiyun 		if (q_int) {
338*4882a593Smuzhiyun 			cmd_q->int_status = status;
339*4882a593Smuzhiyun 			cmd_q->q_status = ioread32(cmd_q->reg_status);
340*4882a593Smuzhiyun 			cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 			/* On error, only save the first error value */
343*4882a593Smuzhiyun 			if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error)
344*4882a593Smuzhiyun 				cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 			cmd_q->int_rcvd = 1;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 			/* Acknowledge the interrupt and wake the kthread */
349*4882a593Smuzhiyun 			iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG);
350*4882a593Smuzhiyun 			wake_up_interruptible(&cmd_q->int_queue);
351*4882a593Smuzhiyun 		}
352*4882a593Smuzhiyun 	}
353*4882a593Smuzhiyun 	ccp_enable_queue_interrupts(ccp);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
ccp_irq_handler(int irq,void * data)356*4882a593Smuzhiyun static irqreturn_t ccp_irq_handler(int irq, void *data)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	struct ccp_device *ccp = (struct ccp_device *)data;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	ccp_disable_queue_interrupts(ccp);
361*4882a593Smuzhiyun 	if (ccp->use_tasklet)
362*4882a593Smuzhiyun 		tasklet_schedule(&ccp->irq_tasklet);
363*4882a593Smuzhiyun 	else
364*4882a593Smuzhiyun 		ccp_irq_bh((unsigned long)ccp);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	return IRQ_HANDLED;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
ccp_init(struct ccp_device * ccp)369*4882a593Smuzhiyun static int ccp_init(struct ccp_device *ccp)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun 	struct device *dev = ccp->dev;
372*4882a593Smuzhiyun 	struct ccp_cmd_queue *cmd_q;
373*4882a593Smuzhiyun 	struct dma_pool *dma_pool;
374*4882a593Smuzhiyun 	char dma_pool_name[MAX_DMAPOOL_NAME_LEN];
375*4882a593Smuzhiyun 	unsigned int qmr, i;
376*4882a593Smuzhiyun 	int ret;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	/* Find available queues */
379*4882a593Smuzhiyun 	ccp->qim = 0;
380*4882a593Smuzhiyun 	qmr = ioread32(ccp->io_regs + Q_MASK_REG);
381*4882a593Smuzhiyun 	for (i = 0; (i < MAX_HW_QUEUES) && (ccp->cmd_q_count < ccp->max_q_count); i++) {
382*4882a593Smuzhiyun 		if (!(qmr & (1 << i)))
383*4882a593Smuzhiyun 			continue;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 		/* Allocate a dma pool for this queue */
386*4882a593Smuzhiyun 		snprintf(dma_pool_name, sizeof(dma_pool_name), "%s_q%d",
387*4882a593Smuzhiyun 			 ccp->name, i);
388*4882a593Smuzhiyun 		dma_pool = dma_pool_create(dma_pool_name, dev,
389*4882a593Smuzhiyun 					   CCP_DMAPOOL_MAX_SIZE,
390*4882a593Smuzhiyun 					   CCP_DMAPOOL_ALIGN, 0);
391*4882a593Smuzhiyun 		if (!dma_pool) {
392*4882a593Smuzhiyun 			dev_err(dev, "unable to allocate dma pool\n");
393*4882a593Smuzhiyun 			ret = -ENOMEM;
394*4882a593Smuzhiyun 			goto e_pool;
395*4882a593Smuzhiyun 		}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 		cmd_q = &ccp->cmd_q[ccp->cmd_q_count];
398*4882a593Smuzhiyun 		ccp->cmd_q_count++;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 		cmd_q->ccp = ccp;
401*4882a593Smuzhiyun 		cmd_q->id = i;
402*4882a593Smuzhiyun 		cmd_q->dma_pool = dma_pool;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 		/* Reserve 2 KSB regions for the queue */
405*4882a593Smuzhiyun 		cmd_q->sb_key = KSB_START + ccp->sb_start++;
406*4882a593Smuzhiyun 		cmd_q->sb_ctx = KSB_START + ccp->sb_start++;
407*4882a593Smuzhiyun 		ccp->sb_count -= 2;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 		/* Preset some register values and masks that are queue
410*4882a593Smuzhiyun 		 * number dependent
411*4882a593Smuzhiyun 		 */
412*4882a593Smuzhiyun 		cmd_q->reg_status = ccp->io_regs + CMD_Q_STATUS_BASE +
413*4882a593Smuzhiyun 				    (CMD_Q_STATUS_INCR * i);
414*4882a593Smuzhiyun 		cmd_q->reg_int_status = ccp->io_regs + CMD_Q_INT_STATUS_BASE +
415*4882a593Smuzhiyun 					(CMD_Q_STATUS_INCR * i);
416*4882a593Smuzhiyun 		cmd_q->int_ok = 1 << (i * 2);
417*4882a593Smuzhiyun 		cmd_q->int_err = 1 << ((i * 2) + 1);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 		cmd_q->free_slots = ccp_get_free_slots(cmd_q);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 		init_waitqueue_head(&cmd_q->int_queue);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 		/* Build queue interrupt mask (two interrupts per queue) */
424*4882a593Smuzhiyun 		ccp->qim |= cmd_q->int_ok | cmd_q->int_err;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun #ifdef CONFIG_ARM64
427*4882a593Smuzhiyun 		/* For arm64 set the recommended queue cache settings */
428*4882a593Smuzhiyun 		iowrite32(ccp->axcache, ccp->io_regs + CMD_Q_CACHE_BASE +
429*4882a593Smuzhiyun 			  (CMD_Q_CACHE_INC * i));
430*4882a593Smuzhiyun #endif
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 		dev_dbg(dev, "queue #%u available\n", i);
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 	if (ccp->cmd_q_count == 0) {
435*4882a593Smuzhiyun 		dev_notice(dev, "no command queues available\n");
436*4882a593Smuzhiyun 		ret = -EIO;
437*4882a593Smuzhiyun 		goto e_pool;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 	dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	/* Disable and clear interrupts until ready */
442*4882a593Smuzhiyun 	ccp_disable_queue_interrupts(ccp);
443*4882a593Smuzhiyun 	for (i = 0; i < ccp->cmd_q_count; i++) {
444*4882a593Smuzhiyun 		cmd_q = &ccp->cmd_q[i];
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 		ioread32(cmd_q->reg_int_status);
447*4882a593Smuzhiyun 		ioread32(cmd_q->reg_status);
448*4882a593Smuzhiyun 	}
449*4882a593Smuzhiyun 	iowrite32(ccp->qim, ccp->io_regs + IRQ_STATUS_REG);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	/* Request an irq */
452*4882a593Smuzhiyun 	ret = sp_request_ccp_irq(ccp->sp, ccp_irq_handler, ccp->name, ccp);
453*4882a593Smuzhiyun 	if (ret) {
454*4882a593Smuzhiyun 		dev_err(dev, "unable to allocate an IRQ\n");
455*4882a593Smuzhiyun 		goto e_pool;
456*4882a593Smuzhiyun 	}
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	/* Initialize the ISR tasklet? */
459*4882a593Smuzhiyun 	if (ccp->use_tasklet)
460*4882a593Smuzhiyun 		tasklet_init(&ccp->irq_tasklet, ccp_irq_bh,
461*4882a593Smuzhiyun 			     (unsigned long)ccp);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	dev_dbg(dev, "Starting threads...\n");
464*4882a593Smuzhiyun 	/* Create a kthread for each queue */
465*4882a593Smuzhiyun 	for (i = 0; i < ccp->cmd_q_count; i++) {
466*4882a593Smuzhiyun 		struct task_struct *kthread;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 		cmd_q = &ccp->cmd_q[i];
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 		kthread = kthread_create(ccp_cmd_queue_thread, cmd_q,
471*4882a593Smuzhiyun 					 "%s-q%u", ccp->name, cmd_q->id);
472*4882a593Smuzhiyun 		if (IS_ERR(kthread)) {
473*4882a593Smuzhiyun 			dev_err(dev, "error creating queue thread (%ld)\n",
474*4882a593Smuzhiyun 				PTR_ERR(kthread));
475*4882a593Smuzhiyun 			ret = PTR_ERR(kthread);
476*4882a593Smuzhiyun 			goto e_kthread;
477*4882a593Smuzhiyun 		}
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 		cmd_q->kthread = kthread;
480*4882a593Smuzhiyun 		wake_up_process(kthread);
481*4882a593Smuzhiyun 	}
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	dev_dbg(dev, "Enabling interrupts...\n");
484*4882a593Smuzhiyun 	/* Enable interrupts */
485*4882a593Smuzhiyun 	ccp_enable_queue_interrupts(ccp);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	dev_dbg(dev, "Registering device...\n");
488*4882a593Smuzhiyun 	ccp_add_device(ccp);
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	ret = ccp_register_rng(ccp);
491*4882a593Smuzhiyun 	if (ret)
492*4882a593Smuzhiyun 		goto e_kthread;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	/* Register the DMA engine support */
495*4882a593Smuzhiyun 	ret = ccp_dmaengine_register(ccp);
496*4882a593Smuzhiyun 	if (ret)
497*4882a593Smuzhiyun 		goto e_hwrng;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	return 0;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun e_hwrng:
502*4882a593Smuzhiyun 	ccp_unregister_rng(ccp);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun e_kthread:
505*4882a593Smuzhiyun 	for (i = 0; i < ccp->cmd_q_count; i++)
506*4882a593Smuzhiyun 		if (ccp->cmd_q[i].kthread)
507*4882a593Smuzhiyun 			kthread_stop(ccp->cmd_q[i].kthread);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	sp_free_ccp_irq(ccp->sp, ccp);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun e_pool:
512*4882a593Smuzhiyun 	for (i = 0; i < ccp->cmd_q_count; i++)
513*4882a593Smuzhiyun 		dma_pool_destroy(ccp->cmd_q[i].dma_pool);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	return ret;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
ccp_destroy(struct ccp_device * ccp)518*4882a593Smuzhiyun static void ccp_destroy(struct ccp_device *ccp)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	struct ccp_cmd_queue *cmd_q;
521*4882a593Smuzhiyun 	struct ccp_cmd *cmd;
522*4882a593Smuzhiyun 	unsigned int i;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	/* Unregister the DMA engine */
525*4882a593Smuzhiyun 	ccp_dmaengine_unregister(ccp);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	/* Unregister the RNG */
528*4882a593Smuzhiyun 	ccp_unregister_rng(ccp);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	/* Remove this device from the list of available units */
531*4882a593Smuzhiyun 	ccp_del_device(ccp);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	/* Disable and clear interrupts */
534*4882a593Smuzhiyun 	ccp_disable_queue_interrupts(ccp);
535*4882a593Smuzhiyun 	for (i = 0; i < ccp->cmd_q_count; i++) {
536*4882a593Smuzhiyun 		cmd_q = &ccp->cmd_q[i];
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 		ioread32(cmd_q->reg_int_status);
539*4882a593Smuzhiyun 		ioread32(cmd_q->reg_status);
540*4882a593Smuzhiyun 	}
541*4882a593Smuzhiyun 	iowrite32(ccp->qim, ccp->io_regs + IRQ_STATUS_REG);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/* Stop the queue kthreads */
544*4882a593Smuzhiyun 	for (i = 0; i < ccp->cmd_q_count; i++)
545*4882a593Smuzhiyun 		if (ccp->cmd_q[i].kthread)
546*4882a593Smuzhiyun 			kthread_stop(ccp->cmd_q[i].kthread);
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	sp_free_ccp_irq(ccp->sp, ccp);
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	for (i = 0; i < ccp->cmd_q_count; i++)
551*4882a593Smuzhiyun 		dma_pool_destroy(ccp->cmd_q[i].dma_pool);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	/* Flush the cmd and backlog queue */
554*4882a593Smuzhiyun 	while (!list_empty(&ccp->cmd)) {
555*4882a593Smuzhiyun 		/* Invoke the callback directly with an error code */
556*4882a593Smuzhiyun 		cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
557*4882a593Smuzhiyun 		list_del(&cmd->entry);
558*4882a593Smuzhiyun 		cmd->callback(cmd->data, -ENODEV);
559*4882a593Smuzhiyun 	}
560*4882a593Smuzhiyun 	while (!list_empty(&ccp->backlog)) {
561*4882a593Smuzhiyun 		/* Invoke the callback directly with an error code */
562*4882a593Smuzhiyun 		cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry);
563*4882a593Smuzhiyun 		list_del(&cmd->entry);
564*4882a593Smuzhiyun 		cmd->callback(cmd->data, -ENODEV);
565*4882a593Smuzhiyun 	}
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun static const struct ccp_actions ccp3_actions = {
569*4882a593Smuzhiyun 	.aes = ccp_perform_aes,
570*4882a593Smuzhiyun 	.xts_aes = ccp_perform_xts_aes,
571*4882a593Smuzhiyun 	.des3 = NULL,
572*4882a593Smuzhiyun 	.sha = ccp_perform_sha,
573*4882a593Smuzhiyun 	.rsa = ccp_perform_rsa,
574*4882a593Smuzhiyun 	.passthru = ccp_perform_passthru,
575*4882a593Smuzhiyun 	.ecc = ccp_perform_ecc,
576*4882a593Smuzhiyun 	.sballoc = ccp_alloc_ksb,
577*4882a593Smuzhiyun 	.sbfree = ccp_free_ksb,
578*4882a593Smuzhiyun 	.init = ccp_init,
579*4882a593Smuzhiyun 	.destroy = ccp_destroy,
580*4882a593Smuzhiyun 	.get_free_slots = ccp_get_free_slots,
581*4882a593Smuzhiyun 	.irqhandler = ccp_irq_handler,
582*4882a593Smuzhiyun };
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun const struct ccp_vdata ccpv3_platform = {
585*4882a593Smuzhiyun 	.version = CCP_VERSION(3, 0),
586*4882a593Smuzhiyun 	.setup = NULL,
587*4882a593Smuzhiyun 	.perform = &ccp3_actions,
588*4882a593Smuzhiyun 	.offset = 0,
589*4882a593Smuzhiyun 	.rsamax = CCP_RSA_MAX_WIDTH,
590*4882a593Smuzhiyun };
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun const struct ccp_vdata ccpv3 = {
593*4882a593Smuzhiyun 	.version = CCP_VERSION(3, 0),
594*4882a593Smuzhiyun 	.setup = NULL,
595*4882a593Smuzhiyun 	.perform = &ccp3_actions,
596*4882a593Smuzhiyun 	.offset = 0x20000,
597*4882a593Smuzhiyun 	.rsamax = CCP_RSA_MAX_WIDTH,
598*4882a593Smuzhiyun };
599