aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-08-28 05:44:31 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-09-01 07:48:05 -0400
commitcab303be91dc47942bc25de33dc1140123540800 (patch)
treefdfec3ef37665af47af9010419e8f1c2236b0e0f
parent8df2e02c5c4de9e65ee60153dd9c442356534ad9 (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.h10
-rw-r--r--kernel/irq/internals.h10
-rw-r--r--kernel/irq/manage.c4
-rw-r--r--kernel/irq/pm.c36
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
199void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action);
200void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action);
201#else
202static inline void
203irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) { }
204static inline void
205irq_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 */
20void 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 */
41void 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
16static void suspend_device_irq(struct irq_desc *desc, int irq) 52static 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))