Page MenuHomeFreeBSD

D45591.id140220.diff
No OneTemporary

D45591.id140220.diff

diff --git a/sys/arm64/qoriq/caam/caam.c b/sys/arm64/qoriq/caam/caam.c
--- a/sys/arm64/qoriq/caam/caam.c
+++ b/sys/arm64/qoriq/caam/caam.c
@@ -32,6 +32,7 @@
#include "caam_debug.h"
#include "caam_internal.h"
#include "caam_test.h"
+#include "caam_trng.h"
#include "jr/caam_jobdesc.h"
#include "jr/caam_jr.h"
#include "jr/caam_jr_hw.h"
@@ -420,21 +421,30 @@
goto cleanup_rman;
}
+ /* After CAAM is ready, initialize the RNG drivers */
+ rv = caam_trng_attach(dev);
+ if (rv != 0) {
+ CAAM_LOG_ERROR("caam_trng_attach failed rv=(%d)\n", rv);
+ goto cleanup_jobrings;
+ }
+
#ifdef CAAM_DEBUG
/* Add the caam test device for development */
rv = caam_test_attach(dev);
if (rv != 0) {
CAAM_LOG_ERROR("caam_test_attach failed rv=(%d)\n", rv);
- goto cleanup_jobrings;
+ goto cleanup_trng;
}
#endif
return (0);
#ifdef CAAM_DEBUG
+cleanup_trng:
+ caam_trng_detach(dev);
+#endif
cleanup_jobrings:
- caam_jobrings_detach(dev);
-#endif
+ caam_jobrings_detach(dev);
cleanup_rman:
rman_fini(&sc->mem_rman);
cleanup_resource:
@@ -495,6 +505,8 @@
{
struct caam_softc *sc = device_get_softc(dev);
+ /* Remove TRNG drivers */
+ caam_trng_detach(dev);
#ifdef CAAM_DEBUG
/* Remove the caam test device */
caam_test_detach(dev);
diff --git a/sys/arm64/qoriq/caam/caam_trng.h b/sys/arm64/qoriq/caam/caam_trng.h
new file mode 100644
--- /dev/null
+++ b/sys/arm64/qoriq/caam/caam_trng.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 Alstom Group
+ * Copyright 2023 Sii Poland
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CAAM_RNG_H
+#define CAAM_RNG_H
+
+#include <sys/types.h>
+#include <sys/mutex.h>
+#include <sys/taskqueue.h>
+
+/*
+ * @brief Initialize CAAM TRNG module.
+ *
+ * Setup random harvester cache and refill.
+ * Register as a random source.
+ * Make TRNG side access /dev/random_caam character device.
+ *
+ * @param [in] dev caam device handle
+ *
+ * @retval :: 0 is returned on success
+ * @retval :: errno is returned on internal error
+ */
+int caam_trng_attach(device_t dev);
+
+/*
+ * @brief Uninitialize CAAM TRNG module and unregister our random source.
+ *
+ * @param [in] dev caam device handle
+ *
+ * @retval :: 0 is returned on success
+ * @retval :: errno is returned on internal error
+ */
+int caam_trng_detach(device_t dev);
+
+#endif /* CAAM_RNG_H */
\ No newline at end of file
diff --git a/sys/arm64/qoriq/caam/caam_trng.c b/sys/arm64/qoriq/caam/caam_trng.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/qoriq/caam/caam_trng.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright 2021 NXP
+ * Copyright 2023 Alstom Group
+ * Copyright 2023 Sii Poland
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/conf.h> /* cdevsw struct */
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/random.h>
+#include <sys/taskqueue.h>
+#include <sys/uio.h> /* uio struct */
+
+#include <machine/atomic.h>
+#include <machine/bus.h>
+
+#include <dev/random/randomdev.h>
+
+#include "caam.h"
+#include "caam_debug.h"
+#include "caam_internal.h"
+#include "caam_trng.h"
+#include "jr/caam_jobdesc.h"
+#include "jr/caam_jr_hw.h"
+
+MALLOC_DEFINE(M_TRNG, "CAAMTRNG", "CAAM TRNG malloc");
+
+#define NEXT_BUF_NUM(num) (((num) + 1) % (TRNG_CACHE_COUNT));
+#define TRNG_CACHE_SIZE 8192
+#define TRNG_CACHE_COUNT 2
+_Static_assert(TRNG_CACHE_COUNT >= 2,
+ "Need at least 2 buffers to function properly");
+
+struct trng_cache;
+
+/* Taskqueue responsible for maintaining proper levels of TRNG cache */
+struct trng_tq {
+ struct taskqueue *tq;
+ struct task task;
+ struct trng_cache *c;
+ device_t dev;
+};
+
+/*
+ * NOTE: Currently there is only one cache consumer so atomic r/w
+ * on data_left ensures that data is either non-empty and read or
+ * empty and pending refill.
+ * If there will be more concurrent consumers, we need to add locks.
+ */
+struct cache_buf {
+ uint8_t *data;
+ uint32_t data_left;
+};
+
+/* Precached random data for fast access by harvester callback */
+struct trng_cache {
+ int current_buf;
+ struct cache_buf buf[TRNG_CACHE_COUNT];
+
+ struct trng_tq *refill_tq;
+};
+static struct trng_cache g_cache;
+
+/* Workaround for API limitations of random(4). */
+static device_t g_caam_dev;
+
+int caam_trng_get_bytes(device_t dev, uint8_t *bytes, int byte_len);
+
+/*
+ * Wrapper for reading from random cache.
+ * Reads len bytes or up to bytes available in current buffer.
+ * If the current one has become exhausted gets a new buffer and
+ * enqueues a refill job.
+ */
+static uint32_t
+trng_cache_buf_read(struct trng_cache *c, uint8_t *buf, uint32_t len)
+{
+ struct cache_buf *cur;
+ uint32_t read_len;
+
+ cur = &c->buf[c->current_buf];
+
+ read_len = MIN(len, atomic_load_int(&cur->data_left));
+ memcpy(buf, &cur->data[TRNG_CACHE_SIZE - cur->data_left], read_len);
+
+ atomic_subtract_int(&cur->data_left, read_len);
+
+ if (atomic_load_int(&cur->data_left) == 0) {
+ c->current_buf = NEXT_BUF_NUM(c->current_buf);
+ taskqueue_enqueue(c->refill_tq->tq, &c->refill_tq->task);
+ }
+
+ return (read_len);
+}
+
+/* Run RNG job with cache buffer as data destination */
+static int
+trng_cache_refill(device_t dev, struct trng_cache *c, int buf_num)
+{
+ int ret = 0;
+
+ ret = caam_trng_get_bytes(dev, c->buf[buf_num].data, TRNG_CACHE_SIZE);
+ if (ret != 0) {
+ CAAM_LOG_ERROR("caam_trng_get_bytes failed\n");
+ } else {
+ atomic_store_int(&c->buf[buf_num].data_left, TRNG_CACHE_SIZE);
+ }
+
+ return (ret);
+}
+
+/* Traverse random cache buffers array and run refill jobs on empty ones */
+static void
+trng_cache_refill_worker(void *context, int pending)
+{
+ struct trng_tq *tq = context;
+ struct trng_cache *c = tq->c;
+ int buf_num = c->current_buf;
+
+ /* Refill empty buffers starting with the next one to be used */
+ for (int i = 0; i < TRNG_CACHE_COUNT - 1; ++i) {
+ buf_num = NEXT_BUF_NUM(buf_num);
+ if (atomic_load_int(&c->buf[buf_num].data_left) == 0) {
+ trng_cache_refill(tq->dev, c, buf_num);
+ }
+ }
+}
+
+/* Setup random cache refill task */
+static struct trng_tq *
+trng_cache_refill_setup(device_t dev, struct trng_cache *c)
+{
+ struct trng_tq *trng_tq;
+
+ trng_tq = malloc(sizeof(*trng_tq), M_TRNG, M_WAITOK | M_ZERO);
+ if (trng_tq == NULL) {
+ CAAM_LOG_ERROR("Could not allocate trng_tq\n");
+ return (NULL);
+ }
+ trng_tq->c = c;
+ trng_tq->dev = dev;
+
+ TASK_INIT(&trng_tq->task, 0, trng_cache_refill_worker, trng_tq);
+ trng_tq->tq = taskqueue_create_fast("caam_trng_tq", M_WAITOK | M_ZERO,
+ taskqueue_thread_enqueue, &trng_tq->tq);
+ taskqueue_start_threads(&trng_tq->tq, 1, PI_SOFT, "caam_trng_th");
+
+ return (trng_tq);
+}
+
+/* Stop and teardown random cache refill task */
+static void
+trng_cache_refill_teardown(struct trng_tq *tq)
+{
+ taskqueue_free(tq->tq);
+ free(tq, M_TRNG);
+}
+
+/*
+ * Allocate cache buffers and setup refill task.
+ * Deinit with trng_cache_deinit().
+ */
+static int
+trng_cache_init(device_t dev, struct trng_cache *c, size_t cache_size)
+{
+ int i;
+ int ret = 0;
+
+ c->current_buf = 0;
+
+ /*
+ * Contigmalloc will actively reclaim memory until it can make
+ * a contiguous buffer. This can take a varying amount of time so
+ * we'll allocate only once at attach while memory is not (that)
+ * fragmented.
+ */
+ for (i = 0; i < TRNG_CACHE_COUNT; ++i) {
+ c->buf[i].data_left = 0;
+ c->buf[i].data = contigmalloc(TRNG_CACHE_SIZE, M_TRNG, M_WAITOK,
+ 0, ~(vm_paddr_t)0, PAGE_SIZE, 0);
+ if (!c->buf[i].data) {
+ CAAM_LOG_ERROR(
+ "Could not allocate trng_tq->contig_buf\n");
+ ret = ENOMEM;
+ goto free_bufs;
+ }
+ }
+
+ c->refill_tq = trng_cache_refill_setup(dev, c);
+ if (!c->refill_tq) {
+ CAAM_LOG_ERROR("trng_cache_init failed\n");
+ ret = ENOMEM;
+ goto free_bufs;
+ }
+
+ return (0);
+
+free_bufs:
+ for (i -= 1; i >= 0; --i)
+ contigfree(c->buf[i].data, TRNG_CACHE_SIZE, M_TRNG);
+
+ return (ret);
+}
+
+/*
+ * Free cache buffers and teardown refill task.
+ */
+static void
+trng_cache_deinit(struct trng_cache *c)
+{
+ trng_cache_refill_teardown(c->refill_tq);
+
+ for (int i = 0; i < TRNG_CACHE_COUNT; ++i)
+ contigfree(c->buf[i].data, TRNG_CACHE_SIZE, M_TRNG);
+}
+
+/*----------------------- RNG initialization functions ----------------------*/
+/* Is the HW RNG instantiated?
+ * Return code:
+ * 0 - Not in the instantiated state
+ * 1 - In the instantiated state
+ * state_handle - 0 for SH0, 1 for SH1
+ */
+static int
+is_trng_instantiated(device_t dev, uint32_t *state_handle)
+{
+ int ret_code = 0;
+ uint32_t rdsta;
+
+ rdsta = caam_reg_read(dev, RNG_REG_RDSTA_OFFSET);
+
+ /*Check if either of the two state handles has been instantiated */
+ if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
+ *state_handle = 0;
+ ret_code = 1;
+ } else if (rdsta & RNG_STATE1_HANDLE_INSTANTIATED) {
+ *state_handle = 1;
+ ret_code = 1;
+ }
+
+ return ret_code;
+}
+
+/* Construct descriptor to instantiate RNG */
+static int
+cnstr_trng_instantiate_jobdesc(uint32_t *desc)
+{
+ caam_jobdesc_init(desc);
+ caam_jobdesc_add_word(desc, 0xb0800000u);
+ /* Class1 Alg Operation,RNG Optype, Instantiate */
+ caam_jobdesc_add_word(desc, 0x82500004u);
+ /* Wait for done */
+ caam_jobdesc_add_word(desc, 0xa2000001u);
+ /*Load to clear written */
+ caam_jobdesc_add_word(desc, 0x10880004u);
+ /*Pri Mode Reg clear */
+ caam_jobdesc_add_word(desc, 0x00000001u);
+ /* Generate secure keys */
+ caam_jobdesc_add_word(desc, 0x82501000u);
+
+ return 0;
+}
+
+/* @brief Submit descriptor to instantiate the RNG
+ * @retval 0 on success
+ * @retval other on error
+ */
+static int
+run_trng_instantiate_job(device_t dev)
+{
+ int ret = 0;
+ struct job_descriptor desc;
+ struct job_descriptor *jobdesc = &desc;
+ jobdesc->arg = NULL;
+ jobdesc->callback = NULL;
+
+ /* create the hw_rng descriptor */
+ cnstr_trng_instantiate_jobdesc(jobdesc->desc);
+
+ /* Finally, generate the requested random data bytes */
+ ret = caam_run_descriptor_jr_blocking(dev, jobdesc, NULL);
+ if (ret != 0) {
+ CAAM_LOG_WARN("Error in running descriptor\n");
+ ret = EIO;
+ }
+
+ return ret;
+}
+
+/* @brief Kick the TRNG block of the RNG HW Engine
+ * @param [in] ent_delay Entropy delay to be used
+ * By default, the TRNG runs for 200 clocks per sample;
+ * 1200 clocks per sample generates better entropy.
+ */
+static void
+kick_trng(device_t dev, int ent_delay)
+{
+ uint32_t val;
+
+ /* put RNG4 into program mode */
+ val = caam_reg_read(dev, RNG_REG_RTMCTL_OFFSET);
+ val = val | RTMCTL_PRGM;
+ caam_reg_write(dev, RNG_REG_RTMCTL_OFFSET, val);
+
+ /* rtsdctl bits 0-15 contain "Entropy Delay, which defines the
+ * length (in system clocks) of each Entropy sample taken
+ */
+ val = caam_reg_read(dev, RNG_REG_RTSDCTL_OFFSET);
+ val = (val & ~RTSDCTL_ENT_DLY_MASK) |
+ (ent_delay << RTSDCTL_ENT_DLY_SHIFT);
+ caam_reg_write(dev, RNG_REG_RTSDCTL_OFFSET, val);
+ /* min. freq. count, equal to 1/4 of the entropy sample length */
+ caam_reg_write(dev, RNG_REG_RTFRQMIN_OFFSET, ent_delay >> 2);
+ /* disable maximum frequency count */
+ caam_reg_write(dev, RNG_REG_RTFRQMAX_OFFSET, RTFRQMAX_DISABLE);
+
+ /* select raw sampling in both entropy shifter
+ * and statistical checker
+ */
+ val = caam_reg_read(dev, RNG_REG_RTMCTL_OFFSET);
+ val = val | RTMCTL_SAMP_MODE_RAW_ES_SC;
+ caam_reg_write(dev, RNG_REG_RTMCTL_OFFSET, val);
+
+ /* put RNG4 into run mode */
+ val = caam_reg_read(dev, RNG_REG_RTMCTL_OFFSET);
+ val = val & ~RTMCTL_PRGM;
+ caam_reg_write(dev, RNG_REG_RTMCTL_OFFSET, val);
+}
+
+/* This function instantiates the rng
+ *
+ * Return code:
+ * 0 - All is well
+ * <0 - Error occurred somewhere
+ */
+static int
+instantiate_trng(device_t dev)
+{
+ int ret = 0;
+ int ent_delay = RTSDCTL_ENT_DLY_MIN;
+ uint32_t state_handle;
+
+ ret = is_trng_instantiated(dev, &state_handle);
+ if (ret != 0) {
+ CAAM_LOG_NOTICE(
+ "RNG already instantiated, make sure it is running\n");
+
+ /* put RNG4 into run mode */
+ uint32_t val = caam_reg_read(dev, RNG_REG_RTMCTL_OFFSET);
+ val = val & ~RTMCTL_PRGM;
+ caam_reg_write(dev, RNG_REG_RTMCTL_OFFSET, val);
+
+ return 0;
+ }
+
+ do {
+ kick_trng(dev, ent_delay);
+ ent_delay += 400;
+ /*if instantiate_rng(...) fails, the loop will rerun
+ *and the kick_trng(...) function will modify the
+ *upper and lower limits of the entropy sampling
+ *interval, leading to a sucessful initialization
+ */
+ ret = run_trng_instantiate_job(dev);
+ } while ((ret != 0) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
+
+ if (ret != 0) {
+ CAAM_LOG_ERROR("RNG: Failed to instantiate RNG\n");
+ return ret;
+ }
+
+ CAAM_LOG_INFO("RNG: Instantiated\n");
+
+ return ret;
+}
+
+/*------------------ Functions to generate the RNG numbers ------------------*/
+/* Construct descriptor to generate Random words */
+static int
+cnstr_trng_jobdesc(uint32_t *desc, uint32_t state_handle, uint32_t *add_inp,
+ uint32_t add_ip_len, caam_jr_dma_map_t *out_data_map, bool little_endian)
+{
+ bus_addr_t phys_addr_out = out_data_map->bus_addr;
+
+ /* Current descriptor support only 64K length */
+ if (out_data_map->buflen > 0xffffu)
+ return EINVAL;
+ /* Additional Input not supported by current descriptor */
+ if (add_ip_len > 0U)
+ return EINVAL;
+
+ CAAM_LOG_DEBUG("Constructing descriptor\n");
+ caam_jobdesc_init(desc);
+ /* Class1 Alg Operation,RNG Optype, Generate */
+ caam_jobdesc_add_word(desc, 0xb0800000u);
+ caam_jobdesc_add_word(desc,
+ 0x82500000u | (state_handle << ALG_AAI_SH_SHIFT));
+ caam_jobdesc_add_word(desc, 0x60340000u | out_data_map->buflen);
+ caam_jobdesc_add_ptr(desc, phys_addr_out, little_endian);
+
+ return 0;
+}
+
+/* Generate Random Data using HW RNG
+ * Parameters:
+ * uint8_t* add_input - user specified optional input byte array
+ * uint32_t add_input_len - number of bytes of additional input
+ * uint8_t* out - user specified output byte array
+ * uint32_t out_len - number of bytes to store in output byte array
+ * Return code:
+ * 0 - SUCCESS
+ * !0 - ERROR
+ */
+static int
+run_trng_generate_job(device_t dev, uint32_t *add_input, uint32_t add_input_len,
+ uint8_t *out, uint32_t out_len, uint32_t state_handle)
+{
+ int ret = 0;
+ struct job_descriptor desc;
+ struct job_descriptor *jobdesc = &desc;
+ caam_jr_dma_map_t out_data_map;
+ struct caam_softc *sc;
+ device_t jr_dev;
+
+ sc = device_get_softc(dev);
+
+ jobdesc->arg = NULL;
+ jobdesc->callback = NULL;
+
+ jr_dev = jr_pool_acquire(&sc->jr_pool);
+ if (jr_dev == NULL) {
+ CAAM_LOG_ERROR("Failed to acquire JR\n");
+ goto exit;
+ }
+
+ /* Map the output buffer to the DMA memory */
+ ret = caam_jr_dma_map(jr_dev, &out_data_map, out, out_len, 0,
+ BUS_DMA_NOWAIT, JR_MAP_SYNC);
+ if (ret != 0) {
+ CAAM_LOG_ERROR("DMA mapping failed\n");
+ goto jr_free;
+ }
+
+ /* create the hw_rng descriptor */
+ ret = cnstr_trng_jobdesc(jobdesc->desc, state_handle, add_input,
+ add_input_len, &out_data_map, sc->little_endian);
+ if (ret != 0) {
+ CAAM_LOG_ERROR("Descriptor construction failed\n");
+ goto dma_unmap;
+ }
+
+ /* Finally, generate the requested random data bytes */
+ ret = caam_run_descriptor_jr_blocking(dev, jobdesc, jr_dev);
+ if (ret != 0) {
+ CAAM_LOG_ERROR("Error in running descriptor\n");
+ goto dma_unmap;
+ }
+
+dma_unmap:
+ caam_jr_dma_unmap(jr_dev, &out_data_map, JR_MAP_SYNC);
+
+jr_free:
+ jr_pool_release(&sc->jr_pool, jr_dev);
+
+exit:
+ return ret;
+}
+
+/* Generate random bytes, and stuff them into the bytes buffer
+ *
+ * If the HW RNG has not already been instantiated,
+ * it will be instantiated before data is generated.
+ *
+ * Parameters:
+ * uint8_t* bytes - byte buffer large enough to hold the requested random date
+ * int byte_len - number of random bytes to generate
+ *
+ * Return code:
+ * 0 - All is well
+ * ~0 - Error occurred somewhere
+ */
+int
+caam_trng_get_bytes(device_t dev, uint8_t *bytes, int byte_len)
+{
+ int ret_code = 0;
+ int init_ret_code = 0;
+ uint32_t state_handle = 0;
+
+ /* If this is the first time this routine is called,
+ * then the rng will not already be instantiated.
+ * Therefore, before generating data, instantiate the rng
+ */
+ init_ret_code = is_trng_instantiated(dev, &state_handle);
+ if (init_ret_code == 0) {
+ CAAM_LOG_INFO("Instantiating the HW RNG\n");
+
+ /* Instantiate the hw RNG */
+ ret_code = instantiate_trng(dev);
+ if (ret_code != 0) {
+ CAAM_LOG_ERROR("HW RNG Instantiate failed\n");
+ }
+ }
+
+ if (ret_code == 0) {
+ ret_code = run_trng_generate_job(dev, 0, 0, bytes, byte_len,
+ state_handle);
+ if (ret_code != 0) {
+ CAAM_LOG_ERROR("HW RNG Generate failed\n");
+ }
+ }
+
+ return ret_code;
+}
+
+/*------------ Random harvester (random_caam) interface functions -----------*/
+static u_int random_caam_read(void *, u_int);
+
+static struct random_source random_caam = {
+ .rs_ident = "NXP QorIQ platforms CAAM TRNG",
+ .rs_source = RANDOM_PURE_CAAMTRNG,
+ .rs_read = random_caam_read
+};
+
+/* Blocking read function will return prebuffered data */
+static u_int
+random_caam_read(void *buf, u_int c)
+{
+ struct trng_cache *cache = &g_cache;
+
+ c = trng_cache_buf_read(cache, buf, c);
+
+ CAAM_LOG_DEBUG("Read out %iB\n", c);
+
+ return c;
+}
+
+/*------ Random character device (random_caam_cdev) interface functions -----*/
+#define BUFFERSIZE 256
+
+/* Function prototypes */
+static d_open_t random_caam_cdev_open;
+static d_close_t random_caam_cdev_close;
+static d_read_t random_caam_cdev_read;
+
+/* Character device entry points */
+static struct cdevsw random_caam_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = random_caam_cdev_open,
+ .d_close = random_caam_cdev_close,
+ .d_read = random_caam_cdev_read,
+ .d_name = "random_caam_cdev",
+};
+
+/* vars */
+static struct cdev *random_caam_cdev;
+
+static int
+random_caam_cdev_open(struct cdev *dev __unused, int oflags __unused,
+ int devtype __unused, struct thread *td __unused)
+{
+ device_t caam_dev = g_caam_dev;
+
+ if (caam_dev == NULL) {
+ CAAM_LOG_ERROR("No CAAM module available!\n");
+ return (ENXIO);
+ }
+
+ CAAM_LOG_DEBUG("Opened CAAM TRNG character device successfully.\n");
+ return (0);
+}
+
+static int
+random_caam_cdev_close(struct cdev *dev __unused, int fflag __unused,
+ int devtype __unused, struct thread *td __unused)
+{
+ CAAM_LOG_DEBUG("Closing CAAM TRNG character device.\n");
+ return (0);
+}
+
+/*
+ * The read function reads from random device and set it to userland for
+ * accessing.
+ */
+static int
+random_caam_cdev_read(struct cdev *dev __unused, struct uio *uio,
+ int ioflag __unused)
+{
+ size_t read_len;
+ int error = 0;
+ uint8_t random_buf[BUFFERSIZE];
+ device_t caam_dev = g_caam_dev;
+
+ while (uio->uio_resid > 0) {
+ /* Maximum data to read is either local buff or user request */
+ read_len = MIN((size_t)uio->uio_resid, sizeof(random_buf));
+
+ error = caam_trng_get_bytes(caam_dev, random_buf, read_len);
+ if (error != 0) {
+ CAAM_LOG_ERROR("RNG generation failed!\n");
+ break;
+ }
+
+ /*
+ * uiomove() may yield the CPU before each 'read_len' bytes (up
+ * to bufsize) are copied out.
+ */
+ if ((error = uiomove(random_buf, read_len, uio)) != 0) {
+ CAAM_LOG_ERROR("uiomove failed!\n");
+ break;
+ }
+ }
+
+ explicit_bzero(random_buf, sizeof(random_buf));
+
+ return (error);
+}
+
+/*--------------------- CAAM device management functions --------------------*/
+int
+caam_trng_attach(device_t dev)
+{
+ int error = 0;
+ struct make_dev_args args;
+ struct trng_cache *c = &g_cache;
+
+ /* Add the random source and the character device only on the first CAAM
+ * device.*/
+ if (g_caam_dev == NULL) {
+ g_caam_dev = dev;
+
+ error = trng_cache_init(dev, c, TRNG_CACHE_SIZE);
+ if (error) {
+ CAAM_LOG_ERROR("Failed to init TRNG cache ret=%d\n",
+ error);
+ goto exit;
+ }
+
+ /* Initial fill before harvester can read from our buffers */
+ for (int i = 0; i < TRNG_CACHE_COUNT; ++i) {
+ error = trng_cache_refill(dev, c, i);
+ if (error) {
+ trng_cache_deinit(c);
+ goto exit;
+ }
+ }
+
+ random_source_register(&random_caam);
+ CAAM_LOG_INFO("CAAM TRNG registering fast provider: \"%s\"\n",
+ random_caam.rs_ident);
+
+ /* Register the device as read only */
+ make_dev_args_init(&args);
+ args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
+ args.mda_devsw = &random_caam_cdevsw;
+ args.mda_cr = 0;
+ args.mda_uid = UID_ROOT;
+ args.mda_gid = GID_WHEEL;
+ args.mda_mode = 0400;
+
+ error = make_dev_s(&args, &random_caam_cdev, "random_caam");
+
+ CAAM_LOG_INFO(
+ "CAAM TRNG /dev/random_caam character device loaded.\n");
+ }
+
+exit:
+ return error;
+}
+
+int
+caam_trng_detach(device_t dev)
+{
+ struct trng_cache *c = &g_cache;
+
+ /* Deregister rng source and rmove character device only if correct CAAM
+ * device is detached */
+ if (dev == g_caam_dev) {
+ CAAM_LOG_INFO(
+ "CAAM TRNG /dev/random_caam character device removed.\n");
+ destroy_dev(random_caam_cdev);
+
+ CAAM_LOG_INFO("CAAM TRNG deregistering fast provider: \"%s\"\n",
+ random_caam.rs_ident);
+ random_source_deregister(&random_caam);
+
+ trng_cache_deinit(c);
+
+ /* at this time no clients should exist that can use the
+ * g_caam_dev */
+ g_caam_dev = NULL;
+ }
+
+ return 0;
+}
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -687,6 +687,7 @@
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/caam_trng.c optional caam soc_nxp_ls
arm64/qoriq/caam/caam_test.c optional caam caam_debug 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
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -385,6 +385,7 @@
[RANDOM_PURE_VMGENID] = "PURE_VMGENID",
[RANDOM_PURE_QUALCOMM] = "PURE_QUALCOMM",
[RANDOM_PURE_ARMV8] = "PURE_ARMV8",
+ [RANDOM_PURE_CAAMTRNG] = "PURE_CAAMTRNG",
/* "ENTROPYSOURCE" */
};
diff --git a/sys/sys/random.h b/sys/sys/random.h
--- a/sys/sys/random.h
+++ b/sys/sys/random.h
@@ -103,6 +103,7 @@
RANDOM_PURE_VMGENID,
RANDOM_PURE_QUALCOMM,
RANDOM_PURE_ARMV8,
+ RANDOM_PURE_CAAMTRNG,
ENTROPYSOURCE
};
_Static_assert(ENTROPYSOURCE <= 32,

File Metadata

Mime Type
text/plain
Expires
Tue, May 19, 6:40 PM (11 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33283305
Default Alt Text
D45591.id140220.diff (21 KB)

Event Timeline