diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2014-08-28 05:44:31 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-09-01 07:48:05 -0400 |
commit | cab303be91dc47942bc25de33dc1140123540800 (patch) | |
tree | fdfec3ef37665af47af9010419e8f1c2236b0e0f | |
parent | 8df2e02c5c4de9e65ee60153dd9c442356534ad9 (diff) |
genirq: Add sanity checks for PM options on shared interrupt lines
Account the IRQF_NO_SUSPEND and IRQF_RESUME_EARLY actions on shared
interrupt lines and yell loudly if there is a mismatch.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | include/linux/irqdesc.h | 10 | ||||
-rw-r--r-- | kernel/irq/internals.h | 10 | ||||
-rw-r--r-- | kernel/irq/manage.c | 4 | ||||
-rw-r--r-- | kernel/irq/pm.c | 36 |
4 files changed, 60 insertions, 0 deletions
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 472c021a2d4f..cb1a31e448ae 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h | |||
@@ -36,6 +36,11 @@ struct irq_desc; | |||
36 | * @threads_oneshot: bitfield to handle shared oneshot threads | 36 | * @threads_oneshot: bitfield to handle shared oneshot threads |
37 | * @threads_active: number of irqaction threads currently running | 37 | * @threads_active: number of irqaction threads currently running |
38 | * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers | 38 | * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers |
39 | * @nr_actions: number of installed actions on this descriptor | ||
40 | * @no_suspend_depth: number of irqactions on a irq descriptor with | ||
41 | * IRQF_NO_SUSPEND set | ||
42 | * @force_resume_depth: number of irqactions on a irq descriptor with | ||
43 | * IRQF_FORCE_RESUME set | ||
39 | * @dir: /proc/irq/ procfs entry | 44 | * @dir: /proc/irq/ procfs entry |
40 | * @name: flow handler name for /proc/interrupts output | 45 | * @name: flow handler name for /proc/interrupts output |
41 | */ | 46 | */ |
@@ -68,6 +73,11 @@ struct irq_desc { | |||
68 | unsigned long threads_oneshot; | 73 | unsigned long threads_oneshot; |
69 | atomic_t threads_active; | 74 | atomic_t threads_active; |
70 | wait_queue_head_t wait_for_threads; | 75 | wait_queue_head_t wait_for_threads; |
76 | #ifdef CONFIG_PM_SLEEP | ||
77 | unsigned int nr_actions; | ||
78 | unsigned int no_suspend_depth; | ||
79 | unsigned int force_resume_depth; | ||
80 | #endif | ||
71 | #ifdef CONFIG_PROC_FS | 81 | #ifdef CONFIG_PROC_FS |
72 | struct proc_dir_entry *dir; | 82 | struct proc_dir_entry *dir; |
73 | #endif | 83 | #endif |
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index af2821178900..c402502a5111 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
@@ -194,3 +194,13 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *d | |||
194 | __this_cpu_inc(*desc->kstat_irqs); | 194 | __this_cpu_inc(*desc->kstat_irqs); |
195 | __this_cpu_inc(kstat.irqs_sum); | 195 | __this_cpu_inc(kstat.irqs_sum); |
196 | } | 196 | } |
197 | |||
198 | #ifdef CONFIG_PM_SLEEP | ||
199 | void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); | ||
200 | void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action); | ||
201 | #else | ||
202 | static inline void | ||
203 | irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) { } | ||
204 | static inline void | ||
205 | irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) { } | ||
206 | #endif | ||
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index fa564e8db996..0a9104b4608b 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -1200,6 +1200,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
1200 | new->irq = irq; | 1200 | new->irq = irq; |
1201 | *old_ptr = new; | 1201 | *old_ptr = new; |
1202 | 1202 | ||
1203 | irq_pm_install_action(desc, new); | ||
1204 | |||
1203 | /* Reset broken irq detection when installing new handler */ | 1205 | /* Reset broken irq detection when installing new handler */ |
1204 | desc->irq_count = 0; | 1206 | desc->irq_count = 0; |
1205 | desc->irqs_unhandled = 0; | 1207 | desc->irqs_unhandled = 0; |
@@ -1318,6 +1320,8 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
1318 | /* Found it - now remove it from the list of entries: */ | 1320 | /* Found it - now remove it from the list of entries: */ |
1319 | *action_ptr = action->next; | 1321 | *action_ptr = action->next; |
1320 | 1322 | ||
1323 | irq_pm_remove_action(desc, action); | ||
1324 | |||
1321 | /* If this was the last handler, shut down the IRQ line: */ | 1325 | /* If this was the last handler, shut down the IRQ line: */ |
1322 | if (!desc->action) { | 1326 | if (!desc->action) { |
1323 | irq_shutdown(desc); | 1327 | irq_shutdown(desc); |
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index b84141dcee5e..1b1b67a73218 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c | |||
@@ -13,6 +13,42 @@ | |||
13 | 13 | ||
14 | #include "internals.h" | 14 | #include "internals.h" |
15 | 15 | ||
16 | /* | ||
17 | * Called from __setup_irq() with desc->lock held after @action has | ||
18 | * been installed in the action chain. | ||
19 | */ | ||
20 | void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) | ||
21 | { | ||
22 | desc->nr_actions++; | ||
23 | |||
24 | if (action->flags & IRQF_FORCE_RESUME) | ||
25 | desc->force_resume_depth++; | ||
26 | |||
27 | WARN_ON_ONCE(desc->force_resume_depth && | ||
28 | desc->force_resume_depth != desc->nr_actions); | ||
29 | |||
30 | if (action->flags & IRQF_NO_SUSPEND) | ||
31 | desc->no_suspend_depth++; | ||
32 | |||
33 | WARN_ON_ONCE(desc->no_suspend_depth && | ||
34 | desc->no_suspend_depth != desc->nr_actions); | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Called from __free_irq() with desc->lock held after @action has | ||
39 | * been removed from the action chain. | ||
40 | */ | ||
41 | void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) | ||
42 | { | ||
43 | desc->nr_actions--; | ||
44 | |||
45 | if (action->flags & IRQF_FORCE_RESUME) | ||
46 | desc->force_resume_depth--; | ||
47 | |||
48 | if (action->flags & IRQF_NO_SUSPEND) | ||
49 | desc->no_suspend_depth--; | ||
50 | } | ||
51 | |||
16 | static void suspend_device_irq(struct irq_desc *desc, int irq) | 52 | static void suspend_device_irq(struct irq_desc *desc, int irq) |
17 | { | 53 | { |
18 | if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)) | 54 | if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)) |