1 // SPDX-License-Identifier: GPL-2.0+
3 * caam - Freescale FSL CAAM support for hw_random
5 * Copyright 2011 Freescale Semiconductor, Inc.
6 * Copyright 2018-2019 NXP
8 * Based on caamalg.c crypto API driver.
12 #include <linux/hw_random.h>
13 #include <linux/completion.h>
14 #include <linux/atomic.h>
15 #include <linux/kfifo.h>
21 #include "desc_constr.h"
25 #define CAAM_RNG_MAX_FIFO_STORE_SIZE 16
28 * Length of used descriptors, see caam_init_desc()
30 #define CAAM_RNG_DESC_LEN (CAAM_CMD_SZ + \
32 CAAM_CMD_SZ + CAAM_PTR_SZ_MAX)
34 /* rng per-device context */
38 struct device
*ctrldev
;
41 struct work_struct worker
;
45 struct caam_rng_job_ctx
{
46 struct completion
*done
;
50 static struct caam_rng_ctx
*to_caam_rng_ctx(struct hwrng
*r
)
52 return (struct caam_rng_ctx
*)r
->priv
;
55 static void caam_rng_done(struct device
*jrdev
, u32
*desc
, u32 err
,
58 struct caam_rng_job_ctx
*jctx
= context
;
61 *jctx
->err
= caam_jr_strstatus(jrdev
, err
);
66 static u32
*caam_init_desc(u32
*desc
, dma_addr_t dst_dma
)
68 init_job_desc(desc
, 0); /* + 1 cmd_sz */
69 /* Generate random bytes: + 1 cmd_sz */
70 append_operation(desc
, OP_ALG_ALGSEL_RNG
| OP_TYPE_CLASS1_ALG
|
72 /* Store bytes: + 1 cmd_sz + caam_ptr_sz */
73 append_fifo_store(desc
, dst_dma
,
74 CAAM_RNG_MAX_FIFO_STORE_SIZE
, FIFOST_TYPE_RNGSTORE
);
76 print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_ADDRESS
,
77 16, 4, desc
, desc_bytes(desc
), 1);
82 static int caam_rng_read_one(struct device
*jrdev
,
85 struct completion
*done
)
89 struct caam_rng_job_ctx jctx
= {
94 len
= CAAM_RNG_MAX_FIFO_STORE_SIZE
;
96 dst_dma
= dma_map_single(jrdev
, dst
, len
, DMA_FROM_DEVICE
);
97 if (dma_mapping_error(jrdev
, dst_dma
)) {
98 dev_err(jrdev
, "unable to map destination memory\n");
102 init_completion(done
);
103 err
= caam_jr_enqueue(jrdev
,
104 caam_init_desc(desc
, dst_dma
),
105 caam_rng_done
, &jctx
);
106 if (err
== -EINPROGRESS
) {
107 wait_for_completion(done
);
111 dma_unmap_single(jrdev
, dst_dma
, len
, DMA_FROM_DEVICE
);
113 return err
?: (ret
?: len
);
116 static void caam_rng_fill_async(struct caam_rng_ctx
*ctx
)
118 struct scatterlist sg
[1];
119 struct completion done
;
122 sg_init_table(sg
, ARRAY_SIZE(sg
));
123 nents
= kfifo_dma_in_prepare(&ctx
->fifo
, sg
, ARRAY_SIZE(sg
),
124 CAAM_RNG_MAX_FIFO_STORE_SIZE
);
128 len
= caam_rng_read_one(ctx
->jrdev
, sg_virt(&sg
[0]),
135 kfifo_dma_in_finish(&ctx
->fifo
, len
);
138 static void caam_rng_worker(struct work_struct
*work
)
140 struct caam_rng_ctx
*ctx
= container_of(work
, struct caam_rng_ctx
,
142 caam_rng_fill_async(ctx
);
145 static int caam_read(struct hwrng
*rng
, void *dst
, size_t max
, bool wait
)
147 struct caam_rng_ctx
*ctx
= to_caam_rng_ctx(rng
);
151 struct completion done
;
153 return caam_rng_read_one(ctx
->jrdev
, dst
, max
,
154 ctx
->desc_sync
, &done
);
157 out
= kfifo_out(&ctx
->fifo
, dst
, max
);
158 if (kfifo_is_empty(&ctx
->fifo
))
159 schedule_work(&ctx
->worker
);
164 static void caam_cleanup(struct hwrng
*rng
)
166 struct caam_rng_ctx
*ctx
= to_caam_rng_ctx(rng
);
168 flush_work(&ctx
->worker
);
169 caam_jr_free(ctx
->jrdev
);
170 kfifo_free(&ctx
->fifo
);
173 static int caam_init(struct hwrng
*rng
)
175 struct caam_rng_ctx
*ctx
= to_caam_rng_ctx(rng
);
178 ctx
->desc_sync
= devm_kzalloc(ctx
->ctrldev
, CAAM_RNG_DESC_LEN
,
179 GFP_DMA
| GFP_KERNEL
);
183 ctx
->desc_async
= devm_kzalloc(ctx
->ctrldev
, CAAM_RNG_DESC_LEN
,
184 GFP_DMA
| GFP_KERNEL
);
185 if (!ctx
->desc_async
)
188 if (kfifo_alloc(&ctx
->fifo
, CAAM_RNG_MAX_FIFO_STORE_SIZE
,
189 GFP_DMA
| GFP_KERNEL
))
192 INIT_WORK(&ctx
->worker
, caam_rng_worker
);
194 ctx
->jrdev
= caam_jr_alloc();
195 err
= PTR_ERR_OR_ZERO(ctx
->jrdev
);
197 kfifo_free(&ctx
->fifo
);
198 pr_err("Job Ring Device allocation for transform failed\n");
203 * Fill async buffer to have early randomness data for
206 caam_rng_fill_async(ctx
);
211 int caam_rng_init(struct device
*ctrldev
);
213 void caam_rng_exit(struct device
*ctrldev
)
215 devres_release_group(ctrldev
, caam_rng_init
);
218 int caam_rng_init(struct device
*ctrldev
)
220 struct caam_rng_ctx
*ctx
;
222 struct caam_drv_private
*priv
= dev_get_drvdata(ctrldev
);
225 /* Check for an instantiated RNG before registration */
227 rng_inst
= (rd_reg32(&priv
->ctrl
->perfmon
.cha_num_ls
) &
228 CHA_ID_LS_RNG_MASK
) >> CHA_ID_LS_RNG_SHIFT
;
230 rng_inst
= rd_reg32(&priv
->ctrl
->vreg
.rng
) & CHA_VER_NUM_MASK
;
235 if (!devres_open_group(ctrldev
, caam_rng_init
, GFP_KERNEL
))
238 ctx
= devm_kzalloc(ctrldev
, sizeof(*ctx
), GFP_KERNEL
);
242 ctx
->ctrldev
= ctrldev
;
244 ctx
->rng
.name
= "rng-caam";
245 ctx
->rng
.init
= caam_init
;
246 ctx
->rng
.cleanup
= caam_cleanup
;
247 ctx
->rng
.read
= caam_read
;
248 ctx
->rng
.priv
= (unsigned long)ctx
;
249 ctx
->rng
.quality
= 1024;
251 dev_info(ctrldev
, "registering rng-caam\n");
253 ret
= devm_hwrng_register(ctrldev
, &ctx
->rng
);
255 caam_rng_exit(ctrldev
);
259 devres_close_group(ctrldev
, caam_rng_init
);