Path: blob/master/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c
26292 views
// SPDX-License-Identifier: GPL-2.01/*2* sun8i-ss-prng.c - hardware cryptographic offloader for3* Allwinner A80/A83T SoC4*5* Copyright (C) 2015-2020 Corentin Labbe <[email protected]>6*7* This file handle the PRNG found in the SS8*9* You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst10*/11#include "sun8i-ss.h"12#include <linux/dma-mapping.h>13#include <linux/kernel.h>14#include <linux/mm.h>15#include <linux/pm_runtime.h>16#include <crypto/internal/rng.h>1718int sun8i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,19unsigned int slen)20{21struct sun8i_ss_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm);2223if (ctx->seed && ctx->slen != slen) {24kfree_sensitive(ctx->seed);25ctx->slen = 0;26ctx->seed = NULL;27}28if (!ctx->seed)29ctx->seed = kmalloc(slen, GFP_KERNEL);30if (!ctx->seed)31return -ENOMEM;3233memcpy(ctx->seed, seed, slen);34ctx->slen = slen;3536return 0;37}3839int sun8i_ss_prng_init(struct crypto_tfm *tfm)40{41struct sun8i_ss_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm);4243memset(ctx, 0, sizeof(struct sun8i_ss_rng_tfm_ctx));44return 0;45}4647void sun8i_ss_prng_exit(struct crypto_tfm *tfm)48{49struct sun8i_ss_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm);5051kfree_sensitive(ctx->seed);52ctx->seed = NULL;53ctx->slen = 0;54}5556int sun8i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,57unsigned int slen, u8 *dst, unsigned int dlen)58{59struct sun8i_ss_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm);60struct rng_alg *alg = crypto_rng_alg(tfm);61struct sun8i_ss_alg_template *algt;62unsigned int todo_with_padding;63struct sun8i_ss_dev *ss;64dma_addr_t dma_iv, dma_dst;65unsigned int todo;66int err = 0;67int flow;68void *d;69u32 v;7071algt = container_of(alg, struct sun8i_ss_alg_template, alg.rng);72ss = algt->ss;7374if (ctx->slen == 0) {75dev_err(ss->dev, "The PRNG is not seeded\n");76return -EINVAL;77}7879/* The SS does not give an updated seed, so we need to get a new one.80* So we will ask for an extra PRNG_SEED_SIZE data.81* We want dlen + seedsize rounded up to a multiple of PRNG_DATA_SIZE82*/83todo = dlen + PRNG_SEED_SIZE + PRNG_DATA_SIZE;84todo -= todo % PRNG_DATA_SIZE;8586todo_with_padding = ALIGN(todo, dma_get_cache_alignment());87if (todo_with_padding < todo || todo < dlen)88return -EOVERFLOW;8990d = kzalloc(todo_with_padding, GFP_KERNEL);91if (!d)92return -ENOMEM;9394flow = sun8i_ss_get_engine_number(ss);9596#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG97algt->stat_req++;98algt->stat_bytes += todo;99#endif100101v = SS_ALG_PRNG | SS_PRNG_CONTINUE | SS_START;102if (flow)103v |= SS_FLOW1;104else105v |= SS_FLOW0;106107dma_iv = dma_map_single(ss->dev, ctx->seed, ctx->slen, DMA_TO_DEVICE);108if (dma_mapping_error(ss->dev, dma_iv)) {109dev_err(ss->dev, "Cannot DMA MAP IV\n");110err = -EFAULT;111goto err_free;112}113114dma_dst = dma_map_single(ss->dev, d, todo, DMA_FROM_DEVICE);115if (dma_mapping_error(ss->dev, dma_dst)) {116dev_err(ss->dev, "Cannot DMA MAP DST\n");117err = -EFAULT;118goto err_iv;119}120121err = pm_runtime_resume_and_get(ss->dev);122if (err < 0)123goto err_pm;124err = 0;125126mutex_lock(&ss->mlock);127writel(dma_iv, ss->base + SS_IV_ADR_REG);128/* the PRNG act badly (failing rngtest) without SS_KEY_ADR_REG set */129writel(dma_iv, ss->base + SS_KEY_ADR_REG);130writel(dma_dst, ss->base + SS_DST_ADR_REG);131writel(todo / 4, ss->base + SS_LEN_ADR_REG);132133reinit_completion(&ss->flows[flow].complete);134ss->flows[flow].status = 0;135/* Be sure all data is written before enabling the task */136wmb();137138writel(v, ss->base + SS_CTL_REG);139140wait_for_completion_interruptible_timeout(&ss->flows[flow].complete,141msecs_to_jiffies(todo));142if (ss->flows[flow].status == 0) {143dev_err(ss->dev, "DMA timeout for PRNG (size=%u)\n", todo);144err = -EFAULT;145}146/* Since cipher and hash use the linux/cryptoengine and that we have147* a cryptoengine per flow, we are sure that they will issue only one148* request per flow.149* Since the cryptoengine wait for completion before submitting a new150* one, the mlock could be left just after the final writel.151* But cryptoengine cannot handle crypto_rng, so we need to be sure152* nothing will use our flow.153* The easiest way is to grab mlock until the hardware end our requests.154* We could have used a per flow lock, but this would increase155* complexity.156* The drawback is that no request could be handled for the other flow.157*/158mutex_unlock(&ss->mlock);159160pm_runtime_put(ss->dev);161162err_pm:163dma_unmap_single(ss->dev, dma_dst, todo, DMA_FROM_DEVICE);164err_iv:165dma_unmap_single(ss->dev, dma_iv, ctx->slen, DMA_TO_DEVICE);166167if (!err) {168memcpy(dst, d, dlen);169/* Update seed */170memcpy(ctx->seed, d + dlen, ctx->slen);171}172err_free:173kfree_sensitive(d);174175return err;176}177178179