* [PATCH] crypto: qat - fix restarting state leak on allocation failure
From: Ahsan Atta @ 2026-05-20 12:33 UTC (permalink / raw)
To: herbert
Cc: linux-crypto, qat-linux, Ahsan Atta, stable, Maksim Lukoshkov,
Giovanni Cabiddu
In adf_dev_aer_schedule_reset(), ADF_STATUS_RESTARTING is set before
allocating reset_data. If the allocation fails, the function returns
-ENOMEM without queuing reset work, so nothing ever clears the bit.
This leaves the device permanently stuck in the restarting state,
causing all subsequent reset attempts to be silently skipped.
Fix this by using test_and_set_bit() to atomically claim the
RESTARTING state, preventing duplicate reset scheduling races under
concurrent fatal error reporting. If the subsequent allocation fails,
clear the bit to restore clean state so future reset attempts can
proceed.
Cc: stable@vger.kernel.org
Fixes: d8cba25d2c68 ("crypto: qat - Intel(R) QAT driver framework")
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Co-developed-by: Maksim Lukoshkov <maksim.lukoshkov@intel.com>
Signed-off-by: Maksim Lukoshkov <maksim.lukoshkov@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
---
drivers/crypto/intel/qat/qat_common/adf_aer.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c
index af028488e660..3fc7d13e882c 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c
@@ -207,13 +207,14 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev,
struct adf_reset_dev_data *reset_data;
if (!adf_dev_started(accel_dev) ||
- test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
+ test_and_set_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
return 0;
- set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
reset_data = kzalloc_obj(*reset_data);
- if (!reset_data)
+ if (!reset_data) {
+ clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
return -ENOMEM;
+ }
reset_data->accel_dev = accel_dev;
init_completion(&reset_data->compl);
reset_data->mode = mode;
--
2.50.1
--------------------------------------------------------------
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] crypto: qat - protect service table iterations with service_lock
From: Ahsan Atta @ 2026-05-20 12:41 UTC (permalink / raw)
To: herbert
Cc: linux-crypto, qat-linux, Ahsan Atta, stable, Maksim Lukoshkov,
Giovanni Cabiddu
The service_table list is protected by service_lock when entries are
added or removed (in adf_service_add() and adf_service_remove()), but
several functions iterate over the list without holding this lock.
A concurrent adf_service_register() or adf_service_unregister() call
could modify the list during traversal, leading to list corruption or
a use-after-free.
Fix this by holding service_lock across all list_for_each_entry()
iterations of service_table in adf_dev_init(), adf_dev_start(),
adf_dev_stop(), adf_dev_shutdown(), adf_dev_restarting_notify(),
adf_dev_restarted_notify(), and adf_error_notifier().
The lock ordering is safe: callers of the static helpers (adf_dev_up()
and adf_dev_down()) acquire state_lock before service_lock, and no
event_hld callback or service_lock holder ever acquires state_lock in
the reverse order.
Cc: stable@vger.kernel.org
Fixes: d8cba25d2c68 ("crypto: qat - Intel(R) QAT driver framework")
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Co-developed-by: Maksim Lukoshkov <maksim.lukoshkov@intel.com>
Signed-off-by: Maksim Lukoshkov <maksim.lukoshkov@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
---
drivers/crypto/intel/qat/qat_common/adf_init.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c
index f9f5696ed476..1c7f9e49914d 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_init.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_init.c
@@ -155,15 +155,18 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev)
* This is to facilitate any ordering dependencies between services
* prior to starting any of the accelerators.
*/
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_INIT)) {
dev_err(&GET_DEV(accel_dev),
"Failed to initialise service %s\n",
service->name);
+ mutex_unlock(&service_lock);
return -EFAULT;
}
set_bit(accel_dev->accel_id, service->init_status);
}
+ mutex_unlock(&service_lock);
return 0;
}
@@ -233,15 +236,18 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev)
if (ret && ret != -EOPNOTSUPP)
return ret;
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_START)) {
dev_err(&GET_DEV(accel_dev),
"Failed to start service %s\n",
service->name);
+ mutex_unlock(&service_lock);
return -EFAULT;
}
set_bit(accel_dev->accel_id, service->start_status);
}
+ mutex_unlock(&service_lock);
clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
set_bit(ADF_STATUS_STARTED, &accel_dev->status);
@@ -315,6 +321,7 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev)
qat_comp_algs_unregister(hw_data->accel_capabilities_ext_mask);
clear_bit(ADF_STATUS_COMP_ALGS_REGISTERED, &accel_dev->status);
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (!test_bit(accel_dev->accel_id, service->start_status))
continue;
@@ -326,6 +333,7 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev)
clear_bit(accel_dev->accel_id, service->start_status);
}
}
+ mutex_unlock(&service_lock);
if (hw_data->stop_timer)
hw_data->stop_timer(accel_dev);
@@ -375,6 +383,7 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
&accel_dev->status);
}
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (!test_bit(accel_dev->accel_id, service->init_status))
continue;
@@ -385,6 +394,7 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
else
clear_bit(accel_dev->accel_id, service->init_status);
}
+ mutex_unlock(&service_lock);
adf_rl_exit(accel_dev);
@@ -419,12 +429,14 @@ int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev)
{
struct service_hndl *service;
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_RESTARTING))
dev_err(&GET_DEV(accel_dev),
"Failed to restart service %s.\n",
service->name);
}
+ mutex_unlock(&service_lock);
return 0;
}
@@ -432,12 +444,14 @@ int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev)
{
struct service_hndl *service;
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_RESTARTED))
dev_err(&GET_DEV(accel_dev),
"Failed to restart service %s.\n",
service->name);
}
+ mutex_unlock(&service_lock);
return 0;
}
@@ -445,12 +459,14 @@ void adf_error_notifier(struct adf_accel_dev *accel_dev)
{
struct service_hndl *service;
+ mutex_lock(&service_lock);
list_for_each_entry(service, &service_table, list) {
if (service->event_hld(accel_dev, ADF_EVENT_FATAL_ERROR))
dev_err(&GET_DEV(accel_dev),
"Failed to send error event to %s.\n",
service->name);
}
+ mutex_unlock(&service_lock);
}
int adf_dev_down(struct adf_accel_dev *accel_dev)
--
2.50.1
--------------------------------------------------------------
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] crypto: qat - use pci logging variants for PCI-specific messages
From: Ahsan Atta @ 2026-05-20 12:51 UTC (permalink / raw)
To: herbert
Cc: linux-crypto, qat-linux, Ahsan Atta, Andy Shevchenko,
Giovanni Cabiddu
Replace dev_err(&pdev->dev, ...), dev_info(&pdev->dev, ...) and
dev_dbg(&pdev->dev, ...) with pci_err(), pci_info() and pci_dbg()
where the log message relates to a PCI subsystem operation such as
device enable, BAR mapping, PCI region requests, PCI state
save/restore, and SR-IOV management.
Messages about driver-level logic (NUMA topology, device matching,
accelerator units, capabilities, configuration, DMA) are intentionally
left as dev_err() even when a struct pci_dev pointer is in scope,
since those concern the device or driver rather than the PCI bus.
No functional change.
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/crypto/intel/qat/qat_420xx/adf_drv.c | 8 +++----
drivers/crypto/intel/qat/qat_4xxx/adf_drv.c | 8 +++----
drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c | 4 ++--
.../crypto/intel/qat/qat_c3xxxvf/adf_drv.c | 2 +-
drivers/crypto/intel/qat/qat_c62x/adf_drv.c | 4 ++--
drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c | 2 +-
drivers/crypto/intel/qat/qat_common/adf_aer.c | 21 +++++++++----------
.../crypto/intel/qat/qat_common/adf_sriov.c | 2 +-
.../crypto/intel/qat/qat_dh895xcc/adf_drv.c | 4 ++--
.../crypto/intel/qat/qat_dh895xccvf/adf_drv.c | 2 +-
10 files changed, 28 insertions(+), 29 deletions(-)
diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
index 265bd52778c5..0f0827e2b0bd 100644
--- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c
@@ -101,7 +101,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Enable PCI device */
ret = pcim_enable_device(pdev);
if (ret) {
- dev_err(&pdev->dev, "Can't enable PCI device.\n");
+ pci_err(pdev, "Can't enable PCI device.\n");
goto out_err;
}
@@ -131,7 +131,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ret = pcim_request_all_regions(pdev, pci_name(pdev));
if (ret) {
- dev_err(&pdev->dev, "Failed to request PCI regions.\n");
+ pci_err(pdev, "Failed to request PCI regions.\n");
goto out_err;
}
@@ -140,14 +140,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bar = &accel_pci_dev->pci_bars[i++];
bar->virt_addr = pcim_iomap(pdev, bar_nr, 0);
if (!bar->virt_addr) {
- dev_err(&pdev->dev, "Failed to ioremap PCI region.\n");
+ pci_err(pdev, "Failed to ioremap PCI region.\n");
ret = -ENOMEM;
goto out_err;
}
}
if (pci_save_state(pdev)) {
- dev_err(&pdev->dev, "Failed to save pci state.\n");
+ pci_err(pdev, "Failed to save pci state.\n");
ret = -ENOMEM;
goto out_err;
}
diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
index 681c4dd8f3d2..aa95f762cb4b 100644
--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c
@@ -103,7 +103,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Enable PCI device */
ret = pcim_enable_device(pdev);
if (ret) {
- dev_err(&pdev->dev, "Can't enable PCI device.\n");
+ pci_err(pdev, "Can't enable PCI device.\n");
goto out_err;
}
@@ -133,7 +133,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ret = pcim_request_all_regions(pdev, pci_name(pdev));
if (ret) {
- dev_err(&pdev->dev, "Failed to request PCI regions.\n");
+ pci_err(pdev, "Failed to request PCI regions.\n");
goto out_err;
}
@@ -142,14 +142,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bar = &accel_pci_dev->pci_bars[i++];
bar->virt_addr = pcim_iomap(pdev, bar_nr, 0);
if (!bar->virt_addr) {
- dev_err(&pdev->dev, "Failed to ioremap PCI region.\n");
+ pci_err(pdev, "Failed to ioremap PCI region.\n");
ret = -ENOMEM;
goto out_err;
}
}
if (pci_save_state(pdev)) {
- dev_err(&pdev->dev, "Failed to save pci state.\n");
+ pci_err(pdev, "Failed to save pci state.\n");
ret = -ENOMEM;
goto out_err;
}
diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
index ded52744b4fc..e816cc00632f 100644
--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c
@@ -162,14 +162,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bar->size = pci_resource_len(pdev, bar_nr);
bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0);
if (!bar->virt_addr) {
- dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr);
+ pci_err(pdev, "Failed to map BAR %d\n", bar_nr);
ret = -EFAULT;
goto out_err_free_reg;
}
}
if (pci_save_state(pdev)) {
- dev_err(&pdev->dev, "Failed to save pci state\n");
+ pci_err(pdev, "Failed to save pci state\n");
ret = -ENOMEM;
goto out_err_free_reg;
}
diff --git a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
index e7600d284ed3..1c77f0a1882b 100644
--- a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c
@@ -158,7 +158,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bar->size = pci_resource_len(pdev, bar_nr);
bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0);
if (!bar->virt_addr) {
- dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr);
+ pci_err(pdev, "Failed to map BAR %d\n", bar_nr);
ret = -EFAULT;
goto out_err_free_reg;
}
diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
index 2ebff5855b01..f48f3b437545 100644
--- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c
@@ -162,14 +162,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bar->size = pci_resource_len(pdev, bar_nr);
bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0);
if (!bar->virt_addr) {
- dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr);
+ pci_err(pdev, "Failed to map BAR %d\n", bar_nr);
ret = -EFAULT;
goto out_err_free_reg;
}
}
if (pci_save_state(pdev)) {
- dev_err(&pdev->dev, "Failed to save pci state\n");
+ pci_err(pdev, "Failed to save pci state\n");
ret = -ENOMEM;
goto out_err_free_reg;
}
diff --git a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
index 91e148bb4870..b96f19e31d05 100644
--- a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c
@@ -158,7 +158,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bar->size = pci_resource_len(pdev, bar_nr);
bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0);
if (!bar->virt_addr) {
- dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr);
+ pci_err(pdev, "Failed to map BAR %d\n", bar_nr);
ret = -EFAULT;
goto out_err_free_reg;
}
diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c
index 3fc7d13e882c..d58cd7fbf707 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c
@@ -22,7 +22,7 @@ static pci_ers_result_t reset_prepare(struct pci_dev *pdev)
struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev);
if (!accel_dev) {
- dev_err(&pdev->dev, "Can't find acceleration device\n");
+ pci_err(pdev, "Can't find acceleration device\n");
return PCI_ERS_RESULT_DISCONNECT;
}
@@ -46,7 +46,7 @@ static pci_ers_result_t reset_done(struct pci_dev *pdev)
int res;
if (!accel_dev) {
- dev_err(&pdev->dev, "Can't find acceleration device\n");
+ pci_err(pdev, "Can't find acceleration device\n");
return PCI_ERS_RESULT_DISCONNECT;
}
@@ -64,7 +64,7 @@ static pci_ers_result_t reset_done(struct pci_dev *pdev)
clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
reset_complete:
- dev_info(&pdev->dev, "Device reset completed successfully\n");
+ pci_info(pdev, "Device reset completed successfully\n");
return PCI_ERS_RESULT_RECOVERED;
}
@@ -74,14 +74,14 @@ static pci_ers_result_t adf_error_detected(struct pci_dev *pdev,
{
struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev);
- dev_info(&pdev->dev, "Acceleration driver hardware error detected.\n");
+ pci_info(pdev, "Acceleration driver hardware error detected.\n");
if (!accel_dev) {
- dev_err(&pdev->dev, "Can't find acceleration device\n");
+ pci_err(pdev, "Can't find acceleration device\n");
return PCI_ERS_RESULT_DISCONNECT;
}
if (state == pci_channel_io_perm_failure) {
- dev_err(&pdev->dev, "Can't recover from device error\n");
+ pci_err(pdev, "Can't recover from device error\n");
return PCI_ERS_RESULT_DISCONNECT;
}
@@ -116,10 +116,9 @@ void adf_reset_sbr(struct adf_accel_dev *accel_dev)
parent = pdev;
if (!pci_wait_for_pending_transaction(pdev))
- dev_info(&GET_DEV(accel_dev),
- "Transaction still in progress. Proceeding\n");
+ pci_info(pdev, "Transaction still in progress. Proceeding\n");
- dev_info(&GET_DEV(accel_dev), "Secondary bus reset\n");
+ pci_info(pdev, "Secondary bus reset\n");
pci_read_config_word(parent, PCI_BRIDGE_CONTROL, &bridge_ctl);
bridge_ctl |= PCI_BRIDGE_CTL_BUS_RESET;
@@ -247,8 +246,8 @@ static pci_ers_result_t adf_slot_reset(struct pci_dev *pdev)
static void adf_resume(struct pci_dev *pdev)
{
- dev_info(&pdev->dev, "Acceleration driver reset completed\n");
- dev_info(&pdev->dev, "Device is up and running\n");
+ pci_info(pdev, "Acceleration driver reset completed\n");
+ pci_info(pdev, "Device is up and running\n");
}
static void adf_reset_prepare(struct pci_dev *pdev)
diff --git a/drivers/crypto/intel/qat/qat_common/adf_sriov.c b/drivers/crypto/intel/qat/qat_common/adf_sriov.c
index f2011300a929..f45ca2eecc00 100644
--- a/drivers/crypto/intel/qat/qat_common/adf_sriov.c
+++ b/drivers/crypto/intel/qat/qat_common/adf_sriov.c
@@ -240,7 +240,7 @@ void adf_reenable_sriov(struct adf_accel_dev *accel_dev)
if (adf_add_sriov_configuration(accel_dev))
return;
- dev_dbg(&pdev->dev, "Re-enabling SRIOV\n");
+ pci_dbg(pdev, "Re-enabling SRIOV\n");
adf_enable_sriov(accel_dev);
}
diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
index 97ad53eef38f..571f302edea3 100644
--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c
@@ -162,14 +162,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bar->size = pci_resource_len(pdev, bar_nr);
bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0);
if (!bar->virt_addr) {
- dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr);
+ pci_err(pdev, "Failed to map BAR %d\n", bar_nr);
ret = -EFAULT;
goto out_err_free_reg;
}
}
if (pci_save_state(pdev)) {
- dev_err(&pdev->dev, "Failed to save pci state\n");
+ pci_err(pdev, "Failed to save pci state\n");
ret = -ENOMEM;
goto out_err_free_reg;
}
diff --git a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
index a5edda8bad32..481551a08708 100644
--- a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
+++ b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c
@@ -158,7 +158,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
bar->size = pci_resource_len(pdev, bar_nr);
bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0);
if (!bar->virt_addr) {
- dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr);
+ pci_err(pdev, "Failed to map BAR %d\n", bar_nr);
ret = -EFAULT;
goto out_err_free_reg;
}
--
2.50.1
--------------------------------------------------------------
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
* Re: [PATCH] crypto: octeontx - use strscpy_pad in ucode_load_store
From: David Laight @ 2026-05-20 13:36 UTC (permalink / raw)
To: Thorsten Blum
Cc: Srujana Challa, Bharat Bhushan, Herbert Xu, David S. Miller,
Kees Cook, linux-crypto, linux-kernel
In-Reply-To: <20260520100031.246078-2-thorsten.blum@linux.dev>
On Wed, 20 May 2026 12:00:30 +0200
Thorsten Blum <thorsten.blum@linux.dev> wrote:
> Instead of zero-initializing the temporary buffer and then copying into
> it with strscpy(), use strscpy_pad() to copy the string and zero-pad any
> trailing bytes. Drop the explicit size argument to further simplify the
> code since strscpy_pad() can determine it automatically when the
> destination buffer has a fixed length.
>
> Also use strscpy_pad() to check for string truncation instead of the
> hard-coded OTX_CPT_UCODE_NAME_LENGTH.
This code is horrid :-)
It really ought to be possible to parse the string without taking a writeable
copy.
There is also the 'fun' that it is passed the length of the string - hopefully
it is '\0' terminated at the same length.
Then there is this beauty:
if (strnstr(val, " ", strlen(val)))
-- David
>
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
> drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c b/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> index e0f38d32bc93..205579a6ba2b 100644
> --- a/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> +++ b/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> @@ -1318,7 +1318,7 @@ static ssize_t ucode_load_store(struct device *dev,
> {
> struct otx_cpt_engines engs[OTX_CPT_MAX_ETYPES_PER_GRP] = { {0} };
> char *ucode_filename[OTX_CPT_MAX_ETYPES_PER_GRP];
> - char tmp_buf[OTX_CPT_UCODE_NAME_LENGTH] = { 0 };
> + char tmp_buf[OTX_CPT_UCODE_NAME_LENGTH];
> char *start, *val, *err_msg, *tmp;
> struct otx_cpt_eng_grps *eng_grps;
> int grp_idx = 0, ret = -EINVAL;
> @@ -1326,12 +1326,11 @@ static ssize_t ucode_load_store(struct device *dev,
> int del_grp_idx = -1;
> int ucode_idx = 0;
>
> - if (count >= OTX_CPT_UCODE_NAME_LENGTH)
> + if (strscpy_pad(tmp_buf, buf) < 0)
> return -EINVAL;
>
> eng_grps = container_of(attr, struct otx_cpt_eng_grps, ucode_load_attr);
> err_msg = "Invalid engine group format";
> - strscpy(tmp_buf, buf, OTX_CPT_UCODE_NAME_LENGTH);
> start = tmp_buf;
>
> has_se = has_ie = has_ae = false;
>
^ permalink raw reply
* Re: [PATCH v2 1/3] crypto: atmel-sha204a - Drop of_device_id data
From: Uwe Kleine-König (The Capable Hub) @ 2026-05-20 15:25 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Thorsten Blum, Herbert Xu, David S. Miller, Nicolas Ferre,
Alexandre Belloni, Claudiu Beznea, linux-crypto, linux-arm-kernel,
linux-kernel
In-Reply-To: <46130020-eaa5-44ad-9c6d-62ccb30c19d9@app.fastmail.com>
[-- Attachment #1: Type: text/plain, Size: 2397 bytes --]
Hello Ard,
On Wed, May 20, 2026 at 09:49:49AM +0200, Ard Biesheuvel wrote:
> On Wed, 20 May 2026, at 09:01, Uwe Kleine-König (The Capable Hub) wrote:
> > The driver binds to i2c devices only and thus in the absence of an
> > assignment for .data in the of_device_id array i2c_get_match_data()
> > falls back to .driver_data from the i2c_device_id array. So only provide
> > &atsha204_quality once to reduce duplication.
> >
> > Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> > ---
> > drivers/crypto/atmel-sha204a.c | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
> > index 6e6ac4770416..f17e1f6af1a3 100644
> > --- a/drivers/crypto/atmel-sha204a.c
> > +++ b/drivers/crypto/atmel-sha204a.c
> > @@ -208,8 +208,8 @@ static void atmel_sha204a_remove(struct i2c_client *client)
> > }
> >
> > static const struct of_device_id atmel_sha204a_dt_ids[] = {
> > - { .compatible = "atmel,atsha204", .data = &atsha204_quality },
> > - { .compatible = "atmel,atsha204a", },
> > + { .compatible = "atmel,atsha204" },
> > + { .compatible = "atmel,atsha204a" },
> > { }
> > };
> > MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids);
>
> Just trying to figure out how this is supposed to work:
>
> i2c_get_match_data()
> data = device_get_match_data(&client->dev);
> ... returns NULL ...
> if (!data) {
> match = i2c_match_id(driver->id_table, client);
> ... compares client->name with { "atsha204", "atsha204a" }
>
> So we will be relying on client->name having been set to either
> "atsha204" or "atsha204a" on the DT probe path before
> i2c_match_data() is called, but I am struggling to see where
> that might happen.
That happens when the client is created. Relevant are:
int of_i2c_get_board_info(struct device *dev, struct device_node *node,
...
{
...
if (of_alias_from_compatible(node, info->type, sizeof(info->type)) < 0) {
...
}
which sets info->type from .compatible with the vendor part skipped.
Then
static struct i2c_client *of_i2c_register_device(...)
{
...
ret = of_i2c_get_board_info(&adap->dev, node, &info);
...
client = i2c_new_client_device(adap, &info);
...
}
where i2c_new_client_device() uses info->type to populate client->name.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH v3 00/12] crypto: atmel - introduce shared i2c core client management and capability-based selection framework
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
This patch series introduces a staged refactoring of the Atmel crypto I2C
drivers in preparation for a shared core-based architecture. The goal is to
consolidate I2C client management and selection logic into a common
atmel-i2c core driver while keeping ECC (ECDH) and SHA204A client drivers
functionally separate but interoperating through shared infrastructure.
The series moves existing ECC-specific client tracking into a shared
management structure, relocates allocation and selection logic, and
introduces capability-based filtering for hardware selection. This allows
individual crypto drivers to request hardware clients based on supported
features while still benefiting from a unified least-loaded selection
strategy.
Subsequent patches extend this base by:
- migrating client management fully into the core driver,
- introducing explicit capability advertisement by each hardware client,
- updating ECC and SHA204A drivers to participate in capability-aware allocation,
- and cleaning up probe/remove paths to ensure consistent lifecycle handling.
No functional behavioral changes are intended at this stage beyond internal
refactoring and preparation for future feature expansion. The series is
designed to preserve existing crypto functionality while gradually
centralizing shared logic in the atmel-i2c core layer, reducing duplication
and improving maintainability across all Atmel crypto drivers.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
v2 -> v3:
- sashiko feedback[2]
- ecc: reorder setting ready flag in probe()
- i2c: unconditionally call flush in unregister client function, to avoid UAF for multiple devices
- i2c: fixed a sleep-in-atomic bug by moving atmel_i2c_flush_queue() outside the spin_lock section
- sha204a: reorder calls in remove() avoid UAF flagged risk
- sha204a: rephrase commit messages
[2] https://sashiko.dev/#/patchset/20260519204803.17034-1-l.rubusch%40gmail.com
v1 -> v2:
- going over Sashiko feedback[1]
- rephrasing commit messages and titles
- fix: introduce a ready/state flag to address the UAF risk
- fix: add kpp lock and refcnt to impede overwriting global driver struct
- fix: explicitely clearing rng cached buffer in return branch
- unregistering ready state by dedicated function
- reorder Atmel ECC related things and atmel I2C at beginning
- reorder Atmel SHA204a related things behind introduction of cap
- patches dropped: NULL checks in remove functions
- changed to EXPORT_SYMBOL_GPL
- additionally to alloc hw client also migrate freeing it to core driver
[1] https://sashiko.dev/#/patchset/20260517180639.9657-1-l.rubusch%40gmail.com
---
Lothar Rubusch (12):
crypto: atmel-ecc - rename driver_data before moving it into atmel-i2c
crypto: atmel-ecc - fix use after free situation
crypto: atmel-ecc - fix multi-device kpp registration
crypto: atmel - rename atmel_ecc_driver_data to atmel_i2c_client_mgmt
crypto: atmel-i2c - move client management instance into core
crypto: atmel-i2c - introduce shared teardown helpers and fix queue
flush
crypto: atmel-ecc - switch to module_i2c_driver
crypto: atmel-i2c - move shared client allocation logic to core
crypto: atmel-i2c - implement capability-based client selection
crypto: atmel-sha204a - integrate into core management tracking
crypto: atmel-sha204a - fix heap info leak on I2C transfer failure
crypto: atmel-sha204a - switch to module_i2c_driver
drivers/crypto/atmel-ecc.c | 133 ++++++++++-----------------------
drivers/crypto/atmel-i2c.c | 76 +++++++++++++++++++
drivers/crypto/atmel-i2c.h | 17 ++++-
drivers/crypto/atmel-sha204a.c | 51 ++++++++-----
4 files changed, 166 insertions(+), 111 deletions(-)
base-commit: 6c9dddeb582fde005360f4fe02c760d45ca05fb5
--
2.39.5
^ permalink raw reply
* [PATCH v3 01/12] crypto: atmel-ecc - rename driver_data before moving it into atmel-i2c
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Rename the local driver_data instance to atmel_i2c_mgmt in
preparation for moving the shared I2C client management
infrastructure into the atmel-i2c core driver in a subsequent
change.
No functional changes intended.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 9660f6426a84..c9f798ebf44f 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -23,7 +23,7 @@
#include <crypto/kpp.h>
#include "atmel-i2c.h"
-static struct atmel_ecc_driver_data driver_data;
+static struct atmel_ecc_driver_data atmel_i2c_mgmt;
/**
* struct atmel_ecdh_ctx - transformation context
@@ -209,14 +209,14 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
int min_tfm_cnt = INT_MAX;
int tfm_cnt;
- spin_lock(&driver_data.i2c_list_lock);
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
- if (list_empty(&driver_data.i2c_client_list)) {
- spin_unlock(&driver_data.i2c_list_lock);
+ if (list_empty(&atmel_i2c_mgmt.i2c_client_list)) {
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
return ERR_PTR(-ENODEV);
}
- list_for_each_entry(i2c_priv, &driver_data.i2c_client_list,
+ list_for_each_entry(i2c_priv, &atmel_i2c_mgmt.i2c_client_list,
i2c_client_list_node) {
tfm_cnt = atomic_read(&i2c_priv->tfm_count);
if (tfm_cnt < min_tfm_cnt) {
@@ -232,7 +232,7 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
client = min_i2c_priv->client;
}
- spin_unlock(&driver_data.i2c_list_lock);
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
return client;
}
@@ -323,16 +323,16 @@ static int atmel_ecc_probe(struct i2c_client *client)
i2c_priv = i2c_get_clientdata(client);
- spin_lock(&driver_data.i2c_list_lock);
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
list_add_tail(&i2c_priv->i2c_client_list_node,
- &driver_data.i2c_client_list);
- spin_unlock(&driver_data.i2c_list_lock);
+ &atmel_i2c_mgmt.i2c_client_list);
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
if (ret) {
- spin_lock(&driver_data.i2c_list_lock);
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
list_del(&i2c_priv->i2c_client_list_node);
- spin_unlock(&driver_data.i2c_list_lock);
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
dev_err(&client->dev, "%s alg registration failed\n",
atmel_ecdh_nist_p256.base.cra_driver_name);
@@ -363,9 +363,9 @@ static void atmel_ecc_remove(struct i2c_client *client)
crypto_unregister_kpp(&atmel_ecdh_nist_p256);
- spin_lock(&driver_data.i2c_list_lock);
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
list_del(&i2c_priv->i2c_client_list_node);
- spin_unlock(&driver_data.i2c_list_lock);
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
}
static const struct of_device_id atmel_ecc_dt_ids[] = {
@@ -394,8 +394,8 @@ static struct i2c_driver atmel_ecc_driver = {
static int __init atmel_ecc_init(void)
{
- spin_lock_init(&driver_data.i2c_list_lock);
- INIT_LIST_HEAD(&driver_data.i2c_client_list);
+ spin_lock_init(&atmel_i2c_mgmt.i2c_list_lock);
+ INIT_LIST_HEAD(&atmel_i2c_mgmt.i2c_client_list);
return i2c_add_driver(&atmel_ecc_driver);
}
--
2.39.5
^ permalink raw reply related
* [PATCH v3 02/12] crypto: atmel-ecc - fix use after free situation
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Fixes the very likely race condition, having multiple of such devices
attached (identified by sashiko feedback).
The Scenario:
Thread A (Device 1 Probe): Successfully adds i2c_priv to the global
list (Line 324). The lock is released.
Thread B (An active crypto request): Concurrently calls
atmel_ecc_i2c_client_alloc(). It scans the global list, sees
Device 1, and assigns a crypto job to it.
Thread A: Moves to line 332. crypto_register_kpp() fails (e.g., out of
memory or name clash).
Thread A: Enters the error path. It removes Device 1 from the list and
frees the i2c_priv memory.
Thread B: Is still actively trying to talk to the I2C hardware using
the i2c_priv pointer it grabbed in Step 2. The memory is now
gone. Result: Kernel crash (Use-After-Free).
Fixes: 11105693fa05 ("crypto: atmel-ecc - introduce Microchip / Atmel ECC driver")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 10 ++++++++++
drivers/crypto/atmel-i2c.h | 2 ++
2 files changed, 12 insertions(+)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index c9f798ebf44f..4c6860fc3dd9 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -218,6 +218,8 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
list_for_each_entry(i2c_priv, &atmel_i2c_mgmt.i2c_client_list,
i2c_client_list_node) {
+ if (!i2c_priv->ready)
+ continue;
tfm_cnt = atomic_read(&i2c_priv->tfm_count);
if (tfm_cnt < min_tfm_cnt) {
min_tfm_cnt = tfm_cnt;
@@ -322,20 +324,24 @@ static int atmel_ecc_probe(struct i2c_client *client)
return ret;
i2c_priv = i2c_get_clientdata(client);
+ i2c_priv->ready = false;
spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
list_add_tail(&i2c_priv->i2c_client_list_node,
&atmel_i2c_mgmt.i2c_client_list);
+ i2c_priv->ready = true;
spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
if (ret) {
spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
list_del(&i2c_priv->i2c_client_list_node);
+ i2c_priv->ready = false;
spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
dev_err(&client->dev, "%s alg registration failed\n",
atmel_ecdh_nist_p256.base.cra_driver_name);
+ return ret;
} else {
dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
}
@@ -347,6 +353,10 @@ static void atmel_ecc_remove(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+ i2c_priv->ready = false;
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
/* Return EBUSY if i2c client already allocated. */
if (atomic_read(&i2c_priv->tfm_count)) {
/*
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 72f04c15682f..e3b12030f9c4 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -129,6 +129,7 @@ struct atmel_ecc_driver_data {
* @wake_token_sz : size in bytes of the wake_token
* @tfm_count : number of active crypto transformations on i2c client
* @hwrng : hold the hardware generated rng
+ * @ready : hw client is ready to use
*
* Reads and writes from/to the i2c client are sequential. The first byte
* transmitted to the device is treated as the byte size. Any attempt to send
@@ -145,6 +146,7 @@ struct atmel_i2c_client_priv {
size_t wake_token_sz;
atomic_t tfm_count ____cacheline_aligned;
struct hwrng hwrng;
+ bool ready;
};
/**
--
2.39.5
^ permalink raw reply related
* [PATCH v3 03/12] crypto: atmel-ecc - fix multi-device kpp registration
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
In a scenario where multiple such devices are attached, the following
situation may arise (finding by sashiko):
Device 1 Probes:
Calls crypto_register_kpp(&atmel_ecdh_nist_p256). The Crypto Core modifies
fields inside this global structure to link it into the system-wide
algorithm list. Registration succeeds.
Device 2 Probes (Minutes later, on a system with two of these I2C chips):
It executes the exact same line of code. It passes the exact same global
&atmel_ecdh_nist_p256 memory address to crypto_register_kpp().
The Disaster:
The Crypto Core tries to register it again. It overwrites the internal
fields that Device 1 was already using. This corrupts the Linux crypto
subsystem's internal linked lists, usually leading to an immediate kernel
panic or silent memory corruption.
Introduce a global mutex and reference counter to ensure that the static
kpp algorithm is registered only once by the first probing device, and
unregistered only when the last matching device is removed.
Fixes: 11105693fa05 ("crypto: atmel-ecc - introduce Microchip / Atmel ECC driver")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 56 ++++++++++++++++++++------------------
1 file changed, 30 insertions(+), 26 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 4c6860fc3dd9..2f82f529228d 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -23,6 +23,9 @@
#include <crypto/kpp.h>
#include "atmel-i2c.h"
+static DEFINE_MUTEX(atmel_ecc_kpp_lock);
+static int atmel_ecc_kpp_refcnt;
+
static struct atmel_ecc_driver_data atmel_i2c_mgmt;
/**
@@ -332,20 +335,26 @@ static int atmel_ecc_probe(struct i2c_client *client)
i2c_priv->ready = true;
spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
- ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
- if (ret) {
- spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
- list_del(&i2c_priv->i2c_client_list_node);
- i2c_priv->ready = false;
- spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+ mutex_lock(&atmel_ecc_kpp_lock);
+ if (atmel_ecc_kpp_refcnt == 0) {
+ ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
+ if (ret) {
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+ list_del(&i2c_priv->i2c_client_list_node);
+ i2c_priv->ready = false;
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
- dev_err(&client->dev, "%s alg registration failed\n",
- atmel_ecdh_nist_p256.base.cra_driver_name);
- return ret;
- } else {
- dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
+ dev_err(&client->dev, "%s alg registration failed\n",
+ atmel_ecdh_nist_p256.base.cra_driver_name);
+
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ return ret;
+ }
}
+ atmel_ecc_kpp_refcnt++;
+ mutex_unlock(&atmel_ecc_kpp_lock);
+ dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
return ret;
}
@@ -357,21 +366,16 @@ static void atmel_ecc_remove(struct i2c_client *client)
i2c_priv->ready = false;
spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
- /* Return EBUSY if i2c client already allocated. */
- if (atomic_read(&i2c_priv->tfm_count)) {
- /*
- * After we return here, the memory backing the device is freed.
- * That happens no matter what the return value of this function
- * is because in the Linux device model there is no error
- * handling for unbinding a driver.
- * If there is still some action pending, it probably involves
- * accessing the freed memory.
- */
- dev_emerg(&client->dev, "Device is busy, expect memory corruption.\n");
- return;
- }
-
- crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+ /*
+ * Note, the Linux Crypto Core automatically blocks until all active
+ * transformations utilizing that specific algorithm structure
+ * are fully freed and closed.
+ */
+ mutex_lock(&atmel_ecc_kpp_lock);
+ atmel_ecc_kpp_refcnt--;
+ if (atmel_ecc_kpp_refcnt == 0)
+ crypto_unregister_kpp(&atmel_ecdh_nist_p256);
+ mutex_unlock(&atmel_ecc_kpp_lock);
spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
list_del(&i2c_priv->i2c_client_list_node);
--
2.39.5
^ permalink raw reply related
* [PATCH v3 04/12] crypto: atmel - rename atmel_ecc_driver_data to atmel_i2c_client_mgmt
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Rename struct atmel_ecc_driver_data to atmel_i2c_client_mgmt to reflect its
generic role in shared I2C client tracking and locking. A subsequent change
will move the client management infrastructure into the atmel-i2c core
driver.
No functional changes intended.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 2 +-
drivers/crypto/atmel-i2c.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 2f82f529228d..b06d47babd2e 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -26,7 +26,7 @@
static DEFINE_MUTEX(atmel_ecc_kpp_lock);
static int atmel_ecc_kpp_refcnt;
-static struct atmel_ecc_driver_data atmel_i2c_mgmt;
+static struct atmel_i2c_client_mgmt atmel_i2c_mgmt;
/**
* struct atmel_ecdh_ctx - transformation context
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index e3b12030f9c4..30ed816814af 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -115,7 +115,7 @@ struct atmel_i2c_cmd {
#define ECDH_PREFIX_MODE 0x00
/* Used for binding tfm objects to i2c clients. */
-struct atmel_ecc_driver_data {
+struct atmel_i2c_client_mgmt {
struct list_head i2c_client_list;
spinlock_t i2c_list_lock;
} ____cacheline_aligned;
--
2.39.5
^ permalink raw reply related
* [PATCH v3 05/12] crypto: atmel-i2c - move client management instance into core
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Move the global 'atmel_i2c_mgmt' tracking instance out of the ECC driver
and into the atmel-i2c core library.
This change consolidates the shared I2C client infrastructure into a
central core driver. This centralization allows both the ECC and
upcoming SHA204A driver modules to access and reference a unified,
common device-management context.
As part of this relocation, replace the explicit runtime initialization
calls inside the module init block with static, compile-time macros
(__SPIN_LOCK_UNLOCKED and LIST_HEAD_INIT). Export the tracking structure
via EXPORT_SYMBOL_GPL() to make it available to dependent sub-modules.
No functional change intended.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 4 ----
drivers/crypto/atmel-i2c.c | 6 ++++++
drivers/crypto/atmel-i2c.h | 1 +
3 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index b06d47babd2e..cf6abc94d6c9 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -26,8 +26,6 @@
static DEFINE_MUTEX(atmel_ecc_kpp_lock);
static int atmel_ecc_kpp_refcnt;
-static struct atmel_i2c_client_mgmt atmel_i2c_mgmt;
-
/**
* struct atmel_ecdh_ctx - transformation context
* @client : pointer to i2c client device
@@ -408,8 +406,6 @@ static struct i2c_driver atmel_ecc_driver = {
static int __init atmel_ecc_init(void)
{
- spin_lock_init(&atmel_i2c_mgmt.i2c_list_lock);
- INIT_LIST_HEAD(&atmel_i2c_mgmt.i2c_client_list);
return i2c_add_driver(&atmel_ecc_driver);
}
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index 0e275dbdc8c5..db24f65ae90e 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -21,6 +21,12 @@
#include <linux/workqueue.h>
#include "atmel-i2c.h"
+struct atmel_i2c_client_mgmt atmel_i2c_mgmt = {
+ .i2c_list_lock = __SPIN_LOCK_UNLOCKED(atmel_i2c_mgmt.i2c_list_lock),
+ .i2c_client_list = LIST_HEAD_INIT(atmel_i2c_mgmt.i2c_client_list),
+};
+EXPORT_SYMBOL_GPL(atmel_i2c_mgmt);
+
static const struct {
u8 value;
const char *error_text;
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 30ed816814af..d54bd836e0f5 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -119,6 +119,7 @@ struct atmel_i2c_client_mgmt {
struct list_head i2c_client_list;
spinlock_t i2c_list_lock;
} ____cacheline_aligned;
+extern struct atmel_i2c_client_mgmt atmel_i2c_mgmt;
/**
* atmel_i2c_client_priv - i2c_client private data
--
2.39.5
^ permalink raw reply related
* [PATCH v3 06/12] crypto: atmel-i2c - introduce shared teardown helpers and fix queue flush
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Introduce atmel_i2c_deactivate_client() and atmel_i2c_unregister_client()
helpers in the atmel-i2c core library to modularize client teardown. This
encapsulates common client state tracking and list manipulation operations.
Convert the ECC driver's error recovery and device removal paths to utilize
these new helpers, ensuring consistent execution ordering when modifying
device-readiness states and deleting linked-list nodes.
Additionally, migrate the atmel_i2c_flush_queue() call out of the module
exit path. It now runs inside the core unregistration helper. Export both
new tracking symbols via EXPORT_SYMBOL_GPL() to match the existing core
driver licensing standard.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 16 ++++------------
drivers/crypto/atmel-i2c.c | 20 ++++++++++++++++++++
drivers/crypto/atmel-i2c.h | 3 +++
3 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index cf6abc94d6c9..433f40224be2 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -337,11 +337,8 @@ static int atmel_ecc_probe(struct i2c_client *client)
if (atmel_ecc_kpp_refcnt == 0) {
ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
if (ret) {
- spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
- list_del(&i2c_priv->i2c_client_list_node);
- i2c_priv->ready = false;
- spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
-
+ atmel_i2c_deactivate_client(i2c_priv);
+ atmel_i2c_unregister_client(i2c_priv);
dev_err(&client->dev, "%s alg registration failed\n",
atmel_ecdh_nist_p256.base.cra_driver_name);
@@ -360,9 +357,7 @@ static void atmel_ecc_remove(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
- spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
- i2c_priv->ready = false;
- spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+ atmel_i2c_deactivate_client(i2c_priv);
/*
* Note, the Linux Crypto Core automatically blocks until all active
@@ -375,9 +370,7 @@ static void atmel_ecc_remove(struct i2c_client *client)
crypto_unregister_kpp(&atmel_ecdh_nist_p256);
mutex_unlock(&atmel_ecc_kpp_lock);
- spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
- list_del(&i2c_priv->i2c_client_list_node);
- spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+ atmel_i2c_unregister_client(i2c_priv);
}
static const struct of_device_id atmel_ecc_dt_ids[] = {
@@ -411,7 +404,6 @@ static int __init atmel_ecc_init(void)
static void __exit atmel_ecc_exit(void)
{
- atmel_i2c_flush_queue();
i2c_del_driver(&atmel_ecc_driver);
}
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index db24f65ae90e..cf3c57745414 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -354,6 +354,26 @@ static int device_sanity_check(struct i2c_client *client)
return ret;
}
+void atmel_i2c_deactivate_client(struct atmel_i2c_client_priv *i2c_priv)
+{
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+ i2c_priv->ready = false;
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+}
+EXPORT_SYMBOL_GPL(atmel_i2c_deactivate_client);
+
+void atmel_i2c_unregister_client(struct atmel_i2c_client_priv *i2c_priv)
+{
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+ if (!list_empty(&i2c_priv->i2c_client_list_node))
+ list_del_init(&i2c_priv->i2c_client_list_node);
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
+ /* don't sleep inside spin locks */
+ atmel_i2c_flush_queue();
+}
+EXPORT_SYMBOL_GPL(atmel_i2c_unregister_client);
+
int atmel_i2c_probe(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv;
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index d54bd836e0f5..351306c426aa 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -192,4 +192,7 @@ 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);
+void atmel_i2c_deactivate_client(struct atmel_i2c_client_priv *i2c_priv);
+void atmel_i2c_unregister_client(struct atmel_i2c_client_priv *i2c_priv);
+
#endif /* __ATMEL_I2C_H__ */
--
2.39.5
^ permalink raw reply related
* [PATCH v3 07/12] crypto: atmel-ecc - switch to module_i2c_driver
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Remove custom boilerplate module configuration code and convert the module
init/exit paths to use the modern module_i2c_driver() helper macro.
This shortens and simplifies driver initialization. Custom structure setup
is no longer required here since management tracking context initialization
was already safely moved into the atmel-i2c core library module.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 433f40224be2..f166144febfe 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -397,18 +397,7 @@ static struct i2c_driver atmel_ecc_driver = {
.id_table = atmel_ecc_id,
};
-static int __init atmel_ecc_init(void)
-{
- return i2c_add_driver(&atmel_ecc_driver);
-}
-
-static void __exit atmel_ecc_exit(void)
-{
- i2c_del_driver(&atmel_ecc_driver);
-}
-
-module_init(atmel_ecc_init);
-module_exit(atmel_ecc_exit);
+module_i2c_driver(atmel_ecc_driver);
MODULE_AUTHOR("Tudor Ambarus");
MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");
--
2.39.5
^ permalink raw reply related
* [PATCH v3 08/12] crypto: atmel-i2c - move shared client allocation logic to core
From: Lothar Rubusch @ 2026-05-20 15:56 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Migrate the I2C client allocation and runtime load-balancing routines out
of the ECC driver code and into the central atmel-i2c core library module.
Export the symmetric lifecycle helper interfaces atmel_i2c_client_alloc()
and atmel_i2c_client_free() using EXPORT_SYMBOL_GPL() to expose a unified
client management API. This consolidation enables the dynamic selection
subsystem (which chooses the least-loaded client device based on the active
transformation count) to be shared by both the ECC driver and upcoming
Atmel crypto modules.
Refactor the ECC driver's transformation context initialization (init_tfm)
and teardown (exit_tfm) paths to use this centralized core API.
No functional change is intended.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 50 +++-----------------------------------
drivers/crypto/atmel-i2c.c | 46 +++++++++++++++++++++++++++++++++++
drivers/crypto/atmel-i2c.h | 3 +++
3 files changed, 52 insertions(+), 47 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index f166144febfe..19e9ee9c15e5 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -203,50 +203,6 @@ static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)
return ret;
}
-static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
-{
- struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL;
- struct i2c_client *client = ERR_PTR(-ENODEV);
- int min_tfm_cnt = INT_MAX;
- int tfm_cnt;
-
- spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
-
- if (list_empty(&atmel_i2c_mgmt.i2c_client_list)) {
- spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
- return ERR_PTR(-ENODEV);
- }
-
- list_for_each_entry(i2c_priv, &atmel_i2c_mgmt.i2c_client_list,
- i2c_client_list_node) {
- if (!i2c_priv->ready)
- continue;
- tfm_cnt = atomic_read(&i2c_priv->tfm_count);
- if (tfm_cnt < min_tfm_cnt) {
- min_tfm_cnt = tfm_cnt;
- min_i2c_priv = i2c_priv;
- }
- if (!min_tfm_cnt)
- break;
- }
-
- if (min_i2c_priv) {
- atomic_inc(&min_i2c_priv->tfm_count);
- client = min_i2c_priv->client;
- }
-
- spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
-
- return client;
-}
-
-static void atmel_ecc_i2c_client_free(struct i2c_client *client)
-{
- struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
-
- atomic_dec(&i2c_priv->tfm_count);
-}
-
static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
{
const char *alg = kpp_alg_name(tfm);
@@ -254,7 +210,7 @@ static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
ctx->curve_id = ECC_CURVE_NIST_P256;
- ctx->client = atmel_ecc_i2c_client_alloc();
+ ctx->client = atmel_i2c_client_alloc();
if (IS_ERR(ctx->client)) {
pr_err("tfm - i2c_client binding failed\n");
return PTR_ERR(ctx->client);
@@ -264,7 +220,7 @@ static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
if (IS_ERR(fallback)) {
dev_err(&ctx->client->dev, "Failed to allocate transformation for '%s': %ld\n",
alg, PTR_ERR(fallback));
- atmel_ecc_i2c_client_free(ctx->client);
+ atmel_i2c_client_free(ctx->client);
return PTR_ERR(fallback);
}
@@ -280,7 +236,7 @@ static void atmel_ecdh_exit_tfm(struct crypto_kpp *tfm)
kfree(ctx->public_key);
crypto_free_kpp(ctx->fallback);
- atmel_ecc_i2c_client_free(ctx->client);
+ atmel_i2c_client_free(ctx->client);
}
static unsigned int atmel_ecdh_max_size(struct crypto_kpp *tfm)
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index cf3c57745414..e10713a7bcfe 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -57,6 +57,52 @@ static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd)
*__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len)));
}
+struct i2c_client *atmel_i2c_client_alloc(void)
+{
+ struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL;
+ struct i2c_client *client = ERR_PTR(-ENODEV);
+ int min_tfm_cnt = INT_MAX;
+ int tfm_cnt;
+
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+
+ if (list_empty(&atmel_i2c_mgmt.i2c_client_list)) {
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+ return ERR_PTR(-ENODEV);
+ }
+
+ list_for_each_entry(i2c_priv, &atmel_i2c_mgmt.i2c_client_list,
+ i2c_client_list_node) {
+ if (!i2c_priv->ready)
+ continue;
+ tfm_cnt = atomic_read(&i2c_priv->tfm_count);
+ if (tfm_cnt < min_tfm_cnt) {
+ min_tfm_cnt = tfm_cnt;
+ min_i2c_priv = i2c_priv;
+ }
+ if (!min_tfm_cnt)
+ break;
+ }
+
+ if (min_i2c_priv) {
+ atomic_inc(&min_i2c_priv->tfm_count);
+ client = min_i2c_priv->client;
+ }
+
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
+ return client;
+}
+EXPORT_SYMBOL_GPL(atmel_i2c_client_alloc);
+
+void atmel_i2c_client_free(struct i2c_client *client)
+{
+ struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+
+ atomic_dec(&i2c_priv->tfm_count);
+}
+EXPORT_SYMBOL_GPL(atmel_i2c_client_free);
+
void atmel_i2c_init_read_config_cmd(struct atmel_i2c_cmd *cmd)
{
cmd->word_addr = COMMAND;
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 351306c426aa..6c2d86fd9068 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -192,6 +192,9 @@ 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);
+struct i2c_client *atmel_i2c_client_alloc(void);
+void atmel_i2c_client_free(struct i2c_client *client);
+
void atmel_i2c_deactivate_client(struct atmel_i2c_client_priv *i2c_priv);
void atmel_i2c_unregister_client(struct atmel_i2c_client_priv *i2c_priv);
--
2.39.5
^ permalink raw reply related
* [PATCH v3 09/12] crypto: atmel-i2c - implement capability-based client selection
From: Lothar Rubusch @ 2026-05-20 15:57 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Extend the shared I2C client allocation interface to support feature-aware
hardware selection by introducing capability filtering.
Add a 'caps' mask to 'struct atmel_i2c_client_priv' alongside an
'atmel_i2c_capability' enum. The allocator now explicitly filters hardware
nodes by a requested capability bit while retaining the least-loaded device
load-balancing scheme.
Update the ECC driver to advertise ATMEL_CAP_ECDH configuration capability
during probe, and adapt the tfm context setup execution path to request
this specific capability variant. Initialize the bitmask field to zero
inside the SHA204A driver context for now.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 4 +++-
drivers/crypto/atmel-i2c.c | 6 +++++-
drivers/crypto/atmel-i2c.h | 8 +++++++-
drivers/crypto/atmel-sha204a.c | 2 ++
4 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 19e9ee9c15e5..ec8535b1d4f8 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -210,7 +210,7 @@ static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
ctx->curve_id = ECC_CURVE_NIST_P256;
- ctx->client = atmel_i2c_client_alloc();
+ ctx->client = atmel_i2c_client_alloc(ATMEL_CAP_ECDH);
if (IS_ERR(ctx->client)) {
pr_err("tfm - i2c_client binding failed\n");
return PTR_ERR(ctx->client);
@@ -283,6 +283,8 @@ static int atmel_ecc_probe(struct i2c_client *client)
i2c_priv = i2c_get_clientdata(client);
i2c_priv->ready = false;
+ i2c_priv->caps = BIT(ATMEL_CAP_ECDH);
+
spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
list_add_tail(&i2c_priv->i2c_client_list_node,
&atmel_i2c_mgmt.i2c_client_list);
diff --git a/drivers/crypto/atmel-i2c.c b/drivers/crypto/atmel-i2c.c
index e10713a7bcfe..7ef62b40c353 100644
--- a/drivers/crypto/atmel-i2c.c
+++ b/drivers/crypto/atmel-i2c.c
@@ -57,7 +57,7 @@ static void atmel_i2c_checksum(struct atmel_i2c_cmd *cmd)
*__crc16 = cpu_to_le16(bitrev16(crc16(0, data, len)));
}
-struct i2c_client *atmel_i2c_client_alloc(void)
+struct i2c_client *atmel_i2c_client_alloc(enum atmel_i2c_capability cap)
{
struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL;
struct i2c_client *client = ERR_PTR(-ENODEV);
@@ -75,6 +75,10 @@ struct i2c_client *atmel_i2c_client_alloc(void)
i2c_client_list_node) {
if (!i2c_priv->ready)
continue;
+
+ if (!(i2c_priv->caps & BIT(cap)))
+ continue;
+
tfm_cnt = atomic_read(&i2c_priv->tfm_count);
if (tfm_cnt < min_tfm_cnt) {
min_tfm_cnt = tfm_cnt;
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 6c2d86fd9068..636d21bd1348 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -115,6 +115,10 @@ struct atmel_i2c_cmd {
#define ECDH_PREFIX_MODE 0x00
/* Used for binding tfm objects to i2c clients. */
+enum atmel_i2c_capability {
+ ATMEL_CAP_ECDH = 0,
+};
+
struct atmel_i2c_client_mgmt {
struct list_head i2c_client_list;
spinlock_t i2c_list_lock;
@@ -131,6 +135,7 @@ extern struct atmel_i2c_client_mgmt atmel_i2c_mgmt;
* @tfm_count : number of active crypto transformations on i2c client
* @hwrng : hold the hardware generated rng
* @ready : hw client is ready to use
+ * @caps : feature capability of the particular driver
*
* Reads and writes from/to the i2c client are sequential. The first byte
* transmitted to the device is treated as the byte size. Any attempt to send
@@ -148,6 +153,7 @@ struct atmel_i2c_client_priv {
atomic_t tfm_count ____cacheline_aligned;
struct hwrng hwrng;
bool ready;
+ u32 caps;
};
/**
@@ -192,7 +198,7 @@ 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);
-struct i2c_client *atmel_i2c_client_alloc(void);
+struct i2c_client *atmel_i2c_client_alloc(enum atmel_i2c_capability cap);
void atmel_i2c_client_free(struct i2c_client *client);
void atmel_i2c_deactivate_client(struct atmel_i2c_client_priv *i2c_priv);
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 6e6ac4770416..3853d2b95449 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -173,6 +173,8 @@ static int atmel_sha204a_probe(struct i2c_client *client)
i2c_priv = i2c_get_clientdata(client);
+ i2c_priv->caps = 0;
+
memset(&i2c_priv->hwrng, 0, sizeof(i2c_priv->hwrng));
i2c_priv->hwrng.name = dev_name(&client->dev);
--
2.39.5
^ permalink raw reply related
* [PATCH v3 10/12] crypto: atmel-sha204a - integrate into core management tracking
From: Lothar Rubusch @ 2026-05-20 15:57 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Register the SHA204A I2C device instance into the shared atmel_i2c client
management tracking list during the probe phase. This allows the driver to
participate in the central hardware selection infrastructure.
Rework the error-unwind paths inside atmel_sha204a_probe() to prevent stale
entries from remaining in the global tracking structures if a partial
initialization failure occurs. If sysfs group creation fails, explicitly
trigger devm_hwrng_unregister() to preserve the strict lifecycle ordering
introduced in previous stability fixes.
Convert the removal path to use the core teardown helpers. Ensure the
device readiness state is deactivated using atmel_i2c_deactivate_client()
and the tracking node is removed via atmel_i2c_unregister_client() before
local memory resources are freed. This guarantees that any in-flight work
queue items are unconditionally flushed, eliminating a potential
Use-After-Free (UAF) window during device removal.
No functional change intended beyond improved lifecycle handling.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-sha204a.c | 29 ++++++++++++++++++++++++-----
1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 3853d2b95449..db61ac0177f6 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -172,9 +172,15 @@ static int atmel_sha204a_probe(struct i2c_client *client)
return ret;
i2c_priv = i2c_get_clientdata(client);
+ i2c_priv->ready = false;
i2c_priv->caps = 0;
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+ list_add_tail(&i2c_priv->i2c_client_list_node,
+ &atmel_i2c_mgmt.i2c_client_list);
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
memset(&i2c_priv->hwrng, 0, sizeof(i2c_priv->hwrng));
i2c_priv->hwrng.name = dev_name(&client->dev);
@@ -185,15 +191,28 @@ static int atmel_sha204a_probe(struct i2c_client *client)
i2c_priv->hwrng.quality = *quality;
ret = devm_hwrng_register(&client->dev, &i2c_priv->hwrng);
- if (ret)
+ if (ret) {
dev_warn(&client->dev, "failed to register RNG (%d)\n", ret);
+ goto err_list_del;
+ }
ret = sysfs_create_group(&client->dev.kobj, &atmel_sha204a_groups);
if (ret) {
dev_err(&client->dev, "failed to register sysfs entry\n");
- return ret;
+ goto err_hwrng_unregister;
}
+ spin_lock(&atmel_i2c_mgmt.i2c_list_lock);
+ i2c_priv->ready = true;
+ spin_unlock(&atmel_i2c_mgmt.i2c_list_lock);
+
+ return 0;
+
+err_hwrng_unregister:
+ devm_hwrng_unregister(&client->dev, &i2c_priv->hwrng);
+err_list_del:
+ atmel_i2c_unregister_client(i2c_priv);
+
return ret;
}
@@ -201,9 +220,10 @@ static void atmel_sha204a_remove(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
- devm_hwrng_unregister(&client->dev, &i2c_priv->hwrng);
- atmel_i2c_flush_queue();
+ atmel_i2c_deactivate_client(i2c_priv);
+ devm_hwrng_unregister(&client->dev, &i2c_priv->hwrng);
+ atmel_i2c_unregister_client(i2c_priv);
sysfs_remove_group(&client->dev.kobj, &atmel_sha204a_groups);
kfree((void *)i2c_priv->hwrng.priv);
@@ -239,7 +259,6 @@ static int __init atmel_sha204a_init(void)
static void __exit atmel_sha204a_exit(void)
{
- atmel_i2c_flush_queue();
i2c_del_driver(&atmel_sha204a_driver);
}
--
2.39.5
^ permalink raw reply related
* [PATCH v3 11/12] crypto: atmel-sha204a - fix heap info leak on I2C transfer failure
From: Lothar Rubusch @ 2026-05-20 15:57 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
When a non-blocking read operation is requested, the driver dynamically
allocates memory to track asynchronous transfer status. If the underlying
I2C transmission fails, atmel_sha204a_rng_done() logs a rate-limited
warning but incorrectly proceeds to cache the pointer to this uninitialized
buffer inside the rng->priv data field anyway.
On subsequent execution passes, atmel_sha204a_rng_read_nonblocking()
detects the stale rng->priv value, skips executing a hardware data read,
and copies up to 32 bytes of uninitialized kernel heap data from this
garbage memory pool straight back into the system's hwrng data stream.
Fix this information disclosure vector by immediately releasing the
allocated asynchronous work data buffer and explicitly clearing the
tracking pointer context whenever an I2C transaction returns a non-zero
error status.
Additionally, duplicate the tfm counter decrement within the new error
path to ensure the reference counter is properly released before executing
the early return, maintaining the driver's availability for subsequent
requests.
Fixes: da001fb651b0 ("crypto: atmel-i2c - add support for SHA204A random number generator")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-sha204a.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index db61ac0177f6..b51031ced7d1 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -31,10 +31,15 @@ static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,
struct atmel_i2c_client_priv *i2c_priv = work_data->ctx;
struct hwrng *rng = areq;
- if (status)
+ if (status) {
dev_warn_ratelimited(&i2c_priv->client->dev,
"i2c transaction failed (%d)\n",
status);
+ kfree(work_data);
+ rng->priv = 0;
+ atomic_dec(&i2c_priv->tfm_count);
+ return;
+ }
rng->priv = (unsigned long)work_data;
atomic_dec(&i2c_priv->tfm_count);
--
2.39.5
^ permalink raw reply related
* [PATCH v3 12/12] crypto: atmel-sha204a - switch to module_i2c_driver
From: Lothar Rubusch @ 2026-05-20 15:57 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, ardb, linusw
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
In-Reply-To: <20260520155703.23018-1-l.rubusch@gmail.com>
Replace explicit module init and exit boilerplate functions with the
module_i2c_driver() macro helper to simplify the driver registration
path.
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-sha204a.c | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index b51031ced7d1..41685b1df442 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -257,18 +257,7 @@ static struct i2c_driver atmel_sha204a_driver = {
.driver.of_match_table = atmel_sha204a_dt_ids,
};
-static int __init atmel_sha204a_init(void)
-{
- return i2c_add_driver(&atmel_sha204a_driver);
-}
-
-static void __exit atmel_sha204a_exit(void)
-{
- i2c_del_driver(&atmel_sha204a_driver);
-}
-
-module_init(atmel_sha204a_init);
-module_exit(atmel_sha204a_exit);
+module_i2c_driver(atmel_sha204a_driver);
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
MODULE_DESCRIPTION("Microchip / Atmel SHA204A (I2C) driver");
--
2.39.5
^ permalink raw reply related
* Re: [PATCH] crypto: tegra - Fix dma_free_coherent size error
From: Vladislav Dronov @ 2026-05-20 16:03 UTC (permalink / raw)
To: herbert; +Cc: akhilrajeev, linux-crypto, ptalbert, vdronov
In-Reply-To: <agvleqNqloWB6tpf@gondor.apana.org.au>
Hi, Herbert, thanks!
With the subsequent ENOMEM fix please feel free to use my:
Reviewed-by: Vladislav Dronov <vdronov@redhat.com>
Best regards,
Vladislav Dronov
^ permalink raw reply
* Re: [PATCH] crypto: tegra - Return ENOMEM when input buffer allocation fails for ccm
From: Vladislav Dronov @ 2026-05-20 16:08 UTC (permalink / raw)
To: herbert; +Cc: akhilrajeev, linux-crypto, ptalbert, vdronov
In-Reply-To: <ag0houiGk0cLZ9ls@gondor.apana.org.au>
Hi, Herbert,
Thank you for this fix! Please feel free to use my:
Reviewed-by: Vladislav Dronov <vdronov@redhat.com>
Best regards,
Vladislav Dronov
^ permalink raw reply
* Re: [PATCH] crypto: tegra - Return ENOMEM when input buffer allocation fails for ccm
From: Vladislav Dronov @ 2026-05-20 16:28 UTC (permalink / raw)
To: herbert; +Cc: akhilrajeev, linux-crypto, ptalbert, vdronov
In-Reply-To: <ag0houiGk0cLZ9ls@gondor.apana.org.au>
Hi, Herbert,
I would also add the fixes: tag to your ENOMEM fix:
Fixes: 1e245948ca0c ("crypto: tegra - finalize crypto req on error")
Best regards,
Vladislav Dronov
^ permalink raw reply
* Re: [PATCH v3] crypto/ccp: Introduce SNP_VERIFY_MITIGATION command
From: Tycho Andersen @ 2026-05-20 16:46 UTC (permalink / raw)
To: Pratik R. Sampat
Cc: ashish.kalra, thomas.lendacky, john.allen, herbert, davem,
linux-crypto, linux-kernel, aik, nikunj, michael.roth
In-Reply-To: <36137b565d183fa2f2985ad098f2e2096f1c432f.1779219958.git.prsampat@amd.com>
On Tue, May 19, 2026 at 02:50:29PM -0500, Pratik R. Sampat wrote:
> The SEV-SNP firmware provides the SNP_VERIFY_MITIGATION command, which
> can be used to query the status of currently supported vulnerability
> mitigations and to initiate mitigations within the firmware.
>
> This command is an explicit mechanism to ascertain if a firmware
> mitigation is applied without needing a full RMP re-build, which is most
> useful in a live firmware update scenario.
>
> The firmware supports two subcommands: STATUS and VERIFY. The STATUS
> subcommand is used to query the supported and verified mitigation bits.
> The VERIFY subcommand initiates the mitigation process within the FW for
> the specified vulnerability. Expose a userspace interface under:
> /sys/firmware/sev/vulnerabilities/
> - supported_mitigations (read-only): supported mitigation vector mask
> - verified_mitigations (read/write): current verified mask; write a
> vector to request VERIFY for that bit
>
> The behavior of SNP_VERIFY_MITIGATION and the pre-requisites for using
> it are bug-specific. Information about supported mitigations and its
> corresponding vector is to be published as part of the AMD Security
> Bulletin.
>
> See SEV-SNP Firmware ABI specifications 1.58, SNP_VERIFY_MITIGATION for
> more details.
>
> Signed-off-by: Pratik R. Sampat <prsampat@amd.com>
Reviewed-by: Tycho Andersen (AMD) <tycho@kernel.org>
^ permalink raw reply
* Re: [PATCH v3] crypto/ccp: Introduce SNP_VERIFY_MITIGATION command
From: kernel test robot @ 2026-05-20 18:27 UTC (permalink / raw)
To: Pratik R. Sampat, ashish.kalra, thomas.lendacky, john.allen,
herbert, davem
Cc: oe-kbuild-all, linux-crypto, linux-kernel, aik, tycho, nikunj,
michael.roth, prsampat
In-Reply-To: <36137b565d183fa2f2985ad098f2e2096f1c432f.1779219958.git.prsampat@amd.com>
Hi Pratik,
kernel test robot noticed the following build warnings:
[auto build test WARNING on herbert-cryptodev-2.6/master]
[also build test WARNING on herbert-crypto-2.6/master linus/master v7.1-rc4]
[cannot apply to next-20260520]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Pratik-R-Sampat/crypto-ccp-Introduce-SNP_VERIFY_MITIGATION-command/20260520-035846
base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
patch link: https://lore.kernel.org/r/36137b565d183fa2f2985ad098f2e2096f1c432f.1779219958.git.prsampat%40amd.com
patch subject: [PATCH v3] crypto/ccp: Introduce SNP_VERIFY_MITIGATION command
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260520/202605202038.zpyF8AIf-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605202038.zpyF8AIf-lkp@intel.com/
All warnings (new ones prefixed by >>):
WARNING: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode is defined 2 times: Documentation/ABI/testing/sysfs-driver-hid-lenovo-go:364; Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s:234
WARNING: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/os_mode_index is defined 2 times: Documentation/ABI/testing/sysfs-driver-hid-lenovo-go:373; Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s:243
WARNING: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled is defined 2 times: Documentation/ABI/testing/sysfs-driver-hid-lenovo-go:636; Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s:252
WARNING: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/touchpad/enabled_index is defined 2 times: Documentation/ABI/testing/sysfs-driver-hid-lenovo-go:645; Documentation/ABI/testing/sysfs-driver-hid-lenovo-go-s:261
Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities:1: ERROR: Unexpected indentation. [docutils]
>> Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities:1: WARNING: Block quote ends without a blank line; unexpected unindent. [docutils]
>> Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities:1: WARNING: Definition list ends without a blank line; unexpected unindent. [docutils]
Documentation/arch/riscv/zicfilp.rst:79: WARNING: Inline literal start-string without end-string. [docutils]
Documentation/core-api/kref:328: ./include/linux/kref.h:72: WARNING: Invalid C declaration: Expected end of definition. [error at 96]
int kref_put_mutex (struct kref *kref, void (*release)(struct kref *kref), struct mutex *mutex) __cond_acquires(true# mutex)
------------------------------------------------------------------------------------------------^
Documentation/core-api/kref:328: ./include/linux/kref.h:94: WARNING: Invalid C declaration: Expected end of definition. [error at 92]
vim +1 Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities
> 1 What: /sys/firmware/sev/vulnerabilities/
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v16 01/38] tpm: Initial step to reorganize TPM public headers
From: Daniel P. Smith @ 2026-05-20 20:12 UTC (permalink / raw)
To: Dave Hansen, Jason Gunthorpe, Jarkko Sakkinen
Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, tglx, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, luto,
nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, daniel.kiper, andrew.cooper3, trenchboot-devel
In-Reply-To: <8f8328d3-a7db-4a64-82f8-1e0e3eff93cf@intel.com>
On 5/15/26 7:10 PM, Dave Hansen wrote:
> On 5/15/26 16:05, Jason Gunthorpe wrote:
>> Can we please split out and progress the TPM reorg mini-series at the
>> front?
>
> Yes, please.
>
Yes, we will split this out, address the Sashiko comments, and work on
getting it out next week.
> Any way to break this down and merge in more bite-size pieces would be
> better for everyone involved.
I went through the TPM only part of the series and only one commit was
of substantial length, note I am not considering those that were only
moving headers around. That's the new buffer allocation patch from
Jarkko. We can see if there is a way to split it up without resulting in
either unused code or breaking the TPM driver.
V/r,
Daniel P. Smith
^ permalink raw reply
* Re: [PATCH v3] crypto/ccp: Introduce SNP_VERIFY_MITIGATION command
From: Tom Lendacky @ 2026-05-20 20:22 UTC (permalink / raw)
To: Pratik R. Sampat, ashish.kalra, john.allen, herbert, davem
Cc: linux-crypto, linux-kernel, aik, tycho, nikunj, michael.roth
In-Reply-To: <36137b565d183fa2f2985ad098f2e2096f1c432f.1779219958.git.prsampat@amd.com>
On 5/19/26 14:50, Pratik R. Sampat wrote:
> The SEV-SNP firmware provides the SNP_VERIFY_MITIGATION command, which
> can be used to query the status of currently supported vulnerability
> mitigations and to initiate mitigations within the firmware.
>
> This command is an explicit mechanism to ascertain if a firmware
> mitigation is applied without needing a full RMP re-build, which is most
> useful in a live firmware update scenario.
>
> The firmware supports two subcommands: STATUS and VERIFY. The STATUS
> subcommand is used to query the supported and verified mitigation bits.
> The VERIFY subcommand initiates the mitigation process within the FW for
> the specified vulnerability. Expose a userspace interface under:
> /sys/firmware/sev/vulnerabilities/
> - supported_mitigations (read-only): supported mitigation vector mask
> - verified_mitigations (read/write): current verified mask; write a
> vector to request VERIFY for that bit
>
> The behavior of SNP_VERIFY_MITIGATION and the pre-requisites for using
> it are bug-specific. Information about supported mitigations and its
> corresponding vector is to be published as part of the AMD Security
> Bulletin.
>
> See SEV-SNP Firmware ABI specifications 1.58, SNP_VERIFY_MITIGATION for
> more details.
>
> Signed-off-by: Pratik R. Sampat <prsampat@amd.com>
> ---
> .../sysfs-firmware-sev-vulnerabilities | 17 ++
> drivers/crypto/ccp/sev-dev.c | 172 ++++++++++++++++++
> drivers/crypto/ccp/sev-dev.h | 3 +
> include/linux/psp-sev.h | 51 ++++++
> 4 files changed, 243 insertions(+)
> create mode 100644 Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities
>
> diff --git a/Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities b/Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities
> new file mode 100644
> index 000000000000..cc84adbac3c0
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-firmware-sev-vulnerabilities
> @@ -0,0 +1,17 @@
> +What: /sys/firmware/sev/vulnerabilities/
> + /sys/firmware/sev/vulnerabilities/supported_mitigations
> + /sys/firmware/sev/vulnerabilities/verified_mitigations
> +Date: May 2026
> +Contact: linux-crypto@vger.kernel.org
> +Description: Information about SEV-SNP firmware vulnerability mitigations.
> + supported_mitigations: Read-only interface that reports
> + the vector of mitigations supported by
> + the firmware.
> + verified_mitigations: Read/write interface that reports
> + the vector of mitigations already verified
> + by the firmware. Writing a vector value
> + requests the firmware to VERIFY the
> + corresponding mitigation bit(s).
> + The list of supported mitigations and the meaning of each
> + vector bit are both platform- and bug-specific and are
> + published as part of the AMD Security Bulletin.
> diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
> index d1e9e0ac63b6..eec4864c6597 100644
> --- a/drivers/crypto/ccp/sev-dev.c
> +++ b/drivers/crypto/ccp/sev-dev.c
> @@ -57,6 +57,7 @@
> #define CMD_BUF_DESC_MAX (CMD_BUF_FW_WRITABLE_MAX + 1)
>
> static DEFINE_MUTEX(sev_cmd_mutex);
> +static DEFINE_MUTEX(sev_mit_sysfs_mutex);
> static struct sev_misc_dev *misc_dev;
>
> static int psp_cmd_timeout = 100;
> @@ -245,6 +246,7 @@ static int sev_cmd_buffer_len(int cmd)
> case SEV_CMD_SNP_LAUNCH_FINISH: return sizeof(struct sev_data_snp_launch_finish);
> case SEV_CMD_SNP_DBG_DECRYPT: return sizeof(struct sev_data_snp_dbg);
> case SEV_CMD_SNP_DBG_ENCRYPT: return sizeof(struct sev_data_snp_dbg);
> + case SEV_CMD_SNP_VERIFY_MITIGATION: return sizeof(struct sev_data_snp_verify_mitigation);
> case SEV_CMD_SNP_PAGE_UNSMASH: return sizeof(struct sev_data_snp_page_unsmash);
> case SEV_CMD_SNP_PLATFORM_STATUS: return sizeof(struct sev_data_snp_addr);
> case SEV_CMD_SNP_GUEST_REQUEST: return sizeof(struct sev_data_snp_guest_request);
> @@ -1351,6 +1353,162 @@ static int snp_filter_reserved_mem_regions(struct resource *rs, void *arg)
> return 0;
> }
>
> +static int snp_verify_mitigation(u16 command, u64 vector,
> + struct sev_data_snp_verify_mitigation_dst *dst)
> +{
> + struct sev_data_snp_verify_mitigation_dst *mit_dst = NULL;
> + struct sev_data_snp_verify_mitigation data = {0};
> + struct sev_device *sev = psp_master->sev_data;
> + int ret, error = 0;
> +
> + mit_dst = snp_alloc_firmware_page(GFP_KERNEL | __GFP_ZERO);
> + if (!mit_dst)
> + return -ENOMEM;
> +
> + data.length = sizeof(data);
> + data.subcommand = command;
> + data.vector = vector;
> + data.dst_paddr = __psp_pa(mit_dst);
> + data.dst_paddr_en = true;
> +
> + ret = sev_do_cmd(SEV_CMD_SNP_VERIFY_MITIGATION, &data, &error);
> + if (!ret)
> + memcpy(dst, mit_dst, sizeof(*mit_dst));
> + else
> + dev_err(sev->dev, "SNP_VERIFY_MITIGATION command failed, ret = %d, error = %#x\n",
> + ret, error);
> +
> + snp_free_firmware_page(mit_dst);
> +
> + return ret;
> +}
Should this function also be under the CONFIG_SYSFS #ifdef? Won't you get
an unused function warning if CONFIG_SYSFS isn't defined?
> +
> +#ifdef CONFIG_SYSFS
> +static ssize_t supported_mitigations_show(struct kobject *kobj,
> + struct kobj_attribute *attr, char *buf)
> +{
> + struct sev_data_snp_verify_mitigation_dst dst;
> + int ret;
> +
> + ret = snp_verify_mitigation(SNP_MIT_SUBCMD_REQ_STATUS, 0, &dst);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "0x%llx\n", dst.mit_supported_vector);
> +}
> +
> +static struct kobj_attribute supported_attr =
> + __ATTR_RO_MODE(supported_mitigations, 0400);
> +
> +static ssize_t verified_mitigations_show(struct kobject *kobj,
> + struct kobj_attribute *attr, char *buf)
> +{
> + struct sev_data_snp_verify_mitigation_dst dst;
> + int ret;
> +
> + ret = snp_verify_mitigation(SNP_MIT_SUBCMD_REQ_STATUS, 0, &dst);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "0x%llx\n", dst.mit_verified_vector);
> +}
> +
> +static ssize_t verified_mitigations_store(struct kobject *kobj,
> + struct kobj_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct sev_data_snp_verify_mitigation_dst dst;
> + struct sev_device *sev = psp_master->sev_data;
> + u64 vector;
> + int ret;
> +
> + ret = kstrtoull(buf, 0, &vector);
> + if (ret)
> + return ret;
> +
> + ret = snp_verify_mitigation(SNP_MIT_SUBCMD_REQ_VERIFY, vector, &dst);
> + if (ret)
> + return ret;
> +
> + if (dst.mit_failure_status) {
> + dev_err(sev->dev, "Verify Mitigation - failure status: 0x%x\n",
> + dst.mit_failure_status);
> + return -EIO;
> + }
> +
> + return count;
> +}
> +
> +static struct kobj_attribute verified_attr =
> + __ATTR_RW_MODE(verified_mitigations, 0600);
> +
> +static struct attribute *mitigation_attrs[] = {
> + &supported_attr.attr,
> + &verified_attr.attr,
> + NULL
> +};
> +
> +static const struct attribute_group mit_attr_group = {
> + .attrs = mitigation_attrs,
> +};
> +
> +static void sev_snp_register_verify_mitigation(struct sev_device *sev)
> +{
> + int rc;
> +
> + if (!sev->snp_initialized || !sev->snp_plat_status.feature_info ||
> + !(sev->snp_feat_info_0.ecx & SNP_VERIFY_MITIGATION_SUPPORTED))
> + return;
> +
> + guard(mutex)(&sev_mit_sysfs_mutex);
> +
> + if (sev->verify_mit)
> + return;
> +
> + if (!sev->sev_kobj) {
> + sev->sev_kobj = kobject_create_and_add("sev", firmware_kobj);
> + if (!sev->sev_kobj)
> + return;
> + }
> +
> + sev->verify_mit = kobject_create_and_add("vulnerabilities", sev->sev_kobj);
> + if (!sev->verify_mit)
> + goto err_sev_kobj;
> +
> + rc = sysfs_create_group(sev->verify_mit, &mit_attr_group);
> + if (rc)
> + goto err_verify_mit;
> +
> + return;
> +
> +err_verify_mit:
> + kobject_put(sev->verify_mit);
> + sev->verify_mit = NULL;
> +err_sev_kobj:
> + kobject_put(sev->sev_kobj);
> + sev->sev_kobj = NULL;
> +}
> +
> +static void sev_snp_unregister_verify_mitigation(struct sev_device *sev)
> +{
> + guard(mutex)(&sev_mit_sysfs_mutex);
> +
> + if (sev->verify_mit) {
> + sysfs_remove_group(sev->verify_mit, &mit_attr_group);
> + kobject_put(sev->verify_mit);
> + sev->verify_mit = NULL;
> + }
> +
> + if (sev->sev_kobj) {
> + kobject_put(sev->sev_kobj);
> + sev->sev_kobj = NULL;
> + }
> +}
> +#else
> +static void sev_snp_register_verify_mitigation(struct sev_device *sev) { }
> +static void sev_snp_unregister_verify_mitigation(struct sev_device *sev) { }
> +#endif
> +
> static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid)
> {
> struct sev_data_range_list *snp_range_list __free(kfree) = NULL;
> @@ -1670,6 +1828,14 @@ int sev_platform_init(struct sev_platform_init_args *args)
> rc = _sev_platform_init_locked(args);
> mutex_unlock(&sev_cmd_mutex);
>
> + /*
> + * The shutdown + init path can race with in-flight _show()/_store() operations
> + * which acquire the sev_cmd_mutex. Register the sysfs interface outside
> + * the sev_cmd_mutex and serialize by sev_mit_sysfs_mutex instead.
I'm not quite sure I follow this. The shutdown and init path can't race
with each other, right? In which case this new mutex doesn't really matter
unless you take it on _show()/_short(), right?
Thanks,
Tom
> + */
> + if (!rc)
> + sev_snp_register_verify_mitigation(psp_master->sev_data);
> +
> return rc;
> }
> EXPORT_SYMBOL_GPL(sev_platform_init);
> @@ -2796,6 +2962,12 @@ static void sev_firmware_shutdown(struct sev_device *sev)
> if (sev->tio_status)
> sev_tsm_uninit(sev);
>
> + /*
> + * Concurrent access to the sysfs entry will call sev_do_cmd() for
> + * SNP_VERIFY_MITIGATION which locks the mutex and can cause a deadlock.
> + */
> + sev_snp_unregister_verify_mitigation(sev);
> +
> mutex_lock(&sev_cmd_mutex);
>
> __sev_firmware_shutdown(sev, false);
> diff --git a/drivers/crypto/ccp/sev-dev.h b/drivers/crypto/ccp/sev-dev.h
> index b1cd556bbbf6..d5e596606def 100644
> --- a/drivers/crypto/ccp/sev-dev.h
> +++ b/drivers/crypto/ccp/sev-dev.h
> @@ -59,6 +59,9 @@ struct sev_device {
>
> bool snp_initialized;
>
> + struct kobject *sev_kobj;
> + struct kobject *verify_mit;
> +
> struct sev_user_data_status sev_plat_status;
>
> struct sev_user_data_snp_status snp_plat_status;
> diff --git a/include/linux/psp-sev.h b/include/linux/psp-sev.h
> index d5099a2baca5..98666c5a6f79 100644
> --- a/include/linux/psp-sev.h
> +++ b/include/linux/psp-sev.h
> @@ -129,6 +129,7 @@ enum sev_cmd {
> SEV_CMD_SNP_LAUNCH_FINISH = 0x0A2,
> SEV_CMD_SNP_DBG_DECRYPT = 0x0B0,
> SEV_CMD_SNP_DBG_ENCRYPT = 0x0B1,
> + SEV_CMD_SNP_VERIFY_MITIGATION = 0x0B2,
> SEV_CMD_SNP_PAGE_SWAP_OUT = 0x0C0,
> SEV_CMD_SNP_PAGE_SWAP_IN = 0x0C1,
> SEV_CMD_SNP_PAGE_MOVE = 0x0C2,
> @@ -898,10 +899,60 @@ struct snp_feature_info {
> #define SNP_CIPHER_TEXT_HIDING_SUPPORTED BIT(3)
> #define SNP_AES_256_XTS_POLICY_SUPPORTED BIT(4)
> #define SNP_CXL_ALLOW_POLICY_SUPPORTED BIT(5)
> +#define SNP_VERIFY_MITIGATION_SUPPORTED BIT(13)
>
> /* Feature bits in EBX */
> #define SNP_SEV_TIO_SUPPORTED BIT(1)
>
> +#define SNP_MIT_SUBCMD_REQ_STATUS 0x0
> +#define SNP_MIT_SUBCMD_REQ_VERIFY 0x1
> +
> +/**
> + * struct sev_data_snp_verify_mitigation - SNP_VERIFY_MITIGATION command params
> + *
> + * @length: Length of the command buffer read by the PSP
> + * @subcommand: Mitigation sub-command for the firmware to execute.
> + * REQ_STATUS: 0x0 - Request status about currently supported and
> + * verified mitigations
> + * REQ_VERIFY: 0x1 - Request to initiate verification mitigation
> + * operation on a specific mitigation
> + * @rsvd: Reserved
> + * @vector: Bit specifying the vulnerability mitigation to process
> + * @dst_paddr_en: Destination paddr enabled
> + * @src_paddr_en: Source paddr enabled
> + * @rsvd1: Reserved
> + * @rsvd2: Reserved
> + * @src_paddr: Source address for optional input data
> + * @dst_paddr: Destination address to write the result
> + * @rsvd3: Reserved
> + */
> +struct sev_data_snp_verify_mitigation {
> + u32 length;
> + u16 subcommand;
> + u16 rsvd;
> + u64 vector;
> + u32 dst_paddr_en : 1,
> + src_paddr_en : 1,
> + rsvd1 : 30;
> + u8 rsvd2[4];
> + u64 src_paddr;
> + u64 dst_paddr;
> + u8 rsvd3[24];
> +} __packed;
> +
> +/**
> + * struct sev_data_snp_verify_mitigation_dst - mitigation result vectors
> + *
> + * @mit_verified_vector: Bit vector of vulnerability mitigations verified
> + * @mit_supported_vector: Bit vector of vulnerability mitigations supported
> + * @mit_failure_status: Status of the verification operation
> + */
> +struct sev_data_snp_verify_mitigation_dst {
> + u64 mit_verified_vector; /* OUT */
> + u64 mit_supported_vector; /* OUT */
> + u32 mit_failure_status; /* OUT */
> +} __packed;
> +
> #ifdef CONFIG_CRYPTO_DEV_SP_PSP
>
> /**
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox