Linux cryptographic layer development
 help / color / mirror / Atom feed
* 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

* [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

* [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 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

* 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

* 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/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

* [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] 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

* 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

* [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

* [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 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 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 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 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 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] 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

* Re: [PATCH 01/29] crypto: talitos/hash - Use CRYPTO_AHASH_BLOCK_ONLY API
From: Christophe Leroy (CS GROUP) @ 2026-06-01  5:40 UTC (permalink / raw)
  To: Paul Louvel, Herbert Xu, David S. Miller
  Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-1-cb1ad6cdea49@bootlin.com>



Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> The hash implementation maintained a software buffer to accumulate
> partial blocks across update() calls, copying data to/from scatterlists
> with sg_copy_to_buffer()/sg_pcopy_to_buffer() and chaining in a virtual
> scatterlist entry.  This is unnecessary now with
> CRYPTO_AHASH_ALG_BLOCK_ONLY flag.
> 
> Remove unnecessary fields in the request and export structure. On
> completion, pass any remaining tail bytes back via
> ahash_request_complete() so that the core re-submits them with the next
> request.
> 
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>

I have a build failure with this patch:

   UPD     include/config/kernel.release
   UPD     include/generated/utsrelease.h
   DESCEND objtool
   INSTALL libsubcmd_headers
   CC      drivers/crypto/talitos.o
drivers/crypto/talitos.c: In function 'talitos_cra_init_ahash':
drivers/crypto/talitos.c:3150:34: warning: statement with no effect 
[-Wunused-value]
  3150 |                                  sizeof(struct 
talitos_ahash_req_ctx));
       |                                  ^~~~~~
drivers/crypto/talitos.c:3150:70: error: expected ';' before ')' token
  3150 |                                  sizeof(struct 
talitos_ahash_req_ctx));
       | 
      ^
       | 
      ;
drivers/crypto/talitos.c:3150:70: error: expected statement before ')' token
make[4]: *** [scripts/Makefile.build:289: drivers/crypto/talitos.o] Error 1
make[3]: *** [scripts/Makefile.build:548: drivers/crypto] Error 2
make[2]: *** [scripts/Makefile.build:548: drivers] Error 2
make[1]: *** [/home/chleroy/linux-powerpc/Makefile:2141: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2


> ---
>   drivers/crypto/talitos.c | 149 ++++++++++++++++++-----------------------------
>   1 file changed, 57 insertions(+), 92 deletions(-)
> 
> diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
> index 584508963241..3610d9f6d5ea 100644
> --- a/drivers/crypto/talitos.c
> +++ b/drivers/crypto/talitos.c
> @@ -941,25 +941,18 @@ struct talitos_ctx {
>   struct talitos_ahash_req_ctx {
>   	u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
>   	unsigned int hw_context_size;
> -	u8 buf[2][HASH_MAX_BLOCK_SIZE];
> -	int buf_idx;
>   	unsigned int swinit;
>   	unsigned int first_request;
>   	unsigned int last_request;
>   	unsigned int to_hash_later;
> -	unsigned int nbuf;
> -	struct scatterlist bufsl[2];
> -	struct scatterlist *psrc;
>   };
>   
>   struct talitos_export_state {
>   	u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
> -	u8 buf[HASH_MAX_BLOCK_SIZE];
>   	unsigned int swinit;
>   	unsigned int first_request;
>   	unsigned int last_request;
>   	unsigned int to_hash_later;
> -	unsigned int nbuf;
>   };
>   
>   static int aead_setkey(struct crypto_aead *authenc,
> @@ -1826,14 +1819,8 @@ static void ahash_done(struct device *dev,
>   	struct talitos_edesc *next;
>   
>   	if (is_sec1) {
> -		if (!req_ctx->last_request && req_ctx->to_hash_later) {
> -			/* Position any partial block for next update/final/finup */
> -			req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
> -			req_ctx->nbuf = req_ctx->to_hash_later;
> -		}
> -
>   		free_edesc_list_from(areq, edesc);
> -		ahash_request_complete(areq, err);
> +		ahash_request_complete(areq, err ?: req_ctx->to_hash_later);
>   	} else {
>   		next = edesc->next_desc;
>   
> @@ -1851,14 +1838,9 @@ static void ahash_done(struct device *dev,
>   			return;
>   		}
>   out:
> -		if (!req_ctx->last_request && req_ctx->to_hash_later) {
> -			/* Position any partial block for next update/final/finup */
> -			req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
> -			req_ctx->nbuf = req_ctx->to_hash_later;
> -		}
>   		if (err && next)
>   			free_edesc_list_from(areq, next);
> -		ahash_request_complete(areq, err);
> +		ahash_request_complete(areq, err ?: req_ctx->to_hash_later);
>   	}
>   }
>   
> @@ -1978,7 +1960,7 @@ ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes,
>   	size_t offset = 0;
>   
>   	do {
> -		src = scatterwalk_ffwd(tmp, req_ctx->psrc, offset);
> +		src = scatterwalk_ffwd(tmp, areq->src, offset);
>   
>   		to_hash_this_desc =
>   			min(nbytes, ALIGN_DOWN(desc_max, blocksize));
> @@ -1991,8 +1973,7 @@ ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes,
>   			return edesc;
>   		}
>   
> -		edesc->src =
> -			scatterwalk_ffwd(edesc->bufsl, req_ctx->psrc, offset);
> +		edesc->src = scatterwalk_ffwd(edesc->bufsl, areq->src, offset);
>   		edesc->desc.hdr = ctx->desc_hdr_template;
>   		edesc->first = offset == 0;
>   		edesc->last = nbytes - to_hash_this_desc == 0;
> @@ -2045,62 +2026,17 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
>   	bool is_sec1 = has_ftr_sec1(dev_get_drvdata(ctx->dev));
>   	unsigned int nbytes_to_hash;
>   	unsigned int to_hash_later;
> -	unsigned int nsg;
> -	int nents;
>   	struct device *dev = ctx->dev;
> -	u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
>   	int ret;
>   
> -	if (!req_ctx->last_request && (nbytes + req_ctx->nbuf <= blocksize)) {
> -		/* Buffer up to one whole block */
> -		nents = sg_nents_for_len(areq->src, nbytes);
> -		if (nents < 0) {
> -			dev_err(dev, "Invalid number of src SG.\n");
> -			return nents;
> -		}
> -		sg_copy_to_buffer(areq->src, nents,
> -				  ctx_buf + req_ctx->nbuf, nbytes);
> -		req_ctx->nbuf += nbytes;
> -		return 0;
> -	}
> -
> -	/* At least (blocksize + 1) bytes are available to hash */
> -	nbytes_to_hash = nbytes + req_ctx->nbuf;
> -	to_hash_later = nbytes_to_hash & (blocksize - 1);
> +	nbytes_to_hash = ALIGN_DOWN(nbytes, blocksize);
> +	to_hash_later = nbytes - nbytes_to_hash;
>   
> -	if (req_ctx->last_request)
> +	if (req_ctx->last_request) {
> +		nbytes_to_hash = nbytes;
>   		to_hash_later = 0;
> -	else if (to_hash_later)
> -		/* There is a partial block. Hash the full block(s) now */
> -		nbytes_to_hash -= to_hash_later;
> -	else {
> -		/* Keep one block buffered */
> -		nbytes_to_hash -= blocksize;
> -		to_hash_later = blocksize;
> -	}
> -
> -	/* Chain in any previously buffered data */
> -	if (req_ctx->nbuf) {
> -		nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1;
> -		sg_init_table(req_ctx->bufsl, nsg);
> -		sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
> -		if (nsg > 1)
> -			sg_chain(req_ctx->bufsl, 2, areq->src);
> -		req_ctx->psrc = req_ctx->bufsl;
> -	} else
> -		req_ctx->psrc = areq->src;
> -
> -	if (to_hash_later) {
> -		nents = sg_nents_for_len(areq->src, nbytes);
> -		if (nents < 0) {
> -			dev_err(dev, "Invalid number of src SG.\n");
> -			return nents;
> -		}
> -		sg_pcopy_to_buffer(areq->src, nents,
> -				   req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
> -				      to_hash_later,
> -				      nbytes - to_hash_later);
>   	}
> +
>   	req_ctx->to_hash_later = to_hash_later;
>   
>   	edesc = ahash_process_req_prepare(areq, nbytes_to_hash, blocksize,
> @@ -2125,8 +2061,6 @@ static int ahash_init(struct ahash_request *areq)
>   	dma_addr_t dma;
>   
>   	/* Initialize the context */
> -	req_ctx->buf_idx = 0;
> -	req_ctx->nbuf = 0;
>   	req_ctx->first_request = 1;
>   	req_ctx->swinit = 0; /* assume h/w init of context */
>   	size =	(crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
> @@ -2223,12 +2157,10 @@ static int ahash_export(struct ahash_request *areq, void *out)
>   
>   	memcpy(export->hw_context, req_ctx->hw_context,
>   	       req_ctx->hw_context_size);
> -	memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
>   	export->swinit = req_ctx->swinit;
>   	export->first_request = req_ctx->first_request;
>   	export->last_request = req_ctx->last_request;
>   	export->to_hash_later = req_ctx->to_hash_later;
> -	export->nbuf = req_ctx->nbuf;
>   
>   	return 0;
>   }
> @@ -2249,12 +2181,10 @@ static int ahash_import(struct ahash_request *areq, const void *in)
>   			: TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
>   	req_ctx->hw_context_size = size;
>   	memcpy(req_ctx->hw_context, export->hw_context, size);
> -	memcpy(req_ctx->buf[0], export->buf, export->nbuf);
>   	req_ctx->swinit = export->swinit;
>   	req_ctx->first_request = export->first_request;
>   	req_ctx->last_request = export->last_request;
>   	req_ctx->to_hash_later = export->to_hash_later;
> -	req_ctx->nbuf = export->nbuf;
>   
>   	dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
>   			     DMA_TO_DEVICE);
> @@ -2932,8 +2862,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "md5",
>   				.cra_driver_name = "md5-talitos",
>   				.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -2948,8 +2881,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "sha1",
>   				.cra_driver_name = "sha1-talitos",
>   				.cra_blocksize = SHA1_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -2964,8 +2900,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "sha224",
>   				.cra_driver_name = "sha224-talitos",
>   				.cra_blocksize = SHA224_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -2980,8 +2919,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "sha256",
>   				.cra_driver_name = "sha256-talitos",
>   				.cra_blocksize = SHA256_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -2996,8 +2938,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "sha384",
>   				.cra_driver_name = "sha384-talitos",
>   				.cra_blocksize = SHA384_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3012,8 +2957,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "sha512",
>   				.cra_driver_name = "sha512-talitos",
>   				.cra_blocksize = SHA512_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3028,8 +2976,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "hmac(md5)",
>   				.cra_driver_name = "hmac-md5-talitos",
>   				.cra_blocksize = MD5_HMAC_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3044,8 +2995,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "hmac(sha1)",
>   				.cra_driver_name = "hmac-sha1-talitos",
>   				.cra_blocksize = SHA1_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3060,8 +3014,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "hmac(sha224)",
>   				.cra_driver_name = "hmac-sha224-talitos",
>   				.cra_blocksize = SHA224_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3076,8 +3033,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "hmac(sha256)",
>   				.cra_driver_name = "hmac-sha256-talitos",
>   				.cra_blocksize = SHA256_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3092,8 +3052,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "hmac(sha384)",
>   				.cra_driver_name = "hmac-sha384-talitos",
>   				.cra_blocksize = SHA384_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3108,8 +3071,11 @@ static struct talitos_alg_template driver_algs[] = {
>   				.cra_name = "hmac(sha512)",
>   				.cra_driver_name = "hmac-sha512-talitos",
>   				.cra_blocksize = SHA512_BLOCK_SIZE,
> +				.cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
>   				.cra_flags = CRYPTO_ALG_ASYNC |
> -					     CRYPTO_ALG_ALLOCATES_MEMORY,
> +					     CRYPTO_ALG_ALLOCATES_MEMORY |
> +					     CRYPTO_AHASH_ALG_BLOCK_ONLY |
> +					     CRYPTO_AHASH_ALG_FINAL_NONZERO,
>   			}
>   		},
>   		.desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3181,7 +3147,6 @@ static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
>   				   algt.alg.hash);
>   
>   	ctx->keylen = 0;
> -	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
>   				 sizeof(struct talitos_ahash_req_ctx));
>   
>   	return talitos_init_common(ctx, talitos_alg);
> 


^ permalink raw reply

* Re: [PATCH 06/29] crypto: talitos - Introduce registration helper
From: Christophe Leroy (CS GROUP) @ 2026-06-01  5:45 UTC (permalink / raw)
  To: Paul Louvel, Herbert Xu, David S. Miller
  Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-6-cb1ad6cdea49@bootlin.com>



Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> Add talitos_register_common() that will be called in each respective
> crypto implementation file.
> 
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>

Build warning:

   DESCEND objtool
   INSTALL libsubcmd_headers
   CC      drivers/crypto/talitos/talitos.o
drivers/crypto/talitos/talitos.c:3097:13: warning: 
'talitos_alg_set_common' defined but not used [-Wunused-function]
  3097 | static void talitos_alg_set_common(struct talitos_private *priv,
       |             ^~~~~~~~~~~~~~~~~~~~~~
   CC      drivers/crypto/talitos/talitos-rng.o
   AR      drivers/crypto/talitos/built-in.a


> ---
>   drivers/crypto/talitos/talitos.c | 53 ++++++++++++++++++++++++++++++++++++++++
>   drivers/crypto/talitos/talitos.h |  3 +++
>   2 files changed, 56 insertions(+)
> 
> diff --git a/drivers/crypto/talitos/talitos.c b/drivers/crypto/talitos/talitos.c
> index 3fc1069062da..869739dcc4d7 100644
> --- a/drivers/crypto/talitos/talitos.c
> +++ b/drivers/crypto/talitos/talitos.c
> @@ -3095,6 +3095,59 @@ static void talitos_remove(struct platform_device *ofdev)
>   		tasklet_kill(&priv->done_task[1]);
>   }
>   
> +static void talitos_alg_set_common(struct talitos_private *priv,
> +				   struct crypto_alg *alg, u32 custom_priority,
> +				   u32 type)
> +{
> +	alg->cra_module = THIS_MODULE;
> +	if (custom_priority)
> +		alg->cra_priority = custom_priority;
> +	else
> +		alg->cra_priority = TALITOS_CRA_PRIORITY;
> +	if (has_ftr_sec1(priv) && type != CRYPTO_ALG_TYPE_AHASH)
> +		alg->cra_alignmask = 3;
> +	else
> +		alg->cra_alignmask = 0;
> +	alg->cra_ctxsize = sizeof(struct talitos_ctx);
> +	alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY;
> +}
> +
> +int talitos_register_common(struct device *dev,
> +			    struct talitos_alg_template *template)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +	struct talitos_crypto_alg *t_alg;
> +	struct crypto_alg *alg;
> +	int ret;
> +
> +	t_alg = devm_kzalloc(dev, sizeof(struct talitos_crypto_alg),
> +			     GFP_KERNEL);
> +	if (!t_alg)
> +		return -ENOMEM;
> +
> +	t_alg->algt = *template;
> +
> +	switch (t_alg->algt.type) {
> +	default:
> +		dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type);
> +		devm_kfree(dev, t_alg);
> +		return -EINVAL;
> +	}
> +
> +	if (ret) {
> +		dev_err(dev, "%s alg registration failed\n",
> +			alg->cra_driver_name);
> +		devm_kfree(dev, t_alg);
> +		return 0;
> +	}
> +
> +	t_alg->dev = dev;
> +
> +	list_add_tail(&t_alg->entry, &priv->alg_list);
> +
> +	return 0;
> +}
> +
>   static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
>   						    struct talitos_alg_template
>   						           *template)
> diff --git a/drivers/crypto/talitos/talitos.h b/drivers/crypto/talitos/talitos.h
> index 1f81d336dae8..afed9947f4c0 100644
> --- a/drivers/crypto/talitos/talitos.h
> +++ b/drivers/crypto/talitos/talitos.h
> @@ -523,6 +523,9 @@ int talitos_init_common(struct talitos_ctx *ctx,
>   			struct talitos_crypto_alg *talitos_alg);
>   void talitos_cra_exit(struct crypto_tfm *tfm);
>   
> +int talitos_register_common(struct device *dev,
> +			    struct talitos_alg_template *template);
> +
>   /* Hardware RNG */
>   
>   int talitos_register_rng(struct device *dev);
> 


^ permalink raw reply

* Re: [PATCH 18/29] crypto: talitos - Split SEC1/SEC2 code into separate function variants
From: Christophe Leroy (CS GROUP) @ 2026-06-01  5:51 UTC (permalink / raw)
  To: Paul Louvel, Herbert Xu, David S. Miller
  Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-18-cb1ad6cdea49@bootlin.com>



Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> Split the functions that have SEC1/SEC2-specific behavior into
> separate sec1_ and sec2_ function variants, removing the runtime
> is_sec1 checks from within each function body.
> 
> The callers still dispatch between the two variants using local
> is_sec1 variables and if/else checks.
> 
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>

Build fails:

   DESCEND objtool
   INSTALL libsubcmd_headers
   CC      drivers/crypto/talitos/talitos.o
drivers/crypto/talitos/talitos.c: In function 'sec1_talitos_handle_error':
drivers/crypto/talitos/talitos.c:752:21: error: 'struct talitos_private' 
has no member named 'ops'
   752 |                 priv->ops->reset_channel(dev, ch);
       |                     ^~
drivers/crypto/talitos/talitos.c: In function 'sec2_talitos_handle_error':
drivers/crypto/talitos/talitos.c:811:29: error: 'struct talitos_private' 
has no member named 'ops'
   811 |                         priv->ops->reset_channel(dev, ch);
       |                             ^~
make[5]: *** [scripts/Makefile.build:289: 
drivers/crypto/talitos/talitos.o] Error 1
   CC      drivers/crypto/talitos/talitos-rng.o
   CC      drivers/crypto/talitos/talitos-hash.o
   CC      drivers/crypto/talitos/talitos-skcipher.o
   CC      drivers/crypto/talitos/talitos-aead.o
make[5]: Target 'drivers/crypto/talitos/' not remade because of errors.
make[4]: *** [scripts/Makefile.build:548: drivers/crypto/talitos] Error 2
make[4]: Target 'drivers/crypto/talitos/' not remade because of errors.
make[3]: *** [scripts/Makefile.build:548: drivers/crypto] Error 2
make[3]: Target 'drivers/crypto/talitos/' not remade because of errors.
make[2]: *** [scripts/Makefile.build:548: drivers] Error 2
make[2]: Target 'drivers/crypto/talitos/' not remade because of errors.
make[1]: *** [/home/chleroy/linux-powerpc/Makefile:2141: .] Error 2
make[1]: Target 'drivers/crypto/talitos/' not remade because of errors.
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'drivers/crypto/talitos/' not remade because of errors.


> ---
>   drivers/crypto/talitos/talitos.c | 524 +++++++++++++++++++++++++--------------
>   drivers/crypto/talitos/talitos.h |  36 ++-
>   2 files changed, 357 insertions(+), 203 deletions(-)
> 
> diff --git a/drivers/crypto/talitos/talitos.c b/drivers/crypto/talitos/talitos.c
> index f38a156a0459..b6793d97735e 100644
> --- a/drivers/crypto/talitos/talitos.c
> +++ b/drivers/crypto/talitos/talitos.c
> @@ -133,75 +133,124 @@ void unmap_single_talitos_ptr(struct device *dev,
>   			 from_talitos_ptr_len(ptr, is_sec1), dir);
>   }
>   
> -static int reset_channel(struct device *dev, int ch)
> +static int sec1_reset_channel(struct device *dev, int ch)
>   {
>   	struct talitos_private *priv = dev_get_drvdata(dev);
>   	unsigned int timeout = TALITOS_TIMEOUT;
> -	bool is_sec1 = has_ftr_sec1(priv);
>   
> -	if (is_sec1) {
> -		setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
> -			  TALITOS1_CCCR_LO_RESET);
> +	setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, TALITOS1_CCCR_LO_RESET);
>   
> -		while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR_LO) &
> -			TALITOS1_CCCR_LO_RESET) && --timeout)
> -			cpu_relax();
> -	} else {
> -		setbits32(priv->chan[ch].reg + TALITOS_CCCR,
> -			  TALITOS2_CCCR_RESET);
> +	while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR_LO) &
> +		TALITOS1_CCCR_LO_RESET) &&
> +	       --timeout)
> +		cpu_relax();
>   
> -		while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) &
> -			TALITOS2_CCCR_RESET) && --timeout)
> -			cpu_relax();
> +	if (timeout == 0) {
> +		dev_err(dev, "failed to reset sec1 channel %d\n", ch);
> +		return -EIO;
>   	}
>   
> +	setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
> +		  TALITOS_CCCR_LO_NE | TALITOS_CCCR_LO_CDIE |
> +			  TALITOS_CCCR_LO_CDWE);
> +
> +	return 0;
> +}
> +
> +static int sec2_reset_channel(struct device *dev, int ch)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +	unsigned int timeout = TALITOS_TIMEOUT;
> +
> +	setbits32(priv->chan[ch].reg + TALITOS_CCCR, TALITOS2_CCCR_RESET);
> +
> +	while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) &
> +		TALITOS2_CCCR_RESET) &&
> +	       --timeout)
> +		cpu_relax();
> +
>   	if (timeout == 0) {
> -		dev_err(dev, "failed to reset channel %d\n", ch);
> +		dev_err(dev, "failed to reset sec2 channel %d\n", ch);
>   		return -EIO;
>   	}
>   
> -	/* set 36-bit addressing, done writeback enable and done IRQ enable */
> -	setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, TALITOS_CCCR_LO_EAE |
> -		  TALITOS_CCCR_LO_CDWE | TALITOS_CCCR_LO_CDIE);
> -	/* enable chaining descriptors */
> -	if (is_sec1)
> -		setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
> -			  TALITOS_CCCR_LO_NE);
> +	setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
> +		  TALITOS_CCCR_LO_EAE | TALITOS_CCCR_LO_CDWE |
> +			  TALITOS_CCCR_LO_CDIE);
>   
> -	/* and ICCR writeback, if available */
> +	/* ICCR writeback, if available */
>   	if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
>   		setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
> -		          TALITOS_CCCR_LO_IWSE);
> +			  TALITOS_CCCR_LO_IWSE);
>   
>   	return 0;
>   }
>   
> -static int reset_device(struct device *dev)
> +static int sec1_reset_device(struct device *dev)
>   {
>   	struct talitos_private *priv = dev_get_drvdata(dev);
>   	unsigned int timeout = TALITOS_TIMEOUT;
> -	bool is_sec1 = has_ftr_sec1(priv);
> -	u32 mcr = is_sec1 ? TALITOS1_MCR_SWR : TALITOS2_MCR_SWR;
>   
> -	setbits32(priv->reg + TALITOS_MCR, mcr);
> +	setbits32(priv->reg + TALITOS_MCR, TALITOS1_MCR_SWR);
>   
> -	while ((in_be32(priv->reg + TALITOS_MCR) & mcr)
> -	       && --timeout)
> +	while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS1_MCR_SWR) &&
> +	       --timeout)
>   		cpu_relax();
>   
> -	if (priv->irq[1]) {
> -		mcr = TALITOS_MCR_RCA1 | TALITOS_MCR_RCA3;
> -		setbits32(priv->reg + TALITOS_MCR, mcr);
> +	if (timeout == 0) {
> +		dev_err(dev, "failed to reset sec1 device\n");
> +		return -EIO;
>   	}
>   
> +	return 0;
> +}
> +
> +static int sec2_reset_device(struct device *dev)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +	unsigned int timeout = TALITOS_TIMEOUT;
> +
> +	setbits32(priv->reg + TALITOS_MCR, TALITOS2_MCR_SWR);
> +
> +	while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS2_MCR_SWR) &&
> +	       --timeout)
> +		cpu_relax();
> +
> +	if (priv->irq[1])
> +		setbits32(priv->reg + TALITOS_MCR,
> +			  TALITOS_MCR_RCA1 | TALITOS_MCR_RCA3);
> +
>   	if (timeout == 0) {
> -		dev_err(dev, "failed to reset device\n");
> +		dev_err(dev, "failed to reset sec2 device\n");
>   		return -EIO;
>   	}
>   
>   	return 0;
>   }
>   
> +static void sec1_configure_device(struct device *dev)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +
> +	clrbits32(priv->reg + TALITOS_IMR, TALITOS1_IMR_INIT);
> +	clrbits32(priv->reg + TALITOS_IMR_LO, TALITOS1_IMR_LO_INIT);
> +	/* disable parity error check in DEU (erroneous? test vect.) */
> +	setbits32(priv->reg_deu + TALITOS_EUICR, TALITOS1_DEUICR_KPE);
> +}
> +
> +static void sec2_configure_device(struct device *dev)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +
> +	setbits32(priv->reg + TALITOS_IMR, TALITOS2_IMR_INIT);
> +	setbits32(priv->reg + TALITOS_IMR_LO, TALITOS2_IMR_LO_INIT);
> +
> +	/* disable integrity check error interrupts (use writeback instead) */
> +	if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
> +		setbits32(priv->reg_mdeu + TALITOS_EUICR_LO,
> +			  TALITOS_MDEUICR_LO_ICE);
> +}
> +
>   /*
>    * Reset and initialize the device
>    */
> @@ -217,80 +266,81 @@ static int init_device(struct device *dev)
>   	 * are not fully cleared by writing the MCR:SWR bit,
>   	 * set bit twice to completely reset
>   	 */
> -	err = reset_device(dev);
> +	if (is_sec1)
> +		err = sec1_reset_device(dev);
> +	else
> +		err = sec2_reset_device(dev);
> +
>   	if (err)
>   		return err;
>   
> -	err = reset_device(dev);
> +	if (is_sec1)
> +		err = sec1_reset_device(dev);
> +	else
> +		err = sec2_reset_device(dev);
>   	if (err)
>   		return err;
>   
>   	/* reset channels */
>   	for (ch = 0; ch < priv->num_channels; ch++) {
> -		err = reset_channel(dev, ch);
> +		if (is_sec1)
> +			err = sec1_reset_channel(dev, ch);
> +		else
> +			err = sec2_reset_channel(dev, ch);
>   		if (err)
>   			return err;
>   	}
>   
> -	/* enable channel done and error interrupts */
> -	if (is_sec1) {
> -		clrbits32(priv->reg + TALITOS_IMR, TALITOS1_IMR_INIT);
> -		clrbits32(priv->reg + TALITOS_IMR_LO, TALITOS1_IMR_LO_INIT);
> -		/* disable parity error check in DEU (erroneous? test vect.) */
> -		setbits32(priv->reg_deu + TALITOS_EUICR, TALITOS1_DEUICR_KPE);
> -	} else {
> -		setbits32(priv->reg + TALITOS_IMR, TALITOS2_IMR_INIT);
> -		setbits32(priv->reg + TALITOS_IMR_LO, TALITOS2_IMR_LO_INIT);
> -	}
> -
> -	/* disable integrity check error interrupts (use writeback instead) */
> -	if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
> -		setbits32(priv->reg_mdeu + TALITOS_EUICR_LO,
> -		          TALITOS_MDEUICR_LO_ICE);
> +	if (is_sec1)
> +		sec1_configure_device(dev);
> +	else
> +		sec2_configure_device(dev);
>   
>   	return 0;
>   }
>   
> -static void dma_map_request(struct device *dev, struct talitos_request *request,
> -			    struct talitos_desc *desc, bool is_sec1)
> +static void sec1_dma_map_request(struct device *dev,
> +				 struct talitos_request *request,
> +				 struct talitos_desc *desc)
>   {
>   	struct talitos_edesc *edesc =
>   		container_of(desc, struct talitos_edesc, desc);
>   	dma_addr_t dma_desc, prev_dma_desc;
>   	struct talitos_edesc *prev_edesc = NULL;
>   
> -	if (is_sec1) {
> -		while (edesc) {
> -			edesc->desc.hdr1 = edesc->desc.hdr;
> +	while (edesc) {
> +		edesc->desc.hdr1 = edesc->desc.hdr;
>   
> -			dma_desc = dma_map_single(dev, &edesc->desc.hdr1,
> -						  TALITOS_DESC_SIZE,
> -						  DMA_BIDIRECTIONAL);
> +		dma_desc = dma_map_single(dev, &edesc->desc.hdr1,
> +					  TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
>   
> -			if (!prev_edesc) {
> -				request->dma_desc = dma_desc;
> -				goto next;
> -			}
> +		if (!prev_edesc) {
> +			request->dma_desc = dma_desc;
> +			goto next;
> +		}
>   
> -			/* Chain in any previous descriptors. */
> +		/* Chain in any previous descriptors. */
>   
> -			prev_edesc->desc.next_desc = cpu_to_be32(dma_desc);
> +		prev_edesc->desc.next_desc = cpu_to_be32(dma_desc);
>   
> -			dma_sync_single_for_device(dev, prev_dma_desc,
> -						   TALITOS_DESC_SIZE,
> -						   DMA_TO_DEVICE);
> +		dma_sync_single_for_device(dev, prev_dma_desc,
> +					   TALITOS_DESC_SIZE, DMA_TO_DEVICE);
>   
>   next:
> -			prev_edesc = edesc;
> -			prev_dma_desc = dma_desc;
> -			edesc = edesc->next_desc;
> -		}
> -	} else {
> -		request->dma_desc = dma_map_single(dev, desc, TALITOS_DESC_SIZE,
> -						   DMA_BIDIRECTIONAL);
> +		prev_edesc = edesc;
> +		prev_dma_desc = dma_desc;
> +		edesc = edesc->next_desc;
>   	}
>   }
>   
> +static void sec2_dma_map_request(struct device *dev,
> +				 struct talitos_request *request,
> +				 struct talitos_desc *desc)
> +{
> +	request->dma_desc =
> +		dma_map_single(dev, desc, TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
> +}
> +
>   /**
>    * talitos_submit - submits a descriptor to the device for processing
>    * @dev:	the SEC device to be used
> @@ -327,7 +377,10 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
>   	request = &priv->chan[ch].fifo[head];
>   
>   	/* map descriptor and save caller data */
> -	dma_map_request(dev, request, desc, is_sec1);
> +	if (is_sec1)
> +		sec1_dma_map_request(dev, request, desc);
> +	else
> +		sec2_dma_map_request(dev, request, desc);
>   	request->callback = callback;
>   	request->context = context;
>   
> @@ -349,19 +402,12 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
>   	return -EINPROGRESS;
>   }
>   
> -static __be32 get_request_hdr(struct device *dev,
> -			      struct talitos_request *request, bool is_sec1)
> +static __be32 sec1_get_request_hdr(struct device *dev,
> +				   struct talitos_request *request)
>   {
>   	struct talitos_edesc *edesc;
>   	dma_addr_t dma_desc;
>   
> -	if (!is_sec1) {
> -		dma_sync_single_for_cpu(dev, request->dma_desc,
> -					TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
> -
> -		return request->desc->hdr;
> -	}
> -
>   	edesc = container_of(request->desc, struct talitos_edesc, desc);
>   	dma_desc = request->dma_desc;
>   	while (edesc->next_desc) {
> @@ -375,27 +421,37 @@ static __be32 get_request_hdr(struct device *dev,
>   	return edesc->desc.hdr1;
>   }
>   
> -static void dma_unmap_request(struct device *dev,
> -			      struct talitos_request *request, bool is_sec1)
> +static __be32 sec2_get_request_hdr(struct device *dev,
> +				   struct talitos_request *request)
> +{
> +	dma_sync_single_for_cpu(dev, request->dma_desc, TALITOS_DESC_SIZE,
> +				DMA_BIDIRECTIONAL);
> +
> +	return request->desc->hdr;
> +}
> +
> +static void sec1_dma_unmap_request(struct device *dev,
> +				   struct talitos_request *request)
>   {
>   	struct talitos_edesc *edesc;
>   
> -	if (is_sec1) {
> -		dma_unmap_single(dev, request->dma_desc, TALITOS_DESC_SIZE,
> -				 DMA_BIDIRECTIONAL);
> -		edesc = container_of(request->desc, struct talitos_edesc, desc);
> -		while (edesc->next_desc) {
> -			dma_unmap_single(dev,
> -					 be32_to_cpu(edesc->desc.next_desc),
> -					 TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
> -			edesc = edesc->next_desc;
> -		}
> -	} else {
> -		dma_unmap_single(dev, request->dma_desc, TALITOS_DESC_SIZE,
> -				 DMA_BIDIRECTIONAL);
> +	dma_unmap_single(dev, request->dma_desc, TALITOS_DESC_SIZE,
> +			 DMA_BIDIRECTIONAL);
> +	edesc = container_of(request->desc, struct talitos_edesc, desc);
> +	while (edesc->next_desc) {
> +		dma_unmap_single(dev, be32_to_cpu(edesc->desc.next_desc),
> +				 TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
> +		edesc = edesc->next_desc;
>   	}
>   }
>   
> +static void sec2_dma_unmap_request(struct device *dev,
> +				   struct talitos_request *request)
> +{
> +	dma_unmap_single(dev, request->dma_desc, TALITOS_DESC_SIZE,
> +			 DMA_BIDIRECTIONAL);
> +}
> +
>   /*
>    * process what was done, notify callback of error if not
>    */
> @@ -417,7 +473,10 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
>   
>   		/* descriptors with their done bits set don't get the error */
>   		rmb();
> -		hdr = get_request_hdr(dev, request, is_sec1);
> +		if (is_sec1)
> +			hdr = sec1_get_request_hdr(dev, request);
> +		else
> +			hdr = sec2_get_request_hdr(dev, request);
>   
>   		if ((hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
>   			status = 0;
> @@ -427,7 +486,10 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
>   			else
>   				status = error;
>   
> -		dma_unmap_request(dev, request, is_sec1);
> +		if (is_sec1)
> +			sec1_dma_unmap_request(dev, request);
> +		else
> +			sec2_dma_unmap_request(dev, request);
>   
>   		/* copy entries so we can call callback outside lock */
>   		saved_req.desc = request->desc;
> @@ -516,21 +578,30 @@ DEF_TALITOS2_DONE(ch0, TALITOS2_ISR_CH_0_DONE)
>   DEF_TALITOS2_DONE(ch0_2, TALITOS2_ISR_CH_0_2_DONE)
>   DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CH_1_3_DONE)
>   
> -static __be32 search_desc_hdr_in_request(struct talitos_request *request,
> -					 dma_addr_t cur_desc, bool is_sec1)
> +static __be32 sec1_search_desc_hdr_in_request(struct talitos_request *request,
> +					      dma_addr_t cur_desc)
>   {
>   	struct talitos_edesc *edesc;
>   
> -	if (request->dma_desc == cur_desc) {
> +
> +	if (request->dma_desc == cur_desc)
>   		return request->desc->hdr;
> -	} else if (is_sec1) {
> -		edesc = container_of(request->desc, struct talitos_edesc, desc);
> -		while (edesc->next_desc) {
> -			if (edesc->desc.next_desc == cpu_to_be32(cur_desc))
> -				return edesc->next_desc->desc.hdr1;
> -			edesc = edesc->next_desc;
> -		}
> +
> +	edesc = container_of(request->desc, struct talitos_edesc, desc);
> +	while (edesc->next_desc) {
> +		if (edesc->desc.next_desc == cpu_to_be32(cur_desc))
> +			return edesc->next_desc->desc.hdr1;
> +		edesc = edesc->next_desc;
>   	}
> +
> +	return 0;
> +}
> +
> +static __be32 sec2_search_desc_hdr_in_request(struct talitos_request *request,
> +					      dma_addr_t cur_desc)
> +{
> +	if (request->dma_desc == cur_desc)
> +		return request->desc->hdr;
>   	return 0;
>   }
>   
> @@ -559,7 +630,10 @@ static __be32 current_desc_hdr(struct device *dev, int ch)
>   	do {
>   		request = &priv->chan[ch].fifo[iter];
>   
> -		hdr = search_desc_hdr_in_request(request, cur_desc, is_sec1);
> +		if (is_sec1)
> +			hdr = sec1_search_desc_hdr_in_request(request, cur_desc);
> +		else
> +			hdr = sec2_search_desc_hdr_in_request(request, cur_desc);
>   		if (hdr)
>   			break;
>   
> @@ -647,79 +721,100 @@ static void report_eu_error(struct device *dev, int ch, __be32 desc_hdr)
>   			in_be32(priv->chan[ch].reg + TALITOS_DESCBUF_LO + 8*i));
>   }
>   
> -/*
> - * recover from error interrupts
> - */
> -static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
> +static int sec1_talitos_handle_error(struct device *dev, u32 isr, u32 isr_lo)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +	int ch, error;
> +	u32 v_lo;
> +
> +	for (ch = 0; ch < priv->num_channels; ch++) {
> +		if (!TALITOS1_CH_HAS_ERROR(isr, ch))
> +			continue;
> +
> +		v_lo = in_be32(priv->chan[ch].reg + TALITOS_CCPSR_LO);
> +
> +		error = -EINVAL;
> +
> +		if (v_lo & TALITOS1_CCPSR_LO_TEA)
> +			dev_err(dev, "transfer error acknowledge\n");
> +		if (v_lo & TALITOS1_CCPSR_LO_PTRNC)
> +			dev_err(dev, "pointer not complete error\n");
> +		if (v_lo & TALITOS1_CCPSR_LO_PE)
> +			dev_err(dev, "parity error\n");
> +		if (v_lo & TALITOS1_CCPSR_LO_IDH)
> +			dev_err(dev, "illegal descriptor header error\n");
> +		if (v_lo & TALITOS1_CCPSR_LO_SA)
> +			dev_err(dev, "static assignment error\n");
> +		if (v_lo & TALITOS1_CCPSR_LO_EU)
> +			report_eu_error(dev, ch, current_desc_hdr(dev, ch));
> +
> +		flush_channel(dev, ch, error, 1);
> +		priv->ops->reset_channel(dev, ch);
> +	}
> +
> +	if (isr_lo & TALITOS1_ISR_TEA_ERR)
> +		dev_err(dev, "TEA error: ISR 0x%08x_%08x\n", isr, isr_lo);
> +
> +	return (isr & ~TALITOS1_ISR_4CHERR) || isr_lo;
> +}
> +
> +static int sec2_talitos_handle_error(struct device *dev, u32 isr, u32 isr_lo)
>   {
>   	struct talitos_private *priv = dev_get_drvdata(dev);
>   	unsigned int timeout = TALITOS_TIMEOUT;
>   	int ch, error, reset_dev = 0;
>   	u32 v_lo;
> -	bool is_sec1 = has_ftr_sec1(priv);
> -	int reset_ch = is_sec1 ? 1 : 0; /* only SEC2 supports continuation */
> +	int reset_ch = 0;
>   
>   	for (ch = 0; ch < priv->num_channels; ch++) {
> -		/* skip channels without errors */
> -		if (is_sec1) {
> -			/* bits 29, 31, 17, 19 */
> -			if (!(isr & (1 << (29 + (ch & 1) * 2 - (ch & 2) * 6))))
> -				continue;
> -		} else {
> -			if (!(isr & (1 << (ch * 2 + 1))))
> -				continue;
> -		}
> +		if (!TALITOS2_CH_HAS_ERROR(isr, ch))
> +			continue;
>   
>   		error = -EINVAL;
>   
>   		v_lo = in_be32(priv->chan[ch].reg + TALITOS_CCPSR_LO);
>   
> -		if (v_lo & TALITOS_CCPSR_LO_DOF) {
> +		if (v_lo & TALITOS2_CCPSR_LO_DOF) {
>   			dev_err(dev, "double fetch fifo overflow error\n");
>   			error = -EAGAIN;
>   			reset_ch = 1;
>   		}
> -		if (v_lo & TALITOS_CCPSR_LO_SOF) {
> +		if (v_lo & TALITOS2_CCPSR_LO_SOF) {
>   			/* h/w dropped descriptor */
>   			dev_err(dev, "single fetch fifo overflow error\n");
>   			error = -EAGAIN;
>   		}
> -		if (v_lo & TALITOS_CCPSR_LO_MDTE)
> +		if (v_lo & TALITOS2_CCPSR_LO_MDTE)
>   			dev_err(dev, "master data transfer error\n");
> -		if (v_lo & TALITOS_CCPSR_LO_SGDLZ)
> -			dev_err(dev, is_sec1 ? "pointer not complete error\n"
> -					     : "s/g data length zero error\n");
> -		if (v_lo & TALITOS_CCPSR_LO_FPZ)
> -			dev_err(dev, is_sec1 ? "parity error\n"
> -					     : "fetch pointer zero error\n");
> -		if (v_lo & TALITOS_CCPSR_LO_IDH)
> +		if (v_lo & TALITOS2_CCPSR_LO_SGDLZ)
> +			dev_err(dev, "s/g data length zero error\n");
> +		if (v_lo & TALITOS2_CCPSR_LO_FPZ)
> +			dev_err(dev, "fetch pointer zero error\n");
> +		if (v_lo & TALITOS2_CCPSR_LO_IDH)
>   			dev_err(dev, "illegal descriptor header error\n");
> -		if (v_lo & TALITOS_CCPSR_LO_IEU)
> -			dev_err(dev, is_sec1 ? "static assignment error\n"
> -					     : "invalid exec unit error\n");
> -		if (v_lo & TALITOS_CCPSR_LO_EU)
> +		if (v_lo & TALITOS2_CCPSR_LO_IEU)
> +			dev_err(dev, "invalid exec unit error\n");
> +		if (v_lo & TALITOS2_CCPSR_LO_EU)
>   			report_eu_error(dev, ch, current_desc_hdr(dev, ch));
> -		if (!is_sec1) {
> -			if (v_lo & TALITOS_CCPSR_LO_GB)
> -				dev_err(dev, "gather boundary error\n");
> -			if (v_lo & TALITOS_CCPSR_LO_GRL)
> -				dev_err(dev, "gather return/length error\n");
> -			if (v_lo & TALITOS_CCPSR_LO_SB)
> -				dev_err(dev, "scatter boundary error\n");
> -			if (v_lo & TALITOS_CCPSR_LO_SRL)
> -				dev_err(dev, "scatter return/length error\n");
> -		}
> +		if (v_lo & TALITOS2_CCPSR_LO_GB)
> +			dev_err(dev, "gather boundary error\n");
> +		if (v_lo & TALITOS2_CCPSR_LO_GRL)
> +			dev_err(dev, "gather return/length error\n");
> +		if (v_lo & TALITOS2_CCPSR_LO_SB)
> +			dev_err(dev, "scatter boundary error\n");
> +		if (v_lo & TALITOS2_CCPSR_LO_SRL)
> +			dev_err(dev, "scatter return/length error\n");
>   
>   		flush_channel(dev, ch, error, reset_ch);
>   
>   		if (reset_ch) {
> -			reset_channel(dev, ch);
> +			priv->ops->reset_channel(dev, ch);
>   		} else {
>   			setbits32(priv->chan[ch].reg + TALITOS_CCCR,
>   				  TALITOS2_CCCR_CONT);
>   			setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, 0);
>   			while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) &
> -			       TALITOS2_CCCR_CONT) && --timeout)
> +				TALITOS2_CCCR_CONT) && --timeout)
>   				cpu_relax();
>   			if (timeout == 0) {
>   				dev_err(dev, "failed to restart channel %d\n",
> @@ -728,14 +823,29 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
>   			}
>   		}
>   	}
> -	if (reset_dev || (is_sec1 && isr & ~TALITOS1_ISR_4CHERR) ||
> -	    (!is_sec1 && isr & ~TALITOS2_ISR_4CHERR) || isr_lo) {
> -		if (is_sec1 && (isr_lo & TALITOS1_ISR_TEA_ERR))
> -			dev_err(dev, "TEA error: ISR 0x%08x_%08x\n",
> -				isr, isr_lo);
> -		else
> -			dev_err(dev, "done overflow, internal time out, or "
> -				"rngu error: ISR 0x%08x_%08x\n", isr, isr_lo);
> +
> +	return reset_dev || (isr & ~TALITOS2_ISR_4CHERR) || isr_lo;
> +}
> +
> +/*
> + * recover from error interrupts
> + */
> +static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +	bool is_sec1 = has_ftr_sec1(priv);
> +	int ch, reset_dev;
> +
> +	if (is_sec1)
> +		reset_dev = sec1_talitos_handle_error(dev, isr, isr_lo);
> +	else
> +		reset_dev = sec2_talitos_handle_error(dev, isr, isr_lo);
> +
> +	if (reset_dev) {
> +		dev_err(dev,
> +			"done overflow, internal time out, or "
> +			"rngu error: ISR 0x%08x_%08x\n",
> +			isr, isr_lo);
>   
>   		/* purge request queues */
>   		for (ch = 0; ch < priv->num_channels; ch++)
> @@ -1181,25 +1291,41 @@ int talitos_register_common(struct device *dev,
>   	return 0;
>   }
>   
> -static int talitos_probe_irq(struct platform_device *ofdev)
> +static int sec1_talitos_probe_irq(struct platform_device *ofdev)
>   {
>   	struct device *dev = &ofdev->dev;
>   	struct device_node *np = ofdev->dev.of_node;
>   	struct talitos_private *priv = dev_get_drvdata(dev);
>   	int err;
> -	bool is_sec1 = has_ftr_sec1(priv);
>   
>   	priv->irq[0] = irq_of_parse_and_map(np, 0);
>   	if (!priv->irq[0]) {
>   		dev_err(dev, "failed to map irq\n");
>   		return -EINVAL;
>   	}
> -	if (is_sec1) {
> -		err = request_irq(priv->irq[0], talitos1_interrupt_4ch, 0,
> -				  dev_driver_string(dev), dev);
> -		goto primary_out;
> +	err = request_irq(priv->irq[0], talitos1_interrupt_4ch, 0,
> +			  dev_driver_string(dev), dev);
> +	if (err) {
> +		dev_err(dev, "failed to request primary irq\n");
> +		irq_dispose_mapping(priv->irq[0]);
> +		priv->irq[0] = 0;
>   	}
>   
> +	return err;
> +}
> +
> +static int sec2_talitos_probe_irq(struct platform_device *ofdev)
> +{
> +	struct device *dev = &ofdev->dev;
> +	struct device_node *np = ofdev->dev.of_node;
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +	int err;
> +
> +	priv->irq[0] = irq_of_parse_and_map(np, 0);
> +	if (!priv->irq[0]) {
> +		dev_err(dev, "failed to map irq\n");
> +		return -EINVAL;
> +	}
>   	priv->irq[1] = irq_of_parse_and_map(np, 1);
>   
>   	/* get the primary irq line */
> @@ -1235,6 +1361,36 @@ static int talitos_probe_irq(struct platform_device *ofdev)
>   	return err;
>   }
>   
> +static void sec1_init_task(struct device *dev)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +
> +	if (priv->num_channels == 1)
> +		tasklet_init(&priv->done_task[0], talitos1_done_ch0,
> +			     (unsigned long)dev);
> +	else
> +		tasklet_init(&priv->done_task[0], talitos1_done_4ch,
> +			     (unsigned long)dev);
> +}
> +
> +static void sec2_init_task(struct device *dev)
> +{
> +	struct talitos_private *priv = dev_get_drvdata(dev);
> +
> +	if (priv->irq[1]) {
> +		tasklet_init(&priv->done_task[0], talitos2_done_ch0_2,
> +			     (unsigned long)dev);
> +		tasklet_init(&priv->done_task[1], talitos2_done_ch1_3,
> +			     (unsigned long)dev);
> +	} else if (priv->num_channels == 1) {
> +		tasklet_init(&priv->done_task[0], talitos2_done_ch0,
> +			     (unsigned long)dev);
> +	} else {
> +		tasklet_init(&priv->done_task[0], talitos2_done_4ch,
> +			     (unsigned long)dev);
> +	}
> +}
> +
>   static int talitos_probe(struct platform_device *ofdev)
>   {
>   	struct device *dev = &ofdev->dev;
> @@ -1317,31 +1473,17 @@ static int talitos_probe(struct platform_device *ofdev)
>   		stride = TALITOS2_CH_STRIDE;
>   	}
>   
> -	err = talitos_probe_irq(ofdev);
> +	if (has_ftr_sec1(priv))
> +		err = sec1_talitos_probe_irq(ofdev);
> +	else
> +		err = sec2_talitos_probe_irq(ofdev);
>   	if (err)
>   		goto err_out;
>   
> -	if (has_ftr_sec1(priv)) {
> -		if (priv->num_channels == 1)
> -			tasklet_init(&priv->done_task[0], talitos1_done_ch0,
> -				     (unsigned long)dev);
> -		else
> -			tasklet_init(&priv->done_task[0], talitos1_done_4ch,
> -				     (unsigned long)dev);
> -	} else {
> -		if (priv->irq[1]) {
> -			tasklet_init(&priv->done_task[0], talitos2_done_ch0_2,
> -				     (unsigned long)dev);
> -			tasklet_init(&priv->done_task[1], talitos2_done_ch1_3,
> -				     (unsigned long)dev);
> -		} else if (priv->num_channels == 1) {
> -			tasklet_init(&priv->done_task[0], talitos2_done_ch0,
> -				     (unsigned long)dev);
> -		} else {
> -			tasklet_init(&priv->done_task[0], talitos2_done_4ch,
> -				     (unsigned long)dev);
> -		}
> -	}
> +	if (has_ftr_sec1(priv))
> +		sec1_init_task(dev);
> +	else
> +		sec2_init_task(dev);
>   
>   	priv->fifo_len = roundup_pow_of_two(priv->chfifo_len);
>   
> diff --git a/drivers/crypto/talitos/talitos.h b/drivers/crypto/talitos/talitos.h
> index 6cf3628c52c2..904fdc9dec80 100644
> --- a/drivers/crypto/talitos/talitos.h
> +++ b/drivers/crypto/talitos/talitos.h
> @@ -301,20 +301,32 @@ static inline bool has_ftr_sec1(struct talitos_private *priv)
>   #define   TALITOS1_CCCR_LO_RESET	0x1    /* channel reset on SEC1 */
>   
>   /* CCPSR: channel pointer status register */
> +
> +/* bits 29, 31, 17, 19 */
> +#define TALITOS1_CH_HAS_ERROR(isr, ch) \
> +	((isr) & (1 << (29 + ((ch) & 1) * 2 - ((ch) & 2) * 6)))
> +#define TALITOS2_CH_HAS_ERROR(isr, ch) ((isr) & (1 << ((ch) * 2 + 1)))
> +
>   #define TALITOS_CCPSR			0x10
>   #define TALITOS_CCPSR_LO		0x14
> -#define   TALITOS_CCPSR_LO_DOF		0x8000 /* double FF write oflow error */
> -#define   TALITOS_CCPSR_LO_SOF		0x4000 /* single FF write oflow error */
> -#define   TALITOS_CCPSR_LO_MDTE		0x2000 /* master data transfer error */
> -#define   TALITOS_CCPSR_LO_SGDLZ	0x1000 /* s/g data len zero error */
> -#define   TALITOS_CCPSR_LO_FPZ		0x0800 /* fetch ptr zero error */
> -#define   TALITOS_CCPSR_LO_IDH		0x0400 /* illegal desc hdr error */
> -#define   TALITOS_CCPSR_LO_IEU		0x0200 /* invalid EU error */
> -#define   TALITOS_CCPSR_LO_EU		0x0100 /* EU error detected */
> -#define   TALITOS_CCPSR_LO_GB		0x0080 /* gather boundary error */
> -#define   TALITOS_CCPSR_LO_GRL		0x0040 /* gather return/length error */
> -#define   TALITOS_CCPSR_LO_SB		0x0020 /* scatter boundary error */
> -#define   TALITOS_CCPSR_LO_SRL		0x0010 /* scatter return/length error */
> +#define   TALITOS1_CCPSR_LO_TEA		0x2000 /* transfer error acknowledge */
> +#define   TALITOS1_CCPSR_LO_PTRNC	0x1000 /* pointer not complete error */
> +#define   TALITOS1_CCPSR_LO_PE		0x0800 /* parity error */
> +#define   TALITOS1_CCPSR_LO_IDH		0x0400 /* illegal desc hdr error */
> +#define   TALITOS1_CCPSR_LO_SA		0x0200 /* static assignment error */
> +#define   TALITOS1_CCPSR_LO_EU		0x0100 /* EU error detected */
> +#define   TALITOS2_CCPSR_LO_DOF		0x8000 /* double FF write oflow error */
> +#define   TALITOS2_CCPSR_LO_SOF		0x4000 /* single FF write oflow error */
> +#define   TALITOS2_CCPSR_LO_MDTE	0x2000 /* master data transfer error */
> +#define   TALITOS2_CCPSR_LO_SGDLZ	0x1000 /* s/g data len zero error */
> +#define   TALITOS2_CCPSR_LO_FPZ		0x0800 /* fetch ptr zero error */
> +#define   TALITOS2_CCPSR_LO_IDH		0x0400 /* illegal desc hdr error */
> +#define   TALITOS2_CCPSR_LO_IEU		0x0200 /* invalid EU error */
> +#define   TALITOS2_CCPSR_LO_EU		0x0100 /* EU error detected */
> +#define   TALITOS2_CCPSR_LO_GB		0x0080 /* gather boundary error */
> +#define   TALITOS2_CCPSR_LO_GRL		0x0040 /* gather return/length error */
> +#define   TALITOS2_CCPSR_LO_SB		0x0020 /* scatter boundary error */
> +#define   TALITOS2_CCPSR_LO_SRL		0x0010 /* scatter return/length error */
>   
>   /* channel fetch fifo register */
>   #define TALITOS_FF			0x48
> 


^ permalink raw reply

* Re: [PATCH 00/29] crypto: talitos - Driver cleanup
From: Christophe Leroy (CS GROUP) @ 2026-06-01  6:15 UTC (permalink / raw)
  To: Paul Louvel, Herbert Xu, David S. Miller
  Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-0-cb1ad6cdea49@bootlin.com>



Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> The Freescale Integrated Security Engine (SEC) aka "Talitos" driver
> implementation is a monolithic ~3800-line file that mixes SEC1 and SEC2
> hardware variants with hash, skcipher, aead and hwrng algorithm.
> 
> This series reorganises the driver to improve readability and
> maintainability.

Did you analyse the cost of this series ? bloat-o-meter gives the 
following result, allthough I'm a bit surprised there are only added 
items, no removed items:

add/remove: 36/0 grow/shrink: 44/0 up/down: 34309/0 (34309)
Function                                     old     new   delta
aead_driver_algs                               -    9280   +9280
hash_driver_algs                               -    5568   +5568
skcipher_driver_algs                           -    3712   +3712
ipsec_esp                                   1552    3088   +1536
ahash_process_req                           1912    3368   +1456
common_nonsnoop.constprop                    884    1704    +820
aead_des3_setkey                             628    1256    +628
ahash_setkey                                 608    1220    +612
ipsec_esp_unmap                              468    1028    +560
sec1_talitos_handle_error                      -     548    +548
aead_setkey                                  460     920    +460
talitos1_interrupt_4ch                      2204    2648    +444
aead_decrypt                                 432     868    +436
free_edesc_list_from                         348     772    +424
sec1_dma_map_request                           -     356    +356
ahash_import                                 352     708    +356
talitos_register_hash                          -     344    +344
skcipher_setkey.isra                           -     336    +336
ahash_export                                 312     628    +316
ahash_init                                   300     604    +304
talitos1_done_4ch                            280     560    +280
common_nonsnoop_unmap                        192     460    +268
talitos_rng_init                             252     504    +252
ipsec_esp_decrypt_swauth_done                236     472    +236
sec1_reset_device                              -     220    +220
talitos_register_aead                          -     208    +208
sec1_reset_channel                             -     208    +208
sec1_talitos_probe_irq                         -     204    +204
talitos1_done_ch0                            196     392    +196
skcipher_encrypt                             164     360    +196
skcipher_decrypt                             164     360    +196
skcipher_des3_setkey                         192     380    +188
ipsec_esp_decrypt_hwauth_done                144     320    +176
ipsec_esp_encrypt_done                       172     344    +172
ahash_digest_sha224_swinit                   172     344    +172
talitos_rng_data_present                     164     328    +164
ahash_init_sha224_swinit                     164     328    +164
aead_encrypt                                 132     296    +164
skcipher_done                                144     292    +148
talitos_register_skcipher                      -     144    +144
skcipher_des_setkey                          140     280    +140
sec1_get_request_hdr                           -     132    +132
sec1_dma_unmap_request                         -     132    +132
crypto_des_verify_key                        132     264    +132
talitos_register_rng                           -     124    +124
sec1_configure_device                          -     108    +108
aead_edesc_alloc                             104     208    +104
skcipher_edesc_alloc                          92     184     +92
ahash_done                                    92     184     +92
skcipher_aes_setkey                           44     120     +76
sec1_search_desc_hdr_in_request                -      76     +76
talitos_unregister_rng                         -      68     +68
talitos_rng_data_read                         64     128     +64
padded_hash                                   64     128     +64
ahash_digest                                  60     120     +60
sec1_init_task                                 -      52     +52
sec1_ops                                       -      40     +40
talitos_register_sec1                          -      32     +32
talitos_cra_init_ahash                        84     108     +24
sec1_ptr_ops                                   -      24     +24
sec1_copy_talitos_ptr                          -      20     +20
talitos_cra_init_skcipher                     76      92     +16
talitos_cra_init_aead                         76      92     +16
sec1_get_ptr                                   -      16     +16
sec1_desc_ops                                  -      16     +16
ahash_update                                  16      32     +16
ahash_finup                                   16      32     +16
ahash_final                                   16      32     +16
sec1_to_talitos_ptr                            -      12     +12
talitos_cra_exit_skcipher                      -       8      +8
talitos_cra_exit_ahash                         -       8      +8
talitos_cra_exit_aead                          -       8      +8
sec1_set_hdr                                   -       8      +8
sec1_get_ptr_value                             -       8      +8
sec1_get_hdr_lo                                -       8      +8
sec1_get_hdr                                   -       8      +8
sec1_from_talitos_ptr_len                      -       8      +8
__already_done                                 2       7      +5
sec1_to_talitos_ptr_ext_set                    -       4      +4
sec1_to_talitos_ptr_ext_or                     -       4      +4
Total: Before=41269, After=75578, chg +83.14%



> One of the main motivation for this series is to eleminate all the
> conditionals around the has_ftr_sec1(). Some checks still remains in
> crypto algorithm implementation at the end of the series.
> 
> Patch 1 adds the CRYPTO_AHASH_ALG_BLOCK_ONLY flag for the ahash
> implementation to eliminate manual partial-block buffering.
> 
> Driver reorganisation (patches 2-9):
> 
>    Move the driver into a dedicated directory, split the different crypto
>    implementation into dedicated translation units.
> 
> Algorithm definition cleanup (patches 10-17):
> 
>    Remove algorithm property mutations from the registration loop, delete
>    the now-unused priority field in struct talitos_alg_template, and
>    convert hash, skcipher and aead to the type-specific init_tfm/exit_tfm
>    API, replacing the deprecated cra_init/cra_exit fields.
> 
>    Use preprocessor macros to deduplicate the hash, skcipher and aead
>    algorithm definitions.
> 
> SEC1/SEC2 ops abstraction (patches 18-27):
> 
>    Introduce struct talitos_ops, split SEC1/SEC2-specific
>    code into separate function variants, and replace runtime is_sec1
>    conditionals with indirect calls through the ops table.
> 
>    Export common channel and error handling routines, and move SEC1 and
>    SEC2 ops into dedicated translation units.
> 
>    Introduce struct talitos_ptr_ops to abstract SEC1/SEC2 pointer
>    helpers behind per-SEC-version ops, then remove the now-unused
>    global pointer helper functions.
> 
>    Introduce per-SEC-version descriptor structures and ops.
> 
> Patch 28 cleans up the includes in the core driver file now that all
> crypto implementation code has been moved out.
> 
> Patch 29 removes a now-useless macro.
> 
> No functional changes are intended for patches 2-29.
> 
> This series depends on the "crypto: talitos - bug fixes" series :
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatch.msgid.link%2F20260507-bootlin_test-7-1-rc1_sec_bugfix-v3-0-c98d7589b942%40bootlin.com&data=05%7C02%7Cchristophe.leroy%40csgroup.eu%7C55c202dc74294a47211f08debc98cf05%7C8b87af7d86474dc78df45f69a2011bb5%7C0%7C0%7C639155561647821924%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=jor10ujpsx58tqxZUNGvDx63lqwVJW5asMdUS8CF1zg%3D&reserved=0
> 
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
> ---
> Paul Louvel (29):
>        crypto: talitos/hash - Use CRYPTO_AHASH_BLOCK_ONLY API
>        crypto: talitos - Move driver into dedicated directory
>        crypto: talitos - Add missing includes to driver header file
>        crypto: talitos/hwrng - Move into separate file
>        crypto: talitos - Prepare crypto implementation file splitting
>        crypto: talitos - Introduce registration helper
>        crypto: talitos/hash - Move into separate file
>        crypto: talitos/skcipher - Move into separate file
>        crypto: talitos/aead - Move into separate file
>        crypto: talitos - Remove alg settings in talitos_register_common()
>        crypto: talitos - Remove unused priority field in struct talitos_alg_template
>        crypto: talitos/hash - Convert to init_tfm/exit_tfm type-specific API
>        crypto: talitos/skcipher - Convert to init/exit type-specific API
>        crypto: talitos/aead - Convert to init/exit type-specific API
>        crypto: talitos/hash - Use macro for algorithm definitions
>        crypto: talitos/skcipher - Use macro for algorithm definitions
>        crypto: talitos/aead - Use macro for algorithm definitions
>        crypto: talitos - Split SEC1/SEC2 code into separate function variants
>        crypto: talitos - Introduce struct talitos_ops
>        crypto: talitos - Replace SEC1/SEC2 conditionals with ops dispatch
>        crypto: talitos - Export common channel and error handling routines
>        crypto: talitos - Move SEC1 ops into talitos-sec1.c
>        crypto: talitos - Move SEC2 ops into talitos-sec2.c
>        crypto: talitos - Introduce per-SEC-version pointer helper ops
>        crypto: talitos - Dispatch pointer helpers through ptr_ops
>        crypto: talitos - Remove now-unused global pointer helpers
>        crypto: talitos - Introduce per-SEC-version descriptor structures and ops
>        crypto: talitos - Clean up includes in core driver file
>        crypto: talitos - Remove TALITOS_DESC_SIZE macro
> 
>   drivers/crypto/Kconfig                    |   38 +-
>   drivers/crypto/Makefile                   |    2 +-
>   drivers/crypto/talitos.c                  | 3640 -----------------------------
>   drivers/crypto/talitos/Kconfig            |   36 +
>   drivers/crypto/talitos/Makefile           |    6 +
>   drivers/crypto/talitos/talitos-aead.c     |  677 ++++++
>   drivers/crypto/talitos/talitos-hash.c     |  711 ++++++
>   drivers/crypto/talitos/talitos-rng.c      |   93 +
>   drivers/crypto/talitos/talitos-sec1.c     |  374 +++
>   drivers/crypto/talitos/talitos-sec2.c     |  404 ++++
>   drivers/crypto/talitos/talitos-skcipher.c |  364 +++
>   drivers/crypto/talitos/talitos.c          |  917 ++++++++
>   drivers/crypto/{ => talitos}/talitos.h    |  255 +-
>   13 files changed, 3810 insertions(+), 3707 deletions(-)
> ---
> base-commit: db8b9f227833e729faf44a512aa1e88a625b5ad8
> change-id: 20260518-7-1-rc1_talitos_cleanup-9231a64e29fa
> prerequisite-change-id: 20260504-bootlin_test-7-1-rc1_sec_bugfix-13169ed07ddc:v3
> prerequisite-patch-id: 7b364911e4b8d1c1033eb14e67ed24dac6a4bc13
> prerequisite-patch-id: 2c1cd7fdd003d9a116a697efa25d1716d548389f
> prerequisite-patch-id: b12bdbf565747609e0cfe0609a42cf69b5d816a1
> prerequisite-patch-id: 72cb2bc0fc2a48a5a029b049c199f4c86085cf04
> prerequisite-patch-id: 5f1f5ad6add760161bd48875df48c0893aa12613
> prerequisite-patch-id: 934931086968229434d15a2f2358aeb7e6975a1d
> prerequisite-patch-id: 8a0b4828fc0690e0c841bc9adcc6568bb522e0e8
> prerequisite-patch-id: 1d870f32e7dbf9a8bd3b8979558544107693e0f4
> prerequisite-patch-id: 758c18d7c9fabb14bd90df62e5e8a62a6f880db4
> prerequisite-patch-id: ce6e9e585f8edc1861ae6bb8fbdd836c20cbd290
> prerequisite-patch-id: 9446dc03e442ea81c5f5b39e802e01b37da29971
> 
> Best regards,
> --
> Paul Louvel, Bootlin
> Embedded Linux and Kernel engineering
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbootlin.com%2F&data=05%7C02%7Cchristophe.leroy%40csgroup.eu%7C55c202dc74294a47211f08debc98cf05%7C8b87af7d86474dc78df45f69a2011bb5%7C0%7C0%7C639155561647851452%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=orDISoOYFS%2F%2F0ThHpS71R6nscnJxyMar0jASTbsYdG8%3D&reserved=0
> 


^ permalink raw reply

* Re: [PATCH 01/29] crypto: talitos/hash - Use CRYPTO_AHASH_BLOCK_ONLY API
From: Paul Louvel @ 2026-06-01  8:06 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP), Paul Louvel, Herbert Xu,
	David S. Miller
  Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <f70f5279-e136-467a-8306-a1af1ea27015@kernel.org>

Christophe,

>
> I have a build failure with this patch:
>
>    UPD     include/config/kernel.release
>    UPD     include/generated/utsrelease.h
>    DESCEND objtool
>    INSTALL libsubcmd_headers
>    CC      drivers/crypto/talitos.o
> drivers/crypto/talitos.c: In function 'talitos_cra_init_ahash':
> drivers/crypto/talitos.c:3150:34: warning: statement with no effect 
> [-Wunused-value]
>   3150 |                                  sizeof(struct 
> talitos_ahash_req_ctx));
>        |                                  ^~~~~~
> drivers/crypto/talitos.c:3150:70: error: expected ';' before ')' token
>   3150 |                                  sizeof(struct 
> talitos_ahash_req_ctx));
>        | 
>       ^
>        | 
>       ;
> drivers/crypto/talitos.c:3150:70: error: expected statement before ')' token
> make[4]: *** [scripts/Makefile.build:289: drivers/crypto/talitos.o] Error 1
> make[3]: *** [scripts/Makefile.build:548: drivers/crypto] Error 2
> make[2]: *** [scripts/Makefile.build:548: drivers] Error 2
> make[1]: *** [/home/chleroy/linux-powerpc/Makefile:2141: .] Error 2
> make: *** [Makefile:248: __sub-make] Error 2
>
>

Thanks for reporting,
Paul.

-- 
Paul Louvel, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply

* Re: [PATCH 05/29] crypto: talitos - Prepare crypto implementation file splitting
From: Paul Louvel @ 2026-06-01  8:49 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP), Paul Louvel, Herbert Xu,
	David S. Miller
  Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <22245899-e046-41f1-8707-94f172b310e9@kernel.org>

Hi Christophe,

> Le 28/05/2026 à 11:08, Paul Louvel a écrit :
>> Remove the static qualifier on multiple function that will be called
>> inside each crypto implementation file.
>> Add them to the main driver header file.
>
> I didn't have time to look at the generated text yet but I'm a bit 
> sceptic with this change, or more than the change itself, about its 
> purpose. And even more when I see patches 24 and 25.

About patch 24 and 25: one of the main purpose of this series is to get rid of
the is_sec1 scattered around the core code of the driver.

> Most functions here are small helpers. To be shared between several C 
> files they deserve becoming static inlines in talitos.h, not global 
> functions.

I did not look at the generated text either for this change but I bet the
compiler is inlining these calls. Adding them as static inline is more explicit.

I understand that there is a performance penalty, since there will be no
inlining, and a memory dereferencing for a call through function pointer.

> Indeed, most of the time is_sec1 is known at build time because in most 
> cases has_ftr_sec1() will constant fold into true or false during build. 
> This is because it is very unlikely that someone build a kernel to run 
> on both MPC 82xx and MPC 83xx at the same time. Therefore it is really 
> unlikely that this in built with both CRYPTO_DEV_TALITOS1 and 
> CRYPTO_DEV_TALITOS2 at the same time.

As for patch 24, 25 and onwards, the same space optimization apply here. If the
kernel is built with CRYPTO_DEV_TALITOS1, there will be no SEC2-related function
in the generated text, and vice versa.

>
> I can understand for a function like talitos_submit() but not for 
> functions like to_talitos_ptr() or to_talitos_ptr_ext_set() whose 
> purpose is really to get inlined into the caller.
>
> Christophe
>

These changes are needed to split the driver into multiple files.

Best regards,
Paul.

-- 
Paul Louvel, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply

* [PATCH v3 0/4] crypto: skcipher - per-tfm multi-data-unit batching
From: Leonid Ravich @ 2026-06-01  8:56 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Alasdair Kergon, Ard Biesheuvel, Eric Biggers, Jens Axboe,
	Horia Geanta, Gilad Ben-Yossef, linux-crypto, dm-devel,
	linux-block

This is v3 of the multi-data-unit skcipher request series, addressing
review feedback from Mikulas Patocka on v2.

v2: https://lore.kernel.org/linux-crypto/20260527065021.19525-1-lravich@amazon.com/
v1: https://lore.kernel.org/linux-crypto/20260519115955.27267-1-lravich@amazon.com/

The series adds a per-tfm "data unit size" to the skcipher API so a
caller can submit several data units in one crypto request, mirroring
the data_unit_size concept already exposed by struct blk_crypto_config
for inline encryption hardware.  The first user is dm-crypt, which
today issues one skcipher request per sector and so pays a per-sector
cost in request allocation, callback dispatch, completion handling,
and scatterlist setup.

Proof-of-concept performance numbers from the RFC reply [1]: +19%
throughput / -40% CPU on a single-core arm64 system with a hardware
XTS-AES-256 accelerator running fio 4 KiB sequential writes through
dm-crypt, when an out-of-tree arm64 xts driver advertises the new
flag.  This series itself does not include arch enablement.

[1] https://lore.kernel.org/linux-crypto/20260428101225.24316-1-lravich@amazon.com/

Changes since v2
----------------

Patch 4 (dm-crypt) only.  Patches 1-3 are unchanged from v2.

  - Replace integer division with the equivalent shift, and tighten
    the size sanity check from "is total < sector_size?" to "is
    total a multiple of sector_size?".  Reject unaligned residues
    explicitly instead of silently truncating them.  The local
    n_sectors variable used only for a now-redundant !=0 check was
    dropped — crypt_convert()'s outer while-loop already guarantees
    iter_in.bi_size > 0 on entry.  (Mikulas)

  - Drop `min(iter_in.bi_size, iter_out.bi_size)` in favour of using
    iter_in.bi_size directly, with a WARN_ON_ONCE() to flag any
    future violation of the "iter_in and iter_out describe equally-
    sized payloads" invariant maintained by crypt_convert_init().
    Replaces a silent mask of a real bug with an explicit warning.
    (Mikulas)

Changes since v1
----------------

Patch 4 only.  Addressed Mikulas's review of v1:

  - Multi-DU scatterlist allocation uses
    GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN.

  - On scatterlist allocation failure, return -EAGAIN.
    crypt_convert() handles -EAGAIN by clearing its local multi_du
    flag and re-entering the per-sector path for the rest of this
    crypt_convert() invocation.  The per-tfm data_unit_size on the
    cipher remains set, so subsequent bios (which start a fresh
    crypt_convert() and re-read cipher_flags) get to try multi-DU
    again once memory pressure eases.

    This gives forward progress under total memory exhaustion: the
    per-sector path uses only cc->req_pool (a mempool with reservoir
    set up at table-load time) and the inline
    dmreq->sg_in[]/sg_out[] arrays, never doing any allocation that
    could fail.

  - Walk the bio with __bio_for_each_bvec instead of
    __bio_for_each_segment for folio-friendly SG construction.

Design overview (unchanged from v1)
-----------------------------------

* Patch 1 adds an `unsigned int data_unit_size` field to
  `struct crypto_skcipher` (per-tfm: invariant for the consumer's
  lifetime, set once via `crypto_skcipher_set_data_unit_size()`),
  plus a capability flag CRYPTO_ALG_SKCIPHER_MULTI_DATA_UNIT in
  `cra_flags` (type-specific high-byte range, mirroring the
  CRYPTO_AHASH_ALG_BLOCK_ONLY precedent).  `crypto_skcipher_encrypt()`
  and `crypto_skcipher_decrypt()` validate that `cryptlen` is a
  positive multiple of `data_unit_size`.  The setter rejects
  sub-blocksize values; algorithm registration rejects the flag for
  algorithms with `ivsize != 16`.

  Also exposes `skcipher_walk_data_units()` in
  <crypto/internal/skcipher.h> as a default per-DU dispatcher for
  drivers that don't want to roll their own.

* Patch 2 lets the generic `xts(...)` template advertise the flag
  when the inner cipher is synchronous.

* Patch 3 extends `testmgr` with a self-comparison test that fires
  automatically for every alg advertising the flag.

* Patch 4 turns dm-crypt on automatically when all of the
  following hold at table load: skcipher (not aead), tfms_count
  == 1, IV mode is plain or plain64, no per-sector
  iv_gen_ops->post() hook, no dm-integrity stacking, and the
  underlying cipher advertises the capability.

This series intentionally does NOT add the capability flag to any
arch crypto driver.  Arch maintainers can opt in independently in
follow-up patches.

Verification
------------

A formal regression protocol is included in the project tree
(.claude/regression-protocol.md, .claude/run-regression.sh).  The
v3 reference run reports 12/12 cases PASS:

  - x86 + arm64 build clean (with and without out-of-tree arch
    enablement).
  - checkpatch.pl --strict: clean on all 4 patches.
  - testmgr self-comparison: PASS for any algorithm advertising the
    flag (verified end-to-end against an out-of-tree arm64/x86 xts
    driver during regression).
  - dm-crypt activation gating: plain/plain64 enabled,
    essiv:sha256 / plain64be fall back.
  - dm-crypt round-trip plain64: PASS with multi-DU active.
  - dm-crypt round-trip essiv:sha256 (per-sector path on multi-DU
    kernel): PASS.
  - dm-crypt low-memory (mem=128M): PASS, no OOM kill.
  - Byte-equivalence: 256 MB of ciphertext written through the
    multi-DU path is bit-identical to ciphertext written through
    the per-sector path on an unpatched axboe/for-next baseline
    (sha256
    4913910b1aa6f8859fcb8f4adec20230274993a3ade8f4dd0140a323dc43efc0).
    The on-disk format is unchanged.
  - arm64 functional (activation + round-trip) under qemu-aarch64:
    PASS.

The OOM-fallback path (multi-DU helper returns -EAGAIN, caller
reverts to per-sector) is verified by inspection: the fallback is
two lines in crypt_convert(), the per-sector path uses only the
existing mempool reserve and the inline dmreq SG arrays (no
allocation that could fail), and there is no shared state between
the two paths that could deadlock.

Leonid Ravich (4):
  crypto: skcipher - add per-tfm data_unit_size for batched requests
  crypto: xts - support multiple data units per request in template
  crypto: testmgr - exercise multi-data-unit path for skcipher
  dm crypt: batch all sectors of a bio per crypto request

 crypto/skcipher.c                  | 120 ++++++++++++
 crypto/testmgr.c                   | 129 +++++++++++++
 crypto/xts.c                       |  25 ++-
 drivers/md/dm-crypt.c              | 281 ++++++++++++++++++++++++++++-
 include/crypto/internal/skcipher.h |  34 ++++
 include/crypto/skcipher.h          |  85 +++++++++
 6 files changed, 665 insertions(+), 9 deletions(-)


base-commit: a8cafdf8c949f17c92eca0045532e88ac0dac30d
-- 
2.47.3


^ 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