1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver to expose SEC4 PRNG via crypto RNG API
9 #include <linux/completion.h>
10 #include <crypto/internal/rng.h>
11 #include <linux/dma-mapping.h>
12 #include <linux/kernel.h>
16 #include "desc_constr.h"
21 * Length of used descriptors, see caam_init_desc()
23 #define CAAM_PRNG_MAX_DESC_LEN (CAAM_CMD_SZ + \
25 CAAM_CMD_SZ + CAAM_PTR_SZ_MAX)
27 /* prng per-device context */
28 struct caam_prng_ctx
{
30 struct completion done
;
33 struct caam_prng_alg
{
38 static void caam_prng_done(struct device
*jrdev
, u32
*desc
, u32 err
,
41 struct caam_prng_ctx
*jctx
= context
;
43 jctx
->err
= err
? caam_jr_strstatus(jrdev
, err
) : 0;
45 complete(&jctx
->done
);
48 static u32
*caam_init_reseed_desc(u32
*desc
)
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
|
55 print_hex_dump_debug("prng reseed desc@: ", DUMP_PREFIX_ADDRESS
,
56 16, 4, desc
, desc_bytes(desc
), 1);
61 static u32
*caam_init_prng_desc(u32
*desc
, dma_addr_t dst_dma
, u32 len
)
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
);
70 print_hex_dump_debug("prng job desc@: ", DUMP_PREFIX_ADDRESS
,
71 16, 4, desc
, desc_bytes(desc
), 1);
76 static int caam_prng_generate(struct crypto_rng
*tfm
,
77 const u8
*src
, unsigned int slen
,
78 u8
*dst
, unsigned int dlen
)
80 unsigned int aligned_dlen
= ALIGN(dlen
, dma_get_cache_alignment());
81 struct caam_prng_ctx ctx
;
88 if (aligned_dlen
< dlen
)
91 buf
= kzalloc(aligned_dlen
, GFP_KERNEL
);
95 jrdev
= caam_jr_alloc();
96 ret
= PTR_ERR_OR_ZERO(jrdev
);
98 pr_err("Job Ring Device allocation failed\n");
103 desc
= kzalloc(CAAM_PRNG_MAX_DESC_LEN
, GFP_KERNEL
);
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");
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
);
121 if (ret
== -EINPROGRESS
) {
122 wait_for_completion(&ctx
.done
);
126 dma_unmap_single(jrdev
, dst_dma
, dlen
, DMA_FROM_DEVICE
);
129 memcpy(dst
, buf
, dlen
);
138 static void caam_prng_exit(struct crypto_tfm
*tfm
) {}
140 static int caam_prng_init(struct crypto_tfm
*tfm
)
145 static int caam_prng_seed(struct crypto_rng
*tfm
,
146 const u8
*seed
, unsigned int slen
)
148 struct caam_prng_ctx ctx
;
149 struct device
*jrdev
;
154 pr_err("Seed length should be zero\n");
158 jrdev
= caam_jr_alloc();
159 ret
= PTR_ERR_OR_ZERO(jrdev
);
161 pr_err("Job Ring Device allocation failed\n");
165 desc
= kzalloc(CAAM_PRNG_MAX_DESC_LEN
, GFP_KERNEL
);
171 init_completion(&ctx
.done
);
172 ret
= caam_jr_enqueue(jrdev
,
173 caam_init_reseed_desc(desc
),
174 caam_prng_done
, &ctx
);
176 if (ret
== -EINPROGRESS
) {
177 wait_for_completion(&ctx
.done
);
186 static struct caam_prng_alg caam_prng_alg
= {
188 .generate
= caam_prng_generate
,
189 .seed
= caam_prng_seed
,
192 .cra_name
= "stdrng",
193 .cra_driver_name
= "prng-caam",
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
,
203 void caam_prng_unregister(void *data
)
205 if (caam_prng_alg
.registered
)
206 crypto_unregister_rng(&caam_prng_alg
.rng
);
209 int caam_prng_register(struct device
*ctrldev
)
211 struct caam_drv_private
*priv
= dev_get_drvdata(ctrldev
);
215 /* Check for available RNG blocks before registration */
217 rng_inst
= (rd_reg32(&priv
->jr
[0]->perfmon
.cha_num_ls
) &
218 CHA_ID_LS_RNG_MASK
) >> CHA_ID_LS_RNG_SHIFT
;
220 rng_inst
= rd_reg32(&priv
->jr
[0]->vreg
.rng
) & CHA_VER_NUM_MASK
;
223 dev_dbg(ctrldev
, "RNG block is not available... skipping registering algorithm\n");
227 ret
= crypto_register_rng(&caam_prng_alg
.rng
);
230 "couldn't register rng crypto alg: %d\n",
235 caam_prng_alg
.registered
= true;
238 "rng crypto API alg registered %s\n", caam_prng_alg
.rng
.base
.cra_driver_name
);