Linux cryptographic layer development
 help / color / mirror / Atom feed
* [PATCH 4/6] crypto: qat - skip restart for down devices
From: Ahsan Atta @ 2026-05-13 15:16 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, qat-linux, Ahsan Atta, stable, Giovanni Cabiddu
In-Reply-To: <cover.1778685152.git.ahsan.atta@intel.com>

Skip the shutdown and restart flow when adf_slot_reset() is entered
for a device that is already down. In that case, leave
ADF_STATUS_RESTARTING clear and let adf_slot_reset() restore PCI
function state without calling adf_dev_up(), re-enabling SR-IOV, or
sending restarted notifications.

This is in preparation for adding reset_prepare() and reset_done()
callbacks in adf_aer.c.

Cc: stable@vger.kernel.org
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
---
 drivers/crypto/intel/qat/qat_common/adf_aer.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c
index 365637e40439..7255cac5aaa6 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c
@@ -33,6 +33,9 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev,
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 
+	if (!adf_dev_started(accel_dev))
+		return PCI_ERS_RESULT_CAN_RECOVER;
+
 	adf_error_notifier(accel_dev);
 	adf_pf2vf_notify_fatal_error(accel_dev);
 	set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
@@ -204,6 +207,9 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev)
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 
+	if (!adf_devmgr_in_reset(accel_dev))
+		goto reset_complete;
+
 	pci_restore_state(pdev);
 	res = adf_dev_up(accel_dev, false);
 	if (res && res != -EALREADY)
@@ -213,6 +219,8 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev)
 	adf_pf2vf_notify_restarted(accel_dev);
 	adf_dev_restarted_notify(accel_dev);
 	clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
+
+reset_complete:
 	return PCI_ERS_RESULT_RECOVERED;
 }
 
-- 
2.45.0

--------------------------------------------------------------
Intel Research and Development Ireland Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263


This e-mail and any attachments may contain confidential material for the sole
use of the intended recipient(s). Any review or distribution by others is
strictly prohibited. If you are not the intended recipient, please contact the
sender and delete all copies.


^ permalink raw reply related

* [PATCH 3/6] crypto: qat - centralize bus master enable
From: Ahsan Atta @ 2026-05-13 15:16 UTC (permalink / raw)
  To: herbert
  Cc: linux-crypto, qat-linux, Ahsan Atta, stable, Giovanni Cabiddu,
	Andy Shevchenko
In-Reply-To: <cover.1778685152.git.ahsan.atta@intel.com>

QAT driver currently toggles PCI bus mastering in multiple places
(probe paths, and reset callbacks). This makes BME state depend on
call ordering and on what PCI command bits were captured in saved PCI
config state.

Make BME control explicit and deterministic:
- remove pci_set_master() from device-specific probe paths
- add adf_set_bme() and call it from adf_dev_init() so BME is enabled
  at one point before device bring-up
- drop redundant pci_set_master() and pci_clear_master from adf_aer.c
  and rely on the unified init path for BME enablement

This is in preparation for adding reset_prepare() and reset_done()
hooks. In the PCI reset callback flow, the PCI core saves and
restores device configuration state around reset_prepare() and
reset_done(). This change is needed to ensure that we are able to
properly shutdown or reinitialize the device post sysfs triggered
resets.

Cc: stable@vger.kernel.org
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
 drivers/crypto/intel/qat/qat_420xx/adf_drv.c         |  2 --
 drivers/crypto/intel/qat/qat_4xxx/adf_drv.c          |  2 --
 drivers/crypto/intel/qat/qat_6xxx/adf_drv.c          |  2 --
 drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c         |  1 -
 drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c       |  1 -
 drivers/crypto/intel/qat/qat_c62x/adf_drv.c          |  1 -
 drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c        |  1 -
 drivers/crypto/intel/qat/qat_common/adf_aer.c        | 10 +++++++---
 drivers/crypto/intel/qat/qat_common/adf_common_drv.h |  1 +
 drivers/crypto/intel/qat/qat_common/adf_init.c       |  2 ++
 drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c      |  1 -
 drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c    |  1 -
 12 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
index 566adc0a2d11..265bd52778c5 100644
--- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
@@ -146,8 +146,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		}
 	}
 
-	pci_set_master(pdev);
-
 	if (pci_save_state(pdev)) {
 		dev_err(&pdev->dev, "Failed to save pci state.\n");
 		ret = -ENOMEM;
diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
index daca73651c14..681c4dd8f3d2 100644
--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
@@ -148,8 +148,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		}
 	}
 
-	pci_set_master(pdev);
-
 	if (pci_save_state(pdev)) {
 		dev_err(&pdev->dev, "Failed to save pci state.\n");
 		ret = -ENOMEM;
diff --git a/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c
index c52462a48c34..ab62b91ecb51 100644
--- a/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_6xxx/adf_drv.c
@@ -189,8 +189,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		}
 	}
 
-	pci_set_master(pdev);
-
 	/*
 	 * The PCI config space is saved at this point and will be restored
 	 * after a Function Level Reset (FLR) as the FLR does not completely
diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
index 7a59bca3242f..ded52744b4fc 100644
--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			goto out_err_free_reg;
 		}
 	}
-	pci_set_master(pdev);
 
 	if (pci_save_state(pdev)) {
 		dev_err(&pdev->dev, "Failed to save pci state\n");
diff --git a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
index 0881575f7670..e7600d284ed3 100644
--- a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			goto out_err_free_reg;
 		}
 	}
-	pci_set_master(pdev);
 	/* Completion for VF2PF request/response message exchange */
 	init_completion(&accel_dev->vf.msg_received);
 
diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
index 4972e52dd944..2ebff5855b01 100644
--- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			goto out_err_free_reg;
 		}
 	}
-	pci_set_master(pdev);
 
 	if (pci_save_state(pdev)) {
 		dev_err(&pdev->dev, "Failed to save pci state\n");
diff --git a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
index d3f728b9f2f2..91e148bb4870 100644
--- a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			goto out_err_free_reg;
 		}
 	}
-	pci_set_master(pdev);
 	/* Completion for VF2PF request/response message exchange */
 	init_completion(&accel_dev->vf.msg_received);
 
diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c
index 9c6bfb9fef80..365637e40439 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c
@@ -41,7 +41,6 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev,
 		accel_dev->hw_device->exit_arb(accel_dev);
 	}
 	adf_dev_restarting_notify(accel_dev);
-	pci_clear_master(pdev);
 	adf_dev_down(accel_dev);
 
 	return PCI_ERS_RESULT_NEED_RESET;
@@ -106,6 +105,13 @@ void adf_dev_restore(struct adf_accel_dev *accel_dev)
 	}
 }
 
+void adf_set_bme(struct adf_accel_dev *accel_dev)
+{
+	struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
+
+	pci_set_master(pdev);
+}
+
 static void adf_device_sriov_worker(struct work_struct *work)
 {
 	struct adf_sriov_dev_data *sriov_data =
@@ -198,8 +204,6 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev)
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 
-	if (!pdev->is_busmaster)
-		pci_set_master(pdev);
 	pci_restore_state(pdev);
 	res = adf_dev_up(accel_dev, false);
 	if (res && res != -EALREADY)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
index b9188ea9aa72..762a0b5e774a 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
@@ -77,6 +77,7 @@ extern const struct pci_error_handlers adf_err_handler;
 void adf_reset_sbr(struct adf_accel_dev *accel_dev);
 void adf_reset_flr(struct adf_accel_dev *accel_dev);
 void adf_dev_restore(struct adf_accel_dev *accel_dev);
+void adf_set_bme(struct adf_accel_dev *accel_dev);
 int adf_init_aer(void);
 void adf_exit_aer(void);
 int adf_init_arb(struct adf_accel_dev *accel_dev);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c
index f8088388cf12..f9f5696ed476 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_init.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_init.c
@@ -74,6 +74,8 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev)
 		return -EFAULT;
 	}
 
+	adf_set_bme(accel_dev);
+
 	if (!test_bit(ADF_STATUS_CONFIGURED, &accel_dev->status) &&
 	    !accel_dev->is_vf) {
 		dev_err(&GET_DEV(accel_dev), "Device not configured\n");
diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
index 8a863d7d86d7..97ad53eef38f 100644
--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			goto out_err_free_reg;
 		}
 	}
-	pci_set_master(pdev);
 
 	if (pci_save_state(pdev)) {
 		dev_err(&pdev->dev, "Failed to save pci state\n");
diff --git a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
index f8a6e10a1de7..a5edda8bad32 100644
--- a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			goto out_err_free_reg;
 		}
 	}
-	pci_set_master(pdev);
 	/* Completion for VF2PF request/response message exchange */
 	init_completion(&accel_dev->vf.msg_received);
 
-- 
2.45.0

--------------------------------------------------------------
Intel Research and Development Ireland Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263


This e-mail and any attachments may contain confidential material for the sole
use of the intended recipient(s). Any review or distribution by others is
strictly prohibited. If you are not the intended recipient, please contact the
sender and delete all copies.


^ permalink raw reply related

* [PATCH 2/6] crypto: qat - notify fatal error before AER reset preparation
From: Ahsan Atta @ 2026-05-13 15:16 UTC (permalink / raw)
  To: herbert
  Cc: linux-crypto, qat-linux, Ahsan Atta, stable, Giovanni Cabiddu,
	Damian Muszynski
In-Reply-To: <cover.1778685152.git.ahsan.atta@intel.com>

Send fatal error notifications to subsystems and VFs as soon as
AER error detection starts, before entering the reset preparation
shutdown sequence.

This reduces notification latency and ensures peers are informed
immediately on fatal detection, rather than after restart-state setup
and arbitration teardown.

Cc: stable@vger.kernel.org
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Damian Muszynski <damian.muszynski@intel.com>
---
 drivers/crypto/intel/qat/qat_common/adf_aer.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c
index ed01fb9ad74e..9c6bfb9fef80 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c
@@ -33,13 +33,13 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev,
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 
+	adf_error_notifier(accel_dev);
+	adf_pf2vf_notify_fatal_error(accel_dev);
 	set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
 	if (accel_dev->hw_device->exit_arb) {
 		dev_dbg(&pdev->dev, "Disabling arbitration\n");
 		accel_dev->hw_device->exit_arb(accel_dev);
 	}
-	adf_error_notifier(accel_dev);
-	adf_pf2vf_notify_fatal_error(accel_dev);
 	adf_dev_restarting_notify(accel_dev);
 	pci_clear_master(pdev);
 	adf_dev_down(accel_dev);
-- 
2.45.0

--------------------------------------------------------------
Intel Research and Development Ireland Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263


This e-mail and any attachments may contain confidential material for the sole
use of the intended recipient(s). Any review or distribution by others is
strictly prohibited. If you are not the intended recipient, please contact the
sender and delete all copies.


^ permalink raw reply related

* [PATCH 1/6] crypto: qat - keep VFs enabled during reset
From: Ahsan Atta @ 2026-05-13 15:16 UTC (permalink / raw)
  To: herbert
  Cc: linux-crypto, qat-linux, Ahsan Atta, stable, Giovanni Cabiddu,
	Damian Muszynski
In-Reply-To: <cover.1778685152.git.ahsan.atta@intel.com>

When a reset is triggered via sysfs, the PCI core invokes the
reset_prepare() callback while holding pci_dev_lock(), which includes
the PCI configuration space access semaphore. If reset_prepare() calls
adf_dev_down(), the call chain adf_dev_stop() -> adf_disable_sriov()
-> pci_disable_sriov() attempts to acquire the same semaphore,
resulting in a deadlock.

Avoid this by skipping pci_disable_sriov() when ADF_STATUS_RESTARTING
is set. During reset the PCI topology is preserved, so VF devices
remain valid and enumerated across the reset. VF notification and the
quiesce handshake via adf_pf2vf_notify_restarting() are still
performed unconditionally so that VFs stop submitting work before the
PF shuts down.

Correspondingly, skip pci_enable_sriov() in adf_enable_sriov() when
VFs are already present, since their PCI devices were preserved from
before the restart.

This is in preparation for adding reset_prepare() and reset_done()
callbacks in adf_aer.c.

Cc: stable@vger.kernel.org
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Damian Muszynski <damian.muszynski@intel.com>
---
 drivers/crypto/intel/qat/qat_common/adf_sriov.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c
index 96939572109e..f2011300a929 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c
@@ -91,6 +91,10 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev)
 	/* Enable VF to PF interrupts for all VFs */
 	adf_enable_all_vf2pf_interrupts(accel_dev, totalvfs);
 
+	/* Do not enable SR-IOV if already enabled */
+	if (pci_num_vf(pdev))
+		return 0;
+
 	/*
 	 * Due to the hardware design, when SR-IOV and the ring arbiter
 	 * are enabled all the VFs supported in hardware must be enabled in
@@ -260,7 +264,13 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev)
 
 	adf_pf2vf_notify_restarting(accel_dev);
 	adf_pf2vf_wait_for_restarting_complete(accel_dev);
-	pci_disable_sriov(accel_to_pci_dev(accel_dev));
+	/*
+	 * When the device is restarting, preserve VF PCI devices across
+	 * the reset by skipping pci_disable_sriov(). VFs are notified to
+	 * quiesce regardless so the PF can safely shut down.
+	 */
+	if (!test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
+		pci_disable_sriov(accel_to_pci_dev(accel_dev));
 
 	/* Block VF2PF work and disable VF to PF interrupts */
 	adf_disable_all_vf2pf_interrupts(accel_dev);
-- 
2.45.0

--------------------------------------------------------------
Intel Research and Development Ireland Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263


This e-mail and any attachments may contain confidential material for the sole
use of the intended recipient(s). Any review or distribution by others is
strictly prohibited. If you are not the intended recipient, please contact the
sender and delete all copies.


^ permalink raw reply related

* [PATCH 0/6] crypto: qat - add sysfs PCI reset support for QAT devices
From: Ahsan Atta @ 2026-05-13 15:16 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, qat-linux, Ahsan Atta

A PCI reset triggered through sysfs (/sys/bus/pci/devices/.../reset)
leaves QAT devices in an unusable state because the driver has never
implemented the reset_prepare() and reset_done() callbacks. The reset
proceeds without quiescing the device or restoring it afterward. This
series adds the missing sysfs reset support and fixes the deadlocks,
state-management issues, and corner cases that surface when the reset
path is actually exercised.

Note on stable backport:
Since this support was entirely absent rather than broken by a specific
commit, there is no individual Fixes tag that can be cited. We believe
this series warrants inclusion in stable to allow users to perform
standard PCI resets on QAT devices without rendering them
non-functional. We will need to revisit/retest when doing the backport
as the PCI core may have changed.

In summary:
Patch #1: Skip VF disable and enable during device restart when the VF
topology is already present. This avoids lock-order issues in PCI
reset callbacks while keeping VF quiesce notification intact.

Patch #2: Move fatal error notification earlier in the AER path. This
ensures subsystems and VFs are informed as soon as fatal error handling
begins.

Patch #3: Centralize PCI bus-master enable into a single init path.
Remove scattered pci_set_master()/pci_clear_master() calls so BME
state is deterministic across reset flows.

Patch #4: Skip the shutdown and restart flow for devices that were
already administratively down before PCI reset. PCI state is still
restored, but the device remains down as expected.

Patch #5: Factor the common AER shutdown and recovery sequences into
reset_prepare() and reset_done() helpers to simplify the reset path
and prepare it for reuse.

Patch #6: Hook reset_prepare() and reset_done() into the QAT PCI error
handler. This makes sysfs-triggered PCI reset follow the same quiesce
and recovery flow as AER reset.

Ahsan Atta (6):
  crypto: qat - keep VFs enabled during reset
  crypto: qat - notify fatal error before AER reset preparation
  crypto: qat - centralize bus master enable
  crypto: qat - skip restart for down devices
  crypto: qat - factor out AER reset helpers
  crypto: qat - handle sysfs-triggered reset callbacks

 drivers/crypto/intel/qat/qat_420xx/adf_drv.c  |   2 -
 drivers/crypto/intel/qat/qat_4xxx/adf_drv.c   |   2 -
 drivers/crypto/intel/qat/qat_6xxx/adf_drv.c   |   2 -
 drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c  |   1 -
 .../crypto/intel/qat/qat_c3xxxvf/adf_drv.c    |   1 -
 drivers/crypto/intel/qat/qat_c62x/adf_drv.c   |   1 -
 drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c |   1 -
 drivers/crypto/intel/qat/qat_common/adf_aer.c | 102 +++++++++++++-----
 .../intel/qat/qat_common/adf_common_drv.h     |   1 +
 .../crypto/intel/qat/qat_common/adf_init.c    |   2 +
 .../crypto/intel/qat/qat_common/adf_sriov.c   |  12 ++-
 .../crypto/intel/qat/qat_dh895xcc/adf_drv.c   |   1 -
 .../crypto/intel/qat/qat_dh895xccvf/adf_drv.c |   1 -
 13 files changed, 87 insertions(+), 42 deletions(-)


base-commit: 6a69430dcc874c47fe5a25b70d87861c1cc9c0d8
-- 
2.45.0

--------------------------------------------------------------
Intel Research and Development Ireland Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263


This e-mail and any attachments may contain confidential material for the sole
use of the intended recipient(s). Any review or distribution by others is
strictly prohibited. If you are not the intended recipient, please contact the
sender and delete all copies.


^ permalink raw reply

* Re: [PATCH 10/16] clk: Add support for clock nexus dt bindings
From: Frank Li @ 2026-05-13 15:05 UTC (permalink / raw)
  To: Miquel Raynal (Schneider Electric)
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Thomas Gleixner, Olivia Mackall, Herbert Xu,
	Jayesh Choudhary, David S. Miller, Christian Marangi,
	Antoine Tenart, Geert Uytterhoeven, Magnus Damm, Thomas Petazzoni,
	Pascal EBERHARD, Wolfram Sang, linux-clk, devicetree,
	linux-kernel, linux-crypto, linux-renesas-soc, Herve Codina
In-Reply-To: <20260327-schneider-v7-0-rc1-crypto-v1-10-5e6ff7853994@bootlin.com>

On Fri, Mar 27, 2026 at 09:09:32PM +0100, Miquel Raynal (Schneider Electric) wrote:
> A nexus node is some kind of parent device abstracting the outer
> connections. They are particularly useful for describing connectors-like
> interfaces but not only. Certain IP blocks will typically include inner
> blocks and distribute resources to them.
>
> In the case of clocks, there is already the concept of clock controller,
> but this usually indicates some kind of control over the said clock,
> ie. gate or rate control. When there is none of this, an existing
> approach is to reference the upper clock, which is wrong from a hardware
> point of view.
>
> Nexus nodes are already part of the device-tree specification and clocks
> are already mentioned:
> https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter2-devicetree-basics.rst#nexus-nodes-and-specifier-mapping
>
> Following the introductions of nexus nodes support for interrupts, gpios
> and pwms, here is the same logic applied again to the clk subsystem,
> just by transitioning from of_parse_phandle_with_args() to
> of_parse_phandle_with_args_map():
>
> * Nexus OF support:
> commit bd6f2fd5a1d5 ("of: Support parsing phandle argument lists through a nexus node")
> * GPIO adoption:
> commit c11e6f0f04db ("gpio: Support gpio nexus dt bindings")
> * PWM adoption:
> commit e71e46a6f19c ("pwm: Add support for pwm nexus dt bindings")
>
> Expected Nexus properties supported:
> - clock-map: maps inner clocks to inlet clocks,
> - clock-map-mask: specifier cell(s) which will be remapped,
> - clock-map-pass-thru: specifier cell(s) not used for remapping,
>   forwarded as-is.
>
> In my own usage I had to deal with controllers where clock-map-mask and
> clock-map-pass-thru were not relevant, but here is a made up example
> showing how all these properties could go together:
>
> Example:
>     soc_clk: clock-controller {
>         #clock-cells = <2>;
>     };
>
>     container: container {
>         #clock-cells = <2>;
>         clock-map = <0 0 &soc_clk 2 0>,
>                     <1 0 &soc_clk 6 0>;
>         clock-map-mask = <0xffffffff 0x0>;
>         clock-map-pass-thru = <0x0 0xffffffff>;
>
>         child-device {
>             clocks = <&container 1 0>;
> 	    /* This is equivalent to <&soc_clk 6 0> */
>         };
>     };
>
> The child device does not need to know about the outer implementation,
> and only knows about what the nexus provides. The nexus acts as a
> pass-through, with no extra control.
>
> Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
> Reviewed-by: Herve Codina <herve.codina@bootlin.com>
> ---

Thanks.

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/clk/clk.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 93e33ff30f3a..196ba727e84b 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -5218,8 +5218,8 @@ static int of_parse_clkspec(const struct device_node *np, int index,
>  		 */
>  		if (name)
>  			index = of_property_match_string(np, "clock-names", name);
> -		ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells",
> -						 index, out_args);
> +		ret = of_parse_phandle_with_args_map(np, "clocks", "clock",
> +						     index, out_args);
>  		if (!ret)
>  			break;
>  		if (name && index >= 0)
>
> --
> 2.51.1
>

^ permalink raw reply

* [PATCH v2] crypto: qat - fix VF2PF work teardown race in adf_disable_sriov()
From: Giovanni Cabiddu @ 2026-05-13 14:47 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, qat-linux, Giovanni Cabiddu, stable, Ahsan Atta

The VF2PF interrupt handler queues PF-side response work that stores a
raw pointer to per-VF state (struct adf_accel_vf_info). Currently,
adf_disable_sriov() destroys per-VF mutexes and frees vf_info without
stopping new VF2PF work or waiting for in-flight workers to complete. A
concurrently scheduled or already queued worker can then dereference
freed memory.

This manifests as a use-after-free when KASAN is enabled:

  BUG: KASAN: null-ptr-deref in mutex_lock+0x76/0xe0
  Write of size 8 at addr 0000000000000260 by task kworker/24:2/...
  Workqueue: qat_pf2vf_resp_wq adf_iov_send_resp [intel_qat]
  Call Trace:
    kasan_report+0x119/0x140
    mutex_lock+0x76/0xe0
    adf_gen4_pfvf_send+0xd4/0x1f0 [intel_qat]
    adf_recv_and_handle_vf2pf_msg+0x290/0x360 [intel_qat]
    adf_iov_send_resp+0x8c/0xe0 [intel_qat]
    process_one_work+0x6ac/0xfd0
    worker_thread+0x4dd/0xd30
    kthread+0x326/0x410
    ret_from_fork+0x33b/0x670

Add a PF-local flag, vf2pf_disabled, that gates work queueing, worker
processing, and interrupt re-enabling during teardown. Set this flag
atomically with the hardware interrupt mask inside
adf_disable_all_vf2pf_interrupts(). After masking, synchronize the AE
cluster MSI-X interrupt and flush the PF response workqueue before
tearing down per-VF locks and state so all in-flight work completes
before vf_info is destroyed.

Introduce adf_enable_all_vf2pf_interrupts() to clear the flag and
unmask all VF2PF interrupts under the same lock when SR-IOV is
re-enabled. This ensures the software flag and hardware state transition
atomically on both the enable and disable paths.

Cc: stable@vger.kernel.org
Fixes: ed8ccaef52fa ("crypto: qat - Add support for SRIOV")
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Ahsan Atta <ahsan.atta@intel.com>
---
Changes since v1:
- Reworked the bail-out check in adf_enable_all_vf2pf_interrupts() to
  compute vf_mask first and check it instead of num_vfs.
- Removed the unreachable kfree() fallback in adf_schedule_vf2pf_handler().
  Since pf2vf_resp is freshly allocated and initialized via INIT_WORK(),
  queue_work() is guaranteed to return true for a work_struct that has
  never been queued.
- Replaced '>= 0' with '>0' after pci_irq_vector() to allow only for
  strictly positive IRQ vectors.

 .../intel/qat/qat_common/adf_accel_devices.h  |  2 +
 .../intel/qat/qat_common/adf_common_drv.h     |  2 +
 drivers/crypto/intel/qat/qat_common/adf_isr.c | 39 +++++++++++++++++++
 .../crypto/intel/qat/qat_common/adf_sriov.c   | 20 +++++++++-
 4 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
index 03a4e9690208..d9b2a1cf474e 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h
@@ -480,6 +480,8 @@ struct adf_accel_dev {
 		struct {
 			/* protects VF2PF interrupts access */
 			spinlock_t vf2pf_ints_lock;
+			/* prevents VF2PF handling from racing with VF state teardown */
+			bool vf2pf_disabled;
 			/* vf_info is non-zero when SR-IOV is init'ed */
 			struct adf_accel_vf_info *vf_info;
 		} pf;
diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
index a05d149423b0..b9188ea9aa72 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
@@ -110,6 +110,7 @@ void qat_comp_alg_callback(void *resp);
 
 int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev);
 void adf_isr_resource_free(struct adf_accel_dev *accel_dev);
+void adf_isr_sync_ae_cluster(struct adf_accel_dev *accel_dev);
 int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev);
 void adf_vf_isr_resource_free(struct adf_accel_dev *accel_dev);
 
@@ -183,6 +184,7 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs);
 void adf_disable_sriov(struct adf_accel_dev *accel_dev);
 void adf_reenable_sriov(struct adf_accel_dev *accel_dev);
 void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask);
+void adf_enable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 num_vfs);
 void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev);
 bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev);
 bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr);
diff --git a/drivers/crypto/intel/qat/qat_common/adf_isr.c b/drivers/crypto/intel/qat/qat_common/adf_isr.c
index 4639d7fd93e6..159e91a50106 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_isr.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_isr.c
@@ -62,6 +62,23 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)
 	unsigned long flags;
 
 	spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
+	if (!READ_ONCE(accel_dev->pf.vf2pf_disabled))
+		GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask);
+	spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
+}
+
+void adf_enable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 num_vfs)
+{
+	void __iomem *pmisc_addr = adf_get_pmisc_base(accel_dev);
+	unsigned long flags;
+	u32 vf_mask;
+
+	vf_mask = BIT_ULL(num_vfs) - 1;
+	if (!vf_mask)
+		return;
+
+	spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
+	WRITE_ONCE(accel_dev->pf.vf2pf_disabled, false);
 	GET_PFVF_OPS(accel_dev)->enable_vf2pf_interrupts(pmisc_addr, vf_mask);
 	spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
 }
@@ -72,6 +89,7 @@ void adf_disable_all_vf2pf_interrupts(struct adf_accel_dev *accel_dev)
 	unsigned long flags;
 
 	spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags);
+	WRITE_ONCE(accel_dev->pf.vf2pf_disabled, true);
 	GET_PFVF_OPS(accel_dev)->disable_all_vf2pf_interrupts(pmisc_addr);
 	spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags);
 }
@@ -174,6 +192,27 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr)
 	return IRQ_NONE;
 }
 
+void adf_isr_sync_ae_cluster(struct adf_accel_dev *accel_dev)
+{
+	struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
+	struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
+	u32 num_entries = pci_dev_info->msix_entries.num_entries;
+	struct adf_irq *irqs = pci_dev_info->msix_entries.irqs;
+	u32 irq_idx;
+	int irq;
+
+	if (!test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status) || !irqs)
+		return;
+
+	irq_idx = num_entries > 1 ? hw_data->num_banks : 0;
+	if (irq_idx >= num_entries || !irqs[irq_idx].enabled)
+		return;
+
+	irq = pci_irq_vector(pci_dev_info->pci_dev, hw_data->num_banks);
+	if (irq > 0)
+		synchronize_irq(irq);
+}
+
 static void adf_free_irqs(struct adf_accel_dev *accel_dev)
 {
 	struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev;
diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c
index 8bf0fe1fcb4d..96939572109e 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c
@@ -26,6 +26,9 @@ static void adf_iov_send_resp(struct work_struct *work)
 	u32 vf_nr = vf_info->vf_nr;
 	bool ret;
 
+	if (READ_ONCE(accel_dev->pf.vf2pf_disabled))
+		goto out;
+
 	mutex_lock(&vf_info->pfvf_mig_lock);
 	ret = adf_recv_and_handle_vf2pf_msg(accel_dev, vf_nr);
 	if (ret)
@@ -33,13 +36,18 @@ static void adf_iov_send_resp(struct work_struct *work)
 		adf_enable_vf2pf_interrupts(accel_dev, 1 << vf_nr);
 	mutex_unlock(&vf_info->pfvf_mig_lock);
 
+out:
 	kfree(pf2vf_resp);
 }
 
 void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info)
 {
+	struct adf_accel_dev *accel_dev = vf_info->accel_dev;
 	struct adf_pf2vf_resp *pf2vf_resp;
 
+	if (READ_ONCE(accel_dev->pf.vf2pf_disabled))
+		return;
+
 	pf2vf_resp = kzalloc_obj(*pf2vf_resp, GFP_ATOMIC);
 	if (!pf2vf_resp)
 		return;
@@ -49,6 +57,12 @@ void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info)
 	queue_work(pf2vf_resp_wq, &pf2vf_resp->pf2vf_resp_work);
 }
 
+static void adf_flush_pf2vf_resp_wq(void)
+{
+	if (pf2vf_resp_wq)
+		flush_workqueue(pf2vf_resp_wq);
+}
+
 static int adf_enable_sriov(struct adf_accel_dev *accel_dev)
 {
 	struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
@@ -75,7 +89,7 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev)
 		hw_data->configure_iov_threads(accel_dev, true);
 
 	/* Enable VF to PF interrupts for all VFs */
-	adf_enable_vf2pf_interrupts(accel_dev, BIT_ULL(totalvfs) - 1);
+	adf_enable_all_vf2pf_interrupts(accel_dev, totalvfs);
 
 	/*
 	 * Due to the hardware design, when SR-IOV and the ring arbiter
@@ -248,8 +262,10 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev)
 	adf_pf2vf_wait_for_restarting_complete(accel_dev);
 	pci_disable_sriov(accel_to_pci_dev(accel_dev));
 
-	/* Disable VF to PF interrupts */
+	/* Block VF2PF work and disable VF to PF interrupts */
 	adf_disable_all_vf2pf_interrupts(accel_dev);
+	adf_isr_sync_ae_cluster(accel_dev);
+	adf_flush_pf2vf_resp_wq();
 
 	/* Clear Valid bits in AE Thread to PCIe Function Mapping */
 	if (hw_data->configure_iov_threads)

base-commit: 1b0b8d04c100e162957c4615f6c37da0efbb6f91
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH net v2 2/4] crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks
From: Jeffrey E Altman @ 2026-05-13 14:33 UTC (permalink / raw)
  To: David Howells, netdev
  Cc: Hyunwoo Kim, Marc Dionne, Jakub Kicinski, David S. Miller,
	Eric Dumazet, Paolo Abeni, Simon Horman, linux-afs, linux-kernel,
	Herbert Xu, Chuck Lever, linux-nfs, linux-crypto, stable
In-Reply-To: <20260513131941.1439155-3-dhowells@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 8427 bytes --]

On 5/13/2026 9:19 AM, David Howells wrote:

> Change the krb5 crypto library to provide facilities to precheck the length
> of the message about to be decrypted or verified.
>
> Fix AF_RXRPC to make use of this to validate DATA packets secured with
> RxGK.
>
> Fixes: 9d1d2b59341f ("rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI)")
> Closes: https://sashiko.dev/#/patchset/20260511160753.607296-1-dhowells%40redhat.com
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Marc Dionne <marc.dionne@auristor.com>
> cc: Jeffrey Altman <jaltman@auristor.com>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: "David S. Miller" <davem@davemloft.net>
> cc: Eric Dumazet <edumazet@google.com>
> cc: Jakub Kicinski <kuba@kernel.org>
> cc: Paolo Abeni <pabeni@redhat.com>
> cc: Simon Horman <horms@kernel.org>
> cc: Chuck Lever <chuck.lever@oracle.com>
> cc: netdev@vger.kernel.org
> cc: linux-afs@lists.infradead.org
> cc: linux-nfs@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> cc: stable@vger.kernel.org
> ---
>   Documentation/crypto/krb5.rst | 17 ++++++++---
>   crypto/krb5/krb5_api.c        | 54 +++++++++++++++++++++++++++++++----
>   include/crypto/krb5.h         |  9 ++++--
>   include/trace/events/rxrpc.h  |  1 +
>   net/rxrpc/rxgk.c              | 11 +++++--
>   5 files changed, 77 insertions(+), 15 deletions(-)
>
> diff --git a/Documentation/crypto/krb5.rst b/Documentation/crypto/krb5.rst
> index beffa0133446..f62e07ac6811 100644
> --- a/Documentation/crypto/krb5.rst
> +++ b/Documentation/crypto/krb5.rst
> @@ -158,13 +158,22 @@ returned.
>   When a message has been received, the location and size of the data with the
>   message can be determined by calling::
>   
> -	void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
> -					   enum krb5_crypto_mode mode,
> -					   size_t *_offset, size_t *_len);
> +	int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
> +					  enum krb5_crypto_mode mode,
> +					  size_t *_offset, size_t *_len);
>   
>   The caller provides the offset and length of the message to the function, which
>   then alters those values to indicate the region containing the data (plus any
> -padding).  It is up to the caller to determine how much padding there is.
> +padding).  It is up to the caller to determine how much padding there is.  The
> +function returns an error if the length is too small or if the mode is
> +unsupported.  An additional function::
> +
> +	int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
> +				       enum krb5_crypto_mode mode,
> +				       size_t len, size_t min_content);
> +
> +is provided to just do a basic check that the decrypted/verified message would
> +have a sufficient minimum payload.
>   
>   Preparation Functions
>   ---------------------
> diff --git a/crypto/krb5/krb5_api.c b/crypto/krb5/krb5_api.c
> index 23026d4206c8..c7ea40f900a7 100644
> --- a/crypto/krb5/krb5_api.c
> +++ b/crypto/krb5/krb5_api.c
> @@ -134,27 +134,69 @@ EXPORT_SYMBOL(crypto_krb5_how_much_data);
>    * Find the offset and size of the data in a secure message so that this
>    * information can be used in the metadata buffer which will get added to the
>    * digest by crypto_krb5_verify_mic().
> + *
> + * Return: 0 if successful, -EBADMSG if the message is too short or -EINVAL if
> + * the mode is unsupported.
>    */
> -void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
> -				   enum krb5_crypto_mode mode,
> -				   size_t *_offset, size_t *_len)
> +int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
> +				  enum krb5_crypto_mode mode,
> +				  size_t *_offset, size_t *_len)
>   {
>   	switch (mode) {
>   	case KRB5_CHECKSUM_MODE:
> +		if (*_len < krb5->cksum_len)
> +			return -EBADMSG;
>   		*_offset += krb5->cksum_len;
>   		*_len -= krb5->cksum_len;
> -		return;
> +		return 0;
>   	case KRB5_ENCRYPT_MODE:
> +		if (*_len < krb5->conf_len + krb5->cksum_len)
> +			return -EBADMSG;
>   		*_offset += krb5->conf_len;
>   		*_len -= krb5->conf_len + krb5->cksum_len;
> -		return;
> +		return 0;
>   	default:
>   		WARN_ON_ONCE(1);
> -		return;
> +		return -EINVAL;
>   	}
>   }
>   EXPORT_SYMBOL(crypto_krb5_where_is_the_data);
>   
> +/**
> + * crypto_krb5_check_data_len - Check a message is big enough
> + * @krb5: The encoding to use.
> + * @mode: Mode of operation.
> + * @len: The length of the secure blob.
> + * @min_content: Minimum length of the content inside the blob.
> + *
> + * Check that a message is large enough to hold whatever bits the encryption
> + * type wants to glue on (nonce, checksum) plus a minimum amount of content.
> + *
> + * Return: 0 if successful, -EBADMSG if the message is too short or -EINVAL if
> + * the mode is unsupported.
> + */
> +int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
> +			       enum krb5_crypto_mode mode,
> +			       size_t len, size_t min_content)
> +{
> +	switch (mode) {
> +	case KRB5_CHECKSUM_MODE:
> +		if (len < krb5->cksum_len ||
> +		    len - krb5->cksum_len < min_content)
> +			return -EBADMSG;
> +		return 0;
> +	case KRB5_ENCRYPT_MODE:
> +		if (len < krb5->conf_len + krb5->cksum_len ||
> +		    len - (krb5->conf_len + krb5->cksum_len) < min_content)
> +			return -EBADMSG;
> +		return 0;
> +	default:
> +		WARN_ON_ONCE(1);
> +		return -EINVAL;
> +	}
> +}
> +EXPORT_SYMBOL(crypto_krb5_check_data_len);
> +
>   /*
>    * Prepare the encryption with derived key data.
>    */
> diff --git a/include/crypto/krb5.h b/include/crypto/krb5.h
> index 71dd38f59be1..aac3ecf88467 100644
> --- a/include/crypto/krb5.h
> +++ b/include/crypto/krb5.h
> @@ -121,9 +121,12 @@ size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,
>   size_t crypto_krb5_how_much_data(const struct krb5_enctype *krb5,
>   				 enum krb5_crypto_mode mode,
>   				 size_t *_buffer_size, size_t *_offset);
> -void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
> -				   enum krb5_crypto_mode mode,
> -				   size_t *_offset, size_t *_len);
> +int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
> +				  enum krb5_crypto_mode mode,
> +				  size_t *_offset, size_t *_len);
> +int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
> +			       enum krb5_crypto_mode mode,
> +			       size_t len, size_t min_content);
>   struct crypto_aead *crypto_krb5_prepare_encryption(const struct krb5_enctype *krb5,
>   						   const struct krb5_buffer *TK,
>   						   u32 usage, gfp_t gfp);
> diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
> index 573f2df3a2c9..704a10de6670 100644
> --- a/include/trace/events/rxrpc.h
> +++ b/include/trace/events/rxrpc.h
> @@ -71,6 +71,7 @@
>   	EM(rxkad_abort_resp_unknown_tkt,	"rxkad-resp-unknown-tkt") \
>   	EM(rxkad_abort_resp_version,		"rxkad-resp-version")	\
>   	/* RxGK security errors */					\
> +	EM(rxgk_abort_1_short_header,		"rxgk1-short-hdr")	\
>   	EM(rxgk_abort_1_verify_mic_eproto,	"rxgk1-vfy-mic-eproto")	\
>   	EM(rxgk_abort_2_decrypt_eproto,		"rxgk2-dec-eproto")	\
>   	EM(rxgk_abort_2_short_data,		"rxgk2-short-data")	\
> diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
> index 0d5e654da918..41180263e527 100644
> --- a/net/rxrpc/rxgk.c
> +++ b/net/rxrpc/rxgk.c
> @@ -480,8 +480,10 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call,
>   
>   	_enter("");
>   
> -	crypto_krb5_where_is_the_data(gk->krb5, KRB5_CHECKSUM_MODE,
> -				      &data_offset, &data_len);
> +	if (crypto_krb5_where_is_the_data(gk->krb5, KRB5_CHECKSUM_MODE,
> +					  &data_offset, &data_len) < 0)
> +		return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
> +					  rxgk_abort_1_short_header);
>   
>   	hdr = kzalloc_obj(*hdr, GFP_NOFS);
>   	if (!hdr)
> @@ -529,6 +531,11 @@ static int rxgk_verify_packet_encrypted(struct rxrpc_call *call,
>   
>   	_enter("");
>   
> +	if (crypto_krb5_check_data_len(gk->krb5, KRB5_ENCRYPT_MODE,
> +				       len, sizeof(*hdr)) < 0)
> +		return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
> +					  rxgk_abort_2_short_header);
> +
>   	ret = rxgk_decrypt_skb(gk->krb5, gk->rx_enc, skb, &offset, &len, &ac);
>   	if (ret < 0) {
>   		if (ret != -ENOMEM)

Reviewed-by: Jeffrey Altman <jaltman@auristor.com>



[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4467 bytes --]

^ permalink raw reply

* Re: [PATCH v2] crypto: ecc - Fix carry overflow in vli multiplication
From: Lukas Wunner @ 2026-05-13 14:31 UTC (permalink / raw)
  To: Anastasia Tishchenko
  Cc: Stefan Berger, Ignat Korchagin, Herbert Xu, David S . Miller,
	linux-crypto, linux-kernel, stable
In-Reply-To: <20260513105741.55534-1-sv3iry@gmail.com>

On Wed, May 13, 2026 at 01:57:40PM +0300, Anastasia Tishchenko wrote:
> The carry flag calculation fails when r01.m_high is saturated
> (0xFFFFFFFFFFFFFFFF) and addition of lower bits overflows.
> 
> The condition (r01.m_high < product.m_high) doesn't handle the case
> where r01.m_high == product.m_high and an additional carry exists
> from lower-bit overflow.
> 
> When commit 3c4b23901a0c ("crypto: ecdh - Add ECDH software support")
> introduced crypto/ecc.c, it split the muladd() function in the
> micro-ecc library into separate mul_64_64() and add_128_128() helpers.
> It seems the check got lost in translation.
> 
> Add proper handling for this boundary by accounting for the carry
> from the lower addition.
> 
> Fixes: 3c4b23901a0c ("crypto: ecdh - Add ECDH software support")
> Signed-off-by: Anastasia Tishchenko <sv3iry@gmail.com>
> Cc: stable@vger.kernel.org # v4.8+

Reviewed-by: Lukas Wunner <lukas@wunner.de>

^ permalink raw reply

* Re: [PATCH] crypto: af_alg - Document the deprecation of AF_ALG
From: Jeff Barnes @ 2026-05-13 14:29 UTC (permalink / raw)
  To: Ignat Korchagin
  Cc: Eric Biggers, Kamran Khan, Andy Lutomirski,
	linux-crypto@vger.kernel.org, Herbert Xu,
	linux-doc@vger.kernel.org, linux-api@vger.kernel.org,
	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	Linus Torvalds
In-Reply-To: <CAOs+rJUA+bz6Y2GKioHnFGFKX_uAP+4LaPRs=ZDgRQoUi4mWkg@mail.gmail.com>



On May 12 2026, at 5:18 pm, Ignat Korchagin <ignat@linux.win> wrote:

> On Mon, May 11, 2026 at 10:38 PM Eric Biggers <ebiggers@kernel.org> wrote:
>>  
>> On Mon, May 11, 2026 at 10:03:21PM +0100, Ignat Korchagin wrote:
>> > I don't think fully discounting hardware offloading is beneficial
>> here. HW
>> > accelerators will be produced and without a common interface
>> vendors would
>> > start implementing their own "bespoke" drivers with bespoke userspace
>> > interfaces (we already had such proposals), which in turn may
>> introduce more
>> > attack surface. Yes, AF_ALG needs substantial improvement, but at
>> least it
>> > can be a standardisation point.
>>  
>> That isn't the best way to accelerate symmetric crypto anymore though,
>> if it ever was.  This has been known for a long time.
>>  
>> > > In any case, any hypothetical security benefit provided by AF_ALG would
>> > > have to be *very high* to outweigh the continuous stream of
>> > > vulnerabilities in it.  I understand that people using AF_ALG
>> might not
>> > > be familiar with that continuous stream of vulnerabilities, but
>> it would
>> >
>> >
>> > Is it actually that much compared to other features/subsystems,
>> like eBPF or
>> > user namespaces? But we don't rush to deprecate those - instead
>> trying to
>> > harden them and come up with better design.
>>  
>> There are plenty of other kernel features with a large attack surface,
>> of course.  But they tend to be much more useful than AF_ALG.  It's all
>> about weighing benefits vs. risks.
>  
> If divide number of CVEs in such systems on imaginary units of
> usefulness, I think the ratio is similar.
>  
>> When we get the point where a large number of Linux users *had* to
>> disable AF_ALG as an emergency vulnerability response, and at the same
>> time their systems weren't even using AF_ALG so nothing even broke and
>> they could have just done that to begin with, I think we get a very
>  
> Well, there were: cryptsetup, RHEL fips check, so there are some...

cryptsetup does not have a hard dependency on AF_ALG.
It is a potential consumer via AF_ALG.

AF_ALG provides a broad, hard-to-control interface
cryptsetup (and similar tools) are not blockers

AF_ALG removal does not necessarily break cryptsetup usage. Removal does
improve FIPS boundary clarity.


>  
>> clear idea of which side is heavier for AF_ALG in the real world.
>  
> Same thing could be said for unprivileged user namespaces - distros
> even put a custom sysctl to restrict it and no-one noticed.
>  
>> The main relevance of AF_ALG to the Linux community is that it allows
>> their systems to be exploited.
>  
> To be clear I'm not arguing for the current AF_ALG implementation. I
> agree, the splice zero-copy is... suboptimal (to be soft) and is
> actually not-so-zero copy. But I think it was just added before we had
> more modern approaches like io_uring (have their own can of worms, but
> hey - people adopt it fast).
>  
> But I advocate for the usefulness of the concept itself - kernel/OS
> providing crypto services to userspace. As mentioned in other threads,
> other operating systems have it and Linux lags behind. There are use
> cases: common interface for HW accelerators, embedded systems, which
> don't have the space to bring a userspace lib etc. Even non-technical:
> there are environments that just don't want to rely on third-party
> userspace libraries like OpenSSL purely for licensing reasons. And I
> agree, that it is hard to do it right, but we can piggy-back on other
> subsystems (such as io_uring mentioned or other ideas).
>  
>> - Eric
>>  
>  
> Ignat
>  
Jeff

^ permalink raw reply

* Re: [PATCH v2] crypto: ecc - Fix carry overflow in vli multiplication
From: Lukas Wunner @ 2026-05-13 14:09 UTC (permalink / raw)
  To: Qingfang Deng
  Cc: Anastasia Tishchenko, Stefan Berger, Ignat Korchagin, Herbert Xu,
	David S. Miller, linux-crypto, linux-kernel, stable
In-Reply-To: <20260513123948.842-1-qingfang.deng@linux.dev>

On Wed, May 13, 2026 at 08:39:48PM +0800, Qingfang Deng wrote:
> On Wed, 13 May 2026 at 13:57:40 +0300, Anastasia Tishchenko wrote:
> > +++ b/crypto/ecc.c
> > @@ -393,14 +393,26 @@ static uint128_t mul_64_64(u64 left, u64 right)
> >  	return result;
> >  }
> >  
> > -static uint128_t add_128_128(uint128_t a, uint128_t b)
> > +/* Calculate addition with overflow checking. Returns true on wrap-around,
> > + * false otherwise.
> > + */
> > +static bool check_add_128_128_overflow(uint128_t *result, uint128_t a,
> > +				       uint128_t b)
> >  {
> > -	uint128_t result;
> > +	bool carry;
> >  
> > -	result.m_low = a.m_low + b.m_low;
> > -	result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
> > +	result->m_low = a.m_low + b.m_low;
> > +	carry = (result->m_low < a.m_low);
> >  
> > -	return result;
> > +	result->m_high = a.m_high + b.m_high + carry;
> 
> If CONFIG_ARCH_SUPPORTS_INT128 is defined, you can convert them to
> "unsigned __int128" as done in mul_64_64(), and use check_add_overflow()
> to get the carry.

Okay, but that would be a separate feature on top of this fix.
This fix applies to *all* architectures whereas using native
128-bit integers would only solve the problem on arches which
support such integers.

ARCH_SUPPORTS_INT128 actually depends on CC_HAS_INT128 on all arches
that support it (arm64, loongarch, riscv, s390, x86).  Interestingly,
s390 additionally requires CC_IS_CLANG.  Commit fbac266f095d ("s390:
select ARCH_SUPPORTS_INT128") explains that "gcc generates inefficient
code, which may lead to stack overflows" when handling 128-bit integers.
It goes on to say: "The gcc generated functions have 6kb stack frames,
compared to only 1kb of the code generated with clang."

That reminds me of the high stack usage issue we're seeing when compiling
crypto/ecc.c on arm 32-bit:

https://lore.kernel.org/r/7e3d64a53efb28740b32d1f934e78c10086208ab.1778073318.git.lukas@wunner.de/

I'm fine with adding native 128-bit usage to check_add_128_128_overflow()
on top of this fix if somebody wants to submit a patch.  But I suspect
it might only actually be useful on s390 with clang.

Thanks,

Lukas

^ permalink raw reply

* [PATCH net v2 2/4] crypto/krb5, rxrpc: Fix lack of pre-decrypt/pre-verify length checks
From: David Howells @ 2026-05-13 13:19 UTC (permalink / raw)
  To: netdev
  Cc: David Howells, Hyunwoo Kim, Marc Dionne, Jakub Kicinski,
	David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
	linux-afs, linux-kernel, Jeffrey Altman, Herbert Xu, Chuck Lever,
	linux-nfs, linux-crypto, stable
In-Reply-To: <20260513131941.1439155-1-dhowells@redhat.com>

Change the krb5 crypto library to provide facilities to precheck the length
of the message about to be decrypted or verified.

Fix AF_RXRPC to make use of this to validate DATA packets secured with
RxGK.

Fixes: 9d1d2b59341f ("rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI)")
Closes: https://sashiko.dev/#/patchset/20260511160753.607296-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: "David S. Miller" <davem@davemloft.net>
cc: Eric Dumazet <edumazet@google.com>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: Chuck Lever <chuck.lever@oracle.com>
cc: netdev@vger.kernel.org
cc: linux-afs@lists.infradead.org
cc: linux-nfs@vger.kernel.org
cc: linux-crypto@vger.kernel.org
cc: stable@vger.kernel.org
---
 Documentation/crypto/krb5.rst | 17 ++++++++---
 crypto/krb5/krb5_api.c        | 54 +++++++++++++++++++++++++++++++----
 include/crypto/krb5.h         |  9 ++++--
 include/trace/events/rxrpc.h  |  1 +
 net/rxrpc/rxgk.c              | 11 +++++--
 5 files changed, 77 insertions(+), 15 deletions(-)

diff --git a/Documentation/crypto/krb5.rst b/Documentation/crypto/krb5.rst
index beffa0133446..f62e07ac6811 100644
--- a/Documentation/crypto/krb5.rst
+++ b/Documentation/crypto/krb5.rst
@@ -158,13 +158,22 @@ returned.
 When a message has been received, the location and size of the data with the
 message can be determined by calling::
 
-	void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
-					   enum krb5_crypto_mode mode,
-					   size_t *_offset, size_t *_len);
+	int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
+					  enum krb5_crypto_mode mode,
+					  size_t *_offset, size_t *_len);
 
 The caller provides the offset and length of the message to the function, which
 then alters those values to indicate the region containing the data (plus any
-padding).  It is up to the caller to determine how much padding there is.
+padding).  It is up to the caller to determine how much padding there is.  The
+function returns an error if the length is too small or if the mode is
+unsupported.  An additional function::
+
+	int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
+				       enum krb5_crypto_mode mode,
+				       size_t len, size_t min_content);
+
+is provided to just do a basic check that the decrypted/verified message would
+have a sufficient minimum payload.
 
 Preparation Functions
 ---------------------
diff --git a/crypto/krb5/krb5_api.c b/crypto/krb5/krb5_api.c
index 23026d4206c8..c7ea40f900a7 100644
--- a/crypto/krb5/krb5_api.c
+++ b/crypto/krb5/krb5_api.c
@@ -134,27 +134,69 @@ EXPORT_SYMBOL(crypto_krb5_how_much_data);
  * Find the offset and size of the data in a secure message so that this
  * information can be used in the metadata buffer which will get added to the
  * digest by crypto_krb5_verify_mic().
+ *
+ * Return: 0 if successful, -EBADMSG if the message is too short or -EINVAL if
+ * the mode is unsupported.
  */
-void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
-				   enum krb5_crypto_mode mode,
-				   size_t *_offset, size_t *_len)
+int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
+				  enum krb5_crypto_mode mode,
+				  size_t *_offset, size_t *_len)
 {
 	switch (mode) {
 	case KRB5_CHECKSUM_MODE:
+		if (*_len < krb5->cksum_len)
+			return -EBADMSG;
 		*_offset += krb5->cksum_len;
 		*_len -= krb5->cksum_len;
-		return;
+		return 0;
 	case KRB5_ENCRYPT_MODE:
+		if (*_len < krb5->conf_len + krb5->cksum_len)
+			return -EBADMSG;
 		*_offset += krb5->conf_len;
 		*_len -= krb5->conf_len + krb5->cksum_len;
-		return;
+		return 0;
 	default:
 		WARN_ON_ONCE(1);
-		return;
+		return -EINVAL;
 	}
 }
 EXPORT_SYMBOL(crypto_krb5_where_is_the_data);
 
+/**
+ * crypto_krb5_check_data_len - Check a message is big enough
+ * @krb5: The encoding to use.
+ * @mode: Mode of operation.
+ * @len: The length of the secure blob.
+ * @min_content: Minimum length of the content inside the blob.
+ *
+ * Check that a message is large enough to hold whatever bits the encryption
+ * type wants to glue on (nonce, checksum) plus a minimum amount of content.
+ *
+ * Return: 0 if successful, -EBADMSG if the message is too short or -EINVAL if
+ * the mode is unsupported.
+ */
+int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
+			       enum krb5_crypto_mode mode,
+			       size_t len, size_t min_content)
+{
+	switch (mode) {
+	case KRB5_CHECKSUM_MODE:
+		if (len < krb5->cksum_len ||
+		    len - krb5->cksum_len < min_content)
+			return -EBADMSG;
+		return 0;
+	case KRB5_ENCRYPT_MODE:
+		if (len < krb5->conf_len + krb5->cksum_len ||
+		    len - (krb5->conf_len + krb5->cksum_len) < min_content)
+			return -EBADMSG;
+		return 0;
+	default:
+		WARN_ON_ONCE(1);
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(crypto_krb5_check_data_len);
+
 /*
  * Prepare the encryption with derived key data.
  */
diff --git a/include/crypto/krb5.h b/include/crypto/krb5.h
index 71dd38f59be1..aac3ecf88467 100644
--- a/include/crypto/krb5.h
+++ b/include/crypto/krb5.h
@@ -121,9 +121,12 @@ size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,
 size_t crypto_krb5_how_much_data(const struct krb5_enctype *krb5,
 				 enum krb5_crypto_mode mode,
 				 size_t *_buffer_size, size_t *_offset);
-void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
-				   enum krb5_crypto_mode mode,
-				   size_t *_offset, size_t *_len);
+int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
+				  enum krb5_crypto_mode mode,
+				  size_t *_offset, size_t *_len);
+int crypto_krb5_check_data_len(const struct krb5_enctype *krb5,
+			       enum krb5_crypto_mode mode,
+			       size_t len, size_t min_content);
 struct crypto_aead *crypto_krb5_prepare_encryption(const struct krb5_enctype *krb5,
 						   const struct krb5_buffer *TK,
 						   u32 usage, gfp_t gfp);
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 573f2df3a2c9..704a10de6670 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -71,6 +71,7 @@
 	EM(rxkad_abort_resp_unknown_tkt,	"rxkad-resp-unknown-tkt") \
 	EM(rxkad_abort_resp_version,		"rxkad-resp-version")	\
 	/* RxGK security errors */					\
+	EM(rxgk_abort_1_short_header,		"rxgk1-short-hdr")	\
 	EM(rxgk_abort_1_verify_mic_eproto,	"rxgk1-vfy-mic-eproto")	\
 	EM(rxgk_abort_2_decrypt_eproto,		"rxgk2-dec-eproto")	\
 	EM(rxgk_abort_2_short_data,		"rxgk2-short-data")	\
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index 0d5e654da918..41180263e527 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -480,8 +480,10 @@ static int rxgk_verify_packet_integrity(struct rxrpc_call *call,
 
 	_enter("");
 
-	crypto_krb5_where_is_the_data(gk->krb5, KRB5_CHECKSUM_MODE,
-				      &data_offset, &data_len);
+	if (crypto_krb5_where_is_the_data(gk->krb5, KRB5_CHECKSUM_MODE,
+					  &data_offset, &data_len) < 0)
+		return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
+					  rxgk_abort_1_short_header);
 
 	hdr = kzalloc_obj(*hdr, GFP_NOFS);
 	if (!hdr)
@@ -529,6 +531,11 @@ static int rxgk_verify_packet_encrypted(struct rxrpc_call *call,
 
 	_enter("");
 
+	if (crypto_krb5_check_data_len(gk->krb5, KRB5_ENCRYPT_MODE,
+				       len, sizeof(*hdr)) < 0)
+		return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
+					  rxgk_abort_2_short_header);
+
 	ret = rxgk_decrypt_skb(gk->krb5, gk->rx_enc, skb, &offset, &len, &ac);
 	if (ret < 0) {
 		if (ret != -ENOMEM)


^ permalink raw reply related

* Re: [PATCH v2] crypto: ecc - Fix carry overflow in vli multiplication
From: Qingfang Deng @ 2026-05-13 12:39 UTC (permalink / raw)
  To: Anastasia Tishchenko
  Cc: Lukas Wunner, Stefan Berger, Ignat Korchagin, Herbert Xu,
	David S. Miller, linux-crypto, linux-kernel, stable
In-Reply-To: <20260513105741.55534-1-sv3iry@gmail.com>

On Wed, 13 May 2026 at 13:57:40 +0300, Anastasia Tishchenko wrote:
> diff --git a/crypto/ecc.c b/crypto/ecc.c
> index 43b0def3a225..6eb4d97a5f0d 100644
> --- a/crypto/ecc.c
> +++ b/crypto/ecc.c
> @@ -393,14 +393,26 @@ static uint128_t mul_64_64(u64 left, u64 right)
>  	return result;
>  }
>  
> -static uint128_t add_128_128(uint128_t a, uint128_t b)
> +/* Calculate addition with overflow checking. Returns true on wrap-around,
> + * false otherwise.
> + */
> +static bool check_add_128_128_overflow(uint128_t *result, uint128_t a,
> +				       uint128_t b)
>  {
> -	uint128_t result;
> +	bool carry;
>  
> -	result.m_low = a.m_low + b.m_low;
> -	result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
> +	result->m_low = a.m_low + b.m_low;
> +	carry = (result->m_low < a.m_low);
>  
> -	return result;
> +	result->m_high = a.m_high + b.m_high + carry;

If CONFIG_ARCH_SUPPORTS_INT128 is defined, you can convert them to
"unsigned __int128" as done in mul_64_64(), and use check_add_overflow()
to get the carry.

> +
> +	/* Using constant-time bitwise arithmetic to prevent timing
> +	 * side-channels.
> +	 */
> +	carry = (result->m_high < a.m_high) |
> +		((result->m_high == a.m_high) & carry);
> +
> +	return carry;
>  }
>  

Regards,
Qingfang

^ permalink raw reply

* [PATCH v2] crypto: ecc - Fix carry overflow in vli multiplication
From: Anastasia Tishchenko @ 2026-05-13 10:57 UTC (permalink / raw)
  To: Lukas Wunner, Stefan Berger
  Cc: Ignat Korchagin, Herbert Xu, David S . Miller, linux-crypto,
	linux-kernel, Anastasia Tishchenko, stable

The carry flag calculation fails when r01.m_high is saturated
(0xFFFFFFFFFFFFFFFF) and addition of lower bits overflows.

The condition (r01.m_high < product.m_high) doesn't handle the case
where r01.m_high == product.m_high and an additional carry exists
from lower-bit overflow.

When commit 3c4b23901a0c ("crypto: ecdh - Add ECDH software support")
introduced crypto/ecc.c, it split the muladd() function in the
micro-ecc library into separate mul_64_64() and add_128_128() helpers.
It seems the check got lost in translation.

Add proper handling for this boundary by accounting for the carry
from the lower addition.

Fixes: 3c4b23901a0c ("crypto: ecdh - Add ECDH software support")
Signed-off-by: Anastasia Tishchenko <sv3iry@gmail.com>
Cc: stable@vger.kernel.org # v4.8+
---
Changes v1 -> v2:
* Rename add_128_128() to check_add_128_128_overflow() and let it return a bool
  indicating whether an overflow occurred
* Rewrite an explicit if-else statement using constant-time bitwise arithmetic
  to avoid a timing side-channel

Link to v1:
https://lore.kernel.org/r/20260508114844.29694-1-sv3iry@gmail.com/
---
 crypto/ecc.c | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index 43b0def3a225..6eb4d97a5f0d 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -393,14 +393,26 @@ static uint128_t mul_64_64(u64 left, u64 right)
 	return result;
 }
 
-static uint128_t add_128_128(uint128_t a, uint128_t b)
+/* Calculate addition with overflow checking. Returns true on wrap-around,
+ * false otherwise.
+ */
+static bool check_add_128_128_overflow(uint128_t *result, uint128_t a,
+				       uint128_t b)
 {
-	uint128_t result;
+	bool carry;
 
-	result.m_low = a.m_low + b.m_low;
-	result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
+	result->m_low = a.m_low + b.m_low;
+	carry = (result->m_low < a.m_low);
 
-	return result;
+	result->m_high = a.m_high + b.m_high + carry;
+
+	/* Using constant-time bitwise arithmetic to prevent timing
+	 * side-channels.
+	 */
+	carry = (result->m_high < a.m_high) |
+		((result->m_high == a.m_high) & carry);
+
+	return carry;
 }
 
 static void vli_mult(u64 *result, const u64 *left, const u64 *right,
@@ -425,9 +437,7 @@ static void vli_mult(u64 *result, const u64 *left, const u64 *right,
 			uint128_t product;
 
 			product = mul_64_64(left[i], right[k - i]);
-
-			r01 = add_128_128(r01, product);
-			r2 += (r01.m_high < product.m_high);
+			r2 += check_add_128_128_overflow(&r01, r01, product);
 		}
 
 		result[k] = r01.m_low;
@@ -450,7 +460,7 @@ static void vli_umult(u64 *result, const u64 *left, u32 right,
 		uint128_t product;
 
 		product = mul_64_64(left[k], right);
-		r01 = add_128_128(r01, product);
+		check_add_128_128_overflow(&r01, r01, product);
 		/* no carry */
 		result[k] = r01.m_low;
 		r01.m_low = r01.m_high;
@@ -487,8 +497,7 @@ static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
 				product.m_low <<= 1;
 			}
 
-			r01 = add_128_128(r01, product);
-			r2 += (r01.m_high < product.m_high);
+			r2 += check_add_128_128_overflow(&r01, r01, product);
 		}
 
 		result[k] = r01.m_low;
-- 
2.43.0


^ permalink raw reply related

* Re: FAILED: patch "[PATCH] lib/crypto: mpi: Fix integer underflow in" failed to apply to 6.1-stable tree
From: Greg KH @ 2026-05-13 10:34 UTC (permalink / raw)
  To: Eric Biggers; +Cc: lukas, ignat, jarkko, yimingqian591, stable, linux-crypto
In-Reply-To: <20260513025130.GA3110@sol>

On Tue, May 12, 2026 at 07:51:30PM -0700, Eric Biggers wrote:
> [+Cc linux-crypto@vger.kernel.org]
> 
> On Tue, May 12, 2026 at 04:01:23PM +0200, gregkh@linuxfoundation.org wrote:
> > 
> > The patch below does not apply to the 6.1-stable tree.
> > If someone wants it applied there, or to any other stable or longterm
> > tree, then please email the backport, including the original git commit
> > id to <stable@vger.kernel.org>.
> > 
> > To reproduce the conflict and resubmit, you may use the following commands:
> > 
> > git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
> > git checkout FETCH_HEAD
> > git cherry-pick -x 8c2f1288250a90a4b5cabed5d888d7e3aeed4035
> > # <resolve conflicts, build, test, etc.>
> > git commit -s
> > git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026051223-undercoat-reps-6626@gregkh' --subject-prefix 'PATCH 6.1.y' HEAD^..
> > 
> > Possible dependencies:
> 
> A couple issues.  First, this email wasn't sent to the subsystem's
> mailing list (linux-crypto@vger.kernel.org in this case).  That greatly
> reduces the number of people who are made aware that this didn't get
> automatically backported.

We never send out these FAILED emails to the mailing lists, as that
would make just even more noise.  It's always been this way, sorry.

> Second, the upstream commit cherry-picks to 6.1, 5.15, and 5.10 without
> conflict.  (The file being changed was renamed between 6.1 and 6.6, but
> 'git cherry-pick' handles that automatically.)
> 
> I don't know what you're doing exactly that caused it to be
> unnecessarily marked as FAILED.  But whatever it is, it's not working,
> and it is causing backports to be missed.

We don't use git for cherry-picking as we have a patch queue, so renames
will often times fail, like it did here.  This has always been the case
in the decades we have been running the stable kernels :)

thanks,

greg k-h

^ permalink raw reply

* [PATCH] hwrng: core - Do not read data during PM sleep transition
From: Thomas Richard (TI) @ 2026-05-13  9:27 UTC (permalink / raw)
  To: Olivia Mackall, Herbert Xu
  Cc: Thomas Petazzoni, linux-crypto, linux-kernel, gregory.clement,
	richard.genoud, u-kumar1, a-kumar2, Thomas Richard (TI)

The hwrng_fillfn() kernel thread accesses the RNG device directly. During
suspend and resume sequences, hwrng_fillfn() may attempt to access the RNG
device while it is suspended. To address this, the hwrng_fillfn() kernel
thread checks if a PM sleep transition is in progress before to access the
RNG device.

Issue was found while doing suspend-to-ram on J72S2 EVM board with omap-rng
driver.

echo mem > /sys/power/state
[   27.922259] PM: suspend entry (deep)
[   27.927191] Filesystems sync: 0.000 seconds
[   27.933858] Freezing user space processes
[   27.939119] Freezing user space processes completed (elapsed 0.001 seconds)
[   27.946090] OOM killer disabled.
[   27.949315] Freezing remaining freezable tasks
[   27.954887] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[   27.963337] GFP mask restricted
[   27.967069] omap_rng 4e10000.rng: PM: calling platform_pm_suspend @ 195, parent: 4e00000.crypto
[   27.967072] mmcblk mmc1:9fb0: PM: calling mmc_bus_suspend @ 122, parent: mmc1
[   27.968636] mmcblk mmc1:9fb0: PM: mmc_bus_suspend returned 0 after 1546 usecs
[   27.975778] omap_rng 4e10000.rng: PM: platform_pm_suspend returned 0 after 3 usecs
...
[   33.510667] ti-sci 44083000.system-controller: PM: ti_sci_suspend_noirq returned 0 after 0 usecs
[   33.510671] SError Interrupt on CPU0, code 0x00000000bf000000 -- SError
[   33.510681] CPU: 0 UID: 0 PID: 132 Comm: hwrng Tainted: G   M    W           7.0.0-12695-g8923b7a6e11d #19 PREEMPT
[   33.510690] Tainted: [M]=MACHINE_CHECK, [W]=WARN
[   33.510693] Hardware name: Texas Instruments J721S2 EVM (DT)
[   33.510697] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[   33.510701] pc : omap_rng_do_read+0x3c/0xe0
[   33.510709] lr : omap_rng_do_read+0x58/0xe0
[   33.510712] sp : ffff80008942be00
[   33.510713] x29: ffff80008942be00 x28: 0000000000000000 x27: 0000000000000000
[   33.510719] x26: 0000000000000010 x25: 0000000000000010 x24: ffff0008065644e8
[   33.510724] x23: ffff8000878b3370 x22: ffff00080148b2c0 x21: 0000000000000000
[   33.510728] x20: ffff000806564480 x19: 0000000000000064 x18: 0000000000000000
[   33.510732] x17: 6573752031207265 x16: 7466612030206465 x15: 6e72757465722071
[   33.510737] x14: ffff0008062c8080 x13: 000031702bc0da42 x12: 0000000000000001
[   33.510741] x11: 00000000000000c0 x10: 0000000000000b30 x9 : ffff80008942bc80
[   33.510745] x8 : ffff0008062c8b90 x7 : ffff000b7dfa34c0 x6 : 0000000805ca16c1
[   33.510749] x5 : 0000000000000000 x4 : ffff800080e17bfc x3 : ffff800087389c68
[   33.510753] x2 : 0000000000000000 x1 : 0000000000000010 x0 : 000000000000a7c6
[   33.510759] Kernel panic - not syncing: Asynchronous SError Interrupt
[   33.510762] CPU: 0 UID: 0 PID: 132 Comm: hwrng Tainted: G   M    W           7.0.0-12695-g8923b7a6e11d #19 PREEMPT
[   33.510767] Tainted: [M]=MACHINE_CHECK, [W]=WARN
[   33.510768] Hardware name: Texas Instruments J721S2 EVM (DT)
[   33.510770] Call trace:
[   33.510772]  show_stack+0x18/0x24 (C)
[   33.510780]  dump_stack_lvl+0x34/0x8c
[   33.510788]  dump_stack+0x18/0x24
[   33.510792]  vpanic+0x47c/0x4dc
[   33.510799]  do_panic_on_target_cpu+0x0/0x1c
[   33.510803]  add_taint+0x0/0xbc
[   33.510807]  arm64_serror_panic+0x70/0x80
[   33.510812]  do_serror+0x3c/0x70
[   33.510815]  el1h_64_error_handler+0x34/0x50
[   33.510823]  el1h_64_error+0x6c/0x70
[   33.510827]  omap_rng_do_read+0x3c/0xe0 (P)
[   33.510831]  hwrng_fillfn+0x98/0x330
[   33.510834]  kthread+0x130/0x13c
[   33.510845]  ret_from_fork+0x10/0x20
[   33.510850] SMP: stopping secondary CPUs
[   33.519442] Kernel Offset: disabled
[   33.519444] CPU features: 0x04000000,800a0008,00040001,0400421b
[   33.519448] Memory Limit: none
[   33.732904] ---[ end Kernel panic - not syncing: Asynchronous SError Interrupt ]---

Signed-off-by: Thomas Richard (TI) <thomas.richard@bootlin.com>
---
This patch is related to the patch [1]. But it fixes the issue in a very
different way. Patch [1] set the hwrng_fillfn() kernel thread freezable,
but this solution was not acceptable as it could introduce an important
delay in the suspend sequence (up to 10s to freeze the freezable kernel
threads).

[1] https://lore.kernel.org/all/20260427-hw-random-set-hwrng-fillfn-kthread-freezable-v1-1-9bbe4f88b43a@bootlin.com/
---
 drivers/char/hw_random/core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index aba92d777f72..98178f903335 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -25,6 +25,7 @@
 #include <linux/sched/signal.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/suspend.h>
 #include <linux/uaccess.h>
 #include <linux/workqueue.h>
 
@@ -538,8 +539,9 @@ static int hwrng_fillfn(void *unused)
 		}
 
 		mutex_lock(&reading_mutex);
-		rc = rng_get_data(rng, rng_fillbuf,
-				  rng_buffer_size(), 1);
+		if (!pm_sleep_transition_in_progress())
+			rc = rng_get_data(rng, rng_fillbuf,
+					  rng_buffer_size(), 1);
 		if (current_quality != rng->quality)
 			rng->quality = current_quality; /* obsolete */
 		quality = rng->quality;

---
base-commit: f615e82f0b35c473499583a1432ade66060a02b2
change-id: 20260513-hw-random-fix-hwrng-fillfn-crash-suspend-resume-29fdb0638f59

Best regards,
-- 
Thomas Richard (TI) <thomas.richard@bootlin.com>


^ permalink raw reply related

* [PATCH] crypto: qat - remove MODULE_VERSION
From: Giovanni Cabiddu @ 2026-05-13  8:57 UTC (permalink / raw)
  To: herbert
  Cc: linux-crypto, qat-linux, Giovanni Cabiddu, Ahsan Atta,
	Andy Shevchenko

In-tree drivers do not need MODULE_VERSION as the kernel release
identifies the version of their code. The static version "0.6.0", which
the QAT drivers currently report, can be misleading as it might suggest
the drivers are outdated.

Remove MODULE_VERSION() from all QAT driver modules and the related
ADF_DRV_VERSION, ADF_MAJOR_VERSION, ADF_MINOR_VERSION and
ADF_BUILD_VERSION macros from adf_common_drv.h.

Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Ahsan Atta <ahsan.atta@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
 drivers/crypto/intel/qat/qat_420xx/adf_drv.c         | 1 -
 drivers/crypto/intel/qat/qat_4xxx/adf_drv.c          | 1 -
 drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c         | 1 -
 drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c       | 1 -
 drivers/crypto/intel/qat/qat_c62x/adf_drv.c          | 1 -
 drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c        | 1 -
 drivers/crypto/intel/qat/qat_common/adf_common_drv.h | 7 -------
 drivers/crypto/intel/qat/qat_common/adf_module.c     | 1 -
 drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c      | 1 -
 drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c    | 1 -
 10 files changed, 16 deletions(-)

diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
index cfa00daeb4fb..566adc0a2d11 100644
--- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
@@ -210,6 +210,5 @@ MODULE_AUTHOR("Intel");
 MODULE_FIRMWARE(ADF_420XX_FW);
 MODULE_FIRMWARE(ADF_420XX_MMP);
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_SOFTDEP("pre: crypto-intel_qat");
 MODULE_IMPORT_NS("CRYPTO_QAT");
diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
index c9be5dcddb27..daca73651c14 100644
--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
@@ -214,6 +214,5 @@ MODULE_FIRMWARE(ADF_402XX_FW);
 MODULE_FIRMWARE(ADF_4XXX_MMP);
 MODULE_FIRMWARE(ADF_402XX_MMP);
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_SOFTDEP("pre: crypto-intel_qat");
 MODULE_IMPORT_NS("CRYPTO_QAT");
diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
index bceb5dd8b148..7a59bca3242f 100644
--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
@@ -256,5 +256,4 @@ MODULE_AUTHOR("Intel");
 MODULE_FIRMWARE(ADF_C3XXX_FW);
 MODULE_FIRMWARE(ADF_C3XXX_MMP);
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_IMPORT_NS("CRYPTO_QAT");
diff --git a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
index c622793e94a8..0881575f7670 100644
--- a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
@@ -225,5 +225,4 @@ module_exit(adfdrv_release);
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Intel");
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_IMPORT_NS("CRYPTO_QAT");
diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
index 23ccb72b6ea2..4972e52dd944 100644
--- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
@@ -256,5 +256,4 @@ MODULE_AUTHOR("Intel");
 MODULE_FIRMWARE(ADF_C62X_FW);
 MODULE_FIRMWARE(ADF_C62X_MMP);
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_IMPORT_NS("CRYPTO_QAT");
diff --git a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
index 4840d44bbd5b..d3f728b9f2f2 100644
--- a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
@@ -225,5 +225,4 @@ module_exit(adfdrv_release);
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Intel");
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_IMPORT_NS("CRYPTO_QAT");
diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
index e8dd76751dfb..a05d149423b0 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h
@@ -9,13 +9,6 @@
 #include "icp_qat_fw_loader_handle.h"
 #include "icp_qat_hal.h"
 
-#define ADF_MAJOR_VERSION	0
-#define ADF_MINOR_VERSION	6
-#define ADF_BUILD_VERSION	0
-#define ADF_DRV_VERSION		__stringify(ADF_MAJOR_VERSION) "." \
-				__stringify(ADF_MINOR_VERSION) "." \
-				__stringify(ADF_BUILD_VERSION)
-
 #define ADF_STATUS_RESTARTING 0
 #define ADF_STATUS_STARTING 1
 #define ADF_STATUS_CONFIGURED 2
diff --git a/drivers/crypto/intel/qat/qat_common/adf_module.c b/drivers/crypto/intel/qat/qat_common/adf_module.c
index fccaa71eeedc..30069feec3c1 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_module.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_module.c
@@ -60,5 +60,4 @@ MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Intel");
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
 MODULE_ALIAS_CRYPTO("intel_qat");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_IMPORT_NS("CRYPTO_INTERNAL");
diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
index b59e0cc49e52..8a863d7d86d7 100644
--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
@@ -256,5 +256,4 @@ MODULE_AUTHOR("Intel");
 MODULE_FIRMWARE(ADF_DH895XCC_FW);
 MODULE_FIRMWARE(ADF_DH895XCC_MMP);
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_IMPORT_NS("CRYPTO_QAT");
diff --git a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
index 7cd528ee31e7..f8a6e10a1de7 100644
--- a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
@@ -225,5 +225,4 @@ module_exit(adfdrv_release);
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Intel");
 MODULE_DESCRIPTION("Intel(R) QuickAssist Technology");
-MODULE_VERSION(ADF_DRV_VERSION);
 MODULE_IMPORT_NS("CRYPTO_QAT");

base-commit: dd0db6d3f236c9b81a9495a2d9e532237d3d6944
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH] crypto : ecc - Fix carry overflow in vli multiplication
From: Lukas Wunner @ 2026-05-13  8:32 UTC (permalink / raw)
  To: Anastasia
  Cc: Ignat Korchagin, Stefan Berger, Herbert Xu, David S . Miller,
	linux-crypto, linux-kernel
In-Reply-To: <CAMtNSrhkfsGL04DtOb9M9fijHK=Xy0D-pBahiCqV+zPuJyRSLw@mail.gmail.com>

On Tue, May 12, 2026 at 06:20:14PM +0300, Anastasia wrote:
> However, I have a few questions regarding the proposed
> check_add_128_128_overflow():
> 
> Should this function return u64 (carry flag) instead of bool to be
> consistent with existing overflow-checking functions like vli_add()?

I think if the return value can only be 1 or 0 (carry or no carry),
then bool is clearer.  If the carry can be > 1 then u64 would be
merited.

I think it's confusing that vli_add() returns u64, but this was just
copy-pasted from the micro-ecc library, whose uECC_vli_add() returns
uECC_word_t:

https://github.com/kmackay/micro-ecc/blob/master/uECC.c#L333

> Regarding argument order: if the function returns a result, shouldn't it be
> the first argument rather than the third (like vli_add())?

I think by convention, the result or destination is the first argument,
as e.g. in memcpy().  I don't know why check_add_overflow() doesn't
adhere to that convention but suspect there's probably no good reason.

> And replace:
> r01 = add_128_128(r01, product);
> r2 += (r01.m_high < product.m_high);
> with:
> r2 += check_add_128_128_overflow(&r01, r01, product);
> in functions vli_mult, vli_umult and vli_square

LGTM.

BTW a small nit, the commit subject contains a superfluous blank
in-between "crypto" and the succeeding colon.

Thanks,

Lukas

^ permalink raw reply

* Re: [PATCH 01/19] btrfs: require at least 4 devices for RAID 6
From: Christoph Hellwig @ 2026-05-13  5:47 UTC (permalink / raw)
  To: David Sterba
  Cc: Christoph Hellwig, Andrew Morton, Catalin Marinas, Will Deacon,
	Ard Biesheuvel, Huacai Chen, WANG Xuerui, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Herbert Xu, Dan Williams, Chris Mason, David Sterba,
	Arnd Bergmann, Song Liu, Yu Kuai, Li Nan, linux-kernel,
	linux-arm-kernel, loongarch, linuxppc-dev, linux-riscv,
	linux-s390, linux-crypto, linux-btrfs, linux-arch, linux-raid
In-Reply-To: <20260512114231.GG2558453@suse.cz>

On Tue, May 12, 2026 at 01:42:31PM +0200, David Sterba wrote:
> On Tue, May 12, 2026 at 07:20:41AM +0200, Christoph Hellwig wrote:
> > While the RAID6 algorithm could in theory support 3 devices by just
> > copying the data disk to the two parity disks, this version is not only
> > useless because it is a suboptimal version of 3-way mirroring, but also
> > broken with various crashes and incorrect parity generation in various
> > architecture-optimized implementations.  Disallow it similar to mdraid
> > which requires at least 4 devices for RAID 6.
> > 
> > Fixes: 53b381b3abeb ("Btrfs: RAID5 and RAID6")
> > Signed-off-by: Christoph Hellwig <hch@lst.de>
> 
> This patch should have been sent separately as it has user visible
> impact and can potentially break some setups.

It _is_ sent out separate.

> The degenerate modes of
> raid0, 5, or 6 are explicit as a possible middle step when converting
> profiles.  We can use a fallback implementation for this case if the
> accelerated implementations cannot do it.

This is not about a degenerated mode.  For a degenerated RAID 6, parity
generation uses the RAID 5 XOR routines as the second parity will be
missing.  This is about generating two parities for a single data disk,
which must be explicitly selected.

^ permalink raw reply

* Re: FAILED: patch "[PATCH] lib/crypto: mpi: Fix integer underflow in" failed to apply to 6.1-stable tree
From: Eric Biggers @ 2026-05-13  2:51 UTC (permalink / raw)
  To: gregkh; +Cc: lukas, ignat, jarkko, yimingqian591, stable, linux-crypto
In-Reply-To: <2026051223-undercoat-reps-6626@gregkh>

[+Cc linux-crypto@vger.kernel.org]

On Tue, May 12, 2026 at 04:01:23PM +0200, gregkh@linuxfoundation.org wrote:
> 
> The patch below does not apply to the 6.1-stable tree.
> If someone wants it applied there, or to any other stable or longterm
> tree, then please email the backport, including the original git commit
> id to <stable@vger.kernel.org>.
> 
> To reproduce the conflict and resubmit, you may use the following commands:
> 
> git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
> git checkout FETCH_HEAD
> git cherry-pick -x 8c2f1288250a90a4b5cabed5d888d7e3aeed4035
> # <resolve conflicts, build, test, etc.>
> git commit -s
> git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026051223-undercoat-reps-6626@gregkh' --subject-prefix 'PATCH 6.1.y' HEAD^..
> 
> Possible dependencies:

A couple issues.  First, this email wasn't sent to the subsystem's
mailing list (linux-crypto@vger.kernel.org in this case).  That greatly
reduces the number of people who are made aware that this didn't get
automatically backported.

Second, the upstream commit cherry-picks to 6.1, 5.15, and 5.10 without
conflict.  (The file being changed was renamed between 6.1 and 6.6, but
'git cherry-pick' handles that automatically.)

I don't know what you're doing exactly that caused it to be
unnecessarily marked as FAILED.  But whatever it is, it's not working,
and it is causing backports to be missed.

- Eric

^ permalink raw reply

* [PATCH 12/12] crypto: atmel - add SHA256 ahash support
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260512224349.64621-1-l.rubusch@gmail.com>

Add SHA256 ahash support for ATSHA204A and ECC based devices using
the hardware SHA engine provided by the Atmel secure element devices.

Implement common SHA256 request handling in the atmel-i2c core driver,
including init, update, final, finup, digest, export and import
operations. Scatterlist input is processed using the crypto hash
walker.

ATSHA204A devices require software-side SHA256 padding according to
FIPS 180-4 before submitting the final data blocks to the device.
Newer ECC devices instead support a dedicated SHA final command which
performs padding internally in hardware. For these devices, the final
block length is passed through the command parameter field.

The SHA engine requires a strict multi-command transaction sequence:
SHA INIT, followed by one or more SHA COMPUTE operations and, on ECC
devices, a terminating SHA FINAL operation. The device SHA context is
lost if the device enters sleep mode or if unrelated commands are
interleaved during the sequence.

To support these hardware requirements, split the existing
send/receive helper into a low-level transfer helper and a higher
level wrapper handling wakeup, sleep and locking. SHA operations keep
the device awake and hold the i2c client lock across the complete hash
transaction until the final digest has been retrieved.

Register the SHA256 ahash algorithm in both atmel-sha204a and
atmel-ecc drivers and add capability based client allocation for SHA
operations.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
 drivers/crypto/atmel-ecc.c     |  50 +++++-
 drivers/crypto/atmel-i2c.c     | 273 +++++++++++++++++++++++++++++++--
 drivers/crypto/atmel-i2c.h     |  40 +++++
 drivers/crypto/atmel-sha204a.c |  55 ++++++-
 4 files changed, 407 insertions(+), 11 deletions(-)

diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index ed8c0ce5562b..aacf9e8add7a 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -19,10 +19,50 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <crypto/internal/kpp.h>
+#include <crypto/internal/hash.h>
 #include <crypto/ecdh.h>
 #include <crypto/kpp.h>
+#include <crypto/sha2.h>
 #include "atmel-i2c.h"
 
+static int atmel_ecc_sha_init_tfm(struct crypto_tfm *tfm)
+{
+	struct atmel_i2c_sha_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	ctx->client = atmel_i2c_client_alloc(ATMEL_CAP_SHA);
+	if (IS_ERR(ctx->client)) {
+		pr_err("tfm - i2c_client binding failed\n");
+		return PTR_ERR(ctx->client);
+	}
+
+	return 0;
+}
+
+static struct ahash_alg atmel_ecc_sha = {
+	.init = atmel_i2c_sha_init,
+	.update	= atmel_i2c_sha_update,
+	.final = atmel_i2c_sha_final,
+	.finup = atmel_i2c_sha_finup,
+	.digest	= atmel_i2c_sha_digest,
+	.export = atmel_i2c_sha_export,
+	.import = atmel_i2c_sha_import,
+	.halg = {
+		.digestsize = SHA256_DIGEST_SIZE,
+		.statesize = sizeof(struct atmel_i2c_sha_reqctx),
+		.base = {
+			.cra_name		= "sha256",
+			.cra_driver_name	= "atmel-sha256",
+			.cra_init		= atmel_ecc_sha_init_tfm,
+			.cra_priority		= ATMEL_I2C_PRIORITY,
+			.cra_flags		= CRYPTO_ALG_TYPE_AHASH,
+			.cra_blocksize		= SHA256_BLOCK_SIZE,
+			.cra_ctxsize		= sizeof(struct atmel_i2c_sha_ctx),
+			.cra_reqsize		= sizeof(struct atmel_i2c_sha_reqctx),
+			.cra_module		= THIS_MODULE,
+		}
+	}
+};
+
 static ssize_t config_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	return atmel_i2c_eeprom_display(dev, attr, buf, ATMEL_EEPROM_CONFIG_ZONE);
@@ -321,7 +361,7 @@ static int atmel_ecc_probe(struct i2c_client *client)
 
 	i2c_priv = i2c_get_clientdata(client);
 	i2c_priv->data = data;
-	i2c_priv->caps = BIT(ATMEL_CAP_ECDH);
+	i2c_priv->caps = BIT(ATMEL_CAP_ECDH) | BIT(ATMEL_CAP_SHA);
 
 	ret = atmel_i2c_device_sanity_check(client);
 	if (ret) {
@@ -364,6 +404,12 @@ static int atmel_ecc_probe(struct i2c_client *client)
 		dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
 	}
 
+	ret = crypto_register_ahash(&atmel_ecc_sha);
+	if (ret) {
+		dev_err(&client->dev, "SHA256 registration failed\n");
+		goto err_list_del;
+	}
+
 	goto done;
 
 err_list_del:
@@ -392,6 +438,7 @@ static void atmel_ecc_remove(struct i2c_client *client)
 	atmel_i2c_flush_queue();
 
 	crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+	crypto_unregister_ahash(&atmel_ecc_sha);
 
 	if (i2c_priv->hwrng.priv) {
 		kfree((void *)i2c_priv->hwrng.priv);
@@ -405,6 +452,7 @@ static const struct atmel_i2c_of_match_data atecc508a_match_data = {
 		.max_exec_time_genkey = 115,
 		.max_exec_time_random = 23,
 		.max_exec_time_read = 1,
+		.max_exec_time_sha = 9,
 		.max_exec_time_write = 42,
 	},
 	.eeprom_zone_size = {
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index 53aba2f4bedb..cbdc8c0e5aca 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -19,6 +19,10 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <crypto/hash.h>
+#include <crypto/sha2.h>
+#include <crypto/internal/hash.h>
+
 #include "atmel-i2c.h"
 
 #define ATMEL_I2C_COMMAND		0x03 /* packet function */
@@ -49,12 +53,17 @@
 #define ATMEL_I2C_ECDH_RSP_SIZE		(32 + ATMEL_I2C_RSP_OVERHEAD_SIZE)
 #define ATMEL_I2C_ECDH_PREFIX_MODE	0x00
 
+/* Definitions for the SHA Command */
+#define ATMEL_I2C_SHA_RSP_SIZE		(ATMEL_I2C_RSP_OVERHEAD_SIZE + \
+					SHA256_DIGEST_SIZE)
+
 /* Command opcode */
 #define ATMEL_I2C_OPCODE_ECDH		0x43
 #define ATMEL_I2C_OPCODE_GENKEY		0x40
 #define ATMEL_I2C_OPCODE_READ		0x02
 #define ATMEL_I2C_OPCODE_RANDOM		0x1b
 #define ATMEL_I2C_OPCODE_WRITE		0x12
+#define ATMEL_I2C_OPCODE_SHA		0x47
 
 /*
  * Wake High delay to data communication (microseconds). SDA should be stable
@@ -244,6 +253,43 @@ int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
 }
 EXPORT_SYMBOL(atmel_i2c_init_ecdh_cmd);
 
+int atmel_i2c_init_sha_cmd(struct atmel_i2c_cmd *cmd,
+			   u8 *challenge, size_t len,
+			   enum atmel_i2c_sha_engine_cmd sha_engine_cmd,
+			   const struct atmel_i2c_max_exec_timings *timings)
+{
+	cmd->word_addr = ATMEL_I2C_COMMAND;
+	cmd->opcode = ATMEL_I2C_OPCODE_SHA;
+	cmd->param1 = sha_engine_cmd;
+
+	cmd->param2 = cpu_to_le16(0);
+	/*
+	 * Starting with the bigger ECCs, the device learned how to do SHA256
+	 * padding (FIPS 180-4). Since SHA UPDATE always consumes 64B (SHA256
+	 * block size), the only length needed to communicate is the number of
+	 * used bytes in the final block. For the Atmel ECC series, this is
+	 * passed in the param2.
+	 */
+	if (sha_engine_cmd == atmel_sha_ecc_end)
+		cmd->param2 = cpu_to_le16(len);
+
+	cmd->count = ATMEL_I2C_COUNT_OVERHEAD_SIZE;
+	if (sha_engine_cmd == atmel_sha_init) {
+		memset(cmd->data, 0, sizeof(cmd->data));
+	} else {
+		memcpy(cmd->data, challenge, len);
+		cmd->count += len;
+	}
+
+	atmel_i2c_checksum(cmd);
+
+	cmd->msecs = timings->max_exec_time_sha;
+	cmd->rxsize = atmel_i2c_sha_rsp_size[sha_engine_cmd];
+
+	return 0;
+}
+EXPORT_SYMBOL(atmel_i2c_init_sha_cmd);
+
 static void atmel_i2c_rng_done(struct atmel_i2c_work_data *work_data,
 			       void *areq, int status)
 {
@@ -492,21 +538,15 @@ static int atmel_i2c_sleep(struct i2c_client *client)
  * counter other than to put the device into sleep or idle mode and then
  * wake it up again.
  */
-int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd)
+static int _atmel_i2c_send_receive(struct i2c_client *client,
+				   struct atmel_i2c_cmd *cmd)
 {
-	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
 	int ret;
 
-	mutex_lock(&i2c_priv->lock);
-
-	ret = atmel_i2c_wakeup(client);
-	if (ret)
-		goto err;
-
 	/* send the command */
 	ret = i2c_master_send(client, (u8 *)cmd, cmd->count + ATMEL_I2C_ADDR_SIZE);
 	if (ret < 0)
-		goto err;
+		return ret;
 
 	/* delay the appropriate amount of time for command to execute */
 	msleep(cmd->msecs);
@@ -514,6 +554,24 @@ int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd)
 	/* receive the response */
 	ret = i2c_master_recv(client, cmd->data, cmd->rxsize);
 	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd)
+{
+	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+	int ret;
+
+	mutex_lock(&i2c_priv->lock);
+
+	ret = atmel_i2c_wakeup(client);
+	if (ret)
+		goto err;
+
+	ret = _atmel_i2c_send_receive(client, cmd);
+	if (ret)
 		goto err;
 
 	/* put the device into low-power mode */
@@ -529,6 +587,203 @@ int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd)
 }
 EXPORT_SYMBOL(atmel_i2c_send_receive);
 
+int atmel_i2c_sha_init(struct ahash_request *req)
+{
+	struct atmel_i2c_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct atmel_i2c_sha_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(ctx->client);
+	const struct atmel_i2c_of_match_data *data = i2c_priv->data;
+	struct atmel_i2c_cmd *cmd;
+	int ret;
+
+	rctx->bufcnt = 0;
+	rctx->total = 0;
+	rctx->ctx = i2c_get_clientdata(ctx->client);
+
+	cmd = kmalloc_obj(*cmd);
+	if (!cmd)
+		return -ENOMEM;
+
+	/* SHA init */
+	ret = atmel_i2c_init_sha_cmd(cmd, NULL, 0, atmel_sha_init, &data->timings);
+	if (ret)
+		goto err_free;
+
+	mutex_lock(&i2c_priv->lock);
+
+	ret = atmel_i2c_wakeup(ctx->client);
+	if (ret)
+		goto err;
+
+	ret = _atmel_i2c_send_receive(ctx->client, cmd);
+	if (ret)
+		goto err;
+
+	/* we keep the lock hold until error out or _sha_final() is called */
+	return 0;
+err:
+	mutex_unlock(&i2c_priv->lock);
+err_free:
+	kfree_sensitive(cmd);
+	return ret;
+}
+EXPORT_SYMBOL(atmel_i2c_sha_init);
+
+int atmel_i2c_sha_update(struct ahash_request *req)
+{
+	struct atmel_i2c_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct atmel_i2c_sha_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(ctx->client);
+	const struct atmel_i2c_of_match_data *data = i2c_priv->data;
+	struct atmel_i2c_cmd *cmd;
+	struct crypto_hash_walk walk;
+	int nbytes, take, copied = 0;
+	const u8 *pdata;
+	int ret;
+
+	rctx->total += req->nbytes;
+
+	cmd = kmalloc_obj(*cmd);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto err_nomem;
+	}
+
+	/*
+	 * Note, we are actively holding the i2c_priv->lock while the SHA engine
+	 * operates. This covers init, update and final steps.
+	 */
+	nbytes = crypto_hash_walk_first(req, &walk);
+	for (; nbytes > 0; nbytes = crypto_hash_walk_done(&walk, copied)) {
+		copied = nbytes;
+		pdata = walk.data;
+		while (copied > 0) {
+			take = min(copied, SHA256_BLOCK_SIZE - rctx->bufcnt);
+
+			memcpy(rctx->buffer + rctx->bufcnt, pdata, take);
+			pdata += take;
+			copied -= take;
+			rctx->bufcnt += take;
+			if (rctx->bufcnt == SHA256_BLOCK_SIZE) {
+				ret = atmel_i2c_init_sha_cmd(cmd, rctx->buffer,
+							     SHA256_BLOCK_SIZE,
+							     atmel_sha_compute,
+							     &data->timings);
+				if (ret)
+					goto err;
+
+				ret = _atmel_i2c_send_receive(ctx->client, cmd);
+				if (ret)
+					goto err;
+
+				rctx->bufcnt = 0;
+			}
+		}
+	}
+
+	kfree_sensitive(cmd);
+	return 0;
+err:
+	kfree_sensitive(cmd);
+err_nomem:
+	mutex_unlock(&i2c_priv->lock);
+	return ret;
+}
+EXPORT_SYMBOL(atmel_i2c_sha_update);
+
+int atmel_i2c_sha_final(struct ahash_request *req)
+{
+	struct atmel_i2c_sha_reqctx *rctx = ahash_request_ctx(req);
+	struct atmel_i2c_sha_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(ctx->client);
+	const struct atmel_i2c_of_match_data *data = i2c_priv->data;
+	struct atmel_i2c_cmd *cmd;
+	u8 final_blocks[2 * SHA256_BLOCK_SIZE];
+	u32 total_pad;
+	__be64 bits;
+	int i, ret = 0;
+
+	cmd = kmalloc_obj(*cmd);
+	if (!cmd) {
+		ret = -ENOMEM;
+		goto err_nomem;
+	}
+
+	if (data->needs_sha_padding) {
+		/*
+		 * Determine if padding fits in current block or needs another,
+		 * SHA256 needs 8 bytes for length at the end of a 64-byte block.
+		 */
+		memset(final_blocks, 0, sizeof(final_blocks));
+		memcpy(final_blocks, rctx->buffer, rctx->bufcnt);
+		final_blocks[rctx->bufcnt] = 0x80; /* pad bit */
+		total_pad = SHA256_BLOCK_SIZE * (rctx->bufcnt < 56 ? 1 : 2);
+		bits = cpu_to_be64((u64)rctx->total << 3); /* needs num of bits */
+		memcpy(final_blocks + total_pad - 8, &bits, 8);
+		for (i = 0; i < total_pad; i += SHA256_BLOCK_SIZE) {
+			ret = atmel_i2c_init_sha_cmd(cmd, final_blocks + i,
+						     SHA256_BLOCK_SIZE,
+						     atmel_sha_compute, &data->timings);
+			if (ret)
+				goto err_or_done;
+
+			ret = _atmel_i2c_send_receive(ctx->client, cmd);
+			if (ret)
+				goto err_or_done;
+		}
+	} else {
+		ret = atmel_i2c_init_sha_cmd(cmd, rctx->buffer, rctx->bufcnt,
+					     atmel_sha_ecc_end, &data->timings);
+		if (ret)
+			goto err_or_done;
+
+		ret = _atmel_i2c_send_receive(ctx->client, cmd);
+		if (ret)
+			goto err_or_done;
+	}
+
+	memcpy(req->result, &cmd->data[ATMEL_I2C_RSP_DATA_IDX],
+	       SHA256_DIGEST_SIZE);
+
+	/* Sleep returns a positive int on success, API requires 0 on success */
+	ret = atmel_i2c_sleep(ctx->client);
+	if (ret < 0)
+		goto err_or_done;
+	ret = 0;
+err_or_done:
+	kfree_sensitive(cmd);
+err_nomem:
+	mutex_unlock(&i2c_priv->lock);
+	return ret;
+}
+EXPORT_SYMBOL(atmel_i2c_sha_final);
+
+int atmel_i2c_sha_finup(struct ahash_request *req)
+{
+	return atmel_i2c_sha_update(req) ? : atmel_i2c_sha_final(req);
+}
+EXPORT_SYMBOL(atmel_i2c_sha_finup);
+
+int atmel_i2c_sha_digest(struct ahash_request *req)
+{
+	return atmel_i2c_sha_init(req) ? : atmel_i2c_sha_finup(req);
+}
+EXPORT_SYMBOL(atmel_i2c_sha_digest);
+
+int atmel_i2c_sha_export(struct ahash_request *req, void *out)
+{
+	memcpy(out, ahash_request_ctx(req), sizeof(struct atmel_i2c_sha_reqctx));
+	return 0;
+}
+EXPORT_SYMBOL(atmel_i2c_sha_export);
+
+int atmel_i2c_sha_import(struct ahash_request *req, const void *in)
+{
+	memcpy(ahash_request_ctx(req), in, sizeof(struct atmel_i2c_sha_reqctx));
+	return 0;
+}
+EXPORT_SYMBOL(atmel_i2c_sha_import);
+
 static void atmel_i2c_work_handler(struct work_struct *work)
 {
 	struct atmel_i2c_work_data *work_data =
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 20afe2da4f8d..e0021d4ea686 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -7,8 +7,11 @@
 #ifndef __ATMEL_I2C_H__
 #define __ATMEL_I2C_H__
 
+#include <linux/device.h>
+#include <crypto/internal/hash.h>
 #include <linux/hw_random.h>
 #include <linux/types.h>
+#include <crypto/sha2.h>
 
 #define ATMEL_I2C_PRIORITY		300
 
@@ -79,11 +82,13 @@ struct atmel_i2c_max_exec_timings {
 	unsigned int max_exec_time_ecdh;
 	unsigned int max_exec_time_random;
 	unsigned int max_exec_time_read;
+	unsigned int max_exec_time_sha;
 	unsigned int max_exec_time_write;
 };
 
 struct atmel_i2c_of_match_data {
 	const unsigned short needs_legacy_hwrng;
+	const unsigned short needs_sha_padding;
 	struct atmel_i2c_max_exec_timings timings;
 	size_t eeprom_zone_size[3]; /* all atmel devices have three zones */
 };
@@ -91,6 +96,30 @@ struct atmel_i2c_of_match_data {
 /* Used for binding tfm objects to i2c clients. */
 enum atmel_i2c_capability {
 	ATMEL_CAP_ECDH = 0,
+	ATMEL_CAP_SHA,
+};
+
+enum atmel_i2c_sha_engine_cmd {
+	atmel_sha_init = 0,
+	atmel_sha_compute,
+	atmel_sha_ecc_end,
+};
+
+size_t atmel_i2c_sha_rsp_size[] = {
+	[atmel_sha_init] = ATMEL_I2C_STATUS_RSP_SIZE,
+	[atmel_sha_compute] = SHA256_DIGEST_SIZE + ATMEL_I2C_RSP_OVERHEAD_SIZE,
+	[atmel_sha_ecc_end] = SHA256_DIGEST_SIZE + ATMEL_I2C_RSP_OVERHEAD_SIZE,
+};
+
+struct atmel_i2c_sha_ctx {
+	struct i2c_client *client;
+};
+
+struct atmel_i2c_sha_reqctx {
+	u8 buffer[SHA256_BLOCK_SIZE];
+	size_t bufcnt;
+	size_t total; /* size of full input, needed for padding */
+	struct atmel_i2c_client_priv *ctx;
 };
 
 struct atmel_i2c_client_mgmt {
@@ -172,9 +201,20 @@ void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid,
 int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
 			    struct scatterlist *pubkey,
 			    const struct atmel_i2c_max_exec_timings *timings);
+int atmel_i2c_init_sha_cmd(struct atmel_i2c_cmd *cmd, u8 *challenge, size_t len,
+			   enum atmel_i2c_sha_engine_cmd sha_engine_cmd,
+			   const struct atmel_i2c_max_exec_timings *timings);
 int atmel_i2c_register_rng(struct atmel_i2c_client_priv *i2c_priv,
 			   struct device *dev);
 
+int atmel_i2c_sha_init(struct ahash_request *req);
+int atmel_i2c_sha_update(struct ahash_request *req);
+int atmel_i2c_sha_final(struct ahash_request *req);
+int atmel_i2c_sha_finup(struct ahash_request *req);
+int atmel_i2c_sha_digest(struct ahash_request *req);
+int atmel_i2c_sha_export(struct ahash_request *req, void *out);
+int atmel_i2c_sha_import(struct ahash_request *req, const void *in);
+
 int atmel_i2c_device_sanity_check(struct i2c_client *client);
 
 ssize_t atmel_i2c_eeprom_display(struct device *dev,
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 6a41024ae40d..74535480edeb 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -17,8 +17,48 @@
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 #include <linux/workqueue.h>
+#include <crypto/sha2.h>
+
 #include "atmel-i2c.h"
 
+static int atmel_sha204a_sha_init_tfm(struct crypto_tfm *tfm)
+{
+	struct atmel_i2c_sha_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	ctx->client = atmel_i2c_client_alloc(ATMEL_CAP_SHA);
+	if (IS_ERR(ctx->client)) {
+		pr_err("tfm - i2c_client binding failed\n");
+		return PTR_ERR(ctx->client);
+	}
+
+	return 0;
+}
+
+static struct ahash_alg atmel_sha204a_sha = {
+	.init = atmel_i2c_sha_init,
+	.update	= atmel_i2c_sha_update,
+	.final = atmel_i2c_sha_final,
+	.finup = atmel_i2c_sha_finup,
+	.digest	= atmel_i2c_sha_digest,
+	.export = atmel_i2c_sha_export,
+	.import = atmel_i2c_sha_import,
+	.halg = {
+		.digestsize = SHA256_DIGEST_SIZE,
+		.statesize = sizeof(struct atmel_i2c_sha_reqctx),
+		.base = {
+			.cra_name		= "sha256",
+			.cra_driver_name	= "atmel-sha256",
+			.cra_init		= atmel_sha204a_sha_init_tfm,
+			.cra_priority		= ATMEL_I2C_PRIORITY,
+			.cra_flags		= CRYPTO_ALG_TYPE_AHASH,
+			.cra_blocksize		= SHA256_BLOCK_SIZE,
+			.cra_ctxsize		= sizeof(struct atmel_i2c_sha_ctx),
+			.cra_reqsize		= sizeof(struct atmel_i2c_sha_reqctx),
+			.cra_module		= THIS_MODULE,
+		}
+	}
+};
+
 static ssize_t config_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	return atmel_i2c_eeprom_display(dev, attr, buf, ATMEL_EEPROM_CONFIG_ZONE);
@@ -62,7 +102,7 @@ static int atmel_sha204a_probe(struct i2c_client *client)
 
 	i2c_priv = i2c_get_clientdata(client);
 	i2c_priv->data = data;
-	i2c_priv->caps = 0;
+	i2c_priv->caps = BIT(ATMEL_CAP_SHA);
 
 	ret = atmel_i2c_device_sanity_check(client);
 	if (ret) {
@@ -95,6 +135,13 @@ static int atmel_sha204a_probe(struct i2c_client *client)
 		goto err_list_del;
 	}
 
+	/* register algorithms */
+	ret = crypto_register_ahash(&atmel_sha204a_sha);
+	if (ret) {
+		dev_err(&client->dev, "SHA256 registration failed\n");
+		goto err_list_del;
+	}
+
 	goto done;
 
 err_list_del:
@@ -119,6 +166,8 @@ static void atmel_sha204a_remove(struct i2c_client *client)
 	devm_hwrng_unregister(&client->dev, &i2c_priv->hwrng);
 	atmel_i2c_flush_queue();
 
+	crypto_unregister_ahash(&atmel_sha204a_sha);
+
 	if (i2c_priv->hwrng.priv) {
 		kfree((void *)i2c_priv->hwrng.priv);
 		i2c_priv->hwrng.priv = 0;
@@ -130,6 +179,7 @@ static const struct atmel_i2c_of_match_data atsha204_match_data = {
 		.max_exec_time_genkey = 43,
 		.max_exec_time_random = 50,
 		.max_exec_time_read = 4,
+		.max_exec_time_sha = 22,
 		.max_exec_time_write = 42,
 	},
 	.eeprom_zone_size = {
@@ -142,6 +192,7 @@ static const struct atmel_i2c_of_match_data atsha204_match_data = {
 	 * [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html
 	 */
 	.needs_legacy_hwrng = 1,
+	.needs_sha_padding = 1,
 };
 
 static const struct atmel_i2c_of_match_data atsha204a_match_data = {
@@ -149,6 +200,7 @@ static const struct atmel_i2c_of_match_data atsha204a_match_data = {
 		.max_exec_time_genkey = 43,
 		.max_exec_time_random = 50,
 		.max_exec_time_read = 4,
+		.max_exec_time_sha = 22,
 		.max_exec_time_write = 42,
 	},
 	.eeprom_zone_size = {
@@ -156,6 +208,7 @@ static const struct atmel_i2c_of_match_data atsha204a_match_data = {
 		[ATMEL_EEPROM_OTP_ZONE] = 64,
 		[ATMEL_EEPROM_DATA_ZONE] = 512
 	},
+	.needs_sha_padding = 1,
 };
 
 static const struct of_device_id atmel_sha204a_dt_ids[] __maybe_unused = {
-- 
2.53.0


^ permalink raw reply related

* [PATCH 11/12] crypto: atmel - refactor and localize driver constants
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260512224349.64621-1-l.rubusch@gmail.com>

After refactoring the client drivers to use the shared atmel-i2c core,
many constants and definitions no longer need global visibility.

Move command definitions, timing constants, status codes and related
helpers from the public header into the local compile unit of the core
driver where possible.

As part of this cleanup, rename macros and constants to use consistent
ATMEL_I2C_* naming and align them with common kernel driver conventions.
Also replace remaining hardcoded values with named constants throughout
the driver.

This is a preparatory cleanup and does not change functionality.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
 drivers/crypto/atmel-ecc.c |   4 +-
 drivers/crypto/atmel-i2c.c | 115 +++++++++++++++++++++++++------------
 drivers/crypto/atmel-i2c.h |  76 +++++++++---------------
 3 files changed, 108 insertions(+), 87 deletions(-)

diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 9ad6d42b6eef..ed8c0ce5562b 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -137,7 +137,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
 
 	ctx->do_fallback = false;
 
-	atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2, &data->timings);
+	atmel_i2c_init_genkey_cmd(cmd, ATMEL_I2C_ECDH_SLOT_DEFAULT, &data->timings);
 
 	ret = atmel_i2c_send_receive(ctx->client, cmd);
 	if (ret)
@@ -296,7 +296,7 @@ static struct kpp_alg atmel_ecdh_nist_p256 = {
 		.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
 		.cra_name = "ecdh-nist-p256",
 		.cra_driver_name = "atmel-ecdh",
-		.cra_priority = ATMEL_ECC_PRIORITY,
+		.cra_priority = ATMEL_I2C_PRIORITY,
 		.cra_module = THIS_MODULE,
 		.cra_ctxsize = sizeof(struct atmel_ecdh_ctx),
 	},
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index 0ec2d768a763..53aba2f4bedb 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -21,19 +21,62 @@
 #include <linux/workqueue.h>
 #include "atmel-i2c.h"
 
-#define ATMEL_I2C_COMMAND			0x03 /* packet function */
+#define ATMEL_I2C_COMMAND		0x03 /* packet function */
+#define ATMEL_I2C_SLEEP_TOKEN		0x01
 
 /* Definitions for the device lock state */
-#define ATMEL_I2C_DEVICE_LOCK_ADDR		0x15
-#define ATMEL_I2C_LOCK_VALUE_IDX		(ATMEL_I2C_RSP_DATA_IDX + 2)
-#define ATMEL_I2C_LOCK_CONFIG_IDX		(ATMEL_I2C_RSP_DATA_IDX + 3)
+#define ATMEL_I2C_DEVICE_LOCK_ADDR	0x15
+#define ATMEL_I2C_LOCK_VALUE_IDX	(ATMEL_I2C_RSP_DATA_IDX + 2)
+#define ATMEL_I2C_LOCK_CONFIG_IDX	(ATMEL_I2C_RSP_DATA_IDX + 3)
+
+/* Definitions for the READ Command */
+#define ATMEL_I2C_READ_COUNT		ATMEL_I2C_COUNT_OVERHEAD_SIZE
+#define ATMEL_I2C_READ_RSP_SIZE		(4 + ATMEL_I2C_RSP_OVERHEAD_SIZE)
+
+/* Definitions for the RANDOM Command */
+#define ATMEL_I2C_RANDOM_COUNT		ATMEL_I2C_COUNT_OVERHEAD_SIZE
+#define ATMEL_I2C_RNG_BLOCK_SIZE	32
+#define ATMEL_I2C_RANDOM_RSP_SIZE	(ATMEL_I2C_RNG_BLOCK_SIZE + \
+					ATMEL_I2C_RSP_OVERHEAD_SIZE)
+#define ATMEL_I2C_RANDOM_COUNT		ATMEL_I2C_COUNT_OVERHEAD_SIZE
+
+/* Definitions for the GenKey Command */
+#define ATMEL_I2C_GENKEY_COUNT		ATMEL_I2C_COUNT_OVERHEAD_SIZE
+#define ATMEL_I2C_GENKEY_MODE_PRIVATE	0x04
+
+/* Definitions for the ECDH Command */
+#define ATMEL_I2C_ECDH_COUNT		71
+#define ATMEL_I2C_ECDH_RSP_SIZE		(32 + ATMEL_I2C_RSP_OVERHEAD_SIZE)
+#define ATMEL_I2C_ECDH_PREFIX_MODE	0x00
 
 /* Command opcode */
-#define ATMEL_I2C_OPCODE_ECDH			0x43
-#define ATMEL_I2C_OPCODE_GENKEY			0x40
-#define ATMEL_I2C_OPCODE_READ			0x02
-#define ATMEL_I2C_OPCODE_RANDOM			0x1b
-#define ATMEL_I2C_OPCODE_WRITE			0x12
+#define ATMEL_I2C_OPCODE_ECDH		0x43
+#define ATMEL_I2C_OPCODE_GENKEY		0x40
+#define ATMEL_I2C_OPCODE_READ		0x02
+#define ATMEL_I2C_OPCODE_RANDOM		0x1b
+#define ATMEL_I2C_OPCODE_WRITE		0x12
+
+/*
+ * Wake High delay to data communication (microseconds). SDA should be stable
+ * high for this entire duration.
+ */
+#define ATMEL_I2C_TWHI_MIN		1500
+#define ATMEL_I2C_TWHI_MAX		1550
+
+/* Wake Low duration */
+#define ATMEL_I2C_TWLO_USEC		60
+
+/* Status/Error codes */
+enum atmel_i2c_error_codes {
+	ATMEL_STATUS_OK_NOERR = 0x00,            /* success */
+	ATMEL_STATUS_CHECKMAC_OR_VERIFY_MISCOMPARE = 0x01,
+	ATMEL_STATUS_PARSE_ERROR = 0x03,
+	ATMEL_STATUS_ECC_FAULT = 0x05,
+	ATMEL_STATUS_EXECUTION_FAULT = 0x0F,
+	ATMEL_STATUS_OK_WAKE_SUCCESSFULL = 0x11, /* success */
+	ATMEL_STATUS_WATCHDOG_EXPIRE = 0xEE,
+	ATMEL_STATUS_CRC_ERROR = 0xFF,
+};
 
 struct atmel_i2c_client_mgmt atmel_i2c_mgmt = {
 	.i2c_list_lock = __SPIN_LOCK_UNLOCKED(atmel_i2c_mgmt.i2c_list_lock),
@@ -45,12 +88,12 @@ static const struct {
 	u8 value;
 	const char *error_text;
 } error_list[] = {
-	{ 0x01, "CheckMac or Verify miscompare" },
-	{ 0x03, "Parse Error" },
-	{ 0x05, "ECC Fault" },
-	{ 0x0F, "Execution Error" },
-	{ 0xEE, "Watchdog about to expire" },
-	{ 0xFF, "CRC or other communication error" },
+	{ ATMEL_STATUS_CHECKMAC_OR_VERIFY_MISCOMPARE, "CheckMac or Verify miscompare" },
+	{ ATMEL_STATUS_PARSE_ERROR, "Parse Error" },
+	{ ATMEL_STATUS_ECC_FAULT, "ECC Fault" },
+	{ ATMEL_STATUS_EXECUTION_FAULT, "Execution Error" },
+	{ ATMEL_STATUS_WATCHDOG_EXPIRE, "Watchdog about to expire" },
+	{ ATMEL_STATUS_CRC_ERROR, "CRC or other communication error" },
 };
 
 /**
@@ -65,7 +108,7 @@ static const struct {
 static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd)
 {
 	u8 *data = &cmd->count;
-	size_t len = cmd->count - CRC_SIZE;
+	size_t len = cmd->count - ATMEL_I2C_CRC_SIZE;
 	__le16 *__crc16 = (__le16 *)(data + len);
 
 	*__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len)));
@@ -141,12 +184,12 @@ void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd,
 	cmd->opcode = ATMEL_I2C_OPCODE_RANDOM;
 	cmd->param1 = 0;
 	cmd->param2 = 0;
-	cmd->count = RANDOM_COUNT;
+	cmd->count = ATMEL_I2C_RANDOM_COUNT;
 
 	atmel_i2c_checksum(cmd);
 
 	cmd->msecs = timings->max_exec_time_random;
-	cmd->rxsize = RANDOM_RSP_SIZE;
+	cmd->rxsize = ATMEL_I2C_RANDOM_RSP_SIZE;
 }
 EXPORT_SYMBOL(atmel_i2c_init_random_cmd);
 
@@ -154,16 +197,16 @@ void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid,
 			       const struct atmel_i2c_max_exec_timings *timings)
 {
 	cmd->word_addr = ATMEL_I2C_COMMAND;
-	cmd->count = GENKEY_COUNT;
+	cmd->count = ATMEL_I2C_GENKEY_COUNT;
 	cmd->opcode = ATMEL_I2C_OPCODE_GENKEY;
-	cmd->param1 = GENKEY_MODE_PRIVATE;
+	cmd->param1 = ATMEL_I2C_GENKEY_MODE_PRIVATE;
 	/* a random private key will be generated and stored in slot keyID */
 	cmd->param2 = cpu_to_le16(keyid);
 
 	atmel_i2c_checksum(cmd);
 
 	cmd->msecs = timings->max_exec_time_genkey;
-	cmd->rxsize = GENKEY_RSP_SIZE;
+	cmd->rxsize = ATMEL_I2C_GENKEY_RSP_SIZE;
 }
 EXPORT_SYMBOL(atmel_i2c_init_genkey_cmd);
 
@@ -174,11 +217,11 @@ int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
 	size_t copied;
 
 	cmd->word_addr = ATMEL_I2C_COMMAND;
-	cmd->count = ECDH_COUNT;
+	cmd->count = ATMEL_I2C_ECDH_COUNT;
 	cmd->opcode = ATMEL_I2C_OPCODE_ECDH;
-	cmd->param1 = ECDH_PREFIX_MODE;
+	cmd->param1 = ATMEL_I2C_ECDH_PREFIX_MODE;
 	/* private key slot */
-	cmd->param2 = cpu_to_le16(DATA_SLOT_2);
+	cmd->param2 = cpu_to_le16(ATMEL_I2C_ECDH_SLOT_DEFAULT);
 
 	/*
 	 * The device only supports NIST P256 ECC keys. The public key size will
@@ -195,7 +238,7 @@ int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
 	atmel_i2c_checksum(cmd);
 
 	cmd->msecs = timings->max_exec_time_ecdh;
-	cmd->rxsize = ECDH_RSP_SIZE;
+	cmd->rxsize = ATMEL_I2C_ECDH_RSP_SIZE;
 
 	return 0;
 }
@@ -231,7 +274,7 @@ static int atmel_i2c_rng_read_nonblocking(struct hwrng *rng, void *buf,
 
 	if (rng->priv) {
 		work_data = (struct atmel_i2c_work_data *)rng->priv;
-		max = min(RANDOM_RSP_SIZE - CMD_OVERHEAD_SIZE, max);
+		max = min(ATMEL_I2C_RANDOM_RSP_SIZE - ATMEL_I2C_RSP_OVERHEAD_SIZE, max);
 		memcpy(buf, &work_data->cmd.data[ATMEL_I2C_RSP_DATA_IDX], max);
 		rng->priv = 0;
 	} else {
@@ -271,7 +314,7 @@ static int atmel_i2c_rng_read(struct hwrng *rng, void *buf, size_t max,
 	if (ret)
 		return ret;
 
-	max = min(RANDOM_RSP_SIZE - CMD_OVERHEAD_SIZE, max);
+	max = min(ATMEL_I2C_RANDOM_RSP_SIZE - ATMEL_I2C_RSP_OVERHEAD_SIZE, max);
 	memcpy(buf, &cmd.data[ATMEL_I2C_RSP_DATA_IDX], max);
 
 	return max;
@@ -323,7 +366,7 @@ static int atmel_i2c_eeprom_read(struct i2c_client *client, u16 addr,
 		goto err;
 	}
 
-	memcpy(buf, cmd->data + ATMEL_I2C_RSP_DATA_IDX, 4);
+	memcpy(buf, cmd->data + ATMEL_I2C_RSP_DATA_IDX, ATMEL_I2C_STATUS_RSP_SIZE);
 
 err:
 	kfree(cmd);
@@ -381,10 +424,10 @@ static int atmel_i2c_status(struct device *dev, u8 *status)
 	int i;
 	u8 err_id = status[1];
 
-	if (*status != STATUS_SIZE)
+	if (*status != ATMEL_I2C_STATUS_RSP_SIZE)
 		return 0;
 
-	if (err_id == STATUS_WAKE_SUCCESSFUL || err_id == STATUS_NOERR)
+	if (err_id == ATMEL_STATUS_OK_WAKE_SUCCESSFULL || err_id == ATMEL_STATUS_OK_NOERR)
 		return 0;
 
 	for (i = 0; i < err_list_len; i++)
@@ -403,7 +446,7 @@ static int atmel_i2c_status(struct device *dev, u8 *status)
 static int atmel_i2c_wakeup(struct i2c_client *client)
 {
 	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
-	u8 status[STATUS_RSP_SIZE];
+	u8 status[ATMEL_I2C_STATUS_RSP_SIZE];
 	int ret;
 
 	/*
@@ -418,9 +461,9 @@ static int atmel_i2c_wakeup(struct i2c_client *client)
 	 * Wait to wake the device. Typical execution times for ecdh and genkey
 	 * are around tens of milliseconds. Delta is chosen to 50 microseconds.
 	 */
-	usleep_range(TWHI_MIN, TWHI_MAX);
+	usleep_range(ATMEL_I2C_TWHI_MIN, ATMEL_I2C_TWHI_MAX);
 
-	ret = i2c_master_recv(client, status, STATUS_SIZE);
+	ret = i2c_master_recv(client, status, ATMEL_I2C_STATUS_RSP_SIZE);
 	if (ret < 0)
 		return ret;
 
@@ -429,7 +472,7 @@ static int atmel_i2c_wakeup(struct i2c_client *client)
 
 static int atmel_i2c_sleep(struct i2c_client *client)
 {
-	u8 sleep = SLEEP_TOKEN;
+	u8 sleep = ATMEL_I2C_SLEEP_TOKEN;
 
 	return i2c_master_send(client, &sleep, 1);
 }
@@ -461,7 +504,7 @@ int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd)
 		goto err;
 
 	/* send the command */
-	ret = i2c_master_send(client, (u8 *)cmd, cmd->count + WORD_ADDR_SIZE);
+	ret = i2c_master_send(client, (u8 *)cmd, cmd->count + ATMEL_I2C_ADDR_SIZE);
 	if (ret < 0)
 		goto err;
 
@@ -521,7 +564,7 @@ EXPORT_SYMBOL(atmel_i2c_flush_queue);
 
 static inline size_t atmel_i2c_wake_token_sz(u32 bus_clk_rate)
 {
-	u32 no_of_bits = DIV_ROUND_UP(TWLO_USEC * bus_clk_rate, USEC_PER_SEC);
+	u32 no_of_bits = DIV_ROUND_UP(ATMEL_I2C_TWLO_USEC * bus_clk_rate, USEC_PER_SEC);
 
 	/* return the size of the wake_token in bytes */
 	return DIV_ROUND_UP(no_of_bits, 8);
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 2f76e107340e..20afe2da4f8d 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -10,28 +10,39 @@
 #include <linux/hw_random.h>
 #include <linux/types.h>
 
-#define ATMEL_ECC_PRIORITY		300
+#define ATMEL_I2C_PRIORITY		300
 
-#define SLEEP_TOKEN			0x01
-#define WAKE_TOKEN_MAX_SIZE		8
+#define ATMEL_I2C_WAKE_TOKEN_MAX_SIZE	8
 
 /* Definitions of Data and Command sizes */
-#define WORD_ADDR_SIZE			1
-#define COUNT_SIZE			1
-#define CRC_SIZE			2
-#define CMD_OVERHEAD_SIZE		(COUNT_SIZE + CRC_SIZE)
+#define ATMEL_I2C_ADDR_SIZE		1
+#define ATMEL_I2C_OPCODE_SIZE		1
+#define ATMEL_I2C_COUNT_SIZE		1
+#define ATMEL_I2C_PARAM1_SIZE		1
+#define ATMEL_I2C_PARAM2_SIZE		2
+#define ATMEL_I2C_CRC_SIZE		2
+
+#define ATMEL_I2C_RSP_OVERHEAD_SIZE	(ATMEL_I2C_COUNT_SIZE + \
+					ATMEL_I2C_CRC_SIZE)
+#define ATMEL_I2C_COUNT_OVERHEAD_SIZE	(ATMEL_I2C_OPCODE_SIZE + \
+					ATMEL_I2C_COUNT_SIZE + \
+					ATMEL_I2C_PARAM1_SIZE + \
+					ATMEL_I2C_PARAM2_SIZE + \
+					ATMEL_I2C_CRC_SIZE)
+
+/* Definitions for the status Command */
+#define ATMEL_I2C_STATUS_RSP_SIZE	4
 
 /* size in bytes of the n prime */
 #define ATMEL_ECC_NIST_P256_N_SIZE	32
 #define ATMEL_ECC_PUBKEY_SIZE		(2 * ATMEL_ECC_NIST_P256_N_SIZE)
+#define ATMEL_I2C_GENKEY_RSP_SIZE	(ATMEL_ECC_PUBKEY_SIZE + \
+					 ATMEL_I2C_RSP_OVERHEAD_SIZE)
+#define ATMEL_I2C_MAX_RSP_SIZE		ATMEL_I2C_GENKEY_RSP_SIZE
 
-#define STATUS_RSP_SIZE			4
-#define ECDH_RSP_SIZE			(32 + CMD_OVERHEAD_SIZE)
-#define GENKEY_RSP_SIZE			(ATMEL_ECC_PUBKEY_SIZE + \
-					 CMD_OVERHEAD_SIZE)
-#define ATMEL_I2C_READ_RSP_SIZE		(4 + CMD_OVERHEAD_SIZE)
-#define RANDOM_RSP_SIZE			(32 + CMD_OVERHEAD_SIZE)
-#define MAX_RSP_SIZE			GENKEY_RSP_SIZE
+/* Definitions for Indexes common to all commands */
+#define ATMEL_I2C_RSP_DATA_IDX		1 /* buffer index of data in response */
+#define ATMEL_I2C_ECDH_SLOT_DEFAULT	2
 
 /**
  * atmel_i2c_cmd - structure used for communicating with the device.
@@ -51,7 +62,7 @@ struct atmel_i2c_cmd {
 	u8 opcode;
 	u8 param1;
 	__le16 param2;
-	u8 data[MAX_RSP_SIZE];
+	u8 data[ATMEL_I2C_MAX_RSP_SIZE];
 	u8 msecs;
 	u16 rxsize;
 } __packed;
@@ -77,39 +88,6 @@ struct atmel_i2c_of_match_data {
 	size_t eeprom_zone_size[3]; /* all atmel devices have three zones */
 };
 
-/* Status/Error codes */
-#define STATUS_SIZE			0x04
-#define STATUS_NOERR			0x00
-#define STATUS_WAKE_SUCCESSFUL		0x11
-
-/* Definitions for Indexes common to all commands */
-#define ATMEL_I2C_RSP_DATA_IDX		1 /* buffer index of data in response */
-#define DATA_SLOT_2			2 /* used for ECDH private key */
-
-/*
- * Wake High delay to data communication (microseconds). SDA should be stable
- * high for this entire duration.
- */
-#define TWHI_MIN			1500
-#define TWHI_MAX			1550
-
-/* Wake Low duration */
-#define TWLO_USEC			60
-
-/* Definitions for the READ Command */
-#define ATMEL_I2C_READ_COUNT		7
-
-/* Definitions for the RANDOM Command */
-#define RANDOM_COUNT			7
-
-/* Definitions for the GenKey Command */
-#define GENKEY_COUNT			7
-#define GENKEY_MODE_PRIVATE		0x04
-
-/* Definitions for the ECDH Command */
-#define ECDH_COUNT			71
-#define ECDH_PREFIX_MODE		0x00
-
 /* Used for binding tfm objects to i2c clients. */
 enum atmel_i2c_capability {
 	ATMEL_CAP_ECDH = 0,
@@ -144,7 +122,7 @@ struct atmel_i2c_client_priv {
 	struct i2c_client *client;
 	struct list_head i2c_client_list_node;
 	struct mutex lock;
-	u8 wake_token[WAKE_TOKEN_MAX_SIZE];
+	u8 wake_token[ATMEL_I2C_WAKE_TOKEN_MAX_SIZE];
 	size_t wake_token_sz;
 	atomic_t tfm_count ____cacheline_aligned;
 	struct hwrng hwrng;
-- 
2.53.0


^ permalink raw reply related

* [PATCH 10/12] crypto: atmel - update workqueue flags and add flush on exit
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260512224349.64621-1-l.rubusch@gmail.com>

Update workqueue initialization to use WQ_MEM_RECLAIM instead of
WQ_PERCPU. WQ_MEM_RECLAIM already provides per-CPU execution
semantics via a bound workqueue while also ensuring forward progress
via a rescue thread.

Add a flush_workqueue() call during module exit to ensure all queued
work is completed before destroying the workqueue.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
 drivers/crypto/atmel-i2c.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index 50b6bce478d2..0ec2d768a763 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -626,12 +626,13 @@ EXPORT_SYMBOL(atmel_i2c_probe);
 
 static int __init atmel_i2c_init(void)
 {
-	atmel_wq = alloc_workqueue("atmel_wq", WQ_PERCPU, 0);
+	atmel_wq = alloc_workqueue("atmel_wq", WQ_MEM_RECLAIM, 0);
 	return atmel_wq ? 0 : -ENOMEM;
 }
 
 static void __exit atmel_i2c_exit(void)
 {
+	flush_workqueue(atmel_wq);
 	destroy_workqueue(atmel_wq);
 }
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH 09/12] crypto: atmel - check client data in remove callbacks
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260512224349.64621-1-l.rubusch@gmail.com>

Check the i2c client private data pointer in the remove callbacks of
the Atmel ECC and SHA204A drivers before accessing driver state.
Move sysfs group removal ahead of the NULL check so cleanup can still
proceed even if client data is unavailable. Also downgrade the
busy-device warning in the ECC remove path from dev_emerg() to
dev_warn().

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
 drivers/crypto/atmel-ecc.c     | 20 ++++++--------------
 drivers/crypto/atmel-sha204a.c |  7 +++++--
 2 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index f6d1a9694d63..9ad6d42b6eef 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -380,19 +380,13 @@ 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");
+	sysfs_remove_group(&client->dev.kobj, &atmel_ecc508a_groups);
+
+	if (!i2c_priv)
 		return;
-	}
+
+	if (atomic_read(&i2c_priv->tfm_count))
+		dev_warn(&client->dev, "Device is busy, remove it anyhow\n");
 
 	atmel_i2c_unregister_client(i2c_priv);
 	atmel_i2c_flush_queue();
@@ -403,8 +397,6 @@ static void atmel_ecc_remove(struct i2c_client *client)
 		kfree((void *)i2c_priv->hwrng.priv);
 		i2c_priv->hwrng.priv = 0;
 	}
-
-	sysfs_remove_group(&client->dev.kobj, &atmel_ecc508a_groups);
 }
 
 static const struct atmel_i2c_of_match_data atecc508a_match_data = {
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 88726f6ef87c..6a41024ae40d 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -111,6 +111,11 @@ static void atmel_sha204a_remove(struct i2c_client *client)
 {
 	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
 
+	sysfs_remove_group(&client->dev.kobj, &atmel_sha204a_groups);
+
+	if (!i2c_priv)
+		return;
+
 	devm_hwrng_unregister(&client->dev, &i2c_priv->hwrng);
 	atmel_i2c_flush_queue();
 
@@ -118,8 +123,6 @@ static void atmel_sha204a_remove(struct i2c_client *client)
 		kfree((void *)i2c_priv->hwrng.priv);
 		i2c_priv->hwrng.priv = 0;
 	}
-
-	sysfs_remove_group(&client->dev.kobj, &atmel_sha204a_groups);
 }
 
 static const struct atmel_i2c_of_match_data atsha204_match_data = {
-- 
2.53.0


^ permalink raw reply related

* [PATCH 08/12] crypto: atmel - move device sanity check to core driver
From: Lothar Rubusch @ 2026-05-12 22:43 UTC (permalink / raw)
  To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
	claudiu.beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260512224349.64621-1-l.rubusch@gmail.com>

Move the device sanity check implementation into the shared Atmel
I2C core driver and reuse the generic EEPROM access helpers for
reading the CONFIG zone lock state.

This removes duplicate CONFIG zone handling and consolidates common
response index and lock state definitions under the Atmel I2C core
namespace.

Update both SHA204A and ECC drivers to invoke the shared sanity
check helper during probe.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
 drivers/crypto/atmel-ecc.c     | 10 ++++++--
 drivers/crypto/atmel-i2c.c     | 43 ++++++++++++----------------------
 drivers/crypto/atmel-i2c.h     | 14 +++--------
 drivers/crypto/atmel-sha204a.c |  6 +++++
 4 files changed, 32 insertions(+), 41 deletions(-)

diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index f08fdf284b60..f6d1a9694d63 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -81,7 +81,7 @@ static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq,
 
 	/* copy the shared secret */
 	copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, n_sz),
-				     &cmd->data[RSP_DATA_IDX], n_sz);
+				     &cmd->data[ATMEL_I2C_RSP_DATA_IDX], n_sz);
 	if (copied != n_sz)
 		status = -EINVAL;
 
@@ -144,7 +144,7 @@ static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
 		goto free_public_key;
 
 	/* save the public key */
-	memcpy(public_key, &cmd->data[RSP_DATA_IDX], ATMEL_ECC_PUBKEY_SIZE);
+	memcpy(public_key, &cmd->data[ATMEL_I2C_RSP_DATA_IDX], ATMEL_ECC_PUBKEY_SIZE);
 	ctx->public_key = public_key;
 
 	kfree(cmd);
@@ -323,6 +323,12 @@ static int atmel_ecc_probe(struct i2c_client *client)
 	i2c_priv->data = data;
 	i2c_priv->caps = BIT(ATMEL_CAP_ECDH);
 
+	ret = atmel_i2c_device_sanity_check(client);
+	if (ret) {
+		dev_err(&client->dev, "failed to read EEPROM, is hardware attached?\n");
+		goto done;
+	}
+
 	/* add to client list */
 	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
 	list_add_tail(&i2c_priv->i2c_client_list_node,
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index 26863573a10f..50b6bce478d2 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -23,6 +23,11 @@
 
 #define ATMEL_I2C_COMMAND			0x03 /* packet function */
 
+/* Definitions for the device lock state */
+#define ATMEL_I2C_DEVICE_LOCK_ADDR		0x15
+#define ATMEL_I2C_LOCK_VALUE_IDX		(ATMEL_I2C_RSP_DATA_IDX + 2)
+#define ATMEL_I2C_LOCK_CONFIG_IDX		(ATMEL_I2C_RSP_DATA_IDX + 3)
+
 /* Command opcode */
 #define ATMEL_I2C_OPCODE_ECDH			0x43
 #define ATMEL_I2C_OPCODE_GENKEY			0x40
@@ -129,26 +134,6 @@ static int atmel_i2c_init_read_eeprom_cmd(struct atmel_i2c_cmd *cmd, u16 addr,
 	return 0;
 }
 
-void atmel_i2c_init_read_config_cmd(struct atmel_i2c_cmd *cmd,
-				    const struct atmel_i2c_max_exec_timings *timings)
-{
-	cmd->word_addr = ATMEL_I2C_COMMAND;
-	cmd->opcode = ATMEL_I2C_OPCODE_READ;
-	/*
-	 * Read the word from Configuration zone that contains the lock bytes
-	 * (UserExtra, Selector, LockValue, LockConfig).
-	 */
-	cmd->param1 = CONFIGURATION_ZONE;
-	cmd->param2 = cpu_to_le16(DEVICE_LOCK_ADDR);
-	cmd->count = ATMEL_I2C_READ_COUNT;
-
-	atmel_i2c_checksum(cmd);
-
-	cmd->msecs = timings->max_exec_time_read;
-	cmd->rxsize = ATMEL_I2C_READ_RSP_SIZE;
-}
-EXPORT_SYMBOL(atmel_i2c_init_read_config_cmd);
-
 void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd,
 			       const struct atmel_i2c_max_exec_timings *timings)
 {
@@ -247,7 +232,7 @@ static int atmel_i2c_rng_read_nonblocking(struct hwrng *rng, void *buf,
 	if (rng->priv) {
 		work_data = (struct atmel_i2c_work_data *)rng->priv;
 		max = min(RANDOM_RSP_SIZE - CMD_OVERHEAD_SIZE, max);
-		memcpy(buf, &work_data->cmd.data[RSP_DATA_IDX], max);
+		memcpy(buf, &work_data->cmd.data[ATMEL_I2C_RSP_DATA_IDX], max);
 		rng->priv = 0;
 	} else {
 		work_data = kmalloc_obj(*work_data, GFP_ATOMIC);
@@ -287,7 +272,7 @@ static int atmel_i2c_rng_read(struct hwrng *rng, void *buf, size_t max,
 		return ret;
 
 	max = min(RANDOM_RSP_SIZE - CMD_OVERHEAD_SIZE, max);
-	memcpy(buf, &cmd.data[RSP_DATA_IDX], max);
+	memcpy(buf, &cmd.data[ATMEL_I2C_RSP_DATA_IDX], max);
 
 	return max;
 }
@@ -338,7 +323,7 @@ static int atmel_i2c_eeprom_read(struct i2c_client *client, u16 addr,
 		goto err;
 	}
 
-	memcpy(buf, cmd->data + RSP_DATA_IDX, 4);
+	memcpy(buf, cmd->data + ATMEL_I2C_RSP_DATA_IDX, 4);
 
 err:
 	kfree(cmd);
@@ -542,7 +527,7 @@ static inline size_t atmel_i2c_wake_token_sz(u32 bus_clk_rate)
 	return DIV_ROUND_UP(no_of_bits, 8);
 }
 
-static int device_sanity_check(struct i2c_client *client)
+int atmel_i2c_device_sanity_check(struct i2c_client *client)
 {
 	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
 	const struct atmel_i2c_of_match_data *data = i2c_priv->data;
@@ -553,7 +538,8 @@ static int device_sanity_check(struct i2c_client *client)
 	if (!cmd)
 		return -ENOMEM;
 
-	atmel_i2c_init_read_config_cmd(cmd, &data->timings);
+	atmel_i2c_init_read_eeprom_cmd(cmd, ATMEL_I2C_DEVICE_LOCK_ADDR,
+				       ATMEL_EEPROM_CONFIG_ZONE, data);
 
 	ret = atmel_i2c_send_receive(client, cmd);
 	if (ret)
@@ -565,8 +551,8 @@ static int device_sanity_check(struct i2c_client *client)
 	 * Failure to lock these zones may permit modification of any secret
 	 * keys and may lead to other security problems.
 	 */
-	if (cmd->data[LOCK_CONFIG_IDX] || cmd->data[LOCK_VALUE_IDX]) {
-		dev_err(&client->dev, "Configuration or Data and OTP zones are unlocked!\n");
+	if (cmd->data[ATMEL_I2C_LOCK_CONFIG_IDX] || cmd->data[ATMEL_I2C_LOCK_VALUE_IDX]) {
+		dev_err(&client->dev, "Config, Data and OTP zones are unlocked!\n");
 		ret = -ENOTSUPP;
 	}
 
@@ -575,6 +561,7 @@ static int device_sanity_check(struct i2c_client *client)
 	kfree(cmd);
 	return ret;
 }
+EXPORT_SYMBOL(atmel_i2c_device_sanity_check);
 
 void atmel_i2c_unregister_client(struct atmel_i2c_client_priv *i2c_priv)
 {
@@ -633,7 +620,7 @@ int atmel_i2c_probe(struct i2c_client *client)
 
 	i2c_set_clientdata(client, i2c_priv);
 
-	return device_sanity_check(client);
+	return 0;
 }
 EXPORT_SYMBOL(atmel_i2c_probe);
 
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index e30e0c417de2..2f76e107340e 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -82,18 +82,10 @@ struct atmel_i2c_of_match_data {
 #define STATUS_NOERR			0x00
 #define STATUS_WAKE_SUCCESSFUL		0x11
 
-/* Definitions for eeprom organization */
-#define CONFIGURATION_ZONE		0
-
 /* Definitions for Indexes common to all commands */
-#define RSP_DATA_IDX			1 /* buffer index of data in response */
+#define ATMEL_I2C_RSP_DATA_IDX		1 /* buffer index of data in response */
 #define DATA_SLOT_2			2 /* used for ECDH private key */
 
-/* Definitions for the device lock state */
-#define DEVICE_LOCK_ADDR		0x15
-#define LOCK_VALUE_IDX			(RSP_DATA_IDX + 2)
-#define LOCK_CONFIG_IDX			(RSP_DATA_IDX + 3)
-
 /*
  * Wake High delay to data communication (microseconds). SDA should be stable
  * high for this entire duration.
@@ -195,8 +187,6 @@ void atmel_i2c_flush_queue(void);
 
 int atmel_i2c_send_receive(struct i2c_client *client, struct atmel_i2c_cmd *cmd);
 
-void atmel_i2c_init_read_config_cmd(struct atmel_i2c_cmd *cmd,
-				    const struct atmel_i2c_max_exec_timings *timings);
 void atmel_i2c_init_random_cmd(struct atmel_i2c_cmd *cmd,
 			       const struct atmel_i2c_max_exec_timings *timings);
 void atmel_i2c_init_genkey_cmd(struct atmel_i2c_cmd *cmd, u16 keyid,
@@ -207,6 +197,8 @@ int atmel_i2c_init_ecdh_cmd(struct atmel_i2c_cmd *cmd,
 int atmel_i2c_register_rng(struct atmel_i2c_client_priv *i2c_priv,
 			   struct device *dev);
 
+int atmel_i2c_device_sanity_check(struct i2c_client *client);
+
 ssize_t atmel_i2c_eeprom_display(struct device *dev,
 				 struct device_attribute *attr,
 				 char *buf,
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 341554b7b7a2..88726f6ef87c 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -64,6 +64,12 @@ static int atmel_sha204a_probe(struct i2c_client *client)
 	i2c_priv->data = data;
 	i2c_priv->caps = 0;
 
+	ret = atmel_i2c_device_sanity_check(client);
+	if (ret) {
+		dev_err(&client->dev, "failed to read EEPROM, is hardware attached?\n");
+		goto done;
+	}
+
 	/* add to client list */
 	spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
 	list_add_tail(&i2c_priv->i2c_client_list_node,
-- 
2.53.0


^ permalink raw reply related


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