* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Eric Biggers @ 2026-05-30 19:26 UTC (permalink / raw)
To: Aleksander Jan Bajkowski
Cc: linux-crypto, Herbert Xu, Christian Lamparter, linuxppc-dev,
linux-kernel, stable
In-Reply-To: <5c74c261-53cf-4185-a8a0-7554bc9fe5f7@wp.pl>
On Sat, May 30, 2026 at 05:05:19PM +0200, Aleksander Jan Bajkowski wrote:
> Hi Eric,
>
> On 30/05/2026 00:04, Eric Biggers wrote:
> > Remove crypto4xx_rng, as it is insecure and unused:
> >
> > - It has only a 64-bit security strength, which is highly inadequate.
> > This can be seen by the fact that crypto4xx_hw_init() seeds it with
> > only 64 bits of entropy, and the fact that the original commit
> > mentions that it implements ANSI X9.17 Annex C.
>
> In addition to a seed, the PRNG also uses ring oscillators as sources of
> entropy. The entropy should be higher than 64b. This is the Rambus EIP-73d
> IP core. The same IP core is built into eip93 (EIP-73a), eip97 (EIP-73d),
> and eip197 (EIP-73d). You can find the documentation online. The complete
> "container" is actually Rambus EIP-94, and one of its parts is EIP-73d.
Just because it may have another source of entropy doesn't mean its
security strength is higher than 64 bits.
I cannot find any documentation other than
https://datasheet.octopart.com/PPC460EX-SUB800T-AMCC-datasheet-11553412.pdf
which says "ANSI X9.17 Annex C compliant using a DES algorithm".
DES actually has a 56-bit key, so maybe I was over-generous.
And according to https://cacr.uwaterloo.ca/hac/about/chap5.pdf ANSI
X9.17 has only a 64-bit state anyway. So even if we assume the
datasheet is incorrect and the algorithm is actually 3DES which has a
longer key, the state is likely still 64-bit.
So it isn't looking good. And since it's an undocumented proprietary
design it shouldn't be given the benefit of the doubt either.
> This PRNG is also used internally for Generation IV with IPSEC offload. The
> IPSEC offload implementation for eip93 was recently submitted to upstream.
> I am not sure whether eip94 shares some of the logic for IPSEC offload and
> it will be possible to use some of the code.
That's not related to this patch.
- Eric
^ permalink raw reply
* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Eric Biggers @ 2026-05-30 19:12 UTC (permalink / raw)
To: Christian Lamparter
Cc: linux-crypto, Herbert Xu, linuxppc-dev, linux-kernel, stable
In-Reply-To: <e0b3cfc2-c6da-46d4-9dec-027dafaba74e@gmail.com>
On Sat, May 30, 2026 at 12:20:57PM +0200, Christian Lamparter wrote:
> > diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
> > index 1038061224da..73d626308a84 100644
> > --- a/drivers/crypto/amcc/crypto4xx_reg_def.h
> > +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
> > @@ -88,24 +88,13 @@
> > #define CRYPTO4XX_DMA_CFG 0x000600d4
> > #define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
> > #define CRYPTO4XX_ENDIAN_CFG 0x000600d8
> > -#define CRYPTO4XX_PRNG_STAT 0x00070000
> > -#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
> > #define CRYPTO4XX_PRNG_CTRL 0x00070004
> > #define CRYPTO4XX_PRNG_SEED_L 0x00070008
> > #define CRYPTO4XX_PRNG_SEED_H 0x0007000c
> > -
> > -#define CRYPTO4XX_PRNG_RES_0 0x00070020
> > -#define CRYPTO4XX_PRNG_RES_1 0x00070024
> > -#define CRYPTO4XX_PRNG_RES_2 0x00070028
> > -#define CRYPTO4XX_PRNG_RES_3 0x0007002C
> > -
> > -#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
> > -#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
> > -
>
> Hmm, don't think these defines will hurt anyone? As these are part of the hardware spec.
> Or do you forsee a future where AI-Agents will sent patches hallucinating that it "fixed"
> the issue which readds it? I have no idea.
Well, there's not really any point in keeping these when they aren't
used.
- Eric
^ permalink raw reply
* [PATCH 4/4] arm64: dts: rockchip: Add crypto node to rk3588-base
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
To: herbert, davem, heiko
Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
In-Reply-To: <20260530160704.3453555-1-dawidro@gmail.com>
Add the device tree node for the V2 cryptographic hardware accelerator
on RK3588.
On RK3588 the crypto IP sits inside the secure domain controlled by
SECURECRU, a register bank that is exclusively accessible to the
TrustZone firmware (TF-A). Linux must therefore obtain its clocks and
reset line through the ARM SCMI interface provided by the firmware
rather than mapping the CRU registers directly. Attempting direct MMIO
access to SECURECRU from the non-secure world triggers an asynchronous
bus fault.
The interrupt uses the four-cell GICv3 format as required by the RK3588
GIC node definition (the fourth cell is the CPU affinity/partition
specifier; 0 means no affinity constraint).
The node is disabled by default; board files that wish to use hardware
crypto offload must enable it.
Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
---
arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index 4fb8888c281c..4f336741d11f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -2257,6 +2257,18 @@ rng@fe378000 {
resets = <&scmi_reset SCMI_SRST_H_TRNG_NS>;
};
+ crypto: crypto@fe370000 {
+ compatible = "rockchip,rk3588-crypto";
+ reg = <0x0 0xfe370000 0x0 0x2000>;
+ interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&scmi_clk SCMI_CRYPTO_CORE>, <&scmi_clk SCMI_ACLK_SECURE_NS>,
+ <&scmi_clk SCMI_HCLK_SECURE_NS>;
+ clock-names = "core", "aclk", "hclk";
+ resets = <&scmi_reset SCMI_SRST_CRYPTO_CORE>;
+ reset-names = "core";
+ status = "disabled";
+ };
+
i2s0_8ch: i2s@fe470000 {
compatible = "rockchip,rk3588-i2s-tdm";
reg = <0x0 0xfe470000 0x0 0x1000>;
--
2.47.3
^ permalink raw reply related
* [PATCH 3/4] arm64: dts: rockchip: Add crypto node to rk356x-base
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
To: herbert, davem, heiko
Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
In-Reply-To: <20260530160704.3453555-1-dawidro@gmail.com>
Add the device tree node for the V2 cryptographic hardware accelerator
on RK356x SoCs (RK3566, RK3568).
The IP block sits in the non-secure peripheral domain. Its three clocks
(core, aclk, hclk) and reset line are accessible directly through the
main non-secure CRU, so no firmware intermediary is required.
The node is disabled by default; board files that wish to use hardware
crypto offload must enable it.
Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
---
arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
index 64bdd8b7754b..3b73a56046e7 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
@@ -1171,6 +1171,18 @@ gpu_leakage: gpu-leakage@1d {
};
};
+ crypto: crypto@fe380000 {
+ compatible = "rockchip,rk3568-crypto";
+ reg = <0x0 0xfe380000 0x0 0x2000>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru CLK_CRYPTO_NS_CORE>, <&cru ACLK_CRYPTO_NS>,
+ <&cru HCLK_CRYPTO_NS>;
+ clock-names = "core", "aclk", "hclk";
+ resets = <&cru SRST_CRYPTO_NS_CORE>;
+ reset-names = "core";
+ status = "disabled";
+ };
+
i2s0_8ch: i2s@fe400000 {
compatible = "rockchip,rk3568-i2s-tdm";
reg = <0x0 0xfe400000 0x0 0x1000>;
--
2.47.3
^ permalink raw reply related
* [PATCH 2/4] crypto: rockchip: Add RK356x/RK3588 cryptographic offloader driver
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
To: herbert, davem, heiko
Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
In-Reply-To: <20260530160704.3453555-1-dawidro@gmail.com>
Add a driver for the second-generation Rockchip cryptographic hardware
accelerator found on RK3568 and RK3588 SoCs (compatible strings
"rockchip,rk3568-crypto" and "rockchip,rk3588-crypto").
The hardware provides:
- AES block cipher engine: ECB, CBC, and XTS modes, 128/192/256-bit
keys. XTS hardware is limited to single-SG requests.
- Hash engine: SHA-1, SHA-256, SHA-384, SHA-512, MD5, SM3.
The hardware padding engine (HW_PAD) requires the total message
length upfront and cannot maintain state across LLI descriptor
boundaries, so multi-SG and unaligned requests are routed to a
software fallback.
- DMA engine: linked-list descriptor (LLI) based, with a 20-entry
coherent descriptor table.
Design overview:
- Built on top of the crypto engine framework (crypto/engine.h) for
serialised hardware request dispatch and automatic fallback handling.
- Each platform device gets its own private copy of the algorithm
descriptor table at probe time (devm_kmemdup), so the dev pointer in
each template always refers to the correct hardware instance. This
avoids a global device list without any locking overhead.
- Runtime PM with autosuspend (2 s idle timeout) gates clocks and
asserts reset between requests to save power.
- Symmetric software fallback for all registered algorithms handles
requests that cannot be processed in hardware (misaligned buffers,
multi-SG inputs for hash, zero-length payloads).
Co-developed-by: Corentin Labbe <clabbe@baylibre.com>
Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
---
drivers/crypto/Kconfig | 33 +
drivers/crypto/Makefile | 1 +
drivers/crypto/rockchip/Makefile | 5 +
drivers/crypto/rockchip/rk2_crypto.c | 740 ++++++++++++++++++
drivers/crypto/rockchip/rk2_crypto.h | 243 ++++++
drivers/crypto/rockchip/rk2_crypto_ahash.c | 547 +++++++++++++
drivers/crypto/rockchip/rk2_crypto_skcipher.c | 724 +++++++++++++++++
7 files changed, 2293 insertions(+)
create mode 100644 drivers/crypto/rockchip/rk2_crypto.c
create mode 100644 drivers/crypto/rockchip/rk2_crypto.h
create mode 100644 drivers/crypto/rockchip/rk2_crypto_ahash.c
create mode 100644 drivers/crypto/rockchip/rk2_crypto_skcipher.c
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index d23b58b81ca3..47a891593814 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -709,6 +709,39 @@ config CRYPTO_DEV_ROCKCHIP_DEBUG
This will create /sys/kernel/debug/rk3288_crypto/stats for displaying
the number of requests per algorithm and other internal stats.
+config CRYPTO_DEV_ROCKCHIP2
+ tristate "Rockchip's cryptographic offloader"
+ depends on OF && ARCH_ROCKCHIP
+ depends on PM
+ select CRYPTO_ECB
+ select CRYPTO_CBC
+ select CRYPTO_AES
+ select CRYPTO_MD5
+ select CRYPTO_SHA1
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ select CRYPTO_SM3_GENERIC
+ select CRYPTO_HASH
+ select CRYPTO_XTS
+ select CRYPTO_SKCIPHER
+ select CRYPTO_ENGINE
+
+ help
+ This driver interfaces with the hardware crypto offloader present
+ on RK3566, RK3568 and RK3588 SoCs. It provides hardware acceleration
+ for symmetric block ciphers and hashing functions, offloading the
+ main CPU cores during heavy cryptographic workflows.
+
+config CRYPTO_DEV_ROCKCHIP2_DEBUG
+ bool "Enable Rockchip crypto stats"
+ depends on CRYPTO_DEV_ROCKCHIP2
+ depends on DEBUG_FS
+ help
+ Say y to enable Rockchip crypto debug stats.
+ This will create a directory using the device name
+ (e.g., /sys/kernel/debug/fe370000.crypto/stats) for displaying
+ the number of requests per algorithm and other internal stats.
+
config CRYPTO_DEV_TEGRA
tristate "Enable Tegra Security Engine"
depends on TEGRA_HOST1X
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 283bbc650b5b..905538078017 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/
obj-$(CONFIG_CRYPTO_DEV_QCOM_RNG) += qcom-rng.o
obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/
+obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP2) += rockchip/
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
obj-$(CONFIG_CRYPTO_DEV_SA2UL) += sa2ul.o
obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile
index 785277aca71e..452a12ff6538 100644
--- a/drivers/crypto/rockchip/Makefile
+++ b/drivers/crypto/rockchip/Makefile
@@ -3,3 +3,8 @@ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rk_crypto.o
rk_crypto-objs := rk3288_crypto.o \
rk3288_crypto_skcipher.o \
rk3288_crypto_ahash.o
+
+obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP2) += rk_crypto2.o
+rk_crypto2-objs := rk2_crypto.o \
+ rk2_crypto_skcipher.o \
+ rk2_crypto_ahash.o
diff --git a/drivers/crypto/rockchip/rk2_crypto.c b/drivers/crypto/rockchip/rk2_crypto.c
new file mode 100644
index 000000000000..df7dab4d7ca0
--- /dev/null
+++ b/drivers/crypto/rockchip/rk2_crypto.c
@@ -0,0 +1,740 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * hardware cryptographic offloader for RK3568/RK3588 SoC
+ *
+ * Copyright (c) 2022-2023, Corentin Labbe <clabbe@baylibre.com>
+ */
+
+#include "rk2_crypto.h"
+#include <linux/clk.h>
+#include <linux/crypto.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <crypto/aes.h>
+
+static const struct rk2_variant rk3568_variant = {
+ .num_clks = 3,
+};
+
+static const struct rk2_variant rk3588_variant = {
+ .num_clks = 3,
+};
+
+static int rk2_crypto_get_clks(struct rk2_crypto_dev *dev)
+{
+ dev->num_clks = devm_clk_bulk_get_all(dev->dev, &dev->clks);
+ if (dev->num_clks < 0)
+ return dev_err_probe(dev->dev, dev->num_clks, "Failed to get clocks\n");
+ if (dev->num_clks < dev->variant->num_clks)
+ return dev_err_probe(dev->dev, -EINVAL,
+ "Missing clocks, got %d instead of %d\n",
+ dev->num_clks, dev->variant->num_clks);
+ return 0;
+}
+
+static int rk2_crypto_pm_suspend(struct device *dev)
+{
+ struct rk2_crypto_dev *rkdev = dev_get_drvdata(dev);
+
+ reset_control_assert(rkdev->rst);
+ udelay(10);
+ clk_bulk_disable_unprepare(rkdev->num_clks, rkdev->clks);
+
+ return 0;
+}
+
+static int rk2_crypto_pm_resume(struct device *dev)
+{
+ struct rk2_crypto_dev *rkdev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(rkdev->num_clks, rkdev->clks);
+ if (ret)
+ return ret;
+
+ udelay(10);
+ reset_control_deassert(rkdev->rst);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rk2_crypto_pm_ops = {
+ RUNTIME_PM_OPS(rk2_crypto_pm_suspend, rk2_crypto_pm_resume, NULL)
+};
+
+static int rk2_crypto_pm_init(struct rk2_crypto_dev *rkdev)
+{
+ int err;
+
+ pm_runtime_use_autosuspend(rkdev->dev);
+ pm_runtime_set_autosuspend_delay(rkdev->dev, 2000);
+
+ err = pm_runtime_set_suspended(rkdev->dev);
+ if (err)
+ return err;
+ pm_runtime_enable(rkdev->dev);
+
+ return 0;
+}
+
+static void rk2_crypto_pm_exit(struct rk2_crypto_dev *rkdev)
+{
+ pm_runtime_disable(rkdev->dev);
+}
+
+static irqreturn_t rk2_crypto_irq_handle(int irq, void *dev_id)
+{
+ struct rk2_crypto_dev *rkc = platform_get_drvdata(dev_id);
+ u32 v;
+
+ v = readl(rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+ if (!v)
+ return IRQ_NONE;
+
+ writel(v, rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+
+ /*
+ * Only signal completion on list-done or hard DMA error.
+ * Intermediate SRC_INT (BIT(1)/BIT(2)) fire for every LLI
+ * entry that has RK2_LLI_DMA_CTRL_SRC_INT set. Completing
+ * early on those causes the driver to read hash registers
+ * before all data has been processed, producing wrong results.
+ */
+ if (v & RK2_CRYPTO_DMA_INT_ERR_MASK) {
+ dev_warn(rkc->dev, "DMA Error\n");
+ rkc->status = 0;
+ complete(&rkc->complete);
+ } else if (v & RK2_CRYPTO_DMA_INT_LISTDONE) {
+ rkc->status = 1;
+ complete(&rkc->complete);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct rk2_crypto_template rk2_crypto_algs_template[] = {
+ {
+ .type = CRYPTO_ALG_TYPE_SKCIPHER,
+ .rk2_mode = RK2_CRYPTO_AES_ECB,
+ .alg.skcipher.base = {
+ .base.cra_name = "ecb(aes)",
+ .base.cra_driver_name = "ecb-aes-rk2",
+ .base.cra_priority = 300,
+ .base.cra_flags =
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize = sizeof(struct rk2_cipher_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+ .init = rk2_cipher_tfm_init,
+ .exit = rk2_cipher_tfm_exit,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = rk2_aes_setkey,
+ .encrypt = rk2_skcipher_encrypt,
+ .decrypt = rk2_skcipher_decrypt,
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk2_cipher_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_SKCIPHER,
+ .rk2_mode = RK2_CRYPTO_AES_CBC,
+ .alg.skcipher.base = {
+ .base.cra_name = "cbc(aes)",
+ .base.cra_driver_name = "cbc-aes-rk2",
+ .base.cra_priority = 300,
+ .base.cra_flags =
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize =
+ sizeof(struct rk2_cipher_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+ .init = rk2_cipher_tfm_init,
+ .exit = rk2_cipher_tfm_exit,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = rk2_aes_setkey,
+ .encrypt = rk2_skcipher_encrypt,
+ .decrypt = rk2_skcipher_decrypt,
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk2_cipher_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_SKCIPHER,
+ .rk2_mode = RK2_CRYPTO_AES_XTS,
+ .is_xts = true,
+ .alg.skcipher.base = {
+ .base.cra_name = "xts(aes)",
+ .base.cra_driver_name = "xts-aes-rk2",
+ .base.cra_priority = 300,
+ .base.cra_flags =
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
+ .base.cra_blocksize = AES_BLOCK_SIZE,
+ .base.cra_ctxsize =
+ sizeof(struct rk2_cipher_ctx),
+ .base.cra_alignmask = 0,
+ .base.cra_module = THIS_MODULE,
+ .init = rk2_cipher_tfm_init,
+ .exit = rk2_cipher_tfm_exit,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = rk2_aes_xts_setkey,
+ .encrypt = rk2_skcipher_encrypt,
+ .decrypt = rk2_skcipher_decrypt,
+ },
+ .alg.skcipher.op = {
+ .do_one_request = rk2_cipher_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_AHASH,
+ .rk2_mode = RK2_CRYPTO_MD5,
+ .alg.hash.base = {
+ .init = rk2_ahash_init,
+ .update = rk2_ahash_update,
+ .final = rk2_ahash_final,
+ .finup = rk2_ahash_finup,
+ .export = rk2_ahash_export,
+ .import = rk2_ahash_import,
+ .digest = rk2_ahash_digest,
+ .init_tfm = rk2_hash_init_tfm,
+ .exit_tfm = rk2_hash_exit_tfm,
+ .halg = {
+ .digestsize = MD5_DIGEST_SIZE,
+ .statesize = sizeof(struct md5_state),
+ .base = {
+ .cra_name = "md5",
+ .cra_driver_name = "rk2-md5",
+ .cra_priority = 300,
+ .cra_flags =
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize =
+ MD5_HMAC_BLOCK_SIZE,
+ .cra_ctxsize =
+ sizeof(struct rk2_ahash_ctx),
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk2_hash_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_AHASH,
+ .rk2_mode = RK2_CRYPTO_SHA1,
+ .alg.hash.base = {
+ .init = rk2_ahash_init,
+ .update = rk2_ahash_update,
+ .final = rk2_ahash_final,
+ .finup = rk2_ahash_finup,
+ .export = rk2_ahash_export,
+ .import = rk2_ahash_import,
+ .digest = rk2_ahash_digest,
+ .init_tfm = rk2_hash_init_tfm,
+ .exit_tfm = rk2_hash_exit_tfm,
+ .halg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct sha1_state),
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "rk2-sha1",
+ .cra_priority = 300,
+ .cra_flags =
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize =
+ sizeof(struct rk2_ahash_ctx),
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk2_hash_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_AHASH,
+ .rk2_mode = RK2_CRYPTO_SHA224,
+ .alg.hash.base = {
+ .init = rk2_ahash_init,
+ .update = rk2_ahash_update,
+ .final = rk2_ahash_final,
+ .finup = rk2_ahash_finup,
+ .export = rk2_ahash_export,
+ .import = rk2_ahash_import,
+ .digest = rk2_ahash_digest,
+ .init_tfm = rk2_hash_init_tfm,
+ .exit_tfm = rk2_hash_exit_tfm,
+ .halg = {
+ .digestsize = SHA224_DIGEST_SIZE,
+ .statesize = sizeof(struct sha256_state),
+ .base = {
+ .cra_name = "sha224",
+ .cra_driver_name = "rk2-sha224",
+ .cra_priority = 300,
+ .cra_flags =
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize =
+ sizeof(struct rk2_ahash_ctx),
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk2_hash_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_AHASH,
+ .rk2_mode = RK2_CRYPTO_SHA256,
+ .alg.hash.base = {
+ .init = rk2_ahash_init,
+ .update = rk2_ahash_update,
+ .final = rk2_ahash_final,
+ .finup = rk2_ahash_finup,
+ .export = rk2_ahash_export,
+ .import = rk2_ahash_import,
+ .digest = rk2_ahash_digest,
+ .init_tfm = rk2_hash_init_tfm,
+ .exit_tfm = rk2_hash_exit_tfm,
+ .halg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct sha256_state),
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "rk2-sha256",
+ .cra_priority = 300,
+ .cra_flags =
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize =
+ sizeof(struct rk2_ahash_ctx),
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk2_hash_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_AHASH,
+ .rk2_mode = RK2_CRYPTO_SHA384,
+ .alg.hash.base = {
+ .init = rk2_ahash_init,
+ .update = rk2_ahash_update,
+ .final = rk2_ahash_final,
+ .finup = rk2_ahash_finup,
+ .export = rk2_ahash_export,
+ .import = rk2_ahash_import,
+ .digest = rk2_ahash_digest,
+ .init_tfm = rk2_hash_init_tfm,
+ .exit_tfm = rk2_hash_exit_tfm,
+ .halg = {
+ .digestsize = SHA384_DIGEST_SIZE,
+ .statesize = sizeof(struct sha512_state),
+ .base = {
+ .cra_name = "sha384",
+ .cra_driver_name = "rk2-sha384",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA384_BLOCK_SIZE,
+ .cra_ctxsize =
+ sizeof(struct rk2_ahash_ctx),
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk2_hash_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_AHASH,
+ .rk2_mode = RK2_CRYPTO_SHA512,
+ .alg.hash.base = {
+ .init = rk2_ahash_init,
+ .update = rk2_ahash_update,
+ .final = rk2_ahash_final,
+ .finup = rk2_ahash_finup,
+ .export = rk2_ahash_export,
+ .import = rk2_ahash_import,
+ .digest = rk2_ahash_digest,
+ .init_tfm = rk2_hash_init_tfm,
+ .exit_tfm = rk2_hash_exit_tfm,
+ .halg = {
+ .digestsize = SHA512_DIGEST_SIZE,
+ .statesize = sizeof(struct sha512_state),
+ .base = {
+ .cra_name = "sha512",
+ .cra_driver_name = "rk2-sha512",
+ .cra_priority = 300,
+ .cra_flags =
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_ctxsize =
+ sizeof(struct rk2_ahash_ctx),
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk2_hash_run,
+ },
+ },
+ {
+ .type = CRYPTO_ALG_TYPE_AHASH,
+ .rk2_mode = RK2_CRYPTO_SM3,
+ .alg.hash.base = {
+ .init = rk2_ahash_init,
+ .update = rk2_ahash_update,
+ .final = rk2_ahash_final,
+ .finup = rk2_ahash_finup,
+ .export = rk2_ahash_export,
+ .import = rk2_ahash_import,
+ .digest = rk2_ahash_digest,
+ .init_tfm = rk2_hash_init_tfm,
+ .exit_tfm = rk2_hash_exit_tfm,
+ .halg = {
+ .digestsize = SM3_DIGEST_SIZE,
+ .statesize = sizeof(struct sm3_state),
+ .base = {
+ .cra_name = "sm3",
+ .cra_driver_name = "rk2-sm3",
+ .cra_priority = 300,
+ .cra_flags =
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SM3_BLOCK_SIZE,
+ .cra_ctxsize =
+ sizeof(struct rk2_ahash_ctx),
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ .alg.hash.op = {
+ .do_one_request = rk2_hash_run,
+ },
+ },
+};
+
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+static int rk2_crypto_debugfs_stats_show(struct seq_file *seq, void *v)
+{
+ struct rk2_crypto_dev *rkc = seq->private;
+ unsigned int i;
+
+ seq_printf(seq, "%s %s requests: %lu\n",
+ dev_driver_string(rkc->dev), dev_name(rkc->dev), rkc->nreq);
+
+ for (i = 0; i < rkc->num_algs; i++) {
+ switch (rkc->algs[i].type) {
+ case CRYPTO_ALG_TYPE_SKCIPHER:
+ seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
+ rkc->algs[i].alg.skcipher.base.base.cra_driver_name,
+ rkc->algs[i].alg.skcipher.base.base.cra_name,
+ rkc->algs[i].stat_req, rkc->algs[i].stat_fb);
+ seq_printf(seq, "\tfallback due to length: %lu\n",
+ rkc->algs[i].stat_fb_len);
+ seq_printf(seq, "\tfallback due to alignment: %lu\n",
+ rkc->algs[i].stat_fb_align);
+ seq_printf(seq, "\tfallback due to SGs: %lu\n",
+ rkc->algs[i].stat_fb_sgdiff);
+ break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
+ rkc->algs[i].alg.hash.base.halg.base.cra_driver_name,
+ rkc->algs[i].alg.hash.base.halg.base.cra_name,
+ rkc->algs[i].stat_req,
+ rkc->algs[i].stat_fb);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int rk2_crypto_debugfs_info_show(struct seq_file *seq, void *d)
+{
+ struct rk2_crypto_dev *rkc = seq->private;
+ u32 v;
+ int err;
+
+ err = pm_runtime_resume_and_get(rkc->dev);
+ if (err)
+ return err;
+
+ v = readl(rkc->reg + RK2_CRYPTO_CLK_CTL);
+ seq_printf(seq, "CRYPTO_CLK_CTL %x\n", v);
+ v = readl(rkc->reg + RK2_CRYPTO_RST_CTL);
+ seq_printf(seq, "CRYPTO_RST_CTL %x\n", v);
+ v = readl(rkc->reg + CRYPTO_AES_VERSION);
+ seq_printf(seq, "CRYPTO_AES_VERSION %x\n", v);
+ if (v & BIT(17))
+ seq_puts(seq, "AES 192\n");
+ v = readl(rkc->reg + CRYPTO_DES_VERSION);
+ seq_printf(seq, "CRYPTO_DES_VERSION %x\n", v);
+ v = readl(rkc->reg + CRYPTO_SM4_VERSION);
+ seq_printf(seq, "CRYPTO_SM4_VERSION %x\n", v);
+ v = readl(rkc->reg + CRYPTO_HASH_VERSION);
+ seq_printf(seq, "CRYPTO_HASH_VERSION %x\n", v);
+ v = readl(rkc->reg + CRYPTO_HMAC_VERSION);
+ seq_printf(seq, "CRYPTO_HMAC_VERSION %x\n", v);
+ v = readl(rkc->reg + CRYPTO_RNG_VERSION);
+ seq_printf(seq, "CRYPTO_RNG_VERSION %x\n", v);
+ v = readl(rkc->reg + CRYPTO_PKA_VERSION);
+ seq_printf(seq, "CRYPTO_PKA_VERSION %x\n", v);
+ v = readl(rkc->reg + CRYPTO_CRYPTO_VERSION);
+ seq_printf(seq, "CRYPTO_CRYPTO_VERSION %x\n", v);
+
+ pm_runtime_mark_last_busy(rkc->dev);
+ pm_runtime_put_autosuspend(rkc->dev);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(rk2_crypto_debugfs_stats);
+DEFINE_SHOW_ATTRIBUTE(rk2_crypto_debugfs_info);
+
+#endif
+
+static void register_debugfs(struct rk2_crypto_dev *rkc)
+{
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+ /* Create a directory using the device name
+ * (e.g., /sys/kernel/debug/fe370000.crypto)
+ */
+ rkc->dbgfs_dir = debugfs_create_dir(dev_name(rkc->dev), NULL);
+
+ debugfs_create_file("stats", 0440, rkc->dbgfs_dir, rkc,
+ &rk2_crypto_debugfs_stats_fops);
+ debugfs_create_file("info", 0440, rkc->dbgfs_dir, rkc,
+ &rk2_crypto_debugfs_info_fops);
+#endif
+}
+
+static int rk2_crypto_register(struct rk2_crypto_dev *rkc)
+{
+ int i, k, err = 0;
+
+ for (i = 0; i < rkc->num_algs; i++) {
+ rkc->algs[i].dev = rkc; /* Tie this alg copy to this device */
+ switch (rkc->algs[i].type) {
+ case CRYPTO_ALG_TYPE_SKCIPHER:
+ err = crypto_engine_register_skcipher(&rkc->algs[i].alg.skcipher);
+ break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ err = crypto_engine_register_ahash(&rkc->algs[i].alg.hash);
+ break;
+ }
+ if (err)
+ goto err_cipher_algs;
+ }
+ return 0;
+
+ err_cipher_algs:
+ for (k = 0; k < i; k++) {
+ if (rkc->algs[k].type == CRYPTO_ALG_TYPE_SKCIPHER)
+ crypto_engine_unregister_skcipher(&rkc->algs[k].alg.skcipher);
+ else
+ crypto_engine_unregister_ahash(&rkc->algs[k].alg.hash);
+ }
+ return err;
+}
+
+static void rk2_crypto_unregister(struct rk2_crypto_dev *rkc)
+{
+ int i;
+
+ for (i = 0; i < rkc->num_algs; i++) {
+ if (rkc->algs[i].type == CRYPTO_ALG_TYPE_SKCIPHER)
+ crypto_engine_unregister_skcipher(&rkc->algs[i].alg.skcipher);
+ else
+ crypto_engine_unregister_ahash(&rkc->algs[i].alg.hash);
+ }
+}
+
+static const struct of_device_id crypto_of_id_table[] = {
+ {.compatible = "rockchip,rk3568-crypto",
+ .data = &rk3568_variant,
+ },
+ {.compatible = "rockchip,rk3588-crypto",
+ .data = &rk3588_variant,
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, crypto_of_id_table);
+
+static int rk2_crypto_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rk2_crypto_dev *rkc;
+ int err = 0;
+
+ rkc = devm_kzalloc(dev, sizeof(*rkc), GFP_KERNEL);
+ if (!rkc)
+ return -ENOMEM;
+
+ rkc->dev = dev;
+ platform_set_drvdata(pdev, rkc);
+
+ /* Duplicate the algorithms locally for this specific device */
+ rkc->num_algs = ARRAY_SIZE(rk2_crypto_algs_template);
+ rkc->algs = devm_kmemdup(dev, rk2_crypto_algs_template,
+ sizeof(rk2_crypto_algs_template), GFP_KERNEL);
+ if (!rkc->algs)
+ return -ENOMEM;
+
+ rkc->variant = of_device_get_match_data(dev);
+ if (!rkc->variant)
+ return dev_err_probe(dev, -EINVAL, "Missing variant\n");
+
+ rkc->rst = devm_reset_control_array_get_exclusive(dev);
+ if (IS_ERR(rkc->rst))
+ return dev_err_probe(dev, PTR_ERR(rkc->rst), "Fail to get resets\n");
+
+ /* Manual DMA allocation requires manual cleanup in error paths */
+ rkc->tl = dma_alloc_coherent(dev,
+ sizeof(struct rk2_crypto_lli) * MAX_LLI,
+ &rkc->t_phy, GFP_KERNEL);
+
+ if (!rkc->tl)
+ return -ENOMEM;
+
+ rkc->reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(rkc->reg)) {
+ err = dev_err_probe(dev, PTR_ERR(rkc->reg), "Fail to get resources\n");
+ goto err_dma;
+ }
+
+ err = rk2_crypto_get_clks(rkc);
+ if (err)
+ goto err_dma;
+
+ rkc->irq = platform_get_irq(pdev, 0);
+ if (rkc->irq < 0) {
+ err = dev_err_probe(dev, rkc->irq, "Interrupt is not available.\n");
+ goto err_dma;
+ }
+
+ err = devm_request_irq(dev, rkc->irq,
+ rk2_crypto_irq_handle, IRQF_SHARED,
+ "rk-crypto", pdev);
+
+ if (err) {
+ err = dev_err_probe(dev, err, "irq request failed.\n");
+ goto err_dma;
+ }
+
+ rkc->engine = crypto_engine_alloc_init(dev, true);
+ if (!rkc->engine) {
+ err = -ENOMEM;
+ goto err_dma;
+ }
+
+ err = crypto_engine_start(rkc->engine);
+ if (err) {
+ err = dev_err_probe(dev, err, "Failed to start crypto engine\n");
+ goto err_engine;
+ }
+
+ init_completion(&rkc->complete);
+
+ err = rk2_crypto_pm_init(rkc);
+ if (err) {
+ err = dev_err_probe(dev, err, "Failed to initialize runtime PM\n");
+ goto err_engine;
+ }
+
+ err = pm_runtime_resume_and_get(dev);
+ if (err) {
+ err = dev_err_probe(dev, err, "Failed to resume device\n");
+ goto err_pm;
+ }
+
+ /* Register algorithms specific to THIS device */
+ err = rk2_crypto_register(rkc);
+ if (err) {
+ err = dev_err_probe(dev, err, "Fail to register crypto algorithms\n");
+ goto err_pm_put;
+ }
+
+ register_debugfs(rkc);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+
+ err_pm_put:
+ pm_runtime_put_sync(dev);
+ err_pm:
+ rk2_crypto_pm_exit(rkc);
+ err_engine:
+ crypto_engine_exit(rkc->engine);
+ err_dma:
+ dma_free_coherent(dev, sizeof(struct rk2_crypto_lli) * MAX_LLI,
+ rkc->tl, rkc->t_phy);
+ return err;
+}
+
+static void rk2_crypto_remove(struct platform_device *pdev)
+{
+ struct rk2_crypto_dev *rkc = platform_get_drvdata(pdev);
+
+ /* Stop engine to prevent new requests */
+ crypto_engine_stop(rkc->engine);
+
+ /* Unregister algorithms for this specific device */
+ rk2_crypto_unregister(rkc);
+
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+ debugfs_remove_recursive(rkc->dbgfs_dir);
+#endif
+
+ /* Safe to kill the engine completely */
+ crypto_engine_exit(rkc->engine);
+
+ rk2_crypto_pm_exit(rkc);
+ dma_free_coherent(rkc->dev, sizeof(struct rk2_crypto_lli) * MAX_LLI,
+ rkc->tl, rkc->t_phy);
+}
+
+static struct platform_driver crypto_driver = {
+ .probe = rk2_crypto_probe,
+ .remove = rk2_crypto_remove,
+ .driver = {
+ .name = "rk2-crypto",
+ .pm = pm_ptr(&rk2_crypto_pm_ops),
+ .of_match_table = crypto_of_id_table,
+ },
+};
+
+module_platform_driver(crypto_driver);
+
+MODULE_DESCRIPTION("Rockchip Crypto Engine cryptographic offloader");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
+MODULE_AUTHOR("Dawid Olesinski <dawidro@gmail.com>");
+
diff --git a/drivers/crypto/rockchip/rk2_crypto.h b/drivers/crypto/rockchip/rk2_crypto.h
new file mode 100644
index 000000000000..40e20235cf7e
--- /dev/null
+++ b/drivers/crypto/rockchip/rk2_crypto.h
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __RK2_CRYPTO_H__
+#define __RK2_CRYPTO_H__
+
+#include <crypto/aes.h>
+#include <crypto/engine.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/sm3.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+
+#define RK2_CRYPTO_CLK_CTL 0x0000
+#define RK2_CRYPTO_RST_CTL 0x0004
+
+#define RK2_CRYPTO_DMA_INT_EN 0x0008
+
+/* RK2_CRYPTO_DMA_INT_ST / RK2_CRYPTO_DMA_INT_EN bit definitions */
+#define RK2_CRYPTO_DMA_INT_LISTDONE BIT(0) /* LLI list complete */
+#define RK2_CRYPTO_DMA_INT_SRC_ITEM_INT BIT(1) /* per-entry src interrupt */
+#define RK2_CRYPTO_DMA_INT_DST_ITEM_INT BIT(2) /* per-entry dst interrupt */
+#define RK2_CRYPTO_DMA_INT_LIST_SRC_ERR BIT(3) /* LLI src error */
+#define RK2_CRYPTO_DMA_INT_LIST_DST_ERR BIT(4) /* LLI dst error */
+#define RK2_CRYPTO_DMA_INT_SRC_ERR BIT(5) /* DMA src error */
+#define RK2_CRYPTO_DMA_INT_DST_ERR BIT(6) /* DMA dst error */
+
+#define RK2_CRYPTO_DMA_INT_ERR_MASK (RK2_CRYPTO_DMA_INT_LIST_SRC_ERR | \
+ RK2_CRYPTO_DMA_INT_LIST_DST_ERR | \
+ RK2_CRYPTO_DMA_INT_SRC_ERR | \
+ RK2_CRYPTO_DMA_INT_DST_ERR)
+
+#define RK2_CRYPTO_DMA_INT_ALL_MASK 0x7F
+
+/* The DMA interrupt enable register uses the upper 16 bits as a write-enable mask.
+ * To enable bits 0-6, we must write 1s to bits 16-22 as well.
+ */
+#define RK2_CRYPTO_DMA_INT_ENABLE_ALL ((RK2_CRYPTO_DMA_INT_ALL_MASK << 16) | \
+ RK2_CRYPTO_DMA_INT_ALL_MASK)
+
+/* values in RK2_CRYPTO_DMA_INT_ST are the same than in RK2_CRYPTO_DMA_INT_EN */
+#define RK2_CRYPTO_DMA_INT_ST 0x000C
+
+#define RK2_CRYPTO_DMA_CTL 0x0010
+#define RK2_CRYPTO_DMA_CTL_START BIT(0)
+
+#define RK2_CRYPTO_DMA_LLI_ADDR 0x0014
+#define RK2_CRYPTO_DMA_ST 0x0018
+#define RK2_CRYPTO_DMA_STATE 0x001C
+#define RK2_CRYPTO_DMA_LLI_RADDR 0x0020
+#define RK2_CRYPTO_DMA_SRC_RADDR 0x0024
+#define RK2_CRYPTO_DMA_DST_WADDR 0x0028
+#define RK2_CRYPTO_DMA_ITEM_ID 0x002C
+
+#define RK2_CRYPTO_FIFO_CTL 0x0040
+
+#define RK2_CRYPTO_BC_CTL 0x0044
+#define RK2_CRYPTO_AES (0 << 8)
+#define RK2_CRYPTO_MODE_ECB (0 << 4)
+#define RK2_CRYPTO_MODE_CBC (1 << 4)
+#define RK2_CRYPTO_XTS (6 << 4)
+
+#define RK2_CRYPTO_HASH_CTL 0x0048
+#define RK2_CRYPTO_HW_PAD BIT(2)
+#define RK2_CRYPTO_SHA1 (0 << 4)
+#define RK2_CRYPTO_MD5 (1 << 4)
+#define RK2_CRYPTO_SHA224 (3 << 4)
+#define RK2_CRYPTO_SHA256 (2 << 4)
+#define RK2_CRYPTO_SHA384 (9 << 4)
+#define RK2_CRYPTO_SHA512 (8 << 4)
+#define RK2_CRYPTO_SM3 (4 << 4)
+
+#define RK2_CRYPTO_AES_ECB (RK2_CRYPTO_AES | RK2_CRYPTO_MODE_ECB)
+#define RK2_CRYPTO_AES_CBC (RK2_CRYPTO_AES | RK2_CRYPTO_MODE_CBC)
+#define RK2_CRYPTO_AES_XTS (RK2_CRYPTO_AES | RK2_CRYPTO_XTS)
+#define RK2_CRYPTO_AES_128BIT_key (0 << 2)
+#define RK2_CRYPTO_AES_192BIT_key (1 << 2)
+#define RK2_CRYPTO_AES_256BIT_key (2 << 2)
+
+#define RK2_CRYPTO_DEC BIT(1)
+#define RK2_CRYPTO_ENABLE BIT(0)
+
+#define RK2_CRYPTO_CIPHER_ST 0x004C
+#define RK2_CRYPTO_CIPHER_STATE 0x0050
+
+#define RK2_CRYPTO_CH0_IV_0 0x0100
+
+#define RK2_CRYPTO_KEY0 0x0180
+#define RK2_CRYPTO_KEY1 0x0184
+#define RK2_CRYPTO_KEY2 0x0188
+#define RK2_CRYPTO_KEY3 0x018C
+#define RK2_CRYPTO_KEY4 0x0190
+#define RK2_CRYPTO_KEY5 0x0194
+#define RK2_CRYPTO_KEY6 0x0198
+#define RK2_CRYPTO_KEY7 0x019C
+#define RK2_CRYPTO_CH4_KEY0 0x01c0
+
+#define RK2_CRYPTO_CH0_PC_LEN_0 0x0280
+
+#define RK2_CRYPTO_CH0_IV_LEN 0x0300
+
+#define RK2_CRYPTO_HASH_DOUT_0 0x03A0
+#define RK2_CRYPTO_HASH_VALID 0x03E4
+
+#define RK2_CRYPTO_TRNG_CTL 0x0400
+#define RK2_CRYPTO_TRNG_START BIT(0)
+#define RK2_CRYPTO_TRNG_ENABLE BIT(1)
+#define RK2_CRYPTO_TRNG_256 (0x3 << 4)
+#define RK2_CRYPTO_TRNG_SAMPLE_CNT 0x0404
+#define RK2_CRYPTO_TRNG_DOUT 0x0410
+
+#define CRYPTO_AES_VERSION 0x0680
+#define CRYPTO_DES_VERSION 0x0684
+#define CRYPTO_SM4_VERSION 0x0688
+#define CRYPTO_HASH_VERSION 0x068C
+#define CRYPTO_HMAC_VERSION 0x0690
+#define CRYPTO_RNG_VERSION 0x0694
+#define CRYPTO_PKA_VERSION 0x0698
+#define CRYPTO_CRYPTO_VERSION 0x06F0
+
+#define RK2_LLI_DMA_CTRL_SRC_INT BIT(10)
+#define RK2_LLI_DMA_CTRL_DST_INT BIT(9)
+#define RK2_LLI_DMA_CTRL_LIST_INT BIT(8)
+#define RK2_LLI_DMA_CTRL_LAST BIT(0)
+
+#define RK2_LLI_STRING_LAST BIT(2)
+#define RK2_LLI_STRING_FIRST BIT(1)
+#define RK2_LLI_CIPHER_START BIT(0)
+
+#define MAX_LLI 20
+
+struct rk2_crypto_lli {
+ __le32 src_addr;
+ __le32 src_len;
+ __le32 dst_addr;
+ __le32 dst_len;
+ __le32 user;
+ __le32 iv;
+ __le32 dma_ctrl;
+ __le32 next;
+};
+
+struct rk2_variant {
+ int num_clks;
+};
+
+struct rk2_crypto_dev {
+ struct device *dev;
+ struct clk_bulk_data *clks;
+ int num_clks;
+ struct reset_control *rst;
+ void __iomem *reg;
+ int irq;
+ const struct rk2_variant *variant;
+ unsigned long nreq;
+ struct crypto_engine *engine;
+ struct completion complete;
+ int status;
+ struct rk2_crypto_lli *tl;
+ dma_addr_t t_phy;
+ struct rk2_crypto_template *algs;
+ int num_algs;
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+ struct dentry *dbgfs_dir;
+#endif
+};
+
+/* the private variable of hash */
+struct rk2_ahash_ctx {
+ /* for fallback */
+ struct crypto_ahash *fallback_tfm;
+};
+
+/* the private variable of hash for fallback */
+struct rk2_ahash_rctx {
+ struct rk2_crypto_dev *dev;
+ u32 mode;
+ int nrsgs;
+ struct ahash_request fallback_req;
+};
+
+/* the private variable of cipher */
+struct rk2_cipher_ctx {
+ unsigned int keylen;
+ u8 key[AES_MAX_KEY_SIZE * 2];
+ struct crypto_skcipher *fallback_tfm;
+};
+
+struct rk2_cipher_rctx {
+ struct rk2_crypto_dev *dev;
+ u8 backup_iv[AES_BLOCK_SIZE];
+ u32 mode;
+ /* must be last, see __ctx placement */
+ struct skcipher_request fallback_req;
+};
+
+struct rk2_crypto_template {
+ u32 type;
+ u32 rk2_mode;
+ bool is_xts;
+ struct rk2_crypto_dev *dev;
+ union {
+ struct skcipher_engine_alg skcipher;
+ struct ahash_engine_alg hash;
+ } alg;
+ unsigned long stat_req;
+ unsigned long stat_fb;
+ unsigned long stat_fb_len;
+ unsigned long stat_fb_sglen;
+ unsigned long stat_fb_align;
+ unsigned long stat_fb_sgdiff;
+};
+
+int rk2_cipher_run(struct crypto_engine *engine, void *async_req);
+int rk2_hash_run(struct crypto_engine *engine, void *breq);
+
+int rk2_cipher_tfm_init(struct crypto_skcipher *tfm);
+void rk2_cipher_tfm_exit(struct crypto_skcipher *tfm);
+int rk2_aes_setkey(struct crypto_skcipher *cipher, const u8 *key,
+ unsigned int keylen);
+int rk2_aes_xts_setkey(struct crypto_skcipher *cipher, const u8 *key,
+ unsigned int keylen);
+int rk2_skcipher_encrypt(struct skcipher_request *req);
+int rk2_skcipher_decrypt(struct skcipher_request *req);
+
+int rk2_ahash_init(struct ahash_request *req);
+int rk2_ahash_update(struct ahash_request *req);
+int rk2_ahash_final(struct ahash_request *req);
+int rk2_ahash_finup(struct ahash_request *req);
+int rk2_ahash_import(struct ahash_request *req, const void *in);
+int rk2_ahash_export(struct ahash_request *req, void *out);
+int rk2_ahash_digest(struct ahash_request *req);
+int rk2_hash_init_tfm(struct crypto_ahash *tfm);
+void rk2_hash_exit_tfm(struct crypto_ahash *tfm);
+
+#endif /* __RK2_CRYPTO_H__ */
diff --git a/drivers/crypto/rockchip/rk2_crypto_ahash.c b/drivers/crypto/rockchip/rk2_crypto_ahash.c
new file mode 100644
index 000000000000..5aeff32d1402
--- /dev/null
+++ b/drivers/crypto/rockchip/rk2_crypto_ahash.c
@@ -0,0 +1,547 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Crypto offloader support for Rockchip RK3568/RK3588
+ *
+ * Copyright (c) 2022-2023 Corentin Labbe <clabbe@baylibre.com>
+ */
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/scatterlist.h>
+#include <linux/unaligned.h>
+#include <crypto/aes.h>
+#include <crypto/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/sm3.h>
+#include "rk2_crypto.h"
+
+static bool rk2_ahash_need_fallback(struct ahash_request *areq)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.hash.base);
+ struct scatterlist *sg;
+ int nents = sg_nents_for_len(areq->src, areq->nbytes);
+
+ /*
+ * The hardware's Merkle-Damgard padding engine (HW_PAD) requires the
+ * total message length to be known upfront via CH0_PC_LEN_0. When a
+ * request spans multiple LLI descriptors, the hardware either treats
+ * each descriptor as an independent padded message, or loses running
+ * hash state at descriptor boundaries. Either way the result is a
+ * wrong digest. This behaviour is not documented in the RK3588 TRM,
+ * which advertises LLI chaining but does not specify whether hash
+ * operations may span multiple linked descriptors.
+ * Work around this by falling back to software for any multi-SG
+ * request. Single-SG requests with HW_PAD work correctly.
+ */
+
+ if (nents < 0) {
+ dev_err(algt->dev->dev, "Invalid SG list: length mismatch\n");
+ return true; /* force fallback safely */
+ }
+ if (nents > 1) {
+ algt->stat_fb_sgdiff++;
+ return true;
+ }
+
+ sg = areq->src;
+ while (sg) {
+ if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
+ algt->stat_fb_align++;
+ return true;
+ }
+ if (sg->length % 4) {
+ algt->stat_fb_sglen++;
+ return true;
+ }
+ sg = sg_next(sg);
+ }
+ return false;
+}
+
+static int rk2_ahash_digest_fb(struct ahash_request *areq)
+{
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct rk2_ahash_ctx *tfmctx = crypto_ahash_ctx(tfm);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.hash.base);
+
+ algt->stat_fb++;
+
+ ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm);
+ ahash_request_set_callback(&rctx->fallback_req, areq->base.flags,
+ areq->base.complete, areq->base.data);
+
+ rctx->fallback_req.nbytes = areq->nbytes;
+ rctx->fallback_req.src = areq->src;
+ rctx->fallback_req.result = areq->result;
+
+ return crypto_ahash_digest(&rctx->fallback_req);
+}
+
+static int zero_message_process(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.hash.base);
+ int digestsize = crypto_ahash_digestsize(tfm);
+
+ switch (algt->rk2_mode) {
+ case RK2_CRYPTO_SHA1:
+ memcpy(req->result, sha1_zero_message_hash, digestsize);
+ break;
+ case RK2_CRYPTO_SHA256:
+ memcpy(req->result, sha256_zero_message_hash, digestsize);
+ break;
+ case RK2_CRYPTO_SHA384:
+ memcpy(req->result, sha384_zero_message_hash, digestsize);
+ break;
+ case RK2_CRYPTO_SHA512:
+ memcpy(req->result, sha512_zero_message_hash, digestsize);
+ break;
+ case RK2_CRYPTO_MD5:
+ memcpy(req->result, md5_zero_message_hash, digestsize);
+ break;
+ case RK2_CRYPTO_SM3:
+ memcpy(req->result, sm3_zero_message_hash, digestsize);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * rk2_ahash_init() - Initialize context for a hash request
+ * @req: The asynchronous hash request structure.
+ *
+ * Initializes the software fallback context. The physical hardware engine
+ * is only utilized during atomic digest operations.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_init(struct ahash_request *req)
+{
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+ req->base.complete, req->base.data);
+
+ return crypto_ahash_init(&rctx->fallback_req);
+}
+
+/**
+ * rk2_ahash_update() - Feed a message block into the hash stream
+ * @req: The asynchronous hash request structure.
+ *
+ * Passes the message block to the software fallback. The hardware engine
+ * does not support fragmented streaming updates.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_update(struct ahash_request *req)
+{
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+ req->base.complete, req->base.data);
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
+
+ return crypto_ahash_update(&rctx->fallback_req);
+}
+
+/**
+ * rk2_ahash_final() - Finalize the hashing operation
+ * @req: The asynchronous hash request structure.
+ *
+ * Finalizes the hash and extracts the digest via the software fallback.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_final(struct ahash_request *req)
+{
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+ req->base.complete, req->base.data);
+ rctx->fallback_req.result = req->result;
+
+ return crypto_ahash_final(&rctx->fallback_req);
+}
+
+/**
+ * rk2_ahash_finup() - Perform update and final hash operations sequentially
+ * @req: The asynchronous hash request structure.
+ *
+ * Convenience wrapper that performs update and final operations
+ * via the software fallback.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_finup(struct ahash_request *req)
+{
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+ req->base.complete, req->base.data);
+
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
+ rctx->fallback_req.result = req->result;
+
+ return crypto_ahash_finup(&rctx->fallback_req);
+}
+
+/**
+ * rk2_ahash_import() - Restore a saved hash context
+ * @req: The target asynchronous hash request structure.
+ * @in: Buffer containing the previously exported state.
+ *
+ * Restores the software fallback state from an export block.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_import(struct ahash_request *req, const void *in)
+{
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+ req->base.complete, req->base.data);
+
+ return crypto_ahash_import(&rctx->fallback_req, in);
+}
+
+/**
+ * rk2_ahash_export() - Serialize an active hash context
+ * @req: The source asynchronous hash request structure.
+ * @out: Destination buffer where the state will be written.
+ *
+ * Freezes the progression of the software fallback stream into a byte array.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_ahash_export(struct ahash_request *req, void *out)
+{
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct rk2_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ ahash_request_set_callback(&rctx->fallback_req, req->base.flags,
+ req->base.complete, req->base.data);
+
+ return crypto_ahash_export(&rctx->fallback_req, out);
+}
+
+/**
+ * rk2_ahash_digest() - Compute a complete message digest in a single transaction
+ * @req: The asynchronous hash request structure.
+ *
+ * Evaluates hardware constraints (e.g., scatterlist alignment) and either
+ * routes the atomic request to the hardware engine or diverts to the fallback.
+ *
+ * Return: 0 on synchronous completion, -EINPROGRESS if submitted to the
+ * hardware engine, or a negative error code on failure.
+ */
+int rk2_ahash_digest(struct ahash_request *req)
+{
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk2_crypto_template *algt;
+ struct rk2_crypto_dev *rkc;
+ struct crypto_engine *engine;
+
+ if (!req->nbytes)
+ return zero_message_process(req);
+
+ if (rk2_ahash_need_fallback(req))
+ return rk2_ahash_digest_fb(req);
+
+ /* Extract the device pointer from the algorithm template! */
+ algt = container_of(alg, struct rk2_crypto_template, alg.hash.base);
+ rkc = algt->dev;
+ if (!rkc)
+ return -ENODEV;
+
+ rctx->dev = rkc;
+ engine = rkc->engine;
+
+ return crypto_transfer_hash_request_to_engine(engine, req);
+}
+
+static int rk2_hash_prepare(struct crypto_engine *engine, void *breq)
+{
+ struct ahash_request *areq =
+ container_of(breq, struct ahash_request, base);
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq);
+ struct rk2_crypto_dev *rkc = rctx->dev;
+ int n = sg_nents_for_len(areq->src, areq->nbytes);
+ int ret;
+
+ if (n < 0) {
+ dev_err(rkc->dev, "SG list too short for %u bytes\n", areq->nbytes);
+ return -EINVAL;
+ }
+ rctx->nrsgs = n;
+ ret = dma_map_sg(rkc->dev, areq->src, rctx->nrsgs, DMA_TO_DEVICE);
+ if (ret <= 0) {
+ /*
+ * clear nrsgs on map failure to prevent spurious unmap in unprepare
+ */
+ rctx->nrsgs = 0;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void rk2_hash_unprepare(struct crypto_engine *engine, void *breq)
+{
+ struct ahash_request *areq =
+ container_of(breq, struct ahash_request, base);
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq);
+ struct rk2_crypto_dev *rkc = rctx->dev;
+
+ if (rctx->nrsgs)
+ dma_unmap_sg(rkc->dev, areq->src, rctx->nrsgs, DMA_TO_DEVICE);
+}
+
+/**
+ * rk2_hash_run() - Execute an asynchronous hash request via the hardware
+ * @engine: The crypto engine queue managing this request.
+ * @breq: The asynchronous hash request to process.
+ *
+ * Configures the hardware hash engine, programs DMA block descriptors,
+ * and copies the final digest back from the hardware registers.
+ *
+ * Return: Always 0. Errors are reported through the crypto engine
+ * finalization callback.
+ */
+int rk2_hash_run(struct crypto_engine *engine, void *breq)
+{
+ struct ahash_request *areq =
+ container_of(breq, struct ahash_request, base);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct rk2_ahash_rctx *rctx = ahash_request_ctx(areq);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.hash.base);
+ struct scatterlist *sgs = areq->src;
+ struct rk2_crypto_dev *rkc = rctx->dev;
+ struct rk2_crypto_lli *dd = &rkc->tl[0];
+ int ddi = 0;
+ int err = 0;
+ unsigned int len = areq->nbytes;
+ unsigned int todo;
+ unsigned long timeout;
+ u32 v;
+ int i;
+
+ err = rk2_hash_prepare(engine, breq);
+ if (err)
+ goto exit_unmap;
+
+ err = pm_runtime_resume_and_get(rkc->dev);
+ if (err)
+ goto exit_unmap;
+
+ dev_dbg(rkc->dev, "%s %s len=%u\n", __func__,
+ crypto_tfm_alg_name(areq->base.tfm), areq->nbytes);
+
+ algt->stat_req++;
+ rkc->nreq++;
+
+ /* the upper bits are a write enable mask, so we need to write 1 to all
+ * upper 16 bits to allow write to the 16 lower bits
+ */
+ rctx->mode = algt->rk2_mode;
+ rctx->mode |= 0xffff0000;
+ rctx->mode |= RK2_CRYPTO_ENABLE | RK2_CRYPTO_HW_PAD;
+ writel(rctx->mode, rkc->reg + RK2_CRYPTO_HASH_CTL);
+
+ while (sgs && len > 0) {
+ if (ddi >= MAX_LLI) {
+ dev_err(rkc->dev,
+ "Too many SG entries (current: %d, max: %d)\n",
+ ddi, MAX_LLI);
+ err = -EINVAL;
+ goto exit;
+ }
+ dd = &rkc->tl[ddi];
+
+ todo = min(sg_dma_len(sgs), len);
+ dd->src_addr = sg_dma_address(sgs);
+ dd->src_len = todo;
+ dd->dst_addr = 0;
+ dd->dst_len = 0;
+ dd->dma_ctrl = ddi << 24;
+ dd->iv = 0;
+ dd->next =
+ rkc->t_phy + sizeof(struct rk2_crypto_lli) * (ddi + 1);
+
+ if (ddi == 0)
+ dd->user = RK2_LLI_CIPHER_START | RK2_LLI_STRING_FIRST;
+ else
+ dd->user = 0;
+
+ len -= todo;
+ if (len == 0) {
+ dd->user |= RK2_LLI_STRING_LAST;
+ dd->dma_ctrl |= RK2_LLI_DMA_CTRL_LAST |
+ RK2_LLI_DMA_CTRL_SRC_INT |
+ RK2_LLI_DMA_CTRL_LIST_INT;
+ }
+ dev_dbg(rkc->dev,
+ "HASH SG %d sglen=%u user=%x dma=%x mode=%x len=%u todo=%u phy=%pad\n",
+ ddi, sgs->length, dd->user, dd->dma_ctrl, rctx->mode,
+ len, todo, &rkc->t_phy);
+
+ sgs = sg_next(sgs);
+ ddi++;
+ }
+
+ /*
+ * next is ignored by hardware when RK2_LLI_DMA_CTRL_LAST is set in
+ * dma_ctrl. Set it to an obviously-invalid-but-non-zero sentinel so
+ * it stands out if ever read in a debug dump.
+ */
+ dd->next = 1;
+
+ /* Program total payload length for hardware padding */
+ writel(areq->nbytes, rkc->reg + RK2_CRYPTO_CH0_PC_LEN_0);
+
+ /* Clear stale interrupts, then enable with proper write-mask */
+ writel(RK2_CRYPTO_DMA_INT_ALL_MASK, rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+ writel(RK2_CRYPTO_DMA_INT_ENABLE_ALL, rkc->reg + RK2_CRYPTO_DMA_INT_EN);
+
+ writel(rkc->t_phy, rkc->reg + RK2_CRYPTO_DMA_LLI_ADDR);
+
+ reinit_completion(&rkc->complete);
+ rkc->status = 0;
+
+ writel(RK2_CRYPTO_DMA_CTL_START | (RK2_CRYPTO_DMA_CTL_START << 16),
+ rkc->reg + RK2_CRYPTO_DMA_CTL);
+
+ timeout = wait_for_completion_timeout(&rkc->complete,
+ msecs_to_jiffies(2000));
+ if (!timeout) {
+ dev_err(rkc->dev, "DMA timeout\n");
+ err = -ETIMEDOUT;
+ reset_control_assert(rkc->rst);
+ udelay(10);
+ reset_control_deassert(rkc->rst);
+ goto exit;
+ }
+ if (!rkc->status) {
+ dev_err(rkc->dev, "DMA error\n");
+ err = -EIO;
+ reset_control_assert(rkc->rst);
+ udelay(10);
+ reset_control_deassert(rkc->rst);
+ goto exit;
+ }
+
+ err =
+ readl_poll_timeout_atomic(rkc->reg + RK2_CRYPTO_HASH_VALID, v,
+ v == 1, 10, 1000);
+ if (err) {
+ dev_err(rkc->dev, "Hash result not valid\n");
+ goto exit;
+ }
+
+ /*
+ * Hardware outputs digest words in big-endian format.
+ * Because readl() performs a native little-endian read,
+ * put_unaligned_be32() is used to store the result correctly
+ * into the byte array.
+ */
+ for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++) {
+ v = readl(rkc->reg + RK2_CRYPTO_HASH_DOUT_0 + i * 4);
+ put_unaligned_be32(v, areq->result + i * 4);
+ }
+ exit:
+ writel(0xffff0000, rkc->reg + RK2_CRYPTO_HASH_CTL);
+ pm_runtime_mark_last_busy(rkc->dev);
+ pm_runtime_put_autosuspend(rkc->dev);
+
+ exit_unmap:
+ rk2_hash_unprepare(engine, breq);
+ local_bh_disable();
+ crypto_finalize_hash_request(engine, breq, err);
+ local_bh_enable();
+
+ return 0;
+}
+
+/**
+ * rk2_hash_init_tfm() - Initialize the transformation context
+ * @tfm: The crypto ahash handle.
+ *
+ * Allocates software fallback transformations required to guarantee
+ * processing integrity when hardware constraints are violated.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_hash_init_tfm(struct crypto_ahash *tfm)
+{
+ struct rk2_ahash_ctx *tctx = crypto_ahash_ctx(tfm);
+ const char *alg_name = crypto_ahash_alg_name(tfm);
+ struct ahash_alg *alg = crypto_ahash_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.hash.base);
+ unsigned int fallback_statesize;
+
+ tctx->fallback_tfm = crypto_alloc_ahash(alg_name, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(tctx->fallback_tfm)) {
+ dev_err(algt->dev->dev, "Could not load fallback driver.\n");
+ return PTR_ERR(tctx->fallback_tfm);
+ }
+
+ /* Promote statesize if fallback needs more space for export/import */
+ fallback_statesize = crypto_ahash_statesize(tctx->fallback_tfm);
+ if (fallback_statesize > crypto_ahash_statesize(tfm))
+ crypto_ahash_set_statesize(tfm, fallback_statesize);
+
+ crypto_ahash_set_reqsize(tfm,
+ sizeof(struct rk2_ahash_rctx) +
+ crypto_ahash_reqsize(tctx->fallback_tfm));
+ return 0;
+}
+
+/**
+ * rk2_hash_exit_tfm() - Clean up an ahash transformation context
+ * @tfm: The crypto ahash handle.
+ *
+ * Safely frees internal software fallback transformations.
+ */
+void rk2_hash_exit_tfm(struct crypto_ahash *tfm)
+{
+ struct rk2_ahash_ctx *tctx = crypto_ahash_ctx(tfm);
+
+ crypto_free_ahash(tctx->fallback_tfm);
+}
diff --git a/drivers/crypto/rockchip/rk2_crypto_skcipher.c b/drivers/crypto/rockchip/rk2_crypto_skcipher.c
new file mode 100644
index 000000000000..e1a1a1a13096
--- /dev/null
+++ b/drivers/crypto/rockchip/rk2_crypto_skcipher.c
@@ -0,0 +1,724 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * hardware cryptographic offloader for RK3568/RK3588 SoC
+ *
+ * Copyright (c) 2022-2023 Corentin Labbe <clabbe@baylibre.com>
+ */
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/aes.h>
+#include <crypto/xts.h>
+#include "rk2_crypto.h"
+
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+static void rk2_print(struct rk2_crypto_dev *rkc)
+{
+ u32 v;
+
+ v = readl(rkc->reg + RK2_CRYPTO_DMA_ST);
+ dev_info(rkc->dev, "DMA_ST %x\n", v);
+ switch (v) {
+ case 0:
+ dev_info(rkc->dev, "DMA_ST: DMA IDLE\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "DMA_ST: DMA BUSY\n");
+ break;
+ default:
+ dev_err(rkc->dev, "DMA_ST: invalid value\n");
+ }
+
+ v = readl(rkc->reg + RK2_CRYPTO_DMA_STATE);
+ dev_info(rkc->dev, "DMA_STATE %x\n", v);
+
+ switch (v & 0x3) {
+ case 0:
+ dev_info(rkc->dev, "DMA_STATE: DMA DST IDLE\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "DMA_STATE: DMA DST LOAD\n");
+ break;
+ case 2:
+ dev_info(rkc->dev, "DMA_STATE: DMA DST WORK\n");
+ break;
+ default:
+ dev_err(rkc->dev, "DMA DST invalid\n");
+ break;
+ }
+ switch ((v >> 2) & 0x3) {
+ case 0:
+ dev_info(rkc->dev, "DMA_STATE: DMA SRC IDLE\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "DMA_STATE: DMA SRC LOAD\n");
+ break;
+ case 2:
+ dev_info(rkc->dev, "DMA_STATE: DMA SRC WORK\n");
+ break;
+ default:
+ dev_err(rkc->dev, "DMA_STATE: DMA SRC invalid\n");
+ break;
+ }
+ switch ((v >> 4) & 0x3) {
+ case 0:
+ dev_info(rkc->dev, "DMA_STATE: DMA LLI IDLE\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "DMA_STATE: DMA LLI LOAD\n");
+ break;
+ case 2:
+ dev_info(rkc->dev, "DMA_STATE: LLI WORK\n");
+ break;
+ default:
+ dev_err(rkc->dev, "DMA_STATE: LLI invalid\n");
+ break;
+ }
+
+ v = readl(rkc->reg + RK2_CRYPTO_DMA_LLI_RADDR);
+ dev_info(rkc->dev, "DMA_LLI_RADDR %x\n", v);
+ v = readl(rkc->reg + RK2_CRYPTO_DMA_SRC_RADDR);
+ dev_info(rkc->dev, "DMA_SRC_RADDR %x\n", v);
+ v = readl(rkc->reg + RK2_CRYPTO_DMA_DST_WADDR);
+ dev_info(rkc->dev, "DMA_DST_WADDR %x\n", v);
+ v = readl(rkc->reg + RK2_CRYPTO_DMA_ITEM_ID);
+ dev_info(rkc->dev, "DMA_ITEM_ID %x\n", v);
+
+ v = readl(rkc->reg + RK2_CRYPTO_CIPHER_ST);
+ dev_info(rkc->dev, "CIPHER_ST %x\n", v);
+ if (v & BIT(0))
+ dev_info(rkc->dev, "CIPHER_ST: BLOCK CIPHER BUSY\n");
+ else
+ dev_info(rkc->dev, "CIPHER_ST: BLOCK CIPHER IDLE\n");
+ if (v & BIT(2))
+ dev_info(rkc->dev, "CIPHER_ST: HASH BUSY\n");
+ else
+ dev_info(rkc->dev, "CIPHER_ST: HASH IDLE\n");
+ if (v & BIT(3))
+ dev_info(rkc->dev, "CIPHER_ST: OTP KEY VALID\n");
+ else
+ dev_info(rkc->dev, "CIPHER_ST: OTP KEY INVALID\n");
+
+ v = readl(rkc->reg + RK2_CRYPTO_CIPHER_STATE);
+ dev_info(rkc->dev, "CIPHER_STATE %x\n", v);
+ switch (v & 0x3) {
+ case 0:
+ dev_info(rkc->dev, "serial: IDLE state\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "serial: PRE state\n");
+ break;
+ case 2:
+ dev_info(rkc->dev, "serial: BULK state\n");
+ break;
+ default:
+ dev_info(rkc->dev, "serial: reserved state\n");
+ break;
+ }
+ switch ((v >> 2) & 0x3) {
+ case 0:
+ dev_info(rkc->dev, "mac_state: IDLE state\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "mac_state: PRE state\n");
+ break;
+ case 2:
+ dev_info(rkc->dev, "mac_state: BULK state\n");
+ break;
+ default:
+ dev_info(rkc->dev, "mac_state: reserved state\n");
+ break;
+ }
+ switch ((v >> 4) & 0x3) {
+ case 0:
+ dev_info(rkc->dev, "parallel_state: IDLE state\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "parallel_state: PRE state\n");
+ break;
+ case 2:
+ dev_info(rkc->dev, "parallel_state: BULK state\n");
+ break;
+ default:
+ dev_info(rkc->dev, "parallel_state: reserved state\n");
+ break;
+ }
+ switch ((v >> 6) & 0x3) {
+ case 0:
+ dev_info(rkc->dev, "ccm_state: IDLE state\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "ccm_state: PRE state\n");
+ break;
+ case 2:
+ dev_info(rkc->dev, "ccm_state: NA state\n");
+ break;
+ default:
+ dev_info(rkc->dev, "ccm_state: reserved state\n");
+ break;
+ }
+ switch ((v >> 8) & 0xF) {
+ case 0:
+ dev_info(rkc->dev, "gcm_state: IDLE state\n");
+ break;
+ case 1:
+ dev_info(rkc->dev, "gcm_state: PRE state\n");
+ break;
+ case 2:
+ dev_info(rkc->dev, "gcm_state: NA state\n");
+ break;
+ case 3:
+ dev_info(rkc->dev, "gcm_state: PC state\n");
+ break;
+ }
+ switch ((v >> 10) & 0x1F) {
+ case 0x1:
+ dev_info(rkc->dev, "hash_state: IDLE state\n");
+ break;
+ case 0x2:
+ dev_info(rkc->dev, "hash_state: IPAD state\n");
+ break;
+ case 0x4:
+ dev_info(rkc->dev, "hash_state: TEXT state\n");
+ break;
+ case 0x8:
+ dev_info(rkc->dev, "hash_state: OPAD state\n");
+ break;
+ case 0x10:
+ dev_info(rkc->dev, "hash_state: OPAD EXT state\n");
+ break;
+ default:
+ dev_info(rkc->dev, "hash_state: invalid state\n");
+ break;
+ }
+
+ v = readl(rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+ dev_info(rkc->dev, "RK2_CRYPTO_DMA_INT_ST %x\n", v);
+}
+#endif
+
+static int rk2_cipher_need_fallback(struct skcipher_request *req)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+ struct scatterlist *sgs, *sgd;
+ unsigned int stodo, dtodo, len;
+ unsigned int bs = crypto_skcipher_blocksize(tfm);
+
+ if (!req->cryptlen)
+ return true;
+
+ /*
+ * The hardware XTS implementation programs the tweak once before
+ * DMA starts and cannot update it at SG boundaries. Restrict to
+ * exactly one source and one destination SG entry.
+ */
+ if (algt->is_xts) {
+ if (sg_nents_for_len(req->src, req->cryptlen) != 1)
+ return true;
+ if (sg_nents_for_len(req->dst, req->cryptlen) != 1)
+ return true;
+ }
+
+ len = req->cryptlen;
+ sgs = req->src;
+ sgd = req->dst;
+
+ while (len > 0 && sgs && sgd) {
+ if (!IS_ALIGNED(sgs->offset, sizeof(u32))) {
+ algt->stat_fb_align++;
+ return true;
+ }
+ if (!IS_ALIGNED(sgd->offset, sizeof(u32))) {
+ algt->stat_fb_align++;
+ return true;
+ }
+
+ stodo = min(len, sgs->length);
+ if (stodo % bs) {
+ algt->stat_fb_len++;
+ return true;
+ }
+
+ dtodo = min(len, sgd->length);
+ if (dtodo % bs) {
+ algt->stat_fb_len++;
+ return true;
+ }
+
+ /* DMA engines usually require symmetrical source/destination chunks */
+ if (stodo != dtodo) {
+ algt->stat_fb_sgdiff++;
+ return true;
+ }
+
+ len -= stodo;
+ sgs = sg_next(sgs);
+ sgd = sg_next(sgd);
+ }
+
+ /* If len > 0, the scatterlist was too short for the request */
+ return len > 0;
+}
+
+static int rk2_cipher_fallback(struct skcipher_request *areq)
+{
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct rk2_cipher_ctx *op = crypto_skcipher_ctx(tfm);
+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(areq);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+ int err;
+
+ algt->stat_fb++;
+
+ skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm);
+ skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags,
+ areq->base.complete, areq->base.data);
+ skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst,
+ areq->cryptlen, areq->iv);
+
+ if (rctx->mode & RK2_CRYPTO_DEC)
+ err = crypto_skcipher_decrypt(&rctx->fallback_req);
+ else
+ err = crypto_skcipher_encrypt(&rctx->fallback_req);
+ return err;
+}
+
+static int rk2_cipher_handle_req(struct skcipher_request *req)
+{
+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+ struct rk2_crypto_dev *rkc;
+ struct crypto_engine *engine;
+
+ if (algt->is_xts && ctx->keylen == AES_KEYSIZE_192 * 2)
+ return rk2_cipher_fallback(req);
+
+ if (rk2_cipher_need_fallback(req))
+ return rk2_cipher_fallback(req);
+
+ rkc = algt->dev;
+ if (!rkc)
+ return -ENODEV;
+ engine = rkc->engine;
+ rctx->dev = rkc;
+
+ return crypto_transfer_skcipher_request_to_engine(engine, req);
+}
+
+/**
+ * rk2_aes_setkey() - Configure the key for standard AES algorithms
+ * @cipher: The crypto skcipher handle.
+ * @key: Buffer containing the raw key material.
+ * @keylen: Length of the key in bytes.
+ *
+ * Validates key length, stores the key in the context, and configures
+ * the software fallback transformation.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_aes_setkey(struct crypto_skcipher *cipher, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher);
+ struct rk2_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
+ keylen != AES_KEYSIZE_256)
+ return -EINVAL;
+ ctx->keylen = keylen;
+ memcpy(ctx->key, key, keylen);
+
+ crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK);
+ crypto_skcipher_set_flags(ctx->fallback_tfm,
+ crypto_skcipher_get_flags(cipher) & CRYPTO_TFM_REQ_MASK);
+
+ return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen);
+}
+
+/**
+ * rk2_aes_xts_setkey() - Configure the key for AES-XTS mode
+ * @cipher: The crypto skcipher handle.
+ * @key: Buffer containing both cipher and tweak keys.
+ * @keylen: Total length of the key in bytes.
+ *
+ * Validates XTS-specific bounds (e.g., FIPS requirements) and configures
+ * both the hardware context and fallback.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_aes_xts_setkey(struct crypto_skcipher *cipher, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher);
+ struct rk2_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ int err;
+
+ err = xts_verify_key(cipher, key, keylen);
+ if (err)
+ return err;
+
+ ctx->keylen = keylen;
+ memcpy(ctx->key, key, keylen);
+
+ crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK);
+ crypto_skcipher_set_flags(ctx->fallback_tfm,
+ crypto_skcipher_get_flags(cipher) & CRYPTO_TFM_REQ_MASK);
+
+ return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen);
+}
+
+/**
+ * rk2_skcipher_encrypt() - General skcipher encryption entry point
+ * @req: The skcipher request structure.
+ *
+ * Evaluates hardware constraints and enqueues the request into the crypto
+ * engine, or diverts to software fallback.
+ *
+ * Return: 0 on success, negative error code, or -EINPROGRESS.
+ */
+int rk2_skcipher_encrypt(struct skcipher_request *req)
+{
+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+
+ rctx->mode = algt->rk2_mode;
+ return rk2_cipher_handle_req(req);
+}
+
+/**
+ * rk2_skcipher_decrypt() - General skcipher decryption entry point
+ * @req: The skcipher request structure.
+ *
+ * Evaluates hardware constraints and enqueues the request into the crypto
+ * engine, or diverts to software fallback.
+ *
+ * Return: 0 on success, negative error code, or -EINPROGRESS.
+ */
+int rk2_skcipher_decrypt(struct skcipher_request *req)
+{
+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(req);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+
+ rctx->mode = algt->rk2_mode | RK2_CRYPTO_DEC;
+ return rk2_cipher_handle_req(req);
+}
+
+/**
+ * rk2_cipher_run() - Execute an asynchronous skcipher request
+ * @engine: The crypto engine queue managing this request.
+ * @async_req: The asynchronous skcipher request to process.
+ *
+ * Prepares the hardware context, configures DMA descriptors, programs
+ * cipher registers, and triggers the physical cryptographic accelerator.
+ *
+ * Return: Always 0. Errors are reported through the crypto engine
+ * finalization callback.
+ */
+int rk2_cipher_run(struct crypto_engine *engine, void *async_req)
+{
+ struct skcipher_request *areq =
+ container_of(async_req, struct skcipher_request, base);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq);
+ struct rk2_cipher_rctx *rctx = skcipher_request_ctx(areq);
+ struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+ struct scatterlist *sgs, *sgd;
+ int err = 0;
+ int ivsize = crypto_skcipher_ivsize(tfm);
+ unsigned int len = areq->cryptlen;
+ unsigned int todo;
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+ struct rk2_crypto_dev *rkc = rctx->dev;
+ struct rk2_crypto_lli *dd = &rkc->tl[0];
+ u32 m, v;
+ u32 *rkey = (u32 *) ctx->key;
+ u32 *riv = (u32 *) areq->iv;
+ int i;
+ unsigned int offset;
+ unsigned long timeout;
+
+ m = rctx->mode | RK2_CRYPTO_ENABLE;
+ if (algt->is_xts) {
+ switch (ctx->keylen) {
+ case AES_KEYSIZE_128 * 2:
+ m |= RK2_CRYPTO_AES_128BIT_key;
+ break;
+ case AES_KEYSIZE_256 * 2:
+ m |= RK2_CRYPTO_AES_256BIT_key;
+ break;
+ default:
+ dev_err(rkc->dev, "Invalid key length %u\n",
+ ctx->keylen);
+ err = -EINVAL;
+ goto exit_no_pm;
+ }
+ } else {
+ switch (ctx->keylen) {
+ case AES_KEYSIZE_128:
+ m |= RK2_CRYPTO_AES_128BIT_key;
+ break;
+ case AES_KEYSIZE_192:
+ m |= RK2_CRYPTO_AES_192BIT_key;
+ break;
+ case AES_KEYSIZE_256:
+ m |= RK2_CRYPTO_AES_256BIT_key;
+ break;
+ default:
+ dev_err(rkc->dev, "Invalid key length %u\n",
+ ctx->keylen);
+ err = -EINVAL;
+ goto exit_no_pm;
+ }
+ }
+
+ err = pm_runtime_resume_and_get(rkc->dev);
+ if (err)
+ goto exit_no_pm;
+
+ algt->stat_req++;
+ rkc->nreq++;
+
+ /* the upper bits are a write enable mask, so we need to write 1 to all
+ * upper 16 bits to allow write to the 16 lower bits
+ */
+ m |= 0xffff0000;
+
+ dev_dbg(rkc->dev, "%s %s len=%u keylen=%u mode=%x\n", __func__,
+ crypto_tfm_alg_name(areq->base.tfm),
+ areq->cryptlen, ctx->keylen, m);
+ sgs = areq->src;
+ sgd = areq->dst;
+
+ while (sgs && sgd && len) {
+ if (!sgs->length) {
+ sgs = sg_next(sgs);
+ sgd = sg_next(sgd);
+ continue;
+ }
+
+ if (areq->iv && crypto_skcipher_ivsize(tfm) > 0) {
+ if (rctx->mode & RK2_CRYPTO_DEC) {
+ offset = sgs->length - ivsize;
+ scatterwalk_map_and_copy(rctx->backup_iv, sgs,
+ offset, ivsize, 0);
+ }
+ }
+
+ dev_dbg(rkc->dev, "SG len=%u mode=%x ivsize=%u\n", sgs->length,
+ m, ivsize);
+
+ if (sgs == sgd) {
+ err = dma_map_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL);
+ if (err != 1) {
+ dev_err(rkc->dev, "Invalid sg number %d\n",
+ err);
+ err = -EINVAL;
+ goto exit;
+ }
+ } else {
+ err = dma_map_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE);
+ if (err != 1) {
+ dev_err(rkc->dev, "Invalid sg number %d\n",
+ err);
+ err = -EINVAL;
+ goto exit;
+ }
+ err = dma_map_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE);
+ if (err != 1) {
+ dev_err(rkc->dev, "Invalid sg number %d\n",
+ err);
+ err = -EINVAL;
+ dma_unmap_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE);
+ goto exit;
+ }
+ }
+ err = 0;
+ writel(m, rkc->reg + RK2_CRYPTO_BC_CTL);
+
+ if (algt->is_xts) {
+ for (i = 0; i < ctx->keylen / 8; i++) {
+ v = cpu_to_be32(rkey[i]);
+ writel(v, rkc->reg + RK2_CRYPTO_KEY0 + i * 4);
+ }
+ for (i = 0; i < (ctx->keylen / 8); i++) {
+ v = cpu_to_be32(rkey[i + ctx->keylen / 8]);
+ writel(v,
+ rkc->reg + RK2_CRYPTO_CH4_KEY0 + i * 4);
+ }
+ } else {
+ for (i = 0; i < ctx->keylen / 4; i++) {
+ v = cpu_to_be32(rkey[i]);
+ writel(v, rkc->reg + RK2_CRYPTO_KEY0 + i * 4);
+ }
+ }
+
+ if (ivsize) {
+ for (i = 0; i < ivsize / 4; i++)
+ writel(cpu_to_be32(riv[i]),
+ rkc->reg + RK2_CRYPTO_CH0_IV_0 + i * 4);
+ writel(ivsize, rkc->reg + RK2_CRYPTO_CH0_IV_LEN);
+ }
+
+ /*
+ * Process one SG entry per DMA operation. The cipher engine requires
+ * the IV to be updated between SG entries for CBC and XTS modes;
+ * the backup_iv mechanism handles this correctly for decryption.
+ * Building a full multi-descriptor chain is possible but adds
+ * complexity for no measurable throughput gain on typical workloads.
+ */
+ todo = min(sg_dma_len(sgs), len);
+ len -= todo;
+ dd->src_addr = sg_dma_address(sgs);
+ dd->src_len = todo;
+ dd->dst_addr = sg_dma_address(sgd);
+ dd->dst_len = todo;
+ dd->iv = 0;
+
+ /*
+ * next is ignored by hardware when RK2_LLI_DMA_CTRL_LAST is set in
+ * dma_ctrl. Set it to an obviously-invalid-but-non-zero sentinel so
+ * it stands out if ever read in a debug dump.
+ */
+ dd->next = 1;
+
+ dd->user = RK2_LLI_CIPHER_START |
+ RK2_LLI_STRING_FIRST | RK2_LLI_STRING_LAST;
+ dd->dma_ctrl = RK2_LLI_DMA_CTRL_DST_INT |
+ RK2_LLI_DMA_CTRL_LAST | RK2_LLI_DMA_CTRL_LIST_INT;
+
+ /* Clear stale interrupts, then enable with proper write-mask */
+ writel(RK2_CRYPTO_DMA_INT_ALL_MASK, rkc->reg + RK2_CRYPTO_DMA_INT_ST);
+ writel(RK2_CRYPTO_DMA_INT_ENABLE_ALL, rkc->reg + RK2_CRYPTO_DMA_INT_EN);
+
+ writel(rkc->t_phy, rkc->reg + RK2_CRYPTO_DMA_LLI_ADDR);
+
+ reinit_completion(&rkc->complete);
+ rkc->status = 0;
+
+ writel(RK2_CRYPTO_DMA_CTL_START |
+ (RK2_CRYPTO_DMA_CTL_START << 16),
+ rkc->reg + RK2_CRYPTO_DMA_CTL);
+
+ timeout = wait_for_completion_timeout(&rkc->complete,
+ msecs_to_jiffies(2000));
+ if (sgs == sgd) {
+ dma_unmap_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL);
+ } else {
+ dma_unmap_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE);
+ dma_unmap_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE);
+ }
+
+ if (!timeout) {
+ dev_err(rkc->dev, "DMA timeout\n");
+ err = -ETIMEDOUT;
+ reset_control_assert(rkc->rst);
+ udelay(10);
+ reset_control_deassert(rkc->rst);
+ goto exit;
+ }
+
+ if (!rkc->status) {
+ dev_err(rkc->dev, "DMA error\n");
+#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP2_DEBUG
+ rk2_print(rkc);
+#endif
+ err = -EIO;
+ reset_control_assert(rkc->rst);
+ udelay(10);
+ reset_control_deassert(rkc->rst);
+ goto exit;
+ }
+
+ if (areq->iv && ivsize > 0) {
+ offset = sgd->length - ivsize;
+ if (rctx->mode & RK2_CRYPTO_DEC) {
+ memcpy(areq->iv, rctx->backup_iv, ivsize);
+ memzero_explicit(rctx->backup_iv, ivsize);
+ } else {
+ scatterwalk_map_and_copy(areq->iv, sgd, offset,
+ ivsize, 0);
+ }
+ }
+ sgs = sg_next(sgs);
+ sgd = sg_next(sgd);
+ }
+ exit:
+ writel(0xffff0000, rkc->reg + RK2_CRYPTO_BC_CTL);
+ pm_runtime_mark_last_busy(rkc->dev);
+ pm_runtime_put_autosuspend(rkc->dev);
+ exit_no_pm:
+ local_bh_disable();
+ crypto_finalize_skcipher_request(engine, areq, err);
+ local_bh_enable();
+ return 0;
+}
+
+/**
+ * rk2_cipher_tfm_init() - Initialize the transformation context
+ * @tfm: The crypto skcipher handle.
+ *
+ * Allocates the software fallback transformations required when requests
+ * fail to meet hardware constraints (e.g., severe scatterlist misalignment).
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int rk2_cipher_tfm_init(struct crypto_skcipher *tfm)
+{
+ struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+ const char *name = crypto_tfm_alg_name(&tfm->base);
+ struct skcipher_alg *alg = crypto_skcipher_alg(tfm);
+ struct rk2_crypto_template *algt =
+ container_of(alg, struct rk2_crypto_template, alg.skcipher.base);
+
+ ctx->fallback_tfm =
+ crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(ctx->fallback_tfm)) {
+ dev_err(algt->dev->dev,
+ "Cannot allocate fallback for %s %ld\n", name,
+ PTR_ERR(ctx->fallback_tfm));
+ return PTR_ERR(ctx->fallback_tfm);
+ }
+
+ dev_dbg(algt->dev->dev, "Fallback for %s is %s\n",
+ crypto_tfm_alg_driver_name(&tfm->base),
+ crypto_tfm_alg_driver_name(crypto_skcipher_tfm
+ (ctx->fallback_tfm)));
+
+ tfm->reqsize = sizeof(struct rk2_cipher_rctx) +
+ crypto_skcipher_reqsize(ctx->fallback_tfm);
+
+ return 0;
+}
+
+/**
+ * rk2_cipher_tfm_exit() - Free skcipher initialization resources
+ * @tfm: The crypto skcipher handle.
+ *
+ * Synchronously releases internal software fallback transformations
+ * and zeroes out sensitive key material.
+ */
+void rk2_cipher_tfm_exit(struct crypto_skcipher *tfm)
+{
+ struct rk2_cipher_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ memzero_explicit(ctx->key, ctx->keylen);
+ crypto_free_skcipher(ctx->fallback_tfm);
+}
--
2.47.3
^ permalink raw reply related
* [PATCH 1/4] dt-bindings: crypto: rockchip: Add RK356x/RK3588 crypto engine binding
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
To: herbert, davem, heiko
Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
In-Reply-To: <20260530160704.3453555-1-dawidro@gmail.com>
Add a YAML device tree binding for the Rockchip second-generation (V2)
cryptographic hardware accelerator present on the RK3568 and RK3588 SoCs.
The IP block exposes AES-ECB, AES-CBC, AES-XTS block ciphers, SHA-1,
SHA-224, SHA-256, SHA-384, SHA-512, MD5, and SM3 hash algorithms, each
with a hardware DMA engine controlled via linked-list descriptors.
The binding covers two compatible strings:
- rockchip,rk3568-crypto: clocks and resets are driven directly by the
non-secure CRU (accessible to Linux at EL1).
- rockchip,rk3588-crypto: clocks and resets live in SECURECRU, a
register bank sandboxed to TrustZone. Linux must request them through
the ARM SCMI firmware interface (scmi_clk / scmi_reset), as direct
MMIO access to SECURECRU from EL1 triggers a bus fault.
Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
---
.../crypto/rockchip,rk3588-crypto.yaml | 69 +++++++++++++++++++
1 file changed, 69 insertions(+)
create mode 100644 Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml
diff --git a/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml b/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml
new file mode 100644
index 000000000000..4188ed8920db
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/rockchip,rk3588-crypto.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip cryptographic offloader
+
+maintainers:
+ - Heiko Stuebner <heiko@sntech.de>
+ - Corentin Labbe <clabbe@baylibre.com>
+ - Dawid Olesinski <dawidro@gmail.com>
+
+properties:
+ compatible:
+ enum:
+ - rockchip,rk3568-crypto
+ - rockchip,rk3588-crypto
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Core clock for the crypto IP internal logic
+ - description: AXI interconnect clock interface
+ - description: AHB interface clock
+
+ clock-names:
+ items:
+ - const: core
+ - const: aclk
+ - const: hclk
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ items:
+ - const: core
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ crypto@fe370000 {
+ compatible = "rockchip,rk3588-crypto";
+ reg = <0x0 0xfe370000 0x0 0x2000>;
+ interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&scmi_clk SCMI_CRYPTO_CORE>,
+ <&scmi_clk SCMI_ACLK_SECURE_NS>,
+ <&scmi_clk SCMI_HCLK_SECURE_NS>;
+ clock-names = "core", "aclk", "hclk";
+ resets = <&scmi_reset SCMI_SRST_CRYPTO_CORE>;
+ reset-names = "core";
+ };
--
2.47.3
^ permalink raw reply related
* [PATCH 0/4] crypto: rockchip: Add RK356x/RK3588 cryptographic
From: Dawid Olesinski @ 2026-05-30 16:06 UTC (permalink / raw)
To: herbert, davem, heiko
Cc: linux-crypto, linux-rockchip, devicetree, linux-arm-kernel,
clabbe, robh, krzk+dt, conor+dt, linux-kernel, Dawid Olesinski
This series adds support for the second-generation (V2) Rockchip
cryptographic hardware accelerator found on RK3568 and RK3588 SoCs.
The IP block provides AES (ECB, CBC, XTS) and hash (SHA-1, SHA-256,
SHA-384, SHA-512, MD5, SM3) offload via an LLI-based DMA engine.
The series is ordered as required: binding first, then driver, then
the two DTS nodes that reference the binding.
A prerequisite patch removing SECURECRU reset definitions from the
non-secure CRU driver is sent separately to the clk/reset tree, as it
touches a different subsystem. That patch is not a hard dependency for
the driver to build or load, but it is needed for correctness on RK3588:
those register offsets map into TrustZone-protected MMIO and must not be
accessed directly by Linux.
This work started from unmerged patches by Corentin Labbe
<clabbe@baylibre.com> posted at:
https://patchew.org/linux/20231107155532.3747113-1-clabbe@baylibre.com/
The implementation has been substantially reworked. Notable changes from
Corentin's original series:
- DMA descriptor race condition and DMA mapping leak on timeout fixed
- Per-device algorithm copy replaces global device list, removing a
locking bottleneck and correctly supporting multiple instances
- Runtime PM autosuspend added; clocks and reset gated between requests
- Multi-SG hash requests routed to software fallback (hardware padding
engine requires total message length upfront and cannot maintain
state across LLI boundaries)
- Hardware interrupt enable register write corrected to use the
HIWORD_UPDATE mask that the hardware requires
- Software fallback for all registered algorithms; statesize promotion
for export/import compatibility with ARM Crypto Extensions drivers
- SCMI reset and clock references in DTS corrected for RK3588
Tested on Orange Pi 5 Pro (RK3588S). All nine algorithm selftests pass.
AES-CBC throughput measured at ~100 MiB/s with cryptsetup. PM
autosuspend/resume verified over 1000 consecutive hash requests with no
errors. 20 modprobe/rmmod cycles produce no DMA coherent memory leaks.
Patch series for the crypto subsystem:
[1/4] dt-bindings: crypto: rockchip: Add RK356x/RK3588 crypto engine
binding
[2/4] crypto: rockchip: Add RK356x/RK3588 cryptographic offloader driver
[3/4] arm64: dts: rockchip: Add crypto node to rk356x-base
[4/4] arm64: dts: rockchip: Add crypto node to rk3588-base
Separate patch for clk/reset tree:
clk: rockchip: rk3588: Remove SECURECRU reset definitions
Signed-off-by: Dawid Olesinski <dawidro@gmail.com>
Dawid Olesinski (4):
dt-bindings: crypto: rockchip: Add RK356x/RK3588 crypto engine binding
crypto: rockchip: Add RK356x/RK3588 cryptographic offloader driver
arm64: dts: rockchip: Add crypto node to rk356x-base
arm64: dts: rockchip: Add crypto node to rk3588-base
.../crypto/rockchip,rk3588-crypto.yaml | 69 ++
arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 12 +
arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 12 +
drivers/crypto/Kconfig | 33 +
drivers/crypto/Makefile | 1 +
drivers/crypto/rockchip/Makefile | 5 +
drivers/crypto/rockchip/rk2_crypto.c | 740 ++++++++++++++++++
drivers/crypto/rockchip/rk2_crypto.h | 243 ++++++
drivers/crypto/rockchip/rk2_crypto_ahash.c | 547 +++++++++++++
drivers/crypto/rockchip/rk2_crypto_skcipher.c | 724 +++++++++++++++++
10 files changed, 2386 insertions(+)
create mode 100644 Documentation/devicetree/bindings/crypto/rockchip,rk3588-crypto.yaml
create mode 100644 drivers/crypto/rockchip/rk2_crypto.c
create mode 100644 drivers/crypto/rockchip/rk2_crypto.h
create mode 100644 drivers/crypto/rockchip/rk2_crypto_ahash.c
create mode 100644 drivers/crypto/rockchip/rk2_crypto_skcipher.c
--
2.47.3
^ permalink raw reply
* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Aleksander Jan Bajkowski @ 2026-05-30 15:05 UTC (permalink / raw)
To: Eric Biggers, linux-crypto, Herbert Xu
Cc: Christian Lamparter, linuxppc-dev, linux-kernel, stable
In-Reply-To: <20260529220430.34135-1-ebiggers@kernel.org>
Hi Eric,
On 30/05/2026 00:04, Eric Biggers wrote:
> Remove crypto4xx_rng, as it is insecure and unused:
>
> - It has only a 64-bit security strength, which is highly inadequate.
> This can be seen by the fact that crypto4xx_hw_init() seeds it with
> only 64 bits of entropy, and the fact that the original commit
> mentions that it implements ANSI X9.17 Annex C.
In addition to a seed, the PRNG also uses ring oscillators as sources of
entropy. The entropy should be higher than 64b. This is the Rambus EIP-73d
IP core. The same IP core is built into eip93 (EIP-73a), eip97 (EIP-73d),
and eip197 (EIP-73d). You can find the documentation online. The complete
"container" is actually Rambus EIP-94, and one of its parts is EIP-73d.
>
> Another issue was that this driver didn't implement the crypto_rng API
> correctly, as crypto4xx_prng_generate() didn't return 0 on success.
>
> - No user of this code is known. It's usable only theoretically via the
> "rng" algorithm type of AF_ALG. But userspace actually just uses the
> actual Linux RNG (/dev/random etc) instead. And rng_algs don't
> contribute entropy to the actual Linux RNG either. (This may have
> been confused with hwrng, which does contribute entropy.)
This PRNG is also used internally for Generation IV with IPSEC offload. The
IPSEC offload implementation for eip93 was recently submitted to upstream.
I am not sure whether eip94 shares some of the logic for IPSEC offload and
it will be possible to use some of the code.
>
> Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support")
> Cc: stable@vger.kernel.org
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> Acked-by: Christian Lamparter <chunkeey@gmail.com>
> ---
> drivers/crypto/Kconfig | 1 -
> drivers/crypto/amcc/crypto4xx_core.c | 88 -------------------------
> drivers/crypto/amcc/crypto4xx_core.h | 4 --
> drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ----
> 4 files changed, 104 deletions(-)
>
>
> base-commit: 49e05bb00f2e8168695f7af4d694c39e1423e8a2
>
> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> index 3449b3c9c6ad..5dab813a9f74 100644
> --- a/drivers/crypto/Kconfig
> +++ b/drivers/crypto/Kconfig
> @@ -299,11 +299,10 @@ config CRYPTO_DEV_PPC4XX
> select CRYPTO_AES
> select CRYPTO_LIB_AES
> select CRYPTO_CCM
> select CRYPTO_CTR
> select CRYPTO_GCM
> - select CRYPTO_RNG
> select CRYPTO_SKCIPHER
> help
> This option allows you to have support for AMCC crypto acceleration.
>
> config HW_RANDOM_PPC4XX
> diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
> index b7b6c97d2147..68c5ff7a85b4 100644
> --- a/drivers/crypto/amcc/crypto4xx_core.c
> +++ b/drivers/crypto/amcc/crypto4xx_core.c
> @@ -29,15 +29,13 @@
> #include <crypto/aead.h>
> #include <crypto/aes.h>
> #include <crypto/ctr.h>
> #include <crypto/gcm.h>
> #include <crypto/sha1.h>
> -#include <crypto/rng.h>
> #include <crypto/scatterwalk.h>
> #include <crypto/skcipher.h>
> #include <crypto/internal/aead.h>
> -#include <crypto/internal/rng.h>
> #include <crypto/internal/skcipher.h>
> #include "crypto4xx_reg_def.h"
> #include "crypto4xx_core.h"
> #include "crypto4xx_sa.h"
> #include "crypto4xx_trng.h"
> @@ -983,14 +981,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
> switch (alg->alg.type) {
> case CRYPTO_ALG_TYPE_AEAD:
> rc = crypto_register_aead(&alg->alg.u.aead);
> break;
>
> - case CRYPTO_ALG_TYPE_RNG:
> - rc = crypto_register_rng(&alg->alg.u.rng);
> - break;
> -
> default:
> rc = crypto_register_skcipher(&alg->alg.u.cipher);
> break;
> }
>
> @@ -1012,14 +1006,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
> switch (alg->alg.type) {
> case CRYPTO_ALG_TYPE_AEAD:
> crypto_unregister_aead(&alg->alg.u.aead);
> break;
>
> - case CRYPTO_ALG_TYPE_RNG:
> - crypto_unregister_rng(&alg->alg.u.rng);
> - break;
> -
> default:
> crypto_unregister_skcipher(&alg->alg.u.cipher);
> }
> kfree(alg);
> }
> @@ -1074,73 +1064,10 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
> {
> return crypto4xx_interrupt_handler(irq, data, PPC4XX_INTERRUPT_CLR |
> PPC4XX_TMO_ERR_INT);
> }
>
> -static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
> - u8 *data, unsigned int max)
> -{
> - unsigned int i, curr = 0;
> - u32 val[2];
> -
> - do {
> - /* trigger PRN generation */
> - writel(PPC4XX_PRNG_CTRL_AUTO_EN,
> - dev->ce_base + CRYPTO4XX_PRNG_CTRL);
> -
> - for (i = 0; i < 1024; i++) {
> - /* usually 19 iterations are enough */
> - if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
> - CRYPTO4XX_PRNG_STAT_BUSY))
> - continue;
> -
> - val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
> - val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
> - break;
> - }
> - if (i == 1024)
> - return -ETIMEDOUT;
> -
> - if ((max - curr) >= 8) {
> - memcpy(data, &val, 8);
> - data += 8;
> - curr += 8;
> - } else {
> - /* copy only remaining bytes */
> - memcpy(data, &val, max - curr);
> - break;
> - }
> - } while (curr < max);
> -
> - return curr;
> -}
> -
> -static int crypto4xx_prng_generate(struct crypto_rng *tfm,
> - const u8 *src, unsigned int slen,
> - u8 *dstn, unsigned int dlen)
> -{
> - struct rng_alg *alg = crypto_rng_alg(tfm);
> - struct crypto4xx_alg *amcc_alg;
> - struct crypto4xx_device *dev;
> - int ret;
> -
> - amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
> - dev = amcc_alg->dev;
> -
> - mutex_lock(&dev->core_dev->rng_lock);
> - ret = ppc4xx_prng_data_read(dev, dstn, dlen);
> - mutex_unlock(&dev->core_dev->rng_lock);
> - return ret;
> -}
> -
> -
> -static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
> - unsigned int slen)
> -{
> - return 0;
> -}
> -
> /*
> * Supported Crypto Algorithms
> */
> static struct crypto4xx_alg_common crypto4xx_alg[] = {
> /* Crypto AES modes */
> @@ -1266,22 +1193,10 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
> .cra_blocksize = 1,
> .cra_ctxsize = sizeof(struct crypto4xx_ctx),
> .cra_module = THIS_MODULE,
> },
> } },
> - { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
> - .base = {
> - .cra_name = "stdrng",
> - .cra_driver_name = "crypto4xx_rng",
> - .cra_priority = 300,
> - .cra_ctxsize = 0,
> - .cra_module = THIS_MODULE,
> - },
> - .generate = crypto4xx_prng_generate,
> - .seed = crypto4xx_prng_seed,
> - .seedsize = 0,
> - } },
> };
>
> /*
> * Module Initialization Routine
> */
> @@ -1351,13 +1266,10 @@ static int crypto4xx_probe(struct platform_device *ofdev)
> }
>
> core_dev->dev->core_dev = core_dev;
> core_dev->dev->is_revb = is_revb;
> core_dev->device = dev;
> - rc = devm_mutex_init(&ofdev->dev, &core_dev->rng_lock);
> - if (rc)
> - return rc;
> spin_lock_init(&core_dev->lock);
> INIT_LIST_HEAD(&core_dev->dev->alg_list);
> ratelimit_default_init(&core_dev->dev->aead_ratelimit);
> rc = crypto4xx_build_sdr(core_dev->dev);
> if (rc)
> diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
> index ee36630c670f..3a028aec3f0c 100644
> --- a/drivers/crypto/amcc/crypto4xx_core.h
> +++ b/drivers/crypto/amcc/crypto4xx_core.h
> @@ -12,14 +12,12 @@
>
> #ifndef __CRYPTO4XX_CORE_H__
> #define __CRYPTO4XX_CORE_H__
>
> #include <linux/ratelimit.h>
> -#include <linux/mutex.h>
> #include <linux/scatterlist.h>
> #include <crypto/internal/aead.h>
> -#include <crypto/internal/rng.h>
> #include <crypto/internal/skcipher.h>
> #include "crypto4xx_reg_def.h"
> #include "crypto4xx_sa.h"
>
> #define PPC460SX_SDR0_SRST 0x201
> @@ -109,11 +107,10 @@ struct crypto4xx_core_device {
> struct hwrng *trng;
> u32 int_status;
> u32 irq;
> struct tasklet_struct tasklet;
> spinlock_t lock;
> - struct mutex rng_lock;
> };
>
> struct crypto4xx_ctx {
> struct crypto4xx_device *dev;
> struct dynamic_sa_ctl *sa_in;
> @@ -133,11 +130,10 @@ struct crypto4xx_aead_reqctx {
> struct crypto4xx_alg_common {
> u32 type;
> union {
> struct skcipher_alg cipher;
> struct aead_alg aead;
> - struct rng_alg rng;
> } u;
> };
>
> struct crypto4xx_alg {
> struct list_head entry;
> diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
> index 1038061224da..73d626308a84 100644
> --- a/drivers/crypto/amcc/crypto4xx_reg_def.h
> +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
> @@ -88,24 +88,13 @@
>
> #define CRYPTO4XX_DMA_CFG 0x000600d4
> #define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
> #define CRYPTO4XX_ENDIAN_CFG 0x000600d8
>
> -#define CRYPTO4XX_PRNG_STAT 0x00070000
> -#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
> #define CRYPTO4XX_PRNG_CTRL 0x00070004
> #define CRYPTO4XX_PRNG_SEED_L 0x00070008
> #define CRYPTO4XX_PRNG_SEED_H 0x0007000c
> -
> -#define CRYPTO4XX_PRNG_RES_0 0x00070020
> -#define CRYPTO4XX_PRNG_RES_1 0x00070024
> -#define CRYPTO4XX_PRNG_RES_2 0x00070028
> -#define CRYPTO4XX_PRNG_RES_3 0x0007002C
> -
> -#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
> -#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
> -
> /*
> * Initialize CRYPTO ENGINE registers, and memory bases.
> */
> #define PPC4XX_PDR_POLL 0x3ff
> #define PPC4XX_OUTPUT_THRESHOLD 2
^ permalink raw reply
* Re: [PATCH 1/2] crypto: Delete Qualcomm crypto engine driver
From: Krzysztof Kozlowski @ 2026-05-30 10:48 UTC (permalink / raw)
To: Eric Biggers
Cc: Demi Marie Obenour, Dmitry Baryshkov, Herbert Xu, David S. Miller,
Thara Gopinath, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Russell King, linux-kernel,
linux-crypto, linux-arm-msm, Ard Biesheuvel, devicetree,
linux-arm-kernel
In-Reply-To: <20260524204537.GB110177@quark>
On Sun, May 24, 2026 at 03:45:37PM -0500, Eric Biggers wrote:
> On Sun, May 24, 2026 at 10:29:28PM +0200, Krzysztof Kozlowski wrote:
> > On 24/05/2026 22:12, Demi Marie Obenour wrote:
> > > On 5/24/26 12:42, Dmitry Baryshkov wrote:
> > >> On Sat, May 23, 2026 at 03:03:56PM -0400, Demi Marie Obenour via B4 Relay wrote:
> > >>> From: Demi Marie Obenour <demiobenour@gmail.com>
> > >>>
> > >>> It's slower than the generic C code and causes problems.
> > >>
> > >> Which problems?
> > >
> > > See https://lore.kernel.org/all/20260522024912.GC5937@quark/.
> >
> > Your commit is still incomplete and other people's opinion is poor
> > reason. If you do not know what to write, ask that person to make
> > necessary changes.
> >
> > Not mentioning that removing driver is not even necessary to achieve the
> > goal Eric was mentioning and if I understood correctly: you are removing
> > even the pieces Eric found useful.
>
> This driver is more than an order of magnitude slower than the CPU for
> both encryption and hashing. See:
>
> https://lore.kernel.org/r/20250704070322.20692-1-ebiggers@kernel.org/
> https://lore.kernel.org/r/20250615031807.GA81869@sol/
>
> There are many examples of it having bugs as well, for example see the
> second link above.
>
> That's why it had to be disabled via the cra_priority system. This
> driver was actively making Linux worse.
>
> This isn't particularly unique to drivers/crypto/, of course. This one
> we just have data on, so it's a bit clearer.
>
> I've yet to see any real reason to keep this driver.
>
> Crypto drivers need to be held to a higher standard than other device
> drivers, as well. The onus is on those who want to keep a particular
> crypto driver to prove that it's worth keeping.
Commit doing the work should have all these explanations, including
numbers. External references are not a proper justification for commits.
Make your case, describe the findings including impact (or lack of
impact) on ongoing hw wrapped keys work and inlined encryption for other
devices (ICE).
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 4/5] dt-bindings: dma: qcom,bam-dma: Increase iommus maxItems to seven
From: Krzysztof Kozlowski @ 2026-05-30 10:39 UTC (permalink / raw)
To: Kuldeep Singh
Cc: Herbert Xu, David S. Miller, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Vinod Koul, Thara Gopinath,
Konrad Dybcio, Frank Li, Andy Gross, Harshal Dev, linux-arm-msm,
linux-crypto, devicetree, linux-kernel, dmaengine
In-Reply-To: <20260521-shikra_crypto_changse-v1-4-0154cc9cc0de@oss.qualcomm.com>
On Thu, May 21, 2026 at 06:47:11PM +0530, Kuldeep Singh wrote:
> Shikra bam dma engine support 7 iommu entries and not 6.
> Increase maxItems property for iommus to pass dtbs_check errors.
What errors? There is no Shikra in upstream so how could we have errors?
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 1/5] dt-bindings: crypto: qcom,inline-crypto-engine: Document Shikra ICE
From: Krzysztof Kozlowski @ 2026-05-30 10:38 UTC (permalink / raw)
To: Kuldeep Singh
Cc: Herbert Xu, David S. Miller, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Vinod Koul, Thara Gopinath,
Konrad Dybcio, Frank Li, Andy Gross, Harshal Dev, linux-arm-msm,
linux-crypto, devicetree, linux-kernel, dmaengine
In-Reply-To: <20260521-shikra_crypto_changse-v1-1-0154cc9cc0de@oss.qualcomm.com>
On Thu, May 21, 2026 at 06:47:08PM +0530, Kuldeep Singh wrote:
> Document the Inline Crypto Engine (ICE) on the Qualcomm Shikra platform.
>
> Signed-off-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
> ---
> Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml | 1 +
> 1 file changed, 1 insertion(+)
Missing constraints for clocks.
That's also v3, not v1.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 2/2] dt-bindings: crypto: qcom,inline-crypto-engine: Document Hawi ICE
From: Krzysztof Kozlowski @ 2026-05-30 10:37 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Herbert Xu, David S. Miller, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Bjorn Andersson, linux-arm-msm,
linux-crypto, devicetree, linux-kernel, Manivannan Sadhasivam
In-Reply-To: <20260521-hawi-crypto-v1-2-9176a3b51bc0@kernel.org>
On Thu, May 21, 2026 at 12:36:21PM +0000, Manivannan Sadhasivam wrote:
> From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
>
> The Inline Crypto Engine found in Hawi SoC is compatible with the common
> baseline IP 'qcom,inline-crypto-engine'. Hence, document the compatible as
> such.
>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> ---
> Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml | 1 +
> 1 file changed, 1 insertion(+)
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: crypto: qcom,prng: Document Hawi TRNG
From: Krzysztof Kozlowski @ 2026-05-30 10:37 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Herbert Xu, David S. Miller, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Bjorn Andersson, linux-arm-msm,
linux-crypto, devicetree, linux-kernel, Manivannan Sadhasivam
In-Reply-To: <20260521-hawi-crypto-v1-1-9176a3b51bc0@kernel.org>
On Thu, May 21, 2026 at 12:36:20PM +0000, Manivannan Sadhasivam wrote:
> From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
>
> Hawi SoC has the True Random Number Generator (TRNG) which is compatible
> with the baseline IP "qcom,trng". Hence, document the compatible as such.
>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> ---
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Christian Lamparter @ 2026-05-30 10:20 UTC (permalink / raw)
To: Eric Biggers, linux-crypto, Herbert Xu; +Cc: linuxppc-dev, linux-kernel, stable
In-Reply-To: <20260529220430.34135-1-ebiggers@kernel.org>
Hi!
On 5/30/26 12:04 AM, 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.
Yes, that "ANSI X9.17 Annex C" comes from the datasheet for the PRNG.
> Another issue was that this driver didn't implement the crypto_rng API
> correctly, as crypto4xx_prng_generate() didn't return 0 on success.
Oh! Hmm, I think I copied that "return amount;" from another driver that
had it implemented? But I'm not sure, this was sooo long ago. That said,
if this never worked...
> - No user of this code is known. It's usable only theoretically via the
> "rng" algorithm type of AF_ALG. But userspace actually just uses the
> actual Linux RNG (/dev/random etc) instead. And rng_algs don't
> contribute entropy to the actual Linux RNG either. (This may have
> been confused with hwrng, which does contribute entropy.)
... and it's completely redundant: Sure!
just in case, this counts for anything, but as the person that added it in the
first place:
Acked-by: Christian Lamparter <chunkeey@gmail.com>
> Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support")
> Cc: stable@vger.kernel.org
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> ---
> drivers/crypto/Kconfig | 1 -
> drivers/crypto/amcc/crypto4xx_core.c | 88 -------------------------
> drivers/crypto/amcc/crypto4xx_core.h | 4 --
> drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ----
> 4 files changed, 104 deletions(-)
>
> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> index 3449b3c9c6ad..5dab813a9f74 100644
> --- a/drivers/crypto/Kconfig
> +++ b/drivers/crypto/Kconfig
> @@ -299,11 +299,10 @@ config CRYPTO_DEV_PPC4XX
> select CRYPTO_AES
> select CRYPTO_LIB_AES
> select CRYPTO_CCM
> select CRYPTO_CTR
> select CRYPTO_GCM
> - select CRYPTO_RNG
> select CRYPTO_SKCIPHER
> help
> This option allows you to have support for AMCC crypto acceleration.
>
> config HW_RANDOM_PPC4XX
> diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
> index b7b6c97d2147..68c5ff7a85b4 100644
> --- a/drivers/crypto/amcc/crypto4xx_core.c
> +++ b/drivers/crypto/amcc/crypto4xx_core.c
> @@ -29,15 +29,13 @@
> #include <crypto/aead.h>
> #include <crypto/aes.h>
> #include <crypto/ctr.h>
> #include <crypto/gcm.h>
> #include <crypto/sha1.h>
> -#include <crypto/rng.h>
> #include <crypto/scatterwalk.h>
> #include <crypto/skcipher.h>
> #include <crypto/internal/aead.h>
> -#include <crypto/internal/rng.h>
> #include <crypto/internal/skcipher.h>
> #include "crypto4xx_reg_def.h"
> #include "crypto4xx_core.h"
> #include "crypto4xx_sa.h"
> #include "crypto4xx_trng.h"
> @@ -983,14 +981,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
> switch (alg->alg.type) {
> case CRYPTO_ALG_TYPE_AEAD:
> rc = crypto_register_aead(&alg->alg.u.aead);
> break;
>
> - case CRYPTO_ALG_TYPE_RNG:
> - rc = crypto_register_rng(&alg->alg.u.rng);
> - break;
> -
> default:
> rc = crypto_register_skcipher(&alg->alg.u.cipher);
> break;
> }
>
> @@ -1012,14 +1006,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
> switch (alg->alg.type) {
> case CRYPTO_ALG_TYPE_AEAD:
> crypto_unregister_aead(&alg->alg.u.aead);
> break;
>
> - case CRYPTO_ALG_TYPE_RNG:
> - crypto_unregister_rng(&alg->alg.u.rng);
> - break;
> -
> default:
> crypto_unregister_skcipher(&alg->alg.u.cipher);
> }
> kfree(alg);
> }
> @@ -1074,73 +1064,10 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
> {
> return crypto4xx_interrupt_handler(irq, data, PPC4XX_INTERRUPT_CLR |
> PPC4XX_TMO_ERR_INT);
> }
>
> -static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
> - u8 *data, unsigned int max)
> -{
> - unsigned int i, curr = 0;
> - u32 val[2];
> -
> - do {
> - /* trigger PRN generation */
> - writel(PPC4XX_PRNG_CTRL_AUTO_EN,
> - dev->ce_base + CRYPTO4XX_PRNG_CTRL);
> -
> - for (i = 0; i < 1024; i++) {
> - /* usually 19 iterations are enough */
> - if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
> - CRYPTO4XX_PRNG_STAT_BUSY))
> - continue;
> -
> - val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
> - val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
> - break;
> - }
> - if (i == 1024)
> - return -ETIMEDOUT;
> -
> - if ((max - curr) >= 8) {
> - memcpy(data, &val, 8);
> - data += 8;
> - curr += 8;
> - } else {
> - /* copy only remaining bytes */
> - memcpy(data, &val, max - curr);
> - break;
> - }
> - } while (curr < max);
> -
> - return curr;
> -}
> -
> -static int crypto4xx_prng_generate(struct crypto_rng *tfm,
> - const u8 *src, unsigned int slen,
> - u8 *dstn, unsigned int dlen)
> -{
> - struct rng_alg *alg = crypto_rng_alg(tfm);
> - struct crypto4xx_alg *amcc_alg;
> - struct crypto4xx_device *dev;
> - int ret;
> -
> - amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
> - dev = amcc_alg->dev;
> -
> - mutex_lock(&dev->core_dev->rng_lock);
> - ret = ppc4xx_prng_data_read(dev, dstn, dlen);
> - mutex_unlock(&dev->core_dev->rng_lock);
> - return ret;
> -}
> -
> -
> -static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
> - unsigned int slen)
> -{
> - return 0;
> -}
> -
> /*
> * Supported Crypto Algorithms
> */
> static struct crypto4xx_alg_common crypto4xx_alg[] = {
> /* Crypto AES modes */
> @@ -1266,22 +1193,10 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
> .cra_blocksize = 1,
> .cra_ctxsize = sizeof(struct crypto4xx_ctx),
> .cra_module = THIS_MODULE,
> },
> } },
> - { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
> - .base = {
> - .cra_name = "stdrng",
> - .cra_driver_name = "crypto4xx_rng",
> - .cra_priority = 300,
> - .cra_ctxsize = 0,
> - .cra_module = THIS_MODULE,
> - },
> - .generate = crypto4xx_prng_generate,
> - .seed = crypto4xx_prng_seed,
> - .seedsize = 0,
> - } },
> };
>
> /*
> * Module Initialization Routine
> */
> @@ -1351,13 +1266,10 @@ static int crypto4xx_probe(struct platform_device *ofdev)
> }
>
> core_dev->dev->core_dev = core_dev;
> core_dev->dev->is_revb = is_revb;
> core_dev->device = dev;
> - rc = devm_mutex_init(&ofdev->dev, &core_dev->rng_lock);
> - if (rc)
> - return rc;
> spin_lock_init(&core_dev->lock);
> INIT_LIST_HEAD(&core_dev->dev->alg_list);
> ratelimit_default_init(&core_dev->dev->aead_ratelimit);
> rc = crypto4xx_build_sdr(core_dev->dev);
> if (rc)
> diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
> index ee36630c670f..3a028aec3f0c 100644
> --- a/drivers/crypto/amcc/crypto4xx_core.h
> +++ b/drivers/crypto/amcc/crypto4xx_core.h
> @@ -12,14 +12,12 @@
>
> #ifndef __CRYPTO4XX_CORE_H__
> #define __CRYPTO4XX_CORE_H__
>
> #include <linux/ratelimit.h>
> -#include <linux/mutex.h>
> #include <linux/scatterlist.h>
> #include <crypto/internal/aead.h>
> -#include <crypto/internal/rng.h>
> #include <crypto/internal/skcipher.h>
> #include "crypto4xx_reg_def.h"
> #include "crypto4xx_sa.h"
>
> #define PPC460SX_SDR0_SRST 0x201
> @@ -109,11 +107,10 @@ struct crypto4xx_core_device {
> struct hwrng *trng;
> u32 int_status;
> u32 irq;
> struct tasklet_struct tasklet;
> spinlock_t lock;
> - struct mutex rng_lock;
> };
>
> struct crypto4xx_ctx {
> struct crypto4xx_device *dev;
> struct dynamic_sa_ctl *sa_in;
> @@ -133,11 +130,10 @@ struct crypto4xx_aead_reqctx {
> struct crypto4xx_alg_common {
> u32 type;
> union {
> struct skcipher_alg cipher;
> struct aead_alg aead;
> - struct rng_alg rng;
> } u;
> };
>
> struct crypto4xx_alg {
> struct list_head entry;
> diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
> index 1038061224da..73d626308a84 100644
> --- a/drivers/crypto/amcc/crypto4xx_reg_def.h
> +++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
> @@ -88,24 +88,13 @@
>
> #define CRYPTO4XX_DMA_CFG 0x000600d4
> #define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
> #define CRYPTO4XX_ENDIAN_CFG 0x000600d8
>
> -#define CRYPTO4XX_PRNG_STAT 0x00070000
> -#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
> #define CRYPTO4XX_PRNG_CTRL 0x00070004
> #define CRYPTO4XX_PRNG_SEED_L 0x00070008
> #define CRYPTO4XX_PRNG_SEED_H 0x0007000c
> -
> -#define CRYPTO4XX_PRNG_RES_0 0x00070020
> -#define CRYPTO4XX_PRNG_RES_1 0x00070024
> -#define CRYPTO4XX_PRNG_RES_2 0x00070028
> -#define CRYPTO4XX_PRNG_RES_3 0x0007002C
> -
> -#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
> -#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
> -
Hmm, don't think these defines will hurt anyone? As these are part of the hardware spec.
Or do you forsee a future where AI-Agents will sent patches hallucinating that it "fixed"
the issue which readds it? I have no idea.
> /*
> * Initialize CRYPTO ENGINE registers, and memory bases.
> */
> #define PPC4XX_PDR_POLL 0x3ff
> #define PPC4XX_OUTPUT_THRESHOLD 2
Cheers,
Christian
^ permalink raw reply
* [PATCH 4/4] hwrng: qcom - Move qcom-rng.c into drivers/char/hw_random/
From: Eric Biggers @ 2026-05-30 2:03 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers
In-Reply-To: <20260530020332.143058-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>
---
arch/arm/configs/multi_v7_defconfig | 2 +-
arch/arm/configs/qcom_defconfig | 2 +-
arch/arm64/configs/defconfig | 2 +-
drivers/char/hw_random/Kconfig | 11 +++++++++++
drivers/char/hw_random/Makefile | 1 +
drivers/{crypto => char/hw_random}/qcom-rng.c | 0
drivers/crypto/Kconfig | 11 -----------
drivers/crypto/Makefile | 1 -
drivers/gpu/drm/ci/arm64.config | 2 +-
9 files changed, 16 insertions(+), 16 deletions(-)
rename drivers/{crypto => char/hw_random}/qcom-rng.c (100%)
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index bcc9aabc1202..a3c612a9d423 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -404,10 +404,11 @@ CONFIG_SERIAL_DEV_BUS=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_ASPEED_KCS_IPMI_BMC=m
CONFIG_ASPEED_BT_IPMI_BMC=m
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_ST=y
+CONFIG_HW_RANDOM_QCOM=m
CONFIG_TCG_TPM=m
CONFIG_TCG_TIS_I2C_INFINEON=m
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_ARB_GPIO_CHALLENGE=m
CONFIG_I2C_MUX_GPIO=y
@@ -1334,11 +1335,10 @@ 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
CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCOM_RNG=m
CONFIG_CRYPTO_DEV_ROCKCHIP=m
CONFIG_CRYPTO_DEV_STM32_HASH=m
CONFIG_CRYPTO_DEV_STM32_CRYP=m
CONFIG_CMA_SIZE_MBYTES=64
CONFIG_PRINTK_TIME=y
diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index 29a1dea500f0..d57554971c03 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -115,10 +115,11 @@ CONFIG_SERIO_LIBPS2=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_DEV_BUS=y
CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_QCOM=m
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
@@ -309,11 +310,10 @@ CONFIG_CRYPTO_USER=m
CONFIG_CRYPTO_USER_API=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_DEV_QCOM_RNG=m
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=64
CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index d905a0777f93..bb930cce7233 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_QCOM=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
@@ -1951,11 +1952,10 @@ CONFIG_CRYPTO_AES_ARM64_BS=m
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_QCOM_RNG=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
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 492a2a61a65b..7102e03dcf0a 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -613,10 +613,21 @@ config HW_RANDOM_ROCKCHIP
To compile this driver as a module, choose M here: the
module will be called rockchip-rng.
If unsure, say Y.
+config HW_RANDOM_QCOM
+ tristate "Qualcomm True Random Number Generator Driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on HW_RANDOM
+ help
+ This driver provides support for the True Random Number
+ 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.
+
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 b9132b3f5d21..605ba8df5a8f 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -50,5 +50,6 @@ obj-$(CONFIG_HW_RANDOM_XIPHERA) += xiphera-trng.o
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
diff --git a/drivers/crypto/qcom-rng.c b/drivers/char/hw_random/qcom-rng.c
similarity index 100%
rename from drivers/crypto/qcom-rng.c
rename to drivers/char/hw_random/qcom-rng.c
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index a12cd677467b..07f0fa3341fc 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -654,21 +654,10 @@ config CRYPTO_DEV_QCE_SW_MAX_LEN
Note that 192-bit keys are not supported by the hardware and are
always processed by the software fallback, and all DES requests
are done by the hardware.
-config CRYPTO_DEV_QCOM_RNG
- tristate "Qualcomm Random Number Generator Driver"
- depends on ARCH_QCOM || COMPILE_TEST
- depends on HW_RANDOM
- help
- This driver provides support for the Random Number
- Generator hardware found on Qualcomm SoCs.
-
- To compile this driver as a module, choose M here. The
- module will be called qcom-rng. If unsure, say N.
-
config CRYPTO_DEV_IMGTEC_HASH
tristate "Imagination Technologies hardware hash accelerator"
depends on MIPS || COMPILE_TEST
select CRYPTO_MD5
select CRYPTO_SHA1
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 283bbc650b5b..a5f3d388f4d0 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -26,11 +26,10 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_DES) += omap-des.o
obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/
-obj-$(CONFIG_CRYPTO_DEV_QCOM_RNG) += qcom-rng.o
obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
obj-$(CONFIG_CRYPTO_DEV_SA2UL) += sa2ul.o
obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
obj-$(CONFIG_CRYPTO_DEV_SL3516) += gemini/
diff --git a/drivers/gpu/drm/ci/arm64.config b/drivers/gpu/drm/ci/arm64.config
index 563a69669a7b..c46125c1f80f 100644
--- a/drivers/gpu/drm/ci/arm64.config
+++ b/drivers/gpu/drm/ci/arm64.config
@@ -76,11 +76,10 @@ CONFIG_INTERCONNECT_QCOM_SDM845=y
CONFIG_INTERCONNECT_QCOM_MSM8916=y
CONFIG_INTERCONNECT_QCOM_MSM8996=y
CONFIG_INTERCONNECT_QCOM_OSM_L3=y
CONFIG_INTERCONNECT_QCOM_SC7180=y
CONFIG_INTERCONNECT_QCOM_SM8350=y
-CONFIG_CRYPTO_DEV_QCOM_RNG=y
CONFIG_SC_DISPCC_7180=y
CONFIG_SC_GPUCC_7180=y
CONFIG_SM_GPUCC_8350=y
CONFIG_QCOM_SPMI_ADC5=y
CONFIG_QCOM_SPMI_VADC=y
@@ -187,10 +186,11 @@ CONFIG_PWM_MEDIATEK=y
CONFIG_DRM_MEDIATEK_HDMI=y
CONFIG_GNSS=y
CONFIG_GNSS_MTK_SERIAL=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MTK=y
+CONFIG_HW_RANDOM_QCOM=y
CONFIG_MTK_DEVAPC=y
CONFIG_PWM_MTK_DISP=y
CONFIG_MTK_CMDQ=y
CONFIG_REGULATOR_DA9211=y
CONFIG_DRM_ANALOGIX_ANX7625=y
--
2.54.0
^ permalink raw reply related
* [PATCH 3/4] crypto: qcom-rng - Remove crypto_rng interface
From: Eric Biggers @ 2026-05-30 2:03 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers, stable
In-Reply-To: <20260530020332.143058-1-ebiggers@kernel.org>
qcom-rng.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, qcom_rng_generate() synchronizes with itself but not with
qcom_hwrng_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.
Note that while this means the driver stops supporting "qcom,prng" and
"qcom,prng-ee", it didn't do anything useful on SoCs with those anyway.
Fixes: f29cd5bb64c2 ("crypto: qcom-rng - Add hw_random interface support")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
drivers/crypto/Kconfig | 1 -
drivers/crypto/qcom-rng.c | 175 ++------------------------------------
2 files changed, 9 insertions(+), 167 deletions(-)
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 3449b3c9c6ad..a12cd677467b 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -658,11 +658,10 @@ config CRYPTO_DEV_QCE_SW_MAX_LEN
config CRYPTO_DEV_QCOM_RNG
tristate "Qualcomm Random Number Generator Driver"
depends on ARCH_QCOM || COMPILE_TEST
depends on HW_RANDOM
- select CRYPTO_RNG
help
This driver provides support for the Random Number
Generator hardware found on Qualcomm SoCs.
To compile this driver as a module, choose M here. The
diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c
index b7f3b9695dac..48b605687b28 100644
--- a/drivers/crypto/qcom-rng.c
+++ b/drivers/crypto/qcom-rng.c
@@ -1,14 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-18 Linaro Limited
//
// Based on msm-rng.c and downstream driver
-#include <crypto/internal/rng.h>
-#include <linux/acpi.h>
#include <linux/clk.h>
-#include <linux/crypto.h>
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -30,28 +27,15 @@
#define WORD_SZ 4
#define QCOM_TRNG_QUALITY 1024
struct qcom_rng {
- struct mutex lock;
void __iomem *base;
struct clk *clk;
struct hwrng hwrng;
- struct qcom_rng_match_data *match_data;
};
-struct qcom_rng_ctx {
- struct qcom_rng *rng;
-};
-
-struct qcom_rng_match_data {
- bool skip_init;
- bool hwrng_support;
-};
-
-static struct qcom_rng *qcom_rng_dev;
-
static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max)
{
unsigned int currsize = 0;
u32 val;
int ret;
@@ -77,41 +61,10 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max)
} while (currsize < max);
return currsize;
}
-static int qcom_rng_generate(struct crypto_rng *tfm,
- const u8 *src, unsigned int slen,
- u8 *dstn, unsigned int dlen)
-{
- struct qcom_rng_ctx *ctx = crypto_rng_ctx(tfm);
- struct qcom_rng *rng = ctx->rng;
- int ret;
-
- ret = clk_prepare_enable(rng->clk);
- if (ret)
- return ret;
-
- mutex_lock(&rng->lock);
-
- ret = qcom_rng_read(rng, dstn, dlen);
-
- mutex_unlock(&rng->lock);
- clk_disable_unprepare(rng->clk);
-
- if (ret >= 0)
- ret = 0;
-
- return ret;
-}
-
-static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed,
- unsigned int slen)
-{
- return 0;
-}
-
static int qcom_hwrng_init(struct hwrng *hwrng)
{
struct qcom_rng *qrng = container_of(hwrng, struct qcom_rng, hwrng);
return clk_prepare_enable(qrng->clk);
@@ -129,159 +82,49 @@ static void qcom_hwrng_cleanup(struct hwrng *hwrng)
struct qcom_rng *qrng = container_of(hwrng, struct qcom_rng, hwrng);
clk_disable_unprepare(qrng->clk);
}
-static int qcom_rng_enable(struct qcom_rng *rng)
-{
- u32 val;
- int ret;
-
- ret = clk_prepare_enable(rng->clk);
- if (ret)
- return ret;
-
- /* Enable PRNG only if it is not already enabled */
- val = readl_relaxed(rng->base + PRNG_CONFIG);
- if (val & PRNG_CONFIG_HW_ENABLE)
- goto already_enabled;
-
- val = readl_relaxed(rng->base + PRNG_LFSR_CFG);
- val &= ~PRNG_LFSR_CFG_MASK;
- val |= PRNG_LFSR_CFG_CLOCKS;
- writel(val, rng->base + PRNG_LFSR_CFG);
-
- val = readl_relaxed(rng->base + PRNG_CONFIG);
- val |= PRNG_CONFIG_HW_ENABLE;
- writel(val, rng->base + PRNG_CONFIG);
-
-already_enabled:
- clk_disable_unprepare(rng->clk);
-
- return 0;
-}
-
-static int qcom_rng_init(struct crypto_tfm *tfm)
-{
- struct qcom_rng_ctx *ctx = crypto_tfm_ctx(tfm);
-
- ctx->rng = qcom_rng_dev;
-
- if (!ctx->rng->match_data->skip_init)
- return qcom_rng_enable(ctx->rng);
-
- return 0;
-}
-
-static struct rng_alg qcom_rng_alg = {
- .generate = qcom_rng_generate,
- .seed = qcom_rng_seed,
- .seedsize = 0,
- .base = {
- .cra_name = "stdrng",
- .cra_driver_name = "qcom-rng",
- .cra_flags = CRYPTO_ALG_TYPE_RNG,
- .cra_priority = 300,
- .cra_ctxsize = sizeof(struct qcom_rng_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = qcom_rng_init,
- }
-};
-
static int qcom_rng_probe(struct platform_device *pdev)
{
struct qcom_rng *rng;
int ret;
rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
if (!rng)
return -ENOMEM;
- platform_set_drvdata(pdev, rng);
- mutex_init(&rng->lock);
-
rng->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(rng->base))
return PTR_ERR(rng->base);
rng->clk = devm_clk_get_optional(&pdev->dev, "core");
if (IS_ERR(rng->clk))
return PTR_ERR(rng->clk);
- rng->match_data = (struct qcom_rng_match_data *)device_get_match_data(&pdev->dev);
-
- qcom_rng_dev = rng;
- ret = crypto_register_rng(&qcom_rng_alg);
- if (ret) {
- dev_err(&pdev->dev, "Register crypto rng failed: %d\n", ret);
- qcom_rng_dev = NULL;
- return ret;
- }
-
- if (rng->match_data->hwrng_support) {
- rng->hwrng.name = "qcom_hwrng";
- rng->hwrng.init = qcom_hwrng_init;
- rng->hwrng.read = qcom_hwrng_read;
- rng->hwrng.cleanup = qcom_hwrng_cleanup;
- rng->hwrng.quality = QCOM_TRNG_QUALITY;
- ret = devm_hwrng_register(&pdev->dev, &rng->hwrng);
- if (ret) {
- dev_err(&pdev->dev, "Register hwrng failed: %d\n", ret);
- qcom_rng_dev = NULL;
- goto fail;
- }
- }
-
- return ret;
-fail:
- crypto_unregister_rng(&qcom_rng_alg);
+ rng->hwrng.name = "qcom_hwrng";
+ rng->hwrng.init = qcom_hwrng_init;
+ rng->hwrng.read = qcom_hwrng_read;
+ rng->hwrng.cleanup = qcom_hwrng_cleanup;
+ rng->hwrng.quality = QCOM_TRNG_QUALITY;
+ ret = devm_hwrng_register(&pdev->dev, &rng->hwrng);
+ if (ret)
+ dev_err(&pdev->dev, "Register hwrng failed: %d\n", ret);
return ret;
}
-static void qcom_rng_remove(struct platform_device *pdev)
-{
- crypto_unregister_rng(&qcom_rng_alg);
-
- qcom_rng_dev = NULL;
-}
-
-static struct qcom_rng_match_data qcom_prng_match_data = {
- .skip_init = false,
- .hwrng_support = false,
-};
-
-static struct qcom_rng_match_data qcom_prng_ee_match_data = {
- .skip_init = true,
- .hwrng_support = false,
-};
-
-static struct qcom_rng_match_data qcom_trng_match_data = {
- .skip_init = true,
- .hwrng_support = true,
-};
-
-static const struct acpi_device_id __maybe_unused qcom_rng_acpi_match[] = {
- { .id = "QCOM8160", .driver_data = (kernel_ulong_t)&qcom_prng_ee_match_data },
- {}
-};
-MODULE_DEVICE_TABLE(acpi, qcom_rng_acpi_match);
-
static const struct of_device_id __maybe_unused qcom_rng_of_match[] = {
- { .compatible = "qcom,prng", .data = &qcom_prng_match_data },
- { .compatible = "qcom,prng-ee", .data = &qcom_prng_ee_match_data },
- { .compatible = "qcom,trng", .data = &qcom_trng_match_data },
+ { .compatible = "qcom,trng" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_rng_of_match);
static struct platform_driver qcom_rng_driver = {
.probe = qcom_rng_probe,
- .remove = qcom_rng_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = qcom_rng_of_match,
- .acpi_match_table = ACPI_PTR(qcom_rng_acpi_match),
}
};
module_platform_driver(qcom_rng_driver);
MODULE_ALIAS("platform:" KBUILD_MODNAME);
--
2.54.0
^ permalink raw reply related
* [PATCH 2/4] crypto: qcom-rng - Allow zero as a random number
From: Eric Biggers @ 2026-05-30 2:03 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers, stable
In-Reply-To: <20260530020332.143058-1-ebiggers@kernel.org>
Zero is a valid random number and needs to be allowed. Otherwise the
output is distinguishable from random.
Fixes: f29cd5bb64c2 ("crypto: qcom-rng - Add hw_random interface support")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
drivers/crypto/qcom-rng.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c
index f31a7fe07ba7..b7f3b9695dac 100644
--- a/drivers/crypto/qcom-rng.c
+++ b/drivers/crypto/qcom-rng.c
@@ -63,13 +63,10 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max)
200, 10000);
if (ret)
return ret;
val = readl_relaxed(rng->base + PRNG_DATA_OUT);
- if (!val)
- return -EINVAL;
-
if ((max - currsize) >= WORD_SZ) {
memcpy(data, &val, WORD_SZ);
data += WORD_SZ;
currsize += WORD_SZ;
} else {
--
2.54.0
^ permalink raw reply related
* [PATCH 1/4] crypto: qcom-rng - Enable clock in hwrng case
From: Eric Biggers @ 2026-05-30 2:03 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers, stable
In-Reply-To: <20260530020332.143058-1-ebiggers@kernel.org>
Fix qcom-rng.c to enable the clock before accessing the hardware.
Fixes: f29cd5bb64c2 ("crypto: qcom-rng - Add hw_random interface support")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
drivers/crypto/qcom-rng.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c
index 150e5802e351..f31a7fe07ba7 100644
--- a/drivers/crypto/qcom-rng.c
+++ b/drivers/crypto/qcom-rng.c
@@ -111,17 +111,31 @@ static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed,
unsigned int slen)
{
return 0;
}
+static int qcom_hwrng_init(struct hwrng *hwrng)
+{
+ struct qcom_rng *qrng = container_of(hwrng, struct qcom_rng, hwrng);
+
+ return clk_prepare_enable(qrng->clk);
+}
+
static int qcom_hwrng_read(struct hwrng *hwrng, void *data, size_t max, bool wait)
{
struct qcom_rng *qrng = container_of(hwrng, struct qcom_rng, hwrng);
return qcom_rng_read(qrng, data, max);
}
+static void qcom_hwrng_cleanup(struct hwrng *hwrng)
+{
+ struct qcom_rng *qrng = container_of(hwrng, struct qcom_rng, hwrng);
+
+ clk_disable_unprepare(qrng->clk);
+}
+
static int qcom_rng_enable(struct qcom_rng *rng)
{
u32 val;
int ret;
@@ -206,11 +220,13 @@ static int qcom_rng_probe(struct platform_device *pdev)
return ret;
}
if (rng->match_data->hwrng_support) {
rng->hwrng.name = "qcom_hwrng";
+ rng->hwrng.init = qcom_hwrng_init;
rng->hwrng.read = qcom_hwrng_read;
+ rng->hwrng.cleanup = qcom_hwrng_cleanup;
rng->hwrng.quality = QCOM_TRNG_QUALITY;
ret = devm_hwrng_register(&pdev->dev, &rng->hwrng);
if (ret) {
dev_err(&pdev->dev, "Register hwrng failed: %d\n", ret);
qcom_rng_dev = NULL;
--
2.54.0
^ permalink raw reply related
* [PATCH 0/4] qcom-rng fixes and cleanups
From: Eric Biggers @ 2026-05-30 2:03 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers
This series fixes several bugs in qcom-rng, including failure to enable
the clock before accessing the hardware, generating biased random
numbers, and generating duplicate or non-random numbers due to missing
locking. To fix the latter bug, it drops the support for the
duplicative crypto_rng interface, which isn't used in practice, leaving
just hwrng which is the one that actually matters.
This series is targeting cryptodev/master
Eric Biggers (4):
crypto: qcom-rng - Enable clock in hwrng case
crypto: qcom-rng - Allow zero as a random number
crypto: qcom-rng - Remove crypto_rng interface
hwrng: qcom - Move qcom-rng.c into drivers/char/hw_random/
arch/arm/configs/multi_v7_defconfig | 2 +-
arch/arm/configs/qcom_defconfig | 2 +-
arch/arm64/configs/defconfig | 2 +-
drivers/char/hw_random/Kconfig | 11 ++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/qcom-rng.c | 132 +++++++++++++
drivers/crypto/Kconfig | 12 --
drivers/crypto/Makefile | 1 -
drivers/crypto/qcom-rng.c | 276 ----------------------------
drivers/gpu/drm/ci/arm64.config | 2 +-
10 files changed, 148 insertions(+), 293 deletions(-)
create mode 100644 drivers/char/hw_random/qcom-rng.c
delete mode 100644 drivers/crypto/qcom-rng.c
base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
--
2.54.0
^ permalink raw reply
* [PATCH] crypto: loongson - Remove broken and unused loongson-rng
From: Eric Biggers @ 2026-05-29 23:32 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, loongarch, Qunqin Zhao, Huacai Chen, Yinggang Gu,
Lee Jones, Eric Biggers, stable
The loongson-rng rng_alg has several vulnerabilities, including not
providing forward security, and a use-after-free bug due to the use of
wait_for_completion_interruptible().
Meanwhile, the rng_alg framework doesn't really have any purpose in the
first place other than to access the software algorithms crypto/drbg.c
and crypto/jitterentropy.c. Hardware-specific rng_algs have no
in-kernel user, and unlike hwrng there's no feed into the actual Linux
RNG. As such, there's really no point to this code. There are of
course other rng_alg drivers that are similarly unused, but they're
similarly in the process of being phased out, e.g.
https://lore.kernel.org/r/20260529193648.18172-1-ebiggers@kernel.org and
https://lore.kernel.org/r/20260529220430.34135-1-ebiggers@kernel.org
Given that, there's no point in fixing forward these vulnerabilities,
and it makes much more sense to simply roll back the addition of this
driver. If this platform provides TRNG (not PRNG) functionality, it
could make sense to add a hwrng driver, but it would be quite different.
Link: https://lore.kernel.org/linux-crypto/20260525145939.GC2018@quark/
Fixes: 766b2d724c8d ("crypto: loongson - add Loongson RNG driver support")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
MAINTAINERS | 1 -
arch/loongarch/configs/loongson32_defconfig | 1 -
arch/loongarch/configs/loongson64_defconfig | 1 -
drivers/crypto/Kconfig | 1 -
drivers/crypto/Makefile | 1 -
drivers/crypto/loongson/Kconfig | 6 -
drivers/crypto/loongson/Makefile | 1 -
drivers/crypto/loongson/loongson-rng.c | 209 --------------------
8 files changed, 221 deletions(-)
delete mode 100644 drivers/crypto/loongson/Kconfig
delete mode 100644 drivers/crypto/loongson/Makefile
delete mode 100644 drivers/crypto/loongson/loongson-rng.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 882214b0e7db..6c805560c77c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15068,11 +15068,10 @@ F: drivers/pwm/pwm-loongson.c
LOONGSON SECURITY ENGINE DRIVERS
M: Qunqin Zhao <zhaoqunqin@loongson.cn>
L: linux-crypto@vger.kernel.org
S: Maintained
F: drivers/char/tpm/tpm_loongson.c
-F: drivers/crypto/loongson/
F: drivers/mfd/loongson-se.c
F: include/linux/mfd/loongson-se.h
LOONGSON-2 SOC SERIES CLOCK DRIVER
M: Yinbo Zhu <zhuyinbo@loongson.cn>
diff --git a/arch/loongarch/configs/loongson32_defconfig b/arch/loongarch/configs/loongson32_defconfig
index d5ef396dffe3..82897236863f 100644
--- a/arch/loongarch/configs/loongson32_defconfig
+++ b/arch/loongarch/configs/loongson32_defconfig
@@ -1089,11 +1089,10 @@ CONFIG_CRYPTO_LZ4HC=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_DEV_VIRTIO=m
-CONFIG_CRYPTO_DEV_LOONGSON_RNG=m
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_PRINTK_TIME=y
CONFIG_STRIP_ASM_SYMS=y
CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/loongarch/configs/loongson64_defconfig b/arch/loongarch/configs/loongson64_defconfig
index cba4cdff5acd..a94e88bd7ec5 100644
--- a/arch/loongarch/configs/loongson64_defconfig
+++ b/arch/loongarch/configs/loongson64_defconfig
@@ -1122,11 +1122,10 @@ CONFIG_CRYPTO_LZ4HC=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_DEV_VIRTIO=m
-CONFIG_CRYPTO_DEV_LOONGSON_RNG=m
CONFIG_DMA_CMA=y
CONFIG_DMA_NUMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_PRINTK_TIME=y
CONFIG_STRIP_ASM_SYMS=y
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 3449b3c9c6ad..075ec9432789 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -844,11 +844,10 @@ config CRYPTO_DEV_CCREE
Choose this if you wish to use hardware acceleration of
cryptographic operations on the system REE.
If unsure say Y.
source "drivers/crypto/hisilicon/Kconfig"
-source "drivers/crypto/loongson/Kconfig"
source "drivers/crypto/amlogic/Kconfig"
config CRYPTO_DEV_SA2UL
tristate "Support for TI security accelerator"
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 283bbc650b5b..ad773158ae56 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -41,11 +41,10 @@ obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio/
obj-$(CONFIG_CRYPTO_DEV_BCM_SPU) += bcm/
obj-y += inside-secure/
obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
obj-y += xilinx/
obj-y += hisilicon/
-obj-y += loongson/
obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
obj-y += intel/
obj-y += starfive/
obj-y += cavium/
obj-y += ti/
diff --git a/drivers/crypto/loongson/Kconfig b/drivers/crypto/loongson/Kconfig
deleted file mode 100644
index f4e1544ffbb4..000000000000
--- a/drivers/crypto/loongson/Kconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-config CRYPTO_DEV_LOONGSON_RNG
- tristate "Support for Loongson RNG Driver"
- depends on MFD_LOONGSON_SE
- select CRYPTO_RNG
- help
- Support for Loongson RNG Driver.
diff --git a/drivers/crypto/loongson/Makefile b/drivers/crypto/loongson/Makefile
deleted file mode 100644
index 1ce5ec32b553..000000000000
--- a/drivers/crypto/loongson/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o
diff --git a/drivers/crypto/loongson/loongson-rng.c b/drivers/crypto/loongson/loongson-rng.c
deleted file mode 100644
index 3a4940260f9e..000000000000
--- a/drivers/crypto/loongson/loongson-rng.c
+++ /dev/null
@@ -1,209 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (c) 2019 HiSilicon Limited. */
-/* Copyright (c) 2025 Loongson Technology Corporation Limited. */
-
-#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/mfd/loongson-se.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <crypto/internal/rng.h>
-
-#define SE_SEED_SIZE 32
-
-struct loongson_rng_list {
- struct mutex lock;
- struct list_head list;
- int registered;
-};
-
-struct loongson_rng {
- u32 used;
- struct loongson_se_engine *engine;
- struct list_head list;
- struct mutex lock;
-};
-
-struct loongson_rng_ctx {
- struct loongson_rng *rng;
-};
-
-struct loongson_rng_cmd {
- u32 cmd_id;
- union {
- u32 len;
- u32 ret;
- } u;
- u32 seed_off;
- u32 out_off;
- u32 pad[4];
-};
-
-static struct loongson_rng_list rng_devices = {
- .lock = __MUTEX_INITIALIZER(rng_devices.lock),
- .list = LIST_HEAD_INIT(rng_devices.list),
-};
-
-static int loongson_rng_generate(struct crypto_rng *tfm, const u8 *src,
- unsigned int slen, u8 *dstn, unsigned int dlen)
-{
- struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm);
- struct loongson_rng *rng = ctx->rng;
- struct loongson_rng_cmd *cmd = rng->engine->command;
- int err, len;
-
- mutex_lock(&rng->lock);
- cmd->seed_off = 0;
- do {
- len = min(dlen, rng->engine->buffer_size);
- cmd = rng->engine->command;
- cmd->u.len = len;
- err = loongson_se_send_engine_cmd(rng->engine);
- if (err)
- break;
-
- cmd = rng->engine->command_ret;
- if (cmd->u.ret) {
- err = -EIO;
- break;
- }
-
- memcpy(dstn, rng->engine->data_buffer, len);
- dlen -= len;
- dstn += len;
- } while (dlen > 0);
- mutex_unlock(&rng->lock);
-
- return err;
-}
-
-static int loongson_rng_init(struct crypto_tfm *tfm)
-{
- struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
- struct loongson_rng *rng;
- u32 min_used = U32_MAX;
-
- mutex_lock(&rng_devices.lock);
- list_for_each_entry(rng, &rng_devices.list, list) {
- if (rng->used < min_used) {
- ctx->rng = rng;
- min_used = rng->used;
- }
- }
- ctx->rng->used++;
- mutex_unlock(&rng_devices.lock);
-
- return 0;
-}
-
-static void loongson_rng_exit(struct crypto_tfm *tfm)
-{
- struct loongson_rng_ctx *ctx = crypto_tfm_ctx(tfm);
-
- mutex_lock(&rng_devices.lock);
- ctx->rng->used--;
- mutex_unlock(&rng_devices.lock);
-}
-
-static int loongson_rng_seed(struct crypto_rng *tfm, const u8 *seed,
- unsigned int slen)
-{
- struct loongson_rng_ctx *ctx = crypto_rng_ctx(tfm);
- struct loongson_rng *rng = ctx->rng;
- struct loongson_rng_cmd *cmd;
- int err;
-
- if (slen < SE_SEED_SIZE)
- return -EINVAL;
-
- slen = min(slen, rng->engine->buffer_size);
-
- mutex_lock(&rng->lock);
- cmd = rng->engine->command;
- cmd->u.len = slen;
- cmd->seed_off = rng->engine->buffer_off;
- memcpy(rng->engine->data_buffer, seed, slen);
- err = loongson_se_send_engine_cmd(rng->engine);
- if (err)
- goto out;
-
- cmd = rng->engine->command_ret;
- if (cmd->u.ret)
- err = -EIO;
-out:
- mutex_unlock(&rng->lock);
-
- return err;
-}
-
-static struct rng_alg loongson_rng_alg = {
- .generate = loongson_rng_generate,
- .seed = loongson_rng_seed,
- .seedsize = SE_SEED_SIZE,
- .base = {
- .cra_name = "stdrng",
- .cra_driver_name = "loongson_stdrng",
- .cra_priority = 300,
- .cra_ctxsize = sizeof(struct loongson_rng_ctx),
- .cra_module = THIS_MODULE,
- .cra_init = loongson_rng_init,
- .cra_exit = loongson_rng_exit,
- },
-};
-
-static int loongson_rng_probe(struct platform_device *pdev)
-{
- struct loongson_rng_cmd *cmd;
- struct loongson_rng *rng;
- int ret = 0;
-
- rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
- if (!rng)
- return -ENOMEM;
-
- rng->engine = loongson_se_init_engine(pdev->dev.parent, SE_ENGINE_RNG);
- if (!rng->engine)
- return -ENODEV;
- cmd = rng->engine->command;
- cmd->cmd_id = SE_CMD_RNG;
- cmd->out_off = rng->engine->buffer_off;
- mutex_init(&rng->lock);
-
- mutex_lock(&rng_devices.lock);
-
- if (!rng_devices.registered) {
- ret = crypto_register_rng(&loongson_rng_alg);
- if (ret) {
- dev_err(&pdev->dev, "failed to register crypto(%d)\n", ret);
- goto out;
- }
- rng_devices.registered = 1;
- }
-
- list_add_tail(&rng->list, &rng_devices.list);
-out:
- mutex_unlock(&rng_devices.lock);
-
- return ret;
-}
-
-static struct platform_driver loongson_rng_driver = {
- .probe = loongson_rng_probe,
- .driver = {
- .name = "loongson-rng",
- },
-};
-module_platform_driver(loongson_rng_driver);
-
-MODULE_ALIAS("platform:loongson-rng");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Yinggang Gu <guyinggang@loongson.cn>");
-MODULE_AUTHOR("Qunqin Zhao <zhaoqunqin@loongson.cn>");
-MODULE_DESCRIPTION("Loongson Random Number Generator driver");
base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
--
2.54.0
^ permalink raw reply related
* [PATCH] crypto: crypto4xx - Remove insecure and unused rng_alg
From: Eric Biggers @ 2026-05-29 22:04 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: Christian Lamparter, linuxppc-dev, linux-kernel, Eric Biggers,
stable
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.
Another issue was that this driver didn't implement the crypto_rng API
correctly, as crypto4xx_prng_generate() didn't return 0 on success.
- No user of this code is known. It's usable only theoretically via the
"rng" algorithm type of AF_ALG. But userspace actually just uses the
actual Linux RNG (/dev/random etc) instead. And rng_algs don't
contribute entropy to the actual Linux RNG either. (This may have
been confused with hwrng, which does contribute entropy.)
Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
drivers/crypto/Kconfig | 1 -
drivers/crypto/amcc/crypto4xx_core.c | 88 -------------------------
drivers/crypto/amcc/crypto4xx_core.h | 4 --
drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ----
4 files changed, 104 deletions(-)
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 3449b3c9c6ad..5dab813a9f74 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -299,11 +299,10 @@ config CRYPTO_DEV_PPC4XX
select CRYPTO_AES
select CRYPTO_LIB_AES
select CRYPTO_CCM
select CRYPTO_CTR
select CRYPTO_GCM
- select CRYPTO_RNG
select CRYPTO_SKCIPHER
help
This option allows you to have support for AMCC crypto acceleration.
config HW_RANDOM_PPC4XX
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index b7b6c97d2147..68c5ff7a85b4 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -29,15 +29,13 @@
#include <crypto/aead.h>
#include <crypto/aes.h>
#include <crypto/ctr.h>
#include <crypto/gcm.h>
#include <crypto/sha1.h>
-#include <crypto/rng.h>
#include <crypto/scatterwalk.h>
#include <crypto/skcipher.h>
#include <crypto/internal/aead.h>
-#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h>
#include "crypto4xx_reg_def.h"
#include "crypto4xx_core.h"
#include "crypto4xx_sa.h"
#include "crypto4xx_trng.h"
@@ -983,14 +981,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
switch (alg->alg.type) {
case CRYPTO_ALG_TYPE_AEAD:
rc = crypto_register_aead(&alg->alg.u.aead);
break;
- case CRYPTO_ALG_TYPE_RNG:
- rc = crypto_register_rng(&alg->alg.u.rng);
- break;
-
default:
rc = crypto_register_skcipher(&alg->alg.u.cipher);
break;
}
@@ -1012,14 +1006,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
switch (alg->alg.type) {
case CRYPTO_ALG_TYPE_AEAD:
crypto_unregister_aead(&alg->alg.u.aead);
break;
- case CRYPTO_ALG_TYPE_RNG:
- crypto_unregister_rng(&alg->alg.u.rng);
- break;
-
default:
crypto_unregister_skcipher(&alg->alg.u.cipher);
}
kfree(alg);
}
@@ -1074,73 +1064,10 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
{
return crypto4xx_interrupt_handler(irq, data, PPC4XX_INTERRUPT_CLR |
PPC4XX_TMO_ERR_INT);
}
-static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
- u8 *data, unsigned int max)
-{
- unsigned int i, curr = 0;
- u32 val[2];
-
- do {
- /* trigger PRN generation */
- writel(PPC4XX_PRNG_CTRL_AUTO_EN,
- dev->ce_base + CRYPTO4XX_PRNG_CTRL);
-
- for (i = 0; i < 1024; i++) {
- /* usually 19 iterations are enough */
- if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
- CRYPTO4XX_PRNG_STAT_BUSY))
- continue;
-
- val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
- val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
- break;
- }
- if (i == 1024)
- return -ETIMEDOUT;
-
- if ((max - curr) >= 8) {
- memcpy(data, &val, 8);
- data += 8;
- curr += 8;
- } else {
- /* copy only remaining bytes */
- memcpy(data, &val, max - curr);
- break;
- }
- } while (curr < max);
-
- return curr;
-}
-
-static int crypto4xx_prng_generate(struct crypto_rng *tfm,
- const u8 *src, unsigned int slen,
- u8 *dstn, unsigned int dlen)
-{
- struct rng_alg *alg = crypto_rng_alg(tfm);
- struct crypto4xx_alg *amcc_alg;
- struct crypto4xx_device *dev;
- int ret;
-
- amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
- dev = amcc_alg->dev;
-
- mutex_lock(&dev->core_dev->rng_lock);
- ret = ppc4xx_prng_data_read(dev, dstn, dlen);
- mutex_unlock(&dev->core_dev->rng_lock);
- return ret;
-}
-
-
-static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
- unsigned int slen)
-{
- return 0;
-}
-
/*
* Supported Crypto Algorithms
*/
static struct crypto4xx_alg_common crypto4xx_alg[] = {
/* Crypto AES modes */
@@ -1266,22 +1193,10 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
} },
- { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
- .base = {
- .cra_name = "stdrng",
- .cra_driver_name = "crypto4xx_rng",
- .cra_priority = 300,
- .cra_ctxsize = 0,
- .cra_module = THIS_MODULE,
- },
- .generate = crypto4xx_prng_generate,
- .seed = crypto4xx_prng_seed,
- .seedsize = 0,
- } },
};
/*
* Module Initialization Routine
*/
@@ -1351,13 +1266,10 @@ static int crypto4xx_probe(struct platform_device *ofdev)
}
core_dev->dev->core_dev = core_dev;
core_dev->dev->is_revb = is_revb;
core_dev->device = dev;
- rc = devm_mutex_init(&ofdev->dev, &core_dev->rng_lock);
- if (rc)
- return rc;
spin_lock_init(&core_dev->lock);
INIT_LIST_HEAD(&core_dev->dev->alg_list);
ratelimit_default_init(&core_dev->dev->aead_ratelimit);
rc = crypto4xx_build_sdr(core_dev->dev);
if (rc)
diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
index ee36630c670f..3a028aec3f0c 100644
--- a/drivers/crypto/amcc/crypto4xx_core.h
+++ b/drivers/crypto/amcc/crypto4xx_core.h
@@ -12,14 +12,12 @@
#ifndef __CRYPTO4XX_CORE_H__
#define __CRYPTO4XX_CORE_H__
#include <linux/ratelimit.h>
-#include <linux/mutex.h>
#include <linux/scatterlist.h>
#include <crypto/internal/aead.h>
-#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h>
#include "crypto4xx_reg_def.h"
#include "crypto4xx_sa.h"
#define PPC460SX_SDR0_SRST 0x201
@@ -109,11 +107,10 @@ struct crypto4xx_core_device {
struct hwrng *trng;
u32 int_status;
u32 irq;
struct tasklet_struct tasklet;
spinlock_t lock;
- struct mutex rng_lock;
};
struct crypto4xx_ctx {
struct crypto4xx_device *dev;
struct dynamic_sa_ctl *sa_in;
@@ -133,11 +130,10 @@ struct crypto4xx_aead_reqctx {
struct crypto4xx_alg_common {
u32 type;
union {
struct skcipher_alg cipher;
struct aead_alg aead;
- struct rng_alg rng;
} u;
};
struct crypto4xx_alg {
struct list_head entry;
diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
index 1038061224da..73d626308a84 100644
--- a/drivers/crypto/amcc/crypto4xx_reg_def.h
+++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
@@ -88,24 +88,13 @@
#define CRYPTO4XX_DMA_CFG 0x000600d4
#define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
#define CRYPTO4XX_ENDIAN_CFG 0x000600d8
-#define CRYPTO4XX_PRNG_STAT 0x00070000
-#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
#define CRYPTO4XX_PRNG_CTRL 0x00070004
#define CRYPTO4XX_PRNG_SEED_L 0x00070008
#define CRYPTO4XX_PRNG_SEED_H 0x0007000c
-
-#define CRYPTO4XX_PRNG_RES_0 0x00070020
-#define CRYPTO4XX_PRNG_RES_1 0x00070024
-#define CRYPTO4XX_PRNG_RES_2 0x00070028
-#define CRYPTO4XX_PRNG_RES_3 0x0007002C
-
-#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
-#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
-
/*
* Initialize CRYPTO ENGINE registers, and memory bases.
*/
#define PPC4XX_PDR_POLL 0x3ff
#define PPC4XX_OUTPUT_THRESHOLD 2
base-commit: 49e05bb00f2e8168695f7af4d694c39e1423e8a2
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] crypto: sun4i-ss - Remove insecure and unused rng_alg
From: Eric Biggers @ 2026-05-29 20:54 UTC (permalink / raw)
To: sashiko-reviews; +Cc: linux-sunxi, linux-crypto, Corentin Labbe
In-Reply-To: <20260529195725.5C7B91F00898@smtp.kernel.org>
On Fri, May 29, 2026 at 07:57:24PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] The debugfs directory and files created during probe are never removed on driver unbind, module unload, or probe failure, leading to a resource leak and potential Use-After-Free or page fault.
> - [High] The driver modifies a static global array (`ss_algs`) to store per-device context (`ss`), which breaks if multiple instances of the device are probed.
> - [High] Missing check on `sg_miter_next` return value leads to an infinite loop (DoS) inside a `spin_lock_bh` critical section.
Just par for the course for drivers/crypto/.
- Eric
^ permalink raw reply
* Re: [PATCH 0/2] Add hw_random Rust bindings
From: Manos Pitsidianakis @ 2026-05-29 20:35 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu, rust-for-linux, linux-kernel,
linux-crypto, manos.pitsidianakis
In-Reply-To: <CANiq72mU=yQ_L_D6emvTj4c5E_ankLFvpXzkE7yTfcYfLB5T=g@mail.gmail.com>
Hi Miguel,
On Fri, 29 May 2026 23:02, Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> wrote:
>On Fri, May 29, 2026 at 5:50 PM Manos Pitsidianakis
><manos@pitsidianak.is> wrote:
>>
>> A virtio-rng Rust driver that uses them will be submitted as a separate
>> series since it also depends on the virtio abstractions series.
>
>Please include that at least as a reference to a branch or similar,
>since in most cases the user is needed to evaluate abstractions etc.
Good point, thanks.
My WIP branch is here
https://github.com/epilys/linux/tree/b4/rust-virtio-rng (HEAD is the
driver that uses the abstraction in this series)
It uses atomics instead of a spinlock since we can't sleep during virtio
driver probe. I didn't want to overcomplicate it by deferring all the
sleeping work to a workqueue, but maybe it's a necessity until we get
spinlocks that can disable IRQs.
>
>Thanks!
>
>Cheers,
>Miguel
^ permalink raw reply
* Re: [PATCH 0/2] Add hw_random Rust bindings
From: Miguel Ojeda @ 2026-05-29 20:02 UTC (permalink / raw)
To: Manos Pitsidianakis
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu, rust-for-linux, linux-kernel,
linux-crypto, manos.pitsidianakis
In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-0-b3153dd90311@pitsidianak.is>
On Fri, May 29, 2026 at 5:50 PM Manos Pitsidianakis
<manos@pitsidianak.is> wrote:
>
> A virtio-rng Rust driver that uses them will be submitted as a separate
> series since it also depends on the virtio abstractions series.
Please include that at least as a reference to a branch or similar,
since in most cases the user is needed to evaluate abstractions etc.
Thanks!
Cheers,
Miguel
^ permalink raw reply
* Re: [PATCH 2/2] rust: add hw_random module
From: Miguel Ojeda @ 2026-05-29 20:01 UTC (permalink / raw)
To: Manos Pitsidianakis
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu, rust-for-linux, linux-kernel,
linux-crypto, manos.pitsidianakis
In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-2-b3153dd90311@pitsidianak.is>
Hi Manos,
Some quick doc nits I noticed while managing our list...
On Fri, May 29, 2026 at 5:50 PM Manos Pitsidianakis
<manos@pitsidianak.is> wrote:
>
> +//! # Example
"Examples" is the section name we use.
> +//!# fn no_run() {
> +//!# use kernel::hw_random::*;
> +//!# use kernel::str::CString;
> +//!# use kernel::prelude::*;
Missing indentation.
> +//! fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()> {
-> Result
> +//! // write zeroes - in your driver, this should write actual data from your hardware.
"Write"
> +//! let name = CString::try_from(c"example_hwrng").unwrap();
Could you avoid `unwrap()`s, perhaps using `?` etc.? It is not
critical, but good practice to try to show how "real code" would be
written.
> + from_result, //
> + to_result, //
> + VTABLE_DEFAULT_ERROR, //
Please only use the slashes in the last one:
> + },
...but add one here, since this level doesn't have it.
> + /// Returns `true` if the buffer has been filled.
[`true`]
> + // SAFETY: u8 and MaybeUninit<u8> have the same layout
Please use Markdown (but no intra-doc links needed) in comments too, e.g.
`u8` ... `MaybeUninit<u8>`
There are other instances below.
> +/// [`struct hwrng`]: srctree/include/linux/hw_random.h
Is this reference used?
> +#[vtable]
> +/// Trait for the implementation of hardware RNGs.
Attributes after documentation.
Other instances below too.
> + /// [`hwrng_unregister`]: srctree/include/linux/hw_random.h
> + #[inline]
> + #[doc(alias = "hwrng_unregister")]
Is this one for the alias? How does it behave when rendered?
> + pub fn unregister(&self) {
> + if self
> + .registered
> + .compare_exchange(true, false, Ordering::SeqCst, Ordering::Acquire)
> + .is_ok()
We are starting to add `// ORDERING: ...` comments for things like
this, so it would be nice to have them here already.
> + // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
Please start comments capitalized. Other instances elsewhere too.
Cheers,
Miguel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox