aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2013-02-08 00:09:32 -0500
committerZhang Rui <rui.zhang@intel.com>2013-03-26 02:33:43 -0400
commitfc35b35cbe24ef021ea9acfba21e54da958df747 (patch)
tree9bac0a697808c5e7c830bd551808729093a743c8
parent3912a677f68f6084e0a7b6a1a29310ac1b083713 (diff)
Thermal: cpufreq cooling: fix parsing per_cpu cpufreq_frequency_table
cpufreq cooling uses different frequencies as different cooling states. But the per_cpu cpufreq_frequency_table may contain duplicate, invalid entries, and it may be in either ascending or descending order. And currently, code for parsing the per_cpu cpufreq_frequency_table is used in several places and inconsistent. Now introduce new code to 1. get the maximum cooling states 2. translate cooling state to cpu frequency 3. translate cpu frequency to cooling state in one place, with the correct logic of handling per_cpu cpufreq_frequency_table. Signed-off-by: Zhang Rui <rui.zhang@intel.com> Tested-by: Amit Daniel kachhap <amit.daniel@samsung.com>
-rw-r--r--drivers/thermal/cpu_cooling.c143
1 files changed, 93 insertions, 50 deletions
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 8dc44cbb3e09..9e208d300647 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -108,54 +108,109 @@ 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 }
148 167
149 /*Scan the table in reverse order and match the level*/ 168 if (property == GET_FREQ)
150 while (i >= 0) { 169 level = descend ? input : (max_level - input -1);
170
171
172 for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
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
199/**
200 * get_cpu_frequency - get the absolute value of frequency from level.
201 * @cpu: cpu for which frequency is fetched.
202 * @level: level of frequency, equals cooling state of cpu cooling device
203 * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
204 */
205static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
206{
207 int ret = 0;
208 unsigned int freq;
209
210 ret = get_property(cpu, level, &freq, GET_FREQ);
211 if (ret)
212 return 0;
213 return freq;
159} 214}
160 215
161/** 216/**
@@ -237,29 +292,17 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
237 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; 292 struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
238 struct cpumask *maskPtr = &cpufreq_device->allowed_cpus; 293 struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
239 unsigned int cpu; 294 unsigned int cpu;
240 struct cpufreq_frequency_table *table;
241 unsigned long count = 0; 295 unsigned long count = 0;
242 int i = 0; 296 int ret;
243 297
244 cpu = cpumask_any(maskPtr); 298 cpu = cpumask_any(maskPtr);
245 table = cpufreq_frequency_get_table(cpu);
246 if (!table) {
247 *state = 0;
248 return 0;
249 }
250 299
251 for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { 300 ret = get_property(cpu, 0, (unsigned int *)&count, GET_MAXL);
252 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
253 continue;
254 count++;
255 }
256 301
257 if (count > 0) { 302 if (count > 0)
258 *state = --count; 303 *state = count;
259 return 0;
260 }
261 304
262 return -EINVAL; 305 return ret;
263} 306}
264 307
265/** 308/**