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;
- return true;
- }
+ genpd->states[i].power_off_latency_ns)))
+ break;
+
} while (--i >= 0);
- return false;
+ 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;
+ }
+ state_idx--;
+ }
+
+ return false;
+}
+
struct dev_power_governor pm_domain_cpu_gov = {
.suspend_ok = default_suspend_ok,
.power_down_ok = cpu_power_down_ok,