cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

caamrng.c (5707B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * caam - Freescale FSL CAAM support for hw_random
      4 *
      5 * Copyright 2011 Freescale Semiconductor, Inc.
      6 * Copyright 2018-2019 NXP
      7 *
      8 * Based on caamalg.c crypto API driver.
      9 *
     10 */
     11
     12#include <linux/hw_random.h>
     13#include <linux/completion.h>
     14#include <linux/atomic.h>
     15#include <linux/kfifo.h>
     16
     17#include "compat.h"
     18
     19#include "regs.h"
     20#include "intern.h"
     21#include "desc_constr.h"
     22#include "jr.h"
     23#include "error.h"
     24
     25#define CAAM_RNG_MAX_FIFO_STORE_SIZE	16
     26
     27/*
     28 * Length of used descriptors, see caam_init_desc()
     29 */
     30#define CAAM_RNG_DESC_LEN (CAAM_CMD_SZ +				\
     31			   CAAM_CMD_SZ +				\
     32			   CAAM_CMD_SZ + CAAM_PTR_SZ_MAX)
     33
     34/* rng per-device context */
     35struct caam_rng_ctx {
     36	struct hwrng rng;
     37	struct device *jrdev;
     38	struct device *ctrldev;
     39	void *desc_async;
     40	void *desc_sync;
     41	struct work_struct worker;
     42	struct kfifo fifo;
     43};
     44
     45struct caam_rng_job_ctx {
     46	struct completion *done;
     47	int *err;
     48};
     49
     50static struct caam_rng_ctx *to_caam_rng_ctx(struct hwrng *r)
     51{
     52	return (struct caam_rng_ctx *)r->priv;
     53}
     54
     55static void caam_rng_done(struct device *jrdev, u32 *desc, u32 err,
     56			  void *context)
     57{
     58	struct caam_rng_job_ctx *jctx = context;
     59
     60	if (err)
     61		*jctx->err = caam_jr_strstatus(jrdev, err);
     62
     63	complete(jctx->done);
     64}
     65
     66static u32 *caam_init_desc(u32 *desc, dma_addr_t dst_dma)
     67{
     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 |
     71			 OP_ALG_PR_ON);
     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);
     75
     76	print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_ADDRESS,
     77			     16, 4, desc, desc_bytes(desc), 1);
     78
     79	return desc;
     80}
     81
     82static int caam_rng_read_one(struct device *jrdev,
     83			     void *dst, int len,
     84			     void *desc,
     85			     struct completion *done)
     86{
     87	dma_addr_t dst_dma;
     88	int err, ret = 0;
     89	struct caam_rng_job_ctx jctx = {
     90		.done = done,
     91		.err  = &ret,
     92	};
     93
     94	len = CAAM_RNG_MAX_FIFO_STORE_SIZE;
     95
     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");
     99		return -ENOMEM;
    100	}
    101
    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);
    108		err = 0;
    109	}
    110
    111	dma_unmap_single(jrdev, dst_dma, len, DMA_FROM_DEVICE);
    112
    113	return err ?: (ret ?: len);
    114}
    115
    116static void caam_rng_fill_async(struct caam_rng_ctx *ctx)
    117{
    118	struct scatterlist sg[1];
    119	struct completion done;
    120	int len, nents;
    121
    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);
    125	if (!nents)
    126		return;
    127
    128	len = caam_rng_read_one(ctx->jrdev, sg_virt(&sg[0]),
    129				sg[0].length,
    130				ctx->desc_async,
    131				&done);
    132	if (len < 0)
    133		return;
    134
    135	kfifo_dma_in_finish(&ctx->fifo, len);
    136}
    137
    138static void caam_rng_worker(struct work_struct *work)
    139{
    140	struct caam_rng_ctx *ctx = container_of(work, struct caam_rng_ctx,
    141						worker);
    142	caam_rng_fill_async(ctx);
    143}
    144
    145static int caam_read(struct hwrng *rng, void *dst, size_t max, bool wait)
    146{
    147	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);
    148	int out;
    149
    150	if (wait) {
    151		struct completion done;
    152
    153		return caam_rng_read_one(ctx->jrdev, dst, max,
    154					 ctx->desc_sync, &done);
    155	}
    156
    157	out = kfifo_out(&ctx->fifo, dst, max);
    158	if (kfifo_is_empty(&ctx->fifo))
    159		schedule_work(&ctx->worker);
    160
    161	return out;
    162}
    163
    164static void caam_cleanup(struct hwrng *rng)
    165{
    166	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);
    167
    168	flush_work(&ctx->worker);
    169	caam_jr_free(ctx->jrdev);
    170	kfifo_free(&ctx->fifo);
    171}
    172
    173static int caam_init(struct hwrng *rng)
    174{
    175	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);
    176	int err;
    177
    178	ctx->desc_sync = devm_kzalloc(ctx->ctrldev, CAAM_RNG_DESC_LEN,
    179				      GFP_DMA | GFP_KERNEL);
    180	if (!ctx->desc_sync)
    181		return -ENOMEM;
    182
    183	ctx->desc_async = devm_kzalloc(ctx->ctrldev, CAAM_RNG_DESC_LEN,
    184				       GFP_DMA | GFP_KERNEL);
    185	if (!ctx->desc_async)
    186		return -ENOMEM;
    187
    188	if (kfifo_alloc(&ctx->fifo, CAAM_RNG_MAX_FIFO_STORE_SIZE,
    189			GFP_DMA | GFP_KERNEL))
    190		return -ENOMEM;
    191
    192	INIT_WORK(&ctx->worker, caam_rng_worker);
    193
    194	ctx->jrdev = caam_jr_alloc();
    195	err = PTR_ERR_OR_ZERO(ctx->jrdev);
    196	if (err) {
    197		kfifo_free(&ctx->fifo);
    198		pr_err("Job Ring Device allocation for transform failed\n");
    199		return err;
    200	}
    201
    202	/*
    203	 * Fill async buffer to have early randomness data for
    204	 * hw_random
    205	 */
    206	caam_rng_fill_async(ctx);
    207
    208	return 0;
    209}
    210
    211int caam_rng_init(struct device *ctrldev);
    212
    213void caam_rng_exit(struct device *ctrldev)
    214{
    215	devres_release_group(ctrldev, caam_rng_init);
    216}
    217
    218int caam_rng_init(struct device *ctrldev)
    219{
    220	struct caam_rng_ctx *ctx;
    221	u32 rng_inst;
    222	struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
    223	int ret;
    224
    225	/* Check for an instantiated RNG before registration */
    226	if (priv->era < 10)
    227		rng_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
    228			    CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
    229	else
    230		rng_inst = rd_reg32(&priv->ctrl->vreg.rng) & CHA_VER_NUM_MASK;
    231
    232	if (!rng_inst)
    233		return 0;
    234
    235	if (!devres_open_group(ctrldev, caam_rng_init, GFP_KERNEL))
    236		return -ENOMEM;
    237
    238	ctx = devm_kzalloc(ctrldev, sizeof(*ctx), GFP_KERNEL);
    239	if (!ctx)
    240		return -ENOMEM;
    241
    242	ctx->ctrldev = ctrldev;
    243
    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;
    250
    251	dev_info(ctrldev, "registering rng-caam\n");
    252
    253	ret = devm_hwrng_register(ctrldev, &ctx->rng);
    254	if (ret) {
    255		caam_rng_exit(ctrldev);
    256		return ret;
    257	}
    258
    259	devres_close_group(ctrldev, caam_rng_init);
    260	return 0;
    261}