brintos

brintos / linux-shallow public Read only

0
0
Text · 6.6 KiB · b3d14a7 Raw
312 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * caam - Freescale FSL CAAM support for hw_random4 *5 * Copyright 2011 Freescale Semiconductor, Inc.6 * Copyright 2018-2019, 2023 NXP7 *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/dma-mapping.h>16#include <linux/kernel.h>17#include <linux/kfifo.h>18 19#include "compat.h"20 21#include "regs.h"22#include "intern.h"23#include "desc_constr.h"24#include "jr.h"25#include "error.h"26 27#define CAAM_RNG_MAX_FIFO_STORE_SIZE	1628 29/*30 * Length of used descriptors, see caam_init_desc()31 */32#define CAAM_RNG_DESC_LEN (CAAM_CMD_SZ +				\33			   CAAM_CMD_SZ +				\34			   CAAM_CMD_SZ + CAAM_PTR_SZ_MAX)35 36/* rng per-device context */37struct caam_rng_ctx {38	struct hwrng rng;39	struct device *jrdev;40	struct device *ctrldev;41	void *desc_async;42	void *desc_sync;43	struct work_struct worker;44	struct kfifo fifo;45};46 47struct caam_rng_job_ctx {48	struct completion *done;49	int *err;50};51 52static struct caam_rng_ctx *to_caam_rng_ctx(struct hwrng *r)53{54	return (struct caam_rng_ctx *)r->priv;55}56 57static void caam_rng_done(struct device *jrdev, u32 *desc, u32 err,58			  void *context)59{60	struct caam_rng_job_ctx *jctx = context;61 62	if (err)63		*jctx->err = caam_jr_strstatus(jrdev, err);64 65	complete(jctx->done);66}67 68static u32 *caam_init_desc(u32 *desc, dma_addr_t dst_dma)69{70	init_job_desc(desc, 0);	/* + 1 cmd_sz */71	/* Generate random bytes: + 1 cmd_sz */72	append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG |73			 OP_ALG_PR_ON);74	/* Store bytes: + 1 cmd_sz + caam_ptr_sz  */75	append_fifo_store(desc, dst_dma,76			  CAAM_RNG_MAX_FIFO_STORE_SIZE, FIFOST_TYPE_RNGSTORE);77 78	print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_ADDRESS,79			     16, 4, desc, desc_bytes(desc), 1);80 81	return desc;82}83 84static int caam_rng_read_one(struct device *jrdev,85			     void *dst, int len,86			     void *desc,87			     struct completion *done)88{89	dma_addr_t dst_dma;90	int err, ret = 0;91	struct caam_rng_job_ctx jctx = {92		.done = done,93		.err  = &ret,94	};95 96	len = CAAM_RNG_MAX_FIFO_STORE_SIZE;97 98	dst_dma = dma_map_single(jrdev, dst, len, DMA_FROM_DEVICE);99	if (dma_mapping_error(jrdev, dst_dma)) {100		dev_err(jrdev, "unable to map destination memory\n");101		return -ENOMEM;102	}103 104	init_completion(done);105	err = caam_jr_enqueue(jrdev,106			      caam_init_desc(desc, dst_dma),107			      caam_rng_done, &jctx);108	if (err == -EINPROGRESS) {109		wait_for_completion(done);110		err = 0;111	}112 113	dma_unmap_single(jrdev, dst_dma, len, DMA_FROM_DEVICE);114 115	return err ?: (ret ?: len);116}117 118static void caam_rng_fill_async(struct caam_rng_ctx *ctx)119{120	struct scatterlist sg[1];121	struct completion done;122	int len, nents;123 124	sg_init_table(sg, ARRAY_SIZE(sg));125	nents = kfifo_dma_in_prepare(&ctx->fifo, sg, ARRAY_SIZE(sg),126				     CAAM_RNG_MAX_FIFO_STORE_SIZE);127	if (!nents)128		return;129 130	len = caam_rng_read_one(ctx->jrdev, sg_virt(&sg[0]),131				sg[0].length,132				ctx->desc_async,133				&done);134	if (len < 0)135		return;136 137	kfifo_dma_in_finish(&ctx->fifo, len);138}139 140static void caam_rng_worker(struct work_struct *work)141{142	struct caam_rng_ctx *ctx = container_of(work, struct caam_rng_ctx,143						worker);144	caam_rng_fill_async(ctx);145}146 147static int caam_read(struct hwrng *rng, void *dst, size_t max, bool wait)148{149	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);150	int out;151 152	if (wait) {153		struct completion done;154 155		return caam_rng_read_one(ctx->jrdev, dst, max,156					 ctx->desc_sync, &done);157	}158 159	out = kfifo_out(&ctx->fifo, dst, max);160	if (kfifo_is_empty(&ctx->fifo))161		schedule_work(&ctx->worker);162 163	return out;164}165 166static void caam_cleanup(struct hwrng *rng)167{168	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);169 170	flush_work(&ctx->worker);171	caam_jr_free(ctx->jrdev);172	kfifo_free(&ctx->fifo);173}174 175#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST176static inline void test_len(struct hwrng *rng, size_t len, bool wait)177{178	u8 *buf;179	int read_len;180	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);181	struct device *dev = ctx->ctrldev;182 183	buf = kcalloc(CAAM_RNG_MAX_FIFO_STORE_SIZE, sizeof(u8), GFP_KERNEL);184 185	while (len > 0) {186		read_len = rng->read(rng, buf, len, wait);187 188		if (read_len < 0 || (read_len == 0 && wait)) {189			dev_err(dev, "RNG Read FAILED received %d bytes\n",190				read_len);191			kfree(buf);192			return;193		}194 195		print_hex_dump_debug("random bytes@: ",196			DUMP_PREFIX_ADDRESS, 16, 4,197			buf, read_len, 1);198 199		len = len - read_len;200	}201 202	kfree(buf);203}204 205static inline void test_mode_once(struct hwrng *rng, bool wait)206{207	test_len(rng, 32, wait);208	test_len(rng, 64, wait);209	test_len(rng, 128, wait);210}211 212static void self_test(struct hwrng *rng)213{214	pr_info("Executing RNG SELF-TEST with wait\n");215	test_mode_once(rng, true);216}217#endif218 219static int caam_init(struct hwrng *rng)220{221	struct caam_rng_ctx *ctx = to_caam_rng_ctx(rng);222	int err;223 224	ctx->desc_sync = devm_kzalloc(ctx->ctrldev, CAAM_RNG_DESC_LEN,225				      GFP_KERNEL);226	if (!ctx->desc_sync)227		return -ENOMEM;228 229	ctx->desc_async = devm_kzalloc(ctx->ctrldev, CAAM_RNG_DESC_LEN,230				       GFP_KERNEL);231	if (!ctx->desc_async)232		return -ENOMEM;233 234	if (kfifo_alloc(&ctx->fifo, ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE,235					  dma_get_cache_alignment()),236			GFP_KERNEL))237		return -ENOMEM;238 239	INIT_WORK(&ctx->worker, caam_rng_worker);240 241	ctx->jrdev = caam_jr_alloc();242	err = PTR_ERR_OR_ZERO(ctx->jrdev);243	if (err) {244		kfifo_free(&ctx->fifo);245		pr_err("Job Ring Device allocation for transform failed\n");246		return err;247	}248 249	/*250	 * Fill async buffer to have early randomness data for251	 * hw_random252	 */253	caam_rng_fill_async(ctx);254 255	return 0;256}257 258int caam_rng_init(struct device *ctrldev);259 260void caam_rng_exit(struct device *ctrldev)261{262	devres_release_group(ctrldev, caam_rng_init);263}264 265int caam_rng_init(struct device *ctrldev)266{267	struct caam_rng_ctx *ctx;268	u32 rng_inst;269	struct caam_drv_private *priv = dev_get_drvdata(ctrldev);270	int ret;271 272	/* Check for an instantiated RNG before registration */273	if (priv->era < 10)274		rng_inst = (rd_reg32(&priv->jr[0]->perfmon.cha_num_ls) &275			    CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;276	else277		rng_inst = rd_reg32(&priv->jr[0]->vreg.rng) & CHA_VER_NUM_MASK;278 279	if (!rng_inst)280		return 0;281 282	if (!devres_open_group(ctrldev, caam_rng_init, GFP_KERNEL))283		return -ENOMEM;284 285	ctx = devm_kzalloc(ctrldev, sizeof(*ctx), GFP_KERNEL);286	if (!ctx)287		return -ENOMEM;288 289	ctx->ctrldev = ctrldev;290 291	ctx->rng.name    = "rng-caam";292	ctx->rng.init    = caam_init;293	ctx->rng.cleanup = caam_cleanup;294	ctx->rng.read    = caam_read;295	ctx->rng.priv    = (unsigned long)ctx;296 297	dev_info(ctrldev, "registering rng-caam\n");298 299	ret = devm_hwrng_register(ctrldev, &ctx->rng);300	if (ret) {301		caam_rng_exit(ctrldev);302		return ret;303	}304 305#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST306	self_test(&ctx->rng);307#endif308 309	devres_close_group(ctrldev, caam_rng_init);310	return 0;311}312