From patchwork Thu Jun 21 01:52:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Kaehlcke X-Patchwork-Id: 10478957 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 BC84D60365 for ; Thu, 21 Jun 2018 01:53:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AA77728A4C for ; Thu, 21 Jun 2018 01:53:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9E4D528A5C; Thu, 21 Jun 2018 01:53:12 +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=-7.9 required=2.0 tests=BAYES_00, 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 D282F28A4C for ; Thu, 21 Jun 2018 01:53:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754572AbeFUBxI (ORCPT ); Wed, 20 Jun 2018 21:53:08 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:36951 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754464AbeFUBxB (ORCPT ); Wed, 20 Jun 2018 21:53:01 -0400 Received: by mail-pf0-f195.google.com with SMTP id y5-v6so684101pfn.4 for ; Wed, 20 Jun 2018 18:53:00 -0700 (PDT) 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=93CgxeywGrGMB06DUJT8XMEVmNlriJEOmS/HPBt2YBc=; b=NbL9I0nfyG0FV7stbCxSkuYv1bHUyoqHndcimWQSUxK+ypUaP6xohXmMNqI1OzsikC czmOAqSlon3LgMsSBu2aFZBh2PzFNOrW4GFlRxzaKNeb0vDBV8fp+60Qz++tSZkXrkik cCIg+hzk4jqn2wwKBBxMQU3CvpykJg3pK2MTeLQprhQrFfW8nts9/2+2mw+IMGg/5w/U 6i0DKdNQqYk6O3dMgBoDIDDX0hSoxM0iW7bFGWP2+rdd6i4pBdEmDJV9fv6hVsBJ3dHC 1aCbTP4pvGnJblIpuqIjMeKZb5YxfgETfucGsiEu0G5f+rtmbv0uKggQk2qzsTN+NsR6 KZrQ== X-Gm-Message-State: APt69E0nh2yFvuw2jeN9hLUvE4gLM1/vGF2lyHE9eV0cTUaXqRZTio+I DuLh2to9uDg2eEHVyAllgxB0tg== X-Google-Smtp-Source: ADUXVKLSJF7h7JssCKbm2JsiFnaXjRRs+aA4qlpspCr0NyPkdvtep50oh4m5LQbpOEX5kj1s8VMzRA== X-Received: by 2002:aa7:80cf:: with SMTP id a15-v6mr5735220pfn.19.1529545979993; Wed, 20 Jun 2018 18:52:59 -0700 (PDT) Received: from mka.mtv.corp.google.com ([2620:0:1000:1501:8e2d:4727:1211:622]) by smtp.gmail.com with ESMTPSA id p12-v6sm6585877pfi.175.2018.06.20.18.52.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 20 Jun 2018 18:52:59 -0700 (PDT) From: Matthias Kaehlcke To: MyungJoo Ham Cc: Kyungmin Park , Chanwoo Choi , Arnd Bergmann , Greg Kroah-Hartman , Rob Herring , Mark Rutland , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Norris , Douglas Anderson , Enric Balletbo i Serra , "Rafael J . Wysocki" , Viresh Kumar , Lee Jones , Benson Leung , Olof Johansson , Matthias Kaehlcke Subject: [PATCH v4 05/12] PM / devfreq: Add support for policy notifiers Date: Wed, 20 Jun 2018 18:52:30 -0700 Message-Id: <20180621015237.100100-6-mka@chromium.org> X-Mailer: git-send-email 2.18.0.rc2.346.g013aa6912e-goog In-Reply-To: <20180621015237.100100-1-mka@chromium.org> References: <20180621015237.100100-1-mka@chromium.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 Policy notifiers are called before a frequency change and may narrow the min/max frequency range in devfreq_policy, which is used to adjust the target frequency if it is beyond this range. Also add a few helpers: - devfreq_verify_within_[dev_]limits() - should be used by the notifiers for policy adjustments. - dev_to_devfreq() - lookup a devfreq strict from a device pointer Signed-off-by: Matthias Kaehlcke Reviewed-by: Brian Norris --- Changes in v4: - Fixed typo in commit message: devfreg => devfreq - added 'Reviewed-by: Brian Norris ' tag Changes in v3: - devfreq.h: fixed misspelling of struct devfreq_policy Changes in v2: - performance, powersave and simpleondemand governors don't need changes with "PM / devfreq: Don't adjust to user limits in governors" - formatting fixes --- drivers/devfreq/devfreq.c | 48 ++++++++++++++++++++++------- include/linux/devfreq.h | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 11 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 21604d6ae2b8..4cbaa7ad1972 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -72,6 +72,21 @@ static struct devfreq *find_device_devfreq(struct device *dev) return ERR_PTR(-ENODEV); } +/** + * dev_to_devfreq() - find devfreq struct using device pointer + * @dev: device pointer used to lookup device devfreq. + */ +struct devfreq *dev_to_devfreq(struct device *dev) +{ + struct devfreq *devfreq; + + mutex_lock(&devfreq_list_lock); + devfreq = find_device_devfreq(dev); + mutex_unlock(&devfreq_list_lock); + + return devfreq; +} + static unsigned long find_available_min_freq(struct devfreq *devfreq) { struct dev_pm_opp *opp; @@ -269,20 +284,21 @@ int update_devfreq(struct devfreq *devfreq) if (!policy->governor) return -EINVAL; + policy->min = policy->devinfo.min_freq; + policy->max = policy->devinfo.max_freq; + + srcu_notifier_call_chain(&devfreq->policy_notifier_list, + DEVFREQ_ADJUST, policy); + /* Reevaluate the proper frequency */ err = policy->governor->get_target_freq(devfreq, &freq); if (err) return err; - /* - * Adjust the frequency with user freq, QoS and available freq. - * - * List from the highest priority - * max_freq - * min_freq - */ - max_freq = MIN(policy->devinfo.max_freq, policy->user.max_freq); - min_freq = MAX(policy->devinfo.min_freq, policy->user.min_freq); + /* Adjust the frequency */ + + max_freq = MIN(policy->max, policy->user.max_freq); + min_freq = MAX(policy->min, policy->user.min_freq); if (freq < min_freq) { freq = min_freq; @@ -645,6 +661,7 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->last_stat_updated = jiffies; srcu_init_notifier_head(&devfreq->transition_notifier_list); + srcu_init_notifier_head(&devfreq->policy_notifier_list); mutex_unlock(&devfreq->lock); @@ -1445,7 +1462,7 @@ EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier); * devfreq_register_notifier() - Register a driver with devfreq * @devfreq: The devfreq object. * @nb: The notifier block to register. - * @list: DEVFREQ_TRANSITION_NOTIFIER. + * @list: DEVFREQ_TRANSITION_NOTIFIER or DEVFREQ_POLICY_NOTIFIER. */ int devfreq_register_notifier(struct devfreq *devfreq, struct notifier_block *nb, @@ -1461,6 +1478,10 @@ int devfreq_register_notifier(struct devfreq *devfreq, ret = srcu_notifier_chain_register( &devfreq->transition_notifier_list, nb); break; + case DEVFREQ_POLICY_NOTIFIER: + ret = srcu_notifier_chain_register( + &devfreq->policy_notifier_list, nb); + break; default: ret = -EINVAL; } @@ -1473,7 +1494,7 @@ EXPORT_SYMBOL(devfreq_register_notifier); * devfreq_unregister_notifier() - Unregister a driver with devfreq * @devfreq: The devfreq object. * @nb: The notifier block to be unregistered. - * @list: DEVFREQ_TRANSITION_NOTIFIER. + * @list: DEVFREQ_TRANSITION_NOTIFIER or DEVFREQ_POLICY_NOTIFIER. */ int devfreq_unregister_notifier(struct devfreq *devfreq, struct notifier_block *nb, @@ -1489,6 +1510,11 @@ int devfreq_unregister_notifier(struct devfreq *devfreq, ret = srcu_notifier_chain_unregister( &devfreq->transition_notifier_list, nb); break; + case DEVFREQ_POLICY_NOTIFIER: + ret = srcu_notifier_chain_unregister( + &devfreq->policy_notifier_list, nb); + break; + default: ret = -EINVAL; } diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 9bf23b976f4d..7c8dce96db73 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -33,6 +33,10 @@ #define DEVFREQ_PRECHANGE (0) #define DEVFREQ_POSTCHANGE (1) +#define DEVFREQ_POLICY_NOTIFIER 1 + +#define DEVFREQ_ADJUST 0 + struct devfreq; struct devfreq_governor; @@ -121,12 +125,16 @@ struct devfreq_freq_limits { /** * struct devfreq_policy - Devfreq policy + * @min: minimum frequency (adjustable by policy notifiers) + * @min: maximum frequency (adjustable by policy notifiers) * @user: frequency limits requested by the user * @devinfo: frequency limits of the device (available OPPs) * @governor: method how to choose frequency based on the usage. * @governor_name: devfreq governor name for use with this devfreq */ struct devfreq_policy { + unsigned long min; + unsigned long max; struct devfreq_freq_limits user; struct devfreq_freq_limits devinfo; const struct devfreq_governor *governor; @@ -155,6 +163,7 @@ struct devfreq_policy { * @time_in_state: Statistics of devfreq states * @last_stat_updated: The last time stat updated * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier + * @policy_notifier_list: list head of DEVFREQ_POLICY_NOTIFIER notifier * * This structure stores the devfreq information for a give device. * @@ -188,6 +197,7 @@ struct devfreq { unsigned long last_stat_updated; struct srcu_notifier_head transition_notifier_list; + struct srcu_notifier_head policy_notifier_list; }; struct devfreq_freqs { @@ -240,6 +250,45 @@ extern void devm_devfreq_unregister_notifier(struct device *dev, extern struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index); +/** + * devfreq_verify_within_limits() - Adjust a devfreq policy if needed to make + * sure its min/max values are within a + * specified range. + * @policy: the policy + * @min: the minimum frequency + * @max: the maximum frequency + */ +static inline void devfreq_verify_within_limits(struct devfreq_policy *policy, + unsigned int min, unsigned int max) +{ + if (policy->min < min) + policy->min = min; + if (policy->max < min) + policy->max = min; + if (policy->min > max) + policy->min = max; + if (policy->max > max) + policy->max = max; + if (policy->min > policy->max) + policy->min = policy->max; +} + +/** + * devfreq_verify_within_dev_limits() - Adjust a devfreq policy if needed to + * make sure its min/max values are within + * the frequency range supported by the + * device. + * @policy: the policy + */ +static inline void +devfreq_verify_within_dev_limits(struct devfreq_policy *policy) +{ + devfreq_verify_within_limits(policy, policy->devinfo.min_freq, + policy->devinfo.max_freq); +} + +struct devfreq *dev_to_devfreq(struct device *dev); + #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) /** * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq @@ -394,10 +443,26 @@ static inline struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, return ERR_PTR(-ENODEV); } +static inline void devfreq_verify_within_limits(struct devfreq_policy *policy, + unsigned int min, unsigned int max) +{ +} + +static inline void +devfreq_verify_within_dev_limits(struct devfreq_policy *policy) +{ +} + static inline int devfreq_update_stats(struct devfreq *df) { return -EINVAL; } + +static inline struct devfreq *dev_to_devfreq(struct device *dev) +{ + return NULL; +} + #endif /* CONFIG_PM_DEVFREQ */ #endif /* __LINUX_DEVFREQ_H__ */