aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorSudeep Holla <sudeep.holla@kernel.org>2026-07-14 13:56:25 +0100
committerSudeep Holla <sudeep.holla@kernel.org>2026-07-14 21:19:22 +0100
commitc38b1e19485aaa820e52cfe162525a8af67563da (patch)
tree335e05c5d90aed0173b522217d2e2a56011e6208
parentfirmware: arm_scmi: Free transport channel on IDR failure (diff)
firmware: arm_scmi: Avoid IDR updates while cleaning channels
scmi_cleanup_channels() walks the TX/RX channel IDRs with idr_for_each() to free transport resources and destroy the dedicated transport devices before calling idr_destroy(). The destroy callback removed each entry from the same IDR being walked. That is not needed for this cleanup path, and it is unsafe because idr_for_each() has not advanced its radix-tree iterator while the callback is running. Removing the current entry from the callback can invalidate the iterator state. The callback also cannot be protected by rcu_read_lock(), because scmi_device_destroy() may sleep. Leave IDR teardown to the following idr_destroy() call and keep the callback limited to device destruction. Fixes: 05a2801d8b90 ("firmware: arm_scmi: Use dedicated devices to initialize channels") Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://patch.msgid.link/20260714-scmi_core_fixes-v6-6-3afe499d46e3@kernel.org Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
-rw-r--r--drivers/firmware/arm_scmi/driver.c4
1 files changed, 1 insertions, 3 deletions
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 6ee2152f6b01..d17559c897a9 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -2885,7 +2885,7 @@ static int scmi_channels_setup(struct scmi_info *info)
return 0;
}
-static int scmi_chan_destroy(int id, void *p, void *idr)
+static int scmi_chan_destroy(int id, void *p, void *data)
{
struct scmi_chan_info *cinfo = p;
@@ -2898,8 +2898,6 @@ static int scmi_chan_destroy(int id, void *p, void *idr)
cinfo->dev = NULL;
}
- idr_remove(idr, id);
-
return 0;
}