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