Blame view

drivers/cpuidle/governors/ladder.c 5.04 KB
4f86d3a8e   Len Brown   cpuidle: consolid...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   * ladder.c - the residency ladder algorithm
   *
   *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
   *  Copyright (C) 2004, 2005 Dominik Brodowski <linux@brodo.de>
   *
   * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
   *               Shaohua Li <shaohua.li@intel.com>
   *               Adam Belay <abelay@novell.com>
   *
   * This code is licenced under the GPL.
   */
  
  #include <linux/kernel.h>
  #include <linux/cpuidle.h>
e8db0be12   Jean Pihet   PM QoS: Move and ...
17
  #include <linux/pm_qos.h>
70e522a02   Paul Gortmaker   cpuidle: ladder.c...
18
  #include <linux/module.h>
4f86d3a8e   Len Brown   cpuidle: consolid...
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  #include <linux/jiffies.h>
  
  #include <asm/io.h>
  #include <asm/uaccess.h>
  
  #define PROMOTION_COUNT 4
  #define DEMOTION_COUNT 1
  
  struct ladder_device_state {
  	struct {
  		u32 promotion_count;
  		u32 demotion_count;
  		u32 promotion_time;
  		u32 demotion_time;
  	} threshold;
  	struct {
  		int promotion_count;
  		int demotion_count;
  	} stats;
  };
  
  struct ladder_device {
  	struct ladder_device_state states[CPUIDLE_STATE_MAX];
  	int last_state_idx;
  };
  
  static DEFINE_PER_CPU(struct ladder_device, ladder_devices);
  
  /**
   * ladder_do_selection - prepares private data for a state change
   * @ldev: the ladder device
   * @old_idx: the current state index
   * @new_idx: the new target state index
   */
  static inline void ladder_do_selection(struct ladder_device *ldev,
  				       int old_idx, int new_idx)
  {
  	ldev->states[old_idx].stats.promotion_count = 0;
  	ldev->states[old_idx].stats.demotion_count = 0;
  	ldev->last_state_idx = new_idx;
  }
  
  /**
   * ladder_select_state - selects the next state to enter
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
63
   * @drv: cpuidle driver
4f86d3a8e   Len Brown   cpuidle: consolid...
64
65
   * @dev: the CPU
   */
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
66
67
  static int ladder_select_state(struct cpuidle_driver *drv,
  				struct cpuidle_device *dev)
4f86d3a8e   Len Brown   cpuidle: consolid...
68
  {
229b6863b   Christoph Lameter   drivers/cpuidle: ...
69
  	struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
4f86d3a8e   Len Brown   cpuidle: consolid...
70
71
  	struct ladder_device_state *last_state;
  	int last_residency, last_idx = ldev->last_state_idx;
ed77134bf   Mark Gross   PM QOS update
72
  	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
4f86d3a8e   Len Brown   cpuidle: consolid...
73

a2bd92023   venkatesh.pallipadi@intel.com   cpuidle: Do not u...
74
75
76
77
78
  	/* Special case when user has set very strict latency requirement */
  	if (unlikely(latency_req == 0)) {
  		ladder_do_selection(ldev, last_idx, 0);
  		return 0;
  	}
4f86d3a8e   Len Brown   cpuidle: consolid...
79
  	last_state = &ldev->states[last_idx];
b73026b9c   Len Brown   cpuidle: ladder: ...
80
  	last_residency = cpuidle_get_last_residency(dev) - drv->states[last_idx].exit_latency;
4f86d3a8e   Len Brown   cpuidle: consolid...
81
82
  
  	/* consider promotion */
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
83
  	if (last_idx < drv->state_count - 1 &&
66804c13f   Rafael J. Wysocki   PM / cpuidle: Mak...
84
  	    !drv->states[last_idx + 1].disabled &&
62d6ae880   Carsten Emde   Honor state disab...
85
  	    !dev->states_usage[last_idx + 1].disable &&
4f86d3a8e   Len Brown   cpuidle: consolid...
86
  	    last_residency > last_state->threshold.promotion_time &&
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
87
  	    drv->states[last_idx + 1].exit_latency <= latency_req) {
4f86d3a8e   Len Brown   cpuidle: consolid...
88
89
90
91
92
93
94
95
96
  		last_state->stats.promotion_count++;
  		last_state->stats.demotion_count = 0;
  		if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
  			ladder_do_selection(ldev, last_idx, last_idx + 1);
  			return last_idx + 1;
  		}
  	}
  
  	/* consider demotion */
a2bd92023   venkatesh.pallipadi@intel.com   cpuidle: Do not u...
97
  	if (last_idx > CPUIDLE_DRIVER_STATE_START &&
66804c13f   Rafael J. Wysocki   PM / cpuidle: Mak...
98
99
  	    (drv->states[last_idx].disabled ||
  	    dev->states_usage[last_idx].disable ||
62d6ae880   Carsten Emde   Honor state disab...
100
  	    drv->states[last_idx].exit_latency > latency_req)) {
06d9e908b   venkatesh.pallipadi@intel.com   cpuidle: Make lad...
101
102
103
  		int i;
  
  		for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) {
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
104
  			if (drv->states[i].exit_latency <= latency_req)
06d9e908b   venkatesh.pallipadi@intel.com   cpuidle: Make lad...
105
106
107
108
109
110
111
  				break;
  		}
  		ladder_do_selection(ldev, last_idx, i);
  		return i;
  	}
  
  	if (last_idx > CPUIDLE_DRIVER_STATE_START &&
4f86d3a8e   Len Brown   cpuidle: consolid...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  	    last_residency < last_state->threshold.demotion_time) {
  		last_state->stats.demotion_count++;
  		last_state->stats.promotion_count = 0;
  		if (last_state->stats.demotion_count >= last_state->threshold.demotion_count) {
  			ladder_do_selection(ldev, last_idx, last_idx - 1);
  			return last_idx - 1;
  		}
  	}
  
  	/* otherwise remain at the current state */
  	return last_idx;
  }
  
  /**
   * ladder_enable_device - setup for the governor
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
127
   * @drv: cpuidle driver
4f86d3a8e   Len Brown   cpuidle: consolid...
128
129
   * @dev: the CPU
   */
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
130
131
  static int ladder_enable_device(struct cpuidle_driver *drv,
  				struct cpuidle_device *dev)
4f86d3a8e   Len Brown   cpuidle: consolid...
132
133
134
135
136
  {
  	int i;
  	struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu);
  	struct ladder_device_state *lstate;
  	struct cpuidle_state *state;
a2bd92023   venkatesh.pallipadi@intel.com   cpuidle: Do not u...
137
  	ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START;
4f86d3a8e   Len Brown   cpuidle: consolid...
138

146924461   Mohammad Merajul Islam Molla   cpuidle: ladder g...
139
  	for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
140
  		state = &drv->states[i];
4f86d3a8e   Len Brown   cpuidle: consolid...
141
142
143
144
145
146
147
  		lstate = &ldev->states[i];
  
  		lstate->stats.promotion_count = 0;
  		lstate->stats.demotion_count = 0;
  
  		lstate->threshold.promotion_count = PROMOTION_COUNT;
  		lstate->threshold.demotion_count = DEMOTION_COUNT;
46bcfad7a   Deepthi Dharwar   cpuidle: Single/G...
148
  		if (i < drv->state_count - 1)
4f86d3a8e   Len Brown   cpuidle: consolid...
149
  			lstate->threshold.promotion_time = state->exit_latency;
146924461   Mohammad Merajul Islam Molla   cpuidle: ladder g...
150
  		if (i > CPUIDLE_DRIVER_STATE_START)
4f86d3a8e   Len Brown   cpuidle: consolid...
151
152
153
154
155
  			lstate->threshold.demotion_time = state->exit_latency;
  	}
  
  	return 0;
  }
e978aa7d7   Deepthi Dharwar   cpuidle: Move dev...
156
157
158
159
160
161
162
  /**
   * ladder_reflect - update the correct last_state_idx
   * @dev: the CPU
   * @index: the index of actual state entered
   */
  static void ladder_reflect(struct cpuidle_device *dev, int index)
  {
229b6863b   Christoph Lameter   drivers/cpuidle: ...
163
  	struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
e978aa7d7   Deepthi Dharwar   cpuidle: Move dev...
164
165
166
  	if (index > 0)
  		ldev->last_state_idx = index;
  }
4f86d3a8e   Len Brown   cpuidle: consolid...
167
168
169
170
171
  static struct cpuidle_governor ladder_governor = {
  	.name =		"ladder",
  	.rating =	10,
  	.enable =	ladder_enable_device,
  	.select =	ladder_select_state,
e978aa7d7   Deepthi Dharwar   cpuidle: Move dev...
172
  	.reflect =	ladder_reflect,
4f86d3a8e   Len Brown   cpuidle: consolid...
173
174
175
176
177
178
179
180
181
182
  	.owner =	THIS_MODULE,
  };
  
  /**
   * init_ladder - initializes the governor
   */
  static int __init init_ladder(void)
  {
  	return cpuidle_register_governor(&ladder_governor);
  }
137b944e1   Daniel Lezcano   cpuidle: Make it ...
183
  postcore_initcall(init_ladder);