]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
i2c: atr: Fix lockdep for nested ATRs
authorTomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Wed, 7 May 2025 12:19:07 +0000 (15:19 +0300)
committerWolfram Sang <wsa+renesas@sang-engineering.com>
Thu, 22 May 2025 09:06:40 +0000 (11:06 +0200)
When we have an ATR, and another ATR as a subdevice of the first ATR,
we get lockdep warnings for the i2c_atr.lock and
i2c_atr_chan.orig_addrs_lock. This is because lockdep uses a static key
for the locks, and doesn't see the locks of the separate ATR instances
as separate.

Fix this by generating a dynamic lock key per lock instance.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Signed-off-by: Cosmin Tanislav <demonsingur@gmail.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
drivers/i2c/i2c-atr.c

index 4f78e75b63a05a2ea574b431cec4daa51634b398..9ec1678761064f7fab35588ec64ca7c14f42c8b7 100644 (file)
@@ -68,11 +68,13 @@ struct i2c_atr_alias_pool {
  * @atr:             The parent I2C ATR
  * @chan_id:         The ID of this channel
  * @alias_pairs_lock: Mutex protecting @alias_pairs
+ * @alias_pairs_lock_key: Lock key for @alias_pairs_lock
  * @alias_pairs:     List of @struct i2c_atr_alias_pair containing the
  *                   assigned aliases
  * @alias_pool:      Pool of available client aliases
  *
  * @orig_addrs_lock: Mutex protecting @orig_addrs
+ * @orig_addrs_lock_key: Lock key for @orig_addrs_lock
  * @orig_addrs:      Buffer used to store the original addresses during transmit
  * @orig_addrs_size: Size of @orig_addrs
  */
@@ -83,11 +85,13 @@ struct i2c_atr_chan {
 
        /* Lock alias_pairs during attach/detach */
        struct mutex alias_pairs_lock;
+       struct lock_class_key alias_pairs_lock_key;
        struct list_head alias_pairs;
        struct i2c_atr_alias_pool *alias_pool;
 
        /* Lock orig_addrs during xfer */
        struct mutex orig_addrs_lock;
+       struct lock_class_key orig_addrs_lock_key;
        u16 *orig_addrs;
        unsigned int orig_addrs_size;
 };
@@ -100,6 +104,7 @@ struct i2c_atr_chan {
  * @priv:      Private driver data, set with i2c_atr_set_driver_data()
  * @algo:      The &struct i2c_algorithm for adapters
  * @lock:      Lock for the I2C bus segment (see &struct i2c_lock_operations)
+ * @lock_key:  Lock key for @lock
  * @max_adapters: Maximum number of adapters this I2C ATR can have
  * @alias_pool: Optional common pool of available client aliases
  * @i2c_nb:    Notifier for remote client add & del events
@@ -115,6 +120,7 @@ struct i2c_atr {
        struct i2c_algorithm algo;
        /* lock for the I2C bus segment (see struct i2c_lock_operations) */
        struct mutex lock;
+       struct lock_class_key lock_key;
        int max_adapters;
 
        struct i2c_atr_alias_pool *alias_pool;
@@ -683,7 +689,8 @@ struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev,
        if (!atr)
                return ERR_PTR(-ENOMEM);
 
-       mutex_init(&atr->lock);
+       lockdep_register_key(&atr->lock_key);
+       mutex_init_with_key(&atr->lock, &atr->lock_key);
 
        atr->parent = parent;
        atr->dev = dev;
@@ -711,6 +718,7 @@ err_free_alias_pool:
        i2c_atr_free_alias_pool(atr->alias_pool);
 err_destroy_mutex:
        mutex_destroy(&atr->lock);
+       lockdep_unregister_key(&atr->lock_key);
        kfree(atr);
 
        return ERR_PTR(ret);
@@ -727,6 +735,7 @@ void i2c_atr_delete(struct i2c_atr *atr)
        bus_unregister_notifier(&i2c_bus_type, &atr->i2c_nb);
        i2c_atr_free_alias_pool(atr->alias_pool);
        mutex_destroy(&atr->lock);
+       lockdep_unregister_key(&atr->lock_key);
        kfree(atr);
 }
 EXPORT_SYMBOL_NS_GPL(i2c_atr_delete, "I2C_ATR");
@@ -761,8 +770,10 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *desc)
        chan->atr = atr;
        chan->chan_id = chan_id;
        INIT_LIST_HEAD(&chan->alias_pairs);
-       mutex_init(&chan->alias_pairs_lock);
-       mutex_init(&chan->orig_addrs_lock);
+       lockdep_register_key(&chan->alias_pairs_lock_key);
+       lockdep_register_key(&chan->orig_addrs_lock_key);
+       mutex_init_with_key(&chan->alias_pairs_lock, &chan->alias_pairs_lock_key);
+       mutex_init_with_key(&chan->orig_addrs_lock, &chan->orig_addrs_lock_key);
 
        snprintf(chan->adap.name, sizeof(chan->adap.name), "i2c-%d-atr-%d",
                 i2c_adapter_id(parent), chan_id);
@@ -839,6 +850,8 @@ err_fwnode_put:
        fwnode_handle_put(dev_fwnode(&chan->adap.dev));
        mutex_destroy(&chan->orig_addrs_lock);
        mutex_destroy(&chan->alias_pairs_lock);
+       lockdep_unregister_key(&chan->orig_addrs_lock_key);
+       lockdep_unregister_key(&chan->alias_pairs_lock_key);
        kfree(chan);
        return ret;
 }
@@ -876,6 +889,8 @@ void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id)
        fwnode_handle_put(fwnode);
        mutex_destroy(&chan->orig_addrs_lock);
        mutex_destroy(&chan->alias_pairs_lock);
+       lockdep_unregister_key(&chan->orig_addrs_lock_key);
+       lockdep_unregister_key(&chan->alias_pairs_lock_key);
        kfree(chan->orig_addrs);
        kfree(chan);
 }