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