Branch data Line data Source code
1 : : /*
2 : : * linux/kernel/irq/pm.c
3 : : *
4 : : * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
5 : : *
6 : : * This file contains power management functions related to interrupts.
7 : : */
8 : :
9 : : #include <linux/irq.h>
10 : : #include <linux/module.h>
11 : : #include <linux/interrupt.h>
12 : : #include <linux/syscore_ops.h>
13 : :
14 : : #include "internals.h"
15 : :
16 : : /**
17 : : * suspend_device_irqs - disable all currently enabled interrupt lines
18 : : *
19 : : * During system-wide suspend or hibernation device drivers need to be prevented
20 : : * from receiving interrupts and this function is provided for this purpose.
21 : : * It marks all interrupt lines in use, except for the timer ones, as disabled
22 : : * and sets the IRQS_SUSPENDED flag for each of them.
23 : : */
24 : 0 : void suspend_device_irqs(void)
25 : : {
26 : : struct irq_desc *desc;
27 : : int irq;
28 : :
29 [ # # ][ # # ]: 0 : for_each_irq_desc(irq, desc) {
30 : : unsigned long flags;
31 : :
32 : 0 : raw_spin_lock_irqsave(&desc->lock, flags);
33 : 0 : __disable_irq(desc, irq, true);
34 : 0 : raw_spin_unlock_irqrestore(&desc->lock, flags);
35 : : }
36 : :
37 [ # # ][ # # ]: 0 : for_each_irq_desc(irq, desc)
38 [ # # ]: 0 : if (desc->istate & IRQS_SUSPENDED)
39 : 0 : synchronize_irq(irq);
40 : 0 : }
41 : : EXPORT_SYMBOL_GPL(suspend_device_irqs);
42 : :
43 : 0 : static void resume_irqs(bool want_early)
44 : : {
45 : : struct irq_desc *desc;
46 : : int irq;
47 : :
48 [ # # ][ # # ]: 0 : for_each_irq_desc(irq, desc) {
49 : : unsigned long flags;
50 [ # # ][ # # ]: 0 : bool is_early = desc->action &&
51 : 0 : desc->action->flags & IRQF_EARLY_RESUME;
52 : :
53 [ # # ]: 0 : if (!is_early && want_early)
54 : 0 : continue;
55 : :
56 : 0 : raw_spin_lock_irqsave(&desc->lock, flags);
57 : 0 : __enable_irq(desc, irq, true);
58 : 0 : raw_spin_unlock_irqrestore(&desc->lock, flags);
59 : : }
60 : 0 : }
61 : :
62 : : /**
63 : : * irq_pm_syscore_ops - enable interrupt lines early
64 : : *
65 : : * Enable all interrupt lines with %IRQF_EARLY_RESUME set.
66 : : */
67 : 0 : static void irq_pm_syscore_resume(void)
68 : : {
69 : 0 : resume_irqs(true);
70 : 0 : }
71 : :
72 : : static struct syscore_ops irq_pm_syscore_ops = {
73 : : .resume = irq_pm_syscore_resume,
74 : : };
75 : :
76 : 0 : static int __init irq_pm_init_ops(void)
77 : : {
78 : 0 : register_syscore_ops(&irq_pm_syscore_ops);
79 : 0 : return 0;
80 : : }
81 : :
82 : : device_initcall(irq_pm_init_ops);
83 : :
84 : : /**
85 : : * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs()
86 : : *
87 : : * Enable all non-%IRQF_EARLY_RESUME interrupt lines previously
88 : : * disabled by suspend_device_irqs() that have the IRQS_SUSPENDED flag
89 : : * set as well as those with %IRQF_FORCE_RESUME.
90 : : */
91 : 0 : void resume_device_irqs(void)
92 : : {
93 : 0 : resume_irqs(false);
94 : 0 : }
95 : : EXPORT_SYMBOL_GPL(resume_device_irqs);
96 : :
97 : : /**
98 : : * check_wakeup_irqs - check if any wake-up interrupts are pending
99 : : */
100 : 0 : int check_wakeup_irqs(void)
101 : : {
102 : 0 : struct irq_desc *desc;
103 : : int irq;
104 : :
105 [ # # ][ # # ]: 0 : for_each_irq_desc(irq, desc) {
106 [ # # ]: 0 : if (irqd_is_wakeup_set(&desc->irq_data)) {
107 [ # # ]: 0 : if (desc->istate & IRQS_PENDING) {
108 [ # # ][ # # ]: 0 : pr_info("Wakeup IRQ %d %s pending, suspend aborted\n",
109 : : irq,
110 : : desc->action && desc->action->name ?
111 : : desc->action->name : "");
112 : 0 : return -EBUSY;
113 : : }
114 : 0 : continue;
115 : : }
116 : : /*
117 : : * Check the non wakeup interrupts whether they need
118 : : * to be masked before finally going into suspend
119 : : * state. That's for hardware which has no wakeup
120 : : * source configuration facility. The chip
121 : : * implementation indicates that with
122 : : * IRQCHIP_MASK_ON_SUSPEND.
123 : : */
124 [ # # ][ # # ]: 0 : if (desc->istate & IRQS_SUSPENDED &&
125 : 0 : irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
126 : 0 : mask_irq(desc);
127 : : }
128 : :
129 : : return 0;
130 : : }
|