mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 04:02:26 +00:00
PM / Domains: Rework default device stop governor function, v2
The existing default device stop governor function for PM domains, default_stop_ok(), is supposed to check whether or not the device's PM QoS latency constraint will be violated if the device is stopped by pm_genpd_runtime_suspend(). However, the computations carried out by it don't reflect the definition of the PM QoS latency constrait in Documentation/ABI/testing/sysfs-devices-power. Make default_stop_ok() follow the definition of the PM QoS latency constrait. In particular, make it take the device's start and stop latencies correctly. Add a new field, effective_constraint_ns, to struct gpd_timing_data and use it to store the difference between the device's PM QoS constraint and its resume latency for use by the device's parent (the effective_constraint_ns values for the children are used for computing the parent's one along with its PM QoS constraint). Remove the break_even_ns field from struct gpd_timing_data, because it's not used any more. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
This commit is contained in:
parent
69964ea4c7
commit
a5bef810ad
@ -506,6 +506,7 @@ static int pm_genpd_runtime_suspend(struct device *dev)
|
|||||||
if (dev_gpd_data(dev)->always_on)
|
if (dev_gpd_data(dev)->always_on)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
dev_gpd_data(dev)->td.effective_constraint_ns = -1;
|
||||||
stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
|
stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
|
||||||
if (stop_ok && !stop_ok(dev))
|
if (stop_ok && !stop_ok(dev))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -14,6 +14,31 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_PM_RUNTIME
|
#ifdef CONFIG_PM_RUNTIME
|
||||||
|
|
||||||
|
static int dev_update_qos_constraint(struct device *dev, void *data)
|
||||||
|
{
|
||||||
|
s64 *constraint_ns_p = data;
|
||||||
|
s32 constraint_ns = -1;
|
||||||
|
|
||||||
|
if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
|
||||||
|
constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
|
||||||
|
|
||||||
|
if (constraint_ns < 0) {
|
||||||
|
constraint_ns = dev_pm_qos_read_value(dev);
|
||||||
|
constraint_ns *= NSEC_PER_USEC;
|
||||||
|
}
|
||||||
|
if (constraint_ns == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* constraint_ns cannot be negative here, because the device has been
|
||||||
|
* suspended.
|
||||||
|
*/
|
||||||
|
if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
|
||||||
|
*constraint_ns_p = constraint_ns;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* default_stop_ok - Default PM domain governor routine for stopping devices.
|
* default_stop_ok - Default PM domain governor routine for stopping devices.
|
||||||
* @dev: Device to check.
|
* @dev: Device to check.
|
||||||
@ -21,14 +46,34 @@
|
|||||||
bool default_stop_ok(struct device *dev)
|
bool default_stop_ok(struct device *dev)
|
||||||
{
|
{
|
||||||
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
|
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
|
||||||
|
s64 constraint_ns;
|
||||||
|
|
||||||
dev_dbg(dev, "%s()\n", __func__);
|
dev_dbg(dev, "%s()\n", __func__);
|
||||||
|
|
||||||
if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0)
|
constraint_ns = dev_pm_qos_read_value(dev);
|
||||||
return true;
|
if (constraint_ns < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns
|
constraint_ns *= NSEC_PER_USEC;
|
||||||
&& td->break_even_ns < dev->power.max_time_suspended_ns;
|
/*
|
||||||
|
* We can walk the children without any additional locking, because
|
||||||
|
* they all have been suspended at this point.
|
||||||
|
*/
|
||||||
|
if (!dev->power.ignore_children)
|
||||||
|
device_for_each_child(dev, &constraint_ns,
|
||||||
|
dev_update_qos_constraint);
|
||||||
|
|
||||||
|
if (constraint_ns > 0) {
|
||||||
|
constraint_ns -= td->start_latency_ns;
|
||||||
|
if (constraint_ns == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
td->effective_constraint_ns = constraint_ns;
|
||||||
|
/*
|
||||||
|
* The children have been suspended already, so we don't need to take
|
||||||
|
* their stop latencies into account here.
|
||||||
|
*/
|
||||||
|
return constraint_ns > td->stop_latency_ns || constraint_ns == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,7 +93,7 @@ struct gpd_timing_data {
|
|||||||
s64 start_latency_ns;
|
s64 start_latency_ns;
|
||||||
s64 save_state_latency_ns;
|
s64 save_state_latency_ns;
|
||||||
s64 restore_state_latency_ns;
|
s64 restore_state_latency_ns;
|
||||||
s64 break_even_ns;
|
s64 effective_constraint_ns;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct generic_pm_domain_data {
|
struct generic_pm_domain_data {
|
||||||
|
Loading…
Reference in New Issue
Block a user