i2c: atr: serialize attach/detach against bus transfers

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@q-lab.dev>
Signed-off-by: Dumitru Ceclan <dumitru.ceclan@analog.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
This commit is contained in:
Dumitru Ceclan 2026-09-30 01:41:47 +03:00 committed by Sakari Ailus
parent 7398f90718
commit 424e37817b

View File

@ -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,