subsystem.
 
 What:          /sys/power/state
-Date:          August 2006
+Date:          May 2014
 Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
 Description:
-               The /sys/power/state file controls the system power state.
-               Reading from this file returns what states are supported,
-               which is hard-coded to 'freeze' (Low-Power Idle), 'standby'
-               (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk'
-               (Suspend-to-Disk).
+               The /sys/power/state file controls system sleep states.
+               Reading from this file returns the available sleep state
+               labels, which may be "mem", "standby", "freeze" and "disk"
+               (hibernation).  The meanings of the first three labels depend on
+               the relative_sleep_states command line argument as follows:
+                1) relative_sleep_states = 1
+                   "mem", "standby", "freeze" represent non-hibernation sleep
+                   states from the deepest ("mem", always present) to the
+                   shallowest ("freeze").  "standby" and "freeze" may or may
+                   not be present depending on the capabilities of the
+                   platform.  "freeze" can only be present if "standby" is
+                   present.
+                2) relative_sleep_states = 0 (default)
+                   "mem" - "suspend-to-RAM", present if supported.
+                   "standby" - "power-on suspend", present if supported.
+                   "freeze" - "suspend-to-idle", always present.
 
                Writing to this file one of these strings causes the system to
-               transition into that state. Please see the file
-               Documentation/power/states.txt for a description of each of
-               these states.
+               transition into the corresponding state, if available.  See
+               Documentation/power/states.txt for a description of what
+               "suspend-to-RAM", "power-on suspend" and "suspend-to-idle" mean.
 
 What:          /sys/power/disk
 Date:          September 2006
 
+System Power Management Sleep States
 
-System Power Management States
+(C) 2014 Intel Corp., Rafael J. Wysocki <rafael.j.wysocki@intel.com>
 
+The kernel supports up to four system sleep states generically, although three
+of them depend on the platform support code to implement the low-level details
+for each state.
 
-The kernel supports four power management states generically, though
-one is generic and the other three are dependent on platform support
-code to implement the low-level details for each state.
-This file describes each state, what they are
-commonly called, what ACPI state they map to, and what string to write
-to /sys/power/state to enter that state
+The states are represented by strings that can be read or written to the
+/sys/power/state file.  Those strings may be "mem", "standby", "freeze" and
+"disk", where the last one always represents hibernation (Suspend-To-Disk) and
+the meaning of the remaining ones depends on the relative_sleep_states command
+line argument.
 
-state:         Freeze / Low-Power Idle
+For relative_sleep_states=1, the strings "mem", "standby" and "freeze" label the
+available non-hibernation sleep states from the deepest to the shallowest,
+respectively.  In that case, "mem" is always present in /sys/power/state,
+because there is at least one non-hibernation sleep state in every system.  If
+the given system supports two non-hibernation sleep states, "standby" is present
+in /sys/power/state in addition to "mem".  If the system supports three
+non-hibernation sleep states, "freeze" will be present in /sys/power/state in
+addition to "mem" and "standby".
+
+For relative_sleep_states=0, which is the default, the following descriptions
+apply.
+
+state:         Suspend-To-Idle
 ACPI state:    S0
-String:                "freeze"
+Label:         "freeze"
 
-This state is a generic, pure software, light-weight, low-power state.
-It allows more energy to be saved relative to idle by freezing user
+This state is a generic, pure software, light-weight, system sleep state.
+It allows more energy to be saved relative to runtime idle by freezing user
 space and putting all I/O devices into low-power states (possibly
 lower-power than available at run time), such that the processors can
 spend more time in their idle states.
-This state can be used for platforms without Standby/Suspend-to-RAM
+
+This state can be used for platforms without Power-On Suspend/Suspend-to-RAM
 support, or it can be used in addition to Suspend-to-RAM (memory sleep)
-to provide reduced resume latency.
+to provide reduced resume latency.  It is always supported.
 
 
 State:         Standby / Power-On Suspend
 ACPI State:    S1
-String:                "standby"
+Label:         "standby"
 
-This state offers minimal, though real, power savings, while providing
-a very low-latency transition back to a working system. No operating
-state is lost (the CPU retains power), so the system easily starts up
+This state, if supported, offers moderate, though real, power savings, while
+providing a relatively low-latency transition back to a working system.  No
+operating state is lost (the CPU retains power), so the system easily starts up
 again where it left off. 
 
-We try to put devices in a low-power state equivalent to D1, which
-also offers low power savings, but low resume latency. Not all devices
-support D1, and those that don't are left on. 
+In addition to freezing user space and putting all I/O devices into low-power
+states, which is done for Suspend-To-Idle too, nonboot CPUs are taken offline
+and all low-level system functions are suspended during transitions into this
+state.  For this reason, it should allow more energy to be saved relative to
+Suspend-To-Idle, but the resume latency will generally be greater than for that
+state.
 
 
 State:         Suspend-to-RAM
 ACPI State:    S3
-String:                "mem"
+Label:         "mem"
 
-This state offers significant power savings as everything in the
-system is put into a low-power state, except for memory, which is
-placed in self-refresh mode to retain its contents. 
+This state, if supported, offers significant power savings as everything in the
+system is put into a low-power state, except for memory, which should be placed
+into the self-refresh mode to retain its contents.  All of the steps carried out
+when entering Power-On Suspend are also carried out during transitions to STR.
+Additional operations may take place depending on the platform capabilities.  In
+particular, on ACPI systems the kernel passes control to the BIOS (platform
+firmware) as the last step during STR transitions and that usually results in
+powering down some more low-level components that aren't directly controlled by
+the kernel.
 
-System and device state is saved and kept in memory. All devices are
-suspended and put into D3. In many cases, all peripheral buses lose
-power when entering STR, so devices must be able to handle the
-transition back to the On state. 
+System and device state is saved and kept in memory.  All devices are suspended
+and put into low-power states.  In many cases, all peripheral buses lose power
+when entering STR, so devices must be able to handle the transition back to the
+"on" state.
 
-For at least ACPI, STR requires some minimal boot-strapping code to
-resume the system from STR. This may be true on other platforms. 
+For at least ACPI, STR requires some minimal boot-strapping code to resume the
+system from it.  This may be the case on other platforms too.
 
 
 State:         Suspend-to-disk
 ACPI State:    S4
-String:                "disk"
+Label:         "disk"
 
 This state offers the greatest power savings, and can be used even in
 the absence of low-level platform support for power management. This
 
        return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
 }
 
+/*
+ * If this is set, the "mem" label always corresponds to the deepest sleep state
+ * available, the "standby" label corresponds to the second deepest sleep state
+ * available (if any), and the "freeze" label corresponds to the remaining
+ * available sleep state (if there is one).
+ */
+static bool relative_states;
+
+static int __init sleep_states_setup(char *str)
+{
+       relative_states = !strncmp(str, "1", 1);
+       if (relative_states) {
+               pm_states[PM_SUSPEND_MEM].state = PM_SUSPEND_FREEZE;
+               pm_states[PM_SUSPEND_FREEZE].state = 0;
+       }
+       return 1;
+}
+
+__setup("relative_sleep_states=", sleep_states_setup);
+
 /**
  * suspend_set_ops - Set the global suspend method table.
  * @ops: Suspend operations to use.
 void suspend_set_ops(const struct platform_suspend_ops *ops)
 {
        suspend_state_t i;
+       int j = PM_SUSPEND_MAX - 1;
 
        lock_system_sleep();
 
        suspend_ops = ops;
-       for (i = PM_SUSPEND_STANDBY; i <= PM_SUSPEND_MEM; i++)
-               pm_states[i].state = valid_state(i) ? i : 0;
+       for (i = PM_SUSPEND_MEM; i >= PM_SUSPEND_STANDBY; i--)
+               if (valid_state(i))
+                       pm_states[j--].state = i;
+               else if (!relative_states)
+                       pm_states[j--].state = 0;
+
+       pm_states[j--].state = PM_SUSPEND_FREEZE;
+       while (j >= PM_SUSPEND_MIN)
+               pm_states[j--].state = 0;
 
        unlock_system_sleep();
 }