Message ID | 20220304114123.3762649-1-meenakshi.aggarwal@nxp.com |
---|---|
State | New |
Headers | show |
Series | crypto: caam/rng: Add support for PRNG | expand |
Hi, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on herbert-cryptodev-2.6/master] [also build test WARNING on herbert-crypto-2.6/master v5.17-rc7 next-20220308] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/meenakshi-aggarwal-nxp-com/crypto-caam-rng-Add-support-for-PRNG/20220307-142401 base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master config: arm-multi_v7_defconfig (https://download.01.org/0day-ci/archive/20220309/202203090603.qhbToPLJ-lkp@intel.com/config) compiler: arm-linux-gnueabi-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/bc27c1a2748de5052fb4c042d90fa1e0e4132043 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review meenakshi-aggarwal-nxp-com/crypto-caam-rng-Add-support-for-PRNG/20220307-142401 git checkout bc27c1a2748de5052fb4c042d90fa1e0e4132043 # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arm SHELL=/bin/bash drivers/crypto/caam/ drivers/rtc/ If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): In file included from drivers/crypto/caam/compat.h:18, from drivers/crypto/caam/caamprng.c:11: drivers/crypto/caam/caamprng.c: In function 'caam_prng_seed': >> drivers/crypto/caam/caamprng.c:156:46: warning: passing argument 2 of 'dma_map_single_attrs' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers] 156 | seed_dma = dma_map_single(ctx.jrdev, seed, slen, DMA_FROM_DEVICE); | ^~~~ include/linux/dma-mapping.h:406:60: note: in definition of macro 'dma_map_single' 406 | #define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0) | ^ include/linux/dma-mapping.h:322:73: note: expected 'void *' but argument is of type 'const u8 *' {aka 'const unsigned char *'} 322 | static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, | ~~~~~~^~~ vim +156 drivers/crypto/caam/caamprng.c > 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_DESC_LEN (CAAM_CMD_SZ + \ 22 CAAM_CMD_SZ + \ 23 CAAM_CMD_SZ + CAAM_PTR_SZ_MAX) 24 25 /* prng per-device context */ 26 struct caam_prng_ctx { 27 struct device *jrdev; 28 struct completion done; 29 }; 30 31 struct caam_prng_alg { 32 struct rng_alg rng; 33 bool registered; 34 }; 35 36 static void caam_prng_done(struct device *jrdev, u32 *desc, u32 err, 37 void *context) 38 { 39 struct caam_prng_ctx *jctx = context; 40 41 if (err) 42 caam_jr_strstatus(jrdev, err); 43 44 complete(&jctx->done); 45 } 46 47 static u32 *caam_init_reseed_desc(u32 *desc, dma_addr_t seed_dma, u32 len) 48 { 49 init_job_desc(desc, 0); /* + 1 cmd_sz */ 50 /* Generate random bytes: + 1 cmd_sz */ 51 append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | 52 OP_ALG_AS_FINALIZE | OP_ALG_AI_ON); 53 /* Store bytes: + 1 cmd_sz + caam_ptr_sz */ 54 append_load(desc, seed_dma, len, CLASS_1 | LDST_SRCDST_BYTE_CONTEXT); 55 56 print_hex_dump_debug("prng reseed desc@: ", DUMP_PREFIX_ADDRESS, 57 16, 4, desc, desc_bytes(desc), 1); 58 59 return desc; 60 } 61 62 static u32 *caam_init_prng_desc(u32 *desc, dma_addr_t dst_dma, u32 len) 63 { 64 init_job_desc(desc, 0); /* + 1 cmd_sz */ 65 /* Generate random bytes: + 1 cmd_sz */ 66 append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG); 67 /* Store bytes: + 1 cmd_sz + caam_ptr_sz */ 68 append_fifo_store(desc, dst_dma, 69 len, FIFOST_TYPE_RNGSTORE); 70 71 print_hex_dump_debug("prng job desc@: ", DUMP_PREFIX_ADDRESS, 72 16, 4, desc, desc_bytes(desc), 1); 73 74 return desc; 75 } 76 77 static int caam_prng_generate(struct crypto_rng *tfm, 78 const u8 *src, unsigned int slen, 79 u8 *dst, unsigned int dlen) 80 { 81 struct caam_prng_ctx ctx; 82 dma_addr_t dst_dma; 83 u32 *desc; 84 int ret; 85 86 ctx.jrdev = caam_jr_alloc(); 87 ret = PTR_ERR_OR_ZERO(ctx.jrdev); 88 if (ret) { 89 pr_err("Job Ring Device allocation failed\n"); 90 return ret; 91 } 92 93 desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA); 94 if (!desc) { 95 caam_jr_free(ctx.jrdev); 96 return -ENOMEM; 97 } 98 99 dst_dma = dma_map_single(ctx.jrdev, dst, dlen, DMA_FROM_DEVICE); 100 if (dma_mapping_error(ctx.jrdev, dst_dma)) { 101 dev_err(ctx.jrdev, "Failed to map destination buffer memory\n"); 102 ret = -ENOMEM; 103 goto out; 104 } 105 106 init_completion(&ctx.done); 107 ret = caam_jr_enqueue(ctx.jrdev, 108 caam_init_prng_desc(desc, dst_dma, dlen), 109 caam_prng_done, &ctx); 110 111 if (ret == -EINPROGRESS) { 112 wait_for_completion(&ctx.done); 113 ret = 0; 114 } 115 116 dma_unmap_single(ctx.jrdev, dst_dma, dlen, DMA_FROM_DEVICE); 117 118 out: 119 kfree(desc); 120 caam_jr_free(ctx.jrdev); 121 return ret; 122 } 123 124 static void caam_prng_exit(struct crypto_tfm *tfm) 125 { 126 127 return; 128 } 129 130 static int caam_prng_init(struct crypto_tfm *tfm) 131 { 132 return 0; 133 } 134 135 static int caam_prng_seed(struct crypto_rng *tfm, 136 const u8 *seed, unsigned int slen) 137 { 138 struct caam_prng_ctx ctx; 139 dma_addr_t seed_dma; 140 u32 *desc; 141 int ret; 142 143 ctx.jrdev = caam_jr_alloc(); 144 ret = PTR_ERR_OR_ZERO(ctx.jrdev); 145 if (ret) { 146 pr_err("Job Ring Device allocation failed\n"); 147 return ret; 148 } 149 150 desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA); 151 if (!desc) { 152 caam_jr_free(ctx.jrdev); 153 return -ENOMEM; 154 } 155 > 156 seed_dma = dma_map_single(ctx.jrdev, seed, slen, DMA_FROM_DEVICE); 157 if (dma_mapping_error(ctx.jrdev, seed_dma)) { 158 dev_err(ctx.jrdev, "Failed to map destination buffer memory\n"); 159 ret = -ENOMEM; 160 goto out; 161 } 162 163 init_completion(&ctx.done); 164 ret = caam_jr_enqueue(ctx.jrdev, 165 caam_init_reseed_desc(desc, seed_dma, slen), 166 caam_prng_done, &ctx); 167 168 if (ret == -EINPROGRESS) { 169 wait_for_completion(&ctx.done); 170 ret = 0; 171 } 172 173 dma_unmap_single(ctx.jrdev, seed_dma, slen, DMA_FROM_DEVICE); 174 175 out: 176 kfree(desc); 177 caam_jr_free(ctx.jrdev); 178 return ret; 179 } 180 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On 3/16/2022 8:02 PM, Meenakshi Aggarwal wrote: > From: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com> > > Add support for random number generation using PRNG > mode of CAAM and expose the interface through crypto API. > According to the RM, the HW implementation of the DRBG follows NIST SP 800-90A specification for DRBG_Hash SHA-256 function (https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf). This should be mentioned in the commit message at minimum. > Reported-by: kernel test robot <lkp@intel.com> This isn't required and doesn't make sense once you've squashed the fix. > +/* prng per-device context */ > +struct caam_prng_ctx { > + struct device *jrdev; jrdev doesn't have to be saved in this struct, it's lifetime is very limited. > + 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); The error returned by caam_jr_strstatus() should be propagated back to who initially enqueued the corresponding. For this purpose, struct caam_prng_ctx could be extended with an "err" member. > + > + complete(&jctx->done); > +} > + > +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; > + u8 *buf; > + int ret; > + > + buf = kzalloc(dlen, GFP_KERNEL); > + if (!buf) > + return -ENOMEM; > + > + ctx.jrdev = caam_jr_alloc(); > + ret = PTR_ERR_OR_ZERO(ctx.jrdev); > + if (ret) { > + pr_err("Job Ring Device allocation failed\n"); > + kfree(buf); > + return ret; > + } > + > + desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA); > + if (!desc) { > + caam_jr_free(ctx.jrdev); > + kfree(buf); > + return -ENOMEM; Please fix the error handling to reuse the free code at the end of the function. > + } > + > + dst_dma = dma_map_single(ctx.jrdev, buf, 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); > + > + memcpy(dst, buf, dlen); I am a bit worried wrt. performance, considering the memory allocations and the memcpy on the hotpath. Previous version of CAAM PRNG driver was getting ~ 200 MB/s on LS and 50 MB/s on i.MX8. How does the current version compare? Given that there's no prefetch buffer and there are memory allocation, copy operations on the hotpath, I'd expect a hefty penalty. > +out: > + caam_jr_free(ctx.jrdev); > + kfree(desc); > + kfree(buf); > + return ret; > +} > + > +static void caam_prng_exit(struct crypto_tfm *tfm) {} > + > +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; > + u8 *buf; > + int ret = 0; > + > + if (seed == NULL) { > + pr_err("Seed not provided\n"); > + return ret; > + } > + > + buf = kzalloc(slen, GFP_KERNEL); > + if (!buf) > + return -ENOMEM; > + > + ctx.jrdev = caam_jr_alloc(); > + ret = PTR_ERR_OR_ZERO(ctx.jrdev); > + if (ret) { > + pr_err("Job Ring Device allocation failed\n"); > + kfree(buf); > + return ret; > + } > + > + desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA); > + if (!desc) { > + caam_jr_free(ctx.jrdev); > + kfree(buf); > + return -ENOMEM; Same here, error handling at the end of the function should be reused. > + } > + > + memcpy(buf, seed, slen); > + > + seed_dma = dma_map_single(ctx.jrdev, buf, slen, DMA_FROM_DEVICE); > + if (dma_mapping_error(ctx.jrdev, seed_dma)) { > + dev_err(ctx.jrdev, "Failed to map seed 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: > + caam_jr_free(ctx.jrdev); > + kfree(desc); > + kfree(buf); > + return ret; > +} > + > +static struct caam_prng_alg caam_prng_alg = { > + .rng = { > + .generate = caam_prng_generate, > + .seed = caam_prng_seed, > + .seedsize = 32, seedsize should be set to 0, HW does not need an externally-provided seed since it fetches it internally from TRNG. > +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 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); driver_name should be printed, it's more specific / unique. > diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c > index 7f2b1101f567..11849362f912 100644 > --- a/drivers/crypto/caam/jr.c > +++ b/drivers/crypto/caam/jr.c > @@ -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: > @@ -56,6 +57,7 @@ static void unregister_algs(void) > > caam_pkc_exit(); > caam_algapi_hash_exit(); > + caam_prng_unregister(NULL); Unregistering order should be the reverse order of registering. Horia
HI, Thanks for the review. Will incorporate all suggested changes in v3. On i.MX8, performance is coming ~ 42 MB/s Thanks, Meenakshi > -----Original Message----- > From: Horia Geanta <horia.geanta@nxp.com> > Sent: Tuesday, April 5, 2022 6:02 PM > To: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>; Pankaj Gupta > <pankaj.gupta@nxp.com>; Gaurav Jain <gaurav.jain@nxp.com>; Varun Sethi > <V.Sethi@nxp.com>; Herbert Xu <herbert@gondor.apana.org.au>; David S . > Miller <davem@davemloft.net> > Cc: linux-crypto@vger.kernel.org; linux-kernel@vger.kernel.org; dl-linux-imx > <linux-imx@nxp.com>; kernel test robot <lkp@intel.com> > Subject: Re: [PATCH v2 1/1] crypto: caam/rng: Add support for PRNG > > On 3/16/2022 8:02 PM, Meenakshi Aggarwal wrote: > > From: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com> > > > > Add support for random number generation using PRNG mode of CAAM and > > expose the interface through crypto API. > > > According to the RM, the HW implementation of the DRBG follows NIST SP 800- > 90A specification for DRBG_Hash SHA-256 function > (https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf). > This should be mentioned in the commit message at minimum. > > > Reported-by: kernel test robot <lkp@intel.com> > This isn't required and doesn't make sense once you've squashed the fix. > > > +/* prng per-device context */ > > +struct caam_prng_ctx { > > + struct device *jrdev; > jrdev doesn't have to be saved in this struct, it's lifetime is very limited. > > > + 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); > The error returned by caam_jr_strstatus() should be propagated back to who > initially enqueued the corresponding. > For this purpose, struct caam_prng_ctx could be extended with an "err" member. > > > + > > + complete(&jctx->done); > > +} > > + > > > +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; > > + u8 *buf; > > + int ret; > > + > > + buf = kzalloc(dlen, GFP_KERNEL); > > + if (!buf) > > + return -ENOMEM; > > + > > + ctx.jrdev = caam_jr_alloc(); > > + ret = PTR_ERR_OR_ZERO(ctx.jrdev); > > + if (ret) { > > + pr_err("Job Ring Device allocation failed\n"); > > + kfree(buf); > > + return ret; > > + } > > + > > + desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA); > > + if (!desc) { > > + caam_jr_free(ctx.jrdev); > > + kfree(buf); > > + return -ENOMEM; > Please fix the error handling to reuse the free code at the end of the function. > > > + } > > + > > + dst_dma = dma_map_single(ctx.jrdev, buf, 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); > > + > > + memcpy(dst, buf, dlen); > I am a bit worried wrt. performance, considering the memory allocations and > the memcpy on the hotpath. > > Previous version of CAAM PRNG driver was getting ~ 200 MB/s on LS and 50 > MB/s on i.MX8. > > How does the current version compare? > Given that there's no prefetch buffer and there are memory allocation, copy > operations on the hotpath, I'd expect a hefty penalty. > > > +out: > > + caam_jr_free(ctx.jrdev); > > + kfree(desc); > > + kfree(buf); > > + return ret; > > +} > > + > > +static void caam_prng_exit(struct crypto_tfm *tfm) {} > > + > > +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; > > + u8 *buf; > > + int ret = 0; > > + > > + if (seed == NULL) { > > + pr_err("Seed not provided\n"); > > + return ret; > > + } > > + > > + buf = kzalloc(slen, GFP_KERNEL); > > + if (!buf) > > + return -ENOMEM; > > + > > + ctx.jrdev = caam_jr_alloc(); > > + ret = PTR_ERR_OR_ZERO(ctx.jrdev); > > + if (ret) { > > + pr_err("Job Ring Device allocation failed\n"); > > + kfree(buf); > > + return ret; > > + } > > + > > + desc = kzalloc(CAAM_PRNG_DESC_LEN, GFP_KERNEL | GFP_DMA); > > + if (!desc) { > > + caam_jr_free(ctx.jrdev); > > + kfree(buf); > > + return -ENOMEM; > Same here, error handling at the end of the function should be reused. > > > + } > > + > > + memcpy(buf, seed, slen); > > + > > + seed_dma = dma_map_single(ctx.jrdev, buf, slen, DMA_FROM_DEVICE); > > + if (dma_mapping_error(ctx.jrdev, seed_dma)) { > > + dev_err(ctx.jrdev, "Failed to map seed 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: > > + caam_jr_free(ctx.jrdev); > > + kfree(desc); > > + kfree(buf); > > + return ret; > > +} > > + > > +static struct caam_prng_alg caam_prng_alg = { > > + .rng = { > > + .generate = caam_prng_generate, > > + .seed = caam_prng_seed, > > + .seedsize = 32, > seedsize should be set to 0, HW does not need an externally-provided seed since > it fetches it internally from TRNG. > > > +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 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); > driver_name should be printed, it's more specific / unique. > > > diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index > > 7f2b1101f567..11849362f912 100644 > > --- a/drivers/crypto/caam/jr.c > > +++ b/drivers/crypto/caam/jr.c > > @@ -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: > > @@ -56,6 +57,7 @@ static void unregister_algs(void) > > > > caam_pkc_exit(); > > caam_algapi_hash_exit(); > > + caam_prng_unregister(NULL); > Unregistering order should be the reverse order of registering. > > Horia
diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 84ea7cba5ee5..d94250348b32 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -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 diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index 3570286eb9ce..59961a0bbfe4 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -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),) diff --git a/drivers/crypto/caam/caamprng.c b/drivers/crypto/caam/caamprng.c new file mode 100644 index 000000000000..be0cf0e214f0 --- /dev/null +++ b/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; +} diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h index e13470901586..33db8ed2b49e 100644 --- a/drivers/crypto/caam/desc.h +++ b/drivers/crypto/caam/desc.h @@ -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 diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 7d45b21bd55a..c2f51365df1b 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -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); diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 7f2b1101f567..11849362f912 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -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: @@ -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: