diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2008-10-01 17:46:18 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-02 04:24:09 -0400 |
commit | 0c5d1eb77a8be917b638344a22afe1398236482b (patch) | |
tree | 57d57c9b270cc10428f818cfec9725a1344b78ce /kernel/irq | |
parent | d6d5aeb661fc14655c417f3582ae7ec52985d2a8 (diff) |
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>
Diffstat (limited to 'kernel/irq')
-rw-r--r-- | kernel/irq/chip.c | 15 | ||||
-rw-r--r-- | kernel/irq/internals.h | 3 | ||||
-rw-r--r-- | kernel/irq/manage.c | 21 |
3 files changed, 29 insertions, 10 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index d663338cb4a8..5203a599d211 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -111,9 +111,9 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip) | |||
111 | EXPORT_SYMBOL(set_irq_chip); | 111 | EXPORT_SYMBOL(set_irq_chip); |
112 | 112 | ||
113 | /** | 113 | /** |
114 | * set_irq_type - set the irq type for an irq | 114 | * set_irq_type - set the irq trigger type for an irq |
115 | * @irq: irq number | 115 | * @irq: irq number |
116 | * @type: interrupt type - see include/linux/interrupt.h | 116 | * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h |
117 | */ | 117 | */ |
118 | int set_irq_type(unsigned int irq, unsigned int type) | 118 | int set_irq_type(unsigned int irq, unsigned int type) |
119 | { | 119 | { |
@@ -127,11 +127,12 @@ int set_irq_type(unsigned int irq, unsigned int type) | |||
127 | } | 127 | } |
128 | 128 | ||
129 | desc = irq_desc + irq; | 129 | desc = irq_desc + irq; |
130 | if (desc->chip->set_type) { | 130 | if (type == IRQ_TYPE_NONE) |
131 | spin_lock_irqsave(&desc->lock, flags); | 131 | return 0; |
132 | ret = desc->chip->set_type(irq, type); | 132 | |
133 | spin_unlock_irqrestore(&desc->lock, flags); | 133 | spin_lock_irqsave(&desc->lock, flags); |
134 | } | 134 | ret = __irq_set_trigger(desc, irq, flags); |
135 | spin_unlock_irqrestore(&desc->lock, flags); | ||
135 | return ret; | 136 | return ret; |
136 | } | 137 | } |
137 | EXPORT_SYMBOL(set_irq_type); | 138 | EXPORT_SYMBOL(set_irq_type); |
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 08a849a22447..422dd00c8bd3 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
@@ -10,6 +10,9 @@ extern void irq_chip_set_defaults(struct irq_chip *chip); | |||
10 | /* Set default handler: */ | 10 | /* Set default handler: */ |
11 | extern void compat_irq_chip_set_default_handler(struct irq_desc *desc); | 11 | extern void compat_irq_chip_set_default_handler(struct irq_desc *desc); |
12 | 12 | ||
13 | extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | ||
14 | unsigned long flags); | ||
15 | |||
13 | #ifdef CONFIG_PROC_FS | 16 | #ifdef CONFIG_PROC_FS |
14 | extern void register_irq_proc(unsigned int irq); | 17 | extern void register_irq_proc(unsigned int irq); |
15 | extern void register_handler_proc(unsigned int irq, struct irqaction *action); | 18 | extern void register_handler_proc(unsigned int irq, struct irqaction *action); |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d62f69ba7453..e59157b591f8 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -216,7 +216,7 @@ void enable_irq(unsigned int irq) | |||
216 | } | 216 | } |
217 | EXPORT_SYMBOL(enable_irq); | 217 | EXPORT_SYMBOL(enable_irq); |
218 | 218 | ||
219 | int set_irq_wake_real(unsigned int irq, unsigned int on) | 219 | static int set_irq_wake_real(unsigned int irq, unsigned int on) |
220 | { | 220 | { |
221 | struct irq_desc *desc = irq_desc + irq; | 221 | struct irq_desc *desc = irq_desc + irq; |
222 | int ret = -ENXIO; | 222 | int ret = -ENXIO; |
@@ -305,10 +305,11 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc) | |||
305 | desc->handle_irq = NULL; | 305 | desc->handle_irq = NULL; |
306 | } | 306 | } |
307 | 307 | ||
308 | static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq, | 308 | int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, |
309 | unsigned long flags) | 309 | unsigned long flags) |
310 | { | 310 | { |
311 | int ret; | 311 | int ret; |
312 | struct irq_chip *chip = desc->chip; | ||
312 | 313 | ||
313 | if (!chip || !chip->set_type) { | 314 | if (!chip || !chip->set_type) { |
314 | /* | 315 | /* |
@@ -326,6 +327,11 @@ static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq, | |||
326 | pr_err("setting trigger mode %d for irq %u failed (%pF)\n", | 327 | pr_err("setting trigger mode %d for irq %u failed (%pF)\n", |
327 | (int)(flags & IRQF_TRIGGER_MASK), | 328 | (int)(flags & IRQF_TRIGGER_MASK), |
328 | irq, chip->set_type); | 329 | irq, chip->set_type); |
330 | else { | ||
331 | /* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */ | ||
332 | desc->status &= ~IRQ_TYPE_SENSE_MASK; | ||
333 | desc->status |= flags & IRQ_TYPE_SENSE_MASK; | ||
334 | } | ||
329 | 335 | ||
330 | return ret; | 336 | return ret; |
331 | } | 337 | } |
@@ -404,7 +410,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
404 | 410 | ||
405 | /* Setup the type (level, edge polarity) if configured: */ | 411 | /* Setup the type (level, edge polarity) if configured: */ |
406 | if (new->flags & IRQF_TRIGGER_MASK) { | 412 | if (new->flags & IRQF_TRIGGER_MASK) { |
407 | ret = __irq_set_trigger(desc->chip, irq, new->flags); | 413 | ret = __irq_set_trigger(desc, irq, new->flags); |
408 | 414 | ||
409 | if (ret) { | 415 | if (ret) { |
410 | spin_unlock_irqrestore(&desc->lock, flags); | 416 | spin_unlock_irqrestore(&desc->lock, flags); |
@@ -430,6 +436,14 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
430 | 436 | ||
431 | /* Set default affinity mask once everything is setup */ | 437 | /* Set default affinity mask once everything is setup */ |
432 | irq_select_affinity(irq); | 438 | irq_select_affinity(irq); |
439 | |||
440 | } else if ((new->flags & IRQF_TRIGGER_MASK) | ||
441 | && (new->flags & IRQF_TRIGGER_MASK) | ||
442 | != (desc->status & IRQ_TYPE_SENSE_MASK)) { | ||
443 | /* hope the handler works with the actual trigger mode... */ | ||
444 | pr_warning("IRQ %d uses trigger mode %d; requested %d\n", | ||
445 | irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK), | ||
446 | (int)(new->flags & IRQF_TRIGGER_MASK)); | ||
433 | } | 447 | } |
434 | 448 | ||
435 | *p = new; | 449 | *p = new; |
@@ -586,6 +600,7 @@ EXPORT_SYMBOL(free_irq); | |||
586 | * IRQF_SHARED Interrupt is shared | 600 | * IRQF_SHARED Interrupt is shared |
587 | * IRQF_DISABLED Disable local interrupts while processing | 601 | * IRQF_DISABLED Disable local interrupts while processing |
588 | * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy | 602 | * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy |
603 | * IRQF_TRIGGER_* Specify active edge(s) or level | ||
589 | * | 604 | * |
590 | */ | 605 | */ |
591 | int request_irq(unsigned int irq, irq_handler_t handler, | 606 | int request_irq(unsigned int irq, irq_handler_t handler, |