diff mbox

irq: Consider a negative return value of irq_startup() as an error

Message ID alpine.DEB.2.02.1403080857160.18573@ionos.tec.linutronix.de (mailing list archive)
State New, archived
Headers show

Commit Message

Thomas Gleixner March 8, 2014, 9:15 a.m. UTC
On Fri, 7 Mar 2014, Linus Walleij wrote:
> I'll see what Jean-Jacques comes up with and take it from there unless
> he's interested in taking it all the way.

Thought more about it while trying to come up with a persuasive
argument for the other Linus to take the irq_startup change that late
in the cycle:

Using startup is the wrong point in __setup_irq() because we call
chip->irq_set_type() before we call chip->irq_startup(). And we want
this to be in that order to avoid spurious interrupts.

Proper solution below. That leaves the startup/unmask logic untouched
and provides separate callbacks for this kind of requirements. That
makes it also simpler to have common functions for all gpios as you
don't have to do the mask/unmask dance in startup/shutdown. So you can
simply create gpio_irq_request/release_resources() and let the drivers
add those to their callbacks.

If you agree, I put that into a separate branch based on an upstream
-rc so you can pull it into your gpiolib stuff and work from there.

Thanks,

	tglx

---------------------->
Subject: genirq: Provide irq_request/release_resources chip callbacks
From: Thomas Gleixner <tglx@linutronix.de>
Date: Sat, 08 Mar 2014 08:59:58 +0100

For certain irq types, e.g. gpios, it's necessary to request resources
before starting up the irq.

This might fail so we cannot use the irq_startup() callback because we
might call the irq_set_type() callback before that which does not make
sense when the resource is not available. Calling irq_startup() before
irq_set_type() can lead to spurious interrupts which is not desired
either.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/irq.h |    6 ++++++
 kernel/irq/manage.c |   28 +++++++++++++++++++++++++++-
 2 files changed, 33 insertions(+), 1 deletion(-)

Comments

Linus Walleij March 12, 2014, 2:49 p.m. UTC | #1
On Sat, Mar 8, 2014 at 10:15 AM, Thomas Gleixner <tglx@linutronix.de> wrote:

> On Fri, 7 Mar 2014, Linus Walleij wrote:
>> I'll see what Jean-Jacques comes up with and take it from there unless
>> he's interested in taking it all the way.
>
> Thought more about it while trying to come up with a persuasive
> argument for the other Linus to take the irq_startup change that late
> in the cycle:
>
> Using startup is the wrong point in __setup_irq() because we call
> chip->irq_set_type() before we call chip->irq_startup(). And we want
> this to be in that order to avoid spurious interrupts.
>
> Proper solution below. That leaves the startup/unmask logic untouched
> and provides separate callbacks for this kind of requirements. That
> makes it also simpler to have common functions for all gpios as you
> don't have to do the mask/unmask dance in startup/shutdown. So you can
> simply create gpio_irq_request/release_resources() and let the drivers
> add those to their callbacks.
>
> If you agree, I put that into a separate branch based on an upstream
> -rc so you can pull it into your gpiolib stuff and work from there.

Yeah I really like the looks of this!
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

We need to think about whether the gpiolib changes are serious
enough to be pushed this late in the -rc cycle though.

The thing is that the flagging of GPIO lines as IRQs was to fix
up the ages-old mess of sequential semantic dependencies between
different unrelated gpiolib and irqchip calls, and these bugs have
been around since the first irqchip was implemented in
drivers/gpio I think :-(

But if you prefer, I'll surely do it.

Yours,
Linus Walleij
Thomas Gleixner March 12, 2014, 3:10 p.m. UTC | #2
On Wed, 12 Mar 2014, Linus Walleij wrote:
> On Sat, Mar 8, 2014 at 10:15 AM, Thomas Gleixner <tglx@linutronix.de> wrote:
> 
> > On Fri, 7 Mar 2014, Linus Walleij wrote:
> >> I'll see what Jean-Jacques comes up with and take it from there unless
> >> he's interested in taking it all the way.
> >
> > Thought more about it while trying to come up with a persuasive
> > argument for the other Linus to take the irq_startup change that late
> > in the cycle:
> >
> > Using startup is the wrong point in __setup_irq() because we call
> > chip->irq_set_type() before we call chip->irq_startup(). And we want
> > this to be in that order to avoid spurious interrupts.
> >
> > Proper solution below. That leaves the startup/unmask logic untouched
> > and provides separate callbacks for this kind of requirements. That
> > makes it also simpler to have common functions for all gpios as you
> > don't have to do the mask/unmask dance in startup/shutdown. So you can
> > simply create gpio_irq_request/release_resources() and let the drivers
> > add those to their callbacks.
> >
> > If you agree, I put that into a separate branch based on an upstream
> > -rc so you can pull it into your gpiolib stuff and work from there.
> 
> Yeah I really like the looks of this!
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> 
> We need to think about whether the gpiolib changes are serious
> enough to be pushed this late in the -rc cycle though.
> 
> The thing is that the flagging of GPIO lines as IRQs was to fix
> up the ages-old mess of sequential semantic dependencies between
> different unrelated gpiolib and irqchip calls, and these bugs have
> been around since the first irqchip was implemented in
> drivers/gpio I think :-(
> 
> But if you prefer, I'll surely do it.

Nah. We can just do that for 3.15. If people have the urge to backport
it, it's simple enough to do so.

I pushed out the patch to a separate branch

  git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip irq/for-gpio

and merged that branch back into irq/core.

So you can just pull irq/for-gpio into the gpio work and base the gpio
related changes on top of that. Just mention it in the pull request to
the other Linus that it contains an irq/core change which avoids merge
dependencies.

Thanks,

	tglx
Linus Walleij March 14, 2014, 9:28 a.m. UTC | #3
On Wed, Mar 12, 2014 at 4:10 PM, Thomas Gleixner <tglx@linutronix.de> wrote:

> I pushed out the patch to a separate branch
>
>   git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip irq/for-gpio
>
> and merged that branch back into irq/core.
>
> So you can just pull irq/for-gpio into the gpio work and base the gpio
> related changes on top of that. Just mention it in the pull request to
> the other Linus that it contains an irq/core change which avoids merge
> dependencies.

OK I first merged in the v3.14-rc6 as base and then pulled this in,
so I will proceed to switch the calls over to request/release
resources.

Yours,
Linus Walleij
diff mbox

Patch

Index: linux-2.6/include/linux/irq.h
===================================================================
--- linux-2.6.orig/include/linux/irq.h
+++ linux-2.6/include/linux/irq.h
@@ -303,6 +303,10 @@  static inline irq_hw_number_t irqd_to_hw
  * @irq_pm_shutdown:	function called from core code on shutdown once per chip
  * @irq_calc_mask:	Optional function to set irq_data.mask for special cases
  * @irq_print_chip:	optional to print special chip info in show_interrupts
+ * @irq_request_resources:	optional to request resources before calling
+ *				any other callback related to this irq
+ * @irq_release_resources:	optional to release resources acquired with
+ *				irq_request_resources
  * @flags:		chip specific flags
  */
 struct irq_chip {
@@ -336,6 +340,8 @@  struct irq_chip {
 	void		(*irq_calc_mask)(struct irq_data *data);
 
 	void		(*irq_print_chip)(struct irq_data *data, struct seq_file *p);
+	int		(*irq_request_resources)(struct irq_data *data);
+	void		(*irq_release_resources)(struct irq_data *data);
 
 	unsigned long	flags;
 };
Index: linux-2.6/kernel/irq/manage.c
===================================================================
--- linux-2.6.orig/kernel/irq/manage.c
+++ linux-2.6/kernel/irq/manage.c
@@ -897,6 +897,23 @@  static void irq_setup_forced_threading(s
 	}
 }
 
+static int irq_request_resources(struct irq_desc *desc)
+{
+	struct irq_data *d = &desc->irq_data;
+	struct irq_chip *c = d->chip;
+
+	return c->irq_request_resources ? c->irq_request_resources(d) : 0;
+}
+
+static void irq_release_resources(struct irq_desc *desc)
+{
+	struct irq_data *d = &desc->irq_data;
+	struct irq_chip *c = d->chip;
+
+	if (c->irq_release_resources)
+		c->irq_release_resources(d);
+}
+
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
@@ -1092,6 +1109,13 @@  __setup_irq(unsigned int irq, struct irq
 	}
 
 	if (!shared) {
+		ret = irq_request_resources(desc);
+		if (ret) {
+			pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
+			       new->name, irq, desc->irq_data.chip->name);
+			goto out_mask;
+		}
+
 		init_waitqueue_head(&desc->wait_for_threads);
 
 		/* Setup the type (level, edge polarity) if configured: */
@@ -1262,8 +1286,10 @@  static struct irqaction *__free_irq(unsi
 	*action_ptr = action->next;
 
 	/* If this was the last handler, shut down the IRQ line: */
-	if (!desc->action)
+	if (!desc->action) {
 		irq_shutdown(desc);
+		irq_release_resources(desc);
+	}
 
 #ifdef CONFIG_SMP
 	/* make sure affinity_hint is cleaned up */