02c3de1105
- Operating Performance Points (OPP) framework fixes, cleanups and switch over from RCU-based synchronization to reference counting using krefs (Viresh Kumar, Wei Yongjun, Dave Gerlach). - cpufreq core cleanups and documentation updates (Viresh Kumar, Rafael Wysocki). - New cpufreq driver for Broadcom BMIPS SoCs (Markus Mayer). - New cpufreq-dt sub-driver for TI SoCs requiring special handling, like in the AM335x, AM437x, DRA7x, and AM57x families, along with new DT bindings for it (Dave Gerlach, Paul Gortmaker). - ARM64 SoCs support for the qoriq cpufreq driver (Tang Yuantian). - intel_pstate driver updates including a new sysfs knob to control the driver's operation mode and fixes related to the no_turbo sysfs knob and the hardware-managed P-states feature support (Rafael Wysocki, Srinivas Pandruvada). - New interface to export ultra-turbo frequencies for the powernv cpufreq driver (Shilpasri Bhat). - Assorted fixes for cpufreq drivers (Arnd Bergmann, Dan Carpenter, Wei Yongjun). - devfreq core fixes, mostly related to the sysfs interface exported by it (Chanwoo Choi, Chris Diamand). - Updates of the exynos-bus and exynos-ppmu devfreq drivers (Chanwoo Choi). - Device PM QoS extension to support CPUs and support for per-CPU wakeup (device resume) latency constraints in the cpuidle menu governor (Alex Shi). - Wakeup IRQs framework fixes (Grygorii Strashko). - Generic power domains framework update including a fix to make it handle asynchronous invocations of *noirq suspend/resume callbacks correctly (Ulf Hansson, Geert Uytterhoeven). - Assorted fixes and cleanups in the core suspend/hibernate code, PM QoS framework and x86 ACPI idle support code (Corentin Labbe, Geert Uytterhoeven, Geliang Tang, John Keeping, Nick Desaulniers). - Update of the analyze_suspend.py script is updated to version 4.5 offering multiple improvements (Todd Brandt). - New tool for intel_pstate diagnostics using the pstate_sample tracepoint (Doug Smythies). -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJYq3IjAAoJEILEb/54YlRx/lYP+gNXhfETSzjd4kWSHy3FVEDb gc5rMiE2j0OYgVSXwBI7p4EqMPy56lSWBASvbF2o6v9CIxb880KLFEsMDCVHwn46 6xfEnIRxf1oeRqn7EG9ZPIcTgNsUyvK+gah7zgLXu/0KU7ceXxygvNk47qpeOZ8f dKYgIk/TOSGPC8H2nsg8VBKlK/ZOj5hID4F3MmFw6yDuWVCYuh2EokYXS4Nx0JwY UQGpWtz+FWWs71vhgVl33GbPXWvPqA7OMe0btZ3RCnhnz4tA/mH+jDWiaspCdS3J vKGeZyZptjIMJcufm3X7s7ghYjELheqQusMODDXk4AaWQ5nz8V5/h7NThYfa9J1b M93Tb0rMb2MqUhBpv/M6D3qQroZmhq55QKfQrul3QWSOiQUzTWJcbbpyeBQ7nkrI F1qNqQfuCnBL/r9y7HpW8P2iFg9kCHkwTtXMdp/lzGXdKzSGtAUSkYg5ohnUzQTp 2WCPTEk+5DxLVPjW5rDoZOotr5p1kdcdWBk6r3MEWRokZK6PJo7rJBcnTtXSo2mO lLRba006q+fTlI5wZtjAI0rOiS3JgtT6cRx7uPjZlze9TGjklJhdsCPJbM5gcOT+ YiOxvqD+9if5QRSxiEZNj3bQ43wYhXmpctfIanyxziq09BPIPxvgfRR/BkUzc34R ps4CIvImim5v5xc8Zsbk =57xJ -----END PGP SIGNATURE----- Merge tag 'pm-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull power management updates from Rafael Wysocki: "The majority of changes go into the Operating Performance Points (OPP) framework and cpufreq this time, followed by devfreq and some scattered updates all over. The OPP changes are mostly related to switching over from RCU-based synchronization, that turned out to be overly complicated and problematic, to reference counting using krefs. In the cpufreq land there are core cleanups, documentation updates, a new driver for Broadcom BMIPS SoCs, a new cpufreq-dt sub-driver for TI SoCs that require special handling, ARM64 SoCs support for the qoriq driver, intel_pstate updates, powernv driver update and assorted fixes. The devfreq changes are mostly fixes related to the sysfs interface and some Exynos drivers updates. Apart from that, the cpuidle menu governor will support per-CPU PM QoS constraints for the wakeup latency now, some bugs in the wakeup IRQs framework are fixed, the generic power domains framework should handle asynchronous invocations of *noirq suspend/resume callbacks from now on, the analyze_suspend.py script is updated and there is a new tool for intel_pstate diagnostics. Specifics: - Operating Performance Points (OPP) framework fixes, cleanups and switch over from RCU-based synchronization to reference counting using krefs (Viresh Kumar, Wei Yongjun, Dave Gerlach) - cpufreq core cleanups and documentation updates (Viresh Kumar, Rafael Wysocki) - New cpufreq driver for Broadcom BMIPS SoCs (Markus Mayer) - New cpufreq-dt sub-driver for TI SoCs requiring special handling, like in the AM335x, AM437x, DRA7x, and AM57x families, along with new DT bindings for it (Dave Gerlach, Paul Gortmaker) - ARM64 SoCs support for the qoriq cpufreq driver (Tang Yuantian) - intel_pstate driver updates including a new sysfs knob to control the driver's operation mode and fixes related to the no_turbo sysfs knob and the hardware-managed P-states feature support (Rafael Wysocki, Srinivas Pandruvada) - New interface to export ultra-turbo frequencies for the powernv cpufreq driver (Shilpasri Bhat) - Assorted fixes for cpufreq drivers (Arnd Bergmann, Dan Carpenter, Wei Yongjun) - devfreq core fixes, mostly related to the sysfs interface exported by it (Chanwoo Choi, Chris Diamand) - Updates of the exynos-bus and exynos-ppmu devfreq drivers (Chanwoo Choi) - Device PM QoS extension to support CPUs and support for per-CPU wakeup (device resume) latency constraints in the cpuidle menu governor (Alex Shi) - Wakeup IRQs framework fixes (Grygorii Strashko) - Generic power domains framework update including a fix to make it handle asynchronous invocations of *noirq suspend/resume callbacks correctly (Ulf Hansson, Geert Uytterhoeven) - Assorted fixes and cleanups in the core suspend/hibernate code, PM QoS framework and x86 ACPI idle support code (Corentin Labbe, Geert Uytterhoeven, Geliang Tang, John Keeping, Nick Desaulniers) - Update of the analyze_suspend.py script is updated to version 4.5 offering multiple improvements (Todd Brandt) - New tool for intel_pstate diagnostics using the pstate_sample tracepoint (Doug Smythies)" * tag 'pm-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (85 commits) MAINTAINERS: cpufreq: add bmips-cpufreq.c PM / QoS: Fix memory leak on resume_latency.notifiers PM / Documentation: Spelling s/wrtie/write/ PM / sleep: Fix test_suspend after sleep state rework cpufreq: CPPC: add ACPI_PROCESSOR dependency cpufreq: make ti-cpufreq explicitly non-modular cpufreq: Do not clear real_cpus mask on policy init tools/power/x86: Debug utility for intel_pstate driver AnalyzeSuspend: fix drag and zoom bug in javascript PM / wakeirq: report a wakeup_event on dedicated wekup irq PM / wakeirq: Fix spurious wake-up events for dedicated wakeirqs PM / wakeirq: Enable dedicated wakeirq for suspend cpufreq: dt: Don't use generic platdev driver for ti-cpufreq platforms cpufreq: ti: Add cpufreq driver to determine available OPPs at runtime Documentation: dt: add bindings for ti-cpufreq PM / OPP: Expose _of_get_opp_desc_node as dev_pm_opp API cpufreq: qoriq: Don't look at clock implementation details cpufreq: qoriq: add ARM64 SoCs support PM / Domains: Provide dummy governors if CONFIG_PM_GENERIC_DOMAINS=n cpufreq: brcmstb-avs-cpufreq: remove unnecessary platform_set_drvdata() ...
251 lines
6.1 KiB
C
251 lines
6.1 KiB
C
/*
|
|
* drivers/cpufreq/cpufreq_stats.c
|
|
*
|
|
* Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
|
|
* (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/cpu.h>
|
|
#include <linux/cpufreq.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
|
|
static DEFINE_SPINLOCK(cpufreq_stats_lock);
|
|
|
|
struct cpufreq_stats {
|
|
unsigned int total_trans;
|
|
unsigned long long last_time;
|
|
unsigned int max_state;
|
|
unsigned int state_num;
|
|
unsigned int last_index;
|
|
u64 *time_in_state;
|
|
unsigned int *freq_table;
|
|
unsigned int *trans_table;
|
|
};
|
|
|
|
static int cpufreq_stats_update(struct cpufreq_stats *stats)
|
|
{
|
|
unsigned long long cur_time = get_jiffies_64();
|
|
|
|
spin_lock(&cpufreq_stats_lock);
|
|
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 void cpufreq_stats_clear_table(struct cpufreq_stats *stats)
|
|
{
|
|
unsigned int count = stats->max_state;
|
|
|
|
memset(stats->time_in_state, 0, count * sizeof(u64));
|
|
memset(stats->trans_table, 0, count * count * sizeof(int));
|
|
stats->last_time = get_jiffies_64();
|
|
stats->total_trans = 0;
|
|
}
|
|
|
|
static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
|
|
{
|
|
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;
|
|
|
|
if (policy->fast_switch_enabled)
|
|
return 0;
|
|
|
|
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(stats->time_in_state[i]));
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
|
|
size_t count)
|
|
{
|
|
/* We don't care what is written to the attribute. */
|
|
cpufreq_stats_clear_table(policy->stats);
|
|
return count;
|
|
}
|
|
|
|
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;
|
|
|
|
if (policy->fast_switch_enabled)
|
|
return 0;
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
|
|
len += snprintf(buf + len, PAGE_SIZE - len, " : ");
|
|
for (i = 0; i < stats->state_num; i++) {
|
|
if (len >= PAGE_SIZE)
|
|
break;
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
|
|
stats->freq_table[i]);
|
|
}
|
|
if (len >= PAGE_SIZE)
|
|
return PAGE_SIZE;
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
|
|
|
|
for (i = 0; i < stats->state_num; i++) {
|
|
if (len >= PAGE_SIZE)
|
|
break;
|
|
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
|
|
stats->freq_table[i]);
|
|
|
|
for (j = 0; j < stats->state_num; j++) {
|
|
if (len >= PAGE_SIZE)
|
|
break;
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
|
|
stats->trans_table[i*stats->max_state+j]);
|
|
}
|
|
if (len >= PAGE_SIZE)
|
|
break;
|
|
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
|
|
}
|
|
if (len >= PAGE_SIZE)
|
|
return PAGE_SIZE;
|
|
return len;
|
|
}
|
|
cpufreq_freq_attr_ro(trans_table);
|
|
|
|
cpufreq_freq_attr_ro(total_trans);
|
|
cpufreq_freq_attr_ro(time_in_state);
|
|
cpufreq_freq_attr_wo(reset);
|
|
|
|
static struct attribute *default_attrs[] = {
|
|
&total_trans.attr,
|
|
&time_in_state.attr,
|
|
&reset.attr,
|
|
&trans_table.attr,
|
|
NULL
|
|
};
|
|
static struct attribute_group stats_attr_group = {
|
|
.attrs = default_attrs,
|
|
.name = "stats"
|
|
};
|
|
|
|
static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq)
|
|
{
|
|
int index;
|
|
for (index = 0; index < stats->max_state; index++)
|
|
if (stats->freq_table[index] == freq)
|
|
return index;
|
|
return -1;
|
|
}
|
|
|
|
void cpufreq_stats_free_table(struct cpufreq_policy *policy)
|
|
{
|
|
struct cpufreq_stats *stats = policy->stats;
|
|
|
|
/* Already freed */
|
|
if (!stats)
|
|
return;
|
|
|
|
pr_debug("%s: Free stats table\n", __func__);
|
|
|
|
sysfs_remove_group(&policy->kobj, &stats_attr_group);
|
|
kfree(stats->time_in_state);
|
|
kfree(stats);
|
|
policy->stats = NULL;
|
|
}
|
|
|
|
void cpufreq_stats_create_table(struct cpufreq_policy *policy)
|
|
{
|
|
unsigned int i = 0, count = 0, ret = -ENOMEM;
|
|
struct cpufreq_stats *stats;
|
|
unsigned int alloc_size;
|
|
struct cpufreq_frequency_table *pos, *table;
|
|
|
|
/* We need cpufreq table for creating stats table */
|
|
table = policy->freq_table;
|
|
if (unlikely(!table))
|
|
return;
|
|
|
|
/* stats already initialized */
|
|
if (policy->stats)
|
|
return;
|
|
|
|
stats = kzalloc(sizeof(*stats), GFP_KERNEL);
|
|
if (!stats)
|
|
return;
|
|
|
|
/* Find total allocation size */
|
|
cpufreq_for_each_valid_entry(pos, table)
|
|
count++;
|
|
|
|
alloc_size = count * sizeof(int) + count * sizeof(u64);
|
|
|
|
alloc_size += count * count * sizeof(int);
|
|
|
|
/* 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);
|
|
|
|
stats->trans_table = stats->freq_table + count;
|
|
|
|
stats->max_state = count;
|
|
|
|
/* Find valid-unique entries */
|
|
cpufreq_for_each_valid_entry(pos, table)
|
|
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;
|
|
|
|
/* We failed, release resources */
|
|
policy->stats = NULL;
|
|
kfree(stats->time_in_state);
|
|
free_stat:
|
|
kfree(stats);
|
|
}
|
|
|
|
void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
|
|
unsigned int new_freq)
|
|
{
|
|
struct cpufreq_stats *stats = policy->stats;
|
|
int old_index, new_index;
|
|
|
|
if (!stats) {
|
|
pr_debug("%s: No stats found\n", __func__);
|
|
return;
|
|
}
|
|
|
|
old_index = stats->last_index;
|
|
new_index = freq_table_get_index(stats, new_freq);
|
|
|
|
/* We can't do stats->time_in_state[-1]= .. */
|
|
if (old_index == -1 || new_index == -1 || old_index == new_index)
|
|
return;
|
|
|
|
cpufreq_stats_update(stats);
|
|
|
|
stats->last_index = new_index;
|
|
stats->trans_table[old_index * stats->max_state + new_index]++;
|
|
stats->total_trans++;
|
|
}
|