crypto/caam_jr: add basic job ring routines

This patch adds following job ring routines
 - init_job_ring (configure hw/sw resources)
 - shutdown_job_ring (releases hw/sw resources)
 - close_job_ring (flush job ring)

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>
This commit is contained in:
Gagandeep Singh 2018-10-12 20:10:46 +05:30 committed by Akhil Goyal
parent e7a45f3cc2
commit 1d678de329

View File

@ -17,12 +17,142 @@
#include <rte_security_driver.h>
#include <rte_hexdump.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 <of.h>
#define CRYPTODEV_NAME_CAAM_JR_PMD crypto_caam_jr
static uint8_t cryptodev_driver_id;
int caam_jr_logtype;
enum rta_sec_era rta_sec_era;
/* Lists the states possible for the SEC user space driver. */
enum sec_driver_state_e {
SEC_DRIVER_STATE_IDLE, /* Driver not initialized */
SEC_DRIVER_STATE_STARTED, /* Driver initialized and can be used*/
SEC_DRIVER_STATE_RELEASE, /* Driver release is in progress */
};
/* Job rings used for communication with SEC HW */
static struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS];
/* The current state of SEC user space driver */
static enum sec_driver_state_e g_driver_state = SEC_DRIVER_STATE_IDLE;
/* The number of job rings used by SEC user space driver */
static int g_job_rings_no;
static int g_job_rings_max;
/* @brief Poll the HW for already processed jobs in the JR
* and silently discard the available jobs or notify them to UA
* with indicated error code.
*
* @param [in,out] job_ring The job ring to poll.
* @param [in] do_notify Can be #TRUE or #FALSE. Indicates if
* descriptors are to be discarded
* or notified to UA with given error_code.
* @param [out] notified_descs Number of notified descriptors. Can be NULL
* if do_notify is #FALSE
*/
static void
hw_flush_job_ring(struct sec_job_ring_t *job_ring,
uint32_t do_notify,
uint32_t *notified_descs)
{
int32_t jobs_no_to_discard = 0;
int32_t discarded_descs_no = 0;
PMD_INIT_FUNC_TRACE();
CAAM_JR_DEBUG("Jr[%p] pi[%d] ci[%d].Flushing jr notify desc=[%d]",
job_ring, job_ring->pidx, job_ring->cidx, do_notify);
jobs_no_to_discard = hw_get_no_finished_jobs(job_ring);
/* Discard all jobs */
CAAM_JR_DEBUG("Jr[%p] pi[%d] ci[%d].Discarding %d descs",
job_ring, job_ring->pidx, job_ring->cidx,
jobs_no_to_discard);
while (jobs_no_to_discard > discarded_descs_no) {
discarded_descs_no++;
/* Now increment the consumer index for the current job ring,
* AFTER saving job in temporary location!
* Increment the consumer index for the current job ring
*/
job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx,
SEC_JOB_RING_SIZE);
hw_remove_entries(job_ring, 1);
}
if (do_notify == true) {
ASSERT(notified_descs != NULL);
*notified_descs = discarded_descs_no;
}
}
/* @brief Flush job rings of any processed descs.
* The processed descs are silently dropped,
* WITHOUT being notified to UA.
*/
static void
close_job_ring(struct sec_job_ring_t *job_ring)
{
PMD_INIT_FUNC_TRACE();
if (job_ring->irq_fd) {
/* Producer index is frozen. If consumer index is not equal
* with producer index, then we have descs to flush.
*/
while (job_ring->pidx != job_ring->cidx)
hw_flush_job_ring(job_ring, false, NULL);
/* free the uio job ring */
free_job_ring(job_ring->irq_fd);
job_ring->irq_fd = 0;
caam_jr_dma_free(job_ring->input_ring);
caam_jr_dma_free(job_ring->output_ring);
g_job_rings_no--;
}
}
/** @brief Release the software and hardware resources tied to a job ring.
* @param [in] job_ring The job ring
*
* @retval 0 for success
* @retval -1 for error
*/
static int
shutdown_job_ring(struct sec_job_ring_t *job_ring)
{
int ret = 0;
PMD_INIT_FUNC_TRACE();
ASSERT(job_ring != NULL);
ret = hw_shutdown_job_ring(job_ring);
SEC_ASSERT(ret == 0, ret,
"Failed to shutdown hardware job ring %p",
job_ring);
if (job_ring->coalescing_en)
hw_job_ring_disable_coalescing(job_ring);
if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
ret = caam_jr_disable_irqs(job_ring->irq_fd);
SEC_ASSERT(ret == 0, ret,
"Failed to disable irqs for job ring %p",
job_ring);
}
return ret;
}
/*
* @brief Release the resources used by the SEC user space driver.
*
@ -40,28 +170,195 @@ int caam_jr_logtype;
static int
caam_jr_dev_uninit(struct rte_cryptodev *dev)
{
struct sec_job_ring_t *internals;
PMD_INIT_FUNC_TRACE();
if (dev == NULL)
return -ENODEV;
internals = dev->data->dev_private;
rte_free(dev->security_ctx);
/* If any descriptors in flight , poll and wait
* until all descriptors are received and silently discarded.
*/
if (internals) {
shutdown_job_ring(internals);
close_job_ring(internals);
rte_mempool_free(internals->ctx_pool);
}
CAAM_JR_INFO("Closing crypto device %s", dev->data->name);
return 0;
/* last caam jr instance) */
if (g_job_rings_no == 0)
g_driver_state = SEC_DRIVER_STATE_IDLE;
return SEC_SUCCESS;
}
/* @brief Initialize the software and hardware resources tied to a job ring.
* @param [in] jr_mode; Model to be used by SEC Driver to receive
* notifications from SEC. Can be either
* of the three: #SEC_NOTIFICATION_TYPE_NAPI
* #SEC_NOTIFICATION_TYPE_IRQ or
* #SEC_NOTIFICATION_TYPE_POLL
* @param [in] NAPI_mode The NAPI work mode to configure a job ring at
* startup. Used only when #SEC_NOTIFICATION_TYPE
* is set to #SEC_NOTIFICATION_TYPE_NAPI.
* @param [in] irq_coalescing_timer This value determines the maximum
* amount of time after processing a
* descriptor before raising an interrupt.
* @param [in] irq_coalescing_count This value determines how many
* descriptors are completed before
* raising an interrupt.
* @param [in] reg_base_addr, The job ring base address register
* @param [in] irq_id The job ring interrupt identification number.
* @retval job_ring_handle for successful job ring configuration
* @retval NULL on error
*
*/
static void *
init_job_ring(void *reg_base_addr, uint32_t irq_id)
{
struct sec_job_ring_t *job_ring = NULL;
int i, ret = 0;
int jr_mode = SEC_NOTIFICATION_TYPE_POLL;
int napi_mode = 0;
int irq_coalescing_timer = 0;
int irq_coalescing_count = 0;
for (i = 0; i < MAX_SEC_JOB_RINGS; i++) {
if (g_job_rings[i].irq_fd == 0) {
job_ring = &g_job_rings[i];
g_job_rings_no++;
break;
}
}
if (job_ring == NULL) {
CAAM_JR_ERR("No free job ring\n");
return NULL;
}
job_ring->register_base_addr = reg_base_addr;
job_ring->jr_mode = jr_mode;
job_ring->napi_mode = 0;
job_ring->irq_fd = irq_id;
/* Allocate mem for input and output ring */
/* Allocate memory for input ring */
job_ring->input_ring = caam_jr_dma_mem_alloc(L1_CACHE_BYTES,
SEC_DMA_MEM_INPUT_RING_SIZE);
memset(job_ring->input_ring, 0, SEC_DMA_MEM_INPUT_RING_SIZE);
/* Allocate memory for output ring */
job_ring->output_ring = caam_jr_dma_mem_alloc(L1_CACHE_BYTES,
SEC_DMA_MEM_OUTPUT_RING_SIZE);
memset(job_ring->output_ring, 0, SEC_DMA_MEM_OUTPUT_RING_SIZE);
/* Reset job ring in SEC hw and configure job ring registers */
ret = hw_reset_job_ring(job_ring);
if (ret != 0) {
CAAM_JR_ERR("Failed to reset hardware job ring");
goto cleanup;
}
if (jr_mode == SEC_NOTIFICATION_TYPE_NAPI) {
/* When SEC US driver works in NAPI mode, the UA can select
* if the driver starts with IRQs on or off.
*/
if (napi_mode == SEC_STARTUP_INTERRUPT_MODE) {
CAAM_JR_INFO("Enabling DONE IRQ generationon job ring - %p",
job_ring);
ret = caam_jr_enable_irqs(job_ring->irq_fd);
if (ret != 0) {
CAAM_JR_ERR("Failed to enable irqs for job ring");
goto cleanup;
}
}
} else if (jr_mode == SEC_NOTIFICATION_TYPE_IRQ) {
/* When SEC US driver works in pure interrupt mode,
* IRQ's are always enabled.
*/
CAAM_JR_INFO("Enabling DONE IRQ generation on job ring - %p",
job_ring);
ret = caam_jr_enable_irqs(job_ring->irq_fd);
if (ret != 0) {
CAAM_JR_ERR("Failed to enable irqs for job ring");
goto cleanup;
}
}
if (irq_coalescing_timer || irq_coalescing_count) {
hw_job_ring_set_coalescing_param(job_ring,
irq_coalescing_timer,
irq_coalescing_count);
hw_job_ring_enable_coalescing(job_ring);
job_ring->coalescing_en = 1;
}
job_ring->jr_state = SEC_JOB_RING_STATE_STARTED;
job_ring->max_nb_queue_pairs = RTE_CAAM_MAX_NB_SEC_QPS;
job_ring->max_nb_sessions = RTE_CAAM_JR_PMD_MAX_NB_SESSIONS;
return job_ring;
cleanup:
caam_jr_dma_free(job_ring->output_ring);
caam_jr_dma_free(job_ring->input_ring);
return NULL;
}
static int
caam_jr_dev_init(const char *name,
struct rte_vdev_device *vdev,
struct rte_cryptodev_pmd_init_params *init_params)
{
struct rte_cryptodev *dev;
struct uio_job_ring *job_ring;
char str[RTE_CRYPTODEV_NAME_MAX_LEN];
PMD_INIT_FUNC_TRACE();
/* Validate driver state */
if (g_driver_state == SEC_DRIVER_STATE_IDLE) {
g_job_rings_max = sec_configure();
if (!g_job_rings_max) {
CAAM_JR_ERR("No job ring detected on UIO !!!!");
return -1;
}
/* Update driver state */
g_driver_state = SEC_DRIVER_STATE_STARTED;
}
if (g_job_rings_no >= g_job_rings_max) {
CAAM_JR_ERR("No more job rings available max=%d!!!!",
g_job_rings_max);
return -1;
}
job_ring = config_job_ring();
if (job_ring == NULL) {
CAAM_JR_ERR("failed to create job ring");
goto init_error;
}
snprintf(str, sizeof(str), "caam_jr%d", job_ring->jr_id);
dev = rte_cryptodev_pmd_create(name, &vdev->device, init_params);
if (dev == NULL) {
CAAM_JR_ERR("failed to create cryptodev vdev");
goto cleanup;
}
/*TODO free it during teardown*/
dev->data->dev_private = init_job_ring(job_ring->register_base_addr,
job_ring->uio_fd);
if (!dev->data->dev_private) {
CAAM_JR_ERR("Ring memory allocation failed\n");
goto cleanup2;
}
dev->driver_id = cryptodev_driver_id;
dev->dev_ops = NULL;
@ -79,7 +376,12 @@ caam_jr_dev_init(const char *name,
return 0;
cleanup2:
caam_jr_dev_uninit(dev);
rte_cryptodev_pmd_release_device(dev);
cleanup:
free_job_ring(job_ring->uio_fd);
init_error:
CAAM_JR_ERR("driver %s: cryptodev_caam_jr_create failed",
init_params->name);
@ -92,7 +394,7 @@ cryptodev_caam_jr_probe(struct rte_vdev_device *vdev)
{
struct rte_cryptodev_pmd_init_params init_params = {
"",
128,
sizeof(struct sec_job_ring_t),
rte_socket_id(),
RTE_CRYPTODEV_PMD_DEFAULT_MAX_NB_QUEUE_PAIRS
};
@ -106,6 +408,29 @@ cryptodev_caam_jr_probe(struct rte_vdev_device *vdev)
input_args = rte_vdev_device_args(vdev);
rte_cryptodev_pmd_parse_input_args(&init_params, input_args);
/* if sec device version is not configured */
if (!rta_get_sec_era()) {
const struct device_node *caam_node;
for_each_compatible_node(caam_node, NULL, "fsl,sec-v4.0") {
const uint32_t *prop = of_get_property(caam_node,
"fsl,sec-era",
NULL);
if (prop) {
rta_set_sec_era(
INTL_SEC_ERA(cpu_to_caam32(*prop)));
break;
}
}
}
#ifdef RTE_LIBRTE_PMD_CAAM_JR_BE
if (rta_get_sec_era() > RTA_SEC_ERA_8) {
RTE_LOG(ERR, PMD,
"CAAM is compiled in BE mode for device with sec era > 8???\n");
return -EINVAL;
}
#endif
return caam_jr_dev_init(name, vdev, &init_params);
}