diff --git a/sys/arm64/conf/std.nxp b/sys/arm64/conf/std.nxp --- a/sys/arm64/conf/std.nxp +++ b/sys/arm64/conf/std.nxp @@ -25,6 +25,9 @@ device dpaa2 # Data Path Acceleration Architecture (2nd Gen) device enetc # QorIQ LS1028A NIC +# SEC4/CAAM cypto coprocessor +device caam + # SFF/SFP device sff # Small Form Factor Transceivers diff --git a/sys/arm64/qoriq/caam/caam.h b/sys/arm64/qoriq/caam/caam.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/caam.h @@ -0,0 +1,99 @@ +/* + * Copyright 2017-2021 NXP + * Copyright 2023 Alstom Group + * Copyright 2023 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef CAAM_H +#define CAAM_H + +#include +#include + +#include "jr/caam_jr.h" + +/* + * If CAAM_JR_MODE_ASYNC is defined: + * - Jobrings will initialize in SEC_NOTIFICATION_TYPE_IRQ mode + * - Use caam_run_descriptor_jr_async() to enqueue jobs + * - jobdesc should have a callback set + * - callback should set job_arg status and JR_JOB_ARG_SIG_DONE + * - callers may wait for completion using JR_JOB_ARG_WAIT_DONE + * + * else: + * - Jobrings will initialize in SEC_NOTIFICATION_TYPE_POLL mode + * - Use caam_run_descriptor_jr_blocking() to enqueue jobs and wait for + * completion + * + * Both caam_run_descriptor_jr_async and caam_run_descriptor_jr_blocking are + * available at runtime but it's callers responsibility to reinitialize jobring + * in an appropriate mode and ensure the jobring is not used in a previous mode + * anymore. + */ +#define CAAM_JR_MODE_ASYNC 1 + +/* The hardware max Scatter-Gather entries */ +#define MAX_SGT_ENTRIES 32 + +/* These functions manage external data that need to be passed to/from DMA */ + +/* + * @brief Read common caam register. + * + * @param [in] dev caam device handle + * @param [in] reg register offset + * + * @retval :: uint32_t register value + */ +uint32_t caam_reg_read(device_t dev, uint32_t reg); + +/* + * @brief Write common caam register. + * + * @param [in] dev caam device handle + * @param [in] reg register offset + * @param [in] val value to write + */ +void caam_reg_write(device_t dev, uint32_t reg, uint32_t val); + +#if defined(CAAM_JR_MODE_ASYNC) +/* + * @brief Submit a job for execution, non-blocking. + * + * To control completion and status use completion callback with + * caam_jr::struct jr_job_arg + * + * Selected jobring must be started in SEC_NOTIFICATION_TYPE_IRQ mode + * + * @param [in] dev caam device handle + * @param [in] jobdesc job descriptor + * @param [in] jr_dev optional handle for a jobring device to use, get with + * jr_pool_acquire + * + * @retval :: 0 is returned on success + * @retval :: errno is returned on failure + */ +int caam_run_descriptor_jr_async(device_t dev, struct job_descriptor *jobdesc, + device_t jr_dev); +#endif + +/* + * @brief Submit a job for execution, will poll for job completion. + * + * Selected jobring must be started in SEC_NOTIFICATION_TYPE_POLL mode + * + * @param [in] dev caam device handle + * @param [in] jobdesc job descriptor + * @param [in] jr_dev optional handle for a jobring device to use, get with + * jr_pool_acquire + * + * @retval :: 0 is returned on success + * @retval :: errno is returned on failure + */ +int caam_run_descriptor_jr_blocking(device_t dev, + struct job_descriptor *jobdesc, device_t jr_dev); + +#endif /* CAAM_H */ diff --git a/sys/arm64/qoriq/caam/caam.c b/sys/arm64/qoriq/caam/caam.c new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/caam.c @@ -0,0 +1,641 @@ +/* + * Copyright 2021 NXP + * Copyright 2023, 2024 Alstom Group + * Copyright 2023, 2024 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + * This driver is based on arm-trusted-firmware/drivers/nxp/crypto/caam code. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "caam.h" +#include "caam_debug.h" +#include "caam_internal.h" +#include "jr/caam_jobdesc.h" +#include "jr/caam_jr.h" +#include "jr/caam_jr_hw.h" +#include "jr/caam_jr_pool.h" + +/*-------------------------- SFR access functions --------------------------*/ +uint32_t +caam_reg_read(device_t dev, uint32_t reg) +{ + struct caam_softc *sc = device_get_softc(dev); + uint32_t result; + + CAAM_LOG_DEBUG("caam_reg_read(%08X) --> ", reg); + result = bus_read_4(sc->mem_res, reg); + result = sc->little_endian ? le32toh(result): be32toh(result); + + CAAM_LOG_DEBUG("%08X\n", result); + + return result; +} + +void +caam_reg_write(device_t dev, uint32_t reg, uint32_t val) +{ + struct caam_softc *sc = device_get_softc(dev); + CAAM_LOG_DEBUG("caam_reg_write(%08X, %08X)\n", reg, val); + + val = sc->little_endian ? htole32(val): htobe32(val); + + bus_write_4(sc->mem_res, reg, val); + bus_barrier(sc->mem_res, reg, 4, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); +} + +/*----------------------- CAAM configuration functions ----------------------*/ + +/* This function checks if Virtualization is enabled for JR and + * accordingly sets the bot for starting JR in JRSTARTR register + */ +static void +start_jr(device_t dev, int jr_num) +{ + uint32_t ctpr = caam_reg_read(dev, SEC_REG_CTPR_MS_OFFSET); + uint32_t jrstartr = caam_reg_read(dev, SEC_REG_JRSTARTR_OFFSET); + uint32_t scfgr = caam_reg_read(dev, SEC_REG_SCFGR_OFFSET); + bool start = false; + + /* HW limitation of JRSTARTR reg size */ + MPASS(jr_num < sizeof(jrstartr) * 8); + + if ((ctpr & CTPR_VIRT_EN_INC) != 0U) { + if (((ctpr & CTPR_VIRT_EN_POR) != 0U) || + ((scfgr & SCFGR_VIRT_EN) != 0U)) { + start = true; + } + } else { + if ((ctpr & CTPR_VIRT_EN_POR) != 0U) { + start = true; + } + } + + if (start) { + jrstartr |= 1 << jr_num; + caam_reg_write(dev, SEC_REG_JRSTARTR_OFFSET, jrstartr); + } +} + +/* This functions configures the Job Ring + */ +static int +configure_jr(device_t caam_dev, device_t jr_dev, int jr_num) +{ + int ret; + + start_jr(caam_dev, jr_num); + + /* Do HW configuration of the JR */ +#if defined(CAAM_JR_MODE_ASYNC) + ret = caam_jr_init(jr_dev, SEC_NOTIFICATION_TYPE_IRQ, + SEC_INTERRUPT_COALESCING_TIMER_THRESH, + SEC_INTERRUPT_COALESCING_DESCRIPTOR_COUNT_THRESH); +#else + ret = caam_jr_init(jr_dev, SEC_NOTIFICATION_TYPE_POLL, 0, 0); +#endif + + if (ret != 0) { + CAAM_LOG_ERROR("Error in caam_jr_init ret=(%d)\n", ret); + return ret; + } + + return ret; +} + +/* This function configure SEC block: + * - It does basic parameter setting + */ +static void +configure_caam(device_t dev) +{ + uint32_t mcfgr; + + mcfgr = caam_reg_read(dev, SEC_REG_MCFGR_OFFSET); + + /* Modify CAAM Read/Write attributes (based on LS1046A) + * AXI Write - Cacheable + */ + mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0x2 << MCFGR_AWCACHE_SHIFT); + + /* Set PS bit to 1 as we are on arm64 architecture */ + mcfgr |= (1 << MCFGR_PS_SHIFT); + caam_reg_write(dev, SEC_REG_MCFGR_OFFSET, mcfgr); +} + +/* + * @brief Submit a job for execution. + * + * This is a shared implementation of caam_run_descriptor_jr_async/blocking, + * use those wrappers instead. + * + * @retval :: 0 is returned on success + * @retval :: errno is returned on failure + */ +static int +caam_run_descriptor_jr(device_t dev, struct job_descriptor *jobdesc, + bool polling, device_t jr_dev) +{ + int i = 0, ret = 0; + uint32_t *desc_addr = jobdesc->desc; + uint32_t desc_len = caam_jobdesc_length(jobdesc->desc); + uint32_t desc_word; + + struct caam_softc *sc = device_get_softc(dev); + struct jr_pool *p = &sc->jr_pool; + device_t jr; + + CAAM_LOG_DEBUG("Descriptor org: \n"); + for (i = 0; i < desc_len; i++) { + desc_word = desc_addr[i]; + CAAM_LOG_DEBUG("%08X\n", desc_word); + sec_mem_out32((uint32_t *)&desc_addr[i], desc_word, sc->little_endian); + } + + CAAM_LOG_DEBUG("Descriptor final: \n"); + for (i = 0; i < desc_len; i++) { + CAAM_LOG_DEBUG("%08X\n", desc_addr[i]); + } + + if (jr_dev == NULL) { + jr = jr_pool_acquire(p); + if (jr == NULL) { + return EBUSY; + } + } else { + jr = jr_dev; + } + + ret = caam_jr_enqueue(jr, jobdesc); + if (ret == 0) { + CAAM_LOG_DEBUG("JR enqueue done...\n"); + } else { + CAAM_LOG_WARN("Error in Enqueue\n"); + return ret; + } + + if (polling) { + CAAM_LOG_DEBUG("Dequeue in progress\n"); + ret = caam_jr_dequeue(jr, -1); + if (ret == 0) { + CAAM_LOG_DEBUG("Dequeue of %x desc success\n", ret); + } else { + CAAM_LOG_WARN("deq_ret %x\n", ret); + ret = EIO; + } + } + + if (jr_dev == NULL) + jr_pool_release(p, jr); + + return ret; +} + +/*--------------------- CAAM Public interface functions ---------------------*/ +#if defined(CAAM_JR_MODE_ASYNC) +int +caam_run_descriptor_jr_async(device_t dev, struct job_descriptor *jobdesc, + device_t jr_dev) +{ + return caam_run_descriptor_jr(dev, jobdesc, false, jr_dev); +} + +static void +caam_run_op_done(uint32_t *desc, uint32_t status, void *arg, device_t dev) +{ + if (arg != NULL) { + struct jr_job_arg *job_arg = arg; + + job_arg->desc = desc; + job_arg->status = status; + job_arg->dev = dev; + + JR_JOB_ARG_SIG_DONE(*job_arg); + } +} +#endif /* defined(CAAM_JR_MODE_ASYNC) */ + +int +caam_run_descriptor_jr_blocking(device_t dev, struct job_descriptor *jobdesc, + device_t jr_dev) +{ +#if defined(CAAM_JR_MODE_ASYNC) + /* Implement the blocking interface using conditional variable */ + int rv = 0; + void *backup_arg; + user_callback backup_callback; + + struct jr_job_arg job_arg; + JR_JOB_ARG_INIT(job_arg, caam_run_descriptor); + + backup_arg = jobdesc->arg; + backup_callback = jobdesc->callback; + + jobdesc->arg = &job_arg; + jobdesc->callback = caam_run_op_done; + + rv = caam_run_descriptor_jr(dev, jobdesc, false, jr_dev); + if (rv != 0) { + CAAM_LOG_DEV_WARN(dev, + "Failed to enqueue async descriptor rv=(%d)\n", rv); + goto exit; + } + + JR_JOB_ARG_WAIT_DONE(job_arg); + if (job_arg.status != 0) { + CAAM_LOG_ERROR("Job failed with status %x\n", job_arg.status); + rv = EIO; + } + + if (backup_callback != NULL) + backup_callback(job_arg.desc, job_arg.status, backup_arg, + job_arg.dev); + +exit: + JR_JOB_ARG_DEINIT(job_arg); + + return (rv); +#else + return caam_run_descriptor_jr(dev, jobdesc, true, jr_dev); +#endif /* defined(CAAM_JR_MODE_ASYNC) */ +} + +/*----------------------- Device management functions -----------------------*/ +static int +caam_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,sec-v4.0")) + return (ENXIO); + + device_set_desc(dev, "CAAM backend driver"); + + return (BUS_PROBE_DEFAULT); +} + +/* Find all jobring child devices, configure and add to jr_pool */ +static int +caam_jobrings_attach(device_t parent) +{ + int rv = 0; + struct caam_softc *sc; + device_t cdev; + phandle_t node; + struct jr_pool *p; + + node = ofw_bus_get_node(parent); + if (node == -1) + return (ENXIO); + + sc = device_get_softc(parent); + p = &sc->jr_pool; + jr_pool_init(p); + + /* + * Now walk the OFW tree and attach all job rings devices. + * Failing will reduce available jobring count, + * but with at least one CAAM remains functional. + */ + for (node = OF_child(node); node > 0; node = OF_peer(node)) { + if (!ofw_bus_node_is_compatible(node, "fsl,sec-v4.0-job-ring")) + continue; + + cdev = simplebus_add_device(parent, node, 0, NULL, -1, NULL); + if (cdev == NULL) { + CAAM_LOG_ERROR("Failed to add child device\n"); + continue; + } + rv = device_probe_and_attach(cdev); + if (rv != 0) + continue; + + rv = configure_jr(parent, cdev, jr_pool_dev_cnt(p)); + if (rv != 0) { + CAAM_LOG_ERROR("Job ring %zu configuration failure\n", + jr_pool_dev_cnt(p)); + continue; + } + + jr_pool_add(p, cdev); + } + + CAAM_LOG_INFO("Initialized %lu CAAM job rings\n", jr_pool_dev_cnt(p)); + + if (jr_pool_dev_cnt(p) < 1) { + CAAM_LOG_ERROR("No jobrings available\n"); + rv = ENODEV; + } + + return (rv); +} + +static void caam_jobrings_detach(device_t dev); + +static int +caam_attach(device_t dev) +{ + struct caam_softc *sc; + phandle_t node; + int rv; + int rid; + + sc = device_get_softc(dev); + sc->dev = dev; + + node = ofw_bus_get_node(dev); + if (node == -1) + return (ENXIO); + + sc->little_endian = OF_hasprop(node, "little-endian"); + + simplebus_init(dev, node); + if (simplebus_fill_ranges(node, &sc->sc) < 0) { + CAAM_LOG_ERROR("Failed to fill ranges\n"); + return (ENXIO); + } + + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE | RF_SHAREABLE); + + if (sc->mem_res == NULL) { + CAAM_LOG_ERROR("Failed to allocate resource\n"); + rv = ENXIO; + goto cleanup_simplebus; + } + + sc->mem_rman.rm_type = RMAN_ARRAY; + sc->mem_rman.rm_descr = "CAAM Device Memory"; + sc->mem_rman.rm_start = rman_get_start(sc->mem_res); + sc->mem_rman.rm_end = rman_get_end(sc->mem_res); + rv = rman_init(&sc->mem_rman); + if (rv != 0) { + CAAM_LOG_ERROR("Failed to initialize rman\n"); + goto cleanup_resource; + } + rv = rman_manage_region(&sc->mem_rman, rman_get_start(sc->mem_res), + rman_get_end(sc->mem_res)); + if (rv != 0) { + CAAM_LOG_ERROR("Failed to initialize RMAN region\n"); + goto cleanup_rman; + } + + /* + * Allow devices to identify. + */ + rv = bus_generic_probe(dev); + if (rv != 0) { + CAAM_LOG_ERROR("bus_generic_probe failed rv=(%d)\n", rv); + goto cleanup_rman; + } + + /* Initialize the simple CAAM driver stack */ + configure_caam(dev); + + /* Attach, probe and config jobrings */ + rv = caam_jobrings_attach(dev); + if (rv != 0) { + CAAM_LOG_ERROR("caam_jobrings_attach failed rv=(%d)\n", rv); + goto cleanup_rman; + } + + return (0); + +cleanup_rman: + rman_fini(&sc->mem_rman); +cleanup_resource: + bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); +cleanup_simplebus: + free(sc->sc.ranges, M_DEVBUF); + + return (rv); +} + +/* + * Acquire all jobrings, wait until all work is completed and deinitialize. + * Deinit jr_pool. + */ +static void +caam_jobrings_detach(device_t dev) +{ + struct caam_softc *sc = device_get_softc(dev); + struct jr_pool *p = &sc->jr_pool; + device_t jr, *jr_drained; + int rv, i, maxwait; + + jr_drained = malloc(sizeof(device_t) * jr_pool_dev_cnt(p), M_DEVBUF, + M_WAITOK); + + jr_pool_shutdown(p); + + for (i = 0; i < jr_pool_dev_cnt(p); ++i) { + jr = jr_pool_shutdown_acquire(p); + + maxwait = 1000; + while (caam_jr_busy(jr) && maxwait--) { + pause("caam_jr detach", hz / 1000); + } + + caam_jr_shutdown(jr); + rv = device_detach(jr); + if (rv != 0) + CAAM_LOG_ERROR( + "Failed to detach job ring device %p rv=(%d)\n", jr, + rv); + + jr_drained[i] = jr; + } + + /* must free all before vmem_destroy */ + for (i -= 1; i >= 0; --i) { + jr_pool_release(p, jr_drained[i]); + } + + jr_pool_deinit(p); + + free(jr_drained, M_DEVBUF); +} + +static int +caam_detach(device_t dev) +{ + struct caam_softc *sc = device_get_softc(dev); + + caam_jobrings_detach(dev); + + rman_fini(&sc->mem_rman); + bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); + free(sc->sc.ranges, M_DEVBUF); + + return (0); +} + +static int +caam_activate_resource(device_t bus, device_t child, struct resource *res) +{ + struct caam_softc *sc; + bus_space_tag_t bt; + bus_space_handle_t bh; + int i, rv; + + sc = device_get_softc(bus); + if (rman_get_type(res) != SYS_RES_IRQ) { + for (i = 0; i < sc->sc.nranges; i++) { + if (rman_is_region_manager(res, &sc->mem_rman) != 0) { + bt = rman_get_bustag(sc->mem_res); + rv = bus_space_subregion(bt, + rman_get_bushandle(sc->mem_res), + rman_get_start(res) - + rman_get_start(sc->mem_res), + rman_get_size(res), &bh); + if (rv != 0) + return (rv); + rman_set_bustag(res, bt); + rman_set_bushandle(res, bh); + return (rman_activate_resource(res)); + } + } + return (EINVAL); + } + return (bus_generic_activate_resource(bus, child, res)); +} + +static int +caam_release_resource(device_t bus, device_t child, struct resource *res) +{ + struct resource_list *rl; + struct resource_list_entry *rle; + int passthrough, rv; + int rid, type, flags; + + passthrough = (device_get_parent(child) != bus); + rl = BUS_GET_RESOURCE_LIST(bus, child); + + /* Read resource fields before modifying it */ + rid = rman_get_rid(res); + type = rman_get_type(res); + flags = rman_get_flags(res); + + if (type != SYS_RES_IRQ) { + if ((flags & RF_ACTIVE) != 0){ + rv = rman_deactivate_resource(res); + if (rv != 0) + return (rv); + } + rv = rman_release_resource(res); + if (rv != 0) + return (rv); + if (!passthrough) { + rle = resource_list_find(rl, type, rid); + KASSERT(rle != NULL, + ("%s: resource entry not found!", __func__)); + KASSERT(rle->res != NULL, + ("%s: resource entry is not busy", __func__)); + rle->res = NULL; + } + return (0); + } + return (resource_list_release(rl, bus, child, res)); +} + +static struct resource * +caam_alloc_resource(device_t bus, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct caam_softc *sc; + struct resource_list *rl; + struct resource_list_entry *rle = NULL; + struct resource *res; + int i, isdefault, passthrough; + + isdefault = RMAN_IS_DEFAULT_RANGE(start, end); + passthrough = (device_get_parent(child) != bus); + sc = device_get_softc(bus); + rl = BUS_GET_RESOURCE_LIST(bus, child); + switch (type) { + case SYS_RES_MEMORY: + KASSERT(!(isdefault && passthrough), + ("%s: passthrough of default allocation", __func__)); + if (!passthrough) { + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + return (NULL); + KASSERT(rle->res == NULL, + ("%s: resource entry is busy", __func__)); + if (isdefault) { + start = rle->start; + count = ulmax(count, rle->count); + end = ulmax(rle->end, start + count - 1); + } + } + + res = NULL; + /* Map caam ranges to nexus ranges. */ + for (i = 0; i < sc->sc.nranges; i++) { + if (start >= sc->sc.ranges[i].bus && end < + sc->sc.ranges[i].bus + sc->sc.ranges[i].size) { + start += rman_get_start(sc->mem_res); + end += rman_get_start(sc->mem_res); + res = rman_reserve_resource(&sc->mem_rman, start, + end, count, flags & ~RF_ACTIVE, child); + if (res == NULL) + return (NULL); + rman_set_rid(res, *rid); + rman_set_type(res, type); + if ((flags & RF_ACTIVE) != 0 && bus_activate_resource( + child, type, *rid, res) != 0) { + rman_release_resource(res); + return (NULL); + } + break; + } + } + if (!passthrough) + rle->res = res; + return (res); + case SYS_RES_IRQ: + return (resource_list_alloc(rl, bus, child, type, rid, start, + end, count, flags)); + } + return (NULL); +} + +static device_method_t caam_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, caam_probe), + DEVMETHOD(device_attach, caam_attach), + DEVMETHOD(device_detach, caam_detach), + + DEVMETHOD(bus_alloc_resource, caam_alloc_resource), + DEVMETHOD(bus_activate_resource, caam_activate_resource), + DEVMETHOD(bus_release_resource, caam_release_resource), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(caam, caam_driver, caam_methods, sizeof(struct caam_softc), + simplebus_driver); + +DRIVER_MODULE(caam, simplebus, caam_driver, 0, 0); +MODULE_VERSION(caam, 1); diff --git a/sys/arm64/qoriq/caam/caam_debug.h b/sys/arm64/qoriq/caam/caam_debug.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/caam_debug.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2023 Alstom Group + * Copyright (c) 2023 Sii Poland + + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CAAM_DEBUG_H +#define CAAM_DEBUG_H + +/* + * The log output macros print output to the console. These macros produce + * compiled log output only if the LOG_LEVEL defined in the makefile (or the + * make command line) is greater or equal than the level required for that + * type of log output. + * + * The format expected is the same as for printf(). For example: + * CAAM_LOG_INFO("Info %s.\n", "message") -> INFO: Info message. + * CAAM_LOG_WARN("Warning %s.\n", "message") -> WARNING: Warning message. + */ + +#define LOG_LEVEL_NONE (0u) +#define LOG_LEVEL_ERROR (10u) +#define LOG_LEVEL_NOTICE (20u) +#define LOG_LEVEL_WARNING (30u) +#define LOG_LEVEL_INFO (40u) +#define LOG_LEVEL_DEBUG (50u) + +#ifndef __ASSEMBLER__ + +#include + +#include +#include +#include +#include + +#ifdef DEBUG +#define LOG_LEVEL LOG_LEVEL_INFO +#else +#define LOG_LEVEL LOG_LEVEL_ERROR +#endif + +/* + * If the log output is too low then this macro is used in place of tf_log() + * below. The intent is to get the compiler to evaluate the function call for + * type checking and format specifier correctness but let it optimize it out. + */ +#define no_tf_log(fmt, ...) \ + do { \ + if (false) { \ + log(LOG_INFO, fmt, ##__VA_ARGS__); \ + } \ + } while (false) + +#if LOG_LEVEL >= LOG_LEVEL_ERROR +#define CAAM_LOG_ERROR(...) log(LOG_ERR, __VA_ARGS__) +#define CAAM_LOG_ERROR_NL() log(LOG_ERR, "\n") +#else +#define CAAM_LOG_ERROR(...) no_tf_log(__VA_ARGS__) +#define CAAM_LOG_ERROR_NL() +#endif + +#if LOG_LEVEL >= LOG_LEVEL_NOTICE +#define CAAM_LOG_NOTICE(...) log(LOG_NOTICE, __VA_ARGS__) +#else +#define CAAM_LOG_NOTICE(...) no_tf_log(__VA_ARGS__) +#endif + +#if LOG_LEVEL >= LOG_LEVEL_WARNING +#define CAAM_LOG_WARN(...) log(LOG_WARNING, __VA_ARGS__) +#define CAAM_LOG_DEV_WARN(dev, ...) device_log(dev, LOG_WARNING, __VA_ARGS__) +#else +#define CAAM_LOG_WARN(...) no_tf_log(__VA_ARGS__) +#define CAAM_LOG_DEV_WARN(dev, ...) no_tf_log(__VA_ARGS__) +#endif + +#if LOG_LEVEL >= LOG_LEVEL_INFO +#define CAAM_LOG_INFO(...) log(LOG_INFO, __VA_ARGS__) +#else +#define CAAM_LOG_INFO(...) no_tf_log(__VA_ARGS__) +#endif + +#if LOG_LEVEL >= LOG_LEVEL_DEBUG +#define CAAM_LOG_DEBUG(...) log(LOG_DEBUG, __VA_ARGS__) +#else +#define CAAM_LOG_DEBUG(...) no_tf_log(__VA_ARGS__) +#endif + +#endif /* __ASSEMBLER__ */ +#endif /* CAAM_DEBUG_H */ diff --git a/sys/arm64/qoriq/caam/caam_internal.h b/sys/arm64/qoriq/caam/caam_internal.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/caam_internal.h @@ -0,0 +1,36 @@ +/* + * Copyright 2024 Alstom Group + * Copyright 2024 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef CAAM_INTERNAL_H +#define CAAM_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "jr/caam_jr_pool.h" + +/* software context */ +struct caam_softc { + struct simplebus_softc sc; + device_t dev; + struct resource *mem_res; + struct rman mem_rman; + bool little_endian; + + struct jr_pool jr_pool; +}; + +#endif /* CAAM_INTERNAL_H */ diff --git a/sys/arm64/qoriq/caam/jr/caam_desc_defines.h b/sys/arm64/qoriq/caam/jr/caam_desc_defines.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_desc_defines.h @@ -0,0 +1,748 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2018-2021 NXP + * + * Brief CAAM Descriptor defines. + */ + +/* + * File imported from OP-TEE. + */ +#ifndef __CAAM_DESC_DEFINES_H__ +#define __CAAM_DESC_DEFINES_H__ + +#define BIT32(i) (1 << (i)) +#define SHIFT_U32(value, shift) ((uint32_t)(value) << (shift)) +/* + * Common Command constants + */ +#define CMD_TYPE(cmd) SHIFT_U32((cmd) & 0x1F, 27) +#define GET_CMD_TYPE(op) ((op) & (SHIFT_U32(0x1F, 27))) +#define CMD_CLASS(val) SHIFT_U32((val) & 0x3, 25) +#define CLASS_NO 0x0 +#define CLASS_1 0x1 +#define CLASS_2 0x2 +#define CLASS_DECO 0x3 +#define VLF SHIFT_U32(1, 24) + +#define CMD_SGT BIT32(24) +#define CMD_IMM BIT32(23) + +/* + * HEADER Job Descriptor Header format + */ +#define CMD_HDR_JD_TYPE CMD_TYPE(0x16) +/* + * HEADER Shared Descriptor Header format + */ +#define CMD_HDR_SHR_TYPE CMD_TYPE(0x17) + +/* Must be ONE */ +#define HDR_JD_ONE BIT32(23) + +/* Start Index if SHR = 0 */ +#define HDR_JD_START_IDX(line) SHIFT_U32((line) & 0x3F, 16) + +#define HDR_SHARE_MASK 0x00000700 +#define HDR_SHARE_NEVER 0x00000000 +#define HDR_SHARE_WAIT 0x00000100 +#define HDR_SHARE_SERIAL 0x00000200 +#define HDR_SHARE_ALWAYS 0x00000300 +#define HDR_SHARE_DEFER 0x00000400 +#define HDR_SHR SHIFT_U32(1, 12) +#define HDR_SC SHIFT_U32(1, 12) +#define HDR_REVERSE 0x00000800 + +/* Descriptor Length */ +#define HDR_JD_DESCLEN(len) SHIFT_U32((len) & 0x7F, 0) +#define GET_JD_DESCLEN(entry) ((entry) & 0x7F) + +/* + * KEY Command fields + */ +#define CMD_KEY_TYPE CMD_TYPE(0x00) + +/* Key Destination */ +#define KEY_DEST(val) SHIFT_U32((KEY_DEST_##val) & 0x3, 16) +#define KEY_DEST_REG 0x0 +#define KEY_DEST_PKHA_E 0x1 +#define KEY_DEST_AFHA_SBOX 0x2 +#define KEY_DEST_MDHA_SPLIT 0x3 + +/* Plaintext Store */ +#define KEY_PTS BIT32(14) + +/* Key Length */ +#define KEY_LENGTH(len) SHIFT_U32((len) & 0x3FF, 0) + +/* + * LOAD Command fields + */ +#define CMD_LOAD_TYPE CMD_TYPE(0x02) +#define CMD_LOAD_SEQ_TYPE CMD_TYPE(0x03) + +/* Load Destination */ +#define LOAD_DST(reg) SHIFT_U32((reg) & 0x7F, 16) + +/* Offset in destination register */ +#define LOAD_OFFSET(off) SHIFT_U32((off) & 0xFF, 8) + +/* Length */ +#define LOAD_LENGTH(len) SHIFT_U32((len) & 0xFF, 0) + +/* + * STORE Command fields + */ +#define CMD_STORE_TYPE CMD_TYPE(0x0A) +#define CMD_STORE_SEQ_TYPE CMD_TYPE(0x0B) + +/* Store Source */ +#define STORE_SRC(reg) SHIFT_U32((reg) & 0x7F, 16) + +/* Offset in source register */ +#define STORE_OFFSET(off) SHIFT_U32((off) & 0xFF, 8) + +/* Length */ +#define STORE_LENGTH(len) SHIFT_U32((len) & 0xFF, 0) + +/* + * Define the Load/Store Registers Source and Destination + */ +#define REG_MODE 0x00 +#define REG_KEY_SIZE 0x01 +#define REG_DATA_SIZE 0x02 +#define REG_ICV_SIZE 0x03 +#define REG_DECO_MID_STATUS 0x04 +#define REG_DECO_CTRL2 0x05 +#define REG_CHA_CTRL 0x06 +#define REG_DECO_CTRL 0x06 +#define REG_IRQ_CTRL 0x07 +#define REG_DECO_PROT_OVERWRITE 0x07 +#define REG_CLEAR_WRITTEN 0x08 +#define REG_MATH0 0x08 +#define REG_MATH1 0x09 +#define REG_MATH2 0x0A +#define REG_CHA_INST_SELECT 0x0A +#define REG_AAD_SIZE 0x0B +#define REG_MATH3 0x0B +#define REG_ALT_DATA_SIZE_C1 0x0F +#define REG_PKHA_A_SIZE 0x10 +#define REG_PKHA_B_SIZE 0x11 +#define REG_PKHA_N_SIZE 0x12 +#define REG_PKHA_E_SIZE 0x13 +#define REG_CTX 0x20 +#define REG_MATH0_DW 0x30 +#define REG_MATH1_DW 0x31 +#define REG_MATH2_DW 0x32 +#define REG_MATH3_DW 0x33 +#define REG_MATH0_B 0x38 +#define REG_MATH1_B 0x39 +#define REG_MATH2_B 0x3A +#define REG_MATH3_B 0x3B +#define REG_KEY 0x40 +#define REG_DECO_DESC 0x40 +#define REG_NFIFO_n_SIZE 0x70 +#define REG_NFIFO_MATH 0x73 +#define REG_SIZE 0x74 +#define REG_SIZE_MATH 0x75 +#define REG_IFIFO_SHIFT 0x76 +#define REG_OFIFO_SHIFT 0x77 +#define REG_AUX_FIFO 0x78 +#define REG_NFIFO 0x7A +#define REG_IFIFO 0x7C +#define REG_OFIFO 0x7E + +/* + * FIFO LOAD Command fields + */ +#define CMD_FIFO_LOAD_TYPE CMD_TYPE(0x04) +#define CMD_SEQ_FIFO_LOAD_TYPE CMD_TYPE(0x05) + +/* Extended Length */ +#define FIFO_LOAD_EXT BIT32(22) + +/* Input data */ +#define FIFO_LOAD_INPUT(reg) SHIFT_U32((FIFO_LOAD_##reg) & 0x3F, 16) +#define FIFO_LOAD_ACTION(act) SHIFT_U32((FIFO_LOAD_##act) & 0x3F, 16) + +/* Length */ +#define FIFO_LOAD_MAX 0xFFFF +#define FIFO_LOAD_LENGTH(len) SHIFT_U32((len) & FIFO_LOAD_MAX, 0) + +/* + * Define the FIFO Load Type Input + */ +#define FIFO_LOAD_PKHA_A0 0x00 +#define FIFO_LOAD_PKHA_A1 0x01 +#define FIFO_LOAD_PKHA_A2 0x02 +#define FIFO_LOAD_PKHA_A3 0x03 +#define FIFO_LOAD_PKHA_B0 0x04 +#define FIFO_LOAD_PKHA_B1 0x05 +#define FIFO_LOAD_PKHA_B2 0x06 +#define FIFO_LOAD_PKHA_B3 0x07 +#define FIFO_LOAD_PKHA_N 0x08 +#define FIFO_LOAD_PKHA_A 0x0C +#define FIFO_LOAD_PKHA_B 0x0D +#define FIFO_LOAD_NO_INFO_NFIFO 0x0F +#define FIFO_LOAD_MSG 0x10 +#define FIFO_LOAD_MSG_C1_OUT_C2 0x18 +#define FIFO_LOAD_IV 0x20 +#define FIFO_LOAD_BITDATA 0x2C +#define FIFO_LOAD_AAD 0x30 +#define FIFO_LOAD_ICV 0x38 + +/* Define Action of some FIFO Data */ +#define FIFO_LOAD_NOACTION 0x0 +#define FIFO_LOAD_FLUSH 0x1 +#define FIFO_LOAD_LAST_C1 0x2 +#define FIFO_LOAD_LAST_C2 0x4 + +/* + * FIFO STORE Command fields + */ +#define CMD_FIFO_STORE_TYPE CMD_TYPE(0x0C) +#define CMD_SEQ_FIFO_STORE_TYPE CMD_TYPE(0x0D) + +/* Extended Length */ +#define FIFO_STORE_EXT BIT32(22) + +/* Output data */ +#define FIFO_STORE_OUTPUT(reg) SHIFT_U32((FIFO_STORE_##reg) & 0x3F, 16) + +/* Length */ +#define FIFO_STORE_MAX 0xFFFF +#define FIFO_STORE_LENGTH(len) SHIFT_U32((len) & FIFO_STORE_MAX, 0) + +/* + * Define the FIFO Store Type Output + */ +#define FIFO_STORE_PKHA_A0 0x00 +#define FIFO_STORE_PKHA_A1 0x01 +#define FIFO_STORE_PKHA_A2 0x02 +#define FIFO_STORE_PKHA_A3 0x03 +#define FIFO_STORE_PKHA_B0 0x04 +#define FIFO_STORE_PKHA_B1 0x05 +#define FIFO_STORE_PKHA_B2 0x06 +#define FIFO_STORE_PKHA_B3 0x07 +#define FIFO_STORE_PKHA_N 0x08 +#define FIFO_STORE_PKHA_A 0x0C +#define FIFO_STORE_PKHA_B 0x0D +#define FIFO_STORE_AFHA_SBOX_AES_CCM_JKEK 0x10 +#define FIFO_STORE_AFHA_SBOX_AES_CCM_TKEK 0x11 +#define FIFO_STORE_PKHA_E_AES_CCM_JKEK 0x12 +#define FIFO_STORE_PKHA_E_AES_CCM_TKEK 0x13 +#define FIFO_STORE_KEY_AES_CCM_JKEK 0x14 +#define FIFO_STORE_KEY_AES_CCM_TKEK 0x15 +#define FIFO_STORE_C2_MDHA_SPLIT_KEY_AES_CCM_JKEK 0x16 +#define FIFO_STORE_C2_MDHA_SPLIT_KEY_AES_CCM_TKEK 0x17 +#define FIFO_STORE_AFHA_SBOX_AES_ECB_JKEK 0x20 +#define FIFO_STORE_AFHA_SBOX_AES_ECB_TKEK 0x21 +#define FIFO_STORE_PKHA_E_AES_ECB_JKEK 0x22 +#define FIFO_STORE_PKHA_E_AES_ECB_TKEK 0x23 +#define FIFO_STORE_KEY_AES_ECB_JKEK 0x24 +#define FIFO_STORE_KEY_AES_ECB_TKEK 0x25 +#define FIFO_STORE_C2_MDHA_SPLIT_KEY_AES_ECB_JKEK 0x26 +#define FIFO_STORE_C2_MDHA_SPLIT_KEY_AES_ECB_TKEK 0x27 +#define FIFO_STORE_MSG_DATA 0x30 +#define FIFO_STORE_RNG_TO_MEM 0x34 +#define FIFO_STORE_RNG_STAY_FIFO 0x35 +#define FIFO_STORE_SKIP 0x3F + +/* + * MOVE Command fields + */ +#define CMD_MOVE_TYPE CMD_TYPE(0x0F) + +/* Auxiliary */ +#define MOVE_AUX(val) SHIFT_U32((val) & 0x3, 25) + +/* Wait for completion */ +#define MOVE_WC BIT32(24) + +/* Source */ +#define MOVE_SRC(src) MOVE_SRC_##src +#define MOVE_REG_SRC(reg) SHIFT_U32((reg) & 0xF, 20) +#define MOVE_SRC_C1_CTX_REG MOVE_REG_SRC(0x0) +#define MOVE_SRC_C2_CTX_REG MOVE_REG_SRC(0x1) +#define MOVE_SRC_OFIFO MOVE_REG_SRC(0x2) +#define MOVE_SRC_DESC_BUF MOVE_REG_SRC(0x3) +#define MOVE_SRC_MATH_REG0 MOVE_REG_SRC(0x4) +#define MOVE_SRC_MATH_REG1 MOVE_REG_SRC(0x5) +#define MOVE_SRC_MATH_REG2 MOVE_REG_SRC(0x6) +#define MOVE_SRC_MATH_REG3 MOVE_REG_SRC(0x7) +#define MOVE_SRC_NFIFO_DECO_ALIGN MOVE_REG_SRC(0x8) +#define MOVE_SRC_NFIFO_C1_ALIGN (MOVE_REG_SRC(0x9) | MOVE_AUX(0x1)) +#define MOVE_SRC_NFIFO_C2_ALIGN (MOVE_REG_SRC(0x9) | MOVE_AUX(0x0)) +#define MOVE_SRC_DECO_ALIGN (MOVE_REG_SRC(0xA) | MOVE_AUX(0x0)) +#define MOVE_SRC_C1_ALIGN (MOVE_REG_SRC(0xA) | MOVE_AUX(0x1)) +#define MOVE_SRC_C2_ALIGN (MOVE_REG_SRC(0xA) | MOVE_AUX(0x2)) +#define MOVE_SRC_C1_KEY MOVE_REG_SRC(0xD) +#define MOVE_SRC_C2_KEY MOVE_REG_SRC(0xE) + +/* Destination */ +#define MOVE_DST(dst) SHIFT_U32((MOVE_DST_##dst), 16) +#define MOVE_DST_C1_CTX_REG 0x0 +#define MOVE_DST_C2_CTX_REG 0x1 +#define MOVE_DST_OFIFO 0x2 +#define MOVE_DST_DESC_BUF 0x3 +#define MOVE_DST_MATH_REG0 0x4 +#define MOVE_DST_MATH_REG1 0x5 +#define MOVE_DST_MATH_REG2 0x6 +#define MOVE_DST_MATH_REG3 0x7 +#define MOVE_DST_IFIFO_C1 0x8 +#define MOVE_DST_IFIFO_C2 0x9 +#define MOVE_DST_IFIFO_C2_LC2 ((0x9 << 16 | MOVE_AUX(0x1)) >> 16) +#define MOVE_DST_IFIFO 0xA +#define MOVE_DST_PKHA_A 0xC +#define MOVE_DST_C1_KEY 0xD +#define MOVE_DST_C2_KEY 0xE +#define MOVE_DST_AUX_FIFO 0xF + +/* Offset */ +#define MOVE_OFFSET(off) SHIFT_U32((off) & 0xFF, 8) + +/* Length */ +#define MOVE_LENGTH(len) SHIFT_U32((len) & 0xFF, 0) + +/* + * Operation Command fields + * Algorithm/Protocol/PKHA + */ +#define CMD_OP_TYPE CMD_TYPE(0x10) + +/* Operation Type */ +#define OP_TYPE(type) SHIFT_U32((OP_TYPE_##type) & 0x7, 24) +#define OP_TYPE_UNI 0x0 +#define OP_TYPE_PKHA 0x1 +#define OP_TYPE_CLASS1 0x2 +#define OP_TYPE_CLASS2 0x4 +#define OP_TYPE_DECAPS 0x6 +#define OP_TYPE_ENCAPS 0x7 + +/* Protocol Identifier */ +#define PROTID(id) SHIFT_U32((PROTID_##id) & 0xFF, 16) +#define PROTID_BLOB 0x0D +#define PROTID_MPKEY 0x14 +#define PROTID_PKKEY 0x14 +#define PROTID_MPSIGN 0x15 +#define PROTID_DSASIGN 0x15 +#define PROTID_DSAVERIFY 0x16 +#define PROTID_SHARED_SECRET 0x17 +#define PROTID_RSA_ENC 0x18 +#define PROTID_RSA_DEC 0x19 +#define PROTID_RSA_FINISH_KEY 0x1A + +/* + * RSA Protocol Information + */ +#define PROT_RSA_FMT(format) SHIFT_U32((PROT_RSA_FMT_##format) & 0x1, 12) +#define PROT_RSA_FMT_NO 0 +#define PROT_RSA_FMT_PKCS_V1_5 1 + +#define PROT_RSA_DEC_KEYFORM(format) SHIFT_U32(((format) - 1) & 0x3, 0) + +/* RSA Key Protocol Information */ +#define PROT_RSA_KEY(format) SHIFT_U32((PROT_RSA_KEY_##format) & 0x3, 0) +#define PROT_RSA_KEY_ALL 0 +#define PROT_RSA_KEY_N_D 2 + +/* + * ECC Protocol Information + */ +#define PROT_PK_MSG(type) SHIFT_U32(PROT_PK_MSG_##type, 10) +#define PROT_PK_MSG_HASHED 2 +#define PROT_PK_TYPE(type) SHIFT_U32(PROT_PK_##type, 1) +#define PROT_PK_DL 0 +#define PROT_PK_ECC 1 + +/* + * BLOB Protocol Information + */ +#define PROT_BLOB_FMT_MSTR BIT32(1) +#define PROT_BLOB_TYPE(type) SHIFT_U32(1, PROT_BLOB_TYPE_##type) +#define PROT_BLOB_TYPE_BLACK_KEY BIT32(2) +#define PROT_BLOB_TYPE_RED 0 +#define PROT_BLOB_SEC_MEM BIT32(3) +#define PROT_BLOB_EKT 8 +#define PROT_BLOB_INFO(aes) SHIFT_U32(PROT_BLOB_AES_##aes, \ + PROT_BLOB_EKT) +#define PROT_BLOB_AES_CCM 1 +#define PROT_BLOB_AES_ECB 0 +#define PROT_BLOB_FORMAT(format) SHIFT_U32(0, PROT_BLOB_FORMAT_##format) +#define PROT_BLOB_FORMAT_NORMAL 0 + +/* + * MP Protocol Information + */ +#define PROT_MP_PUBK_SGT BIT32(31) +#define PROT_MP_CURVE(curve) SHIFT_U32((curve) & 0xF, 17) + +/* + * Algorithm Identifier + */ +#define OP_ALGO(algo) SHIFT_U32((ALGO_##algo) & 0xFF, 16) +#define ALGO_AES 0x10 +#define ALGO_DES 0x20 +#define ALGO_3DES 0x21 +#define ALGO_ARC4 0x30 +#define ALGO_RNG 0x50 +#define ALGO_MD5 0x40 +#define ALGO_SHA1 0x41 +#define ALGO_SHA224 0x42 +#define ALGO_SHA256 0x43 +#define ALGO_SHA384 0x44 +#define ALGO_SHA512 0x45 +#define ALGO_SHA512_224 0x46 +#define ALGO_SHA512_256 0x47 + +/* Algorithm Additional Information */ +#define ALGO_AAI(info) SHIFT_U32((AAI_##info) & 0x1FF, 4) + +/* AES AAI */ +#define AAI_AES_CTR_MOD128 0x00 +#define AAI_AES_CBC 0x10 +#define AAI_AES_ECB 0x20 +#define AAI_AES_CFB 0x30 +#define AAI_AES_OFB 0x40 +#define AAI_AES_XTS 0x50 +#define AAI_AES_CMAC 0x60 +#define AAI_AES_XCBC_MAC 0x70 +#define AAI_AES_CCM 0x80 +#define AAI_AES_GCM 0x90 + +/* DES AAI */ +#define AAI_DES_CBC 0x10 +#define AAI_DES_ECB 0x20 +#define AAI_DES_CFB 0x30 +#define AAI_DES_OFB 0x40 + +/* Digest MD5/SHA AAI */ +#define AAI_DIGEST_HASH 0x00 +#define AAI_DIGEST_HMAC 0x01 +#define AAI_DIGEST_SMAC 0x02 +#define AAI_DIGEST_HMAC_PRECOMP 0x04 + +/* Algorithm State */ +#define ALGO_AS(state) SHIFT_U32((AS_##state) & 0x3, 2) +#define AS_UPDATE 0x0 +#define AS_INIT 0x1 +#define AS_FINAL 0x2 +#define AS_INIT_FINAL 0x3 + +/* Algorithm Encrypt/Decrypt */ +#define ALGO_DECRYPT SHIFT_U32(0x0, 0) +#define ALGO_ENCRYPT SHIFT_U32(0x1, 0) + +/* + * Specific RNG Algorithm bits 12-0 + */ +/* Secure Key */ +#define ALGO_RNG_SK BIT32(12) + +/* State Handle */ +#define ALGO_RNG_SH(sh) SHIFT_U32((sh) & 0x3, 4) + +/* Prediction Resistance */ +#define ALGO_RNG_PR BIT32(1) + +/* State */ +#define AS_RNG_GENERATE 0x0 +#define AS_RNG_INSTANTIATE 0x1 +#define AS_RNG_RESEED 0x2 +#define AS_RNG_UNINSTANTIATE 0x3 + +/* + * JUMP Command fields + */ +#define CMD_JUMP_TYPE CMD_TYPE(0x14) + +/* Jump Select Type */ +#define JMP_JSL BIT32(24) + +/* Jump Type */ +#define JUMP_TYPE(type) SHIFT_U32((JMP_##type) & 0xF, 20) +#define JMP_LOCAL 0x0 +#define JMP_LOCAL_INC 0x1 +#define JMP_SUBROUTINE_CALL 0x2 +#define JMP_LOCAL_DEC 0x3 +#define JMP_NON_LOCAL 0x4 +#define JMP_SUBROUTINE_RET 0x6 +#define JMP_HALT 0x8 +#define JMP_HALT_USER_STATUS 0xC + +/* Test Type */ +#define JUMP_TST_TYPE(type) SHIFT_U32((JMP_TST_##type) & 0x3, 16) +#define JMP_TST_ALL_COND_TRUE 0x0 +#define JMP_TST_ALL_COND_FALSE 0x1 +#define JMP_TST_ANY_COND_TRUE 0x2 +#define JMP_TST_ANY_COND_FALSE 0x3 + +/* Jump Source to increment/decrement */ +#define JMP_SRC(src) SHIFT_U32((JMP_SRC_##src) & 0xF, 12) +#define JMP_SRC_MATH_0 0x0 + +/* Test Condition */ +#define JMP_COND(cond) SHIFT_U32((JMP_COND_##cond) & 0xFF, 8) +#define JMP_COND_MATH(cond) SHIFT_U32((JMP_COND_MATH_##cond) & 0xF, 8) +#define JMP_COND_NONE 0x00 +#define JMP_COND_PKHA_IS_ZERO 0x80 +#define JMP_COND_PKHA_GCD_1 0x40 +#define JMP_COND_PKHA_IS_PRIME 0x20 +#define JMP_COND_MATH_N 0x08 +#define JMP_COND_MATH_Z 0x04 +#define JMP_COND_NIFP 0x04 +#define JMP_COND_MATH_C 0x02 +#define JMP_COND_MATH_NV 0x01 + +/* Local Offset */ +#define JMP_LOCAL_OFFSET(off) SHIFT_U32((off) & 0xFF, 0) + +/* + * MATH Command fields + */ +#define CMD_MATH_TYPE CMD_TYPE(0x15) +#define CMD_MATHI_TYPE CMD_TYPE(0x1D) + +/* Immediate Four Bytes */ +#define MATH_IFB BIT32(26) + +/* Function Mathematical */ +#define MATH_FUNC(func) SHIFT_U32((MATH_FUNC_##func) & 0xF, 20) +#define MATH_FUNC_ADD 0x0 +#define MATH_FUNC_ADD_W_CARRY 0x1 +#define MATH_FUNC_SUB 0x2 +#define MATH_FUNC_SUB_W_BORROW 0x3 +#define MATH_FUNC_OR 0x4 +#define MATH_FUNC_AND 0x5 +#define MATH_FUNC_XOR 0x6 +#define MATH_FUNC_SHIFT_L 0x7 +#define MATH_FUNC_SHIFT_R 0x8 +#define MATH_FUNC_SHLD 0x9 +#define MATH_FUNC_ZBYTE 0xA +#define MATH_FUNC_SWAP_BYTES 0xB + +/* Source 0 */ +#define MATH_SRC0(reg) SHIFT_U32((MATH_SRC0_##reg) & 0xF, 16) +#define MATH_SRC0_REG0 0x0 +#define MATH_SRC0_REG1 0x1 +#define MATH_SRC0_REG2 0x2 +#define MATH_SRC0_IMM_DATA 0x4 +#define MATH_SRC0_DPOVRD 0x7 +#define MATH_SRC0_SIL 0x8 +#define MATH_SRC0_SOL 0x9 +#define MATH_SRC0_VSIL 0xA +#define MATH_SRC0_VSOL 0xB +#define MATH_SRC0_ZERO 0xC +#define MATH_SRC0_ONE 0xF + +/* Source 1 */ +#define MATH_SRC1(reg) SHIFT_U32((MATH_SRC1_##reg) & 0xF, 12) +#define MATH_SRC1_REG0 0x0 +#define MATH_SRC1_REG1 0x1 +#define MATH_SRC1_REG2 0x2 +#define MATH_SRC1_IMM_DATA 0x4 +#define MATH_SRC1_DPOVRD 0x7 +#define MATH_SRC1_VSIL 0x8 +#define MATH_SRC1_VSOL 0x9 +#define MATH_SRC1_IFIFO 0xA +#define MATH_SRC1_OFIFO 0xB +#define MATH_SRC1_ONE 0xC +#define MATH_SRC1_ZERO 0xF + +/* Destination */ +#define MATH_DST(reg) SHIFT_U32((MATH_DST_##reg) & 0xF, 8) +#define MATH_DST_REG0 0x0 +#define MATH_DST_REG1 0x1 +#define MATH_DST_REG2 0x2 +#define MATH_DST_DPOVRD 0x7 +#define MATH_DST_SIL 0x8 +#define MATH_DST_SOL 0x9 +#define MATH_DST_VSIL 0xA +#define MATH_DST_VSOL 0xB +#define MATH_DST_NODEST 0xF + +/* Length */ +#define MATH_LENGTH(len) SHIFT_U32((len) & 0xF, 0) + +/* Immediate Value - MATHI operation */ +#define MATHI_SRC(reg) SHIFT_U32((MATH_SRC0_##reg) & 0xF, 16) +#define MATHI_DST(reg) SHIFT_U32((MATH_DST_##reg) & 0xF, 12) +#define MATHI_IMM_VALUE(val) SHIFT_U32((val) & 0xFF, 4) + +/* + * Sequence Input/Output + */ +#define CMD_SEQ_IN_TYPE CMD_TYPE(0x1E) +#define CMD_SEQ_OUT_TYPE CMD_TYPE(0x1F) + +/* Extended Length */ +#define SEQ_EXT BIT32(22) + +/* Length */ +#define SEQ_LENGTH(len) SHIFT_U32((len) & 0xFFFF, 0) + +/* + * PKHA Operation + */ +#define PKHA_ALG SHIFT_U32(0x8, 20) + +#define PKHA_F2M BIT32(17) + +#define PKHA_OUTSEL(dst) SHIFT_U32((PKHA_OUTSEL_##dst) & 0x3, 8) +#define PKHA_OUTSEL_B 0x0 +#define PKHA_OUTSEL_A 0x1 + +#define PKHA_FUNC(func) SHIFT_U32((PKHA_FUNC_##func) & 0x3F, 0) +#define PKHA_FUNC_CPY_NSIZE 0x10 +#define PKHA_FUNC_CPY_SSIZE 0x11 +#define PKHA_FUNC_MOD_ADD_A_B 0x02 +#define PKHA_FUNC_MOD_SUB_A_B 0x03 +#define PKHA_FUNC_MOD_SUB_B_A 0x04 +#define PKHA_FUNC_MOD_MUL_A_B 0x05 +#define PKHA_FUNC_MOD_EXP_A_E 0x06 +#define PKHA_FUNC_MOD_AMODN 0x07 +#define PKHA_FUNC_MOD_INV_A 0x08 +#define PKHA_FUNC_ECC_POINT_ADD_P1_P2 0x09 +#define PKHA_FUNC_ECC_POINT_DBL_P1 0x0A +#define PKHA_FUNC_ECC_POINT_MUL_E_P1 0x0B +#define PKHA_FUNC_MONT_RADIX_R2_MODE_N 0x0C +#define PKHA_FUNC_GCD_A_N 0x0E +#define PKHA_FUNC_MR_PRIMER_TEST 0x0F +#define PKHA_FUNC_MOD_CHECK_POINT 0x1C + +/* PKHA Copy Memory Source and Destination */ +#define PKHA_REG_SRC(reg) SHIFT_U32((PKHA_REG_##reg) & 0x7, 17) +#define PKHA_REG_DST(reg) SHIFT_U32((PKHA_REG_##reg) & 0x3, 10) +#define PKHA_REG_A 0x0 +#define PKHA_REG_B 0x1 +#define PKHA_REG_E 0x2 +#define PKHA_REG_N 0x3 + +#define PKHA_SEG_SRC(seg) SHIFT_U32((seg) & 0x3, 8) +#define PKHA_SEG_DST(seg) SHIFT_U32((seg) & 0x3, 6) + +#define PKHA_CPY_SRC(src) PKHA_CPY_SRC_##src +#define PKHA_CPY_SRC_A0 (PKHA_REG_SRC(A) | PKHA_SEG_SRC(0)) +#define PKHA_CPY_SRC_A1 (PKHA_REG_SRC(A) | PKHA_SEG_SRC(1)) +#define PKHA_CPY_SRC_A2 (PKHA_REG_SRC(A) | PKHA_SEG_SRC(2)) +#define PKHA_CPY_SRC_A3 (PKHA_REG_SRC(A) | PKHA_SEG_SRC(3)) +#define PKHA_CPY_SRC_B0 (PKHA_REG_SRC(B) | PKHA_SEG_SRC(0)) +#define PKHA_CPY_SRC_B1 (PKHA_REG_SRC(B) | PKHA_SEG_SRC(1)) +#define PKHA_CPY_SRC_B2 (PKHA_REG_SRC(B) | PKHA_SEG_SRC(2)) +#define PKHA_CPY_SRC_B3 (PKHA_REG_SRC(B) | PKHA_SEG_SRC(3)) +#define PKHA_CPY_SRC_N0 (PKHA_REG_SRC(N) | PKHA_SEG_SRC(0)) +#define PKHA_CPY_SRC_N1 (PKHA_REG_SRC(N) | PKHA_SEG_SRC(1)) +#define PKHA_CPY_SRC_N2 (PKHA_REG_SRC(N) | PKHA_SEG_SRC(2)) +#define PKHA_CPY_SRC_N3 (PKHA_REG_SRC(N) | PKHA_SEG_SRC(3)) + +#define PKHA_CPY_DST(dst) PKHA_CPY_DST_##dst +#define PKHA_CPY_DST_A0 (PKHA_REG_DST(A) | PKHA_SEG_DST(0)) +#define PKHA_CPY_DST_A1 (PKHA_REG_DST(A) | PKHA_SEG_DST(1)) +#define PKHA_CPY_DST_A2 (PKHA_REG_DST(A) | PKHA_SEG_DST(2)) +#define PKHA_CPY_DST_A3 (PKHA_REG_DST(A) | PKHA_SEG_DST(3)) +#define PKHA_CPY_DST_B0 (PKHA_REG_DST(B) | PKHA_SEG_DST(0)) +#define PKHA_CPY_DST_B1 (PKHA_REG_DST(B) | PKHA_SEG_DST(1)) +#define PKHA_CPY_DST_B2 (PKHA_REG_DST(B) | PKHA_SEG_DST(2)) +#define PKHA_CPY_DST_B3 (PKHA_REG_DST(B) | PKHA_SEG_DST(3)) +#define PKHA_CPY_DST_N0 (PKHA_REG_DST(N) | PKHA_SEG_DST(0)) +#define PKHA_CPY_DST_N1 (PKHA_REG_DST(N) | PKHA_SEG_DST(1)) +#define PKHA_CPY_DST_N2 (PKHA_REG_DST(N) | PKHA_SEG_DST(2)) +#define PKHA_CPY_DST_N3 (PKHA_REG_DST(N) | PKHA_SEG_DST(3)) +#define PKHA_CPY_DST_E (PKHA_REG_DST(E)) + +/* + * Descriptor Protocol Data Block + */ +/* RSA Encryption */ +#define PDB_RSA_ENC_SGT_F SHIFT_U32(1, 31) +#define PDB_RSA_ENC_SGT_G SHIFT_U32(1, 30) +#define PDB_RSA_ENC_E_SIZE(len) SHIFT_U32((len) & 0xFFF, 12) +#define PDB_RSA_ENC_N_SIZE(len) SHIFT_U32((len) & 0xFFF, 0) +#define PDB_RSA_ENC_F_SIZE(len) SHIFT_U32((len) & 0xFFF, 0) + +/* RSA Decryption */ +#define PDB_RSA_DEC_SGT_G SHIFT_U32(1, 31) +#define PDB_RSA_DEC_SGT_F SHIFT_U32(1, 30) +#define PDB_RSA_DEC_D_SIZE(len) SHIFT_U32((len) & 0xFFF, 12) +#define PDB_RSA_DEC_N_SIZE(len) SHIFT_U32((len) & 0xFFF, 0) +#define PDB_RSA_DEC_Q_SIZE(len) SHIFT_U32((len) & 0xFFF, 12) +#define PDB_RSA_DEC_P_SIZE(len) SHIFT_U32((len) & 0xFFF, 0) + +/* RSA Finalize Key */ +#define PDB_RSA_KEY_P_SIZE(len) SHIFT_U32((len) & 0x1FF, 0) +#define PDB_RSA_KEY_E_SIZE(len) SHIFT_U32((len) & 0x3FF, 0) +#define PDB_RSA_KEY_N_SIZE(len) SHIFT_U32((len) & 0x3FF, 16) + +/* Manufacturing Curve Select */ +#define PDB_SGT_MP_SIGN_MSG SHIFT_U32(1, 31) +#define PDB_SGT_MP_SIGN_C SHIFT_U32(1, 29) +#define PDB_SGT_MP_SIGN_D SHIFT_U32(1, 28) +#define PDB_MP_CSEL_P256 0x03 +#define PDB_MP_CSEL_P384 0x04 +#define PDB_MP_CSEL_P521 0x05 + +/* Public Key Generation */ +#define PDB_PKGEN_PD1 SHIFT_U32(1, 25) +/* Public Key Signature */ +#define PDB_PKSIGN_PD1 SHIFT_U32(1, 22) +/* Public Key Verify */ +#define PDB_PKVERIFY_PD1 SHIFT_U32(1, 22) +/* Shared Secret */ +#define PDB_SHARED_SECRET_PD1 SHIFT_U32(1, 25) + +/* DSA Signatures */ +#define PDB_DSA_SIGN_N(len) SHIFT_U32((len) & (0x7F), 0) +#define PDB_DSA_SIGN_L(len) SHIFT_U32((len) & (0x3FF), 7) + +/* SGT Flags Signature */ +#define PDB_SGT_PKSIGN_MSG SHIFT_U32(1, 27) +#define PDB_SGT_PKSIGN_SIGN_C SHIFT_U32(1, 26) +#define PDB_SGT_PKSIGN_SIGN_D SHIFT_U32(1, 25) + +/* DSA Verify */ +#define PDB_DSA_VERIF_N(len) SHIFT_U32((len) & (0x7F), 0) +#define PDB_DSA_VERIF_L(len) SHIFT_U32((len) & (0x3FF), 7) + +/* SGT Flags Verify */ +#define PDB_SGT_PKVERIF_MSG SHIFT_U32(1, 27) +#define PDB_SGT_PKVERIF_SIGN_C SHIFT_U32(1, 26) +#define PDB_SGT_PKVERIF_SIGN_D SHIFT_U32(1, 25) + +/* SGT Flags Shared Secret */ +#define PDB_SGT_PKDH_SECRET SHIFT_U32(1, 27) + +/* DL Keypair Generation */ +#define PDB_DL_KEY_L_SIZE(len) SHIFT_U32((len) & (0x3FF), 7) +#define PDB_DL_KEY_N_MASK 0x7F +#define PDB_DL_KEY_N_SIZE(len) SHIFT_U32((len) & (PDB_DL_KEY_N_MASK), 0) + +/* ECC Domain Selection */ +#define PDB_ECC_ECDSEL(curve) SHIFT_U32((curve) & 0x3F, 7) + +/* Black key padding */ +#define BLACK_KEY_NONCE_SIZE 6 +#define BLACK_KEY_ICV_SIZE 6 + +/* + * ECC Predefined Domain + */ +enum caam_ecc_curve { + CAAM_ECC_P192 = (0x00), + CAAM_ECC_P224, + CAAM_ECC_P256, + CAAM_ECC_P384, + CAAM_ECC_P521, + CAAM_ECC_MAX, + CAAM_ECC_UNKNOWN = (0xFF), +}; + +/* + * Blob encapsulation + */ +#define BLOB_KEY_MODIFIER_SIZE 16 +#define BLOB_KEY_BLOB_SIZE 32 +#define BLOB_MAC_SIZE 16 +#define BLOB_MAX_BUFFER_LEN ((1ull << 32) - 1) +#define CAAM_CRYPTO_BLOB_OVERHEAD ((BLOB_KEY_BLOB_SIZE) + (BLOB_MAC_SIZE)) + +#endif /* __CAAM_DESC_DEFINES_H__ */ diff --git a/sys/arm64/qoriq/caam/jr/caam_desc_helper.h b/sys/arm64/qoriq/caam/jr/caam_desc_helper.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_desc_helper.h @@ -0,0 +1,568 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2018-2021 NXP + * + * Brief CAAM Descriptor interface. + */ + +/* + * File imported from OP-TEE. + */ + +#ifndef __CAAM_DESC_HELPER_H__ +#define __CAAM_DESC_HELPER_H__ + +#include + +#include "caam_desc_defines.h" + +/* + * Returns the descriptor size in bytes of nbEntries + */ +#define DESC_SZBYTES(nbentries) ((nbentries) * sizeof(uint32_t)) + +/* + * Descriptor Header starting at idx w/o descriptor length + */ +#define DESC_HDR(idx) (CMD_HDR_JD_TYPE | HDR_JD_ONE | HDR_JD_START_IDX(idx)) + +/* + * Shared Descriptor Header starting at idx + */ +#define DESC_SHR_HDR(idx) (CMD_HDR_SHR_TYPE | HDR_JD_ONE | HDR_JD_START_IDX(idx)) + +/* + * Descriptor Header starting at index 0 with descriptor length len + */ +#define DESC_HEADER(len) (DESC_HDR(0) | HDR_JD_DESCLEN(len)) + +/* + * Shared descriptor header starting at index 0 with length len + */ +#define DESC_SHR_HEADER(len) (DESC_SHR_HDR(0) | HDR_JD_DESCLEN(len)) + +/* + * Descriptor Header starting at idx with descriptor length len + */ +#define DESC_HEADER_IDX(len, idx) (DESC_HDR(idx) | HDR_JD_DESCLEN(len)) + +/* + * Jump Local of class cla to descriptor offset if test meet the + * condition cond + */ +#define JUMP_LOCAL(cla, test, cond, offset) \ + (CMD_JUMP_TYPE | CMD_CLASS(cla) | JUMP_TYPE(LOCAL) | \ + JUMP_TST_TYPE(test) | (cond) | JMP_LOCAL_OFFSET(offset)) + +/* + * Jump Local of no class to descriptor offset if test meet the + * condition cond + */ +#define JUMP_CNO_LOCAL(test, cond, offset) \ + JUMP_LOCAL(CLASS_NO, test, cond, offset) + +/* + * Jump Local of class 1 to descriptor offset if test meet the + * condition cond + */ +#define JUMP_C1_LOCAL(test, cond, offset) \ + JUMP_LOCAL(CLASS_1, test, cond, offset) + +/* + * First decrement specified source then + * Jump Local of no class to descriptor offset if test meet the + * condition cond + */ +#define JUMP_CNO_LOCAL_DEC(test, src, cond, offset) \ + (CMD_JUMP_TYPE | CMD_CLASS(CLASS_NO) | JUMP_TYPE(LOCAL_DEC) | \ + JUMP_TST_TYPE(test) | JMP_SRC(src) | (cond) | \ + JMP_LOCAL_OFFSET(offset)) + +/* + * Wait until test condition meet and jump next + */ +#define WAIT_COND(test, cond) \ + (JUMP_LOCAL(CLASS_NO, test, JMP_COND(cond), 1) | JMP_JSL) + +/* + * Jump No Local of class cla to descriptor offset if test meet the + * condition cond + */ +#define JUMP_NOTLOCAL(cla, test, cond) \ + (CMD_JUMP_TYPE | CMD_CLASS(cla) | JUMP_TYPE(NON_LOCAL) | \ + JUMP_TST_TYPE(test) | (cond)) + +/* + * User Halt with error if test meet the condition cond + */ +#define HALT_USER(test, cond, error) \ + (CMD_JUMP_TYPE | JUMP_TYPE(HALT_USER_STATUS) | JUMP_TST_TYPE(test) | \ + JMP_COND(cond) | JMP_LOCAL_OFFSET(error)) + +/* + * Load Immediate value of length len to register dst of class cla + */ +#define LD_IMM(cla, dst, len) \ + (CMD_LOAD_TYPE | CMD_CLASS(cla) | CMD_IMM | LOAD_DST(dst) | \ + LOAD_LENGTH(len)) + +/** + * @brief Load Immediate value of length \a len to register \a dst of + * class \a cla starting of register offset \a off + */ +#define LD_IMM_OFF(cla, dst, len, off) \ + (CMD_LOAD_TYPE | CMD_CLASS(cla) | CMD_IMM | LOAD_DST(dst) | \ + LOAD_OFFSET(off) | LOAD_LENGTH(len)) + +/* + * Load Immediate value of length len to register dst w/o class + */ +#define LD_NOCLASS_IMM(dst, len) LD_IMM(CLASS_NO, dst, len) + +/* + * Load value of length len to register dst of class cla + */ +#define LD_NOIMM(cla, dst, len) \ + (CMD_LOAD_TYPE | CMD_CLASS(cla) | LOAD_DST(dst) | LOAD_LENGTH(len)) + +/* + * Load value of length len to register dst of class cla starting + * at register offset off + */ +#define LD_NOIMM_OFF(cla, dst, len, off) \ + (CMD_LOAD_TYPE | CMD_CLASS(cla) | LOAD_DST(dst) | LOAD_OFFSET(off) | \ + LOAD_LENGTH(len)) + +/* + * FIFO Load to register dst class cla with action act + */ +#define FIFO_LD(cla, dst, act, len) \ + (CMD_FIFO_LOAD_TYPE | CMD_CLASS(cla) | FIFO_LOAD_INPUT(dst) | \ + FIFO_LOAD_ACTION(act) | FIFO_LOAD_LENGTH(len)) + +/* + * FIFO Load to register dst class cla with action act. + * Pointer is a Scatter/Gather Table + */ +#define FIFO_LD_SGT(cla, dst, act, len) \ + (CMD_FIFO_LOAD_TYPE | CMD_CLASS(cla) | CMD_SGT | \ + FIFO_LOAD_INPUT(dst) | FIFO_LOAD_ACTION(act) | FIFO_LOAD_LENGTH(len)) + +/* + * FIFO Load to register dst class cla with action act. + * Pointer is a Scatter/Gather Table + * The length is externally defined + */ +#define FIFO_LD_SGT_EXT(cla, dst, act) \ + (CMD_FIFO_LOAD_TYPE | CMD_CLASS(cla) | CMD_SGT | FIFO_LOAD_EXT | \ + FIFO_LOAD_INPUT(dst) | FIFO_LOAD_ACTION(act)) + +/* + * FIFO Load to register dst class cla with action act. + * The length is externally defined + */ +#define FIFO_LD_EXT(cla, dst, act) \ + (CMD_FIFO_LOAD_TYPE | FIFO_LOAD_EXT | CMD_CLASS(cla) | \ + FIFO_LOAD_INPUT(dst) | FIFO_LOAD_ACTION(act)) + +/* + * FIFO Load Immediate data length len to register dst class cla + * with action act. + */ +#define FIFO_LD_IMM(cla, dst, act, len) \ + (CMD_FIFO_LOAD_TYPE | CMD_IMM | CMD_CLASS(cla) | \ + FIFO_LOAD_INPUT(dst) | FIFO_LOAD_ACTION(act) | FIFO_LOAD_LENGTH(len)) + +/* + * Store value of length len from register src of class cla + */ +#define ST_NOIMM(cla, src, len) \ + (CMD_STORE_TYPE | CMD_CLASS(cla) | STORE_SRC(src) | STORE_LENGTH(len)) + +/* + * Store value of length len from register src of class cla + * Pointer is a Scatter/Gather Table + */ +#define ST_SGT_NOIMM(cla, src, len) \ + (CMD_STORE_TYPE | CMD_CLASS(cla) | CMD_SGT | STORE_SRC(src) | \ + STORE_LENGTH(len)) + +/* + * Store value of length len from register src of class cla starting + * at register offset off + */ +#define ST_NOIMM_OFF(cla, src, len, off) \ + (CMD_STORE_TYPE | CMD_CLASS(cla) | STORE_SRC(src) | \ + STORE_OFFSET(off) | STORE_LENGTH(len)) + +/* + * Store value of length len from register src of class cla + */ +#define ST_NOIMM_SEQ(cla, src, len) \ + (CMD_STORE_SEQ_TYPE | CMD_CLASS(cla) | STORE_SRC(src) | \ + STORE_LENGTH(len)) + +/* + * FIFO Store from register src of length len + */ +#define FIFO_ST(src, len) \ + (CMD_FIFO_STORE_TYPE | FIFO_STORE_OUTPUT(src) | FIFO_STORE_LENGTH(len)) + +/* + * FIFO Store from register src. + * The length is externally defined + */ +#define FIFO_ST_EXT(src) \ + (CMD_FIFO_STORE_TYPE | FIFO_STORE_EXT | FIFO_STORE_OUTPUT(src)) + +/* + * FIFO Store from register src of length len. + * Pointer is a Scatter/Gather Table + */ +#define FIFO_ST_SGT(src, len) \ + (CMD_FIFO_STORE_TYPE | CMD_SGT | FIFO_STORE_OUTPUT(src) | \ + FIFO_STORE_LENGTH(len)) + +/* + * FIFO Store from register src. + * Pointer is a Scatter/Gather Table + * The length is externally defined + */ +#define FIFO_ST_SGT_EXT(src) \ + (CMD_FIFO_STORE_TYPE | CMD_SGT | FIFO_STORE_EXT | \ + FIFO_STORE_OUTPUT(src)) + +/* + * SEQ FIFO Store from register src of length len + */ +#define FIFO_ST_SEQ(src, len) \ + (CMD_SEQ_FIFO_STORE_TYPE | FIFO_STORE_OUTPUT(src) | \ + FIFO_STORE_LENGTH(len)) + +/* + * RNG State Handle instantation operation for sh ID + */ +#define RNG_SH_INST(sh) \ + (CMD_OP_TYPE | OP_TYPE(CLASS1) | OP_ALGO(RNG) | ALGO_RNG_SH(sh) | \ + ALGO_AS(RNG_INSTANTIATE) | ALGO_RNG_PR) + +/* + * RNG Generates Secure Keys + */ +#define RNG_GEN_SECKEYS \ + (CMD_OP_TYPE | OP_TYPE(CLASS1) | OP_ALGO(RNG) | ALGO_RNG_SK | \ + ALGO_AS(RNG_GENERATE)) + +/* + * RNG Generates Data + */ +#define RNG_GEN_DATA \ + (CMD_OP_TYPE | OP_TYPE(CLASS1) | OP_ALGO(RNG) | ALGO_AS(RNG_GENERATE)) + +/* + * Hash Init Operation of algorithm algo + */ +#define HASH_INIT(algo) \ + (CMD_OP_TYPE | OP_TYPE(CLASS2) | (algo) | ALGO_AS(INIT) | ALGO_ENCRYPT) + +/* + * Hash Update Operation of algorithm algo + */ +#define HASH_UPDATE(algo) \ + (CMD_OP_TYPE | OP_TYPE(CLASS2) | (algo) | ALGO_AS(UPDATE) | \ + ALGO_ENCRYPT) + +/* + * Hash Final Operation of algorithm algo + */ +#define HASH_FINAL(algo) \ + (CMD_OP_TYPE | OP_TYPE(CLASS2) | (algo) | ALGO_AS(FINAL) | ALGO_ENCRYPT) + +/* + * Hash Init and Final Operation of algorithm algo + */ +#define HASH_INITFINAL(algo) \ + (CMD_OP_TYPE | OP_TYPE(CLASS2) | (algo) | ALGO_AS(INIT_FINAL) | \ + ALGO_ENCRYPT) + +/* + * HMAC Init Decryption Operation of algorithm algo + */ +#define HMAC_INIT_DECRYPT(algo) \ + (CMD_OP_TYPE | OP_TYPE(CLASS2) | (algo) | ALGO_AS(INIT) | \ + ALGO_AAI(DIGEST_HMAC) | ALGO_DECRYPT) + +/* + * HMAC Init and Final Operation of algorithm algo with Precomp key + */ +#define HMAC_INITFINAL_PRECOMP(algo) \ + (CMD_OP_TYPE | OP_TYPE(CLASS2) | (algo) | ALGO_AS(INIT_FINAL) | \ + ALGO_AAI(DIGEST_HMAC_PRECOMP) | ALGO_ENCRYPT) + +/* + * HMAC Init Operation of algorithm algo with Precomp key + */ +#define HMAC_INIT_PRECOMP(algo) \ + (CMD_OP_TYPE | OP_TYPE(CLASS2) | (algo) | ALGO_AS(INIT) | \ + ALGO_AAI(DIGEST_HMAC_PRECOMP) | ALGO_ENCRYPT) + +/* + * HMAC Final Operation of algorithm algo with Precomp key + */ +#define HMAC_FINAL_PRECOMP(algo) \ + (CMD_OP_TYPE | OP_TYPE(CLASS2) | (algo) | ALGO_AS(FINAL) | \ + ALGO_AAI(DIGEST_HMAC_PRECOMP) | ALGO_ENCRYPT) + +/* + * Cipher Init and Final Operation of algorithm algo + */ +#define CIPHER_INITFINAL(algo, encrypt) \ + (CMD_OP_TYPE | OP_TYPE(CLASS1) | (algo) | ALGO_AS(INIT_FINAL) | \ + ((encrypt) ? ALGO_ENCRYPT : ALGO_DECRYPT)) + +/* + * Cipher Init Operation of algorithm algo + */ +#define CIPHER_INIT(algo, encrypt) \ + (CMD_OP_TYPE | OP_TYPE(CLASS1) | (algo) | ALGO_AS(INIT) | \ + ((encrypt) ? ALGO_ENCRYPT : ALGO_DECRYPT)) + +/* + * Cipher Update Operation of algorithm algo + */ +#define CIPHER_UPDATE(algo, encrypt) \ + (CMD_OP_TYPE | OP_TYPE(CLASS1) | (algo) | ALGO_AS(UPDATE) | \ + ((encrypt) ? ALGO_ENCRYPT : ALGO_DECRYPT)) + +/* + * Cipher Final Operation of algorithm algo + */ +#define CIPHER_FINAL(algo, encrypt) \ + (CMD_OP_TYPE | OP_TYPE(CLASS1) | (algo) | ALGO_AS(FINAL) | \ + ((encrypt) ? ALGO_ENCRYPT : ALGO_DECRYPT)) + +/* + * Cipher Init Final Operation of algorithm algo + */ +#define CIPHER_INIT_FINAL(algo, encrypt) \ + (CMD_OP_TYPE | OP_TYPE(CLASS1) | (algo) | ALGO_AS(INIT_FINAL) | \ + ((encrypt) ? ALGO_ENCRYPT : ALGO_DECRYPT)) + +/* + * Load a class cla key of length len to register dst. + * Immediate version of instruction. + */ +#define LD_KEY_IMM(cla, dst, len) \ + (CMD_KEY_TYPE | CMD_CLASS(cla) | KEY_DEST(dst) | \ + KEY_LENGTH(len) | CMD_IMM) + +/* + * Load a class cla key of length len to register dst. + * Key can be stored in plain text. + */ +#define LD_KEY_PLAIN(cla, dst, len) \ + (CMD_KEY_TYPE | CMD_CLASS(cla) | KEY_PTS | KEY_DEST(dst) | \ + KEY_LENGTH(len)) + +/* + * Load a class cla key of length len to register dst. + * Key can be stored in plain text. + * Pointer is a Scatter/Gatter Table + */ +#define LD_KEY_SGT_PLAIN(cla, dst, len) \ + (CMD_KEY_TYPE | CMD_CLASS(cla) | CMD_SGT | KEY_PTS | KEY_DEST(dst) | \ + KEY_LENGTH(len)) + +/* + * Load a split key of length len. + */ +#define LD_KEY_SPLIT(len) \ + (CMD_KEY_TYPE | CMD_CLASS(CLASS_2) | KEY_DEST(MDHA_SPLIT) | \ + KEY_LENGTH(len)) + +/* + * MPPRIVK generation function. + */ +#define MPPRIVK (CMD_OP_TYPE | OP_TYPE(ENCAPS) | PROTID(MPKEY)) + +/* + * MPPUBK generation function. + */ +#define MPPUBK (CMD_OP_TYPE | OP_TYPE(DECAPS) | PROTID(MPKEY)) + +/* + * MPSIGN function. + */ +#define MPSIGN_OP (CMD_OP_TYPE | OP_TYPE(DECAPS) | PROTID(MPSIGN)) + +/* + * Operation Mathematical of length len + * dest = src0 (operation func) src1 + */ +#define MATH(func, src0, src1, dst, len) \ + (CMD_MATH_TYPE | MATH_FUNC(func) | MATH_SRC0(src0) | MATH_SRC1(src1) | \ + MATH_DST(dst) | MATH_LENGTH(len)) + +/* + * Operation Mathematical of length len using an immediate value as operand 1 + * dest = src (operation func) val + */ +#define MATHI_OP1(func, src, val, dst, len) \ + (CMD_MATHI_TYPE | MATH_FUNC(func) | MATHI_SRC(src) | \ + MATHI_IMM_VALUE(val) | MATHI_DST(dst) | MATH_LENGTH(len)) + +/* + * PKHA Copy function from src to dst. Copy number of words specified + * in Source size register + */ +#define PKHA_CPY_SSIZE(src, dst) \ + (CMD_OP_TYPE | OP_TYPE(PKHA) | PKHA_ALG | PKHA_FUNC(CPY_SSIZE) | \ + PKHA_CPY_SRC(src) | PKHA_CPY_DST(dst)) + +/* + * PKHA Copy N-Size function from src to dst. Copy number of words specified + * in PKHA N size register + */ +#define PKHA_CPY_NSIZE(src, dst) \ + (CMD_OP_TYPE | OP_TYPE(PKHA) | PKHA_ALG | PKHA_FUNC(CPY_NSIZE) | \ + PKHA_CPY_SRC(src) | PKHA_CPY_DST(dst)) + +/* + * PKHA Operation op result into dst + */ +#define PKHA_OP(op, dst) \ + (CMD_OP_TYPE | OP_TYPE(PKHA) | PKHA_ALG | PKHA_FUNC(op) | \ + PKHA_OUTSEL(dst)) + +/* + * PKHA Binomial operation op result into dst + */ +#define PKHA_F2M_OP(op, dst) \ + (CMD_OP_TYPE | OP_TYPE(PKHA) | PKHA_ALG | PKHA_F2M | PKHA_FUNC(op) | \ + PKHA_OUTSEL(dst)) + +/* + * Move src to dst + */ +#define MOVE(src, dst, off, len) \ + (CMD_MOVE_TYPE | MOVE_SRC(src) | MOVE_DST(dst) | MOVE_OFFSET(off) | \ + MOVE_LENGTH(len)) + +/* + * Move src to dst and wait until completion + */ +#define MOVE_WAIT(src, dst, off, len) \ + (CMD_MOVE_TYPE | MOVE_WC | MOVE_SRC(src) | MOVE_DST(dst) | \ + MOVE_OFFSET(off) | MOVE_LENGTH(len)) + +/* + * RSA Encryption using format + */ +#define RSA_ENCRYPT(format) \ + (CMD_OP_TYPE | PROTID(RSA_ENC) | PROT_RSA_FMT(format)) + +/* + * RSA Decryption using format + */ +#define RSA_DECRYPT(format) \ + (CMD_OP_TYPE | PROTID(RSA_DEC) | PROT_RSA_FMT(format)) + +/* + * RSA Finalize Key in format + */ +#define RSA_FINAL_KEY(format) \ + (CMD_OP_TYPE | PROTID(RSA_FINISH_KEY) | PROT_RSA_KEY(format)) + +/* + * Public Keypair generation + */ +#define PK_KEYPAIR_GEN(type) \ + (CMD_OP_TYPE | OP_TYPE(UNI) | PROTID(PKKEY) | PROT_PK_TYPE(type)) + +/* + * DSA/ECDSA signature of message hashed + */ +#define DSA_SIGN(type) \ + (CMD_OP_TYPE | OP_TYPE(UNI) | PROTID(DSASIGN) | PROT_PK_MSG(HASHED) | \ + PROT_PK_TYPE(type)) + +/* + * DSA/ECDSA signature verify message hashed + */ +#define DSA_VERIFY(type) \ + (CMD_OP_TYPE | OP_TYPE(UNI) | PROTID(DSAVERIFY) | \ + PROT_PK_MSG(HASHED) | PROT_PK_TYPE(type)) + +/* + * DH/ECC Shared Secret + */ +#define SHARED_SECRET(type) \ + (CMD_OP_TYPE | OP_TYPE(UNI) | PROTID(SHARED_SECRET) | \ + PROT_PK_TYPE(type)) + +/* + * Blob Master Key Verification + */ +#define BLOB_MSTR_KEY \ + (CMD_OP_TYPE | OP_TYPE(ENCAPS) | PROTID(BLOB) | PROT_BLOB_FMT_MSTR) + +/* + * Blob encapsulation + */ +#define BLOB_ENCAPS \ + (CMD_OP_TYPE | OP_TYPE(ENCAPS) | PROTID(BLOB) | \ + PROT_BLOB_FORMAT(NORMAL)) + +/* + * Blob decapsulation + */ +#define BLOB_DECAPS \ + (CMD_OP_TYPE | OP_TYPE(DECAPS) | PROTID(BLOB) | \ + PROT_BLOB_FORMAT(NORMAL)) + +/* + * Black key CCM size + */ +#define BLACK_KEY_CCM_SIZE(size) \ + (ROUNDUP(size, 8) + BLACK_KEY_NONCE_SIZE + BLACK_KEY_ICV_SIZE) + +/* + * Black key ECB size + */ +#define BLACK_KEY_ECB_SIZE(size) ROUNDUP(size, 16) + +/* + * Sequence Input Pointer of length len + */ +#define SEQ_IN_PTR(len) (CMD_SEQ_IN_TYPE | SEQ_LENGTH(len)) + +/* + * Sequence Input Pointer with length in EXT_LENGTH optional word + */ +#define SEQ_IN_PTR_EXT ((SEQ_IN_PTR(0)) | SEQ_EXT) + +/* + * Sequence Output Pointer of length len + */ +#define SEQ_OUT_PTR(len) (CMD_SEQ_OUT_TYPE | SEQ_LENGTH(len)) + +/* + * Sequence Output Pointer with length in EXT_LENGTH optional word + */ +#define SEQ_OUT_PTR_EXT ((SEQ_OUT_PTR(0)) | SEQ_EXT) + +/* + * Sequence Output SGT of length len + */ +#define SEQ_OUT_SGT_PTR(len) (CMD_SEQ_OUT_TYPE | CMD_SGT | SEQ_LENGTH(len)) + +struct caam_sgt_entry { + uint32_t ptr_hi; + uint32_t ptr_lo; + uint32_t len_f_e; + uint32_t offset; +}; + +#define CAAM_SGT_FINAL 0x40000000 + +#endif /* __CAAM_DESC_HELPER_H__ */ diff --git a/sys/arm64/qoriq/caam/jr/caam_jobdesc.h b/sys/arm64/qoriq/caam/jr/caam_jobdesc.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_jobdesc.h @@ -0,0 +1,69 @@ +/* + * Copyright 2017-2021 NXP + * Copyright 2023 Alstom Group + * Copyright 2023 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef CAAM_JOBDESC_H +#define CAAM_JOBDESC_H + +#include + +#include +#include + +#define DESC_LEN_MASK 0x7f + +#define DESC_START_SHIFT 16 + +#define CLASS_SHIFT 25 + +#define CMD_SHIFT 27 +#define OP_TYPE_SHIFT 24 +#define OP_PCLID_SHIFT 16 + +/* + * @brief Initialize the descriptor. + * + * @param [in] desc descriptor pointer + */ +void caam_jobdesc_init(uint32_t *desc); + +/* + * @brief Update start index in first word of descriptor. + * + * @param [in] desc descriptor pointer + * @param [in] index new start index + */ +void caam_jobdesc_update_start_index(uint32_t *desc, uint32_t index); + +/* + * @brief Return Length of descriptor from first word. + * + * @param [in] desc descriptor pointer + * + * @retval :: uint32_t descriptor length + */ +uint32_t caam_jobdesc_length(uint32_t *desc); + +/* + * @brief Add word in the descriptor and increment the length. + * + * @param [in] desc descriptor pointer + * @param [in] word word to append + */ +void caam_jobdesc_add_word(uint32_t *desc, uint32_t word); + +/* + * @brief Add Pointer to the descriptor and increment the length. + * + * @param [in] desc descriptor pointer + * @param [in] ptr pointer to append + * @param [in] little_endian the endianess of the job descriptor + */ +void caam_jobdesc_add_ptr(uint32_t *desc, bus_addr_t ptr, bool little_endian); + +#endif /* CAAM_JOBDESC_H */ diff --git a/sys/arm64/qoriq/caam/jr/caam_jobdesc.c b/sys/arm64/qoriq/caam/jr/caam_jobdesc.c new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_jobdesc.c @@ -0,0 +1,70 @@ +/* + * Copyright 2017-2020 NXP + * Copyright 2023 Alstom Group + * Copyright 2023 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include + +#include + +#include "caam_jobdesc.h" +#include "caam_jr.h" +#include "caam_jr_hw.h" + +void +caam_jobdesc_init(uint32_t *desc) +{ + *desc = 0; +} + +void +caam_jobdesc_update_start_index(uint32_t *desc, uint32_t index) +{ + desc[0] |= (index << DESC_START_SHIFT); +} + +uint32_t +caam_jobdesc_length(uint32_t *desc) +{ + return desc[0] & DESC_LEN_MASK; +} + +void +caam_jobdesc_add_word(uint32_t *desc, uint32_t word) +{ + uint32_t len = caam_jobdesc_length(desc); + + /* We can add only if there is place */ + MPASS(len < MAX_DESC_SIZE_WORDS); + + /* Add Word at Last */ + uint32_t *last = desc + len; + *last = word; + + /* Increase the length */ + desc[0] += 1; +} + +void +caam_jobdesc_add_ptr(uint32_t *desc, bus_addr_t ptr, bool little_endian) +{ + uint32_t len = caam_jobdesc_length(desc); + + /* Add Word at Last */ + ptr_addr_t *ptr_addr = (ptr_addr_t *)(desc + len); + + if (little_endian) { + ptr_addr->m_halves.high = PHYS_ADDR_HI(ptr); + ptr_addr->m_halves.low = PHYS_ADDR_LO(ptr); + } else { + ptr_addr->m_halves.high = PHYS_ADDR_LO(ptr); + ptr_addr->m_halves.low = PHYS_ADDR_HI(ptr); + } + + /* Increase the length */ + desc[0] += (uint32_t)(sizeof(bus_addr_t) / sizeof(uint32_t)); +} diff --git a/sys/arm64/qoriq/caam/jr/caam_jr.h b/sys/arm64/qoriq/caam/jr/caam_jr.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_jr.h @@ -0,0 +1,315 @@ +/* + * Copyright 2017-2021 NXP + * Copyright 2023 Alstom Group + * Copyright 2023 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef CAAM_JR_H +#define CAAM_JR_H + +#include +#include +#include +#include + +#include "caam_jr_cfg.h" + +/* The maximum size of a CAAM descriptor, in WORDs (32 bits). */ +#define MAX_DESC_SIZE_WORDS 64 + +/* Return codes for JR driver APIs */ +typedef enum caam_jr_return_code_e { + CAAM_SUCCESS = 0, + CAAM_INVALID_INPUT_PARAM, + CAAM_OUT_OF_MEMORY, + CAAM_DESCRIPTOR_IN_FLIGHT, + CAAM_LAST_DESCRIPTOR_IN_FLIGHT, + CAAM_PROCESSING_ERROR, + CAAM_DESC_PROCESSING_ERROR, + CAAM_JR_IS_FULL, + CAAM_DRIVER_RELEASE_IN_PROGRESS, + CAAM_DRIVER_ALREADY_INITIALIZED, + CAAM_DRIVER_NOT_INITIALIZED, + CAAM_JOB_RING_RESET_IN_PROGRESS, + CAAM_RESET_ENGINE_FAILED, + CAAM_ENABLE_IRQS_FAILED, + CAAM_DISABLE_IRQS_FAILED, + CAAM_RETURN_CODE_MAX_VALUE, +} caam_jr_return_code_t; + +typedef struct caam_jr_dma_map { + bus_dmamap_t mmap; + void *buf; + size_t buflen; + bus_addr_t bus_addr; +} caam_jr_dma_map_t; + +/* STRUCTURES AND OTHER TYPEDEFS */ + +/* + * @brief Function called by JR User Space driver to notify every processed + * descriptor. + * + * Callback provided by the User Application. + * Callback is invoked by JR User Space driver for each descriptor processed by + * CAAM + * @param [in] status Status word indicating processing result for + * this descriptor. + * @param [in] arg Opaque data passed by User Application + * It is opaque from JR driver's point of view. + * @param [in] job_ring The job ring handle on which the processed + * descriptor word was enqueued + */ +typedef void ( + *user_callback)(uint32_t *desc, uint32_t status, void *arg, device_t dev); + +/* + * Structure encompassing a job descriptor which is to be processed + * by CAAM. User should also initialise this structure with the callback + * function pointer which will be called by driver after recieving proccessed + * descriptor from CAAM. User data is also passed in this data structure which + * will be sent as an argument to the user callback function. + */ +struct job_descriptor { + uint32_t desc[MAX_DESC_SIZE_WORDS]; + void *arg; + user_callback callback; +}; + +/* + * @brief Jobring callback control structure and utilities + */ +struct jr_job_arg { + struct cv cv; + struct mtx mtx; + uint32_t *desc; + uint32_t status; + device_t dev; + bool done; +}; + +/* + * @brief Initializes jr_job_arg intance + * + * @param [in] job_arg Instance to initialize + * @param [in] name cv and mutex name prefix + */ +#define JR_JOB_ARG_INIT(job_arg, name) \ + memset(&(job_arg), 0, sizeof((job_arg))); \ + mtx_init(&(job_arg).mtx, #name " cv", NULL, MTX_DEF); \ + cv_init(&(job_arg).cv, #name " job") + +/* + * @brief deinitializes jr_job_arg intance + * + * @param [in] job_arg Instance to deinitialize + */ +#define JR_JOB_ARG_DEINIT(job_arg) \ + cv_destroy(&(job_arg).cv); \ + mtx_destroy(&(job_arg).mtx) + +/* + * @brief Blocks until JR_JOB_ARG_SIG_DONE() is performed + * + * job_arg.status (if used) should be up-to-date after the unblock + * + * @param [in] job_arg jr_job_arg instance to watch + */ +#define JR_JOB_ARG_WAIT_DONE(job_arg) \ + mtx_lock(&(job_arg).mtx); \ + if (!(job_arg).done) { \ + cv_wait(&(job_arg).cv, &(job_arg).mtx); \ + } \ + mtx_unlock(&(job_arg).mtx) + +/* + * @brief Unblocks all JR_JOB_ARG_WAIT_DONE() + * + * If used at all, job_arg.status should be set before this call + * + * @param [in] job_arg jr_job_arg intance to signal + */ +#define JR_JOB_ARG_SIG_DONE(job_arg) \ + mtx_lock(&(job_arg).mtx); \ + (job_arg).done = true; \ + cv_broadcast(&(job_arg).cv); \ + mtx_unlock(&(job_arg).mtx) + +/* + * @brief Initializes the CAAM Job Ring + * This functions sets up the job ring for receiving descriptors + * + * @param [in] dev The handle for the CAAM_JR device to + * execute the job on. + * @param [in] jr_mode The mode to use (irq or pool) + * @param [in] irq_coalescing_timer Timer parameter for IRQ mode + * @param [in] irq_coalescing_count Count parameter for IRQ mode + * + * @note Only pool mode is allowed at this time + * @retval :: 0 is returned in case shutdown was successful + * @retval :: -1 is returned in case of some error + */ +int caam_jr_init(device_t dev, uint8_t jr_mode, uint16_t irq_coalescing_timer, + uint8_t irq_coalescing_count); + +/* + * @brief Submit a descriptor for CAAM processing. + * This function creates a "job" which is meant to instruct CAAM HW + * to perform the processing on the input buffer. The "job" is enqueued + * in the Job Ring associated. The function will return after the "job" + * enqueue is finished. The function will not wait for CAAM to + * start or/and finish the "job" processing. + * After the processing is finished the CAAM HW writes the processing result + * to the provided output buffer. + * The Caller must poll JR driver using caam_jr_dequeue() + * to receive notifications of the processing completion + * status. The notifications are received by caller by means of callback + * (see ::user_callback). + * @param [in] dev The handle for the CAAM_JR device to execute + * the job on. + * @param [in] jobdescr The job descriptor structure of type + * struct job_descriptor. This structure + * should be filled with job descriptor along + * with callback function to be called after + * processing of descriptor and some + * opaque data passed to be passed to the + * callback function + * + * @retval ::0 is returned for successful execution + * @retval ::-1 is returned if there is some enqueue failure + */ +int caam_jr_enqueue(device_t dev, struct job_descriptor *jobdescr); + +/* + * @brief Polls for available descriptors processed by CAAM on a specific + * Job Ring + * This function polls the CAAM Job Rings and delivers processed descriptors + * Each processed descriptor has a user_callback registered. + * This user_callback is invoked for each processed descriptor. + * The polling is stopped when "limit" descriptors are notified or when + * there are no more descriptors to notify. + * @note The caam_jr_dequeue() API cannot be called from within a user_callback + * function + * @param [in] dev The handle for the CAAM_JR device to execute + * the job on. + * @param [in] limit This value represents the maximum number + * of processed descriptors that can be + * notified API call on this Job Ring. + * Note that fewer descriptors may be notified + * if enough processed descriptors are not + * available. + * If limit has a negative value, then all + * ready descriptors will be notified. + * + * @retval :: >=0 is returned where retval is the total + * Number of descriptors notified + * during this function call. + * @retval :: -1 is returned in case of some error + */ +int caam_jr_dequeue(device_t dev, int32_t limit); + +/* + * @brief Shut down the CAAM Job Ring + * This functions clears the current jobs and resets the JobRing hardware. + * + * @param [in] dev The handle for the CAAM_JR device to execute + * the job on. + * + * @retval :: 0 is returned in case shutdown was successful + * @retval :: -1 is returned in case of some error + */ +int caam_jr_shutdown(device_t dev); + + +/* + * @brief Check if jobring has currently any jobs enqueued, processing or + * waiting to be dequeued. + * + * @param [in] dev The handle for the CAAM_JR device to check + * + * @retval :: true is returned in case there is any unfinished job on the jr + * @retval :: false is returned in case the jr is idle + */ +bool caam_jr_busy(device_t dev); + +/* + * @brief Getter for dma_tag. + * + * @param [in] dev The handle for the CAAM_JR device. + * + * @retval :: bus_dma_tag_t + */ +bus_dma_tag_t caam_jr_get_tag(device_t dev); + +/* + * @brief Getter for DMA data_tag. + * + * @param [in] dev The handle for the CAAM_JR device. + * + * @retval :: bus_dma_tag_t + */ +bus_dma_tag_t caam_jr_get_data_tag(device_t dev); + +/* caam_jr_dma_map and caam_jr_dma_unmap sync options */ +#define JR_MAP_SYNC (true) +#define JR_MAP_NOSYNC (false) + +/* + * @brief DMA map memory with jobrings DMA tag. + * + * Sync if requested. + * + * @param [in] dev The handle for the CAAM_JR device + * @param [out] bmap DMA mapping details + * @param [in] buf buffer to map + * @param [in] buflen len to map + * @param [in] create_flags dma_map_create flags + * @param [in] load_flags dma_map_load flags + * @param [in] sync make a prewrite sync to DMA memory + * + * @retval :: 0 is returned on success + * @retval :: errno is returned on failure + */ +int caam_jr_dma_map(device_t dev, caam_jr_dma_map_t *bmap, void *buf, size_t buflen, + int create_flags, int load_flags, bool sync); + +/* + * @brief Unmap caam_jr_dma_map() mapped memory. + * + * Sync if requested + * + * @param [in] dev The handle for the CAAM_JR device + * @param [in] bmap DMA mapping details + * @param [in] sync make a postread sync from DMA memory + * + * @retval :: 0 is returned on success + * @retval :: errno is returned on failure + */ +int caam_jr_dma_unmap(device_t dev, caam_jr_dma_map_t *bmap, bool sync); + +/* + * @brief Sync mapped memory after write. + * + * @param [in] dev The handle for the CAAM_JR device + * @param [in] in DMA mapping details + * + * @retval :: 0 is returned on success + * @retval :: errno is returned on failure + */ +void caam_jr_dma_sync_to_dma(device_t dev, caam_jr_dma_map_t *bmap); + +/* + * @brief Sync mapped memory before read. + * + * @param [in] dev The handle for the CAAM_JR device + * @param [out] in DMA mapping details + * + * @retval :: 0 is returned on success + * @retval :: errno is returned on failure + */ +void caam_jr_dma_sync_from_dma(device_t dev, caam_jr_dma_map_t *bmap); + +#endif /* CAAM_JR_H */ diff --git a/sys/arm64/qoriq/caam/jr/caam_jr.c b/sys/arm64/qoriq/caam/jr/caam_jr.c new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_jr.c @@ -0,0 +1,1251 @@ +/* + * Copyright 2021 NXP + * Copyright 2023 Alstom Group + * Copyright 2023 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "../caam.h" +#include "../caam_debug.h" +#include "caam_jr.h" +#include "caam_jr_cfg.h" +#include "caam_jr_hw.h" + +#define CAAM_JR_POOL_MAX_COUNT 1000 /* Pool retry count */ + +/* + * Jobring taskqueue responsible for dequeueing completed jobs + * from the output ring. + * Triggered from jr_intr according to coalescing settings. + */ +struct jobring_tq { + struct taskqueue *tq; + struct task task; + device_t dev; +}; + +/* software context */ +struct caam_jr_softc { + device_t dev; + device_t dev_caam; + struct resource *mem_res; + struct resource *irq_res; + void *irq_cookie; + bus_dma_tag_t dma_tag; + bus_dma_tag_t data_tag; + + struct sec_job_ring_t job_ring; + + caam_jr_dma_map_t ip_ring_map; + uint8_t ip_ring_buf[SEC_DMA_MEM_INPUT_RING_SIZE]; + + caam_jr_dma_map_t op_ring_map; + uint8_t op_ring_buf[SEC_DMA_MEM_OUTPUT_RING_SIZE]; + + caam_jr_dma_map_t desc_ring[SEC_JOB_RING_SIZE]; + + struct jobring_tq *tq; + + int pending; + bool little_endian; +}; + +/* Schedule jobring_worker to run */ +static void caam_jr_sched_dequeue(device_t dev) +{ + struct caam_jr_softc *sc = device_get_softc(dev); + + taskqueue_enqueue(sc->tq->tq, &sc->tq->task); +} + +/* Dequeue finished jobs and unmask interrupts for related jobring */ +static void jobring_worker(void *context, int pending) +{ + int ret; + struct jobring_tq *tq = context; + + CAAM_LOG_DEBUG("Dequeue in progress\n"); + + ret = caam_jr_dequeue(tq->dev, -1); + if (ret == 0) { + CAAM_LOG_DEBUG("Dequeue of %x desc success\n", ret); + } else { + CAAM_LOG_WARN("deq_ret %x\n", ret); + } +} + +/* + * Initialize and return dequeue handling taskqueue. + * Free with caam_free_jobring_task(). +*/ +static struct jobring_tq * caam_create_jobring_task(device_t dev) +{ + struct jobring_tq *jobring_tq; + + jobring_tq = malloc(sizeof(*jobring_tq), M_DEVBUF, M_WAITOK | M_ZERO); + jobring_tq->dev = dev; + + TASK_INIT(&jobring_tq->task, 0, jobring_worker, jobring_tq); + jobring_tq->tq = taskqueue_create_fast( + "caam_jobring_tq", + M_NOWAIT | M_ZERO, + taskqueue_thread_enqueue, + &jobring_tq->tq); + taskqueue_start_threads(&jobring_tq->tq, 1, PI_SOFT, "caam_jobring_th"); + + return jobring_tq; +} + +/* + * Stop and free taskqueue created by caam_create_jobring_task(). + */ +static void +caam_free_jobring_task(struct jobring_tq *tq) +{ + taskqueue_free(tq->tq); + free(tq, M_DEVBUF); +} + +/*----------------------- JobRing SFR access functions ----------------------*/ +/* a Macro that can be used to get the offset of Job Ring register */ +#define jr_reg(reg_name) offsetof(struct jobring_regs, reg_name), #reg_name + +static uint32_t +reg_read(struct caam_jr_softc *sc, uint32_t reg, const char *reg_name) +{ + uint32_t result; + + CAAM_LOG_DEBUG("reg_read(%s[%08X]) --> ", reg_name, reg); + result = bus_read_4(sc->mem_res, reg); + result = sc->little_endian ? le32toh(result): be32toh(result); + + CAAM_LOG_DEBUG("%08X\n", result); + + return result; +} + +static void +reg_write(struct caam_jr_softc *sc, uint32_t reg, const char *reg_name, + uint32_t val) +{ + CAAM_LOG_DEBUG("reg_write(%s[%08X], %08X)\n", reg_name, reg, val); + + val = sc->little_endian ? htole32(val): htobe32(val); + + bus_write_4(sc->mem_res, reg, val); + bus_barrier(sc->mem_res, reg, 4, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); +} + +/* Do a Read-Modify-Write of a jr register, change only masked bits */ +static void +reg_write_mask(struct caam_jr_softc *sc, uint32_t reg, const char *reg_name, + uint32_t val, uint32_t mask) +{ + uint32_t cur; + + cur = reg_read(sc, reg, reg_name); + cur &= mask; + cur |= mask & val; + reg_write(sc, reg, reg_name, cur); +} + +/*-------------------- JobRing hardware access functions --------------------*/ +static inline void +set_jr_input_ring_start_addr(struct caam_jr_softc *sc, bus_addr_t start_addr) +{ + if (sc->little_endian) { + reg_write(sc, jr_reg(irba_h), PHYS_ADDR_HI(start_addr)); + reg_write(sc, jr_reg(irba_l), PHYS_ADDR_LO(start_addr)); + } else { + reg_write(sc, jr_reg(irba_h), PHYS_ADDR_LO(start_addr)); + reg_write(sc, jr_reg(irba_l), PHYS_ADDR_HI(start_addr)); + } +} + +static inline void +set_jr_output_ring_start_addr(struct caam_jr_softc *sc, bus_addr_t start_addr) +{ + if (sc->little_endian) { + reg_write(sc, jr_reg(orba_h), PHYS_ADDR_HI(start_addr)); + reg_write(sc, jr_reg(orba_l), PHYS_ADDR_LO(start_addr)); + } else { + reg_write(sc, jr_reg(orba_h), PHYS_ADDR_LO(start_addr)); + reg_write(sc, jr_reg(orba_l), PHYS_ADDR_HI(start_addr)); + } +} + +/* + * IRJA - Input Ring Jobs Added Register shows + * how many new jobs were added to the Input Ring. + */ +static inline void +add_jr_entries(struct caam_jr_softc *sc, int num) +{ + atomic_add_int(&sc->pending, num); + + /* This action triggers the job execution. + In extreme case the whole job processing will already finish + before we return from this function. */ + reg_write(sc, jr_reg(irja), num); +} + +/* ORJR - Output Ring Jobs Removed Register shows how many jobs were + * removed from the Output Ring for processing by software. This is done after + * the software has processed the entries. + */ +static inline void +remove_jr_entries(struct caam_jr_softc *sc, int num) +{ + reg_write(sc, jr_reg(orjr), num); + atomic_subtract_int(&sc->pending, num); +} + +#ifdef notyet +/* IRSA - Input Ring Slots Available register holds the number of entries in + * the Job Ring's input ring. Once a job is enqueued, the value returned is + * decremented by the hardware by the number of jobs enqueued. + */ +static inline int +get_jr_available_slots(struct caam_jr_softc *sc) +{ + return reg_read(sc, jr_reg(irsa)); +} +#endif + +/* ORSFR - Output Ring Slots Full register holds the number of jobs which were + * processed by the SEC and can be retrieved by the software. Once a job has + * been processed by software, the user will call jr_remove_one_entry in order + * to notify the SEC that the entry was processed + */ +static inline int +get_jr_finished_jobs(struct caam_jr_softc *sc) +{ + return reg_read(sc, jr_reg(orsf)); +} + +/* Unmask interrupts for a jobring */ +static int +enable_jr_irqs(struct caam_jr_softc *sc) +{ + uint32_t reg_val = 0U; + + /* Get the current value of the register */ + reg_val = reg_read(sc, jr_reg(jrcfg1)); + + /* Enable interrupts by disabling interrupt masking*/ + reg_val &= ~JR_REG_JRCFG_LO_IMSK_EN; + + /* Update parameters in HW */ + reg_write(sc, jr_reg(jrcfg1), reg_val); + + CAAM_LOG_DEBUG("Enable interrupts on JR\n"); + + return 0; +} + +/* Mask interrupts for a jobring. This will NOT clear interrupt status */ +static int +disable_jr_irqs(struct caam_jr_softc *sc) +{ + uint32_t reg_val = 0U; + + /* Get the current value of the register */ + reg_val = reg_read(sc, jr_reg(jrcfg1)); + + /* Disable interrupts by enabling interrupt masking*/ + reg_val |= JR_REG_JRCFG_LO_IMSK_EN; + + /* Update parameters in HW */ + reg_write(sc, jr_reg(jrcfg1), reg_val); + + CAAM_LOG_DEBUG("Disable interrupts on JR\n"); + + return 0; +} + +/* + * Group finished jobs before issuing an interrupt. + * SEC should interrupt if irq_coalescing_count jobs finished since last + * interrupt or if irq_coalescing_timer SEC cycles passed since last job completed. + */ +static int +set_jr_coalescing_param(struct caam_jr_softc *sc, uint16_t irq_coalescing_timer, + uint8_t irq_coalescing_count) +{ + uint32_t reg_val = 0U; + + /* 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 */ + reg_write(sc, jr_reg(jrcfg1), reg_val); + + CAAM_LOG_DEBUG("Set coalescing params on jr\n"); + + return 0; +} + +/* Enable set_jr_coalescing_param settings */ +static int +enable_jr_coalescing(struct caam_jr_softc *sc) +{ + uint32_t reg_val = 0U; + + /* Get the current value of the register */ + reg_val = reg_read(sc, jr_reg(jrcfg1)); + + /* Enable coalescing */ + reg_val |= JR_REG_JRCFG_LO_ICEN_EN; + + /* Write in hw */ + reg_write(sc, jr_reg(jrcfg1), reg_val); + + CAAM_LOG_DEBUG("Enabled coalescing on jr\n"); + + return 0; +} + +/* Disable set_jr_coalescing_param settings */ +static int +disable_jr_coalescing(struct caam_jr_softc *sc) +{ + uint32_t reg_val = 0U; + + /* Get the current value of the register */ + reg_val = reg_read(sc, jr_reg(jrcfg1)); + + /* Disable coalescing */ + reg_val &= ~JR_REG_JRCFG_LO_ICEN_EN; + + /* Write in hw */ + reg_write(sc, jr_reg(jrcfg1), reg_val); + + CAAM_LOG_DEBUG("Disabled coalescing on jr"); + + return 0; +} + +/*--------------------- JobRing Error handling functions --------------------*/ +/* @brief Process Jump Halt Condition related errors + * @param [in] error_code The error code in the descriptor status word + */ +static inline void +handle_desc_jmp_halt_cond_err(union jr_error_code error_code) +{ + CAAM_LOG_WARN("JMP %x\n", error_code.error_desc.jmp_halt_cond_src.jmp); + CAAM_LOG_WARN("Descriptor Index: %d\n", + error_code.error_desc.jmp_halt_cond_src.desc_idx); + CAAM_LOG_WARN(" Condition %x\n", error_code.error_desc.jmp_halt_cond_src.cond); +} + +/* @brief Process DECO related errors + * @param [in] error_code The error code in the descriptor status word + */ +static inline void +handle_desc_deco_err(union jr_error_code error_code) +{ + CAAM_LOG_WARN("JMP %x\n", error_code.error_desc.deco_src.jmp); + CAAM_LOG_WARN("Descriptor Index: 0x%x", + 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_LOG_WARN(" Descriptor completed but exceeds the Threshold"); + break; + default: + CAAM_LOG_WARN("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 +handle_desc_jmp_halt_user_err(union jr_error_code error_code) +{ + CAAM_LOG_WARN("Not implemented\n"); +} + +/* @brief Process CCB related errors + * @param [in] error_code The error code in the descriptor status word + */ +static inline void +handle_desc_ccb_err(union jr_error_code jr_error_code) +{ + CAAM_LOG_WARN("Not implemented\n"); +} + +/* @brief Process Job Ring related errors + * @param [in] error_code The error code in the descriptor status word + */ +static inline void +handle_desc_jr_err(union jr_error_code jr_error_code) +{ + CAAM_LOG_WARN("Not implemented\n"); +} + +/* Handle job descriptor processing errors */ +static void +handle_desc_error(struct caam_jr_softc *sc, uint32_t error_code) +{ + union jr_error_code jr_err_code; + + jr_err_code.error = error_code; + + switch (jr_err_code.error_desc.value.ssrc) { + case SEC_HW_ERR_SSRC_NO_SRC: + CAAM_LOG_WARN("No Status Source "); + break; + case SEC_HW_ERR_SSRC_CCB_ERR: + CAAM_LOG_WARN("CCB Status Source"); + handle_desc_ccb_err(jr_err_code); + break; + case SEC_HW_ERR_SSRC_JMP_HALT_U: + CAAM_LOG_WARN("Jump Halt User Status Source"); + handle_desc_jmp_halt_user_err(jr_err_code); + break; + case SEC_HW_ERR_SSRC_DECO: + CAAM_LOG_WARN("DECO Status Source"); + handle_desc_deco_err(jr_err_code); + break; + case SEC_HW_ERR_SSRC_JR: + CAAM_LOG_WARN("Job Ring Status Source"); + handle_desc_jr_err(jr_err_code); + break; + case SEC_HW_ERR_SSRC_JMP_HALT_COND: + CAAM_LOG_WARN("Jump Halt Condition Codes"); + handle_desc_jmp_halt_cond_err(jr_err_code); + break; + default: + CAAM_LOG_WARN("Unknown SSRC"); + break; + } +} + +/* Print a log message according to current JRINT register JRE field */ +static int +read_jr_hw_error(struct caam_jr_softc *sc) +{ + uint32_t jrint_error_code; + + if (JR_REG_JRINT_JRE_EXTRACT(reg_read(sc, jr_reg(jrint))) == 0) { + return 0; + } + + jrint_error_code = JR_REG_JRINT_ERR_TYPE_EXTRACT( + reg_read(sc, jr_reg(jrint))); + switch (jrint_error_code) { + case JRINT_ERR_WRITE_STATUS: + CAAM_LOG_WARN("Error writing status to Output Ring "); + break; + case JRINT_ERR_BAD_INPUT_BASE: + CAAM_LOG_WARN("Bad Input Ring Base (not on a 4-byte boundary)\n"); + break; + case JRINT_ERR_BAD_OUTPUT_BASE: + CAAM_LOG_WARN("Bad Output Ring Base (not on a 4-byte boundary)\n"); + break; + case JRINT_ERR_WRITE_2_IRBA: + CAAM_LOG_WARN("Invalid write to Input Ring Base Address Register\n"); + break; + case JRINT_ERR_WRITE_2_ORBA: + CAAM_LOG_WARN("Invalid write to Output Ring Base Address Register\n"); + break; + case JRINT_ERR_RES_B4_HALT: + CAAM_LOG_WARN("Job Ring released before Job Ring is halted\n"); + break; + case JRINT_ERR_REM_TOO_MANY: + CAAM_LOG_WARN("Removed too many jobs from job ring\n"); + break; + case JRINT_ERR_ADD_TOO_MANY: + CAAM_LOG_WARN("Added too many jobs on job ring\n"); + break; + default: + CAAM_LOG_WARN("Unknown SEC JR Error :%d\n", jrint_error_code); + break; + } + return jrint_error_code; +} + +/*------------------ Low level JobRing management functions -----------------*/ +static int +shutdown_job_ring(struct caam_jr_softc *sc) +{ + unsigned int timeout = SEC_TIMEOUT; + uint32_t tmp = 0U; + + CAAM_LOG_DEBUG("Resetting Job ring\n"); + + /* + * 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 + */ + + disable_jr_irqs(sc); + + /* initiate flush (required prior to reset) */ + reg_write(sc, jr_reg(jrcr), JR_REG_JRCR_VAL_RESET); + + /* dummy read */ + tmp = reg_read(sc, jr_reg(jrcr)); + (void)tmp; + + do { + tmp = reg_read(sc, jr_reg(jrint)); + } while (((tmp & JRINT_ERR_HALT_MASK) == JRINT_ERR_HALT_INPROGRESS) && + ((--timeout) != 0U)); + + if ((tmp & JRINT_ERR_HALT_MASK) != JRINT_ERR_HALT_COMPLETE || + timeout == 0U) { + CAAM_LOG_ERROR("Failed to flush hw job ring %x\n %u", tmp, timeout); + /* unmask interrupts */ + if (sc->job_ring.jr_mode != SEC_NOTIFICATION_TYPE_POLL) { + enable_jr_irqs(sc); + } + return EIO; + } + /* Initiate reset */ + timeout = SEC_TIMEOUT; + reg_write(sc, jr_reg(jrcr), JR_REG_JRCR_VAL_RESET); + + do { + tmp = reg_read(sc, jr_reg(jrcr)); + } while (((tmp & JR_REG_JRCR_VAL_RESET) != 0U) && ((--timeout) != 0U)); + + if (timeout == 0U) { + CAAM_LOG_ERROR("Failed to reset hw job ring\n"); + /* unmask interrupts */ + if (sc->job_ring.jr_mode != SEC_NOTIFICATION_TYPE_POLL) { + enable_jr_irqs(sc); + } + return EIO; + } + /* unmask interrupts */ + if (sc->job_ring.jr_mode != SEC_NOTIFICATION_TYPE_POLL) { + enable_jr_irqs(sc); + } + return 0; +} + +static int +reset_job_ring(struct caam_jr_softc *sc) +{ + int ret = 0; + + /* First reset the job ring in hw */ + ret = shutdown_job_ring(sc); + if (ret != 0) { + CAAM_LOG_ERROR("Failed resetting job ring in hardware"); + return ret; + } + /* 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 + */ + reg_write(sc, jr_reg(irs), SEC_JOB_RING_SIZE); + + /* Write the JR output queue size to the HW register */ + reg_write(sc, jr_reg(ors), SEC_JOB_RING_SIZE); + + /* Write the JR input queue start address */ + set_jr_input_ring_start_addr(sc, sc->ip_ring_map.bus_addr); + + /* Write the JR output queue start address */ + set_jr_output_ring_start_addr(sc, sc->op_ring_map.bus_addr); + + return 0; +} + +/* Remove all currently finished jobs from output ring without executing callbacks */ +static void +flush_job_ring(struct caam_jr_softc *sc, uint32_t do_notify, + uint32_t error_code, uint32_t *notified_descs) +{ + int32_t jobs_no_to_discard = 0; + int32_t discarded_descs_no = 0; + int32_t number_of_jobs_available = 0; + + CAAM_LOG_DEBUG("JR pi[%d]i ci[%d]\n", sc->job_ring.pidx, sc->job_ring.cidx); + CAAM_LOG_DEBUG("error code %x\n", error_code); + CAAM_LOG_DEBUG("Notify_desc = %d\n", do_notify); + + number_of_jobs_available = get_jr_finished_jobs(sc); + + /* Discard all jobs */ + jobs_no_to_discard = number_of_jobs_available; + + CAAM_LOG_DEBUG("JR pi[%d]i ci[%d]\n", sc->job_ring.pidx, sc->job_ring.cidx); + CAAM_LOG_DEBUG("Discarding desc = %d\n", 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 + */ + + sc->job_ring.cidx = SEC_CIRCULAR_COUNTER(sc->job_ring.cidx, + SEC_JOB_RING_SIZE); + + remove_jr_entries(sc, 1); + } + + if (do_notify == true) { + if (notified_descs == NULL) { + return; + } + *notified_descs = discarded_descs_no; + } +} + +/* return 0 in case of success + * !0 in case of error from SEC block + * + * notified is 0 in case job not yet processed by SEC + */ +static int +poll_job_ring(struct caam_jr_softc *sc, int32_t limit, int32_t *notified) +{ + int32_t jobs_no_to_notify = 0; + int32_t number_of_jobs_available = 0; + int32_t notified_descs_no = 0; + uint32_t sec_error_code = 0U; + uintptr_t *fnptr, *arg_addr; + user_callback usercall = NULL; + uint8_t *current_desc; + void *arg; + uintptr_t current_desc_addr; + bus_addr_t current_desc_loc; + int i; + + /* check here if any JR error that cannot be written + * in the output status word has occurred + */ + sec_error_code = read_jr_hw_error(sc); + if (unlikely(sec_error_code) != 0) { + CAAM_LOG_WARN("Error here itself %x\n", sec_error_code); + return EIO; + } + /* Compute the number of notifications that need to be raised to UA + * If limit < 0 -> notify all done jobs + * If limit > total number of done jobs -> notify all done jobs + * If limit = 0 -> error + * If limit > 0 && limit < total number of done jobs -> notify a number + * of done jobs equal with limit + */ + + /*compute the number of jobs available in the job ring based on the + * producer and consumer index values. + */ + + number_of_jobs_available = get_jr_finished_jobs(sc); + jobs_no_to_notify = (limit < 0 || limit > number_of_jobs_available) ? + number_of_jobs_available : + limit; + CAAM_LOG_DEBUG("JR - pi %d, ci %d,\n", sc->job_ring.pidx, sc->job_ring.cidx); + CAAM_LOG_DEBUG("Jobs submitted %d \n", number_of_jobs_available); + CAAM_LOG_DEBUG("Jobs to notify %d \n", jobs_no_to_notify); + + while (jobs_no_to_notify > notified_descs_no) { + /* Make sure that the Output Ring contain data written by the + * Job Ring hardware */ + caam_jr_dma_sync_from_dma(sc->dev, &sc->op_ring_map); + CAAM_LOG_DEBUG("output_ring[%i] = %016lX, %08X\n", 0, + sc->job_ring.output_ring[sc->job_ring.cidx].desc, + sc->job_ring.output_ring[sc->job_ring.cidx].status); + + /* Get job status here */ + sec_error_code = sec_mem_in32( + &(sc->job_ring.output_ring[sc->job_ring.cidx].status), sc->little_endian); + + /* Get completed descriptor */ + current_desc_loc = (uintptr_t)&sc->job_ring + .output_ring[sc->job_ring.cidx] + .desc; + current_desc_addr = sec_read_addr(current_desc_loc, sc->little_endian); + + CAAM_LOG_DEBUG("output_ring[%d] [%016lX]=%016lX\n ", sc->job_ring.cidx, + (uintptr_t)current_desc_loc, current_desc_addr); + + /* search the descriptor with this bus address */ + current_desc = NULL; + i = sc->job_ring.cidx; + do { + if(sc->desc_ring[i].bus_addr == current_desc_addr) { + current_desc = sc->desc_ring[i].buf; + + CAAM_LOG_DEBUG( + "Found descriptor at: phy:%016lX -> vir:%016lX\n ", + (uintptr_t)current_desc_addr, + (uintptr_t)current_desc); + + /* The DMA is no longer needed, sync and unmap it */ + caam_jr_dma_unmap(sc->dev, &sc->desc_ring[i], JR_MAP_SYNC); + sc->desc_ring[i].buf = NULL; + sc->desc_ring[i].bus_addr = 0; + + break; + + } + i = SEC_CIRCULAR_COUNTER(i, SEC_JOB_RING_SIZE); + } while (i != sc->job_ring.pidx); + + /* now increment the consumer index for the current job ring, + * AFTER saving job in temporary location! + */ + sc->job_ring.cidx = SEC_CIRCULAR_COUNTER(sc->job_ring.cidx, + SEC_JOB_RING_SIZE); + + /* Signal that the job has been processed & the slot is free */ + remove_jr_entries(sc, 1); + + /* In case we could not find the descriptor we will not be able to execute the callback */ + if ((current_desc_addr == 0) || (current_desc == NULL)) { + CAAM_LOG_ERROR("No descriptor returned from SEC\n"); + return EIO; + } + + /* Execute the user provided callback */ + arg_addr = (uintptr_t *)(current_desc + + (MAX_DESC_SIZE_WORDS * sizeof(uint32_t))); + + fnptr = (uintptr_t *)(current_desc + + (MAX_DESC_SIZE_WORDS * sizeof(uint32_t) + sizeof(void *))); + + arg = (void *)*(arg_addr); + if (*fnptr != 0) { + CAAM_LOG_DEBUG("Callback Function called\n"); + usercall = (user_callback) * (fnptr); + (*usercall)((uint32_t *)current_desc, sec_error_code, + arg, sc->dev); + } + + /* In case error was detected, print it and return */ + if (sec_error_code != 0) { + CAAM_LOG_WARN("desc at cidx %d, error: %x\n ", sc->job_ring.cidx, sec_error_code); + handle_desc_error(sc, sec_error_code); + return EIO; + } + + notified_descs_no++; + } + + *notified = notified_descs_no; + return 0; +} + +/*-------------------- JobRing Public interface functions -------------------*/ +int +caam_jr_init(device_t dev, uint8_t jr_mode, uint16_t irq_coalescing_timer, + uint8_t irq_coalescing_count) +{ + int ret = 0; + struct caam_jr_softc *sc = device_get_softc(dev); + + sc->job_ring.jr_mode = jr_mode; + sc->job_ring.irq_fd = 0; + + sc->job_ring.input_ring = (bus_addr_t *)sc->ip_ring_buf; + memset(sc->job_ring.input_ring, 0, SEC_DMA_MEM_INPUT_RING_SIZE); + + sc->job_ring.output_ring = (struct sec_outring_entry *)sc->op_ring_buf; + memset(sc->job_ring.output_ring, 0, SEC_DMA_MEM_OUTPUT_RING_SIZE); + + caam_jr_dma_sync_to_dma(sc->dev, &sc->ip_ring_map); + caam_jr_dma_sync_to_dma(sc->dev, &sc->op_ring_map); + + /* Reset job ring in SEC hw and configure job ring registers */ + ret = reset_job_ring(sc); + if (ret != 0) { + CAAM_LOG_ERROR("Failed to reset hardware job ring\n"); + return ret; + } + + if (jr_mode == SEC_NOTIFICATION_TYPE_IRQ) { + /* Enable IRQ if driver work sin interrupt mode */ + CAAM_LOG_ERROR("Enabling DONE IRQ generation on job ring\n"); + ret = enable_jr_irqs(sc); + if (ret != 0) { + CAAM_LOG_ERROR("Failed to enable irqs for job ring\n"); + return ret; + } + } + if ((irq_coalescing_timer != 0) || (irq_coalescing_count != 0)) { + set_jr_coalescing_param(sc, irq_coalescing_timer, + irq_coalescing_count); + + enable_jr_coalescing(sc); + sc->job_ring.coalescing_en = 1; + } + + sc->job_ring.jr_state = SEC_JOB_RING_STATE_STARTED; + + return ret; +} + +int +caam_jr_enqueue(device_t dev, struct job_descriptor *jobdescr) +{ + struct caam_jr_softc *sc = device_get_softc(dev); + + /* Check job ring state */ + if (sc->job_ring.jr_state != SEC_JOB_RING_STATE_STARTED) { + CAAM_LOG_WARN("Job ring is currently resetting\n"); + return ENXIO; + } + + if (SEC_JOB_RING_IS_FULL(sc->job_ring.pidx, sc->job_ring.cidx, + SEC_JOB_RING_SIZE, SEC_JOB_RING_SIZE)) { + CAAM_LOG_WARN("Job ring is full, pending: %d\n", + atomic_load_int(&sc->pending)); + return ENOMEM; + } + + /* Create DMA mapping and load the descriptor to bus memmory for this + * job */ + caam_jr_dma_map(dev, &sc->desc_ring[sc->job_ring.pidx], jobdescr, + sizeof(struct job_descriptor), 0, BUS_DMA_NOWAIT, JR_MAP_SYNC); + + /* Set ptr in input ring to current descriptor */ + sec_write_addr(&sc->job_ring.input_ring[sc->job_ring.pidx], + sc->desc_ring[sc->job_ring.pidx].bus_addr, sc->little_endian); + + caam_jr_dma_sync_to_dma(dev, &sc->ip_ring_map); + CAAM_LOG_DEBUG("input_ring[%i] = %016lX\n", sc->job_ring.pidx, + sc->job_ring.input_ring[sc->job_ring.pidx]); + + /* increment the producer index for the current job ring */ + sc->job_ring.pidx = SEC_CIRCULAR_COUNTER(sc->job_ring.pidx, + SEC_JOB_RING_SIZE); + + /* Notify HW that a new job is enqueued */ + add_jr_entries(sc, 1); + + return 0; +} + +int +caam_jr_dequeue(device_t dev, int32_t limit) +{ + int ret = 0, irq_ret = 0; + int notified_descs_no = 0; + struct caam_jr_softc *sc = device_get_softc(dev); + uint64_t pool_count; + + /* Validate input arguments */ + if (((limit == 0) || (limit > SEC_JOB_RING_SIZE))) { + CAAM_LOG_WARN("Invalid limit parameter configuration\n"); + return EINVAL; + } + + CAAM_LOG_DEBUG("JR Polling limit[%d]\n", limit); + + /* Poll job ring + * If limit < 0 -> poll JR until no more notifications are available. + * If limit > 0 -> poll JR until limit is reached. + */ + pool_count = 0; + + while (notified_descs_no == 0) { + /* Run hw poll job ring */ + ret = poll_job_ring(sc, limit, ¬ified_descs_no); + if (ret != 0) { + CAAM_LOG_WARN("Error polling SEC engine job ring\n"); + break; + } + + CAAM_LOG_DEBUG("Jobs notified[%d]. ", notified_descs_no); + + pool_count++; + if (pool_count >= CAAM_JR_POOL_MAX_COUNT) { + CAAM_LOG_NOTICE("Timeout during job dequeue\n"); + break; + } + } + + if (sc->job_ring.jr_mode == SEC_NOTIFICATION_TYPE_IRQ) { + /* Always enable IRQ generation when in pure IRQ mode */ + irq_ret = enable_jr_irqs(sc); + if (irq_ret != 0) { + CAAM_LOG_WARN("Failed to enable irqs for job ring"); + ret = irq_ret; + } + } + + return ret; +} + +int +caam_jr_shutdown(device_t dev) +{ + int ret = 0; + struct caam_jr_softc *sc = device_get_softc(dev); + + ret = shutdown_job_ring(sc); + if (ret != 0) { + CAAM_LOG_ERROR("Failed to shutdown hardware job ring\n"); + return ret; + } + + if (sc->job_ring.coalescing_en != 0) { + disable_jr_coalescing(sc); + } + + if (sc->job_ring.jr_mode != SEC_NOTIFICATION_TYPE_POLL) { + ret = disable_jr_irqs(sc); + if (ret != 0) { + CAAM_LOG_ERROR("Failed to disable irqs for job ring"); + return ret; + } + } + + return 0; +} + +bool +caam_jr_busy(device_t dev) +{ + struct caam_jr_softc *sc = device_get_softc(dev); + + return (atomic_load_int(&sc->pending) != 0); +} + +bus_dma_tag_t +caam_jr_get_tag(device_t dev) +{ + struct caam_jr_softc *sc = device_get_softc(dev); + + return (sc->dma_tag); +} + +bus_dma_tag_t +caam_jr_get_data_tag(device_t dev) +{ + struct caam_jr_softc *sc = device_get_softc(dev); + + return (sc->data_tag); +} + +static void +dma_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + if (error) + return; + *(bus_addr_t *)arg = segs[0].ds_addr; +} + +int +caam_jr_dma_map(device_t dev, caam_jr_dma_map_t *bmap, void *buf, size_t buflen, + int create_flags, int load_flags, bool sync) +{ + int error; + struct caam_jr_softc *sc = device_get_softc(dev); + + /* Remember the CPU visible memory */ + bmap->buf = buf; + bmap->buflen = buflen; + + /* Map and load the buffer */ + error = bus_dmamap_create(sc->dma_tag, create_flags, &bmap->mmap); + if (error != 0) { + CAAM_LOG_ERROR("Cannot create DMA map, %i\n", error); + return (error); + } + + bmap->bus_addr = ULONG_MAX; + error = bus_dmamap_load(sc->dma_tag, /* DMA tag */ + bmap->mmap, /* DMA map */ + bmap->buf, /* buffer */ + bmap->buflen, /* buffersize */ + dma_callback, /* callback */ + &bmap->bus_addr, /* callbackarg */ + load_flags); /* flags */ + if (error || bmap->bus_addr == ULONG_MAX) { + CAAM_LOG_ERROR("Cannot map memory!\n"); + bus_dmamap_destroy(sc->dma_tag, bmap->mmap); + bmap->mmap = NULL; + return (ENOMEM); + } + + if (sync) { + /* Make sure that the data is synchronized to DMA memory */ + caam_jr_dma_sync_to_dma(dev, bmap); + } + + return error; +} + +int +caam_jr_dma_unmap(device_t dev, caam_jr_dma_map_t *bmap, bool sync) +{ + int error = 0; + struct caam_jr_softc *sc = device_get_softc(dev); + + if (bmap->mmap != NULL) { + if (sync) { + /* Make sure that the data is synchronized to CPU memory */ + caam_jr_dma_sync_from_dma(dev, bmap); + } + + /* Now it is safe to remove the mapping */ + bus_dmamap_unload(sc->dma_tag, bmap->mmap); + error = bus_dmamap_destroy(sc->dma_tag, bmap->mmap); + bmap->mmap = NULL; + if (error) + CAAM_LOG_ERROR("%s: bus_dmamap_destroy failed: %d\n", __func__, + error); + } + + return error; +} + +void +caam_jr_dma_sync_to_dma(device_t dev, caam_jr_dma_map_t *bmap) +{ + struct caam_jr_softc *sc = device_get_softc(dev); + + bus_dmamap_sync(sc->dma_tag, bmap->mmap, BUS_DMASYNC_PREWRITE); +} + +void +caam_jr_dma_sync_from_dma(device_t dev, caam_jr_dma_map_t *bmap) +{ + struct caam_jr_softc *sc = device_get_softc(dev); + + bus_dmamap_sync(sc->dma_tag, bmap->mmap, BUS_DMASYNC_POSTREAD); +} + +/*----------------------- Device management functions -----------------------*/ +static int +init_caam_jr_dma(struct caam_jr_softc *sc) +{ + int error; + + /* Map and load the Input Ring buffer */ + error = caam_jr_dma_map(sc->dev, &sc->ip_ring_map, sc->ip_ring_buf, + SEC_DMA_MEM_INPUT_RING_SIZE, 0, BUS_DMA_NOWAIT, JR_MAP_SYNC); + if (error != 0) { + CAAM_LOG_ERROR("cannot create Input Ring map, %i\n", error); + return (error); + } + + /* Map and load the Output Ring buffer */ + error = caam_jr_dma_map(sc->dev, &sc->op_ring_map, sc->op_ring_buf, + SEC_DMA_MEM_OUTPUT_RING_SIZE, 0, BUS_DMA_NOWAIT, JR_MAP_SYNC); + if (error != 0) { + CAAM_LOG_ERROR("cannot create Output Ring map\n"); + return (error); + } + + return (0); +} + +static void +free_caam_jr_dma(struct caam_jr_softc *sc) +{ + caam_jr_dma_unmap(sc->dev, &sc->ip_ring_map, JR_MAP_SYNC); + caam_jr_dma_unmap(sc->dev, &sc->op_ring_map, JR_MAP_SYNC); +} + +static int +caam_jr_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,sec-v4.0-job-ring")) + return (ENXIO); + + device_set_desc(dev, "CAAM Job Ring backend driver"); + + return (BUS_PROBE_DEFAULT); +} + +/* + * Jobring descriptor completion interrupt handler. + * Interrupt should occur after each completion or according to coalescing settings. + */ +static void +jr_intr(void *arg) +{ + struct caam_jr_softc *sc = (struct caam_jr_softc *)arg; + + /* We might have switched to polled mode midway */ + if (sc->job_ring.jr_mode != SEC_NOTIFICATION_TYPE_IRQ) + return; + + disable_jr_irqs(sc); + + /* Clear current interrupt */ + reg_write_mask(sc, jr_reg(jrint), JRINT_JRI_CLEAR, JRINT_JRI_MASK); + + /* dequeue will re-enable interrupts after processing user callbacks */ + caam_jr_sched_dequeue(sc->dev); +} + +static int +caam_jr_attach(device_t dev) +{ + CAAM_LOG_DEBUG("caam_jr_attach\n"); + + int rid = 0; + phandle_t parent_node; + struct caam_jr_softc *sc = device_get_softc(dev); + + sc->dev = dev; + sc->dev_caam = device_get_parent(dev); + + /* The endianess of the job ring need to be the same as parent CAAM device */ + parent_node = ofw_bus_get_node(sc->dev_caam); + if (parent_node == -1) + return (ENXIO); + sc->little_endian = OF_hasprop(parent_node, "little-endian"); + sc->pending = 0; + + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE | RF_SHAREABLE); + if (sc->mem_res == NULL) { + goto error; + } + + if (bus_dma_tag_create(bus_get_dma_tag(dev), 4, 0, + BUS_SPACE_MAXADDR_40BIT, BUS_SPACE_MAXADDR, NULL, NULL, + BUS_SPACE_MAXSIZE_32BIT, 1, BUS_SPACE_MAXSIZE_32BIT, + BUS_DMA_COHERENT, NULL, NULL, &sc->dma_tag)) { + CAAM_LOG_ERROR("Cannot create JR DMA tag\n"); + goto free_res_mem; + } + + if (bus_dma_tag_create(bus_get_dma_tag(dev), 4, 0, + BUS_SPACE_MAXADDR_40BIT, BUS_SPACE_MAXADDR, NULL, NULL, + BUS_SPACE_MAXSIZE_32BIT, MAX_SGT_ENTRIES, BUS_SPACE_MAXSIZE_32BIT, + BUS_DMA_COHERENT, NULL, NULL, &sc->data_tag)) { + CAAM_LOG_ERROR("Cannot create JR DMA tag\n"); + goto free_dma_tag; + } + + if (init_caam_jr_dma(sc) != 0) { + CAAM_LOG_ERROR("Failed to setup jr dma\n"); + goto free_data_tag; + } + + sc->tq = caam_create_jobring_task(dev); + if (sc->tq == NULL) { + CAAM_LOG_ERROR("Failed to setup jr interrupt handling\n"); + goto free_jr_dma; + } + + sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE | RF_SHAREABLE); + if (sc->irq_res == NULL) { + CAAM_LOG_ERROR("Failed to alloc jr IRQ\n"); + goto free_jobring; + } + + if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + NULL, jr_intr, sc, &sc->irq_cookie)) { + CAAM_LOG_ERROR("Failed to setup jr interrupts\n"); + goto free_res_irq; + } + + return (0); + +free_res_irq: + bus_free_resource(dev, SYS_RES_IRQ, sc->irq_res); + +free_jobring: + caam_free_jobring_task(sc->tq); + +free_jr_dma: + free_caam_jr_dma(sc); + +free_data_tag: + bus_dma_tag_destroy(sc->data_tag); + +free_dma_tag: + bus_dma_tag_destroy(sc->dma_tag); + +free_res_mem: + bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); + +error: + return (ENXIO); +} + +static int +caam_jr_detach(device_t dev) +{ + CAAM_LOG_DEBUG("caam_jr_detach\n"); + + struct caam_jr_softc *sc = device_get_softc(dev); + + /* If any descriptors in flight , poll and wait + * until all descriptors are received and silently discarded. + */ + flush_job_ring(sc, false, 0, NULL); + + bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); + + bus_free_resource(dev, SYS_RES_IRQ, sc->irq_res); + + caam_free_jobring_task(sc->tq); + + free_caam_jr_dma(sc); + + bus_dma_tag_destroy(sc->data_tag); + + bus_dma_tag_destroy(sc->dma_tag); + + bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res); + + return (0); +} + +static device_method_t caam_jr_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, caam_jr_probe), + DEVMETHOD(device_attach, caam_jr_attach), + DEVMETHOD(device_detach, caam_jr_detach), + + DEVMETHOD_END +}; + +static driver_t caam_jr_driver = { + "caam_jr", + caam_jr_methods, + sizeof(struct caam_jr_softc), +}; + +DRIVER_MODULE(caam_jr, simplebus, caam_jr_driver, 0, 0); +MODULE_VERSION(caam_jr, 1); diff --git a/sys/arm64/qoriq/caam/jr/caam_jr_cfg.h b/sys/arm64/qoriq/caam/jr/caam_jr_cfg.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_jr_cfg.h @@ -0,0 +1,171 @@ +/* + * Copyright 2017-2021 NXP + * Copyright 2023 Alstom Group + * Copyright 2023 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef CAAM_JR_CFG_H +#define CAAM_JR_CFG_H + +#include +#include + +/* Helper defines */ +/* Define used for setting a flag on */ +#define ON 1 +/* Define used for setting a flag off */ +#define OFF 0 + +/* SEC is configured to start work in polling mode, */ +#define SEC_STARTUP_POLLING_MODE 0 +/* + * SEC is configured to start work in interrupt mode, + * when configured for NAPI notification style. + */ +#define SEC_STARTUP_INTERRUPT_MODE 1 + +/* + * SEC driver will use ONLY interrupts to receive notifications + * for processed packets from SEC engine hardware. + */ +#define SEC_NOTIFICATION_TYPE_IRQ 1 +/* + * SEC driver will use ONLY polling to receive notifications + * for processed packets from SEC engine hardware. + */ +#define SEC_NOTIFICATION_TYPE_POLL 2 + +/* + * Size of cryptographic context that is used directly in communicating + * with SEC device. + * SEC device works only with physical addresses. This is the maximum size + * for a SEC descriptor ( = 64 words). + */ +#define SEC_CRYPTO_DESCRIPTOR_SIZE 256 + +/* + * Size of job descriptor submitted to SEC device for each packet to be + * processed. + * Job descriptor contains 3 DMA address pointers: + * - to shared descriptor, to input buffer and to output buffer. + * The job descriptor contains other SEC specific commands as well: + * - HEADER command, SEQ IN PTR command SEQ OUT PTR command and opaque + * data, each measuring 4 bytes. + * Job descriptor size, depending on physical address representation: + * - 32 bit - size is 28 bytes - cacheline-aligned size is 64 bytes + * - 36 bit - size is 40 bytes - cacheline-aligned size is 64 bytes + * @note: Job descriptor must be cacheline-aligned to ensure efficient memory + * access. + * @note: If other format is used for job descriptor, then the size must be + * revised. + */ +#define SEC_JOB_DESCRIPTOR_SIZE 64 + +/* + * Size of one entry in the input ring of a job ring. + * Input ring contains pointers to job descriptors. + * The memory used for an input ring and output ring must be physically + * contiguous. + */ +#define SEC_JOB_INPUT_RING_ENTRY_SIZE sizeof(bus_addr_t) + +/* + * Size of one entry in the output ring of a job ring. + * Output ring entry is a pointer to a job descriptor followed by a 4 byte + * status word. + * The memory used for an input ring and output ring must be physically + * contiguous. + * @note If desired to use also the optional SEQ OUT indication in output + * ring entries, then 4 more bytes must be added to the size. + */ +#define SEC_JOB_OUTPUT_RING_ENTRY_SIZE (SEC_JOB_INPUT_RING_ENTRY_SIZE + 4) + +/* DMA memory required for an input ring of a job ring. */ +#define SEC_DMA_MEM_INPUT_RING_SIZE \ + ((SEC_JOB_INPUT_RING_ENTRY_SIZE) * (SEC_JOB_RING_SIZE)) + +/* + * DMA memory required for an output ring of a job ring. + * Required extra 4 byte for status word per each entry. + */ +#define SEC_DMA_MEM_OUTPUT_RING_SIZE \ + ((SEC_JOB_OUTPUT_RING_ENTRY_SIZE) * (SEC_JOB_RING_SIZE)) + +/* + * SEC DEVICE related configuration. + + * Enable/Disable logging support at compile time. + * Valid values: + * ON - enable logging + * OFF - disable logging + * The messages are logged at stdout. + */ +#define SEC_DRIVER_LOGGING OFF + +/* + * Configure logging level at compile time. + * Valid values: + * SEC_DRIVER_LOG_ERROR - log only errors + * SEC_DRIVER_LOG_INFO - log errors and info messages + * SEC_DRIVER_LOG_DEBUG - log errors, info and debug messages + */ +#define SEC_DRIVER_LOGGING_LEVEL SEC_DRIVER_LOG_DEBUG + +/* + * SEC JOB RING related configuration. + + * Configure the size of the JOB RING. + * The maximum size of the ring is hardware limited to 1024. + * However the number of packets in flight in a time interval of + * 1ms can be calculated + * from the traffic rate (Mbps) and packet size. + * Here it was considered a packet size of 40 bytes. + * @note Round up to nearest power of 2 for optimized update + * of producer/consumer indexes of each job ring + * \todo Should set to 750, according to the calculation above, but + * the JR size must be power of 2, thus the next closest value must + * be chosen (i.e. 512 since 1024 is not available) + * For firmware choose this to be 16 + */ +#define SEC_JOB_RING_SIZE 16 + +/* + * Interrupt coalescing related configuration. + * NOTE: SEC hardware enabled interrupt + * coalescing is not supported on SEC version 3.1! + * SEC version 4.4 has support for interrupt + * coalescing. + */ +#define SEC_INT_COALESCING_ENABLE ON +/* + * Interrupt Coalescing Descriptor Count Threshold. + * While interrupt coalescing is enabled (ICEN=1), this value determines + * how many Descriptors are completed before raising an interrupt. + * Valid values for this field are from 0 to 255. + * Note that a value of 1 functionally defeats the advantages of interrupt + * coalescing since the threshold value is reached each time that a + * Job Descriptor is completed. A value of 0 is treated in the same + * manner as a value of 1. + * + * Currently set to 0 to minimize delay. + */ +#define SEC_INTERRUPT_COALESCING_DESCRIPTOR_COUNT_THRESH 0 + +/* + * Interrupt Coalescing Timer Threshold. + * While interrupt coalescing is enabled (ICEN=1), this value determines the + * maximum amount of time after processing a Descriptor before raising an + * interrupt. + * The threshold value is represented in units equal to 64 CAAM interface + * clocks. Valid values for this field are from 1 to 65535. + * A value of 0 results in behavior identical to that when interrupt + * coalescing is disabled. + * + * Currently set to 0 to minimize delay. + */ +#define SEC_INTERRUPT_COALESCING_TIMER_THRESH 0 + +#endif /* CAAM_JR_CFG_H */ diff --git a/sys/arm64/qoriq/caam/jr/caam_jr_hw.h b/sys/arm64/qoriq/caam/jr/caam_jr_hw.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_jr_hw.h @@ -0,0 +1,327 @@ +/* + * Copyright 2017-2021 NXP + * Copyright 2023 Alstom Group + * Copyright 2023 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef CAAM_JR_HW_H +#define CAAM_JR_HW_H + +#include +#include +/* DEFINES AND MACROS */ + +/* Used to retry resetting a job ring in SEC hardware. */ +#define SEC_TIMEOUT 100000 + +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define SEC_JOB_RING_IS_FULL(pi, ci, ring_max_size, ring_threshold) \ + ((((pi) + 1 + ((ring_max_size) - (ring_threshold))) & \ + (ring_max_size - 1)) == ((ci))) + +#define SEC_CIRCULAR_COUNTER(x, max) (((x) + 1) & (max - 1)) + +/* Struct representing various job ring registers (in little endian view) */ +struct jobring_regs { + unsigned int irba_l; + unsigned int irba_h; + unsigned int rsvd1; + unsigned int irs; + unsigned int rsvd2; + unsigned int irsa; + unsigned int rsvd3; + unsigned int irja; + unsigned int orba_l; + unsigned int orba_h; + unsigned int rsvd4; + unsigned int ors; + unsigned int rsvd5; + unsigned int orjr; + unsigned int rsvd6; + unsigned int orsf; + unsigned int rsvd7; + unsigned int jrsta; + unsigned int rsvd8; + unsigned int jrint; + unsigned int jrcfg0; + unsigned int jrcfg1; + unsigned int rsvd9; + unsigned int irri; + unsigned int rsvd10; + unsigned int orwi; + unsigned int rsvd11; + unsigned int jrcr; +}; + +/* Offsets representing common SEC Registers */ +#define SEC_REG_MCFGR_OFFSET 0x0004 +#define SEC_REG_SCFGR_OFFSET 0x000C +#define SEC_REG_JR0ICIDR_MS_OFFSET 0x0010 +#define SEC_REG_JR0ICIDR_LS_OFFSET 0x0014 +#define SEC_REG_JR1ICIDR_MS_OFFSET 0x0018 +#define SEC_REG_JR1ICIDR_LS_OFFSET 0x001C +#define SEC_REG_JR2ICIDR_MS_OFFSET 0x0020 +#define SEC_REG_JR2ICIDR_LS_OFFSET 0x0024 +#define SEC_REG_JR3ICIDR_MS_OFFSET 0x0028 +#define SEC_REG_JR3ICIDR_LS_OFFSET 0x002C +#define SEC_REG_JRSTARTR_OFFSET 0x005C +#define SEC_REG_CTPR_MS_OFFSET 0x0FA8 + +#define SEC_REG_SSTA_OFFSET 0x0FD4 +#define SSTA_MOO_SHIFT 8 +#define SSTA_MOO_MASK (0x3 << SSTA_MOO_SHIFT) +#define SSTA_MOO_NON_SECURE 0x0 +#define SSTA_MOO_SECURE 0x1 +#define SSTA_MOO_TRUSTED 0x2 +#define SSTA_MOO_FAIL 0x3 + +/* Offsets representing various RNG registers */ +#define RNG_REG_RTMCTL_OFFSET 0x0600 +#define RNG_REG_RTSDCTL_OFFSET 0x0610 +#define RNG_REG_RTFRQMIN_OFFSET 0x0618 +#define RNG_REG_RTFRQMAX_OFFSET 0x061C +#define RNG_REG_RDSTA_OFFSET 0x06C0 +#define ALG_AAI_SH_SHIFT 4 + +/* SEC Registers Bitmasks */ +#define MCFGR_PS_SHIFT 16 +#define MCFGR_AWCACHE_SHIFT 8 +#define MCFGR_AWCACHE_MASK (0xF << MCFGR_AWCACHE_SHIFT) +#define MCFGR_ARCACHE_SHIFT 12 +#define MCFGR_ARCACHE_MASK (0xF << MCFGR_ARCACHE_SHIFT) + +#define SCFGR_RNGSH0 0x00000200 +#define SCFGR_VIRT_EN 0x00008000 + +#define JRICID_MS_LICID 0x80000000 +#define JRICID_MS_LAMTD 0x00020000 +#define JRICID_MS_AMTDT 0x00010000 +#define JRICID_MS_TZ 0x00008000 +#define JRICID_LS_SDID_MASK 0x00000FFF +#define JRICID_LS_NSEQID_MASK 0x0FFF0000 +#define JRICID_LS_NSEQID_SHIFT 16 +#define JRICID_LS_SEQID_MASK 0x00000FFF + +#define JRSTARTR_STARTJR0 0x00000001 +#define JRSTARTR_STARTJR1 0x00000002 +#define JRSTARTR_STARTJR2 0x00000004 +#define JRSTARTR_STARTJR3 0x00000008 + +#define CTPR_VIRT_EN_POR 0x00000002 +#define CTPR_VIRT_EN_INC 0x00000001 + +/* RNG RDSTA bitmask */ +#define RNG_STATE0_HANDLE_INSTANTIATED 0x00000001 +#define RNG_STATE1_HANDLE_INSTANTIATED 0x00000002 +#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */ +/* use von Neumann data in both entropy shifter and statistical checker */ +#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC 0 +/* use raw data in both entropy shifter and statistical checker */ +#define RTMCTL_SAMP_MODE_RAW_ES_SC 1 +/* use von Neumann data in entropy shifter, raw data in statistical checker */ +#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_RAW_SC 2 +/* invalid combination */ +#define RTMCTL_SAMP_MODE_INVALID 3 +#define RTSDCTL_ENT_DLY_MIN 3200 +#define RTSDCTL_ENT_DLY_MAX 12800 +#define RTSDCTL_ENT_DLY_SHIFT 16 +#define RTSDCTL_ENT_DLY_MASK ((0xffffu) << RTSDCTL_ENT_DLY_SHIFT) +#define RTFRQMAX_DISABLE (1 << 20) + +/* Job ring interrupt handling */ +#define JR_REG_JRINIT_JRI_SHIFT 0 +#define JRINT_JRI_MASK (1 << JR_REG_JRINIT_JRI_SHIFT) +#define JRINT_JRI_CLEAR (1 << JR_REG_JRINIT_JRI_SHIFT) + +/* Constants for error handling on job ring */ +#define JR_REG_JRINT_ERR_TYPE_SHIFT 8 +#define JR_REG_JRINT_ERR_ORWI_SHIFT 16 +#define JR_REG_JRINIT_JRE_SHIFT 1 + +#define JRINT_JRE (1 << JR_REG_JRINIT_JRE_SHIFT) +#define JRINT_ERR_WRITE_STATUS (1 << JR_REG_JRINT_ERR_TYPE_SHIFT) +#define JRINT_ERR_BAD_INPUT_BASE (3 << JR_REG_JRINT_ERR_TYPE_SHIFT) +#define JRINT_ERR_BAD_OUTPUT_BASE (4 << JR_REG_JRINT_ERR_TYPE_SHIFT) +#define JRINT_ERR_WRITE_2_IRBA (5 << JR_REG_JRINT_ERR_TYPE_SHIFT) +#define JRINT_ERR_WRITE_2_ORBA (6 << JR_REG_JRINT_ERR_TYPE_SHIFT) +#define JRINT_ERR_RES_B4_HALT (7 << JR_REG_JRINT_ERR_TYPE_SHIFT) +#define JRINT_ERR_REM_TOO_MANY (8 << JR_REG_JRINT_ERR_TYPE_SHIFT) +#define JRINT_ERR_ADD_TOO_MANY (9 << JR_REG_JRINT_ERR_TYPE_SHIFT) +#define JRINT_ERR_HALT_MASK 0x0C +#define JRINT_ERR_HALT_INPROGRESS 0x04 +#define JRINT_ERR_HALT_COMPLETE 0x08 + +#define JR_REG_JRCR_VAL_RESET 0x00000001 + +#define JR_REG_JRCFG_LO_ICTT_SHIFT 0x10 +#define JR_REG_JRCFG_LO_ICDCT_SHIFT 0x08 +#define JR_REG_JRCFG_LO_ICEN_EN 0x02 +#define JR_REG_JRCFG_LO_IMSK_EN 0x01 + +/* Constants for Descriptor Processing errors */ +#define SEC_HW_ERR_SSRC_NO_SRC 0x00 +#define SEC_HW_ERR_SSRC_CCB_ERR 0x02 +#define SEC_HW_ERR_SSRC_JMP_HALT_U 0x03 +#define SEC_HW_ERR_SSRC_DECO 0x04 +#define SEC_HW_ERR_SSRC_JR 0x06 +#define SEC_HW_ERR_SSRC_JMP_HALT_COND 0x07 + +#define SEC_HW_ERR_DECO_HFN_THRESHOLD 0xF1 +#define SEC_HW_ERR_CCB_ICV_CHECK_FAIL 0x0A + +/* Macros for extracting error codes for the job ring */ + +#define JR_REG_JRINT_ERR_TYPE_EXTRACT(value) ((value)&0x00000F00) + +#define JR_REG_JRINT_ERR_ORWI_EXTRACT(value) \ + (((value)&0x3FFF0000) >> JR_REG_JRINT_ERR_ORWI_SHIFT) + +#define JR_REG_JRINT_JRE_EXTRACT(value) ((value)&JRINT_JRE) + +/* Macros for manipulating JR registers */ +typedef union { + uint64_t m_whole; + struct { + uint32_t low; + uint32_t high; + } m_halves; +} ptr_addr_t; + +/* Return higher 32 bits of physical address */ +#define PHYS_ADDR_HI(phys_addr) (uint32_t)(((uint64_t)phys_addr) >> 32) + +/* Return lower 32 bits of physical address */ +#define PHYS_ADDR_LO(phys_addr) (uint32_t)(((uint64_t)phys_addr) & 0xFFFFFFFF) + +#define sec_mem_in32(a, le) ((le) ? le32toh(*(uint32_t *)(uintptr_t)(a)) : be32toh(*(uint32_t *)(uintptr_t)(a))) +#define sec_mem_out32(a, v, le) \ + ({ *(uint32_t *)(uintptr_t)(a) = (le) ? (uint32_t)htole32(v) : (uint32_t)htobe32(v); }) +#define sec_mem_in64(addr, le) \ + (((uint64_t)sec_mem_in32((uintptr_t)(addr), (le)) << 32) | \ + (sec_mem_in32(((uintptr_t)(addr)) + 4, (le)))) +#define sec_mem_out64(addr, val, le) \ + ({ \ + sec_mem_out32(((uintptr_t)(addr)), (uint32_t)((val) >> 32), (le)); \ + sec_mem_out32(((uintptr_t)(addr)) + 4, (uint32_t)(val), (le)); \ + }) + +#define sec_read_addr(a, le) sec_mem_in64((a), (le)) +#define sec_write_addr(a, v, le) sec_mem_out64((a), (v), (le)) + +/* STRUCTURES AND OTHER TYPEDEFS */ +/* Lists the possible states for a job ring. */ +typedef enum sec_job_ring_state_e { + SEC_JOB_RING_STATE_STARTED, /* Job ring is initialized */ + SEC_JOB_RING_STATE_RESET, /* Job ring reset is in progres */ +} sec_job_ring_state_t; + +struct sec_job_ring_t { + /* + * Consumer index for job ring (jobs array). + * @note: cidx and pidx are accessed from + * different threads. + * Place the cidx and pidx inside the structure + * so that they lay on different cachelines, to + * avoid false sharing between threads when the + * threads run on different cores! + */ + uint32_t cidx; + + /* Producer index for job ring (jobs array) */ + uint32_t pidx; + + /* Ring of input descriptors. Size of array is power of 2 to allow + * fast update of producer/consumer indexes with bitwise operations. + */ + bus_addr_t *input_ring; + + /* Ring of output descriptors. */ + struct sec_outring_entry *output_ring; + + /* The file descriptor used for polling for interrupts notifications */ + uint32_t irq_fd; + + /* Model used by SEC Driver to receive notifications from SEC. + * Can be either of the three: + * #SEC_NOTIFICATION_TYPE_IRQ or + * #SEC_NOTIFICATION_TYPE_POLL + */ + uint32_t jr_mode; + /* notifies if coelescing is enabled for the job ring */ + uint8_t coalescing_en; + /* The state of this job ring */ + sec_job_ring_state_t jr_state; +}; + +/* Forward structure declaration */ +typedef struct sec_job_ring_t sec_job_ring_t; + +struct sec_outring_entry { + bus_addr_t desc; /* Pointer to completed descriptor */ + uint32_t status; /* Status for completed descriptor */ +} __packed; + +/* Lists the states possible for the SEC user space driver. */ +typedef enum sec_driver_state_e { + SEC_DRIVER_STATE_IDLE, /*< Driver not initialized */ + SEC_DRIVER_STATE_STARTED, /*< Driver initialized and */ + SEC_DRIVER_STATE_RELEASE, /*< Driver release is in progress */ +} sec_driver_state_t; + +/* Union describing the possible error codes that */ +/* can be set in the descriptor status word */ + +union jr_error_code { + uint32_t error; + union { + struct { + uint32_t ssrc : 4; + uint32_t ssed_val : 28; + } __packed value; + struct { + uint32_t ssrc : 4; + uint32_t res : 28; + } __packed no_status_src; + struct { + uint32_t ssrc : 4; + uint32_t jmp : 1; + uint32_t res : 11; + uint32_t desc_idx : 8; + uint32_t cha_id : 4; + uint32_t err_id : 4; + } __packed ccb_status_src; + struct { + uint32_t ssrc : 4; + uint32_t jmp : 1; + uint32_t res : 11; + uint32_t desc_idx : 8; + uint32_t offset : 8; + } __packed jmp_halt_user_src; + struct { + uint32_t ssrc : 4; + uint32_t jmp : 1; + uint32_t res : 11; + uint32_t desc_idx : 8; + uint32_t desc_err : 8; + } __packed deco_src; + struct { + uint32_t ssrc : 4; + uint32_t res : 17; + uint32_t naddr : 3; + uint32_t desc_err : 8; + } __packed jr_src; + struct { + uint32_t ssrc : 4; + uint32_t jmp : 1; + uint32_t res : 11; + uint32_t desc_idx : 8; + uint32_t cond : 8; + } __packed jmp_halt_cond_src; + } __packed error_desc; +} __packed; + +#endif /* CAAM_JR_HW_H */ diff --git a/sys/arm64/qoriq/caam/jr/caam_jr_pool.h b/sys/arm64/qoriq/caam/jr/caam_jr_pool.h new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_jr_pool.h @@ -0,0 +1,125 @@ +/* + * Copyright 2021 NXP + * Copyright 2023 Alstom Group + * Copyright 2024 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef CAAM_JR_POOL_H +#define CAAM_JR_POOL_H + +#include +#include +#include + +/* + * @brief Jobring allocator control structure + */ +struct jr_pool +{ + size_t jr_dev_cnt; + vmem_t *vm; + + /* Allow releases but not acquires */ + bool shutting_down; +}; + +/* + * @brief Take ownership of a jobring and get its device pointer. + * + * Release acquired jobring with jr_pool_release() on the same pool. + * Will block until a jobring can be acquired unless there is an internal + * failure or jr_pool is in a shutdown state. + * + * @param [in] p jr_pool to acquire from + * + * @retval :: device_t is returned if there is a jobring available + * @retval :: NULL is returned if shutting down or on internal error + */ +device_t +jr_pool_acquire(struct jr_pool *p); + +/* + * @brief Release a jobring and return it to jr_pool. + * + * @param [in] p jr_pool to release to + */ +void +jr_pool_release(struct jr_pool *p, device_t jr); + +/* + * @brief Add a new jobring to jr_pool. + * + * @param [in] p jr_pool to add to + * @param [in] device jobring device pointer + * + * @retval :: 0 is returned on success + * @retval :: errno is returned on internal error + */ +int +jr_pool_add(struct jr_pool *p, device_t device); + +/* + * @brief Return current jr_pool size. + * + * @param [in] p jr_pool + * + * @retval :: size_t total jobrings added to this pool. + */ +size_t +jr_pool_dev_cnt(struct jr_pool *p); + +/* + * @brief Initialize jr_pool instance. + * + * @param [in] p jr_pool to initialize. + */ +void +jr_pool_init(struct jr_pool *p); + +/* + * @brief Enter shutdown state on a pool. + * + * When pool is in shutdown state any jr_pool_acquire() requests will be + * rejected and return NULL, releases are still allowed. + * + * @param [in] p jr_pool to shut down + */ +void +jr_pool_shutdown(struct jr_pool *p); + +/* + * @brief Take ownership of a jobring and get its device pointer. + * + * Allowed while in shutdown state. + * Release acquired jobring with jr_pool_release() on the same pool. + * Will block until a jobring can be acquired unless there is an internal + * failure. + * + * @param [in] p jr_pool to acquire from + * + * @retval :: device_t is returned if there is a jobring available + * @retval :: NULL is returned if shutting down or on internal error + */ +device_t +jr_pool_shutdown_acquire(struct jr_pool *p); + +/* + * @brief Deinitialize jr_pool instance. + * + * Each pool member needs to be released before deinit can be called. + * + * A recommended approach is to mark jr_pool_shutdown() and + * wait until all members are released by acquirers. + * jr_pool_shutdown_acquire() can be then used to perform additional operations + * on pool members during shutdown. + * After all members return to the pool deinit can be safely called. + * + * @param [in] p jr_pool to deinit. + */ +void +jr_pool_deinit(struct jr_pool *p); + +#endif /* CAAM_JR_POOL_H */ diff --git a/sys/arm64/qoriq/caam/jr/caam_jr_pool.c b/sys/arm64/qoriq/caam/jr/caam_jr_pool.c new file mode 100644 --- /dev/null +++ b/sys/arm64/qoriq/caam/jr/caam_jr_pool.c @@ -0,0 +1,94 @@ +/* + * Copyright 2021 NXP + * Copyright 2023 Alstom Group + * Copyright 2024 Sii Poland + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include + +#include +#include +#include + +#include "../caam_debug.h" +#include "caam_jr_pool.h" + +device_t +jr_pool_acquire(struct jr_pool *p) +{ + int ret; + device_t jr = NULL; + + if (p->shutting_down) + return (NULL); + + ret = vmem_alloc(p->vm, 1, M_WAITOK | M_FIRSTFIT, (vmem_addr_t *)&jr); + if (ret != 0) { + CAAM_LOG_ERROR("vmem_alloc failed ret=%d\n", ret); + return (NULL); + } + + return (jr); +} + +void +jr_pool_release(struct jr_pool *p, device_t jr) +{ + vmem_free(p->vm, (vmem_addr_t)jr, 1); +} + +int +jr_pool_add(struct jr_pool *p, device_t device) +{ + p->jr_dev_cnt++; + + return vmem_add(p->vm, (vmem_addr_t)device, 1, M_WAITOK); +} + +size_t +jr_pool_dev_cnt(struct jr_pool *p) +{ + return p->jr_dev_cnt; +} + +void +jr_pool_init(struct jr_pool *p) +{ + p->jr_dev_cnt = 0; + p->shutting_down = false; + p->vm = vmem_create("jr_pool", 0, 0, 1, 0, M_ZERO | M_WAITOK); + if (p->vm == NULL) { + CAAM_LOG_ERROR("Failed to create vm arena\n"); + return; + } +} + +void +jr_pool_shutdown(struct jr_pool *p) +{ + p->shutting_down = true; +} + +device_t +jr_pool_shutdown_acquire(struct jr_pool *p) +{ + int ret; + device_t jr = NULL; + + ret = vmem_alloc(p->vm, 1, M_WAITOK | M_FIRSTFIT, (vmem_addr_t *)&jr); + if (ret != 0) { + CAAM_LOG_ERROR("vmem_alloc failed ret=%d\n", ret); + return (NULL); + } + + return (jr); +} + +void +jr_pool_deinit(struct jr_pool *p) +{ + vmem_destroy(p->vm); +} diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -695,6 +695,10 @@ arm64/qoriq/clk/lx2160a_clkgen.c optional clk soc_nxp_ls fdt arm64/qoriq/clk/qoriq_clk_pll.c optional clk soc_nxp_ls arm64/qoriq/clk/qoriq_clkgen.c optional clk soc_nxp_ls fdt +arm64/qoriq/caam/caam.c optional caam soc_nxp_ls +arm64/qoriq/caam/jr/caam_jr.c optional caam soc_nxp_ls +arm64/qoriq/caam/jr/caam_jr_pool.c optional caam soc_nxp_ls +arm64/qoriq/caam/jr/caam_jobdesc.c optional caam soc_nxp_ls dev/ahci/ahci_fsl_fdt.c optional soc_nxp_ls ahci fdt dev/flash/flexspi/flex_spi.c optional clk flex_spi soc_nxp_ls fdt