Pankaj Gupta | 95c7eee | 2020-12-09 14:02:39 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2021 NXP |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | * |
| 6 | */ |
| 7 | |
| 8 | #include <assert.h> |
| 9 | #include <errno.h> |
| 10 | #include <stdbool.h> |
| 11 | #include <stdint.h> |
| 12 | #include <stdio.h> |
| 13 | #include <stdlib.h> |
| 14 | |
| 15 | #include <arch_helpers.h> |
| 16 | #include "caam.h" |
| 17 | #include <common/debug.h> |
| 18 | #include "jobdesc.h" |
| 19 | #include "sec_hw_specific.h" |
| 20 | |
| 21 | |
| 22 | /* Job rings used for communication with SEC HW */ |
| 23 | extern struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS]; |
| 24 | |
| 25 | /* The current state of SEC user space driver */ |
| 26 | extern volatile sec_driver_state_t g_driver_state; |
| 27 | |
| 28 | /* The number of job rings used by SEC user space driver */ |
| 29 | extern int g_job_rings_no; |
| 30 | |
| 31 | /* LOCAL FUNCTIONS */ |
| 32 | static inline void hw_set_input_ring_start_addr(struct jobring_regs *regs, |
| 33 | phys_addr_t *start_addr) |
| 34 | { |
| 35 | #if defined(CONFIG_PHYS_64BIT) |
| 36 | sec_out32(®s->irba_h, PHYS_ADDR_HI(start_addr)); |
| 37 | #else |
| 38 | sec_out32(®s->irba_h, 0); |
| 39 | #endif |
| 40 | sec_out32(®s->irba_l, PHYS_ADDR_LO(start_addr)); |
| 41 | } |
| 42 | |
| 43 | static inline void hw_set_output_ring_start_addr(struct jobring_regs *regs, |
| 44 | phys_addr_t *start_addr) |
| 45 | { |
| 46 | #if defined(CONFIG_PHYS_64BIT) |
| 47 | sec_out32(®s->orba_h, PHYS_ADDR_HI(start_addr)); |
| 48 | #else |
| 49 | sec_out32(®s->orba_h, 0); |
| 50 | #endif |
| 51 | sec_out32(®s->orba_l, PHYS_ADDR_LO(start_addr)); |
| 52 | } |
| 53 | |
| 54 | /* ORJR - Output Ring Jobs Removed Register shows how many jobs were |
| 55 | * removed from the Output Ring for processing by software. This is done after |
| 56 | * the software has processed the entries. |
| 57 | */ |
| 58 | static inline void hw_remove_entries(sec_job_ring_t *jr, int num) |
| 59 | { |
| 60 | struct jobring_regs *regs = |
| 61 | (struct jobring_regs *)jr->register_base_addr; |
| 62 | |
| 63 | sec_out32(®s->orjr, num); |
| 64 | } |
| 65 | |
| 66 | /* IRSA - Input Ring Slots Available register holds the number of entries in |
| 67 | * the Job Ring's input ring. Once a job is enqueued, the value returned is |
| 68 | * decremented by the hardware by the number of jobs enqueued. |
| 69 | */ |
| 70 | static inline int hw_get_available_slots(sec_job_ring_t *jr) |
| 71 | { |
| 72 | struct jobring_regs *regs = |
| 73 | (struct jobring_regs *)jr->register_base_addr; |
| 74 | |
| 75 | return sec_in32(®s->irsa); |
| 76 | } |
| 77 | |
| 78 | /* ORSFR - Output Ring Slots Full register holds the number of jobs which were |
| 79 | * processed by the SEC and can be retrieved by the software. Once a job has |
| 80 | * been processed by software, the user will call hw_remove_one_entry in order |
| 81 | * to notify the SEC that the entry was processed |
| 82 | */ |
| 83 | static inline int hw_get_no_finished_jobs(sec_job_ring_t *jr) |
| 84 | { |
| 85 | struct jobring_regs *regs = |
| 86 | (struct jobring_regs *)jr->register_base_addr; |
| 87 | |
| 88 | return sec_in32(®s->orsf); |
| 89 | } |
| 90 | |
| 91 | /* @brief Process Jump Halt Condition related errors |
| 92 | * @param [in] error_code The error code in the descriptor status word |
| 93 | */ |
| 94 | static inline void hw_handle_jmp_halt_cond_err(union hw_error_code error_code) |
| 95 | { |
| 96 | ERROR("JMP %x\n", error_code.error_desc.jmp_halt_cond_src.jmp); |
| 97 | ERROR("Descriptor Index: %d\n", |
| 98 | error_code.error_desc.jmp_halt_cond_src.desc_idx); |
| 99 | ERROR(" Condition %x\n", error_code.error_desc.jmp_halt_cond_src.cond); |
| 100 | } |
| 101 | |
| 102 | /* @brief Process DECO related errors |
| 103 | * @param [in] error_code The error code in the descriptor status word |
| 104 | */ |
| 105 | static inline void hw_handle_deco_err(union hw_error_code error_code) |
| 106 | { |
| 107 | ERROR("JMP %x\n", error_code.error_desc.deco_src.jmp); |
| 108 | ERROR("Descriptor Index: 0x%x", |
| 109 | error_code.error_desc.deco_src.desc_idx); |
| 110 | |
| 111 | switch (error_code.error_desc.deco_src.desc_err) { |
| 112 | case SEC_HW_ERR_DECO_HFN_THRESHOLD: |
| 113 | WARN(" Descriptor completed but exceeds the Threshold"); |
| 114 | break; |
| 115 | default: |
| 116 | ERROR("Error 0x%04x not implemented", |
| 117 | error_code.error_desc.deco_src.desc_err); |
| 118 | break; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | /* @brief Process Jump Halt User Status related errors |
| 123 | * @param [in] error_code The error code in the descriptor status word |
| 124 | */ |
| 125 | static inline void hw_handle_jmp_halt_user_err(union hw_error_code error_code) |
| 126 | { |
| 127 | WARN(" Not implemented"); |
| 128 | } |
| 129 | |
| 130 | /* @brief Process CCB related errors |
| 131 | * @param [in] error_code The error code in the descriptor status word |
| 132 | */ |
| 133 | static inline void hw_handle_ccb_err(union hw_error_code hw_error_code) |
| 134 | { |
| 135 | WARN(" Not implemented"); |
| 136 | } |
| 137 | |
| 138 | /* @brief Process Job Ring related errors |
| 139 | * @param [in] error_code The error code in the descriptor status word |
| 140 | */ |
| 141 | static inline void hw_handle_jr_err(union hw_error_code hw_error_code) |
| 142 | { |
| 143 | WARN(" Not implemented"); |
| 144 | } |
| 145 | |
| 146 | /* GLOBAL FUNCTIONS */ |
| 147 | |
| 148 | int hw_reset_job_ring(sec_job_ring_t *job_ring) |
| 149 | { |
| 150 | int ret = 0; |
| 151 | struct jobring_regs *regs = |
| 152 | (struct jobring_regs *)job_ring->register_base_addr; |
| 153 | |
| 154 | /* First reset the job ring in hw */ |
| 155 | ret = hw_shutdown_job_ring(job_ring); |
| 156 | if (ret != 0) { |
| 157 | ERROR("Failed resetting job ring in hardware"); |
| 158 | return ret; |
| 159 | } |
| 160 | /* In order to have the HW JR in a workable state |
| 161 | *after a reset, I need to re-write the input |
| 162 | * queue size, input start address, output queue |
| 163 | * size and output start address |
| 164 | * Write the JR input queue size to the HW register |
| 165 | */ |
| 166 | sec_out32(®s->irs, SEC_JOB_RING_SIZE); |
| 167 | |
| 168 | /* Write the JR output queue size to the HW register */ |
| 169 | sec_out32(®s->ors, SEC_JOB_RING_SIZE); |
| 170 | |
| 171 | /* Write the JR input queue start address */ |
| 172 | hw_set_input_ring_start_addr(regs, vtop(job_ring->input_ring)); |
| 173 | |
| 174 | /* Write the JR output queue start address */ |
| 175 | hw_set_output_ring_start_addr(regs, vtop(job_ring->output_ring)); |
| 176 | |
| 177 | return 0; |
| 178 | } |
| 179 | |
| 180 | int hw_shutdown_job_ring(sec_job_ring_t *job_ring) |
| 181 | { |
| 182 | struct jobring_regs *regs = |
| 183 | (struct jobring_regs *)job_ring->register_base_addr; |
| 184 | unsigned int timeout = SEC_TIMEOUT; |
| 185 | uint32_t tmp = 0U; |
| 186 | |
| 187 | VERBOSE("Resetting Job ring\n"); |
| 188 | |
| 189 | /* |
| 190 | * Mask interrupts since we are going to poll |
| 191 | * for reset completion status |
| 192 | * Also, at POR, interrupts are ENABLED on a JR, thus |
| 193 | * this is the point where I can disable them without |
| 194 | * changing the code logic too much |
| 195 | */ |
| 196 | |
| 197 | jr_disable_irqs(job_ring); |
| 198 | |
| 199 | /* initiate flush (required prior to reset) */ |
| 200 | sec_out32(®s->jrcr, JR_REG_JRCR_VAL_RESET); |
| 201 | |
| 202 | /* dummy read */ |
| 203 | tmp = sec_in32(®s->jrcr); |
| 204 | |
| 205 | do { |
| 206 | tmp = sec_in32(®s->jrint); |
| 207 | } while (((tmp & JRINT_ERR_HALT_MASK) == |
| 208 | JRINT_ERR_HALT_INPROGRESS) && ((--timeout) != 0U)); |
| 209 | |
| 210 | if ((tmp & JRINT_ERR_HALT_MASK) != JRINT_ERR_HALT_COMPLETE || |
| 211 | timeout == 0U) { |
| 212 | ERROR("Failed to flush hw job ring %x\n %u", tmp, timeout); |
| 213 | /* unmask interrupts */ |
| 214 | if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) { |
| 215 | jr_enable_irqs(job_ring); |
| 216 | } |
| 217 | return -1; |
| 218 | } |
| 219 | /* Initiate reset */ |
| 220 | timeout = SEC_TIMEOUT; |
| 221 | sec_out32(®s->jrcr, JR_REG_JRCR_VAL_RESET); |
| 222 | |
| 223 | do { |
| 224 | tmp = sec_in32(®s->jrcr); |
| 225 | } while (((tmp & JR_REG_JRCR_VAL_RESET) != 0U) && |
| 226 | ((--timeout) != 0U)); |
| 227 | |
| 228 | if (timeout == 0U) { |
| 229 | ERROR("Failed to reset hw job ring\n"); |
| 230 | /* unmask interrupts */ |
| 231 | if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) { |
| 232 | jr_enable_irqs(job_ring); |
| 233 | } |
| 234 | return -1; |
| 235 | } |
| 236 | /* unmask interrupts */ |
| 237 | if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) { |
| 238 | jr_enable_irqs(job_ring); |
| 239 | } |
| 240 | return 0; |
| 241 | |
| 242 | } |
| 243 | |
| 244 | void hw_handle_job_ring_error(sec_job_ring_t *job_ring, uint32_t error_code) |
| 245 | { |
| 246 | union hw_error_code hw_err_code; |
| 247 | |
| 248 | hw_err_code.error = error_code; |
| 249 | |
| 250 | switch (hw_err_code.error_desc.value.ssrc) { |
| 251 | case SEC_HW_ERR_SSRC_NO_SRC: |
| 252 | INFO("No Status Source "); |
| 253 | break; |
| 254 | case SEC_HW_ERR_SSRC_CCB_ERR: |
| 255 | INFO("CCB Status Source"); |
| 256 | hw_handle_ccb_err(hw_err_code); |
| 257 | break; |
| 258 | case SEC_HW_ERR_SSRC_JMP_HALT_U: |
| 259 | INFO("Jump Halt User Status Source"); |
| 260 | hw_handle_jmp_halt_user_err(hw_err_code); |
| 261 | break; |
| 262 | case SEC_HW_ERR_SSRC_DECO: |
| 263 | INFO("DECO Status Source"); |
| 264 | hw_handle_deco_err(hw_err_code); |
| 265 | break; |
| 266 | case SEC_HW_ERR_SSRC_JR: |
| 267 | INFO("Job Ring Status Source"); |
| 268 | hw_handle_jr_err(hw_err_code); |
| 269 | break; |
| 270 | case SEC_HW_ERR_SSRC_JMP_HALT_COND: |
| 271 | INFO("Jump Halt Condition Codes"); |
| 272 | hw_handle_jmp_halt_cond_err(hw_err_code); |
| 273 | break; |
| 274 | default: |
| 275 | INFO("Unknown SSRC"); |
| 276 | break; |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | int hw_job_ring_error(sec_job_ring_t *job_ring) |
| 281 | { |
| 282 | uint32_t jrint_error_code; |
| 283 | struct jobring_regs *regs = |
| 284 | (struct jobring_regs *)job_ring->register_base_addr; |
| 285 | |
| 286 | if (JR_REG_JRINT_JRE_EXTRACT(sec_in32(®s->jrint)) == 0) { |
| 287 | return 0; |
| 288 | } |
| 289 | |
| 290 | jrint_error_code = |
| 291 | JR_REG_JRINT_ERR_TYPE_EXTRACT(sec_in32(®s->jrint)); |
| 292 | switch (jrint_error_code) { |
| 293 | case JRINT_ERR_WRITE_STATUS: |
| 294 | ERROR("Error writing status to Output Ring "); |
| 295 | break; |
| 296 | case JRINT_ERR_BAD_INPUT_BASE: |
| 297 | ERROR("Bad Input Ring Base (not on a 4-byte boundary)\n"); |
| 298 | break; |
| 299 | case JRINT_ERR_BAD_OUTPUT_BASE: |
| 300 | ERROR("Bad Output Ring Base (not on a 4-byte boundary)\n"); |
| 301 | break; |
| 302 | case JRINT_ERR_WRITE_2_IRBA: |
| 303 | ERROR("Invalid write to Input Ring Base Address Register\n"); |
| 304 | break; |
| 305 | case JRINT_ERR_WRITE_2_ORBA: |
| 306 | ERROR("Invalid write to Output Ring Base Address Register\n"); |
| 307 | break; |
| 308 | case JRINT_ERR_RES_B4_HALT: |
| 309 | ERROR("Job Ring released before Job Ring is halted\n"); |
| 310 | break; |
| 311 | case JRINT_ERR_REM_TOO_MANY: |
| 312 | ERROR("Removed too many jobs from job ring\n"); |
| 313 | break; |
| 314 | case JRINT_ERR_ADD_TOO_MANY: |
| 315 | ERROR("Added too many jobs on job ring\n"); |
| 316 | break; |
| 317 | default: |
| 318 | ERROR("Unknown SEC JR Error :%d\n", jrint_error_code); |
| 319 | break; |
| 320 | } |
| 321 | return jrint_error_code; |
| 322 | } |
| 323 | |
| 324 | int hw_job_ring_set_coalescing_param(sec_job_ring_t *job_ring, |
| 325 | uint16_t irq_coalescing_timer, |
| 326 | uint8_t irq_coalescing_count) |
| 327 | { |
| 328 | uint32_t reg_val = 0U; |
| 329 | struct jobring_regs *regs = |
| 330 | (struct jobring_regs *)job_ring->register_base_addr; |
| 331 | |
| 332 | /* Set descriptor count coalescing */ |
| 333 | reg_val |= (irq_coalescing_count << JR_REG_JRCFG_LO_ICDCT_SHIFT); |
| 334 | |
| 335 | /* Set coalescing timer value */ |
| 336 | reg_val |= (irq_coalescing_timer << JR_REG_JRCFG_LO_ICTT_SHIFT); |
| 337 | |
| 338 | /* Update parameters in HW */ |
| 339 | sec_out32(®s->jrcfg1, reg_val); |
| 340 | |
| 341 | VERBOSE("Set coalescing params on jr\n"); |
| 342 | |
| 343 | return 0; |
| 344 | } |
| 345 | |
| 346 | int hw_job_ring_enable_coalescing(sec_job_ring_t *job_ring) |
| 347 | { |
| 348 | uint32_t reg_val = 0U; |
| 349 | struct jobring_regs *regs = |
| 350 | (struct jobring_regs *)job_ring->register_base_addr; |
| 351 | |
| 352 | /* Get the current value of the register */ |
| 353 | reg_val = sec_in32(®s->jrcfg1); |
| 354 | |
| 355 | /* Enable coalescing */ |
| 356 | reg_val |= JR_REG_JRCFG_LO_ICEN_EN; |
| 357 | |
| 358 | /* Write in hw */ |
| 359 | sec_out32(®s->jrcfg1, reg_val); |
| 360 | |
| 361 | VERBOSE("Enabled coalescing on jr\n"); |
| 362 | |
| 363 | return 0; |
| 364 | } |
| 365 | |
| 366 | int hw_job_ring_disable_coalescing(sec_job_ring_t *job_ring) |
| 367 | { |
| 368 | uint32_t reg_val = 0U; |
| 369 | struct jobring_regs *regs = |
| 370 | (struct jobring_regs *)job_ring->register_base_addr; |
| 371 | |
| 372 | /* Get the current value of the register */ |
| 373 | reg_val = sec_in32(®s->jrcfg1); |
| 374 | |
| 375 | /* Disable coalescing */ |
| 376 | reg_val &= ~JR_REG_JRCFG_LO_ICEN_EN; |
| 377 | |
| 378 | /* Write in hw */ |
| 379 | sec_out32(®s->jrcfg1, reg_val); |
| 380 | |
| 381 | VERBOSE("Disabled coalescing on jr"); |
| 382 | |
| 383 | return 0; |
| 384 | |
| 385 | } |
| 386 | |
| 387 | void hw_flush_job_ring(struct sec_job_ring_t *job_ring, |
| 388 | uint32_t do_notify, |
| 389 | uint32_t error_code, uint32_t *notified_descs) |
| 390 | { |
| 391 | int32_t jobs_no_to_discard = 0; |
| 392 | int32_t discarded_descs_no = 0; |
| 393 | int32_t number_of_jobs_available = 0; |
| 394 | |
| 395 | VERBOSE("JR pi[%d]i ci[%d]\n", job_ring->pidx, job_ring->cidx); |
| 396 | VERBOSE("error code %x\n", error_code); |
| 397 | VERBOSE("Notify_desc = %d\n", do_notify); |
| 398 | |
| 399 | number_of_jobs_available = hw_get_no_finished_jobs(job_ring); |
| 400 | |
| 401 | /* Discard all jobs */ |
| 402 | jobs_no_to_discard = number_of_jobs_available; |
| 403 | |
| 404 | VERBOSE("JR pi[%d]i ci[%d]\n", job_ring->pidx, job_ring->cidx); |
| 405 | VERBOSE("Discarding desc = %d\n", jobs_no_to_discard); |
| 406 | |
| 407 | while (jobs_no_to_discard > discarded_descs_no) { |
| 408 | discarded_descs_no++; |
| 409 | /* Now increment the consumer index for the current job ring, |
| 410 | * AFTER saving job in temporary location! |
| 411 | * Increment the consumer index for the current job ring |
| 412 | */ |
| 413 | |
| 414 | job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx, |
| 415 | SEC_JOB_RING_SIZE); |
| 416 | |
| 417 | hw_remove_entries(job_ring, 1); |
| 418 | } |
| 419 | |
| 420 | if (do_notify == true) { |
| 421 | if (notified_descs == NULL) { |
| 422 | return; |
| 423 | } |
| 424 | *notified_descs = discarded_descs_no; |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | /* return >0 in case of success |
| 429 | * -1 in case of error from SEC block |
| 430 | * 0 in case job not yet processed by SEC |
| 431 | * or Descriptor returned is NULL after dequeue |
| 432 | */ |
| 433 | int hw_poll_job_ring(struct sec_job_ring_t *job_ring, int32_t limit) |
| 434 | { |
| 435 | int32_t jobs_no_to_notify = 0; |
| 436 | int32_t number_of_jobs_available = 0; |
| 437 | int32_t notified_descs_no = 0; |
| 438 | uint32_t error_descs_no = 0U; |
| 439 | uint32_t sec_error_code = 0U; |
| 440 | uint32_t do_driver_shutdown = false; |
| 441 | phys_addr_t *fnptr, *arg_addr; |
| 442 | user_callback usercall = NULL; |
| 443 | uint8_t *current_desc; |
| 444 | void *arg; |
| 445 | uintptr_t current_desc_addr; |
| 446 | phys_addr_t current_desc_loc; |
| 447 | |
| 448 | #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2) |
| 449 | inv_dcache_range((uintptr_t)job_ring->register_base_addr, sizeof(struct jobring_regs)); |
| 450 | dmbsy(); |
| 451 | #endif |
| 452 | |
| 453 | /* check here if any JR error that cannot be written |
| 454 | * in the output status word has occurred |
| 455 | */ |
| 456 | sec_error_code = hw_job_ring_error(job_ring); |
| 457 | if (unlikely(sec_error_code) != 0) { |
| 458 | ERROR("Error here itself %x\n", sec_error_code); |
| 459 | return -1; |
| 460 | } |
| 461 | /* Compute the number of notifications that need to be raised to UA |
| 462 | * If limit < 0 -> notify all done jobs |
| 463 | * If limit > total number of done jobs -> notify all done jobs |
| 464 | * If limit = 0 -> error |
| 465 | * If limit > 0 && limit < total number of done jobs -> notify a number |
| 466 | * of done jobs equal with limit |
| 467 | */ |
| 468 | |
| 469 | /*compute the number of jobs available in the job ring based on the |
| 470 | * producer and consumer index values. |
| 471 | */ |
| 472 | |
| 473 | number_of_jobs_available = hw_get_no_finished_jobs(job_ring); |
| 474 | jobs_no_to_notify = (limit < 0 || limit > number_of_jobs_available) ? |
| 475 | number_of_jobs_available : limit; |
| 476 | VERBOSE("JR - pi %d, ci %d, ", job_ring->pidx, job_ring->cidx); |
| 477 | VERBOSE("Jobs submitted %d", number_of_jobs_available); |
| 478 | VERBOSE("Jobs to notify %d\n", jobs_no_to_notify); |
| 479 | |
| 480 | while (jobs_no_to_notify > notified_descs_no) { |
| 481 | |
| 482 | #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2) |
| 483 | inv_dcache_range( |
| 484 | (uintptr_t)(&job_ring->output_ring[job_ring->cidx]), |
| 485 | sizeof(struct sec_outring_entry)); |
| 486 | dmbsy(); |
| 487 | #endif |
| 488 | |
| 489 | /* Get job status here */ |
| 490 | sec_error_code = |
| 491 | sec_in32(&(job_ring->output_ring[job_ring->cidx].status)); |
| 492 | |
| 493 | /* Get completed descriptor |
| 494 | */ |
| 495 | current_desc_loc = (uintptr_t) |
| 496 | &job_ring->output_ring[job_ring->cidx].desc; |
| 497 | current_desc_addr = sec_read_addr(current_desc_loc); |
| 498 | |
| 499 | current_desc = ptov((phys_addr_t *) current_desc_addr); |
| 500 | if (current_desc == 0) { |
| 501 | ERROR("No descriptor returned from SEC"); |
| 502 | assert(current_desc); |
| 503 | return 0; |
| 504 | } |
| 505 | /* now increment the consumer index for the current job ring, |
| 506 | * AFTER saving job in temporary location! |
| 507 | */ |
| 508 | job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx, |
| 509 | SEC_JOB_RING_SIZE); |
| 510 | |
| 511 | if (sec_error_code != 0) { |
| 512 | ERROR("desc at cidx %d\n ", job_ring->cidx); |
| 513 | ERROR("generated error %x\n", sec_error_code); |
| 514 | |
| 515 | sec_handle_desc_error(job_ring, |
| 516 | sec_error_code, |
| 517 | &error_descs_no, |
| 518 | &do_driver_shutdown); |
| 519 | hw_remove_entries(job_ring, 1); |
| 520 | |
| 521 | return -1; |
| 522 | } |
| 523 | /* Signal that the job has been processed & the slot is free */ |
| 524 | hw_remove_entries(job_ring, 1); |
| 525 | notified_descs_no++; |
| 526 | |
| 527 | arg_addr = (phys_addr_t *) (current_desc + |
| 528 | (MAX_DESC_SIZE_WORDS * sizeof(uint32_t))); |
| 529 | |
| 530 | fnptr = (phys_addr_t *) (current_desc + |
| 531 | (MAX_DESC_SIZE_WORDS * sizeof(uint32_t) |
| 532 | + sizeof(void *))); |
| 533 | |
| 534 | arg = (void *)*(arg_addr); |
| 535 | if (*fnptr != 0) { |
| 536 | VERBOSE("Callback Function called\n"); |
| 537 | usercall = (user_callback) *(fnptr); |
| 538 | (*usercall) ((uint32_t *) current_desc, |
| 539 | sec_error_code, arg, job_ring); |
| 540 | } |
| 541 | } |
| 542 | |
| 543 | return notified_descs_no; |
| 544 | } |
| 545 | |
| 546 | void sec_handle_desc_error(sec_job_ring_t *job_ring, |
| 547 | uint32_t sec_error_code, |
| 548 | uint32_t *notified_descs, |
| 549 | uint32_t *do_driver_shutdown) |
| 550 | { |
| 551 | /* Analyze the SEC error on this job ring */ |
| 552 | hw_handle_job_ring_error(job_ring, sec_error_code); |
| 553 | } |
| 554 | |
| 555 | void flush_job_rings(void) |
| 556 | { |
| 557 | struct sec_job_ring_t *job_ring = NULL; |
| 558 | int i = 0; |
| 559 | |
| 560 | for (i = 0; i < g_job_rings_no; i++) { |
| 561 | job_ring = &g_job_rings[i]; |
| 562 | /* Producer index is frozen. If consumer index is not equal |
| 563 | * with producer index, then we have descs to flush. |
| 564 | */ |
| 565 | while (job_ring->pidx != job_ring->cidx) { |
| 566 | hw_flush_job_ring(job_ring, false, 0, /* no error */ |
| 567 | NULL); |
| 568 | } |
| 569 | } |
| 570 | } |
| 571 | |
| 572 | int shutdown_job_ring(struct sec_job_ring_t *job_ring) |
| 573 | { |
| 574 | int ret = 0; |
| 575 | |
| 576 | ret = hw_shutdown_job_ring(job_ring); |
| 577 | if (ret != 0) { |
| 578 | ERROR("Failed to shutdown hardware job ring\n"); |
| 579 | return ret; |
| 580 | } |
| 581 | |
| 582 | if (job_ring->coalescing_en != 0) { |
| 583 | hw_job_ring_disable_coalescing(job_ring); |
| 584 | } |
| 585 | |
| 586 | if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) { |
| 587 | ret = jr_disable_irqs(job_ring); |
| 588 | if (ret != 0) { |
| 589 | ERROR("Failed to disable irqs for job ring"); |
| 590 | return ret; |
| 591 | } |
| 592 | } |
| 593 | |
| 594 | return 0; |
| 595 | } |
| 596 | |
| 597 | int jr_enable_irqs(struct sec_job_ring_t *job_ring) |
| 598 | { |
| 599 | uint32_t reg_val = 0U; |
| 600 | struct jobring_regs *regs = |
| 601 | (struct jobring_regs *)job_ring->register_base_addr; |
| 602 | |
| 603 | /* Get the current value of the register */ |
| 604 | reg_val = sec_in32(®s->jrcfg1); |
| 605 | |
| 606 | /* Enable interrupts by disabling interrupt masking*/ |
| 607 | reg_val &= ~JR_REG_JRCFG_LO_IMSK_EN; |
| 608 | |
| 609 | /* Update parameters in HW */ |
| 610 | sec_out32(®s->jrcfg1, reg_val); |
| 611 | |
| 612 | VERBOSE("Enable interrupts on JR\n"); |
| 613 | |
| 614 | return 0; |
| 615 | } |
| 616 | |
| 617 | int jr_disable_irqs(struct sec_job_ring_t *job_ring) |
| 618 | { |
| 619 | uint32_t reg_val = 0U; |
| 620 | struct jobring_regs *regs = |
| 621 | (struct jobring_regs *)job_ring->register_base_addr; |
| 622 | |
| 623 | /* Get the current value of the register */ |
| 624 | reg_val = sec_in32(®s->jrcfg1); |
| 625 | |
| 626 | /* Disable interrupts by enabling interrupt masking*/ |
| 627 | reg_val |= JR_REG_JRCFG_LO_IMSK_EN; |
| 628 | |
| 629 | /* Update parameters in HW */ |
| 630 | sec_out32(®s->jrcfg1, reg_val); |
| 631 | |
| 632 | VERBOSE("Disable interrupts on JR\n"); |
| 633 | |
| 634 | return 0; |
| 635 | } |