forked from Minki/linux
Merge branches 'pm-sleep', 'pm-domains', 'powercap' and 'pm-tools'
* pm-sleep: PM: sleep: spread "const char *" correctness PM: hibernate: fix white space in a few places freezer: Add unsafe version of freezable_schedule_timeout_interruptible() for NFS PM: sleep: core: Emit changed uevent on wakeup_sysfs_add/remove * pm-domains: PM: domains: Restore comment indentation for generic_pm_domain.child_links PM: domains: Fix up terminology with parent/child * powercap: powercap: Add Power Limit4 support powercap: idle_inject: Replace play_idle() with play_idle_precise() in comments powercap: intel_rapl: add support for Sapphire Rapids * pm-tools: pm-graph v5.7 - important s2idle fixes cpupower: Replace HTTP links with HTTPS ones cpupower: Fix NULL but dereferenced coccicheck errors cpupower: Fix comparing pointer to 0 coccicheck warns
This commit is contained in:
commit
86ba54fb08
@ -167,11 +167,13 @@ For example::
|
|||||||
package-0
|
package-0
|
||||||
---------
|
---------
|
||||||
|
|
||||||
The Intel RAPL technology allows two constraints, short term and long term,
|
Depending on different power zones, the Intel RAPL technology allows
|
||||||
with two different time windows to be applied to each power zone. Thus for
|
one or multiple constraints like short term, long term and peak power,
|
||||||
each zone there are 2 attributes representing the constraint names, 2 power
|
with different time windows to be applied to each power zone.
|
||||||
limits and 2 attributes representing the sizes of the time windows. Such that,
|
All the zones contain attributes representing the constraint names,
|
||||||
constraint_j_* attributes correspond to the jth constraint (j = 0,1).
|
power limits and the sizes of the time windows. Note that time window
|
||||||
|
is not applicable to peak power. Here, constraint_j_* attributes
|
||||||
|
correspond to the jth constraint (j = 0,1,2).
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
@ -181,6 +183,9 @@ For example::
|
|||||||
constraint_1_name
|
constraint_1_name
|
||||||
constraint_1_power_limit_uw
|
constraint_1_power_limit_uw
|
||||||
constraint_1_time_window_us
|
constraint_1_time_window_us
|
||||||
|
constraint_2_name
|
||||||
|
constraint_2_power_limit_uw
|
||||||
|
constraint_2_time_window_us
|
||||||
|
|
||||||
Power Zone Attributes
|
Power Zone Attributes
|
||||||
=====================
|
=====================
|
||||||
|
@ -263,18 +263,18 @@ static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd,
|
|||||||
/*
|
/*
|
||||||
* Traverse all sub-domains within the domain. This can be
|
* Traverse all sub-domains within the domain. This can be
|
||||||
* done without any additional locking as the link->performance_state
|
* done without any additional locking as the link->performance_state
|
||||||
* field is protected by the master genpd->lock, which is already taken.
|
* field is protected by the parent genpd->lock, which is already taken.
|
||||||
*
|
*
|
||||||
* Also note that link->performance_state (subdomain's performance state
|
* Also note that link->performance_state (subdomain's performance state
|
||||||
* requirement to master domain) is different from
|
* requirement to parent domain) is different from
|
||||||
* link->slave->performance_state (current performance state requirement
|
* link->child->performance_state (current performance state requirement
|
||||||
* of the devices/sub-domains of the subdomain) and so can have a
|
* of the devices/sub-domains of the subdomain) and so can have a
|
||||||
* different value.
|
* different value.
|
||||||
*
|
*
|
||||||
* Note that we also take vote from powered-off sub-domains into account
|
* Note that we also take vote from powered-off sub-domains into account
|
||||||
* as the same is done for devices right now.
|
* as the same is done for devices right now.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(link, &genpd->master_links, master_node) {
|
list_for_each_entry(link, &genpd->parent_links, parent_node) {
|
||||||
if (link->performance_state > state)
|
if (link->performance_state > state)
|
||||||
state = link->performance_state;
|
state = link->performance_state;
|
||||||
}
|
}
|
||||||
@ -285,40 +285,40 @@ static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd,
|
|||||||
static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
|
static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
|
||||||
unsigned int state, int depth)
|
unsigned int state, int depth)
|
||||||
{
|
{
|
||||||
struct generic_pm_domain *master;
|
struct generic_pm_domain *parent;
|
||||||
struct gpd_link *link;
|
struct gpd_link *link;
|
||||||
int master_state, ret;
|
int parent_state, ret;
|
||||||
|
|
||||||
if (state == genpd->performance_state)
|
if (state == genpd->performance_state)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Propagate to masters of genpd */
|
/* Propagate to parents of genpd */
|
||||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
list_for_each_entry(link, &genpd->child_links, child_node) {
|
||||||
master = link->master;
|
parent = link->parent;
|
||||||
|
|
||||||
if (!master->set_performance_state)
|
if (!parent->set_performance_state)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Find master's performance state */
|
/* Find parent's performance state */
|
||||||
ret = dev_pm_opp_xlate_performance_state(genpd->opp_table,
|
ret = dev_pm_opp_xlate_performance_state(genpd->opp_table,
|
||||||
master->opp_table,
|
parent->opp_table,
|
||||||
state);
|
state);
|
||||||
if (unlikely(ret < 0))
|
if (unlikely(ret < 0))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
master_state = ret;
|
parent_state = ret;
|
||||||
|
|
||||||
genpd_lock_nested(master, depth + 1);
|
genpd_lock_nested(parent, depth + 1);
|
||||||
|
|
||||||
link->prev_performance_state = link->performance_state;
|
link->prev_performance_state = link->performance_state;
|
||||||
link->performance_state = master_state;
|
link->performance_state = parent_state;
|
||||||
master_state = _genpd_reeval_performance_state(master,
|
parent_state = _genpd_reeval_performance_state(parent,
|
||||||
master_state);
|
parent_state);
|
||||||
ret = _genpd_set_performance_state(master, master_state, depth + 1);
|
ret = _genpd_set_performance_state(parent, parent_state, depth + 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
link->performance_state = link->prev_performance_state;
|
link->performance_state = link->prev_performance_state;
|
||||||
|
|
||||||
genpd_unlock(master);
|
genpd_unlock(parent);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
@ -333,26 +333,26 @@ static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
/* Encountered an error, lets rollback */
|
/* Encountered an error, lets rollback */
|
||||||
list_for_each_entry_continue_reverse(link, &genpd->slave_links,
|
list_for_each_entry_continue_reverse(link, &genpd->child_links,
|
||||||
slave_node) {
|
child_node) {
|
||||||
master = link->master;
|
parent = link->parent;
|
||||||
|
|
||||||
if (!master->set_performance_state)
|
if (!parent->set_performance_state)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
genpd_lock_nested(master, depth + 1);
|
genpd_lock_nested(parent, depth + 1);
|
||||||
|
|
||||||
master_state = link->prev_performance_state;
|
parent_state = link->prev_performance_state;
|
||||||
link->performance_state = master_state;
|
link->performance_state = parent_state;
|
||||||
|
|
||||||
master_state = _genpd_reeval_performance_state(master,
|
parent_state = _genpd_reeval_performance_state(parent,
|
||||||
master_state);
|
parent_state);
|
||||||
if (_genpd_set_performance_state(master, master_state, depth + 1)) {
|
if (_genpd_set_performance_state(parent, parent_state, depth + 1)) {
|
||||||
pr_err("%s: Failed to roll back to %d performance state\n",
|
pr_err("%s: Failed to roll back to %d performance state\n",
|
||||||
master->name, master_state);
|
parent->name, parent_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
genpd_unlock(master);
|
genpd_unlock(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -552,7 +552,7 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If sd_count > 0 at this point, one of the subdomains hasn't
|
* If sd_count > 0 at this point, one of the subdomains hasn't
|
||||||
* managed to call genpd_power_on() for the master yet after
|
* managed to call genpd_power_on() for the parent yet after
|
||||||
* incrementing it. In that case genpd_power_on() will wait
|
* incrementing it. In that case genpd_power_on() will wait
|
||||||
* for us to drop the lock, so we can call .power_off() and let
|
* for us to drop the lock, so we can call .power_off() and let
|
||||||
* the genpd_power_on() restore power for us (this shouldn't
|
* the genpd_power_on() restore power for us (this shouldn't
|
||||||
@ -566,22 +566,22 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
|
|||||||
genpd->status = GPD_STATE_POWER_OFF;
|
genpd->status = GPD_STATE_POWER_OFF;
|
||||||
genpd_update_accounting(genpd);
|
genpd_update_accounting(genpd);
|
||||||
|
|
||||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
list_for_each_entry(link, &genpd->child_links, child_node) {
|
||||||
genpd_sd_counter_dec(link->master);
|
genpd_sd_counter_dec(link->parent);
|
||||||
genpd_lock_nested(link->master, depth + 1);
|
genpd_lock_nested(link->parent, depth + 1);
|
||||||
genpd_power_off(link->master, false, depth + 1);
|
genpd_power_off(link->parent, false, depth + 1);
|
||||||
genpd_unlock(link->master);
|
genpd_unlock(link->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* genpd_power_on - Restore power to a given PM domain and its masters.
|
* genpd_power_on - Restore power to a given PM domain and its parents.
|
||||||
* @genpd: PM domain to power up.
|
* @genpd: PM domain to power up.
|
||||||
* @depth: nesting count for lockdep.
|
* @depth: nesting count for lockdep.
|
||||||
*
|
*
|
||||||
* Restore power to @genpd and all of its masters so that it is possible to
|
* Restore power to @genpd and all of its parents so that it is possible to
|
||||||
* resume a device belonging to it.
|
* resume a device belonging to it.
|
||||||
*/
|
*/
|
||||||
static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
|
static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
|
||||||
@ -594,20 +594,20 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The list is guaranteed not to change while the loop below is being
|
* The list is guaranteed not to change while the loop below is being
|
||||||
* executed, unless one of the masters' .power_on() callbacks fiddles
|
* executed, unless one of the parents' .power_on() callbacks fiddles
|
||||||
* with it.
|
* with it.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
list_for_each_entry(link, &genpd->child_links, child_node) {
|
||||||
struct generic_pm_domain *master = link->master;
|
struct generic_pm_domain *parent = link->parent;
|
||||||
|
|
||||||
genpd_sd_counter_inc(master);
|
genpd_sd_counter_inc(parent);
|
||||||
|
|
||||||
genpd_lock_nested(master, depth + 1);
|
genpd_lock_nested(parent, depth + 1);
|
||||||
ret = genpd_power_on(master, depth + 1);
|
ret = genpd_power_on(parent, depth + 1);
|
||||||
genpd_unlock(master);
|
genpd_unlock(parent);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
genpd_sd_counter_dec(master);
|
genpd_sd_counter_dec(parent);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,12 +623,12 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
list_for_each_entry_continue_reverse(link,
|
list_for_each_entry_continue_reverse(link,
|
||||||
&genpd->slave_links,
|
&genpd->child_links,
|
||||||
slave_node) {
|
child_node) {
|
||||||
genpd_sd_counter_dec(link->master);
|
genpd_sd_counter_dec(link->parent);
|
||||||
genpd_lock_nested(link->master, depth + 1);
|
genpd_lock_nested(link->parent, depth + 1);
|
||||||
genpd_power_off(link->master, false, depth + 1);
|
genpd_power_off(link->parent, false, depth + 1);
|
||||||
genpd_unlock(link->master);
|
genpd_unlock(link->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -932,13 +932,13 @@ late_initcall(genpd_power_off_unused);
|
|||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* genpd_sync_power_off - Synchronously power off a PM domain and its masters.
|
* genpd_sync_power_off - Synchronously power off a PM domain and its parents.
|
||||||
* @genpd: PM domain to power off, if possible.
|
* @genpd: PM domain to power off, if possible.
|
||||||
* @use_lock: use the lock.
|
* @use_lock: use the lock.
|
||||||
* @depth: nesting count for lockdep.
|
* @depth: nesting count for lockdep.
|
||||||
*
|
*
|
||||||
* Check if the given PM domain can be powered off (during system suspend or
|
* Check if the given PM domain can be powered off (during system suspend or
|
||||||
* hibernation) and do that if so. Also, in that case propagate to its masters.
|
* hibernation) and do that if so. Also, in that case propagate to its parents.
|
||||||
*
|
*
|
||||||
* This function is only called in "noirq" and "syscore" stages of system power
|
* This function is only called in "noirq" and "syscore" stages of system power
|
||||||
* transitions. The "noirq" callbacks may be executed asynchronously, thus in
|
* transitions. The "noirq" callbacks may be executed asynchronously, thus in
|
||||||
@ -963,21 +963,21 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock,
|
|||||||
|
|
||||||
genpd->status = GPD_STATE_POWER_OFF;
|
genpd->status = GPD_STATE_POWER_OFF;
|
||||||
|
|
||||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
list_for_each_entry(link, &genpd->child_links, child_node) {
|
||||||
genpd_sd_counter_dec(link->master);
|
genpd_sd_counter_dec(link->parent);
|
||||||
|
|
||||||
if (use_lock)
|
if (use_lock)
|
||||||
genpd_lock_nested(link->master, depth + 1);
|
genpd_lock_nested(link->parent, depth + 1);
|
||||||
|
|
||||||
genpd_sync_power_off(link->master, use_lock, depth + 1);
|
genpd_sync_power_off(link->parent, use_lock, depth + 1);
|
||||||
|
|
||||||
if (use_lock)
|
if (use_lock)
|
||||||
genpd_unlock(link->master);
|
genpd_unlock(link->parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* genpd_sync_power_on - Synchronously power on a PM domain and its masters.
|
* genpd_sync_power_on - Synchronously power on a PM domain and its parents.
|
||||||
* @genpd: PM domain to power on.
|
* @genpd: PM domain to power on.
|
||||||
* @use_lock: use the lock.
|
* @use_lock: use the lock.
|
||||||
* @depth: nesting count for lockdep.
|
* @depth: nesting count for lockdep.
|
||||||
@ -994,16 +994,16 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock,
|
|||||||
if (genpd_status_on(genpd))
|
if (genpd_status_on(genpd))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
list_for_each_entry(link, &genpd->child_links, child_node) {
|
||||||
genpd_sd_counter_inc(link->master);
|
genpd_sd_counter_inc(link->parent);
|
||||||
|
|
||||||
if (use_lock)
|
if (use_lock)
|
||||||
genpd_lock_nested(link->master, depth + 1);
|
genpd_lock_nested(link->parent, depth + 1);
|
||||||
|
|
||||||
genpd_sync_power_on(link->master, use_lock, depth + 1);
|
genpd_sync_power_on(link->parent, use_lock, depth + 1);
|
||||||
|
|
||||||
if (use_lock)
|
if (use_lock)
|
||||||
genpd_unlock(link->master);
|
genpd_unlock(link->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
_genpd_power_on(genpd, false);
|
_genpd_power_on(genpd, false);
|
||||||
@ -1443,12 +1443,12 @@ static void genpd_update_cpumask(struct generic_pm_domain *genpd,
|
|||||||
if (!genpd_is_cpu_domain(genpd))
|
if (!genpd_is_cpu_domain(genpd))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
list_for_each_entry(link, &genpd->child_links, child_node) {
|
||||||
struct generic_pm_domain *master = link->master;
|
struct generic_pm_domain *parent = link->parent;
|
||||||
|
|
||||||
genpd_lock_nested(master, depth + 1);
|
genpd_lock_nested(parent, depth + 1);
|
||||||
genpd_update_cpumask(master, cpu, set, depth + 1);
|
genpd_update_cpumask(parent, cpu, set, depth + 1);
|
||||||
genpd_unlock(master);
|
genpd_unlock(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
@ -1636,17 +1636,17 @@ static int genpd_add_subdomain(struct generic_pm_domain *genpd,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(itr, &genpd->master_links, master_node) {
|
list_for_each_entry(itr, &genpd->parent_links, parent_node) {
|
||||||
if (itr->slave == subdomain && itr->master == genpd) {
|
if (itr->child == subdomain && itr->parent == genpd) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
link->master = genpd;
|
link->parent = genpd;
|
||||||
list_add_tail(&link->master_node, &genpd->master_links);
|
list_add_tail(&link->parent_node, &genpd->parent_links);
|
||||||
link->slave = subdomain;
|
link->child = subdomain;
|
||||||
list_add_tail(&link->slave_node, &subdomain->slave_links);
|
list_add_tail(&link->child_node, &subdomain->child_links);
|
||||||
if (genpd_status_on(subdomain))
|
if (genpd_status_on(subdomain))
|
||||||
genpd_sd_counter_inc(genpd);
|
genpd_sd_counter_inc(genpd);
|
||||||
|
|
||||||
@ -1660,7 +1660,7 @@ static int genpd_add_subdomain(struct generic_pm_domain *genpd,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
|
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
|
||||||
* @genpd: Master PM domain to add the subdomain to.
|
* @genpd: Leader PM domain to add the subdomain to.
|
||||||
* @subdomain: Subdomain to be added.
|
* @subdomain: Subdomain to be added.
|
||||||
*/
|
*/
|
||||||
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
||||||
@ -1678,7 +1678,7 @@ EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
|
* pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
|
||||||
* @genpd: Master PM domain to remove the subdomain from.
|
* @genpd: Leader PM domain to remove the subdomain from.
|
||||||
* @subdomain: Subdomain to be removed.
|
* @subdomain: Subdomain to be removed.
|
||||||
*/
|
*/
|
||||||
int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
||||||
@ -1693,19 +1693,19 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
|||||||
genpd_lock(subdomain);
|
genpd_lock(subdomain);
|
||||||
genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING);
|
genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING);
|
||||||
|
|
||||||
if (!list_empty(&subdomain->master_links) || subdomain->device_count) {
|
if (!list_empty(&subdomain->parent_links) || subdomain->device_count) {
|
||||||
pr_warn("%s: unable to remove subdomain %s\n",
|
pr_warn("%s: unable to remove subdomain %s\n",
|
||||||
genpd->name, subdomain->name);
|
genpd->name, subdomain->name);
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_safe(link, l, &genpd->master_links, master_node) {
|
list_for_each_entry_safe(link, l, &genpd->parent_links, parent_node) {
|
||||||
if (link->slave != subdomain)
|
if (link->child != subdomain)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
list_del(&link->master_node);
|
list_del(&link->parent_node);
|
||||||
list_del(&link->slave_node);
|
list_del(&link->child_node);
|
||||||
kfree(link);
|
kfree(link);
|
||||||
if (genpd_status_on(subdomain))
|
if (genpd_status_on(subdomain))
|
||||||
genpd_sd_counter_dec(genpd);
|
genpd_sd_counter_dec(genpd);
|
||||||
@ -1770,8 +1770,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
|
|||||||
if (IS_ERR_OR_NULL(genpd))
|
if (IS_ERR_OR_NULL(genpd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&genpd->master_links);
|
INIT_LIST_HEAD(&genpd->parent_links);
|
||||||
INIT_LIST_HEAD(&genpd->slave_links);
|
INIT_LIST_HEAD(&genpd->child_links);
|
||||||
INIT_LIST_HEAD(&genpd->dev_list);
|
INIT_LIST_HEAD(&genpd->dev_list);
|
||||||
genpd_lock_init(genpd);
|
genpd_lock_init(genpd);
|
||||||
genpd->gov = gov;
|
genpd->gov = gov;
|
||||||
@ -1848,15 +1848,15 @@ static int genpd_remove(struct generic_pm_domain *genpd)
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!list_empty(&genpd->master_links) || genpd->device_count) {
|
if (!list_empty(&genpd->parent_links) || genpd->device_count) {
|
||||||
genpd_unlock(genpd);
|
genpd_unlock(genpd);
|
||||||
pr_err("%s: unable to remove %s\n", __func__, genpd->name);
|
pr_err("%s: unable to remove %s\n", __func__, genpd->name);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry_safe(link, l, &genpd->slave_links, slave_node) {
|
list_for_each_entry_safe(link, l, &genpd->child_links, child_node) {
|
||||||
list_del(&link->master_node);
|
list_del(&link->parent_node);
|
||||||
list_del(&link->slave_node);
|
list_del(&link->child_node);
|
||||||
kfree(link);
|
kfree(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2827,12 +2827,12 @@ static int genpd_summary_one(struct seq_file *s,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Modifications on the list require holding locks on both
|
* Modifications on the list require holding locks on both
|
||||||
* master and slave, so we are safe.
|
* parent and child, so we are safe.
|
||||||
* Also genpd->name is immutable.
|
* Also genpd->name is immutable.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(link, &genpd->master_links, master_node) {
|
list_for_each_entry(link, &genpd->parent_links, parent_node) {
|
||||||
seq_printf(s, "%s", link->slave->name);
|
seq_printf(s, "%s", link->child->name);
|
||||||
if (!list_is_last(&link->master_node, &genpd->master_links))
|
if (!list_is_last(&link->parent_node, &genpd->parent_links))
|
||||||
seq_puts(s, ", ");
|
seq_puts(s, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2860,7 +2860,7 @@ static int summary_show(struct seq_file *s, void *data)
|
|||||||
struct generic_pm_domain *genpd;
|
struct generic_pm_domain *genpd;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
seq_puts(s, "domain status slaves\n");
|
seq_puts(s, "domain status children\n");
|
||||||
seq_puts(s, " /device runtime status\n");
|
seq_puts(s, " /device runtime status\n");
|
||||||
seq_puts(s, "----------------------------------------------------------------------\n");
|
seq_puts(s, "----------------------------------------------------------------------\n");
|
||||||
|
|
||||||
@ -2915,8 +2915,8 @@ static int sub_domains_show(struct seq_file *s, void *data)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
list_for_each_entry(link, &genpd->master_links, master_node)
|
list_for_each_entry(link, &genpd->parent_links, parent_node)
|
||||||
seq_printf(s, "%s\n", link->slave->name);
|
seq_printf(s, "%s\n", link->child->name);
|
||||||
|
|
||||||
genpd_unlock(genpd);
|
genpd_unlock(genpd);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -135,8 +135,8 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
|
|||||||
*
|
*
|
||||||
* All subdomains have been powered off already at this point.
|
* All subdomains have been powered off already at this point.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(link, &genpd->master_links, master_node) {
|
list_for_each_entry(link, &genpd->parent_links, parent_node) {
|
||||||
struct generic_pm_domain *sd = link->slave;
|
struct generic_pm_domain *sd = link->child;
|
||||||
s64 sd_max_off_ns = sd->max_off_time_ns;
|
s64 sd_max_off_ns = sd->max_off_time_ns;
|
||||||
|
|
||||||
if (sd_max_off_ns < 0)
|
if (sd_max_off_ns < 0)
|
||||||
@ -217,13 +217,13 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to invalidate the cached results for the masters, so
|
* We have to invalidate the cached results for the parents, so
|
||||||
* use the observation that default_power_down_ok() is not
|
* use the observation that default_power_down_ok() is not
|
||||||
* going to be called for any master until this instance
|
* going to be called for any parent until this instance
|
||||||
* returns.
|
* returns.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(link, &genpd->slave_links, slave_node)
|
list_for_each_entry(link, &genpd->child_links, child_node)
|
||||||
link->master->max_off_time_changed = true;
|
link->parent->max_off_time_changed = true;
|
||||||
|
|
||||||
genpd->max_off_time_ns = -1;
|
genpd->max_off_time_ns = -1;
|
||||||
genpd->max_off_time_changed = false;
|
genpd->max_off_time_changed = false;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* sysfs entries for device PM */
|
/* sysfs entries for device PM */
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/kobject.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/pm_qos.h>
|
#include <linux/pm_qos.h>
|
||||||
@ -739,12 +740,18 @@ int dpm_sysfs_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid)
|
|||||||
|
|
||||||
int wakeup_sysfs_add(struct device *dev)
|
int wakeup_sysfs_add(struct device *dev)
|
||||||
{
|
{
|
||||||
return sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
|
int ret = sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wakeup_sysfs_remove(struct device *dev)
|
void wakeup_sysfs_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
|
sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
|
||||||
|
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pm_qos_sysfs_add_resume_latency(struct device *dev)
|
int pm_qos_sysfs_add_resume_latency(struct device *dev)
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
* The idle + run duration is specified via separate helpers and that allows
|
* The idle + run duration is specified via separate helpers and that allows
|
||||||
* idle injection to be started.
|
* idle injection to be started.
|
||||||
*
|
*
|
||||||
* The idle injection kthreads will call play_idle() with the idle duration
|
* The idle injection kthreads will call play_idle_precise() with the idle
|
||||||
* specified as per the above.
|
* duration and max allowed latency specified as per the above.
|
||||||
*
|
*
|
||||||
* After all of them have been woken up, a timer is set to start the next idle
|
* After all of them have been woken up, a timer is set to start the next idle
|
||||||
* injection cycle.
|
* injection cycle.
|
||||||
@ -100,7 +100,7 @@ static void idle_inject_wakeup(struct idle_inject_device *ii_dev)
|
|||||||
*
|
*
|
||||||
* This function is called when the idle injection timer expires. It wakes up
|
* This function is called when the idle injection timer expires. It wakes up
|
||||||
* idle injection tasks associated with the timer and they, in turn, invoke
|
* idle injection tasks associated with the timer and they, in turn, invoke
|
||||||
* play_idle() to inject a specified amount of CPU idle time.
|
* play_idle_precise() to inject a specified amount of CPU idle time.
|
||||||
*
|
*
|
||||||
* Return: HRTIMER_RESTART.
|
* Return: HRTIMER_RESTART.
|
||||||
*/
|
*/
|
||||||
@ -124,8 +124,8 @@ static enum hrtimer_restart idle_inject_timer_fn(struct hrtimer *timer)
|
|||||||
* idle_inject_fn - idle injection work function
|
* idle_inject_fn - idle injection work function
|
||||||
* @cpu: the CPU owning the task
|
* @cpu: the CPU owning the task
|
||||||
*
|
*
|
||||||
* This function calls play_idle() to inject a specified amount of CPU idle
|
* This function calls play_idle_precise() to inject a specified amount of CPU
|
||||||
* time.
|
* idle time.
|
||||||
*/
|
*/
|
||||||
static void idle_inject_fn(unsigned int cpu)
|
static void idle_inject_fn(unsigned int cpu)
|
||||||
{
|
{
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
#define POWER_HIGH_LOCK BIT_ULL(63)
|
#define POWER_HIGH_LOCK BIT_ULL(63)
|
||||||
#define POWER_LOW_LOCK BIT(31)
|
#define POWER_LOW_LOCK BIT(31)
|
||||||
|
|
||||||
|
#define POWER_LIMIT4_MASK 0x1FFF
|
||||||
|
|
||||||
#define TIME_WINDOW1_MASK (0x7FULL<<17)
|
#define TIME_WINDOW1_MASK (0x7FULL<<17)
|
||||||
#define TIME_WINDOW2_MASK (0x7FULL<<49)
|
#define TIME_WINDOW2_MASK (0x7FULL<<49)
|
||||||
|
|
||||||
@ -82,6 +84,7 @@ enum unit_type {
|
|||||||
|
|
||||||
static const char pl1_name[] = "long_term";
|
static const char pl1_name[] = "long_term";
|
||||||
static const char pl2_name[] = "short_term";
|
static const char pl2_name[] = "short_term";
|
||||||
|
static const char pl4_name[] = "peak_power";
|
||||||
|
|
||||||
#define power_zone_to_rapl_domain(_zone) \
|
#define power_zone_to_rapl_domain(_zone) \
|
||||||
container_of(_zone, struct rapl_domain, power_zone)
|
container_of(_zone, struct rapl_domain, power_zone)
|
||||||
@ -93,6 +96,7 @@ struct rapl_defaults {
|
|||||||
u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
|
u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
|
||||||
bool to_raw);
|
bool to_raw);
|
||||||
unsigned int dram_domain_energy_unit;
|
unsigned int dram_domain_energy_unit;
|
||||||
|
unsigned int psys_domain_energy_unit;
|
||||||
};
|
};
|
||||||
static struct rapl_defaults *rapl_defaults;
|
static struct rapl_defaults *rapl_defaults;
|
||||||
|
|
||||||
@ -337,6 +341,9 @@ static int set_power_limit(struct powercap_zone *power_zone, int cid,
|
|||||||
case PL2_ENABLE:
|
case PL2_ENABLE:
|
||||||
rapl_write_data_raw(rd, POWER_LIMIT2, power_limit);
|
rapl_write_data_raw(rd, POWER_LIMIT2, power_limit);
|
||||||
break;
|
break;
|
||||||
|
case PL4_ENABLE:
|
||||||
|
rapl_write_data_raw(rd, POWER_LIMIT4, power_limit);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
@ -371,6 +378,9 @@ static int get_current_power_limit(struct powercap_zone *power_zone, int cid,
|
|||||||
case PL2_ENABLE:
|
case PL2_ENABLE:
|
||||||
prim = POWER_LIMIT2;
|
prim = POWER_LIMIT2;
|
||||||
break;
|
break;
|
||||||
|
case PL4_ENABLE:
|
||||||
|
prim = POWER_LIMIT4;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
put_online_cpus();
|
put_online_cpus();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -440,6 +450,13 @@ static int get_time_window(struct powercap_zone *power_zone, int cid,
|
|||||||
case PL2_ENABLE:
|
case PL2_ENABLE:
|
||||||
ret = rapl_read_data_raw(rd, TIME_WINDOW2, true, &val);
|
ret = rapl_read_data_raw(rd, TIME_WINDOW2, true, &val);
|
||||||
break;
|
break;
|
||||||
|
case PL4_ENABLE:
|
||||||
|
/*
|
||||||
|
* Time window parameter is not applicable for PL4 entry
|
||||||
|
* so assigining '0' as default value.
|
||||||
|
*/
|
||||||
|
val = 0;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
put_online_cpus();
|
put_online_cpus();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -483,6 +500,9 @@ static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data)
|
|||||||
case PL2_ENABLE:
|
case PL2_ENABLE:
|
||||||
prim = MAX_POWER;
|
prim = MAX_POWER;
|
||||||
break;
|
break;
|
||||||
|
case PL4_ENABLE:
|
||||||
|
prim = MAX_POWER;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
put_online_cpus();
|
put_online_cpus();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -492,6 +512,10 @@ static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data)
|
|||||||
else
|
else
|
||||||
*data = val;
|
*data = val;
|
||||||
|
|
||||||
|
/* As a generalization rule, PL4 would be around two times PL2. */
|
||||||
|
if (rd->rpl[id].prim_id == PL4_ENABLE)
|
||||||
|
*data = *data * 2;
|
||||||
|
|
||||||
put_online_cpus();
|
put_online_cpus();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -524,21 +548,42 @@ static void rapl_init_domains(struct rapl_package *rp)
|
|||||||
rd->id = i;
|
rd->id = i;
|
||||||
rd->rpl[0].prim_id = PL1_ENABLE;
|
rd->rpl[0].prim_id = PL1_ENABLE;
|
||||||
rd->rpl[0].name = pl1_name;
|
rd->rpl[0].name = pl1_name;
|
||||||
/* some domain may support two power limits */
|
|
||||||
if (rp->priv->limits[i] == 2) {
|
/*
|
||||||
|
* The PL2 power domain is applicable for limits two
|
||||||
|
* and limits three
|
||||||
|
*/
|
||||||
|
if (rp->priv->limits[i] >= 2) {
|
||||||
rd->rpl[1].prim_id = PL2_ENABLE;
|
rd->rpl[1].prim_id = PL2_ENABLE;
|
||||||
rd->rpl[1].name = pl2_name;
|
rd->rpl[1].name = pl2_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enable PL4 domain if the total power limits are three */
|
||||||
|
if (rp->priv->limits[i] == 3) {
|
||||||
|
rd->rpl[2].prim_id = PL4_ENABLE;
|
||||||
|
rd->rpl[2].name = pl4_name;
|
||||||
|
}
|
||||||
|
|
||||||
for (j = 0; j < RAPL_DOMAIN_REG_MAX; j++)
|
for (j = 0; j < RAPL_DOMAIN_REG_MAX; j++)
|
||||||
rd->regs[j] = rp->priv->regs[i][j];
|
rd->regs[j] = rp->priv->regs[i][j];
|
||||||
|
|
||||||
if (i == RAPL_DOMAIN_DRAM) {
|
switch (i) {
|
||||||
|
case RAPL_DOMAIN_DRAM:
|
||||||
rd->domain_energy_unit =
|
rd->domain_energy_unit =
|
||||||
rapl_defaults->dram_domain_energy_unit;
|
rapl_defaults->dram_domain_energy_unit;
|
||||||
if (rd->domain_energy_unit)
|
if (rd->domain_energy_unit)
|
||||||
pr_info("DRAM domain energy unit %dpj\n",
|
pr_info("DRAM domain energy unit %dpj\n",
|
||||||
rd->domain_energy_unit);
|
rd->domain_energy_unit);
|
||||||
|
break;
|
||||||
|
case RAPL_DOMAIN_PLATFORM:
|
||||||
|
rd->domain_energy_unit =
|
||||||
|
rapl_defaults->psys_domain_energy_unit;
|
||||||
|
if (rd->domain_energy_unit)
|
||||||
|
pr_info("Platform domain energy unit %dpj\n",
|
||||||
|
rd->domain_energy_unit);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
rd++;
|
rd++;
|
||||||
}
|
}
|
||||||
@ -587,6 +632,8 @@ static struct rapl_primitive_info rpi[] = {
|
|||||||
RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
|
RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
|
||||||
PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32,
|
PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32,
|
||||||
RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
|
RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
|
||||||
|
PRIMITIVE_INFO_INIT(POWER_LIMIT4, POWER_LIMIT4_MASK, 0,
|
||||||
|
RAPL_DOMAIN_REG_PL4, POWER_UNIT, 0),
|
||||||
PRIMITIVE_INFO_INIT(FW_LOCK, POWER_LOW_LOCK, 31,
|
PRIMITIVE_INFO_INIT(FW_LOCK, POWER_LOW_LOCK, 31,
|
||||||
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
|
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
|
||||||
PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
|
PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
|
||||||
@ -597,6 +644,8 @@ static struct rapl_primitive_info rpi[] = {
|
|||||||
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
|
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
|
||||||
PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48,
|
PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48,
|
||||||
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
|
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
|
||||||
|
PRIMITIVE_INFO_INIT(PL4_ENABLE, POWER_LIMIT4_MASK, 0,
|
||||||
|
RAPL_DOMAIN_REG_PL4, ARBITRARY_UNIT, 0),
|
||||||
PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17,
|
PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17,
|
||||||
RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
|
RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
|
||||||
PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49,
|
PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49,
|
||||||
@ -919,6 +968,14 @@ static const struct rapl_defaults rapl_defaults_hsw_server = {
|
|||||||
.dram_domain_energy_unit = 15300,
|
.dram_domain_energy_unit = 15300,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct rapl_defaults rapl_defaults_spr_server = {
|
||||||
|
.check_unit = rapl_check_unit_core,
|
||||||
|
.set_floor_freq = set_floor_freq_default,
|
||||||
|
.compute_time_window = rapl_compute_time_window_core,
|
||||||
|
.dram_domain_energy_unit = 15300,
|
||||||
|
.psys_domain_energy_unit = 1000000000,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct rapl_defaults rapl_defaults_byt = {
|
static const struct rapl_defaults rapl_defaults_byt = {
|
||||||
.floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_BYT,
|
.floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_BYT,
|
||||||
.check_unit = rapl_check_unit_atom,
|
.check_unit = rapl_check_unit_atom,
|
||||||
@ -978,6 +1035,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
|
|||||||
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &rapl_defaults_core),
|
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &rapl_defaults_core),
|
||||||
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &rapl_defaults_core),
|
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &rapl_defaults_core),
|
||||||
X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &rapl_defaults_core),
|
X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &rapl_defaults_core),
|
||||||
|
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &rapl_defaults_spr_server),
|
||||||
|
|
||||||
X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, &rapl_defaults_byt),
|
X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, &rapl_defaults_byt),
|
||||||
X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, &rapl_defaults_cht),
|
X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, &rapl_defaults_cht),
|
||||||
@ -1252,6 +1310,7 @@ void rapl_remove_package(struct rapl_package *rp)
|
|||||||
if (find_nr_power_limit(rd) > 1) {
|
if (find_nr_power_limit(rd) > 1) {
|
||||||
rapl_write_data_raw(rd, PL2_ENABLE, 0);
|
rapl_write_data_raw(rd, PL2_ENABLE, 0);
|
||||||
rapl_write_data_raw(rd, PL2_CLAMP, 0);
|
rapl_write_data_raw(rd, PL2_CLAMP, 0);
|
||||||
|
rapl_write_data_raw(rd, PL4_ENABLE, 0);
|
||||||
}
|
}
|
||||||
if (rd->id == RAPL_DOMAIN_PACKAGE) {
|
if (rd->id == RAPL_DOMAIN_PACKAGE) {
|
||||||
rd_package = rd;
|
rd_package = rd;
|
||||||
@ -1360,6 +1419,13 @@ static void power_limit_state_save(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
rd->rpl[i].last_power_limit = 0;
|
rd->rpl[i].last_power_limit = 0;
|
||||||
break;
|
break;
|
||||||
|
case PL4_ENABLE:
|
||||||
|
ret = rapl_read_data_raw(rd,
|
||||||
|
POWER_LIMIT4, true,
|
||||||
|
&rd->rpl[i].last_power_limit);
|
||||||
|
if (ret)
|
||||||
|
rd->rpl[i].last_power_limit = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1390,6 +1456,11 @@ static void power_limit_state_restore(void)
|
|||||||
rapl_write_data_raw(rd, POWER_LIMIT2,
|
rapl_write_data_raw(rd, POWER_LIMIT2,
|
||||||
rd->rpl[i].last_power_limit);
|
rd->rpl[i].last_power_limit);
|
||||||
break;
|
break;
|
||||||
|
case PL4_ENABLE:
|
||||||
|
if (rd->rpl[i].last_power_limit)
|
||||||
|
rapl_write_data_raw(rd, POWER_LIMIT4,
|
||||||
|
rd->rpl[i].last_power_limit);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
/* Local defines */
|
/* Local defines */
|
||||||
#define MSR_PLATFORM_POWER_LIMIT 0x0000065C
|
#define MSR_PLATFORM_POWER_LIMIT 0x0000065C
|
||||||
|
#define MSR_VR_CURRENT_CONFIG 0x00000601
|
||||||
|
|
||||||
/* private data for RAPL MSR Interface */
|
/* private data for RAPL MSR Interface */
|
||||||
static struct rapl_if_priv rapl_msr_priv = {
|
static struct rapl_if_priv rapl_msr_priv = {
|
||||||
@ -123,13 +124,27 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra)
|
|||||||
return ra->err;
|
return ra->err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* List of verified CPUs. */
|
||||||
|
static const struct x86_cpu_id pl4_support_ids[] = {
|
||||||
|
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
static int rapl_msr_probe(struct platform_device *pdev)
|
static int rapl_msr_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
const struct x86_cpu_id *id = x86_match_cpu(pl4_support_ids);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rapl_msr_priv.read_raw = rapl_msr_read_raw;
|
rapl_msr_priv.read_raw = rapl_msr_read_raw;
|
||||||
rapl_msr_priv.write_raw = rapl_msr_write_raw;
|
rapl_msr_priv.write_raw = rapl_msr_write_raw;
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
rapl_msr_priv.limits[RAPL_DOMAIN_PACKAGE] = 3;
|
||||||
|
rapl_msr_priv.regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PL4] =
|
||||||
|
MSR_VR_CURRENT_CONFIG;
|
||||||
|
pr_info("PL4 support detected.\n");
|
||||||
|
}
|
||||||
|
|
||||||
rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
|
rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
|
||||||
if (IS_ERR(rapl_msr_priv.control_type)) {
|
if (IS_ERR(rapl_msr_priv.control_type)) {
|
||||||
pr_debug("failed to register powercap control_type.\n");
|
pr_debug("failed to register powercap control_type.\n");
|
||||||
|
@ -414,7 +414,7 @@ static int nfs4_delay_interruptible(long *timeout)
|
|||||||
{
|
{
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
|
||||||
freezable_schedule_timeout_interruptible(nfs4_update_delay(timeout));
|
freezable_schedule_timeout_interruptible_unsafe(nfs4_update_delay(timeout));
|
||||||
if (!signal_pending(current))
|
if (!signal_pending(current))
|
||||||
return 0;
|
return 0;
|
||||||
return __fatal_signal_pending(current) ? -EINTR :-ERESTARTSYS;
|
return __fatal_signal_pending(current) ? -EINTR :-ERESTARTSYS;
|
||||||
|
@ -207,6 +207,17 @@ static inline long freezable_schedule_timeout_interruptible(long timeout)
|
|||||||
return __retval;
|
return __retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
|
||||||
|
static inline long freezable_schedule_timeout_interruptible_unsafe(long timeout)
|
||||||
|
{
|
||||||
|
long __retval;
|
||||||
|
|
||||||
|
freezer_do_not_count();
|
||||||
|
__retval = schedule_timeout_interruptible(timeout);
|
||||||
|
freezer_count_unsafe();
|
||||||
|
return __retval;
|
||||||
|
}
|
||||||
|
|
||||||
/* Like schedule_timeout_killable(), but should not block the freezer. */
|
/* Like schedule_timeout_killable(), but should not block the freezer. */
|
||||||
static inline long freezable_schedule_timeout_killable(long timeout)
|
static inline long freezable_schedule_timeout_killable(long timeout)
|
||||||
{
|
{
|
||||||
@ -285,6 +296,9 @@ static inline void set_freezable(void) {}
|
|||||||
#define freezable_schedule_timeout_interruptible(timeout) \
|
#define freezable_schedule_timeout_interruptible(timeout) \
|
||||||
schedule_timeout_interruptible(timeout)
|
schedule_timeout_interruptible(timeout)
|
||||||
|
|
||||||
|
#define freezable_schedule_timeout_interruptible_unsafe(timeout) \
|
||||||
|
schedule_timeout_interruptible(timeout)
|
||||||
|
|
||||||
#define freezable_schedule_timeout_killable(timeout) \
|
#define freezable_schedule_timeout_killable(timeout) \
|
||||||
schedule_timeout_killable(timeout)
|
schedule_timeout_killable(timeout)
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ enum rapl_domain_reg_id {
|
|||||||
RAPL_DOMAIN_REG_PERF,
|
RAPL_DOMAIN_REG_PERF,
|
||||||
RAPL_DOMAIN_REG_POLICY,
|
RAPL_DOMAIN_REG_POLICY,
|
||||||
RAPL_DOMAIN_REG_INFO,
|
RAPL_DOMAIN_REG_INFO,
|
||||||
|
RAPL_DOMAIN_REG_PL4,
|
||||||
RAPL_DOMAIN_REG_MAX,
|
RAPL_DOMAIN_REG_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,12 +39,14 @@ enum rapl_primitives {
|
|||||||
ENERGY_COUNTER,
|
ENERGY_COUNTER,
|
||||||
POWER_LIMIT1,
|
POWER_LIMIT1,
|
||||||
POWER_LIMIT2,
|
POWER_LIMIT2,
|
||||||
|
POWER_LIMIT4,
|
||||||
FW_LOCK,
|
FW_LOCK,
|
||||||
|
|
||||||
PL1_ENABLE, /* power limit 1, aka long term */
|
PL1_ENABLE, /* power limit 1, aka long term */
|
||||||
PL1_CLAMP, /* allow frequency to go below OS request */
|
PL1_CLAMP, /* allow frequency to go below OS request */
|
||||||
PL2_ENABLE, /* power limit 2, aka short term, instantaneous */
|
PL2_ENABLE, /* power limit 2, aka short term, instantaneous */
|
||||||
PL2_CLAMP,
|
PL2_CLAMP,
|
||||||
|
PL4_ENABLE, /* power limit 4, aka max peak power */
|
||||||
|
|
||||||
TIME_WINDOW1, /* long term */
|
TIME_WINDOW1, /* long term */
|
||||||
TIME_WINDOW2, /* short term */
|
TIME_WINDOW2, /* short term */
|
||||||
@ -65,7 +68,7 @@ struct rapl_domain_data {
|
|||||||
unsigned long timestamp;
|
unsigned long timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NR_POWER_LIMITS (2)
|
#define NR_POWER_LIMITS (3)
|
||||||
struct rapl_power_limit {
|
struct rapl_power_limit {
|
||||||
struct powercap_zone_constraint *constraint;
|
struct powercap_zone_constraint *constraint;
|
||||||
int prim_id; /* primitive ID used to enable */
|
int prim_id; /* primitive ID used to enable */
|
||||||
|
@ -95,8 +95,8 @@ struct generic_pm_domain {
|
|||||||
struct device dev;
|
struct device dev;
|
||||||
struct dev_pm_domain domain; /* PM domain operations */
|
struct dev_pm_domain domain; /* PM domain operations */
|
||||||
struct list_head gpd_list_node; /* Node in the global PM domains list */
|
struct list_head gpd_list_node; /* Node in the global PM domains list */
|
||||||
struct list_head master_links; /* Links with PM domain as a master */
|
struct list_head parent_links; /* Links with PM domain as a parent */
|
||||||
struct list_head slave_links; /* Links with PM domain as a slave */
|
struct list_head child_links; /* Links with PM domain as a child */
|
||||||
struct list_head dev_list; /* List of devices */
|
struct list_head dev_list; /* List of devices */
|
||||||
struct dev_power_governor *gov;
|
struct dev_power_governor *gov;
|
||||||
struct work_struct power_off_work;
|
struct work_struct power_off_work;
|
||||||
@ -151,10 +151,10 @@ static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct gpd_link {
|
struct gpd_link {
|
||||||
struct generic_pm_domain *master;
|
struct generic_pm_domain *parent;
|
||||||
struct list_head master_node;
|
struct list_head parent_node;
|
||||||
struct generic_pm_domain *slave;
|
struct generic_pm_domain *child;
|
||||||
struct list_head slave_node;
|
struct list_head child_node;
|
||||||
|
|
||||||
/* Sub-domain's per-master domain performance state */
|
/* Sub-domain's per-master domain performance state */
|
||||||
unsigned int performance_state;
|
unsigned int performance_state;
|
||||||
|
@ -1062,7 +1062,7 @@ power_attr(disk);
|
|||||||
static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
|
return sprintf(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
|
||||||
MINOR(swsusp_resume_device));
|
MINOR(swsusp_resume_device));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1162,7 +1162,7 @@ static ssize_t reserved_size_store(struct kobject *kobj,
|
|||||||
|
|
||||||
power_attr(reserved_size);
|
power_attr(reserved_size);
|
||||||
|
|
||||||
static struct attribute * g[] = {
|
static struct attribute *g[] = {
|
||||||
&disk_attr.attr,
|
&disk_attr.attr,
|
||||||
&resume_offset_attr.attr,
|
&resume_offset_attr.attr,
|
||||||
&resume_attr.attr,
|
&resume_attr.attr,
|
||||||
@ -1190,7 +1190,7 @@ static int __init resume_setup(char *str)
|
|||||||
if (noresume)
|
if (noresume)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
strncpy( resume_file, str, 255 );
|
strncpy(resume_file, str, 255);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ static inline int init_header_complete(struct swsusp_info *info)
|
|||||||
return arch_hibernation_header_save(info, MAX_ARCH_HEADER_SIZE);
|
return arch_hibernation_header_save(info, MAX_ARCH_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *check_image_kernel(struct swsusp_info *info)
|
static inline const char *check_image_kernel(struct swsusp_info *info)
|
||||||
{
|
{
|
||||||
return arch_hibernation_header_restore(info) ?
|
return arch_hibernation_header_restore(info) ?
|
||||||
"architecture specific data" : NULL;
|
"architecture specific data" : NULL;
|
||||||
|
@ -2023,7 +2023,7 @@ static int init_header_complete(struct swsusp_info *info)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *check_image_kernel(struct swsusp_info *info)
|
static const char *check_image_kernel(struct swsusp_info *info)
|
||||||
{
|
{
|
||||||
if (info->version_code != LINUX_VERSION_CODE)
|
if (info->version_code != LINUX_VERSION_CODE)
|
||||||
return "kernel version";
|
return "kernel version";
|
||||||
@ -2176,7 +2176,7 @@ static void mark_unsafe_pages(struct memory_bitmap *bm)
|
|||||||
|
|
||||||
static int check_header(struct swsusp_info *info)
|
static int check_header(struct swsusp_info *info)
|
||||||
{
|
{
|
||||||
char *reason;
|
const char *reason;
|
||||||
|
|
||||||
reason = check_image_kernel(info);
|
reason = check_image_kernel(info);
|
||||||
if (!reason && info->num_physpages != get_num_physpages())
|
if (!reason && info->num_physpages != get_num_physpages())
|
||||||
|
@ -49,17 +49,17 @@ Output is similar to /sys/kernel/debug/pm_genpd/pm_genpd_summary'''
|
|||||||
else:
|
else:
|
||||||
status_string = 'off-{}'.format(genpd['state_idx'])
|
status_string = 'off-{}'.format(genpd['state_idx'])
|
||||||
|
|
||||||
slave_names = []
|
child_names = []
|
||||||
for link in list_for_each_entry(
|
for link in list_for_each_entry(
|
||||||
genpd['master_links'],
|
genpd['parent_links'],
|
||||||
device_link_type.get_type().pointer(),
|
device_link_type.get_type().pointer(),
|
||||||
'master_node'):
|
'parent_node'):
|
||||||
slave_names.apend(link['slave']['name'])
|
child_names.append(link['child']['name'])
|
||||||
|
|
||||||
gdb.write('%-30s %-15s %s\n' % (
|
gdb.write('%-30s %-15s %s\n' % (
|
||||||
genpd['name'].string(),
|
genpd['name'].string(),
|
||||||
status_string,
|
status_string,
|
||||||
', '.join(slave_names)))
|
', '.join(child_names)))
|
||||||
|
|
||||||
# Print devices in domain
|
# Print devices in domain
|
||||||
for pm_data in list_for_each_entry(genpd['dev_list'],
|
for pm_data in list_for_each_entry(genpd['dev_list'],
|
||||||
@ -70,7 +70,7 @@ Output is similar to /sys/kernel/debug/pm_genpd/pm_genpd_summary'''
|
|||||||
gdb.write(' %-50s %s\n' % (kobj_path, rtpm_status_str(dev)))
|
gdb.write(' %-50s %s\n' % (kobj_path, rtpm_status_str(dev)))
|
||||||
|
|
||||||
def invoke(self, arg, from_tty):
|
def invoke(self, arg, from_tty):
|
||||||
gdb.write('domain status slaves\n');
|
gdb.write('domain status children\n');
|
||||||
gdb.write(' /device runtime status\n');
|
gdb.write(' /device runtime status\n');
|
||||||
gdb.write('----------------------------------------------------------------------\n');
|
gdb.write('----------------------------------------------------------------------\n');
|
||||||
for genpd in list_for_each_entry(
|
for genpd in list_for_each_entry(
|
||||||
|
@ -285,7 +285,7 @@ struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned
|
|||||||
} else {
|
} else {
|
||||||
first = malloc(sizeof(*first));
|
first = malloc(sizeof(*first));
|
||||||
if (!first)
|
if (!first)
|
||||||
goto error_out;
|
return NULL;
|
||||||
current = first;
|
current = first;
|
||||||
}
|
}
|
||||||
current->first = first;
|
current->first = first;
|
||||||
@ -362,7 +362,7 @@ struct cpufreq_available_frequencies
|
|||||||
} else {
|
} else {
|
||||||
first = malloc(sizeof(*first));
|
first = malloc(sizeof(*first));
|
||||||
if (!first)
|
if (!first)
|
||||||
goto error_out;
|
return NULL;
|
||||||
current = first;
|
current = first;
|
||||||
}
|
}
|
||||||
current->first = first;
|
current->first = first;
|
||||||
@ -418,7 +418,7 @@ struct cpufreq_available_frequencies
|
|||||||
} else {
|
} else {
|
||||||
first = malloc(sizeof(*first));
|
first = malloc(sizeof(*first));
|
||||||
if (!first)
|
if (!first)
|
||||||
goto error_out;
|
return NULL;
|
||||||
current = first;
|
current = first;
|
||||||
}
|
}
|
||||||
current->first = first;
|
current->first = first;
|
||||||
@ -493,7 +493,7 @@ static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu,
|
|||||||
} else {
|
} else {
|
||||||
first = malloc(sizeof(*first));
|
first = malloc(sizeof(*first));
|
||||||
if (!first)
|
if (!first)
|
||||||
goto error_out;
|
return NULL;
|
||||||
current = first;
|
current = first;
|
||||||
}
|
}
|
||||||
current->first = first;
|
current->first = first;
|
||||||
@ -726,7 +726,7 @@ struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
|
|||||||
} else {
|
} else {
|
||||||
first = malloc(sizeof(*first));
|
first = malloc(sizeof(*first));
|
||||||
if (!first)
|
if (!first)
|
||||||
goto error_out;
|
return NULL;
|
||||||
current = first;
|
current = first;
|
||||||
}
|
}
|
||||||
current->first = first;
|
current->first = first;
|
||||||
|
@ -170,7 +170,7 @@ displayed.
|
|||||||
|
|
||||||
.SH REFERENCES
|
.SH REFERENCES
|
||||||
"BIOS and Kernel Developer’s Guide (BKDG) for AMD Family 14h Processors"
|
"BIOS and Kernel Developer’s Guide (BKDG) for AMD Family 14h Processors"
|
||||||
http://support.amd.com/us/Processor_TechDocs/43170.pdf
|
https://support.amd.com/us/Processor_TechDocs/43170.pdf
|
||||||
|
|
||||||
"Intel® Turbo Boost Technology
|
"Intel® Turbo Boost Technology
|
||||||
in Intel® Core™ Microarchitecture (Nehalem) Based Processors"
|
in Intel® Core™ Microarchitecture (Nehalem) Based Processors"
|
||||||
@ -178,7 +178,7 @@ http://download.intel.com/design/processor/applnots/320354.pdf
|
|||||||
|
|
||||||
"Intel® 64 and IA-32 Architectures Software Developer's Manual
|
"Intel® 64 and IA-32 Architectures Software Developer's Manual
|
||||||
Volume 3B: System Programming Guide"
|
Volume 3B: System Programming Guide"
|
||||||
http://www.intel.com/products/processor/manuals
|
https://www.intel.com/products/processor/manuals
|
||||||
|
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.ta
|
.ta
|
||||||
|
@ -26,11 +26,11 @@ struct bitmask *bitmask_alloc(unsigned int n)
|
|||||||
struct bitmask *bmp;
|
struct bitmask *bmp;
|
||||||
|
|
||||||
bmp = malloc(sizeof(*bmp));
|
bmp = malloc(sizeof(*bmp));
|
||||||
if (bmp == 0)
|
if (!bmp)
|
||||||
return 0;
|
return 0;
|
||||||
bmp->size = n;
|
bmp->size = n;
|
||||||
bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
|
bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
|
||||||
if (bmp->maskp == 0) {
|
if (!bmp->maskp) {
|
||||||
free(bmp);
|
free(bmp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ struct bitmask *bitmask_alloc(unsigned int n)
|
|||||||
/* Free `struct bitmask` */
|
/* Free `struct bitmask` */
|
||||||
void bitmask_free(struct bitmask *bmp)
|
void bitmask_free(struct bitmask *bmp)
|
||||||
{
|
{
|
||||||
if (bmp == 0)
|
if (!bmp)
|
||||||
return;
|
return;
|
||||||
free(bmp->maskp);
|
free(bmp->maskp);
|
||||||
bmp->maskp = (unsigned long *)0xdeadcdef; /* double free tripwire */
|
bmp->maskp = (unsigned long *)0xdeadcdef; /* double free tripwire */
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|_| |___/ |_|
|
|_| |___/ |_|
|
||||||
|
|
||||||
pm-graph: suspend/resume/boot timing analysis tools
|
pm-graph: suspend/resume/boot timing analysis tools
|
||||||
Version: 5.6
|
Version: 5.7
|
||||||
Author: Todd Brandt <todd.e.brandt@intel.com>
|
Author: Todd Brandt <todd.e.brandt@intel.com>
|
||||||
Home Page: https://01.org/pm-graph
|
Home Page: https://01.org/pm-graph
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ def ascii(text):
|
|||||||
# store system values and test parameters
|
# store system values and test parameters
|
||||||
class SystemValues:
|
class SystemValues:
|
||||||
title = 'SleepGraph'
|
title = 'SleepGraph'
|
||||||
version = '5.6'
|
version = '5.7'
|
||||||
ansi = False
|
ansi = False
|
||||||
rs = 0
|
rs = 0
|
||||||
display = ''
|
display = ''
|
||||||
@ -198,7 +198,7 @@ class SystemValues:
|
|||||||
'suspend_console': {},
|
'suspend_console': {},
|
||||||
'acpi_pm_prepare': {},
|
'acpi_pm_prepare': {},
|
||||||
'syscore_suspend': {},
|
'syscore_suspend': {},
|
||||||
'arch_thaw_secondary_cpus_end': {},
|
'arch_enable_nonboot_cpus_end': {},
|
||||||
'syscore_resume': {},
|
'syscore_resume': {},
|
||||||
'acpi_pm_finish': {},
|
'acpi_pm_finish': {},
|
||||||
'resume_console': {},
|
'resume_console': {},
|
||||||
@ -924,10 +924,7 @@ class SystemValues:
|
|||||||
tp = TestProps()
|
tp = TestProps()
|
||||||
tf = self.openlog(self.ftracefile, 'r')
|
tf = self.openlog(self.ftracefile, 'r')
|
||||||
for line in tf:
|
for line in tf:
|
||||||
# determine the trace data type (required for further parsing)
|
if tp.stampInfo(line, self):
|
||||||
m = re.match(tp.tracertypefmt, line)
|
|
||||||
if(m):
|
|
||||||
tp.setTracerType(m.group('t'))
|
|
||||||
continue
|
continue
|
||||||
# parse only valid lines, if this is not one move on
|
# parse only valid lines, if this is not one move on
|
||||||
m = re.match(tp.ftrace_line_fmt, line)
|
m = re.match(tp.ftrace_line_fmt, line)
|
||||||
@ -1244,8 +1241,8 @@ class DevProps:
|
|||||||
if self.xtraclass:
|
if self.xtraclass:
|
||||||
return ' '+self.xtraclass
|
return ' '+self.xtraclass
|
||||||
if self.isasync:
|
if self.isasync:
|
||||||
return ' async_device'
|
return ' (async)'
|
||||||
return ' sync_device'
|
return ' (sync)'
|
||||||
|
|
||||||
# Class: DeviceNode
|
# Class: DeviceNode
|
||||||
# Description:
|
# Description:
|
||||||
@ -1301,6 +1298,7 @@ class Data:
|
|||||||
'FAIL' : r'(?i).*\bFAILED\b.*',
|
'FAIL' : r'(?i).*\bFAILED\b.*',
|
||||||
'INVALID' : r'(?i).*\bINVALID\b.*',
|
'INVALID' : r'(?i).*\bINVALID\b.*',
|
||||||
'CRASH' : r'(?i).*\bCRASHED\b.*',
|
'CRASH' : r'(?i).*\bCRASHED\b.*',
|
||||||
|
'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*',
|
||||||
'IRQ' : r'.*\bgenirq: .*',
|
'IRQ' : r'.*\bgenirq: .*',
|
||||||
'TASKFAIL': r'.*Freezing of tasks *.*',
|
'TASKFAIL': r'.*Freezing of tasks *.*',
|
||||||
'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*',
|
'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*',
|
||||||
@ -1358,11 +1356,11 @@ class Data:
|
|||||||
if self.dmesg[p]['order'] == order:
|
if self.dmesg[p]['order'] == order:
|
||||||
return p
|
return p
|
||||||
return ''
|
return ''
|
||||||
def lastPhase(self):
|
def lastPhase(self, depth=1):
|
||||||
plist = self.sortedPhases()
|
plist = self.sortedPhases()
|
||||||
if len(plist) < 1:
|
if len(plist) < depth:
|
||||||
return ''
|
return ''
|
||||||
return plist[-1]
|
return plist[-1*depth]
|
||||||
def turbostatInfo(self):
|
def turbostatInfo(self):
|
||||||
tp = TestProps()
|
tp = TestProps()
|
||||||
out = {'syslpi':'N/A','pkgpc10':'N/A'}
|
out = {'syslpi':'N/A','pkgpc10':'N/A'}
|
||||||
@ -1382,9 +1380,12 @@ class Data:
|
|||||||
if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
|
if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
|
||||||
lf = sysvals.openlog(sysvals.dmesgfile, 'r')
|
lf = sysvals.openlog(sysvals.dmesgfile, 'r')
|
||||||
i = 0
|
i = 0
|
||||||
|
tp = TestProps()
|
||||||
list = []
|
list = []
|
||||||
for line in lf:
|
for line in lf:
|
||||||
i += 1
|
i += 1
|
||||||
|
if tp.stampInfo(line, sysvals):
|
||||||
|
continue
|
||||||
m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
|
m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
|
||||||
if not m:
|
if not m:
|
||||||
continue
|
continue
|
||||||
@ -1400,15 +1401,15 @@ class Data:
|
|||||||
list.append((msg, err, dir, t, i, i))
|
list.append((msg, err, dir, t, i, i))
|
||||||
self.kerror = True
|
self.kerror = True
|
||||||
break
|
break
|
||||||
msglist = []
|
tp.msglist = []
|
||||||
for msg, type, dir, t, idx1, idx2 in list:
|
for msg, type, dir, t, idx1, idx2 in list:
|
||||||
msglist.append(msg)
|
tp.msglist.append(msg)
|
||||||
self.errorinfo[dir].append((type, t, idx1, idx2))
|
self.errorinfo[dir].append((type, t, idx1, idx2))
|
||||||
if self.kerror:
|
if self.kerror:
|
||||||
sysvals.dmesglog = True
|
sysvals.dmesglog = True
|
||||||
if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
|
if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
|
||||||
lf.close()
|
lf.close()
|
||||||
return msglist
|
return tp
|
||||||
def setStart(self, time, msg=''):
|
def setStart(self, time, msg=''):
|
||||||
self.start = time
|
self.start = time
|
||||||
if msg:
|
if msg:
|
||||||
@ -1623,6 +1624,8 @@ class Data:
|
|||||||
if('src' in d):
|
if('src' in d):
|
||||||
for e in d['src']:
|
for e in d['src']:
|
||||||
e.time = self.trimTimeVal(e.time, t0, dT, left)
|
e.time = self.trimTimeVal(e.time, t0, dT, left)
|
||||||
|
e.end = self.trimTimeVal(e.end, t0, dT, left)
|
||||||
|
e.length = e.end - e.time
|
||||||
for dir in ['suspend', 'resume']:
|
for dir in ['suspend', 'resume']:
|
||||||
list = []
|
list = []
|
||||||
for e in self.errorinfo[dir]:
|
for e in self.errorinfo[dir]:
|
||||||
@ -1640,7 +1643,12 @@ class Data:
|
|||||||
if tL > 0:
|
if tL > 0:
|
||||||
left = True if tR > tZero else False
|
left = True if tR > tZero else False
|
||||||
self.trimTime(tS, tL, left)
|
self.trimTime(tS, tL, left)
|
||||||
self.tLow.append('%.0f'%(tL*1000))
|
if 'trying' in self.dmesg[lp] and self.dmesg[lp]['trying'] >= 0.001:
|
||||||
|
tTry = round(self.dmesg[lp]['trying'] * 1000)
|
||||||
|
text = '%.0f (-%.0f waking)' % (tL * 1000, tTry)
|
||||||
|
else:
|
||||||
|
text = '%.0f' % (tL * 1000)
|
||||||
|
self.tLow.append(text)
|
||||||
lp = phase
|
lp = phase
|
||||||
def getMemTime(self):
|
def getMemTime(self):
|
||||||
if not self.hwstart or not self.hwend:
|
if not self.hwstart or not self.hwend:
|
||||||
@ -1776,7 +1784,7 @@ class Data:
|
|||||||
length = -1.0
|
length = -1.0
|
||||||
if(start >= 0 and end >= 0):
|
if(start >= 0 and end >= 0):
|
||||||
length = end - start
|
length = end - start
|
||||||
if pid == -2:
|
if pid == -2 or name not in sysvals.tracefuncs.keys():
|
||||||
i = 2
|
i = 2
|
||||||
origname = name
|
origname = name
|
||||||
while(name in list):
|
while(name in list):
|
||||||
@ -1789,6 +1797,15 @@ class Data:
|
|||||||
if color:
|
if color:
|
||||||
list[name]['color'] = color
|
list[name]['color'] = color
|
||||||
return name
|
return name
|
||||||
|
def findDevice(self, phase, name):
|
||||||
|
list = self.dmesg[phase]['list']
|
||||||
|
mydev = ''
|
||||||
|
for devname in sorted(list):
|
||||||
|
if name == devname or re.match('^%s\[(?P<num>[0-9]*)\]$' % name, devname):
|
||||||
|
mydev = devname
|
||||||
|
if mydev:
|
||||||
|
return list[mydev]
|
||||||
|
return False
|
||||||
def deviceChildren(self, devname, phase):
|
def deviceChildren(self, devname, phase):
|
||||||
devlist = []
|
devlist = []
|
||||||
list = self.dmesg[phase]['list']
|
list = self.dmesg[phase]['list']
|
||||||
@ -2779,6 +2796,7 @@ class TestProps:
|
|||||||
testerrfmt = '^# enter_sleep_error (?P<e>.*)'
|
testerrfmt = '^# enter_sleep_error (?P<e>.*)'
|
||||||
sysinfofmt = '^# sysinfo .*'
|
sysinfofmt = '^# sysinfo .*'
|
||||||
cmdlinefmt = '^# command \| (?P<cmd>.*)'
|
cmdlinefmt = '^# command \| (?P<cmd>.*)'
|
||||||
|
kparamsfmt = '^# kparams \| (?P<kp>.*)'
|
||||||
devpropfmt = '# Device Properties: .*'
|
devpropfmt = '# Device Properties: .*'
|
||||||
pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)'
|
pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)'
|
||||||
tracertypefmt = '# tracer: (?P<t>.*)'
|
tracertypefmt = '# tracer: (?P<t>.*)'
|
||||||
@ -2790,8 +2808,9 @@ class TestProps:
|
|||||||
'[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)'
|
'[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)'
|
||||||
ftrace_line_fmt_nop = \
|
ftrace_line_fmt_nop = \
|
||||||
' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\
|
' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\
|
||||||
'(?P<flags>.{4}) *(?P<time>[0-9\.]*): *'+\
|
'(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\
|
||||||
'(?P<msg>.*)'
|
'(?P<msg>.*)'
|
||||||
|
machinesuspend = 'machine_suspend\[.*'
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.stamp = ''
|
self.stamp = ''
|
||||||
self.sysinfo = ''
|
self.sysinfo = ''
|
||||||
@ -2812,16 +2831,13 @@ class TestProps:
|
|||||||
self.ftrace_line_fmt = self.ftrace_line_fmt_nop
|
self.ftrace_line_fmt = self.ftrace_line_fmt_nop
|
||||||
else:
|
else:
|
||||||
doError('Invalid tracer format: [%s]' % tracer)
|
doError('Invalid tracer format: [%s]' % tracer)
|
||||||
def stampInfo(self, line):
|
def stampInfo(self, line, sv):
|
||||||
if re.match(self.stampfmt, line):
|
if re.match(self.stampfmt, line):
|
||||||
self.stamp = line
|
self.stamp = line
|
||||||
return True
|
return True
|
||||||
elif re.match(self.sysinfofmt, line):
|
elif re.match(self.sysinfofmt, line):
|
||||||
self.sysinfo = line
|
self.sysinfo = line
|
||||||
return True
|
return True
|
||||||
elif re.match(self.cmdlinefmt, line):
|
|
||||||
self.cmdline = line
|
|
||||||
return True
|
|
||||||
elif re.match(self.tstatfmt, line):
|
elif re.match(self.tstatfmt, line):
|
||||||
self.turbostat.append(line)
|
self.turbostat.append(line)
|
||||||
return True
|
return True
|
||||||
@ -2834,6 +2850,20 @@ class TestProps:
|
|||||||
elif re.match(self.firmwarefmt, line):
|
elif re.match(self.firmwarefmt, line):
|
||||||
self.fwdata.append(line)
|
self.fwdata.append(line)
|
||||||
return True
|
return True
|
||||||
|
elif(re.match(self.devpropfmt, line)):
|
||||||
|
self.parseDevprops(line, sv)
|
||||||
|
return True
|
||||||
|
elif(re.match(self.pinfofmt, line)):
|
||||||
|
self.parsePlatformInfo(line, sv)
|
||||||
|
return True
|
||||||
|
m = re.match(self.cmdlinefmt, line)
|
||||||
|
if m:
|
||||||
|
self.cmdline = m.group('cmd')
|
||||||
|
return True
|
||||||
|
m = re.match(self.tracertypefmt, line)
|
||||||
|
if(m):
|
||||||
|
self.setTracerType(m.group('t'))
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
def parseStamp(self, data, sv):
|
def parseStamp(self, data, sv):
|
||||||
# global test data
|
# global test data
|
||||||
@ -2858,9 +2888,13 @@ class TestProps:
|
|||||||
data.stamp[key] = val
|
data.stamp[key] = val
|
||||||
sv.hostname = data.stamp['host']
|
sv.hostname = data.stamp['host']
|
||||||
sv.suspendmode = data.stamp['mode']
|
sv.suspendmode = data.stamp['mode']
|
||||||
|
if sv.suspendmode == 'freeze':
|
||||||
|
self.machinesuspend = 'timekeeping_freeze\[.*'
|
||||||
|
else:
|
||||||
|
self.machinesuspend = 'machine_suspend\[.*'
|
||||||
if sv.suspendmode == 'command' and sv.ftracefile != '':
|
if sv.suspendmode == 'command' and sv.ftracefile != '':
|
||||||
modes = ['on', 'freeze', 'standby', 'mem', 'disk']
|
modes = ['on', 'freeze', 'standby', 'mem', 'disk']
|
||||||
fp = sysvals.openlog(sv.ftracefile, 'r')
|
fp = sv.openlog(sv.ftracefile, 'r')
|
||||||
for line in fp:
|
for line in fp:
|
||||||
m = re.match('.* machine_suspend\[(?P<mode>.*)\]', line)
|
m = re.match('.* machine_suspend\[(?P<mode>.*)\]', line)
|
||||||
if m and m.group('mode') in ['1', '2', '3', '4']:
|
if m and m.group('mode') in ['1', '2', '3', '4']:
|
||||||
@ -2868,9 +2902,7 @@ class TestProps:
|
|||||||
data.stamp['mode'] = sv.suspendmode
|
data.stamp['mode'] = sv.suspendmode
|
||||||
break
|
break
|
||||||
fp.close()
|
fp.close()
|
||||||
m = re.match(self.cmdlinefmt, self.cmdline)
|
sv.cmdline = self.cmdline
|
||||||
if m:
|
|
||||||
sv.cmdline = m.group('cmd')
|
|
||||||
if not sv.stamp:
|
if not sv.stamp:
|
||||||
sv.stamp = data.stamp
|
sv.stamp = data.stamp
|
||||||
# firmware data
|
# firmware data
|
||||||
@ -3052,20 +3084,7 @@ def appendIncompleteTraceLog(testruns):
|
|||||||
for line in tf:
|
for line in tf:
|
||||||
# remove any latent carriage returns
|
# remove any latent carriage returns
|
||||||
line = line.replace('\r\n', '')
|
line = line.replace('\r\n', '')
|
||||||
if tp.stampInfo(line):
|
if tp.stampInfo(line, sysvals):
|
||||||
continue
|
|
||||||
# determine the trace data type (required for further parsing)
|
|
||||||
m = re.match(tp.tracertypefmt, line)
|
|
||||||
if(m):
|
|
||||||
tp.setTracerType(m.group('t'))
|
|
||||||
continue
|
|
||||||
# device properties line
|
|
||||||
if(re.match(tp.devpropfmt, line)):
|
|
||||||
tp.parseDevprops(line, sysvals)
|
|
||||||
continue
|
|
||||||
# platform info line
|
|
||||||
if(re.match(tp.pinfofmt, line)):
|
|
||||||
tp.parsePlatformInfo(line, sysvals)
|
|
||||||
continue
|
continue
|
||||||
# parse only valid lines, if this is not one move on
|
# parse only valid lines, if this is not one move on
|
||||||
m = re.match(tp.ftrace_line_fmt, line)
|
m = re.match(tp.ftrace_line_fmt, line)
|
||||||
@ -3166,33 +3185,19 @@ def parseTraceLog(live=False):
|
|||||||
if sysvals.usekprobes:
|
if sysvals.usekprobes:
|
||||||
tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend',
|
tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend',
|
||||||
'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON',
|
'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON',
|
||||||
'CPU_OFF', 'timekeeping_freeze', 'acpi_suspend']
|
'CPU_OFF', 'acpi_suspend']
|
||||||
|
|
||||||
# extract the callgraph and traceevent data
|
# extract the callgraph and traceevent data
|
||||||
|
s2idle_enter = hwsus = False
|
||||||
tp = TestProps()
|
tp = TestProps()
|
||||||
testruns = []
|
testruns, testdata = [], []
|
||||||
testdata = []
|
testrun, data, limbo = 0, 0, True
|
||||||
testrun = 0
|
|
||||||
data, limbo = 0, True
|
|
||||||
tf = sysvals.openlog(sysvals.ftracefile, 'r')
|
tf = sysvals.openlog(sysvals.ftracefile, 'r')
|
||||||
phase = 'suspend_prepare'
|
phase = 'suspend_prepare'
|
||||||
for line in tf:
|
for line in tf:
|
||||||
# remove any latent carriage returns
|
# remove any latent carriage returns
|
||||||
line = line.replace('\r\n', '')
|
line = line.replace('\r\n', '')
|
||||||
if tp.stampInfo(line):
|
if tp.stampInfo(line, sysvals):
|
||||||
continue
|
|
||||||
# tracer type line: determine the trace data type
|
|
||||||
m = re.match(tp.tracertypefmt, line)
|
|
||||||
if(m):
|
|
||||||
tp.setTracerType(m.group('t'))
|
|
||||||
continue
|
|
||||||
# device properties line
|
|
||||||
if(re.match(tp.devpropfmt, line)):
|
|
||||||
tp.parseDevprops(line, sysvals)
|
|
||||||
continue
|
|
||||||
# platform info line
|
|
||||||
if(re.match(tp.pinfofmt, line)):
|
|
||||||
tp.parsePlatformInfo(line, sysvals)
|
|
||||||
continue
|
continue
|
||||||
# ignore all other commented lines
|
# ignore all other commented lines
|
||||||
if line[0] == '#':
|
if line[0] == '#':
|
||||||
@ -3303,16 +3308,29 @@ def parseTraceLog(live=False):
|
|||||||
phase = data.setPhase('suspend_noirq', t.time, isbegin)
|
phase = data.setPhase('suspend_noirq', t.time, isbegin)
|
||||||
continue
|
continue
|
||||||
# suspend_machine/resume_machine
|
# suspend_machine/resume_machine
|
||||||
elif(re.match('machine_suspend\[.*', t.name)):
|
elif(re.match(tp.machinesuspend, t.name)):
|
||||||
|
lp = data.lastPhase()
|
||||||
if(isbegin):
|
if(isbegin):
|
||||||
lp = data.lastPhase()
|
hwsus = True
|
||||||
if lp.startswith('resume_machine'):
|
if lp.startswith('resume_machine'):
|
||||||
data.dmesg[lp]['end'] = t.time
|
# trim out s2idle loops, track time trying to freeze
|
||||||
|
llp = data.lastPhase(2)
|
||||||
|
if llp.startswith('suspend_machine'):
|
||||||
|
if 'trying' not in data.dmesg[llp]:
|
||||||
|
data.dmesg[llp]['trying'] = 0
|
||||||
|
data.dmesg[llp]['trying'] += \
|
||||||
|
t.time - data.dmesg[lp]['start']
|
||||||
|
data.currphase = ''
|
||||||
|
del data.dmesg[lp]
|
||||||
|
continue
|
||||||
phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True)
|
phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True)
|
||||||
data.setPhase(phase, t.time, False)
|
data.setPhase(phase, t.time, False)
|
||||||
if data.tSuspended == 0:
|
if data.tSuspended == 0:
|
||||||
data.tSuspended = t.time
|
data.tSuspended = t.time
|
||||||
else:
|
else:
|
||||||
|
if lp.startswith('resume_machine'):
|
||||||
|
data.dmesg[lp]['end'] = t.time
|
||||||
|
continue
|
||||||
phase = data.setPhase('resume_machine', t.time, True)
|
phase = data.setPhase('resume_machine', t.time, True)
|
||||||
if(sysvals.suspendmode in ['mem', 'disk']):
|
if(sysvals.suspendmode in ['mem', 'disk']):
|
||||||
susp = phase.replace('resume', 'suspend')
|
susp = phase.replace('resume', 'suspend')
|
||||||
@ -3343,6 +3361,19 @@ def parseTraceLog(live=False):
|
|||||||
# global events (outside device calls) are graphed
|
# global events (outside device calls) are graphed
|
||||||
if(name not in testrun.ttemp):
|
if(name not in testrun.ttemp):
|
||||||
testrun.ttemp[name] = []
|
testrun.ttemp[name] = []
|
||||||
|
# special handling for s2idle_enter
|
||||||
|
if name == 'machine_suspend':
|
||||||
|
if hwsus:
|
||||||
|
s2idle_enter = hwsus = False
|
||||||
|
elif s2idle_enter and not isbegin:
|
||||||
|
if(len(testrun.ttemp[name]) > 0):
|
||||||
|
testrun.ttemp[name][-1]['end'] = t.time
|
||||||
|
testrun.ttemp[name][-1]['loop'] += 1
|
||||||
|
elif not s2idle_enter and isbegin:
|
||||||
|
s2idle_enter = True
|
||||||
|
testrun.ttemp[name].append({'begin': t.time,
|
||||||
|
'end': t.time, 'pid': pid, 'loop': 0})
|
||||||
|
continue
|
||||||
if(isbegin):
|
if(isbegin):
|
||||||
# create a new list entry
|
# create a new list entry
|
||||||
testrun.ttemp[name].append(\
|
testrun.ttemp[name].append(\
|
||||||
@ -3374,9 +3405,8 @@ def parseTraceLog(live=False):
|
|||||||
if(not m):
|
if(not m):
|
||||||
continue
|
continue
|
||||||
n = m.group('d')
|
n = m.group('d')
|
||||||
list = data.dmesg[phase]['list']
|
dev = data.findDevice(phase, n)
|
||||||
if(n in list):
|
if dev:
|
||||||
dev = list[n]
|
|
||||||
dev['length'] = t.time - dev['start']
|
dev['length'] = t.time - dev['start']
|
||||||
dev['end'] = t.time
|
dev['end'] = t.time
|
||||||
# kprobe event processing
|
# kprobe event processing
|
||||||
@ -3479,7 +3509,12 @@ def parseTraceLog(live=False):
|
|||||||
# add actual trace funcs
|
# add actual trace funcs
|
||||||
for name in sorted(test.ttemp):
|
for name in sorted(test.ttemp):
|
||||||
for event in test.ttemp[name]:
|
for event in test.ttemp[name]:
|
||||||
data.newActionGlobal(name, event['begin'], event['end'], event['pid'])
|
if event['end'] - event['begin'] <= 0:
|
||||||
|
continue
|
||||||
|
title = name
|
||||||
|
if name == 'machine_suspend' and 'loop' in event:
|
||||||
|
title = 's2idle_enter_%dx' % event['loop']
|
||||||
|
data.newActionGlobal(title, event['begin'], event['end'], event['pid'])
|
||||||
# add the kprobe based virtual tracefuncs as actual devices
|
# add the kprobe based virtual tracefuncs as actual devices
|
||||||
for key in sorted(tp.ktemp):
|
for key in sorted(tp.ktemp):
|
||||||
name, pid = key
|
name, pid = key
|
||||||
@ -3548,8 +3583,9 @@ def parseTraceLog(live=False):
|
|||||||
for p in sorted(phasedef, key=lambda k:phasedef[k]['order']):
|
for p in sorted(phasedef, key=lambda k:phasedef[k]['order']):
|
||||||
if p not in data.dmesg:
|
if p not in data.dmesg:
|
||||||
if not terr:
|
if not terr:
|
||||||
pprint('TEST%s FAILED: %s failed in %s phase' % (tn, sysvals.suspendmode, lp))
|
ph = p if 'machine' in p else lp
|
||||||
terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, lp)
|
terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph)
|
||||||
|
pprint('TEST%s FAILED: %s' % (tn, terr))
|
||||||
error.append(terr)
|
error.append(terr)
|
||||||
if data.tSuspended == 0:
|
if data.tSuspended == 0:
|
||||||
data.tSuspended = data.dmesg[lp]['end']
|
data.tSuspended = data.dmesg[lp]['end']
|
||||||
@ -3611,7 +3647,7 @@ def loadKernelLog():
|
|||||||
idx = line.find('[')
|
idx = line.find('[')
|
||||||
if idx > 1:
|
if idx > 1:
|
||||||
line = line[idx:]
|
line = line[idx:]
|
||||||
if tp.stampInfo(line):
|
if tp.stampInfo(line, sysvals):
|
||||||
continue
|
continue
|
||||||
m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
|
m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
|
||||||
if(not m):
|
if(not m):
|
||||||
@ -3959,18 +3995,20 @@ def addCallgraphs(sv, hf, data):
|
|||||||
if sv.cgphase and p != sv.cgphase:
|
if sv.cgphase and p != sv.cgphase:
|
||||||
continue
|
continue
|
||||||
list = data.dmesg[p]['list']
|
list = data.dmesg[p]['list']
|
||||||
for devname in data.sortedDevices(p):
|
for d in data.sortedDevices(p):
|
||||||
if len(sv.cgfilter) > 0 and devname not in sv.cgfilter:
|
if len(sv.cgfilter) > 0 and d not in sv.cgfilter:
|
||||||
continue
|
continue
|
||||||
dev = list[devname]
|
dev = list[d]
|
||||||
color = 'white'
|
color = 'white'
|
||||||
if 'color' in data.dmesg[p]:
|
if 'color' in data.dmesg[p]:
|
||||||
color = data.dmesg[p]['color']
|
color = data.dmesg[p]['color']
|
||||||
if 'color' in dev:
|
if 'color' in dev:
|
||||||
color = dev['color']
|
color = dev['color']
|
||||||
name = devname
|
name = d if '[' not in d else d.split('[')[0]
|
||||||
if(devname in sv.devprops):
|
if(d in sv.devprops):
|
||||||
name = sv.devprops[devname].altName(devname)
|
name = sv.devprops[d].altName(d)
|
||||||
|
if 'drv' in dev and dev['drv']:
|
||||||
|
name += ' {%s}' % dev['drv']
|
||||||
if sv.suspendmode in suspendmodename:
|
if sv.suspendmode in suspendmodename:
|
||||||
name += ' '+p
|
name += ' '+p
|
||||||
if('ftrace' in dev):
|
if('ftrace' in dev):
|
||||||
@ -4517,12 +4555,9 @@ def createHTML(testruns, testfail):
|
|||||||
# draw the devices for this phase
|
# draw the devices for this phase
|
||||||
phaselist = data.dmesg[b]['list']
|
phaselist = data.dmesg[b]['list']
|
||||||
for d in sorted(data.tdevlist[b]):
|
for d in sorted(data.tdevlist[b]):
|
||||||
name = d
|
dname = d if '[' not in d else d.split('[')[0]
|
||||||
drv = ''
|
name, dev = dname, phaselist[d]
|
||||||
dev = phaselist[d]
|
drv = xtraclass = xtrainfo = xtrastyle = ''
|
||||||
xtraclass = ''
|
|
||||||
xtrainfo = ''
|
|
||||||
xtrastyle = ''
|
|
||||||
if 'htmlclass' in dev:
|
if 'htmlclass' in dev:
|
||||||
xtraclass = dev['htmlclass']
|
xtraclass = dev['htmlclass']
|
||||||
if 'color' in dev:
|
if 'color' in dev:
|
||||||
@ -4553,7 +4588,7 @@ def createHTML(testruns, testfail):
|
|||||||
title += b
|
title += b
|
||||||
devtl.html += devtl.html_device.format(dev['id'], \
|
devtl.html += devtl.html_device.format(dev['id'], \
|
||||||
title, left, top, '%.3f'%rowheight, width, \
|
title, left, top, '%.3f'%rowheight, width, \
|
||||||
d+drv, xtraclass, xtrastyle)
|
dname+drv, xtraclass, xtrastyle)
|
||||||
if('cpuexec' in dev):
|
if('cpuexec' in dev):
|
||||||
for t in sorted(dev['cpuexec']):
|
for t in sorted(dev['cpuexec']):
|
||||||
start, end = t
|
start, end = t
|
||||||
@ -4571,6 +4606,8 @@ def createHTML(testruns, testfail):
|
|||||||
continue
|
continue
|
||||||
# draw any trace events for this device
|
# draw any trace events for this device
|
||||||
for e in dev['src']:
|
for e in dev['src']:
|
||||||
|
if e.length == 0:
|
||||||
|
continue
|
||||||
height = '%.3f' % devtl.rowH
|
height = '%.3f' % devtl.rowH
|
||||||
top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH))
|
top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH))
|
||||||
left = '%f' % (((e.time-m0)*100)/mTotal)
|
left = '%f' % (((e.time-m0)*100)/mTotal)
|
||||||
@ -5876,7 +5913,7 @@ def getArgFloat(name, args, min, max, main=True):
|
|||||||
|
|
||||||
def processData(live=False, quiet=False):
|
def processData(live=False, quiet=False):
|
||||||
if not quiet:
|
if not quiet:
|
||||||
pprint('PROCESSING DATA')
|
pprint('PROCESSING: %s' % sysvals.htmlfile)
|
||||||
sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \
|
sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \
|
||||||
(sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes))
|
(sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes))
|
||||||
error = ''
|
error = ''
|
||||||
@ -5928,7 +5965,7 @@ def processData(live=False, quiet=False):
|
|||||||
sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile)
|
sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile)
|
||||||
createHTML(testruns, error)
|
createHTML(testruns, error)
|
||||||
if not quiet:
|
if not quiet:
|
||||||
pprint('DONE')
|
pprint('DONE: %s' % sysvals.htmlfile)
|
||||||
data = testruns[0]
|
data = testruns[0]
|
||||||
stamp = data.stamp
|
stamp = data.stamp
|
||||||
stamp['suspend'], stamp['resume'] = data.getTimeValues()
|
stamp['suspend'], stamp['resume'] = data.getTimeValues()
|
||||||
@ -5984,25 +6021,27 @@ def runTest(n=0, quiet=False):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
def find_in_html(html, start, end, firstonly=True):
|
def find_in_html(html, start, end, firstonly=True):
|
||||||
n, cnt, out = 0, len(html), []
|
cnt, out, list = len(html), [], []
|
||||||
while n < cnt:
|
if firstonly:
|
||||||
e = cnt if (n + 10000 > cnt or n == 0) else n + 10000
|
m = re.search(start, html)
|
||||||
m = re.search(start, html[n:e])
|
if m:
|
||||||
|
list.append(m)
|
||||||
|
else:
|
||||||
|
list = re.finditer(start, html)
|
||||||
|
for match in list:
|
||||||
|
s = match.end()
|
||||||
|
e = cnt if (len(out) < 1 or s + 10000 > cnt) else s + 10000
|
||||||
|
m = re.search(end, html[s:e])
|
||||||
if not m:
|
if not m:
|
||||||
break
|
break
|
||||||
i = m.end()
|
e = s + m.start()
|
||||||
m = re.search(end, html[n+i:e])
|
str = html[s:e]
|
||||||
if not m:
|
|
||||||
break
|
|
||||||
j = m.start()
|
|
||||||
str = html[n+i:n+i+j]
|
|
||||||
if end == 'ms':
|
if end == 'ms':
|
||||||
num = re.search(r'[-+]?\d*\.\d+|\d+', str)
|
num = re.search(r'[-+]?\d*\.\d+|\d+', str)
|
||||||
str = num.group() if num else 'NaN'
|
str = num.group() if num else 'NaN'
|
||||||
if firstonly:
|
if firstonly:
|
||||||
return str
|
return str
|
||||||
out.append(str)
|
out.append(str)
|
||||||
n += i+j
|
|
||||||
if firstonly:
|
if firstonly:
|
||||||
return ''
|
return ''
|
||||||
return out
|
return out
|
||||||
@ -6034,7 +6073,7 @@ def data_from_html(file, outpath, issues, fulldetail=False):
|
|||||||
else:
|
else:
|
||||||
result = 'pass'
|
result = 'pass'
|
||||||
# extract error info
|
# extract error info
|
||||||
ilist = []
|
tp, ilist = False, []
|
||||||
extra = dict()
|
extra = dict()
|
||||||
log = find_in_html(html, '<div id="dmesglog" style="display:none;">',
|
log = find_in_html(html, '<div id="dmesglog" style="display:none;">',
|
||||||
'</div>').strip()
|
'</div>').strip()
|
||||||
@ -6042,8 +6081,8 @@ def data_from_html(file, outpath, issues, fulldetail=False):
|
|||||||
d = Data(0)
|
d = Data(0)
|
||||||
d.end = 999999999
|
d.end = 999999999
|
||||||
d.dmesgtext = log.split('\n')
|
d.dmesgtext = log.split('\n')
|
||||||
msglist = d.extractErrorInfo()
|
tp = d.extractErrorInfo()
|
||||||
for msg in msglist:
|
for msg in tp.msglist:
|
||||||
sysvals.errorSummary(issues, msg)
|
sysvals.errorSummary(issues, msg)
|
||||||
if stmp[2] == 'freeze':
|
if stmp[2] == 'freeze':
|
||||||
extra = d.turbostatInfo()
|
extra = d.turbostatInfo()
|
||||||
@ -6059,8 +6098,8 @@ def data_from_html(file, outpath, issues, fulldetail=False):
|
|||||||
if wifi:
|
if wifi:
|
||||||
extra['wifi'] = wifi
|
extra['wifi'] = wifi
|
||||||
low = find_in_html(html, 'freeze time: <b>', ' ms</b>')
|
low = find_in_html(html, 'freeze time: <b>', ' ms</b>')
|
||||||
if low and '|' in low:
|
if low and 'waking' in low:
|
||||||
issue = 'FREEZEx%d' % len(low.split('|'))
|
issue = 'FREEZEWAKE'
|
||||||
match = [i for i in issues if i['match'] == issue]
|
match = [i for i in issues if i['match'] == issue]
|
||||||
if len(match) > 0:
|
if len(match) > 0:
|
||||||
match[0]['count'] += 1
|
match[0]['count'] += 1
|
||||||
@ -6126,6 +6165,11 @@ def data_from_html(file, outpath, issues, fulldetail=False):
|
|||||||
data[key] = extra[key]
|
data[key] = extra[key]
|
||||||
if fulldetail:
|
if fulldetail:
|
||||||
data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False)
|
data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False)
|
||||||
|
if tp:
|
||||||
|
for arg in ['-multi ', '-info ']:
|
||||||
|
if arg in tp.cmdline:
|
||||||
|
data['target'] = tp.cmdline[tp.cmdline.find(arg):].split()[1]
|
||||||
|
break
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def genHtml(subdir, force=False):
|
def genHtml(subdir, force=False):
|
||||||
@ -6155,8 +6199,7 @@ def runSummary(subdir, local=True, genhtml=False):
|
|||||||
pprint('Generating a summary of folder:\n %s' % inpath)
|
pprint('Generating a summary of folder:\n %s' % inpath)
|
||||||
if genhtml:
|
if genhtml:
|
||||||
genHtml(subdir)
|
genHtml(subdir)
|
||||||
issues = []
|
target, issues, testruns = '', [], []
|
||||||
testruns = []
|
|
||||||
desc = {'host':[],'mode':[],'kernel':[]}
|
desc = {'host':[],'mode':[],'kernel':[]}
|
||||||
for dirname, dirnames, filenames in os.walk(subdir):
|
for dirname, dirnames, filenames in os.walk(subdir):
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
@ -6165,6 +6208,8 @@ def runSummary(subdir, local=True, genhtml=False):
|
|||||||
data = data_from_html(os.path.join(dirname, filename), outpath, issues)
|
data = data_from_html(os.path.join(dirname, filename), outpath, issues)
|
||||||
if(not data):
|
if(not data):
|
||||||
continue
|
continue
|
||||||
|
if 'target' in data:
|
||||||
|
target = data['target']
|
||||||
testruns.append(data)
|
testruns.append(data)
|
||||||
for key in desc:
|
for key in desc:
|
||||||
if data[key] not in desc[key]:
|
if data[key] not in desc[key]:
|
||||||
@ -6172,6 +6217,8 @@ def runSummary(subdir, local=True, genhtml=False):
|
|||||||
pprint('Summary files:')
|
pprint('Summary files:')
|
||||||
if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1:
|
if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1:
|
||||||
title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0])
|
title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0])
|
||||||
|
if target:
|
||||||
|
title += ' %s' % target
|
||||||
else:
|
else:
|
||||||
title = inpath
|
title = inpath
|
||||||
createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title)
|
createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title)
|
||||||
|
Loading…
Reference in New Issue
Block a user