[PATCH v4 02/16] firmware: arm_scmi: Quiesce notifications before teardown
Sudeep Holla
sudeep.holla at kernel.org
Wed Jul 8 01:59:58 PDT 2026
scmi_notification_exit() clears and releases the notification instance, but
transport callbacks can still deliver incoming notifications until the
TX/RX channels are freed. During remove, an RX interrupt in that window can
enter scmi_notify() while notification state is being torn down and then
dereference freed memory. The same ordering exists on the probe error path
after notification initialization.
The notification late-init worker has a separate lifetime issue: protocol
event registration queues ni->init_work on the system workqueue, so
destroying ni->notify_wq does not drain that work. If the devres group is
released while init_work is still pending or running, the late-init worker
can dereference the freed notification instance.
Unregister the requested device notifier first, stop transport callbacks by
cleaning up TX/RX channels before releasing the notification core, and
cancel init_work before destroying the notification workqueue and releasing
the notification devres group.
Fixes: 1e7cbfaa66d3 ("firmware: arm_scmi: Free mailbox channels if probe fails")
Reported-by: Sashiko <sashiko-bot at kernel.org>
Signed-off-by: Sudeep Holla <sudeep.holla at kernel.org>
---
drivers/firmware/arm_scmi/driver.c | 12 +++++-------
drivers/firmware/arm_scmi/notify.c | 2 ++
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 1d1f5d25d773..6f588840bf11 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -3325,7 +3325,7 @@ static int scmi_probe(struct platform_device *pdev)
dev_err(dev, "%s", err_str);
return 0;
}
- goto notification_exit;
+ goto raw_mode_cleanup;
}
mutex_lock(&scmi_list_mutex);
@@ -3367,10 +3367,9 @@ static int scmi_probe(struct platform_device *pdev)
return 0;
-notification_exit:
+raw_mode_cleanup:
if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT))
scmi_raw_mode_cleanup(info->raw);
- scmi_notification_exit(&info->handle);
clear_dev_req_notifier:
blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
&info->dev_req_nb);
@@ -3378,7 +3377,7 @@ static int scmi_probe(struct platform_device *pdev)
bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
clear_txrx_setup:
scmi_cleanup_txrx_channels(info);
-clear_ida:
+ scmi_notification_exit(&info->handle);
ida_free(&scmi_id, info->id);
out_err:
@@ -3401,6 +3400,8 @@ static void scmi_remove(struct platform_device *pdev)
list_del(&info->node);
mutex_unlock(&scmi_list_mutex);
+ /* Stop transport callbacks before tearing down notifications. */
+ scmi_cleanup_txrx_channels(info);
scmi_notification_exit(&info->handle);
mutex_lock(&info->protocols_mtx);
@@ -3415,9 +3416,6 @@ static void scmi_remove(struct platform_device *pdev)
&info->dev_req_nb);
bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
- /* Safe to free channels since no more users */
- scmi_cleanup_txrx_channels(info);
-
ida_free(&scmi_id, info->id);
}
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 40ec184eedae..be2eadfd93a4 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -1719,6 +1719,8 @@ void scmi_notification_exit(struct scmi_handle *handle)
return;
scmi_notification_instance_data_set(handle, NULL);
+ cancel_work_sync(&ni->init_work);
+
/* Destroy while letting pending work complete */
destroy_workqueue(ni->notify_wq);
--
2.43.0
More information about the linux-arm-kernel
mailing list