summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpio/gpiolib-shared.c20
1 files changed, 9 insertions, 11 deletions
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index a68af06a6cc4..4c57b0928760 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -38,6 +38,7 @@ struct gpio_shared_ref {
int dev_id;
/* Protects the auxiliary device struct and the lookup table. */
struct mutex lock;
+ struct lock_class_key lock_key;
struct auxiliary_device adev;
struct gpiod_lookup_table *lookup;
};
@@ -99,7 +100,8 @@ static struct gpio_shared_ref *gpio_shared_make_ref(struct fwnode_handle *fwnode
ref->flags = flags;
ref->con_id = no_free_ptr(con_id_cpy);
ref->fwnode = fwnode;
- mutex_init(&ref->lock);
+ lockdep_register_key(&ref->lock_key);
+ mutex_init_with_key(&ref->lock, &ref->lock_key);
return no_free_ptr(ref);
}
@@ -378,6 +380,11 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
* arguments match the ones from this consumer's node.
*/
list_for_each_entry(real_ref, &entry->refs, list) {
+ if (real_ref == ref)
+ continue;
+
+ guard(mutex)(&real_ref->lock);
+
if (!real_ref->fwnode)
continue;
@@ -568,15 +575,6 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
continue;
- /*
- * For some reason if we call synchronize_srcu() in GPIO core,
- * descent here and take this mutex and then recursively call
- * synchronize_srcu() again from gpiochip_remove() (which is
- * totally fine) called after gpio_shared_remove_adev(),
- * lockdep prints a false positive deadlock splat. Disable
- * lockdep here.
- */
- lockdep_off();
list_for_each_entry(ref, &entry->refs, list) {
guard(mutex)(&ref->lock);
@@ -589,7 +587,6 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
gpio_shared_remove_adev(&ref->adev);
}
- lockdep_on();
}
}
@@ -685,6 +682,7 @@ static void gpio_shared_drop_ref(struct gpio_shared_ref *ref)
{
list_del(&ref->list);
mutex_destroy(&ref->lock);
+ lockdep_unregister_key(&ref->lock_key);
kfree(ref->con_id);
ida_free(&gpio_shared_ida, ref->dev_id);
fwnode_handle_put(ref->fwnode);