Linux cryptographic layer development
 help / color / mirror / Atom feed
* [PATCH] crypto: atmel-tdes - use scatterlist length before DMA mapping
From: Thorsten Blum @ 2026-05-31 20:41 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, Nicolas Ferre, Alexandre Belloni,
	Claudiu Beznea, Nicolas Royer, Eric Bénard
  Cc: Thorsten Blum, stable, linux-crypto, linux-arm-kernel,
	linux-kernel

Using sg_dma_len() is only valid after mapping the scatterlist with
dma_map_sg(). However, atmel_tdes_crypt_start() uses it before mapping
to compare input/output lengths and to compute the transfer count.

Use the original scatterlist lengths before DMA mapping to avoid reading
stale or uninitialized DMA lengths when CONFIG_NEED_SG_DMA_LENGTH=y.

Fixes: 13802005d8f2 ("crypto: atmel - add Atmel DES/TDES driver")
Fixes: 1f858040c2f7 ("crypto: atmel-tdes - add support for latest release of the IP (0x700)")
Cc: stable@vger.kernel.org
Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
 drivers/crypto/atmel-tdes.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index 643e507f9c02..0d62b24e9fc7 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -463,14 +463,14 @@ static int atmel_tdes_crypt_start(struct atmel_tdes_dev *dd)
 			IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size);
 		fast = in && out;
 
-		if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg))
+		if (dd->in_sg->length != dd->out_sg->length)
 			fast = 0;
 	}
 
 
 	if (fast)  {
-		count = min_t(size_t, dd->total, sg_dma_len(dd->in_sg));
-		count = min_t(size_t, count, sg_dma_len(dd->out_sg));
+		count = min_t(size_t, dd->total, dd->in_sg->length);
+		count = min_t(size_t, count, dd->out_sg->length);
 
 		err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
 		if (!err) {

^ permalink raw reply related

* [PATCH 4/4] hwrng: xilinx - Move xilinx-rng into drivers/char/hw_random/
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
	Michal Simek, linux-arm-kernel, Eric Biggers
In-Reply-To: <20260531191738.55843-1-ebiggers@kernel.org>

Since this file just implements a hwrng driver, move it into
drivers/char/hw_random/.  Rename the kconfig option accordingly as well.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 MAINTAINERS                                          |  2 +-
 arch/arm64/configs/defconfig                         |  2 +-
 drivers/char/hw_random/Kconfig                       | 11 +++++++++++
 drivers/char/hw_random/Makefile                      |  1 +
 .../{crypto/xilinx => char/hw_random}/xilinx-trng.c  |  0
 drivers/crypto/Kconfig                               | 12 ------------
 drivers/crypto/xilinx/Makefile                       |  1 -
 7 files changed, 14 insertions(+), 15 deletions(-)
 rename drivers/{crypto/xilinx => char/hw_random}/xilinx-trng.c (100%)

diff --git a/MAINTAINERS b/MAINTAINERS
index 882214b0e7db..a593e78c30fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29218,11 +29218,11 @@ F:	include/uapi/misc/xilinx_sdfec.h
 
 XILINX TRNG DRIVER
 M:	Mounika Botcha <mounika.botcha@amd.com>
 M:	Harsh Jain <h.jain@amd.com>
 S:	Maintained
-F:	drivers/crypto/xilinx/xilinx-trng.c
+F:	drivers/char/hw_random/xilinx-trng.c
 
 XILINX UARTLITE SERIAL DRIVER
 M:	Peter Korsgaard <jacmet@sunsite.dk>
 L:	linux-serial@vger.kernel.org
 S:	Maintained
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index bb930cce7233..d8fb11e4c36d 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -549,10 +549,11 @@ CONFIG_IPMI_HANDLER=m
 CONFIG_IPMI_DEVICE_INTERFACE=m
 CONFIG_IPMI_SI=m
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_HW_RANDOM_QCOM=m
+CONFIG_HW_RANDOM_XILINX=m
 CONFIG_TCG_TPM=y
 CONFIG_TCG_TIS=m
 CONFIG_TCG_TIS_SPI=m
 CONFIG_TCG_TIS_SPI_CR50=y
 CONFIG_TCG_TIS_I2C_CR50=m
@@ -1953,11 +1954,10 @@ CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
 CONFIG_CRYPTO_DEV_SUN8I_CE=m
 CONFIG_CRYPTO_DEV_FSL_CAAM=m
 CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM=m
 CONFIG_CRYPTO_DEV_QCE=m
 CONFIG_CRYPTO_DEV_TEGRA=m
-CONFIG_CRYPTO_DEV_XILINX_TRNG=m
 CONFIG_CRYPTO_DEV_ZYNQMP_AES=m
 CONFIG_CRYPTO_DEV_ZYNQMP_SHA3=m
 CONFIG_CRYPTO_DEV_CCREE=m
 CONFIG_CRYPTO_DEV_HISI_SEC2=m
 CONFIG_CRYPTO_DEV_HISI_ZIP=m
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 7102e03dcf0a..e0a53ba558a0 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -624,10 +624,21 @@ config HW_RANDOM_QCOM
 	  Generator hardware found on some Qualcomm SoCs.
 
 	  To compile this driver as a module, choose M here. The
 	  module will be called qcom-rng. If unsure, say N.
 
+config HW_RANDOM_XILINX
+	tristate "Support for Xilinx True Random Generator"
+	depends on ZYNQMP_FIRMWARE || COMPILE_TEST
+	select CRYPTO_LIB_SHA512
+	help
+	  Xilinx Versal SoC driver provides kernel-side support for True Random Number
+	  Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called xilinx-trng.
+
 endif # HW_RANDOM
 
 config UML_RANDOM
 	depends on UML
 	select HW_RANDOM
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 605ba8df5a8f..470004ad841a 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -51,5 +51,6 @@ obj-$(CONFIG_HW_RANDOM_ARM_SMCCC_TRNG) += arm_smccc_trng.o
 obj-$(CONFIG_HW_RANDOM_CN10K) += cn10k-rng.o
 obj-$(CONFIG_HW_RANDOM_POLARFIRE_SOC) += mpfs-rng.o
 obj-$(CONFIG_HW_RANDOM_ROCKCHIP) += rockchip-rng.o
 obj-$(CONFIG_HW_RANDOM_JH7110) += jh7110-trng.o
 obj-$(CONFIG_HW_RANDOM_QCOM) += qcom-rng.o
+obj-$(CONFIG_HW_RANDOM_XILINX) += xilinx-trng.o
diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/char/hw_random/xilinx-trng.c
similarity index 100%
rename from drivers/crypto/xilinx/xilinx-trng.c
rename to drivers/char/hw_random/xilinx-trng.c
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index ad6427f08d4f..451d61b33143 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -704,22 +704,10 @@ config CRYPTO_DEV_TEGRA
 
 	help
 	  Select this to enable Tegra Security Engine which accelerates various
 	  AES encryption/decryption and HASH algorithms.
 
-config CRYPTO_DEV_XILINX_TRNG
-	tristate "Support for Xilinx True Random Generator"
-	depends on ZYNQMP_FIRMWARE || COMPILE_TEST
-	select CRYPTO_LIB_SHA512
-	select HW_RANDOM
-	help
-	  Xilinx Versal SoC driver provides kernel-side support for True Random Number
-	  Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called xilinx-trng.
-
 config CRYPTO_DEV_ZYNQMP_AES
 	tristate "Support for Xilinx ZynqMP AES hw accelerator"
 	depends on ZYNQMP_FIRMWARE || COMPILE_TEST
 	select CRYPTO_AES
 	select CRYPTO_ENGINE
diff --git a/drivers/crypto/xilinx/Makefile b/drivers/crypto/xilinx/Makefile
index 9b51636ef75e..730feff5b5f2 100644
--- a/drivers/crypto/xilinx/Makefile
+++ b/drivers/crypto/xilinx/Makefile
@@ -1,4 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_CRYPTO_DEV_XILINX_TRNG) += xilinx-trng.o
 obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_AES) += zynqmp-aes-gcm.o
 obj-$(CONFIG_CRYPTO_DEV_ZYNQMP_SHA3) += zynqmp-sha.o
-- 
2.54.0


^ permalink raw reply related

* [PATCH 3/4] crypto: xilinx-trng - Replace crypto_drbg_ctr_df() with HMAC-SHA512
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
	Michal Simek, linux-arm-kernel, Eric Biggers
In-Reply-To: <20260531191738.55843-1-ebiggers@kernel.org>

This code is just trying to condition 48 bytes of random data.  This can
be done easily using HKDF-SHA512-Extract, saving 300 lines of code.

This commit also fixes forward security (in this particular case) by
clearing the entropy from memory after it's used.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 crypto/Kconfig                      |   5 -
 crypto/Makefile                     |   2 -
 crypto/df_sp80090a.c                | 222 ----------------------------
 drivers/crypto/Kconfig              |   2 +-
 drivers/crypto/xilinx/xilinx-trng.c |  44 ++----
 include/crypto/df_sp80090a.h        |  53 -------
 6 files changed, 16 insertions(+), 312 deletions(-)
 delete mode 100644 crypto/df_sp80090a.c
 delete mode 100644 include/crypto/df_sp80090a.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index b5c5a1e04435..c3d7a20d5cb1 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1244,15 +1244,10 @@ endif	# if CRYPTO_JITTERENTROPY
 config CRYPTO_KDF800108_CTR
 	tristate
 	select CRYPTO_HMAC
 	select CRYPTO_SHA256
 
-config CRYPTO_DF80090A
-	tristate
-	select CRYPTO_AES
-	select CRYPTO_CTR
-
 endmenu
 menu "Userspace interface (deprecated)"
 
 config CRYPTO_USER_API
 	tristate
diff --git a/crypto/Makefile b/crypto/Makefile
index c73f4d51d036..f98f57c7a49f 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -206,8 +206,6 @@ obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
 #
 # Key derivation function
 #
 obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o
 
-obj-$(CONFIG_CRYPTO_DF80090A) += df_sp80090a.o
-
 obj-$(CONFIG_CRYPTO_KRB5) += krb5/
diff --git a/crypto/df_sp80090a.c b/crypto/df_sp80090a.c
deleted file mode 100644
index 90e1973ee40c..000000000000
--- a/crypto/df_sp80090a.c
+++ /dev/null
@@ -1,222 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-/*
- * NIST SP800-90A DRBG derivation function
- *
- * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/unaligned.h>
-#include <crypto/aes.h>
-#include <crypto/df_sp80090a.h>
-
-static void drbg_kcapi_sym(struct aes_enckey *aeskey, unsigned char *outval,
-			   const struct drbg_string *in, u8 blocklen_bytes)
-{
-	/* there is only component in *in */
-	BUG_ON(in->len < blocklen_bytes);
-	aes_encrypt(aeskey, outval, in->buf);
-}
-
-/* BCC function for CTR DRBG as defined in 10.4.3 */
-
-static void drbg_ctr_bcc(struct aes_enckey *aeskey,
-			 unsigned char *out, const unsigned char *key,
-			 struct list_head *in,
-			 u8 blocklen_bytes,
-			 u8 keylen)
-{
-	struct drbg_string *curr = NULL;
-	struct drbg_string data;
-	short cnt = 0;
-
-	drbg_string_fill(&data, out, blocklen_bytes);
-
-	/* 10.4.3 step 2 / 4 */
-	aes_prepareenckey(aeskey, key, keylen);
-	list_for_each_entry(curr, in, list) {
-		const unsigned char *pos = curr->buf;
-		size_t len = curr->len;
-		/* 10.4.3 step 4.1 */
-		while (len) {
-			/* 10.4.3 step 4.2 */
-			if (blocklen_bytes == cnt) {
-				cnt = 0;
-				drbg_kcapi_sym(aeskey, out, &data, blocklen_bytes);
-			}
-			out[cnt] ^= *pos;
-			pos++;
-			cnt++;
-			len--;
-		}
-	}
-	/* 10.4.3 step 4.2 for last block */
-	if (cnt)
-		drbg_kcapi_sym(aeskey, out, &data, blocklen_bytes);
-}
-
-/*
- * scratchpad usage: drbg_ctr_update is interlinked with crypto_drbg_ctr_df
- * (and drbg_ctr_bcc, but this function does not need any temporary buffers),
- * the scratchpad is used as follows:
- * drbg_ctr_update:
- *	temp
- *		start: drbg->scratchpad
- *		length: drbg_statelen(drbg) + drbg_blocklen(drbg)
- *			note: the cipher writing into this variable works
- *			blocklen-wise. Now, when the statelen is not a multiple
- *			of blocklen, the generateion loop below "spills over"
- *			by at most blocklen. Thus, we need to give sufficient
- *			memory.
- *	df_data
- *		start: drbg->scratchpad +
- *				drbg_statelen(drbg) + drbg_blocklen(drbg)
- *		length: drbg_statelen(drbg)
- *
- * crypto_drbg_ctr_df:
- *	pad
- *		start: df_data + drbg_statelen(drbg)
- *		length: drbg_blocklen(drbg)
- *	iv
- *		start: pad + drbg_blocklen(drbg)
- *		length: drbg_blocklen(drbg)
- *	temp
- *		start: iv + drbg_blocklen(drbg)
- *		length: drbg_satelen(drbg) + drbg_blocklen(drbg)
- *			note: temp is the buffer that the BCC function operates
- *			on. BCC operates blockwise. drbg_statelen(drbg)
- *			is sufficient when the DRBG state length is a multiple
- *			of the block size. For AES192 (and maybe other ciphers)
- *			this is not correct and the length for temp is
- *			insufficient (yes, that also means for such ciphers,
- *			the final output of all BCC rounds are truncated).
- *			Therefore, add drbg_blocklen(drbg) to cover all
- *			possibilities.
- * refer to crypto_drbg_ctr_df_datalen() to get required length
- */
-
-/* Derivation Function for CTR DRBG as defined in 10.4.2 */
-int crypto_drbg_ctr_df(struct aes_enckey *aeskey,
-		       unsigned char *df_data, size_t bytes_to_return,
-		       struct list_head *seedlist,
-		       u8 blocklen_bytes,
-		       u8 statelen)
-{
-	unsigned char L_N[8];
-	/* S3 is input */
-	struct drbg_string S1, S2, S4, cipherin;
-	LIST_HEAD(bcc_list);
-	unsigned char *pad = df_data + statelen;
-	unsigned char *iv = pad + blocklen_bytes;
-	unsigned char *temp = iv + blocklen_bytes;
-	size_t padlen = 0;
-	unsigned int templen = 0;
-	/* 10.4.2 step 7 */
-	unsigned int i = 0;
-	/* 10.4.2 step 8 */
-	const unsigned char *K = (unsigned char *)
-			   "\x00\x01\x02\x03\x04\x05\x06\x07"
-			   "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-			   "\x10\x11\x12\x13\x14\x15\x16\x17"
-			   "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
-	unsigned char *X;
-	size_t generated_len = 0;
-	size_t inputlen = 0;
-	struct drbg_string *seed = NULL;
-	u8 keylen;
-
-	memset(pad, 0, blocklen_bytes);
-	memset(iv, 0, blocklen_bytes);
-	keylen = statelen - blocklen_bytes;
-	/* 10.4.2 step 1 is implicit as we work byte-wise */
-
-	/* 10.4.2 step 2 */
-	if ((512 / 8) < bytes_to_return)
-		return -EINVAL;
-
-	/* 10.4.2 step 2 -- calculate the entire length of all input data */
-	list_for_each_entry(seed, seedlist, list)
-		inputlen += seed->len;
-	put_unaligned_be32(inputlen, &L_N[0]);
-
-	/* 10.4.2 step 3 */
-	put_unaligned_be32(bytes_to_return, &L_N[4]);
-
-	/* 10.4.2 step 5: length is L_N, input_string, one byte, padding */
-	padlen = (inputlen + sizeof(L_N) + 1) % (blocklen_bytes);
-	/* wrap the padlen appropriately */
-	if (padlen)
-		padlen = blocklen_bytes - padlen;
-	/*
-	 * pad / padlen contains the 0x80 byte and the following zero bytes.
-	 * As the calculated padlen value only covers the number of zero
-	 * bytes, this value has to be incremented by one for the 0x80 byte.
-	 */
-	padlen++;
-	pad[0] = 0x80;
-
-	/* 10.4.2 step 4 -- first fill the linked list and then order it */
-	drbg_string_fill(&S1, iv, blocklen_bytes);
-	list_add_tail(&S1.list, &bcc_list);
-	drbg_string_fill(&S2, L_N, sizeof(L_N));
-	list_add_tail(&S2.list, &bcc_list);
-	list_splice_tail(seedlist, &bcc_list);
-	drbg_string_fill(&S4, pad, padlen);
-	list_add_tail(&S4.list, &bcc_list);
-
-	/* 10.4.2 step 9 */
-	while (templen < (keylen + (blocklen_bytes))) {
-		/*
-		 * 10.4.2 step 9.1 - the padding is implicit as the buffer
-		 * holds zeros after allocation -- even the increment of i
-		 * is irrelevant as the increment remains within length of i
-		 */
-		put_unaligned_be32(i, iv);
-		/* 10.4.2 step 9.2 -- BCC and concatenation with temp */
-		drbg_ctr_bcc(aeskey, temp + templen, K, &bcc_list,
-			     blocklen_bytes, keylen);
-		/* 10.4.2 step 9.3 */
-		i++;
-		templen += blocklen_bytes;
-	}
-
-	/* 10.4.2 step 11 */
-	X = temp + (keylen);
-	drbg_string_fill(&cipherin, X, blocklen_bytes);
-
-	/* 10.4.2 step 12: overwriting of outval is implemented in next step */
-
-	/* 10.4.2 step 13 */
-	aes_prepareenckey(aeskey, temp, keylen);
-	while (generated_len < bytes_to_return) {
-		short blocklen = 0;
-		/*
-		 * 10.4.2 step 13.1: the truncation of the key length is
-		 * implicit as the key is only drbg_blocklen in size based on
-		 * the implementation of the cipher function callback
-		 */
-		drbg_kcapi_sym(aeskey, X, &cipherin, blocklen_bytes);
-		blocklen = (blocklen_bytes <
-				(bytes_to_return - generated_len)) ?
-			    blocklen_bytes :
-				(bytes_to_return - generated_len);
-		/* 10.4.2 step 13.2 and 14 */
-		memcpy(df_data + generated_len, X, blocklen);
-		generated_len += blocklen;
-	}
-
-	memset(iv, 0, blocklen_bytes);
-	memset(temp, 0, statelen + blocklen_bytes);
-	memset(pad, 0, blocklen_bytes);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(crypto_drbg_ctr_df);
-
-MODULE_IMPORT_NS("CRYPTO_INTERNAL");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
-MODULE_DESCRIPTION("Derivation Function conformant to SP800-90A");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 26194c33cb32..ad6427f08d4f 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -707,11 +707,11 @@ config CRYPTO_DEV_TEGRA
 	  AES encryption/decryption and HASH algorithms.
 
 config CRYPTO_DEV_XILINX_TRNG
 	tristate "Support for Xilinx True Random Generator"
 	depends on ZYNQMP_FIRMWARE || COMPILE_TEST
-	select CRYPTO_DF80090A
+	select CRYPTO_LIB_SHA512
 	select HW_RANDOM
 	help
 	  Xilinx Versal SoC driver provides kernel-side support for True Random Number
 	  Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A.
 
diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/crypto/xilinx/xilinx-trng.c
index a30b0b3b3685..f615d5adddde 100644
--- a/drivers/crypto/xilinx/xilinx-trng.c
+++ b/drivers/crypto/xilinx/xilinx-trng.c
@@ -2,10 +2,11 @@
 /*
  * AMD Versal True Random Number Generator driver
  * Copyright (c) 2024 - 2025 Advanced Micro Devices, Inc.
  */
 
+#include <crypto/sha2.h>
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/firmware/xlnx-zynqmp.h>
 #include <linux/hw_random.h>
@@ -13,13 +14,10 @@
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
-#include <crypto/aes.h>
-#include <crypto/df_sp80090a.h>
-#include <crypto/internal/cipher.h>
 
 /* TRNG Registers Offsets */
 #define TRNG_STATUS_OFFSET			0x4U
 #define TRNG_CTRL_OFFSET			0x8U
 #define TRNG_EXT_SEED_OFFSET			0x40U
@@ -41,11 +39,10 @@
 #define TRNG_STATUS_QCNT_MASK			GENMASK(11, 9)
 #define TRNG_STATUS_QCNT_16_BYTES		0x800
 
 /* Sizes in bytes */
 #define TRNG_SEED_LEN_BYTES			48U
-#define TRNG_ENTROPY_SEED_LEN_BYTES		64U
 #define TRNG_SEC_STRENGTH_SHIFT			5U
 #define TRNG_SEC_STRENGTH_BYTES			BIT(TRNG_SEC_STRENGTH_SHIFT)
 #define TRNG_BYTES_PER_REG			4U
 #define TRNG_RESET_DELAY			10
 #define TRNG_NUM_INIT_REGS			12U
@@ -53,12 +50,10 @@
 #define TRNG_DATA_READ_DELAY			8000
 
 struct xilinx_rng {
 	void __iomem *rng_base;
 	struct device *dev;
-	unsigned char *scratchpadbuf;
-	struct aes_enckey *aeskey;
 	struct hwrng trng;
 };
 
 static void xtrng_readwrite32(void __iomem *addr, u32 mask, u8 value)
 {
@@ -170,33 +165,34 @@ static void xtrng_enable_entropy(struct xilinx_rng *rng)
 	iowrite32(TRNG_CTRL_EUMODE_MASK | TRNG_CTRL_TRSSEN_MASK, rng->rng_base + TRNG_CTRL_OFFSET);
 }
 
 static int xtrng_reseed_internal(struct xilinx_rng *rng)
 {
-	u8 entropy[TRNG_ENTROPY_SEED_LEN_BYTES];
-	struct drbg_string data;
-	LIST_HEAD(seedlist);
+	static const u8 default_salt[SHA512_DIGEST_SIZE];
+	u8 entropy[SHA512_DIGEST_SIZE] __aligned(4);
 	u32 val;
 	int ret;
 
-	drbg_string_fill(&data, entropy, TRNG_SEED_LEN_BYTES);
-	list_add_tail(&data.list, &seedlist);
-	memset(entropy, 0, sizeof(entropy));
 	xtrng_enable_entropy(rng);
 
-	/* collect random data to use it as entropy (input for DF) */
+	/* Collect some output from the TRNG. */
+	static_assert(sizeof(entropy) >= TRNG_SEED_LEN_BYTES);
 	ret = xtrng_collect_random_data(rng, entropy, TRNG_SEED_LEN_BYTES, true);
 	if (ret != TRNG_SEED_LEN_BYTES)
 		return -EINVAL;
-	ret = crypto_drbg_ctr_df(rng->aeskey, rng->scratchpadbuf,
-				 TRNG_SEED_LEN_BYTES, &seedlist, AES_BLOCK_SIZE,
-				 TRNG_SEED_LEN_BYTES);
-	if (ret)
-		return ret;
 
+	/* Extract entropy from the TRNG output using HKDF-SHA512-Extract. */
+	hmac_sha512_usingrawkey(default_salt, sizeof(default_salt), entropy,
+				TRNG_SEED_LEN_BYTES, entropy);
+
+	/* Write the extracted entropy to the hardware. */
 	xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET,
-				       (u32 *)rng->scratchpadbuf, TRNG_NUM_INIT_REGS);
+				       (u32 *)entropy, TRNG_NUM_INIT_REGS);
+
+	/* Clear the entropy from the stack. */
+	memzero_explicit(entropy, sizeof(entropy));
+
 	/* select reseed operation */
 	iowrite32(TRNG_CTRL_PRNGXS_MASK, rng->rng_base + TRNG_CTRL_OFFSET);
 
 	/* Start the reseed operation with above configuration and wait for STATUS.Done bit to be
 	 * set. Monitor STATUS.CERTF bit, if set indicates SP800-90B entropy health test has failed.
@@ -276,11 +272,10 @@ static void xtrng_hwrng_unregister(struct hwrng *trng)
 }
 
 static int xtrng_probe(struct platform_device *pdev)
 {
 	struct xilinx_rng *rng;
-	size_t sb_size;
 	int ret;
 
 	rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
 	if (!rng)
 		return -ENOMEM;
@@ -290,19 +285,10 @@ static int xtrng_probe(struct platform_device *pdev)
 	if (IS_ERR(rng->rng_base)) {
 		dev_err(&pdev->dev, "Failed to map resource %pe\n", rng->rng_base);
 		return PTR_ERR(rng->rng_base);
 	}
 
-	rng->aeskey = devm_kzalloc(&pdev->dev, sizeof(*rng->aeskey), GFP_KERNEL);
-	if (!rng->aeskey)
-		return -ENOMEM;
-
-	sb_size = crypto_drbg_ctr_df_datalen(TRNG_SEED_LEN_BYTES, AES_BLOCK_SIZE);
-	rng->scratchpadbuf = devm_kzalloc(&pdev->dev, sb_size, GFP_KERNEL);
-	if (!rng->scratchpadbuf)
-		return -ENOMEM;
-
 	xtrng_trng_reset(rng->rng_base);
 	ret = xtrng_reseed_internal(rng);
 	if (ret) {
 		dev_err(&pdev->dev, "TRNG Seed fail\n");
 		return ret;
diff --git a/include/crypto/df_sp80090a.h b/include/crypto/df_sp80090a.h
deleted file mode 100644
index e594fb718eb8..000000000000
--- a/include/crypto/df_sp80090a.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-/*
- * Copyright Stephan Mueller <smueller@chronox.de>, 2014
- */
-
-#ifndef _CRYPTO_DF80090A_H
-#define _CRYPTO_DF80090A_H
-
-#include <crypto/internal/cipher.h>
-#include <crypto/aes.h>
-#include <linux/list.h>
-
-/*
- * Concatenation Helper and string operation helper
- *
- * SP800-90A requires the concatenation of different data. To avoid copying
- * buffers around or allocate additional memory, the following data structure
- * is used to point to the original memory with its size. In addition, it
- * is used to build a linked list. The linked list defines the concatenation
- * of individual buffers. The order of memory block referenced in that
- * linked list determines the order of concatenation.
- */
-struct drbg_string {
-	const unsigned char *buf;
-	size_t len;
-	struct list_head list;
-};
-
-static inline void drbg_string_fill(struct drbg_string *string,
-				    const unsigned char *buf, size_t len)
-{
-	string->buf = buf;
-	string->len = len;
-	INIT_LIST_HEAD(&string->list);
-}
-
-static inline int crypto_drbg_ctr_df_datalen(u8 statelen, u8 blocklen)
-{
-	return statelen +       /* df_data */
-		blocklen +      /* pad */
-		blocklen +      /* iv */
-		statelen + blocklen;  /* temp */
-}
-
-int crypto_drbg_ctr_df(struct aes_enckey *aes,
-		       unsigned char *df_data,
-		       size_t bytes_to_return,
-		       struct list_head *seedlist,
-		       u8 blocklen_bytes,
-		       u8 statelen);
-
-#endif /* _CRYPTO_DF80090A_H */
-- 
2.54.0


^ permalink raw reply related

* [PATCH 2/4] crypto: xilinx-trng - Fix return value of xtrng_hwrng_trng_read()
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
	Michal Simek, linux-arm-kernel, Eric Biggers, stable
In-Reply-To: <20260531191738.55843-1-ebiggers@kernel.org>

Implementations of hwrng::read are expected to return the number of
bytes generated.  Update xtrng_hwrng_trng_read() to match that.

Fixes: 8979744aca80 ("crypto: xilinx - Add TRNG driver for Versal")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 drivers/crypto/xilinx/xilinx-trng.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/crypto/xilinx/xilinx-trng.c
index a35643baa489..a30b0b3b3685 100644
--- a/drivers/crypto/xilinx/xilinx-trng.c
+++ b/drivers/crypto/xilinx/xilinx-trng.c
@@ -237,22 +237,25 @@ static int xtrng_random_bytes_generate(struct xilinx_rng *rng, u8 *rand_buf_ptr,
 
 static int xtrng_hwrng_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait)
 {
 	u8 buf[TRNG_SEC_STRENGTH_BYTES];
 	struct xilinx_rng *rng;
-	int ret = -EINVAL, i = 0;
+	int ret = 0, i = 0;
 
 	rng = container_of(hwrng, struct xilinx_rng, trng);
 	while (i < max) {
 		ret = xtrng_random_bytes_generate(rng, buf, TRNG_SEC_STRENGTH_BYTES, wait);
-		if (ret < 0)
+		if (ret < 0) {
+			if (i == 0)
+				return ret;
 			break;
+		}
 
 		memcpy(data + i, buf, min_t(int, ret, (max - i)));
 		i += min_t(int, ret, (max - i));
 	}
-	return ret;
+	return i;
 }
 
 static int xtrng_hwrng_register(struct hwrng *trng)
 {
 	int ret;
-- 
2.54.0


^ permalink raw reply related

* [PATCH 1/4] crypto: xilinx-trng - Remove crypto_rng interface
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
	Michal Simek, linux-arm-kernel, Eric Biggers, stable
In-Reply-To: <20260531191738.55843-1-ebiggers@kernel.org>

Implementing the crypto_rng interface has no purpose, as it isn't used
in practice.  It's being removed from other drivers too.  Just remove
it.  This leaves hwrng, which is actually used.

Tagging with 'Cc stable' due to the bugs that this removes:

  - xtrng_trng_generate() sometimes returned success even when it didn't
    fill in all the bytes.

  - It was possible for xtrng_trng_generate() and
    xtrng_hwrng_trng_read() to run concurrently and interfere with each
    other, as the locking code in xtrng_hwrng_trng_read() was broken.

Fixes: 8979744aca80 ("crypto: xilinx - Add TRNG driver for Versal")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 drivers/crypto/Kconfig              |  1 -
 drivers/crypto/xilinx/xilinx-trng.c | 85 ++---------------------------
 2 files changed, 4 insertions(+), 82 deletions(-)

diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 07f0fa3341fc..26194c33cb32 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -708,11 +708,10 @@ config CRYPTO_DEV_TEGRA
 
 config CRYPTO_DEV_XILINX_TRNG
 	tristate "Support for Xilinx True Random Generator"
 	depends on ZYNQMP_FIRMWARE || COMPILE_TEST
 	select CRYPTO_DF80090A
-	select CRYPTO_RNG
 	select HW_RANDOM
 	help
 	  Xilinx Versal SoC driver provides kernel-side support for True Random Number
 	  Generator and Pseudo random Number in CTR_DRBG mode as defined in NIST SP800-90A.
 
diff --git a/drivers/crypto/xilinx/xilinx-trng.c b/drivers/crypto/xilinx/xilinx-trng.c
index 43a4832f07e7..a35643baa489 100644
--- a/drivers/crypto/xilinx/xilinx-trng.c
+++ b/drivers/crypto/xilinx/xilinx-trng.c
@@ -4,25 +4,22 @@
  * Copyright (c) 2024 - 2025 Advanced Micro Devices, Inc.
  */
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
-#include <linux/crypto.h>
 #include <linux/delay.h>
 #include <linux/firmware/xlnx-zynqmp.h>
 #include <linux/hw_random.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/mutex.h>
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
 #include <crypto/aes.h>
 #include <crypto/df_sp80090a.h>
 #include <crypto/internal/cipher.h>
-#include <crypto/internal/rng.h>
 
 /* TRNG Registers Offsets */
 #define TRNG_STATUS_OFFSET			0x4U
 #define TRNG_CTRL_OFFSET			0x8U
 #define TRNG_EXT_SEED_OFFSET			0x40U
@@ -58,20 +55,13 @@
 struct xilinx_rng {
 	void __iomem *rng_base;
 	struct device *dev;
 	unsigned char *scratchpadbuf;
 	struct aes_enckey *aeskey;
-	struct mutex lock;	/* Protect access to TRNG device */
 	struct hwrng trng;
 };
 
-struct xilinx_rng_ctx {
-	struct xilinx_rng *rng;
-};
-
-static struct xilinx_rng *xilinx_rng_dev;
-
 static void xtrng_readwrite32(void __iomem *addr, u32 mask, u8 value)
 {
 	u32 val;
 
 	val = ioread32(addr);
@@ -243,74 +233,25 @@ static int xtrng_random_bytes_generate(struct xilinx_rng *rng, u8 *rand_buf_ptr,
 	}
 
 	return nbytes;
 }
 
-static int xtrng_trng_generate(struct crypto_rng *tfm, const u8 *src, u32 slen,
-			       u8 *dst, u32 dlen)
-{
-	struct xilinx_rng_ctx *ctx = crypto_rng_ctx(tfm);
-	int ret;
-
-	mutex_lock(&ctx->rng->lock);
-	ret = xtrng_random_bytes_generate(ctx->rng, dst, dlen, true);
-	mutex_unlock(&ctx->rng->lock);
-
-	return ret < 0 ? ret : 0;
-}
-
-static int xtrng_trng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
-{
-	return 0;
-}
-
-static int xtrng_trng_init(struct crypto_tfm *rtfm)
-{
-	struct xilinx_rng_ctx *ctx = crypto_tfm_ctx(rtfm);
-
-	ctx->rng = xilinx_rng_dev;
-
-	return 0;
-}
-
-static struct rng_alg xtrng_trng_alg = {
-	.generate = xtrng_trng_generate,
-	.seed = xtrng_trng_seed,
-	.seedsize = 0,
-	.base = {
-		.cra_name = "stdrng",
-		.cra_driver_name = "xilinx-trng",
-		.cra_priority = 300,
-		.cra_ctxsize = sizeof(struct xilinx_rng_ctx),
-		.cra_module = THIS_MODULE,
-		.cra_init = xtrng_trng_init,
-	},
-};
-
 static int xtrng_hwrng_trng_read(struct hwrng *hwrng, void *data, size_t max, bool wait)
 {
 	u8 buf[TRNG_SEC_STRENGTH_BYTES];
 	struct xilinx_rng *rng;
 	int ret = -EINVAL, i = 0;
 
 	rng = container_of(hwrng, struct xilinx_rng, trng);
-	/* Return in case wait not set and lock not available. */
-	if (!mutex_trylock(&rng->lock) && !wait)
-		return 0;
-	else if (!mutex_is_locked(&rng->lock) && wait)
-		mutex_lock(&rng->lock);
-
 	while (i < max) {
 		ret = xtrng_random_bytes_generate(rng, buf, TRNG_SEC_STRENGTH_BYTES, wait);
 		if (ret < 0)
 			break;
 
 		memcpy(data + i, buf, min_t(int, ret, (max - i)));
 		i += min_t(int, ret, (max - i));
 	}
-	mutex_unlock(&rng->lock);
-
 	return ret;
 }
 
 static int xtrng_hwrng_register(struct hwrng *trng)
 {
@@ -352,60 +293,42 @@ static int xtrng_probe(struct platform_device *pdev)
 	if (!rng->aeskey)
 		return -ENOMEM;
 
 	sb_size = crypto_drbg_ctr_df_datalen(TRNG_SEED_LEN_BYTES, AES_BLOCK_SIZE);
 	rng->scratchpadbuf = devm_kzalloc(&pdev->dev, sb_size, GFP_KERNEL);
-	if (!rng->scratchpadbuf) {
-		ret = -ENOMEM;
-		goto end;
-	}
+	if (!rng->scratchpadbuf)
+		return -ENOMEM;
 
 	xtrng_trng_reset(rng->rng_base);
 	ret = xtrng_reseed_internal(rng);
 	if (ret) {
 		dev_err(&pdev->dev, "TRNG Seed fail\n");
-		goto end;
-	}
-
-	xilinx_rng_dev = rng;
-	mutex_init(&rng->lock);
-	ret = crypto_register_rng(&xtrng_trng_alg);
-	if (ret) {
-		dev_err(&pdev->dev, "Crypto Random device registration failed: %d\n", ret);
-		goto end;
+		return ret;
 	}
 
 	ret = xtrng_hwrng_register(&rng->trng);
 	if (ret) {
 		dev_err(&pdev->dev, "HWRNG device registration failed: %d\n", ret);
-		goto crypto_rng_free;
+		return ret;
 	}
 	platform_set_drvdata(pdev, rng);
 
 	return 0;
-
-crypto_rng_free:
-	crypto_unregister_rng(&xtrng_trng_alg);
-
-end:
-	return ret;
 }
 
 static void xtrng_remove(struct platform_device *pdev)
 {
 	struct xilinx_rng *rng;
 	u32 zero[TRNG_NUM_INIT_REGS] = { };
 
 	rng = platform_get_drvdata(pdev);
 	xtrng_hwrng_unregister(&rng->trng);
-	crypto_unregister_rng(&xtrng_trng_alg);
 	xtrng_write_multiple_registers(rng->rng_base + TRNG_EXT_SEED_OFFSET, zero,
 				       TRNG_NUM_INIT_REGS);
 	xtrng_write_multiple_registers(rng->rng_base + TRNG_PER_STRNG_OFFSET, zero,
 				       TRNG_NUM_INIT_REGS);
 	xtrng_hold_reset(rng->rng_base);
-	xilinx_rng_dev = NULL;
 }
 
 static const struct of_device_id xtrng_of_match[] = {
 	{ .compatible = "xlnx,versal-trng", },
 	{},
-- 
2.54.0


^ permalink raw reply related

* [PATCH 0/4] Xilinx TRNG fix and simplification
From: Eric Biggers @ 2026-05-31 19:17 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: linux-kernel, Mounika Botcha, Harsh Jain, Olivia Mackall,
	Michal Simek, linux-arm-kernel, Eric Biggers

This series fixes and greatly simplifies the Xilinx TRNG driver by:

- Removing the gratuitous crypto_rng interface, leaving just hwrng which
  is the one that actually matters.

- Replacing the really complicated AES based entropy extraction
  algorithm with a much simpler one.

Note that this mirrors similar changes in other drivers.

Eric Biggers (4):
  crypto: xilinx-trng - Remove crypto_rng interface
  crypto: xilinx-trng - Fix return value of xtrng_hwrng_trng_read()
  crypto: xilinx-trng - Replace crypto_drbg_ctr_df() with HMAC-SHA512
  hwrng: xilinx - Move xilinx-rng into drivers/char/hw_random/

 MAINTAINERS                                   |   2 +-
 arch/arm64/configs/defconfig                  |   2 +-
 crypto/Kconfig                                |   5 -
 crypto/Makefile                               |   2 -
 crypto/df_sp80090a.c                          | 222 ------------------
 drivers/char/hw_random/Kconfig                |  11 +
 drivers/char/hw_random/Makefile               |   1 +
 .../xilinx => char/hw_random}/xilinx-trng.c   | 134 ++---------
 drivers/crypto/Kconfig                        |  13 -
 drivers/crypto/xilinx/Makefile                |   1 -
 include/crypto/df_sp80090a.h                  |  53 -----
 11 files changed, 37 insertions(+), 409 deletions(-)
 delete mode 100644 crypto/df_sp80090a.c
 rename drivers/{crypto/xilinx => char/hw_random}/xilinx-trng.c (75%)
 delete mode 100644 include/crypto/df_sp80090a.h


base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
prerequisite-patch-id: 07e982b663ac3f8312ca524f6b91b5b38661df5e
prerequisite-patch-id: 72064361a8f36e015ab0b7e1fa4d364b40d90506
prerequisite-patch-id: 8978b8e0db7f47935e5f6f0aff14a97f55d3073c
prerequisite-patch-id: 6aa0e3e93a008279d71e535a3d0cf48643f55e19
-- 
2.54.0


^ permalink raw reply

* [PATCH v2 1/1] crypto: atmel-sha204a - fix heap info leak on I2C transfer failure
From: Lothar Rubusch @ 2026-05-31 19:16 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea, ardb, krzk+dt
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch

The nonblocking RNG path allocates a work_data structure to track the
state of an in-flight asynchronous I2C request. This pointer is stored
in rng->priv and later consumed by the read path once the transaction
completes.

If the underlying I2C transfer fails, the completion callback is invoked
with a non-zero status. In this case, the allocated work_data is not
usable for producing RNG output and must not remain associated with the
hwrng state.

Previously, the failure path only logged a warning but left the pointer
state uncleared, which can result in subsequent read attempts observing
stale state and interpreting it as valid completion data.

Fix this by freeing the pending work_data and clearing rng->priv when
the I2C transaction reports an error. This ensures that failed requests
do not leave residual state behind that could be interpreted as valid
RNG data on later reads.

The explicit clearing of rng->priv in the error path is retained as a
defensive measure. While it may overlap with existing state handling in the
read path, the ownership and lifecycle across asynchronous completion,
read, and teardown paths is not fully localised. Clearing the pointer
ensures no stale state remains after a failed transaction.

Fixes: da001fb651b0 ("crypto: atmel-i2c - add support for SHA204A random number generator")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
Reviewed-by: Thorsten Blum <thorsten.blum@linux.dev>
---
v1 -> v2:
- Reword commit message for clarity and precision
- Keep existing error-path cleanup behavior unchanged, update commit msg

 drivers/crypto/atmel-sha204a.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 4c9af737b33a..20cd915ea8a3 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -31,10 +31,15 @@ static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,
 	struct atmel_i2c_client_priv *i2c_priv = work_data->ctx;
 	struct hwrng *rng = areq;
 
-	if (status)
+	if (status) {
 		dev_warn_ratelimited(&i2c_priv->client->dev,
 				     "i2c transaction failed (%d)\n",
 				     status);
+		kfree(work_data);
+		rng->priv = 0;
+		atomic_dec(&i2c_priv->tfm_count);
+		return;
+	}
 
 	rng->priv = (unsigned long)work_data;
 	atomic_dec(&i2c_priv->tfm_count);

base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
-- 
2.53.0


^ permalink raw reply related

* [PATCH] crypto: exynos-rng - Remove exynos-rng driver
From: Eric Biggers @ 2026-05-31 17:59 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: linux-samsung-soc, Krzysztof Kozlowski, Alim Akhtar, linux-kernel,
	Eric Biggers

This driver has no purpose.  It doesn't feed into the Linux RNG, nor
does it implement the hwrng interface.  It is accessible only via the
"rng" algorithm type of AF_ALG, which isn't used in practice.  Everyone
uses either the Linux RNG, or rarely /dev/hwrng.

Moreover, this is a PRNG whose only source of entropy is the 160-bit
seed the user passes in.  So this can be used only by a user who already
has a source of cryptographically secure random numbers, such as
/dev/random.  Which they can, and do, just use in the first place.

Just remove this driver.  There's no need to keep useless code around.

Note that the other crypto_rng drivers in drivers/crypto/ are similarly
unused and are being removed too.  This commit just handles exynos-rng.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 MAINTAINERS                         |   8 -
 arch/arm/configs/exynos_defconfig   |   1 -
 arch/arm/configs/multi_v7_defconfig |   1 -
 drivers/crypto/Kconfig              |  18 --
 drivers/crypto/Makefile             |   1 -
 drivers/crypto/exynos-rng.c         | 399 ----------------------------
 6 files changed, 428 deletions(-)
 delete mode 100644 drivers/crypto/exynos-rng.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 882214b0e7db..a7f2762baac1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23701,18 +23701,10 @@ L:	linux-samsung-soc@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/mailbox/google,gs101-mbox.yaml
 F:	drivers/mailbox/exynos-mailbox.c
 F:	include/linux/mailbox/exynos-message.h
 
-SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
-M:	Krzysztof Kozlowski <krzk@kernel.org>
-L:	linux-crypto@vger.kernel.org
-L:	linux-samsung-soc@vger.kernel.org
-S:	Maintained
-F:	Documentation/devicetree/bindings/rng/samsung,exynos4-rng.yaml
-F:	drivers/crypto/exynos-rng.c
-
 SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
 M:	Łukasz Stelmach <l.stelmach@samsung.com>
 L:	linux-samsung-soc@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/rng/samsung,exynos5250-trng.yaml
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index 84070e9698e8..8b072a5c0a5e 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -362,11 +362,10 @@ CONFIG_CRYPTO_LZ4=m
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_CRYPTO_AES_ARM_BS=m
-CONFIG_CRYPTO_DEV_EXYNOS_RNG=y
 CONFIG_CRYPTO_DEV_S5P=y
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=96
 CONFIG_FONTS=y
 CONFIG_FONT_7x14=y
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index bcc9aabc1202..3672dd12df60 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -1327,11 +1327,10 @@ CONFIG_CRYPTO_GHASH_ARM_CE=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_AES_ARM_BS=m
 CONFIG_CRYPTO_AES_ARM_CE=m
 CONFIG_CRYPTO_DEV_SUN4I_SS=m
 CONFIG_CRYPTO_DEV_FSL_CAAM=m
-CONFIG_CRYPTO_DEV_EXYNOS_RNG=m
 CONFIG_CRYPTO_DEV_S5P=m
 CONFIG_CRYPTO_DEV_ATMEL_AES=m
 CONFIG_CRYPTO_DEV_ATMEL_TDES=m
 CONFIG_CRYPTO_DEV_ATMEL_SHA=m
 CONFIG_CRYPTO_DEV_MARVELL_CESA=m
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 3449b3c9c6ad..39c7b195bb33 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -373,25 +373,10 @@ config CRYPTO_DEV_SAHARA
 	select CRYPTO_ENGINE
 	help
 	  This option enables support for the SAHARA HW crypto accelerator
 	  found in some Freescale i.MX chips.
 
-config CRYPTO_DEV_EXYNOS_RNG
-	tristate "Exynos HW pseudo random number generator support"
-	depends on ARCH_EXYNOS || COMPILE_TEST
-	depends on HAS_IOMEM
-	select CRYPTO_RNG
-	help
-	  This driver provides kernel-side support through the
-	  cryptographic API for the pseudo random number generator hardware
-	  found on Exynos SoCs.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called exynos-rng.
-
-	  If unsure, say Y.
-
 config CRYPTO_DEV_S5P
 	tristate "Support for Samsung S5PV210/Exynos crypto accelerator"
 	depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
 	depends on HAS_IOMEM
 	select CRYPTO_AES
@@ -402,20 +387,17 @@ config CRYPTO_DEV_S5P
 	  algorithms execution.
 
 config CRYPTO_DEV_EXYNOS_HASH
 	bool "Support for Samsung Exynos HASH accelerator"
 	depends on CRYPTO_DEV_S5P
-	depends on !CRYPTO_DEV_EXYNOS_RNG && CRYPTO_DEV_EXYNOS_RNG!=m
 	select CRYPTO_SHA1
 	select CRYPTO_MD5
 	select CRYPTO_SHA256
 	help
 	  Select this to offload Exynos from HASH MD5/SHA1/SHA256.
 	  This will select software SHA1, MD5 and SHA256 as they are
 	  needed for small and zero-size messages.
-	  HASH algorithms will be disabled if EXYNOS_RNG
-	  is enabled due to hw conflict.
 
 config CRYPTO_DEV_NX
 	bool "Support for IBM PowerPC Nest (NX) cryptographic acceleration"
 	depends on PPC64
 	help
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 283bbc650b5b..e141ab0dd741 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -9,11 +9,10 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_I2C) += atmel-i2c.o
 obj-$(CONFIG_CRYPTO_DEV_ATMEL_ECC) += atmel-ecc.o
 obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA204A) += atmel-sha204a.o
 obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/
 obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/
 obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chelsio/
-obj-$(CONFIG_CRYPTO_DEV_EXYNOS_RNG) += exynos-rng.o
 obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += caam/
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
 obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
 obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o
 obj-$(CONFIG_CRYPTO_DEV_MARVELL) += marvell/
diff --git a/drivers/crypto/exynos-rng.c b/drivers/crypto/exynos-rng.c
deleted file mode 100644
index 2aaa98f9b44e..000000000000
--- a/drivers/crypto/exynos-rng.c
+++ /dev/null
@@ -1,399 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * exynos-rng.c - Random Number Generator driver for the Exynos
- *
- * Copyright (c) 2017 Krzysztof Kozlowski <krzk@kernel.org>
- *
- * Loosely based on old driver from drivers/char/hw_random/exynos-rng.c:
- * Copyright (C) 2012 Samsung Electronics
- * Jonghwa Lee <jonghwa3.lee@samsung.com>
- */
-
-#include <linux/clk.h>
-#include <linux/crypto.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-
-#include <crypto/internal/rng.h>
-
-#define EXYNOS_RNG_CONTROL		0x0
-#define EXYNOS_RNG_STATUS		0x10
-
-#define EXYNOS_RNG_SEED_CONF		0x14
-#define EXYNOS_RNG_GEN_PRNG	        BIT(1)
-
-#define EXYNOS_RNG_SEED_BASE		0x140
-#define EXYNOS_RNG_SEED(n)		(EXYNOS_RNG_SEED_BASE + (n * 0x4))
-#define EXYNOS_RNG_OUT_BASE		0x160
-#define EXYNOS_RNG_OUT(n)		(EXYNOS_RNG_OUT_BASE + (n * 0x4))
-
-/* EXYNOS_RNG_CONTROL bit fields */
-#define EXYNOS_RNG_CONTROL_START	0x18
-/* EXYNOS_RNG_STATUS bit fields */
-#define EXYNOS_RNG_STATUS_SEED_SETTING_DONE	BIT(1)
-#define EXYNOS_RNG_STATUS_RNG_DONE		BIT(5)
-
-/* Five seed and output registers, each 4 bytes */
-#define EXYNOS_RNG_SEED_REGS		5
-#define EXYNOS_RNG_SEED_SIZE		(EXYNOS_RNG_SEED_REGS * 4)
-
-enum exynos_prng_type {
-	EXYNOS_PRNG_UNKNOWN = 0,
-	EXYNOS_PRNG_EXYNOS4,
-	EXYNOS_PRNG_EXYNOS5,
-};
-
-/*
- * Driver re-seeds itself with generated random numbers to hinder
- * backtracking of the original seed.
- *
- * Time for next re-seed in ms.
- */
-#define EXYNOS_RNG_RESEED_TIME		1000
-#define EXYNOS_RNG_RESEED_BYTES		65536
-
-/*
- * In polling mode, do not wait infinitely for the engine to finish the work.
- */
-#define EXYNOS_RNG_WAIT_RETRIES		100
-
-/* Context for crypto */
-struct exynos_rng_ctx {
-	struct exynos_rng_dev		*rng;
-};
-
-/* Device associated memory */
-struct exynos_rng_dev {
-	struct device			*dev;
-	enum exynos_prng_type		type;
-	void __iomem			*mem;
-	struct clk			*clk;
-	struct mutex 			lock;
-	/* Generated numbers stored for seeding during resume */
-	u8				seed_save[EXYNOS_RNG_SEED_SIZE];
-	unsigned int			seed_save_len;
-	/* Time of last seeding in jiffies */
-	unsigned long			last_seeding;
-	/* Bytes generated since last seeding */
-	unsigned long			bytes_seeding;
-};
-
-static struct exynos_rng_dev *exynos_rng_dev;
-
-static u32 exynos_rng_readl(struct exynos_rng_dev *rng, u32 offset)
-{
-	return readl_relaxed(rng->mem + offset);
-}
-
-static void exynos_rng_writel(struct exynos_rng_dev *rng, u32 val, u32 offset)
-{
-	writel_relaxed(val, rng->mem + offset);
-}
-
-static int exynos_rng_set_seed(struct exynos_rng_dev *rng,
-			       const u8 *seed, unsigned int slen)
-{
-	u32 val;
-	int i;
-
-	/* Round seed length because loop iterates over full register size */
-	slen = ALIGN_DOWN(slen, 4);
-
-	if (slen < EXYNOS_RNG_SEED_SIZE)
-		return -EINVAL;
-
-	for (i = 0; i < slen ; i += 4) {
-		unsigned int seed_reg = (i / 4) % EXYNOS_RNG_SEED_REGS;
-
-		val = seed[i] << 24;
-		val |= seed[i + 1] << 16;
-		val |= seed[i + 2] << 8;
-		val |= seed[i + 3] << 0;
-
-		exynos_rng_writel(rng, val, EXYNOS_RNG_SEED(seed_reg));
-	}
-
-	val = exynos_rng_readl(rng, EXYNOS_RNG_STATUS);
-	if (!(val & EXYNOS_RNG_STATUS_SEED_SETTING_DONE)) {
-		dev_warn(rng->dev, "Seed setting not finished\n");
-		return -EIO;
-	}
-
-	rng->last_seeding = jiffies;
-	rng->bytes_seeding = 0;
-
-	return 0;
-}
-
-/*
- * Start the engine and poll for finish.  Then read from output registers
- * filling the 'dst' buffer up to 'dlen' bytes or up to size of generated
- * random data (EXYNOS_RNG_SEED_SIZE).
- *
- * On success: return 0 and store number of read bytes under 'read' address.
- * On error: return -ERRNO.
- */
-static int exynos_rng_get_random(struct exynos_rng_dev *rng,
-				 u8 *dst, unsigned int dlen,
-				 unsigned int *read)
-{
-	int retry = EXYNOS_RNG_WAIT_RETRIES;
-
-	if (rng->type == EXYNOS_PRNG_EXYNOS4) {
-		exynos_rng_writel(rng, EXYNOS_RNG_CONTROL_START,
-				  EXYNOS_RNG_CONTROL);
-	} else if (rng->type == EXYNOS_PRNG_EXYNOS5) {
-		exynos_rng_writel(rng, EXYNOS_RNG_GEN_PRNG,
-				  EXYNOS_RNG_SEED_CONF);
-	}
-
-	while (!(exynos_rng_readl(rng,
-			EXYNOS_RNG_STATUS) & EXYNOS_RNG_STATUS_RNG_DONE) && --retry)
-		cpu_relax();
-
-	if (!retry)
-		return -ETIMEDOUT;
-
-	/* Clear status bit */
-	exynos_rng_writel(rng, EXYNOS_RNG_STATUS_RNG_DONE,
-			  EXYNOS_RNG_STATUS);
-	*read = min_t(size_t, dlen, EXYNOS_RNG_SEED_SIZE);
-	memcpy_fromio(dst, rng->mem + EXYNOS_RNG_OUT_BASE, *read);
-	rng->bytes_seeding += *read;
-
-	return 0;
-}
-
-/* Re-seed itself from time to time */
-static void exynos_rng_reseed(struct exynos_rng_dev *rng)
-{
-	unsigned long next_seeding = rng->last_seeding + \
-				     msecs_to_jiffies(EXYNOS_RNG_RESEED_TIME);
-	unsigned long now = jiffies;
-	unsigned int read = 0;
-	u8 seed[EXYNOS_RNG_SEED_SIZE];
-
-	if (time_before(now, next_seeding) &&
-	    rng->bytes_seeding < EXYNOS_RNG_RESEED_BYTES)
-		return;
-
-	if (exynos_rng_get_random(rng, seed, sizeof(seed), &read))
-		return;
-
-	exynos_rng_set_seed(rng, seed, read);
-
-	/* Let others do some of their job. */
-	mutex_unlock(&rng->lock);
-	mutex_lock(&rng->lock);
-}
-
-static int exynos_rng_generate(struct crypto_rng *tfm,
-			       const u8 *src, unsigned int slen,
-			       u8 *dst, unsigned int dlen)
-{
-	struct exynos_rng_ctx *ctx = crypto_rng_ctx(tfm);
-	struct exynos_rng_dev *rng = ctx->rng;
-	unsigned int read = 0;
-	int ret;
-
-	ret = clk_prepare_enable(rng->clk);
-	if (ret)
-		return ret;
-
-	mutex_lock(&rng->lock);
-	do {
-		ret = exynos_rng_get_random(rng, dst, dlen, &read);
-		if (ret)
-			break;
-
-		dlen -= read;
-		dst += read;
-
-		exynos_rng_reseed(rng);
-	} while (dlen > 0);
-	mutex_unlock(&rng->lock);
-
-	clk_disable_unprepare(rng->clk);
-
-	return ret;
-}
-
-static int exynos_rng_seed(struct crypto_rng *tfm, const u8 *seed,
-			   unsigned int slen)
-{
-	struct exynos_rng_ctx *ctx = crypto_rng_ctx(tfm);
-	struct exynos_rng_dev *rng = ctx->rng;
-	int ret;
-
-	ret = clk_prepare_enable(rng->clk);
-	if (ret)
-		return ret;
-
-	mutex_lock(&rng->lock);
-	ret = exynos_rng_set_seed(ctx->rng, seed, slen);
-	mutex_unlock(&rng->lock);
-
-	clk_disable_unprepare(rng->clk);
-
-	return ret;
-}
-
-static int exynos_rng_kcapi_init(struct crypto_tfm *tfm)
-{
-	struct exynos_rng_ctx *ctx = crypto_tfm_ctx(tfm);
-
-	ctx->rng = exynos_rng_dev;
-
-	return 0;
-}
-
-static struct rng_alg exynos_rng_alg = {
-	.generate		= exynos_rng_generate,
-	.seed			= exynos_rng_seed,
-	.seedsize		= EXYNOS_RNG_SEED_SIZE,
-	.base			= {
-		.cra_name		= "stdrng",
-		.cra_driver_name	= "exynos_rng",
-		.cra_priority		= 300,
-		.cra_ctxsize		= sizeof(struct exynos_rng_ctx),
-		.cra_module		= THIS_MODULE,
-		.cra_init		= exynos_rng_kcapi_init,
-	}
-};
-
-static int exynos_rng_probe(struct platform_device *pdev)
-{
-	struct exynos_rng_dev *rng;
-	int ret;
-
-	if (exynos_rng_dev)
-		return -EEXIST;
-
-	rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
-	if (!rng)
-		return -ENOMEM;
-
-	rng->type = (uintptr_t)of_device_get_match_data(&pdev->dev);
-
-	mutex_init(&rng->lock);
-
-	rng->dev = &pdev->dev;
-	rng->clk = devm_clk_get(&pdev->dev, "secss");
-	if (IS_ERR(rng->clk)) {
-		dev_err(&pdev->dev, "Couldn't get clock.\n");
-		return PTR_ERR(rng->clk);
-	}
-
-	rng->mem = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(rng->mem))
-		return PTR_ERR(rng->mem);
-
-	platform_set_drvdata(pdev, rng);
-
-	exynos_rng_dev = rng;
-
-	ret = crypto_register_rng(&exynos_rng_alg);
-	if (ret) {
-		dev_err(&pdev->dev,
-			"Couldn't register rng crypto alg: %d\n", ret);
-		exynos_rng_dev = NULL;
-	}
-
-	return ret;
-}
-
-static void exynos_rng_remove(struct platform_device *pdev)
-{
-	crypto_unregister_rng(&exynos_rng_alg);
-
-	exynos_rng_dev = NULL;
-}
-
-static int __maybe_unused exynos_rng_suspend(struct device *dev)
-{
-	struct exynos_rng_dev *rng = dev_get_drvdata(dev);
-	int ret;
-
-	/* If we were never seeded then after resume it will be the same */
-	if (!rng->last_seeding)
-		return 0;
-
-	rng->seed_save_len = 0;
-	ret = clk_prepare_enable(rng->clk);
-	if (ret)
-		return ret;
-
-	mutex_lock(&rng->lock);
-
-	/* Get new random numbers and store them for seeding on resume. */
-	exynos_rng_get_random(rng, rng->seed_save, sizeof(rng->seed_save),
-			      &(rng->seed_save_len));
-
-	mutex_unlock(&rng->lock);
-
-	dev_dbg(rng->dev, "Stored %u bytes for seeding on system resume\n",
-		rng->seed_save_len);
-
-	clk_disable_unprepare(rng->clk);
-
-	return 0;
-}
-
-static int __maybe_unused exynos_rng_resume(struct device *dev)
-{
-	struct exynos_rng_dev *rng = dev_get_drvdata(dev);
-	int ret;
-
-	/* Never seeded so nothing to do */
-	if (!rng->last_seeding)
-		return 0;
-
-	ret = clk_prepare_enable(rng->clk);
-	if (ret)
-		return ret;
-
-	mutex_lock(&rng->lock);
-
-	ret = exynos_rng_set_seed(rng, rng->seed_save, rng->seed_save_len);
-
-	mutex_unlock(&rng->lock);
-
-	clk_disable_unprepare(rng->clk);
-
-	return ret;
-}
-
-static SIMPLE_DEV_PM_OPS(exynos_rng_pm_ops, exynos_rng_suspend,
-			 exynos_rng_resume);
-
-static const struct of_device_id exynos_rng_dt_match[] = {
-	{
-		.compatible = "samsung,exynos4-rng",
-		.data = (const void *)EXYNOS_PRNG_EXYNOS4,
-	}, {
-		.compatible = "samsung,exynos5250-prng",
-		.data = (const void *)EXYNOS_PRNG_EXYNOS5,
-	},
-	{ },
-};
-MODULE_DEVICE_TABLE(of, exynos_rng_dt_match);
-
-static struct platform_driver exynos_rng_driver = {
-	.driver		= {
-		.name	= "exynos-rng",
-		.pm	= &exynos_rng_pm_ops,
-		.of_match_table = exynos_rng_dt_match,
-	},
-	.probe		= exynos_rng_probe,
-	.remove		= exynos_rng_remove,
-};
-
-module_platform_driver(exynos_rng_driver);
-
-MODULE_DESCRIPTION("Exynos H/W Random Number Generator driver");
-MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
-MODULE_LICENSE("GPL v2");

base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v19 00/14] crypto/dmaengine: qce: introduce BAM locking and use DMA for register I/O
From: Bartosz Golaszewski @ 2026-05-31 16:27 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Bartosz Golaszewski, Vinod Koul, Jonathan Corbet, Thara Gopinath,
	Herbert Xu, David S. Miller, Udit Tiwari, Md Sadre Alam,
	Dmitry Baryshkov, Manivannan Sadhasivam, Stephan Gerhold,
	Bjorn Andersson, Peter Ujfalusi, Michal Simek, Frank Li,
	Andy Gross, Neil Armstrong, dmaengine, linux-doc, linux-kernel,
	linux-arm-msm, linux-crypto, linux-arm-kernel,
	Bartosz Golaszewski, Dmitry Baryshkov, Konrad Dybcio
In-Reply-To: <20260529162251.GB2706@sol>

On Fri, May 29, 2026 at 6:24 PM Eric Biggers <ebiggers@kernel.org> wrote:
>
> On Tue, May 26, 2026 at 03:10:48PM +0200, Bartosz Golaszewski wrote:
> > I feel like I fell into the trap of trying to address pre-existing
> > issues reported by sashiko and in the process provoking more reports so
> > let this be the last iteration where I do this. Vinod can we get this
> > queued for v7.2 now and iron out any previously existing problems in
> > tree?
> >
> > Merging strategy: there are build-time dependencies between the crypto
> > and DMA patches so the best approach is for Vinod to create an immutable
> > branch with the DMA part pulled in by the crypto tree.
> >
> > This iteration continues to build on top of v12 but uses the BAM's NWD
> > bit on data descriptors as suggested by Stephan. To that end, there are
> > some more changes like reversing the order of command and data
> > descriptors queuedy by the QCE driver.
> >
> > Currently the QCE crypto driver accesses the crypto engine registers
> > directly via CPU. Trust Zone may perform crypto operations simultaneously
> > resulting in a race condition. To remedy that, let's introduce support
> > for BAM locking/unlocking to the driver. The BAM driver will now wrap
> > any existing issued descriptor chains with additional descriptors
> > performing the locking when the client starts the transaction
> > (dmaengine_issue_pending()). The client wanting to profit from locking
> > needs to switch to performing register I/O over DMA and communicate the
> > address to which to perform the dummy writes via a call to
> > dmaengine_desc_attach_metadata().
> >
> > In the specific case of the BAM DMA this translates to sending command
> > descriptors performing dummy writes with the relevant flags set. The BAM
> > will then lock all other pipes not related to the current pipe group, and
> > keep handling the current pipe only until it sees the the unlock bit.
> >
> > In order for the locking to work correctly, we also need to switch to
> > using DMA for all register I/O.
> >
> > On top of this, the series contains some additional tweaks and
> > refactoring.
> >
> > The goal of this is not to improve the performance but to prepare the
> > driver for supporting decryption into secure buffers in the future.
> >
> > Tested with tcrypt.ko, kcapi and cryptsetup.
> >
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>
> None of these fixes are Cc'ed to stable, so stable kernels will remain
> vulnerable to these race conditions.
>
> Shouldn't this be preceded by a patch, Cc'ed to stable, that marks the
> driver as BROKEN?  As discussed in the other thread
> (https://lore.kernel.org/linux-crypto/20260515-shikra_qcrypto-v1-0-80f07b345c29@oss.qualcomm.com/T/#u),
> none of the current functionality of this driver is actually useful in
> Linux.  It's just been causing problems.
>

I don't believe any of it should be backported. This is not a
regression, multiple EEs were never supported, so it's a new feature.
Also: backporting of over 500 diff lines across two subsystems doesn't
sound like a good idea to me.

On the other hand, if marking the driver as BROKEN for the time being
allows for a faster pace of queuing any changes to it, then I'm for
it. Let's unmark it once we fix it.

Bart

^ permalink raw reply

* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Eric Biggers @ 2026-05-31 16:00 UTC (permalink / raw)
  To: Aleksander Jan Bajkowski
  Cc: linux-crypto, Herbert Xu, Christian Lamparter, linuxppc-dev,
	linux-kernel, stable
In-Reply-To: <465adf3a-2c27-43d0-afdb-68ae12b89d10@wp.pl>

On Sun, May 31, 2026 at 12:15:49PM +0200, Aleksander Jan Bajkowski wrote:
> Hi Eric,
> 
> On 30/05/2026 21:26, Eric Biggers wrote:
> > On Sat, May 30, 2026 at 05:05:19PM +0200, Aleksander Jan Bajkowski wrote:
> > > Hi Eric,
> > > 
> > > On 30/05/2026 00:04, Eric Biggers wrote:
> > > > Remove crypto4xx_rng, as it is insecure and unused:
> > > > 
> > > > - It has only a 64-bit security strength, which is highly inadequate.
> > > >     This can be seen by the fact that crypto4xx_hw_init() seeds it with
> > > >     only 64 bits of entropy, and the fact that the original commit
> > > >     mentions that it implements ANSI X9.17 Annex C.
> > > In addition to a seed, the PRNG also uses ring oscillators as sources of
> > > entropy. The entropy should be higher than 64b. This is the Rambus EIP-73d
> > > IP core. The same IP core is built into eip93 (EIP-73a), eip97 (EIP-73d),
> > > and eip197 (EIP-73d). You can find the documentation online. The complete
> > > "container" is actually Rambus EIP-94, and one of its parts is EIP-73d.
> > Just because it may have another source of entropy doesn't mean its
> > security strength is higher than 64 bits.
> > 
> > I cannot find any documentation other than
> > https://datasheet.octopart.com/PPC460EX-SUB800T-AMCC-datasheet-11553412.pdf
> > which says "ANSI X9.17 Annex C compliant using a DES algorithm".
> > 
> > DES actually has a 56-bit key, so maybe I was over-generous.
> > 
> > And according to https://cacr.uwaterloo.ca/hac/about/chap5.pdf ANSI
> > X9.17 has only a 64-bit state anyway.  So even if we assume the
> > datasheet is incorrect and the algorithm is actually 3DES which has a
> > longer key, the state is likely still 64-bit.
> According to the datasheet, there is no second source of entropy. The PRNG
> has three built-in LFSRs. Each of them can be initialized independently. The
> first LFSR is used to generate input data. The second and third are used to
> generate keys for DES encryption. The output of the first LFSR is encrypted
> using 3DES with two 64-bit keys. Between individual DES operations, data is
> XORed with the seed. It sounds like a fairly secure design if properly
> reseeded.
> There is also a newer design (EIP73a) based on the same algorithm. The
> only difference is the replacing of 3DES with AES using a 2TDEA scheme.
> The DES-based variant is more widely used, even in new SoCs.

Okay, it sounds like you're walking back your claim that there's a
second source of entropy.  That leaves just the 64-bit seed that the
driver writes to CRYPTO4XX_PRNG_SEED_L || CRYPTO4XX_PRNG_SEED_H, which
probably corresponds to the "first LFSR" you mentioned.  The driver
doesn't initialize the other LFSRs.

> > So it isn't looking good.  And since it's an undocumented proprietary
> > design it shouldn't be given the benefit of the doubt either.
> > 
> As I mentioned earlier, this IP core is quite well documented[1] (page 198).
> Half of all SOHO routers have the EIP-73d built in. The algorithm is also
> described in TRM for some of these SoCs :)
> 
> List od SoCs with EIP-73d:
> AMCC PPC405EX/PPC460EX,
> Intel/Maxlinear GRX350, URX850,
> Marvell Armada 37x0, 7k, 8k,
> Mediatek MT7623/MT7981/MT7986/MT7987/MT7988,
> Qualcomm IPQ975x.
> 
> [1] https://www.scribd.com/document/734250956/Safexcel-Ip-94-Plb-Sas-v1-5?_gl=1*dng4pf*_up*MQ..*_ga*OTQ4NjkzMTAxLjE3ODAyMjA4ODI.*_ga_Z4ZC50DED6*czE3ODAyMjA4ODEkbzEkZzEkdDE3ODAyMjA4ODEkajYwJGwwJGgw*_ga_8KZ8BV0P5W*czE3ODAyMjA4ODEkbzEkZzEkdDE3ODAyMjA4ODEkajYwJGwwJGgw

The option to download the file is paywalled.

Anyway, even if it turns out that this is secure (it won't), it's still
unused code that should be removed anyway.  The fact that it's not up to
modern security standards just provides some additional motivation.

- Eric

^ permalink raw reply

* [PATCH v3] hwrng: virtio: clamp device-reported used.len at copy_data()
From: Michael Bommarito @ 2026-05-31 14:22 UTC (permalink / raw)
  To: Olivia Mackall, Herbert Xu, linux-crypto
  Cc: Michael S . Tsirkin, Jason Wang, Kees Cook, Christian Borntraeger,
	virtualization, linux-kernel

random_recv_done() stores the device-reported used.len directly into
vi->data_avail.  copy_data() then indexes vi->data[] using
vi->data_idx (advanced by previous copy_data() calls) and issues a
memcpy() without re-validating either value against the posted
buffer size sizeof(vi->data) (SMP_CACHE_BYTES bytes, typically 32
or 64).

A malicious or buggy virtio-rng backend can set used.len beyond
sizeof(vi->data), steering the memcpy() past the end of the inline
array into adjacent kmalloc-1k slab bytes.  hwrng_fillfn() mixes
those bytes into the guest RNG, and guest root can also observe
them directly via /dev/hwrng.

Concrete impact is inside the guest:

 - Memory-safety / hardening: any virtio-rng backend that
   over-reports used.len causes the driver to read past vi->data
   into unrelated slab contents.  hwrng_fillfn() is a kernel thread
   that runs as soon as the device is probed; no guest userspace
   interaction is required to first-trigger the OOB.

 - Cross-boundary leak (confidential-compute threat model): a
   malicious hypervisor cooperating with a malicious or compromised
   guest root userspace can use /dev/hwrng as a leak channel for
   guest-kernel heap data.  The host sets a large used.len, guest
   root reads /dev/hwrng, and the returned bytes contain guest
   kernel slab contents that were adjacent to vi->data.  In
   practice, confidential-compute guests (SEV-SNP, TDX) usually
   disable virtio-rng entirely, so this path is narrow, but the
   fix is still worth carrying because the underlying
   memory-safety bug contaminates the guest RNG on any host.

KASAN confirms the OOB on a 7.1-rc4 guest whose virtio-rng backend
has been patched to report used.len = 0x10000:

  BUG: KASAN: slab-out-of-bounds in virtio_read+0x394/0x5d0
  Read of size 64 at addr ffff88800ae0ba20 by task hwrng/52
  Call Trace:
   __asan_memcpy+0x23/0x60
   virtio_read+0x394/0x5d0
   hwrng_fillfn+0xb2/0x470
   kthread+0x2cc/0x3a0
  Allocated by task 1:
   probe_common+0xa5/0x660
   virtio_dev_probe+0x549/0xbc0
  The buggy address belongs to the object at ffff88800ae0b800
   which belongs to the cache kmalloc-1k of size 1024
  The buggy address is located 0 bytes to the right of
   allocated 544-byte region [ffff88800ae0b800, ffff88800ae0ba20)

Same class of bug as commit c04db81cd028 ("net/9p: Fix buffer
overflow in USB transport layer"), which hardened
usb9pfs_rx_complete() against unchecked device-reported length in
the USB 9p transport.

With the clamp at point of use and array_index_nospec() in place,
the same harness boots cleanly: copy_data() returns zero for the
bogus report, the device-supplied bytes after data_idx are
discarded, and the driver issues a fresh request.

Fixes: f7f510ec1957 ("virtio: An entropy device, as suggested by hpa.")
Cc: stable@vger.kernel.org
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
Changes in v3:
- No functional change from v2.  Reposting the v2 clamp after the v2
  thread went quiet on linux-crypto.  Michael S. Tsirkin reconfirmed
  off-list that clamping the device-reported used.len at
  sizeof(vi->data) addresses his earlier concern, so this resends that
  fix unchanged.
- Rebased onto v7.1-rc4.  copy_data() is unchanged since 2023, so the
  clamp applies as-is, and the KASAN reproduction above was re-run on
  v7.1-rc4 (stock splats, patched boots clean).

Changes in v2 (Michael S. Tsirkin review):
- move the bound check from random_recv_done() into copy_data(), so the
  clamp sits immediately next to the memcpy() it protects.
- clamp to sizeof(vi->data) rather than substituting len = 0, so a
  previously-working but buggy device that occasionally over-reports
  used.len does not start returning zero-length reads.
- add array_index_nospec() on vi->data_idx to defeat a speculative
  out-of-bounds read given the malicious-backend threat model.
- expand the commit message with the /dev/hwrng observation path and
  the hypervisor plus guest-root cooperation scenario.

v1: https://lore.kernel.org/all/20260418000020.1847122-1-michael.bommarito@gmail.com/
v2: https://lore.kernel.org/all/20260418150613.3522589-1-michael.bommarito@gmail.com/

 drivers/char/hw_random/virtio-rng.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 0ce02d7e5048e..5e83ffa105e41 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -7,6 +7,7 @@
 #include <asm/barrier.h>
 #include <linux/err.h>
 #include <linux/hw_random.h>
+#include <linux/nospec.h>
 #include <linux/scatterlist.h>
 #include <linux/spinlock.h>
 #include <linux/virtio.h>
@@ -69,8 +70,26 @@ static void request_entropy(struct virtrng_info *vi)
 static unsigned int copy_data(struct virtrng_info *vi, void *buf,
 			      unsigned int size)
 {
-	size = min_t(unsigned int, size, vi->data_avail);
-	memcpy(buf, vi->data + vi->data_idx, size);
+	unsigned int idx, avail;
+
+	/*
+	 * vi->data_avail was set from the device-reported used.len and
+	 * vi->data_idx was advanced by previous copy_data() calls.  A
+	 * malicious or buggy virtio-rng backend can drive either past
+	 * sizeof(vi->data).  Clamp at point of use and harden the index
+	 * with array_index_nospec() so the memcpy() below cannot be
+	 * steered into adjacent slab memory, including under
+	 * speculation.
+	 */
+	avail = min_t(unsigned int, vi->data_avail, sizeof(vi->data));
+	if (vi->data_idx >= avail) {
+		vi->data_avail = 0;
+		request_entropy(vi);
+		return 0;
+	}
+	size = min_t(unsigned int, size, avail - vi->data_idx);
+	idx = array_index_nospec(vi->data_idx, sizeof(vi->data));
+	memcpy(buf, vi->data + idx, size);
 	vi->data_idx += size;
 	vi->data_avail -= size;
 	if (vi->data_avail == 0)

base-commit: a1f173eb51db0dc78536334729ef832c62d6c65a
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH 1/1] crypto: atmel-sha204a - fix heap info leak on I2C transfer failure
From: Thorsten Blum @ 2026-05-31 14:02 UTC (permalink / raw)
  To: Lothar Rubusch
  Cc: herbert, davem, nicolas.ferre, alexandre.belloni, claudiu.beznea,
	ardb, krzk+dt, linux-crypto, linux-arm-kernel, linux-kernel
In-Reply-To: <20260529094336.33809-1-l.rubusch@gmail.com>

On Fri, May 29, 2026 at 09:43:36AM +0000, Lothar Rubusch wrote:
> When a non-blocking read operation is requested, the driver dynamically
> allocates memory to track asynchronous transfer status. If the underlying
> I2C transmission fails, atmel_sha204a_rng_done() logs a rate-limited
> warning but incorrectly proceeds to cache the pointer to this uninitialized
> buffer inside the rng->priv data field anyway.

The buffer is not necessarily uninitialized. cmd.data could also contain
a device error/status response or stale data from a previous request. An
uninitialized buffer is only one possibility.

Also, "rng->priv data field" is a bit confusing; maybe say that the
callback caches the work_data pointer in rng->priv instead?

> On subsequent execution passes, atmel_sha204a_rng_read_nonblocking()
> detects the stale rng->priv value, skips executing a hardware data read,

The cache-hit path still queues a new async read request and copies
invalid/stale data, but "skips a hardware data read" is probably not
correct. Did you mean the returned bytes aren't from a successful read?

> and copies up to 32 bytes of uninitialized kernel heap data from this
> garbage memory pool straight back into the system's hwrng data stream.

Same as above: it's not necessarily garbage or uninitialized data.

> Fix this information disclosure vector by immediately releasing the
> allocated asynchronous work data buffer and explicitly clearing the
> tracking pointer context whenever an I2C transaction returns a non-zero
> error status.
> 
> Additionally, duplicate the tfm counter decrement within the new error
> path to ensure the reference counter is properly released before executing
> the early return, maintaining the driver's availability for subsequent
> requests.
> 
> Fixes: da001fb651b0 ("crypto: atmel-i2c - add support for SHA204A random number generator")
> Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
> ---
>  drivers/crypto/atmel-sha204a.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
> index 4c9af737b33a..20cd915ea8a3 100644
> --- a/drivers/crypto/atmel-sha204a.c
> +++ b/drivers/crypto/atmel-sha204a.c
> @@ -31,10 +31,15 @@ static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,
>  	struct atmel_i2c_client_priv *i2c_priv = work_data->ctx;
>  	struct hwrng *rng = areq;
>  
> -	if (status)
> +	if (status) {
>  		dev_warn_ratelimited(&i2c_priv->client->dev,
>  				     "i2c transaction failed (%d)\n",
>  				     status);
> +		kfree(work_data);
> +		rng->priv = 0;

Setting rng->priv = 0 is redundant here. rng_read_nonblocking() already
clears it before enqueuing new work, and the ->tfm_count gate prevents
others from setting it.

> +		atomic_dec(&i2c_priv->tfm_count);
> +		return;
> +	}
>  
>  	rng->priv = (unsigned long)work_data;
>  	atomic_dec(&i2c_priv->tfm_count);
> 
> base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e

The fix itself looks good to me.

For a v2, could you please reword the commit message to be more precise,
and ideally drop the redundant rng->priv assignment? And feel free to
add a stable tag, as this should probably be backported.

With the above addressed, feel free to add:

Reviewed-by: Thorsten Blum <thorsten.blum@linux.dev>

Thanks,
Thorsten

^ permalink raw reply

* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Aleksander Jan Bajkowski @ 2026-05-31 10:15 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-crypto, Herbert Xu, Christian Lamparter, linuxppc-dev,
	linux-kernel, stable
In-Reply-To: <20260530192630.GB6807@quark>

Hi Eric,

On 30/05/2026 21:26, Eric Biggers wrote:
> On Sat, May 30, 2026 at 05:05:19PM +0200, Aleksander Jan Bajkowski wrote:
>> Hi Eric,
>>
>> On 30/05/2026 00:04, Eric Biggers wrote:
>>> Remove crypto4xx_rng, as it is insecure and unused:
>>>
>>> - It has only a 64-bit security strength, which is highly inadequate.
>>>     This can be seen by the fact that crypto4xx_hw_init() seeds it with
>>>     only 64 bits of entropy, and the fact that the original commit
>>>     mentions that it implements ANSI X9.17 Annex C.
>> In addition to a seed, the PRNG also uses ring oscillators as sources of
>> entropy. The entropy should be higher than 64b. This is the Rambus EIP-73d
>> IP core. The same IP core is built into eip93 (EIP-73a), eip97 (EIP-73d),
>> and eip197 (EIP-73d). You can find the documentation online. The complete
>> "container" is actually Rambus EIP-94, and one of its parts is EIP-73d.
> Just because it may have another source of entropy doesn't mean its
> security strength is higher than 64 bits.
>
> I cannot find any documentation other than
> https://datasheet.octopart.com/PPC460EX-SUB800T-AMCC-datasheet-11553412.pdf
> which says "ANSI X9.17 Annex C compliant using a DES algorithm".
>
> DES actually has a 56-bit key, so maybe I was over-generous.
>
> And according to https://cacr.uwaterloo.ca/hac/about/chap5.pdf ANSI
> X9.17 has only a 64-bit state anyway.  So even if we assume the
> datasheet is incorrect and the algorithm is actually 3DES which has a
> longer key, the state is likely still 64-bit.
According to the datasheet, there is no second source of entropy. The PRNG
has three built-in LFSRs. Each of them can be initialized independently. The
first LFSR is used to generate input data. The second and third are used to
generate keys for DES encryption. The output of the first LFSR is encrypted
using 3DES with two 64-bit keys. Between individual DES operations, data is
XORed with the seed. It sounds like a fairly secure design if properly 
reseeded.
There is also a newer design (EIP73a) based on the same algorithm. The
only difference is the replacing of 3DES with AES using a 2TDEA scheme.
The DES-based variant is more widely used, even in new SoCs.
>
> So it isn't looking good.  And since it's an undocumented proprietary
> design it shouldn't be given the benefit of the doubt either.
>
As I mentioned earlier, this IP core is quite well documented[1] (page 198).
Half of all SOHO routers have the EIP-73d built in. The algorithm is also
described in TRM for some of these SoCs :)

List od SoCs with EIP-73d:
AMCC PPC405EX/PPC460EX,
Intel/Maxlinear GRX350, URX850,
Marvell Armada 37x0, 7k, 8k,
Mediatek MT7623/MT7981/MT7986/MT7987/MT7988,
Qualcomm IPQ975x.

[1] 
https://www.scribd.com/document/734250956/Safexcel-Ip-94-Plb-Sas-v1-5?_gl=1*dng4pf*_up*MQ..*_ga*OTQ4NjkzMTAxLjE3ODAyMjA4ODI.*_ga_Z4ZC50DED6*czE3ODAyMjA4ODEkbzEkZzEkdDE3ODAyMjA4ODEkajYwJGwwJGgw*_ga_8KZ8BV0P5W*czE3ODAyMjA4ODEkbzEkZzEkdDE3ODAyMjA4ODEkajYwJGwwJGgw

Best regards,
Aleksander


^ permalink raw reply

* Re: [PATCH 1/4] dt-bindings: crypto: rockchip: Add RK356x/RK3588 crypto engine binding
From: Rob Herring (Arm) @ 2026-05-30 20:48 UTC (permalink / raw)
  To: Dawid Olesinski
  Cc: devicetree, clabbe, linux-rockchip, heiko, linux-arm-kernel,
	krzk+dt, conor+dt, davem, linux-kernel, linux-crypto, herbert
In-Reply-To: <20260530160704.3453555-2-dawidro@gmail.com>


On Sat, 30 May 2026 17:06:42 +0100, Dawid Olesinski wrote:
> Add a YAML device tree binding for the Rockchip second-generation (V2)
> cryptographic hardware accelerator present on the RK3568 and RK3588 SoCs.
> 
> The IP block exposes AES-ECB, AES-CBC, AES-XTS block ciphers, SHA-1,
> SHA-224, SHA-256, SHA-384, SHA-512, MD5, and SM3 hash algorithms, each
> with a hardware DMA engine controlled via linked-list descriptors.
> 
> The binding covers two compatible strings:
> 
>   - rockchip,rk3568-crypto: clocks and resets are driven directly by the
>     non-secure CRU (accessible to Linux at EL1).
>   - rockchip,rk3588-crypto: clocks and resets live in SECURECRU, a
>     register bank sandboxed to TrustZone. Linux must request them through
>     the ARM SCMI firmware interface (scmi_clk / scmi_reset), as direct
>     MMIO access to SECURECRU from EL1 triggers a bus fault.
> 
> Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
> ---
>  .../crypto/rockchip,rk3588-crypto.yaml        | 69 +++++++++++++++++++
>  1 file changed, 69 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Lexical error: Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.example.dts:30.33-49 Unexpected 'SCMI_CRYPTO_CORE'
Lexical error: Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.example.dts:31.33-52 Unexpected 'SCMI_ACLK_SECURE_NS'
Lexical error: Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.example.dts:32.33-52 Unexpected 'SCMI_HCLK_SECURE_NS'
Lexical error: Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.example.dts:34.35-56 Unexpected 'SCMI_SRST_CRYPTO_CORE'
FATAL ERROR: Syntax error parsing input tree
make[2]: *** [scripts/Makefile.dtbs:140: Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.example.dtb] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1660: dt_binding_check] Error 2
make: *** [Makefile:248: __sub-make] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20260530160704.3453555-2-dawidro@gmail.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply

* [PATCH 2/2] hwrng: hisi-trng - Move hisi-trng into drivers/char/hw_random/
From: Eric Biggers @ 2026-05-30 20:26 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: Olivia Mackall, Weili Qian, Wei Xu, Longfang Liu,
	linux-arm-kernel, linux-kernel, Eric Biggers
In-Reply-To: <20260530202624.20768-1-ebiggers@kernel.org>

Since this file just implements a hwrng driver, move it into
drivers/char/hw_random/.  Rename the kconfig option accordingly as well.

Note that this moves the file back to its original location.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 MAINTAINERS                                            |  2 +-
 arch/arm64/configs/defconfig                           |  2 +-
 drivers/char/hw_random/Kconfig                         | 10 ++++++++++
 drivers/char/hw_random/Makefile                        |  1 +
 .../trng/trng.c => char/hw_random/hisi-trng-v2.c}      |  0
 drivers/crypto/hisilicon/Kconfig                       |  7 -------
 drivers/crypto/hisilicon/Makefile                      |  1 -
 drivers/crypto/hisilicon/trng/Makefile                 |  2 --
 8 files changed, 13 insertions(+), 12 deletions(-)
 rename drivers/{crypto/hisilicon/trng/trng.c => char/hw_random/hisi-trng-v2.c} (100%)
 delete mode 100644 drivers/crypto/hisilicon/trng/Makefile

diff --git a/MAINTAINERS b/MAINTAINERS
index 882214b0e7db..dcbbc56368be 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11703,11 +11703,11 @@ F:	Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
 F:	drivers/mfd/hi6421-spmi-pmic.c
 
 HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
 M:	Weili Qian <qianweili@huawei.com>
 S:	Maintained
-F:	drivers/crypto/hisilicon/trng/trng.c
+F:	drivers/char/hw_random/hisi-trng-v2.c
 
 HISILICON V3XX SPI NOR FLASH Controller Driver
 M:	Yang Shen <shenyang39@huawei.com>
 S:	Maintained
 W:	http://www.hisilicon.com
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index bb930cce7233..9aa62b675023 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -548,10 +548,11 @@ CONFIG_VIRTIO_CONSOLE=y
 CONFIG_IPMI_HANDLER=m
 CONFIG_IPMI_DEVICE_INTERFACE=m
 CONFIG_IPMI_SI=m
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_HW_RANDOM_HISI_TRNG=m
 CONFIG_HW_RANDOM_QCOM=m
 CONFIG_TCG_TPM=y
 CONFIG_TCG_TIS=m
 CONFIG_TCG_TIS_SPI=m
 CONFIG_TCG_TIS_SPI_CR50=y
@@ -1960,11 +1961,10 @@ CONFIG_CRYPTO_DEV_ZYNQMP_AES=m
 CONFIG_CRYPTO_DEV_ZYNQMP_SHA3=m
 CONFIG_CRYPTO_DEV_CCREE=m
 CONFIG_CRYPTO_DEV_HISI_SEC2=m
 CONFIG_CRYPTO_DEV_HISI_ZIP=m
 CONFIG_CRYPTO_DEV_HISI_HPRE=m
-CONFIG_CRYPTO_DEV_HISI_TRNG=m
 CONFIG_CRYPTO_DEV_SA2UL=m
 CONFIG_DMA_RESTRICTED_POOL=y
 CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_KERNEL=y
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 7102e03dcf0a..6d8012d55ac0 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -371,10 +371,20 @@ config HW_RANDOM_HISTB
 	  Generator hardware found on Hisilicon Hi37xx SoC.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called histb-rng.
 
+config HW_RANDOM_HISI_TRNG
+	tristate "HiSilicon True Random Number Generator support"
+	depends on ARM64 && ACPI
+	help
+	  This driver provides kernel-side support for the True Random Number
+	  Generator hardware found on some HiSilicon SoCs.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called hisi-trng-v2.
+
 config HW_RANDOM_ST
 	tristate "ST Microelectronics HW Random Number Generator support"
 	depends on ARCH_STI || COMPILE_TEST
 	help
 	  This driver provides kernel-side support for the Random Number
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 605ba8df5a8f..f2888524b6ef 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -29,10 +29,11 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
 obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
 obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
 obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_HISI)	+= hisi-rng.o
 obj-$(CONFIG_HW_RANDOM_HISTB) += histb-rng.o
+obj-$(CONFIG_HW_RANDOM_HISI_TRNG) += hisi-trng-v2.o
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
 obj-$(CONFIG_HW_RANDOM_BCM74110) += bcm74110-rng.o
 obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
 obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o
 obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/char/hw_random/hisi-trng-v2.c
similarity index 100%
rename from drivers/crypto/hisilicon/trng/trng.c
rename to drivers/char/hw_random/hisi-trng-v2.c
diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig
index 8aa23c939775..aeff08ccbadd 100644
--- a/drivers/crypto/hisilicon/Kconfig
+++ b/drivers/crypto/hisilicon/Kconfig
@@ -73,12 +73,5 @@ config CRYPTO_DEV_HISI_HPRE
 	select CRYPTO_RSA
 	select CRYPTO_ECDH
 	help
 	  Support for HiSilicon HPRE(High Performance RSA Engine)
 	  accelerator, which can accelerate RSA and DH algorithms.
-
-config CRYPTO_DEV_HISI_TRNG
-	tristate "Support for HISI TRNG Driver"
-	depends on ARM64 && ACPI
-	select HW_RANDOM
-	help
-	  Support for HiSilicon TRNG Driver.
diff --git a/drivers/crypto/hisilicon/Makefile b/drivers/crypto/hisilicon/Makefile
index 8595a5a5d228..e1068ee9f973 100644
--- a/drivers/crypto/hisilicon/Makefile
+++ b/drivers/crypto/hisilicon/Makefile
@@ -3,6 +3,5 @@ obj-$(CONFIG_CRYPTO_DEV_HISI_HPRE) += hpre/
 obj-$(CONFIG_CRYPTO_DEV_HISI_SEC) += sec/
 obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += sec2/
 obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += hisi_qm.o
 hisi_qm-objs = qm.o sgl.o debugfs.o
 obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += zip/
-obj-$(CONFIG_CRYPTO_DEV_HISI_TRNG) += trng/
diff --git a/drivers/crypto/hisilicon/trng/Makefile b/drivers/crypto/hisilicon/trng/Makefile
deleted file mode 100644
index d909079f351c..000000000000
--- a/drivers/crypto/hisilicon/trng/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_CRYPTO_DEV_HISI_TRNG) += hisi-trng-v2.o
-hisi-trng-v2-objs = trng.o
-- 
2.54.0


^ permalink raw reply related

* [PATCH 1/2] crypto: hisi-trng - Remove crypto_rng interface
From: Eric Biggers @ 2026-05-30 20:26 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: Olivia Mackall, Weili Qian, Wei Xu, Longfang Liu,
	linux-arm-kernel, linux-kernel, Eric Biggers, stable
In-Reply-To: <20260530202624.20768-1-ebiggers@kernel.org>

drivers/crypto/hisilicon/trng/trng.c exposes the same hardware through
two completely separate interfaces, crypto_rng and hwrng.  However, the
implementation of this is buggy because it permits generation operations
from these interfaces to run concurrently with each other, accessing the
same registers.  That is, hisi_trng_generate() synchronizes with itself
but not with hisi_trng_read().  This results in potential repetition of
output from the RNG, output of non-random values, etc.

Fortunately, there's actually no point in hardware RNG drivers
implementing the crypto_rng interface.  It's not actually used by
anything besides the "rng" algorithm type of AF_ALG, which in turn is
not actually used in practice.  Other crypto_rng hardware drivers are
likewise being phased out, leaving just the hwrng support.

Thus, remove it to simplify the code and avoid conflict (and confusion)
with the hwrng interface which is the one that actually matters.

Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 drivers/crypto/hisilicon/Kconfig     |   1 -
 drivers/crypto/hisilicon/trng/trng.c | 296 +--------------------------
 2 files changed, 2 insertions(+), 295 deletions(-)

diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig
index 1e6d772f4bb6..8aa23c939775 100644
--- a/drivers/crypto/hisilicon/Kconfig
+++ b/drivers/crypto/hisilicon/Kconfig
@@ -78,8 +78,7 @@ config CRYPTO_DEV_HISI_HPRE
 
 config CRYPTO_DEV_HISI_TRNG
 	tristate "Support for HISI TRNG Driver"
 	depends on ARM64 && ACPI
 	select HW_RANDOM
-	select CRYPTO_RNG
 	help
 	  Support for HiSilicon TRNG Driver.
diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c
index 5ca0b90859a8..6584ed051e09 100644
--- a/drivers/crypto/hisilicon/trng/trng.c
+++ b/drivers/crypto/hisilicon/trng/trng.c
@@ -1,236 +1,29 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright (c) 2019 HiSilicon Limited. */
 
-#include <crypto/internal/rng.h>
 #include <linux/acpi.h>
-#include <linux/crypto.h>
 #include <linux/err.h>
 #include <linux/hw_random.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
-#include <linux/list.h>
 #include <linux/module.h>
-#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/random.h>
 
 #define HISI_TRNG_REG		0x00F0
 #define HISI_TRNG_BYTES		4
 #define HISI_TRNG_QUALITY	512
-#define HISI_TRNG_VERSION	0x01B8
-#define HISI_TRNG_VER_V1	GENMASK(31, 0)
 #define SLEEP_US		10
 #define TIMEOUT_US		10000
-#define SW_DRBG_NUM_SHIFT	2
-#define SW_DRBG_KEY_BASE	0x082C
-#define SW_DRBG_SEED(n)         (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT))
-#define SW_DRBG_SEED_REGS_NUM	12
-#define SW_DRBG_SEED_SIZE	48
-#define SW_DRBG_BLOCKS		0x0830
-#define SW_DRBG_INIT		0x0834
-#define SW_DRBG_GEN		0x083c
-#define SW_DRBG_STATUS		0x0840
-#define SW_DRBG_BLOCKS_NUM	4095
-#define SW_DRBG_DATA_BASE	0x0850
-#define SW_DRBG_DATA_NUM	4
-#define SW_DRBG_DATA(n)		(SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT))
-#define SW_DRBG_BYTES		16
-#define SW_DRBG_ENABLE_SHIFT	12
-#define SEED_SHIFT_24		24
-#define SEED_SHIFT_16		16
-#define SEED_SHIFT_8		8
-#define SW_MAX_RANDOM_BYTES	65520
-
-struct hisi_trng_list {
-	struct mutex lock;
-	struct list_head list;
-	bool is_init;
-};
 
 struct hisi_trng {
 	void __iomem *base;
-	struct hisi_trng_list *trng_list;
-	struct list_head list;
 	struct hwrng rng;
-	u32 ver;
-	u32 ctx_num;
-	/* The bytes of the random number generated since the last seeding. */
-	u32 random_bytes;
-	struct mutex lock;
-};
-
-struct hisi_trng_ctx {
-	struct hisi_trng *trng;
 };
 
-static atomic_t trng_active_devs;
-static struct hisi_trng_list trng_devices;
-static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait);
-
-static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
-{
-	u32 val, seed_reg, i;
-	int ret;
-
-	writel(0x0, trng->base + SW_DRBG_BLOCKS);
-
-	for (i = 0; i < SW_DRBG_SEED_SIZE;
-	     i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
-		val = seed[i] << SEED_SHIFT_24;
-		val |= seed[i + 1UL] << SEED_SHIFT_16;
-		val |= seed[i + 2UL] << SEED_SHIFT_8;
-		val |= seed[i + 3UL];
-
-		seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
-		writel(val, trng->base + SW_DRBG_SEED(seed_reg));
-	}
-
-	writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
-	       trng->base + SW_DRBG_BLOCKS);
-	writel(0x1, trng->base + SW_DRBG_INIT);
-	ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
-					 val, val & BIT(0), SLEEP_US, TIMEOUT_US);
-	if (ret) {
-		pr_err("failed to init trng(%d)\n", ret);
-		return -EIO;
-	}
-
-	trng->random_bytes = 0;
-
-	return 0;
-}
-
-static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
-			  unsigned int slen)
-{
-	struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
-	struct hisi_trng *trng = ctx->trng;
-	int ret;
-
-	if (slen < SW_DRBG_SEED_SIZE) {
-		pr_err("slen(%u) is not matched with trng(%d)\n", slen,
-			SW_DRBG_SEED_SIZE);
-		return -EINVAL;
-	}
-
-	mutex_lock(&trng->lock);
-	ret = hisi_trng_set_seed(trng, seed);
-	mutex_unlock(&trng->lock);
-
-	return ret;
-}
-
-static int hisi_trng_reseed(struct hisi_trng *trng)
-{
-	u8 seed[SW_DRBG_SEED_SIZE];
-	int size;
-
-	if (!trng->random_bytes)
-		return 0;
-
-	size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false);
-	if (size != SW_DRBG_SEED_SIZE)
-		return -EIO;
-
-	return hisi_trng_set_seed(trng, seed);
-}
-
-static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen)
-{
-	u32 data[SW_DRBG_DATA_NUM];
-	u32 currsize = 0;
-	u32 val = 0;
-	int ret;
-	u32 i;
-
-	ret = hisi_trng_reseed(trng);
-	if (ret)
-		return ret;
-
-	do {
-		ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
-						 val, val & BIT(1), SLEEP_US, TIMEOUT_US);
-		if (ret) {
-			pr_err("failed to generate random number(%d)!\n", ret);
-			break;
-		}
-
-		for (i = 0; i < SW_DRBG_DATA_NUM; i++)
-			data[i] = readl(trng->base + SW_DRBG_DATA(i));
-
-		if (dlen - currsize >= SW_DRBG_BYTES) {
-			memcpy(dstn + currsize, data, SW_DRBG_BYTES);
-			currsize += SW_DRBG_BYTES;
-		} else {
-			memcpy(dstn + currsize, data, dlen - currsize);
-			currsize = dlen;
-		}
-
-		trng->random_bytes += SW_DRBG_BYTES;
-		writel(0x1, trng->base + SW_DRBG_GEN);
-	} while (currsize < dlen);
-
-	return ret;
-}
-
-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
-			      unsigned int slen, u8 *dstn, unsigned int dlen)
-{
-	struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
-	struct hisi_trng *trng = ctx->trng;
-	unsigned int currsize = 0;
-	unsigned int block_size;
-	int ret;
-
-	if (!dstn || !dlen) {
-		pr_err("output is error, dlen %u!\n", dlen);
-		return -EINVAL;
-	}
-
-	do {
-		block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES);
-		mutex_lock(&trng->lock);
-		ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size);
-		mutex_unlock(&trng->lock);
-		if (ret)
-			return ret;
-		currsize += block_size;
-	} while (currsize < dlen);
-
-	return 0;
-}
-
-static int hisi_trng_init(struct crypto_tfm *tfm)
-{
-	struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
-	struct hisi_trng *trng;
-	u32 ctx_num = ~0;
-
-	mutex_lock(&trng_devices.lock);
-	list_for_each_entry(trng, &trng_devices.list, list) {
-		if (trng->ctx_num < ctx_num) {
-			ctx_num = trng->ctx_num;
-			ctx->trng = trng;
-		}
-	}
-	ctx->trng->ctx_num++;
-	mutex_unlock(&trng_devices.lock);
-
-	return 0;
-}
-
-static void hisi_trng_exit(struct crypto_tfm *tfm)
-{
-	struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
-
-	mutex_lock(&trng_devices.lock);
-	ctx->trng->ctx_num--;
-	mutex_unlock(&trng_devices.lock);
-}
-
 static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
 {
 	struct hisi_trng *trng;
 	int currsize = 0;
 	u32 val = 0;
@@ -258,126 +51,41 @@ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
 	} while (currsize < max);
 
 	return currsize;
 }
 
-static struct rng_alg hisi_trng_alg = {
-	.generate = hisi_trng_generate,
-	.seed =	hisi_trng_seed,
-	.seedsize = SW_DRBG_SEED_SIZE,
-	.base = {
-		.cra_name = "stdrng",
-		.cra_driver_name = "hisi_stdrng",
-		.cra_priority = 300,
-		.cra_ctxsize = sizeof(struct hisi_trng_ctx),
-		.cra_module = THIS_MODULE,
-		.cra_init = hisi_trng_init,
-		.cra_exit = hisi_trng_exit,
-	},
-};
-
-static void hisi_trng_add_to_list(struct hisi_trng *trng)
-{
-	mutex_lock(&trng_devices.lock);
-	list_add_tail(&trng->list, &trng_devices.list);
-	mutex_unlock(&trng_devices.lock);
-}
-
-static int hisi_trng_del_from_list(struct hisi_trng *trng)
-{
-	int ret = -EBUSY;
-
-	mutex_lock(&trng_devices.lock);
-	if (!trng->ctx_num) {
-		list_del(&trng->list);
-		ret = 0;
-	}
-	mutex_unlock(&trng_devices.lock);
-
-	return ret;
-}
-
 static int hisi_trng_probe(struct platform_device *pdev)
 {
 	struct hisi_trng *trng;
 	int ret;
 
 	trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
 	if (!trng)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, trng);
-
 	trng->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(trng->base))
 		return PTR_ERR(trng->base);
 
-	trng->ctx_num = 0;
-	trng->random_bytes = SW_MAX_RANDOM_BYTES;
-	mutex_init(&trng->lock);
-	trng->ver = readl(trng->base + HISI_TRNG_VERSION);
-	if (!trng_devices.is_init) {
-		INIT_LIST_HEAD(&trng_devices.list);
-		mutex_init(&trng_devices.lock);
-		trng_devices.is_init = true;
-	}
-
-	hisi_trng_add_to_list(trng);
-	if (trng->ver != HISI_TRNG_VER_V1 &&
-	    atomic_inc_return(&trng_active_devs) == 1) {
-		ret = crypto_register_rng(&hisi_trng_alg);
-		if (ret) {
-			dev_err(&pdev->dev,
-				"failed to register crypto(%d)\n", ret);
-			atomic_dec_return(&trng_active_devs);
-			goto err_remove_from_list;
-		}
-	}
-
 	trng->rng.name = pdev->name;
 	trng->rng.read = hisi_trng_read;
 	trng->rng.quality = HISI_TRNG_QUALITY;
+
 	ret = devm_hwrng_register(&pdev->dev, &trng->rng);
-	if (ret) {
+	if (ret)
 		dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret);
-		goto err_crypto_unregister;
-	}
-
-	return ret;
-
-err_crypto_unregister:
-	if (trng->ver != HISI_TRNG_VER_V1 &&
-	    atomic_dec_return(&trng_active_devs) == 0)
-		crypto_unregister_rng(&hisi_trng_alg);
-
-err_remove_from_list:
-	hisi_trng_del_from_list(trng);
 	return ret;
 }
 
-static void hisi_trng_remove(struct platform_device *pdev)
-{
-	struct hisi_trng *trng = platform_get_drvdata(pdev);
-
-	/* Wait until the task is finished */
-	while (hisi_trng_del_from_list(trng))
-		;
-
-	if (trng->ver != HISI_TRNG_VER_V1 &&
-	    atomic_dec_return(&trng_active_devs) == 0)
-		crypto_unregister_rng(&hisi_trng_alg);
-}
-
 static const struct acpi_device_id hisi_trng_acpi_match[] = {
 	{ "HISI02B3", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
 
 static struct platform_driver hisi_trng_driver = {
 	.probe		= hisi_trng_probe,
-	.remove         = hisi_trng_remove,
 	.driver		= {
 		.name	= "hisi-trng-v2",
 		.acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
 	},
 };
-- 
2.54.0


^ permalink raw reply related

* [PATCH 0/2] HiSilicon TRNG fix and simplification
From: Eric Biggers @ 2026-05-30 20:26 UTC (permalink / raw)
  To: linux-crypto, Herbert Xu
  Cc: Olivia Mackall, Weili Qian, Wei Xu, Longfang Liu,
	linux-arm-kernel, linux-kernel, Eric Biggers

This series fixes and greatly simplifies the HiSilicon TRNG driver by
removing the gratuitous crypto_rng interface, leaving just hwrng which
is the one that actually matters.

Note that this mirrors similar changes in other drivers such as qcom-rng
(https://lore.kernel.org/r/20260530020332.143058-1-ebiggers@kernel.org)

Eric Biggers (2):
  crypto: hisi-trng - Remove crypto_rng interface
  hwrng: hisi-trng - Move hisi-trng into drivers/char/hw_random/

 MAINTAINERS                            |   2 +-
 arch/arm64/configs/defconfig           |   2 +-
 drivers/char/hw_random/Kconfig         |  10 +
 drivers/char/hw_random/Makefile        |   1 +
 drivers/char/hw_random/hisi-trng-v2.c  |  98 +++++++
 drivers/crypto/hisilicon/Kconfig       |   8 -
 drivers/crypto/hisilicon/Makefile      |   1 -
 drivers/crypto/hisilicon/trng/Makefile |   2 -
 drivers/crypto/hisilicon/trng/trng.c   | 390 -------------------------
 9 files changed, 111 insertions(+), 403 deletions(-)
 create mode 100644 drivers/char/hw_random/hisi-trng-v2.c
 delete mode 100644 drivers/crypto/hisilicon/trng/Makefile
 delete mode 100644 drivers/crypto/hisilicon/trng/trng.c


base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
prerequisite-patch-id: 07e982b663ac3f8312ca524f6b91b5b38661df5e
prerequisite-patch-id: 72064361a8f36e015ab0b7e1fa4d364b40d90506
prerequisite-patch-id: 8978b8e0db7f47935e5f6f0aff14a97f55d3073c
prerequisite-patch-id: 6aa0e3e93a008279d71e535a3d0cf48643f55e19
-- 
2.54.0


^ permalink raw reply

* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Eric Biggers @ 2026-05-30 19:26 UTC (permalink / raw)
  To: Aleksander Jan Bajkowski
  Cc: linux-crypto, Herbert Xu, Christian Lamparter, linuxppc-dev,
	linux-kernel, stable
In-Reply-To: <5c74c261-53cf-4185-a8a0-7554bc9fe5f7@wp.pl>

On Sat, May 30, 2026 at 05:05:19PM +0200, Aleksander Jan Bajkowski wrote:
> Hi Eric,
> 
> On 30/05/2026 00:04, Eric Biggers wrote:
> > Remove crypto4xx_rng, as it is insecure and unused:
> > 
> > - It has only a 64-bit security strength, which is highly inadequate.
> >    This can be seen by the fact that crypto4xx_hw_init() seeds it with
> >    only 64 bits of entropy, and the fact that the original commit
> >    mentions that it implements ANSI X9.17 Annex C.
> 
> In addition to a seed, the PRNG also uses ring oscillators as sources of
> entropy. The entropy should be higher than 64b. This is the Rambus EIP-73d
> IP core. The same IP core is built into eip93 (EIP-73a), eip97 (EIP-73d),
> and eip197 (EIP-73d). You can find the documentation online. The complete
> "container" is actually Rambus EIP-94, and one of its parts is EIP-73d.

Just because it may have another source of entropy doesn't mean its
security strength is higher than 64 bits.

I cannot find any documentation other than
https://datasheet.octopart.com/PPC460EX-SUB800T-AMCC-datasheet-11553412.pdf
which says "ANSI X9.17 Annex C compliant using a DES algorithm".

DES actually has a 56-bit key, so maybe I was over-generous.

And according to https://cacr.uwaterloo.ca/hac/about/chap5.pdf ANSI
X9.17 has only a 64-bit state anyway.  So even if we assume the
datasheet is incorrect and the algorithm is actually 3DES which has a
longer key, the state is likely still 64-bit.

So it isn't looking good.  And since it's an undocumented proprietary
design it shouldn't be given the benefit of the doubt either.

> This PRNG is also used internally for Generation IV with IPSEC offload. The
> IPSEC offload implementation for eip93 was recently submitted to upstream.
> I am not sure whether eip94 shares some of the logic for IPSEC offload and
> it will be possible to use some of the code.

That's not related to this patch.

- Eric

^ permalink raw reply

* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Eric Biggers @ 2026-05-30 19:12 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: linux-crypto, Herbert Xu, linuxppc-dev, linux-kernel, stable
In-Reply-To: <e0b3cfc2-c6da-46d4-9dec-027dafaba74e@gmail.com>

On Sat, May 30, 2026 at 12:20:57PM +0200, Christian Lamparter wrote:
> > diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
> > index 1038061224da..73d626308a84 100644
> > --- a/drivers/crypto/amcc/crypto4xx_reg_def.h
> > +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
> > @@ -88,24 +88,13 @@
> >   #define CRYPTO4XX_DMA_CFG	        	0x000600d4
> >   #define CRYPTO4XX_BYTE_ORDER_CFG 		0x000600d8
> >   #define CRYPTO4XX_ENDIAN_CFG			0x000600d8
> > -#define CRYPTO4XX_PRNG_STAT			0x00070000
> > -#define CRYPTO4XX_PRNG_STAT_BUSY		0x1
> >   #define CRYPTO4XX_PRNG_CTRL			0x00070004
> >   #define CRYPTO4XX_PRNG_SEED_L			0x00070008
> >   #define CRYPTO4XX_PRNG_SEED_H			0x0007000c
> > -
> > -#define CRYPTO4XX_PRNG_RES_0			0x00070020
> > -#define CRYPTO4XX_PRNG_RES_1			0x00070024
> > -#define CRYPTO4XX_PRNG_RES_2			0x00070028
> > -#define CRYPTO4XX_PRNG_RES_3			0x0007002C
> > -
> > -#define CRYPTO4XX_PRNG_LFSR_L			0x00070030
> > -#define CRYPTO4XX_PRNG_LFSR_H			0x00070034
> > -
> 
> Hmm, don't think these defines will hurt anyone? As these are part of the hardware spec.
> Or do you forsee a future where AI-Agents will sent patches hallucinating that it "fixed"
> the issue which readds it? I have no idea.

Well, there's not really any point in keeping these when they aren't
used.

- Eric

^ permalink raw reply

* [PATCH 4/4] arm64: dts: rockchip: Add crypto node to rk3588-base
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
  To: herbert, davem, heiko
  Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
	clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
In-Reply-To: <20260530160704.3453555-1-dawidro@gmail.com>

Add the device tree node for the V2 cryptographic hardware accelerator
on RK3588.

On RK3588 the crypto IP sits inside the secure domain controlled by
SECURECRU, a register bank that is exclusively accessible to the
TrustZone firmware (TF-A). Linux must therefore obtain its clocks and
reset line through the ARM SCMI interface provided by the firmware
rather than mapping the CRU registers directly. Attempting direct MMIO
access to SECURECRU from the non-secure world triggers an asynchronous
bus fault.

The interrupt uses the four-cell GICv3 format as required by the RK3588
GIC node definition (the fourth cell is the CPU affinity/partition
specifier; 0 means no affinity constraint).

The node is disabled by default; board files that wish to use hardware
crypto offload must enable it.

Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index 4fb8888c281c..4f336741d11f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -2257,6 +2257,18 @@ rng@fe378000 {
 		resets = <&scmi_reset SCMI_SRST_H_TRNG_NS>;
 	};
 
+	crypto: crypto@fe370000 {
+		compatible = "rockchip,rk3588-crypto";
+		reg = <0x0 0xfe370000 0x0 0x2000>;
+		interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&scmi_clk SCMI_CRYPTO_CORE>, <&scmi_clk SCMI_ACLK_SECURE_NS>,
+			 <&scmi_clk SCMI_HCLK_SECURE_NS>;
+		clock-names = "core", "aclk", "hclk";
+		resets = <&scmi_reset SCMI_SRST_CRYPTO_CORE>;
+		reset-names = "core";
+		status = "disabled";
+	};
+
 	i2s0_8ch: i2s@fe470000 {
 		compatible = "rockchip,rk3588-i2s-tdm";
 		reg = <0x0 0xfe470000 0x0 0x1000>;
-- 
2.47.3


^ permalink raw reply related

* [PATCH 3/4] arm64: dts: rockchip: Add crypto node to rk356x-base
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
  To: herbert, davem, heiko
  Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
	clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
In-Reply-To: <20260530160704.3453555-1-dawidro@gmail.com>

Add the device tree node for the V2 cryptographic hardware accelerator
on RK356x SoCs (RK3566, RK3568).

The IP block sits in the non-secure peripheral domain. Its three clocks
(core, aclk, hclk) and reset line are accessible directly through the
main non-secure CRU, so no firmware intermediary is required.

The node is disabled by default; board files that wish to use hardware
crypto offload must enable it.

Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
index 64bdd8b7754b..3b73a56046e7 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
@@ -1171,6 +1171,18 @@ gpu_leakage: gpu-leakage@1d {
 		};
 	};
 
+	crypto: crypto@fe380000 {
+		compatible = "rockchip,rk3568-crypto";
+		reg = <0x0 0xfe380000 0x0 0x2000>;
+		interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru CLK_CRYPTO_NS_CORE>, <&cru ACLK_CRYPTO_NS>,
+			 <&cru HCLK_CRYPTO_NS>;
+		clock-names = "core", "aclk", "hclk";
+		resets = <&cru SRST_CRYPTO_NS_CORE>;
+		reset-names = "core";
+		status = "disabled";
+	};
+
 	i2s0_8ch: i2s@fe400000 {
 		compatible = "rockchip,rk3568-i2s-tdm";
 		reg = <0x0 0xfe400000 0x0 0x1000>;
-- 
2.47.3


^ permalink raw reply related

* [PATCH 2/4] crypto: rockchip: Add RK356x/RK3588 cryptographic offloader driver
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
  To: herbert, davem, heiko
  Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
	clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
In-Reply-To: <20260530160704.3453555-1-dawidro@gmail.com>

Add a driver for the second-generation Rockchip cryptographic hardware
accelerator found on RK3568 and RK3588 SoCs (compatible strings
"rockchip,rk3568-crypto" and "rockchip,rk3588-crypto").

The hardware provides:
  - AES block cipher engine: ECB, CBC, and XTS modes, 128/192/256-bit
    keys. XTS hardware is limited to single-SG requests.
  - Hash engine: SHA-1, SHA-256, SHA-384, SHA-512, MD5, SM3.
    The hardware padding engine (HW_PAD) requires the total message
    length upfront and cannot maintain state across LLI descriptor
    boundaries, so multi-SG and unaligned requests are routed to a
    software fallback.
  - DMA engine: linked-list descriptor (LLI) based, with a 20-entry
    coherent descriptor table.

Design overview:
  - Built on top of the crypto engine framework (crypto/engine.h) for
    serialised hardware request dispatch and automatic fallback handling.
  - Each platform device gets its own private copy of the algorithm
    descriptor table at probe time (devm_kmemdup), so the dev pointer in
    each template always refers to the correct hardware instance. This
    avoids a global device list without any locking overhead.
  - Runtime PM with autosuspend (2 s idle timeout) gates clocks and
    asserts reset between requests to save power.
  - Symmetric software fallback for all registered algorithms handles
    requests that cannot be processed in hardware (misaligned buffers,
    multi-SG inputs for hash, zero-length payloads).

Co-developed-by: Corentin Labbe <clabbe@baylibre.com>
Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
---
 drivers/crypto/Kconfig                        |  33 +
 drivers/crypto/Makefile                       |   1 +
 drivers/crypto/rockchip/Makefile              |   5 +
 drivers/crypto/rockchip/rk2_crypto.c          | 740 ++++++++++++++++++
 drivers/crypto/rockchip/rk2_crypto.h          | 243 ++++++
 drivers/crypto/rockchip/rk2_crypto_ahash.c    | 547 +++++++++++++
 drivers/crypto/rockchip/rk2_crypto_skcipher.c | 724 +++++++++++++++++
 7 files changed, 2293 insertions(+)
 create mode 100644 drivers/crypto/rockchip/rk2_crypto.c
 create mode 100644 drivers/crypto/rockchip/rk2_crypto.h
 create mode 100644 drivers/crypto/rockchip/rk2_crypto_ahash.c
 create mode 100644 drivers/crypto/rockchip/rk2_crypto_skcipher.c

diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index d23b58b81ca3..47a891593814 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -709,6 +709,39 @@ config CRYPTO_DEV_ROCKCHIP_DEBUG
 	  This will create /sys/kernel/debug/rk3288_crypto/stats for displaying
 	  the number of requests per algorithm and other internal stats.
 
+config CRYPTO_DEV_ROCKCHIP2
+	tristate "Rockchip's cryptographic offloader"
+	depends on OF && ARCH_ROCKCHIP
+	depends on PM
+	select CRYPTO_ECB
+	select CRYPTO_CBC
+	select CRYPTO_AES
+	select CRYPTO_MD5
+	select CRYPTO_SHA1
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	select CRYPTO_SM3_GENERIC
+	select CRYPTO_HASH
+	select CRYPTO_XTS
+	select CRYPTO_SKCIPHER
+	select CRYPTO_ENGINE
+
+	help
+	  This driver interfaces with the hardware crypto offloader present
+	  on RK3566, RK3568 and RK3588 SoCs. It provides hardware acceleration
+	  for symmetric block ciphers and hashing functions, offloading the
+	  main CPU cores during heavy cryptographic workflows.
+
+config CRYPTO_DEV_ROCKCHIP2_DEBUG
+	bool "Enable Rockchip crypto stats"
+	depends on CRYPTO_DEV_ROCKCHIP2
+	depends on DEBUG_FS
+	help
+	  Say y to enable Rockchip crypto debug stats.
+	  This will create a directory using the device name
+	  (e.g., /sys/kernel/debug/fe370000.crypto/stats) for displaying
+	  the number of requests per algorithm and other internal stats.
+
 config CRYPTO_DEV_TEGRA
 	tristate "Enable Tegra Security Engine"
 	depends on TEGRA_HOST1X
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 283bbc650b5b..905538078017 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
 obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/
 obj-$(CONFIG_CRYPTO_DEV_QCOM_RNG) += qcom-rng.o
 obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/
+obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP2) += rockchip/
 obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
 obj-$(CONFIG_CRYPTO_DEV_SA2UL) += sa2ul.o
 obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile
index 785277aca71e..452a12ff6538 100644
--- a/drivers/crypto/rockchip/Makefile
+++ b/drivers/crypto/rockchip/Makefile
@@ -3,3 +3,8 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rk_crypto.o
 rk_crypto-objs := rk3288_crypto.o \
 		  rk3288_crypto_skcipher.o \
 		  rk3288_crypto_ahash.o
+
+obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP2) += rk_crypto2.o
+rk_crypto2-objs := rk2_crypto.o \
+		  rk2_crypto_skcipher.o \
+		  rk2_crypto_ahash.o
diff --git a/drivers/crypto/rockchip/rk2_crypto.c b/drivers/crypto/rockchip/rk2_crypto.c
new file mode 100644
index 000000000000..df7dab4d7ca0
--- /dev/null
+++ b/drivers/crypto/rockchip/rk2_crypto.c
@@ -0,0 +1,740 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * hardware cryptographic offloader for RK3568/RK3588 SoC
+ *
+ * Copyright (c) 2022-2023, Corentin Labbe <clabbe@baylibre.com>
+ */
+
+#include "rk2_crypto.h"
+#include <linux/clk.h>
+#include <linux/crypto.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <crypto/aes.h>
+
+static const struct rk2_variant rk3568_variant = {
+	.num_clks = 3,
+};
+
+static const struct rk2_variant rk3588_variant = {
+	.num_clks = 3,
+};
+
+static int rk2_crypto_get_clks(struct rk2_crypto_dev *dev)
+{
+	dev->num_clks = devm_clk_bulk_get_all(dev->dev, &dev->clks);
+	if (dev->num_clks < 0)
+		return dev_err_probe(dev->dev, dev->num_clks, "Failed to get clocks\n");
+	if (dev->num_clks < dev->variant->num_clks)
+		return dev_err_probe(dev->dev, -EINVAL,
+				"Missing clocks, got %d instead of %d\n",
+				dev->num_clks, dev->variant->num_clks);
+	return 0;
+}
+
+static int rk2_crypto_pm_suspend(struct device *dev)
+{
+	struct rk2_crypto_dev *rkdev = dev_get_drvdata(dev);
+
+	reset_control_assert(rkdev->rst);
+	udelay(10);
+	clk_bulk_disable_unprepare(rkdev->num_clks, rkdev->clks);
+
+	return 0;
+}
+
+static int rk2_crypto_pm_resume(struct device *dev)
+{
+	struct rk2_crypto_dev *rkdev = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_bulk_prepare_enable(rkdev->num_clks, rkdev->clks);
+	if (ret)
+		return ret;
+
+	udelay(10);
+	reset_control_deassert(rkdev->rst);
+
+	return 0;
+}
+
+static const struct dev_pm_ops rk2_crypto_pm_ops = {
+	RUNTIME_PM_OPS(rk2_crypto_pm_suspend, rk2_crypto_pm_resume, NULL)
+};
+
+static int rk2_crypto_pm_init(struct rk2_crypto_dev *rkdev)
+{
+	int err;
+
+	pm_runtime_use_autosuspend(rkdev->dev);
+	pm_runtime_set_autosuspend_delay(rkdev->dev, 2000);
+
+	err = pm_runtime_set_suspended(rkdev->dev);
+	if (err)
+		return err;
+	pm_runtime_enable(rkdev->dev);
+
+	return 0;
+}
+
+static void rk2_crypto_pm_exit(struct rk2_crypto_dev *rkdev)
+{
+	pm_runtime_disable(rkdev->dev);
+}
+
+static irqreturn_t rk2_crypto_irq_handle(int irq, void *dev_id)
+{
+	struct rk2_crypto_dev *rkc = platform_get_drvdata(dev_id);
+	u32 v;
+
+	v = readl(rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+	if (!v)
+		return IRQ_NONE;
+
+	writel(v, rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+
+	/*
+	 * Only signal completion on list-done or hard DMA error.
+	 * Intermediate SRC_INT (BIT(1)/BIT(2)) fire for every LLI
+	 * entry that has RK2_LLI_DMA_CTRL_SRC_INT set. Completing
+	 * early on those causes the driver to read hash registers
+	 * before all data has been processed, producing wrong results.
+	 */
+	if (v & RK2_CRYPTO_DMA_INT_ERR_MASK) {
+		dev_warn(rkc->dev, "DMA Error\n");
+		rkc->status = 0;
+		complete(&rkc->complete);
+	} else if (v & RK2_CRYPTO_DMA_INT_LISTDONE) {
+		rkc->status = 1;
+		complete(&rkc->complete);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static const struct rk2_crypto_template rk2_crypto_algs_template[] = {
+	{
+	.type = CRYPTO_ALG_TYPE_SKCIPHER,
+	.rk2_mode = RK2_CRYPTO_AES_ECB,
+	.alg.skcipher.base = {
+			.base.cra_name = "ecb(aes)",
+			.base.cra_driver_name = "ecb-aes-rk2",
+			.base.cra_priority = 300,
+			.base.cra_flags =
+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+			.base.cra_blocksize = AES_BLOCK_SIZE,
+			.base.cra_ctxsize = sizeof(struct rk2_cipher_ctx),
+			.base.cra_alignmask = 0,
+			.base.cra_module = THIS_MODULE,
+			.init = rk2_cipher_tfm_init,
+			.exit = rk2_cipher_tfm_exit,
+			.min_keysize = AES_MIN_KEY_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE,
+			.setkey = rk2_aes_setkey,
+			.encrypt = rk2_skcipher_encrypt,
+			.decrypt = rk2_skcipher_decrypt,
+			},
+	.alg.skcipher.op = {
+		.do_one_request = rk2_cipher_run,
+		},
+	},
+	{
+	 .type = CRYPTO_ALG_TYPE_SKCIPHER,
+	 .rk2_mode = RK2_CRYPTO_AES_CBC,
+	 .alg.skcipher.base = {
+			.base.cra_name = "cbc(aes)",
+			.base.cra_driver_name = "cbc-aes-rk2",
+			.base.cra_priority = 300,
+			.base.cra_flags =
+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+			.base.cra_blocksize = AES_BLOCK_SIZE,
+			.base.cra_ctxsize =
+			sizeof(struct rk2_cipher_ctx),
+			.base.cra_alignmask = 0,
+			.base.cra_module = THIS_MODULE,
+			.init = rk2_cipher_tfm_init,
+			.exit = rk2_cipher_tfm_exit,
+			.min_keysize = AES_MIN_KEY_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE,
+			.ivsize = AES_BLOCK_SIZE,
+			.setkey = rk2_aes_setkey,
+			.encrypt = rk2_skcipher_encrypt,
+			.decrypt = rk2_skcipher_decrypt,
+			},
+	.alg.skcipher.op = {
+		.do_one_request = rk2_cipher_run,
+		},
+	},
+	{
+	.type = CRYPTO_ALG_TYPE_SKCIPHER,
+	.rk2_mode = RK2_CRYPTO_AES_XTS,
+	.is_xts = true,
+	.alg.skcipher.base = {
+			.base.cra_name = "xts(aes)",
+			.base.cra_driver_name = "xts-aes-rk2",
+			.base.cra_priority = 300,
+			.base.cra_flags =
+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+			.base.cra_blocksize = AES_BLOCK_SIZE,
+			.base.cra_ctxsize =
+			sizeof(struct rk2_cipher_ctx),
+			.base.cra_alignmask = 0,
+			.base.cra_module = THIS_MODULE,
+			.init = rk2_cipher_tfm_init,
+			.exit = rk2_cipher_tfm_exit,
+			.min_keysize = AES_MIN_KEY_SIZE * 2,
+			.max_keysize = AES_MAX_KEY_SIZE * 2,
+			.ivsize = AES_BLOCK_SIZE,
+			.setkey = rk2_aes_xts_setkey,
+			.encrypt = rk2_skcipher_encrypt,
+			.decrypt = rk2_skcipher_decrypt,
+			},
+	.alg.skcipher.op = {
+		.do_one_request = rk2_cipher_run,
+		},
+	},
+	{
+	.type = CRYPTO_ALG_TYPE_AHASH,
+	.rk2_mode = RK2_CRYPTO_MD5,
+	.alg.hash.base = {
+			.init = rk2_ahash_init,
+			.update = rk2_ahash_update,
+			.final = rk2_ahash_final,
+			.finup = rk2_ahash_finup,
+			.export = rk2_ahash_export,
+			.import = rk2_ahash_import,
+			.digest = rk2_ahash_digest,
+			.init_tfm = rk2_hash_init_tfm,
+			.exit_tfm = rk2_hash_exit_tfm,
+			.halg = {
+				.digestsize = MD5_DIGEST_SIZE,
+				.statesize = sizeof(struct md5_state),
+				.base = {
+					.cra_name = "md5",
+					.cra_driver_name = "rk2-md5",
+					.cra_priority = 300,
+					.cra_flags =
+					CRYPTO_ALG_ASYNC |
+					CRYPTO_ALG_NEED_FALLBACK,
+					.cra_blocksize =
+					MD5_HMAC_BLOCK_SIZE,
+					.cra_ctxsize =
+					sizeof(struct rk2_ahash_ctx),
+					.cra_module = THIS_MODULE,
+					}
+				}
+			},
+	.alg.hash.op = {
+			.do_one_request = rk2_hash_run,
+			},
+	},
+	{
+	.type = CRYPTO_ALG_TYPE_AHASH,
+	.rk2_mode = RK2_CRYPTO_SHA1,
+	.alg.hash.base = {
+			.init = rk2_ahash_init,
+			.update = rk2_ahash_update,
+			.final = rk2_ahash_final,
+			.finup = rk2_ahash_finup,
+			.export = rk2_ahash_export,
+			.import = rk2_ahash_import,
+			.digest = rk2_ahash_digest,
+			.init_tfm = rk2_hash_init_tfm,
+			.exit_tfm = rk2_hash_exit_tfm,
+			.halg = {
+				.digestsize = SHA1_DIGEST_SIZE,
+				.statesize = sizeof(struct sha1_state),
+				.base = {
+					.cra_name = "sha1",
+					.cra_driver_name = "rk2-sha1",
+					.cra_priority = 300,
+					.cra_flags =
+					CRYPTO_ALG_ASYNC |
+					CRYPTO_ALG_NEED_FALLBACK,
+					.cra_blocksize = SHA1_BLOCK_SIZE,
+					.cra_ctxsize =
+					sizeof(struct rk2_ahash_ctx),
+					.cra_module = THIS_MODULE,
+					}
+				}
+			},
+	.alg.hash.op = {
+			.do_one_request = rk2_hash_run,
+			},
+	},
+	{
+	.type = CRYPTO_ALG_TYPE_AHASH,
+	.rk2_mode = RK2_CRYPTO_SHA224,
+	.alg.hash.base = {
+			.init = rk2_ahash_init,
+			.update = rk2_ahash_update,
+			.final = rk2_ahash_final,
+			.finup = rk2_ahash_finup,
+			.export = rk2_ahash_export,
+			.import = rk2_ahash_import,
+			.digest = rk2_ahash_digest,
+			.init_tfm = rk2_hash_init_tfm,
+			.exit_tfm = rk2_hash_exit_tfm,
+			.halg = {
+				.digestsize = SHA224_DIGEST_SIZE,
+				.statesize = sizeof(struct sha256_state),
+				.base = {
+					.cra_name = "sha224",
+					.cra_driver_name = "rk2-sha224",
+					.cra_priority = 300,
+					.cra_flags =
+					CRYPTO_ALG_ASYNC |
+					CRYPTO_ALG_NEED_FALLBACK,
+					.cra_blocksize = SHA256_BLOCK_SIZE,
+					.cra_ctxsize =
+					sizeof(struct rk2_ahash_ctx),
+					.cra_module = THIS_MODULE,
+					}
+				}
+			},
+	.alg.hash.op = {
+			.do_one_request = rk2_hash_run,
+			},
+	},
+	{
+	.type = CRYPTO_ALG_TYPE_AHASH,
+	.rk2_mode = RK2_CRYPTO_SHA256,
+	.alg.hash.base = {
+			.init = rk2_ahash_init,
+			.update = rk2_ahash_update,
+			.final = rk2_ahash_final,
+			.finup = rk2_ahash_finup,
+			.export = rk2_ahash_export,
+			.import = rk2_ahash_import,
+			.digest = rk2_ahash_digest,
+			.init_tfm = rk2_hash_init_tfm,
+			.exit_tfm = rk2_hash_exit_tfm,
+			.halg = {
+				.digestsize = SHA256_DIGEST_SIZE,
+				.statesize = sizeof(struct sha256_state),
+				.base = {
+					.cra_name = "sha256",
+					.cra_driver_name = "rk2-sha256",
+					.cra_priority = 300,
+					.cra_flags =
+					CRYPTO_ALG_ASYNC |
+					CRYPTO_ALG_NEED_FALLBACK,
+					.cra_blocksize = SHA256_BLOCK_SIZE,
+					.cra_ctxsize =
+					sizeof(struct rk2_ahash_ctx),
+					.cra_module = THIS_MODULE,
+					}
+				}
+			},
+	.alg.hash.op = {
+			.do_one_request = rk2_hash_run,
+			},
+	},
+	{
+	.type = CRYPTO_ALG_TYPE_AHASH,
+	.rk2_mode = RK2_CRYPTO_SHA384,
+	.alg.hash.base = {
+			.init = rk2_ahash_init,
+			.update = rk2_ahash_update,
+			.final = rk2_ahash_final,
+			.finup = rk2_ahash_finup,
+			.export = rk2_ahash_export,
+			.import = rk2_ahash_import,
+			.digest = rk2_ahash_digest,
+			.init_tfm = rk2_hash_init_tfm,
+			.exit_tfm = rk2_hash_exit_tfm,
+			.halg = {
+				.digestsize = SHA384_DIGEST_SIZE,
+				.statesize = sizeof(struct sha512_state),
+				.base = {
+					.cra_name = "sha384",
+					.cra_driver_name = "rk2-sha384",
+					.cra_priority = 300,
+					.cra_flags = CRYPTO_ALG_ASYNC |
+					CRYPTO_ALG_NEED_FALLBACK,
+					.cra_blocksize = SHA384_BLOCK_SIZE,
+					.cra_ctxsize =
+					sizeof(struct rk2_ahash_ctx),
+					.cra_module = THIS_MODULE,
+					}
+				}
+			},
+	.alg.hash.op = {
+			.do_one_request = rk2_hash_run,
+			},
+	},
+	{
+	.type = CRYPTO_ALG_TYPE_AHASH,
+	.rk2_mode = RK2_CRYPTO_SHA512,
+	.alg.hash.base = {
+			.init = rk2_ahash_init,
+			.update = rk2_ahash_update,
+			.final = rk2_ahash_final,
+			.finup = rk2_ahash_finup,
+			.export = rk2_ahash_export,
+			.import = rk2_ahash_import,
+			.digest = rk2_ahash_digest,
+			.init_tfm = rk2_hash_init_tfm,
+			.exit_tfm = rk2_hash_exit_tfm,
+			.halg = {
+				.digestsize = SHA512_DIGEST_SIZE,
+				.statesize = sizeof(struct sha512_state),
+				.base = {
+					.cra_name = "sha512",
+					.cra_driver_name = "rk2-sha512",
+					.cra_priority = 300,
+					.cra_flags =
+					CRYPTO_ALG_ASYNC |
+					CRYPTO_ALG_NEED_FALLBACK,
+					.cra_blocksize = SHA512_BLOCK_SIZE,
+					.cra_ctxsize =
+					sizeof(struct rk2_ahash_ctx),
+					.cra_module = THIS_MODULE,
+					}
+				}
+			},
+	.alg.hash.op = {
+			.do_one_request = rk2_hash_run,
+			},
+	},
+	{
+	.type = CRYPTO_ALG_TYPE_AHASH,
+	.rk2_mode = RK2_CRYPTO_SM3,
+	.alg.hash.base = {
+			.init = rk2_ahash_init,
+			.update = rk2_ahash_update,
+			.final = rk2_ahash_final,
+			.finup = rk2_ahash_finup,
+			.export = rk2_ahash_export,
+			.import = rk2_ahash_import,
+			.digest = rk2_ahash_digest,
+			.init_tfm = rk2_hash_init_tfm,
+			.exit_tfm = rk2_hash_exit_tfm,
+			.halg = {
+				.digestsize = SM3_DIGEST_SIZE,
+				.statesize = sizeof(struct sm3_state),
+				.base = {
+					.cra_name = "sm3",
+					.cra_driver_name = "rk2-sm3",
+					.cra_priority = 300,
+					.cra_flags =
+					CRYPTO_ALG_ASYNC |
+					CRYPTO_ALG_NEED_FALLBACK,
+					.cra_blocksize = SM3_BLOCK_SIZE,
+					.cra_ctxsize =
+					sizeof(struct rk2_ahash_ctx),
+					.cra_module = THIS_MODULE,
+					}
+				}
+			},
+	.alg.hash.op = {
+			.do_one_request = rk2_hash_run,
+			},
+	},
+};
+
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+static int rk2_crypto_debugfs_stats_show(struct seq_file *seq, void *v)
+{
+	struct rk2_crypto_dev *rkc = seq->private;
+	unsigned int i;
+
+	seq_printf(seq, "%s %s requests: %lu\n",
+		   dev_driver_string(rkc->dev), dev_name(rkc->dev), rkc->nreq);
+
+	for (i = 0; i < rkc->num_algs; i++) {
+		switch (rkc->algs[i].type) {
+		case CRYPTO_ALG_TYPE_SKCIPHER:
+			seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
+				   rkc->algs[i].alg.skcipher.base.base.cra_driver_name,
+				   rkc->algs[i].alg.skcipher.base.base.cra_name,
+				   rkc->algs[i].stat_req, rkc->algs[i].stat_fb);
+			seq_printf(seq, "\tfallback due to length: %lu\n",
+				   rkc->algs[i].stat_fb_len);
+			seq_printf(seq, "\tfallback due to alignment: %lu\n",
+				   rkc->algs[i].stat_fb_align);
+			seq_printf(seq, "\tfallback due to SGs: %lu\n",
+				   rkc->algs[i].stat_fb_sgdiff);
+			break;
+		case CRYPTO_ALG_TYPE_AHASH:
+			seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
+				   rkc->algs[i].alg.hash.base.halg.base.cra_driver_name,
+				   rkc->algs[i].alg.hash.base.halg.base.cra_name,
+				   rkc->algs[i].stat_req,
+				   rkc->algs[i].stat_fb);
+			break;
+		}
+	}
+	return 0;
+}
+
+static int rk2_crypto_debugfs_info_show(struct seq_file *seq, void *d)
+{
+	struct rk2_crypto_dev *rkc = seq->private;
+	u32 v;
+	int err;
+
+	err = pm_runtime_resume_and_get(rkc->dev);
+	if (err)
+		return err;
+
+	v = readl(rkc->reg + RK2_CRYPTO_CLK_CTL);
+	seq_printf(seq, "CRYPTO_CLK_CTL %x\n", v);
+	v = readl(rkc->reg + RK2_CRYPTO_RST_CTL);
+	seq_printf(seq, "CRYPTO_RST_CTL %x\n", v);
+	v = readl(rkc->reg + CRYPTO_AES_VERSION);
+	seq_printf(seq, "CRYPTO_AES_VERSION %x\n", v);
+	if (v & BIT(17))
+		seq_puts(seq, "AES 192\n");
+	v = readl(rkc->reg + CRYPTO_DES_VERSION);
+	seq_printf(seq, "CRYPTO_DES_VERSION %x\n", v);
+	v = readl(rkc->reg + CRYPTO_SM4_VERSION);
+	seq_printf(seq, "CRYPTO_SM4_VERSION %x\n", v);
+	v = readl(rkc->reg + CRYPTO_HASH_VERSION);
+	seq_printf(seq, "CRYPTO_HASH_VERSION %x\n", v);
+	v = readl(rkc->reg + CRYPTO_HMAC_VERSION);
+	seq_printf(seq, "CRYPTO_HMAC_VERSION %x\n", v);
+	v = readl(rkc->reg + CRYPTO_RNG_VERSION);
+	seq_printf(seq, "CRYPTO_RNG_VERSION %x\n", v);
+	v = readl(rkc->reg + CRYPTO_PKA_VERSION);
+	seq_printf(seq, "CRYPTO_PKA_VERSION %x\n", v);
+	v = readl(rkc->reg + CRYPTO_CRYPTO_VERSION);
+	seq_printf(seq, "CRYPTO_CRYPTO_VERSION %x\n", v);
+
+	pm_runtime_mark_last_busy(rkc->dev);
+	pm_runtime_put_autosuspend(rkc->dev);
+
+	return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(rk2_crypto_debugfs_stats);
+DEFINE_SHOW_ATTRIBUTE(rk2_crypto_debugfs_info);
+
+#endif
+
+static void register_debugfs(struct rk2_crypto_dev *rkc)
+{
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+	/* Create a directory using the device name
+	 * (e.g., /sys/kernel/debug/fe370000.crypto)
+	 */
+	rkc->dbgfs_dir = debugfs_create_dir(dev_name(rkc->dev), NULL);
+
+	debugfs_create_file("stats", 0440, rkc->dbgfs_dir, rkc,
+			    &rk2_crypto_debugfs_stats_fops);
+	debugfs_create_file("info", 0440, rkc->dbgfs_dir, rkc,
+			    &rk2_crypto_debugfs_info_fops);
+#endif
+}
+
+static int rk2_crypto_register(struct rk2_crypto_dev *rkc)
+{
+	int i, k, err = 0;
+
+	for (i = 0; i < rkc->num_algs; i++) {
+		rkc->algs[i].dev = rkc;	/* Tie this alg copy to this device */
+		switch (rkc->algs[i].type) {
+		case CRYPTO_ALG_TYPE_SKCIPHER:
+			err = crypto_engine_register_skcipher(&rkc->algs[i].alg.skcipher);
+			break;
+		case CRYPTO_ALG_TYPE_AHASH:
+			err = crypto_engine_register_ahash(&rkc->algs[i].alg.hash);
+			break;
+		}
+		if (err)
+			goto err_cipher_algs;
+	}
+	return 0;
+
+ err_cipher_algs:
+	for (k = 0; k < i; k++) {
+		if (rkc->algs[k].type == CRYPTO_ALG_TYPE_SKCIPHER)
+			crypto_engine_unregister_skcipher(&rkc->algs[k].alg.skcipher);
+		else
+			crypto_engine_unregister_ahash(&rkc->algs[k].alg.hash);
+	}
+	return err;
+}
+
+static void rk2_crypto_unregister(struct rk2_crypto_dev *rkc)
+{
+	int i;
+
+	for (i = 0; i < rkc->num_algs; i++) {
+		if (rkc->algs[i].type == CRYPTO_ALG_TYPE_SKCIPHER)
+			crypto_engine_unregister_skcipher(&rkc->algs[i].alg.skcipher);
+		else
+			crypto_engine_unregister_ahash(&rkc->algs[i].alg.hash);
+	}
+}
+
+static const struct of_device_id crypto_of_id_table[] = {
+	{.compatible = "rockchip,rk3568-crypto",
+	 .data = &rk3568_variant,
+	 },
+	{.compatible = "rockchip,rk3588-crypto",
+	 .data = &rk3588_variant,
+	 },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, crypto_of_id_table);
+
+static int rk2_crypto_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rk2_crypto_dev *rkc;
+	int err = 0;
+
+	rkc = devm_kzalloc(dev, sizeof(*rkc), GFP_KERNEL);
+	if (!rkc)
+		return -ENOMEM;
+
+	rkc->dev = dev;
+	platform_set_drvdata(pdev, rkc);
+
+	/* Duplicate the algorithms locally for this specific device */
+	rkc->num_algs = ARRAY_SIZE(rk2_crypto_algs_template);
+	rkc->algs = devm_kmemdup(dev, rk2_crypto_algs_template,
+				 sizeof(rk2_crypto_algs_template), GFP_KERNEL);
+	if (!rkc->algs)
+		return -ENOMEM;
+
+	rkc->variant = of_device_get_match_data(dev);
+	if (!rkc->variant)
+		return dev_err_probe(dev, -EINVAL, "Missing variant\n");
+
+	rkc->rst = devm_reset_control_array_get_exclusive(dev);
+	if (IS_ERR(rkc->rst))
+		return dev_err_probe(dev, PTR_ERR(rkc->rst), "Fail to get resets\n");
+
+	/* Manual DMA allocation requires manual cleanup in error paths */
+	rkc->tl = dma_alloc_coherent(dev,
+				     sizeof(struct rk2_crypto_lli) * MAX_LLI,
+				     &rkc->t_phy, GFP_KERNEL);
+
+	if (!rkc->tl)
+		return -ENOMEM;
+
+	rkc->reg = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(rkc->reg)) {
+		err = dev_err_probe(dev, PTR_ERR(rkc->reg), "Fail to get resources\n");
+		goto err_dma;
+	}
+
+	err = rk2_crypto_get_clks(rkc);
+	if (err)
+		goto err_dma;
+
+	rkc->irq = platform_get_irq(pdev, 0);
+	if (rkc->irq < 0) {
+		err = dev_err_probe(dev, rkc->irq, "Interrupt is not available.\n");
+		goto err_dma;
+	}
+
+	err = devm_request_irq(dev, rkc->irq,
+			       rk2_crypto_irq_handle, IRQF_SHARED,
+			       "rk-crypto", pdev);
+
+	if (err) {
+		err = dev_err_probe(dev, err, "irq request failed.\n");
+		goto err_dma;
+	}
+
+	rkc->engine = crypto_engine_alloc_init(dev, true);
+	if (!rkc->engine) {
+		err = -ENOMEM;
+		goto err_dma;
+	}
+
+	err = crypto_engine_start(rkc->engine);
+	if (err) {
+		err = dev_err_probe(dev, err, "Failed to start crypto engine\n");
+		goto err_engine;
+	}
+
+	init_completion(&rkc->complete);
+
+	err = rk2_crypto_pm_init(rkc);
+	if (err) {
+		err = dev_err_probe(dev, err, "Failed to initialize runtime PM\n");
+		goto err_engine;
+	}
+
+	err = pm_runtime_resume_and_get(dev);
+	if (err) {
+		err = dev_err_probe(dev, err, "Failed to resume device\n");
+		goto err_pm;
+	}
+
+	/* Register algorithms specific to THIS device */
+	err = rk2_crypto_register(rkc);
+	if (err) {
+		err = dev_err_probe(dev, err, "Fail to register crypto algorithms\n");
+		goto err_pm_put;
+	}
+
+	register_debugfs(rkc);
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+
+	return 0;
+
+ err_pm_put:
+	pm_runtime_put_sync(dev);
+ err_pm:
+	rk2_crypto_pm_exit(rkc);
+ err_engine:
+	crypto_engine_exit(rkc->engine);
+ err_dma:
+	dma_free_coherent(dev, sizeof(struct rk2_crypto_lli) * MAX_LLI,
+			  rkc->tl, rkc->t_phy);
+	return err;
+}
+
+static void rk2_crypto_remove(struct platform_device *pdev)
+{
+	struct rk2_crypto_dev *rkc = platform_get_drvdata(pdev);
+
+	/* Stop engine to prevent new requests */
+	crypto_engine_stop(rkc->engine);
+
+	/* Unregister algorithms for this specific device */
+	rk2_crypto_unregister(rkc);
+
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+	debugfs_remove_recursive(rkc->dbgfs_dir);
+#endif
+
+	/* Safe to kill the engine completely */
+	crypto_engine_exit(rkc->engine);
+
+	rk2_crypto_pm_exit(rkc);
+	dma_free_coherent(rkc->dev, sizeof(struct rk2_crypto_lli) * MAX_LLI,
+			  rkc->tl, rkc->t_phy);
+}
+
+static struct platform_driver crypto_driver = {
+	.probe = rk2_crypto_probe,
+	.remove = rk2_crypto_remove,
+	.driver = {
+		   .name = "rk2-crypto",
+		   .pm = pm_ptr(&rk2_crypto_pm_ops),
+		   .of_match_table = crypto_of_id_table,
+		   },
+};
+
+module_platform_driver(crypto_driver);
+
+MODULE_DESCRIPTION("Rockchip Crypto Engine cryptographic offloader");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
+MODULE_AUTHOR("Dawid Olesinski <dawidro@gmail.com>");
+
diff --git a/drivers/crypto/rockchip/rk2_crypto.h b/drivers/crypto/rockchip/rk2_crypto.h
new file mode 100644
index 000000000000..40e20235cf7e
--- /dev/null
+++ b/drivers/crypto/rockchip/rk2_crypto.h
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __RK2_CRYPTO_H__
+#define __RK2_CRYPTO_H__
+
+#include <crypto/aes.h>
+#include <crypto/engine.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/sm3.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+
+#define RK2_CRYPTO_CLK_CTL		0x0000
+#define RK2_CRYPTO_RST_CTL		0x0004
+
+#define RK2_CRYPTO_DMA_INT_EN		0x0008
+
+/* RK2_CRYPTO_DMA_INT_ST / RK2_CRYPTO_DMA_INT_EN bit definitions */
+#define RK2_CRYPTO_DMA_INT_LISTDONE      BIT(0)   /* LLI list complete */
+#define RK2_CRYPTO_DMA_INT_SRC_ITEM_INT  BIT(1)   /* per-entry src interrupt */
+#define RK2_CRYPTO_DMA_INT_DST_ITEM_INT  BIT(2)   /* per-entry dst interrupt */
+#define RK2_CRYPTO_DMA_INT_LIST_SRC_ERR  BIT(3)   /* LLI src error */
+#define RK2_CRYPTO_DMA_INT_LIST_DST_ERR  BIT(4)   /* LLI dst error */
+#define RK2_CRYPTO_DMA_INT_SRC_ERR       BIT(5)   /* DMA src error */
+#define RK2_CRYPTO_DMA_INT_DST_ERR       BIT(6)   /* DMA dst error */
+
+#define RK2_CRYPTO_DMA_INT_ERR_MASK      (RK2_CRYPTO_DMA_INT_LIST_SRC_ERR | \
+					  RK2_CRYPTO_DMA_INT_LIST_DST_ERR | \
+					  RK2_CRYPTO_DMA_INT_SRC_ERR      | \
+					  RK2_CRYPTO_DMA_INT_DST_ERR)
+
+#define RK2_CRYPTO_DMA_INT_ALL_MASK	0x7F
+
+/* The DMA interrupt enable register uses the upper 16 bits as a write-enable mask.
+ * To enable bits 0-6, we must write 1s to bits 16-22 as well.
+ */
+#define RK2_CRYPTO_DMA_INT_ENABLE_ALL	((RK2_CRYPTO_DMA_INT_ALL_MASK << 16) | \
+					  RK2_CRYPTO_DMA_INT_ALL_MASK)
+
+/* values in RK2_CRYPTO_DMA_INT_ST are the same than in RK2_CRYPTO_DMA_INT_EN */
+#define RK2_CRYPTO_DMA_INT_ST		0x000C
+
+#define RK2_CRYPTO_DMA_CTL		0x0010
+#define RK2_CRYPTO_DMA_CTL_START	BIT(0)
+
+#define RK2_CRYPTO_DMA_LLI_ADDR		0x0014
+#define RK2_CRYPTO_DMA_ST		0x0018
+#define RK2_CRYPTO_DMA_STATE		0x001C
+#define RK2_CRYPTO_DMA_LLI_RADDR	0x0020
+#define RK2_CRYPTO_DMA_SRC_RADDR	0x0024
+#define RK2_CRYPTO_DMA_DST_WADDR	0x0028
+#define RK2_CRYPTO_DMA_ITEM_ID		0x002C
+
+#define RK2_CRYPTO_FIFO_CTL		0x0040
+
+#define RK2_CRYPTO_BC_CTL		0x0044
+#define RK2_CRYPTO_AES			(0 << 8)
+#define RK2_CRYPTO_MODE_ECB		(0 << 4)
+#define RK2_CRYPTO_MODE_CBC		(1 << 4)
+#define RK2_CRYPTO_XTS			(6 << 4)
+
+#define RK2_CRYPTO_HASH_CTL		0x0048
+#define RK2_CRYPTO_HW_PAD		BIT(2)
+#define RK2_CRYPTO_SHA1			(0 << 4)
+#define RK2_CRYPTO_MD5			(1 << 4)
+#define RK2_CRYPTO_SHA224		(3 << 4)
+#define RK2_CRYPTO_SHA256		(2 << 4)
+#define RK2_CRYPTO_SHA384		(9 << 4)
+#define RK2_CRYPTO_SHA512		(8 << 4)
+#define RK2_CRYPTO_SM3			(4 << 4)
+
+#define RK2_CRYPTO_AES_ECB		(RK2_CRYPTO_AES | RK2_CRYPTO_MODE_ECB)
+#define RK2_CRYPTO_AES_CBC		(RK2_CRYPTO_AES | RK2_CRYPTO_MODE_CBC)
+#define RK2_CRYPTO_AES_XTS		(RK2_CRYPTO_AES | RK2_CRYPTO_XTS)
+#define RK2_CRYPTO_AES_128BIT_key	(0 << 2)
+#define RK2_CRYPTO_AES_192BIT_key	(1 << 2)
+#define RK2_CRYPTO_AES_256BIT_key	(2 << 2)
+
+#define RK2_CRYPTO_DEC			BIT(1)
+#define RK2_CRYPTO_ENABLE		BIT(0)
+
+#define RK2_CRYPTO_CIPHER_ST		0x004C
+#define RK2_CRYPTO_CIPHER_STATE		0x0050
+
+#define RK2_CRYPTO_CH0_IV_0		0x0100
+
+#define RK2_CRYPTO_KEY0			0x0180
+#define RK2_CRYPTO_KEY1			0x0184
+#define RK2_CRYPTO_KEY2			0x0188
+#define RK2_CRYPTO_KEY3			0x018C
+#define RK2_CRYPTO_KEY4			0x0190
+#define RK2_CRYPTO_KEY5			0x0194
+#define RK2_CRYPTO_KEY6			0x0198
+#define RK2_CRYPTO_KEY7			0x019C
+#define RK2_CRYPTO_CH4_KEY0		0x01c0
+
+#define RK2_CRYPTO_CH0_PC_LEN_0		0x0280
+
+#define RK2_CRYPTO_CH0_IV_LEN		0x0300
+
+#define RK2_CRYPTO_HASH_DOUT_0		0x03A0
+#define RK2_CRYPTO_HASH_VALID		0x03E4
+
+#define RK2_CRYPTO_TRNG_CTL		0x0400
+#define RK2_CRYPTO_TRNG_START		BIT(0)
+#define RK2_CRYPTO_TRNG_ENABLE		BIT(1)
+#define RK2_CRYPTO_TRNG_256		(0x3 << 4)
+#define RK2_CRYPTO_TRNG_SAMPLE_CNT	0x0404
+#define RK2_CRYPTO_TRNG_DOUT		0x0410
+
+#define CRYPTO_AES_VERSION		0x0680
+#define CRYPTO_DES_VERSION		0x0684
+#define CRYPTO_SM4_VERSION		0x0688
+#define CRYPTO_HASH_VERSION		0x068C
+#define CRYPTO_HMAC_VERSION		0x0690
+#define CRYPTO_RNG_VERSION		0x0694
+#define CRYPTO_PKA_VERSION		0x0698
+#define CRYPTO_CRYPTO_VERSION		0x06F0
+
+#define RK2_LLI_DMA_CTRL_SRC_INT	BIT(10)
+#define RK2_LLI_DMA_CTRL_DST_INT	BIT(9)
+#define RK2_LLI_DMA_CTRL_LIST_INT	BIT(8)
+#define RK2_LLI_DMA_CTRL_LAST		BIT(0)
+
+#define RK2_LLI_STRING_LAST		BIT(2)
+#define RK2_LLI_STRING_FIRST		BIT(1)
+#define RK2_LLI_CIPHER_START		BIT(0)
+
+#define MAX_LLI 20
+
+struct rk2_crypto_lli {
+	__le32 src_addr;
+	__le32 src_len;
+	__le32 dst_addr;
+	__le32 dst_len;
+	__le32 user;
+	__le32 iv;
+	__le32 dma_ctrl;
+	__le32 next;
+};
+
+struct rk2_variant {
+	int num_clks;
+};
+
+struct rk2_crypto_dev {
+	struct device *dev;
+	struct clk_bulk_data *clks;
+	int num_clks;
+	struct reset_control *rst;
+	void __iomem *reg;
+	int irq;
+	const struct rk2_variant *variant;
+	unsigned long nreq;
+	struct crypto_engine *engine;
+	struct completion complete;
+	int status;
+	struct rk2_crypto_lli *tl;
+	dma_addr_t t_phy;
+	struct rk2_crypto_template *algs;
+	int num_algs;
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+	struct dentry *dbgfs_dir;
+#endif
+};
+
+/* the private variable of hash */
+struct rk2_ahash_ctx {
+	/* for fallback */
+	struct crypto_ahash *fallback_tfm;
+};
+
+/* the private variable of hash for fallback */
+struct rk2_ahash_rctx {
+	struct rk2_crypto_dev *dev;
+	u32 mode;
+	int nrsgs;
+	struct ahash_request fallback_req;
+};
+
+/* the private variable of cipher */
+struct rk2_cipher_ctx {
+	unsigned int keylen;
+	u8 key[AES_MAX_KEY_SIZE * 2];
+	struct crypto_skcipher *fallback_tfm;
+};
+
+struct rk2_cipher_rctx {
+	struct rk2_crypto_dev *dev;
+	u8 backup_iv[AES_BLOCK_SIZE];
+	u32 mode;
+	/* must be last, see __ctx placement */
+	struct skcipher_request fallback_req;
+};
+
+struct rk2_crypto_template {
+	u32 type;
+	u32 rk2_mode;
+	bool is_xts;
+	struct rk2_crypto_dev *dev;
+	union {
+		struct skcipher_engine_alg skcipher;
+		struct ahash_engine_alg hash;
+	} alg;
+	unsigned long stat_req;
+	unsigned long stat_fb;
+	unsigned long stat_fb_len;
+	unsigned long stat_fb_sglen;
+	unsigned long stat_fb_align;
+	unsigned long stat_fb_sgdiff;
+};
+
+int rk2_cipher_run(struct crypto_engine *engine, void *async_req);
+int rk2_hash_run(struct crypto_engine *engine, void *breq);
+
+int rk2_cipher_tfm_init(struct crypto_skcipher *tfm);
+void rk2_cipher_tfm_exit(struct crypto_skcipher *tfm);
+int rk2_aes_setkey(struct crypto_skcipher *cipher, const u8 *key,
+		   unsigned int keylen);
+int rk2_aes_xts_setkey(struct crypto_skcipher *cipher, const u8 *key,
+		       unsigned int keylen);
+int rk2_skcipher_encrypt(struct skcipher_request *req);
+int rk2_skcipher_decrypt(struct skcipher_request *req);
+
+int rk2_ahash_init(struct ahash_request *req);
+int rk2_ahash_update(struct ahash_request *req);
+int rk2_ahash_final(struct ahash_request *req);
+int rk2_ahash_finup(struct ahash_request *req);
+int rk2_ahash_import(struct ahash_request *req, const void *in);
+int rk2_ahash_export(struct ahash_request *req, void *out);
+int rk2_ahash_digest(struct ahash_request *req);
+int rk2_hash_init_tfm(struct crypto_ahash *tfm);
+void rk2_hash_exit_tfm(struct crypto_ahash *tfm);
+
+#endif /* __RK2_CRYPTO_H__ */
diff --git a/drivers/crypto/rockchip/rk2_crypto_ahash.c b/drivers/crypto/rockchip/rk2_crypto_ahash.c
new file mode 100644
index 000000000000..5aeff32d1402
--- /dev/null
+++ b/drivers/crypto/rockchip/rk2_crypto_ahash.c
@@ -0,0 +1,547 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Crypto offloader support for Rockchip RK3568/RK3588
+ *
+ * Copyright (c) 2022-2023 Corentin Labbe <clabbe@baylibre.com>
+ */
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/scatterlist.h>
+#include <linux/unaligned.h>
+#include <crypto/aes.h>
+#include <crypto/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/sm3.h>
+#include "rk2_crypto.h"
+
+static bool rk2_ahash_need_fallback(struct ahash_request *areq)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct ahash_alg *alg = crypto_ahash_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.hash.base);
+	struct scatterlist *sg;
+	int nents = sg_nents_for_len(areq->src, areq->nbytes);
+
+	/*
+	 * The hardware's Merkle-Damgard padding engine (HW_PAD) requires the
+	 * total message length to be known upfront via CH0_PC_LEN_0. When a
+	 * request spans multiple LLI descriptors, the hardware either treats
+	 * each descriptor as an independent padded message, or loses running
+	 * hash state at descriptor boundaries. Either way the result is a
+	 * wrong digest. This behaviour is not documented in the RK3588 TRM,
+	 * which advertises LLI chaining but does not specify whether hash
+	 * operations may span multiple linked descriptors.
+	 * Work around this by falling back to software for any multi-SG
+	 * request. Single-SG requests with HW_PAD work correctly.
+	 */
+
+	if (nents < 0) {
+		dev_err(algt->dev->dev, "Invalid SG list: length mismatch\n");
+		return true;	/* force fallback safely */
+	}
+	if (nents > 1) {
+		algt->stat_fb_sgdiff++;
+		return true;
+	}
+
+	sg = areq->src;
+	while (sg) {
+		if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
+			algt->stat_fb_align++;
+			return true;
+		}
+		if (sg->length % 4) {
+			algt->stat_fb_sglen++;
+			return true;
+		}
+		sg = sg_next(sg);
+	}
+	return false;
+}
+
+static int rk2_ahash_digest_fb(struct ahash_request *areq)
+{
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct rk2_ahash_ctx *tfmctx = crypto_ahash_ctx(tfm);
+	struct ahash_alg *alg = crypto_ahash_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.hash.base);
+
+	algt->stat_fb++;
+
+	ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+	ahash_request_set_callback(&rctx->fallback_req, areq->base.flags,
+				   areq->base.complete, areq->base.data);
+
+	rctx->fallback_req.nbytes = areq->nbytes;
+	rctx->fallback_req.src = areq->src;
+	rctx->fallback_req.result = areq->result;
+
+	return crypto_ahash_digest(&rctx->fallback_req);
+}
+
+static int zero_message_process(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct ahash_alg *alg = crypto_ahash_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.hash.base);
+	int digestsize = crypto_ahash_digestsize(tfm);
+
+	switch (algt->rk2_mode) {
+	case RK2_CRYPTO_SHA1:
+		memcpy(req->result, sha1_zero_message_hash, digestsize);
+		break;
+	case RK2_CRYPTO_SHA256:
+		memcpy(req->result, sha256_zero_message_hash, digestsize);
+		break;
+	case RK2_CRYPTO_SHA384:
+		memcpy(req->result, sha384_zero_message_hash, digestsize);
+		break;
+	case RK2_CRYPTO_SHA512:
+		memcpy(req->result, sha512_zero_message_hash, digestsize);
+		break;
+	case RK2_CRYPTO_MD5:
+		memcpy(req->result, md5_zero_message_hash, digestsize);
+		break;
+	case RK2_CRYPTO_SM3:
+		memcpy(req->result, sm3_zero_message_hash, digestsize);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * rk2_ahash_init() - Initialize context for a hash request
+ * @req: The asynchronous hash request structure.
+ *
+ * Initializes the software fallback context. The physical hardware engine
+ * is only utilized during atomic digest operations.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_init(struct ahash_request *req)
+{
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+	ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+				   req->base.complete, req->base.data);
+
+	return crypto_ahash_init(&rctx->fallback_req);
+}
+
+/**
+ * rk2_ahash_update() - Feed a message block into the hash stream
+ * @req: The asynchronous hash request structure.
+ *
+ * Passes the message block to the software fallback. The hardware engine
+ * does not support fragmented streaming updates.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_update(struct ahash_request *req)
+{
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+	ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+				   req->base.complete, req->base.data);
+	rctx->fallback_req.nbytes = req->nbytes;
+	rctx->fallback_req.src = req->src;
+
+	return crypto_ahash_update(&rctx->fallback_req);
+}
+
+/**
+ * rk2_ahash_final() - Finalize the hashing operation
+ * @req: The asynchronous hash request structure.
+ *
+ * Finalizes the hash and extracts the digest via the software fallback.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_final(struct ahash_request *req)
+{
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+	ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+				   req->base.complete, req->base.data);
+	rctx->fallback_req.result = req->result;
+
+	return crypto_ahash_final(&rctx->fallback_req);
+}
+
+/**
+ * rk2_ahash_finup() - Perform update and final hash operations sequentially
+ * @req: The asynchronous hash request structure.
+ *
+ * Convenience wrapper that performs update and final operations
+ * via the software fallback.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_finup(struct ahash_request *req)
+{
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+	ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+				   req->base.complete, req->base.data);
+
+	rctx->fallback_req.nbytes = req->nbytes;
+	rctx->fallback_req.src = req->src;
+	rctx->fallback_req.result = req->result;
+
+	return crypto_ahash_finup(&rctx->fallback_req);
+}
+
+/**
+ * rk2_ahash_import() - Restore a saved hash context
+ * @req: The target asynchronous hash request structure.
+ * @in: Buffer containing the previously exported state.
+ *
+ * Restores the software fallback state from an export block.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_import(struct ahash_request *req, const void *in)
+{
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+	ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+				   req->base.complete, req->base.data);
+
+	return crypto_ahash_import(&rctx->fallback_req, in);
+}
+
+/**
+ * rk2_ahash_export() - Serialize an active hash context
+ * @req: The source asynchronous hash request structure.
+ * @out: Destination buffer where the state will be written.
+ *
+ * Freezes the progression of the software fallback stream into a byte array.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_export(struct ahash_request *req, void *out)
+{
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+	ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+				   req->base.complete, req->base.data);
+
+	return crypto_ahash_export(&rctx->fallback_req, out);
+}
+
+/**
+ * rk2_ahash_digest() - Compute a complete message digest in a single transaction
+ * @req: The asynchronous hash request structure.
+ *
+ * Evaluates hardware constraints (e.g., scatterlist alignment) and either
+ * routes the atomic request to the hardware engine or diverts to the fallback.
+ *
+ * Return: 0 on synchronous completion, -EINPROGRESS if submitted to the
+ *         hardware engine, or a negative error code on failure.
+ */
+int rk2_ahash_digest(struct ahash_request *req)
+{
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct ahash_alg *alg = crypto_ahash_alg(tfm);
+	struct rk2_crypto_template *algt;
+	struct rk2_crypto_dev *rkc;
+	struct crypto_engine *engine;
+
+	if (!req->nbytes)
+		return zero_message_process(req);
+
+	if (rk2_ahash_need_fallback(req))
+		return rk2_ahash_digest_fb(req);
+
+	/* Extract the device pointer from the algorithm template! */
+	algt = container_of(alg, struct rk2_crypto_template, alg.hash.base);
+	rkc = algt->dev;
+	if (!rkc)
+		return -ENODEV;
+
+	rctx->dev = rkc;
+	engine = rkc->engine;
+
+	return crypto_transfer_hash_request_to_engine(engine, req);
+}
+
+static int rk2_hash_prepare(struct crypto_engine *engine, void *breq)
+{
+	struct ahash_request *areq =
+	    container_of(breq, struct ahash_request, base);
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq);
+	struct rk2_crypto_dev *rkc = rctx->dev;
+	int n = sg_nents_for_len(areq->src, areq->nbytes);
+	int ret;
+
+	if (n < 0) {
+		dev_err(rkc->dev, "SG list too short for %u bytes\n", areq->nbytes);
+		return -EINVAL;
+	}
+	rctx->nrsgs = n;
+	ret = dma_map_sg(rkc->dev, areq->src, rctx->nrsgs, DMA_TO_DEVICE);
+	if (ret <= 0) {
+		/*
+		 * clear nrsgs on map failure to prevent spurious unmap in unprepare
+		 */
+		rctx->nrsgs = 0;
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void rk2_hash_unprepare(struct crypto_engine *engine, void *breq)
+{
+	struct ahash_request *areq =
+	    container_of(breq, struct ahash_request, base);
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq);
+	struct rk2_crypto_dev *rkc = rctx->dev;
+
+	if (rctx->nrsgs)
+		dma_unmap_sg(rkc->dev, areq->src, rctx->nrsgs, DMA_TO_DEVICE);
+}
+
+/**
+ * rk2_hash_run() - Execute an asynchronous hash request via the hardware
+ * @engine: The crypto engine queue managing this request.
+ * @breq: The asynchronous hash request to process.
+ *
+ * Configures the hardware hash engine, programs DMA block descriptors,
+ * and copies the final digest back from the hardware registers.
+ *
+ * Return: Always 0. Errors are reported through the crypto engine
+ *         finalization callback.
+ */
+int rk2_hash_run(struct crypto_engine *engine, void *breq)
+{
+	struct ahash_request *areq =
+	    container_of(breq, struct ahash_request, base);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+	struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq);
+	struct ahash_alg *alg = crypto_ahash_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.hash.base);
+	struct scatterlist *sgs = areq->src;
+	struct rk2_crypto_dev *rkc = rctx->dev;
+	struct rk2_crypto_lli *dd = &rkc->tl[0];
+	int ddi = 0;
+	int err = 0;
+	unsigned int len = areq->nbytes;
+	unsigned int todo;
+	unsigned long timeout;
+	u32 v;
+	int i;
+
+	err = rk2_hash_prepare(engine, breq);
+	if (err)
+		goto exit_unmap;
+
+	err = pm_runtime_resume_and_get(rkc->dev);
+	if (err)
+		goto exit_unmap;
+
+	dev_dbg(rkc->dev, "%s %s len=%u\n", __func__,
+		crypto_tfm_alg_name(areq->base.tfm), areq->nbytes);
+
+	algt->stat_req++;
+	rkc->nreq++;
+
+	/* the upper bits are a write enable mask, so we need to write 1 to all
+	 * upper 16 bits to allow write to the 16 lower bits
+	 */
+	rctx->mode = algt->rk2_mode;
+	rctx->mode |= 0xffff0000;
+	rctx->mode |= RK2_CRYPTO_ENABLE | RK2_CRYPTO_HW_PAD;
+	writel(rctx->mode, rkc->reg + RK2_CRYPTO_HASH_CTL);
+
+	while (sgs && len > 0) {
+		if (ddi >= MAX_LLI) {
+			dev_err(rkc->dev,
+				"Too many SG entries (current: %d, max: %d)\n",
+				ddi, MAX_LLI);
+			err = -EINVAL;
+			goto exit;
+		}
+		dd = &rkc->tl[ddi];
+
+		todo = min(sg_dma_len(sgs), len);
+		dd->src_addr = sg_dma_address(sgs);
+		dd->src_len = todo;
+		dd->dst_addr = 0;
+		dd->dst_len = 0;
+		dd->dma_ctrl = ddi << 24;
+		dd->iv = 0;
+		dd->next =
+		    rkc->t_phy + sizeof(struct rk2_crypto_lli) * (ddi + 1);
+
+		if (ddi == 0)
+			dd->user = RK2_LLI_CIPHER_START | RK2_LLI_STRING_FIRST;
+		else
+			dd->user = 0;
+
+		len -= todo;
+		if (len == 0) {
+			dd->user |= RK2_LLI_STRING_LAST;
+			dd->dma_ctrl |= RK2_LLI_DMA_CTRL_LAST |
+			    RK2_LLI_DMA_CTRL_SRC_INT |
+			    RK2_LLI_DMA_CTRL_LIST_INT;
+		}
+		dev_dbg(rkc->dev,
+			"HASH SG %d sglen=%u user=%x dma=%x mode=%x len=%u todo=%u phy=%pad\n",
+			ddi, sgs->length, dd->user, dd->dma_ctrl, rctx->mode,
+			len, todo, &rkc->t_phy);
+
+		sgs = sg_next(sgs);
+		ddi++;
+	}
+
+	/*
+	 * next is ignored by hardware when RK2_LLI_DMA_CTRL_LAST is set in
+	 * dma_ctrl. Set it to an obviously-invalid-but-non-zero sentinel so
+	 * it stands out if ever read in a debug dump.
+	 */
+	dd->next = 1;
+
+	/* Program total payload length for hardware padding */
+	writel(areq->nbytes, rkc->reg + RK2_CRYPTO_CH0_PC_LEN_0);
+
+	/* Clear stale interrupts, then enable with proper write-mask */
+	writel(RK2_CRYPTO_DMA_INT_ALL_MASK, rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+	writel(RK2_CRYPTO_DMA_INT_ENABLE_ALL, rkc->reg + RK2_CRYPTO_DMA_INT_EN);
+
+	writel(rkc->t_phy, rkc->reg + RK2_CRYPTO_DMA_LLI_ADDR);
+
+	reinit_completion(&rkc->complete);
+	rkc->status = 0;
+
+	writel(RK2_CRYPTO_DMA_CTL_START | (RK2_CRYPTO_DMA_CTL_START << 16),
+	       rkc->reg + RK2_CRYPTO_DMA_CTL);
+
+	timeout = wait_for_completion_timeout(&rkc->complete,
+					      msecs_to_jiffies(2000));
+	if (!timeout) {
+		dev_err(rkc->dev, "DMA timeout\n");
+		err = -ETIMEDOUT;
+		reset_control_assert(rkc->rst);
+		udelay(10);
+		reset_control_deassert(rkc->rst);
+		goto exit;
+	}
+	if (!rkc->status) {
+		dev_err(rkc->dev, "DMA error\n");
+		err = -EIO;
+		reset_control_assert(rkc->rst);
+		udelay(10);
+		reset_control_deassert(rkc->rst);
+		goto exit;
+	}
+
+	err =
+	    readl_poll_timeout_atomic(rkc->reg + RK2_CRYPTO_HASH_VALID, v,
+				      v == 1, 10, 1000);
+	if (err) {
+		dev_err(rkc->dev, "Hash result not valid\n");
+		goto exit;
+	}
+
+	/*
+	 * Hardware outputs digest words in big-endian format.
+	 * Because readl() performs a native little-endian read,
+	 * put_unaligned_be32() is used to store the result correctly
+	 * into the byte array.
+	 */
+	for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++) {
+		v = readl(rkc->reg + RK2_CRYPTO_HASH_DOUT_0 + i * 4);
+		put_unaligned_be32(v, areq->result + i * 4);
+	}
+ exit:
+	writel(0xffff0000, rkc->reg + RK2_CRYPTO_HASH_CTL);
+	pm_runtime_mark_last_busy(rkc->dev);
+	pm_runtime_put_autosuspend(rkc->dev);
+
+ exit_unmap:
+	rk2_hash_unprepare(engine, breq);
+	local_bh_disable();
+	crypto_finalize_hash_request(engine, breq, err);
+	local_bh_enable();
+
+	return 0;
+}
+
+/**
+ * rk2_hash_init_tfm() - Initialize the transformation context
+ * @tfm: The crypto ahash handle.
+ *
+ * Allocates software fallback transformations required to guarantee
+ * processing integrity when hardware constraints are violated.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_hash_init_tfm(struct crypto_ahash *tfm)
+{
+	struct rk2_ahash_ctx *tctx = crypto_ahash_ctx(tfm);
+	const char *alg_name = crypto_ahash_alg_name(tfm);
+	struct ahash_alg *alg = crypto_ahash_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.hash.base);
+	unsigned int fallback_statesize;
+
+	tctx->fallback_tfm = crypto_alloc_ahash(alg_name, 0,
+						CRYPTO_ALG_NEED_FALLBACK);
+	if (IS_ERR(tctx->fallback_tfm)) {
+		dev_err(algt->dev->dev, "Could not load fallback driver.\n");
+		return PTR_ERR(tctx->fallback_tfm);
+	}
+
+	/* Promote statesize if fallback needs more space for export/import */
+	fallback_statesize = crypto_ahash_statesize(tctx->fallback_tfm);
+	if (fallback_statesize > crypto_ahash_statesize(tfm))
+		crypto_ahash_set_statesize(tfm, fallback_statesize);
+
+	crypto_ahash_set_reqsize(tfm,
+				 sizeof(struct rk2_ahash_rctx) +
+				 crypto_ahash_reqsize(tctx->fallback_tfm));
+	return 0;
+}
+
+/**
+ * rk2_hash_exit_tfm() - Clean up an ahash transformation context
+ * @tfm: The crypto ahash handle.
+ *
+ * Safely frees internal software fallback transformations.
+ */
+void rk2_hash_exit_tfm(struct crypto_ahash *tfm)
+{
+	struct rk2_ahash_ctx *tctx = crypto_ahash_ctx(tfm);
+
+	crypto_free_ahash(tctx->fallback_tfm);
+}
diff --git a/drivers/crypto/rockchip/rk2_crypto_skcipher.c b/drivers/crypto/rockchip/rk2_crypto_skcipher.c
new file mode 100644
index 000000000000..e1a1a1a13096
--- /dev/null
+++ b/drivers/crypto/rockchip/rk2_crypto_skcipher.c
@@ -0,0 +1,724 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * hardware cryptographic offloader for RK3568/RK3588 SoC
+ *
+ * Copyright (c) 2022-2023 Corentin Labbe <clabbe@baylibre.com>
+ */
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/aes.h>
+#include <crypto/xts.h>
+#include "rk2_crypto.h"
+
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+static void rk2_print(struct rk2_crypto_dev *rkc)
+{
+	u32 v;
+
+	v = readl(rkc->reg + RK2_CRYPTO_DMA_ST);
+	dev_info(rkc->dev, "DMA_ST %x\n", v);
+	switch (v) {
+	case 0:
+		dev_info(rkc->dev, "DMA_ST: DMA IDLE\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "DMA_ST: DMA BUSY\n");
+		break;
+	default:
+		dev_err(rkc->dev, "DMA_ST: invalid value\n");
+	}
+
+	v = readl(rkc->reg + RK2_CRYPTO_DMA_STATE);
+	dev_info(rkc->dev, "DMA_STATE %x\n", v);
+
+	switch (v & 0x3) {
+	case 0:
+		dev_info(rkc->dev, "DMA_STATE: DMA DST IDLE\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "DMA_STATE: DMA DST LOAD\n");
+		break;
+	case 2:
+		dev_info(rkc->dev, "DMA_STATE: DMA DST WORK\n");
+		break;
+	default:
+		dev_err(rkc->dev, "DMA DST invalid\n");
+		break;
+	}
+	switch ((v >> 2) & 0x3) {
+	case 0:
+		dev_info(rkc->dev, "DMA_STATE: DMA SRC IDLE\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "DMA_STATE: DMA SRC LOAD\n");
+		break;
+	case 2:
+		dev_info(rkc->dev, "DMA_STATE: DMA SRC WORK\n");
+		break;
+	default:
+		dev_err(rkc->dev, "DMA_STATE: DMA SRC invalid\n");
+		break;
+	}
+	switch ((v >> 4) & 0x3) {
+	case 0:
+		dev_info(rkc->dev, "DMA_STATE: DMA LLI IDLE\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "DMA_STATE: DMA LLI LOAD\n");
+		break;
+	case 2:
+		dev_info(rkc->dev, "DMA_STATE: LLI WORK\n");
+		break;
+	default:
+		dev_err(rkc->dev, "DMA_STATE: LLI invalid\n");
+		break;
+	}
+
+	v = readl(rkc->reg + RK2_CRYPTO_DMA_LLI_RADDR);
+	dev_info(rkc->dev, "DMA_LLI_RADDR %x\n", v);
+	v = readl(rkc->reg + RK2_CRYPTO_DMA_SRC_RADDR);
+	dev_info(rkc->dev, "DMA_SRC_RADDR %x\n", v);
+	v = readl(rkc->reg + RK2_CRYPTO_DMA_DST_WADDR);
+	dev_info(rkc->dev, "DMA_DST_WADDR %x\n", v);
+	v = readl(rkc->reg + RK2_CRYPTO_DMA_ITEM_ID);
+	dev_info(rkc->dev, "DMA_ITEM_ID %x\n", v);
+
+	v = readl(rkc->reg + RK2_CRYPTO_CIPHER_ST);
+	dev_info(rkc->dev, "CIPHER_ST %x\n", v);
+	if (v & BIT(0))
+		dev_info(rkc->dev, "CIPHER_ST: BLOCK CIPHER BUSY\n");
+	else
+		dev_info(rkc->dev, "CIPHER_ST: BLOCK CIPHER IDLE\n");
+	if (v & BIT(2))
+		dev_info(rkc->dev, "CIPHER_ST: HASH BUSY\n");
+	else
+		dev_info(rkc->dev, "CIPHER_ST: HASH IDLE\n");
+	if (v & BIT(3))
+		dev_info(rkc->dev, "CIPHER_ST: OTP KEY VALID\n");
+	else
+		dev_info(rkc->dev, "CIPHER_ST: OTP KEY INVALID\n");
+
+	v = readl(rkc->reg + RK2_CRYPTO_CIPHER_STATE);
+	dev_info(rkc->dev, "CIPHER_STATE %x\n", v);
+	switch (v & 0x3) {
+	case 0:
+		dev_info(rkc->dev, "serial: IDLE state\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "serial: PRE state\n");
+		break;
+	case 2:
+		dev_info(rkc->dev, "serial: BULK state\n");
+		break;
+	default:
+		dev_info(rkc->dev, "serial: reserved state\n");
+		break;
+	}
+	switch ((v >> 2) & 0x3) {
+	case 0:
+		dev_info(rkc->dev, "mac_state: IDLE state\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "mac_state: PRE state\n");
+		break;
+	case 2:
+		dev_info(rkc->dev, "mac_state: BULK state\n");
+		break;
+	default:
+		dev_info(rkc->dev, "mac_state: reserved state\n");
+		break;
+	}
+	switch ((v >> 4) & 0x3) {
+	case 0:
+		dev_info(rkc->dev, "parallel_state: IDLE state\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "parallel_state: PRE state\n");
+		break;
+	case 2:
+		dev_info(rkc->dev, "parallel_state: BULK state\n");
+		break;
+	default:
+		dev_info(rkc->dev, "parallel_state: reserved state\n");
+		break;
+	}
+	switch ((v >> 6) & 0x3) {
+	case 0:
+		dev_info(rkc->dev, "ccm_state: IDLE state\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "ccm_state: PRE state\n");
+		break;
+	case 2:
+		dev_info(rkc->dev, "ccm_state: NA state\n");
+		break;
+	default:
+		dev_info(rkc->dev, "ccm_state: reserved state\n");
+		break;
+	}
+	switch ((v >> 8) & 0xF) {
+	case 0:
+		dev_info(rkc->dev, "gcm_state: IDLE state\n");
+		break;
+	case 1:
+		dev_info(rkc->dev, "gcm_state: PRE state\n");
+		break;
+	case 2:
+		dev_info(rkc->dev, "gcm_state: NA state\n");
+		break;
+	case 3:
+		dev_info(rkc->dev, "gcm_state: PC state\n");
+		break;
+	}
+	switch ((v >> 10) & 0x1F) {
+	case 0x1:
+		dev_info(rkc->dev, "hash_state: IDLE state\n");
+		break;
+	case 0x2:
+		dev_info(rkc->dev, "hash_state: IPAD state\n");
+		break;
+	case 0x4:
+		dev_info(rkc->dev, "hash_state: TEXT state\n");
+		break;
+	case 0x8:
+		dev_info(rkc->dev, "hash_state: OPAD state\n");
+		break;
+	case 0x10:
+		dev_info(rkc->dev, "hash_state: OPAD EXT state\n");
+		break;
+	default:
+		dev_info(rkc->dev, "hash_state: invalid state\n");
+		break;
+	}
+
+	v = readl(rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+	dev_info(rkc->dev, "RK2_CRYPTO_DMA_INT_ST %x\n", v);
+}
+#endif
+
+static int rk2_cipher_need_fallback(struct skcipher_request *req)
+{
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+	struct scatterlist *sgs, *sgd;
+	unsigned int stodo, dtodo, len;
+	unsigned int bs = crypto_skcipher_blocksize(tfm);
+
+	if (!req->cryptlen)
+		return true;
+
+	/*
+	 * The hardware XTS implementation programs the tweak once before
+	 * DMA starts and cannot update it at SG boundaries. Restrict to
+	 * exactly one source and one destination SG entry.
+	 */
+	if (algt->is_xts) {
+		if (sg_nents_for_len(req->src, req->cryptlen) != 1)
+			return true;
+		if (sg_nents_for_len(req->dst, req->cryptlen) != 1)
+			return true;
+	}
+
+	len = req->cryptlen;
+	sgs = req->src;
+	sgd = req->dst;
+
+	while (len > 0 && sgs && sgd) {
+		if (!IS_ALIGNED(sgs->offset, sizeof(u32))) {
+			algt->stat_fb_align++;
+			return true;
+		}
+		if (!IS_ALIGNED(sgd->offset, sizeof(u32))) {
+			algt->stat_fb_align++;
+			return true;
+		}
+
+		stodo = min(len, sgs->length);
+		if (stodo % bs) {
+			algt->stat_fb_len++;
+			return true;
+		}
+
+		dtodo = min(len, sgd->length);
+		if (dtodo % bs) {
+			algt->stat_fb_len++;
+			return true;
+		}
+
+		/* DMA engines usually require symmetrical source/destination chunks */
+		if (stodo != dtodo) {
+			algt->stat_fb_sgdiff++;
+			return true;
+		}
+
+		len -= stodo;
+		sgs = sg_next(sgs);
+		sgd = sg_next(sgd);
+	}
+
+	/* If len > 0, the scatterlist was too short for the request */
+	return len > 0;
+}
+
+static int rk2_cipher_fallback(struct skcipher_request *areq)
+{
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+	struct rk2_cipher_ctx *op = crypto_skcipher_ctx(tfm);
+	struct rk2_cipher_rctx *rctx = skcipher_request_ctx(areq);
+	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+	int err;
+
+	algt->stat_fb++;
+
+	skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
+	skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
+				      areq->base.complete, areq->base.data);
+	skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst,
+				   areq->cryptlen, areq->iv);
+
+	if (rctx->mode & RK2_CRYPTO_DEC)
+		err = crypto_skcipher_decrypt(&rctx->fallback_req);
+	else
+		err = crypto_skcipher_encrypt(&rctx->fallback_req);
+	return err;
+}
+
+static int rk2_cipher_handle_req(struct skcipher_request *req)
+{
+	struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req);
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+	struct rk2_crypto_template *algt =
+			container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+	struct rk2_crypto_dev *rkc;
+	struct crypto_engine *engine;
+
+	if (algt->is_xts && ctx->keylen == AES_KEYSIZE_192 * 2)
+		return rk2_cipher_fallback(req);
+
+	if (rk2_cipher_need_fallback(req))
+		return rk2_cipher_fallback(req);
+
+	rkc = algt->dev;
+	if (!rkc)
+		return -ENODEV;
+	engine = rkc->engine;
+	rctx->dev = rkc;
+
+	return crypto_transfer_skcipher_request_to_engine(engine, req);
+}
+
+/**
+ * rk2_aes_setkey() - Configure the key for standard AES algorithms
+ * @cipher: The crypto skcipher handle.
+ * @key: Buffer containing the raw key material.
+ * @keylen: Length of the key in bytes.
+ *
+ * Validates key length, stores the key in the context, and configures
+ * the software fallback transformation.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_aes_setkey(struct crypto_skcipher *cipher, const u8 *key,
+		   unsigned int keylen)
+{
+	struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher);
+	struct rk2_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
+	    keylen != AES_KEYSIZE_256)
+		return -EINVAL;
+	ctx->keylen = keylen;
+	memcpy(ctx->key, key, keylen);
+
+	crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK);
+	crypto_skcipher_set_flags(ctx->fallback_tfm,
+	crypto_skcipher_get_flags(cipher) & CRYPTO_TFM_REQ_MASK);
+
+	return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen);
+}
+
+/**
+ * rk2_aes_xts_setkey() - Configure the key for AES-XTS mode
+ * @cipher: The crypto skcipher handle.
+ * @key: Buffer containing both cipher and tweak keys.
+ * @keylen: Total length of the key in bytes.
+ *
+ * Validates XTS-specific bounds (e.g., FIPS requirements) and configures
+ * both the hardware context and fallback.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_aes_xts_setkey(struct crypto_skcipher *cipher, const u8 *key,
+		       unsigned int keylen)
+{
+	struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher);
+	struct rk2_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	int err;
+
+	err = xts_verify_key(cipher, key, keylen);
+	if (err)
+		return err;
+
+	ctx->keylen = keylen;
+	memcpy(ctx->key, key, keylen);
+
+	crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK);
+	crypto_skcipher_set_flags(ctx->fallback_tfm,
+	crypto_skcipher_get_flags(cipher) & CRYPTO_TFM_REQ_MASK);
+
+	return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen);
+}
+
+/**
+ * rk2_skcipher_encrypt() - General skcipher encryption entry point
+ * @req: The skcipher request structure.
+ *
+ * Evaluates hardware constraints and enqueues the request into the crypto
+ * engine, or diverts to software fallback.
+ *
+ * Return: 0 on success, negative error code, or -EINPROGRESS.
+ */
+int rk2_skcipher_encrypt(struct skcipher_request *req)
+{
+	struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req);
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+	struct rk2_crypto_template *algt =
+		container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+
+	rctx->mode = algt->rk2_mode;
+	return rk2_cipher_handle_req(req);
+}
+
+/**
+ * rk2_skcipher_decrypt() - General skcipher decryption entry point
+ * @req: The skcipher request structure.
+ *
+ * Evaluates hardware constraints and enqueues the request into the crypto
+ * engine, or diverts to software fallback.
+ *
+ * Return: 0 on success, negative error code, or -EINPROGRESS.
+ */
+int rk2_skcipher_decrypt(struct skcipher_request *req)
+{
+	struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req);
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+
+	rctx->mode = algt->rk2_mode | RK2_CRYPTO_DEC;
+	return rk2_cipher_handle_req(req);
+}
+
+/**
+ * rk2_cipher_run() - Execute an asynchronous skcipher request
+ * @engine: The crypto engine queue managing this request.
+ * @async_req: The asynchronous skcipher request to process.
+ *
+ * Prepares the hardware context, configures DMA descriptors, programs
+ * cipher registers, and triggers the physical cryptographic accelerator.
+ *
+ * Return: Always 0. Errors are reported through the crypto engine
+ *         finalization callback.
+ */
+int rk2_cipher_run(struct crypto_engine *engine, void *async_req)
+{
+	struct skcipher_request *areq =
+	    container_of(async_req, struct skcipher_request, base);
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+	struct rk2_cipher_rctx *rctx = skcipher_request_ctx(areq);
+	struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+	struct scatterlist *sgs, *sgd;
+	int err = 0;
+	int ivsize = crypto_skcipher_ivsize(tfm);
+	unsigned int len = areq->cryptlen;
+	unsigned int todo;
+	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+	struct rk2_crypto_dev *rkc = rctx->dev;
+	struct rk2_crypto_lli *dd = &rkc->tl[0];
+	u32 m, v;
+	u32 *rkey = (u32 *) ctx->key;
+	u32 *riv = (u32 *) areq->iv;
+	int i;
+	unsigned int offset;
+	unsigned long timeout;
+
+	m = rctx->mode | RK2_CRYPTO_ENABLE;
+	if (algt->is_xts) {
+		switch (ctx->keylen) {
+		case AES_KEYSIZE_128 * 2:
+			m |= RK2_CRYPTO_AES_128BIT_key;
+			break;
+		case AES_KEYSIZE_256 * 2:
+			m |= RK2_CRYPTO_AES_256BIT_key;
+			break;
+		default:
+			dev_err(rkc->dev, "Invalid key length %u\n",
+				ctx->keylen);
+			err = -EINVAL;
+			goto exit_no_pm;
+		}
+	} else {
+		switch (ctx->keylen) {
+		case AES_KEYSIZE_128:
+			m |= RK2_CRYPTO_AES_128BIT_key;
+			break;
+		case AES_KEYSIZE_192:
+			m |= RK2_CRYPTO_AES_192BIT_key;
+			break;
+		case AES_KEYSIZE_256:
+			m |= RK2_CRYPTO_AES_256BIT_key;
+			break;
+		default:
+			dev_err(rkc->dev, "Invalid key length %u\n",
+				ctx->keylen);
+			err = -EINVAL;
+			goto exit_no_pm;
+		}
+	}
+
+	err = pm_runtime_resume_and_get(rkc->dev);
+	if (err)
+		goto exit_no_pm;
+
+	algt->stat_req++;
+	rkc->nreq++;
+
+	/* the upper bits are a write enable mask, so we need to write 1 to all
+	 * upper 16 bits to allow write to the 16 lower bits
+	 */
+	m |= 0xffff0000;
+
+	dev_dbg(rkc->dev, "%s %s len=%u keylen=%u mode=%x\n", __func__,
+		crypto_tfm_alg_name(areq->base.tfm),
+		areq->cryptlen, ctx->keylen, m);
+	sgs = areq->src;
+	sgd = areq->dst;
+
+	while (sgs && sgd && len) {
+		if (!sgs->length) {
+			sgs = sg_next(sgs);
+			sgd = sg_next(sgd);
+			continue;
+		}
+
+		if (areq->iv && crypto_skcipher_ivsize(tfm) > 0) {
+			if (rctx->mode & RK2_CRYPTO_DEC) {
+				offset = sgs->length - ivsize;
+				scatterwalk_map_and_copy(rctx->backup_iv, sgs,
+							 offset, ivsize, 0);
+			}
+		}
+
+		dev_dbg(rkc->dev, "SG len=%u mode=%x ivsize=%u\n", sgs->length,
+			m, ivsize);
+
+		if (sgs == sgd) {
+			err = dma_map_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL);
+			if (err != 1) {
+				dev_err(rkc->dev, "Invalid sg number %d\n",
+					err);
+				err = -EINVAL;
+				goto exit;
+			}
+		} else {
+			err = dma_map_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE);
+			if (err != 1) {
+				dev_err(rkc->dev, "Invalid sg number %d\n",
+					err);
+				err = -EINVAL;
+				goto exit;
+			}
+			err = dma_map_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE);
+			if (err != 1) {
+				dev_err(rkc->dev, "Invalid sg number %d\n",
+					err);
+				err = -EINVAL;
+				dma_unmap_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE);
+				goto exit;
+			}
+		}
+		err = 0;
+		writel(m, rkc->reg + RK2_CRYPTO_BC_CTL);
+
+		if (algt->is_xts) {
+			for (i = 0; i < ctx->keylen / 8; i++) {
+				v = cpu_to_be32(rkey[i]);
+				writel(v, rkc->reg + RK2_CRYPTO_KEY0 + i * 4);
+			}
+			for (i = 0; i < (ctx->keylen / 8); i++) {
+				v = cpu_to_be32(rkey[i + ctx->keylen / 8]);
+				writel(v,
+				       rkc->reg + RK2_CRYPTO_CH4_KEY0 + i * 4);
+			}
+		} else {
+			for (i = 0; i < ctx->keylen / 4; i++) {
+				v = cpu_to_be32(rkey[i]);
+				writel(v, rkc->reg + RK2_CRYPTO_KEY0 + i * 4);
+			}
+		}
+
+		if (ivsize) {
+			for (i = 0; i < ivsize / 4; i++)
+				writel(cpu_to_be32(riv[i]),
+				       rkc->reg + RK2_CRYPTO_CH0_IV_0 + i * 4);
+			writel(ivsize, rkc->reg + RK2_CRYPTO_CH0_IV_LEN);
+		}
+
+		/*
+		 * Process one SG entry per DMA operation. The cipher engine requires
+		 * the IV to be updated between SG entries for CBC and XTS modes;
+		 * the backup_iv mechanism handles this correctly for decryption.
+		 * Building a full multi-descriptor chain is possible but adds
+		 * complexity for no measurable throughput gain on typical workloads.
+		 */
+		todo = min(sg_dma_len(sgs), len);
+		len -= todo;
+		dd->src_addr = sg_dma_address(sgs);
+		dd->src_len = todo;
+		dd->dst_addr = sg_dma_address(sgd);
+		dd->dst_len = todo;
+		dd->iv = 0;
+
+		/*
+		 * next is ignored by hardware when RK2_LLI_DMA_CTRL_LAST is set in
+		 * dma_ctrl. Set it to an obviously-invalid-but-non-zero sentinel so
+		 * it stands out if ever read in a debug dump.
+		 */
+		dd->next = 1;
+
+		dd->user = RK2_LLI_CIPHER_START |
+		    RK2_LLI_STRING_FIRST | RK2_LLI_STRING_LAST;
+		dd->dma_ctrl = RK2_LLI_DMA_CTRL_DST_INT |
+		    RK2_LLI_DMA_CTRL_LAST | RK2_LLI_DMA_CTRL_LIST_INT;
+
+		/* Clear stale interrupts, then enable with proper write-mask */
+		writel(RK2_CRYPTO_DMA_INT_ALL_MASK, rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+		writel(RK2_CRYPTO_DMA_INT_ENABLE_ALL, rkc->reg + RK2_CRYPTO_DMA_INT_EN);
+
+		writel(rkc->t_phy, rkc->reg + RK2_CRYPTO_DMA_LLI_ADDR);
+
+		reinit_completion(&rkc->complete);
+		rkc->status = 0;
+
+		writel(RK2_CRYPTO_DMA_CTL_START |
+		       (RK2_CRYPTO_DMA_CTL_START << 16),
+		       rkc->reg + RK2_CRYPTO_DMA_CTL);
+
+		timeout = wait_for_completion_timeout(&rkc->complete,
+						      msecs_to_jiffies(2000));
+		if (sgs == sgd) {
+			dma_unmap_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL);
+		} else {
+			dma_unmap_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE);
+			dma_unmap_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE);
+		}
+
+		if (!timeout) {
+			dev_err(rkc->dev, "DMA timeout\n");
+			err = -ETIMEDOUT;
+			reset_control_assert(rkc->rst);
+			udelay(10);
+			reset_control_deassert(rkc->rst);
+			goto exit;
+		}
+
+		if (!rkc->status) {
+			dev_err(rkc->dev, "DMA error\n");
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+			rk2_print(rkc);
+#endif
+			err = -EIO;
+			reset_control_assert(rkc->rst);
+			udelay(10);
+			reset_control_deassert(rkc->rst);
+			goto exit;
+		}
+
+		if (areq->iv && ivsize > 0) {
+			offset = sgd->length - ivsize;
+			if (rctx->mode & RK2_CRYPTO_DEC) {
+				memcpy(areq->iv, rctx->backup_iv, ivsize);
+				memzero_explicit(rctx->backup_iv, ivsize);
+			} else {
+				scatterwalk_map_and_copy(areq->iv, sgd, offset,
+							 ivsize, 0);
+			}
+		}
+		sgs = sg_next(sgs);
+		sgd = sg_next(sgd);
+	}
+ exit:
+	writel(0xffff0000, rkc->reg + RK2_CRYPTO_BC_CTL);
+	pm_runtime_mark_last_busy(rkc->dev);
+	pm_runtime_put_autosuspend(rkc->dev);
+ exit_no_pm:
+	local_bh_disable();
+	crypto_finalize_skcipher_request(engine, areq, err);
+	local_bh_enable();
+	return 0;
+}
+
+/**
+ * rk2_cipher_tfm_init() - Initialize the transformation context
+ * @tfm: The crypto skcipher handle.
+ *
+ * Allocates the software fallback transformations required when requests
+ * fail to meet hardware constraints (e.g., severe scatterlist misalignment).
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_cipher_tfm_init(struct crypto_skcipher *tfm)
+{
+	struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+	const char *name = crypto_tfm_alg_name(&tfm->base);
+	struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+	struct rk2_crypto_template *algt =
+	    container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+
+	ctx->fallback_tfm =
+	    crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
+	if (IS_ERR(ctx->fallback_tfm)) {
+		dev_err(algt->dev->dev,
+			"Cannot allocate fallback for %s %ld\n", name,
+			PTR_ERR(ctx->fallback_tfm));
+		return PTR_ERR(ctx->fallback_tfm);
+	}
+
+	dev_dbg(algt->dev->dev, "Fallback for %s is %s\n",
+		crypto_tfm_alg_driver_name(&tfm->base),
+		crypto_tfm_alg_driver_name(crypto_skcipher_tfm
+					   (ctx->fallback_tfm)));
+
+	tfm->reqsize = sizeof(struct rk2_cipher_rctx) +
+	    crypto_skcipher_reqsize(ctx->fallback_tfm);
+
+	return 0;
+}
+
+/**
+ * rk2_cipher_tfm_exit() - Free skcipher initialization resources
+ * @tfm: The crypto skcipher handle.
+ *
+ * Synchronously releases internal software fallback transformations
+ * and zeroes out sensitive key material.
+ */
+void rk2_cipher_tfm_exit(struct crypto_skcipher *tfm)
+{
+	struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+	memzero_explicit(ctx->key, ctx->keylen);
+	crypto_free_skcipher(ctx->fallback_tfm);
+}
-- 
2.47.3


^ permalink raw reply related

* [PATCH 1/4] dt-bindings: crypto: rockchip: Add RK356x/RK3588 crypto engine binding
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
  To: herbert, davem, heiko
  Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
	clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
In-Reply-To: <20260530160704.3453555-1-dawidro@gmail.com>

Add a YAML device tree binding for the Rockchip second-generation (V2)
cryptographic hardware accelerator present on the RK3568 and RK3588 SoCs.

The IP block exposes AES-ECB, AES-CBC, AES-XTS block ciphers, SHA-1,
SHA-224, SHA-256, SHA-384, SHA-512, MD5, and SM3 hash algorithms, each
with a hardware DMA engine controlled via linked-list descriptors.

The binding covers two compatible strings:

  - rockchip,rk3568-crypto: clocks and resets are driven directly by the
    non-secure CRU (accessible to Linux at EL1).
  - rockchip,rk3588-crypto: clocks and resets live in SECURECRU, a
    register bank sandboxed to TrustZone. Linux must request them through
    the ARM SCMI firmware interface (scmi_clk / scmi_reset), as direct
    MMIO access to SECURECRU from EL1 triggers a bus fault.

Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
---
 .../crypto/rockchip,rk3588-crypto.yaml        | 69 +++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml

diff --git a/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml b/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml
new file mode 100644
index 000000000000..4188ed8920db
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/rockchip,rk3588-crypto.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip cryptographic offloader
+
+maintainers:
+  - Heiko Stuebner <heiko@sntech.de>
+  - Corentin Labbe <clabbe@baylibre.com>
+  - Dawid Olesinski <dawidro@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk3568-crypto
+      - rockchip,rk3588-crypto
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Core clock for the crypto IP internal logic
+      - description: AXI interconnect clock interface
+      - description: AHB interface clock
+
+  clock-names:
+    items:
+      - const: core
+      - const: aclk
+      - const: hclk
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: core
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    crypto@fe370000 {
+        compatible = "rockchip,rk3588-crypto";
+        reg = <0x0 0xfe370000 0x0 0x2000>;
+        interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH 0>;
+        clocks = <&scmi_clk SCMI_CRYPTO_CORE>,
+                 <&scmi_clk SCMI_ACLK_SECURE_NS>,
+                 <&scmi_clk SCMI_HCLK_SECURE_NS>;
+        clock-names = "core", "aclk", "hclk";
+        resets = <&scmi_reset SCMI_SRST_CRYPTO_CORE>;
+        reset-names = "core";
+    };
-- 
2.47.3


^ permalink raw reply related

* [PATCH 0/4] crypto: rockchip: Add RK356x/RK3588 cryptographic
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
  To: herbert, davem, heiko
  Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
	clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski

This series adds support for the second-generation (V2) Rockchip
cryptographic hardware accelerator found on RK3568 and RK3588 SoCs.

The IP block provides AES (ECB, CBC, XTS) and hash (SHA-1, SHA-256,
SHA-384, SHA-512, MD5, SM3) offload via an LLI-based DMA engine.

The series is ordered as required: binding first, then driver, then
the two DTS nodes that reference the binding.

A prerequisite patch removing SECURECRU reset definitions from the
non-secure CRU driver is sent separately to the clk/reset tree, as it
touches a different subsystem. That patch is not a hard dependency for
the driver to build or load, but it is needed for correctness on RK3588:
those register offsets map into TrustZone-protected MMIO and must not be
accessed directly by Linux.

This work started from unmerged patches by Corentin Labbe
<clabbe@baylibre.com> posted at:
https://patchew.org/linux/20231107155532.3747113-1-clabbe@baylibre.com/

The implementation has been substantially reworked. Notable changes from
Corentin's original series:
  - DMA descriptor race condition and DMA mapping leak on timeout fixed
  - Per-device algorithm copy replaces global device list, removing a
    locking bottleneck and correctly supporting multiple instances
  - Runtime PM autosuspend added; clocks and reset gated between requests
  - Multi-SG hash requests routed to software fallback (hardware padding
    engine requires total message length upfront and cannot maintain
    state across LLI boundaries)
  - Hardware interrupt enable register write corrected to use the
    HIWORD_UPDATE mask that the hardware requires
  - Software fallback for all registered algorithms; statesize promotion
    for export/import compatibility with ARM Crypto Extensions drivers
  - SCMI reset and clock references in DTS corrected for RK3588

Tested on Orange Pi 5 Pro (RK3588S). All nine algorithm selftests pass.
AES-CBC throughput measured at ~100 MiB/s with cryptsetup. PM
autosuspend/resume verified over 1000 consecutive hash requests with no
errors. 20 modprobe/rmmod cycles produce no DMA coherent memory leaks.

Patch series for the crypto subsystem:
  [1/4] dt-bindings: crypto: rockchip: Add RK356x/RK3588 crypto engine
  binding
  [2/4] crypto: rockchip: Add RK356x/RK3588 cryptographic offloader driver
  [3/4] arm64: dts: rockchip: Add crypto node to rk356x-base
  [4/4] arm64: dts: rockchip: Add crypto node to rk3588-base

Separate patch for clk/reset tree:
  clk: rockchip: rk3588: Remove SECURECRU reset definitions

Signed-off-by: Dawid Olesinski <dawidro@gmail.com>

Dawid Olesinski (4):
  dt-bindings: crypto: rockchip: Add RK356x/RK3588 crypto engine binding
  crypto: rockchip: Add RK356x/RK3588 cryptographic offloader driver
  arm64: dts: rockchip: Add crypto node to rk356x-base
  arm64: dts: rockchip: Add crypto node to rk3588-base

 .../crypto/rockchip,rk3588-crypto.yaml        |  69 ++
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi |  12 +
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi |  12 +
 drivers/crypto/Kconfig                        |  33 +
 drivers/crypto/Makefile                       |   1 +
 drivers/crypto/rockchip/Makefile              |   5 +
 drivers/crypto/rockchip/rk2_crypto.c          | 740 ++++++++++++++++++
 drivers/crypto/rockchip/rk2_crypto.h          | 243 ++++++
 drivers/crypto/rockchip/rk2_crypto_ahash.c    | 547 +++++++++++++
 drivers/crypto/rockchip/rk2_crypto_skcipher.c | 724 +++++++++++++++++
 10 files changed, 2386 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml
 create mode 100644 drivers/crypto/rockchip/rk2_crypto.c
 create mode 100644 drivers/crypto/rockchip/rk2_crypto.h
 create mode 100644 drivers/crypto/rockchip/rk2_crypto_ahash.c
 create mode 100644 drivers/crypto/rockchip/rk2_crypto_skcipher.c

-- 
2.47.3


^ permalink raw reply

* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Aleksander Jan Bajkowski @ 2026-05-30 15:05 UTC (permalink / raw)
  To: Eric Biggers, linux-crypto, Herbert Xu
  Cc: Christian Lamparter, linuxppc-dev, linux-kernel, stable
In-Reply-To: <20260529220430.34135-1-ebiggers@kernel.org>

Hi Eric,

On 30/05/2026 00:04, Eric Biggers wrote:
> Remove crypto4xx_rng, as it is insecure and unused:
>
> - It has only a 64-bit security strength, which is highly inadequate.
>    This can be seen by the fact that crypto4xx_hw_init() seeds it with
>    only 64 bits of entropy, and the fact that the original commit
>    mentions that it implements ANSI X9.17 Annex C.

In addition to a seed, the PRNG also uses ring oscillators as sources of
entropy. The entropy should be higher than 64b. This is the Rambus EIP-73d
IP core. The same IP core is built into eip93 (EIP-73a), eip97 (EIP-73d),
and eip197 (EIP-73d). You can find the documentation online. The complete
"container" is actually Rambus EIP-94, and one of its parts is EIP-73d.

>
>    Another issue was that this driver didn't implement the crypto_rng API
>    correctly, as crypto4xx_prng_generate() didn't return 0 on success.
>
> - No user of this code is known.  It's usable only theoretically via the
>    "rng" algorithm type of AF_ALG.  But userspace actually just uses the
>    actual Linux RNG (/dev/random etc) instead.  And rng_algs don't
>    contribute entropy to the actual Linux RNG either.  (This may have
>    been confused with hwrng, which does contribute entropy.)

This PRNG is also used internally for Generation IV with IPSEC offload. The
IPSEC offload implementation for eip93 was recently submitted to upstream.
I am not sure whether eip94 shares some of the logic for IPSEC offload and
it will be possible to use some of the code.

>
> Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support")
> Cc: stable@vger.kernel.org
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> Acked-by: Christian Lamparter <chunkeey@gmail.com>
> ---
>   drivers/crypto/Kconfig                  |  1 -
>   drivers/crypto/amcc/crypto4xx_core.c    | 88 -------------------------
>   drivers/crypto/amcc/crypto4xx_core.h    |  4 --
>   drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ----
>   4 files changed, 104 deletions(-)
>
>
> base-commit: 49e05bb00f2e8168695f7af4d694c39e1423e8a2
>
> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> index 3449b3c9c6ad..5dab813a9f74 100644
> --- a/drivers/crypto/Kconfig
> +++ b/drivers/crypto/Kconfig
> @@ -299,11 +299,10 @@ config CRYPTO_DEV_PPC4XX
>   	select CRYPTO_AES
>   	select CRYPTO_LIB_AES
>   	select CRYPTO_CCM
>   	select CRYPTO_CTR
>   	select CRYPTO_GCM
> -	select CRYPTO_RNG
>   	select CRYPTO_SKCIPHER
>   	help
>   	  This option allows you to have support for AMCC crypto acceleration.
>   
>   config HW_RANDOM_PPC4XX
> diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
> index b7b6c97d2147..68c5ff7a85b4 100644
> --- a/drivers/crypto/amcc/crypto4xx_core.c
> +++ b/drivers/crypto/amcc/crypto4xx_core.c
> @@ -29,15 +29,13 @@
>   #include <crypto/aead.h>
>   #include <crypto/aes.h>
>   #include <crypto/ctr.h>
>   #include <crypto/gcm.h>
>   #include <crypto/sha1.h>
> -#include <crypto/rng.h>
>   #include <crypto/scatterwalk.h>
>   #include <crypto/skcipher.h>
>   #include <crypto/internal/aead.h>
> -#include <crypto/internal/rng.h>
>   #include <crypto/internal/skcipher.h>
>   #include "crypto4xx_reg_def.h"
>   #include "crypto4xx_core.h"
>   #include "crypto4xx_sa.h"
>   #include "crypto4xx_trng.h"
> @@ -983,14 +981,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
>   		switch (alg->alg.type) {
>   		case CRYPTO_ALG_TYPE_AEAD:
>   			rc = crypto_register_aead(&alg->alg.u.aead);
>   			break;
>   
> -		case CRYPTO_ALG_TYPE_RNG:
> -			rc = crypto_register_rng(&alg->alg.u.rng);
> -			break;
> -
>   		default:
>   			rc = crypto_register_skcipher(&alg->alg.u.cipher);
>   			break;
>   		}
>   
> @@ -1012,14 +1006,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
>   		switch (alg->alg.type) {
>   		case CRYPTO_ALG_TYPE_AEAD:
>   			crypto_unregister_aead(&alg->alg.u.aead);
>   			break;
>   
> -		case CRYPTO_ALG_TYPE_RNG:
> -			crypto_unregister_rng(&alg->alg.u.rng);
> -			break;
> -
>   		default:
>   			crypto_unregister_skcipher(&alg->alg.u.cipher);
>   		}
>   		kfree(alg);
>   	}
> @@ -1074,73 +1064,10 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
>   {
>   	return crypto4xx_interrupt_handler(irq, data, PPC4XX_INTERRUPT_CLR |
>   		PPC4XX_TMO_ERR_INT);
>   }
>   
> -static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
> -				 u8 *data, unsigned int max)
> -{
> -	unsigned int i, curr = 0;
> -	u32 val[2];
> -
> -	do {
> -		/* trigger PRN generation */
> -		writel(PPC4XX_PRNG_CTRL_AUTO_EN,
> -		       dev->ce_base + CRYPTO4XX_PRNG_CTRL);
> -
> -		for (i = 0; i < 1024; i++) {
> -			/* usually 19 iterations are enough */
> -			if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
> -			     CRYPTO4XX_PRNG_STAT_BUSY))
> -				continue;
> -
> -			val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
> -			val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
> -			break;
> -		}
> -		if (i == 1024)
> -			return -ETIMEDOUT;
> -
> -		if ((max - curr) >= 8) {
> -			memcpy(data, &val, 8);
> -			data += 8;
> -			curr += 8;
> -		} else {
> -			/* copy only remaining bytes */
> -			memcpy(data, &val, max - curr);
> -			break;
> -		}
> -	} while (curr < max);
> -
> -	return curr;
> -}
> -
> -static int crypto4xx_prng_generate(struct crypto_rng *tfm,
> -				   const u8 *src, unsigned int slen,
> -				   u8 *dstn, unsigned int dlen)
> -{
> -	struct rng_alg *alg = crypto_rng_alg(tfm);
> -	struct crypto4xx_alg *amcc_alg;
> -	struct crypto4xx_device *dev;
> -	int ret;
> -
> -	amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
> -	dev = amcc_alg->dev;
> -
> -	mutex_lock(&dev->core_dev->rng_lock);
> -	ret = ppc4xx_prng_data_read(dev, dstn, dlen);
> -	mutex_unlock(&dev->core_dev->rng_lock);
> -	return ret;
> -}
> -
> -
> -static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
> -			unsigned int slen)
> -{
> -	return 0;
> -}
> -
>   /*
>    * Supported Crypto Algorithms
>    */
>   static struct crypto4xx_alg_common crypto4xx_alg[] = {
>   	/* Crypto AES modes */
> @@ -1266,22 +1193,10 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
>   			.cra_blocksize	= 1,
>   			.cra_ctxsize	= sizeof(struct crypto4xx_ctx),
>   			.cra_module	= THIS_MODULE,
>   		},
>   	} },
> -	{ .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
> -		.base = {
> -			.cra_name		= "stdrng",
> -			.cra_driver_name        = "crypto4xx_rng",
> -			.cra_priority		= 300,
> -			.cra_ctxsize		= 0,
> -			.cra_module		= THIS_MODULE,
> -		},
> -		.generate               = crypto4xx_prng_generate,
> -		.seed                   = crypto4xx_prng_seed,
> -		.seedsize               = 0,
> -	} },
>   };
>   
>   /*
>    * Module Initialization Routine
>    */
> @@ -1351,13 +1266,10 @@ static int crypto4xx_probe(struct platform_device *ofdev)
>   	}
>   
>   	core_dev->dev->core_dev = core_dev;
>   	core_dev->dev->is_revb = is_revb;
>   	core_dev->device = dev;
> -	rc = devm_mutex_init(&ofdev->dev, &core_dev->rng_lock);
> -	if (rc)
> -		return rc;
>   	spin_lock_init(&core_dev->lock);
>   	INIT_LIST_HEAD(&core_dev->dev->alg_list);
>   	ratelimit_default_init(&core_dev->dev->aead_ratelimit);
>   	rc = crypto4xx_build_sdr(core_dev->dev);
>   	if (rc)
> diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
> index ee36630c670f..3a028aec3f0c 100644
> --- a/drivers/crypto/amcc/crypto4xx_core.h
> +++ b/drivers/crypto/amcc/crypto4xx_core.h
> @@ -12,14 +12,12 @@
>   
>   #ifndef __CRYPTO4XX_CORE_H__
>   #define __CRYPTO4XX_CORE_H__
>   
>   #include <linux/ratelimit.h>
> -#include <linux/mutex.h>
>   #include <linux/scatterlist.h>
>   #include <crypto/internal/aead.h>
> -#include <crypto/internal/rng.h>
>   #include <crypto/internal/skcipher.h>
>   #include "crypto4xx_reg_def.h"
>   #include "crypto4xx_sa.h"
>   
>   #define PPC460SX_SDR0_SRST                      0x201
> @@ -109,11 +107,10 @@ struct crypto4xx_core_device {
>   	struct hwrng *trng;
>   	u32 int_status;
>   	u32 irq;
>   	struct tasklet_struct tasklet;
>   	spinlock_t lock;
> -	struct mutex rng_lock;
>   };
>   
>   struct crypto4xx_ctx {
>   	struct crypto4xx_device *dev;
>   	struct dynamic_sa_ctl *sa_in;
> @@ -133,11 +130,10 @@ struct crypto4xx_aead_reqctx {
>   struct crypto4xx_alg_common {
>   	u32 type;
>   	union {
>   		struct skcipher_alg cipher;
>   		struct aead_alg aead;
> -		struct rng_alg rng;
>   	} u;
>   };
>   
>   struct crypto4xx_alg {
>   	struct list_head  entry;
> diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
> index 1038061224da..73d626308a84 100644
> --- a/drivers/crypto/amcc/crypto4xx_reg_def.h
> +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
> @@ -88,24 +88,13 @@
>   
>   #define CRYPTO4XX_DMA_CFG	        	0x000600d4
>   #define CRYPTO4XX_BYTE_ORDER_CFG 		0x000600d8
>   #define CRYPTO4XX_ENDIAN_CFG			0x000600d8
>   
> -#define CRYPTO4XX_PRNG_STAT			0x00070000
> -#define CRYPTO4XX_PRNG_STAT_BUSY		0x1
>   #define CRYPTO4XX_PRNG_CTRL			0x00070004
>   #define CRYPTO4XX_PRNG_SEED_L			0x00070008
>   #define CRYPTO4XX_PRNG_SEED_H			0x0007000c
> -
> -#define CRYPTO4XX_PRNG_RES_0			0x00070020
> -#define CRYPTO4XX_PRNG_RES_1			0x00070024
> -#define CRYPTO4XX_PRNG_RES_2			0x00070028
> -#define CRYPTO4XX_PRNG_RES_3			0x0007002C
> -
> -#define CRYPTO4XX_PRNG_LFSR_L			0x00070030
> -#define CRYPTO4XX_PRNG_LFSR_H			0x00070034
> -
>   /*
>    * Initialize CRYPTO ENGINE registers, and memory bases.
>    */
>   #define PPC4XX_PDR_POLL				0x3ff
>   #define PPC4XX_OUTPUT_THRESHOLD			2

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox