debuggers.hg

view xen/drivers/cpufreq/utility.c @ 20954:a06e9def02bb

xenpm: Allow user to enable/disable dbs governor turbo mode.

Signed-off-by: Lu Guanqun <guanqun.lu@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 08 08:48:40 2010 +0000 (2010-02-08)
parents 532e25fda238
children 7b63f677f245
line source
1 /*
2 * utility.c - misc functions for cpufreq driver and Px statistic
3 *
4 * Copyright (C) 2001 Russell King
5 * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
6 *
7 * Oct 2005 - Ashok Raj <ashok.raj@intel.com>
8 * Added handling for CPU hotplug
9 * Feb 2006 - Jacob Shin <jacob.shin@amd.com>
10 * Fix handling for CPU hotplug -- affected CPUs
11 * Feb 2008 - Liu Jinsong <jinsong.liu@intel.com>
12 * 1. Merge cpufreq.c and freq_table.c of linux 2.6.23
13 * And poring to Xen hypervisor
14 * 2. some Px statistic interface funcdtions
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 *
20 */
22 #include <xen/errno.h>
23 #include <xen/cpumask.h>
24 #include <xen/types.h>
25 #include <xen/spinlock.h>
26 #include <xen/percpu.h>
27 #include <xen/types.h>
28 #include <xen/sched.h>
29 #include <xen/timer.h>
30 #include <xen/trace.h>
31 #include <asm/config.h>
32 #include <acpi/cpufreq/cpufreq.h>
33 #include <public/sysctl.h>
35 struct cpufreq_driver *cpufreq_driver;
36 struct processor_pminfo *__read_mostly processor_pminfo[NR_CPUS];
37 struct cpufreq_policy *__read_mostly cpufreq_cpu_policy[NR_CPUS];
39 DEFINE_PER_CPU(spinlock_t, cpufreq_statistic_lock) = SPIN_LOCK_UNLOCKED;
41 /*********************************************************************
42 * Px STATISTIC INFO *
43 *********************************************************************/
45 void cpufreq_residency_update(unsigned int cpu, uint8_t state)
46 {
47 uint64_t now, total_idle_ns;
48 int64_t delta;
49 struct pm_px *pxpt = cpufreq_statistic_data[cpu];
51 total_idle_ns = get_cpu_idle_time(cpu);
52 now = NOW();
54 delta = (now - pxpt->prev_state_wall) -
55 (total_idle_ns - pxpt->prev_idle_wall);
57 if ( likely(delta >= 0) )
58 pxpt->u.pt[state].residency += delta;
60 pxpt->prev_state_wall = now;
61 pxpt->prev_idle_wall = total_idle_ns;
62 }
64 void cpufreq_statistic_update(unsigned int cpu, uint8_t from, uint8_t to)
65 {
66 struct pm_px *pxpt = cpufreq_statistic_data[cpu];
67 struct processor_pminfo *pmpt = processor_pminfo[cpu];
68 spinlock_t *cpufreq_statistic_lock =
69 &per_cpu(cpufreq_statistic_lock, cpu);
71 spin_lock(cpufreq_statistic_lock);
73 if ( !pxpt || !pmpt ) {
74 spin_unlock(cpufreq_statistic_lock);
75 return;
76 }
78 pxpt->u.last = from;
79 pxpt->u.cur = to;
80 pxpt->u.pt[to].count++;
82 cpufreq_residency_update(cpu, from);
84 (*(pxpt->u.trans_pt + from * pmpt->perf.state_count + to))++;
86 spin_unlock(cpufreq_statistic_lock);
87 }
89 int cpufreq_statistic_init(unsigned int cpuid)
90 {
91 uint32_t i, count;
92 struct pm_px *pxpt = cpufreq_statistic_data[cpuid];
93 const struct processor_pminfo *pmpt = processor_pminfo[cpuid];
94 spinlock_t *cpufreq_statistic_lock =
95 &per_cpu(cpufreq_statistic_lock, cpuid);
97 if ( !pmpt )
98 return -EINVAL;
100 spin_lock(cpufreq_statistic_lock);
102 if ( pxpt ) {
103 spin_unlock(cpufreq_statistic_lock);
104 return 0;
105 }
107 count = pmpt->perf.state_count;
109 pxpt = xmalloc(struct pm_px);
110 if ( !pxpt ) {
111 spin_unlock(cpufreq_statistic_lock);
112 return -ENOMEM;
113 }
114 memset(pxpt, 0, sizeof(*pxpt));
115 cpufreq_statistic_data[cpuid] = pxpt;
117 pxpt->u.trans_pt = xmalloc_array(uint64_t, count * count);
118 if (!pxpt->u.trans_pt) {
119 xfree(pxpt);
120 spin_unlock(cpufreq_statistic_lock);
121 return -ENOMEM;
122 }
124 pxpt->u.pt = xmalloc_array(struct pm_px_val, count);
125 if (!pxpt->u.pt) {
126 xfree(pxpt->u.trans_pt);
127 xfree(pxpt);
128 spin_unlock(cpufreq_statistic_lock);
129 return -ENOMEM;
130 }
132 memset(pxpt->u.trans_pt, 0, count * count * (sizeof(uint64_t)));
133 memset(pxpt->u.pt, 0, count * (sizeof(struct pm_px_val)));
135 pxpt->u.total = pmpt->perf.state_count;
136 pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.platform_limit;
138 for (i=0; i < pmpt->perf.state_count; i++)
139 pxpt->u.pt[i].freq = pmpt->perf.states[i].core_frequency;
141 pxpt->prev_state_wall = NOW();
142 pxpt->prev_idle_wall = get_cpu_idle_time(cpuid);
144 spin_unlock(cpufreq_statistic_lock);
146 return 0;
147 }
149 void cpufreq_statistic_exit(unsigned int cpuid)
150 {
151 struct pm_px *pxpt = cpufreq_statistic_data[cpuid];
152 spinlock_t *cpufreq_statistic_lock =
153 &per_cpu(cpufreq_statistic_lock, cpuid);
155 spin_lock(cpufreq_statistic_lock);
157 if (!pxpt) {
158 spin_unlock(cpufreq_statistic_lock);
159 return;
160 }
162 xfree(pxpt->u.trans_pt);
163 xfree(pxpt->u.pt);
164 xfree(pxpt);
165 cpufreq_statistic_data[cpuid] = NULL;
167 spin_unlock(cpufreq_statistic_lock);
168 }
170 void cpufreq_statistic_reset(unsigned int cpuid)
171 {
172 uint32_t i, j, count;
173 struct pm_px *pxpt = cpufreq_statistic_data[cpuid];
174 const struct processor_pminfo *pmpt = processor_pminfo[cpuid];
175 spinlock_t *cpufreq_statistic_lock =
176 &per_cpu(cpufreq_statistic_lock, cpuid);
178 spin_lock(cpufreq_statistic_lock);
180 if ( !pmpt || !pxpt || !pxpt->u.pt || !pxpt->u.trans_pt ) {
181 spin_unlock(cpufreq_statistic_lock);
182 return;
183 }
185 count = pmpt->perf.state_count;
187 for (i=0; i < count; i++) {
188 pxpt->u.pt[i].residency = 0;
189 pxpt->u.pt[i].count = 0;
191 for (j=0; j < count; j++)
192 *(pxpt->u.trans_pt + i*count + j) = 0;
193 }
195 pxpt->prev_state_wall = NOW();
196 pxpt->prev_idle_wall = get_cpu_idle_time(cpuid);
198 spin_unlock(cpufreq_statistic_lock);
199 }
202 /*********************************************************************
203 * FREQUENCY TABLE HELPERS *
204 *********************************************************************/
206 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
207 struct cpufreq_frequency_table *table)
208 {
209 unsigned int min_freq = ~0;
210 unsigned int max_freq = 0;
211 unsigned int second_max_freq = 0;
212 unsigned int i;
214 for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
215 unsigned int freq = table[i].frequency;
216 if (freq == CPUFREQ_ENTRY_INVALID)
217 continue;
218 if (freq < min_freq)
219 min_freq = freq;
220 if (freq > max_freq)
221 max_freq = freq;
222 }
223 for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
224 unsigned int freq = table[i].frequency;
225 if (freq == CPUFREQ_ENTRY_INVALID || freq == max_freq)
226 continue;
227 if (freq > second_max_freq)
228 second_max_freq = freq;
229 }
230 if (second_max_freq == 0)
231 second_max_freq = max_freq;
232 printk(XENLOG_INFO "max_freq: %u second_max_freq: %u\n",
233 max_freq, second_max_freq);
235 policy->min = policy->cpuinfo.min_freq = min_freq;
236 policy->max = policy->cpuinfo.max_freq = max_freq;
237 policy->cpuinfo.second_max_freq = second_max_freq;
239 if (policy->min == ~0)
240 return -EINVAL;
241 else
242 return 0;
243 }
245 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
246 struct cpufreq_frequency_table *table)
247 {
248 unsigned int next_larger = ~0;
249 unsigned int i;
250 unsigned int count = 0;
252 if (!cpu_online(policy->cpu))
253 return -EINVAL;
255 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
256 policy->cpuinfo.max_freq);
258 for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
259 unsigned int freq = table[i].frequency;
260 if (freq == CPUFREQ_ENTRY_INVALID)
261 continue;
262 if ((freq >= policy->min) && (freq <= policy->max))
263 count++;
264 else if ((next_larger > freq) && (freq > policy->max))
265 next_larger = freq;
266 }
268 if (!count)
269 policy->max = next_larger;
271 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
272 policy->cpuinfo.max_freq);
274 return 0;
275 }
277 int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
278 struct cpufreq_frequency_table *table,
279 unsigned int target_freq,
280 unsigned int relation,
281 unsigned int *index)
282 {
283 struct cpufreq_frequency_table optimal = {
284 .index = ~0,
285 .frequency = 0,
286 };
287 struct cpufreq_frequency_table suboptimal = {
288 .index = ~0,
289 .frequency = 0,
290 };
291 unsigned int i;
293 switch (relation) {
294 case CPUFREQ_RELATION_H:
295 suboptimal.frequency = ~0;
296 break;
297 case CPUFREQ_RELATION_L:
298 optimal.frequency = ~0;
299 break;
300 }
302 if (!cpu_online(policy->cpu))
303 return -EINVAL;
305 for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
306 unsigned int freq = table[i].frequency;
307 if (freq == CPUFREQ_ENTRY_INVALID)
308 continue;
309 if ((freq < policy->min) || (freq > policy->max))
310 continue;
311 switch(relation) {
312 case CPUFREQ_RELATION_H:
313 if (freq <= target_freq) {
314 if (freq >= optimal.frequency) {
315 optimal.frequency = freq;
316 optimal.index = i;
317 }
318 } else {
319 if (freq <= suboptimal.frequency) {
320 suboptimal.frequency = freq;
321 suboptimal.index = i;
322 }
323 }
324 break;
325 case CPUFREQ_RELATION_L:
326 if (freq >= target_freq) {
327 if (freq <= optimal.frequency) {
328 optimal.frequency = freq;
329 optimal.index = i;
330 }
331 } else {
332 if (freq >= suboptimal.frequency) {
333 suboptimal.frequency = freq;
334 suboptimal.index = i;
335 }
336 }
337 break;
338 }
339 }
340 if (optimal.index > i) {
341 if (suboptimal.index > i)
342 return -EINVAL;
343 *index = suboptimal.index;
344 } else
345 *index = optimal.index;
347 return 0;
348 }
351 /*********************************************************************
352 * GOVERNORS *
353 *********************************************************************/
355 int __cpufreq_driver_target(struct cpufreq_policy *policy,
356 unsigned int target_freq,
357 unsigned int relation)
358 {
359 int retval = -EINVAL;
361 if (cpu_online(policy->cpu) && cpufreq_driver->target)
362 {
363 unsigned int prev_freq = policy->cur;
365 retval = cpufreq_driver->target(policy, target_freq, relation);
366 if ( retval == 0 )
367 TRACE_2D(TRC_PM_FREQ_CHANGE, prev_freq/1000, policy->cur/1000);
368 }
370 return retval;
371 }
373 int cpufreq_driver_getavg(unsigned int cpu, unsigned int flag)
374 {
375 struct cpufreq_policy *policy;
376 int freq_avg;
378 policy = cpufreq_cpu_policy[cpu];
379 if (!cpu_online(cpu) || !policy)
380 return 0;
382 if (cpufreq_driver->getavg)
383 {
384 freq_avg = cpufreq_driver->getavg(cpu, flag);
385 if (freq_avg > 0)
386 return freq_avg;
387 }
389 return policy->cur;
390 }
393 /*********************************************************************
394 * POLICY *
395 *********************************************************************/
397 /*
398 * data : current policy.
399 * policy : policy to be set.
400 */
401 int __cpufreq_set_policy(struct cpufreq_policy *data,
402 struct cpufreq_policy *policy)
403 {
404 int ret = 0;
406 memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo));
408 if (policy->min > data->min && policy->min > policy->max)
409 return -EINVAL;
411 /* verify the cpu speed can be set within this limit */
412 ret = cpufreq_driver->verify(policy);
413 if (ret)
414 return ret;
416 data->min = policy->min;
417 data->max = policy->max;
419 if (policy->governor != data->governor) {
420 /* save old, working values */
421 struct cpufreq_governor *old_gov = data->governor;
423 /* end old governor */
424 if (data->governor)
425 __cpufreq_governor(data, CPUFREQ_GOV_STOP);
427 /* start new governor */
428 data->governor = policy->governor;
429 if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
430 printk(KERN_WARNING "Fail change to %s governor\n",
431 data->governor->name);
433 /* new governor failed, so re-start old one */
434 if (old_gov) {
435 data->governor = old_gov;
436 __cpufreq_governor(data, CPUFREQ_GOV_START);
437 printk(KERN_WARNING "Still stay at %s governor\n",
438 data->governor->name);
439 }
440 return -EINVAL;
441 }
442 /* might be a policy change, too, so fall through */
443 }
445 return __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
446 }