Merge branch 'pm-cpufreq'
* pm-cpufreq: (46 commits) intel_pstate: provide option to only use intel_pstate with HWP cpufreq-dt: Drop unnecessary check before cpufreq_cooling_unregister() invocation cpufreq: Create for_each_governor() cpufreq: Create for_each_policy() cpufreq: Drop cpufreq_disabled() check from cpufreq_cpu_{get|put}() cpufreq: Set cpufreq_cpu_data to NULL before putting kobject intel_pstate: honor user space min_perf_pct override on resume intel_pstate: respect cpufreq policy request intel_pstate: Add num_pstates to sysfs intel_pstate: expose turbo range to sysfs intel_pstate: Add support for SkyLake cpufreq: stats: drop unnecessary locking cpufreq: stats: don't update stats on false notifiers cpufreq: stats: don't update stats from show_trans_table() cpufreq: stats: time_in_state can't be NULL in cpufreq_stats_update() cpufreq: stats: create sysfs group once we are ready cpufreq: remove CPUFREQ_UPDATE_POLICY_CPU notifications cpufreq: stats: drop 'cpu' field of struct cpufreq_stats cpufreq: Remove (now) unused 'last_cpu' from struct cpufreq_policy cpufreq: stats: rename 'struct cpufreq_stats' objects as 'stats' ...
This commit is contained in:
commit
7bc95d4ef1
|
@ -37,6 +37,14 @@ controlling P state selection. These files have been added to
|
|||
no_turbo: limits the driver to selecting P states below the turbo
|
||||
frequency range.
|
||||
|
||||
turbo_pct: displays the percentage of the total performance that
|
||||
is supported by hardware that is in the turbo range. This number
|
||||
is independent of whether turbo has been disabled or not.
|
||||
|
||||
num_pstates: displays the number of pstates that are supported
|
||||
by hardware. This number is independent of whether turbo has
|
||||
been disabled or not.
|
||||
|
||||
For contemporary Intel processors, the frequency is controlled by the
|
||||
processor itself and the P-states exposed to software are related to
|
||||
performance levels. The idea that frequency can be set to a single
|
||||
|
|
|
@ -1470,6 +1470,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
no_hwp
|
||||
Do not enable hardware P state control (HWP)
|
||||
if available.
|
||||
hwp_only
|
||||
Only load intel_pstate on systems which support
|
||||
hardware P state control (HWP) if available.
|
||||
|
||||
intremap= [X86-64, Intel-IOMMU]
|
||||
on enable Interrupt Remapping (default)
|
||||
|
|
|
@ -358,6 +358,7 @@
|
|||
|
||||
#define MSR_IA32_PERF_STATUS 0x00000198
|
||||
#define MSR_IA32_PERF_CTL 0x00000199
|
||||
#define INTEL_PERF_CTL_MASK 0xffff
|
||||
#define MSR_AMD_PSTATE_DEF_BASE 0xc0010064
|
||||
#define MSR_AMD_PERF_STATUS 0xc0010063
|
||||
#define MSR_AMD_PERF_CTL 0xc0010062
|
||||
|
|
|
@ -57,6 +57,16 @@ config X86_ACPI_CPUFREQ_CPB
|
|||
By enabling this option the acpi_cpufreq driver provides the old
|
||||
entry in addition to the new boost ones, for compatibility reasons.
|
||||
|
||||
config X86_SFI_CPUFREQ
|
||||
tristate "SFI Performance-States driver"
|
||||
depends on X86_INTEL_MID && SFI
|
||||
help
|
||||
This adds a CPUFreq driver for some Silvermont based Intel Atom
|
||||
architectures like Z34xx and Z35xx which enumerate processor
|
||||
performance states through SFI.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ELAN_CPUFREQ
|
||||
tristate "AMD Elan SC400 and SC410"
|
||||
depends on MELAN
|
||||
|
|
|
@ -41,6 +41,7 @@ obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
|
|||
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
|
||||
obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o
|
||||
obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o
|
||||
obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o
|
||||
|
||||
##################################################################################
|
||||
# ARM SoC drivers
|
||||
|
|
|
@ -320,8 +320,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
|
|||
{
|
||||
struct private_data *priv = policy->driver_data;
|
||||
|
||||
if (priv->cdev)
|
||||
cpufreq_cooling_unregister(priv->cdev);
|
||||
cpufreq_cooling_unregister(priv->cdev);
|
||||
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
|
||||
of_free_opp_table(priv->cpu_dev);
|
||||
clk_put(policy->clk);
|
||||
|
|
|
@ -27,9 +27,21 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/tick.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
/* Macros to iterate over lists */
|
||||
/* Iterate over online CPUs policies */
|
||||
static LIST_HEAD(cpufreq_policy_list);
|
||||
#define for_each_policy(__policy) \
|
||||
list_for_each_entry(__policy, &cpufreq_policy_list, policy_list)
|
||||
|
||||
/* Iterate over governors */
|
||||
static LIST_HEAD(cpufreq_governor_list);
|
||||
#define for_each_governor(__governor) \
|
||||
list_for_each_entry(__governor, &cpufreq_governor_list, governor_list)
|
||||
|
||||
/**
|
||||
* The "cpufreq driver" - the arch- or hardware-dependent low
|
||||
* level driver of CPUFreq support, and its spinlock. This lock
|
||||
|
@ -40,7 +52,6 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
|
|||
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
|
||||
static DEFINE_RWLOCK(cpufreq_driver_lock);
|
||||
DEFINE_MUTEX(cpufreq_governor_lock);
|
||||
static LIST_HEAD(cpufreq_policy_list);
|
||||
|
||||
/* This one keeps track of the previously set governor of a removed CPU */
|
||||
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
|
||||
|
@ -62,7 +73,7 @@ static DECLARE_RWSEM(cpufreq_rwsem);
|
|||
/* internal prototypes */
|
||||
static int __cpufreq_governor(struct cpufreq_policy *policy,
|
||||
unsigned int event);
|
||||
static unsigned int __cpufreq_get(unsigned int cpu);
|
||||
static unsigned int __cpufreq_get(struct cpufreq_policy *policy);
|
||||
static void handle_update(struct work_struct *work);
|
||||
|
||||
/**
|
||||
|
@ -93,7 +104,6 @@ void disable_cpufreq(void)
|
|||
{
|
||||
off = 1;
|
||||
}
|
||||
static LIST_HEAD(cpufreq_governor_list);
|
||||
static DEFINE_MUTEX(cpufreq_governor_mutex);
|
||||
|
||||
bool have_governor_per_policy(void)
|
||||
|
@ -202,7 +212,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
|
|||
struct cpufreq_policy *policy = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
if (cpufreq_disabled() || (cpu >= nr_cpu_ids))
|
||||
if (cpu >= nr_cpu_ids)
|
||||
return NULL;
|
||||
|
||||
if (!down_read_trylock(&cpufreq_rwsem))
|
||||
|
@ -229,9 +239,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
|
|||
|
||||
void cpufreq_cpu_put(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (cpufreq_disabled())
|
||||
return;
|
||||
|
||||
kobject_put(&policy->kobj);
|
||||
up_read(&cpufreq_rwsem);
|
||||
}
|
||||
|
@ -249,12 +256,12 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
|
|||
* systems as each CPU might be scaled differently. So, use the arch
|
||||
* per-CPU loops_per_jiffy value wherever possible.
|
||||
*/
|
||||
#ifndef CONFIG_SMP
|
||||
static unsigned long l_p_j_ref;
|
||||
static unsigned int l_p_j_ref_freq;
|
||||
|
||||
static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
|
||||
{
|
||||
#ifndef CONFIG_SMP
|
||||
static unsigned long l_p_j_ref;
|
||||
static unsigned int l_p_j_ref_freq;
|
||||
|
||||
if (ci->flags & CPUFREQ_CONST_LOOPS)
|
||||
return;
|
||||
|
||||
|
@ -270,13 +277,8 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
|
|||
pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n",
|
||||
loops_per_jiffy, ci->new);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
struct cpufreq_freqs *freqs, unsigned int state)
|
||||
|
@ -432,11 +434,11 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
|
|||
}
|
||||
define_one_global_rw(boost);
|
||||
|
||||
static struct cpufreq_governor *__find_governor(const char *str_governor)
|
||||
static struct cpufreq_governor *find_governor(const char *str_governor)
|
||||
{
|
||||
struct cpufreq_governor *t;
|
||||
|
||||
list_for_each_entry(t, &cpufreq_governor_list, governor_list)
|
||||
for_each_governor(t)
|
||||
if (!strncasecmp(str_governor, t->name, CPUFREQ_NAME_LEN))
|
||||
return t;
|
||||
|
||||
|
@ -463,12 +465,12 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
|
|||
*policy = CPUFREQ_POLICY_POWERSAVE;
|
||||
err = 0;
|
||||
}
|
||||
} else if (has_target()) {
|
||||
} else {
|
||||
struct cpufreq_governor *t;
|
||||
|
||||
mutex_lock(&cpufreq_governor_mutex);
|
||||
|
||||
t = __find_governor(str_governor);
|
||||
t = find_governor(str_governor);
|
||||
|
||||
if (t == NULL) {
|
||||
int ret;
|
||||
|
@ -478,7 +480,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
|
|||
mutex_lock(&cpufreq_governor_mutex);
|
||||
|
||||
if (ret == 0)
|
||||
t = __find_governor(str_governor);
|
||||
t = find_governor(str_governor);
|
||||
}
|
||||
|
||||
if (t != NULL) {
|
||||
|
@ -513,8 +515,7 @@ show_one(cpuinfo_transition_latency, cpuinfo.transition_latency);
|
|||
show_one(scaling_min_freq, min);
|
||||
show_one(scaling_max_freq, max);
|
||||
|
||||
static ssize_t show_scaling_cur_freq(
|
||||
struct cpufreq_policy *policy, char *buf)
|
||||
static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
|
@ -563,7 +564,7 @@ store_one(scaling_max_freq, max);
|
|||
static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
|
||||
char *buf)
|
||||
{
|
||||
unsigned int cur_freq = __cpufreq_get(policy->cpu);
|
||||
unsigned int cur_freq = __cpufreq_get(policy);
|
||||
if (!cur_freq)
|
||||
return sprintf(buf, "<unknown>");
|
||||
return sprintf(buf, "%u\n", cur_freq);
|
||||
|
@ -639,7 +640,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
|
|||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
|
||||
for_each_governor(t) {
|
||||
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
|
||||
- (CPUFREQ_NAME_LEN + 2)))
|
||||
goto out;
|
||||
|
@ -902,7 +903,7 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
|
|||
|
||||
/* set up files for this cpu device */
|
||||
drv_attr = cpufreq_driver->attr;
|
||||
while ((drv_attr) && (*drv_attr)) {
|
||||
while (drv_attr && *drv_attr) {
|
||||
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -936,7 +937,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
|
|||
memcpy(&new_policy, policy, sizeof(*policy));
|
||||
|
||||
/* Update governor of new_policy to the governor used before hotplug */
|
||||
gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
|
||||
gov = find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
|
||||
if (gov)
|
||||
pr_debug("Restoring governor %s for cpu %d\n",
|
||||
policy->governor->name, policy->cpu);
|
||||
|
@ -958,7 +959,6 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
|
||||
unsigned int cpu, struct device *dev)
|
||||
{
|
||||
|
@ -996,7 +996,6 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
|
|||
|
||||
return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
|
||||
{
|
||||
|
@ -1033,6 +1032,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void)
|
|||
init_rwsem(&policy->rwsem);
|
||||
spin_lock_init(&policy->transition_lock);
|
||||
init_waitqueue_head(&policy->transition_wait);
|
||||
init_completion(&policy->kobj_unregister);
|
||||
INIT_WORK(&policy->update, handle_update);
|
||||
|
||||
return policy;
|
||||
|
||||
|
@ -1091,15 +1092,9 @@ static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
|
|||
}
|
||||
|
||||
down_write(&policy->rwsem);
|
||||
|
||||
policy->last_cpu = policy->cpu;
|
||||
policy->cpu = cpu;
|
||||
|
||||
up_write(&policy->rwsem);
|
||||
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_UPDATE_POLICY_CPU, policy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1110,41 +1105,32 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|||
struct cpufreq_policy *policy;
|
||||
unsigned long flags;
|
||||
bool recover_policy = cpufreq_suspended;
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
struct cpufreq_policy *tpolicy;
|
||||
#endif
|
||||
|
||||
if (cpu_is_offline(cpu))
|
||||
return 0;
|
||||
|
||||
pr_debug("adding CPU %u\n", cpu);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* check whether a different CPU already registered this
|
||||
* CPU because it is in the same boat. */
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (unlikely(policy)) {
|
||||
cpufreq_cpu_put(policy);
|
||||
policy = cpufreq_cpu_get_raw(cpu);
|
||||
if (unlikely(policy))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!down_read_trylock(&cpufreq_rwsem))
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/* Check if this cpu was hot-unplugged earlier and has siblings */
|
||||
read_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) {
|
||||
if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) {
|
||||
for_each_policy(policy) {
|
||||
if (cpumask_test_cpu(cpu, policy->related_cpus)) {
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev);
|
||||
ret = cpufreq_add_policy_cpu(policy, cpu, dev);
|
||||
up_read(&cpufreq_rwsem);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Restore the saved policy when doing light-weight init and fall back
|
||||
|
@ -1171,9 +1157,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
|||
|
||||
cpumask_copy(policy->cpus, cpumask_of(cpu));
|
||||
|
||||
init_completion(&policy->kobj_unregister);
|
||||
INIT_WORK(&policy->update, handle_update);
|
||||
|
||||
/* call driver. From then on the cpufreq must be able
|
||||
* to accept all calls to ->verify and ->setpolicy for this CPU
|
||||
*/
|
||||
|
@ -1371,11 +1354,10 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
|||
pr_err("%s: Failed to stop governor\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cpufreq_driver->setpolicy)
|
||||
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
|
||||
policy->governor->name, CPUFREQ_NAME_LEN);
|
||||
}
|
||||
|
||||
down_read(&policy->rwsem);
|
||||
cpus = cpumask_weight(policy->cpus);
|
||||
|
@ -1416,9 +1398,10 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
|
|||
unsigned long flags;
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
read_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
per_cpu(cpufreq_cpu_data, cpu) = NULL;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
if (!policy) {
|
||||
pr_debug("%s: No cpu_data found\n", __func__);
|
||||
|
@ -1473,7 +1456,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
per_cpu(cpufreq_cpu_data, cpu) = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1510,30 +1492,23 @@ static void handle_update(struct work_struct *work)
|
|||
/**
|
||||
* cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
|
||||
* in deep trouble.
|
||||
* @cpu: cpu number
|
||||
* @old_freq: CPU frequency the kernel thinks the CPU runs at
|
||||
* @policy: policy managing CPUs
|
||||
* @new_freq: CPU frequency the CPU actually runs at
|
||||
*
|
||||
* We adjust to current frequency first, and need to clean up later.
|
||||
* So either call to cpufreq_update_policy() or schedule handle_update()).
|
||||
*/
|
||||
static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
|
||||
static void cpufreq_out_of_sync(struct cpufreq_policy *policy,
|
||||
unsigned int new_freq)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n",
|
||||
old_freq, new_freq);
|
||||
policy->cur, new_freq);
|
||||
|
||||
freqs.old = old_freq;
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = new_freq;
|
||||
|
||||
read_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
cpufreq_freq_transition_begin(policy, &freqs);
|
||||
cpufreq_freq_transition_end(policy, &freqs, 0);
|
||||
}
|
||||
|
@ -1583,22 +1558,21 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu)
|
|||
}
|
||||
EXPORT_SYMBOL(cpufreq_quick_get_max);
|
||||
|
||||
static unsigned int __cpufreq_get(unsigned int cpu)
|
||||
static unsigned int __cpufreq_get(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
unsigned int ret_freq = 0;
|
||||
|
||||
if (!cpufreq_driver->get)
|
||||
return ret_freq;
|
||||
|
||||
ret_freq = cpufreq_driver->get(cpu);
|
||||
ret_freq = cpufreq_driver->get(policy->cpu);
|
||||
|
||||
if (ret_freq && policy->cur &&
|
||||
!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
/* verify no discrepancy between actual and
|
||||
saved value exists */
|
||||
if (unlikely(ret_freq != policy->cur)) {
|
||||
cpufreq_out_of_sync(cpu, policy->cur, ret_freq);
|
||||
cpufreq_out_of_sync(policy, ret_freq);
|
||||
schedule_work(&policy->update);
|
||||
}
|
||||
}
|
||||
|
@ -1619,7 +1593,7 @@ unsigned int cpufreq_get(unsigned int cpu)
|
|||
|
||||
if (policy) {
|
||||
down_read(&policy->rwsem);
|
||||
ret_freq = __cpufreq_get(cpu);
|
||||
ret_freq = __cpufreq_get(policy);
|
||||
up_read(&policy->rwsem);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
|
@ -1682,7 +1656,7 @@ void cpufreq_suspend(void)
|
|||
|
||||
pr_debug("%s: Suspending Governors\n", __func__);
|
||||
|
||||
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
|
||||
for_each_policy(policy) {
|
||||
if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
|
||||
pr_err("%s: Failed to stop governor for policy: %p\n",
|
||||
__func__, policy);
|
||||
|
@ -1716,7 +1690,7 @@ void cpufreq_resume(void)
|
|||
|
||||
pr_debug("%s: Resuming Governors\n", __func__);
|
||||
|
||||
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
|
||||
for_each_policy(policy) {
|
||||
if (cpufreq_driver->resume && cpufreq_driver->resume(policy))
|
||||
pr_err("%s: Failed to resume driver: %p\n", __func__,
|
||||
policy);
|
||||
|
@ -2006,10 +1980,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
|
||||
|
||||
/*
|
||||
* when "event" is CPUFREQ_GOV_LIMITS
|
||||
*/
|
||||
|
||||
static int __cpufreq_governor(struct cpufreq_policy *policy,
|
||||
unsigned int event)
|
||||
{
|
||||
|
@ -2107,7 +2077,7 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
|
|||
|
||||
governor->initialized = 0;
|
||||
err = -EBUSY;
|
||||
if (__find_governor(governor->name) == NULL) {
|
||||
if (!find_governor(governor->name)) {
|
||||
err = 0;
|
||||
list_add(&governor->governor_list, &cpufreq_governor_list);
|
||||
}
|
||||
|
@ -2307,8 +2277,7 @@ int cpufreq_update_policy(unsigned int cpu)
|
|||
policy->cur = new_policy.cur;
|
||||
} else {
|
||||
if (policy->cur != new_policy.cur && has_target())
|
||||
cpufreq_out_of_sync(cpu, policy->cur,
|
||||
new_policy.cur);
|
||||
cpufreq_out_of_sync(policy, new_policy.cur);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2364,7 +2333,7 @@ static int cpufreq_boost_set_sw(int state)
|
|||
struct cpufreq_policy *policy;
|
||||
int ret = -EINVAL;
|
||||
|
||||
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
|
||||
for_each_policy(policy) {
|
||||
freq_table = cpufreq_frequency_get_table(policy->cpu);
|
||||
if (freq_table) {
|
||||
ret = cpufreq_frequency_table_cpuinfo(policy,
|
||||
|
@ -2454,9 +2423,6 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
|||
|
||||
pr_debug("trying to register driver %s\n", driver_data->name);
|
||||
|
||||
if (driver_data->setpolicy)
|
||||
driver_data->flags |= CPUFREQ_CONST_LOOPS;
|
||||
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
if (cpufreq_driver) {
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
@ -2465,6 +2431,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
|||
cpufreq_driver = driver_data;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
if (driver_data->setpolicy)
|
||||
driver_data->flags |= CPUFREQ_CONST_LOOPS;
|
||||
|
||||
if (cpufreq_boost_supported()) {
|
||||
/*
|
||||
* Check if driver provides function to enable boost -
|
||||
|
@ -2485,23 +2454,12 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
|||
if (ret)
|
||||
goto err_boost_unreg;
|
||||
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
|
||||
int i;
|
||||
ret = -ENODEV;
|
||||
|
||||
/* check for at least one working CPU */
|
||||
for (i = 0; i < nr_cpu_ids; i++)
|
||||
if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_STICKY) &&
|
||||
list_empty(&cpufreq_policy_list)) {
|
||||
/* if all ->init() calls failed, unregister */
|
||||
if (ret) {
|
||||
pr_debug("no CPU initialized for driver %s\n",
|
||||
driver_data->name);
|
||||
goto err_if_unreg;
|
||||
}
|
||||
pr_debug("%s: No CPU initialized for driver %s\n", __func__,
|
||||
driver_data->name);
|
||||
goto err_if_unreg;
|
||||
}
|
||||
|
||||
register_hotcpu_notifier(&cpufreq_cpu_notifier);
|
||||
|
@ -2556,6 +2514,14 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
|
||||
|
||||
/*
|
||||
* Stop cpufreq at shutdown to make sure it isn't holding any locks
|
||||
* or mutexes when secondary CPUs are halted.
|
||||
*/
|
||||
static struct syscore_ops cpufreq_syscore_ops = {
|
||||
.shutdown = cpufreq_suspend,
|
||||
};
|
||||
|
||||
static int __init cpufreq_core_init(void)
|
||||
{
|
||||
if (cpufreq_disabled())
|
||||
|
@ -2564,6 +2530,8 @@ static int __init cpufreq_core_init(void)
|
|||
cpufreq_global_kobject = kobject_create();
|
||||
BUG_ON(!cpufreq_global_kobject);
|
||||
|
||||
register_syscore_ops(&cpufreq_syscore_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(cpufreq_core_init);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
static spinlock_t cpufreq_stats_lock;
|
||||
|
||||
struct cpufreq_stats {
|
||||
unsigned int cpu;
|
||||
unsigned int total_trans;
|
||||
unsigned long long last_time;
|
||||
unsigned int max_state;
|
||||
|
@ -31,50 +30,33 @@ struct cpufreq_stats {
|
|||
#endif
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table);
|
||||
|
||||
struct cpufreq_stats_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t(*show) (struct cpufreq_stats *, char *);
|
||||
};
|
||||
|
||||
static int cpufreq_stats_update(unsigned int cpu)
|
||||
static int cpufreq_stats_update(struct cpufreq_stats *stats)
|
||||
{
|
||||
struct cpufreq_stats *stat;
|
||||
unsigned long long cur_time;
|
||||
unsigned long long cur_time = get_jiffies_64();
|
||||
|
||||
cur_time = get_jiffies_64();
|
||||
spin_lock(&cpufreq_stats_lock);
|
||||
stat = per_cpu(cpufreq_stats_table, cpu);
|
||||
if (stat->time_in_state)
|
||||
stat->time_in_state[stat->last_index] +=
|
||||
cur_time - stat->last_time;
|
||||
stat->last_time = cur_time;
|
||||
stats->time_in_state[stats->last_index] += cur_time - stats->last_time;
|
||||
stats->last_time = cur_time;
|
||||
spin_unlock(&cpufreq_stats_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
|
||||
if (!stat)
|
||||
return 0;
|
||||
return sprintf(buf, "%d\n",
|
||||
per_cpu(cpufreq_stats_table, stat->cpu)->total_trans);
|
||||
return sprintf(buf, "%d\n", policy->stats->total_trans);
|
||||
}
|
||||
|
||||
static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
struct cpufreq_stats *stats = policy->stats;
|
||||
ssize_t len = 0;
|
||||
int i;
|
||||
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
|
||||
if (!stat)
|
||||
return 0;
|
||||
cpufreq_stats_update(stat->cpu);
|
||||
for (i = 0; i < stat->state_num; i++) {
|
||||
len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
|
||||
|
||||
cpufreq_stats_update(stats);
|
||||
for (i = 0; i < stats->state_num; i++) {
|
||||
len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i],
|
||||
(unsigned long long)
|
||||
jiffies_64_to_clock_t(stat->time_in_state[i]));
|
||||
jiffies_64_to_clock_t(stats->time_in_state[i]));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
@ -82,38 +64,35 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
|
|||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
struct cpufreq_stats *stats = policy->stats;
|
||||
ssize_t len = 0;
|
||||
int i, j;
|
||||
|
||||
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
|
||||
if (!stat)
|
||||
return 0;
|
||||
cpufreq_stats_update(stat->cpu);
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, " : ");
|
||||
for (i = 0; i < stat->state_num; i++) {
|
||||
for (i = 0; i < stats->state_num; i++) {
|
||||
if (len >= PAGE_SIZE)
|
||||
break;
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
|
||||
stat->freq_table[i]);
|
||||
stats->freq_table[i]);
|
||||
}
|
||||
if (len >= PAGE_SIZE)
|
||||
return PAGE_SIZE;
|
||||
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
|
||||
|
||||
for (i = 0; i < stat->state_num; i++) {
|
||||
for (i = 0; i < stats->state_num; i++) {
|
||||
if (len >= PAGE_SIZE)
|
||||
break;
|
||||
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
|
||||
stat->freq_table[i]);
|
||||
stats->freq_table[i]);
|
||||
|
||||
for (j = 0; j < stat->state_num; j++) {
|
||||
for (j = 0; j < stats->state_num; j++) {
|
||||
if (len >= PAGE_SIZE)
|
||||
break;
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
|
||||
stat->trans_table[i*stat->max_state+j]);
|
||||
stats->trans_table[i*stats->max_state+j]);
|
||||
}
|
||||
if (len >= PAGE_SIZE)
|
||||
break;
|
||||
|
@ -142,28 +121,29 @@ static struct attribute_group stats_attr_group = {
|
|||
.name = "stats"
|
||||
};
|
||||
|
||||
static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
|
||||
static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq)
|
||||
{
|
||||
int index;
|
||||
for (index = 0; index < stat->max_state; index++)
|
||||
if (stat->freq_table[index] == freq)
|
||||
for (index = 0; index < stats->max_state; index++)
|
||||
if (stats->freq_table[index] == freq)
|
||||
return index;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void __cpufreq_stats_free_table(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
|
||||
struct cpufreq_stats *stats = policy->stats;
|
||||
|
||||
if (!stat)
|
||||
/* Already freed */
|
||||
if (!stats)
|
||||
return;
|
||||
|
||||
pr_debug("%s: Free stat table\n", __func__);
|
||||
pr_debug("%s: Free stats table\n", __func__);
|
||||
|
||||
sysfs_remove_group(&policy->kobj, &stats_attr_group);
|
||||
kfree(stat->time_in_state);
|
||||
kfree(stat);
|
||||
per_cpu(cpufreq_stats_table, policy->cpu) = NULL;
|
||||
kfree(stats->time_in_state);
|
||||
kfree(stats);
|
||||
policy->stats = NULL;
|
||||
}
|
||||
|
||||
static void cpufreq_stats_free_table(unsigned int cpu)
|
||||
|
@ -174,37 +154,33 @@ static void cpufreq_stats_free_table(unsigned int cpu)
|
|||
if (!policy)
|
||||
return;
|
||||
|
||||
if (cpufreq_frequency_get_table(policy->cpu))
|
||||
__cpufreq_stats_free_table(policy);
|
||||
__cpufreq_stats_free_table(policy);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int i, count = 0, ret = 0;
|
||||
struct cpufreq_stats *stat;
|
||||
unsigned int i = 0, count = 0, ret = -ENOMEM;
|
||||
struct cpufreq_stats *stats;
|
||||
unsigned int alloc_size;
|
||||
unsigned int cpu = policy->cpu;
|
||||
struct cpufreq_frequency_table *pos, *table;
|
||||
|
||||
/* We need cpufreq table for creating stats table */
|
||||
table = cpufreq_frequency_get_table(cpu);
|
||||
if (unlikely(!table))
|
||||
return 0;
|
||||
|
||||
if (per_cpu(cpufreq_stats_table, cpu))
|
||||
return -EBUSY;
|
||||
stat = kzalloc(sizeof(*stat), GFP_KERNEL);
|
||||
if ((stat) == NULL)
|
||||
/* stats already initialized */
|
||||
if (policy->stats)
|
||||
return -EEXIST;
|
||||
|
||||
stats = kzalloc(sizeof(*stats), GFP_KERNEL);
|
||||
if (!stats)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
|
||||
stat->cpu = cpu;
|
||||
per_cpu(cpufreq_stats_table, cpu) = stat;
|
||||
|
||||
/* Find total allocation size */
|
||||
cpufreq_for_each_valid_entry(pos, table)
|
||||
count++;
|
||||
|
||||
|
@ -213,32 +189,40 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
|
|||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
alloc_size += count * count * sizeof(int);
|
||||
#endif
|
||||
stat->max_state = count;
|
||||
stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
|
||||
if (!stat->time_in_state) {
|
||||
ret = -ENOMEM;
|
||||
goto error_alloc;
|
||||
}
|
||||
stat->freq_table = (unsigned int *)(stat->time_in_state + count);
|
||||
|
||||
/* Allocate memory for time_in_state/freq_table/trans_table in one go */
|
||||
stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
|
||||
if (!stats->time_in_state)
|
||||
goto free_stat;
|
||||
|
||||
stats->freq_table = (unsigned int *)(stats->time_in_state + count);
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
stat->trans_table = stat->freq_table + count;
|
||||
stats->trans_table = stats->freq_table + count;
|
||||
#endif
|
||||
i = 0;
|
||||
|
||||
stats->max_state = count;
|
||||
|
||||
/* Find valid-unique entries */
|
||||
cpufreq_for_each_valid_entry(pos, table)
|
||||
if (freq_table_get_index(stat, pos->frequency) == -1)
|
||||
stat->freq_table[i++] = pos->frequency;
|
||||
stat->state_num = i;
|
||||
spin_lock(&cpufreq_stats_lock);
|
||||
stat->last_time = get_jiffies_64();
|
||||
stat->last_index = freq_table_get_index(stat, policy->cur);
|
||||
spin_unlock(&cpufreq_stats_lock);
|
||||
return 0;
|
||||
error_alloc:
|
||||
sysfs_remove_group(&policy->kobj, &stats_attr_group);
|
||||
error_out:
|
||||
kfree(stat);
|
||||
per_cpu(cpufreq_stats_table, cpu) = NULL;
|
||||
if (freq_table_get_index(stats, pos->frequency) == -1)
|
||||
stats->freq_table[i++] = pos->frequency;
|
||||
|
||||
stats->state_num = i;
|
||||
stats->last_time = get_jiffies_64();
|
||||
stats->last_index = freq_table_get_index(stats, policy->cur);
|
||||
|
||||
policy->stats = stats;
|
||||
ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
/* We failed, release resources */
|
||||
policy->stats = NULL;
|
||||
kfree(stats->time_in_state);
|
||||
free_stat:
|
||||
kfree(stats);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -259,30 +243,12 @@ static void cpufreq_stats_create_table(unsigned int cpu)
|
|||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
|
||||
policy->last_cpu);
|
||||
|
||||
pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n",
|
||||
policy->cpu, policy->last_cpu);
|
||||
per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table,
|
||||
policy->last_cpu);
|
||||
per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL;
|
||||
stat->cpu = policy->cpu;
|
||||
}
|
||||
|
||||
static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cpufreq_policy *policy = data;
|
||||
|
||||
if (val == CPUFREQ_UPDATE_POLICY_CPU) {
|
||||
cpufreq_stats_update_policy_cpu(policy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val == CPUFREQ_CREATE_POLICY)
|
||||
ret = __cpufreq_stats_create_table(policy);
|
||||
else if (val == CPUFREQ_REMOVE_POLICY)
|
||||
|
@ -295,35 +261,45 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
|
|||
unsigned long val, void *data)
|
||||
{
|
||||
struct cpufreq_freqs *freq = data;
|
||||
struct cpufreq_stats *stat;
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(freq->cpu);
|
||||
struct cpufreq_stats *stats;
|
||||
int old_index, new_index;
|
||||
|
||||
if (!policy) {
|
||||
pr_err("%s: No policy found\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val != CPUFREQ_POSTCHANGE)
|
||||
return 0;
|
||||
goto put_policy;
|
||||
|
||||
stat = per_cpu(cpufreq_stats_table, freq->cpu);
|
||||
if (!stat)
|
||||
return 0;
|
||||
if (!policy->stats) {
|
||||
pr_debug("%s: No stats found\n", __func__);
|
||||
goto put_policy;
|
||||
}
|
||||
|
||||
old_index = stat->last_index;
|
||||
new_index = freq_table_get_index(stat, freq->new);
|
||||
stats = policy->stats;
|
||||
|
||||
/* We can't do stat->time_in_state[-1]= .. */
|
||||
old_index = stats->last_index;
|
||||
new_index = freq_table_get_index(stats, freq->new);
|
||||
|
||||
/* We can't do stats->time_in_state[-1]= .. */
|
||||
if (old_index == -1 || new_index == -1)
|
||||
return 0;
|
||||
|
||||
cpufreq_stats_update(freq->cpu);
|
||||
goto put_policy;
|
||||
|
||||
if (old_index == new_index)
|
||||
return 0;
|
||||
goto put_policy;
|
||||
|
||||
spin_lock(&cpufreq_stats_lock);
|
||||
stat->last_index = new_index;
|
||||
cpufreq_stats_update(stats);
|
||||
|
||||
stats->last_index = new_index;
|
||||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
stat->trans_table[old_index * stat->max_state + new_index]++;
|
||||
stats->trans_table[old_index * stats->max_state + new_index]++;
|
||||
#endif
|
||||
stat->total_trans++;
|
||||
spin_unlock(&cpufreq_stats_lock);
|
||||
stats->total_trans++;
|
||||
|
||||
put_policy:
|
||||
cpufreq_cpu_put(policy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -374,8 +350,7 @@ static void __exit cpufreq_stats_exit(void)
|
|||
}
|
||||
|
||||
MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
|
||||
MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats "
|
||||
"through sysfs filesystem");
|
||||
MODULE_DESCRIPTION("Export cpufreq stats via sysfs");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(cpufreq_stats_init);
|
||||
|
|
|
@ -148,6 +148,8 @@ struct perf_limits {
|
|||
int32_t min_perf;
|
||||
int max_policy_pct;
|
||||
int max_sysfs_pct;
|
||||
int min_policy_pct;
|
||||
int min_sysfs_pct;
|
||||
};
|
||||
|
||||
static struct perf_limits limits = {
|
||||
|
@ -159,6 +161,8 @@ static struct perf_limits limits = {
|
|||
.min_perf = 0,
|
||||
.max_policy_pct = 100,
|
||||
.max_sysfs_pct = 100,
|
||||
.min_policy_pct = 0,
|
||||
.min_sysfs_pct = 0,
|
||||
};
|
||||
|
||||
static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
|
||||
|
@ -338,6 +342,33 @@ static void __init intel_pstate_debug_expose_params(void)
|
|||
return sprintf(buf, "%u\n", limits.object); \
|
||||
}
|
||||
|
||||
static ssize_t show_turbo_pct(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
struct cpudata *cpu;
|
||||
int total, no_turbo, turbo_pct;
|
||||
uint32_t turbo_fp;
|
||||
|
||||
cpu = all_cpu_data[0];
|
||||
|
||||
total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1;
|
||||
no_turbo = cpu->pstate.max_pstate - cpu->pstate.min_pstate + 1;
|
||||
turbo_fp = div_fp(int_tofp(no_turbo), int_tofp(total));
|
||||
turbo_pct = 100 - fp_toint(mul_fp(turbo_fp, int_tofp(100)));
|
||||
return sprintf(buf, "%u\n", turbo_pct);
|
||||
}
|
||||
|
||||
static ssize_t show_num_pstates(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
struct cpudata *cpu;
|
||||
int total;
|
||||
|
||||
cpu = all_cpu_data[0];
|
||||
total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1;
|
||||
return sprintf(buf, "%u\n", total);
|
||||
}
|
||||
|
||||
static ssize_t show_no_turbo(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -404,7 +435,9 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
|
|||
ret = sscanf(buf, "%u", &input);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
limits.min_perf_pct = clamp_t(int, input, 0 , 100);
|
||||
|
||||
limits.min_sysfs_pct = clamp_t(int, input, 0 , 100);
|
||||
limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
|
||||
if (hwp_active)
|
||||
|
@ -418,11 +451,15 @@ show_one(min_perf_pct, min_perf_pct);
|
|||
define_one_global_rw(no_turbo);
|
||||
define_one_global_rw(max_perf_pct);
|
||||
define_one_global_rw(min_perf_pct);
|
||||
define_one_global_ro(turbo_pct);
|
||||
define_one_global_ro(num_pstates);
|
||||
|
||||
static struct attribute *intel_pstate_attributes[] = {
|
||||
&no_turbo.attr,
|
||||
&max_perf_pct.attr,
|
||||
&min_perf_pct.attr,
|
||||
&turbo_pct.attr,
|
||||
&num_pstates.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -825,6 +862,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
|
|||
ICPU(0x46, core_params),
|
||||
ICPU(0x47, core_params),
|
||||
ICPU(0x4c, byt_params),
|
||||
ICPU(0x4e, core_params),
|
||||
ICPU(0x4f, core_params),
|
||||
ICPU(0x56, core_params),
|
||||
{}
|
||||
|
@ -887,7 +925,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
|
|||
if (!policy->cpuinfo.max_freq)
|
||||
return -ENODEV;
|
||||
|
||||
if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
|
||||
if (policy->policy == CPUFREQ_POLICY_PERFORMANCE &&
|
||||
policy->max >= policy->cpuinfo.max_freq) {
|
||||
limits.min_policy_pct = 100;
|
||||
limits.min_perf_pct = 100;
|
||||
limits.min_perf = int_tofp(1);
|
||||
limits.max_policy_pct = 100;
|
||||
|
@ -897,8 +937,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
|
|||
return 0;
|
||||
}
|
||||
|
||||
limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
||||
limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
|
||||
limits.min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
||||
limits.min_policy_pct = clamp_t(int, limits.min_policy_pct, 0 , 100);
|
||||
limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
|
||||
limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
|
||||
|
@ -978,6 +1019,7 @@ static struct cpufreq_driver intel_pstate_driver = {
|
|||
|
||||
static int __initdata no_load;
|
||||
static int __initdata no_hwp;
|
||||
static int __initdata hwp_only;
|
||||
static unsigned int force_load;
|
||||
|
||||
static int intel_pstate_msrs_not_valid(void)
|
||||
|
@ -1175,6 +1217,9 @@ static int __init intel_pstate_init(void)
|
|||
if (cpu_has(c,X86_FEATURE_HWP) && !no_hwp)
|
||||
intel_pstate_hwp_enable();
|
||||
|
||||
if (!hwp_active && hwp_only)
|
||||
goto out;
|
||||
|
||||
rc = cpufreq_register_driver(&intel_pstate_driver);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
@ -1209,6 +1254,8 @@ static int __init intel_pstate_setup(char *str)
|
|||
no_hwp = 1;
|
||||
if (!strcmp(str, "force"))
|
||||
force_load = 1;
|
||||
if (!strcmp(str, "hwp_only"))
|
||||
hwp_only = 1;
|
||||
return 0;
|
||||
}
|
||||
early_param("intel_pstate", intel_pstate_setup);
|
||||
|
|
|
@ -210,7 +210,6 @@ out:
|
|||
static struct platform_driver ls1x_cpufreq_platdrv = {
|
||||
.driver = {
|
||||
.name = "ls1x-cpufreq",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ls1x_cpufreq_probe,
|
||||
.remove = ls1x_cpufreq_remove,
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* SFI Performance States Driver
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* Author: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
|
||||
* Author: Srinidhi Kasagar <srinidhi.kasagar@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sfi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
#include <asm/msr.h>
|
||||
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
static struct sfi_freq_table_entry *sfi_cpufreq_array;
|
||||
static int num_freq_table_entries;
|
||||
|
||||
static int sfi_parse_freq(struct sfi_table_header *table)
|
||||
{
|
||||
struct sfi_table_simple *sb;
|
||||
struct sfi_freq_table_entry *pentry;
|
||||
int totallen;
|
||||
|
||||
sb = (struct sfi_table_simple *)table;
|
||||
num_freq_table_entries = SFI_GET_NUM_ENTRIES(sb,
|
||||
struct sfi_freq_table_entry);
|
||||
if (num_freq_table_entries <= 1) {
|
||||
pr_err("No p-states discovered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pentry = (struct sfi_freq_table_entry *)sb->pentry;
|
||||
totallen = num_freq_table_entries * sizeof(*pentry);
|
||||
|
||||
sfi_cpufreq_array = kzalloc(totallen, GFP_KERNEL);
|
||||
if (!sfi_cpufreq_array)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(sfi_cpufreq_array, pentry, totallen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sfi_cpufreq_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
unsigned int next_perf_state = 0; /* Index into perf table */
|
||||
u32 lo, hi;
|
||||
|
||||
next_perf_state = policy->freq_table[index].driver_data;
|
||||
|
||||
rdmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, &lo, &hi);
|
||||
lo = (lo & ~INTEL_PERF_CTL_MASK) |
|
||||
((u32) sfi_cpufreq_array[next_perf_state].ctrl_val &
|
||||
INTEL_PERF_CTL_MASK);
|
||||
wrmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, lo, hi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
|
||||
policy->cpuinfo.transition_latency = 100000; /* 100us */
|
||||
|
||||
return cpufreq_table_validate_and_show(policy, freq_table);
|
||||
}
|
||||
|
||||
static struct cpufreq_driver sfi_cpufreq_driver = {
|
||||
.flags = CPUFREQ_CONST_LOOPS,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = sfi_cpufreq_target,
|
||||
.init = sfi_cpufreq_cpu_init,
|
||||
.name = "sfi-cpufreq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
||||
static int __init sfi_cpufreq_init(void)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
/* parse the freq table from SFI */
|
||||
ret = sfi_table_parse(SFI_SIG_FREQ, NULL, NULL, sfi_parse_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
freq_table = kzalloc(sizeof(*freq_table) *
|
||||
(num_freq_table_entries + 1), GFP_KERNEL);
|
||||
if (!freq_table) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_array;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_freq_table_entries; i++) {
|
||||
freq_table[i].driver_data = i;
|
||||
freq_table[i].frequency = sfi_cpufreq_array[i].freq_mhz * 1000;
|
||||
}
|
||||
freq_table[i].frequency = CPUFREQ_TABLE_END;
|
||||
|
||||
ret = cpufreq_register_driver(&sfi_cpufreq_driver);
|
||||
if (ret)
|
||||
goto err_free_tbl;
|
||||
|
||||
return ret;
|
||||
|
||||
err_free_tbl:
|
||||
kfree(freq_table);
|
||||
err_free_array:
|
||||
kfree(sfi_cpufreq_array);
|
||||
return ret;
|
||||
}
|
||||
late_initcall(sfi_cpufreq_init);
|
||||
|
||||
static void __exit sfi_cpufreq_exit(void)
|
||||
{
|
||||
cpufreq_unregister_driver(&sfi_cpufreq_driver);
|
||||
kfree(freq_table);
|
||||
kfree(sfi_cpufreq_array);
|
||||
}
|
||||
module_exit(sfi_cpufreq_exit);
|
||||
|
||||
MODULE_AUTHOR("Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>");
|
||||
MODULE_DESCRIPTION("SFI Performance-States Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -161,7 +161,7 @@ static int sfi_verify_table(struct sfi_table_header *table)
|
|||
* Check for common case that we can re-use mapping to SYST,
|
||||
* which requires syst_pa, syst_va to be initialized.
|
||||
*/
|
||||
struct sfi_table_header *sfi_map_table(u64 pa)
|
||||
static struct sfi_table_header *sfi_map_table(u64 pa)
|
||||
{
|
||||
struct sfi_table_header *th;
|
||||
u32 length;
|
||||
|
@ -189,7 +189,7 @@ struct sfi_table_header *sfi_map_table(u64 pa)
|
|||
* Undoes effect of sfi_map_table() by unmapping table
|
||||
* if it did not completely fit on same page as SYST.
|
||||
*/
|
||||
void sfi_unmap_table(struct sfi_table_header *th)
|
||||
static void sfi_unmap_table(struct sfi_table_header *th)
|
||||
{
|
||||
if (!TABLE_ON_PAGE(syst_va, th, th->len))
|
||||
sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
|
||||
|
|
|
@ -66,8 +66,6 @@ struct cpufreq_policy {
|
|||
unsigned int shared_type; /* ACPI: ANY or ALL affected CPUs
|
||||
should set cpufreq */
|
||||
unsigned int cpu; /* cpu nr of CPU managing this policy */
|
||||
unsigned int last_cpu; /* cpu nr of previous CPU that managed
|
||||
* this policy */
|
||||
struct clk *clk;
|
||||
struct cpufreq_cpuinfo cpuinfo;/* see above */
|
||||
|
||||
|
@ -113,6 +111,9 @@ struct cpufreq_policy {
|
|||
wait_queue_head_t transition_wait;
|
||||
struct task_struct *transition_task; /* Task which is doing the transition */
|
||||
|
||||
/* cpufreq-stats */
|
||||
struct cpufreq_stats *stats;
|
||||
|
||||
/* For cpufreq driver's internal use */
|
||||
void *driver_data;
|
||||
};
|
||||
|
@ -367,9 +368,8 @@ static inline void cpufreq_resume(void) {}
|
|||
#define CPUFREQ_INCOMPATIBLE (1)
|
||||
#define CPUFREQ_NOTIFY (2)
|
||||
#define CPUFREQ_START (3)
|
||||
#define CPUFREQ_UPDATE_POLICY_CPU (4)
|
||||
#define CPUFREQ_CREATE_POLICY (5)
|
||||
#define CPUFREQ_REMOVE_POLICY (6)
|
||||
#define CPUFREQ_CREATE_POLICY (4)
|
||||
#define CPUFREQ_REMOVE_POLICY (5)
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
|
||||
|
|
Loading…
Reference in New Issue