diff options
Diffstat (limited to 'drivers/pmdomain/governor.c')
| -rw-r--r-- | drivers/pmdomain/governor.c | 49 |
1 files changed, 43 insertions, 6 deletions
diff --git a/drivers/pmdomain/governor.c b/drivers/pmdomain/governor.c index 39359811a930..96737abbb496 100644 --- a/drivers/pmdomain/governor.c +++ b/drivers/pmdomain/governor.c @@ -351,7 +351,7 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd) ktime_t domain_wakeup, next_hrtimer; ktime_t now = ktime_get(); struct device *cpu_dev; - s64 cpu_constraint, global_constraint; + s64 cpu_constraint, global_constraint, wakeup_constraint; s64 idle_duration_ns; int cpu, i; @@ -362,7 +362,11 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd) if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN)) return true; + wakeup_constraint = cpu_wakeup_latency_qos_limit(); global_constraint = cpu_latency_qos_limit(); + if (global_constraint > wakeup_constraint) + global_constraint = wakeup_constraint; + /* * Find the next wakeup for any of the online CPUs within the PM domain * and its subdomains. Note, we only need the genpd->cpus, as it already @@ -404,13 +408,45 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd) if ((idle_duration_ns >= (genpd->states[i].residency_ns + genpd->states[i].power_off_latency_ns)) && (global_constraint >= (genpd->states[i].power_on_latency_ns + - genpd->states[i].power_off_latency_ns))) { - genpd->state_idx = i; - genpd->gd->last_enter = now; - genpd->gd->reflect_residency = true; + genpd->states[i].power_off_latency_ns))) + break; + + } while (--i >= 0); + + if (i < 0) + return false; + + if (cpus_peek_for_pending_ipi(genpd->cpus)) + return false; + + genpd->state_idx = i; + genpd->gd->last_enter = now; + genpd->gd->reflect_residency = true; + return true; +} + +static bool cpu_system_power_down_ok(struct dev_pm_domain *pd) +{ + s64 constraint_ns = cpu_wakeup_latency_qos_limit() * NSEC_PER_USEC; + struct generic_pm_domain *genpd = pd_to_genpd(pd); + int state_idx = genpd->state_count - 1; + + if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN)) { + genpd->state_idx = state_idx; + return true; + } + + /* Find the deepest state for the latency constraint. */ + while (state_idx >= 0) { + s64 latency_ns = genpd->states[state_idx].power_off_latency_ns + + genpd->states[state_idx].power_on_latency_ns; + + if (latency_ns <= constraint_ns) { + genpd->state_idx = state_idx; return true; } - } while (--i >= 0); + state_idx--; + } return false; } @@ -418,6 +454,7 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd) struct dev_power_governor pm_domain_cpu_gov = { .suspend_ok = default_suspend_ok, .power_down_ok = cpu_power_down_ok, + .system_power_down_ok = cpu_system_power_down_ok, }; #endif |
