Commit 221e9b58380abdd6c05e11b4538597e2586ee141

Authored by Rafael J. Wysocki
1 parent b02c999ac3

PM / Domains: Add default power off governor function (v4)

Add a function deciding whether or not a given PM domain should
be powered off on the basis of the PM QoS constraints of devices
belonging to it and their PM QoS timing data.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

Showing 3 changed files with 129 additions and 0 deletions Side-by-side Diff

drivers/base/power/domain.c
... ... @@ -398,7 +398,18 @@
398 398 }
399 399  
400 400 genpd->status = GPD_STATE_POWER_OFF;
  401 + genpd->power_off_time = ktime_get();
401 402  
  403 + /* Update PM QoS information for devices in the domain. */
  404 + list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
  405 + struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
  406 +
  407 + pm_runtime_update_max_time_suspended(pdd->dev,
  408 + td->start_latency_ns +
  409 + td->restore_state_latency_ns +
  410 + genpd->power_on_latency_ns);
  411 + }
  412 +
402 413 list_for_each_entry(link, &genpd->slave_links, slave_node) {
403 414 genpd_sd_counter_dec(link->master);
404 415 genpd_queue_power_off_work(link->master);
... ... @@ -1487,6 +1498,7 @@
1487 1498 genpd->resume_count = 0;
1488 1499 genpd->device_count = 0;
1489 1500 genpd->suspended_count = 0;
  1501 + genpd->max_off_time_ns = -1;
1490 1502 genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
1491 1503 genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
1492 1504 genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
drivers/base/power/domain_governor.c
... ... @@ -10,6 +10,7 @@
10 10 #include <linux/kernel.h>
11 11 #include <linux/pm_domain.h>
12 12 #include <linux/pm_qos.h>
  13 +#include <linux/hrtimer.h>
13 14  
14 15 /**
15 16 * default_stop_ok - Default PM domain governor routine for stopping devices.
16 17  
... ... @@ -28,7 +29,116 @@
28 29 && td->break_even_ns < dev->power.max_time_suspended_ns;
29 30 }
30 31  
  32 +/**
  33 + * default_power_down_ok - Default generic PM domain power off governor routine.
  34 + * @pd: PM domain to check.
  35 + *
  36 + * This routine must be executed under the PM domain's lock.
  37 + */
  38 +static bool default_power_down_ok(struct dev_pm_domain *pd)
  39 +{
  40 + struct generic_pm_domain *genpd = pd_to_genpd(pd);
  41 + struct gpd_link *link;
  42 + struct pm_domain_data *pdd;
  43 + s64 min_dev_off_time_ns;
  44 + s64 off_on_time_ns;
  45 + ktime_t time_now = ktime_get();
  46 +
  47 + off_on_time_ns = genpd->power_off_latency_ns +
  48 + genpd->power_on_latency_ns;
  49 + /*
  50 + * It doesn't make sense to remove power from the domain if saving
  51 + * the state of all devices in it and the power off/power on operations
  52 + * take too much time.
  53 + *
  54 + * All devices in this domain have been stopped already at this point.
  55 + */
  56 + list_for_each_entry(pdd, &genpd->dev_list, list_node) {
  57 + if (pdd->dev->driver)
  58 + off_on_time_ns +=
  59 + to_gpd_data(pdd)->td.save_state_latency_ns;
  60 + }
  61 +
  62 + /*
  63 + * Check if subdomains can be off for enough time.
  64 + *
  65 + * All subdomains have been powered off already at this point.
  66 + */
  67 + list_for_each_entry(link, &genpd->master_links, master_node) {
  68 + struct generic_pm_domain *sd = link->slave;
  69 + s64 sd_max_off_ns = sd->max_off_time_ns;
  70 +
  71 + if (sd_max_off_ns < 0)
  72 + continue;
  73 +
  74 + sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now,
  75 + sd->power_off_time));
  76 + /*
  77 + * Check if the subdomain is allowed to be off long enough for
  78 + * the current domain to turn off and on (that's how much time
  79 + * it will have to wait worst case).
  80 + */
  81 + if (sd_max_off_ns <= off_on_time_ns)
  82 + return false;
  83 + }
  84 +
  85 + /*
  86 + * Check if the devices in the domain can be off enough time.
  87 + */
  88 + min_dev_off_time_ns = -1;
  89 + list_for_each_entry(pdd, &genpd->dev_list, list_node) {
  90 + struct gpd_timing_data *td;
  91 + struct device *dev = pdd->dev;
  92 + s64 dev_off_time_ns;
  93 +
  94 + if (!dev->driver || dev->power.max_time_suspended_ns < 0)
  95 + continue;
  96 +
  97 + td = &to_gpd_data(pdd)->td;
  98 + dev_off_time_ns = dev->power.max_time_suspended_ns -
  99 + (td->start_latency_ns + td->restore_state_latency_ns +
  100 + ktime_to_ns(ktime_sub(time_now,
  101 + dev->power.suspend_time)));
  102 + if (dev_off_time_ns <= off_on_time_ns)
  103 + return false;
  104 +
  105 + if (min_dev_off_time_ns > dev_off_time_ns
  106 + || min_dev_off_time_ns < 0)
  107 + min_dev_off_time_ns = dev_off_time_ns;
  108 + }
  109 +
  110 + if (min_dev_off_time_ns < 0) {
  111 + /*
  112 + * There are no latency constraints, so the domain can spend
  113 + * arbitrary time in the "off" state.
  114 + */
  115 + genpd->max_off_time_ns = -1;
  116 + return true;
  117 + }
  118 +
  119 + /*
  120 + * The difference between the computed minimum delta and the time needed
  121 + * to turn the domain on is the maximum theoretical time this domain can
  122 + * spend in the "off" state.
  123 + */
  124 + min_dev_off_time_ns -= genpd->power_on_latency_ns;
  125 +
  126 + /*
  127 + * If the difference between the computed minimum delta and the time
  128 + * needed to turn the domain off and back on on is smaller than the
  129 + * domain's power break even time, removing power from the domain is not
  130 + * worth it.
  131 + */
  132 + if (genpd->break_even_ns >
  133 + min_dev_off_time_ns - genpd->power_off_latency_ns)
  134 + return false;
  135 +
  136 + genpd->max_off_time_ns = min_dev_off_time_ns;
  137 + return true;
  138 +}
  139 +
31 140 struct dev_power_governor simple_qos_governor = {
32 141 .stop_ok = default_stop_ok,
  142 + .power_down_ok = default_power_down_ok,
33 143 };
include/linux/pm_domain.h
... ... @@ -61,8 +61,13 @@
61 61 bool suspend_power_off; /* Power status before system suspend */
62 62 bool dev_irq_safe; /* Device callbacks are IRQ-safe */
63 63 int (*power_off)(struct generic_pm_domain *domain);
  64 + s64 power_off_latency_ns;
64 65 int (*power_on)(struct generic_pm_domain *domain);
  66 + s64 power_on_latency_ns;
65 67 struct gpd_dev_ops dev_ops;
  68 + s64 break_even_ns; /* Power break even for the entire domain. */
  69 + s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
  70 + ktime_t power_off_time;
66 71 };
67 72  
68 73 static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
... ... @@ -80,6 +85,8 @@
80 85 struct gpd_timing_data {
81 86 s64 stop_latency_ns;
82 87 s64 start_latency_ns;
  88 + s64 save_state_latency_ns;
  89 + s64 restore_state_latency_ns;
83 90 s64 break_even_ns;
84 91 };
85 92