1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * sun8i-ce-prng.c - hardware cryptographic offloader for 4 * Allwinner H3/A64/H5/H2+/H6/R40 SoC 5 * 6 * Copyright (C) 2015-2020 Corentin Labbe <clabbe@baylibre.com> 7 * 8 * This file handle the PRNG 9 * 10 * You could find a link for the datasheet in Documentation/arm/sunxi.rst 11 */ 12 #include "sun8i-ce.h" 13 #include <linux/dma-mapping.h> 14 #include <linux/pm_runtime.h> 15 #include <crypto/internal/rng.h> 16 17 int sun8i_ce_prng_init(struct crypto_tfm *tfm) 18 { 19 struct sun8i_ce_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm); 20 21 memset(ctx, 0, sizeof(struct sun8i_ce_rng_tfm_ctx)); 22 return 0; 23 } 24 25 void sun8i_ce_prng_exit(struct crypto_tfm *tfm) 26 { 27 struct sun8i_ce_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm); 28 29 memzero_explicit(ctx->seed, ctx->slen); 30 kfree(ctx->seed); 31 ctx->seed = NULL; 32 ctx->slen = 0; 33 } 34 35 int sun8i_ce_prng_seed(struct crypto_rng *tfm, const u8 *seed, 36 unsigned int slen) 37 { 38 struct sun8i_ce_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm); 39 40 if (ctx->seed && ctx->slen != slen) { 41 memzero_explicit(ctx->seed, ctx->slen); 42 kfree(ctx->seed); 43 ctx->slen = 0; 44 ctx->seed = NULL; 45 } 46 if (!ctx->seed) 47 ctx->seed = kmalloc(slen, GFP_KERNEL | GFP_DMA); 48 if (!ctx->seed) 49 return -ENOMEM; 50 51 memcpy(ctx->seed, seed, slen); 52 ctx->slen = slen; 53 54 return 0; 55 } 56 57 int sun8i_ce_prng_generate(struct crypto_rng *tfm, const u8 *src, 58 unsigned int slen, u8 *dst, unsigned int dlen) 59 { 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; 65 int err = 0; 66 int flow = 3; 67 unsigned int todo; 68 struct sun8i_ce_flow *chan; 69 struct ce_task *cet; 70 u32 common, sym; 71 void *d; 72 73 algt = container_of(alg, struct sun8i_ce_alg_template, alg.rng); 74 ce = algt->ce; 75 76 if (ctx->slen == 0) { 77 dev_err(ce->dev, "not seeded\n"); 78 return -EINVAL; 79 } 80 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; 84 85 d = kzalloc(todo, GFP_KERNEL | GFP_DMA); 86 if (!d) { 87 err = -ENOMEM; 88 goto err_mem; 89 } 90 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); 93 94 #ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG 95 algt->stat_req++; 96 algt->stat_bytes += todo; 97 #endif 98 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"); 102 err = -EFAULT; 103 goto err_iv; 104 } 105 106 dma_dst = dma_map_single(ce->dev, d, todo, DMA_FROM_DEVICE); 107 if (dma_mapping_error(ce->dev, dma_dst)) { 108 dev_err(ce->dev, "Cannot DMA MAP DST\n"); 109 err = -EFAULT; 110 goto err_dst; 111 } 112 113 err = pm_runtime_get_sync(ce->dev); 114 if (err < 0) { 115 pm_runtime_put_noidle(ce->dev); 116 goto err_pm; 117 } 118 119 mutex_lock(&ce->rnglock); 120 chan = &ce->chanlist[flow]; 121 122 cet = &chan->tl[0]; 123 memset(cet, 0, sizeof(struct ce_task)); 124 125 cet->t_id = cpu_to_le32(flow); 126 common = ce->variant->prng | CE_COMM_INT; 127 cet->t_common_ctl = cpu_to_le32(common); 128 129 /* recent CE (H6) need length in bytes, in word otherwise */ 130 if (ce->variant->prng_t_dlen_in_bytes) 131 cet->t_dlen = cpu_to_le32(todo); 132 else 133 cet->t_dlen = cpu_to_le32(todo / 4); 134 135 sym = PRNG_LD; 136 cet->t_sym_ctl = cpu_to_le32(sym); 137 cet->t_asym_ctl = 0; 138 139 cet->t_key = cpu_to_le32(dma_iv); 140 cet->t_iv = cpu_to_le32(dma_iv); 141 142 cet->t_dst[0].addr = cpu_to_le32(dma_dst); 143 cet->t_dst[0].len = cpu_to_le32(todo / 4); 144 ce->chanlist[flow].timeout = 2000; 145 146 err = sun8i_ce_run_task(ce, 3, "PRNG"); 147 mutex_unlock(&ce->rnglock); 148 149 pm_runtime_put(ce->dev); 150 151 err_pm: 152 dma_unmap_single(ce->dev, dma_dst, todo, DMA_FROM_DEVICE); 153 err_dst: 154 dma_unmap_single(ce->dev, dma_iv, ctx->slen, DMA_TO_DEVICE); 155 156 if (!err) { 157 memcpy(dst, d, dlen); 158 memcpy(ctx->seed, d + dlen, ctx->slen); 159 } 160 memzero_explicit(d, todo); 161 err_iv: 162 kfree(d); 163 err_mem: 164 return err; 165 } 166