Merge branches 'pm-devfreq' and 'pm-tools'
* pm-devfreq: PM / devfreq: remove redundant null pointer check before kfree PM / devfreq: stopping the governor before device_unregister() PM / devfreq: Convert to using %pOFn instead of device_node.name PM / devfreq: Make update_devfreq() public PM / devfreq: Don't adjust to user limits in governors PM / devfreq: Fix handling of min/max_freq == 0 PM / devfreq: Drop custom MIN/MAX macros PM / devfreq: Fix devfreq_add_device() when drivers are built as modules. * pm-tools: PM / tools: sleepgraph and bootgraph: upgrade to v5.2 PM / tools: sleepgraph: first batch of v5.2 changes cpupower: Fix coredump on VMWare cpupower: Fix AMD Family 0x17 msr_pstate size cpupower: remove stringop-truncation waring
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kmod.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
@@ -28,9 +29,6 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include "governor.h"
|
#include "governor.h"
|
||||||
|
|
||||||
#define MAX(a,b) ((a > b) ? a : b)
|
|
||||||
#define MIN(a,b) ((a < b) ? a : b)
|
|
||||||
|
|
||||||
static struct class *devfreq_class;
|
static struct class *devfreq_class;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -221,6 +219,49 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
|
|||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* try_then_request_governor() - Try to find the governor and request the
|
||||||
|
* module if is not found.
|
||||||
|
* @name: name of the governor
|
||||||
|
*
|
||||||
|
* Search the list of devfreq governors and request the module and try again
|
||||||
|
* if is not found. This can happen when both drivers (the governor driver
|
||||||
|
* and the driver that call devfreq_add_device) are built as modules.
|
||||||
|
* devfreq_list_lock should be held by the caller. Returns the matched
|
||||||
|
* governor's pointer.
|
||||||
|
*/
|
||||||
|
static struct devfreq_governor *try_then_request_governor(const char *name)
|
||||||
|
{
|
||||||
|
struct devfreq_governor *governor;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(name)) {
|
||||||
|
pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
WARN(!mutex_is_locked(&devfreq_list_lock),
|
||||||
|
"devfreq_list_lock must be locked.");
|
||||||
|
|
||||||
|
governor = find_devfreq_governor(name);
|
||||||
|
if (IS_ERR(governor)) {
|
||||||
|
mutex_unlock(&devfreq_list_lock);
|
||||||
|
|
||||||
|
if (!strncmp(name, DEVFREQ_GOV_SIMPLE_ONDEMAND,
|
||||||
|
DEVFREQ_NAME_LEN))
|
||||||
|
err = request_module("governor_%s", "simpleondemand");
|
||||||
|
else
|
||||||
|
err = request_module("governor_%s", name);
|
||||||
|
/* Restore previous state before return */
|
||||||
|
mutex_lock(&devfreq_list_lock);
|
||||||
|
if (err)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
governor = find_devfreq_governor(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return governor;
|
||||||
|
}
|
||||||
|
|
||||||
static int devfreq_notify_transition(struct devfreq *devfreq,
|
static int devfreq_notify_transition(struct devfreq *devfreq,
|
||||||
struct devfreq_freqs *freqs, unsigned int state)
|
struct devfreq_freqs *freqs, unsigned int state)
|
||||||
{
|
{
|
||||||
@@ -280,14 +321,14 @@ int update_devfreq(struct devfreq *devfreq)
|
|||||||
* max_freq
|
* max_freq
|
||||||
* min_freq
|
* min_freq
|
||||||
*/
|
*/
|
||||||
max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq);
|
max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
|
||||||
min_freq = MAX(devfreq->scaling_min_freq, devfreq->min_freq);
|
min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
|
||||||
|
|
||||||
if (min_freq && freq < min_freq) {
|
if (freq < min_freq) {
|
||||||
freq = min_freq;
|
freq = min_freq;
|
||||||
flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
|
flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
|
||||||
}
|
}
|
||||||
if (max_freq && freq > max_freq) {
|
if (freq > max_freq) {
|
||||||
freq = max_freq;
|
freq = max_freq;
|
||||||
flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
|
flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
|
||||||
}
|
}
|
||||||
@@ -534,10 +575,6 @@ static void devfreq_dev_release(struct device *dev)
|
|||||||
list_del(&devfreq->node);
|
list_del(&devfreq->node);
|
||||||
mutex_unlock(&devfreq_list_lock);
|
mutex_unlock(&devfreq_list_lock);
|
||||||
|
|
||||||
if (devfreq->governor)
|
|
||||||
devfreq->governor->event_handler(devfreq,
|
|
||||||
DEVFREQ_GOV_STOP, NULL);
|
|
||||||
|
|
||||||
if (devfreq->profile->exit)
|
if (devfreq->profile->exit)
|
||||||
devfreq->profile->exit(devfreq->dev.parent);
|
devfreq->profile->exit(devfreq->dev.parent);
|
||||||
|
|
||||||
@@ -646,9 +683,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
|
|||||||
mutex_unlock(&devfreq->lock);
|
mutex_unlock(&devfreq->lock);
|
||||||
|
|
||||||
mutex_lock(&devfreq_list_lock);
|
mutex_lock(&devfreq_list_lock);
|
||||||
list_add(&devfreq->node, &devfreq_list);
|
|
||||||
|
|
||||||
governor = find_devfreq_governor(devfreq->governor_name);
|
governor = try_then_request_governor(devfreq->governor_name);
|
||||||
if (IS_ERR(governor)) {
|
if (IS_ERR(governor)) {
|
||||||
dev_err(dev, "%s: Unable to find governor for the device\n",
|
dev_err(dev, "%s: Unable to find governor for the device\n",
|
||||||
__func__);
|
__func__);
|
||||||
@@ -664,19 +700,20 @@ struct devfreq *devfreq_add_device(struct device *dev,
|
|||||||
__func__);
|
__func__);
|
||||||
goto err_init;
|
goto err_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list_add(&devfreq->node, &devfreq_list);
|
||||||
|
|
||||||
mutex_unlock(&devfreq_list_lock);
|
mutex_unlock(&devfreq_list_lock);
|
||||||
|
|
||||||
return devfreq;
|
return devfreq;
|
||||||
|
|
||||||
err_init:
|
err_init:
|
||||||
list_del(&devfreq->node);
|
|
||||||
mutex_unlock(&devfreq_list_lock);
|
mutex_unlock(&devfreq_list_lock);
|
||||||
|
|
||||||
device_unregister(&devfreq->dev);
|
devfreq_remove_device(devfreq);
|
||||||
devfreq = NULL;
|
devfreq = NULL;
|
||||||
err_dev:
|
err_dev:
|
||||||
if (devfreq)
|
kfree(devfreq);
|
||||||
kfree(devfreq);
|
|
||||||
err_out:
|
err_out:
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
@@ -693,6 +730,9 @@ int devfreq_remove_device(struct devfreq *devfreq)
|
|||||||
if (!devfreq)
|
if (!devfreq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (devfreq->governor)
|
||||||
|
devfreq->governor->event_handler(devfreq,
|
||||||
|
DEVFREQ_GOV_STOP, NULL);
|
||||||
device_unregister(&devfreq->dev);
|
device_unregister(&devfreq->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -991,7 +1031,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&devfreq_list_lock);
|
mutex_lock(&devfreq_list_lock);
|
||||||
governor = find_devfreq_governor(str_governor);
|
governor = try_then_request_governor(str_governor);
|
||||||
if (IS_ERR(governor)) {
|
if (IS_ERR(governor)) {
|
||||||
ret = PTR_ERR(governor);
|
ret = PTR_ERR(governor);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1126,17 +1166,26 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
|
|||||||
struct devfreq *df = to_devfreq(dev);
|
struct devfreq *df = to_devfreq(dev);
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long max;
|
|
||||||
|
|
||||||
ret = sscanf(buf, "%lu", &value);
|
ret = sscanf(buf, "%lu", &value);
|
||||||
if (ret != 1)
|
if (ret != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&df->lock);
|
mutex_lock(&df->lock);
|
||||||
max = df->max_freq;
|
|
||||||
if (value && max && value > max) {
|
if (value) {
|
||||||
ret = -EINVAL;
|
if (value > df->max_freq) {
|
||||||
goto unlock;
|
ret = -EINVAL;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned long *freq_table = df->profile->freq_table;
|
||||||
|
|
||||||
|
/* Get minimum frequency according to sorting order */
|
||||||
|
if (freq_table[0] < freq_table[df->profile->max_state - 1])
|
||||||
|
value = freq_table[0];
|
||||||
|
else
|
||||||
|
value = freq_table[df->profile->max_state - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
df->min_freq = value;
|
df->min_freq = value;
|
||||||
@@ -1152,7 +1201,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
|
|||||||
{
|
{
|
||||||
struct devfreq *df = to_devfreq(dev);
|
struct devfreq *df = to_devfreq(dev);
|
||||||
|
|
||||||
return sprintf(buf, "%lu\n", MAX(df->scaling_min_freq, df->min_freq));
|
return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
|
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
|
||||||
@@ -1161,17 +1210,26 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
|
|||||||
struct devfreq *df = to_devfreq(dev);
|
struct devfreq *df = to_devfreq(dev);
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long min;
|
|
||||||
|
|
||||||
ret = sscanf(buf, "%lu", &value);
|
ret = sscanf(buf, "%lu", &value);
|
||||||
if (ret != 1)
|
if (ret != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&df->lock);
|
mutex_lock(&df->lock);
|
||||||
min = df->min_freq;
|
|
||||||
if (value && min && value < min) {
|
if (value) {
|
||||||
ret = -EINVAL;
|
if (value < df->min_freq) {
|
||||||
goto unlock;
|
ret = -EINVAL;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned long *freq_table = df->profile->freq_table;
|
||||||
|
|
||||||
|
/* Get maximum frequency according to sorting order */
|
||||||
|
if (freq_table[0] < freq_table[df->profile->max_state - 1])
|
||||||
|
value = freq_table[df->profile->max_state - 1];
|
||||||
|
else
|
||||||
|
value = freq_table[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
df->max_freq = value;
|
df->max_freq = value;
|
||||||
@@ -1188,7 +1246,7 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
|
|||||||
{
|
{
|
||||||
struct devfreq *df = to_devfreq(dev);
|
struct devfreq *df = to_devfreq(dev);
|
||||||
|
|
||||||
return sprintf(buf, "%lu\n", MIN(df->scaling_max_freq, df->max_freq));
|
return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RW(max_freq);
|
static DEVICE_ATTR_RW(max_freq);
|
||||||
|
|
||||||
|
@@ -535,8 +535,8 @@ static int of_get_devfreq_events(struct device_node *np,
|
|||||||
|
|
||||||
if (i == ARRAY_SIZE(ppmu_events)) {
|
if (i == ARRAY_SIZE(ppmu_events)) {
|
||||||
dev_warn(dev,
|
dev_warn(dev,
|
||||||
"don't know how to configure events : %s\n",
|
"don't know how to configure events : %pOFn\n",
|
||||||
node->name);
|
node);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,6 +25,9 @@
|
|||||||
#define DEVFREQ_GOV_SUSPEND 0x4
|
#define DEVFREQ_GOV_SUSPEND 0x4
|
||||||
#define DEVFREQ_GOV_RESUME 0x5
|
#define DEVFREQ_GOV_RESUME 0x5
|
||||||
|
|
||||||
|
#define DEVFREQ_MIN_FREQ 0
|
||||||
|
#define DEVFREQ_MAX_FREQ ULONG_MAX
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct devfreq_governor - Devfreq policy governor
|
* struct devfreq_governor - Devfreq policy governor
|
||||||
* @node: list node - contains registered devfreq governors
|
* @node: list node - contains registered devfreq governors
|
||||||
@@ -54,9 +57,6 @@ struct devfreq_governor {
|
|||||||
unsigned int event, void *data);
|
unsigned int event, void *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Caution: devfreq->lock must be locked before calling update_devfreq */
|
|
||||||
extern int update_devfreq(struct devfreq *devfreq);
|
|
||||||
|
|
||||||
extern void devfreq_monitor_start(struct devfreq *devfreq);
|
extern void devfreq_monitor_start(struct devfreq *devfreq);
|
||||||
extern void devfreq_monitor_stop(struct devfreq *devfreq);
|
extern void devfreq_monitor_stop(struct devfreq *devfreq);
|
||||||
extern void devfreq_monitor_suspend(struct devfreq *devfreq);
|
extern void devfreq_monitor_suspend(struct devfreq *devfreq);
|
||||||
|
@@ -20,10 +20,7 @@ static int devfreq_performance_func(struct devfreq *df,
|
|||||||
* target callback should be able to get floor value as
|
* target callback should be able to get floor value as
|
||||||
* said in devfreq.h
|
* said in devfreq.h
|
||||||
*/
|
*/
|
||||||
if (!df->max_freq)
|
*freq = DEVFREQ_MAX_FREQ;
|
||||||
*freq = UINT_MAX;
|
|
||||||
else
|
|
||||||
*freq = df->max_freq;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,7 +20,7 @@ static int devfreq_powersave_func(struct devfreq *df,
|
|||||||
* target callback should be able to get ceiling value as
|
* target callback should be able to get ceiling value as
|
||||||
* said in devfreq.h
|
* said in devfreq.h
|
||||||
*/
|
*/
|
||||||
*freq = df->min_freq;
|
*freq = DEVFREQ_MIN_FREQ;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,7 +27,6 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
|
|||||||
unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
|
unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
|
||||||
unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
|
unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
|
||||||
struct devfreq_simple_ondemand_data *data = df->data;
|
struct devfreq_simple_ondemand_data *data = df->data;
|
||||||
unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;
|
|
||||||
|
|
||||||
err = devfreq_update_stats(df);
|
err = devfreq_update_stats(df);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -47,7 +46,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
|
|||||||
|
|
||||||
/* Assume MAX if it is going to be divided by zero */
|
/* Assume MAX if it is going to be divided by zero */
|
||||||
if (stat->total_time == 0) {
|
if (stat->total_time == 0) {
|
||||||
*freq = max;
|
*freq = DEVFREQ_MAX_FREQ;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,13 +59,13 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
|
|||||||
/* Set MAX if it's busy enough */
|
/* Set MAX if it's busy enough */
|
||||||
if (stat->busy_time * 100 >
|
if (stat->busy_time * 100 >
|
||||||
stat->total_time * dfso_upthreshold) {
|
stat->total_time * dfso_upthreshold) {
|
||||||
*freq = max;
|
*freq = DEVFREQ_MAX_FREQ;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set MAX if we do not know the initial frequency */
|
/* Set MAX if we do not know the initial frequency */
|
||||||
if (stat->current_frequency == 0) {
|
if (stat->current_frequency == 0) {
|
||||||
*freq = max;
|
*freq = DEVFREQ_MAX_FREQ;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,11 +84,6 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
|
|||||||
b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
|
b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
|
||||||
*freq = (unsigned long) b;
|
*freq = (unsigned long) b;
|
||||||
|
|
||||||
if (df->min_freq && *freq < df->min_freq)
|
|
||||||
*freq = df->min_freq;
|
|
||||||
if (df->max_freq && *freq > df->max_freq)
|
|
||||||
*freq = df->max_freq;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,19 +26,11 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
|
|||||||
{
|
{
|
||||||
struct userspace_data *data = df->data;
|
struct userspace_data *data = df->data;
|
||||||
|
|
||||||
if (data->valid) {
|
if (data->valid)
|
||||||
unsigned long adjusted_freq = data->user_frequency;
|
*freq = data->user_frequency;
|
||||||
|
else
|
||||||
if (df->max_freq && adjusted_freq > df->max_freq)
|
|
||||||
adjusted_freq = df->max_freq;
|
|
||||||
|
|
||||||
if (df->min_freq && adjusted_freq < df->min_freq)
|
|
||||||
adjusted_freq = df->min_freq;
|
|
||||||
|
|
||||||
*freq = adjusted_freq;
|
|
||||||
} else {
|
|
||||||
*freq = df->previous_freq; /* No user freq specified yet */
|
*freq = df->previous_freq; /* No user freq specified yet */
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -198,6 +198,14 @@ extern void devm_devfreq_remove_device(struct device *dev,
|
|||||||
extern int devfreq_suspend_device(struct devfreq *devfreq);
|
extern int devfreq_suspend_device(struct devfreq *devfreq);
|
||||||
extern int devfreq_resume_device(struct devfreq *devfreq);
|
extern int devfreq_resume_device(struct devfreq *devfreq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update_devfreq() - Reevaluate the device and configure frequency
|
||||||
|
* @devfreq: the devfreq device
|
||||||
|
*
|
||||||
|
* Note: devfreq->lock must be held
|
||||||
|
*/
|
||||||
|
extern int update_devfreq(struct devfreq *devfreq);
|
||||||
|
|
||||||
/* Helper functions for devfreq user device driver with OPP. */
|
/* Helper functions for devfreq user device driver with OPP. */
|
||||||
extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
|
extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
|
||||||
unsigned long *freq, u32 flags);
|
unsigned long *freq, u32 flags);
|
||||||
|
@@ -145,7 +145,7 @@ struct config *prepare_default_config()
|
|||||||
config->cpu = 0;
|
config->cpu = 0;
|
||||||
config->prio = SCHED_HIGH;
|
config->prio = SCHED_HIGH;
|
||||||
config->verbose = 0;
|
config->verbose = 0;
|
||||||
strncpy(config->governor, "ondemand", 8);
|
strncpy(config->governor, "ondemand", sizeof(config->governor));
|
||||||
|
|
||||||
config->output = stdout;
|
config->output = stdout;
|
||||||
|
|
||||||
|
@@ -200,6 +200,8 @@ static int get_boost_mode(unsigned int cpu)
|
|||||||
printf(_(" Boost States: %d\n"), b_states);
|
printf(_(" Boost States: %d\n"), b_states);
|
||||||
printf(_(" Total States: %d\n"), pstate_no);
|
printf(_(" Total States: %d\n"), pstate_no);
|
||||||
for (i = 0; i < pstate_no; i++) {
|
for (i = 0; i < pstate_no; i++) {
|
||||||
|
if (!pstates[i])
|
||||||
|
continue;
|
||||||
if (i < b_states)
|
if (i < b_states)
|
||||||
printf(_(" Pstate-Pb%d: %luMHz (boost state)"
|
printf(_(" Pstate-Pb%d: %luMHz (boost state)"
|
||||||
"\n"), i, pstates[i]);
|
"\n"), i, pstates[i]);
|
||||||
|
@@ -33,7 +33,7 @@ union msr_pstate {
|
|||||||
unsigned vid:8;
|
unsigned vid:8;
|
||||||
unsigned iddval:8;
|
unsigned iddval:8;
|
||||||
unsigned idddiv:2;
|
unsigned idddiv:2;
|
||||||
unsigned res1:30;
|
unsigned res1:31;
|
||||||
unsigned en:1;
|
unsigned en:1;
|
||||||
} fam17h_bits;
|
} fam17h_bits;
|
||||||
unsigned long long val;
|
unsigned long long val;
|
||||||
@@ -119,6 +119,11 @@ int decode_pstates(unsigned int cpu, unsigned int cpu_family,
|
|||||||
}
|
}
|
||||||
if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
|
if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
|
||||||
return -1;
|
return -1;
|
||||||
|
if ((cpu_family == 0x17) && (!pstate.fam17h_bits.en))
|
||||||
|
continue;
|
||||||
|
else if (!pstate.bits.en)
|
||||||
|
continue;
|
||||||
|
|
||||||
pstates[i] = get_cof(cpu_family, pstate);
|
pstates[i] = get_cof(cpu_family, pstate);
|
||||||
}
|
}
|
||||||
*no = i;
|
*no = i;
|
||||||
|
@@ -23,8 +23,8 @@ install : uninstall
|
|||||||
install -m 644 config/suspend-x2-proc.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
install -m 644 config/suspend-x2-proc.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
||||||
|
|
||||||
install -d $(DESTDIR)$(PREFIX)/bin
|
install -d $(DESTDIR)$(PREFIX)/bin
|
||||||
ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/bootgraph.py $(DESTDIR)$(PREFIX)/bin/bootgraph
|
ln -s ../lib/pm-graph/bootgraph.py $(DESTDIR)$(PREFIX)/bin/bootgraph
|
||||||
ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/sleepgraph.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
|
ln -s ../lib/pm-graph/sleepgraph.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
|
||||||
|
|
||||||
install -d $(DESTDIR)$(PREFIX)/share/man/man8
|
install -d $(DESTDIR)$(PREFIX)/share/man/man8
|
||||||
install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
|
install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
|
||||||
|
@@ -34,6 +34,10 @@ from datetime import datetime, timedelta
|
|||||||
from subprocess import call, Popen, PIPE
|
from subprocess import call, Popen, PIPE
|
||||||
import sleepgraph as aslib
|
import sleepgraph as aslib
|
||||||
|
|
||||||
|
def pprint(msg):
|
||||||
|
print(msg)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
# ----------------- CLASSES --------------------
|
# ----------------- CLASSES --------------------
|
||||||
|
|
||||||
# Class: SystemValues
|
# Class: SystemValues
|
||||||
@@ -157,11 +161,11 @@ class SystemValues(aslib.SystemValues):
|
|||||||
return cmdline
|
return cmdline
|
||||||
def manualRebootRequired(self):
|
def manualRebootRequired(self):
|
||||||
cmdline = self.kernelParams()
|
cmdline = self.kernelParams()
|
||||||
print 'To generate a new timeline manually, follow these steps:\n'
|
pprint('To generate a new timeline manually, follow these steps:\n\n'\
|
||||||
print '1. Add the CMDLINE string to your kernel command line.'
|
'1. Add the CMDLINE string to your kernel command line.\n'\
|
||||||
print '2. Reboot the system.'
|
'2. Reboot the system.\n'\
|
||||||
print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n'
|
'3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n\n'\
|
||||||
print 'CMDLINE="%s"' % cmdline
|
'CMDLINE="%s"' % cmdline)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
def blGrub(self):
|
def blGrub(self):
|
||||||
blcmd = ''
|
blcmd = ''
|
||||||
@@ -431,7 +435,7 @@ def parseTraceLog(data):
|
|||||||
if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0):
|
if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0):
|
||||||
continue
|
continue
|
||||||
if(not cg.postProcess()):
|
if(not cg.postProcess()):
|
||||||
print('Sanity check failed for %s-%d' % (proc, pid))
|
pprint('Sanity check failed for %s-%d' % (proc, pid))
|
||||||
continue
|
continue
|
||||||
# match cg data to devices
|
# match cg data to devices
|
||||||
devname = data.deviceMatch(pid, cg)
|
devname = data.deviceMatch(pid, cg)
|
||||||
@@ -442,8 +446,8 @@ def parseTraceLog(data):
|
|||||||
sysvals.vprint('%s callgraph found for %s %s-%d [%f - %f]' %\
|
sysvals.vprint('%s callgraph found for %s %s-%d [%f - %f]' %\
|
||||||
(kind, cg.name, proc, pid, cg.start, cg.end))
|
(kind, cg.name, proc, pid, cg.start, cg.end))
|
||||||
elif len(cg.list) > 1000000:
|
elif len(cg.list) > 1000000:
|
||||||
print 'WARNING: the callgraph found for %s is massive! (%d lines)' %\
|
pprint('WARNING: the callgraph found for %s is massive! (%d lines)' %\
|
||||||
(devname, len(cg.list))
|
(devname, len(cg.list)))
|
||||||
|
|
||||||
# Function: retrieveLogs
|
# Function: retrieveLogs
|
||||||
# Description:
|
# Description:
|
||||||
@@ -528,7 +532,7 @@ def createBootGraph(data):
|
|||||||
tMax = data.end
|
tMax = data.end
|
||||||
tTotal = tMax - t0
|
tTotal = tMax - t0
|
||||||
if(tTotal == 0):
|
if(tTotal == 0):
|
||||||
print('ERROR: No timeline data')
|
pprint('ERROR: No timeline data')
|
||||||
return False
|
return False
|
||||||
user_mode = '%.0f'%(data.tUserMode*1000)
|
user_mode = '%.0f'%(data.tUserMode*1000)
|
||||||
last_init = '%.0f'%(tTotal*1000)
|
last_init = '%.0f'%(tTotal*1000)
|
||||||
@@ -734,7 +738,7 @@ def updateCron(restore=False):
|
|||||||
op.close()
|
op.close()
|
||||||
res = call([cmd, cronfile])
|
res = call([cmd, cronfile])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print 'Exception: %s' % str(e)
|
pprint('Exception: %s' % str(e))
|
||||||
shutil.move(backfile, cronfile)
|
shutil.move(backfile, cronfile)
|
||||||
res = -1
|
res = -1
|
||||||
if res != 0:
|
if res != 0:
|
||||||
@@ -750,7 +754,7 @@ def updateGrub(restore=False):
|
|||||||
call(sysvals.blexec, stderr=PIPE, stdout=PIPE,
|
call(sysvals.blexec, stderr=PIPE, stdout=PIPE,
|
||||||
env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'})
|
env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'})
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print 'Exception: %s\n' % str(e)
|
pprint('Exception: %s\n' % str(e))
|
||||||
return
|
return
|
||||||
# extract the option and create a grub config without it
|
# extract the option and create a grub config without it
|
||||||
sysvals.rootUser(True)
|
sysvals.rootUser(True)
|
||||||
@@ -797,7 +801,7 @@ def updateGrub(restore=False):
|
|||||||
res = call(sysvals.blexec)
|
res = call(sysvals.blexec)
|
||||||
os.remove(grubfile)
|
os.remove(grubfile)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print 'Exception: %s' % str(e)
|
pprint('Exception: %s' % str(e))
|
||||||
res = -1
|
res = -1
|
||||||
# cleanup
|
# cleanup
|
||||||
shutil.move(tempfile, grubfile)
|
shutil.move(tempfile, grubfile)
|
||||||
@@ -821,7 +825,7 @@ def updateKernelParams(restore=False):
|
|||||||
def doError(msg, help=False):
|
def doError(msg, help=False):
|
||||||
if help == True:
|
if help == True:
|
||||||
printHelp()
|
printHelp()
|
||||||
print 'ERROR: %s\n' % msg
|
pprint('ERROR: %s\n' % msg)
|
||||||
sysvals.outputResult({'error':msg})
|
sysvals.outputResult({'error':msg})
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
@@ -829,52 +833,51 @@ def doError(msg, help=False):
|
|||||||
# Description:
|
# Description:
|
||||||
# print out the help text
|
# print out the help text
|
||||||
def printHelp():
|
def printHelp():
|
||||||
print('')
|
pprint('\n%s v%s\n'\
|
||||||
print('%s v%s' % (sysvals.title, sysvals.version))
|
'Usage: bootgraph <options> <command>\n'\
|
||||||
print('Usage: bootgraph <options> <command>')
|
'\n'\
|
||||||
print('')
|
'Description:\n'\
|
||||||
print('Description:')
|
' This tool reads in a dmesg log of linux kernel boot and\n'\
|
||||||
print(' This tool reads in a dmesg log of linux kernel boot and')
|
' creates an html representation of the boot timeline up to\n'\
|
||||||
print(' creates an html representation of the boot timeline up to')
|
' the start of the init process.\n'\
|
||||||
print(' the start of the init process.')
|
'\n'\
|
||||||
print('')
|
' If no specific command is given the tool reads the current dmesg\n'\
|
||||||
print(' If no specific command is given the tool reads the current dmesg')
|
' and/or ftrace log and creates a timeline\n'\
|
||||||
print(' and/or ftrace log and creates a timeline')
|
'\n'\
|
||||||
print('')
|
' Generates output files in subdirectory: boot-yymmdd-HHMMSS\n'\
|
||||||
print(' Generates output files in subdirectory: boot-yymmdd-HHMMSS')
|
' HTML output: <hostname>_boot.html\n'\
|
||||||
print(' HTML output: <hostname>_boot.html')
|
' raw dmesg output: <hostname>_boot_dmesg.txt\n'\
|
||||||
print(' raw dmesg output: <hostname>_boot_dmesg.txt')
|
' raw ftrace output: <hostname>_boot_ftrace.txt\n'\
|
||||||
print(' raw ftrace output: <hostname>_boot_ftrace.txt')
|
'\n'\
|
||||||
print('')
|
'Options:\n'\
|
||||||
print('Options:')
|
' -h Print this help text\n'\
|
||||||
print(' -h Print this help text')
|
' -v Print the current tool version\n'\
|
||||||
print(' -v Print the current tool version')
|
' -verbose Print extra information during execution and analysis\n'\
|
||||||
print(' -verbose Print extra information during execution and analysis')
|
' -addlogs Add the dmesg log to the html output\n'\
|
||||||
print(' -addlogs Add the dmesg log to the html output')
|
' -result fn Export a results table to a text file for parsing.\n'\
|
||||||
print(' -result fn Export a results table to a text file for parsing.')
|
' -o name Overrides the output subdirectory name when running a new test\n'\
|
||||||
print(' -o name Overrides the output subdirectory name when running a new test')
|
' default: boot-{date}-{time}\n'\
|
||||||
print(' default: boot-{date}-{time}')
|
' [advanced]\n'\
|
||||||
print(' [advanced]')
|
' -fstat Use ftrace to add function detail and statistics (default: disabled)\n'\
|
||||||
print(' -fstat Use ftrace to add function detail and statistics (default: disabled)')
|
' -f/-callgraph Add callgraph detail, can be very large (default: disabled)\n'\
|
||||||
print(' -f/-callgraph Add callgraph detail, can be very large (default: disabled)')
|
' -maxdepth N limit the callgraph data to N call levels (default: 2)\n'\
|
||||||
print(' -maxdepth N limit the callgraph data to N call levels (default: 2)')
|
' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\
|
||||||
print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
|
' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])\n'\
|
||||||
print(' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])')
|
' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\
|
||||||
print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)')
|
' -func list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)\n'\
|
||||||
print(' -func list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)')
|
' -cgfilter S Filter the callgraph output in the timeline\n'\
|
||||||
print(' -cgfilter S Filter the callgraph output in the timeline')
|
' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\
|
||||||
print(' -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)')
|
' -bl name Use the following boot loader for kernel params (default: grub)\n'\
|
||||||
print(' -bl name Use the following boot loader for kernel params (default: grub)')
|
' -reboot Reboot the machine automatically and generate a new timeline\n'\
|
||||||
print(' -reboot Reboot the machine automatically and generate a new timeline')
|
' -manual Show the steps to generate a new timeline manually (used with -reboot)\n'\
|
||||||
print(' -manual Show the steps to generate a new timeline manually (used with -reboot)')
|
'\n'\
|
||||||
print('')
|
'Other commands:\n'\
|
||||||
print('Other commands:')
|
' -flistall Print all functions capable of being captured in ftrace\n'\
|
||||||
print(' -flistall Print all functions capable of being captured in ftrace')
|
' -sysinfo Print out system info extracted from BIOS\n'\
|
||||||
print(' -sysinfo Print out system info extracted from BIOS')
|
' [redo]\n'\
|
||||||
print(' [redo]')
|
' -dmesg file Create HTML output using dmesg input (used with -ftrace)\n'\
|
||||||
print(' -dmesg file Create HTML output using dmesg input (used with -ftrace)')
|
' -ftrace file Create HTML output using ftrace input (used with -dmesg)\n'\
|
||||||
print(' -ftrace file Create HTML output using ftrace input (used with -dmesg)')
|
'' % (sysvals.title, sysvals.version))
|
||||||
print('')
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# ----------------- MAIN --------------------
|
# ----------------- MAIN --------------------
|
||||||
@@ -895,7 +898,7 @@ if __name__ == '__main__':
|
|||||||
printHelp()
|
printHelp()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
elif(arg == '-v'):
|
elif(arg == '-v'):
|
||||||
print("Version %s" % sysvals.version)
|
pprint("Version %s" % sysvals.version)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
elif(arg == '-verbose'):
|
elif(arg == '-verbose'):
|
||||||
sysvals.verbose = True
|
sysvals.verbose = True
|
||||||
@@ -1016,7 +1019,7 @@ if __name__ == '__main__':
|
|||||||
print f
|
print f
|
||||||
elif cmd == 'checkbl':
|
elif cmd == 'checkbl':
|
||||||
sysvals.getBootLoader()
|
sysvals.getBootLoader()
|
||||||
print 'Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec)
|
pprint('Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec))
|
||||||
elif(cmd == 'sysinfo'):
|
elif(cmd == 'sysinfo'):
|
||||||
sysvals.printSystemInfo(True)
|
sysvals.printSystemInfo(True)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
@@ -27,6 +27,7 @@ ktime_get
|
|||||||
# console calls
|
# console calls
|
||||||
printk
|
printk
|
||||||
dev_printk
|
dev_printk
|
||||||
|
__dev_printk
|
||||||
console_unlock
|
console_unlock
|
||||||
|
|
||||||
# memory handling
|
# memory handling
|
||||||
|
@@ -105,7 +105,7 @@ override-dev-timeline-functions: true
|
|||||||
# example: [color=#CC00CC]
|
# example: [color=#CC00CC]
|
||||||
#
|
#
|
||||||
# arglist: A list of arguments from registers/stack addresses. See URL:
|
# arglist: A list of arguments from registers/stack addresses. See URL:
|
||||||
# https://www.kernel.org/doc/Documentation/trace/kprobetrace.rst
|
# https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt
|
||||||
#
|
#
|
||||||
# example: cpu=%di:s32
|
# example: cpu=%di:s32
|
||||||
#
|
#
|
||||||
@@ -170,7 +170,7 @@ pm_restore_console:
|
|||||||
# example: [color=#CC00CC]
|
# example: [color=#CC00CC]
|
||||||
#
|
#
|
||||||
# arglist: A list of arguments from registers/stack addresses. See URL:
|
# arglist: A list of arguments from registers/stack addresses. See URL:
|
||||||
# https://www.kernel.org/doc/Documentation/trace/kprobetrace.rst
|
# https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt
|
||||||
#
|
#
|
||||||
# example: port=+36(%di):s32
|
# example: port=+36(%di):s32
|
||||||
#
|
#
|
||||||
|
@@ -65,9 +65,9 @@ During test, enable/disable runtime suspend for all devices. The test is delayed
|
|||||||
by 5 seconds to allow runtime suspend changes to occur. The settings are restored
|
by 5 seconds to allow runtime suspend changes to occur. The settings are restored
|
||||||
after the test is complete.
|
after the test is complete.
|
||||||
.TP
|
.TP
|
||||||
\fB-display \fIon/off\fR
|
\fB-display \fIon/off/standby/suspend\fR
|
||||||
Turn the display on or off for the test using the xset command. This helps
|
Switch the display to the requested mode for the test using the xset command.
|
||||||
maintain the consistecy of test data for better comparison.
|
This helps maintain the consistency of test data for better comparison.
|
||||||
.TP
|
.TP
|
||||||
\fB-skiphtml\fR
|
\fB-skiphtml\fR
|
||||||
Run the test and capture the trace logs, but skip the timeline generation.
|
Run the test and capture the trace logs, but skip the timeline generation.
|
||||||
@@ -183,6 +183,13 @@ Print out the contents of the ACPI Firmware Performance Data Table.
|
|||||||
\fB-battery\fR
|
\fB-battery\fR
|
||||||
Print out battery status and current charge.
|
Print out battery status and current charge.
|
||||||
.TP
|
.TP
|
||||||
|
\fB-xon/-xoff/-xstandby/-xsuspend\fR
|
||||||
|
Test xset by attempting to switch the display to the given mode. This
|
||||||
|
is the same command which will be issued by \fB-display \fImode\fR.
|
||||||
|
.TP
|
||||||
|
\fB-xstat\fR
|
||||||
|
Get the current DPMS display mode.
|
||||||
|
.TP
|
||||||
\fB-sysinfo\fR
|
\fB-sysinfo\fR
|
||||||
Print out system info extracted from BIOS. Reads /dev/mem directly instead of going through dmidecode.
|
Print out system info extracted from BIOS. Reads /dev/mem directly instead of going through dmidecode.
|
||||||
.TP
|
.TP
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user