summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2026-06-12 11:01:03 +0300
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2026-06-14 22:49:11 +0300
commitb3ba8383da4d0cff15810e32ea785eceb0a80813 (patch)
tree08d1718a5b2c323c1ed81c8c3c7a90919192e610
parentad7fba5cbd6d7ff139a08e7c83edec4536314430 (diff)
downloadlinux-b3ba8383da4d0cff15810e32ea785eceb0a80813.tar.xz
i3c: master: Prevent reuse of dynamic address on device add failure
i3c_master_add_i3c_dev_locked() is called after a device has already been assigned a dynamic address. If the function fails, the address remains marked as free and may be reallocated to another device, leading to address conflicts on the bus. Ensure the address is not marked as free on failure, by updating the address slot state to prevent the address from being re-used. Emit an error message to inform of the failure. Opportunistically remove the !master check because it is impossible. Note, directly resetting the device's dynamic address is no longer an option, since Direct RSTDAA was deprecated from I3C starting from version 1.1 and v1.1 (or later) target devices are meant to NACK it. Fixes: 3a379bbcea0af ("i3c: Add core I3C infrastructure") Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260612080107.11606-4-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
-rw-r--r--drivers/i3c/master.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 9f8d99636f69..b45065ecbd48 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -2345,12 +2345,11 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
bool enable_ibi = false;
int ret;
- if (!master)
- return -EINVAL;
-
newdev = i3c_master_alloc_i3c_dev(master, &info);
- if (IS_ERR(newdev))
- return PTR_ERR(newdev);
+ if (IS_ERR(newdev)) {
+ ret = PTR_ERR(newdev);
+ goto err_prevent_addr_reuse;
+ }
ret = i3c_master_attach_i3c_dev(master, newdev);
if (ret)
@@ -2472,6 +2471,16 @@ err_detach_dev:
err_free_dev:
i3c_master_free_i3c_dev(newdev);
+err_prevent_addr_reuse:
+ /*
+ * Although the device has not been added, the address has been
+ * assigned. Prevent the address from being used again.
+ */
+ if (i3c_bus_get_addr_slot_status(&master->bus, addr) == I3C_ADDR_SLOT_FREE)
+ i3c_bus_set_addr_slot_status(&master->bus, addr, I3C_ADDR_SLOT_I3C_DEV);
+
+ dev_err(&master->dev, "Failed to add I3C device at address %u, error %d\n", addr, ret);
+
return ret;
}
EXPORT_SYMBOL_GPL(i3c_master_add_i3c_dev_locked);