return default_snooze_timeout;
 
        for (i = index + 1; i < drv->state_count; i++) {
-               struct cpuidle_state *s = &drv->states[i];
-               struct cpuidle_state_usage *su = &dev->states_usage[i];
-
-               if (s->disabled || su->disable)
+               if (dev->states_usage[i].disable)
                        continue;
 
-               return s->target_residency * tb_ticks_per_usec;
+               return drv->states[i].target_residency * tb_ticks_per_usec;
        }
 
        return default_snooze_timeout;
 
 
        for (i = 1; i < drv->state_count; i++) {
                struct cpuidle_state *s = &drv->states[i];
-               struct cpuidle_state_usage *su = &dev->states_usage[i];
 
-               if (s->disabled || su->disable || s->exit_latency <= latency_req
-                   || s->exit_latency > max_latency
-                   || (s->flags & forbidden_flags)
-                   || (s2idle && !s->enter_s2idle))
+               if (dev->states_usage[i].disable ||
+                   s->exit_latency <= latency_req ||
+                   s->exit_latency > max_latency ||
+                   (s->flags & forbidden_flags) ||
+                   (s2idle && !s->enter_s2idle))
                        continue;
 
                latency_req = s->exit_latency;
 
                if (diff < drv->states[entered_state].target_residency) {
                        for (i = entered_state - 1; i >= 0; i--) {
-                               if (drv->states[i].disabled ||
-                                   dev->states_usage[i].disable)
+                               if (dev->states_usage[i].disable)
                                        continue;
 
                                /* Shallower states are enabled, so update. */
                        }
                } else if (diff > delay) {
                        for (i = entered_state + 1; i < drv->state_count; i++) {
-                               if (drv->states[i].disabled ||
-                                   dev->states_usage[i].disable)
+                               if (dev->states_usage[i].disable)
                                        continue;
 
                                /*
 
        limit_ns = TICK_NSEC;
        for (i = 1; i < drv->state_count; i++) {
-               if (drv->states[i].disabled || dev->states_usage[i].disable)
+               if (dev->states_usage[i].disable)
                        continue;
 
                limit_ns = (u64)drv->states[i].target_residency * NSEC_PER_USEC;
  */
 static int __cpuidle_register_device(struct cpuidle_device *dev)
 {
-       int ret;
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
+       int i, ret;
 
        if (!try_module_get(drv->owner))
                return -EINVAL;
 
+       for (i = 0; i < drv->state_count; i++)
+               if (drv->states[i].disabled)
+                       dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
+
        per_cpu(cpuidle_devices, dev->cpu) = dev;
        list_add(&dev->device_list, &cpuidle_detected_devices);
 
 
 
        /* consider promotion */
        if (last_idx < drv->state_count - 1 &&
-           !drv->states[last_idx + 1].disabled &&
            !dev->states_usage[last_idx + 1].disable &&
            last_residency > last_state->threshold.promotion_time &&
            drv->states[last_idx + 1].exit_latency <= latency_req) {
 
        /* consider demotion */
        if (last_idx > first_idx &&
-           (drv->states[last_idx].disabled ||
-           dev->states_usage[last_idx].disable ||
+           (dev->states_usage[last_idx].disable ||
            drv->states[last_idx].exit_latency > latency_req)) {
                int i;
 
 
        if (unlikely(drv->state_count <= 1 || latency_req == 0) ||
            ((data->next_timer_us < drv->states[1].target_residency ||
              latency_req < drv->states[1].exit_latency) &&
-            !drv->states[0].disabled && !dev->states_usage[0].disable)) {
+            !dev->states_usage[0].disable)) {
                /*
                 * In this case state[0] will be used no matter what, so return
                 * it right away and keep the tick running if state[0] is a
        idx = -1;
        for (i = 0; i < drv->state_count; i++) {
                struct cpuidle_state *s = &drv->states[i];
-               struct cpuidle_state_usage *su = &dev->states_usage[i];
 
-               if (s->disabled || su->disable)
+               if (dev->states_usage[i].disable)
                        continue;
 
                if (idx == -1)
                         * tick, so try to correct that.
                         */
                        for (i = idx - 1; i >= 0; i--) {
-                               if (drv->states[i].disabled ||
-                                   dev->states_usage[i].disable)
+                               if (dev->states_usage[i].disable)
                                        continue;
 
                                idx = i;
 
        int i;
 
        for (i = state_idx - 1; i >= 0; i--) {
-               if (drv->states[i].disabled || dev->states_usage[i].disable)
+               if (dev->states_usage[i].disable)
                        continue;
 
                state_idx = i;
 
        for (i = 0; i < drv->state_count; i++) {
                struct cpuidle_state *s = &drv->states[i];
-               struct cpuidle_state_usage *su = &dev->states_usage[i];
 
-               if (s->disabled || su->disable) {
+               if (dev->states_usage[i].disable) {
                        /*
                         * Ignore disabled states with target residencies beyond
                         * the anticipated idle duration.
 
        return sprintf(buf, "%u\n", state->_name);\
 }
 
-#define define_store_state_ull_function(_name) \
-static ssize_t store_state_##_name(struct cpuidle_state *state, \
-                                  struct cpuidle_state_usage *state_usage, \
-                                  const char *buf, size_t size)        \
-{ \
-       unsigned long long value; \
-       int err; \
-       if (!capable(CAP_SYS_ADMIN)) \
-               return -EPERM; \
-       err = kstrtoull(buf, 0, &value); \
-       if (err) \
-               return err; \
-       if (value) \
-               state_usage->_name = 1; \
-       else \
-               state_usage->_name = 0; \
-       return size; \
-}
-
 #define define_show_state_ull_function(_name) \
 static ssize_t show_state_##_name(struct cpuidle_state *state, \
                                  struct cpuidle_state_usage *state_usage, \
 define_show_state_ull_function(time)
 define_show_state_str_function(name)
 define_show_state_str_function(desc)
-define_show_state_ull_function(disable)
-define_store_state_ull_function(disable)
 define_show_state_ull_function(above)
 define_show_state_ull_function(below)
 
+static ssize_t show_state_disable(struct cpuidle_state *state,
+                                 struct cpuidle_state_usage *state_usage,
+                                 char *buf)
+{
+       return sprintf(buf, "%llu\n",
+                      state_usage->disable & CPUIDLE_STATE_DISABLED_BY_USER);
+}
+
+static ssize_t store_state_disable(struct cpuidle_state *state,
+                                  struct cpuidle_state_usage *state_usage,
+                                  const char *buf, size_t size)
+{
+       unsigned int value;
+       int err;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       err = kstrtouint(buf, 0, &value);
+       if (err)
+               return err;
+
+       if (value)
+               state_usage->disable |= CPUIDLE_STATE_DISABLED_BY_USER;
+       else
+               state_usage->disable &= ~CPUIDLE_STATE_DISABLED_BY_USER;
+
+       return size;
+}
+
 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);
 
  * CPUIDLE DEVICE INTERFACE *
  ****************************/
 
+#define CPUIDLE_STATE_DISABLED_BY_USER         BIT(0)
+#define CPUIDLE_STATE_DISABLED_BY_DRIVER       BIT(1)
+
 struct cpuidle_state_usage {
        unsigned long long      disable;
        unsigned long long      usage;