From patchwork Wed Mar 27 14:35:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 10873573 X-Patchwork-Delegate: rjw@sisk.pl Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6848C1390 for ; Wed, 27 Mar 2019 14:36:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 573B728698 for ; Wed, 27 Mar 2019 14:36:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4B34228A01; Wed, 27 Mar 2019 14:36:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E221928A17 for ; Wed, 27 Mar 2019 14:36:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728588AbfC0OgA (ORCPT ); Wed, 27 Mar 2019 10:36:00 -0400 Received: from mail-lf1-f68.google.com ([209.85.167.68]:40973 "EHLO mail-lf1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728388AbfC0Of6 (ORCPT ); Wed, 27 Mar 2019 10:35:58 -0400 Received: by mail-lf1-f68.google.com with SMTP id 10so11536446lfr.8 for ; Wed, 27 Mar 2019 07:35:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=xqDhXSTUJNklRs7Nsz2EsWlg0IJVd5TtQANghzoIj6Y=; b=vUdTcIfazo4TkG+buldam+PhyFFNuDthLSslrkpqwoNrYsu9WlNlKvCd+BtFpo5FYh 89eb2KqV9okg5JSqhPhLjyra4l3GTxsGzD17RUxkhr+oB4xNyS+EKB9yX1/Vib1G4qjV kelNtpBQgdCNT31xGRERRrVn/akwMUFsyT193BRZqUMiOFFEBy4T1lHJLhgAB10PDnkf 8q0oG8j60vwlTk0DPt+SCObhXi0ferjtdFQkmBy6EIcmEG0VgMXI+JS9ls6pnKl3PgnR 0pOR0NYNy9SkPTqPIUaMH3BCAe9q6a8sH3awjerhjj642XPPRHMLwUhHddsNk8uq8KKn jkww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xqDhXSTUJNklRs7Nsz2EsWlg0IJVd5TtQANghzoIj6Y=; b=IRvzIsUGllcJVxqCHL7vRKVuDjKU5wEmoYPHrelDPV51UlD0LiJjZIUcYCaiX4kEYY YoJjPSMGVxD5+ZDKUFwQNOGqeRgF0zL6rJ24cgHRPORNwQu06kVQH6WJXhab+pmQGYa8 GeX2cfEHcE/ReMSRcfodbzFHi1MpHkdPc6NR/dTq2i0M6Q2419xZDf5CdvPI5CAo4ojw 2CCZwegsgqVXc9cc2ZwY04OtjGafbI5eNKOEyYXMHqsLoVL78A6K9fJQGE4+KM+x6YYy 41oOV9xtft+iXKpVYHdiSgDKK5I4OBT6MFutL4BP1K7GNfkp7OIz+2twarLxLLlRO3FZ XY4Q== X-Gm-Message-State: APjAAAWN/j4sOLfogVOzCJEZRTstLHVcU/S59aVQVBP37XHTRwqkybfb r48LCdXh+Bq8rhzHPZh3KwLbMg== X-Google-Smtp-Source: APXvYqzEgmGdFWFkPc93PX7NAm6POm61bIL9xLa3T0OreH/UQDLKrqrYmy0xCbUzxhqvX5C9ZJv03g== X-Received: by 2002:a19:d144:: with SMTP id i65mr17047487lfg.52.1553697356770; Wed, 27 Mar 2019 07:35:56 -0700 (PDT) Received: from localhost.localdomain (h-158-174-22-210.NA.cust.bahnhof.se. [158.174.22.210]) by smtp.gmail.com with ESMTPSA id q2sm4548789lfj.58.2019.03.27.07.35.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 27 Mar 2019 07:35:55 -0700 (PDT) From: Ulf Hansson To: "Rafael J . Wysocki" , linux-pm@vger.kernel.org Cc: Frederic Weisbecker , Thomas Gleixner , Sudeep Holla , Lorenzo Pieralisi , Mark Rutland , Daniel Lezcano , "Raju P . L . S . S . S . N" , Stephen Boyd , Tony Lindgren , Kevin Hilman , Lina Iyer , Ulf Hansson , Viresh Kumar , Vincent Guittot , Geert Uytterhoeven , linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v13 1/4] PM / Domains: Add a generic data pointer to the genpd_power_state struct Date: Wed, 27 Mar 2019 15:35:45 +0100 Message-Id: <20190327143548.25305-2-ulf.hansson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190327143548.25305-1-ulf.hansson@linaro.org> References: <20190327143548.25305-1-ulf.hansson@linaro.org> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Let's add a data pointer to the genpd_power_state struct, to allow a genpd backend driver to store per state specific data. To introduce the pointer, we need to change the way genpd deals with freeing of the corresponding allocated data. More precisely, let's clarify the responsibility of whom that shall free the data, by adding a ->free_states() callback to the struct generic_pm_domain. The one allocating the data shall assign the callback, to allow genpd to invoke it from genpd_remove(). Cc: Lina Iyer Co-developed-by: Lina Iyer Acked-by: Daniel Lezcano Signed-off-by: Ulf Hansson --- Changes in v13: - None (re-based). --- drivers/base/power/domain.c | 12 ++++++++++-- include/linux/pm_domain.h | 4 +++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 96a6dc9d305c..ff6f992f7a1d 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1686,6 +1686,12 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, } EXPORT_SYMBOL_GPL(pm_genpd_remove_subdomain); +static void genpd_free_default_power_state(struct genpd_power_state *states, + unsigned int state_count) +{ + kfree(states); +} + static int genpd_set_default_power_state(struct generic_pm_domain *genpd) { struct genpd_power_state *state; @@ -1696,7 +1702,7 @@ static int genpd_set_default_power_state(struct generic_pm_domain *genpd) genpd->states = state; genpd->state_count = 1; - genpd->free = state; + genpd->free_states = genpd_free_default_power_state; return 0; } @@ -1812,7 +1818,9 @@ static int genpd_remove(struct generic_pm_domain *genpd) list_del(&genpd->gpd_list_node); genpd_unlock(genpd); cancel_work_sync(&genpd->power_off_work); - kfree(genpd->free); + if (genpd->free_states) + genpd->free_states(genpd->states, genpd->state_count); + pr_debug("%s: removed %s\n", __func__, genpd->name); return 0; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 1ed5874bcee0..8e1399231753 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -69,6 +69,7 @@ struct genpd_power_state { s64 residency_ns; struct fwnode_handle *fwnode; ktime_t idle_time; + void *data; }; struct genpd_lock_ops; @@ -110,9 +111,10 @@ struct generic_pm_domain { struct device *dev); unsigned int flags; /* Bit field of configs for genpd */ struct genpd_power_state *states; + void (*free_states)(struct genpd_power_state *states, + unsigned int state_count); unsigned int state_count; /* number of states */ unsigned int state_idx; /* state that genpd will go to when off */ - void *free; /* Free the state that was allocated for default */ ktime_t on_time; ktime_t accounting_time; const struct genpd_lock_ops *lock_ops; From patchwork Wed Mar 27 14:35:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 10873589 X-Patchwork-Delegate: rjw@sisk.pl Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D1BF41874 for ; Wed, 27 Mar 2019 14:36:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C0E7328698 for ; Wed, 27 Mar 2019 14:36:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B257428A06; Wed, 27 Mar 2019 14:36:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1EB1328A01 for ; Wed, 27 Mar 2019 14:36:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728459AbfC0OgW (ORCPT ); Wed, 27 Mar 2019 10:36:22 -0400 Received: from mail-lj1-f196.google.com ([209.85.208.196]:37895 "EHLO mail-lj1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728535AbfC0OgB (ORCPT ); Wed, 27 Mar 2019 10:36:01 -0400 Received: by mail-lj1-f196.google.com with SMTP id p14so13626786ljg.5 for ; Wed, 27 Mar 2019 07:35:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Do62RarFZKiaJHchChMBUqt67JhmdRrqCmB3BM4qNsk=; b=KhP79mrRfRrsAir3ZbeLkpEDaUFnZcXgy4dlrUVtV8lML0eWBceZEwB0ezuPNHY+1c Iq1UJXV7GcgXCRg/xcAcpI4MhRAeR3Ll0LQKwPPgj60Xt3muNyAxwTK+WKwMYlApbkgr n1Uw3OLTWqi7HbQxkCZv5Fn+3qOjlxbAkU+B8B4RFb9qShGuTC9ad27zlG+1UQX8V94E jSqOGJW7wKzMSL5V5W0vVquYRSVmMwnr26ysFcHMGWO7oFAh99YyGCYSFX7tHqcUMzFf +dUJ0EdnCraD5KLu2v/H3sruhCmV+Vdk60NEBJLauuw+MGHLv/90O098+wvCCkGT1cur jrJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Do62RarFZKiaJHchChMBUqt67JhmdRrqCmB3BM4qNsk=; b=KTamRUujvgSBYgqzXGW0AkRE34+8R18qGcVNL9mzzQ9HzfwnysRyYRqDVukCugjWYU S23Q5dKxXZN4RYat1OZ/zuxo81udsOqA2GyDsQebI0ESMoOGZVzwPmzbYQ3R3qv01Fj0 aWanvqoblNs7SnqUmtYQdweMaEoQQfrBP9RMr57e8s4VLmEspRAEKuRLj4kTy7Sv1d3D bsnx4AaYbTh06D98NKZyEtlbO84a5SKTrS6eOT7Zbncw6er1iUjKaIaP10g2mge88sHW GXJxa15TO8JOUpaeeutPI9FC4w6Rvc87djx+b9SfU6aVWW1142aJFP/P7IHspjooDNzj GyoA== X-Gm-Message-State: APjAAAWyYrdyZLEKjn4zOpPv3+0cjPuVgR9Gz16yt5UodeislVGuch8W DOaEHAEot7qFtBImQBxx7UlYLw== X-Google-Smtp-Source: APXvYqxvJpHzjkikSC9P794Ufie27oyHGtWUvApWjshRK2vNSuvPv1H/ixxVqHnz+Ufj42EuSVQ5aQ== X-Received: by 2002:a2e:5d94:: with SMTP id v20mr18347734lje.138.1553697358467; Wed, 27 Mar 2019 07:35:58 -0700 (PDT) Received: from localhost.localdomain (h-158-174-22-210.NA.cust.bahnhof.se. [158.174.22.210]) by smtp.gmail.com with ESMTPSA id q2sm4548789lfj.58.2019.03.27.07.35.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 27 Mar 2019 07:35:57 -0700 (PDT) From: Ulf Hansson To: "Rafael J . Wysocki" , linux-pm@vger.kernel.org Cc: Frederic Weisbecker , Thomas Gleixner , Sudeep Holla , Lorenzo Pieralisi , Mark Rutland , Daniel Lezcano , "Raju P . L . S . S . S . N" , Stephen Boyd , Tony Lindgren , Kevin Hilman , Lina Iyer , Ulf Hansson , Viresh Kumar , Vincent Guittot , Geert Uytterhoeven , linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/4] PM / Domains: Add support for CPU devices to genpd Date: Wed, 27 Mar 2019 15:35:46 +0100 Message-Id: <20190327143548.25305-3-ulf.hansson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190327143548.25305-1-ulf.hansson@linaro.org> References: <20190327143548.25305-1-ulf.hansson@linaro.org> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP To enable a device belonging to a CPU to be attached to a PM domain managed by genpd, let's do a few changes to it, as to make it convenient to manage the specifics around CPUs. To be able to quickly find out what CPUs that are attached to a genpd, which typically becomes useful from a genpd governor as following changes is about to show, let's add a cpumask to the struct generic_pm_domain. At the point when a CPU device gets attached to a genpd, let's update the genpd's cpumask. Moreover, let's also propagate changes to the cpumask upwards in the topology to the master PM domains. In this way, the cpumask for a genpd hierarchically reflects all CPUs attached to the topology below it. Finally, let's make this an opt-in feature, to avoid having to manage CPUs and the cpumask for a genpd that doesn't need it. For that reason, let's add a new genpd configuration bit, GENPD_FLAG_CPU_DOMAIN. Cc: Lina Iyer Co-developed-by: Lina Iyer Acked-by: Rafael J. Wysocki Acked-by: Daniel Lezcano Signed-off-by: Ulf Hansson --- Changes in v13: - None (re-based). --- drivers/base/power/domain.c | 65 ++++++++++++++++++++++++++++++++++++- include/linux/pm_domain.h | 13 ++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index ff6f992f7a1d..ecac03dcc9b2 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "power.h" @@ -128,6 +129,7 @@ static const struct genpd_lock_ops genpd_spin_ops = { #define genpd_is_irq_safe(genpd) (genpd->flags & GENPD_FLAG_IRQ_SAFE) #define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON) #define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP) +#define genpd_is_cpu_domain(genpd) (genpd->flags & GENPD_FLAG_CPU_DOMAIN) static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, const struct generic_pm_domain *genpd) @@ -1454,6 +1456,56 @@ static void genpd_free_dev_data(struct device *dev, dev_pm_put_subsys_data(dev); } +static void __genpd_update_cpumask(struct generic_pm_domain *genpd, + int cpu, bool set, unsigned int depth) +{ + struct gpd_link *link; + + if (!genpd_is_cpu_domain(genpd)) + return; + + list_for_each_entry(link, &genpd->slave_links, slave_node) { + struct generic_pm_domain *master = link->master; + + genpd_lock_nested(master, depth + 1); + __genpd_update_cpumask(master, cpu, set, depth + 1); + genpd_unlock(master); + } + + if (set) + cpumask_set_cpu(cpu, genpd->cpus); + else + cpumask_clear_cpu(cpu, genpd->cpus); +} + +static void genpd_update_cpumask(struct generic_pm_domain *genpd, + struct device *dev, bool set) +{ + int cpu; + + if (!genpd_is_cpu_domain(genpd)) + return; + + for_each_possible_cpu(cpu) { + if (get_cpu_device(cpu) == dev) { + __genpd_update_cpumask(genpd, cpu, set, 0); + return; + } + } +} + +static void genpd_set_cpumask(struct generic_pm_domain *genpd, + struct device *dev) +{ + genpd_update_cpumask(genpd, dev, true); +} + +static void genpd_clear_cpumask(struct generic_pm_domain *genpd, + struct device *dev) +{ + genpd_update_cpumask(genpd, dev, false); +} + static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, struct gpd_timing_data *td) { @@ -1475,6 +1527,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, genpd_lock(genpd); + genpd_set_cpumask(genpd, dev); dev_pm_domain_set(dev, &genpd->domain); genpd->device_count++; @@ -1532,6 +1585,7 @@ static int genpd_remove_device(struct generic_pm_domain *genpd, genpd->device_count--; genpd->max_off_time_changed = true; + genpd_clear_cpumask(genpd, dev); dev_pm_domain_set(dev, NULL); list_del_init(&pdd->list_node); @@ -1768,11 +1822,18 @@ int pm_genpd_init(struct generic_pm_domain *genpd, if (genpd_is_always_on(genpd) && !genpd_status_on(genpd)) return -EINVAL; + if (genpd_is_cpu_domain(genpd) && + !zalloc_cpumask_var(&genpd->cpus, GFP_KERNEL)) + return -ENOMEM; + /* Use only one "off" state if there were no states declared */ if (genpd->state_count == 0) { ret = genpd_set_default_power_state(genpd); - if (ret) + if (ret) { + if (genpd_is_cpu_domain(genpd)) + free_cpumask_var(genpd->cpus); return ret; + } } else if (!gov && genpd->state_count > 1) { pr_warn("%s: no governor for states\n", genpd->name); } @@ -1818,6 +1879,8 @@ static int genpd_remove(struct generic_pm_domain *genpd) list_del(&genpd->gpd_list_node); genpd_unlock(genpd); cancel_work_sync(&genpd->power_off_work); + if (genpd_is_cpu_domain(genpd)) + free_cpumask_var(genpd->cpus); if (genpd->free_states) genpd->free_states(genpd->states, genpd->state_count); diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 8e1399231753..a6e251fe9deb 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -16,6 +16,7 @@ #include #include #include +#include /* * Flags to control the behaviour of a genpd. @@ -42,11 +43,22 @@ * GENPD_FLAG_ACTIVE_WAKEUP: Instructs genpd to keep the PM domain powered * on, in case any of its attached devices is used * in the wakeup path to serve system wakeups. + * + * GENPD_FLAG_CPU_DOMAIN: Instructs genpd that it should expect to get + * devices attached, which may belong to CPUs or + * possibly have subdomains with CPUs attached. + * This flag enables the genpd backend driver to + * deploy idle power management support for CPUs + * and groups of CPUs. Note that, the backend + * driver must then comply with the so called, + * last-man-standing algorithm, for the CPUs in the + * PM domain. */ #define GENPD_FLAG_PM_CLK (1U << 0) #define GENPD_FLAG_IRQ_SAFE (1U << 1) #define GENPD_FLAG_ALWAYS_ON (1U << 2) #define GENPD_FLAG_ACTIVE_WAKEUP (1U << 3) +#define GENPD_FLAG_CPU_DOMAIN (1U << 4) enum gpd_status { GPD_STATE_ACTIVE = 0, /* PM domain is active */ @@ -94,6 +106,7 @@ struct generic_pm_domain { unsigned int suspended_count; /* System suspend device counter */ unsigned int prepared_count; /* Suspend counter of prepared devices */ unsigned int performance_state; /* Aggregated max performance state */ + cpumask_var_t cpus; /* A cpumask of the attached CPUs */ int (*power_off)(struct generic_pm_domain *domain); int (*power_on)(struct generic_pm_domain *domain); struct opp_table *opp_table; /* OPP table of the genpd */ From patchwork Wed Mar 27 14:35:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 10873587 X-Patchwork-Delegate: rjw@sisk.pl Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5D8CB1708 for ; Wed, 27 Mar 2019 14:36:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4A89528A06 for ; Wed, 27 Mar 2019 14:36:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3E48F28698; Wed, 27 Mar 2019 14:36:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A9EF428698 for ; Wed, 27 Mar 2019 14:36:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727875AbfC0OgV (ORCPT ); Wed, 27 Mar 2019 10:36:21 -0400 Received: from mail-lj1-f194.google.com ([209.85.208.194]:44979 "EHLO mail-lj1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728459AbfC0OgD (ORCPT ); Wed, 27 Mar 2019 10:36:03 -0400 Received: by mail-lj1-f194.google.com with SMTP id h16so10128584ljg.11 for ; Wed, 27 Mar 2019 07:36:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=5vc0Fh7WVBEgxYINTNsSBAHF75OIY/EqVtxxKOnOMeU=; b=MTrdssA0TPWQa4lNDrtuZYmFjZtQEp9NuJXqUFJnOAP0JcSMEATBgM9kPNKibwinXU +Hd+Ht+XFjZr69eWzu/wdFQb1oaxzSM3Vqkz2IVL2dBjBEZ7pHDVPXOsOEBvd6DNWL7w SJzA23Z7Y/BhudD2sfsUomqLtvK9Id1KfkATcOD1992bWeZAI6VG41atqyO8lZll5aL2 7Mnp0mO3oM5kMbeq09mfXN+TdBg07KXEhJJ4V/z3osDE3X1S5YKv9uHpBJDHbWCoLxQx IYNKfg0a9BAn7WvEBCeEtFW4Jyh4sJGadUhX0hKXJtA4jJT9G1pIQZ7nvHwFWmBJvO6Z tbcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=5vc0Fh7WVBEgxYINTNsSBAHF75OIY/EqVtxxKOnOMeU=; b=fCk8ygtbJaxWlOp9MeMu4kvSiOFx7HJ5Qjak7kgpqxRfIbWpqMrzkCCbl/kQNej85q PYgUvj8qUdbj/NdmNn4vfXblErRn/AexmP8bbquXo6MXtu/I27fmQjDFQOm3aIwIKDPJ O2+7eK6Nr+x8F4G+q42OX2o/4INQvGjSWiCYPN+YgCz4VxxecGPZBGs2cvZRSpLt13Tv Q++j1ouJtXJF2FxwhHnUnedTsqiunxWXB5wcH8/Se+E+4dgEbj/O3JxhwPSDPK24bJxd peHm+/a8d+G/5HN+Rp/GXekjNLVp5rUDHpR0lzmtiSz/H7nw1A6yYBd5BmXpQcX04x7x 2Epg== X-Gm-Message-State: APjAAAX/2iKkSLXYvLaE5gQv+gKkc1zYbQq8oW/mkGUpU6xFq5bl2Rzp Sn+rNZXMq5BRssVOlSxXKNMM3A== X-Google-Smtp-Source: APXvYqxM6qi/XDrPHpLp+RXLlmfNtCXJbY2FGNByAhSqp/7Ums1A1rJ2C5zXW0rMIhKX2jVXPoZkDA== X-Received: by 2002:a2e:6c0f:: with SMTP id h15mr19630105ljc.155.1553697361156; Wed, 27 Mar 2019 07:36:01 -0700 (PDT) Received: from localhost.localdomain (h-158-174-22-210.NA.cust.bahnhof.se. [158.174.22.210]) by smtp.gmail.com with ESMTPSA id q2sm4548789lfj.58.2019.03.27.07.35.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 27 Mar 2019 07:35:59 -0700 (PDT) From: Ulf Hansson To: "Rafael J . Wysocki" , linux-pm@vger.kernel.org Cc: Frederic Weisbecker , Thomas Gleixner , Sudeep Holla , Lorenzo Pieralisi , Mark Rutland , Daniel Lezcano , "Raju P . L . S . S . S . N" , Stephen Boyd , Tony Lindgren , Kevin Hilman , Lina Iyer , Ulf Hansson , Viresh Kumar , Vincent Guittot , Geert Uytterhoeven , linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v13 3/4] cpuidle: Export the next timer/tick expiration for a CPU Date: Wed, 27 Mar 2019 15:35:47 +0100 Message-Id: <20190327143548.25305-4-ulf.hansson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190327143548.25305-1-ulf.hansson@linaro.org> References: <20190327143548.25305-1-ulf.hansson@linaro.org> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP To be able to predict the sleep duration for a CPU that is entering idle, knowing when the next timer/tick is going to expire, is extremely useful. Both the teo and the menu cpuidle governors already makes use of this information, while selecting an idle state. Moving forward, the similar prediction needs to be done, but for a group of idle CPUs rather than for a single idle CPU. Following changes implements a new genpd governor, which needs this. Support this, by sharing a new function called tick_nohz_get_next_hrtimer(), which returns the next hrtimer or the next tick, whatever that expires first. Additionally, when cpuidle is about to invoke the ->enter() callback, then call tick_nohz_get_next_hrtimer() and store its return value in the per CPU struct cpuidle_device, as to make it available outside cpuidle. Do note, at the point when cpuidle calls tick_nohz_get_next_hrtimer(), the governor's ->select() callback has already made a decision whether to stop the tick or not. In this way, tick_nohz_get_next_hrtimer() actually returns the next timer expiration, whatever origin. Cc: Lina Iyer Co-developed-by: Lina Iyer Co-developed-by: Daniel Lezcano Acked-by: Daniel Lezcano Signed-off-by: Ulf Hansson --- Changes in v13: - As suggested by Rafael, use WRITE|READ_ONCE when writing/reading the next_hrtimer variable and also avoid it from containing a stale value. --- drivers/cpuidle/cpuidle.c | 19 +++++++++++++++++-- include/linux/cpuidle.h | 1 + include/linux/tick.h | 7 ++++++- kernel/time/tick-sched.c | 12 ++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 7f108309e871..0f4b7c45df3e 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -328,9 +328,23 @@ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev, int index) { + int ret = 0; + + /* + * Store the next hrtimer, which becomes either next tick or the next + * timer event, whatever expires first. Additionally, to make this data + * useful for consumers outside cpuidle, we rely on that the governor's + * ->select() callback have decided, whether to stop the tick or not. + */ + WRITE_ONCE(dev->next_hrtimer, tick_nohz_get_next_hrtimer()); + if (cpuidle_state_is_coupled(drv, index)) - return cpuidle_enter_state_coupled(dev, drv, index); - return cpuidle_enter_state(dev, drv, index); + ret = cpuidle_enter_state_coupled(dev, drv, index); + else + ret = cpuidle_enter_state(dev, drv, index); + + WRITE_ONCE(dev->next_hrtimer, 0); + return ret; } /** @@ -511,6 +525,7 @@ static void __cpuidle_device_init(struct cpuidle_device *dev) { memset(dev->states_usage, 0, sizeof(dev->states_usage)); dev->last_residency = 0; + dev->next_hrtimer = 0; } /** diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 3b39472324a3..bb9a0db89f1a 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -83,6 +83,7 @@ struct cpuidle_device { unsigned int use_deepest_state:1; unsigned int poll_time_limit:1; unsigned int cpu; + ktime_t next_hrtimer; int last_residency; struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; diff --git a/include/linux/tick.h b/include/linux/tick.h index 55388ab45fd4..8891b5ac3e40 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -122,6 +122,7 @@ extern void tick_nohz_idle_enter(void); extern void tick_nohz_idle_exit(void); extern void tick_nohz_irq_exit(void); extern bool tick_nohz_idle_got_tick(void); +extern ktime_t tick_nohz_get_next_hrtimer(void); extern ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next); extern unsigned long tick_nohz_get_idle_calls(void); extern unsigned long tick_nohz_get_idle_calls_cpu(int cpu); @@ -145,7 +146,11 @@ static inline void tick_nohz_idle_restart_tick(void) { } static inline void tick_nohz_idle_enter(void) { } static inline void tick_nohz_idle_exit(void) { } static inline bool tick_nohz_idle_got_tick(void) { return false; } - +static inline ktime_t tick_nohz_get_next_hrtimer(void) +{ + /* Next wake up is the tick period, assume it starts now */ + return ktime_add(ktime_get(), TICK_NSEC); +} static inline ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next) { *delta_next = TICK_NSEC; diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 6fa52cd6df0b..8d18e03124ff 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -1022,6 +1022,18 @@ bool tick_nohz_idle_got_tick(void) return false; } +/** + * tick_nohz_get_next_hrtimer - return the next expiration time for the hrtimer + * or the tick, whatever that expires first. Note that, if the tick has been + * stopped, it returns the next hrtimer. + * + * Called from power state control code with interrupts disabled + */ +ktime_t tick_nohz_get_next_hrtimer(void) +{ + return __this_cpu_read(tick_cpu_device.evtdev)->next_event; +} + /** * tick_nohz_get_sleep_length - return the expected length of the current sleep * @delta_next: duration until the next event if the tick cannot be stopped From patchwork Wed Mar 27 14:35:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulf Hansson X-Patchwork-Id: 10873575 X-Patchwork-Delegate: rjw@sisk.pl Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C63681708 for ; Wed, 27 Mar 2019 14:36:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF8D528698 for ; Wed, 27 Mar 2019 14:36:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A281A28A06; Wed, 27 Mar 2019 14:36:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0E6A628A1F for ; Wed, 27 Mar 2019 14:36:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728821AbfC0OgF (ORCPT ); Wed, 27 Mar 2019 10:36:05 -0400 Received: from mail-lf1-f68.google.com ([209.85.167.68]:42671 "EHLO mail-lf1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728739AbfC0OgF (ORCPT ); Wed, 27 Mar 2019 10:36:05 -0400 Received: by mail-lf1-f68.google.com with SMTP id b7so6985055lfg.9 for ; Wed, 27 Mar 2019 07:36:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=U/DRGI4bD5hxWQz0RfripmToZCqku1wrBoz6VqQCAxM=; b=AoB0C/P6/wN599c40fA7FnfEHKiR7xeJ7iQmmglTyYj5F7TdqnpFwOiPVkri1hG8sp ARptOc6fXizzOnP4L5FQuk5esopJcWQ+JW8LnKxDNbXzcZ+IAjOG+346RpopY45y7NCv XN9qFMtVdnzZ1twakoIFLSjUOCID5QPM6ZL2TdIVgshdDxw2edfQ5xZpKXu2/bJUNsr6 WujH02a4iLbZyLLKr303Cd/xcwky2IRKn1/FPMIauCLVndH7lwpAi2Cd+OHZjqdPEyrO I01box3+bUsmQsyzJF/nigg3kCfs6jS8swImNBcEH7LbM0wZ5+SJTm1TwdTIr0KUsHSV PstA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=U/DRGI4bD5hxWQz0RfripmToZCqku1wrBoz6VqQCAxM=; b=qwABtPLhFkshPkpRncPghsZVl0pCxK7bXtArtfupg+TxI6o1KKs1gQ4JgZhNzAAwsU RU6dZ426RPI0ZgWKqjUDlS5LhYNoj/H8DYNczSQftC7FuhgDrBGQMxu2znfSZ1rByklr kWW2Xaxy3/2X19NLMaQGV7+rouH5kSO5myRvVekeCiR6RtEBeoegkrmS2KRg7SQlMkpR H0WzK0y5GIpF+zCZ6rQjpHjeD/EhFbHiTfZJ4Po3yKw4n2utAloApH/dzCtb9nVSdFFn Ecrw1KDCeK+VYh7sYK/IHmLLrWHlLfZi1h9SkkGBPdGuMwUl9meG16QB+G2w+yomdp8h +e+g== X-Gm-Message-State: APjAAAW+zryhiIrF/Vwyj48ULDe+BiB2+vaxTJ2KMNAH69uB6yFAlZHI O56vSTC9em88kRlJhCk0/9UmxQ== X-Google-Smtp-Source: APXvYqwVSECMJDyPtKk3qdNVbNspLWl8YfiJbJb0coBO8l42U3F7Cr7jGh2Pwe9hzNBWHEBxdliY8A== X-Received: by 2002:a19:4b53:: with SMTP id y80mr20608817lfa.146.1553697362971; Wed, 27 Mar 2019 07:36:02 -0700 (PDT) Received: from localhost.localdomain (h-158-174-22-210.NA.cust.bahnhof.se. [158.174.22.210]) by smtp.gmail.com with ESMTPSA id q2sm4548789lfj.58.2019.03.27.07.36.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 27 Mar 2019 07:36:02 -0700 (PDT) From: Ulf Hansson To: "Rafael J . Wysocki" , linux-pm@vger.kernel.org Cc: Frederic Weisbecker , Thomas Gleixner , Sudeep Holla , Lorenzo Pieralisi , Mark Rutland , Daniel Lezcano , "Raju P . L . S . S . S . N" , Stephen Boyd , Tony Lindgren , Kevin Hilman , Lina Iyer , Ulf Hansson , Viresh Kumar , Vincent Guittot , Geert Uytterhoeven , linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v13 4/4] PM / Domains: Add genpd governor for CPUs Date: Wed, 27 Mar 2019 15:35:48 +0100 Message-Id: <20190327143548.25305-5-ulf.hansson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190327143548.25305-1-ulf.hansson@linaro.org> References: <20190327143548.25305-1-ulf.hansson@linaro.org> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP As it's now perfectly possible that a PM domain managed by genpd contains devices belonging to CPUs, we should start to take into account the residency values for the idle states during the state selection process. The residency value specifies the minimum duration of time, the CPU or a group of CPUs, needs to spend in an idle state to not waste energy entering it. To deal with this, let's add a new genpd governor, pm_domain_cpu_gov, that may be used for a PM domain that have CPU devices attached or if the CPUs are attached through subdomains. The new governor computes the minimum expected idle duration time for the online CPUs being attached to the PM domain and its subdomains. Then in the state selection process, trying the deepest state first, it verifies that the idle duration time satisfies the state's residency value. It should be noted that, when computing the minimum expected idle duration time, we use the information about the next timer/tick that is stored in the per CPU variable, cpuidle_devices, for the related CPUs. Future wise, this deserves to be improved, as there are obviously more reasons to why a CPU may be woken up from idle. Cc: Lina Iyer Co-developed-by: Lina Iyer Acked-by: Daniel Lezcano Signed-off-by: Ulf Hansson --- Changes in v13: - As suggested by Rafael, use READ_ONCE when reading the next_hrtimer variable. --- drivers/base/power/domain_governor.c | 65 +++++++++++++++++++++++++++- include/linux/pm_domain.h | 3 ++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index 4d07e38a8247..7f9b80f46b3a 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include static int dev_update_qos_constraint(struct device *dev, void *data) { @@ -210,8 +213,10 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) struct generic_pm_domain *genpd = pd_to_genpd(pd); struct gpd_link *link; - if (!genpd->max_off_time_changed) + if (!genpd->max_off_time_changed) { + genpd->state_idx = genpd->cached_power_down_state_idx; return genpd->cached_power_down_ok; + } /* * We have to invalidate the cached results for the masters, so @@ -236,6 +241,7 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) genpd->state_idx--; } + genpd->cached_power_down_state_idx = genpd->state_idx; return genpd->cached_power_down_ok; } @@ -244,6 +250,58 @@ static bool always_on_power_down_ok(struct dev_pm_domain *domain) return false; } +static bool cpu_power_down_ok(struct dev_pm_domain *pd) +{ + struct generic_pm_domain *genpd = pd_to_genpd(pd); + struct cpuidle_device *dev; + ktime_t domain_wakeup, next_hrtimer; + s64 idle_duration_ns; + int cpu, i; + + /* Validate dev PM QoS constraints. */ + if (!default_power_down_ok(pd)) + return false; + + if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN)) + return true; + + /* + * 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 + * contains a mask of all CPUs from subdomains. + */ + domain_wakeup = ktime_set(KTIME_SEC_MAX, 0); + for_each_cpu_and(cpu, genpd->cpus, cpu_online_mask) { + dev = per_cpu(cpuidle_devices, cpu); + if (dev) { + next_hrtimer = READ_ONCE(dev->next_hrtimer); + if (ktime_before(next_hrtimer, domain_wakeup)) + domain_wakeup = next_hrtimer; + } + } + + /* The minimum idle duration is from now - until the next wakeup. */ + idle_duration_ns = ktime_to_ns(ktime_sub(domain_wakeup, ktime_get())); + if (idle_duration_ns <= 0) + return false; + + /* + * Find the deepest idle state that has its residency value satisfied + * and by also taking into account the power off latency for the state. + * Start at the state picked by the dev PM QoS constraint validation. + */ + i = genpd->state_idx; + do { + if (idle_duration_ns >= (genpd->states[i].residency_ns + + genpd->states[i].power_off_latency_ns)) { + genpd->state_idx = i; + return true; + } + } while (--i >= 0); + + return false; +} + struct dev_power_governor simple_qos_governor = { .suspend_ok = default_suspend_ok, .power_down_ok = default_power_down_ok, @@ -256,3 +314,8 @@ struct dev_power_governor pm_domain_always_on_gov = { .power_down_ok = always_on_power_down_ok, .suspend_ok = default_suspend_ok, }; + +struct dev_power_governor pm_domain_cpu_gov = { + .suspend_ok = default_suspend_ok, + .power_down_ok = cpu_power_down_ok, +}; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index a6e251fe9deb..ae7061556a26 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -118,6 +118,7 @@ struct generic_pm_domain { s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ bool max_off_time_changed; bool cached_power_down_ok; + bool cached_power_down_state_idx; int (*attach_dev)(struct generic_pm_domain *domain, struct device *dev); void (*detach_dev)(struct generic_pm_domain *domain, @@ -202,6 +203,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state); extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; +extern struct dev_power_governor pm_domain_cpu_gov; #else static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) @@ -245,6 +247,7 @@ static inline int dev_pm_genpd_set_performance_state(struct device *dev, #define simple_qos_governor (*(struct dev_power_governor *)(NULL)) #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) +#define pm_domain_cpu_gov (*(struct dev_power_governor *)(NULL)) #endif #ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP