* [PATCH v2 3/4] crypto: qcom-rng - Remove crypto_rng interface
From: Eric Biggers @ 2026-06-08 17:58 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers, Neeraj Soni,
Dmitry Baryshkov, Konrad Dybcio, stable
In-Reply-To: <20260608175848.2045229-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.
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 | 158 +++++---------------------------------
2 files changed, 19 insertions(+), 140 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 7058bd98f9e9..4d046caafe5b 100644
--- a/drivers/crypto/qcom-rng.c
+++ b/drivers/crypto/qcom-rng.c
@@ -1,14 +1,12 @@
// 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 +28,19 @@
#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;
@@ -78,41 +67,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);
@@ -130,135 +88,58 @@ 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)
{
+ const struct qcom_rng_match_data *match_data;
struct qcom_rng *rng;
int ret;
+ match_data = device_get_match_data(&pdev->dev);
+ if (match_data == NULL || !match_data->hwrng_support) {
+ dev_info(&pdev->dev, "TRNG support not detected\n");
+ /*
+ * In this case the driver does nothing except the dev_info(),
+ * but bind the device anyway to avoid effects on GCC state.
+ */
+ return 0;
+ }
+
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 },
@@ -274,11 +155,10 @@ static const struct of_device_id __maybe_unused qcom_rng_of_match[] = {
};
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),
}
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related
* [PATCH v2 2/4] crypto: qcom-rng - Allow zero as a random number
From: Eric Biggers @ 2026-06-08 17:58 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers, Neeraj Soni,
Dmitry Baryshkov, Konrad Dybcio, stable
In-Reply-To: <20260608175848.2045229-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
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
drivers/crypto/qcom-rng.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c
index f31a7fe07ba7..7058bd98f9e9 100644
--- a/drivers/crypto/qcom-rng.c
+++ b/drivers/crypto/qcom-rng.c
@@ -63,12 +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;
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply related
* [PATCH v2 1/4] crypto: qcom-rng - Enable clock in hwrng case
From: Eric Biggers @ 2026-06-08 17:58 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers, Neeraj Soni,
Dmitry Baryshkov, Konrad Dybcio, stable
In-Reply-To: <20260608175848.2045229-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
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
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.1064.gd145956f57-goog
^ permalink raw reply related
* [PATCH v2 0/4] qcom-rng fixes and cleanups
From: Eric Biggers @ 2026-06-08 17:58 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, Eric Biggers, Neeraj Soni,
Dmitry Baryshkov, Konrad Dybcio
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
Changed in v2:
- Changed patch 3 to make the driver continue to be bound even when
hwrng is unsupported.
- Added blank line in patch 2
- Added Reviewed-by
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/{crypto => char/hw_random}/qcom-rng.c | 156 +++---------------
drivers/crypto/Kconfig | 12 --
drivers/crypto/Makefile | 1 -
drivers/gpu/drm/ci/arm64.config | 2 +-
9 files changed, 41 insertions(+), 148 deletions(-)
rename drivers/{crypto => char/hw_random}/qcom-rng.c (53%)
base-commit: 79bbe453e5bfa6e1c6aa2e8329bfc8f152b81c9b
--
2.54.0.1064.gd145956f57-goog
^ permalink raw reply
* Re: [PATCH net-next v2 0/5] Consolidate FCrypt and PCBC code into net/rxrpc/
From: Eric Biggers @ 2026-06-08 17:39 UTC (permalink / raw)
To: Marc Dionne
Cc: netdev, linux-afs, David Howells, linux-crypto, linux-kernel,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman
In-Reply-To: <20260603050557.GB18149@sol>
On Tue, Jun 02, 2026 at 10:05:57PM -0700, Eric Biggers wrote:
> On Fri, May 22, 2026 at 10:06:49AM -0300, Marc Dionne wrote:
> > On Fri, May 22, 2026 at 2:07 AM Eric Biggers <ebiggers@kernel.org> wrote:
> > >
> > > The FCrypt "block cipher" and the PCBC mode of operation are obsolete
> > > and insecure. Since their only user is net/rxrpc/, they belong there,
> > > not in the crypto API.
> > >
> > > Therefore, this series removes these algorithms from the crypto API and
> > > replaces them with local implementations in net/rxrpc/.
> > >
> > > The local implementations are simpler too, as they avoid the crypto API
> > > boilerplate.
> > >
> > > I don't know how to test all the code in net/rxrpc/, but everything
> > > should still work. I added a KUnit test for the crypto functions.
> > >
> > > Changed in v2:
> > > - Added missing export of fcrypt_preparekey().
> > > - Write "RxRPC crypto KUnit test" instead of "RxRPC KUnit test".
> > > - Rebased onto latest net-next where decryption now happens in the
> > > linear buffer rxrpc_call::rx_dec_buffer, simplifying the code.
> >
> > Looks good in testing with our kafs test suite, forcing the use of
> > rxkad with encryption.
> >
> > Feel free to add for the series:
> > Tested-by: Marc Dionne <marc.dionne@auristor.com>
>
> Thanks!
>
> If there's no more feedback, could this be applied to net-next?
Any update on this?
- Eric
^ permalink raw reply
* [PATCH v5 1/1] crypto: atmel-ecc - fix multi-device use-after-free and registration races
From: Lothar Rubusch @ 2026-06-08 17:03 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, krzk+dt
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
During parallel driver initialization or driver teardown sequences
in setups with multiple atmel-ecc instances, a race condition exists
between atmel_ecc_i2c_client_alloc() and the probe/remove paths.
A concurrent transformation request can fetch an i2c_client instance
from the global i2c_client_list before the kpp is fully registered, or
while it is actively being unbound, resulting in a use-after-free (UAF)
risk.
1. The initialization problem in probe(): Adding first an i2c client to the
i2c_client_list, and then registering the kpp algorim may result in a race,
when this happens for a second (or further) probed device. In this case the
algorithm is already registered, so a TFM may arrive, while the latest
probing device is added to the list, but not kpp registered. In case this
fails and this last device is going to be removed again from the list, this
leaves a window where the TFM might obtain a pointer to the - now deleted -
i2c client, which opens a UAF risk. Furthermore, there will happen atempts
to multiple registering the same driver to the same type of algorithm.
Note, a simple reverting of the order: first register kpp, second add the
i2c client to the i2c_client_list - is not possible here, since the kpp
registration immediately triggers the self tests, which then will allocate
and require an i2c client.
2. The critical race condition problem: It exists when an Atmel device
instance is rapidly removed and immediately re-probed, before the global
resources are fully cleaned up. In this scenario, the asynchronous
unregistration sequence in the remove() lags behind the incoming probe()
function. Because of the global algorithm structure being not yet
completely cleaned up, the newly re-probed device incorrectly intercepts
the static, partially-dismantled global context. It then overwrites active
pointers and re-acquires the global instance prematurely. In this way, when
the deregistration sequence finally completes its execution, under the
newly initialized device, it may lose the tracking references, leaking the
older driver memory blocks, and introducing an immediate UAF risk.
3. The removal race problem, when a call to remove() starts removing the
device, but another thread executing a TFM, a severe Time-of-Check to
Time-of-Use (TOCTOU) race condition exists in the teardown path between the
asynchronous remove() sequence and completing TFMs. When the device is
unbound, the remove() function evaluates the active tfm_count and decides
whether to wait or proceed with resource deallocation. However, if the
final active TFM finishes its crypto operation and invokes the client free
function immediately after remove() performs its reference check but before
it can sleep, the completion signal is fired into a clearing state. The
unbind thread then misinterprets the zeroed counter, skips the
synchronization barrier entirely, and instantly deallocates the per-device
private structures. This leaves the final TFM worker thread executing code
inside a completely freed memory area, triggering an immediate UAF kernel
panic. Note, simply calling the kpp unregister here won't clean up the
situation in the context of having a setup with external hardware on a slow
bus.
Address this by implementing an independent subsystem reference counter
kpp refcnt protected by a dedicated mutex to ensure the static global kpp
algorithm structure is registered exactly once by the first probing device
instance. In multi-device scenarios, or when extending the resource
management support of the i2c_client_list to all atmel-i2c based device
drivers, such scenarios can become realistic. The particular algorithm is
registered only once. Each i2c client (i.e. each probing device driver) is
added as client to the i2c_client_list. This guarantee that only the first
probe will register the algorithm. The list is populated for further calls
to probe, and subsequent calls to the client alloc function.
Concurrently, decouple list mutations from registration by moving the
global list eviction to the absolute top of the remove lifecycle. This
keeps the quick execution of the list allocation loop intact, ensures that
unbinding hardware is instantly blind to the rest of the system, and
completely bypasses the recursive deadlock condition previously triggered
by synchronous crypto API self-tests.
Fixes: 11105693fa05 ("crypto: atmel-ecc - introduce Microchip / Atmel ECC driver")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
v4 -> v5:
- sashiko warning: revert wait_for_completion_timeout() by
wait_for_completion() when former instance still active at probe()
- change return type of atmel_ecc_wait_for_tfms() to void
v3 -> v4:
- sashiko warning: replace wait_for_completion() by
wait_for_completion_timeout() in remove; decision is a kind of dilemma
- move redundant code of this fix out into a separate function
- make also use of the wait_for_completion_timeout() function at probe for
convenience
v2 -> v3:
- sashiko warning: fix missing init_completion() for remove_done
- add comment naming all three related main problem situations
v1 -> v2:
- remove the initial approach with "ready" state bool, replace it by
this be a more comprehensive approach
drivers/crypto/atmel-ecc.c | 122 ++++++++++++++++++++++++++++---------
drivers/crypto/atmel-i2c.h | 3 +
2 files changed, 97 insertions(+), 28 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 0ca02995a1de..be956508edcc 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -23,6 +23,11 @@
#include <crypto/kpp.h>
#include "atmel-i2c.h"
+static DEFINE_MUTEX(atmel_ecc_kpp_lock);
+static int atmel_ecc_kpp_refcnt;
+DECLARE_COMPLETION(atmel_ecc_unreg_done);
+static bool atmel_ecc_unreg_active;
+
static struct atmel_ecc_driver_data driver_data;
/**
@@ -241,7 +246,10 @@ static void atmel_ecc_i2c_client_free(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
- atomic_dec(&i2c_priv->tfm_count);
+ spin_lock(&driver_data.i2c_list_lock);
+ if (atomic_dec_and_test(&i2c_priv->tfm_count) && i2c_priv->unbinding)
+ complete(&i2c_priv->remove_done);
+ spin_unlock(&driver_data.i2c_list_lock);
}
static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
@@ -276,7 +284,8 @@ static void atmel_ecdh_exit_tfm(struct crypto_kpp *tfm)
struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
kfree(ctx->public_key);
- crypto_free_kpp(ctx->fallback);
+ if (ctx->fallback)
+ crypto_free_kpp(ctx->fallback);
atmel_ecc_i2c_client_free(ctx->client);
}
@@ -295,6 +304,21 @@ static unsigned int atmel_ecdh_max_size(struct crypto_kpp *tfm)
return ATMEL_ECC_PUBKEY_SIZE;
}
+static void atmel_ecc_wait_for_tfms(struct atmel_i2c_client_priv *i2c_priv)
+{
+ spin_lock(&driver_data.i2c_list_lock);
+ list_del(&i2c_priv->i2c_client_list_node);
+ i2c_priv->unbinding = true;
+ reinit_completion(&i2c_priv->remove_done);
+ if (!atomic_read(&i2c_priv->tfm_count)) {
+ spin_unlock(&driver_data.i2c_list_lock);
+ return;
+ }
+ spin_unlock(&driver_data.i2c_list_lock);
+
+ wait_for_completion(&i2c_priv->remove_done);
+}
+
static struct kpp_alg atmel_ecdh_nist_p256 = {
.set_secret = atmel_ecdh_set_secret,
.generate_public_key = atmel_ecdh_generate_public_key,
@@ -315,6 +339,7 @@ static struct kpp_alg atmel_ecdh_nist_p256 = {
static int atmel_ecc_probe(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv;
+ unsigned long timeout;
int ret;
ret = atmel_i2c_probe(client);
@@ -323,49 +348,90 @@ static int atmel_ecc_probe(struct i2c_client *client)
i2c_priv = i2c_get_clientdata(client);
+ init_completion(&i2c_priv->remove_done);
+ i2c_priv->unbinding = false;
+
spin_lock(&driver_data.i2c_list_lock);
list_add_tail(&i2c_priv->i2c_client_list_node,
&driver_data.i2c_client_list);
spin_unlock(&driver_data.i2c_list_lock);
- ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
- if (ret) {
- spin_lock(&driver_data.i2c_list_lock);
- list_del(&i2c_priv->i2c_client_list_node);
- spin_unlock(&driver_data.i2c_list_lock);
-
- dev_err(&client->dev, "%s alg registration failed\n",
- atmel_ecdh_nist_p256.base.cra_driver_name);
- } else {
- dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
+ mutex_lock(&atmel_ecc_kpp_lock);
+ /*
+ * For cases where the same/last such device is still in unregistering,
+ * and now re-registering (refcnt is 0, but completion still exists).
+ * Safely capture the pointer, drop the lock and sleep until it
+ * terminates upon completion or retry limit reached.
+ */
+ while (atmel_ecc_unreg_active) {
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ timeout = wait_for_completion_timeout(&atmel_ecc_unreg_done,
+ msecs_to_jiffies(2000));
+ mutex_lock(&atmel_ecc_kpp_lock);
+ if (timeout == 0) {
+ mutex_unlock(&atmel_ecc_kpp_lock);
+
+ atmel_ecc_wait_for_tfms(i2c_priv);
+ dev_err(&client->dev,
+ "probe timed out, former instance active\n");
+ return -ETIMEDOUT;
+ }
+ }
+ if (atmel_ecc_kpp_refcnt == 0) {
+ ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
+ if (ret) {
+ mutex_unlock(&atmel_ecc_kpp_lock);
+
+ atmel_ecc_wait_for_tfms(i2c_priv);
+ dev_err(&client->dev, "%s alg registration failed\n",
+ atmel_ecdh_nist_p256.base.cra_driver_name);
+ return ret;
+ }
}
+ atmel_ecc_kpp_refcnt++;
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
return ret;
}
static void atmel_ecc_remove(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
-
- /* Return EBUSY if i2c client already allocated. */
- if (atomic_read(&i2c_priv->tfm_count)) {
- /*
- * After we return here, the memory backing the device is freed.
- * That happens no matter what the return value of this function
- * is because in the Linux device model there is no error
- * handling for unbinding a driver.
- * If there is still some action pending, it probably involves
- * accessing the freed memory.
- */
- dev_emerg(&client->dev, "Device is busy, expect memory corruption.\n");
- return;
- }
-
- crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+ bool trigger_unreg = false;
+ bool wait_needed = false;
+ unsigned long timeout;
spin_lock(&driver_data.i2c_list_lock);
list_del(&i2c_priv->i2c_client_list_node);
+ i2c_priv->unbinding = true;
+ reinit_completion(&i2c_priv->remove_done);
+ if (atomic_read(&i2c_priv->tfm_count) > 0)
+ wait_needed = true;
spin_unlock(&driver_data.i2c_list_lock);
+ if (wait_needed) {
+ timeout = wait_for_completion_timeout(&i2c_priv->remove_done,
+ msecs_to_jiffies(5000));
+ if (timeout == 0)
+ dev_emerg(&client->dev, "Teardown timed out! Active TFMs leaked, memory corruption imminent.\n");
+ }
+
+ mutex_lock(&atmel_ecc_kpp_lock);
+ atmel_ecc_kpp_refcnt--;
+ if (atmel_ecc_kpp_refcnt == 0) {
+ trigger_unreg = true;
+ atmel_ecc_unreg_active = true;
+ reinit_completion(&atmel_ecc_unreg_done);
+ }
+ mutex_unlock(&atmel_ecc_kpp_lock);
+
+ if (trigger_unreg) {
+ crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+ mutex_lock(&atmel_ecc_kpp_lock);
+ atmel_ecc_unreg_active = false;
+ complete_all(&atmel_ecc_unreg_done);
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ }
}
static const struct of_device_id atmel_ecc_dt_ids[] = {
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 72f04c15682f..8e6617422191 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -129,6 +129,7 @@ struct atmel_ecc_driver_data {
* @wake_token_sz : size in bytes of the wake_token
* @tfm_count : number of active crypto transformations on i2c client
* @hwrng : hold the hardware generated rng
+ * @unbinding : unbinding handshake
*
* Reads and writes from/to the i2c client are sequential. The first byte
* transmitted to the device is treated as the byte size. Any attempt to send
@@ -145,6 +146,8 @@ struct atmel_i2c_client_priv {
size_t wake_token_sz;
atomic_t tfm_count ____cacheline_aligned;
struct hwrng hwrng;
+ struct completion remove_done;
+ bool unbinding;
};
/**
base-commit: 79bbe453e5bfa6e1c6aa2e8329bfc8f152b81c9b
--
2.53.0
^ permalink raw reply related
* [PATCH] crypto: qat - clear AES key schedule from stack
From: Giovanni Cabiddu @ 2026-06-08 15:04 UTC (permalink / raw)
To: herbert; +Cc: linux-crypto, qat-linux, Giovanni Cabiddu, Ahsan Atta
qat_alg_xts_reverse_key() expands the forward XTS AES key on the stack.
That schedule contains key material and can remain in the stack frame.
Clear the temporary crypto_aes_ctx with memzero_explicit() after the copy.
Fixes: 5106dfeaeabe ("crypto: qat - add AES-XTS support for QAT GEN4 devices")
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Ahsan Atta <ahsan.atta@intel.com>
---
drivers/crypto/intel/qat/qat_common/qat_algs.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/crypto/intel/qat/qat_common/qat_algs.c b/drivers/crypto/intel/qat/qat_common/qat_algs.c
index 7f638a62e3ad..91663805d9e6 100644
--- a/drivers/crypto/intel/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/intel/qat/qat_common/qat_algs.c
@@ -405,6 +405,7 @@ static void qat_alg_xts_reverse_key(const u8 *key_forward, unsigned int keylen,
memcpy(key_reverse + AES_BLOCK_SIZE, key - AES_BLOCK_SIZE,
AES_BLOCK_SIZE);
}
+ memzero_explicit(&aes_expanded, sizeof(aes_expanded));
}
static void qat_alg_skcipher_init_dec(struct qat_alg_skcipher_ctx *ctx,
base-commit: 36d82ddc0f8a88444e8d65646a3c43147005ed35
--
2.54.0
^ permalink raw reply related
* Re: [GIT PULL] Crypto Fixes for 7.1
From: pr-tracker-bot @ 2026-06-08 15:03 UTC (permalink / raw)
To: Herbert Xu
Cc: Linus Torvalds, David S. Miller, Linux Kernel Mailing List,
Linux Crypto Mailing List
In-Reply-To: <aiZWfDt54UazaMJ0@gondor.apana.org.au>
The pull request you sent on Mon, 8 Jun 2026 13:43:24 +0800:
> git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6 tags/v7.1-p5
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/2d3090a8aeb596a26935db0955d46c9a5db5c6ce
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply
* [PATCH] crypto: qat - cancel work on re-enable SR-IOV timeout
From: Giovanni Cabiddu @ 2026-06-08 14:59 UTC (permalink / raw)
To: herbert; +Cc: linux-crypto, qat-linux, Giovanni Cabiddu, Ahsan Atta
The QAT reset worker queues SR-IOV reenable work using a work_struct and
completion embedded in an on-stack adf_sriov_dev_data. If the completion
wait times out, the reset worker can return while device_sriov_wq still
holds or executes the stack-backed work item.
Cancel the work on the device_sriov_wq on timeout before the stack frame
unwinds.
Fixes: 4469f9b23468 ("crypto: qat - re-enable sriov after pf reset")
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Ahsan Atta <ahsan.atta@intel.com>
---
drivers/crypto/intel/qat/qat_common/adf_aer.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c
index d58cd7fbf707..afded3030e9a 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c
@@ -189,6 +189,8 @@ static void adf_device_reset_worker(struct work_struct *work)
queue_work(device_sriov_wq, &sriov_data.sriov_work);
if (wait_for_completion_timeout(&sriov_data.compl, wait_jiffies))
adf_pf2vf_notify_restarted(accel_dev);
+ else
+ cancel_work_sync(&sriov_data.sriov_work);
adf_dev_restarted_notify(accel_dev);
clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
base-commit: 36d82ddc0f8a88444e8d65646a3c43147005ed35
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v2 0/2] Add support for ice sdhc on shikra
From: Kuldeep Singh @ 2026-06-08 10:36 UTC (permalink / raw)
To: Herbert Xu, David S. Miller, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-crypto, devicetree, linux-kernel
In-Reply-To: <20260515-shikra_ice_ufs-v2-0-2724a54339db@oss.qualcomm.com>
On 15-05-2026 16:16, Kuldeep Singh wrote:
> This patchseries attempt to enable ice sdhc on shikra similar to other
> platforms.
>
> Validations:
> - Driver probe on bootup.
>
> Dependency on:
> - https://lore.kernel.org/all/20260512-shikra-dt-v1-0-716438330dd0@oss.qualcomm.com/
> - https://lore.kernel.org/linux-arm-msm/20260416-qcom_ice_power_and_clk_vote-v5-0-5ccf5d7e2846@oss.qualcomm.com/
>
> Signed-off-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
Kind reminder, rng/ice/qcrypto patchsets are sent together sometime back
in single series and please follow here[1] for discussions.
Please consider this series as inactive from merger point of view.
[1]
https://lore.kernel.org/all/20260521-shikra_crypto_changse-v1-0-0154cc9cc0de@oss.qualcomm.com/
--
Regards
Kuldeep
^ permalink raw reply
* Re: [PATCH 0/2] Add support for rng on shikra
From: Kuldeep Singh @ 2026-06-08 10:36 UTC (permalink / raw)
To: Herbert Xu, David S. Miller, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-crypto, devicetree, linux-kernel
In-Reply-To: <20260514-shikra_rng-v1-0-4ea721a1429a@oss.qualcomm.com>
On 14-05-2026 18:46, Kuldeep Singh wrote:
> The patchseries contain dt-binding and DT changes for enabling rng on
> shikra.
>
> This series depends on the following prerequisite patchset:
> - https://lore.kernel.org/all/20260512-shikra-dt-v1-0-716438330dd0@oss.qualcomm.com/
>
> Tested-on: shikra-iqs-evk
>
> Testing:
> - Boot the board and verify qcom_rng driver probe success.
> - Validated rngtest utils
> - validated against dt_binding and dtbs_check.
>
> Steps followed:
> - cat /sys/class/misc/hw_random/rng_available
> - echo qcom_hwrng > /sys/class/misc/hw_random/rng_current
> - cat /sys/class/misc/hw_random/rng_current
> - cat /dev/random | rngtest -c 1000
>
> Signed-off-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
Kind reminder, rng/ice/qcrypto patchsets are sent together sometime back
in single series and please follow here[1] for discussions.
Please consider this series as inactive from merger point of view.
[1]
https://lore.kernel.org/all/20260521-shikra_crypto_changse-v1-0-0154cc9cc0de@oss.qualcomm.com/
--
Regards
Kuldeep
^ permalink raw reply
* Re: [PATCH 0/3] Add support for qcrypto on shikra
From: Kuldeep Singh @ 2026-06-08 10:35 UTC (permalink / raw)
To: Thara Gopinath, Herbert Xu, David S. Miller, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Vinod Koul, Frank Li, Andy Gross
Cc: linux-arm-msm, linux-crypto, devicetree, linux-kernel, dmaengine
In-Reply-To: <20260515-shikra_qcrypto-v1-0-80f07b345c29@oss.qualcomm.com>
On 15-05-2026 00:53, Kuldeep Singh wrote:
> Add qcrypto and cryptobam DT nodes for enabling qcrypto on kaanapali.
> Shikra bam dma supports 7 iommus so update dt-bindings accordingly.
>
> The patchset depends on below. There's recursive dependency so referred
> to base DT patch here.
> - https://lore.kernel.org/all/20260512-shikra-dt-v1-0-716438330dd0@oss.qualcomm.com/
>
> Validations:
> - make ARCH=arm64 DT_CHECKER_FLAGS=-m DT_SCHEMA_FILES=Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml dt_binding_check
> - make ARCH=arm64 qcom/shikra-cqs-evk.dtb CHECK_DTBS=1 DT_SCHEMA_FILES=Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml
> - cryptobam and crypto driver probe
> - kcapi test
>
> Signed-off-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
Kind reminder, rng/ice/qcrypto patchsets are sent together sometime back
in single series and please follow here[1] for discussions.
Please consider this series as inactive from merger point of view.
Can still use for already engaged discussion.
[1]
https://lore.kernel.org/all/20260521-shikra_crypto_changse-v1-0-0154cc9cc0de@oss.qualcomm.com/
--
Regards
Kuldeep
^ permalink raw reply
* Re: [PATCH 5/5] arm64: dts: qcom: shikra: Add ICE, TRNG and QCE nodes
From: Kuldeep Singh @ 2026-06-08 10:09 UTC (permalink / raw)
To: Dmitry Baryshkov, Konrad Dybcio
Cc: Herbert Xu, David S. Miller, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Vinod Koul, Thara Gopinath,
Frank Li, Andy Gross, Harshal Dev, linux-arm-msm, linux-crypto,
devicetree, linux-kernel, dmaengine
In-Reply-To: <enovafjkiuzr4bciu6bu6hh7h56wvnaq5fh7f46m4h7browyrd@7huwa5egaqaq>
>> + cryptobam: dma-controller@1b04000 {
>> + compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0";
>> + reg = <0x0 0x01b04000 0x0 0x24000>;
>> + interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH 0>;
>> + #dma-cells = <1>;
>> + iommus = <&apps_smmu 0x84 0x0011>,
>> + <&apps_smmu 0x86 0x0011>,
>> + <&apps_smmu 0x92 0x0>,
>> + <&apps_smmu 0x94 0x0011>,
>
> 0x84 / 0x0011 is exactly the same as 0x94 / 0x0011. Likewise 0x96
> duplicates 0x86. Drop the duplicate IOMMU specifiers or explain in the
> commit message why they are required.
+Konrad too as there was same discussion in past too.
0x84/0x94 and 0x86/0x96 pairs are actually different even though
resulting sid is same.
Let me explain more.
From sid sheet,
Description SID (hex) MASK RESULT_SID S1 CB
CE descriptors 0x84, 0x85 0x11 0x0084 S1_CRYPTO_KERNEL
(for data pipe 4/5)
CE descriptors 0x86, 0x87 0x11 0x0086 S1_CRYPTO_USER
(for data pipe 6/7)
CE data pipe 4/5 0x94, 0x95 0x11 0x84(same) S1_CRYPTO_KERNEL
CE data pipe 6/7 0x96, 0x97 0x11 0x86(same) S1_CRYPTO_USER
Qualcomm BAM DMA engine driving QCE has 2 major components here:
* Descriptor pipe (0x84/0x86): This carries BAM command descriptors i,e
key, algorithm, length etc. which tell crypto engine what to do.
* Data pipe (0x94/0x96): This carries the actual data payload — the
plaintext/ciphertext buffers being read/written.
The descriptor(SID 0x84) basically contain IOVA address that points to
the data buffer. That same IOVA address is then used by the data pipe
(SID 0x94) to actually DMA the data.
Since, Crypto engine descriptor and crypto engine data are part of same
crypto operation and with the limited number of context banks, smmu
provides an optimization to logically group and resolve them to same
context bank/page tables.
Pipe 4/5 contain 2 SID(0x84/0x94) for kernel and pipe 6/7 contain
sid(0x86/0x96) for user. Pipe 4/5 doesn't touch pipe6/7 buffers so both
are safe.
--
Regards
Kuldeep
^ permalink raw reply
* Re: [PATCH 4/4] hwrng: qcom - Move qcom-rng.c into drivers/char/hw_random/
From: Konrad Dybcio @ 2026-06-08 7:59 UTC (permalink / raw)
To: Dmitry Baryshkov, Eric Biggers
Cc: linux-crypto, linux-kernel, Om Prakash Singh, Bjorn Andersson,
Neil Armstrong, linux-arm-msm, Olivia Mackall
In-Reply-To: <w3nvohaf7qvfwssggdhoqogwtcfmucfzqiuihbtwly6iqa2i46@3tybaiubfn4q>
On 6/7/26 11:04 PM, Dmitry Baryshkov wrote:
> On Fri, May 29, 2026 at 07:03:32PM -0700, Eric Biggers wrote:
>> 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%)
>>
>
Seems you sent an empty reply, Dmitry
Konrad
^ permalink raw reply
* Re: [PATCH 2/4] crypto: qcom-rng - Allow zero as a random number
From: Konrad Dybcio @ 2026-06-08 7:57 UTC (permalink / raw)
To: Eric Biggers, linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, stable
In-Reply-To: <20260530020332.143058-3-ebiggers@kernel.org>
On 5/30/26 4:03 AM, Eric Biggers wrote:
> 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;
> -
nit: in case you respin, please keep the \n between the read and the
following checks
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
> if ((max - currsize) >= WORD_SZ) {
> memcpy(data, &val, WORD_SZ);
> data += WORD_SZ;
> currsize += WORD_SZ;
> } else {
^ permalink raw reply
* Re: [PATCH 1/4] crypto: qcom-rng - Enable clock in hwrng case
From: Konrad Dybcio @ 2026-06-08 7:56 UTC (permalink / raw)
To: Eric Biggers, linux-crypto
Cc: linux-kernel, Om Prakash Singh, Bjorn Andersson, Neil Armstrong,
linux-arm-msm, Olivia Mackall, stable
In-Reply-To: <20260530020332.143058-2-ebiggers@kernel.org>
On 5/30/26 4:03 AM, Eric Biggers wrote:
> 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>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* [GIT PULL] Crypto Fixes for 7.1
From: Herbert Xu @ 2026-06-08 5:43 UTC (permalink / raw)
To: Linus Torvalds, David S. Miller, Linux Kernel Mailing List,
Linux Crypto Mailing List
The following changes since commit d1fa83ecac31093a550534a79a33bc7f4ba8fc10:
rhashtable: Add bucket_table_free_atomic() helper (2026-05-05 16:12:07 +0800)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6 tags/v7.1-p5
for you to fetch changes up to ecf3edd349dfabee9bc8a46c5ff91c9ebd858d48:
crypto: s390 - add select CRYPTO_AEAD for aes (2026-05-29 14:04:03 +0800)
----------------------------------------------------------------
This push contains the following changes:
- Fix random config build failure on s390.
----------------------------------------------------------------
Arnd Bergmann (1):
crypto: s390 - add select CRYPTO_AEAD for aes
arch/s390/crypto/Kconfig | 1 +
1 file changed, 1 insertion(+)
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH 4/4] hwrng: qcom - Move qcom-rng.c into drivers/char/hw_random/
From: Dmitry Baryshkov @ 2026-06-07 21:04 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-crypto, linux-kernel, Om Prakash Singh, Bjorn Andersson,
Neil Armstrong, linux-arm-msm, Olivia Mackall
In-Reply-To: <20260530020332.143058-5-ebiggers@kernel.org>
On Fri, May 29, 2026 at 07:03:32PM -0700, Eric Biggers wrote:
> 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%)
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 3/4] crypto: qcom-rng - Remove crypto_rng interface
From: Dmitry Baryshkov @ 2026-06-07 21:04 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-crypto, linux-kernel, Om Prakash Singh, Bjorn Andersson,
Neil Armstrong, linux-arm-msm, Olivia Mackall, stable
In-Reply-To: <20260530020332.143058-4-ebiggers@kernel.org>
On Fri, May 29, 2026 at 07:03:31PM -0700, Eric Biggers wrote:
> 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.
It looks like Debian codebase knows about exactly two users of "rng":
kernel itself and stress-ng:
https://codesearch.debian.net/search?q=.salg_type.*%22rng%22&literal=0
> 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(-)
>
> 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" },
This means that the devices won't be bound to the driver, which will
affect GCC state when we finally get the clk_sync_state() supported in
the kernel.
I'd ask to keep on binding to the qcom,prng / prng-ee devices and skip
hwrng registration (possibly with some dev_info message).
> {}
> };
> 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
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 2/4] crypto: qcom-rng - Allow zero as a random number
From: Dmitry Baryshkov @ 2026-06-07 20:52 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-crypto, linux-kernel, Om Prakash Singh, Bjorn Andersson,
Neil Armstrong, linux-arm-msm, Olivia Mackall, stable
In-Reply-To: <20260530020332.143058-3-ebiggers@kernel.org>
On Fri, May 29, 2026 at 07:03:30PM -0700, Eric Biggers wrote:
> Zero is a valid random number and needs to be allowed. Otherwise the
> output is distinguishable from random.
ROFL.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
>
> 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(-)
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 1/4] crypto: qcom-rng - Enable clock in hwrng case
From: Dmitry Baryshkov @ 2026-06-07 20:51 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-crypto, linux-kernel, Om Prakash Singh, Bjorn Andersson,
Neil Armstrong, linux-arm-msm, Olivia Mackall, stable
In-Reply-To: <20260530020332.143058-2-ebiggers@kernel.org>
On Fri, May 29, 2026 at 07:03:29PM -0700, Eric Biggers wrote:
> 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(+)
>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
^ permalink raw reply
* [PATCH v4 1/1] crypto: atmel-ecc - fix multi-device use-after-free and registration races
From: Lothar Rubusch @ 2026-06-07 20:02 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, krzk+dt
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
During parallel driver initialization or driver teardown sequences
in setups with multiple atmel-ecc instances, a race condition exists
between atmel_ecc_i2c_client_alloc() and the probe/remove paths.
A concurrent transformation request can fetch an i2c_client instance
from the global i2c_client_list before the kpp is fully registered, or
while it is actively being unbound, resulting in a use-after-free (UAF)
risk.
1. The initialization problem in probe(): Adding first an i2c client to the
i2c_client_list, and then registering the kpp algorim may result in a race,
when this happens for a second (or further) probed device. In this case the
algorithm is already registered, so a TFM may arrive, while the latest
probing device is added to the list, but not kpp registered. In case this
fails and this last device is going to be removed again from the list, this
leaves a window where the TFM might obtain a pointer to the - now deleted -
i2c client, which opens a UAF risk. Furthermore, there will happen atempts
to multiple registering the same driver to the same type of algorithm.
Note, a simple reverting of the order: first register kpp, second add the
i2c client to the i2c_client_list - is not possible here, since the kpp
registration immediately triggers the self tests, which then will allocate
and require an i2c client.
2. The critical race condition problem: It exists when an Atmel device
instance is rapidly removed and immediately re-probed, before the global
resources are fully cleaned up. In this scenario, the asynchronous
unregistration sequence in the remove() lags behind the incoming probe()
function. Because of the global algorithm structure being not yet
completely cleaned up, the newly re-probed device incorrectly intercepts
the static, partially-dismantled global context. It then overwrites active
pointers and re-acquires the global instance prematurely. In this way, when
the deregistration sequence finally completes its execution, under the
newly initialized device, it may lose the tracking references, leaking the
older driver memory blocks, and introducing an immediate UAF risk.
3. The removal race problem, when a call to remove() starts removing the
device, but another thread executing a TFM, a severe Time-of-Check to
Time-of-Use (TOCTOU) race condition exists in the teardown path between the
asynchronous remove() sequence and completing TFMs. When the device is
unbound, the remove() function evaluates the active tfm_count and decides
whether to wait or proceed with resource deallocation. However, if the
final active TFM finishes its crypto operation and invokes the client free
function immediately after remove() performs its reference check but before
it can sleep, the completion signal is fired into a clearing state. The
unbind thread then misinterprets the zeroed counter, skips the
synchronization barrier entirely, and instantly deallocates the per-device
private structures. This leaves the final TFM worker thread executing code
inside a completely freed memory area, triggering an immediate UAF kernel
panic. Note, simply calling the kpp unregister here won't clean up the
situation in the context of having a setup with external hardware on a slow
bus.
Address this by implementing an independent subsystem reference counter
kpp refcnt protected by a dedicated mutex to ensure the static global kpp
algorithm structure is registered exactly once by the first probing device
instance. In multi-device scenarios, or when extending the resource
management support of the i2c_client_list to all atmel-i2c based device
drivers, such scenarios can become realistic. The particular algorithm is
registered only once. Each i2c client (i.e. each probing device driver) is
added as client to the i2c_client_list. This guarantee that only the first
probe will register the algorithm. The list is populated for further calls
to probe, and subsequent calls to the client alloc function.
Concurrently, decouple list mutations from registration by moving the
global list eviction to the absolute top of the remove lifecycle. This
keeps the quick execution of the list allocation loop intact, ensures that
unbinding hardware is instantly blind to the rest of the system, and
completely bypasses the recursive deadlock condition previously triggered
by synchronous crypto API self-tests.
Fixes: 11105693fa05 ("crypto: atmel-ecc - introduce Microchip / Atmel ECC driver")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 130 +++++++++++++++++++++++++++++--------
drivers/crypto/atmel-i2c.h | 3 +
2 files changed, 106 insertions(+), 27 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 0ca02995a1de..7336c3661e52 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -23,6 +23,11 @@
#include <crypto/kpp.h>
#include "atmel-i2c.h"
+static DEFINE_MUTEX(atmel_ecc_kpp_lock);
+static int atmel_ecc_kpp_refcnt;
+DECLARE_COMPLETION(atmel_ecc_unreg_done);
+static bool atmel_ecc_unreg_active;
+
static struct atmel_ecc_driver_data driver_data;
/**
@@ -241,7 +246,10 @@ static void atmel_ecc_i2c_client_free(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
- atomic_dec(&i2c_priv->tfm_count);
+ spin_lock(&driver_data.i2c_list_lock);
+ if (atomic_dec_and_test(&i2c_priv->tfm_count) && i2c_priv->unbinding)
+ complete(&i2c_priv->remove_done);
+ spin_unlock(&driver_data.i2c_list_lock);
}
static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
@@ -276,7 +284,8 @@ static void atmel_ecdh_exit_tfm(struct crypto_kpp *tfm)
struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
kfree(ctx->public_key);
- crypto_free_kpp(ctx->fallback);
+ if (ctx->fallback)
+ crypto_free_kpp(ctx->fallback);
atmel_ecc_i2c_client_free(ctx->client);
}
@@ -295,6 +304,28 @@ static unsigned int atmel_ecdh_max_size(struct crypto_kpp *tfm)
return ATMEL_ECC_PUBKEY_SIZE;
}
+static int atmel_ecc_wait_for_tfms(struct atmel_i2c_client_priv *i2c_priv)
+{
+ unsigned long timeout;
+
+ spin_lock(&driver_data.i2c_list_lock);
+ list_del(&i2c_priv->i2c_client_list_node);
+ i2c_priv->unbinding = true;
+ reinit_completion(&i2c_priv->remove_done);
+ if (!atomic_read(&i2c_priv->tfm_count)) {
+ spin_unlock(&driver_data.i2c_list_lock);
+ return 0;
+ }
+ spin_unlock(&driver_data.i2c_list_lock);
+
+ timeout = wait_for_completion_timeout(&i2c_priv->remove_done,
+ msecs_to_jiffies(2000));
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
static struct kpp_alg atmel_ecdh_nist_p256 = {
.set_secret = atmel_ecdh_set_secret,
.generate_public_key = atmel_ecdh_generate_public_key,
@@ -315,6 +346,7 @@ static struct kpp_alg atmel_ecdh_nist_p256 = {
static int atmel_ecc_probe(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv;
+ unsigned long timeout;
int ret;
ret = atmel_i2c_probe(client);
@@ -323,49 +355,93 @@ static int atmel_ecc_probe(struct i2c_client *client)
i2c_priv = i2c_get_clientdata(client);
+ init_completion(&i2c_priv->remove_done);
+ i2c_priv->unbinding = false;
+
spin_lock(&driver_data.i2c_list_lock);
list_add_tail(&i2c_priv->i2c_client_list_node,
&driver_data.i2c_client_list);
spin_unlock(&driver_data.i2c_list_lock);
- ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
- if (ret) {
- spin_lock(&driver_data.i2c_list_lock);
- list_del(&i2c_priv->i2c_client_list_node);
- spin_unlock(&driver_data.i2c_list_lock);
+ mutex_lock(&atmel_ecc_kpp_lock);
+ /*
+ * For cases where the same/last such device is still in unregistering,
+ * and now re-registering (refcnt is 0, but completion still exists).
+ * Safely capture the pointer, drop the lock and sleep until it
+ * terminates upon completion or retry limit reached.
+ */
+ while (atmel_ecc_unreg_active) {
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ timeout = wait_for_completion_timeout(&atmel_ecc_unreg_done,
+ msecs_to_jiffies(2000));
+ mutex_lock(&atmel_ecc_kpp_lock);
+ if (timeout == 0) {
+ mutex_unlock(&atmel_ecc_kpp_lock);
+
+ ret = atmel_ecc_wait_for_tfms(i2c_priv);
+ if (ret)
+ dev_err(&client->dev,
+ "probe timed out, former instance active\n");
+ return -ETIMEDOUT;
+ }
+ }
+ if (atmel_ecc_kpp_refcnt == 0) {
+ ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
+ if (ret) {
+ mutex_unlock(&atmel_ecc_kpp_lock);
- dev_err(&client->dev, "%s alg registration failed\n",
- atmel_ecdh_nist_p256.base.cra_driver_name);
- } else {
- dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
+ atmel_ecc_wait_for_tfms(i2c_priv);
+ dev_err(&client->dev,
+ "%s alg registration failed\n",
+ atmel_ecdh_nist_p256.base.cra_driver_name);
+
+ return ret;
+ }
}
+ atmel_ecc_kpp_refcnt++;
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
return ret;
}
static void atmel_ecc_remove(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
-
- /* Return EBUSY if i2c client already allocated. */
- if (atomic_read(&i2c_priv->tfm_count)) {
- /*
- * After we return here, the memory backing the device is freed.
- * That happens no matter what the return value of this function
- * is because in the Linux device model there is no error
- * handling for unbinding a driver.
- * If there is still some action pending, it probably involves
- * accessing the freed memory.
- */
- dev_emerg(&client->dev, "Device is busy, expect memory corruption.\n");
- return;
- }
-
- crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+ bool trigger_unreg = false;
+ bool wait_needed = false;
+ unsigned long timeout;
spin_lock(&driver_data.i2c_list_lock);
list_del(&i2c_priv->i2c_client_list_node);
+ i2c_priv->unbinding = true;
+ reinit_completion(&i2c_priv->remove_done);
+ if (atomic_read(&i2c_priv->tfm_count) > 0)
+ wait_needed = true;
spin_unlock(&driver_data.i2c_list_lock);
+ if (wait_needed) {
+ timeout = wait_for_completion_timeout(&i2c_priv->remove_done,
+ msecs_to_jiffies(5000));
+ if (timeout == 0)
+ dev_emerg(&client->dev, "Teardown timed out! Active TFMs leaked, memory corruption imminent.\n");
+ }
+
+ mutex_lock(&atmel_ecc_kpp_lock);
+ atmel_ecc_kpp_refcnt--;
+ if (atmel_ecc_kpp_refcnt == 0) {
+ trigger_unreg = true;
+ atmel_ecc_unreg_active = true;
+ reinit_completion(&atmel_ecc_unreg_done);
+ }
+ mutex_unlock(&atmel_ecc_kpp_lock);
+
+ if (trigger_unreg) {
+ crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+ mutex_lock(&atmel_ecc_kpp_lock);
+ atmel_ecc_unreg_active = false;
+ complete_all(&atmel_ecc_unreg_done);
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ }
}
static const struct of_device_id atmel_ecc_dt_ids[] = {
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 72f04c15682f..8e6617422191 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -129,6 +129,7 @@ struct atmel_ecc_driver_data {
* @wake_token_sz : size in bytes of the wake_token
* @tfm_count : number of active crypto transformations on i2c client
* @hwrng : hold the hardware generated rng
+ * @unbinding : unbinding handshake
*
* Reads and writes from/to the i2c client are sequential. The first byte
* transmitted to the device is treated as the byte size. Any attempt to send
@@ -145,6 +146,8 @@ struct atmel_i2c_client_priv {
size_t wake_token_sz;
atomic_t tfm_count ____cacheline_aligned;
struct hwrng hwrng;
+ struct completion remove_done;
+ bool unbinding;
};
/**
base-commit: 79bbe453e5bfa6e1c6aa2e8329bfc8f152b81c9b
--
2.53.0
^ permalink raw reply related
* [PATCH v3 1/1] crypto: atmel-ecc - fix multi-device use-after-free and registration races
From: Lothar Rubusch @ 2026-06-07 14:18 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, krzk+dt
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
During parallel driver initialization or driver teardown sequences
in setups with multiple atmel-ecc instances, a race condition exists
between atmel_ecc_i2c_client_alloc() and the probe/remove paths.
A concurrent transformation request can fetch an i2c_client instance
from the global i2c_client_list before the kpp is fully registered, or
while it is actively being unbound, resulting in a use-after-free (UAF)
risk.
1. The initialization problem in probe(): Adding first an i2c client to the
i2c_client_list, and then registering the kpp algorim may result in a race,
when this happens for a second (or further) probed device. In this case the
algorithm is already registered, so a TFM may arrive, while the latest
probing device is added to the list, but not kpp registered. In case this
fails and this last device is going to be removed again from the list, this
leaves a window where the TFM might obtain a pointer to the - now deleted -
i2c client, which opens a UAF risk. Furthermore, there will happen atempts
to multiple registering the same driver to the same type of algorithm.
Note, a simple reverting of the order: first register kpp, second add the
i2c client to the i2c_client_list - is not possible here, since the kpp
registration immediately triggers the self tests, which then will allocate
and require an i2c client.
2. The critical race condition problem: It exists when an Atmel device
instance is rapidly removed and immediately re-probed, before the global
resources are fully cleaned up. In this scenario, the asynchronous
unregistration sequence in the remove() lags behind the incoming probe()
function. Because of the global algorithm structure being not yet
completely cleaned up, the newly re-probed device incorrectly intercepts
the static, partially-dismantled global context. It then overwrites active
pointers and re-acquires the global instance prematurely. In this way, when
the deregistration sequence finally completes its execution, under the
newly initialized device, it may lose the tracking references, leaking the
older driver memory blocks, and introducing an immediate UAF risk.
3. The removal race problem, when a call to remove() starts removing the
device, but another thread executing a TFM, a severe Time-of-Check to
Time-of-Use (TOCTOU) race condition exists in the teardown path between the
asynchronous remove() sequence and completing TFMs. When the device is
unbound, the remove() function evaluates the active tfm_count and decides
whether to wait or proceed with resource deallocation. However, if the
final active TFM finishes its crypto operation and invokes the client free
function immediately after remove() performs its reference check but before
it can sleep, the completion signal is fired into a clearing state. The
unbind thread then misinterprets the zeroed counter, skips the
synchronization barrier entirely, and instantly deallocates the per-device
private structures. This leaves the final TFM worker thread executing code
inside a completely freed memory area, triggering an immediate UAF kernel
panic. Note, simply calling the kpp unregister here won't clean up the
situation in the context of having a setup with external hardware on a slow
bus.
Address this by implementing an independent subsystem reference counter
kpp refcnt protected by a dedicated mutex to ensure the static global kpp
algorithm structure is registered exactly once by the first probing device
instance. In multi-device scenarios, or when extending the resource
management support of the i2c_client_list to all atmel-i2c based device
drivers, such scenarios can become realistic. The particular algorithm is
registered only once. Each i2c client (i.e. each probing device driver) is
added as client to the i2c_client_list. This guarantee that only the first
probe will register the algorithm. The list is populated for further calls
to probe, and subsequent calls to the client alloc function.
Concurrently, decouple list mutations from registration by moving the
global list eviction to the absolute top of the remove lifecycle. This
keeps the quick execution of the list allocation loop intact, ensures that
unbinding hardware is instantly blind to the rest of the system, and
completely bypasses the recursive deadlock condition previously triggered
by synchronous crypto API self-tests.
Fixes: 11105693fa05 ("crypto: atmel-ecc - introduce Microchip / Atmel ECC driver")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 106 +++++++++++++++++++++++++++----------
drivers/crypto/atmel-i2c.h | 3 ++
2 files changed, 82 insertions(+), 27 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 0ca02995a1de..df285ca9a6f3 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -23,6 +23,11 @@
#include <crypto/kpp.h>
#include "atmel-i2c.h"
+static DEFINE_MUTEX(atmel_ecc_kpp_lock);
+static int atmel_ecc_kpp_refcnt;
+DECLARE_COMPLETION(atmel_ecc_unreg_done);
+static bool atmel_ecc_unreg_active;
+
static struct atmel_ecc_driver_data driver_data;
/**
@@ -241,7 +246,10 @@ static void atmel_ecc_i2c_client_free(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
- atomic_dec(&i2c_priv->tfm_count);
+ spin_lock(&driver_data.i2c_list_lock);
+ if (atomic_dec_and_test(&i2c_priv->tfm_count) && i2c_priv->unbinding)
+ complete(&i2c_priv->remove_done);
+ spin_unlock(&driver_data.i2c_list_lock);
}
static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
@@ -276,7 +284,8 @@ static void atmel_ecdh_exit_tfm(struct crypto_kpp *tfm)
struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
kfree(ctx->public_key);
- crypto_free_kpp(ctx->fallback);
+ if (ctx->fallback)
+ crypto_free_kpp(ctx->fallback);
atmel_ecc_i2c_client_free(ctx->client);
}
@@ -315,6 +324,7 @@ static struct kpp_alg atmel_ecdh_nist_p256 = {
static int atmel_ecc_probe(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv;
+ unsigned long timeout;
int ret;
ret = atmel_i2c_probe(client);
@@ -323,49 +333,91 @@ static int atmel_ecc_probe(struct i2c_client *client)
i2c_priv = i2c_get_clientdata(client);
+ init_completion(&i2c_priv->remove_done);
+ i2c_priv->unbinding = false;
+
spin_lock(&driver_data.i2c_list_lock);
list_add_tail(&i2c_priv->i2c_client_list_node,
&driver_data.i2c_client_list);
spin_unlock(&driver_data.i2c_list_lock);
- ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
- if (ret) {
- spin_lock(&driver_data.i2c_list_lock);
- list_del(&i2c_priv->i2c_client_list_node);
- spin_unlock(&driver_data.i2c_list_lock);
+ mutex_lock(&atmel_ecc_kpp_lock);
+ /*
+ * For cases where the same/last such device is still in unregistering,
+ * and now re-registering (refcnt is 0, but completion still exists).
+ * Safely capture the pointer, drop the lock and sleep until it
+ * terminates upon completion or retry limit reached.
+ */
+ while (atmel_ecc_unreg_active) {
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ timeout = wait_for_completion_timeout(&atmel_ecc_unreg_done,
+ msecs_to_jiffies(2000));
+ mutex_lock(&atmel_ecc_kpp_lock);
+
+ if (timeout == 0) {
+ spin_lock(&driver_data.i2c_list_lock);
+ list_del(&i2c_priv->i2c_client_list_node);
+ spin_unlock(&driver_data.i2c_list_lock);
+ mutex_unlock(&atmel_ecc_kpp_lock);
+
+ dev_err(&client->dev, "probe timed out, former driver instance not fully deregistered\n");
+ return -ETIMEDOUT;
+ }
+ }
- dev_err(&client->dev, "%s alg registration failed\n",
- atmel_ecdh_nist_p256.base.cra_driver_name);
- } else {
- dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
+ if (atmel_ecc_kpp_refcnt == 0) {
+ ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
+ if (ret) {
+ spin_lock(&driver_data.i2c_list_lock);
+ list_del(&i2c_priv->i2c_client_list_node);
+ spin_unlock(&driver_data.i2c_list_lock);
+ mutex_unlock(&atmel_ecc_kpp_lock);
+
+ dev_err(&client->dev, "%s alg registration failed\n",
+ atmel_ecdh_nist_p256.base.cra_driver_name);
+ return ret;
+ }
}
+ atmel_ecc_kpp_refcnt++;
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
return ret;
}
static void atmel_ecc_remove(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
-
- /* Return EBUSY if i2c client already allocated. */
- if (atomic_read(&i2c_priv->tfm_count)) {
- /*
- * After we return here, the memory backing the device is freed.
- * That happens no matter what the return value of this function
- * is because in the Linux device model there is no error
- * handling for unbinding a driver.
- * If there is still some action pending, it probably involves
- * accessing the freed memory.
- */
- dev_emerg(&client->dev, "Device is busy, expect memory corruption.\n");
- return;
- }
-
- crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+ bool trigger_unreg = false;
+ bool wait_needed = false;
spin_lock(&driver_data.i2c_list_lock);
list_del(&i2c_priv->i2c_client_list_node);
+ i2c_priv->unbinding = true;
+ reinit_completion(&i2c_priv->remove_done);
+ if (atomic_read(&i2c_priv->tfm_count) > 0)
+ wait_needed = true;
spin_unlock(&driver_data.i2c_list_lock);
+
+ if (wait_needed)
+ wait_for_completion(&i2c_priv->remove_done);
+
+ mutex_lock(&atmel_ecc_kpp_lock);
+ atmel_ecc_kpp_refcnt--;
+ if (atmel_ecc_kpp_refcnt == 0) {
+ trigger_unreg = true;
+ atmel_ecc_unreg_active = true;
+ reinit_completion(&atmel_ecc_unreg_done);
+ }
+ mutex_unlock(&atmel_ecc_kpp_lock);
+
+ if (trigger_unreg) {
+ crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+ mutex_lock(&atmel_ecc_kpp_lock);
+ atmel_ecc_unreg_active = false;
+ complete_all(&atmel_ecc_unreg_done);
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ }
}
static const struct of_device_id atmel_ecc_dt_ids[] = {
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 72f04c15682f..8e6617422191 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -129,6 +129,7 @@ struct atmel_ecc_driver_data {
* @wake_token_sz : size in bytes of the wake_token
* @tfm_count : number of active crypto transformations on i2c client
* @hwrng : hold the hardware generated rng
+ * @unbinding : unbinding handshake
*
* Reads and writes from/to the i2c client are sequential. The first byte
* transmitted to the device is treated as the byte size. Any attempt to send
@@ -145,6 +146,8 @@ struct atmel_i2c_client_priv {
size_t wake_token_sz;
atomic_t tfm_count ____cacheline_aligned;
struct hwrng hwrng;
+ struct completion remove_done;
+ bool unbinding;
};
/**
base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
prerequisite-patch-id: c4d6779c74f5ca16536803c314af99c4346a14e1
prerequisite-patch-id: edd38ca9cc59d9e34c0944e2e7b533cdeb422c81
prerequisite-patch-id: 55f668761eaff284d13ab86085686eae426fc524
prerequisite-patch-id: b96e5855ea503314931ff3184f96af049c16b19f
prerequisite-patch-id: 5a761e93900d75ef5f887324002c6e52ba47558a
prerequisite-patch-id: 77570d656bdcb6a9bfa3c70b730db8f22767a70b
prerequisite-patch-id: 10a90dfb8890f39c19ea4117ffbb7cf3c801dcb7
prerequisite-patch-id: 86c4da8c2119be06fe5d494066523f6b8507abe4
--
2.53.0
^ permalink raw reply related
* [PATCH] crypto: ecc - Optimize vli additive operations using compiler builtins
From: Fabian Blatter @ 2026-06-07 11:24 UTC (permalink / raw)
To: lukas, ignat, herbert, davem
Cc: stefanb, linux-crypto, linux-kernel, Fabian Blatter
Replace the software carry flag emulation with compiler builtins.
Even the newest compilers struggle with taking advantage of the
hardware carry flag. Compiler builtins allow the compiler to
much more easily achieve this while still remaining constant-time.
This yields an approximately 6-7% performance improvement
on the ecc_gen_privkey, ecc_make_pub_key and crypto_ecdh_shared_secret
functions on x86_64 on all curve sizes.
Additionally, the code becomes much more readable.
Signed-off-by: Fabian Blatter <fabianblatter09@gmail.com>
---
Hi,
I'd like to expand on the benchmarks, compare the generated assembly,
and clarify some things.
Use of compiler builtins:
This patch uses __builtin_addcll, __builtin_subcll when available and
otherwise __builtin_uaddll_overflow, __builtin_usubll_overflow. the
latter have existed since ancient gcc versions, so no third fallback
is needed.
I have put the add_carry and sub_borrow inline functions with the
preprocessor logic for builtin selection directly in crypto/ecc.c.
Please let me know if you would like them to be somewhere else.
They do not emit data-dependent branches, and so remain constant-time.
Benchmarks:
All benchmarks were run single-threaded on my AMD 7700X CPU limited to
5.6Ghz. I have measured both nanoseconds and clock cycles, since their
combination can hint at downclocking issues and allows calculation of
the clock speed during the benchmark.
I have omitted the raw output from the benchmarking code, as they much
exceed the 72 character limit.
I have calculated the percent differences, included clock speed
calculations and relevant summaries.
Macro benchmarks:
These were run in a virtualized environment using virtme-ng on the
compiled linux kernel image compiled with default flags.
(the first value is the original time per operation, the second the
patched one. cc is short for clock cycles)
Curve keypair generation (ecc_gen_privkey + ecc_make_pub_key):
P256:
- 646963ns/op -> 600632ns/op = -7.71%
- 2911300cc/op -> 2702854cc/op = -7.71%
- 4.4999Ghz -> 4.5000Ghz = no difference
P384:
- 1239160ns/op -> 1153940ns/op = -7.38%
- 5576250cc/op -> 5192749cc/op = -7.38%
- 4.5000Ghz -> 4.5000Ghz = no difference
Shared secret generation (crypto_ecdh_shared_secret):
P256:
- 320114ns/op -> 297548ns/op = -7.58%
- 1440521cc/op -> 1338972cc/op = -7.58%
- 4.5000Ghz -> 4.5000Ghz = no difference
P384:
- 620768ns/op -> 582560ns/op = -6.55%
- 2793467cc/op -> 2621529cc/op = -6.55%
- 4.5000Ghz -> 4.5000Ghz = no difference
The benchmarks clearly indicate a roughly 6-7% performance increase on
the public API functions. It also appears that virtme-ng limited the
clock speed to 4.5Ghz
Micro benchmarks:
Since the vli additive functions only rely on u64 being defined, these
were run without virtualization and with varying compilers and
compiler flags.
The microbenchmarks show much more mixed results, depending
heavily on the compiler and optimization level used.
For instance, on gcc and O2, the vli_add present in the
patch is actually 25.3% slower than the original one. I have tracked
this down to gcc using a weird way to restore the carry flag after
each iteration, causing way more dependent instructions, preventing
ILP from executing multiple at once.
This is quite interesting, since, as far as I know, the kernel compiles
with gcc and O2 by default, yet the macro-level benchmarks still show a
performance increase. The effect seems to be reversed when crypto/ecc.c
gets compiled. Or maybe the linux kernel uses some additional
optimization flags, I am unsure.
However, most of the time, the patched version outperforms the original
one by a wide margin:
- On clang -O2 or -O3, vli_add and vli_uadd show a 4.074x and 5.384x
speedup.
- On gcc, vli_uadd shows a 74% performance increase at O2,
and a 2.07x speedup at O3.
The performance profile of vli_sub and vli_usub is almost identical to
that of vli_add and vli_uadd.
Assembly comparison:
I have put together a piece of code on Compiler explorer, to make sure
it compiles on old gcc versions, view instructions and play around with
compiler settings.
If you would like, you can play around yourself here:
https://godbolt.org/z/1jT5zesz8
When using clang 22.1 at -O3 -march=lunarlake, the difference between
the patched and original version is particularly clear. The patched
version produces this assembly in the unrolled vli_add loop:
mov rax, qword ptr [rsi + 8*rcx + 16]
adc rax, qword ptr [rdx + 8*rcx + 16]
mov qword ptr [rdi + 8*rcx + 16], rax
mov rax, qword ptr [rsi + 8*rcx + 24]
adc rax, qword ptr [rdx + 8*rcx + 24]
mov qword ptr [rdi + 8*rcx + 24], rax
mov rax, qword ptr [rsi + 8*rcx + 32]
adc rax, qword ptr [rdx + 8*rcx + 32]
mov qword ptr [rdi + 8*rcx + 32], rax
mov rax, qword ptr [rsi + 8*rcx + 40]
adc rax, qword ptr [rdx + 8*rcx + 40]
mov qword ptr [rdi + 8*rcx + 40], rax
mov rax, qword ptr [rsi + 8*rcx + 48]
adc rax, qword ptr [rdx + 8*rcx + 48]
This is basically optimal for an inner loop. It's pure adc and mov
instructions. The loop counting part is still nowhere near perfect,
and still uses setc instructions. But it is still better than what
the original version produces with the same compiler and flags:
mov r10, qword ptr [rsi + 8*rcx]
lea r11, [r10 + rax]
add r11, qword ptr [rdx + 8*rcx]
xor ebx, ebx
cmp r11, r10
setb bl
cmove rbx, rax
mov qword ptr [rdi + 8*rcx], r11
mov rax, qword ptr [rsi + 8*rcx + 8]
lea r10, [rax + rbx]
add r10, qword ptr [rdx + 8*rcx + 8]
xor r11d, r11d
cmp r10, rax
setb r11b
cmove r11, rbx
mov qword ptr [rdi + 8*rcx + 8], r10
mov rax, qword ptr [rsi + 8*rcx + 16]
lea r10, [rax + r11]
add r10, qword ptr [rdx + 8*rcx + 16]
xor ebx, ebx
cmp r10, rax
setb bl
cmove rbx, r11
mov qword ptr [rdi + 8*rcx + 16], r10
mov rax, qword ptr [rsi + 8*rcx + 24]
lea r10, [rax + rbx]
add r10, qword ptr [rdx + 8*rcx + 24]
xor r11d, r11d
cmp r10, rax
setb r11b
cmove r11, rbx
This is downright horrendous. that entire block of processes only 4
limbs, thats 8 instructions per limb! The add instructions
are also not adc instructions, showing that the carry flag is
being fully emulated. This demonstrates how even on the newest
compilers and at the highest optimization level, still cannot
generate hardware carry chains without explicit use of builtins.
I should note that not just clang 22.1.0 with -O3 -march=lunarlake
does this. Gcc and clang show this behaviour on every version i have
tested, regardless of target architecture.
I am not very familiar with ARM or RISC-V assembly, but looking at
compiler explorer, the effect clearly persists, and in the case of
RISC-V actually gets much worse.
This affects all architectures across all compilers and compiler
flags.
If you have gotten this far, thank you for reading this and I am looking
forward to any feedback! If you would like any changes to this patch,
I am very happy to send a v2.
crypto/ecc.c | 98 ++++++++++++++++++++++++++++++++--------------------
1 file changed, 60 insertions(+), 38 deletions(-)
diff --git a/crypto/ecc.c b/crypto/ecc.c
index 43b0def3a225..4f7bb6f424d8 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -279,6 +279,48 @@ static void vli_rshift1(u64 *vli, unsigned int ndigits)
}
}
+#ifdef __has_builtin
+#if __has_builtin(__builtin_addcll)
+#define USE_BUILTIN_ADDC
+#endif
+#endif
+
+/* Computes result = left + right + carry_in and updates carry_out */
+static inline void add_carry(u64 left, u64 right, u64 *result, u64 carry_in,
+ u64 *carry_out)
+{
+#ifdef USE_BUILTIN_ADDC
+ *result = __builtin_addcll(left, right, carry_in, carry_out);
+#else
+ u64 sum1, sum2;
+ u64 c1 = __builtin_uaddll_overflow(left, right, &sum1);
+ u64 c2 = __builtin_uaddll_overflow(sum1, carry_in, &sum2);
+ *result = sum2;
+ *carry_out = c1 | c2;
+#endif
+}
+
+#ifdef __has_builtin
+#if __has_builtin(__builtin_subcll)
+#define USE_BUILTIN_SUBC
+#endif
+#endif
+
+/* Computes result = left - right - borrow_in and updates borrow_out */
+static inline void sub_borrow(u64 left, u64 right, u64 *result, u64 borrow_in,
+ u64 *borrow_out)
+{
+#ifdef USE_BUILTIN_SUBC
+ *result = __builtin_subcll(left, right, borrow_in, borrow_out);
+#else
+ u64 diff1, diff2;
+ u64 b1 = __builtin_usubll_overflow(left, right, &diff1);
+ u64 b2 = __builtin_usubll_overflow(diff1, borrow_in, &diff2);
+ *result = diff2;
+ *borrow_out = b1 | b2;
+#endif
+}
+
/* Computes result = left + right, returning carry. Can modify in place. */
static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
unsigned int ndigits)
@@ -286,15 +328,8 @@ static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
u64 carry = 0;
int i;
- for (i = 0; i < ndigits; i++) {
- u64 sum;
-
- sum = left[i] + right[i] + carry;
- if (sum != left[i])
- carry = (sum < left[i]);
-
- result[i] = sum;
- }
+ for (i = 0; i < ndigits; i++)
+ add_carry(left[i], right[i], &result[i], carry, &carry);
return carry;
}
@@ -303,40 +338,29 @@ static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
static u64 vli_uadd(u64 *result, const u64 *left, u64 right,
unsigned int ndigits)
{
- u64 carry = right;
+ u64 carry;
int i;
- for (i = 0; i < ndigits; i++) {
- u64 sum;
+ if (ndigits == 0)
+ return right;
- sum = left[i] + carry;
- if (sum != left[i])
- carry = (sum < left[i]);
- else
- carry = !!carry;
+ carry = __builtin_uaddll_overflow(left[0], right, &result[0]);
- result[i] = sum;
- }
+ for (i = 1; i < ndigits; i++)
+ carry = __builtin_uaddll_overflow(left[i], carry, &result[i]);
return carry;
}
/* Computes result = left - right, returning borrow. Can modify in place. */
u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
- unsigned int ndigits)
+ unsigned int ndigits)
{
u64 borrow = 0;
int i;
- for (i = 0; i < ndigits; i++) {
- u64 diff;
-
- diff = left[i] - right[i] - borrow;
- if (diff != left[i])
- borrow = (diff > left[i]);
-
- result[i] = diff;
- }
+ for (i = 0; i < ndigits; i++)
+ sub_borrow(left[i], right[i], &result[i], borrow, &borrow);
return borrow;
}
@@ -344,20 +368,18 @@ EXPORT_SYMBOL(vli_sub);
/* Computes result = left - right, returning borrow. Can modify in place. */
static u64 vli_usub(u64 *result, const u64 *left, u64 right,
- unsigned int ndigits)
+ unsigned int ndigits)
{
- u64 borrow = right;
+ u64 borrow;
int i;
- for (i = 0; i < ndigits; i++) {
- u64 diff;
+ if (ndigits == 0)
+ return right;
- diff = left[i] - borrow;
- if (diff != left[i])
- borrow = (diff > left[i]);
+ borrow = __builtin_usubll_overflow(left[0], right, &result[0]);
- result[i] = diff;
- }
+ for (i = 1; i < ndigits; i++)
+ borrow = __builtin_usubll_overflow(left[i], borrow, &result[i]);
return borrow;
}
--
2.54.0
^ permalink raw reply related
* Re: [PATCH 5/5] arm64: dts: qcom: shikra: Add ICE, TRNG and QCE nodes
From: Dmitry Baryshkov @ 2026-06-07 10:13 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-5-0154cc9cc0de@oss.qualcomm.com>
On Thu, May 21, 2026 at 06:47:12PM +0530, Kuldeep Singh wrote:
> Add device tree nodes describing the crypto hardware blocks present
> on the Qualcomm Shikra platform:
>
> - BAM DMA controller used by the Qualcomm crypto engine
> - QCE (crypto) engine with DMA support
> - TRNG hardware random number generator
> - Inline crypto engine (ICE)
>
> Also connect the SDHC controller to ICE via "qcom,ice" property to
> support inline encryption.
>
> Signed-off-by: Kuldeep Singh <kuldeep.singh@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/shikra.dtsi | 52 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 52 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/shikra.dtsi b/arch/arm64/boot/dts/qcom/shikra.dtsi
> index 31d0126e5b3e..b617735650ac 100644
> --- a/arch/arm64/boot/dts/qcom/shikra.dtsi
> +++ b/arch/arm64/boot/dts/qcom/shikra.dtsi
> @@ -546,6 +546,41 @@ config_noc: interconnect@1900000 {
> #interconnect-cells = <2>;
> };
>
> + cryptobam: dma-controller@1b04000 {
> + compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0";
> + reg = <0x0 0x01b04000 0x0 0x24000>;
> + interrupts = <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH 0>;
> + #dma-cells = <1>;
> + iommus = <&apps_smmu 0x84 0x0011>,
> + <&apps_smmu 0x86 0x0011>,
> + <&apps_smmu 0x92 0x0>,
> + <&apps_smmu 0x94 0x0011>,
0x84 / 0x0011 is exactly the same as 0x94 / 0x0011. Likewise 0x96
duplicates 0x86. Drop the duplicate IOMMU specifiers or explain in the
commit message why they are required.
> + <&apps_smmu 0x96 0x0011>,
> + <&apps_smmu 0x98 0x0001>,
> + <&apps_smmu 0x9f 0x0>;
> + qcom,ee = <0>;
> + qcom,controlled-remotely;
> + num-channels = <16>;
> + qcom,num-ees = <4>;
> + };
> +
--
With best wishes
Dmitry
^ 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