From patchwork Wed May 17 07:02:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 99905 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp100017qge; Wed, 17 May 2017 00:03:18 -0700 (PDT) X-Received: by 10.99.114.72 with SMTP id c8mr2142039pgn.81.1495004598247; Wed, 17 May 2017 00:03:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495004598; cv=none; d=google.com; s=arc-20160816; b=Ie4i1xbEPDvD+QwrLIdfO9LPVZY9HwDzNsMhDOXx/UWx/S9tfH27QPeV9Pd6sdDooa hBmQcLkO/QlX2ZE4+v1sYOyzqVXjdtt+VCKUiuN4eVMgh+oXXc9bKCdFb/NoIf2joLvI xfUY5LIsXnFwEwTDGhYWpUgowyq0fEz+ygRuHsCOxVE7ZcqkPL0xYgCm6hz80aLvRphc lbsBdXyN9fXATDxp9ODlJ+Fdziyyp6E8eNVqfrIQn+PaSqFJ7PI/VgfUKvddui3psagC wvmzulDBnWQ97HLmkn3faA5CiDJyi0ndgbUbR/5seZcmiQ5sy2zuBBcAAYu6M2zdVvE4 O0ng== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=pvQFI599kS8XmedffgHGfPxgrZfgT5sK3HgfrO05dXg=; b=ATSZLE9ECC0uOu0YtG0o8Wk4Ub8SEmt5MVzUcFK27ZQ2XS7+iTwPGatwHDI34mhTPP BClb18g1HSKcq8dvm6/DR4TjqnoecJ9Gwm2mmHjxe5p8QVLA1urfhhQFBlAwciJ90yas 884RMHeawrGnXRUj+gmIJAzh70p1BBpsdktx2d0LCAEBtJW04gqJzcSeqzJsPkMQje5Z ZIPUSOv1qbWzGEo/Y/kyBQBXo6+sw/7ig9r3SBdghlQBUrLTZvKm/1WCIzQ4CiqABbaZ x4RJgnJPSS0fFt4a1Le1g8t/DX4mXuqs3owWxujI7w1ojFfRup6mFxo7hPeQkIi8s4my Ar8g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y8si1257708pfd.317.2017.05.17.00.03.17; Wed, 17 May 2017 00:03:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753808AbdEQHCz (ORCPT + 25 others); Wed, 17 May 2017 03:02:55 -0400 Received: from mail-pg0-f45.google.com ([74.125.83.45]:33528 "EHLO mail-pg0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753786AbdEQHCw (ORCPT ); Wed, 17 May 2017 03:02:52 -0400 Received: by mail-pg0-f45.google.com with SMTP id u187so2663441pgb.0 for ; Wed, 17 May 2017 00:02:51 -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 :in-reply-to:references; bh=pvQFI599kS8XmedffgHGfPxgrZfgT5sK3HgfrO05dXg=; b=AIswF6eQ4AgLaPLYh9M53iQnyQKbE7PdeCQnWImwwLvo+MiUzhCibHlANEQiYzP1QJ QZ79GlNRNCpL8y2wpdxtAJHonPOLfp3zw5xv3kjL7HIhSjZm0qf0Ez2cbgxpFQZk1AnQ Qbf+qfE+yRKreu/N2lqXf5ktOazoZpng9fM28= 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:in-reply-to:references; bh=pvQFI599kS8XmedffgHGfPxgrZfgT5sK3HgfrO05dXg=; b=i0v9OtOvDlasXqHv9rhm8dUj7h82oS2gs7zZA1a8xoWvRUQQOBdqQfgLmliw3imOqp iMtYdQbO9/QsQN9oKu+yYAmbQFYKmdgCY8sFD38cGG2MYgZm6nEMQxcw/j57kUVPzgs1 ygVhSZRCll9hmxxXpigKKqtpM4Kx9TukfyVfKonyp+aIWOXo7/n6uzeRX06IZqr/NpLU MmrsbVQPlXHUe5IF0OExuO0QG5E8ZdJvvHS8ng2TWwAZ4k2esTjZEKb1clGfTdEcBwA1 OU0BHKQkFpN8BiVr3Hbq44zYTRzTeeugOmeGLLIWz2Di6GKukOxZuhyJpAezYFnBf63N VjTQ== X-Gm-Message-State: AODbwcAFPvVyfqnrs/NzoNKiDtnsC5TGu7/WZVgZ6L2+7nGQ76+sZY6H CW22Hhh9iIILV9Jr X-Received: by 10.99.2.3 with SMTP id 3mr2127054pgc.17.1495004570977; Wed, 17 May 2017 00:02:50 -0700 (PDT) Received: from localhost ([122.172.129.253]) by smtp.gmail.com with ESMTPSA id b1sm1893185pfc.27.2017.05.17.00.02.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 17 May 2017 00:02:50 -0700 (PDT) From: Viresh Kumar To: Rafael Wysocki , ulf.hansson@linaro.org, Kevin Hilman , Pavel Machek , Len Brown Cc: linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , robh+dt@kernel.org, lina.iyer@linaro.org, rnayak@codeaurora.org, sudeep.holla@arm.com, Viresh Kumar Subject: [PATCH V7 1/2] PM / Domains: Add support to select performance-state of domains Date: Wed, 17 May 2017 12:32:42 +0530 Message-Id: <4cc55fce0fd4199941f1d7b785e677255ff792d5.1495003720.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.13.0.303.g4ebf3021692d In-Reply-To: References: In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Some platforms have the capability to configure the performance state of their Power Domains. The performance levels are identified by positive integer values, a lower value represents lower performance state. This patch adds a new genpd API: pm_genpd_update_performance_state(). The caller passes the affected device and the frequency representing its next DVFS state. The power domains get two new callbacks: - get_performance_state(): This is called by the genpd core to retrieve the performance state (integer value) corresponding to a target frequency for the device. This state is used by the genpd core to find the highest requested state by all the devices powered by a domain. - set_performance_state(): The highest state retrieved from above interface is then passed to this callback to finally program the performance state of the power domain. The power domains can avoid supplying these callbacks, if they don't support setting performance-states. A power domain may have only get_performance_state() callback, if it doesn't have the capability of changing the performance state itself but someone in its parent hierarchy has. A power domain may have only set_performance_state(), it doesn't have any direct devices below it and only subdomains. And so the get_performance_state() will never get called. The more common case would be to have both the callbacks set. Another API, pm_genpd_has_performance_state(), is also added to let other parts of the kernel check if the power domain of a device supports performance-states or not. Note that the same performance level as returned by the parent domain of a device is used for every other domain in parent hierarchy. Signed-off-by: Viresh Kumar --- drivers/base/power/domain.c | 172 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 19 +++++ 2 files changed, 191 insertions(+) -- 2.13.0.303.g4ebf3021692d diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 71c95ad808d5..56b666eb1a71 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -466,6 +466,166 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, return NOTIFY_DONE; } +/* + * Returns true if anyone in genpd's parent hierarchy has + * set_performance_state() set. + */ +static bool genpd_has_set_performance_state(struct generic_pm_domain *genpd) +{ + struct gpd_link *link; + + if (genpd->set_performance_state) + return true; + + list_for_each_entry(link, &genpd->slave_links, slave_node) { + if (genpd_has_set_performance_state(link->master)) + return true; + } + + return false; +} + +/** + * pm_genpd_has_performance_state - Checks if power domain does performance + * state management. + * + * @dev: Device whose power domain is getting inquired. + */ +bool pm_genpd_has_performance_state(struct device *dev) +{ + struct generic_pm_domain *genpd = dev_to_genpd(dev); + + /* The parent domain must have set get_performance_state() */ + if (!IS_ERR(genpd) && genpd->get_performance_state) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(pm_genpd_has_performance_state); + +static int genpd_update_performance_state(struct generic_pm_domain *genpd, + int depth) +{ + struct generic_pm_domain_data *pd_data; + struct generic_pm_domain *subdomain; + struct pm_domain_data *pdd; + unsigned int state = 0, prev; + struct gpd_link *link; + int ret; + + /* Traverse all devices within the domain */ + list_for_each_entry(pdd, &genpd->dev_list, list_node) { + pd_data = to_gpd_data(pdd); + + if (pd_data->performance_state > state) + state = pd_data->performance_state; + } + + /* Traverse all subdomains within the domain */ + list_for_each_entry(link, &genpd->master_links, master_node) { + subdomain = link->slave; + + if (subdomain->performance_state > state) + state = subdomain->performance_state; + } + + if (genpd->performance_state == state) + return 0; + + /* + * Not all domains support updating performance state. Move on to their + * parent domains in that case. + */ + if (genpd->set_performance_state) { + ret = genpd->set_performance_state(genpd, state); + if (!ret) + genpd->performance_state = state; + + return ret; + } + + prev = genpd->performance_state; + genpd->performance_state = state; + + list_for_each_entry(link, &genpd->slave_links, slave_node) { + struct generic_pm_domain *master = link->master; + + genpd_lock_nested(master, depth + 1); + ret = genpd_update_performance_state(master, depth + 1); + genpd_unlock(master); + + if (!ret) + continue; + + /* + * Preserve earlier state for all the power domains which have + * been updated. + */ + genpd->performance_state = prev; + + list_for_each_entry(link, &genpd->slave_links, slave_node) { + struct generic_pm_domain *nmaster = link->master; + + if (nmaster == master) + break; + + genpd_lock_nested(nmaster, depth + 1); + genpd_update_performance_state(master, depth + 1); + genpd_unlock(master); + } + + return ret; + } + + return 0; +} + +/** + * pm_genpd_update_performance_state - Update performance state of parent power + * domain for the target frequency for the device. + * + * @dev: Device for which the performance-state needs to be adjusted. + * @rate: Device's next frequency. + */ +int pm_genpd_update_performance_state(struct device *dev, unsigned long rate) +{ + struct generic_pm_domain *genpd = ERR_PTR(-ENODATA); + struct generic_pm_domain_data *gpd_data; + int ret, prev; + + spin_lock_irq(&dev->power.lock); + if (dev->power.subsys_data && dev->power.subsys_data->domain_data) { + gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); + genpd = dev_to_genpd(dev); + } + spin_unlock_irq(&dev->power.lock); + + if (IS_ERR(genpd)) + return -ENODEV; + + if (!genpd->get_performance_state) { + dev_err(dev, "Performance states aren't supported by power domain\n"); + return -EINVAL; + } + + genpd_lock(genpd); + ret = genpd->get_performance_state(dev, rate); + if (ret < 0) + goto unlock; + + prev = gpd_data->performance_state; + gpd_data->performance_state = ret; + ret = genpd_update_performance_state(genpd, 0); + if (ret) + gpd_data->performance_state = prev; + +unlock: + genpd_unlock(genpd); + + return ret; +} +EXPORT_SYMBOL_GPL(pm_genpd_update_performance_state); + /** * genpd_power_off_work_fn - Power off PM domain whose subdomain count is 0. * @work: Work structure used for scheduling the execution of this function. @@ -1156,6 +1316,7 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, gpd_data->td.constraint_changed = true; gpd_data->td.effective_constraint_ns = -1; gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; + gpd_data->performance_state = 0; spin_lock_irq(&dev->power.lock); @@ -1502,6 +1663,17 @@ int pm_genpd_init(struct generic_pm_domain *genpd, genpd->dev_ops.start = pm_clk_resume; } + /* + * If this genpd supports getting performance state, then someone in its + * hierarchy must support setting it too. + */ + if (genpd->get_performance_state && + !genpd_has_set_performance_state(genpd)) { + pr_err("%s: genpd doesn't support updating performance state\n", + genpd->name); + return -ENODEV; + } + /* Always-on domains must be powered on at initialization. */ if (genpd_is_always_on(genpd) && !genpd_status_on(genpd)) return -EINVAL; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index b7803a251044..74502664ea33 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -63,8 +63,12 @@ struct generic_pm_domain { unsigned int device_count; /* Number of devices */ unsigned int suspended_count; /* System suspend device counter */ unsigned int prepared_count; /* Suspend counter of prepared devices */ + unsigned int performance_state; /* Max requested performance state */ int (*power_off)(struct generic_pm_domain *domain); int (*power_on)(struct generic_pm_domain *domain); + int (*get_performance_state)(struct device *dev, unsigned long rate); + int (*set_performance_state)(struct generic_pm_domain *domain, + unsigned int state); struct gpd_dev_ops dev_ops; s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ bool max_off_time_changed; @@ -118,6 +122,7 @@ struct generic_pm_domain_data { struct pm_domain_data base; struct gpd_timing_data td; struct notifier_block nb; + unsigned int performance_state; void *data; }; @@ -148,6 +153,9 @@ extern int pm_genpd_remove(struct generic_pm_domain *genpd); extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; +extern bool pm_genpd_has_performance_state(struct device *dev); +extern int pm_genpd_update_performance_state(struct device *dev, + unsigned long rate); #else static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) @@ -185,6 +193,17 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd) return -ENOTSUPP; } +static inline bool pm_genpd_has_performance_state(struct device *dev) +{ + return false; +} + +static inline int pm_genpd_update_performance_state(struct device *dev, + unsigned long rate) +{ + return -ENOTSUPP; +} + #define simple_qos_governor (*(struct dev_power_governor *)(NULL)) #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) #endif From patchwork Wed May 17 07:02:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 99906 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp100022qge; Wed, 17 May 2017 00:03:19 -0700 (PDT) X-Received: by 10.84.216.77 with SMTP id f13mr2501775plj.130.1495004599136; Wed, 17 May 2017 00:03:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495004599; cv=none; d=google.com; s=arc-20160816; b=wXhol1aj8fo/1X7GgnoK9QusS8dNTz9sceasy73Y3zoCBI/vOPJSCzL+H7p8zJJ1y/ kvVF5tKBO3L57/O7eI9Dbdh5V0284id/ymR4EJFNrQT50P3getrtcyYgS7F+5p1bjifg OyiRVnfl2XV4pvJHK7PwTilFuxxZMep+Hh1uqKrL2rGdew0p5oqGR/QSFMdrJvWUB0Fb TKqudatGBP3qHVYbEMZiXIIPpp0H2oX/CSoHjsRN0hSrc/U7JVjXQJ9stnGCMeJmGZvs kroDP6wU1aR7kGZZQZ/kpz5QiWHqvvgmY8i3go+LVpFE7kQTfC3VAVGoNBG/obXo1oWK n2eg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=M8NO2cFEs6B0cFo1BztVl82+yfDMzWXfL2RElAY9GgY=; b=q6Fy2GhztBiKkBVGl9g/33q5kjVpeB0dZddWsRC746ybJshvL46SQSXhaZ1r33sYUf 9I/6caXyEnVOqImQ6fkGjREaal/vyaXAYfHKHNRkYmqsIBKEwYfWHz33hQ/AFlsvG+tb g6AR2I7fv7aaUDpJlmjdYVY77nbwprvdeXRLp7hqmjjq/gwdhze66uijAnWnjLkxsqaR b1krL0A4MlIf0zNY6NQelJgKJl40BtGY5f3rmVF3EKYr+1ZeOijWFZkaULQ2q2doyqcw ee+140urYzScNl2Jn3LLXhXuXtThtu+JfN+fUmt1ZODU+0yx8aTf6Yg23bGaM+zLjV16 krsg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y8si1257708pfd.317.2017.05.17.00.03.18; Wed, 17 May 2017 00:03:19 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753815AbdEQHDG (ORCPT + 25 others); Wed, 17 May 2017 03:03:06 -0400 Received: from mail-pf0-f176.google.com ([209.85.192.176]:35546 "EHLO mail-pf0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753528AbdEQHCy (ORCPT ); Wed, 17 May 2017 03:02:54 -0400 Received: by mail-pf0-f176.google.com with SMTP id n23so2734759pfb.2 for ; Wed, 17 May 2017 00:02:54 -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 :in-reply-to:references; bh=M8NO2cFEs6B0cFo1BztVl82+yfDMzWXfL2RElAY9GgY=; b=aMNLT4t+dSKkW5Wj0uzeay85XaCHqVVRkOXta/tiIJSe8uThBubq5XVrgY6GowYlVx Jb4QTe1yeLe8u7PO5Enpju7UkJuvhSQuaQtIXk87LAcEuIlvYRzG4VoQlHlAt+656QTV CUc/idTuwRopvLgv84iI9hVKChC1cbDQ9C1yg= 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:in-reply-to:references; bh=M8NO2cFEs6B0cFo1BztVl82+yfDMzWXfL2RElAY9GgY=; b=HESUhH/m5PoDgNt70sNsXAWxcJQ5APIoEoeaoOptM81ho3MhQ55UTEGPx/MUsJeWKz PdMezOU5fqO1nsU2wl2uZ/ZF0oWlFGexj3jlrAdRZawn7ICaofvHPkVRiyb0TEydlRI/ qB+o948UaR4QSrPkXmHD2jVgka0suBihpWkadTNnqCNrP+4IWYZW8huq6umfy9YuPolU 44ebRex+HmQ3iRwwfh1Iw5U4XokwjO6kY4g+R4Ij/DZ+W1+tC2TFyIe/KviMVDU2DJ9a wPFG7ZfLDWMw8wlmh5kNg44F/UM/iV/2xmb120Ec+1RcwH7yXcpd827GXdMjNLHJOord kU3w== X-Gm-Message-State: AODbwcDgZdGBYH3ktaL8fm8Lp/xqTXmmP5pKa6rQpXJEb8et32G+5vd9 M6NSr7PWfKT9EygE X-Received: by 10.99.109.199 with SMTP id i190mr2150685pgc.71.1495004573839; Wed, 17 May 2017 00:02:53 -0700 (PDT) Received: from localhost ([122.172.129.253]) by smtp.gmail.com with ESMTPSA id q82sm2170589pfl.28.2017.05.17.00.02.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 17 May 2017 00:02:53 -0700 (PDT) From: Viresh Kumar To: Rafael Wysocki , ulf.hansson@linaro.org, Kevin Hilman , Viresh Kumar , Nishanth Menon , Stephen Boyd Cc: linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Vincent Guittot , robh+dt@kernel.org, lina.iyer@linaro.org, rnayak@codeaurora.org, sudeep.holla@arm.com, Viresh Kumar Subject: [PATCH V7 2/2] PM / OPP: Support updating performance state of device's power domains Date: Wed, 17 May 2017 12:32:43 +0530 Message-Id: X-Mailer: git-send-email 2.13.0.303.g4ebf3021692d In-Reply-To: References: In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The gendpd framework now provides an API to request device's power domain to update its performance state based on a particular target frequency for the device. Use that interface from the OPP core for devices whose power domains support performance states. Note that the current implementation is restricted to the case where the device doesn't have separate regulators for itself. We shouldn't over engineer the code before we have real use case for them. We can always come back and add more code to support such cases. Signed-off-by: Viresh Kumar --- drivers/base/power/opp/core.c | 48 ++++++++++++++++++++++++++++++++++++++++++- drivers/base/power/opp/opp.h | 2 ++ 2 files changed, 49 insertions(+), 1 deletion(-) -- 2.13.0.303.g4ebf3021692d diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 898f19ea0f60..3c1036f638f6 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "opp.h" @@ -535,6 +536,42 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk, return ret; } +static inline int +_generic_set_opp_domain(struct device *dev, struct clk *clk, + unsigned long old_freq, unsigned long freq) +{ + int ret; + + /* Scaling up? Scale domain performance state before frequency */ + if (freq > old_freq) { + ret = pm_genpd_update_performance_state(dev, freq); + if (ret) + return ret; + } + + ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); + if (ret) + goto restore_domain_state; + + /* Scaling down? Scale domain performance state after frequency */ + if (freq < old_freq) { + ret = pm_genpd_update_performance_state(dev, freq); + if (ret) + goto restore_freq; + } + + return 0; + +restore_freq: + if (_generic_set_opp_clk_only(dev, clk, freq, old_freq)) + dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n", + __func__, old_freq); +restore_domain_state: + pm_genpd_update_performance_state(dev, old_freq); + + return ret; +} + static int _generic_set_opp_regulator(struct opp_table *opp_table, struct device *dev, unsigned long old_freq, @@ -653,7 +690,14 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) /* Only frequency scaling */ if (!opp_table->regulators) { - ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); + /* + * We don't support devices with both regulator and + * domain performance-state for now. + */ + if (opp_table->genpd_performance_state) + ret = _generic_set_opp_domain(dev, clk, old_freq, freq); + else + ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); } else if (!opp_table->set_opp) { ret = _generic_set_opp_regulator(opp_table, dev, old_freq, freq, IS_ERR(old_opp) ? NULL : old_opp->supplies, @@ -755,6 +799,8 @@ static struct opp_table *_allocate_opp_table(struct device *dev) ret); } + opp_table->genpd_performance_state = pm_genpd_has_performance_state(dev); + BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head); INIT_LIST_HEAD(&opp_table->opp_list); mutex_init(&opp_table->lock); diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index 166eef990599..1efa253e1934 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -135,6 +135,7 @@ enum opp_table_access { * @clk: Device's clock handle * @regulators: Supply regulators * @regulator_count: Number of power supply regulators + * @genpd_performance_state: Device's power domain support performance state. * @set_opp: Platform specific set_opp callback * @set_opp_data: Data to be passed to set_opp callback * @dentry: debugfs dentry pointer of the real device directory (not links). @@ -170,6 +171,7 @@ struct opp_table { struct clk *clk; struct regulator **regulators; unsigned int regulator_count; + bool genpd_performance_state; int (*set_opp)(struct dev_pm_set_opp_data *data); struct dev_pm_set_opp_data *set_opp_data;