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