aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-04-29 16:54:17 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-01 15:28:03 -0400
commita5bef810ad9816a3a8e500d8832be77d52903a12 (patch)
treedd108feaf2fa45f9520b63ea94ecec2c42259194
parent69964ea4c7b68c9399f7977aa5b9aa6539a6a98a (diff)
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>
-rw-r--r--drivers/base/power/domain.c1
-rw-r--r--drivers/base/power/domain_governor.c53
-rw-r--r--include/linux/pm_domain.h2
3 files changed, 51 insertions, 5 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 73ce9fbe9839..3c6e94fe058a 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -506,6 +506,7 @@ static int pm_genpd_runtime_suspend(struct device *dev)
506 if (dev_gpd_data(dev)->always_on) 506 if (dev_gpd_data(dev)->always_on)
507 return -EBUSY; 507 return -EBUSY;
508 508
509 dev_gpd_data(dev)->td.effective_constraint_ns = -1;
509 stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; 510 stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
510 if (stop_ok && !stop_ok(dev)) 511 if (stop_ok && !stop_ok(dev))
511 return -EBUSY; 512 return -EBUSY;
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 66a265bf5867..a67f157a7a74 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -14,6 +14,31 @@
14 14
15#ifdef CONFIG_PM_RUNTIME 15#ifdef CONFIG_PM_RUNTIME
16 16
17static int dev_update_qos_constraint(struct device *dev, void *data)
18{
19 s64 *constraint_ns_p = data;
20 s32 constraint_ns = -1;
21
22 if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
23 constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
24
25 if (constraint_ns < 0) {
26 constraint_ns = dev_pm_qos_read_value(dev);
27 constraint_ns *= NSEC_PER_USEC;
28 }
29 if (constraint_ns == 0)
30 return 0;
31
32 /*
33 * constraint_ns cannot be negative here, because the device has been
34 * suspended.
35 */
36 if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
37 *constraint_ns_p = constraint_ns;
38
39 return 0;
40}
41
17/** 42/**
18 * default_stop_ok - Default PM domain governor routine for stopping devices. 43 * default_stop_ok - Default PM domain governor routine for stopping devices.
19 * @dev: Device to check. 44 * @dev: Device to check.
@@ -21,14 +46,34 @@
21bool default_stop_ok(struct device *dev) 46bool default_stop_ok(struct device *dev)
22{ 47{
23 struct gpd_timing_data *td = &dev_gpd_data(dev)->td; 48 struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
49 s64 constraint_ns;
24 50
25 dev_dbg(dev, "%s()\n", __func__); 51 dev_dbg(dev, "%s()\n", __func__);
26 52
27 if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0) 53 constraint_ns = dev_pm_qos_read_value(dev);
28 return true; 54 if (constraint_ns < 0)
55 return false;
56
57 constraint_ns *= NSEC_PER_USEC;
58 /*
59 * We can walk the children without any additional locking, because
60 * they all have been suspended at this point.
61 */
62 if (!dev->power.ignore_children)
63 device_for_each_child(dev, &constraint_ns,
64 dev_update_qos_constraint);
29 65
30 return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns 66 if (constraint_ns > 0) {
31 && td->break_even_ns < dev->power.max_time_suspended_ns; 67 constraint_ns -= td->start_latency_ns;
68 if (constraint_ns == 0)
69 return false;
70 }
71 td->effective_constraint_ns = constraint_ns;
72 /*
73 * The children have been suspended already, so we don't need to take
74 * their stop latencies into account here.
75 */
76 return constraint_ns > td->stop_latency_ns || constraint_ns == 0;
32} 77}
33 78
34/** 79/**
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 91f8286106ea..9c25219458c2 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -93,7 +93,7 @@ struct gpd_timing_data {
93 s64 start_latency_ns; 93 s64 start_latency_ns;
94 s64 save_state_latency_ns; 94 s64 save_state_latency_ns;
95 s64 restore_state_latency_ns; 95 s64 restore_state_latency_ns;
96 s64 break_even_ns; 96 s64 effective_constraint_ns;
97}; 97};
98 98
99struct generic_pm_domain_data { 99struct generic_pm_domain_data {