Commit 0c5d1eb7 authored by David Brownell's avatar David Brownell Committed by Ingo Molnar

genirq: record trigger type

Genirq hasn't previously recorded the trigger type used by any given IRQ,
although some irq_chip support has done so.  That data can be useful when
troubleshooting.  This patch records it in the relevant irq_desc.status
bits, and improves consistency between the two driver-visible calls
affected:

 - Make set_irq_type() usage match request_irq() usage:
    * IRQ_TYPE_NONE should be a NOP; succeed, so irq_chip methods
      won't have to handle that case any more (many do it wrong).
    * IRQ_TYPE_PROBE is ignored; any buggy out-of-tree callers
      might need to switch over to the real IRQ probing code.
    * emit the same diagnostics (from shared utility code)

 - Their kerneldoc now reflects usage:
    * request_irq() flags include IRQF_TRIGGER_* to specify
      active edge(s)/level ... docs previously omitted that
    * set_irq_type() is declared in <linux/irq.h> so callers
      should use the (bit-equivalent) IRQ_TYPE_* symbols there

Also: adds a warning about shared IRQs that don't end up using the
requested trigger mode; and fix an unrelated "sparse" warning.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Acked-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent d6d5aeb6
...@@ -111,9 +111,9 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip) ...@@ -111,9 +111,9 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip)
EXPORT_SYMBOL(set_irq_chip); EXPORT_SYMBOL(set_irq_chip);
/** /**
* set_irq_type - set the irq type for an irq * set_irq_type - set the irq trigger type for an irq
* @irq: irq number * @irq: irq number
* @type: interrupt type - see include/linux/interrupt.h * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
*/ */
int set_irq_type(unsigned int irq, unsigned int type) int set_irq_type(unsigned int irq, unsigned int type)
{ {
...@@ -127,11 +127,12 @@ int set_irq_type(unsigned int irq, unsigned int type) ...@@ -127,11 +127,12 @@ int set_irq_type(unsigned int irq, unsigned int type)
} }
desc = irq_desc + irq; desc = irq_desc + irq;
if (desc->chip->set_type) { if (type == IRQ_TYPE_NONE)
spin_lock_irqsave(&desc->lock, flags); return 0;
ret = desc->chip->set_type(irq, type);
spin_unlock_irqrestore(&desc->lock, flags); spin_lock_irqsave(&desc->lock, flags);
} ret = __irq_set_trigger(desc, irq, flags);
spin_unlock_irqrestore(&desc->lock, flags);
return ret; return ret;
} }
EXPORT_SYMBOL(set_irq_type); EXPORT_SYMBOL(set_irq_type);
......
...@@ -10,6 +10,9 @@ extern void irq_chip_set_defaults(struct irq_chip *chip); ...@@ -10,6 +10,9 @@ extern void irq_chip_set_defaults(struct irq_chip *chip);
/* Set default handler: */ /* Set default handler: */
extern void compat_irq_chip_set_default_handler(struct irq_desc *desc); extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
unsigned long flags);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
extern void register_irq_proc(unsigned int irq); extern void register_irq_proc(unsigned int irq);
extern void register_handler_proc(unsigned int irq, struct irqaction *action); extern void register_handler_proc(unsigned int irq, struct irqaction *action);
......
...@@ -216,7 +216,7 @@ void enable_irq(unsigned int irq) ...@@ -216,7 +216,7 @@ void enable_irq(unsigned int irq)
} }
EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(enable_irq);
int set_irq_wake_real(unsigned int irq, unsigned int on) static int set_irq_wake_real(unsigned int irq, unsigned int on)
{ {
struct irq_desc *desc = irq_desc + irq; struct irq_desc *desc = irq_desc + irq;
int ret = -ENXIO; int ret = -ENXIO;
...@@ -305,10 +305,11 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc) ...@@ -305,10 +305,11 @@ 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, int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
unsigned long flags) unsigned long flags)
{ {
int ret; int ret;
struct irq_chip *chip = desc->chip;
if (!chip || !chip->set_type) { if (!chip || !chip->set_type) {
/* /*
...@@ -326,6 +327,11 @@ static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq, ...@@ -326,6 +327,11 @@ static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq,
pr_err("setting trigger mode %d for irq %u failed (%pF)\n", pr_err("setting trigger mode %d for irq %u failed (%pF)\n",
(int)(flags & IRQF_TRIGGER_MASK), (int)(flags & IRQF_TRIGGER_MASK),
irq, chip->set_type); irq, chip->set_type);
else {
/* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */
desc->status &= ~IRQ_TYPE_SENSE_MASK;
desc->status |= flags & IRQ_TYPE_SENSE_MASK;
}
return ret; return ret;
} }
...@@ -404,7 +410,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) ...@@ -404,7 +410,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
/* Setup the type (level, edge polarity) if configured: */ /* Setup the type (level, edge polarity) if configured: */
if (new->flags & IRQF_TRIGGER_MASK) { if (new->flags & IRQF_TRIGGER_MASK) {
ret = __irq_set_trigger(desc->chip, irq, new->flags); ret = __irq_set_trigger(desc, irq, new->flags);
if (ret) { if (ret) {
spin_unlock_irqrestore(&desc->lock, flags); spin_unlock_irqrestore(&desc->lock, flags);
...@@ -430,6 +436,14 @@ int setup_irq(unsigned int irq, struct irqaction *new) ...@@ -430,6 +436,14 @@ 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);
} else if ((new->flags & IRQF_TRIGGER_MASK)
&& (new->flags & IRQF_TRIGGER_MASK)
!= (desc->status & IRQ_TYPE_SENSE_MASK)) {
/* hope the handler works with the actual trigger mode... */
pr_warning("IRQ %d uses trigger mode %d; requested %d\n",
irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),
(int)(new->flags & IRQF_TRIGGER_MASK));
} }
*p = new; *p = new;
...@@ -586,6 +600,7 @@ EXPORT_SYMBOL(free_irq); ...@@ -586,6 +600,7 @@ EXPORT_SYMBOL(free_irq);
* IRQF_SHARED Interrupt is shared * IRQF_SHARED Interrupt is shared
* IRQF_DISABLED Disable local interrupts while processing * IRQF_DISABLED Disable local interrupts while processing
* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
* IRQF_TRIGGER_* Specify active edge(s) or level
* *
*/ */
int request_irq(unsigned int irq, irq_handler_t handler, int request_irq(unsigned int irq, irq_handler_t handler,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment