aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/power/Makefile2
-rw-r--r--drivers/base/power/main.c1
-rw-r--r--drivers/base/power/sysfs.c15
-rw-r--r--drivers/base/power/wakeup.c229
-rw-r--r--drivers/pci/pci-acpi.c1
-rw-r--r--drivers/pci/pci.c20
-rw-r--r--drivers/pci/pci.h1
-rw-r--r--drivers/pci/pcie/pme/pcie_pme.c5
8 files changed, 271 insertions, 3 deletions
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 89de75325cea..cbccf9a3cee4 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,5 @@
1obj-$(CONFIG_PM) += sysfs.o 1obj-$(CONFIG_PM) += sysfs.o
2obj-$(CONFIG_PM_SLEEP) += main.o 2obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
3obj-$(CONFIG_PM_RUNTIME) += runtime.o 3obj-$(CONFIG_PM_RUNTIME) += runtime.o
4obj-$(CONFIG_PM_OPS) += generic_ops.o 4obj-$(CONFIG_PM_OPS) += generic_ops.o
5obj-$(CONFIG_PM_TRACE_RTC) += trace.o 5obj-$(CONFIG_PM_TRACE_RTC) += trace.o
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 941fcb87e52a..5419a49ff135 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -59,6 +59,7 @@ void device_pm_init(struct device *dev)
59{ 59{
60 dev->power.status = DPM_ON; 60 dev->power.status = DPM_ON;
61 init_completion(&dev->power.completion); 61 init_completion(&dev->power.completion);
62 dev->power.wakeup_count = 0;
62 pm_runtime_init(dev); 63 pm_runtime_init(dev);
63} 64}
64 65
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a4c33bc51257..81d344e0e95d 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -73,6 +73,8 @@
73 * device are known to the PM core. However, for some devices this 73 * device are known to the PM core. However, for some devices this
74 * attribute is set to "enabled" by bus type code or device drivers and in 74 * attribute is set to "enabled" by bus type code or device drivers and in
75 * that cases it should be safe to leave the default value. 75 * that cases it should be safe to leave the default value.
76 *
77 * wakeup_count - Report the number of wakeup events related to the device
76 */ 78 */
77 79
78static const char enabled[] = "enabled"; 80static const char enabled[] = "enabled";
@@ -144,6 +146,16 @@ wake_store(struct device * dev, struct device_attribute *attr,
144 146
145static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); 147static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
146 148
149#ifdef CONFIG_PM_SLEEP
150static ssize_t wakeup_count_show(struct device *dev,
151 struct device_attribute *attr, char *buf)
152{
153 return sprintf(buf, "%lu\n", dev->power.wakeup_count);
154}
155
156static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL);
157#endif
158
147#ifdef CONFIG_PM_ADVANCED_DEBUG 159#ifdef CONFIG_PM_ADVANCED_DEBUG
148#ifdef CONFIG_PM_RUNTIME 160#ifdef CONFIG_PM_RUNTIME
149 161
@@ -230,6 +242,9 @@ static struct attribute * power_attrs[] = {
230 &dev_attr_control.attr, 242 &dev_attr_control.attr,
231#endif 243#endif
232 &dev_attr_wakeup.attr, 244 &dev_attr_wakeup.attr,
245#ifdef CONFIG_PM_SLEEP
246 &dev_attr_wakeup_count.attr,
247#endif
233#ifdef CONFIG_PM_ADVANCED_DEBUG 248#ifdef CONFIG_PM_ADVANCED_DEBUG
234 &dev_attr_async.attr, 249 &dev_attr_async.attr,
235#ifdef CONFIG_PM_RUNTIME 250#ifdef CONFIG_PM_RUNTIME
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
new file mode 100644
index 000000000000..25599077c39c
--- /dev/null
+++ b/drivers/base/power/wakeup.c
@@ -0,0 +1,229 @@
1/*
2 * drivers/base/power/wakeup.c - System wakeup events framework
3 *
4 * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
5 *
6 * This file is released under the GPLv2.
7 */
8
9#include <linux/device.h>
10#include <linux/slab.h>
11#include <linux/sched.h>
12#include <linux/capability.h>
13#include <linux/suspend.h>
14#include <linux/pm.h>
15
16/*
17 * If set, the suspend/hibernate code will abort transitions to a sleep state
18 * if wakeup events are registered during or immediately before the transition.
19 */
20bool events_check_enabled;
21
22/* The counter of registered wakeup events. */
23static unsigned long event_count;
24/* A preserved old value of event_count. */
25static unsigned long saved_event_count;
26/* The counter of wakeup events being processed. */
27static unsigned long events_in_progress;
28
29static DEFINE_SPINLOCK(events_lock);
30
31/*
32 * The functions below use the observation that each wakeup event starts a
33 * period in which the system should not be suspended. The moment this period
34 * will end depends on how the wakeup event is going to be processed after being
35 * detected and all of the possible cases can be divided into two distinct
36 * groups.
37 *
38 * First, a wakeup event may be detected by the same functional unit that will
39 * carry out the entire processing of it and possibly will pass it to user space
40 * for further processing. In that case the functional unit that has detected
41 * the event may later "close" the "no suspend" period associated with it
42 * directly as soon as it has been dealt with. The pair of pm_stay_awake() and
43 * pm_relax(), balanced with each other, is supposed to be used in such
44 * situations.
45 *
46 * Second, a wakeup event may be detected by one functional unit and processed
47 * by another one. In that case the unit that has detected it cannot really
48 * "close" the "no suspend" period associated with it, unless it knows in
49 * advance what's going to happen to the event during processing. This
50 * knowledge, however, may not be available to it, so it can simply specify time
51 * to wait before the system can be suspended and pass it as the second
52 * argument of pm_wakeup_event().
53 */
54
55/**
56 * pm_stay_awake - Notify the PM core that a wakeup event is being processed.
57 * @dev: Device the wakeup event is related to.
58 *
59 * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the
60 * counter of wakeup events being processed. If @dev is not NULL, the counter
61 * of wakeup events related to @dev is incremented too.
62 *
63 * Call this function after detecting of a wakeup event if pm_relax() is going
64 * to be called directly after processing the event (and possibly passing it to
65 * user space for further processing).
66 *
67 * It is safe to call this function from interrupt context.
68 */
69void pm_stay_awake(struct device *dev)
70{
71 unsigned long flags;
72
73 spin_lock_irqsave(&events_lock, flags);
74 if (dev)
75 dev->power.wakeup_count++;
76
77 events_in_progress++;
78 spin_unlock_irqrestore(&events_lock, flags);
79}
80
81/**
82 * pm_relax - Notify the PM core that processing of a wakeup event has ended.
83 *
84 * Notify the PM core that a wakeup event has been processed by decrementing
85 * the counter of wakeup events being processed and incrementing the counter
86 * of registered wakeup events.
87 *
88 * Call this function for wakeup events whose processing started with calling
89 * pm_stay_awake().
90 *
91 * It is safe to call it from interrupt context.
92 */
93void pm_relax(void)
94{
95 unsigned long flags;
96
97 spin_lock_irqsave(&events_lock, flags);
98 if (events_in_progress) {
99 events_in_progress--;
100 event_count++;
101 }
102 spin_unlock_irqrestore(&events_lock, flags);
103}
104
105/**
106 * pm_wakeup_work_fn - Deferred closing of a wakeup event.
107 *
108 * Execute pm_relax() for a wakeup event detected in the past and free the
109 * work item object used for queuing up the work.
110 */
111static void pm_wakeup_work_fn(struct work_struct *work)
112{
113 struct delayed_work *dwork = to_delayed_work(work);
114
115 pm_relax();
116 kfree(dwork);
117}
118
119/**
120 * pm_wakeup_event - Notify the PM core of a wakeup event.
121 * @dev: Device the wakeup event is related to.
122 * @msec: Anticipated event processing time (in milliseconds).
123 *
124 * Notify the PM core of a wakeup event (signaled by @dev) that will take
125 * approximately @msec milliseconds to be processed by the kernel. Increment
126 * the counter of wakeup events being processed and queue up a work item
127 * that will execute pm_relax() for the event after @msec milliseconds. If @dev
128 * is not NULL, the counter of wakeup events related to @dev is incremented too.
129 *
130 * It is safe to call this function from interrupt context.
131 */
132void pm_wakeup_event(struct device *dev, unsigned int msec)
133{
134 unsigned long flags;
135 struct delayed_work *dwork;
136
137 dwork = msec ? kzalloc(sizeof(*dwork), GFP_ATOMIC) : NULL;
138
139 spin_lock_irqsave(&events_lock, flags);
140 if (dev)
141 dev->power.wakeup_count++;
142
143 if (dwork) {
144 INIT_DELAYED_WORK(dwork, pm_wakeup_work_fn);
145 schedule_delayed_work(dwork, msecs_to_jiffies(msec));
146
147 events_in_progress++;
148 } else {
149 event_count++;
150 }
151 spin_unlock_irqrestore(&events_lock, flags);
152}
153
154/**
155 * pm_check_wakeup_events - Check for new wakeup events.
156 *
157 * Compare the current number of registered wakeup events with its preserved
158 * value from the past to check if new wakeup events have been registered since
159 * the old value was stored. Check if the current number of wakeup events being
160 * processed is zero.
161 */
162bool pm_check_wakeup_events(void)
163{
164 unsigned long flags;
165 bool ret = true;
166
167 spin_lock_irqsave(&events_lock, flags);
168 if (events_check_enabled) {
169 ret = (event_count == saved_event_count) && !events_in_progress;
170 events_check_enabled = ret;
171 }
172 spin_unlock_irqrestore(&events_lock, flags);
173 return ret;
174}
175
176/**
177 * pm_get_wakeup_count - Read the number of registered wakeup events.
178 * @count: Address to store the value at.
179 *
180 * Store the number of registered wakeup events at the address in @count. Block
181 * if the current number of wakeup events being processed is nonzero.
182 *
183 * Return false if the wait for the number of wakeup events being processed to
184 * drop down to zero has been interrupted by a signal (and the current number
185 * of wakeup events being processed is still nonzero). Otherwise return true.
186 */
187bool pm_get_wakeup_count(unsigned long *count)
188{
189 bool ret;
190
191 spin_lock_irq(&events_lock);
192 if (capable(CAP_SYS_ADMIN))
193 events_check_enabled = false;
194
195 while (events_in_progress && !signal_pending(current)) {
196 spin_unlock_irq(&events_lock);
197
198 schedule_timeout_interruptible(msecs_to_jiffies(100));
199
200 spin_lock_irq(&events_lock);
201 }
202 *count = event_count;
203 ret = !events_in_progress;
204 spin_unlock_irq(&events_lock);
205 return ret;
206}
207
208/**
209 * pm_save_wakeup_count - Save the current number of registered wakeup events.
210 * @count: Value to compare with the current number of registered wakeup events.
211 *
212 * If @count is equal to the current number of registered wakeup events and the
213 * current number of wakeup events being processed is zero, store @count as the
214 * old number of registered wakeup events to be used by pm_check_wakeup_events()
215 * and return true. Otherwise return false.
216 */
217bool pm_save_wakeup_count(unsigned long count)
218{
219 bool ret = false;
220
221 spin_lock_irq(&events_lock);
222 if (count == event_count && !events_in_progress) {
223 saved_event_count = count;
224 events_check_enabled = true;
225 ret = true;
226 }
227 spin_unlock_irq(&events_lock);
228 return ret;
229}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 2e7a3bf13824..1ab98bbe58dd 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -48,6 +48,7 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
48 if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) { 48 if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
49 pci_check_pme_status(pci_dev); 49 pci_check_pme_status(pci_dev);
50 pm_runtime_resume(&pci_dev->dev); 50 pm_runtime_resume(&pci_dev->dev);
51 pci_wakeup_event(pci_dev);
51 if (pci_dev->subordinate) 52 if (pci_dev->subordinate)
52 pci_pme_wakeup_bus(pci_dev->subordinate); 53 pci_pme_wakeup_bus(pci_dev->subordinate);
53 } 54 }
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 740fb4ea9669..130ed1daf0f8 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1275,6 +1275,22 @@ bool pci_check_pme_status(struct pci_dev *dev)
1275 return ret; 1275 return ret;
1276} 1276}
1277 1277
1278/*
1279 * Time to wait before the system can be put into a sleep state after reporting
1280 * a wakeup event signaled by a PCI device.
1281 */
1282#define PCI_WAKEUP_COOLDOWN 100
1283
1284/**
1285 * pci_wakeup_event - Report a wakeup event related to a given PCI device.
1286 * @dev: Device to report the wakeup event for.
1287 */
1288void pci_wakeup_event(struct pci_dev *dev)
1289{
1290 if (device_may_wakeup(&dev->dev))
1291 pm_wakeup_event(&dev->dev, PCI_WAKEUP_COOLDOWN);
1292}
1293
1278/** 1294/**
1279 * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set. 1295 * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
1280 * @dev: Device to handle. 1296 * @dev: Device to handle.
@@ -1285,8 +1301,10 @@ bool pci_check_pme_status(struct pci_dev *dev)
1285 */ 1301 */
1286static int pci_pme_wakeup(struct pci_dev *dev, void *ign) 1302static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
1287{ 1303{
1288 if (pci_check_pme_status(dev)) 1304 if (pci_check_pme_status(dev)) {
1289 pm_request_resume(&dev->dev); 1305 pm_request_resume(&dev->dev);
1306 pci_wakeup_event(dev);
1307 }
1290 return 0; 1308 return 0;
1291} 1309}
1292 1310
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f8077b3c8c8c..c8b7fd056ccd 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -56,6 +56,7 @@ extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
56extern void pci_disable_enabled_device(struct pci_dev *dev); 56extern void pci_disable_enabled_device(struct pci_dev *dev);
57extern bool pci_check_pme_status(struct pci_dev *dev); 57extern bool pci_check_pme_status(struct pci_dev *dev);
58extern int pci_finish_runtime_suspend(struct pci_dev *dev); 58extern int pci_finish_runtime_suspend(struct pci_dev *dev);
59extern void pci_wakeup_event(struct pci_dev *dev);
59extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); 60extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
60extern void pci_pme_wakeup_bus(struct pci_bus *bus); 61extern void pci_pme_wakeup_bus(struct pci_bus *bus);
61extern void pci_pm_init(struct pci_dev *dev); 62extern void pci_pm_init(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c
index d672a0a63816..bbdea18693d9 100644
--- a/drivers/pci/pcie/pme/pcie_pme.c
+++ b/drivers/pci/pcie/pme/pcie_pme.c
@@ -154,6 +154,7 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus)
154 /* Skip PCIe devices in case we started from a root port. */ 154 /* Skip PCIe devices in case we started from a root port. */
155 if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { 155 if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) {
156 pm_request_resume(&dev->dev); 156 pm_request_resume(&dev->dev);
157 pci_wakeup_event(dev);
157 ret = true; 158 ret = true;
158 } 159 }
159 160
@@ -254,8 +255,10 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
254 if (found) { 255 if (found) {
255 /* The device is there, but we have to check its PME status. */ 256 /* The device is there, but we have to check its PME status. */
256 found = pci_check_pme_status(dev); 257 found = pci_check_pme_status(dev);
257 if (found) 258 if (found) {
258 pm_request_resume(&dev->dev); 259 pm_request_resume(&dev->dev);
260 pci_wakeup_event(dev);
261 }
259 pci_dev_put(dev); 262 pci_dev_put(dev);
260 } else if (devfn) { 263 } else if (devfn) {
261 /* 264 /*