diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq_userspace.c')
-rw-r--r-- | drivers/cpufreq/cpufreq_userspace.c | 78 |
1 files changed, 41 insertions, 37 deletions
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index d32bf3593cd3..92a0be22a2a9 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c | |||
@@ -1,3 +1,4 @@ | |||
1 | |||
1 | /* | 2 | /* |
2 | * linux/drivers/cpufreq/cpufreq_userspace.c | 3 | * linux/drivers/cpufreq/cpufreq_userspace.c |
3 | * | 4 | * |
@@ -21,6 +22,7 @@ | |||
21 | #include <linux/types.h> | 22 | #include <linux/types.h> |
22 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
23 | #include <linux/sysfs.h> | 24 | #include <linux/sysfs.h> |
25 | #include <linux/mutex.h> | ||
24 | 26 | ||
25 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
26 | 28 | ||
@@ -33,9 +35,8 @@ static unsigned int cpu_min_freq[NR_CPUS]; | |||
33 | static unsigned int cpu_cur_freq[NR_CPUS]; /* current CPU freq */ | 35 | static unsigned int cpu_cur_freq[NR_CPUS]; /* current CPU freq */ |
34 | static unsigned int cpu_set_freq[NR_CPUS]; /* CPU freq desired by userspace */ | 36 | static unsigned int cpu_set_freq[NR_CPUS]; /* CPU freq desired by userspace */ |
35 | static unsigned int cpu_is_managed[NR_CPUS]; | 37 | static unsigned int cpu_is_managed[NR_CPUS]; |
36 | static struct cpufreq_policy current_policy[NR_CPUS]; | ||
37 | 38 | ||
38 | static DECLARE_MUTEX (userspace_sem); | 39 | static DEFINE_MUTEX (userspace_mutex); |
39 | 40 | ||
40 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg) | 41 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg) |
41 | 42 | ||
@@ -64,35 +65,34 @@ static struct notifier_block userspace_cpufreq_notifier_block = { | |||
64 | * | 65 | * |
65 | * Sets the CPU frequency to freq. | 66 | * Sets the CPU frequency to freq. |
66 | */ | 67 | */ |
67 | static int cpufreq_set(unsigned int freq, unsigned int cpu) | 68 | static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy) |
68 | { | 69 | { |
69 | int ret = -EINVAL; | 70 | int ret = -EINVAL; |
70 | 71 | ||
71 | dprintk("cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq); | 72 | dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); |
72 | 73 | ||
73 | down(&userspace_sem); | 74 | mutex_lock(&userspace_mutex); |
74 | if (!cpu_is_managed[cpu]) | 75 | if (!cpu_is_managed[policy->cpu]) |
75 | goto err; | 76 | goto err; |
76 | 77 | ||
77 | cpu_set_freq[cpu] = freq; | 78 | cpu_set_freq[policy->cpu] = freq; |
78 | 79 | ||
79 | if (freq < cpu_min_freq[cpu]) | 80 | if (freq < cpu_min_freq[policy->cpu]) |
80 | freq = cpu_min_freq[cpu]; | 81 | freq = cpu_min_freq[policy->cpu]; |
81 | if (freq > cpu_max_freq[cpu]) | 82 | if (freq > cpu_max_freq[policy->cpu]) |
82 | freq = cpu_max_freq[cpu]; | 83 | freq = cpu_max_freq[policy->cpu]; |
83 | 84 | ||
84 | /* | 85 | /* |
85 | * We're safe from concurrent calls to ->target() here | 86 | * We're safe from concurrent calls to ->target() here |
86 | * as we hold the userspace_sem lock. If we were calling | 87 | * as we hold the userspace_mutex lock. If we were calling |
87 | * cpufreq_driver_target, a deadlock situation might occur: | 88 | * cpufreq_driver_target, a deadlock situation might occur: |
88 | * A: cpufreq_set (lock userspace_sem) -> cpufreq_driver_target(lock policy->lock) | 89 | * A: cpufreq_set (lock userspace_mutex) -> cpufreq_driver_target(lock policy->lock) |
89 | * B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_sem) | 90 | * B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_mutex) |
90 | */ | 91 | */ |
91 | ret = __cpufreq_driver_target(¤t_policy[cpu], freq, | 92 | ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); |
92 | CPUFREQ_RELATION_L); | ||
93 | 93 | ||
94 | err: | 94 | err: |
95 | up(&userspace_sem); | 95 | mutex_unlock(&userspace_mutex); |
96 | return ret; | 96 | return ret; |
97 | } | 97 | } |
98 | 98 | ||
@@ -113,7 +113,7 @@ store_speed (struct cpufreq_policy *policy, const char *buf, size_t count) | |||
113 | if (ret != 1) | 113 | if (ret != 1) |
114 | return -EINVAL; | 114 | return -EINVAL; |
115 | 115 | ||
116 | cpufreq_set(freq, policy->cpu); | 116 | cpufreq_set(freq, policy); |
117 | 117 | ||
118 | return count; | 118 | return count; |
119 | } | 119 | } |
@@ -134,44 +134,48 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy, | |||
134 | if (!cpu_online(cpu)) | 134 | if (!cpu_online(cpu)) |
135 | return -EINVAL; | 135 | return -EINVAL; |
136 | BUG_ON(!policy->cur); | 136 | BUG_ON(!policy->cur); |
137 | down(&userspace_sem); | 137 | mutex_lock(&userspace_mutex); |
138 | cpu_is_managed[cpu] = 1; | 138 | cpu_is_managed[cpu] = 1; |
139 | cpu_min_freq[cpu] = policy->min; | 139 | cpu_min_freq[cpu] = policy->min; |
140 | cpu_max_freq[cpu] = policy->max; | 140 | cpu_max_freq[cpu] = policy->max; |
141 | cpu_cur_freq[cpu] = policy->cur; | 141 | cpu_cur_freq[cpu] = policy->cur; |
142 | cpu_set_freq[cpu] = policy->cur; | 142 | cpu_set_freq[cpu] = policy->cur; |
143 | sysfs_create_file (&policy->kobj, &freq_attr_scaling_setspeed.attr); | 143 | sysfs_create_file (&policy->kobj, &freq_attr_scaling_setspeed.attr); |
144 | memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); | ||
145 | 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]); | 144 | 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]); |
146 | up(&userspace_sem); | 145 | mutex_unlock(&userspace_mutex); |
147 | break; | 146 | break; |
148 | case CPUFREQ_GOV_STOP: | 147 | case CPUFREQ_GOV_STOP: |
149 | down(&userspace_sem); | 148 | mutex_lock(&userspace_mutex); |
150 | cpu_is_managed[cpu] = 0; | 149 | cpu_is_managed[cpu] = 0; |
151 | cpu_min_freq[cpu] = 0; | 150 | cpu_min_freq[cpu] = 0; |
152 | cpu_max_freq[cpu] = 0; | 151 | cpu_max_freq[cpu] = 0; |
153 | cpu_set_freq[cpu] = 0; | 152 | cpu_set_freq[cpu] = 0; |
154 | sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr); | 153 | sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr); |
155 | dprintk("managing cpu %u stopped\n", cpu); | 154 | dprintk("managing cpu %u stopped\n", cpu); |
156 | up(&userspace_sem); | 155 | mutex_unlock(&userspace_mutex); |
157 | break; | 156 | break; |
158 | case CPUFREQ_GOV_LIMITS: | 157 | case CPUFREQ_GOV_LIMITS: |
159 | down(&userspace_sem); | 158 | mutex_lock(&userspace_mutex); |
160 | cpu_min_freq[cpu] = policy->min; | 159 | dprintk("limit event for cpu %u: %u - %u kHz," |
161 | cpu_max_freq[cpu] = policy->max; | 160 | "currently %u kHz, last set to %u kHz\n", |
162 | dprintk("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", cpu, cpu_min_freq[cpu], cpu_max_freq[cpu], cpu_cur_freq[cpu], cpu_set_freq[cpu]); | 161 | cpu, policy->min, policy->max, |
162 | cpu_cur_freq[cpu], cpu_set_freq[cpu]); | ||
163 | if (policy->max < cpu_set_freq[cpu]) { | 163 | if (policy->max < cpu_set_freq[cpu]) { |
164 | __cpufreq_driver_target(¤t_policy[cpu], policy->max, | 164 | __cpufreq_driver_target(policy, policy->max, |
165 | CPUFREQ_RELATION_H); | 165 | CPUFREQ_RELATION_H); |
166 | } else if (policy->min > cpu_set_freq[cpu]) { | 166 | } |
167 | __cpufreq_driver_target(¤t_policy[cpu], policy->min, | 167 | else if (policy->min > cpu_set_freq[cpu]) { |
168 | CPUFREQ_RELATION_L); | 168 | __cpufreq_driver_target(policy, policy->min, |
169 | } else { | 169 | CPUFREQ_RELATION_L); |
170 | __cpufreq_driver_target(¤t_policy[cpu], cpu_set_freq[cpu], | ||
171 | CPUFREQ_RELATION_L); | ||
172 | } | 170 | } |
173 | memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); | 171 | else { |
174 | up(&userspace_sem); | 172 | __cpufreq_driver_target(policy, cpu_set_freq[cpu], |
173 | CPUFREQ_RELATION_L); | ||
174 | } | ||
175 | cpu_min_freq[cpu] = policy->min; | ||
176 | cpu_max_freq[cpu] = policy->max; | ||
177 | cpu_cur_freq[cpu] = policy->cur; | ||
178 | mutex_unlock(&userspace_mutex); | ||
175 | break; | 179 | break; |
176 | } | 180 | } |
177 | return 0; | 181 | return 0; |