]>
Commit | Line | Data |
---|---|---|
25940e12 GKH |
1 | From b4bc724e82e80478cba5fe9825b62e71ddf78757 Mon Sep 17 00:00:00 2001 |
2 | From: Thomas Gleixner <tglx@linutronix.de> | |
3 | Date: Wed, 8 Feb 2012 11:57:52 +0100 | |
4 | Subject: genirq: Handle pending irqs in irq_startup() | |
5 | ||
6 | From: Thomas Gleixner <tglx@linutronix.de> | |
7 | ||
8 | commit b4bc724e82e80478cba5fe9825b62e71ddf78757 upstream. | |
9 | ||
10 | An interrupt might be pending when irq_startup() is called, but the | |
11 | startup code does not invoke the resend logic. In some cases this | |
12 | prevents the device from issuing another interrupt which renders the | |
13 | device non functional. | |
14 | ||
15 | Call the resend function in irq_startup() to keep things going. | |
16 | ||
17 | Reported-and-tested-by: Russell King <rmk+kernel@arm.linux.org.uk> | |
18 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
20 | ||
21 | --- | |
22 | kernel/irq/autoprobe.c | 4 ++-- | |
23 | kernel/irq/chip.c | 17 ++++++++++------- | |
24 | kernel/irq/internals.h | 2 +- | |
25 | kernel/irq/manage.c | 2 +- | |
26 | 4 files changed, 14 insertions(+), 11 deletions(-) | |
27 | ||
28 | --- a/kernel/irq/autoprobe.c | |
29 | +++ b/kernel/irq/autoprobe.c | |
30 | @@ -53,7 +53,7 @@ unsigned long probe_irq_on(void) | |
31 | if (desc->irq_data.chip->irq_set_type) | |
32 | desc->irq_data.chip->irq_set_type(&desc->irq_data, | |
33 | IRQ_TYPE_PROBE); | |
34 | - irq_startup(desc); | |
35 | + irq_startup(desc, false); | |
36 | } | |
37 | raw_spin_unlock_irq(&desc->lock); | |
38 | } | |
39 | @@ -70,7 +70,7 @@ unsigned long probe_irq_on(void) | |
40 | raw_spin_lock_irq(&desc->lock); | |
41 | if (!desc->action && irq_settings_can_probe(desc)) { | |
42 | desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; | |
43 | - if (irq_startup(desc)) | |
44 | + if (irq_startup(desc, false)) | |
45 | desc->istate |= IRQS_PENDING; | |
46 | } | |
47 | raw_spin_unlock_irq(&desc->lock); | |
48 | --- a/kernel/irq/chip.c | |
49 | +++ b/kernel/irq/chip.c | |
50 | @@ -157,19 +157,22 @@ static void irq_state_set_masked(struct | |
51 | irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); | |
52 | } | |
53 | ||
54 | -int irq_startup(struct irq_desc *desc) | |
55 | +int irq_startup(struct irq_desc *desc, bool resend) | |
56 | { | |
57 | + int ret = 0; | |
58 | + | |
59 | irq_state_clr_disabled(desc); | |
60 | desc->depth = 0; | |
61 | ||
62 | if (desc->irq_data.chip->irq_startup) { | |
63 | - int ret = desc->irq_data.chip->irq_startup(&desc->irq_data); | |
64 | + ret = desc->irq_data.chip->irq_startup(&desc->irq_data); | |
65 | irq_state_clr_masked(desc); | |
66 | - return ret; | |
67 | + } else { | |
68 | + irq_enable(desc); | |
69 | } | |
70 | - | |
71 | - irq_enable(desc); | |
72 | - return 0; | |
73 | + if (resend) | |
74 | + check_irq_resend(desc, desc->irq_data.irq); | |
75 | + return ret; | |
76 | } | |
77 | ||
78 | void irq_shutdown(struct irq_desc *desc) | |
79 | @@ -596,7 +599,7 @@ __irq_set_handler(unsigned int irq, irq_ | |
80 | irq_settings_set_noprobe(desc); | |
81 | irq_settings_set_norequest(desc); | |
82 | irq_settings_set_nothread(desc); | |
83 | - irq_startup(desc); | |
84 | + irq_startup(desc, true); | |
85 | } | |
86 | out: | |
87 | irq_put_desc_busunlock(desc, flags); | |
88 | --- a/kernel/irq/internals.h | |
89 | +++ b/kernel/irq/internals.h | |
90 | @@ -67,7 +67,7 @@ extern int __irq_set_trigger(struct irq_ | |
91 | extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); | |
92 | extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); | |
93 | ||
94 | -extern int irq_startup(struct irq_desc *desc); | |
95 | +extern int irq_startup(struct irq_desc *desc, bool resend); | |
96 | extern void irq_shutdown(struct irq_desc *desc); | |
97 | extern void irq_enable(struct irq_desc *desc); | |
98 | extern void irq_disable(struct irq_desc *desc); | |
99 | --- a/kernel/irq/manage.c | |
100 | +++ b/kernel/irq/manage.c | |
101 | @@ -1018,7 +1018,7 @@ __setup_irq(unsigned int irq, struct irq | |
102 | desc->istate |= IRQS_ONESHOT; | |
103 | ||
104 | if (irq_settings_can_autoenable(desc)) | |
105 | - irq_startup(desc); | |
106 | + irq_startup(desc, true); | |
107 | else | |
108 | /* Undo nested disables: */ | |
109 | desc->depth = 1; |