diff options
| -rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-ich.c | 93 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/cpufreq/speedstep-lib.c | 1 |
2 files changed, 55 insertions, 39 deletions
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c index 016c1a4fa3fc..6911e91fb4f6 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c | |||
| @@ -89,7 +89,8 @@ static int speedstep_find_register(void) | |||
| 89 | * speedstep_set_state - set the SpeedStep state | 89 | * speedstep_set_state - set the SpeedStep state |
| 90 | * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) | 90 | * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) |
| 91 | * | 91 | * |
| 92 | * Tries to change the SpeedStep state. | 92 | * Tries to change the SpeedStep state. Can be called from |
| 93 | * smp_call_function_single. | ||
| 93 | */ | 94 | */ |
| 94 | static void speedstep_set_state(unsigned int state) | 95 | static void speedstep_set_state(unsigned int state) |
| 95 | { | 96 | { |
| @@ -143,6 +144,11 @@ static void speedstep_set_state(unsigned int state) | |||
| 143 | return; | 144 | return; |
| 144 | } | 145 | } |
| 145 | 146 | ||
| 147 | /* Wrapper for smp_call_function_single. */ | ||
| 148 | static void _speedstep_set_state(void *_state) | ||
| 149 | { | ||
| 150 | speedstep_set_state(*(unsigned int *)_state); | ||
| 151 | } | ||
| 146 | 152 | ||
| 147 | /** | 153 | /** |
| 148 | * speedstep_activate - activate SpeedStep control in the chipset | 154 | * speedstep_activate - activate SpeedStep control in the chipset |
| @@ -226,22 +232,28 @@ static unsigned int speedstep_detect_chipset(void) | |||
| 226 | return 0; | 232 | return 0; |
| 227 | } | 233 | } |
| 228 | 234 | ||
| 229 | static unsigned int _speedstep_get(const struct cpumask *cpus) | 235 | struct get_freq_data { |
| 230 | { | ||
| 231 | unsigned int speed; | 236 | unsigned int speed; |
| 232 | cpumask_t cpus_allowed; | 237 | unsigned int processor; |
| 233 | 238 | }; | |
| 234 | cpus_allowed = current->cpus_allowed; | 239 | |
| 235 | set_cpus_allowed_ptr(current, cpus); | 240 | static void get_freq_data(void *_data) |
| 236 | speed = speedstep_get_frequency(speedstep_processor); | 241 | { |
| 237 | set_cpus_allowed_ptr(current, &cpus_allowed); | 242 | struct get_freq_data *data = _data; |
| 238 | dprintk("detected %u kHz as current frequency\n", speed); | 243 | |
| 239 | return speed; | 244 | data->speed = speedstep_get_frequency(data->processor); |
| 240 | } | 245 | } |
| 241 | 246 | ||
| 242 | static unsigned int speedstep_get(unsigned int cpu) | 247 | static unsigned int speedstep_get(unsigned int cpu) |
| 243 | { | 248 | { |
| 244 | return _speedstep_get(cpumask_of(cpu)); | 249 | struct get_freq_data data = { .processor = cpu }; |
| 250 | |||
| 251 | /* You're supposed to ensure CPU is online. */ | ||
| 252 | if (smp_call_function_single(cpu, get_freq_data, &data, 1) != 0) | ||
| 253 | BUG(); | ||
| 254 | |||
| 255 | dprintk("detected %u kHz as current frequency\n", data.speed); | ||
| 256 | return data.speed; | ||
| 245 | } | 257 | } |
| 246 | 258 | ||
| 247 | /** | 259 | /** |
| @@ -257,16 +269,16 @@ static int speedstep_target(struct cpufreq_policy *policy, | |||
| 257 | unsigned int target_freq, | 269 | unsigned int target_freq, |
| 258 | unsigned int relation) | 270 | unsigned int relation) |
| 259 | { | 271 | { |
| 260 | unsigned int newstate = 0; | 272 | unsigned int newstate = 0, policy_cpu; |
| 261 | struct cpufreq_freqs freqs; | 273 | struct cpufreq_freqs freqs; |
| 262 | cpumask_t cpus_allowed; | ||
| 263 | int i; | 274 | int i; |
| 264 | 275 | ||
| 265 | if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], | 276 | if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], |
| 266 | target_freq, relation, &newstate)) | 277 | target_freq, relation, &newstate)) |
| 267 | return -EINVAL; | 278 | return -EINVAL; |
| 268 | 279 | ||
| 269 | freqs.old = _speedstep_get(policy->cpus); | 280 | policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); |
| 281 | freqs.old = speedstep_get(policy_cpu); | ||
| 270 | freqs.new = speedstep_freqs[newstate].frequency; | 282 | freqs.new = speedstep_freqs[newstate].frequency; |
| 271 | freqs.cpu = policy->cpu; | 283 | freqs.cpu = policy->cpu; |
| 272 | 284 | ||
| @@ -276,20 +288,13 @@ static int speedstep_target(struct cpufreq_policy *policy, | |||
| 276 | if (freqs.old == freqs.new) | 288 | if (freqs.old == freqs.new) |
| 277 | return 0; | 289 | return 0; |
| 278 | 290 | ||
| 279 | cpus_allowed = current->cpus_allowed; | ||
| 280 | |||
| 281 | for_each_cpu(i, policy->cpus) { | 291 | for_each_cpu(i, policy->cpus) { |
| 282 | freqs.cpu = i; | 292 | freqs.cpu = i; |
| 283 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | 293 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); |
| 284 | } | 294 | } |
| 285 | 295 | ||
| 286 | /* switch to physical CPU where state is to be changed */ | 296 | smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate, |
| 287 | set_cpus_allowed_ptr(current, policy->cpus); | 297 | true); |
| 288 | |||
| 289 | speedstep_set_state(newstate); | ||
| 290 | |||
| 291 | /* allow to be run on all CPUs */ | ||
| 292 | set_cpus_allowed_ptr(current, &cpus_allowed); | ||
| 293 | 298 | ||
| 294 | for_each_cpu(i, policy->cpus) { | 299 | for_each_cpu(i, policy->cpus) { |
| 295 | freqs.cpu = i; | 300 | freqs.cpu = i; |
| @@ -312,33 +317,43 @@ static int speedstep_verify(struct cpufreq_policy *policy) | |||
| 312 | return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); | 317 | return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); |
| 313 | } | 318 | } |
| 314 | 319 | ||
| 320 | struct get_freqs { | ||
| 321 | struct cpufreq_policy *policy; | ||
| 322 | int ret; | ||
| 323 | }; | ||
| 324 | |||
| 325 | static void get_freqs_on_cpu(void *_get_freqs) | ||
| 326 | { | ||
| 327 | struct get_freqs *get_freqs = _get_freqs; | ||
| 328 | |||
| 329 | get_freqs->ret = | ||
| 330 | speedstep_get_freqs(speedstep_processor, | ||
| 331 | &speedstep_freqs[SPEEDSTEP_LOW].frequency, | ||
| 332 | &speedstep_freqs[SPEEDSTEP_HIGH].frequency, | ||
| 333 | &get_freqs->policy->cpuinfo.transition_latency, | ||
| 334 | &speedstep_set_state); | ||
| 335 | } | ||
| 315 | 336 | ||
| 316 | static int speedstep_cpu_init(struct cpufreq_policy *policy) | 337 | static int speedstep_cpu_init(struct cpufreq_policy *policy) |
| 317 | { | 338 | { |
| 318 | int result = 0; | 339 | int result; |
| 319 | unsigned int speed; | 340 | unsigned int policy_cpu, speed; |
| 320 | cpumask_t cpus_allowed; | 341 | struct get_freqs gf; |
| 321 | 342 | ||
| 322 | /* only run on CPU to be set, or on its sibling */ | 343 | /* only run on CPU to be set, or on its sibling */ |
| 323 | #ifdef CONFIG_SMP | 344 | #ifdef CONFIG_SMP |
| 324 | cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); | 345 | cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); |
| 325 | #endif | 346 | #endif |
| 326 | 347 | policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); | |
| 327 | cpus_allowed = current->cpus_allowed; | ||
| 328 | set_cpus_allowed_ptr(current, policy->cpus); | ||
| 329 | 348 | ||
| 330 | /* detect low and high frequency and transition latency */ | 349 | /* detect low and high frequency and transition latency */ |
| 331 | result = speedstep_get_freqs(speedstep_processor, | 350 | gf.policy = policy; |
| 332 | &speedstep_freqs[SPEEDSTEP_LOW].frequency, | 351 | smp_call_function_single(policy_cpu, get_freqs_on_cpu, &gf, 1); |
| 333 | &speedstep_freqs[SPEEDSTEP_HIGH].frequency, | 352 | if (gf.ret) |
| 334 | &policy->cpuinfo.transition_latency, | 353 | return gf.ret; |
| 335 | &speedstep_set_state); | ||
| 336 | set_cpus_allowed_ptr(current, &cpus_allowed); | ||
| 337 | if (result) | ||
| 338 | return result; | ||
| 339 | 354 | ||
| 340 | /* get current speed setting */ | 355 | /* get current speed setting */ |
| 341 | speed = _speedstep_get(policy->cpus); | 356 | speed = speedstep_get(policy_cpu); |
| 342 | if (!speed) | 357 | if (!speed) |
| 343 | return -EIO; | 358 | return -EIO; |
| 344 | 359 | ||
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c index 2e3c6862657b..f4c290b8482f 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c | |||
| @@ -226,6 +226,7 @@ static unsigned int pentium4_get_frequency(void) | |||
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | 228 | ||
| 229 | /* Warning: may get called from smp_call_function_single. */ | ||
| 229 | unsigned int speedstep_get_frequency(unsigned int processor) | 230 | unsigned int speedstep_get_frequency(unsigned int processor) |
| 230 | { | 231 | { |
| 231 | switch (processor) { | 232 | switch (processor) { |
