drivers/gpio/gpio-grgpio.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-)
Remove extraneous dropping of the lock just to call 'request_irq'
and locking again afterwards. Increment reference count
before calling 'request_irq'. Rollback reference count if
'request_irq' fails.
Signed-off-by: Alex Tran <alex.t.tran@gmail.com>
---
drivers/gpio/gpio-grgpio.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 0c0f97fa14fc..18d972fddfac 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -227,6 +227,7 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
struct grgpio_priv *priv = d->host_data;
struct grgpio_lirq *lirq;
struct grgpio_uirq *uirq;
+ bool needs_req = false;
unsigned long flags;
int offset = hwirq;
int ret = 0;
@@ -242,30 +243,28 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
irq, offset);
gpio_generic_chip_lock_irqsave(&priv->chip, flags);
-
- /* Request underlying irq if not already requested */
lirq->irq = irq;
uirq = &priv->uirqs[lirq->index];
- if (uirq->refcnt == 0) {
- /*
- * FIXME: This is not how locking works at all, you can't just
- * release the lock for a moment to do something that can't
- * sleep...
- */
- gpio_generic_chip_unlock_irqrestore(&priv->chip, flags);
+ needs_req = (uirq->refcnt == 0);
+ uirq->refcnt++;
+ gpio_generic_chip_unlock_irqrestore(&priv->chip, flags);
+
+ /* Request underlying irq if not already requested */
+ if (needs_req) {
ret = request_irq(uirq->uirq, grgpio_irq_handler, 0,
dev_name(priv->dev), priv);
if (ret) {
dev_err(priv->dev,
"Could not request underlying irq %d\n",
uirq->uirq);
+
+ // rollback
+ gpio_generic_chip_lock_irqsave(&priv->chip, flags);
+ uirq->refcnt--;
+ gpio_generic_chip_unlock_irqrestore(&priv->chip, flags);
return ret;
}
- gpio_generic_chip_lock_irqsave(&priv->chip, flags);
}
- uirq->refcnt++;
-
- gpio_generic_chip_unlock_irqrestore(&priv->chip, flags);
/* Setup irq */
irq_set_chip_data(irq, priv);
--
2.51.0
On Sun, 28 Sep 2025 07:40:19 +0200, Alex Tran <alex.t.tran@gmail.com> said: > Remove extraneous dropping of the lock just to call 'request_irq' > and locking again afterwards. Increment reference count > before calling 'request_irq'. Rollback reference count if > 'request_irq' fails. > > Signed-off-by: Alex Tran <alex.t.tran@gmail.com> > --- > drivers/gpio/gpio-grgpio.c | 25 ++++++++++++------------- > 1 file changed, 12 insertions(+), 13 deletions(-) > > diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c > index 0c0f97fa14fc..18d972fddfac 100644 > --- a/drivers/gpio/gpio-grgpio.c > +++ b/drivers/gpio/gpio-grgpio.c > @@ -227,6 +227,7 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, > struct grgpio_priv *priv = d->host_data; > struct grgpio_lirq *lirq; > struct grgpio_uirq *uirq; > + bool needs_req = false; > unsigned long flags; > int offset = hwirq; > int ret = 0; > @@ -242,30 +243,28 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, > irq, offset); > > gpio_generic_chip_lock_irqsave(&priv->chip, flags); > - > - /* Request underlying irq if not already requested */ > lirq->irq = irq; > uirq = &priv->uirqs[lirq->index]; > - if (uirq->refcnt == 0) { > - /* > - * FIXME: This is not how locking works at all, you can't just > - * release the lock for a moment to do something that can't > - * sleep... > - */ > - gpio_generic_chip_unlock_irqrestore(&priv->chip, flags); > + needs_req = (uirq->refcnt == 0); > + uirq->refcnt++; Any chance this could be made to use atomic_t instead? Like: if (atomic_fetch_add(1, &priv->uirqs) == 0) { request_irq() ... } ? Bart > + gpio_generic_chip_unlock_irqrestore(&priv->chip, flags); > + > + /* Request underlying irq if not already requested */ > + if (needs_req) { > ret = request_irq(uirq->uirq, grgpio_irq_handler, 0, > dev_name(priv->dev), priv); > if (ret) { > dev_err(priv->dev, > "Could not request underlying irq %d\n", > uirq->uirq); > + > + // rollback > + gpio_generic_chip_lock_irqsave(&priv->chip, flags); > + uirq->refcnt--; > + gpio_generic_chip_unlock_irqrestore(&priv->chip, flags); > return ret; > } > - gpio_generic_chip_lock_irqsave(&priv->chip, flags); > } > - uirq->refcnt++; > - > - gpio_generic_chip_unlock_irqrestore(&priv->chip, flags); > > /* Setup irq */ > irq_set_chip_data(irq, priv); > -- > 2.51.0 > >
On Sun, Sep 28, 2025 at 7:41 AM Alex Tran <alex.t.tran@gmail.com> wrote: > Remove extraneous dropping of the lock just to call 'request_irq' > and locking again afterwards. Increment reference count > before calling 'request_irq'. Rollback reference count if > 'request_irq' fails. > > Signed-off-by: Alex Tran <alex.t.tran@gmail.com> This looks right. Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Yours, Linus Walleij
© 2016 - 2025 Red Hat, Inc.