e7a45f3cc2
caam_jr need support from kernel caam driver for job ring initialisation. So to access register space for job ring and allow re configure and map to userspace UIO interface is used. This also allows to handle the caam interrupts from the user space. This patch adds UIO specific operations Signed-off-by: Gagandeep Singh <g.singh@nxp.com> Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com> Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
368 lines
9.6 KiB
C
368 lines
9.6 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright 2017-2018 NXP
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <inttypes.h>
|
|
#include <rte_common.h>
|
|
#include <rte_memory.h>
|
|
#include <rte_malloc.h>
|
|
#include <rte_crypto.h>
|
|
#include <rte_security.h>
|
|
|
|
#include <caam_jr_config.h>
|
|
#include <caam_jr_hw_specific.h>
|
|
#include <caam_jr_pvt.h>
|
|
#include <caam_jr_log.h>
|
|
|
|
/* RTA header files */
|
|
#include <hw/desc/common.h>
|
|
#include <hw/desc/algo.h>
|
|
#include <hw/desc/ipsec.h>
|
|
|
|
/* Used to retry resetting a job ring in SEC hardware. */
|
|
#define SEC_TIMEOUT 100000
|
|
|
|
/* @brief Process Jump Halt Condition related errors
|
|
*
|
|
* @param [in] error_code The error code in the descriptor status word
|
|
*/
|
|
static inline void
|
|
hw_handle_jmp_halt_cond_err(union hw_error_code error_code)
|
|
{
|
|
CAAM_JR_DEBUG("JMP: %d, Descriptor Index: 0x%x, Condition: 0x%x",
|
|
error_code.error_desc.jmp_halt_cond_src.jmp,
|
|
error_code.error_desc.jmp_halt_cond_src.desc_idx,
|
|
error_code.error_desc.jmp_halt_cond_src.cond);
|
|
(void)error_code;
|
|
}
|
|
|
|
/* @brief Process DECO related errors
|
|
*
|
|
* @param [in] error_code The error code in the descriptor status word
|
|
*/
|
|
static inline void
|
|
hw_handle_deco_err(union hw_error_code error_code)
|
|
{
|
|
CAAM_JR_DEBUG("JMP: %d, Descriptor Index: 0x%x",
|
|
error_code.error_desc.deco_src.jmp,
|
|
error_code.error_desc.deco_src.desc_idx);
|
|
|
|
switch (error_code.error_desc.deco_src.desc_err) {
|
|
case SEC_HW_ERR_DECO_HFN_THRESHOLD:
|
|
CAAM_JR_DEBUG(" Warning: Descriptor completed normally,"
|
|
"but 3GPP HFN matches or exceeds the Threshold ");
|
|
break;
|
|
default:
|
|
CAAM_JR_DEBUG("Error 0x%04x not implemented",
|
|
error_code.error_desc.deco_src.desc_err);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* @brief Process Jump Halt User Status related errors
|
|
*
|
|
* @param [in] error_code The error code in the descriptor status word
|
|
*/
|
|
static inline void
|
|
hw_handle_jmp_halt_user_err(union hw_error_code error_code __rte_unused)
|
|
{
|
|
CAAM_JR_DEBUG(" Not implemented");
|
|
}
|
|
|
|
/* @brief Process CCB related errors
|
|
*
|
|
* @param [in] error_code The error code in the descriptor status word
|
|
*/
|
|
static inline void
|
|
hw_handle_ccb_err(union hw_error_code hw_error_code __rte_unused)
|
|
{
|
|
CAAM_JR_DEBUG(" Not implemented");
|
|
}
|
|
|
|
/* @brief Process Job Ring related errors
|
|
*
|
|
* @param [in] error_code The error code in the descriptor status word
|
|
*/
|
|
static inline void
|
|
hw_handle_jr_err(union hw_error_code hw_error_code __rte_unused)
|
|
{
|
|
CAAM_JR_DEBUG(" Not implemented");
|
|
}
|
|
|
|
int
|
|
hw_reset_job_ring(struct sec_job_ring_t *job_ring)
|
|
{
|
|
int ret = 0;
|
|
|
|
ASSERT(job_ring->register_base_addr != NULL);
|
|
|
|
/* First reset the job ring in hw */
|
|
ret = hw_shutdown_job_ring(job_ring);
|
|
SEC_ASSERT(ret == 0, ret, "Failed resetting job ring in hardware");
|
|
|
|
/* In order to have the HW JR in a workable state
|
|
* after a reset, I need to re-write the input
|
|
* queue size, input start address, output queue
|
|
* size and output start address
|
|
*/
|
|
/* Write the JR input queue size to the HW register */
|
|
hw_set_input_ring_size(job_ring, SEC_JOB_RING_SIZE);
|
|
|
|
/* Write the JR output queue size to the HW register */
|
|
hw_set_output_ring_size(job_ring, SEC_JOB_RING_SIZE);
|
|
|
|
/* Write the JR input queue start address */
|
|
hw_set_input_ring_start_addr(job_ring,
|
|
caam_jr_dma_vtop(job_ring->input_ring));
|
|
CAAM_JR_DEBUG(" Set input ring base address to : Virtual: 0x%" PRIx64
|
|
",Physical: 0x%" PRIx64 ", Read from HW: 0x%" PRIx64,
|
|
(uint64_t)(uintptr_t)job_ring->input_ring,
|
|
caam_jr_dma_vtop(job_ring->input_ring),
|
|
hw_get_inp_queue_base(job_ring));
|
|
|
|
/* Write the JR output queue start address */
|
|
hw_set_output_ring_start_addr(job_ring,
|
|
caam_jr_dma_vtop(job_ring->output_ring));
|
|
CAAM_JR_DEBUG(" Set output ring base address to: Virtual: 0x%" PRIx64
|
|
",Physical: 0x%" PRIx64 ", Read from HW: 0x%" PRIx64,
|
|
(uint64_t)(uintptr_t)job_ring->output_ring,
|
|
caam_jr_dma_vtop(job_ring->output_ring),
|
|
hw_get_out_queue_base(job_ring));
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
hw_shutdown_job_ring(struct sec_job_ring_t *job_ring)
|
|
{
|
|
unsigned int timeout = SEC_TIMEOUT;
|
|
uint32_t tmp = 0;
|
|
int usleep_interval = 10;
|
|
|
|
if (job_ring->register_base_addr == NULL) {
|
|
CAAM_JR_ERR("Jr[%p] has reg base addr as NULL.driver not init",
|
|
job_ring);
|
|
return 0;
|
|
}
|
|
|
|
CAAM_JR_INFO("Resetting Job ring %p", job_ring);
|
|
|
|
/*
|
|
* Mask interrupts since we are going to poll
|
|
* for reset completion status
|
|
* Also, at POR, interrupts are ENABLED on a JR, thus
|
|
* this is the point where I can disable them without
|
|
* changing the code logic too much
|
|
*/
|
|
caam_jr_disable_irqs(job_ring->irq_fd);
|
|
|
|
/* initiate flush (required prior to reset) */
|
|
SET_JR_REG(JRCR, job_ring, JR_REG_JRCR_VAL_RESET);
|
|
|
|
/* dummy read */
|
|
tmp = GET_JR_REG(JRCR, job_ring);
|
|
|
|
do {
|
|
tmp = GET_JR_REG(JRINT, job_ring);
|
|
usleep(usleep_interval);
|
|
} while (((tmp & JRINT_ERR_HALT_MASK) ==
|
|
JRINT_ERR_HALT_INPROGRESS) && --timeout);
|
|
|
|
CAAM_JR_INFO("JRINT is %x", tmp);
|
|
if ((tmp & JRINT_ERR_HALT_MASK) != JRINT_ERR_HALT_COMPLETE ||
|
|
timeout == 0) {
|
|
CAAM_JR_ERR("0x%x, %d", tmp, timeout);
|
|
/* unmask interrupts */
|
|
if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL)
|
|
caam_jr_enable_irqs(job_ring->irq_fd);
|
|
return -1;
|
|
}
|
|
|
|
/* Initiate reset */
|
|
timeout = SEC_TIMEOUT;
|
|
SET_JR_REG(JRCR, job_ring, JR_REG_JRCR_VAL_RESET);
|
|
|
|
do {
|
|
tmp = GET_JR_REG(JRCR, job_ring);
|
|
usleep(usleep_interval);
|
|
} while ((tmp & JR_REG_JRCR_VAL_RESET) && --timeout);
|
|
|
|
CAAM_JR_DEBUG("JRCR is %x", tmp);
|
|
if (timeout == 0) {
|
|
CAAM_JR_ERR("Failed to reset hw job ring %p", job_ring);
|
|
/* unmask interrupts */
|
|
if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL)
|
|
caam_jr_enable_irqs(job_ring->irq_fd);
|
|
return -1;
|
|
}
|
|
/* unmask interrupts */
|
|
if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL)
|
|
caam_jr_enable_irqs(job_ring->irq_fd);
|
|
return 0;
|
|
|
|
}
|
|
|
|
void
|
|
hw_handle_job_ring_error(struct sec_job_ring_t *job_ring __rte_unused,
|
|
uint32_t error_code)
|
|
{
|
|
union hw_error_code hw_err_code;
|
|
|
|
hw_err_code.error = error_code;
|
|
switch (hw_err_code.error_desc.value.ssrc) {
|
|
case SEC_HW_ERR_SSRC_NO_SRC:
|
|
ASSERT(hw_err_code.error_desc.no_status_src.res == 0);
|
|
CAAM_JR_ERR("No Status Source ");
|
|
break;
|
|
case SEC_HW_ERR_SSRC_CCB_ERR:
|
|
CAAM_JR_ERR("CCB Status Source");
|
|
hw_handle_ccb_err(hw_err_code);
|
|
break;
|
|
case SEC_HW_ERR_SSRC_JMP_HALT_U:
|
|
CAAM_JR_ERR("Jump Halt User Status Source");
|
|
hw_handle_jmp_halt_user_err(hw_err_code);
|
|
break;
|
|
case SEC_HW_ERR_SSRC_DECO:
|
|
CAAM_JR_ERR("DECO Status Source");
|
|
hw_handle_deco_err(hw_err_code);
|
|
break;
|
|
case SEC_HW_ERR_SSRC_JR:
|
|
CAAM_JR_ERR("Job Ring Status Source");
|
|
hw_handle_jr_err(hw_err_code);
|
|
break;
|
|
case SEC_HW_ERR_SSRC_JMP_HALT_COND:
|
|
CAAM_JR_ERR("Jump Halt Condition Codes");
|
|
hw_handle_jmp_halt_cond_err(hw_err_code);
|
|
break;
|
|
default:
|
|
ASSERT(0);
|
|
CAAM_JR_ERR("Unknown SSRC");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
hw_job_ring_error_print(struct sec_job_ring_t *job_ring, int code)
|
|
{
|
|
switch (code) {
|
|
case JRINT_ERR_WRITE_STATUS:
|
|
CAAM_JR_ERR("Error writing status to Output Ring ");
|
|
break;
|
|
case JRINT_ERR_BAD_INPUT_BASE:
|
|
CAAM_JR_ERR(
|
|
"Bad Input Ring Base (%p) (not on a 4-byte boundary) ",
|
|
(void *)job_ring);
|
|
break;
|
|
case JRINT_ERR_BAD_OUTPUT_BASE:
|
|
CAAM_JR_ERR(
|
|
"Bad Output Ring Base (%p) (not on a 4-byte boundary) ",
|
|
(void *)job_ring);
|
|
break;
|
|
case JRINT_ERR_WRITE_2_IRBA:
|
|
CAAM_JR_ERR(
|
|
"Invalid write to Input Ring Base Address Register ");
|
|
break;
|
|
case JRINT_ERR_WRITE_2_ORBA:
|
|
CAAM_JR_ERR(
|
|
"Invalid write to Output Ring Base Address Register ");
|
|
break;
|
|
case JRINT_ERR_RES_B4_HALT:
|
|
CAAM_JR_ERR(
|
|
"Job Ring [%p] released before Job Ring is halted",
|
|
(void *)job_ring);
|
|
break;
|
|
case JRINT_ERR_REM_TOO_MANY:
|
|
CAAM_JR_ERR("Removed too many jobs from job ring [%p]",
|
|
(void *)job_ring);
|
|
break;
|
|
case JRINT_ERR_ADD_TOO_MANY:
|
|
CAAM_JR_ERR("Added too many jobs on job ring [%p]", job_ring);
|
|
break;
|
|
default:
|
|
CAAM_JR_ERR(" Unknown SEC JR Error :%d",
|
|
code);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
hw_job_ring_set_coalescing_param(struct sec_job_ring_t *job_ring,
|
|
uint16_t irq_coalescing_timer,
|
|
uint8_t irq_coalescing_count)
|
|
{
|
|
uint32_t reg_val = 0;
|
|
|
|
ASSERT(job_ring != NULL);
|
|
if (job_ring->register_base_addr == NULL) {
|
|
CAAM_JR_ERR("Jr[%p] has reg base addr as NULL.driver not init",
|
|
job_ring);
|
|
return -1;
|
|
}
|
|
/* Set descriptor count coalescing */
|
|
reg_val |= (irq_coalescing_count << JR_REG_JRCFG_LO_ICDCT_SHIFT);
|
|
|
|
/* Set coalescing timer value */
|
|
reg_val |= (irq_coalescing_timer << JR_REG_JRCFG_LO_ICTT_SHIFT);
|
|
|
|
/* Update parameters in HW */
|
|
SET_JR_REG_LO(JRCFG, job_ring, reg_val);
|
|
CAAM_JR_DEBUG("Set coalescing params on jr %p timer:%d, desc count: %d",
|
|
job_ring, irq_coalescing_timer, irq_coalescing_timer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
hw_job_ring_enable_coalescing(struct sec_job_ring_t *job_ring)
|
|
{
|
|
uint32_t reg_val = 0;
|
|
|
|
ASSERT(job_ring != NULL);
|
|
if (job_ring->register_base_addr == NULL) {
|
|
CAAM_JR_ERR("Jr[%p] has reg base addr as NULL.driver not init",
|
|
job_ring);
|
|
return -1;
|
|
}
|
|
|
|
/* Get the current value of the register */
|
|
reg_val = GET_JR_REG_LO(JRCFG, job_ring);
|
|
|
|
/* Enable coalescing */
|
|
reg_val |= JR_REG_JRCFG_LO_ICEN_EN;
|
|
|
|
/* Write in hw */
|
|
SET_JR_REG_LO(JRCFG, job_ring, reg_val);
|
|
|
|
CAAM_JR_DEBUG("Enabled coalescing on jr %p ",
|
|
job_ring);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
hw_job_ring_disable_coalescing(struct sec_job_ring_t *job_ring)
|
|
{
|
|
uint32_t reg_val = 0;
|
|
|
|
ASSERT(job_ring != NULL);
|
|
|
|
if (job_ring->register_base_addr == NULL) {
|
|
CAAM_JR_ERR("Jr[%p] has reg base addr as NULL.driver not init",
|
|
job_ring);
|
|
return -1;
|
|
}
|
|
|
|
/* Get the current value of the register */
|
|
reg_val = GET_JR_REG_LO(JRCFG, job_ring);
|
|
|
|
/* Disable coalescing */
|
|
reg_val &= ~JR_REG_JRCFG_LO_ICEN_EN;
|
|
|
|
/* Write in hw */
|
|
SET_JR_REG_LO(JRCFG, job_ring, reg_val);
|
|
CAAM_JR_DEBUG("Disabled coalescing on jr %p ", job_ring);
|
|
|
|
return 0;
|
|
}
|