root/drivers/cpuidle/governors/ladder.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ladder_do_selection
  2. ladder_select_state
  3. ladder_enable_device
  4. ladder_reflect
  5. init_ladder

   1 /*
   2  * ladder.c - the residency ladder algorithm
   3  *
   4  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   5  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
   6  *  Copyright (C) 2004, 2005 Dominik Brodowski <linux@brodo.de>
   7  *
   8  * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
   9  *               Shaohua Li <shaohua.li@intel.com>
  10  *               Adam Belay <abelay@novell.com>
  11  *
  12  * This code is licenced under the GPL.
  13  */
  14 
  15 #include <linux/kernel.h>
  16 #include <linux/cpuidle.h>
  17 #include <linux/jiffies.h>
  18 #include <linux/tick.h>
  19 
  20 #include <asm/io.h>
  21 #include <linux/uaccess.h>
  22 
  23 #define PROMOTION_COUNT 4
  24 #define DEMOTION_COUNT 1
  25 
  26 struct ladder_device_state {
  27         struct {
  28                 u32 promotion_count;
  29                 u32 demotion_count;
  30                 u32 promotion_time;
  31                 u32 demotion_time;
  32         } threshold;
  33         struct {
  34                 int promotion_count;
  35                 int demotion_count;
  36         } stats;
  37 };
  38 
  39 struct ladder_device {
  40         struct ladder_device_state states[CPUIDLE_STATE_MAX];
  41 };
  42 
  43 static DEFINE_PER_CPU(struct ladder_device, ladder_devices);
  44 
  45 /**
  46  * ladder_do_selection - prepares private data for a state change
  47  * @ldev: the ladder device
  48  * @old_idx: the current state index
  49  * @new_idx: the new target state index
  50  */
  51 static inline void ladder_do_selection(struct cpuidle_device *dev,
  52                                        struct ladder_device *ldev,
  53                                        int old_idx, int new_idx)
  54 {
  55         ldev->states[old_idx].stats.promotion_count = 0;
  56         ldev->states[old_idx].stats.demotion_count = 0;
  57         dev->last_state_idx = new_idx;
  58 }
  59 
  60 /**
  61  * ladder_select_state - selects the next state to enter
  62  * @drv: cpuidle driver
  63  * @dev: the CPU
  64  * @dummy: not used
  65  */
  66 static int ladder_select_state(struct cpuidle_driver *drv,
  67                                struct cpuidle_device *dev, bool *dummy)
  68 {
  69         struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
  70         struct ladder_device_state *last_state;
  71         int last_residency, last_idx = dev->last_state_idx;
  72         int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0;
  73         int latency_req = cpuidle_governor_latency_req(dev->cpu);
  74 
  75         /* Special case when user has set very strict latency requirement */
  76         if (unlikely(latency_req == 0)) {
  77                 ladder_do_selection(dev, ldev, last_idx, 0);
  78                 return 0;
  79         }
  80 
  81         last_state = &ldev->states[last_idx];
  82 
  83         last_residency = dev->last_residency - drv->states[last_idx].exit_latency;
  84 
  85         /* consider promotion */
  86         if (last_idx < drv->state_count - 1 &&
  87             !drv->states[last_idx + 1].disabled &&
  88             !dev->states_usage[last_idx + 1].disable &&
  89             last_residency > last_state->threshold.promotion_time &&
  90             drv->states[last_idx + 1].exit_latency <= latency_req) {
  91                 last_state->stats.promotion_count++;
  92                 last_state->stats.demotion_count = 0;
  93                 if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
  94                         ladder_do_selection(dev, ldev, last_idx, last_idx + 1);
  95                         return last_idx + 1;
  96                 }
  97         }
  98 
  99         /* consider demotion */
 100         if (last_idx > first_idx &&
 101             (drv->states[last_idx].disabled ||
 102             dev->states_usage[last_idx].disable ||
 103             drv->states[last_idx].exit_latency > latency_req)) {
 104                 int i;
 105 
 106                 for (i = last_idx - 1; i > first_idx; i--) {
 107                         if (drv->states[i].exit_latency <= latency_req)
 108                                 break;
 109                 }
 110                 ladder_do_selection(dev, ldev, last_idx, i);
 111                 return i;
 112         }
 113 
 114         if (last_idx > first_idx &&
 115             last_residency < last_state->threshold.demotion_time) {
 116                 last_state->stats.demotion_count++;
 117                 last_state->stats.promotion_count = 0;
 118                 if (last_state->stats.demotion_count >= last_state->threshold.demotion_count) {
 119                         ladder_do_selection(dev, ldev, last_idx, last_idx - 1);
 120                         return last_idx - 1;
 121                 }
 122         }
 123 
 124         /* otherwise remain at the current state */
 125         return last_idx;
 126 }
 127 
 128 /**
 129  * ladder_enable_device - setup for the governor
 130  * @drv: cpuidle driver
 131  * @dev: the CPU
 132  */
 133 static int ladder_enable_device(struct cpuidle_driver *drv,
 134                                 struct cpuidle_device *dev)
 135 {
 136         int i;
 137         int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0;
 138         struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu);
 139         struct ladder_device_state *lstate;
 140         struct cpuidle_state *state;
 141 
 142         dev->last_state_idx = first_idx;
 143 
 144         for (i = first_idx; i < drv->state_count; i++) {
 145                 state = &drv->states[i];
 146                 lstate = &ldev->states[i];
 147 
 148                 lstate->stats.promotion_count = 0;
 149                 lstate->stats.demotion_count = 0;
 150 
 151                 lstate->threshold.promotion_count = PROMOTION_COUNT;
 152                 lstate->threshold.demotion_count = DEMOTION_COUNT;
 153 
 154                 if (i < drv->state_count - 1)
 155                         lstate->threshold.promotion_time = state->exit_latency;
 156                 if (i > first_idx)
 157                         lstate->threshold.demotion_time = state->exit_latency;
 158         }
 159 
 160         return 0;
 161 }
 162 
 163 /**
 164  * ladder_reflect - update the correct last_state_idx
 165  * @dev: the CPU
 166  * @index: the index of actual state entered
 167  */
 168 static void ladder_reflect(struct cpuidle_device *dev, int index)
 169 {
 170         if (index > 0)
 171                 dev->last_state_idx = index;
 172 }
 173 
 174 static struct cpuidle_governor ladder_governor = {
 175         .name =         "ladder",
 176         .rating =       10,
 177         .enable =       ladder_enable_device,
 178         .select =       ladder_select_state,
 179         .reflect =      ladder_reflect,
 180 };
 181 
 182 /**
 183  * init_ladder - initializes the governor
 184  */
 185 static int __init init_ladder(void)
 186 {
 187         /*
 188          * When NO_HZ is disabled, or when booting with nohz=off, the ladder
 189          * governor is better so give it a higher rating than the menu
 190          * governor.
 191          */
 192         if (!tick_nohz_enabled)
 193                 ladder_governor.rating = 25;
 194 
 195         return cpuidle_register_governor(&ladder_governor);
 196 }
 197 
 198 postcore_initcall(init_ladder);

/* [<][>][^][v][top][bottom][index][help] */