Hi Linus, On 2018-12-04 13:43, Linus Walleij wrote: > When we get a nonexeclusive GPIO descriptor using managed > resources, we should only add it to the list of managed > resources once: on the first user. Augment the > devm_gpiod_get_index() and devm_gpiod_get_from_of_node() > calls to account for this by checking if the descriptor > is already resource managed before we proceed to allocate > a new resource management struct. > > Cc: Mark Brown <broonie@xxxxxxxxxx> > Cc: Bartosz Golaszewski <bgolaszewski@xxxxxxxxxxxx> > Cc: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> > Fixes: b0ce7b29bfcd ("regulator/gpio: Allow nonexclusive GPIO access") > Reported-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> > Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> > --- > This fix is in response to an issue Marek saw in the fixups > for resource-managed GPIO descriptors used with ena_gpiod > in the regulator subsystem. I will merge this as a fix so > the other fixes can assume it is in place once I have > a confirmation is solves the problem. gpiod_get_from_of_node() still needs a fix for non-exclusive access (current linux-next lacks code for it), but I assume it will be handled by separate patch. The only problem I predict is the lack of refcounting. Assuming that you would like to continue 'Regulator ena_gpiod fixups' approach, the first call to devm_gpiod_unhinge() will remove 'all allocated instances', so if the same descriptor will be used for more than one regulator, it must be somehow handled... > --- > drivers/gpio/gpiolib-devres.c | 50 ++++++++++++++++++++++++++--------- > 1 file changed, 38 insertions(+), 12 deletions(-) > > diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c > index e35751bf0ea8..304ad54dabb7 100644 > --- a/drivers/gpio/gpiolib-devres.c > +++ b/drivers/gpio/gpiolib-devres.c > @@ -98,15 +98,28 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, > struct gpio_desc **dr; > struct gpio_desc *desc; > > + desc = gpiod_get_index(dev, con_id, idx, flags); > + if (IS_ERR(desc)) > + return desc; > + > + /* > + * For non-exclusive GPIO descriptors, check if this descriptor is > + * already under resource management by this device. > + */ > + if (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) { > + struct devres *dres; > + > + dres = devres_find(dev, devm_gpiod_release, > + devm_gpiod_match, desc); > + if (dres) > + return desc; > + } > + > dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), > GFP_KERNEL); > - if (!dr) > + if (!dr) { > + gpiod_put(desc); > return ERR_PTR(-ENOMEM); > - > - desc = gpiod_get_index(dev, con_id, idx, flags); > - if (IS_ERR(desc)) { > - devres_free(dr); > - return desc; > } > > *dr = desc; > @@ -140,15 +153,28 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, > struct gpio_desc **dr; > struct gpio_desc *desc; > > + desc = gpiod_get_from_of_node(node, propname, index, dflags, label); > + if (IS_ERR(desc)) > + return desc; > + > + /* > + * For non-exclusive GPIO descriptors, check if this descriptor is > + * already under resource management by this device. > + */ > + if (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) { > + struct devres *dres; > + > + dres = devres_find(dev, devm_gpiod_release, > + devm_gpiod_match, desc); > + if (dres) > + return desc; > + } > + > dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), > GFP_KERNEL); > - if (!dr) > + if (!dr) { > + gpiod_put(desc); > return ERR_PTR(-ENOMEM); > - > - desc = gpiod_get_from_of_node(node, propname, index, dflags, label); > - if (IS_ERR(desc)) { > - devres_free(dr); > - return desc; > } > > *dr = desc; Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland