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 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 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 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 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 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 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 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 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 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 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 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 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