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