Skip to content

Commit

Permalink
crypto: caam/rng: Add support for PRNG
Browse files Browse the repository at this point in the history
Add support for random number generation using PRNG
mode of CAAM and expose the interface through crypto API.

Signed-off-by: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>
  • Loading branch information
Meenakshi88 authored and intel-lab-lkp committed Mar 7, 2022
1 parent 280ee3c commit bc27c1a
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 0 deletions.
9 changes: 9 additions & 0 deletions drivers/crypto/caam/Kconfig
Expand Up @@ -151,6 +151,15 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
Selecting this will register the SEC4 hardware rng to
the hw_random API for supplying the kernel entropy pool.


config CRYPTO_DEV_FSL_CAAM_PRNG_API
bool "Register Pseudo random number generation implementation with Crypto API"
default y
select CRYPTO_RNG
help
Selecting this will register the SEC hardware prng to
the Crypto API.

endif # CRYPTO_DEV_FSL_CAAM_JR

endif # CRYPTO_DEV_FSL_CAAM
Expand Down
1 change: 1 addition & 0 deletions drivers/crypto/caam/Makefile
Expand Up @@ -21,6 +21,7 @@ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API) += caamprng.o

caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
Expand Down
238 changes: 238 additions & 0 deletions drivers/crypto/caam/caamprng.c
@@ -0,0 +1,238 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver to expose SEC4 PRNG via crypto RNG API
*
* Copyright 2022 NXP
*
*/

#include <linux/completion.h>
#include <crypto/internal/rng.h>
#include "compat.h"
#include "regs.h"
#include "intern.h"
#include "desc_constr.h"
#include "jr.h"
#include "error.h"

/*
* Length of used descriptors, see caam_init_desc()
*/
#define CAAM_PRNG_DESC_LEN (CAAM_CMD_SZ + \
CAAM_CMD_SZ + \
CAAM_CMD_SZ + CAAM_PTR_SZ_MAX)

/* prng per-device context */
struct caam_prng_ctx {
struct device *jrdev;
struct completion done;
};

struct caam_prng_alg {
struct rng_alg rng;
bool registered;
};

static void caam_prng_done(struct device *jrdev, u32 *desc, u32 err,
void *context)
{
struct caam_prng_ctx *jctx = context;

if (err)
caam_jr_strstatus(jrdev, err);

complete(&jctx->done);
}

static u32 *caam_init_reseed_desc(u32 *desc, dma_addr_t seed_dma, u32 len)
{
init_job_desc(desc, 0); /* + 1 cmd_sz */
/* Generate random bytes: + 1 cmd_sz */
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
OP_ALG_AS_FINALIZE | OP_ALG_AI_ON);
/* Store bytes: + 1 cmd_sz + caam_ptr_sz */
append_load(desc, seed_dma, len, CLASS_1 | LDST_SRCDST_BYTE_CONTEXT);

print_hex_dump_debug("prng reseed desc@: ", DUMP_PREFIX_ADDRESS,
16, 4, desc, desc_bytes(desc), 1);

return desc;
}

static u32 *caam_init_prng_desc(u32 *desc, dma_addr_t dst_dma, u32 len)
{
init_job_desc(desc, 0); /* + 1 cmd_sz */
/* Generate random bytes: + 1 cmd_sz */
append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG);
/* Store bytes: + 1 cmd_sz + caam_ptr_sz */
append_fifo_store(desc, dst_dma,
len, FIFOST_TYPE_RNGSTORE);

print_hex_dump_debug("prng job desc@: ", DUMP_PREFIX_ADDRESS,
16, 4, desc, desc_bytes(desc), 1);

return desc;
}

static int caam_prng_generate(struct crypto_rng *tfm,
const u8 *src, unsigned int slen,
u8 *dst, unsigned int dlen)
{
struct caam_prng_ctx ctx;
dma_addr_t dst_dma;
u32 *desc;
int ret;

ctx.jrdev = caam_jr_alloc();
ret = PTR_ERR_OR_ZERO(ctx.jrdev);
if (ret) {
pr_err("Job Ring Device allocation failed\n");
return ret;
}

desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA);
if (!desc) {
caam_jr_free(ctx.jrdev);
return -ENOMEM;
}

dst_dma = dma_map_single(ctx.jrdev, dst, dlen, DMA_FROM_DEVICE);
if (dma_mapping_error(ctx.jrdev, dst_dma)) {
dev_err(ctx.jrdev, "Failed to map destination buffer memory\n");
ret = -ENOMEM;
goto out;
}

init_completion(&ctx.done);
ret = caam_jr_enqueue(ctx.jrdev,
caam_init_prng_desc(desc, dst_dma, dlen),
caam_prng_done, &ctx);

if (ret == -EINPROGRESS) {
wait_for_completion(&ctx.done);
ret = 0;
}

dma_unmap_single(ctx.jrdev, dst_dma, dlen, DMA_FROM_DEVICE);

out:
kfree(desc);
caam_jr_free(ctx.jrdev);
return ret;
}

static void caam_prng_exit(struct crypto_tfm *tfm)
{

return;
}

static int caam_prng_init(struct crypto_tfm *tfm)
{
return 0;
}

static int caam_prng_seed(struct crypto_rng *tfm,
const u8 *seed, unsigned int slen)
{
struct caam_prng_ctx ctx;
dma_addr_t seed_dma;
u32 *desc;
int ret;

ctx.jrdev = caam_jr_alloc();
ret = PTR_ERR_OR_ZERO(ctx.jrdev);
if (ret) {
pr_err("Job Ring Device allocation failed\n");
return ret;
}

desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA);
if (!desc) {
caam_jr_free(ctx.jrdev);
return -ENOMEM;
}

seed_dma = dma_map_single(ctx.jrdev, seed, slen, DMA_FROM_DEVICE);
if (dma_mapping_error(ctx.jrdev, seed_dma)) {
dev_err(ctx.jrdev, "Failed to map destination buffer memory\n");
ret = -ENOMEM;
goto out;
}

init_completion(&ctx.done);
ret = caam_jr_enqueue(ctx.jrdev,
caam_init_reseed_desc(desc, seed_dma, slen),
caam_prng_done, &ctx);

if (ret == -EINPROGRESS) {
wait_for_completion(&ctx.done);
ret = 0;
}

dma_unmap_single(ctx.jrdev, seed_dma, slen, DMA_FROM_DEVICE);

out:
kfree(desc);
caam_jr_free(ctx.jrdev);
return ret;
}

static struct caam_prng_alg caam_prng_alg = {
.rng = {
.generate = caam_prng_generate,
.seed = caam_prng_seed,
.seedsize = 32,
.base = {
.cra_name = "stdrng",
.cra_driver_name = "prng-caam",
.cra_priority = 500,
.cra_ctxsize = sizeof(struct caam_prng_ctx),
.cra_module = THIS_MODULE,
.cra_init = caam_prng_init,
.cra_exit = caam_prng_exit,
},
}
};

void caam_prng_unregister(void *data)
{
if (caam_prng_alg.registered)
crypto_unregister_rng(&caam_prng_alg.rng);
}

int caam_prng_register(struct device *ctrldev)
{
struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
u32 rng_inst;
int ret = 0;

/* Check for available RNG blocks before registration */
if (priv->era < 10)
rng_inst = (rd_reg32(&priv->jr[0]->perfmon.cha_num_ls) &
CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
else
rng_inst = rd_reg32(&priv->jr[0]->vreg.rng) & CHA_VER_NUM_MASK;

if (!rng_inst) {
dev_dbg(ctrldev, "RNG block is not available..."
"skipping registering rng algorithm\n");

return ret;
}

ret = crypto_register_rng(&caam_prng_alg.rng);
if (ret) {
dev_err(ctrldev,
"couldn't register rng crypto alg: %d\n",
ret);
return ret;
}

caam_prng_alg.registered = true;

dev_info(ctrldev,
"rng crypto API alg registered %s\n", caam_prng_alg.rng.base.cra_name);

return 0;
}
1 change: 1 addition & 0 deletions drivers/crypto/caam/desc.h
Expand Up @@ -1255,6 +1255,7 @@
#define OP_ALG_ICV_ON (1 << OP_ALG_ICV_SHIFT)

#define OP_ALG_PR_ON BIT(1)
#define OP_ALG_AI_ON BIT(11)

#define OP_ALG_DIR_SHIFT 0
#define OP_ALG_DIR_MASK 1
Expand Down
15 changes: 15 additions & 0 deletions drivers/crypto/caam/intern.h
Expand Up @@ -185,6 +185,21 @@ static inline void caam_rng_exit(struct device *dev) {}

#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API */

#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API

int caam_prng_register(struct device *dev);
void caam_prng_unregister(void *data);

#else

static inline int caam_prng_register(struct device *dev)
{
return 0;
}

static inline void caam_prng_unregister(void *data) {}
#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API */

#ifdef CONFIG_CAAM_QI

int caam_qi_algapi_init(struct device *dev);
Expand Down
2 changes: 2 additions & 0 deletions drivers/crypto/caam/jr.c
Expand Up @@ -39,6 +39,7 @@ static void register_algs(struct caam_drv_private_jr *jrpriv,
caam_algapi_hash_init(dev);
caam_pkc_init(dev);
jrpriv->hwrng = !caam_rng_init(dev);
caam_prng_register(dev);
caam_qi_algapi_init(dev);

algs_unlock:
Expand All @@ -56,6 +57,7 @@ static void unregister_algs(void)

caam_pkc_exit();
caam_algapi_hash_exit();
caam_prng_unregister(NULL);
caam_algapi_exit();

algs_unlock:
Expand Down

0 comments on commit bc27c1a

Please sign in to comment.