Skip to content

Commit

Permalink
cpufreq: powernv: Set the cpus to nominal frequency during reboot/kexec
Browse files Browse the repository at this point in the history
This patch ensures the cpus to kexec/reboot at nominal frequency.
Nominal frequency is the highest cpu frequency on PowerPC at
which the cores can run without getting throttled.

If the host kernel had set the cpus to a low pstate and then it
kexecs/reboots to a cpufreq disabled kernel it would cause the target
kernel to perform poorly. It will also increase the boot up time of
the target kernel. So set the cpus to high pstate, in this case to
nominal frequency before rebooting to avoid such scenarios.

The reboot notifier will set the cpus to nominal frequncy.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
Reviewed-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
shilpasri authored and rafaeljw committed Sep 29, 2014
1 parent b120339 commit cf30af7
Showing 1 changed file with 35 additions and 0 deletions.
35 changes: 35 additions & 0 deletions drivers/cpufreq/powernv-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/cpufreq.h>
#include <linux/smp.h>
#include <linux/of.h>
#include <linux/reboot.h>

#include <asm/cputhreads.h>
#include <asm/firmware.h>
Expand All @@ -35,6 +36,7 @@
#define POWERNV_MAX_PSTATES 256

static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
static bool rebooting;

/*
* Note: The set of pstates consists of contiguous integers, the
Expand Down Expand Up @@ -283,6 +285,15 @@ static void set_pstate(void *freq_data)
set_pmspr(SPRN_PMCR, val);
}

/*
* get_nominal_index: Returns the index corresponding to the nominal
* pstate in the cpufreq table
*/
static inline unsigned int get_nominal_index(void)
{
return powernv_pstate_info.max - powernv_pstate_info.nominal;
}

/*
* powernv_cpufreq_target_index: Sets the frequency corresponding to
* the cpufreq table entry indexed by new_index on the cpus in the
Expand All @@ -293,6 +304,9 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
{
struct powernv_smp_call_data freq_data;

if (unlikely(rebooting) && new_index != get_nominal_index())
return 0;

freq_data.pstate_id = powernv_freqs[new_index].driver_data;

/*
Expand All @@ -317,6 +331,25 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
return cpufreq_table_validate_and_show(policy, powernv_freqs);
}

static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *unused)
{
int cpu;
struct cpufreq_policy cpu_policy;

rebooting = true;
for_each_online_cpu(cpu) {
cpufreq_get_policy(&cpu_policy, cpu);
powernv_cpufreq_target_index(&cpu_policy, get_nominal_index());
}

return NOTIFY_DONE;
}

static struct notifier_block powernv_cpufreq_reboot_nb = {
.notifier_call = powernv_cpufreq_reboot_notifier,
};

static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy)
{
struct powernv_smp_call_data freq_data;
Expand Down Expand Up @@ -351,12 +384,14 @@ static int __init powernv_cpufreq_init(void)
return rc;
}

register_reboot_notifier(&powernv_cpufreq_reboot_nb);
return cpufreq_register_driver(&powernv_cpufreq_driver);
}
module_init(powernv_cpufreq_init);

static void __exit powernv_cpufreq_exit(void)
{
unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
cpufreq_unregister_driver(&powernv_cpufreq_driver);
}
module_exit(powernv_cpufreq_exit);
Expand Down

0 comments on commit cf30af7

Please sign in to comment.