From patchwork Mon Jul 13 17:33:56 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javi Merino X-Patchwork-Id: 6780721 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id BAEA79F434 for ; Mon, 13 Jul 2015 17:34:25 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BE4B52051C for ; Mon, 13 Jul 2015 17:34:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A093A20502 for ; Mon, 13 Jul 2015 17:34:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751712AbbGMReW (ORCPT ); Mon, 13 Jul 2015 13:34:22 -0400 Received: from foss.arm.com ([217.140.101.70]:58794 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751451AbbGMReW (ORCPT ); Mon, 13 Jul 2015 13:34:22 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 933FA75; Mon, 13 Jul 2015 10:34:43 -0700 (PDT) Received: from e104805.cambridge.arm.com (e104805.cambridge.arm.com [10.2.131.190]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 2CB843F317; Mon, 13 Jul 2015 10:34:21 -0700 (PDT) From: Javi Merino To: linux-pm@vger.kernel.org Cc: Javi Merino , MyungJoo Ham , Kyungmin Park Subject: [PATCH v2 2/4] PM / devfreq: cache the last call to get_dev_status() Date: Mon, 13 Jul 2015 18:33:56 +0100 Message-Id: <1436808838-23391-3-git-send-email-javi.merino@arm.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1436808838-23391-1-git-send-email-javi.merino@arm.com> References: <1436808838-23391-1-git-send-email-javi.merino@arm.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The return value of get_dev_status() can be reused. Cache it so that other parts of the kernel can reuse it instead of having to call the same function again. Cc: MyungJoo Ham Cc: Kyungmin Park Signed-off-by: Javi Merino --- This patch tries to let multiple components. To summarize the discussion in v1[1] I can think of three alternatives: 1) Change get_dev_status() to return absolute values for busy_time and total_time 2) Make core devfreq call get_dev_status() periodically (for example, before calling the governor) and all the entities that want access can do so via a pointer in devfreq 3) Make the simple ondemand governor call get_dev_status() periodically and cache it, forcing all the other entities to rely on that governor being active [1] http://thread.gmane.org/gmane.linux.power-management.general/61936/focus=61993 This patch implements option 3) drivers/devfreq/devfreq.c | 5 +++++ drivers/devfreq/governor_simpleondemand.c | 33 +++++++++++++++++-------------- include/linux/devfreq.h | 7 +++++++ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 5b3f2f32f1e5..83041931910f 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -810,6 +810,11 @@ unlock: } EXPORT_SYMBOL(devfreq_set_min); +int devfreq_update_stats(struct devfreq *df) +{ + return df->profile->get_dev_status(df->dev.parent, &df->last_status); +} + static ssize_t governor_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 0720ba84ca92..ae72ba5e78df 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -21,17 +21,20 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, unsigned long *freq) { - struct devfreq_dev_status stat; - int err = df->profile->get_dev_status(df->dev.parent, &stat); + int err; + struct devfreq_dev_status *stat; unsigned long long a, b; unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; struct devfreq_simple_ondemand_data *data = df->data; unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; + err = devfreq_update_stats(df); if (err) return err; + stat = &df->last_status; + if (data) { if (data->upthreshold) dfso_upthreshold = data->upthreshold; @@ -43,41 +46,41 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, return -EINVAL; /* Assume MAX if it is going to be divided by zero */ - if (stat.total_time == 0) { + if (stat->total_time == 0) { *freq = max; return 0; } /* Prevent overflow */ - if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) { - stat.busy_time >>= 7; - stat.total_time >>= 7; + if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) { + stat->busy_time >>= 7; + stat->total_time >>= 7; } /* Set MAX if it's busy enough */ - if (stat.busy_time * 100 > - stat.total_time * dfso_upthreshold) { + if (stat->busy_time * 100 > + stat->total_time * dfso_upthreshold) { *freq = max; return 0; } /* Set MAX if we do not know the initial frequency */ - if (stat.current_frequency == 0) { + if (stat->current_frequency == 0) { *freq = max; return 0; } /* Keep the current frequency */ - if (stat.busy_time * 100 > - stat.total_time * (dfso_upthreshold - dfso_downdifferential)) { - *freq = stat.current_frequency; + if (stat->busy_time * 100 > + stat->total_time * (dfso_upthreshold - dfso_downdifferential)) { + *freq = stat->current_frequency; return 0; } /* Set the desired frequency based on the load */ - a = stat.busy_time; - a *= stat.current_frequency; - b = div_u64(a, stat.total_time); + a = stat->busy_time; + a *= stat->current_frequency; + b = div_u64(a, stat->total_time); b *= 100; b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); *freq = (unsigned long) b; diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index dce82c695955..1bad6fecf285 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -161,6 +161,7 @@ struct devfreq { struct delayed_work work; unsigned long previous_freq; + struct devfreq_dev_status last_status; void *data; /* private data for governors */ @@ -206,6 +207,7 @@ extern void devm_devfreq_unregister_opp_notifier(struct device *dev, int devfreq_set_min(struct devfreq *df, unsigned long value); int devfreq_set_max(struct devfreq *df, unsigned long value); +int devfreq_update_stats(struct devfreq *df); #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) /** @@ -302,6 +304,11 @@ static inline int devfreq_set_max(struct devfreq *df, unsigned long value) { return -EINVAL; } + +static inline int devfreq_update_stats(struct devfreq *df) +{ + return -EINVAL; +} #endif /* CONFIG_PM_DEVFREQ */ #endif /* __LINUX_DEVFREQ_H__ */