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: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
d6d5aeb661
commit
0c5d1eb77a
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
desc = irq_desc + irq;
|
desc = irq_desc + irq;
|
||||||
if (desc->chip->set_type) {
|
if (type == IRQ_TYPE_NONE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&desc->lock, flags);
|
spin_lock_irqsave(&desc->lock, flags);
|
||||||
ret = desc->chip->set_type(irq, type);
|
ret = __irq_set_trigger(desc, irq, flags);
|
||||||
spin_unlock_irqrestore(&desc->lock, 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);
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
|
|
||||||
/* 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);
|
||||||
* 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,
|
||||||
|
|
Loading…
Reference in New Issue