i3c: master: svc: fix possible assignment of the same address to two devices

svc_i3c_master_do_daa() {
    ...
    for (i = 0; i < dev_nb; i++) {
        ret = i3c_master_add_i3c_dev_locked(m, addrs[i]);
        if (ret)
            goto rpm_out;
    }
}

If two devices (A and B) are detected in DAA and address 0xa is assigned to
device A and 0xb to device B, a failure in i3c_master_add_i3c_dev_locked()
for device A (addr: 0xa) could prevent device B (addr: 0xb) from being
registered on the bus. The I3C stack might still consider 0xb a free
address. If a subsequent Hotjoin occurs, 0xb might be assigned to Device A,
causing both devices A and B to use the same address 0xb, violating the I3C
specification.

The return value for i3c_master_add_i3c_dev_locked() should not be checked
because subsequent steps will scan the entire I3C bus, independent of
whether i3c_master_add_i3c_dev_locked() returns success.

If device A registration fails, there is still a chance to register device
B. i3c_master_add_i3c_dev_locked() can reset DAA if a failure occurs while
retrieving device information.

Cc: stable@kernel.org
Fixes: 317bacf960a4 ("i3c: master: add enable(disable) hot join in sys entry")
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
Link: https://lore.kernel.org/r/20241002-svc-i3c-hj-v6-6-7e6e1d3569ae@nxp.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
Frank Li 2024-10-02 10:50:38 -04:00 committed by Alexandre Belloni
parent 3ca529194e
commit 3b2ac810d8

View File

@ -1103,12 +1103,27 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
if (ret)
goto rpm_out;
/* Register all devices who participated to the core */
for (i = 0; i < dev_nb; i++) {
ret = i3c_master_add_i3c_dev_locked(m, addrs[i]);
if (ret)
goto rpm_out;
}
/*
* Register all devices who participated to the core
*
* If two devices (A and B) are detected in DAA and address 0xa is assigned to
* device A and 0xb to device B, a failure in i3c_master_add_i3c_dev_locked()
* for device A (addr: 0xa) could prevent device B (addr: 0xb) from being
* registered on the bus. The I3C stack might still consider 0xb a free
* address. If a subsequent Hotjoin occurs, 0xb might be assigned to Device A,
* causing both devices A and B to use the same address 0xb, violating the I3C
* specification.
*
* The return value for i3c_master_add_i3c_dev_locked() should not be checked
* because subsequent steps will scan the entire I3C bus, independent of
* whether i3c_master_add_i3c_dev_locked() returns success.
*
* If device A registration fails, there is still a chance to register device
* B. i3c_master_add_i3c_dev_locked() can reset DAA if a failure occurs while
* retrieving device information.
*/
for (i = 0; i < dev_nb; i++)
i3c_master_add_i3c_dev_locked(m, addrs[i]);
/* Configure IBI auto-rules */
ret = svc_i3c_update_ibirules(master);