From patchwork Fri Aug 26 20:17:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lina Iyer X-Patchwork-Id: 9302033 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A44BB601C0 for ; Fri, 26 Aug 2016 20:24:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 94DAD2960A for ; Fri, 26 Aug 2016 20:24:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8971829653; Fri, 26 Aug 2016 20:24:57 +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=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id EF8182960A for ; Fri, 26 Aug 2016 20:24:56 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bdNel-0004H9-9f; Fri, 26 Aug 2016 20:23:15 +0000 Received: from mail-pa0-x234.google.com ([2607:f8b0:400e:c03::234]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bdNaY-00007v-E9 for linux-arm-kernel@lists.infradead.org; Fri, 26 Aug 2016 20:18:58 +0000 Received: by mail-pa0-x234.google.com with SMTP id cy9so9364673pac.0 for ; Fri, 26 Aug 2016 13:18:34 -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=kiL6VV1qcTVmQh3Y0twdN0zgKEDmaLnIV4krv/hTFbU=; b=V6BxDZyc/0fY1ObfNmU1mvf74zmOpvkEFFKFm6/5slltVRTS2E+Tx0HX8qSgbcoKHB itQrPLaqQ43068AqHc4Ng7y7nT3dLnsP3cHts1l0/zL9L8txiTA9NJYry/iF7YkQuQ1I JqlGVkfBcAIV/yHWQl2bxBvW/d3iOp30lUVS0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=kiL6VV1qcTVmQh3Y0twdN0zgKEDmaLnIV4krv/hTFbU=; b=SWmT+/uLD8Hv6Yvy70dbBkzNHySdVEpxlxfdgNcRF7lUTnGt6Ry9U3eGFJJ63EWRWA ZsfnA/wCHb9EkTQRVaASN5v48MYQTP5uu3C10wcgoEhMvKUhBtTamfivGB0eJF3Ykv8r pR4XZlnEyFKYtwL8i9EqePEEY2SsSlbw398YwoHYMW8qh1WNZmp0LZ/qx7qWQv51iYUF xRdpvxJsW9HtRJDGpOenyL0q22gPJxRR9pM+cFCHufkwLh5Ggi3O1fOb79C7ulk1i+kN OEcrPnqPWgXSWlwGfMEAzjvZI/e//ezYw2/Hsj72+IeVw99FDTThYZwPNdOry5FbXBDx oGCg== X-Gm-Message-State: AE9vXwOc05oaf2ub3DXSVNfXxSA7Vs4cYQK4lewwduzHyFtq764G6ILvSmSgBDE3HS5kbfmV X-Received: by 10.66.100.162 with SMTP id ez2mr9186693pab.123.1472242714109; Fri, 26 Aug 2016 13:18:34 -0700 (PDT) Received: from ubuntu.localdomain (i-global254.qualcomm.com. [199.106.103.254]) by smtp.gmail.com with ESMTPSA id m128sm30761463pfm.42.2016.08.26.13.18.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 26 Aug 2016 13:18:33 -0700 (PDT) From: Lina Iyer To: ulf.hansson@linaro.org, khilman@kernel.org, rjw@rjwysocki.net, linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v5 08/16] PM / cpu_domains: Setup PM domains for CPUs/clusters Date: Fri, 26 Aug 2016 14:17:50 -0600 Message-Id: <1472242678-33700-9-git-send-email-lina.iyer@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1472242678-33700-1-git-send-email-lina.iyer@linaro.org> References: <1472242678-33700-1-git-send-email-lina.iyer@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160826_131854_643095_DC35B08F X-CRM114-Status: GOOD ( 19.89 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: lorenzo.pieralisi@arm.com, Juri.Lelli@arm.com, linux-arm-msm@vger.kernel.org, sboyd@codeaurora.org, brendan.jackman@arm.com, sudeep.holla@arm.com, andy.gross@linaro.org, Lina Iyer MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Define and add Generic PM domains (genpd) for CPU clusters. Many new SoCs group CPUs as clusters. Clusters share common resources like power rails, caches, VFP, Coresight etc. When all CPUs in the cluster are idle, these shared resources may also be put in their idle state. CPUs may be associated with their domain providers. The domains in turn may be associated with their providers. This is clean way to model the cluster hierarchy like that of ARM's big.little architecture. Platform drivers may initialize generic PM domains and setup the CPU PM domains for the genpd and attach CPUs to the domain. In the following patches, the CPUs are hooked up to runtime PM framework which helps power down the domain, when all the CPUs in the domain are idle. Cc: Ulf Hansson Suggested-by: Kevin Hilman Signed-off-by: Lina Iyer --- drivers/base/power/Makefile | 2 +- drivers/base/power/cpu_domains.c | 191 +++++++++++++++++++++++++++++++++++++++ include/linux/cpu_domains.h | 49 ++++++++++ 3 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 drivers/base/power/cpu_domains.c create mode 100644 include/linux/cpu_domains.h diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 5998c53..ee383f1 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_OPP) += opp/ -obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o cpu_domains.o obj-$(CONFIG_HAVE_CLK) += clock_ops.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/drivers/base/power/cpu_domains.c b/drivers/base/power/cpu_domains.c new file mode 100644 index 0000000..73e493b --- /dev/null +++ b/drivers/base/power/cpu_domains.c @@ -0,0 +1,191 @@ +/* + * drivers/base/power/cpu_domains.c - Helper functions to create CPU PM domains. + * + * Copyright (C) 2016 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CPU_PD_NAME_MAX 36 + +struct cpu_pm_domain { + struct list_head link; + struct cpu_pd_ops ops; + struct generic_pm_domain *genpd; + struct cpu_pm_domain *parent; + cpumask_var_t cpus; +}; + +/* List of CPU PM domains we care about */ +static LIST_HEAD(of_cpu_pd_list); +static DEFINE_MUTEX(cpu_pd_list_lock); + +static inline struct cpu_pm_domain *to_cpu_pd(struct generic_pm_domain *d) +{ + struct cpu_pm_domain *pd; + struct cpu_pm_domain *res = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(pd, &of_cpu_pd_list, link) + if (pd->genpd == d) { + res = pd; + break; + } + rcu_read_unlock(); + + return res; +} + +static int cpu_pd_power_on(struct generic_pm_domain *genpd) +{ + struct cpu_pm_domain *pd = to_cpu_pd(genpd); + + return pd->ops.power_on ? pd->ops.power_on() : 0; +} + +static int cpu_pd_power_off(struct generic_pm_domain *genpd) +{ + struct cpu_pm_domain *pd = to_cpu_pd(genpd); + + return pd->ops.power_off ? pd->ops.power_off(genpd->state_idx, + genpd->states[genpd->state_idx].param, + pd->cpus) : 0; +} + +/** + * cpu_pd_attach_domain: Attach a child CPU PM to its parent + * + * @parent: The parent generic PM domain + * @child: The child generic PM domain + * + * Generally, the child PM domain is the one to which CPUs are attached. + */ +int cpu_pd_attach_domain(struct generic_pm_domain *parent, + struct generic_pm_domain *child) +{ + struct cpu_pm_domain *cpu_pd, *parent_cpu_pd; + int ret; + + ret = pm_genpd_add_subdomain(parent, child); + if (ret) { + pr_err("%s: Unable to add sub-domain (%s) to %s.\n err=%d", + __func__, child->name, parent->name, ret); + return ret; + } + + cpu_pd = to_cpu_pd(child); + parent_cpu_pd = to_cpu_pd(parent); + + if (cpu_pd && parent_cpu_pd) + cpu_pd->parent = parent_cpu_pd; + + return ret; +} +EXPORT_SYMBOL(cpu_pd_attach_domain); + +/** + * cpu_pd_attach_cpu: Attach a CPU to its CPU PM domain. + * + * @genpd: The parent generic PM domain + * @cpu: The CPU number + */ +int cpu_pd_attach_cpu(struct generic_pm_domain *genpd, int cpu) +{ + int ret; + struct device *cpu_dev; + struct cpu_pm_domain *cpu_pd = to_cpu_pd(genpd); + + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_warn("%s: Unable to get device for CPU%d\n", + __func__, cpu); + return -ENODEV; + } + + ret = genpd_dev_pm_attach(cpu_dev); + if (ret) + dev_warn(cpu_dev, + "%s: Unable to attach to power-domain: %d\n", + __func__, ret); + else + dev_dbg(cpu_dev, "Attached to domain\n"); + + while (!ret && cpu_pd) { + cpumask_set_cpu(cpu, cpu_pd->cpus); + cpu_pd = cpu_pd->parent; + }; + + return ret; +} +EXPORT_SYMBOL(cpu_pd_attach_cpu); + +/** + * cpu_pd_init: Initialize a CPU PM domain for a genpd + * + * @genpd: The initialized generic PM domain object. + * @ops: The power_on/power_off ops for the domain controller. + * + * Initialize a CPU PM domain based on a generic PM domain. The platform driver + * is expected to setup the genpd object and the states associated with the + * generic PM domain, before calling this function. + */ +struct generic_pm_domain *cpu_pd_init(struct generic_pm_domain *genpd, + const struct cpu_pd_ops *ops) +{ + int ret = -ENOMEM; + struct cpu_pm_domain *pd; + + if (IS_ERR_OR_NULL(genpd)) + return ERR_PTR(-EINVAL); + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) + goto fail; + + if (!zalloc_cpumask_var(&pd->cpus, GFP_KERNEL)) + goto fail; + + genpd->power_off = cpu_pd_power_off; + genpd->power_on = cpu_pd_power_on; + genpd->flags |= GENPD_FLAG_IRQ_SAFE; + pd->genpd = genpd; + pd->ops.power_on = ops->power_on; + pd->ops.power_off = ops->power_off; + + INIT_LIST_HEAD_RCU(&pd->link); + mutex_lock(&cpu_pd_list_lock); + list_add_rcu(&pd->link, &of_cpu_pd_list); + mutex_unlock(&cpu_pd_list_lock); + + ret = pm_genpd_init(genpd, &simple_qos_governor, false); + if (ret) { + pr_err("Unable to initialize domain %s\n", genpd->name); + goto fail; + } + + pr_debug("adding %s as CPU PM domain\n", pd->genpd->name); + + return genpd; +fail: + kfree(genpd->name); + kfree(genpd); + if (pd) + kfree(pd->cpus); + kfree(pd); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(cpu_pd_init); diff --git a/include/linux/cpu_domains.h b/include/linux/cpu_domains.h new file mode 100644 index 0000000..3a0a027 --- /dev/null +++ b/include/linux/cpu_domains.h @@ -0,0 +1,49 @@ +/* + * include/linux/cpu_domains.h + * + * Copyright (C) 2016 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __CPU_DOMAINS_H__ +#define __CPU_DOMAINS_H__ + +#include + +struct cpumask; + +struct cpu_pd_ops { + int (*power_off)(u32 state_idx, u32 param, const struct cpumask *mask); + int (*power_on)(void); +}; + +#ifdef CONFIG_PM_GENERIC_DOMAINS + +struct generic_pm_domain *cpu_pd_init(struct generic_pm_domain *genpd, + const struct cpu_pd_ops *ops); + +int cpu_pd_attach_domain(struct generic_pm_domain *parent, + struct generic_pm_domain *child); + +int cpu_pd_attach_cpu(struct generic_pm_domain *genpd, int cpu); + +#else + +static inline +struct generic_pm_domain *cpu_pd_init(struct generic_pm_domain *genpd, + const struct cpu_pd_ops *ops) +{ return ERR_PTR(-ENODEV); } + +static inline int cpu_pd_attach_domain(struct generic_pm_domain *parent, + struct generic_pm_domain *child) +{ return -ENODEV; } + +static inline int cpu_pd_attach_cpu(struct generic_pm_domain *genpd, int cpu) +{ return -ENODEV; } + +#endif /* CONFIG_PM_GENERIC_DOMAINS */ + +#endif /* __CPU_DOMAINS_H__ */