diff options
author | Zhang Rui <rui.zhang@intel.com> | 2013-04-14 21:26:58 -0400 |
---|---|---|
committer | Zhang Rui <rui.zhang@intel.com> | 2013-04-14 21:26:58 -0400 |
commit | d13cb03aef0c062dcdd16b411bd4c02c1574ff08 (patch) | |
tree | 0ee1d535ddf0ca49cd88484f042d12996f689e1c /drivers/thermal/cpu_cooling.c | |
parent | 2fd1db8819fbf73b5f74b4b4a205ab7be0957944 (diff) | |
parent | bbf7fc88c78f7317e2cdcf77e974c8a9a8312641 (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.c | 154 |
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 | /** | 111 | enum 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 | |
117 | static 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 | */ | ||
128 | static 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 | |||
199 | unsigned 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 | |||
208 | EXPORT_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 | */ | ||
216 | static 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 | /** |