[PATCH v18 13/23] i2c: atr: serialize attach/detach against bus transfers

From: Dumitru Ceclan via B4 Relay

Date: Tue Sep 29 2026 - 18:46:03 EST


From: Dumitru Ceclan <dumitru.ceclan@xxxxxxxxxx>

The attach_addr() and detach_addr() callbacks may need to reconfigure
the remote side of the bus. Maxim GMSL deserializers, for example,
disable all links but one to reach a serializer at its default address,
since all serializers power up at the same address.

Transfers on other channels of the same ATR can run concurrently with
these callbacks and fail with -EIO while the links are disabled.

Take the ATR bus lock around both callbacks, before alias_pairs_lock.
i2c_atr_replace_mapping_by_addr() already calls them under this lock,
so ATR drivers see no new constraint.

Suggested-by: Quentin Freimanis <quentin@xxxxxxxxx>
Signed-off-by: Dumitru Ceclan <dumitru.ceclan@xxxxxxxxxx>
---
drivers/i2c/i2c-atr.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c
index ca29633dcd62..b98442ffff94 100644
--- a/drivers/i2c/i2c-atr.c
+++ b/drivers/i2c/i2c-atr.c
@@ -540,6 +540,12 @@ static int i2c_atr_attach_addr(struct i2c_adapter *adapter,
struct i2c_atr_alias_pair *c2a;
int ret = 0;

+ /*
+ * attach_addr() may reconfigure the remote side of the bus, keep
+ * transfers on other channels out until it is done.
+ */
+ mutex_lock(&atr->lock);
+
mutex_lock(&chan->alias_pairs_lock);

c2a = i2c_atr_create_mapping_by_addr(chan, addr);
@@ -557,6 +563,8 @@ static int i2c_atr_attach_addr(struct i2c_adapter *adapter,

out_unlock:
mutex_unlock(&chan->alias_pairs_lock);
+ mutex_unlock(&atr->lock);
+
return ret;
}

@@ -567,6 +575,8 @@ static void i2c_atr_detach_addr(struct i2c_adapter *adapter,
struct i2c_atr *atr = chan->atr;
struct i2c_atr_alias_pair *c2a;

+ mutex_lock(&atr->lock);
+
atr->ops->detach_addr(atr, chan->chan_id, addr);

mutex_lock(&chan->alias_pairs_lock);
@@ -574,6 +584,7 @@ static void i2c_atr_detach_addr(struct i2c_adapter *adapter,
c2a = i2c_atr_find_mapping_by_addr(chan, addr);
if (!c2a) {
mutex_unlock(&chan->alias_pairs_lock);
+ mutex_unlock(&atr->lock);
return;
}

@@ -586,6 +597,7 @@ static void i2c_atr_detach_addr(struct i2c_adapter *adapter,
i2c_atr_destroy_c2a(&c2a);

mutex_unlock(&chan->alias_pairs_lock);
+ mutex_unlock(&atr->lock);
}

static int i2c_atr_bus_notifier_call(struct notifier_block *nb,

--
2.53.0