Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.23-rc9 235 lines 6.3 kB view raw
1 2/* 3 * linux/drivers/cpufreq/cpufreq_userspace.c 4 * 5 * Copyright (C) 2001 Russell King 6 * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 */ 13 14#include <linux/kernel.h> 15#include <linux/module.h> 16#include <linux/smp.h> 17#include <linux/init.h> 18#include <linux/spinlock.h> 19#include <linux/interrupt.h> 20#include <linux/cpufreq.h> 21#include <linux/cpu.h> 22#include <linux/types.h> 23#include <linux/fs.h> 24#include <linux/sysfs.h> 25#include <linux/mutex.h> 26 27#include <asm/uaccess.h> 28 29 30/** 31 * A few values needed by the userspace governor 32 */ 33static unsigned int cpu_max_freq[NR_CPUS]; 34static unsigned int cpu_min_freq[NR_CPUS]; 35static unsigned int cpu_cur_freq[NR_CPUS]; /* current CPU freq */ 36static unsigned int cpu_set_freq[NR_CPUS]; /* CPU freq desired by userspace */ 37static unsigned int cpu_is_managed[NR_CPUS]; 38 39static DEFINE_MUTEX (userspace_mutex); 40static int cpus_using_userspace_governor; 41 42#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg) 43 44/* keep track of frequency transitions */ 45static int 46userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, 47 void *data) 48{ 49 struct cpufreq_freqs *freq = data; 50 51 if (!cpu_is_managed[freq->cpu]) 52 return 0; 53 54 dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n", 55 freq->cpu, freq->new); 56 cpu_cur_freq[freq->cpu] = freq->new; 57 58 return 0; 59} 60 61static struct notifier_block userspace_cpufreq_notifier_block = { 62 .notifier_call = userspace_cpufreq_notifier 63}; 64 65 66/** 67 * cpufreq_set - set the CPU frequency 68 * @freq: target frequency in kHz 69 * @cpu: CPU for which the frequency is to be set 70 * 71 * Sets the CPU frequency to freq. 72 */ 73static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy) 74{ 75 int ret = -EINVAL; 76 77 dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); 78 79 mutex_lock(&userspace_mutex); 80 if (!cpu_is_managed[policy->cpu]) 81 goto err; 82 83 cpu_set_freq[policy->cpu] = freq; 84 85 if (freq < cpu_min_freq[policy->cpu]) 86 freq = cpu_min_freq[policy->cpu]; 87 if (freq > cpu_max_freq[policy->cpu]) 88 freq = cpu_max_freq[policy->cpu]; 89 90 /* 91 * We're safe from concurrent calls to ->target() here 92 * as we hold the userspace_mutex lock. If we were calling 93 * cpufreq_driver_target, a deadlock situation might occur: 94 * A: cpufreq_set (lock userspace_mutex) -> cpufreq_driver_target(lock policy->lock) 95 * B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_mutex) 96 */ 97 ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 98 99 err: 100 mutex_unlock(&userspace_mutex); 101 return ret; 102} 103 104 105/************************** sysfs interface ************************/ 106static ssize_t show_speed (struct cpufreq_policy *policy, char *buf) 107{ 108 return sprintf (buf, "%u\n", cpu_cur_freq[policy->cpu]); 109} 110 111static ssize_t 112store_speed (struct cpufreq_policy *policy, const char *buf, size_t count) 113{ 114 unsigned int freq = 0; 115 unsigned int ret; 116 117 ret = sscanf (buf, "%u", &freq); 118 if (ret != 1) 119 return -EINVAL; 120 121 cpufreq_set(freq, policy); 122 123 return count; 124} 125 126static struct freq_attr freq_attr_scaling_setspeed = 127{ 128 .attr = { .name = "scaling_setspeed", .mode = 0644 }, 129 .show = show_speed, 130 .store = store_speed, 131}; 132 133static int cpufreq_governor_userspace(struct cpufreq_policy *policy, 134 unsigned int event) 135{ 136 unsigned int cpu = policy->cpu; 137 int rc = 0; 138 139 switch (event) { 140 case CPUFREQ_GOV_START: 141 if (!cpu_online(cpu)) 142 return -EINVAL; 143 BUG_ON(!policy->cur); 144 mutex_lock(&userspace_mutex); 145 rc = sysfs_create_file (&policy->kobj, 146 &freq_attr_scaling_setspeed.attr); 147 if (rc) 148 goto start_out; 149 150 if (cpus_using_userspace_governor == 0) { 151 cpufreq_register_notifier( 152 &userspace_cpufreq_notifier_block, 153 CPUFREQ_TRANSITION_NOTIFIER); 154 } 155 cpus_using_userspace_governor++; 156 157 cpu_is_managed[cpu] = 1; 158 cpu_min_freq[cpu] = policy->min; 159 cpu_max_freq[cpu] = policy->max; 160 cpu_cur_freq[cpu] = policy->cur; 161 cpu_set_freq[cpu] = policy->cur; 162 dprintk("managing cpu %u started (%u - %u kHz, currently %u kHz)\n", cpu, cpu_min_freq[cpu], cpu_max_freq[cpu], cpu_cur_freq[cpu]); 163start_out: 164 mutex_unlock(&userspace_mutex); 165 break; 166 case CPUFREQ_GOV_STOP: 167 mutex_lock(&userspace_mutex); 168 cpus_using_userspace_governor--; 169 if (cpus_using_userspace_governor == 0) { 170 cpufreq_unregister_notifier( 171 &userspace_cpufreq_notifier_block, 172 CPUFREQ_TRANSITION_NOTIFIER); 173 } 174 175 cpu_is_managed[cpu] = 0; 176 cpu_min_freq[cpu] = 0; 177 cpu_max_freq[cpu] = 0; 178 cpu_set_freq[cpu] = 0; 179 sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr); 180 dprintk("managing cpu %u stopped\n", cpu); 181 mutex_unlock(&userspace_mutex); 182 break; 183 case CPUFREQ_GOV_LIMITS: 184 mutex_lock(&userspace_mutex); 185 dprintk("limit event for cpu %u: %u - %u kHz," 186 "currently %u kHz, last set to %u kHz\n", 187 cpu, policy->min, policy->max, 188 cpu_cur_freq[cpu], cpu_set_freq[cpu]); 189 if (policy->max < cpu_set_freq[cpu]) { 190 __cpufreq_driver_target(policy, policy->max, 191 CPUFREQ_RELATION_H); 192 } 193 else if (policy->min > cpu_set_freq[cpu]) { 194 __cpufreq_driver_target(policy, policy->min, 195 CPUFREQ_RELATION_L); 196 } 197 else { 198 __cpufreq_driver_target(policy, cpu_set_freq[cpu], 199 CPUFREQ_RELATION_L); 200 } 201 cpu_min_freq[cpu] = policy->min; 202 cpu_max_freq[cpu] = policy->max; 203 cpu_cur_freq[cpu] = policy->cur; 204 mutex_unlock(&userspace_mutex); 205 break; 206 } 207 return rc; 208} 209 210 211struct cpufreq_governor cpufreq_gov_userspace = { 212 .name = "userspace", 213 .governor = cpufreq_governor_userspace, 214 .owner = THIS_MODULE, 215}; 216EXPORT_SYMBOL(cpufreq_gov_userspace); 217 218static int __init cpufreq_gov_userspace_init(void) 219{ 220 return cpufreq_register_governor(&cpufreq_gov_userspace); 221} 222 223 224static void __exit cpufreq_gov_userspace_exit(void) 225{ 226 cpufreq_unregister_governor(&cpufreq_gov_userspace); 227} 228 229 230MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>, Russell King <rmk@arm.linux.org.uk>"); 231MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'"); 232MODULE_LICENSE ("GPL"); 233 234fs_initcall(cpufreq_gov_userspace_init); 235module_exit(cpufreq_gov_userspace_exit);