mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
generic irqs: handle failure of irqchip->set_type in setup_irq
set_type returns an int indicating success or failure, but up to now setup_irq ignores that. In my case this resulted in a machine hang: gpio-keys requested IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, but arm/ns9xxx can only trigger on one direction so set_type didn't touch the configuration which happens do default to a level sensitiveness and returned -EINVAL. setup_irq ignored that and unmasked the irq. This resulted in an endless triggering of the gpio-key interrupt service routine which effectively killed the machine. With this patch applied setup_irq propagates the error to the caller. Note that before in the case chip && !chip->set_type && !chip->name a NULL pointer was feed to printk. This is fixed, too. Signed-off-by: Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
f606ddf42f
commit
82736f4d1d
1 changed files with 42 additions and 22 deletions
|
@ -308,6 +308,30 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc)
|
||||||
desc->handle_irq = NULL;
|
desc->handle_irq = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq,
|
||||||
|
unsigned long flags)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!chip || !chip->set_type) {
|
||||||
|
/*
|
||||||
|
* IRQF_TRIGGER_* but the PIC does not support multiple
|
||||||
|
* flow-types?
|
||||||
|
*/
|
||||||
|
pr_warning("No set_type function for IRQ %d (%s)\n", irq,
|
||||||
|
chip ? (chip->name ? : "unknown") : "unknown");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = chip->set_type(irq, flags & IRQF_TRIGGER_MASK);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
pr_err("setting flow type for irq %u failed (%pF)\n",
|
||||||
|
irq, chip->set_type);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal function to register an irqaction - typically used to
|
* Internal function to register an irqaction - typically used to
|
||||||
* allocate special interrupts that are part of the architecture.
|
* allocate special interrupts that are part of the architecture.
|
||||||
|
@ -319,6 +343,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
|
||||||
const char *old_name = NULL;
|
const char *old_name = NULL;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int shared = 0;
|
int shared = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (irq >= NR_IRQS)
|
if (irq >= NR_IRQS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -376,36 +401,24 @@ int setup_irq(unsigned int irq, struct irqaction *new)
|
||||||
shared = 1;
|
shared = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*p = new;
|
|
||||||
|
|
||||||
/* Exclude IRQ from balancing */
|
|
||||||
if (new->flags & IRQF_NOBALANCING)
|
|
||||||
desc->status |= IRQ_NO_BALANCING;
|
|
||||||
|
|
||||||
if (!shared) {
|
if (!shared) {
|
||||||
irq_chip_set_defaults(desc->chip);
|
irq_chip_set_defaults(desc->chip);
|
||||||
|
|
||||||
|
/* Setup the type (level, edge polarity) if configured: */
|
||||||
|
if (new->flags & IRQF_TRIGGER_MASK) {
|
||||||
|
ret = __irq_set_trigger(desc->chip, irq, new->flags);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
spin_unlock_irqrestore(&desc->lock, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
compat_irq_chip_set_default_handler(desc);
|
||||||
#if defined(CONFIG_IRQ_PER_CPU)
|
#if defined(CONFIG_IRQ_PER_CPU)
|
||||||
if (new->flags & IRQF_PERCPU)
|
if (new->flags & IRQF_PERCPU)
|
||||||
desc->status |= IRQ_PER_CPU;
|
desc->status |= IRQ_PER_CPU;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Setup the type (level, edge polarity) if configured: */
|
|
||||||
if (new->flags & IRQF_TRIGGER_MASK) {
|
|
||||||
if (desc->chip->set_type)
|
|
||||||
desc->chip->set_type(irq,
|
|
||||||
new->flags & IRQF_TRIGGER_MASK);
|
|
||||||
else
|
|
||||||
/*
|
|
||||||
* IRQF_TRIGGER_* but the PIC does not support
|
|
||||||
* multiple flow-types?
|
|
||||||
*/
|
|
||||||
printk(KERN_WARNING "No IRQF_TRIGGER set_type "
|
|
||||||
"function for IRQ %d (%s)\n", irq,
|
|
||||||
desc->chip->name);
|
|
||||||
} else
|
|
||||||
compat_irq_chip_set_default_handler(desc);
|
|
||||||
|
|
||||||
desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
|
desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
|
||||||
IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
|
IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
|
||||||
|
|
||||||
|
@ -423,6 +436,13 @@ int setup_irq(unsigned int irq, struct irqaction *new)
|
||||||
/* Set default affinity mask once everything is setup */
|
/* Set default affinity mask once everything is setup */
|
||||||
irq_select_affinity(irq);
|
irq_select_affinity(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*p = new;
|
||||||
|
|
||||||
|
/* Exclude IRQ from balancing */
|
||||||
|
if (new->flags & IRQF_NOBALANCING)
|
||||||
|
desc->status |= IRQ_NO_BALANCING;
|
||||||
|
|
||||||
/* Reset broken irq detection when installing new handler */
|
/* Reset broken irq detection when installing new handler */
|
||||||
desc->irq_count = 0;
|
desc->irq_count = 0;
|
||||||
desc->irqs_unhandled = 0;
|
desc->irqs_unhandled = 0;
|
||||||
|
|
Loading…
Reference in a new issue