From patchwork Tue Aug 30 22:22:43 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Wysocki X-Patchwork-Id: 1114552 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p7UMM5sv014392 for ; Tue, 30 Aug 2011 22:22:06 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752946Ab1H3WVV (ORCPT ); Tue, 30 Aug 2011 18:21:21 -0400 Received: from ogre.sisk.pl ([217.79.144.158]:49770 "EHLO ogre.sisk.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752276Ab1H3WVU (ORCPT ); Tue, 30 Aug 2011 18:21:20 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by ogre.sisk.pl (Postfix) with ESMTP id B23161BACF0; Tue, 30 Aug 2011 23:38:11 +0200 (CEST) Received: from ogre.sisk.pl ([127.0.0.1]) by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 12791-03; Tue, 30 Aug 2011 23:38:01 +0200 (CEST) Received: from ferrari.rjw.lan (220-bem-13.acn.waw.pl [82.210.184.220]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ogre.sisk.pl (Postfix) with ESMTP id 12CF41BAC62; Tue, 30 Aug 2011 23:37:44 +0200 (CEST) From: "Rafael J. Wysocki" To: Linux PM mailing list Subject: [RFC][PATCH 5/5] PM / Domains: Add default power off governor function Date: Wed, 31 Aug 2011 00:22:43 +0200 User-Agent: KMail/1.13.6 (Linux/3.1.0-rc4+; KDE/4.6.0; x86_64; ; ) Cc: LKML , "Linux-sh list" , Magnus Damm , Kevin Hilman , jean.pihet@newoldbits.com References: <201108310017.03103.rjw@sisk.pl> In-Reply-To: <201108310017.03103.rjw@sisk.pl> MIME-Version: 1.0 Message-Id: <201108310022.43850.rjw@sisk.pl> X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Tue, 30 Aug 2011 22:22:06 +0000 (UTC) From: Rafael J. Wysocki Add a function deciding whether or not a given PM domain should be powered off on the basis of that domain's devices' PM QoS constraints. --- drivers/base/power/domain_governor.c | 96 +++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 7 ++ 2 files changed, 103 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe linux-sh" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Index: linux/include/linux/pm_domain.h =================================================================== --- linux.orig/include/linux/pm_domain.h +++ linux/include/linux/pm_domain.h @@ -49,6 +49,10 @@ struct generic_pm_domain { int (*start_device)(struct device *dev); int (*stop_device)(struct device *dev); bool (*active_wakeup)(struct device *dev); + ktime_t power_off_latency; + ktime_t power_on_latency; + s64 break_even_ns; + s64 min_delta_ns; }; static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) @@ -64,6 +68,9 @@ struct gpd_link { }; struct gpd_gov_dev_data { + ktime_t start_latency; + ktime_t suspend_latency; + ktime_t resume_latency; s64 break_even_ns; }; Index: linux/drivers/base/power/domain_governor.c =================================================================== --- linux.orig/drivers/base/power/domain_governor.c +++ linux/drivers/base/power/domain_governor.c @@ -35,6 +35,102 @@ static bool default_stop_ok(struct devic return constraint_ns > gov_data->break_even_ns; } +/* This routine must be executed under the PM domain's lock. */ +static bool default_power_down_ok(struct dev_pm_domain *pd) +{ + struct generic_pm_domain *genpd = pd_to_genpd(pd); + struct gpd_link *link; + struct pm_domain_data *pdd; + ktime_t off_time, on_time; + s64 delta_ns, min_delta_ns; + + on_time = genpd->power_on_latency; + /* Check if slave domains can be off for enough time. */ + delta_ns = ktime_to_ns(ktime_add(genpd->power_off_latency, on_time)); + min_delta_ns = 0; + /* All slave domains have been powered off at this point. */ + list_for_each_entry(link, &genpd->master_links, master_node) { + if (delta_ns > link->slave->min_delta_ns) + return false; + + delta_ns = link->slave->min_delta_ns - delta_ns; + if (delta_ns < min_delta_ns) + min_delta_ns = delta_ns; + } + + genpd->min_delta_ns = min_delta_ns; + + /* Compute the total time needed to power off the domain. */ + off_time = ktime_set(0, 0); + /* All devices have been stopped at this point. */ + list_for_each_entry(pdd, &genpd->dev_list, list_node) { + struct gpd_gov_dev_data *gov_data; + + if (!pdd->dev->driver) + continue; + + gov_data = to_gpd_data(pdd)->gov_data; + if (!gov_data) + continue; + + off_time = ktime_add(off_time, gov_data->suspend_latency); + } + off_time = ktime_add(off_time, genpd->power_off_latency); + + /* + * For each device in the domain compute the difference between the + * QoS value and the total time required to bring the device back + * assuming that the domain will be powered off and compute the minimum + * of those. + */ + min_delta_ns = 0; + on_time = ktime_add(on_time, off_time); + list_for_each_entry(pdd, &genpd->dev_list, list_node) { + struct gpd_gov_dev_data *gov_data; + struct device *dev = pdd->dev; + ktime_t dev_up_time; + s32 constraint; + s64 constraint_ns; + + if (!dev->driver) + continue; + + gov_data = to_gpd_data(pdd)->gov_data; + if (gov_data) { + dev_up_time = ktime_add(on_time, + gov_data->resume_latency); + dev_up_time = ktime_add(dev_up_time, + gov_data->start_latency); + } else { + dev_up_time = on_time; + } + + constraint = dev_pm_qos_read_value(dev); + if (constraint < 0) + return false; + else if (constraint == 0) /* 0 means "don't care" */ + continue; + + constraint_ns = constraint; + constraint_ns *= NSEC_PER_USEC; + delta_ns = constraint_ns - ktime_to_ns(dev_up_time); + if (min_delta_ns > delta_ns) + min_delta_ns = delta_ns; + } + + /* Compare the computed delta with the break even value. */ + if (min_delta_ns < genpd->break_even_ns) + return false; + + /* Store the computed value for the masters to use. */ + if (genpd->min_delta_ns > min_delta_ns) + genpd->min_delta_ns = min_delta_ns; + + /* The domain can be powered off. */ + return true; +} + struct dev_power_governor default_qos_governor = { .stop_ok = default_stop_ok, + .power_down_ok = default_power_down_ok, };