caamprng.c (5026B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Driver to expose SEC4 PRNG via crypto RNG API 4 * 5 * Copyright 2022 NXP 6 * 7 */ 8 9#include <linux/completion.h> 10#include <crypto/internal/rng.h> 11#include "compat.h" 12#include "regs.h" 13#include "intern.h" 14#include "desc_constr.h" 15#include "jr.h" 16#include "error.h" 17 18/* 19 * Length of used descriptors, see caam_init_desc() 20 */ 21#define CAAM_PRNG_MAX_DESC_LEN (CAAM_CMD_SZ + \ 22 CAAM_CMD_SZ + \ 23 CAAM_CMD_SZ + CAAM_PTR_SZ_MAX) 24 25/* prng per-device context */ 26struct caam_prng_ctx { 27 int err; 28 struct completion done; 29}; 30 31struct caam_prng_alg { 32 struct rng_alg rng; 33 bool registered; 34}; 35 36static void caam_prng_done(struct device *jrdev, u32 *desc, u32 err, 37 void *context) 38{ 39 struct caam_prng_ctx *jctx = context; 40 41 jctx->err = err ? caam_jr_strstatus(jrdev, err) : 0; 42 43 complete(&jctx->done); 44} 45 46static u32 *caam_init_reseed_desc(u32 *desc) 47{ 48 init_job_desc(desc, 0); /* + 1 cmd_sz */ 49 /* Generate random bytes: + 1 cmd_sz */ 50 append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | 51 OP_ALG_AS_FINALIZE); 52 53 print_hex_dump_debug("prng reseed desc@: ", DUMP_PREFIX_ADDRESS, 54 16, 4, desc, desc_bytes(desc), 1); 55 56 return desc; 57} 58 59static u32 *caam_init_prng_desc(u32 *desc, dma_addr_t dst_dma, u32 len) 60{ 61 init_job_desc(desc, 0); /* + 1 cmd_sz */ 62 /* Generate random bytes: + 1 cmd_sz */ 63 append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG); 64 /* Store bytes: + 1 cmd_sz + caam_ptr_sz */ 65 append_fifo_store(desc, dst_dma, 66 len, FIFOST_TYPE_RNGSTORE); 67 68 print_hex_dump_debug("prng job desc@: ", DUMP_PREFIX_ADDRESS, 69 16, 4, desc, desc_bytes(desc), 1); 70 71 return desc; 72} 73 74static int caam_prng_generate(struct crypto_rng *tfm, 75 const u8 *src, unsigned int slen, 76 u8 *dst, unsigned int dlen) 77{ 78 struct caam_prng_ctx ctx; 79 struct device *jrdev; 80 dma_addr_t dst_dma; 81 u32 *desc; 82 u8 *buf; 83 int ret; 84 85 buf = kzalloc(dlen, GFP_KERNEL); 86 if (!buf) 87 return -ENOMEM; 88 89 jrdev = caam_jr_alloc(); 90 ret = PTR_ERR_OR_ZERO(jrdev); 91 if (ret) { 92 pr_err("Job Ring Device allocation failed\n"); 93 kfree(buf); 94 return ret; 95 } 96 97 desc = kzalloc(CAAM_PRNG_MAX_DESC_LEN, GFP_KERNEL | GFP_DMA); 98 if (!desc) { 99 ret = -ENOMEM; 100 goto out1; 101 } 102 103 dst_dma = dma_map_single(jrdev, buf, dlen, DMA_FROM_DEVICE); 104 if (dma_mapping_error(jrdev, dst_dma)) { 105 dev_err(jrdev, "Failed to map destination buffer memory\n"); 106 ret = -ENOMEM; 107 goto out; 108 } 109 110 init_completion(&ctx.done); 111 ret = caam_jr_enqueue(jrdev, 112 caam_init_prng_desc(desc, dst_dma, dlen), 113 caam_prng_done, &ctx); 114 115 if (ret == -EINPROGRESS) { 116 wait_for_completion(&ctx.done); 117 ret = ctx.err; 118 } 119 120 dma_unmap_single(jrdev, dst_dma, dlen, DMA_FROM_DEVICE); 121 122 if (!ret) 123 memcpy(dst, buf, dlen); 124out: 125 kfree(desc); 126out1: 127 caam_jr_free(jrdev); 128 kfree(buf); 129 return ret; 130} 131 132static void caam_prng_exit(struct crypto_tfm *tfm) {} 133 134static int caam_prng_init(struct crypto_tfm *tfm) 135{ 136 return 0; 137} 138 139static int caam_prng_seed(struct crypto_rng *tfm, 140 const u8 *seed, unsigned int slen) 141{ 142 struct caam_prng_ctx ctx; 143 struct device *jrdev; 144 u32 *desc; 145 int ret; 146 147 if (slen) { 148 pr_err("Seed length should be zero\n"); 149 return -EINVAL; 150 } 151 152 jrdev = caam_jr_alloc(); 153 ret = PTR_ERR_OR_ZERO(jrdev); 154 if (ret) { 155 pr_err("Job Ring Device allocation failed\n"); 156 return ret; 157 } 158 159 desc = kzalloc(CAAM_PRNG_MAX_DESC_LEN, GFP_KERNEL | GFP_DMA); 160 if (!desc) { 161 caam_jr_free(jrdev); 162 return -ENOMEM; 163 } 164 165 init_completion(&ctx.done); 166 ret = caam_jr_enqueue(jrdev, 167 caam_init_reseed_desc(desc), 168 caam_prng_done, &ctx); 169 170 if (ret == -EINPROGRESS) { 171 wait_for_completion(&ctx.done); 172 ret = ctx.err; 173 } 174 175 kfree(desc); 176 caam_jr_free(jrdev); 177 return ret; 178} 179 180static struct caam_prng_alg caam_prng_alg = { 181 .rng = { 182 .generate = caam_prng_generate, 183 .seed = caam_prng_seed, 184 .seedsize = 0, 185 .base = { 186 .cra_name = "stdrng", 187 .cra_driver_name = "prng-caam", 188 .cra_priority = 500, 189 .cra_ctxsize = sizeof(struct caam_prng_ctx), 190 .cra_module = THIS_MODULE, 191 .cra_init = caam_prng_init, 192 .cra_exit = caam_prng_exit, 193 }, 194 } 195}; 196 197void caam_prng_unregister(void *data) 198{ 199 if (caam_prng_alg.registered) 200 crypto_unregister_rng(&caam_prng_alg.rng); 201} 202 203int caam_prng_register(struct device *ctrldev) 204{ 205 struct caam_drv_private *priv = dev_get_drvdata(ctrldev); 206 u32 rng_inst; 207 int ret = 0; 208 209 /* Check for available RNG blocks before registration */ 210 if (priv->era < 10) 211 rng_inst = (rd_reg32(&priv->jr[0]->perfmon.cha_num_ls) & 212 CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT; 213 else 214 rng_inst = rd_reg32(&priv->jr[0]->vreg.rng) & CHA_VER_NUM_MASK; 215 216 if (!rng_inst) { 217 dev_dbg(ctrldev, "RNG block is not available... skipping registering algorithm\n"); 218 return ret; 219 } 220 221 ret = crypto_register_rng(&caam_prng_alg.rng); 222 if (ret) { 223 dev_err(ctrldev, 224 "couldn't register rng crypto alg: %d\n", 225 ret); 226 return ret; 227 } 228 229 caam_prng_alg.registered = true; 230 231 dev_info(ctrldev, 232 "rng crypto API alg registered %s\n", caam_prng_alg.rng.base.cra_driver_name); 233 234 return 0; 235}