1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/kernel.h>
5*4882a593Smuzhiyun #include <linux/nospec.h>
6*4882a593Smuzhiyun #include "cc_driver.h"
7*4882a593Smuzhiyun #include "cc_buffer_mgr.h"
8*4882a593Smuzhiyun #include "cc_request_mgr.h"
9*4882a593Smuzhiyun #include "cc_pm.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define CC_MAX_POLL_ITER 10
12*4882a593Smuzhiyun /* The highest descriptor count in used */
13*4882a593Smuzhiyun #define CC_MAX_DESC_SEQ_LEN 23
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun struct cc_req_mgr_handle {
16*4882a593Smuzhiyun /* Request manager resources */
17*4882a593Smuzhiyun unsigned int hw_queue_size; /* HW capability */
18*4882a593Smuzhiyun unsigned int min_free_hw_slots;
19*4882a593Smuzhiyun unsigned int max_used_sw_slots;
20*4882a593Smuzhiyun struct cc_crypto_req req_queue[MAX_REQUEST_QUEUE_SIZE];
21*4882a593Smuzhiyun u32 req_queue_head;
22*4882a593Smuzhiyun u32 req_queue_tail;
23*4882a593Smuzhiyun u32 axi_completed;
24*4882a593Smuzhiyun u32 q_free_slots;
25*4882a593Smuzhiyun /* This lock protects access to HW register
26*4882a593Smuzhiyun * that must be single request at a time
27*4882a593Smuzhiyun */
28*4882a593Smuzhiyun spinlock_t hw_lock;
29*4882a593Smuzhiyun struct cc_hw_desc compl_desc;
30*4882a593Smuzhiyun u8 *dummy_comp_buff;
31*4882a593Smuzhiyun dma_addr_t dummy_comp_buff_dma;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /* backlog queue */
34*4882a593Smuzhiyun struct list_head backlog;
35*4882a593Smuzhiyun unsigned int bl_len;
36*4882a593Smuzhiyun spinlock_t bl_lock; /* protect backlog queue */
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #ifdef COMP_IN_WQ
39*4882a593Smuzhiyun struct workqueue_struct *workq;
40*4882a593Smuzhiyun struct delayed_work compwork;
41*4882a593Smuzhiyun #else
42*4882a593Smuzhiyun struct tasklet_struct comptask;
43*4882a593Smuzhiyun #endif
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun struct cc_bl_item {
47*4882a593Smuzhiyun struct cc_crypto_req creq;
48*4882a593Smuzhiyun struct cc_hw_desc desc[CC_MAX_DESC_SEQ_LEN];
49*4882a593Smuzhiyun unsigned int len;
50*4882a593Smuzhiyun struct list_head list;
51*4882a593Smuzhiyun bool notif;
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static const u32 cc_cpp_int_masks[CC_CPP_NUM_ALGS][CC_CPP_NUM_SLOTS] = {
55*4882a593Smuzhiyun { BIT(CC_HOST_IRR_REE_OP_ABORTED_AES_0_INT_BIT_SHIFT),
56*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_AES_1_INT_BIT_SHIFT),
57*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_AES_2_INT_BIT_SHIFT),
58*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_AES_3_INT_BIT_SHIFT),
59*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_AES_4_INT_BIT_SHIFT),
60*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_AES_5_INT_BIT_SHIFT),
61*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_AES_6_INT_BIT_SHIFT),
62*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_AES_7_INT_BIT_SHIFT) },
63*4882a593Smuzhiyun { BIT(CC_HOST_IRR_REE_OP_ABORTED_SM_0_INT_BIT_SHIFT),
64*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_SM_1_INT_BIT_SHIFT),
65*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_SM_2_INT_BIT_SHIFT),
66*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_SM_3_INT_BIT_SHIFT),
67*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_SM_4_INT_BIT_SHIFT),
68*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_SM_5_INT_BIT_SHIFT),
69*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_SM_6_INT_BIT_SHIFT),
70*4882a593Smuzhiyun BIT(CC_HOST_IRR_REE_OP_ABORTED_SM_7_INT_BIT_SHIFT) }
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun static void comp_handler(unsigned long devarg);
74*4882a593Smuzhiyun #ifdef COMP_IN_WQ
75*4882a593Smuzhiyun static void comp_work_handler(struct work_struct *work);
76*4882a593Smuzhiyun #endif
77*4882a593Smuzhiyun
cc_cpp_int_mask(enum cc_cpp_alg alg,int slot)78*4882a593Smuzhiyun static inline u32 cc_cpp_int_mask(enum cc_cpp_alg alg, int slot)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun alg = array_index_nospec(alg, CC_CPP_NUM_ALGS);
81*4882a593Smuzhiyun slot = array_index_nospec(slot, CC_CPP_NUM_SLOTS);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun return cc_cpp_int_masks[alg][slot];
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
cc_req_mgr_fini(struct cc_drvdata * drvdata)86*4882a593Smuzhiyun void cc_req_mgr_fini(struct cc_drvdata *drvdata)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
89*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (!req_mgr_h)
92*4882a593Smuzhiyun return; /* Not allocated */
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun if (req_mgr_h->dummy_comp_buff_dma) {
95*4882a593Smuzhiyun dma_free_coherent(dev, sizeof(u32), req_mgr_h->dummy_comp_buff,
96*4882a593Smuzhiyun req_mgr_h->dummy_comp_buff_dma);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun dev_dbg(dev, "max_used_hw_slots=%d\n", (req_mgr_h->hw_queue_size -
100*4882a593Smuzhiyun req_mgr_h->min_free_hw_slots));
101*4882a593Smuzhiyun dev_dbg(dev, "max_used_sw_slots=%d\n", req_mgr_h->max_used_sw_slots);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun #ifdef COMP_IN_WQ
104*4882a593Smuzhiyun flush_workqueue(req_mgr_h->workq);
105*4882a593Smuzhiyun destroy_workqueue(req_mgr_h->workq);
106*4882a593Smuzhiyun #else
107*4882a593Smuzhiyun /* Kill tasklet */
108*4882a593Smuzhiyun tasklet_kill(&req_mgr_h->comptask);
109*4882a593Smuzhiyun #endif
110*4882a593Smuzhiyun kfree_sensitive(req_mgr_h);
111*4882a593Smuzhiyun drvdata->request_mgr_handle = NULL;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
cc_req_mgr_init(struct cc_drvdata * drvdata)114*4882a593Smuzhiyun int cc_req_mgr_init(struct cc_drvdata *drvdata)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun struct cc_req_mgr_handle *req_mgr_h;
117*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
118*4882a593Smuzhiyun int rc = 0;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun req_mgr_h = kzalloc(sizeof(*req_mgr_h), GFP_KERNEL);
121*4882a593Smuzhiyun if (!req_mgr_h) {
122*4882a593Smuzhiyun rc = -ENOMEM;
123*4882a593Smuzhiyun goto req_mgr_init_err;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun drvdata->request_mgr_handle = req_mgr_h;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun spin_lock_init(&req_mgr_h->hw_lock);
129*4882a593Smuzhiyun spin_lock_init(&req_mgr_h->bl_lock);
130*4882a593Smuzhiyun INIT_LIST_HEAD(&req_mgr_h->backlog);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun #ifdef COMP_IN_WQ
133*4882a593Smuzhiyun dev_dbg(dev, "Initializing completion workqueue\n");
134*4882a593Smuzhiyun req_mgr_h->workq = create_singlethread_workqueue("ccree");
135*4882a593Smuzhiyun if (!req_mgr_h->workq) {
136*4882a593Smuzhiyun dev_err(dev, "Failed creating work queue\n");
137*4882a593Smuzhiyun rc = -ENOMEM;
138*4882a593Smuzhiyun goto req_mgr_init_err;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun INIT_DELAYED_WORK(&req_mgr_h->compwork, comp_work_handler);
141*4882a593Smuzhiyun #else
142*4882a593Smuzhiyun dev_dbg(dev, "Initializing completion tasklet\n");
143*4882a593Smuzhiyun tasklet_init(&req_mgr_h->comptask, comp_handler,
144*4882a593Smuzhiyun (unsigned long)drvdata);
145*4882a593Smuzhiyun #endif
146*4882a593Smuzhiyun req_mgr_h->hw_queue_size = cc_ioread(drvdata,
147*4882a593Smuzhiyun CC_REG(DSCRPTR_QUEUE_SRAM_SIZE));
148*4882a593Smuzhiyun dev_dbg(dev, "hw_queue_size=0x%08X\n", req_mgr_h->hw_queue_size);
149*4882a593Smuzhiyun if (req_mgr_h->hw_queue_size < MIN_HW_QUEUE_SIZE) {
150*4882a593Smuzhiyun dev_err(dev, "Invalid HW queue size = %u (Min. required is %u)\n",
151*4882a593Smuzhiyun req_mgr_h->hw_queue_size, MIN_HW_QUEUE_SIZE);
152*4882a593Smuzhiyun rc = -ENOMEM;
153*4882a593Smuzhiyun goto req_mgr_init_err;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun req_mgr_h->min_free_hw_slots = req_mgr_h->hw_queue_size;
156*4882a593Smuzhiyun req_mgr_h->max_used_sw_slots = 0;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* Allocate DMA word for "dummy" completion descriptor use */
159*4882a593Smuzhiyun req_mgr_h->dummy_comp_buff =
160*4882a593Smuzhiyun dma_alloc_coherent(dev, sizeof(u32),
161*4882a593Smuzhiyun &req_mgr_h->dummy_comp_buff_dma,
162*4882a593Smuzhiyun GFP_KERNEL);
163*4882a593Smuzhiyun if (!req_mgr_h->dummy_comp_buff) {
164*4882a593Smuzhiyun dev_err(dev, "Not enough memory to allocate DMA (%zu) dropped buffer\n",
165*4882a593Smuzhiyun sizeof(u32));
166*4882a593Smuzhiyun rc = -ENOMEM;
167*4882a593Smuzhiyun goto req_mgr_init_err;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /* Init. "dummy" completion descriptor */
171*4882a593Smuzhiyun hw_desc_init(&req_mgr_h->compl_desc);
172*4882a593Smuzhiyun set_din_const(&req_mgr_h->compl_desc, 0, sizeof(u32));
173*4882a593Smuzhiyun set_dout_dlli(&req_mgr_h->compl_desc, req_mgr_h->dummy_comp_buff_dma,
174*4882a593Smuzhiyun sizeof(u32), NS_BIT, 1);
175*4882a593Smuzhiyun set_flow_mode(&req_mgr_h->compl_desc, BYPASS);
176*4882a593Smuzhiyun set_queue_last_ind(drvdata, &req_mgr_h->compl_desc);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun return 0;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun req_mgr_init_err:
181*4882a593Smuzhiyun cc_req_mgr_fini(drvdata);
182*4882a593Smuzhiyun return rc;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
enqueue_seq(struct cc_drvdata * drvdata,struct cc_hw_desc seq[],unsigned int seq_len)185*4882a593Smuzhiyun static void enqueue_seq(struct cc_drvdata *drvdata, struct cc_hw_desc seq[],
186*4882a593Smuzhiyun unsigned int seq_len)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun int i, w;
189*4882a593Smuzhiyun void __iomem *reg = drvdata->cc_base + CC_REG(DSCRPTR_QUEUE_WORD0);
190*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /*
193*4882a593Smuzhiyun * We do indeed write all 6 command words to the same
194*4882a593Smuzhiyun * register. The HW supports this.
195*4882a593Smuzhiyun */
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun for (i = 0; i < seq_len; i++) {
198*4882a593Smuzhiyun for (w = 0; w <= 5; w++)
199*4882a593Smuzhiyun writel_relaxed(seq[i].word[w], reg);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun if (cc_dump_desc)
202*4882a593Smuzhiyun dev_dbg(dev, "desc[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n",
203*4882a593Smuzhiyun i, seq[i].word[0], seq[i].word[1],
204*4882a593Smuzhiyun seq[i].word[2], seq[i].word[3],
205*4882a593Smuzhiyun seq[i].word[4], seq[i].word[5]);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /**
210*4882a593Smuzhiyun * request_mgr_complete() - Completion will take place if and only if user
211*4882a593Smuzhiyun * requested completion by cc_send_sync_request().
212*4882a593Smuzhiyun *
213*4882a593Smuzhiyun * @dev: Device pointer
214*4882a593Smuzhiyun * @dx_compl_h: The completion event to signal
215*4882a593Smuzhiyun * @dummy: unused error code
216*4882a593Smuzhiyun */
request_mgr_complete(struct device * dev,void * dx_compl_h,int dummy)217*4882a593Smuzhiyun static void request_mgr_complete(struct device *dev, void *dx_compl_h,
218*4882a593Smuzhiyun int dummy)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct completion *this_compl = dx_compl_h;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun complete(this_compl);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
cc_queues_status(struct cc_drvdata * drvdata,struct cc_req_mgr_handle * req_mgr_h,unsigned int total_seq_len)225*4882a593Smuzhiyun static int cc_queues_status(struct cc_drvdata *drvdata,
226*4882a593Smuzhiyun struct cc_req_mgr_handle *req_mgr_h,
227*4882a593Smuzhiyun unsigned int total_seq_len)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun unsigned long poll_queue;
230*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /* SW queue is checked only once as it will not
233*4882a593Smuzhiyun * be changed during the poll because the spinlock_bh
234*4882a593Smuzhiyun * is held by the thread
235*4882a593Smuzhiyun */
236*4882a593Smuzhiyun if (((req_mgr_h->req_queue_head + 1) & (MAX_REQUEST_QUEUE_SIZE - 1)) ==
237*4882a593Smuzhiyun req_mgr_h->req_queue_tail) {
238*4882a593Smuzhiyun dev_err(dev, "SW FIFO is full. req_queue_head=%d sw_fifo_len=%d\n",
239*4882a593Smuzhiyun req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE);
240*4882a593Smuzhiyun return -ENOSPC;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun if (req_mgr_h->q_free_slots >= total_seq_len)
244*4882a593Smuzhiyun return 0;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* Wait for space in HW queue. Poll constant num of iterations. */
247*4882a593Smuzhiyun for (poll_queue = 0; poll_queue < CC_MAX_POLL_ITER ; poll_queue++) {
248*4882a593Smuzhiyun req_mgr_h->q_free_slots =
249*4882a593Smuzhiyun cc_ioread(drvdata, CC_REG(DSCRPTR_QUEUE_CONTENT));
250*4882a593Smuzhiyun if (req_mgr_h->q_free_slots < req_mgr_h->min_free_hw_slots)
251*4882a593Smuzhiyun req_mgr_h->min_free_hw_slots = req_mgr_h->q_free_slots;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun if (req_mgr_h->q_free_slots >= total_seq_len) {
254*4882a593Smuzhiyun /* If there is enough place return */
255*4882a593Smuzhiyun return 0;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun dev_dbg(dev, "HW FIFO is full. q_free_slots=%d total_seq_len=%d\n",
259*4882a593Smuzhiyun req_mgr_h->q_free_slots, total_seq_len);
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun /* No room in the HW queue try again later */
262*4882a593Smuzhiyun dev_dbg(dev, "HW FIFO full, timeout. req_queue_head=%d sw_fifo_len=%d q_free_slots=%d total_seq_len=%d\n",
263*4882a593Smuzhiyun req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE,
264*4882a593Smuzhiyun req_mgr_h->q_free_slots, total_seq_len);
265*4882a593Smuzhiyun return -ENOSPC;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /**
269*4882a593Smuzhiyun * cc_do_send_request() - Enqueue caller request to crypto hardware.
270*4882a593Smuzhiyun * Need to be called with HW lock held and PM running
271*4882a593Smuzhiyun *
272*4882a593Smuzhiyun * @drvdata: Associated device driver context
273*4882a593Smuzhiyun * @cc_req: The request to enqueue
274*4882a593Smuzhiyun * @desc: The crypto sequence
275*4882a593Smuzhiyun * @len: The crypto sequence length
276*4882a593Smuzhiyun * @add_comp: If "true": add an artificial dout DMA to mark completion
277*4882a593Smuzhiyun *
278*4882a593Smuzhiyun */
cc_do_send_request(struct cc_drvdata * drvdata,struct cc_crypto_req * cc_req,struct cc_hw_desc * desc,unsigned int len,bool add_comp)279*4882a593Smuzhiyun static void cc_do_send_request(struct cc_drvdata *drvdata,
280*4882a593Smuzhiyun struct cc_crypto_req *cc_req,
281*4882a593Smuzhiyun struct cc_hw_desc *desc, unsigned int len,
282*4882a593Smuzhiyun bool add_comp)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
285*4882a593Smuzhiyun unsigned int used_sw_slots;
286*4882a593Smuzhiyun unsigned int total_seq_len = len; /*initial sequence length*/
287*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun used_sw_slots = ((req_mgr_h->req_queue_head -
290*4882a593Smuzhiyun req_mgr_h->req_queue_tail) &
291*4882a593Smuzhiyun (MAX_REQUEST_QUEUE_SIZE - 1));
292*4882a593Smuzhiyun if (used_sw_slots > req_mgr_h->max_used_sw_slots)
293*4882a593Smuzhiyun req_mgr_h->max_used_sw_slots = used_sw_slots;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /* Enqueue request - must be locked with HW lock*/
296*4882a593Smuzhiyun req_mgr_h->req_queue[req_mgr_h->req_queue_head] = *cc_req;
297*4882a593Smuzhiyun req_mgr_h->req_queue_head = (req_mgr_h->req_queue_head + 1) &
298*4882a593Smuzhiyun (MAX_REQUEST_QUEUE_SIZE - 1);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun dev_dbg(dev, "Enqueue request head=%u\n", req_mgr_h->req_queue_head);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /*
303*4882a593Smuzhiyun * We are about to push command to the HW via the command registers
304*4882a593Smuzhiyun * that may reference host memory. We need to issue a memory barrier
305*4882a593Smuzhiyun * to make sure there are no outstanding memory writes
306*4882a593Smuzhiyun */
307*4882a593Smuzhiyun wmb();
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /* STAT_PHASE_4: Push sequence */
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun enqueue_seq(drvdata, desc, len);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (add_comp) {
314*4882a593Smuzhiyun enqueue_seq(drvdata, &req_mgr_h->compl_desc, 1);
315*4882a593Smuzhiyun total_seq_len++;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (req_mgr_h->q_free_slots < total_seq_len) {
319*4882a593Smuzhiyun /* This situation should never occur. Maybe indicating problem
320*4882a593Smuzhiyun * with resuming power. Set the free slot count to 0 and hope
321*4882a593Smuzhiyun * for the best.
322*4882a593Smuzhiyun */
323*4882a593Smuzhiyun dev_err(dev, "HW free slot count mismatch.");
324*4882a593Smuzhiyun req_mgr_h->q_free_slots = 0;
325*4882a593Smuzhiyun } else {
326*4882a593Smuzhiyun /* Update the free slots in HW queue */
327*4882a593Smuzhiyun req_mgr_h->q_free_slots -= total_seq_len;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
cc_enqueue_backlog(struct cc_drvdata * drvdata,struct cc_bl_item * bli)331*4882a593Smuzhiyun static void cc_enqueue_backlog(struct cc_drvdata *drvdata,
332*4882a593Smuzhiyun struct cc_bl_item *bli)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle;
335*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun spin_lock_bh(&mgr->bl_lock);
338*4882a593Smuzhiyun list_add_tail(&bli->list, &mgr->backlog);
339*4882a593Smuzhiyun ++mgr->bl_len;
340*4882a593Smuzhiyun dev_dbg(dev, "+++bl len: %d\n", mgr->bl_len);
341*4882a593Smuzhiyun spin_unlock_bh(&mgr->bl_lock);
342*4882a593Smuzhiyun tasklet_schedule(&mgr->comptask);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
cc_proc_backlog(struct cc_drvdata * drvdata)345*4882a593Smuzhiyun static void cc_proc_backlog(struct cc_drvdata *drvdata)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle;
348*4882a593Smuzhiyun struct cc_bl_item *bli;
349*4882a593Smuzhiyun struct cc_crypto_req *creq;
350*4882a593Smuzhiyun void *req;
351*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
352*4882a593Smuzhiyun int rc;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun spin_lock(&mgr->bl_lock);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun while (mgr->bl_len) {
357*4882a593Smuzhiyun bli = list_first_entry(&mgr->backlog, struct cc_bl_item, list);
358*4882a593Smuzhiyun dev_dbg(dev, "---bl len: %d\n", mgr->bl_len);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun spin_unlock(&mgr->bl_lock);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun creq = &bli->creq;
364*4882a593Smuzhiyun req = creq->user_arg;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /*
367*4882a593Smuzhiyun * Notify the request we're moving out of the backlog
368*4882a593Smuzhiyun * but only if we haven't done so already.
369*4882a593Smuzhiyun */
370*4882a593Smuzhiyun if (!bli->notif) {
371*4882a593Smuzhiyun creq->user_cb(dev, req, -EINPROGRESS);
372*4882a593Smuzhiyun bli->notif = true;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun spin_lock(&mgr->hw_lock);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun rc = cc_queues_status(drvdata, mgr, bli->len);
378*4882a593Smuzhiyun if (rc) {
379*4882a593Smuzhiyun /*
380*4882a593Smuzhiyun * There is still no room in the FIFO for
381*4882a593Smuzhiyun * this request. Bail out. We'll return here
382*4882a593Smuzhiyun * on the next completion irq.
383*4882a593Smuzhiyun */
384*4882a593Smuzhiyun spin_unlock(&mgr->hw_lock);
385*4882a593Smuzhiyun return;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun cc_do_send_request(drvdata, &bli->creq, bli->desc, bli->len,
389*4882a593Smuzhiyun false);
390*4882a593Smuzhiyun spin_unlock(&mgr->hw_lock);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /* Remove ourselves from the backlog list */
393*4882a593Smuzhiyun spin_lock(&mgr->bl_lock);
394*4882a593Smuzhiyun list_del(&bli->list);
395*4882a593Smuzhiyun --mgr->bl_len;
396*4882a593Smuzhiyun kfree(bli);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun spin_unlock(&mgr->bl_lock);
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
cc_send_request(struct cc_drvdata * drvdata,struct cc_crypto_req * cc_req,struct cc_hw_desc * desc,unsigned int len,struct crypto_async_request * req)402*4882a593Smuzhiyun int cc_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req,
403*4882a593Smuzhiyun struct cc_hw_desc *desc, unsigned int len,
404*4882a593Smuzhiyun struct crypto_async_request *req)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun int rc;
407*4882a593Smuzhiyun struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle;
408*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
409*4882a593Smuzhiyun bool backlog_ok = req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG;
410*4882a593Smuzhiyun gfp_t flags = cc_gfp_flags(req);
411*4882a593Smuzhiyun struct cc_bl_item *bli;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun rc = cc_pm_get(dev);
414*4882a593Smuzhiyun if (rc) {
415*4882a593Smuzhiyun dev_err(dev, "cc_pm_get returned %x\n", rc);
416*4882a593Smuzhiyun return rc;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun spin_lock_bh(&mgr->hw_lock);
420*4882a593Smuzhiyun rc = cc_queues_status(drvdata, mgr, len);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun #ifdef CC_DEBUG_FORCE_BACKLOG
423*4882a593Smuzhiyun if (backlog_ok)
424*4882a593Smuzhiyun rc = -ENOSPC;
425*4882a593Smuzhiyun #endif /* CC_DEBUG_FORCE_BACKLOG */
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun if (rc == -ENOSPC && backlog_ok) {
428*4882a593Smuzhiyun spin_unlock_bh(&mgr->hw_lock);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun bli = kmalloc(sizeof(*bli), flags);
431*4882a593Smuzhiyun if (!bli) {
432*4882a593Smuzhiyun cc_pm_put_suspend(dev);
433*4882a593Smuzhiyun return -ENOMEM;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun memcpy(&bli->creq, cc_req, sizeof(*cc_req));
437*4882a593Smuzhiyun memcpy(&bli->desc, desc, len * sizeof(*desc));
438*4882a593Smuzhiyun bli->len = len;
439*4882a593Smuzhiyun bli->notif = false;
440*4882a593Smuzhiyun cc_enqueue_backlog(drvdata, bli);
441*4882a593Smuzhiyun return -EBUSY;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (!rc) {
445*4882a593Smuzhiyun cc_do_send_request(drvdata, cc_req, desc, len, false);
446*4882a593Smuzhiyun rc = -EINPROGRESS;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun spin_unlock_bh(&mgr->hw_lock);
450*4882a593Smuzhiyun return rc;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
cc_send_sync_request(struct cc_drvdata * drvdata,struct cc_crypto_req * cc_req,struct cc_hw_desc * desc,unsigned int len)453*4882a593Smuzhiyun int cc_send_sync_request(struct cc_drvdata *drvdata,
454*4882a593Smuzhiyun struct cc_crypto_req *cc_req, struct cc_hw_desc *desc,
455*4882a593Smuzhiyun unsigned int len)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun int rc;
458*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
459*4882a593Smuzhiyun struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun init_completion(&cc_req->seq_compl);
462*4882a593Smuzhiyun cc_req->user_cb = request_mgr_complete;
463*4882a593Smuzhiyun cc_req->user_arg = &cc_req->seq_compl;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun rc = cc_pm_get(dev);
466*4882a593Smuzhiyun if (rc) {
467*4882a593Smuzhiyun dev_err(dev, "cc_pm_get returned %x\n", rc);
468*4882a593Smuzhiyun return rc;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun while (true) {
472*4882a593Smuzhiyun spin_lock_bh(&mgr->hw_lock);
473*4882a593Smuzhiyun rc = cc_queues_status(drvdata, mgr, len + 1);
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun if (!rc)
476*4882a593Smuzhiyun break;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun spin_unlock_bh(&mgr->hw_lock);
479*4882a593Smuzhiyun wait_for_completion_interruptible(&drvdata->hw_queue_avail);
480*4882a593Smuzhiyun reinit_completion(&drvdata->hw_queue_avail);
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun cc_do_send_request(drvdata, cc_req, desc, len, true);
484*4882a593Smuzhiyun spin_unlock_bh(&mgr->hw_lock);
485*4882a593Smuzhiyun wait_for_completion(&cc_req->seq_compl);
486*4882a593Smuzhiyun return 0;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun /**
490*4882a593Smuzhiyun * send_request_init() - Enqueue caller request to crypto hardware during init
491*4882a593Smuzhiyun * process.
492*4882a593Smuzhiyun * Assume this function is not called in the middle of a flow,
493*4882a593Smuzhiyun * since we set QUEUE_LAST_IND flag in the last descriptor.
494*4882a593Smuzhiyun *
495*4882a593Smuzhiyun * @drvdata: Associated device driver context
496*4882a593Smuzhiyun * @desc: The crypto sequence
497*4882a593Smuzhiyun * @len: The crypto sequence length
498*4882a593Smuzhiyun *
499*4882a593Smuzhiyun * Return:
500*4882a593Smuzhiyun * Returns "0" upon success
501*4882a593Smuzhiyun */
send_request_init(struct cc_drvdata * drvdata,struct cc_hw_desc * desc,unsigned int len)502*4882a593Smuzhiyun int send_request_init(struct cc_drvdata *drvdata, struct cc_hw_desc *desc,
503*4882a593Smuzhiyun unsigned int len)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
506*4882a593Smuzhiyun unsigned int total_seq_len = len; /*initial sequence length*/
507*4882a593Smuzhiyun int rc = 0;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun /* Wait for space in HW and SW FIFO. Poll for as much as FIFO_TIMEOUT.
510*4882a593Smuzhiyun */
511*4882a593Smuzhiyun rc = cc_queues_status(drvdata, req_mgr_h, total_seq_len);
512*4882a593Smuzhiyun if (rc)
513*4882a593Smuzhiyun return rc;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun set_queue_last_ind(drvdata, &desc[(len - 1)]);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun /*
518*4882a593Smuzhiyun * We are about to push command to the HW via the command registers
519*4882a593Smuzhiyun * that may reference host memory. We need to issue a memory barrier
520*4882a593Smuzhiyun * to make sure there are no outstanding memory writes
521*4882a593Smuzhiyun */
522*4882a593Smuzhiyun wmb();
523*4882a593Smuzhiyun enqueue_seq(drvdata, desc, len);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun /* Update the free slots in HW queue */
526*4882a593Smuzhiyun req_mgr_h->q_free_slots =
527*4882a593Smuzhiyun cc_ioread(drvdata, CC_REG(DSCRPTR_QUEUE_CONTENT));
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun return 0;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
complete_request(struct cc_drvdata * drvdata)532*4882a593Smuzhiyun void complete_request(struct cc_drvdata *drvdata)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun struct cc_req_mgr_handle *request_mgr_handle =
535*4882a593Smuzhiyun drvdata->request_mgr_handle;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun complete(&drvdata->hw_queue_avail);
538*4882a593Smuzhiyun #ifdef COMP_IN_WQ
539*4882a593Smuzhiyun queue_delayed_work(request_mgr_handle->workq,
540*4882a593Smuzhiyun &request_mgr_handle->compwork, 0);
541*4882a593Smuzhiyun #else
542*4882a593Smuzhiyun tasklet_schedule(&request_mgr_handle->comptask);
543*4882a593Smuzhiyun #endif
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun #ifdef COMP_IN_WQ
comp_work_handler(struct work_struct * work)547*4882a593Smuzhiyun static void comp_work_handler(struct work_struct *work)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun struct cc_drvdata *drvdata =
550*4882a593Smuzhiyun container_of(work, struct cc_drvdata, compwork.work);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun comp_handler((unsigned long)drvdata);
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun #endif
555*4882a593Smuzhiyun
proc_completions(struct cc_drvdata * drvdata)556*4882a593Smuzhiyun static void proc_completions(struct cc_drvdata *drvdata)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun struct cc_crypto_req *cc_req;
559*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
560*4882a593Smuzhiyun struct cc_req_mgr_handle *request_mgr_handle =
561*4882a593Smuzhiyun drvdata->request_mgr_handle;
562*4882a593Smuzhiyun unsigned int *tail = &request_mgr_handle->req_queue_tail;
563*4882a593Smuzhiyun unsigned int *head = &request_mgr_handle->req_queue_head;
564*4882a593Smuzhiyun int rc;
565*4882a593Smuzhiyun u32 mask;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun while (request_mgr_handle->axi_completed) {
568*4882a593Smuzhiyun request_mgr_handle->axi_completed--;
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun /* Dequeue request */
571*4882a593Smuzhiyun if (*head == *tail) {
572*4882a593Smuzhiyun /* We are supposed to handle a completion but our
573*4882a593Smuzhiyun * queue is empty. This is not normal. Return and
574*4882a593Smuzhiyun * hope for the best.
575*4882a593Smuzhiyun */
576*4882a593Smuzhiyun dev_err(dev, "Request queue is empty head == tail %u\n",
577*4882a593Smuzhiyun *head);
578*4882a593Smuzhiyun break;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun cc_req = &request_mgr_handle->req_queue[*tail];
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun if (cc_req->cpp.is_cpp) {
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun dev_dbg(dev, "CPP request completion slot: %d alg:%d\n",
586*4882a593Smuzhiyun cc_req->cpp.slot, cc_req->cpp.alg);
587*4882a593Smuzhiyun mask = cc_cpp_int_mask(cc_req->cpp.alg,
588*4882a593Smuzhiyun cc_req->cpp.slot);
589*4882a593Smuzhiyun rc = (drvdata->irq & mask ? -EPERM : 0);
590*4882a593Smuzhiyun dev_dbg(dev, "Got mask: %x irq: %x rc: %d\n", mask,
591*4882a593Smuzhiyun drvdata->irq, rc);
592*4882a593Smuzhiyun } else {
593*4882a593Smuzhiyun dev_dbg(dev, "None CPP request completion\n");
594*4882a593Smuzhiyun rc = 0;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (cc_req->user_cb)
598*4882a593Smuzhiyun cc_req->user_cb(dev, cc_req->user_arg, rc);
599*4882a593Smuzhiyun *tail = (*tail + 1) & (MAX_REQUEST_QUEUE_SIZE - 1);
600*4882a593Smuzhiyun dev_dbg(dev, "Dequeue request tail=%u\n", *tail);
601*4882a593Smuzhiyun dev_dbg(dev, "Request completed. axi_completed=%d\n",
602*4882a593Smuzhiyun request_mgr_handle->axi_completed);
603*4882a593Smuzhiyun cc_pm_put_suspend(dev);
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
cc_axi_comp_count(struct cc_drvdata * drvdata)607*4882a593Smuzhiyun static inline u32 cc_axi_comp_count(struct cc_drvdata *drvdata)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun return FIELD_GET(AXIM_MON_COMP_VALUE,
610*4882a593Smuzhiyun cc_ioread(drvdata, drvdata->axim_mon_offset));
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun /* Deferred service handler, run as interrupt-fired tasklet */
comp_handler(unsigned long devarg)614*4882a593Smuzhiyun static void comp_handler(unsigned long devarg)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg;
617*4882a593Smuzhiyun struct cc_req_mgr_handle *request_mgr_handle =
618*4882a593Smuzhiyun drvdata->request_mgr_handle;
619*4882a593Smuzhiyun struct device *dev = drvdata_to_dev(drvdata);
620*4882a593Smuzhiyun u32 irq;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun dev_dbg(dev, "Completion handler called!\n");
623*4882a593Smuzhiyun irq = (drvdata->irq & drvdata->comp_mask);
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun /* To avoid the interrupt from firing as we unmask it,
626*4882a593Smuzhiyun * we clear it now
627*4882a593Smuzhiyun */
628*4882a593Smuzhiyun cc_iowrite(drvdata, CC_REG(HOST_ICR), irq);
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun /* Avoid race with above clear: Test completion counter once more */
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun request_mgr_handle->axi_completed += cc_axi_comp_count(drvdata);
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun dev_dbg(dev, "AXI completion after updated: %d\n",
635*4882a593Smuzhiyun request_mgr_handle->axi_completed);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun while (request_mgr_handle->axi_completed) {
638*4882a593Smuzhiyun do {
639*4882a593Smuzhiyun drvdata->irq |= cc_ioread(drvdata, CC_REG(HOST_IRR));
640*4882a593Smuzhiyun irq = (drvdata->irq & drvdata->comp_mask);
641*4882a593Smuzhiyun proc_completions(drvdata);
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun /* At this point (after proc_completions()),
644*4882a593Smuzhiyun * request_mgr_handle->axi_completed is 0.
645*4882a593Smuzhiyun */
646*4882a593Smuzhiyun request_mgr_handle->axi_completed +=
647*4882a593Smuzhiyun cc_axi_comp_count(drvdata);
648*4882a593Smuzhiyun } while (request_mgr_handle->axi_completed > 0);
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun cc_iowrite(drvdata, CC_REG(HOST_ICR), irq);
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun request_mgr_handle->axi_completed += cc_axi_comp_count(drvdata);
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun /* after verifying that there is nothing to do,
656*4882a593Smuzhiyun * unmask AXI completion interrupt
657*4882a593Smuzhiyun */
658*4882a593Smuzhiyun cc_iowrite(drvdata, CC_REG(HOST_IMR),
659*4882a593Smuzhiyun cc_ioread(drvdata, CC_REG(HOST_IMR)) & ~drvdata->comp_mask);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun cc_proc_backlog(drvdata);
662*4882a593Smuzhiyun dev_dbg(dev, "Comp. handler done.\n");
663*4882a593Smuzhiyun }
664