Commit 06a79b82b2a3e4bebb9a20638ca208c780e9e507

Authored by Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
  PM / Hibernate: Fix preallocating of memory
  PM / Hibernate: Remove swsusp.c finally
  PM / Hibernate: Remove trailing space in message
  PM: Allow SCSI devices to suspend/resume asynchronously
  PM: Allow USB devices to suspend/resume asynchronously
  USB: implement non-tree resume ordering constraints for PCI host controllers
  PM: Allow PCI devices to suspend/resume asynchronously
  PM / Hibernate: Swap, remove useless check from swsusp_read()
  PM / Hibernate: Really deprecate deprecated user ioctls
  PM: Allow device drivers to use dpm_wait()
  PM: Start asynchronous resume threads upfront
  PM: Add facility for advanced testing of async suspend/resume
  PM: Add a switch for disabling/enabling asynchronous suspend/resume
  PM: Asynchronous suspend and resume of devices
  PM: Add parent information to timing messages
  PM: Document device power attributes in sysfs
  PM / Runtime: Add sysfs switch for disabling device run-time PM

Showing 28 changed files Side-by-side Diff

Documentation/ABI/testing/sysfs-devices-power
  1 +What: /sys/devices/.../power/
  2 +Date: January 2009
  3 +Contact: Rafael J. Wysocki <rjw@sisk.pl>
  4 +Description:
  5 + The /sys/devices/.../power directory contains attributes
  6 + allowing the user space to check and modify some power
  7 + management related properties of given device.
  8 +
  9 +What: /sys/devices/.../power/wakeup
  10 +Date: January 2009
  11 +Contact: Rafael J. Wysocki <rjw@sisk.pl>
  12 +Description:
  13 + The /sys/devices/.../power/wakeup attribute allows the user
  14 + space to check if the device is enabled to wake up the system
  15 + from sleep states, such as the memory sleep state (suspend to
  16 + RAM) and hibernation (suspend to disk), and to enable or disable
  17 + it to do that as desired.
  18 +
  19 + Some devices support "wakeup" events, which are hardware signals
  20 + used to activate the system from a sleep state. Such devices
  21 + have one of the following two values for the sysfs power/wakeup
  22 + file:
  23 +
  24 + + "enabled\n" to issue the events;
  25 + + "disabled\n" not to do so;
  26 +
  27 + In that cases the user space can change the setting represented
  28 + by the contents of this file by writing either "enabled", or
  29 + "disabled" to it.
  30 +
  31 + For the devices that are not capable of generating system wakeup
  32 + events this file contains "\n". In that cases the user space
  33 + cannot modify the contents of this file and the device cannot be
  34 + enabled to wake up the system.
  35 +
  36 +What: /sys/devices/.../power/control
  37 +Date: January 2009
  38 +Contact: Rafael J. Wysocki <rjw@sisk.pl>
  39 +Description:
  40 + The /sys/devices/.../power/control attribute allows the user
  41 + space to control the run-time power management of the device.
  42 +
  43 + All devices have one of the following two values for the
  44 + power/control file:
  45 +
  46 + + "auto\n" to allow the device to be power managed at run time;
  47 + + "on\n" to prevent the device from being power managed;
  48 +
  49 + The default for all devices is "auto", which means that they may
  50 + be subject to automatic power management, depending on their
  51 + drivers. Changing this attribute to "on" prevents the driver
  52 + from power managing the device at run time. Doing that while
  53 + the device is suspended causes it to be woken up.
  54 +
  55 +What: /sys/devices/.../power/async
  56 +Date: January 2009
  57 +Contact: Rafael J. Wysocki <rjw@sisk.pl>
  58 +Description:
  59 + The /sys/devices/.../async attribute allows the user space to
  60 + enable or diasble the device's suspend and resume callbacks to
  61 + be executed asynchronously (ie. in separate threads, in parallel
  62 + with the main suspend/resume thread) during system-wide power
  63 + transitions (eg. suspend to RAM, hibernation).
  64 +
  65 + All devices have one of the following two values for the
  66 + power/async file:
  67 +
  68 + + "enabled\n" to permit the asynchronous suspend/resume;
  69 + + "disabled\n" to forbid it;
  70 +
  71 + The value of this attribute may be changed by writing either
  72 + "enabled", or "disabled" to it.
  73 +
  74 + It generally is unsafe to permit the asynchronous suspend/resume
  75 + of a device unless it is certain that all of the PM dependencies
  76 + of the device are known to the PM core. However, for some
  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.
Documentation/ABI/testing/sysfs-power
... ... @@ -101,4 +101,17 @@
101 101  
102 102 CAUTION: Using it will cause your machine's real-time (CMOS)
103 103 clock to be set to a random invalid time after a resume.
  104 +
  105 +What: /sys/power/pm_async
  106 +Date: January 2009
  107 +Contact: Rafael J. Wysocki <rjw@sisk.pl>
  108 +Description:
  109 + The /sys/power/pm_async file controls the switch allowing the
  110 + user space to enable or disable asynchronous suspend and resume
  111 + of devices. If enabled, this feature will cause some device
  112 + drivers' suspend and resume callbacks to be executed in parallel
  113 + with each other and with the main suspend thread. It is enabled
  114 + if this file contains "1", which is the default. It may be
  115 + disabled by writing "0" to this file, in which case all devices
  116 + will be suspended and resumed synchronously.
Documentation/feature-removal-schedule.txt
... ... @@ -64,6 +64,17 @@
64 64  
65 65 ---------------------------
66 66  
  67 +What: Deprecated snapshot ioctls
  68 +When: 2.6.36
  69 +
  70 +Why: The ioctls in kernel/power/user.c were marked as deprecated long time
  71 + ago. Now they notify users about that so that they need to replace
  72 + their userspace. After some more time, remove them completely.
  73 +
  74 +Who: Jiri Slaby <jirislaby@gmail.com>
  75 +
  76 +---------------------------
  77 +
67 78 What: The ieee80211_regdom module parameter
68 79 When: March 2010 / desktop catchup
69 80  
drivers/base/power/main.c
... ... @@ -25,6 +25,7 @@
25 25 #include <linux/resume-trace.h>
26 26 #include <linux/interrupt.h>
27 27 #include <linux/sched.h>
  28 +#include <linux/async.h>
28 29  
29 30 #include "../base.h"
30 31 #include "power.h"
... ... @@ -42,6 +43,7 @@
42 43 LIST_HEAD(dpm_list);
43 44  
44 45 static DEFINE_MUTEX(dpm_list_mtx);
  46 +static pm_message_t pm_transition;
45 47  
46 48 /*
47 49 * Set once the preparation of devices for a PM transition has started, reset
... ... @@ -56,6 +58,7 @@
56 58 void device_pm_init(struct device *dev)
57 59 {
58 60 dev->power.status = DPM_ON;
  61 + init_completion(&dev->power.completion);
59 62 pm_runtime_init(dev);
60 63 }
61 64  
... ... @@ -111,6 +114,7 @@
111 114 pr_debug("PM: Removing info for %s:%s\n",
112 115 dev->bus ? dev->bus->name : "No Bus",
113 116 kobject_name(&dev->kobj));
  117 + complete_all(&dev->power.completion);
114 118 mutex_lock(&dpm_list_mtx);
115 119 list_del_init(&dev->power.entry);
116 120 mutex_unlock(&dpm_list_mtx);
... ... @@ -188,6 +192,31 @@
188 192 }
189 193  
190 194 /**
  195 + * dpm_wait - Wait for a PM operation to complete.
  196 + * @dev: Device to wait for.
  197 + * @async: If unset, wait only if the device's power.async_suspend flag is set.
  198 + */
  199 +static void dpm_wait(struct device *dev, bool async)
  200 +{
  201 + if (!dev)
  202 + return;
  203 +
  204 + if (async || (pm_async_enabled && dev->power.async_suspend))
  205 + wait_for_completion(&dev->power.completion);
  206 +}
  207 +
  208 +static int dpm_wait_fn(struct device *dev, void *async_ptr)
  209 +{
  210 + dpm_wait(dev, *((bool *)async_ptr));
  211 + return 0;
  212 +}
  213 +
  214 +static void dpm_wait_for_children(struct device *dev, bool async)
  215 +{
  216 + device_for_each_child(dev, &async, dpm_wait_fn);
  217 +}
  218 +
  219 +/**
191 220 * pm_op - Execute the PM operation appropriate for given PM event.
192 221 * @dev: Device to handle.
193 222 * @ops: PM operations to choose from.
... ... @@ -271,8 +300,9 @@
271 300 ktime_t calltime, delta, rettime;
272 301  
273 302 if (initcall_debug) {
274   - pr_info("calling %s_i+ @ %i\n",
275   - dev_name(dev), task_pid_nr(current));
  303 + pr_info("calling %s+ @ %i, parent: %s\n",
  304 + dev_name(dev), task_pid_nr(current),
  305 + dev->parent ? dev_name(dev->parent) : "none");
276 306 calltime = ktime_get();
277 307 }
278 308  
279 309  
280 310  
281 311  
... ... @@ -468,16 +498,20 @@
468 498 * device_resume - Execute "resume" callbacks for given device.
469 499 * @dev: Device to handle.
470 500 * @state: PM transition of the system being carried out.
  501 + * @async: If true, the device is being resumed asynchronously.
471 502 */
472   -static int device_resume(struct device *dev, pm_message_t state)
  503 +static int device_resume(struct device *dev, pm_message_t state, bool async)
473 504 {
474 505 int error = 0;
475 506  
476 507 TRACE_DEVICE(dev);
477 508 TRACE_RESUME(0);
478 509  
  510 + dpm_wait(dev->parent, async);
479 511 down(&dev->sem);
480 512  
  513 + dev->power.status = DPM_RESUMING;
  514 +
481 515 if (dev->bus) {
482 516 if (dev->bus->pm) {
483 517 pm_dev_dbg(dev, state, "");
484 518  
... ... @@ -510,11 +544,29 @@
510 544 }
511 545 End:
512 546 up(&dev->sem);
  547 + complete_all(&dev->power.completion);
513 548  
514 549 TRACE_RESUME(error);
515 550 return error;
516 551 }
517 552  
  553 +static void async_resume(void *data, async_cookie_t cookie)
  554 +{
  555 + struct device *dev = (struct device *)data;
  556 + int error;
  557 +
  558 + error = device_resume(dev, pm_transition, true);
  559 + if (error)
  560 + pm_dev_err(dev, pm_transition, " async", error);
  561 + put_device(dev);
  562 +}
  563 +
  564 +static bool is_async(struct device *dev)
  565 +{
  566 + return dev->power.async_suspend && pm_async_enabled
  567 + && !pm_trace_is_enabled();
  568 +}
  569 +
518 570 /**
519 571 * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
520 572 * @state: PM transition of the system being carried out.
521 573  
522 574  
523 575  
524 576  
525 577  
... ... @@ -525,21 +577,33 @@
525 577 static void dpm_resume(pm_message_t state)
526 578 {
527 579 struct list_head list;
  580 + struct device *dev;
528 581 ktime_t starttime = ktime_get();
529 582  
530 583 INIT_LIST_HEAD(&list);
531 584 mutex_lock(&dpm_list_mtx);
532   - while (!list_empty(&dpm_list)) {
533   - struct device *dev = to_device(dpm_list.next);
  585 + pm_transition = state;
534 586  
  587 + list_for_each_entry(dev, &dpm_list, power.entry) {
  588 + if (dev->power.status < DPM_OFF)
  589 + continue;
  590 +
  591 + INIT_COMPLETION(dev->power.completion);
  592 + if (is_async(dev)) {
  593 + get_device(dev);
  594 + async_schedule(async_resume, dev);
  595 + }
  596 + }
  597 +
  598 + while (!list_empty(&dpm_list)) {
  599 + dev = to_device(dpm_list.next);
535 600 get_device(dev);
536   - if (dev->power.status >= DPM_OFF) {
  601 + if (dev->power.status >= DPM_OFF && !is_async(dev)) {
537 602 int error;
538 603  
539   - dev->power.status = DPM_RESUMING;
540 604 mutex_unlock(&dpm_list_mtx);
541 605  
542   - error = device_resume(dev, state);
  606 + error = device_resume(dev, state, false);
543 607  
544 608 mutex_lock(&dpm_list_mtx);
545 609 if (error)
... ... @@ -554,6 +618,7 @@
554 618 }
555 619 list_splice(&list, &dpm_list);
556 620 mutex_unlock(&dpm_list_mtx);
  621 + async_synchronize_full();
557 622 dpm_show_time(starttime, state, NULL);
558 623 }
559 624  
560 625  
561 626  
562 627  
563 628  
... ... @@ -731,17 +796,24 @@
731 796 return error;
732 797 }
733 798  
  799 +static int async_error;
  800 +
734 801 /**
735 802 * device_suspend - Execute "suspend" callbacks for given device.
736 803 * @dev: Device to handle.
737 804 * @state: PM transition of the system being carried out.
  805 + * @async: If true, the device is being suspended asynchronously.
738 806 */
739   -static int device_suspend(struct device *dev, pm_message_t state)
  807 +static int __device_suspend(struct device *dev, pm_message_t state, bool async)
740 808 {
741 809 int error = 0;
742 810  
  811 + dpm_wait_for_children(dev, async);
743 812 down(&dev->sem);
744 813  
  814 + if (async_error)
  815 + goto End;
  816 +
745 817 if (dev->class) {
746 818 if (dev->class->pm) {
747 819 pm_dev_dbg(dev, state, "class ");
748 820  
749 821  
... ... @@ -772,12 +844,44 @@
772 844 error = legacy_suspend(dev, state, dev->bus->suspend);
773 845 }
774 846 }
  847 +
  848 + if (!error)
  849 + dev->power.status = DPM_OFF;
  850 +
775 851 End:
776 852 up(&dev->sem);
  853 + complete_all(&dev->power.completion);
777 854  
778 855 return error;
779 856 }
780 857  
  858 +static void async_suspend(void *data, async_cookie_t cookie)
  859 +{
  860 + struct device *dev = (struct device *)data;
  861 + int error;
  862 +
  863 + error = __device_suspend(dev, pm_transition, true);
  864 + if (error) {
  865 + pm_dev_err(dev, pm_transition, " async", error);
  866 + async_error = error;
  867 + }
  868 +
  869 + put_device(dev);
  870 +}
  871 +
  872 +static int device_suspend(struct device *dev)
  873 +{
  874 + INIT_COMPLETION(dev->power.completion);
  875 +
  876 + if (pm_async_enabled && dev->power.async_suspend) {
  877 + get_device(dev);
  878 + async_schedule(async_suspend, dev);
  879 + return 0;
  880 + }
  881 +
  882 + return __device_suspend(dev, pm_transition, false);
  883 +}
  884 +
781 885 /**
782 886 * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
783 887 * @state: PM transition of the system being carried out.
784 888  
... ... @@ -790,13 +894,15 @@
790 894  
791 895 INIT_LIST_HEAD(&list);
792 896 mutex_lock(&dpm_list_mtx);
  897 + pm_transition = state;
  898 + async_error = 0;
793 899 while (!list_empty(&dpm_list)) {
794 900 struct device *dev = to_device(dpm_list.prev);
795 901  
796 902 get_device(dev);
797 903 mutex_unlock(&dpm_list_mtx);
798 904  
799   - error = device_suspend(dev, state);
  905 + error = device_suspend(dev);
800 906  
801 907 mutex_lock(&dpm_list_mtx);
802 908 if (error) {
803 909  
804 910  
805 911  
... ... @@ -804,14 +910,18 @@
804 910 put_device(dev);
805 911 break;
806 912 }
807   - dev->power.status = DPM_OFF;
808 913 if (!list_empty(&dev->power.entry))
809 914 list_move(&dev->power.entry, &list);
810 915 put_device(dev);
  916 + if (async_error)
  917 + break;
811 918 }
812 919 list_splice(&list, dpm_list.prev);
813 920 mutex_unlock(&dpm_list_mtx);
  921 + async_synchronize_full();
814 922 if (!error)
  923 + error = async_error;
  924 + if (!error)
815 925 dpm_show_time(starttime, state, NULL);
816 926 return error;
817 927 }
... ... @@ -936,4 +1046,15 @@
936 1046 printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
937 1047 }
938 1048 EXPORT_SYMBOL_GPL(__suspend_report_result);
  1049 +
  1050 +/**
  1051 + * device_pm_wait_for_dev - Wait for suspend/resume of a device to complete.
  1052 + * @dev: Device to wait for.
  1053 + * @subordinate: Device that needs to wait for @dev.
  1054 + */
  1055 +void device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
  1056 +{
  1057 + dpm_wait(dev, subordinate->power.async_suspend);
  1058 +}
  1059 +EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
drivers/base/power/power.h
... ... @@ -12,10 +12,10 @@
12 12  
13 13 #ifdef CONFIG_PM_SLEEP
14 14  
15   -/*
16   - * main.c
17   - */
  15 +/* kernel/power/main.c */
  16 +extern int pm_async_enabled;
18 17  
  18 +/* drivers/base/power/main.c */
19 19 extern struct list_head dpm_list; /* The active device list */
20 20  
21 21 static inline struct device *to_device(struct list_head *entry)
drivers/base/power/runtime.c
... ... @@ -1011,6 +1011,50 @@
1011 1011 EXPORT_SYMBOL_GPL(pm_runtime_enable);
1012 1012  
1013 1013 /**
  1014 + * pm_runtime_forbid - Block run-time PM of a device.
  1015 + * @dev: Device to handle.
  1016 + *
  1017 + * Increase the device's usage count and clear its power.runtime_auto flag,
  1018 + * so that it cannot be suspended at run time until pm_runtime_allow() is called
  1019 + * for it.
  1020 + */
  1021 +void pm_runtime_forbid(struct device *dev)
  1022 +{
  1023 + spin_lock_irq(&dev->power.lock);
  1024 + if (!dev->power.runtime_auto)
  1025 + goto out;
  1026 +
  1027 + dev->power.runtime_auto = false;
  1028 + atomic_inc(&dev->power.usage_count);
  1029 + __pm_runtime_resume(dev, false);
  1030 +
  1031 + out:
  1032 + spin_unlock_irq(&dev->power.lock);
  1033 +}
  1034 +EXPORT_SYMBOL_GPL(pm_runtime_forbid);
  1035 +
  1036 +/**
  1037 + * pm_runtime_allow - Unblock run-time PM of a device.
  1038 + * @dev: Device to handle.
  1039 + *
  1040 + * Decrease the device's usage count and set its power.runtime_auto flag.
  1041 + */
  1042 +void pm_runtime_allow(struct device *dev)
  1043 +{
  1044 + spin_lock_irq(&dev->power.lock);
  1045 + if (dev->power.runtime_auto)
  1046 + goto out;
  1047 +
  1048 + dev->power.runtime_auto = true;
  1049 + if (atomic_dec_and_test(&dev->power.usage_count))
  1050 + __pm_runtime_idle(dev);
  1051 +
  1052 + out:
  1053 + spin_unlock_irq(&dev->power.lock);
  1054 +}
  1055 +EXPORT_SYMBOL_GPL(pm_runtime_allow);
  1056 +
  1057 +/**
1014 1058 * pm_runtime_init - Initialize run-time PM fields in given device object.
1015 1059 * @dev: Device object to initialize.
1016 1060 */
... ... @@ -1028,6 +1072,7 @@
1028 1072  
1029 1073 atomic_set(&dev->power.child_count, 0);
1030 1074 pm_suspend_ignore_children(dev, false);
  1075 + dev->power.runtime_auto = true;
1031 1076  
1032 1077 dev->power.request_pending = false;
1033 1078 dev->power.request = RPM_REQ_NONE;
drivers/base/power/sysfs.c
... ... @@ -4,9 +4,25 @@
4 4  
5 5 #include <linux/device.h>
6 6 #include <linux/string.h>
  7 +#include <linux/pm_runtime.h>
7 8 #include "power.h"
8 9  
9 10 /*
  11 + * control - Report/change current runtime PM setting of the device
  12 + *
  13 + * Runtime power management of a device can be blocked with the help of
  14 + * this attribute. All devices have one of the following two values for
  15 + * the power/control file:
  16 + *
  17 + * + "auto\n" to allow the device to be power managed at run time;
  18 + * + "on\n" to prevent the device from being power managed at run time;
  19 + *
  20 + * The default for all devices is "auto", which means that devices may be
  21 + * subject to automatic power management, depending on their drivers.
  22 + * Changing this attribute to "on" prevents the driver from power managing
  23 + * the device at run time. Doing that while the device is suspended causes
  24 + * it to be woken up.
  25 + *
10 26 * wakeup - Report/change current wakeup option for device
11 27 *
12 28 * Some devices support "wakeup" events, which are hardware signals
13 29  
... ... @@ -38,11 +54,61 @@
38 54 * wakeup events internally (unless they are disabled), keeping
39 55 * their hardware in low power modes whenever they're unused. This
40 56 * saves runtime power, without requiring system-wide sleep states.
  57 + *
  58 + * async - Report/change current async suspend setting for the device
  59 + *
  60 + * Asynchronous suspend and resume of the device during system-wide power
  61 + * state transitions can be enabled by writing "enabled" to this file.
  62 + * Analogously, if "disabled" is written to this file, the device will be
  63 + * suspended and resumed synchronously.
  64 + *
  65 + * All devices have one of the following two values for power/async:
  66 + *
  67 + * + "enabled\n" to permit the asynchronous suspend/resume of the device;
  68 + * + "disabled\n" to forbid it;
  69 + *
  70 + * NOTE: It generally is unsafe to permit the asynchronous suspend/resume
  71 + * of a device unless it is certain that all of the PM dependencies of the
  72 + * device are known to the PM core. However, for some devices this
  73 + * attribute is set to "enabled" by bus type code or device drivers and in
  74 + * that cases it should be safe to leave the default value.
41 75 */
42 76  
43 77 static const char enabled[] = "enabled";
44 78 static const char disabled[] = "disabled";
45 79  
  80 +#ifdef CONFIG_PM_RUNTIME
  81 +static const char ctrl_auto[] = "auto";
  82 +static const char ctrl_on[] = "on";
  83 +
  84 +static ssize_t control_show(struct device *dev, struct device_attribute *attr,
  85 + char *buf)
  86 +{
  87 + return sprintf(buf, "%s\n",
  88 + dev->power.runtime_auto ? ctrl_auto : ctrl_on);
  89 +}
  90 +
  91 +static ssize_t control_store(struct device * dev, struct device_attribute *attr,
  92 + const char * buf, size_t n)
  93 +{
  94 + char *cp;
  95 + int len = n;
  96 +
  97 + cp = memchr(buf, '\n', n);
  98 + if (cp)
  99 + len = cp - buf;
  100 + if (len == sizeof ctrl_auto - 1 && strncmp(buf, ctrl_auto, len) == 0)
  101 + pm_runtime_allow(dev);
  102 + else if (len == sizeof ctrl_on - 1 && strncmp(buf, ctrl_on, len) == 0)
  103 + pm_runtime_forbid(dev);
  104 + else
  105 + return -EINVAL;
  106 + return n;
  107 +}
  108 +
  109 +static DEVICE_ATTR(control, 0644, control_show, control_store);
  110 +#endif
  111 +
46 112 static ssize_t
47 113 wake_show(struct device * dev, struct device_attribute *attr, char * buf)
48 114 {
49 115  
50 116  
51 117  
... ... @@ -77,9 +143,43 @@
77 143  
78 144 static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
79 145  
  146 +#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG
  147 +static ssize_t async_show(struct device *dev, struct device_attribute *attr,
  148 + char *buf)
  149 +{
  150 + return sprintf(buf, "%s\n",
  151 + device_async_suspend_enabled(dev) ? enabled : disabled);
  152 +}
80 153  
  154 +static ssize_t async_store(struct device *dev, struct device_attribute *attr,
  155 + const char *buf, size_t n)
  156 +{
  157 + char *cp;
  158 + int len = n;
  159 +
  160 + cp = memchr(buf, '\n', n);
  161 + if (cp)
  162 + len = cp - buf;
  163 + if (len == sizeof enabled - 1 && strncmp(buf, enabled, len) == 0)
  164 + device_enable_async_suspend(dev);
  165 + else if (len == sizeof disabled - 1 && strncmp(buf, disabled, len) == 0)
  166 + device_disable_async_suspend(dev);
  167 + else
  168 + return -EINVAL;
  169 + return n;
  170 +}
  171 +
  172 +static DEVICE_ATTR(async, 0644, async_show, async_store);
  173 +#endif /* CONFIG_PM_SLEEP_ADVANCED_DEBUG */
  174 +
81 175 static struct attribute * power_attrs[] = {
  176 +#ifdef CONFIG_PM_RUNTIME
  177 + &dev_attr_control.attr,
  178 +#endif
82 179 &dev_attr_wakeup.attr,
  180 +#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG
  181 + &dev_attr_async.attr,
  182 +#endif
83 183 NULL,
84 184 };
85 185 static struct attribute_group pm_attr_group = {
... ... @@ -1540,6 +1540,7 @@
1540 1540 int pm;
1541 1541 u16 pmc;
1542 1542  
  1543 + device_enable_async_suspend(&dev->dev);
1543 1544 dev->wakeup_prepared = false;
1544 1545 dev->pm_cap = 0;
1545 1546  
drivers/pci/pcie/portdrv_core.c
... ... @@ -285,6 +285,7 @@
285 285 pci_name(pdev),
286 286 get_descriptor_id(pdev->pcie_type, service));
287 287 device->parent = &pdev->dev;
  288 + device_enable_async_suspend(device);
288 289  
289 290 retval = device_register(device);
290 291 if (retval)
... ... @@ -1436,6 +1436,7 @@
1436 1436 if (error)
1437 1437 goto dev_reg_err;
1438 1438 b->bridge = get_device(dev);
  1439 + device_enable_async_suspend(b->bridge);
1439 1440  
1440 1441 if (!parent)
1441 1442 set_dev_node(b->bridge, pcibus_to_node(b));
drivers/scsi/hosts.c
... ... @@ -215,12 +215,16 @@
215 215 shost->shost_gendev.parent = dev ? dev : &platform_bus;
216 216 shost->dma_dev = dma_dev;
217 217  
  218 + device_enable_async_suspend(&shost->shost_gendev);
  219 +
218 220 error = device_add(&shost->shost_gendev);
219 221 if (error)
220 222 goto out;
221 223  
222 224 scsi_host_set_state(shost, SHOST_RUNNING);
223 225 get_device(shost->shost_gendev.parent);
  226 +
  227 + device_enable_async_suspend(&shost->shost_dev);
224 228  
225 229 error = device_add(&shost->shost_dev);
226 230 if (error)
drivers/scsi/scsi_sysfs.c
... ... @@ -847,6 +847,8 @@
847 847 if (starget->state != STARGET_CREATED)
848 848 return 0;
849 849  
  850 + device_enable_async_suspend(&starget->dev);
  851 +
850 852 error = device_add(&starget->dev);
851 853 if (error) {
852 854 dev_err(&starget->dev, "target device_add failed, error %d\n", error);
853 855  
... ... @@ -887,11 +889,13 @@
887 889 return error;
888 890  
889 891 transport_configure_device(&starget->dev);
  892 + device_enable_async_suspend(&sdev->sdev_gendev);
890 893 error = device_add(&sdev->sdev_gendev);
891 894 if (error) {
892 895 printk(KERN_INFO "error 1\n");
893 896 return error;
894 897 }
  898 + device_enable_async_suspend(&sdev->sdev_dev);
895 899 error = device_add(&sdev->sdev_dev);
896 900 if (error) {
897 901 printk(KERN_INFO "error 2\n");
drivers/usb/core/driver.c
... ... @@ -1022,6 +1022,14 @@
1022 1022 goto done;
1023 1023 }
1024 1024  
  1025 + /* Non-root devices on a full/low-speed bus must wait for their
  1026 + * companion high-speed root hub, in case a handoff is needed.
  1027 + */
  1028 + if (!(msg.event & PM_EVENT_AUTO) && udev->parent &&
  1029 + udev->bus->hs_companion)
  1030 + device_pm_wait_for_dev(&udev->dev,
  1031 + &udev->bus->hs_companion->root_hub->dev);
  1032 +
1025 1033 if (udev->quirks & USB_QUIRK_RESET_RESUME)
1026 1034 udev->reset_resume = 1;
1027 1035  
drivers/usb/core/endpoint.c
... ... @@ -186,6 +186,7 @@
186 186 ep_dev->dev.parent = parent;
187 187 ep_dev->dev.release = ep_device_release;
188 188 dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
  189 + device_enable_async_suspend(&ep_dev->dev);
189 190  
190 191 retval = device_register(&ep_dev->dev);
191 192 if (retval)
drivers/usb/core/hcd-pci.c
... ... @@ -19,6 +19,7 @@
19 19 #include <linux/kernel.h>
20 20 #include <linux/module.h>
21 21 #include <linux/pci.h>
  22 +#include <linux/pm_runtime.h>
22 23 #include <linux/usb.h>
23 24  
24 25 #include <asm/io.h>
25 26  
... ... @@ -37,7 +38,123 @@
37 38  
38 39 /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
39 40  
  41 +#ifdef CONFIG_PM_SLEEP
40 42  
  43 +/* Coordinate handoffs between EHCI and companion controllers
  44 + * during system resume
  45 + */
  46 +
  47 +static DEFINE_MUTEX(companions_mutex);
  48 +
  49 +#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
  50 +#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
  51 +#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
  52 +
  53 +enum companion_action {
  54 + SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
  55 +};
  56 +
  57 +static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
  58 + enum companion_action action)
  59 +{
  60 + struct pci_dev *companion;
  61 + struct usb_hcd *companion_hcd;
  62 + unsigned int slot = PCI_SLOT(pdev->devfn);
  63 +
  64 + /* Iterate through other PCI functions in the same slot.
  65 + * If pdev is OHCI or UHCI then we are looking for EHCI, and
  66 + * vice versa.
  67 + */
  68 + companion = NULL;
  69 + for (;;) {
  70 + companion = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, companion);
  71 + if (!companion)
  72 + break;
  73 + if (companion->bus != pdev->bus ||
  74 + PCI_SLOT(companion->devfn) != slot)
  75 + continue;
  76 +
  77 + companion_hcd = pci_get_drvdata(companion);
  78 + if (!companion_hcd)
  79 + continue;
  80 +
  81 + /* For SET_HS_COMPANION, store a pointer to the EHCI bus in
  82 + * the OHCI/UHCI companion bus structure.
  83 + * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus
  84 + * in the OHCI/UHCI companion bus structure.
  85 + * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI
  86 + * companion controllers have fully resumed.
  87 + */
  88 +
  89 + if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) &&
  90 + companion->class == CL_EHCI) {
  91 + /* action must be SET_HS_COMPANION */
  92 + dev_dbg(&companion->dev, "HS companion for %s\n",
  93 + dev_name(&pdev->dev));
  94 + hcd->self.hs_companion = &companion_hcd->self;
  95 +
  96 + } else if (pdev->class == CL_EHCI &&
  97 + (companion->class == CL_OHCI ||
  98 + companion->class == CL_UHCI)) {
  99 + switch (action) {
  100 + case SET_HS_COMPANION:
  101 + dev_dbg(&pdev->dev, "HS companion for %s\n",
  102 + dev_name(&companion->dev));
  103 + companion_hcd->self.hs_companion = &hcd->self;
  104 + break;
  105 + case CLEAR_HS_COMPANION:
  106 + companion_hcd->self.hs_companion = NULL;
  107 + break;
  108 + case WAIT_FOR_COMPANIONS:
  109 + device_pm_wait_for_dev(&pdev->dev,
  110 + &companion->dev);
  111 + break;
  112 + }
  113 + }
  114 + }
  115 +}
  116 +
  117 +static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
  118 +{
  119 + mutex_lock(&companions_mutex);
  120 + dev_set_drvdata(&pdev->dev, hcd);
  121 + companion_common(pdev, hcd, SET_HS_COMPANION);
  122 + mutex_unlock(&companions_mutex);
  123 +}
  124 +
  125 +static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
  126 +{
  127 + mutex_lock(&companions_mutex);
  128 + dev_set_drvdata(&pdev->dev, NULL);
  129 +
  130 + /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */
  131 + if (pdev->class == CL_OHCI || pdev->class == CL_UHCI)
  132 + hcd->self.hs_companion = NULL;
  133 +
  134 + /* Otherwise search for companion buses and clear their pointers */
  135 + else
  136 + companion_common(pdev, hcd, CLEAR_HS_COMPANION);
  137 + mutex_unlock(&companions_mutex);
  138 +}
  139 +
  140 +static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd)
  141 +{
  142 + /* Only EHCI controllers need to wait.
  143 + * No locking is needed because a controller cannot be resumed
  144 + * while one of its companions is getting unbound.
  145 + */
  146 + if (pdev->class == CL_EHCI)
  147 + companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
  148 +}
  149 +
  150 +#else /* !CONFIG_PM_SLEEP */
  151 +
  152 +static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
  153 +static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
  154 +static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {}
  155 +
  156 +#endif /* !CONFIG_PM_SLEEP */
  157 +
41 158 /*-------------------------------------------------------------------------*/
42 159  
43 160 /* configure so an HC device and id are always provided */
... ... @@ -123,7 +240,7 @@
123 240 if (region == PCI_ROM_RESOURCE) {
124 241 dev_dbg(&dev->dev, "no i/o regions available\n");
125 242 retval = -EBUSY;
126   - goto err1;
  243 + goto err2;
127 244 }
128 245 }
129 246  
... ... @@ -132,6 +249,7 @@
132 249 retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
133 250 if (retval != 0)
134 251 goto err4;
  252 + set_hs_companion(dev, hcd);
135 253 return retval;
136 254  
137 255 err4:
... ... @@ -142,6 +260,7 @@
142 260 } else
143 261 release_region(hcd->rsrc_start, hcd->rsrc_len);
144 262 err2:
  263 + clear_hs_companion(dev, hcd);
145 264 usb_put_hcd(hcd);
146 265 err1:
147 266 pci_disable_device(dev);
... ... @@ -180,6 +299,7 @@
180 299 } else {
181 300 release_region(hcd->rsrc_start, hcd->rsrc_len);
182 301 }
  302 + clear_hs_companion(dev, hcd);
183 303 usb_put_hcd(hcd);
184 304 pci_disable_device(dev);
185 305 }
... ... @@ -344,6 +464,11 @@
344 464 clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
345 465  
346 466 if (hcd->driver->pci_resume) {
  467 + /* This call should be made only during system resume,
  468 + * not during runtime resume.
  469 + */
  470 + wait_for_companions(pci_dev, hcd);
  471 +
347 472 retval = hcd->driver->pci_resume(hcd, hibernated);
348 473 if (retval) {
349 474 dev_err(dev, "PCI post-resume error %d!\n", retval);
drivers/usb/core/hub.c
... ... @@ -1817,6 +1817,7 @@
1817 1817 /* Tell the world! */
1818 1818 announce_device(udev);
1819 1819  
  1820 + device_enable_async_suspend(&udev->dev);
1820 1821 /* Register the device. The device driver is responsible
1821 1822 * for configuring the device and invoking the add-device
1822 1823 * notifier chain (used by usbfs and possibly others).
drivers/usb/core/message.c
... ... @@ -1867,6 +1867,7 @@
1867 1867 "adding %s (config #%d, interface %d)\n",
1868 1868 dev_name(&intf->dev), configuration,
1869 1869 intf->cur_altsetting->desc.bInterfaceNumber);
  1870 + device_enable_async_suspend(&intf->dev);
1870 1871 ret = device_add(&intf->dev);
1871 1872 if (ret != 0) {
1872 1873 dev_err(&dev->dev, "device_add(%s) --> %d\n",
include/linux/device.h
... ... @@ -472,6 +472,23 @@
472 472 return dev->kobj.state_in_sysfs;
473 473 }
474 474  
  475 +static inline void device_enable_async_suspend(struct device *dev)
  476 +{
  477 + if (dev->power.status == DPM_ON)
  478 + dev->power.async_suspend = true;
  479 +}
  480 +
  481 +static inline void device_disable_async_suspend(struct device *dev)
  482 +{
  483 + if (dev->power.status == DPM_ON)
  484 + dev->power.async_suspend = false;
  485 +}
  486 +
  487 +static inline bool device_async_suspend_enabled(struct device *dev)
  488 +{
  489 + return !!dev->power.async_suspend;
  490 +}
  491 +
475 492 void driver_init(void);
476 493  
477 494 /*
... ... @@ -26,6 +26,7 @@
26 26 #include <linux/spinlock.h>
27 27 #include <linux/wait.h>
28 28 #include <linux/timer.h>
  29 +#include <linux/completion.h>
29 30  
30 31 /*
31 32 * Callbacks for platform drivers to implement.
32 33  
... ... @@ -412,9 +413,11 @@
412 413 pm_message_t power_state;
413 414 unsigned int can_wakeup:1;
414 415 unsigned int should_wakeup:1;
  416 + unsigned async_suspend:1;
415 417 enum dpm_state status; /* Owned by the PM core */
416 418 #ifdef CONFIG_PM_SLEEP
417 419 struct list_head entry;
  420 + struct completion completion;
418 421 #endif
419 422 #ifdef CONFIG_PM_RUNTIME
420 423 struct timer_list suspend_timer;
... ... @@ -430,6 +433,7 @@
430 433 unsigned int request_pending:1;
431 434 unsigned int deferred_resume:1;
432 435 unsigned int run_wake:1;
  436 + unsigned int runtime_auto:1;
433 437 enum rpm_request request;
434 438 enum rpm_status runtime_status;
435 439 int runtime_error;
... ... @@ -508,6 +512,7 @@
508 512 __suspend_report_result(__func__, fn, ret); \
509 513 } while (0)
510 514  
  515 +extern void device_pm_wait_for_dev(struct device *sub, struct device *dev);
511 516 #else /* !CONFIG_PM_SLEEP */
512 517  
513 518 #define device_pm_lock() do {} while (0)
... ... @@ -520,6 +525,7 @@
520 525  
521 526 #define suspend_report_result(fn, ret) do {} while (0)
522 527  
  528 +static inline void device_pm_wait_for_dev(struct device *a, struct device *b) {}
523 529 #endif /* !CONFIG_PM_SLEEP */
524 530  
525 531 /* How to reorder dpm_list after device_move() */
include/linux/pm_runtime.h
... ... @@ -28,6 +28,8 @@
28 28 extern int pm_runtime_barrier(struct device *dev);
29 29 extern void pm_runtime_enable(struct device *dev);
30 30 extern void __pm_runtime_disable(struct device *dev, bool check_resume);
  31 +extern void pm_runtime_allow(struct device *dev);
  32 +extern void pm_runtime_forbid(struct device *dev);
31 33  
32 34 static inline bool pm_children_suspended(struct device *dev)
33 35 {
... ... @@ -78,6 +80,8 @@
78 80 static inline int pm_runtime_barrier(struct device *dev) { return 0; }
79 81 static inline void pm_runtime_enable(struct device *dev) {}
80 82 static inline void __pm_runtime_disable(struct device *dev, bool c) {}
  83 +static inline void pm_runtime_allow(struct device *dev) {}
  84 +static inline void pm_runtime_forbid(struct device *dev) {}
81 85  
82 86 static inline bool pm_children_suspended(struct device *dev) { return false; }
83 87 static inline void pm_suspend_ignore_children(struct device *dev, bool en) {}
include/linux/resume-trace.h
... ... @@ -6,6 +6,11 @@
6 6  
7 7 extern int pm_trace_enabled;
8 8  
  9 +static inline int pm_trace_is_enabled(void)
  10 +{
  11 + return pm_trace_enabled;
  12 +}
  13 +
9 14 struct device;
10 15 extern void set_trace_device(struct device *);
11 16 extern void generate_resume_trace(const void *tracedata, unsigned int user);
... ... @@ -16,6 +21,8 @@
16 21 } while(0)
17 22  
18 23 #else
  24 +
  25 +static inline int pm_trace_is_enabled(void) { return 0; }
19 26  
20 27 #define TRACE_DEVICE(dev) do { } while (0)
21 28 #define TRACE_RESUME(dev) do { } while (0)
... ... @@ -339,6 +339,7 @@
339 339  
340 340 struct usb_devmap devmap; /* device address allocation map */
341 341 struct usb_device *root_hub; /* Root hub */
  342 + struct usb_bus *hs_companion; /* Companion EHCI bus, if any */
342 343 struct list_head bus_list; /* list of busses */
343 344  
344 345 int bandwidth_allocated; /* on this bus: how much of the time
kernel/power/Kconfig
... ... @@ -27,6 +27,15 @@
27 27 code. This is helpful when debugging and reporting PM bugs, like
28 28 suspend support.
29 29  
  30 +config PM_ADVANCED_DEBUG
  31 + bool "Extra PM attributes in sysfs for low-level debugging/testing"
  32 + depends on PM_DEBUG
  33 + default n
  34 + ---help---
  35 + Add extra sysfs attributes allowing one to access some Power Management
  36 + fields of device objects from user space. If you are not a kernel
  37 + developer interested in debugging/testing Power Management, say "no".
  38 +
30 39 config PM_VERBOSE
31 40 bool "Verbose Power Management debugging"
32 41 depends on PM_DEBUG
... ... @@ -84,6 +93,11 @@
84 93 bool
85 94 depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
86 95 default y
  96 +
  97 +config PM_SLEEP_ADVANCED_DEBUG
  98 + bool
  99 + depends on PM_ADVANCED_DEBUG
  100 + default n
87 101  
88 102 config SUSPEND
89 103 bool "Suspend to RAM and standby"
... ... @@ -44,6 +44,32 @@
44 44 == NOTIFY_BAD) ? -EINVAL : 0;
45 45 }
46 46  
  47 +/* If set, devices may be suspended and resumed asynchronously. */
  48 +int pm_async_enabled = 1;
  49 +
  50 +static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
  51 + char *buf)
  52 +{
  53 + return sprintf(buf, "%d\n", pm_async_enabled);
  54 +}
  55 +
  56 +static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
  57 + const char *buf, size_t n)
  58 +{
  59 + unsigned long val;
  60 +
  61 + if (strict_strtoul(buf, 10, &val))
  62 + return -EINVAL;
  63 +
  64 + if (val > 1)
  65 + return -EINVAL;
  66 +
  67 + pm_async_enabled = val;
  68 + return n;
  69 +}
  70 +
  71 +power_attr(pm_async);
  72 +
47 73 #ifdef CONFIG_PM_DEBUG
48 74 int pm_test_level = TEST_NONE;
49 75  
50 76  
... ... @@ -208,8 +234,11 @@
208 234 #ifdef CONFIG_PM_TRACE
209 235 &pm_trace_attr.attr,
210 236 #endif
211   -#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
  237 +#ifdef CONFIG_PM_SLEEP
  238 + &pm_async_attr.attr,
  239 +#ifdef CONFIG_PM_DEBUG
212 240 &pm_test_attr.attr,
  241 +#endif
213 242 #endif
214 243 NULL,
215 244 };
kernel/power/snapshot.c
... ... @@ -1181,7 +1181,7 @@
1181 1181  
1182 1182 memory_bm_position_reset(&copy_bm);
1183 1183  
1184   - while (to_free_normal > 0 && to_free_highmem > 0) {
  1184 + while (to_free_normal > 0 || to_free_highmem > 0) {
1185 1185 unsigned long pfn = memory_bm_next_pfn(&copy_bm);
1186 1186 struct page *page = pfn_to_page(pfn);
1187 1187  
... ... @@ -1500,7 +1500,7 @@
1500 1500 {
1501 1501 unsigned int nr_pages, nr_highmem;
1502 1502  
1503   - printk(KERN_INFO "PM: Creating hibernation image: \n");
  1503 + printk(KERN_INFO "PM: Creating hibernation image:\n");
1504 1504  
1505 1505 drain_local_pages(NULL);
1506 1506 nr_pages = count_data_pages();
... ... @@ -657,10 +657,6 @@
657 657 struct swsusp_info *header;
658 658  
659 659 *flags_p = swsusp_header->flags;
660   - if (IS_ERR(resume_bdev)) {
661   - pr_debug("PM: Image device not initialised\n");
662   - return PTR_ERR(resume_bdev);
663   - }
664 660  
665 661 memset(&snapshot, 0, sizeof(struct snapshot_handle));
666 662 error = snapshot_write_next(&snapshot, PAGE_SIZE);
kernel/power/swsusp.c
1   -/*
2   - * linux/kernel/power/swsusp.c
3   - *
4   - * This file provides code to write suspend image to swap and read it back.
5   - *
6   - * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
7   - * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
8   - *
9   - * This file is released under the GPLv2.
10   - *
11   - * I'd like to thank the following people for their work:
12   - *
13   - * Pavel Machek <pavel@ucw.cz>:
14   - * Modifications, defectiveness pointing, being with me at the very beginning,
15   - * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17.
16   - *
17   - * Steve Doddi <dirk@loth.demon.co.uk>:
18   - * Support the possibility of hardware state restoring.
19   - *
20   - * Raph <grey.havens@earthling.net>:
21   - * Support for preserving states of network devices and virtual console
22   - * (including X and svgatextmode)
23   - *
24   - * Kurt Garloff <garloff@suse.de>:
25   - * Straightened the critical function in order to prevent compilers from
26   - * playing tricks with local variables.
27   - *
28   - * Andreas Mohr <a.mohr@mailto.de>
29   - *
30   - * Alex Badea <vampire@go.ro>:
31   - * Fixed runaway init
32   - *
33   - * Rafael J. Wysocki <rjw@sisk.pl>
34   - * Reworked the freeing of memory and the handling of swap
35   - *
36   - * More state savers are welcome. Especially for the scsi layer...
37   - *
38   - * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
39   - */
40   -
41   -#include <linux/mm.h>
42   -#include <linux/suspend.h>
43   -#include <linux/spinlock.h>
44   -#include <linux/kernel.h>
45   -#include <linux/major.h>
46   -#include <linux/swap.h>
47   -#include <linux/pm.h>
48   -#include <linux/swapops.h>
49   -#include <linux/bootmem.h>
50   -#include <linux/syscalls.h>
51   -#include <linux/highmem.h>
52   -#include <linux/time.h>
53   -#include <linux/rbtree.h>
54   -#include <linux/io.h>
55   -
56   -#include "power.h"
57   -
58   -int in_suspend __nosavedata = 0;
... ... @@ -195,6 +195,15 @@
195 195 return res;
196 196 }
197 197  
  198 +static void snapshot_deprecated_ioctl(unsigned int cmd)
  199 +{
  200 + if (printk_ratelimit())
  201 + printk(KERN_NOTICE "%pf: ioctl '%.8x' is deprecated and will "
  202 + "be removed soon, update your suspend-to-disk "
  203 + "utilities\n",
  204 + __builtin_return_address(0), cmd);
  205 +}
  206 +
198 207 static long snapshot_ioctl(struct file *filp, unsigned int cmd,
199 208 unsigned long arg)
200 209 {
201 210  
... ... @@ -246,8 +255,9 @@
246 255 data->frozen = 0;
247 256 break;
248 257  
249   - case SNAPSHOT_CREATE_IMAGE:
250 258 case SNAPSHOT_ATOMIC_SNAPSHOT:
  259 + snapshot_deprecated_ioctl(cmd);
  260 + case SNAPSHOT_CREATE_IMAGE:
251 261 if (data->mode != O_RDONLY || !data->frozen || data->ready) {
252 262 error = -EPERM;
253 263 break;
254 264  
... ... @@ -275,8 +285,9 @@
275 285 data->ready = 0;
276 286 break;
277 287  
278   - case SNAPSHOT_PREF_IMAGE_SIZE:
279 288 case SNAPSHOT_SET_IMAGE_SIZE:
  289 + snapshot_deprecated_ioctl(cmd);
  290 + case SNAPSHOT_PREF_IMAGE_SIZE:
280 291 image_size = arg;
281 292 break;
282 293  
283 294  
284 295  
285 296  
... ... @@ -290,15 +301,17 @@
290 301 error = put_user(size, (loff_t __user *)arg);
291 302 break;
292 303  
293   - case SNAPSHOT_AVAIL_SWAP_SIZE:
294 304 case SNAPSHOT_AVAIL_SWAP:
  305 + snapshot_deprecated_ioctl(cmd);
  306 + case SNAPSHOT_AVAIL_SWAP_SIZE:
295 307 size = count_swap_pages(data->swap, 1);
296 308 size <<= PAGE_SHIFT;
297 309 error = put_user(size, (loff_t __user *)arg);
298 310 break;
299 311  
300   - case SNAPSHOT_ALLOC_SWAP_PAGE:
301 312 case SNAPSHOT_GET_SWAP_PAGE:
  313 + snapshot_deprecated_ioctl(cmd);
  314 + case SNAPSHOT_ALLOC_SWAP_PAGE:
302 315 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
303 316 error = -ENODEV;
304 317 break;
... ... @@ -321,6 +334,7 @@
321 334 break;
322 335  
323 336 case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
  337 + snapshot_deprecated_ioctl(cmd);
324 338 if (!swsusp_swap_in_use()) {
325 339 /*
326 340 * User space encodes device types as two-byte values,
... ... @@ -362,6 +376,7 @@
362 376 break;
363 377  
364 378 case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
  379 + snapshot_deprecated_ioctl(cmd);
365 380 error = -EINVAL;
366 381  
367 382 switch (arg) {