New upstream version 18.11-rc1
[deb_dpdk.git] / drivers / crypto / caam_jr / caam_jr_hw.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017-2018 NXP
3  */
4
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <inttypes.h>
8 #include <rte_common.h>
9 #include <rte_memory.h>
10 #include <rte_malloc.h>
11 #include <rte_crypto.h>
12 #include <rte_security.h>
13
14 #include <caam_jr_config.h>
15 #include <caam_jr_hw_specific.h>
16 #include <caam_jr_pvt.h>
17 #include <caam_jr_log.h>
18
19 /* RTA header files */
20 #include <hw/desc/common.h>
21 #include <hw/desc/algo.h>
22 #include <hw/desc/ipsec.h>
23
24 /* Used to retry resetting a job ring in SEC hardware. */
25 #define SEC_TIMEOUT 100000
26
27 /* @brief Process Jump Halt Condition related errors
28  *
29  * @param [in]  error_code        The error code in the descriptor status word
30  */
31 static inline void
32 hw_handle_jmp_halt_cond_err(union hw_error_code error_code)
33 {
34         CAAM_JR_DEBUG("JMP: %d, Descriptor Index: 0x%x, Condition: 0x%x",
35                         error_code.error_desc.jmp_halt_cond_src.jmp,
36                         error_code.error_desc.jmp_halt_cond_src.desc_idx,
37                         error_code.error_desc.jmp_halt_cond_src.cond);
38         (void)error_code;
39 }
40
41 /* @brief Process DECO related errors
42  *
43  * @param [in]  error_code        The error code in the descriptor status word
44  */
45 static inline void
46 hw_handle_deco_err(union hw_error_code error_code)
47 {
48         CAAM_JR_DEBUG("JMP: %d, Descriptor Index: 0x%x",
49                         error_code.error_desc.deco_src.jmp,
50                         error_code.error_desc.deco_src.desc_idx);
51
52         switch (error_code.error_desc.deco_src.desc_err) {
53         case SEC_HW_ERR_DECO_HFN_THRESHOLD:
54                 CAAM_JR_DEBUG(" Warning: Descriptor completed normally,"
55                         "but 3GPP HFN matches or exceeds the Threshold ");
56                 break;
57         default:
58                 CAAM_JR_DEBUG("Error 0x%04x not implemented",
59                                 error_code.error_desc.deco_src.desc_err);
60                 break;
61         }
62 }
63
64 /* @brief Process  Jump Halt User Status related errors
65  *
66  * @param [in]  error_code        The error code in the descriptor status word
67  */
68 static inline void
69 hw_handle_jmp_halt_user_err(union hw_error_code error_code __rte_unused)
70 {
71         CAAM_JR_DEBUG(" Not implemented");
72 }
73
74 /* @brief Process CCB related errors
75  *
76  * @param [in]  error_code        The error code in the descriptor status word
77  */
78 static inline void
79 hw_handle_ccb_err(union hw_error_code hw_error_code __rte_unused)
80 {
81         CAAM_JR_DEBUG(" Not implemented");
82 }
83
84 /* @brief Process Job Ring related errors
85  *
86  * @param [in]  error_code        The error code in the descriptor status word
87  */
88 static inline void
89 hw_handle_jr_err(union hw_error_code hw_error_code __rte_unused)
90 {
91         CAAM_JR_DEBUG(" Not implemented");
92 }
93
94 int
95 hw_reset_job_ring(struct sec_job_ring_t *job_ring)
96 {
97         int ret = 0;
98
99         ASSERT(job_ring->register_base_addr != NULL);
100
101         /* First reset the job ring in hw */
102         ret = hw_shutdown_job_ring(job_ring);
103         SEC_ASSERT(ret == 0, ret, "Failed resetting job ring in hardware");
104
105         /* In order to have the HW JR in a workable state
106          * after a reset, I need to re-write the input
107          * queue size, input start address, output queue
108          * size and output start address
109          */
110         /* Write the JR input queue size to the HW register */
111         hw_set_input_ring_size(job_ring, SEC_JOB_RING_SIZE);
112
113         /* Write the JR output queue size to the HW register */
114         hw_set_output_ring_size(job_ring, SEC_JOB_RING_SIZE);
115
116         /* Write the JR input queue start address */
117         hw_set_input_ring_start_addr(job_ring,
118                         caam_jr_dma_vtop(job_ring->input_ring));
119         CAAM_JR_DEBUG(" Set input ring base address to : Virtual: 0x%" PRIx64
120                       ",Physical: 0x%" PRIx64 ", Read from HW: 0x%" PRIx64,
121                       (uint64_t)(uintptr_t)job_ring->input_ring,
122                       caam_jr_dma_vtop(job_ring->input_ring),
123                       hw_get_inp_queue_base(job_ring));
124
125         /* Write the JR output queue start address */
126         hw_set_output_ring_start_addr(job_ring,
127                         caam_jr_dma_vtop(job_ring->output_ring));
128         CAAM_JR_DEBUG(" Set output ring base address to: Virtual: 0x%" PRIx64
129                       ",Physical: 0x%" PRIx64 ", Read from HW: 0x%" PRIx64,
130                       (uint64_t)(uintptr_t)job_ring->output_ring,
131                       caam_jr_dma_vtop(job_ring->output_ring),
132                       hw_get_out_queue_base(job_ring));
133         return ret;
134 }
135
136 int
137 hw_shutdown_job_ring(struct sec_job_ring_t *job_ring)
138 {
139         unsigned int timeout = SEC_TIMEOUT;
140         uint32_t tmp = 0;
141         int usleep_interval = 10;
142
143         if (job_ring->register_base_addr == NULL) {
144                 CAAM_JR_ERR("Jr[%p] has reg base addr as NULL.driver not init",
145                         job_ring);
146                 return 0;
147         }
148
149         CAAM_JR_INFO("Resetting Job ring %p", job_ring);
150
151         /*
152          * Mask interrupts since we are going to poll
153          * for reset completion status
154          * Also, at POR, interrupts are ENABLED on a JR, thus
155          * this is the point where I can disable them without
156          * changing the code logic too much
157          */
158         caam_jr_disable_irqs(job_ring->irq_fd);
159
160         /* initiate flush (required prior to reset) */
161         SET_JR_REG(JRCR, job_ring, JR_REG_JRCR_VAL_RESET);
162
163         /* dummy read */
164         tmp = GET_JR_REG(JRCR, job_ring);
165
166         do {
167                 tmp = GET_JR_REG(JRINT, job_ring);
168                 usleep(usleep_interval);
169         } while (((tmp & JRINT_ERR_HALT_MASK) ==
170                         JRINT_ERR_HALT_INPROGRESS) && --timeout);
171
172         CAAM_JR_INFO("JRINT is %x", tmp);
173         if ((tmp & JRINT_ERR_HALT_MASK) != JRINT_ERR_HALT_COMPLETE ||
174                 timeout == 0) {
175                 CAAM_JR_ERR("0x%x, %d", tmp, timeout);
176                 /* unmask interrupts */
177                 if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL)
178                         caam_jr_enable_irqs(job_ring->irq_fd);
179                 return -1;
180         }
181
182         /* Initiate reset */
183         timeout = SEC_TIMEOUT;
184         SET_JR_REG(JRCR, job_ring, JR_REG_JRCR_VAL_RESET);
185
186         do {
187                 tmp = GET_JR_REG(JRCR, job_ring);
188                 usleep(usleep_interval);
189         } while ((tmp & JR_REG_JRCR_VAL_RESET) && --timeout);
190
191         CAAM_JR_DEBUG("JRCR is %x", tmp);
192         if (timeout == 0) {
193                 CAAM_JR_ERR("Failed to reset hw job ring %p", job_ring);
194                 /* unmask interrupts */
195                 if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL)
196                         caam_jr_enable_irqs(job_ring->irq_fd);
197                 return -1;
198         }
199         /* unmask interrupts */
200         if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL)
201                 caam_jr_enable_irqs(job_ring->irq_fd);
202         return 0;
203
204 }
205
206 void
207 hw_handle_job_ring_error(struct sec_job_ring_t *job_ring __rte_unused,
208                          uint32_t error_code)
209 {
210         union hw_error_code hw_err_code;
211
212         hw_err_code.error = error_code;
213         switch (hw_err_code.error_desc.value.ssrc) {
214         case SEC_HW_ERR_SSRC_NO_SRC:
215                 ASSERT(hw_err_code.error_desc.no_status_src.res == 0);
216                 CAAM_JR_ERR("No Status Source ");
217                 break;
218         case SEC_HW_ERR_SSRC_CCB_ERR:
219                 CAAM_JR_ERR("CCB Status Source");
220                 hw_handle_ccb_err(hw_err_code);
221                 break;
222         case SEC_HW_ERR_SSRC_JMP_HALT_U:
223                 CAAM_JR_ERR("Jump Halt User Status Source");
224                 hw_handle_jmp_halt_user_err(hw_err_code);
225                 break;
226         case SEC_HW_ERR_SSRC_DECO:
227                 CAAM_JR_ERR("DECO Status Source");
228                 hw_handle_deco_err(hw_err_code);
229                 break;
230         case SEC_HW_ERR_SSRC_JR:
231                 CAAM_JR_ERR("Job Ring Status Source");
232                 hw_handle_jr_err(hw_err_code);
233                 break;
234         case SEC_HW_ERR_SSRC_JMP_HALT_COND:
235                 CAAM_JR_ERR("Jump Halt Condition Codes");
236                 hw_handle_jmp_halt_cond_err(hw_err_code);
237                 break;
238         default:
239                 ASSERT(0);
240                 CAAM_JR_ERR("Unknown SSRC");
241                 break;
242         }
243 }
244
245 void
246 hw_job_ring_error_print(struct sec_job_ring_t *job_ring, int code)
247 {
248         switch (code) {
249         case JRINT_ERR_WRITE_STATUS:
250                 CAAM_JR_ERR("Error writing status to Output Ring ");
251                 break;
252         case JRINT_ERR_BAD_INPUT_BASE:
253                 CAAM_JR_ERR(
254                 "Bad Input Ring Base (%p) (not on a 4-byte boundary) ",
255                 (void *)job_ring);
256                 break;
257         case JRINT_ERR_BAD_OUTPUT_BASE:
258                 CAAM_JR_ERR(
259                 "Bad Output Ring Base (%p) (not on a 4-byte boundary) ",
260                 (void *)job_ring);
261                 break;
262         case JRINT_ERR_WRITE_2_IRBA:
263                 CAAM_JR_ERR(
264                 "Invalid write to Input Ring Base Address Register ");
265                 break;
266         case JRINT_ERR_WRITE_2_ORBA:
267                 CAAM_JR_ERR(
268                 "Invalid write to Output Ring Base Address Register ");
269                 break;
270         case JRINT_ERR_RES_B4_HALT:
271                 CAAM_JR_ERR(
272                 "Job Ring [%p] released before Job Ring is halted",
273                 (void *)job_ring);
274                 break;
275         case JRINT_ERR_REM_TOO_MANY:
276                 CAAM_JR_ERR("Removed too many jobs from job ring [%p]",
277                         (void *)job_ring);
278                 break;
279         case JRINT_ERR_ADD_TOO_MANY:
280                 CAAM_JR_ERR("Added too many jobs on job ring [%p]", job_ring);
281                 break;
282         default:
283                 CAAM_JR_ERR(" Unknown SEC JR Error :%d",
284                                 code);
285                 break;
286         }
287 }
288
289 int
290 hw_job_ring_set_coalescing_param(struct sec_job_ring_t *job_ring,
291                                  uint16_t irq_coalescing_timer,
292                                  uint8_t irq_coalescing_count)
293 {
294         uint32_t reg_val = 0;
295
296         ASSERT(job_ring != NULL);
297         if (job_ring->register_base_addr == NULL) {
298                 CAAM_JR_ERR("Jr[%p] has reg base addr as NULL.driver not init",
299                         job_ring);
300                 return -1;
301         }
302         /* Set descriptor count coalescing */
303         reg_val |= (irq_coalescing_count << JR_REG_JRCFG_LO_ICDCT_SHIFT);
304
305         /* Set coalescing timer value */
306         reg_val |= (irq_coalescing_timer << JR_REG_JRCFG_LO_ICTT_SHIFT);
307
308         /* Update parameters in HW */
309         SET_JR_REG_LO(JRCFG, job_ring, reg_val);
310         CAAM_JR_DEBUG("Set coalescing params on jr %p timer:%d, desc count: %d",
311                         job_ring, irq_coalescing_timer, irq_coalescing_timer);
312
313         return 0;
314 }
315
316 int
317 hw_job_ring_enable_coalescing(struct sec_job_ring_t *job_ring)
318 {
319         uint32_t reg_val = 0;
320
321         ASSERT(job_ring != NULL);
322         if (job_ring->register_base_addr == NULL) {
323                 CAAM_JR_ERR("Jr[%p] has reg base addr as NULL.driver not init",
324                         job_ring);
325                 return -1;
326         }
327
328         /* Get the current value of the register */
329         reg_val = GET_JR_REG_LO(JRCFG, job_ring);
330
331         /* Enable coalescing */
332         reg_val |= JR_REG_JRCFG_LO_ICEN_EN;
333
334         /* Write in hw */
335         SET_JR_REG_LO(JRCFG, job_ring, reg_val);
336
337         CAAM_JR_DEBUG("Enabled coalescing on jr %p ",
338                         job_ring);
339
340         return 0;
341 }
342
343 int
344 hw_job_ring_disable_coalescing(struct sec_job_ring_t *job_ring)
345 {
346         uint32_t reg_val = 0;
347
348         ASSERT(job_ring != NULL);
349
350         if (job_ring->register_base_addr == NULL) {
351                 CAAM_JR_ERR("Jr[%p] has reg base addr as NULL.driver not init",
352                         job_ring);
353                 return -1;
354         }
355
356         /* Get the current value of the register */
357         reg_val = GET_JR_REG_LO(JRCFG, job_ring);
358
359         /* Disable coalescing */
360         reg_val &= ~JR_REG_JRCFG_LO_ICEN_EN;
361
362         /* Write in hw */
363         SET_JR_REG_LO(JRCFG, job_ring, reg_val);
364         CAAM_JR_DEBUG("Disabled coalescing on jr %p ", job_ring);
365
366         return 0;
367 }