cpuidle: Allow idle states to be disabled by default
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 13 Dec 2019 08:56:13 +0000 (09:56 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 27 Dec 2019 10:02:08 +0000 (11:02 +0100)
In certain situations it may be useful to prevent some idle states
from being used by default while allowing user space to enable them
later on.

For this purpose, introduce a new state flag, CPUIDLE_FLAG_OFF, to
mark idle states that should be disabled by default, make the core
set CPUIDLE_STATE_DISABLED_BY_USER for those states at the
initialization time and add a new state attribute in sysfs,
"default_status", to inform user space of the initial status of
the given idle state ("disabled" if CPUIDLE_FLAG_OFF is set for it,
"enabled" otherwise).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/admin-guide/pm/cpuidle.rst
drivers/cpuidle/cpuidle.c
drivers/cpuidle/sysfs.c
include/linux/cpuidle.h

index fc20cde..2e0e3b4 100644 (file)
@@ -196,6 +196,12 @@ Description:
                does not reflect it. Likewise, if one enables a deep state but a
                lighter state still is disabled, then this has no effect.
 
+What:          /sys/devices/system/cpu/cpuX/cpuidle/stateN/default_status
+Date:          December 2019
+KernelVersion: v5.6
+Contact:       Linux power management list <linux-pm@vger.kernel.org>
+Description:
+               (RO) The default status of this state, "enabled" or "disabled".
 
 What:          /sys/devices/system/cpu/cpuX/cpuidle/stateN/residency
 Date:          March 2014
index e70b365..311cd7c 100644 (file)
@@ -506,6 +506,9 @@ object corresponding to it, as follows:
 ``disable``
        Whether or not this idle state is disabled.
 
+``default_status``
+       The default status of this state, "enabled" or "disabled".
+
 ``latency``
        Exit latency of the idle state in microseconds.
 
index 33d19c8..a2af7bb 100644 (file)
@@ -572,10 +572,14 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
        if (!try_module_get(drv->owner))
                return -EINVAL;
 
-       for (i = 0; i < drv->state_count; i++)
+       for (i = 0; i < drv->state_count; i++) {
                if (drv->states[i].flags & CPUIDLE_FLAG_UNUSABLE)
                        dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
 
+               if (drv->states[i].flags & CPUIDLE_FLAG_OFF)
+                       dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_USER;
+       }
+
        per_cpu(cpuidle_devices, dev->cpu) = dev;
        list_add(&dev->device_list, &cpuidle_detected_devices);
 
index 38ef770..254d156 100644 (file)
@@ -327,6 +327,14 @@ static ssize_t store_state_disable(struct cpuidle_state *state,
        return size;
 }
 
+static ssize_t show_state_default_status(struct cpuidle_state *state,
+                                         struct cpuidle_state_usage *state_usage,
+                                         char *buf)
+{
+       return sprintf(buf, "%s\n",
+                      state->flags & CPUIDLE_FLAG_OFF ? "disabled" : "enabled");
+}
+
 define_one_state_ro(name, show_state_name);
 define_one_state_ro(desc, show_state_desc);
 define_one_state_ro(latency, show_state_exit_latency);
@@ -337,6 +345,7 @@ define_one_state_ro(time, show_state_time);
 define_one_state_rw(disable, show_state_disable, store_state_disable);
 define_one_state_ro(above, show_state_above);
 define_one_state_ro(below, show_state_below);
+define_one_state_ro(default_status, show_state_default_status);
 
 static struct attribute *cpuidle_state_default_attrs[] = {
        &attr_name.attr,
@@ -349,6 +358,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
        &attr_disable.attr,
        &attr_above.attr,
        &attr_below.attr,
+       &attr_default_status.attr,
        NULL
 };
 
index 1dabe36..ebfb52b 100644 (file)
@@ -77,6 +77,7 @@ struct cpuidle_state {
 #define CPUIDLE_FLAG_COUPLED   BIT(1) /* state applies to multiple cpus */
 #define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */
 #define CPUIDLE_FLAG_UNUSABLE  BIT(3) /* avoid using this state */
+#define CPUIDLE_FLAG_OFF       BIT(4) /* disable this state by default */
 
 struct cpuidle_device_kobj;
 struct cpuidle_state_kobj;