aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/powernv-cpufreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpufreq/powernv-cpufreq.c')
-rw-r--r--drivers/cpufreq/powernv-cpufreq.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index 379c0837f5a9..2dfd4fdb5a52 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -26,6 +26,7 @@
26#include <linux/cpufreq.h> 26#include <linux/cpufreq.h>
27#include <linux/smp.h> 27#include <linux/smp.h>
28#include <linux/of.h> 28#include <linux/of.h>
29#include <linux/reboot.h>
29 30
30#include <asm/cputhreads.h> 31#include <asm/cputhreads.h>
31#include <asm/firmware.h> 32#include <asm/firmware.h>
@@ -35,6 +36,7 @@
35#define POWERNV_MAX_PSTATES 256 36#define POWERNV_MAX_PSTATES 256
36 37
37static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; 38static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
39static bool rebooting;
38 40
39/* 41/*
40 * Note: The set of pstates consists of contiguous integers, the 42 * Note: The set of pstates consists of contiguous integers, the
@@ -284,6 +286,15 @@ static void set_pstate(void *freq_data)
284} 286}
285 287
286/* 288/*
289 * get_nominal_index: Returns the index corresponding to the nominal
290 * pstate in the cpufreq table
291 */
292static inline unsigned int get_nominal_index(void)
293{
294 return powernv_pstate_info.max - powernv_pstate_info.nominal;
295}
296
297/*
287 * powernv_cpufreq_target_index: Sets the frequency corresponding to 298 * powernv_cpufreq_target_index: Sets the frequency corresponding to
288 * the cpufreq table entry indexed by new_index on the cpus in the 299 * the cpufreq table entry indexed by new_index on the cpus in the
289 * mask policy->cpus 300 * mask policy->cpus
@@ -293,6 +304,9 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
293{ 304{
294 struct powernv_smp_call_data freq_data; 305 struct powernv_smp_call_data freq_data;
295 306
307 if (unlikely(rebooting) && new_index != get_nominal_index())
308 return 0;
309
296 freq_data.pstate_id = powernv_freqs[new_index].driver_data; 310 freq_data.pstate_id = powernv_freqs[new_index].driver_data;
297 311
298 /* 312 /*
@@ -317,6 +331,33 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
317 return cpufreq_table_validate_and_show(policy, powernv_freqs); 331 return cpufreq_table_validate_and_show(policy, powernv_freqs);
318} 332}
319 333
334static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb,
335 unsigned long action, void *unused)
336{
337 int cpu;
338 struct cpufreq_policy cpu_policy;
339
340 rebooting = true;
341 for_each_online_cpu(cpu) {
342 cpufreq_get_policy(&cpu_policy, cpu);
343 powernv_cpufreq_target_index(&cpu_policy, get_nominal_index());
344 }
345
346 return NOTIFY_DONE;
347}
348
349static struct notifier_block powernv_cpufreq_reboot_nb = {
350 .notifier_call = powernv_cpufreq_reboot_notifier,
351};
352
353static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy)
354{
355 struct powernv_smp_call_data freq_data;
356
357 freq_data.pstate_id = powernv_pstate_info.min;
358 smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1);
359}
360
320static struct cpufreq_driver powernv_cpufreq_driver = { 361static struct cpufreq_driver powernv_cpufreq_driver = {
321 .name = "powernv-cpufreq", 362 .name = "powernv-cpufreq",
322 .flags = CPUFREQ_CONST_LOOPS, 363 .flags = CPUFREQ_CONST_LOOPS,
@@ -324,6 +365,7 @@ static struct cpufreq_driver powernv_cpufreq_driver = {
324 .verify = cpufreq_generic_frequency_table_verify, 365 .verify = cpufreq_generic_frequency_table_verify,
325 .target_index = powernv_cpufreq_target_index, 366 .target_index = powernv_cpufreq_target_index,
326 .get = powernv_cpufreq_get, 367 .get = powernv_cpufreq_get,
368 .stop_cpu = powernv_cpufreq_stop_cpu,
327 .attr = powernv_cpu_freq_attr, 369 .attr = powernv_cpu_freq_attr,
328}; 370};
329 371
@@ -342,12 +384,14 @@ static int __init powernv_cpufreq_init(void)
342 return rc; 384 return rc;
343 } 385 }
344 386
387 register_reboot_notifier(&powernv_cpufreq_reboot_nb);
345 return cpufreq_register_driver(&powernv_cpufreq_driver); 388 return cpufreq_register_driver(&powernv_cpufreq_driver);
346} 389}
347module_init(powernv_cpufreq_init); 390module_init(powernv_cpufreq_init);
348 391
349static void __exit powernv_cpufreq_exit(void) 392static void __exit powernv_cpufreq_exit(void)
350{ 393{
394 unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
351 cpufreq_unregister_driver(&powernv_cpufreq_driver); 395 cpufreq_unregister_driver(&powernv_cpufreq_driver);
352} 396}
353module_exit(powernv_cpufreq_exit); 397module_exit(powernv_cpufreq_exit);