Skip to content

Commit 310a4a9

Browse files
author
Bartosz Golaszewski
committed
gpio: shared: shorten the critical section in gpiochip_setup_shared()
Commit 710abda ("gpio: shared: call gpio_chip::of_xlate() if set") introduced a critical section around the adjustmenet of entry->offset. However this may cause a deadlock if we create the auxiliary shared proxy devices with this lock taken. We only need to protect entry->offset while it's read/written so shorten the critical section and release the lock before creating the proxy device as the field in question is no longer accessed at this point. Fixes: 710abda ("gpio: shared: call gpio_chip::of_xlate() if set") Reported-by: Dmitry Baryshkov <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Bartosz Golaszewski <[email protected]>
1 parent c720fb5 commit 310a4a9

1 file changed

Lines changed: 28 additions & 28 deletions

File tree

drivers/gpio/gpiolib-shared.c

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -533,48 +533,48 @@ int gpiochip_setup_shared(struct gpio_chip *gc)
533533
* exposing shared pins. Find them and create the proxy devices.
534534
*/
535535
list_for_each_entry(entry, &gpio_shared_list, list) {
536-
guard(mutex)(&entry->lock);
537-
538536
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
539537
continue;
540538

541539
if (list_count_nodes(&entry->refs) <= 1)
542540
continue;
543541

542+
scoped_guard(mutex, &entry->lock) {
544543
#if IS_ENABLED(CONFIG_OF)
545-
if (is_of_node(entry->fwnode) && gc->of_xlate) {
546-
/*
547-
* This is the earliest that we can tranlate the
548-
* devicetree offset to the chip offset.
549-
*/
550-
struct of_phandle_args gpiospec = { };
544+
if (is_of_node(entry->fwnode) && gc->of_xlate) {
545+
/*
546+
* This is the earliest that we can tranlate the
547+
* devicetree offset to the chip offset.
548+
*/
549+
struct of_phandle_args gpiospec = { };
551550

552-
gpiospec.np = to_of_node(entry->fwnode);
553-
gpiospec.args_count = 2;
554-
gpiospec.args[0] = entry->offset;
551+
gpiospec.np = to_of_node(entry->fwnode);
552+
gpiospec.args_count = 2;
553+
gpiospec.args[0] = entry->offset;
555554

556-
ret = gc->of_xlate(gc, &gpiospec, NULL);
557-
if (ret < 0)
558-
return ret;
555+
ret = gc->of_xlate(gc, &gpiospec, NULL);
556+
if (ret < 0)
557+
return ret;
559558

560-
entry->offset = ret;
561-
}
559+
entry->offset = ret;
560+
}
562561
#endif /* CONFIG_OF */
563562

564-
desc = &gdev->descs[entry->offset];
563+
desc = &gdev->descs[entry->offset];
565564

566-
__set_bit(GPIOD_FLAG_SHARED, &desc->flags);
567-
/*
568-
* Shared GPIOs are not requested via the normal path. Make
569-
* them inaccessible to anyone even before we register the
570-
* chip.
571-
*/
572-
ret = gpiod_request_commit(desc, "shared");
573-
if (ret)
574-
return ret;
565+
__set_bit(GPIOD_FLAG_SHARED, &desc->flags);
566+
/*
567+
* Shared GPIOs are not requested via the normal path. Make
568+
* them inaccessible to anyone even before we register the
569+
* chip.
570+
*/
571+
ret = gpiod_request_commit(desc, "shared");
572+
if (ret)
573+
return ret;
575574

576-
pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
577-
entry->offset, gpio_device_get_label(gdev));
575+
pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
576+
entry->offset, gpio_device_get_label(gdev));
577+
}
578578

579579
list_for_each_entry(ref, &entry->refs, list) {
580580
pr_debug("Setting up a shared GPIO entry for %s (con_id: '%s')\n",

0 commit comments

Comments
 (0)