mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
gpio: shared: shorten the critical section in gpiochip_setup_shared()
Commit710abda580("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:710abda580("gpio: shared: call gpio_chip::of_xlate() if set") Reported-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Link: https://patch.msgid.link/20260325-gpio-shared-deadlock-v1-1-e4e7a5319e95@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
This commit is contained in:
parent
c720fb57d5
commit
310a4a9cbb
|
|
@ -533,48 +533,48 @@ int gpiochip_setup_shared(struct gpio_chip *gc)
|
|||
* exposing shared pins. Find them and create the proxy devices.
|
||||
*/
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
guard(mutex)(&entry->lock);
|
||||
|
||||
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
||||
continue;
|
||||
|
||||
if (list_count_nodes(&entry->refs) <= 1)
|
||||
continue;
|
||||
|
||||
scoped_guard(mutex, &entry->lock) {
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
if (is_of_node(entry->fwnode) && gc->of_xlate) {
|
||||
/*
|
||||
* This is the earliest that we can tranlate the
|
||||
* devicetree offset to the chip offset.
|
||||
*/
|
||||
struct of_phandle_args gpiospec = { };
|
||||
if (is_of_node(entry->fwnode) && gc->of_xlate) {
|
||||
/*
|
||||
* This is the earliest that we can tranlate the
|
||||
* devicetree offset to the chip offset.
|
||||
*/
|
||||
struct of_phandle_args gpiospec = { };
|
||||
|
||||
gpiospec.np = to_of_node(entry->fwnode);
|
||||
gpiospec.args_count = 2;
|
||||
gpiospec.args[0] = entry->offset;
|
||||
gpiospec.np = to_of_node(entry->fwnode);
|
||||
gpiospec.args_count = 2;
|
||||
gpiospec.args[0] = entry->offset;
|
||||
|
||||
ret = gc->of_xlate(gc, &gpiospec, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = gc->of_xlate(gc, &gpiospec, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
entry->offset = ret;
|
||||
}
|
||||
entry->offset = ret;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
desc = &gdev->descs[entry->offset];
|
||||
desc = &gdev->descs[entry->offset];
|
||||
|
||||
__set_bit(GPIOD_FLAG_SHARED, &desc->flags);
|
||||
/*
|
||||
* Shared GPIOs are not requested via the normal path. Make
|
||||
* them inaccessible to anyone even before we register the
|
||||
* chip.
|
||||
*/
|
||||
ret = gpiod_request_commit(desc, "shared");
|
||||
if (ret)
|
||||
return ret;
|
||||
__set_bit(GPIOD_FLAG_SHARED, &desc->flags);
|
||||
/*
|
||||
* Shared GPIOs are not requested via the normal path. Make
|
||||
* them inaccessible to anyone even before we register the
|
||||
* chip.
|
||||
*/
|
||||
ret = gpiod_request_commit(desc, "shared");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
|
||||
entry->offset, gpio_device_get_label(gdev));
|
||||
pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
|
||||
entry->offset, gpio_device_get_label(gdev));
|
||||
}
|
||||
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
pr_debug("Setting up a shared GPIO entry for %s (con_id: '%s')\n",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user