1 // SPDX-License-Identifier: GPL-2.0
3 * sun8i-ce-prng.c - hardware cryptographic offloader for
4 * Allwinner H3/A64/H5/H2+/H6/R40 SoC
6 * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com>
8 * This file handle the PRNG
10 * You could find a link for the datasheet in Documentation/arm/sunxi.rst
13 #include <linux/dma-mapping.h>
14 #include <linux/pm_runtime.h>
15 #include <crypto/internal/rng.h>
17 int sun8i_ce_prng_init(struct crypto_tfm
*tfm
)
19 struct sun8i_ce_rng_tfm_ctx
*ctx
= crypto_tfm_ctx(tfm
);
21 memset(ctx
, 0, sizeof(struct sun8i_ce_rng_tfm_ctx
));
25 void sun8i_ce_prng_exit(struct crypto_tfm
*tfm
)
27 struct sun8i_ce_rng_tfm_ctx
*ctx
= crypto_tfm_ctx(tfm
);
29 memzero_explicit(ctx
->seed
, ctx
->slen
);
35 int sun8i_ce_prng_seed(struct crypto_rng
*tfm
, const u8
*seed
,
38 struct sun8i_ce_rng_tfm_ctx
*ctx
= crypto_rng_ctx(tfm
);
40 if (ctx
->seed
&& ctx
->slen
!= slen
) {
41 memzero_explicit(ctx
->seed
, ctx
->slen
);
47 ctx
->seed
= kmalloc(slen
, GFP_KERNEL
| GFP_DMA
);
51 memcpy(ctx
->seed
, seed
, slen
);
57 int sun8i_ce_prng_generate(struct crypto_rng
*tfm
, const u8
*src
,
58 unsigned int slen
, u8
*dst
, unsigned int dlen
)
60 struct sun8i_ce_rng_tfm_ctx
*ctx
= crypto_rng_ctx(tfm
);
61 struct rng_alg
*alg
= crypto_rng_alg(tfm
);
62 struct sun8i_ce_alg_template
*algt
;
63 struct sun8i_ce_dev
*ce
;
64 dma_addr_t dma_iv
, dma_dst
;
68 struct sun8i_ce_flow
*chan
;
73 algt
= container_of(alg
, struct sun8i_ce_alg_template
, alg
.rng
);
77 dev_err(ce
->dev
, "not seeded\n");
81 /* we want dlen + seedsize rounded up to a multiple of PRNG_DATA_SIZE */
82 todo
= dlen
+ ctx
->slen
+ PRNG_DATA_SIZE
* 2;
83 todo
-= todo
% PRNG_DATA_SIZE
;
85 d
= kzalloc(todo
, GFP_KERNEL
| GFP_DMA
);
91 dev_dbg(ce
->dev
, "%s PRNG slen=%u dlen=%u todo=%u multi=%u\n", __func__
,
92 slen
, dlen
, todo
, todo
/ PRNG_DATA_SIZE
);
94 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
96 algt
->stat_bytes
+= todo
;
99 dma_iv
= dma_map_single(ce
->dev
, ctx
->seed
, ctx
->slen
, DMA_TO_DEVICE
);
100 if (dma_mapping_error(ce
->dev
, dma_iv
)) {
101 dev_err(ce
->dev
, "Cannot DMA MAP IV\n");
105 dma_dst
= dma_map_single(ce
->dev
, d
, todo
, DMA_FROM_DEVICE
);
106 if (dma_mapping_error(ce
->dev
, dma_dst
)) {
107 dev_err(ce
->dev
, "Cannot DMA MAP DST\n");
112 err
= pm_runtime_get_sync(ce
->dev
);
114 pm_runtime_put_noidle(ce
->dev
);
118 mutex_lock(&ce
->rnglock
);
119 chan
= &ce
->chanlist
[flow
];
122 memset(cet
, 0, sizeof(struct ce_task
));
124 cet
->t_id
= cpu_to_le32(flow
);
125 common
= ce
->variant
->prng
| CE_COMM_INT
;
126 cet
->t_common_ctl
= cpu_to_le32(common
);
128 /* recent CE (H6) need length in bytes, in word otherwise */
129 if (ce
->variant
->prng_t_dlen_in_bytes
)
130 cet
->t_dlen
= cpu_to_le32(todo
);
132 cet
->t_dlen
= cpu_to_le32(todo
/ 4);
135 cet
->t_sym_ctl
= cpu_to_le32(sym
);
138 cet
->t_key
= cpu_to_le32(dma_iv
);
139 cet
->t_iv
= cpu_to_le32(dma_iv
);
141 cet
->t_dst
[0].addr
= cpu_to_le32(dma_dst
);
142 cet
->t_dst
[0].len
= cpu_to_le32(todo
/ 4);
143 ce
->chanlist
[flow
].timeout
= 2000;
145 err
= sun8i_ce_run_task(ce
, 3, "PRNG");
146 mutex_unlock(&ce
->rnglock
);
148 pm_runtime_put(ce
->dev
);
151 dma_unmap_single(ce
->dev
, dma_dst
, todo
, DMA_FROM_DEVICE
);
153 dma_unmap_single(ce
->dev
, dma_iv
, ctx
->slen
, DMA_TO_DEVICE
);
156 memcpy(dst
, d
, dlen
);
157 memcpy(ctx
->seed
, d
+ dlen
, ctx
->slen
);
159 memzero_explicit(d
, todo
);