aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal/cpu_cooling.c
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2013-04-14 21:26:58 -0400
committerZhang Rui <rui.zhang@intel.com>2013-04-14 21:26:58 -0400
commitd13cb03aef0c062dcdd16b411bd4c02c1574ff08 (patch)
tree0ee1d535ddf0ca49cd88484f042d12996f689e1c /drivers/thermal/cpu_cooling.c
parent2fd1db8819fbf73b5f74b4b4a205ab7be0957944 (diff)
parentbbf7fc88c78f7317e2cdcf77e974c8a9a8312641 (diff)
Merge branch 'thermal' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux into next
Conflicts: drivers/thermal/cpu_cooling.c
Diffstat (limited to 'drivers/thermal/cpu_cooling.c')
-rw-r--r--drivers/thermal/cpu_cooling.c154
1 files changed, 104 insertions, 50 deletions
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index be2e6b0e5349..5f5c780bcd90 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -108,54 +108,120 @@ static int is_cpufreq_valid(int cpu)
108 return !cpufreq_get_policy(&policy, cpu); 108 return !cpufreq_get_policy(&policy, cpu);
109} 109}
110 110
111/** 111enum cpufreq_cooling_property {
112 * get_cpu_frequency - get the absolute value of frequency from level. 112 GET_LEVEL,
113 * @cpu: cpu for which frequency is fetched. 113 GET_FREQ,
114 * @level: level of frequency, equals cooling state of cpu cooling device 114 GET_MAXL,
115 * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc 115};
116 */ 116
117static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) 117/*
118 * this is the common function to
119 * 1. get maximum cpu cooling states
120 * 2. translate frequency to cooling state
121 * 3. translate cooling state to frequency
122 * Note that the code may be not in good shape
123 * but it is written in this way in order to:
124 * a) reduce duplicate code as most of the code can be shared.
125 * b) make sure the logic is consistent when translating between
126 * cooling states and frequencies.
127*/
128static int get_property(unsigned int cpu, unsigned long input,
129 unsigned int* output, enum cpufreq_cooling_property property)
118{ 130{
119 int ret = 0, i = 0; 131 int i, j;
120 unsigned long level_index; 132 unsigned long max_level = 0, level;
121 bool descend = false; 133 unsigned int freq = CPUFREQ_ENTRY_INVALID;
134 int descend = -1;
122 struct cpufreq_frequency_table *table = 135 struct cpufreq_frequency_table *table =
123 cpufreq_frequency_get_table(cpu); 136 cpufreq_frequency_get_table(cpu);
137
138 if (!output)
139 return -EINVAL;
140
124 if (!table) 141 if (!table)
125 return ret; 142 return -EINVAL;
126 143
127 while (table[i].frequency != CPUFREQ_TABLE_END) { 144
145 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
146 /* ignore invalid entries */
128 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 147 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
129 continue; 148 continue;
130 149
131 /*check if table in ascending or descending order*/ 150 /* ignore duplicate entry */
132 if ((table[i + 1].frequency != CPUFREQ_TABLE_END) && 151 if (freq == table[i].frequency)
133 (table[i + 1].frequency < table[i].frequency) 152 continue;
134 && !descend) { 153
135 descend = true; 154 /* get the frequency order */
136 } 155 if (freq != CPUFREQ_ENTRY_INVALID && descend != -1)
156 descend = !!(freq > table[i].frequency);
137 157
138 /*return if level matched and table in descending order*/ 158 freq = table[i].frequency;
139 if (descend && i == level) 159 max_level++;
140 return table[i].frequency;
141 i++;
142 } 160 }
143 i--;
144 161
145 if (level > i || descend) 162 /* get max level */
146 return ret; 163 if (property == GET_MAXL) {
147 level_index = i - level; 164 *output = (unsigned int)max_level;
165 return 0;
166 }
167
168 if (property == GET_FREQ)
169 level = descend ? input : (max_level - input -1);
170
148 171
149 /*Scan the table in reverse order and match the level*/ 172 for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
150 while (i >= 0) { 173 /* ignore invalid entry */
151 if (table[i].frequency == CPUFREQ_ENTRY_INVALID) 174 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
152 continue; 175 continue;
153 /*return if level matched*/ 176
154 if (i == level_index) 177 /* ignore duplicate entry */
155 return table[i].frequency; 178 if (freq == table[i].frequency)
156 i--; 179 continue;
180
181 /* now we have a valid frequency entry */
182 freq = table[i].frequency;
183
184 if (property == GET_LEVEL && (unsigned int)input == freq) {
185 /* get level by frequency */
186 *output = descend ? j : (max_level - j - 1);
187 return 0;
188 }
189 if (property == GET_FREQ && level == j) {
190 /* get frequency by level */
191 *output = freq;
192 return 0;
193 }
194 j++;
157 } 195 }
158 return ret; 196 return -EINVAL;
197}
198
199unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
200{
201 unsigned int val;
202
203 if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL))
204 return THERMAL_CSTATE_INVALID;
205 return (unsigned long)val;
206}
207
208EXPORT_SYMBOL(cpufreq_cooling_get_level);
209
210/**
211 * get_cpu_frequency - get the absolute value of frequency from level.
212 * @cpu: cpu for which frequency is fetched.
213 * @level: level of frequency, equals cooling state of cpu cooling device
214 * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
215 */
216static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
217{
218 int ret = 0;
219 unsigned int freq;
220
221 ret = get_property(cpu, level, &freq, GET_FREQ);
222 if (ret)
223 return 0;
224 return freq;
159} 225}
160 226
161/** 227/**
@@ -237,29 +303,17 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
237 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; 303 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
238 struct cpumask *mask = &cpufreq_device->allowed_cpus; 304 struct cpumask *mask = &cpufreq_device->allowed_cpus;
239 unsigned int cpu; 305 unsigned int cpu;
240 struct cpufreq_frequency_table *table;
241 unsigned long count = 0; 306 unsigned long count = 0;
242 int i = 0; 307 int ret;
243 308
244 cpu = cpumask_any(mask); 309 cpu = cpumask_any(mask);
245 table = cpufreq_frequency_get_table(cpu);
246 if (!table) {
247 *state = 0;
248 return 0;
249 }
250 310
251 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 311 ret = get_property(cpu, 0, (unsigned int *)&count, GET_MAXL);
252 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
253 continue;
254 count++;
255 }
256 312
257 if (count > 0) { 313 if (count > 0)
258 *state = --count; 314 *state = count;
259 return 0;
260 }
261 315
262 return -EINVAL; 316 return ret;
263} 317}
264 318
265/** 319/**