PM / Wakeup: Introduce wakeup source objects and event statistics (v3)

Introduce struct wakeup_source for representing system wakeup sources
within the kernel and for collecting statistics related to them.
Make the recently introduced helper functions pm_wakeup_event(),
pm_stay_awake() and pm_relax() use struct wakeup_source objects
internally, so that wakeup statistics associated with wakeup devices
can be collected and reported in a consistent way (the definition of
pm_relax() is changed, which is harmless, because this function is
not called directly by anyone yet). Introduce new wakeup-related
sysfs device attributes in /sys/devices/.../power for reporting the
device wakeup statistics.

Change the global wakeup events counters event_count and
events_in_progress into atomic variables, so that it is not necessary
to acquire a global spinlock in pm_wakeup_event(), pm_stay_awake()
and pm_relax(), which should allow us to avoid lock contention in
these functions on SMP systems with many wakeup devices.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

+762 -131
+70
Documentation/ABI/testing/sysfs-devices-power
··· 77 devices this attribute is set to "enabled" by bus type code or 78 device drivers and in that cases it should be safe to leave the 79 default value.
··· 77 devices this attribute is set to "enabled" by bus type code or 78 device drivers and in that cases it should be safe to leave the 79 default value. 80 + 81 + What: /sys/devices/.../power/wakeup_count 82 + Date: September 2010 83 + Contact: Rafael J. Wysocki <rjw@sisk.pl> 84 + Description: 85 + The /sys/devices/.../wakeup_count attribute contains the number 86 + of signaled wakeup events associated with the device. This 87 + attribute is read-only. If the device is not enabled to wake up 88 + the system from sleep states, this attribute is empty. 89 + 90 + What: /sys/devices/.../power/wakeup_active_count 91 + Date: September 2010 92 + Contact: Rafael J. Wysocki <rjw@sisk.pl> 93 + Description: 94 + The /sys/devices/.../wakeup_active_count attribute contains the 95 + number of times the processing of wakeup events associated with 96 + the device was completed (at the kernel level). This attribute 97 + is read-only. If the device is not enabled to wake up the 98 + system from sleep states, this attribute is empty. 99 + 100 + What: /sys/devices/.../power/wakeup_hit_count 101 + Date: September 2010 102 + Contact: Rafael J. Wysocki <rjw@sisk.pl> 103 + Description: 104 + The /sys/devices/.../wakeup_hit_count attribute contains the 105 + number of times the processing of a wakeup event associated with 106 + the device might prevent the system from entering a sleep state. 107 + This attribute is read-only. If the device is not enabled to 108 + wake up the system from sleep states, this attribute is empty. 109 + 110 + What: /sys/devices/.../power/wakeup_active 111 + Date: September 2010 112 + Contact: Rafael J. Wysocki <rjw@sisk.pl> 113 + Description: 114 + The /sys/devices/.../wakeup_active attribute contains either 1, 115 + or 0, depending on whether or not a wakeup event associated with 116 + the device is being processed (1). This attribute is read-only. 117 + If the device is not enabled to wake up the system from sleep 118 + states, this attribute is empty. 119 + 120 + What: /sys/devices/.../power/wakeup_total_time_ms 121 + Date: September 2010 122 + Contact: Rafael J. Wysocki <rjw@sisk.pl> 123 + Description: 124 + The /sys/devices/.../wakeup_total_time_ms attribute contains 125 + the total time of processing wakeup events associated with the 126 + device, in milliseconds. This attribute is read-only. If the 127 + device is not enabled to wake up the system from sleep states, 128 + this attribute is empty. 129 + 130 + What: /sys/devices/.../power/wakeup_max_time_ms 131 + Date: September 2010 132 + Contact: Rafael J. Wysocki <rjw@sisk.pl> 133 + Description: 134 + The /sys/devices/.../wakeup_max_time_ms attribute contains 135 + the maximum time of processing a single wakeup event associated 136 + with the device, in milliseconds. This attribute is read-only. 137 + If the device is not enabled to wake up the system from sleep 138 + states, this attribute is empty. 139 + 140 + What: /sys/devices/.../power/wakeup_last_time_ms 141 + Date: September 2010 142 + Contact: Rafael J. Wysocki <rjw@sisk.pl> 143 + Description: 144 + The /sys/devices/.../wakeup_last_time_ms attribute contains 145 + the value of the monotonic clock corresponding to the time of 146 + signaling the last wakeup event associated with the device, in 147 + milliseconds. This attribute is read-only. If the device is 148 + not enabled to wake up the system from sleep states, this 149 + attribute is empty.
+3 -1
drivers/base/power/main.c
··· 60 dev->power.status = DPM_ON; 61 init_completion(&dev->power.completion); 62 complete_all(&dev->power.completion); 63 - dev->power.wakeup_count = 0; 64 pm_runtime_init(dev); 65 } 66 ··· 121 mutex_lock(&dpm_list_mtx); 122 list_del_init(&dev->power.entry); 123 mutex_unlock(&dpm_list_mtx); 124 pm_runtime_remove(dev); 125 } 126
··· 60 dev->power.status = DPM_ON; 61 init_completion(&dev->power.completion); 62 complete_all(&dev->power.completion); 63 + dev->power.wakeup = NULL; 64 + spin_lock_init(&dev->power.lock); 65 pm_runtime_init(dev); 66 } 67 ··· 120 mutex_lock(&dpm_list_mtx); 121 list_del_init(&dev->power.entry); 122 mutex_unlock(&dpm_list_mtx); 123 + device_wakeup_disable(dev); 124 pm_runtime_remove(dev); 125 } 126
+1
drivers/base/power/power.h
··· 34 35 static inline void device_pm_init(struct device *dev) 36 { 37 pm_runtime_init(dev); 38 } 39
··· 34 35 static inline void device_pm_init(struct device *dev) 36 { 37 + spin_lock_init(&dev->power.lock); 38 pm_runtime_init(dev); 39 } 40
-2
drivers/base/power/runtime.c
··· 1099 */ 1100 void pm_runtime_init(struct device *dev) 1101 { 1102 - spin_lock_init(&dev->power.lock); 1103 - 1104 dev->power.runtime_status = RPM_SUSPENDED; 1105 dev->power.idle_notification = false; 1106
··· 1099 */ 1100 void pm_runtime_init(struct device *dev) 1101 { 1102 dev->power.runtime_status = RPM_SUSPENDED; 1103 dev->power.idle_notification = false; 1104
+119 -2
drivers/base/power/sysfs.c
··· 210 static ssize_t wakeup_count_show(struct device *dev, 211 struct device_attribute *attr, char *buf) 212 { 213 - return sprintf(buf, "%lu\n", dev->power.wakeup_count); 214 } 215 216 static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL); 217 - #endif 218 219 #ifdef CONFIG_PM_ADVANCED_DEBUG 220 #ifdef CONFIG_PM_RUNTIME ··· 399 &dev_attr_wakeup.attr, 400 #ifdef CONFIG_PM_SLEEP 401 &dev_attr_wakeup_count.attr, 402 #endif 403 #ifdef CONFIG_PM_ADVANCED_DEBUG 404 &dev_attr_async.attr,
··· 210 static ssize_t wakeup_count_show(struct device *dev, 211 struct device_attribute *attr, char *buf) 212 { 213 + unsigned long count = 0; 214 + bool enabled = false; 215 + 216 + spin_lock_irq(&dev->power.lock); 217 + if (dev->power.wakeup) { 218 + count = dev->power.wakeup->event_count; 219 + enabled = true; 220 + } 221 + spin_unlock_irq(&dev->power.lock); 222 + return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); 223 } 224 225 static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL); 226 + 227 + static ssize_t wakeup_active_count_show(struct device *dev, 228 + struct device_attribute *attr, char *buf) 229 + { 230 + unsigned long count = 0; 231 + bool enabled = false; 232 + 233 + spin_lock_irq(&dev->power.lock); 234 + if (dev->power.wakeup) { 235 + count = dev->power.wakeup->active_count; 236 + enabled = true; 237 + } 238 + spin_unlock_irq(&dev->power.lock); 239 + return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); 240 + } 241 + 242 + static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL); 243 + 244 + static ssize_t wakeup_hit_count_show(struct device *dev, 245 + struct device_attribute *attr, char *buf) 246 + { 247 + unsigned long count = 0; 248 + bool enabled = false; 249 + 250 + spin_lock_irq(&dev->power.lock); 251 + if (dev->power.wakeup) { 252 + count = dev->power.wakeup->hit_count; 253 + enabled = true; 254 + } 255 + spin_unlock_irq(&dev->power.lock); 256 + return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); 257 + } 258 + 259 + static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL); 260 + 261 + static ssize_t wakeup_active_show(struct device *dev, 262 + struct device_attribute *attr, char *buf) 263 + { 264 + unsigned int active = 0; 265 + bool enabled = false; 266 + 267 + spin_lock_irq(&dev->power.lock); 268 + if (dev->power.wakeup) { 269 + active = dev->power.wakeup->active; 270 + enabled = true; 271 + } 272 + spin_unlock_irq(&dev->power.lock); 273 + return enabled ? sprintf(buf, "%u\n", active) : sprintf(buf, "\n"); 274 + } 275 + 276 + static DEVICE_ATTR(wakeup_active, 0444, wakeup_active_show, NULL); 277 + 278 + static ssize_t wakeup_total_time_show(struct device *dev, 279 + struct device_attribute *attr, char *buf) 280 + { 281 + s64 msec = 0; 282 + bool enabled = false; 283 + 284 + spin_lock_irq(&dev->power.lock); 285 + if (dev->power.wakeup) { 286 + msec = ktime_to_ms(dev->power.wakeup->total_time); 287 + enabled = true; 288 + } 289 + spin_unlock_irq(&dev->power.lock); 290 + return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); 291 + } 292 + 293 + static DEVICE_ATTR(wakeup_total_time_ms, 0444, wakeup_total_time_show, NULL); 294 + 295 + static ssize_t wakeup_max_time_show(struct device *dev, 296 + struct device_attribute *attr, char *buf) 297 + { 298 + s64 msec = 0; 299 + bool enabled = false; 300 + 301 + spin_lock_irq(&dev->power.lock); 302 + if (dev->power.wakeup) { 303 + msec = ktime_to_ms(dev->power.wakeup->max_time); 304 + enabled = true; 305 + } 306 + spin_unlock_irq(&dev->power.lock); 307 + return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); 308 + } 309 + 310 + static DEVICE_ATTR(wakeup_max_time_ms, 0444, wakeup_max_time_show, NULL); 311 + 312 + static ssize_t wakeup_last_time_show(struct device *dev, 313 + struct device_attribute *attr, char *buf) 314 + { 315 + s64 msec = 0; 316 + bool enabled = false; 317 + 318 + spin_lock_irq(&dev->power.lock); 319 + if (dev->power.wakeup) { 320 + msec = ktime_to_ms(dev->power.wakeup->last_time); 321 + enabled = true; 322 + } 323 + spin_unlock_irq(&dev->power.lock); 324 + return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n"); 325 + } 326 + 327 + static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL); 328 + #endif /* CONFIG_PM_SLEEP */ 329 330 #ifdef CONFIG_PM_ADVANCED_DEBUG 331 #ifdef CONFIG_PM_RUNTIME ··· 288 &dev_attr_wakeup.attr, 289 #ifdef CONFIG_PM_SLEEP 290 &dev_attr_wakeup_count.attr, 291 + &dev_attr_wakeup_active_count.attr, 292 + &dev_attr_wakeup_hit_count.attr, 293 + &dev_attr_wakeup_active.attr, 294 + &dev_attr_wakeup_total_time_ms.attr, 295 + &dev_attr_wakeup_max_time_ms.attr, 296 + &dev_attr_wakeup_last_time_ms.attr, 297 #endif 298 #ifdef CONFIG_PM_ADVANCED_DEBUG 299 &dev_attr_async.attr,
+454 -82
drivers/base/power/wakeup.c
··· 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 ··· 23 bool events_check_enabled; 24 25 /* The counter of registered wakeup events. */ 26 - static unsigned long event_count; 27 /* A preserved old value of event_count. */ 28 - static unsigned long saved_event_count; 29 /* The counter of wakeup events being processed. */ 30 - static unsigned long events_in_progress; 31 32 static DEFINE_SPINLOCK(events_lock); 33 34 static void pm_wakeup_timer_fn(unsigned long data); 35 36 - static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0); 37 - static unsigned long events_timer_expires; 38 39 /* 40 * The functions below use the observation that each wakeup event starts a ··· 284 * knowledge, however, may not be available to it, so it can simply specify time 285 * to wait before the system can be suspended and pass it as the second 286 * argument of pm_wakeup_event(). 287 */ 288 289 /** 290 * pm_stay_awake - Notify the PM core that a wakeup event is being processed. 291 * @dev: Device the wakeup event is related to. 292 * 293 - * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the 294 - * counter of wakeup events being processed. If @dev is not NULL, the counter 295 - * of wakeup events related to @dev is incremented too. 296 * 297 * Call this function after detecting of a wakeup event if pm_relax() is going 298 * to be called directly after processing the event (and possibly passing it to 299 * user space for further processing). 300 - * 301 - * It is safe to call this function from interrupt context. 302 */ 303 void pm_stay_awake(struct device *dev) 304 { 305 unsigned long flags; 306 307 - spin_lock_irqsave(&events_lock, flags); 308 - if (dev) 309 - dev->power.wakeup_count++; 310 311 - events_in_progress++; 312 - spin_unlock_irqrestore(&events_lock, flags); 313 } 314 315 /** 316 - * pm_relax - Notify the PM core that processing of a wakeup event has ended. 317 - * 318 - * Notify the PM core that a wakeup event has been processed by decrementing 319 - * the counter of wakeup events being processed and incrementing the counter 320 - * of registered wakeup events. 321 * 322 * Call this function for wakeup events whose processing started with calling 323 - * pm_stay_awake(). 324 * 325 * It is safe to call it from interrupt context. 326 */ 327 - void pm_relax(void) 328 { 329 unsigned long flags; 330 331 - spin_lock_irqsave(&events_lock, flags); 332 - if (events_in_progress) { 333 - events_in_progress--; 334 - event_count++; 335 - } 336 - spin_unlock_irqrestore(&events_lock, flags); 337 } 338 339 /** 340 * pm_wakeup_timer_fn - Delayed finalization of a wakeup event. 341 * 342 - * Decrease the counter of wakeup events being processed after it was increased 343 - * by pm_wakeup_event(). 344 */ 345 static void pm_wakeup_timer_fn(unsigned long data) 346 { 347 - unsigned long flags; 348 - 349 - spin_lock_irqsave(&events_lock, flags); 350 - if (events_timer_expires 351 - && time_before_eq(events_timer_expires, jiffies)) { 352 - events_in_progress--; 353 - events_timer_expires = 0; 354 - } 355 - spin_unlock_irqrestore(&events_lock, flags); 356 } 357 358 /** 359 * pm_wakeup_event - Notify the PM core of a wakeup event. 360 * @dev: Device the wakeup event is related to. 361 * @msec: Anticipated event processing time (in milliseconds). 362 * 363 - * Notify the PM core of a wakeup event (signaled by @dev) that will take 364 - * approximately @msec milliseconds to be processed by the kernel. Increment 365 - * the counter of registered wakeup events and (if @msec is nonzero) set up 366 - * the wakeup events timer to execute pm_wakeup_timer_fn() in future (if the 367 - * timer has not been set up already, increment the counter of wakeup events 368 - * being processed). If @dev is not NULL, the counter of wakeup events related 369 - * to @dev is incremented too. 370 - * 371 - * It is safe to call this function from interrupt context. 372 */ 373 void pm_wakeup_event(struct device *dev, unsigned int msec) 374 { 375 unsigned long flags; 376 377 - spin_lock_irqsave(&events_lock, flags); 378 - event_count++; 379 - if (dev) 380 - dev->power.wakeup_count++; 381 382 - if (msec) { 383 - unsigned long expires; 384 385 - expires = jiffies + msecs_to_jiffies(msec); 386 - if (!expires) 387 - expires = 1; 388 389 - if (!events_timer_expires 390 - || time_after(expires, events_timer_expires)) { 391 - if (!events_timer_expires) 392 - events_in_progress++; 393 - 394 - mod_timer(&events_timer, expires); 395 - events_timer_expires = expires; 396 - } 397 } 398 - spin_unlock_irqrestore(&events_lock, flags); 399 } 400 401 /** ··· 554 555 spin_lock_irqsave(&events_lock, flags); 556 if (events_check_enabled) { 557 - ret = (event_count == saved_event_count) && !events_in_progress; 558 events_check_enabled = ret; 559 } 560 spin_unlock_irqrestore(&events_lock, flags); 561 return ret; 562 } 563 ··· 575 * drop down to zero has been interrupted by a signal (and the current number 576 * of wakeup events being processed is still nonzero). Otherwise return true. 577 */ 578 - bool pm_get_wakeup_count(unsigned long *count) 579 { 580 bool ret; 581 582 - spin_lock_irq(&events_lock); 583 if (capable(CAP_SYS_ADMIN)) 584 events_check_enabled = false; 585 586 - while (events_in_progress && !signal_pending(current)) { 587 - spin_unlock_irq(&events_lock); 588 - 589 - schedule_timeout_interruptible(msecs_to_jiffies(100)); 590 - 591 - spin_lock_irq(&events_lock); 592 } 593 - *count = event_count; 594 - ret = !events_in_progress; 595 - spin_unlock_irq(&events_lock); 596 return ret; 597 } 598 ··· 601 * old number of registered wakeup events to be used by pm_check_wakeup_events() 602 * and return true. Otherwise return false. 603 */ 604 - bool pm_save_wakeup_count(unsigned long count) 605 { 606 bool ret = false; 607 608 spin_lock_irq(&events_lock); 609 - if (count == event_count && !events_in_progress) { 610 - saved_event_count = count; 611 events_check_enabled = true; 612 ret = true; 613 } 614 spin_unlock_irq(&events_lock); 615 return ret; 616 }
··· 11 #include <linux/sched.h> 12 #include <linux/capability.h> 13 #include <linux/suspend.h> 14 + 15 + #include "power.h" 16 + 17 + #define TIMEOUT 100 18 19 /* 20 * If set, the suspend/hibernate code will abort transitions to a sleep state ··· 20 bool events_check_enabled; 21 22 /* The counter of registered wakeup events. */ 23 + static atomic_t event_count = ATOMIC_INIT(0); 24 /* A preserved old value of event_count. */ 25 + static unsigned int saved_count; 26 /* The counter of wakeup events being processed. */ 27 + static atomic_t events_in_progress = ATOMIC_INIT(0); 28 29 static DEFINE_SPINLOCK(events_lock); 30 31 static void pm_wakeup_timer_fn(unsigned long data); 32 33 + static LIST_HEAD(wakeup_sources); 34 + 35 + /** 36 + * wakeup_source_create - Create a struct wakeup_source object. 37 + * @name: Name of the new wakeup source. 38 + */ 39 + struct wakeup_source *wakeup_source_create(const char *name) 40 + { 41 + struct wakeup_source *ws; 42 + 43 + ws = kzalloc(sizeof(*ws), GFP_KERNEL); 44 + if (!ws) 45 + return NULL; 46 + 47 + spin_lock_init(&ws->lock); 48 + if (name) 49 + ws->name = kstrdup(name, GFP_KERNEL); 50 + 51 + return ws; 52 + } 53 + EXPORT_SYMBOL_GPL(wakeup_source_create); 54 + 55 + /** 56 + * wakeup_source_destroy - Destroy a struct wakeup_source object. 57 + * @ws: Wakeup source to destroy. 58 + */ 59 + void wakeup_source_destroy(struct wakeup_source *ws) 60 + { 61 + if (!ws) 62 + return; 63 + 64 + spin_lock_irq(&ws->lock); 65 + while (ws->active) { 66 + spin_unlock_irq(&ws->lock); 67 + 68 + schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); 69 + 70 + spin_lock_irq(&ws->lock); 71 + } 72 + spin_unlock_irq(&ws->lock); 73 + 74 + kfree(ws->name); 75 + kfree(ws); 76 + } 77 + EXPORT_SYMBOL_GPL(wakeup_source_destroy); 78 + 79 + /** 80 + * wakeup_source_add - Add given object to the list of wakeup sources. 81 + * @ws: Wakeup source object to add to the list. 82 + */ 83 + void wakeup_source_add(struct wakeup_source *ws) 84 + { 85 + if (WARN_ON(!ws)) 86 + return; 87 + 88 + setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws); 89 + ws->active = false; 90 + 91 + spin_lock_irq(&events_lock); 92 + list_add_rcu(&ws->entry, &wakeup_sources); 93 + spin_unlock_irq(&events_lock); 94 + synchronize_rcu(); 95 + } 96 + EXPORT_SYMBOL_GPL(wakeup_source_add); 97 + 98 + /** 99 + * wakeup_source_remove - Remove given object from the wakeup sources list. 100 + * @ws: Wakeup source object to remove from the list. 101 + */ 102 + void wakeup_source_remove(struct wakeup_source *ws) 103 + { 104 + if (WARN_ON(!ws)) 105 + return; 106 + 107 + spin_lock_irq(&events_lock); 108 + list_del_rcu(&ws->entry); 109 + spin_unlock_irq(&events_lock); 110 + synchronize_rcu(); 111 + } 112 + EXPORT_SYMBOL_GPL(wakeup_source_remove); 113 + 114 + /** 115 + * wakeup_source_register - Create wakeup source and add it to the list. 116 + * @name: Name of the wakeup source to register. 117 + */ 118 + struct wakeup_source *wakeup_source_register(const char *name) 119 + { 120 + struct wakeup_source *ws; 121 + 122 + ws = wakeup_source_create(name); 123 + if (ws) 124 + wakeup_source_add(ws); 125 + 126 + return ws; 127 + } 128 + EXPORT_SYMBOL_GPL(wakeup_source_register); 129 + 130 + /** 131 + * wakeup_source_unregister - Remove wakeup source from the list and remove it. 132 + * @ws: Wakeup source object to unregister. 133 + */ 134 + void wakeup_source_unregister(struct wakeup_source *ws) 135 + { 136 + wakeup_source_remove(ws); 137 + wakeup_source_destroy(ws); 138 + } 139 + EXPORT_SYMBOL_GPL(wakeup_source_unregister); 140 + 141 + /** 142 + * device_wakeup_attach - Attach a wakeup source object to a device object. 143 + * @dev: Device to handle. 144 + * @ws: Wakeup source object to attach to @dev. 145 + * 146 + * This causes @dev to be treated as a wakeup device. 147 + */ 148 + static int device_wakeup_attach(struct device *dev, struct wakeup_source *ws) 149 + { 150 + spin_lock_irq(&dev->power.lock); 151 + if (dev->power.wakeup) { 152 + spin_unlock_irq(&dev->power.lock); 153 + return -EEXIST; 154 + } 155 + dev->power.wakeup = ws; 156 + spin_unlock_irq(&dev->power.lock); 157 + return 0; 158 + } 159 + 160 + /** 161 + * device_wakeup_enable - Enable given device to be a wakeup source. 162 + * @dev: Device to handle. 163 + * 164 + * Create a wakeup source object, register it and attach it to @dev. 165 + */ 166 + int device_wakeup_enable(struct device *dev) 167 + { 168 + struct wakeup_source *ws; 169 + int ret; 170 + 171 + if (!dev || !dev->power.can_wakeup) 172 + return -EINVAL; 173 + 174 + ws = wakeup_source_register(dev_name(dev)); 175 + if (!ws) 176 + return -ENOMEM; 177 + 178 + ret = device_wakeup_attach(dev, ws); 179 + if (ret) 180 + wakeup_source_unregister(ws); 181 + 182 + return ret; 183 + } 184 + EXPORT_SYMBOL_GPL(device_wakeup_enable); 185 + 186 + /** 187 + * device_wakeup_detach - Detach a device's wakeup source object from it. 188 + * @dev: Device to detach the wakeup source object from. 189 + * 190 + * After it returns, @dev will not be treated as a wakeup device any more. 191 + */ 192 + static struct wakeup_source *device_wakeup_detach(struct device *dev) 193 + { 194 + struct wakeup_source *ws; 195 + 196 + spin_lock_irq(&dev->power.lock); 197 + ws = dev->power.wakeup; 198 + dev->power.wakeup = NULL; 199 + spin_unlock_irq(&dev->power.lock); 200 + return ws; 201 + } 202 + 203 + /** 204 + * device_wakeup_disable - Do not regard a device as a wakeup source any more. 205 + * @dev: Device to handle. 206 + * 207 + * Detach the @dev's wakeup source object from it, unregister this wakeup source 208 + * object and destroy it. 209 + */ 210 + int device_wakeup_disable(struct device *dev) 211 + { 212 + struct wakeup_source *ws; 213 + 214 + if (!dev || !dev->power.can_wakeup) 215 + return -EINVAL; 216 + 217 + ws = device_wakeup_detach(dev); 218 + if (ws) 219 + wakeup_source_unregister(ws); 220 + 221 + return 0; 222 + } 223 + EXPORT_SYMBOL_GPL(device_wakeup_disable); 224 + 225 + /** 226 + * device_init_wakeup - Device wakeup initialization. 227 + * @dev: Device to handle. 228 + * @enable: Whether or not to enable @dev as a wakeup device. 229 + * 230 + * By default, most devices should leave wakeup disabled. The exceptions are 231 + * devices that everyone expects to be wakeup sources: keyboards, power buttons, 232 + * possibly network interfaces, etc. 233 + */ 234 + int device_init_wakeup(struct device *dev, bool enable) 235 + { 236 + int ret = 0; 237 + 238 + if (enable) { 239 + device_set_wakeup_capable(dev, true); 240 + ret = device_wakeup_enable(dev); 241 + } else { 242 + device_set_wakeup_capable(dev, false); 243 + } 244 + 245 + return ret; 246 + } 247 + EXPORT_SYMBOL_GPL(device_init_wakeup); 248 + 249 + /** 250 + * device_set_wakeup_enable - Enable or disable a device to wake up the system. 251 + * @dev: Device to handle. 252 + */ 253 + int device_set_wakeup_enable(struct device *dev, bool enable) 254 + { 255 + if (!dev || !dev->power.can_wakeup) 256 + return -EINVAL; 257 + 258 + return enable ? device_wakeup_enable(dev) : device_wakeup_disable(dev); 259 + } 260 + EXPORT_SYMBOL_GPL(device_set_wakeup_enable); 261 262 /* 263 * The functions below use the observation that each wakeup event starts a ··· 55 * knowledge, however, may not be available to it, so it can simply specify time 56 * to wait before the system can be suspended and pass it as the second 57 * argument of pm_wakeup_event(). 58 + * 59 + * It is valid to call pm_relax() after pm_wakeup_event(), in which case the 60 + * "no suspend" period will be ended either by the pm_relax(), or by the timer 61 + * function executed when the timer expires, whichever comes first. 62 */ 63 + 64 + /** 65 + * wakup_source_activate - Mark given wakeup source as active. 66 + * @ws: Wakeup source to handle. 67 + * 68 + * Update the @ws' statistics and, if @ws has just been activated, notify the PM 69 + * core of the event by incrementing the counter of of wakeup events being 70 + * processed. 71 + */ 72 + static void wakeup_source_activate(struct wakeup_source *ws) 73 + { 74 + ws->active = true; 75 + ws->active_count++; 76 + ws->timer_expires = jiffies; 77 + ws->last_time = ktime_get(); 78 + 79 + atomic_inc(&events_in_progress); 80 + } 81 + 82 + /** 83 + * __pm_stay_awake - Notify the PM core of a wakeup event. 84 + * @ws: Wakeup source object associated with the source of the event. 85 + * 86 + * It is safe to call this function from interrupt context. 87 + */ 88 + void __pm_stay_awake(struct wakeup_source *ws) 89 + { 90 + unsigned long flags; 91 + 92 + if (!ws) 93 + return; 94 + 95 + spin_lock_irqsave(&ws->lock, flags); 96 + ws->event_count++; 97 + if (!ws->active) 98 + wakeup_source_activate(ws); 99 + spin_unlock_irqrestore(&ws->lock, flags); 100 + } 101 + EXPORT_SYMBOL_GPL(__pm_stay_awake); 102 103 /** 104 * pm_stay_awake - Notify the PM core that a wakeup event is being processed. 105 * @dev: Device the wakeup event is related to. 106 * 107 + * Notify the PM core of a wakeup event (signaled by @dev) by calling 108 + * __pm_stay_awake for the @dev's wakeup source object. 109 * 110 * Call this function after detecting of a wakeup event if pm_relax() is going 111 * to be called directly after processing the event (and possibly passing it to 112 * user space for further processing). 113 */ 114 void pm_stay_awake(struct device *dev) 115 { 116 unsigned long flags; 117 118 + if (!dev) 119 + return; 120 121 + spin_lock_irqsave(&dev->power.lock, flags); 122 + __pm_stay_awake(dev->power.wakeup); 123 + spin_unlock_irqrestore(&dev->power.lock, flags); 124 + } 125 + EXPORT_SYMBOL_GPL(pm_stay_awake); 126 + 127 + /** 128 + * wakup_source_deactivate - Mark given wakeup source as inactive. 129 + * @ws: Wakeup source to handle. 130 + * 131 + * Update the @ws' statistics and notify the PM core that the wakeup source has 132 + * become inactive by decrementing the counter of wakeup events being processed 133 + * and incrementing the counter of registered wakeup events. 134 + */ 135 + static void wakeup_source_deactivate(struct wakeup_source *ws) 136 + { 137 + ktime_t duration; 138 + ktime_t now; 139 + 140 + ws->relax_count++; 141 + /* 142 + * __pm_relax() may be called directly or from a timer function. 143 + * If it is called directly right after the timer function has been 144 + * started, but before the timer function calls __pm_relax(), it is 145 + * possible that __pm_stay_awake() will be called in the meantime and 146 + * will set ws->active. Then, ws->active may be cleared immediately 147 + * by the __pm_relax() called from the timer function, but in such a 148 + * case ws->relax_count will be different from ws->active_count. 149 + */ 150 + if (ws->relax_count != ws->active_count) { 151 + ws->relax_count--; 152 + return; 153 + } 154 + 155 + ws->active = false; 156 + 157 + now = ktime_get(); 158 + duration = ktime_sub(now, ws->last_time); 159 + ws->total_time = ktime_add(ws->total_time, duration); 160 + if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time)) 161 + ws->max_time = duration; 162 + 163 + del_timer(&ws->timer); 164 + 165 + /* 166 + * event_count has to be incremented before events_in_progress is 167 + * modified, so that the callers of pm_check_wakeup_events() and 168 + * pm_save_wakeup_count() don't see the old value of event_count and 169 + * events_in_progress equal to zero at the same time. 170 + */ 171 + atomic_inc(&event_count); 172 + smp_mb__before_atomic_dec(); 173 + atomic_dec(&events_in_progress); 174 } 175 176 /** 177 + * __pm_relax - Notify the PM core that processing of a wakeup event has ended. 178 + * @ws: Wakeup source object associated with the source of the event. 179 * 180 * Call this function for wakeup events whose processing started with calling 181 + * __pm_stay_awake(). 182 * 183 * It is safe to call it from interrupt context. 184 */ 185 + void __pm_relax(struct wakeup_source *ws) 186 { 187 unsigned long flags; 188 189 + if (!ws) 190 + return; 191 + 192 + spin_lock_irqsave(&ws->lock, flags); 193 + if (ws->active) 194 + wakeup_source_deactivate(ws); 195 + spin_unlock_irqrestore(&ws->lock, flags); 196 } 197 + EXPORT_SYMBOL_GPL(__pm_relax); 198 + 199 + /** 200 + * pm_relax - Notify the PM core that processing of a wakeup event has ended. 201 + * @dev: Device that signaled the event. 202 + * 203 + * Execute __pm_relax() for the @dev's wakeup source object. 204 + */ 205 + void pm_relax(struct device *dev) 206 + { 207 + unsigned long flags; 208 + 209 + if (!dev) 210 + return; 211 + 212 + spin_lock_irqsave(&dev->power.lock, flags); 213 + __pm_relax(dev->power.wakeup); 214 + spin_unlock_irqrestore(&dev->power.lock, flags); 215 + } 216 + EXPORT_SYMBOL_GPL(pm_relax); 217 218 /** 219 * pm_wakeup_timer_fn - Delayed finalization of a wakeup event. 220 + * @data: Address of the wakeup source object associated with the event source. 221 * 222 + * Call __pm_relax() for the wakeup source whose address is stored in @data. 223 */ 224 static void pm_wakeup_timer_fn(unsigned long data) 225 { 226 + __pm_relax((struct wakeup_source *)data); 227 } 228 + 229 + /** 230 + * __pm_wakeup_event - Notify the PM core of a wakeup event. 231 + * @ws: Wakeup source object associated with the event source. 232 + * @msec: Anticipated event processing time (in milliseconds). 233 + * 234 + * Notify the PM core of a wakeup event whose source is @ws that will take 235 + * approximately @msec milliseconds to be processed by the kernel. If @ws is 236 + * not active, activate it. If @msec is nonzero, set up the @ws' timer to 237 + * execute pm_wakeup_timer_fn() in future. 238 + * 239 + * It is safe to call this function from interrupt context. 240 + */ 241 + void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) 242 + { 243 + unsigned long flags; 244 + unsigned long expires; 245 + 246 + if (!ws) 247 + return; 248 + 249 + spin_lock_irqsave(&ws->lock, flags); 250 + 251 + ws->event_count++; 252 + if (!ws->active) 253 + wakeup_source_activate(ws); 254 + 255 + if (!msec) { 256 + wakeup_source_deactivate(ws); 257 + goto unlock; 258 + } 259 + 260 + expires = jiffies + msecs_to_jiffies(msec); 261 + if (!expires) 262 + expires = 1; 263 + 264 + if (time_after(expires, ws->timer_expires)) { 265 + mod_timer(&ws->timer, expires); 266 + ws->timer_expires = expires; 267 + } 268 + 269 + unlock: 270 + spin_unlock_irqrestore(&ws->lock, flags); 271 + } 272 + EXPORT_SYMBOL_GPL(__pm_wakeup_event); 273 + 274 275 /** 276 * pm_wakeup_event - Notify the PM core of a wakeup event. 277 * @dev: Device the wakeup event is related to. 278 * @msec: Anticipated event processing time (in milliseconds). 279 * 280 + * Call __pm_wakeup_event() for the @dev's wakeup source object. 281 */ 282 void pm_wakeup_event(struct device *dev, unsigned int msec) 283 { 284 unsigned long flags; 285 286 + if (!dev) 287 + return; 288 289 + spin_lock_irqsave(&dev->power.lock, flags); 290 + __pm_wakeup_event(dev->power.wakeup, msec); 291 + spin_unlock_irqrestore(&dev->power.lock, flags); 292 + } 293 + EXPORT_SYMBOL_GPL(pm_wakeup_event); 294 295 + /** 296 + * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources. 297 + */ 298 + static void pm_wakeup_update_hit_counts(void) 299 + { 300 + unsigned long flags; 301 + struct wakeup_source *ws; 302 303 + rcu_read_lock(); 304 + list_for_each_entry_rcu(ws, &wakeup_sources, entry) { 305 + spin_lock_irqsave(&ws->lock, flags); 306 + if (ws->active) 307 + ws->hit_count++; 308 + spin_unlock_irqrestore(&ws->lock, flags); 309 } 310 + rcu_read_unlock(); 311 } 312 313 /** ··· 184 185 spin_lock_irqsave(&events_lock, flags); 186 if (events_check_enabled) { 187 + ret = ((unsigned int)atomic_read(&event_count) == saved_count) 188 + && !atomic_read(&events_in_progress); 189 events_check_enabled = ret; 190 } 191 spin_unlock_irqrestore(&events_lock, flags); 192 + if (!ret) 193 + pm_wakeup_update_hit_counts(); 194 return ret; 195 } 196 ··· 202 * drop down to zero has been interrupted by a signal (and the current number 203 * of wakeup events being processed is still nonzero). Otherwise return true. 204 */ 205 + bool pm_get_wakeup_count(unsigned int *count) 206 { 207 bool ret; 208 209 if (capable(CAP_SYS_ADMIN)) 210 events_check_enabled = false; 211 212 + while (atomic_read(&events_in_progress) && !signal_pending(current)) { 213 + pm_wakeup_update_hit_counts(); 214 + schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); 215 } 216 + 217 + ret = !atomic_read(&events_in_progress); 218 + *count = atomic_read(&event_count); 219 return ret; 220 } 221 ··· 232 * old number of registered wakeup events to be used by pm_check_wakeup_events() 233 * and return true. Otherwise return false. 234 */ 235 + bool pm_save_wakeup_count(unsigned int count) 236 { 237 bool ret = false; 238 239 spin_lock_irq(&events_lock); 240 + if (count == (unsigned int)atomic_read(&event_count) 241 + && !atomic_read(&events_in_progress)) { 242 + saved_count = count; 243 events_check_enabled = true; 244 ret = true; 245 } 246 spin_unlock_irq(&events_lock); 247 + if (!ret) 248 + pm_wakeup_update_hit_counts(); 249 return ret; 250 }
+4 -12
include/linux/pm.h
··· 448 RPM_REQ_RESUME, 449 }; 450 451 struct dev_pm_info { 452 pm_message_t power_state; 453 unsigned int can_wakeup:1; 454 - unsigned int should_wakeup:1; 455 unsigned async_suspend:1; 456 enum dpm_state status; /* Owned by the PM core */ 457 #ifdef CONFIG_PM_SLEEP 458 struct list_head entry; 459 struct completion completion; 460 - unsigned long wakeup_count; 461 #endif 462 #ifdef CONFIG_PM_RUNTIME 463 struct timer_list suspend_timer; 464 unsigned long timer_expires; 465 struct work_struct work; 466 wait_queue_head_t wait_queue; 467 - spinlock_t lock; 468 atomic_t usage_count; 469 atomic_t child_count; 470 unsigned int disable_depth:3; ··· 560 } while (0) 561 562 extern void device_pm_wait_for_dev(struct device *sub, struct device *dev); 563 - 564 - /* drivers/base/power/wakeup.c */ 565 - extern void pm_wakeup_event(struct device *dev, unsigned int msec); 566 - extern void pm_stay_awake(struct device *dev); 567 - extern void pm_relax(void); 568 #else /* !CONFIG_PM_SLEEP */ 569 570 #define device_pm_lock() do {} while (0) ··· 573 #define suspend_report_result(fn, ret) do {} while (0) 574 575 static inline void device_pm_wait_for_dev(struct device *a, struct device *b) {} 576 - 577 - static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {} 578 - static inline void pm_stay_awake(struct device *dev) {} 579 - static inline void pm_relax(void) {} 580 #endif /* !CONFIG_PM_SLEEP */ 581 582 /* How to reorder dpm_list after device_move() */
··· 448 RPM_REQ_RESUME, 449 }; 450 451 + struct wakeup_source; 452 + 453 struct dev_pm_info { 454 pm_message_t power_state; 455 unsigned int can_wakeup:1; 456 unsigned async_suspend:1; 457 enum dpm_state status; /* Owned by the PM core */ 458 + spinlock_t lock; 459 #ifdef CONFIG_PM_SLEEP 460 struct list_head entry; 461 struct completion completion; 462 + struct wakeup_source *wakeup; 463 #endif 464 #ifdef CONFIG_PM_RUNTIME 465 struct timer_list suspend_timer; 466 unsigned long timer_expires; 467 struct work_struct work; 468 wait_queue_head_t wait_queue; 469 atomic_t usage_count; 470 atomic_t child_count; 471 unsigned int disable_depth:3; ··· 559 } while (0) 560 561 extern void device_pm_wait_for_dev(struct device *sub, struct device *dev); 562 #else /* !CONFIG_PM_SLEEP */ 563 564 #define device_pm_lock() do {} while (0) ··· 577 #define suspend_report_result(fn, ret) do {} while (0) 578 579 static inline void device_pm_wait_for_dev(struct device *a, struct device *b) {} 580 #endif /* !CONFIG_PM_SLEEP */ 581 582 /* How to reorder dpm_list after device_move() */
+105 -26
include/linux/pm_wakeup.h
··· 2 * pm_wakeup.h - Power management wakeup interface 3 * 4 * Copyright (C) 2008 Alan Stern 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by ··· 28 29 #include <linux/types.h> 30 31 - #ifdef CONFIG_PM 32 - 33 - /* Changes to device_may_wakeup take effect on the next pm state change. 34 * 35 - * By default, most devices should leave wakeup disabled. The exceptions 36 - * are devices that everyone expects to be wakeup sources: keyboards, 37 - * power buttons, possibly network interfaces, etc. 38 */ 39 - static inline void device_init_wakeup(struct device *dev, bool val) 40 - { 41 - dev->power.can_wakeup = dev->power.should_wakeup = val; 42 - } 43 44 static inline void device_set_wakeup_capable(struct device *dev, bool capable) 45 { ··· 72 return dev->power.can_wakeup; 73 } 74 75 - static inline void device_set_wakeup_enable(struct device *dev, bool enable) 76 - { 77 - dev->power.should_wakeup = enable; 78 - } 79 80 static inline bool device_may_wakeup(struct device *dev) 81 { 82 - return dev->power.can_wakeup && dev->power.should_wakeup; 83 } 84 85 - #else /* !CONFIG_PM */ 86 87 - /* For some reason the following routines work even without CONFIG_PM */ 88 - static inline void device_init_wakeup(struct device *dev, bool val) 89 - { 90 - dev->power.can_wakeup = val; 91 - } 92 93 static inline void device_set_wakeup_capable(struct device *dev, bool capable) 94 { ··· 107 static inline bool device_can_wakeup(struct device *dev) 108 { 109 return dev->power.can_wakeup; 110 - } 111 - 112 - static inline void device_set_wakeup_enable(struct device *dev, bool enable) 113 - { 114 } 115 116 static inline bool device_may_wakeup(struct device *dev) ··· 114 return false; 115 } 116 117 - #endif /* !CONFIG_PM */ 118 119 #endif /* _LINUX_PM_WAKEUP_H */
··· 2 * pm_wakeup.h - Power management wakeup interface 3 * 4 * Copyright (C) 2008 Alan Stern 5 + * Copyright (C) 2010 Rafael J. Wysocki, Novell Inc. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by ··· 27 28 #include <linux/types.h> 29 30 + /** 31 + * struct wakeup_source - Representation of wakeup sources 32 * 33 + * @total_time: Total time this wakeup source has been active. 34 + * @max_time: Maximum time this wakeup source has been continuously active. 35 + * @last_time: Monotonic clock when the wakeup source's was activated last time. 36 + * @event_count: Number of signaled wakeup events. 37 + * @active_count: Number of times the wakeup sorce was activated. 38 + * @relax_count: Number of times the wakeup sorce was deactivated. 39 + * @hit_count: Number of times the wakeup sorce might abort system suspend. 40 + * @active: Status of the wakeup source. 41 */ 42 + struct wakeup_source { 43 + char *name; 44 + struct list_head entry; 45 + spinlock_t lock; 46 + struct timer_list timer; 47 + unsigned long timer_expires; 48 + ktime_t total_time; 49 + ktime_t max_time; 50 + ktime_t last_time; 51 + unsigned long event_count; 52 + unsigned long active_count; 53 + unsigned long relax_count; 54 + unsigned long hit_count; 55 + unsigned int active:1; 56 + }; 57 + 58 + #ifdef CONFIG_PM_SLEEP 59 + 60 + /* 61 + * Changes to device_may_wakeup take effect on the next pm state change. 62 + */ 63 64 static inline void device_set_wakeup_capable(struct device *dev, bool capable) 65 { ··· 50 return dev->power.can_wakeup; 51 } 52 53 + 54 55 static inline bool device_may_wakeup(struct device *dev) 56 { 57 + return dev->power.can_wakeup && !!dev->power.wakeup; 58 } 59 60 + /* drivers/base/power/wakeup.c */ 61 + extern struct wakeup_source *wakeup_source_create(const char *name); 62 + extern void wakeup_source_destroy(struct wakeup_source *ws); 63 + extern void wakeup_source_add(struct wakeup_source *ws); 64 + extern void wakeup_source_remove(struct wakeup_source *ws); 65 + extern struct wakeup_source *wakeup_source_register(const char *name); 66 + extern void wakeup_source_unregister(struct wakeup_source *ws); 67 + extern int device_wakeup_enable(struct device *dev); 68 + extern int device_wakeup_disable(struct device *dev); 69 + extern int device_init_wakeup(struct device *dev, bool val); 70 + extern int device_set_wakeup_enable(struct device *dev, bool enable); 71 + extern void __pm_stay_awake(struct wakeup_source *ws); 72 + extern void pm_stay_awake(struct device *dev); 73 + extern void __pm_relax(struct wakeup_source *ws); 74 + extern void pm_relax(struct device *dev); 75 + extern void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec); 76 + extern void pm_wakeup_event(struct device *dev, unsigned int msec); 77 78 + #else /* !CONFIG_PM_SLEEP */ 79 80 static inline void device_set_wakeup_capable(struct device *dev, bool capable) 81 { ··· 76 static inline bool device_can_wakeup(struct device *dev) 77 { 78 return dev->power.can_wakeup; 79 } 80 81 static inline bool device_may_wakeup(struct device *dev) ··· 87 return false; 88 } 89 90 + static inline struct wakeup_source *wakeup_source_create(const char *name) 91 + { 92 + return NULL; 93 + } 94 + 95 + static inline void wakeup_source_destroy(struct wakeup_source *ws) {} 96 + 97 + static inline void wakeup_source_add(struct wakeup_source *ws) {} 98 + 99 + static inline void wakeup_source_remove(struct wakeup_source *ws) {} 100 + 101 + static inline struct wakeup_source *wakeup_source_register(const char *name) 102 + { 103 + return NULL; 104 + } 105 + 106 + static inline void wakeup_source_unregister(struct wakeup_source *ws) {} 107 + 108 + static inline int device_wakeup_enable(struct device *dev) 109 + { 110 + return -EINVAL; 111 + } 112 + 113 + static inline int device_wakeup_disable(struct device *dev) 114 + { 115 + return 0; 116 + } 117 + 118 + static inline int device_init_wakeup(struct device *dev, bool val) 119 + { 120 + dev->power.can_wakeup = val; 121 + return val ? -EINVAL : 0; 122 + } 123 + 124 + 125 + static inline int device_set_wakeup_enable(struct device *dev, bool enable) 126 + { 127 + return -EINVAL; 128 + } 129 + 130 + static inline void __pm_stay_awake(struct wakeup_source *ws) {} 131 + 132 + static inline void pm_stay_awake(struct device *dev) {} 133 + 134 + static inline void __pm_relax(struct wakeup_source *ws) {} 135 + 136 + static inline void pm_relax(struct device *dev) {} 137 + 138 + static inline void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) {} 139 + 140 + static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {} 141 + 142 + #endif /* !CONFIG_PM_SLEEP */ 143 144 #endif /* _LINUX_PM_WAKEUP_H */
+2 -2
include/linux/suspend.h
··· 293 extern bool events_check_enabled; 294 295 extern bool pm_check_wakeup_events(void); 296 - extern bool pm_get_wakeup_count(unsigned long *count); 297 - extern bool pm_save_wakeup_count(unsigned long count); 298 #else /* !CONFIG_PM_SLEEP */ 299 300 static inline int register_pm_notifier(struct notifier_block *nb)
··· 293 extern bool events_check_enabled; 294 295 extern bool pm_check_wakeup_events(void); 296 + extern bool pm_get_wakeup_count(unsigned int *count); 297 + extern bool pm_save_wakeup_count(unsigned int count); 298 #else /* !CONFIG_PM_SLEEP */ 299 300 static inline int register_pm_notifier(struct notifier_block *nb)
+4 -4
kernel/power/main.c
··· 237 struct kobj_attribute *attr, 238 char *buf) 239 { 240 - unsigned long val; 241 242 - return pm_get_wakeup_count(&val) ? sprintf(buf, "%lu\n", val) : -EINTR; 243 } 244 245 static ssize_t wakeup_count_store(struct kobject *kobj, 246 struct kobj_attribute *attr, 247 const char *buf, size_t n) 248 { 249 - unsigned long val; 250 251 - if (sscanf(buf, "%lu", &val) == 1) { 252 if (pm_save_wakeup_count(val)) 253 return n; 254 }
··· 237 struct kobj_attribute *attr, 238 char *buf) 239 { 240 + unsigned int val; 241 242 + return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR; 243 } 244 245 static ssize_t wakeup_count_store(struct kobject *kobj, 246 struct kobj_attribute *attr, 247 const char *buf, size_t n) 248 { 249 + unsigned int val; 250 251 + if (sscanf(buf, "%u", &val) == 1) { 252 if (pm_save_wakeup_count(val)) 253 return n; 254 }