From patchwork Wed Apr 17 13:28:21 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: rajagopal.venkat@linaro.org X-Patchwork-Id: 16164 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-yh0-f70.google.com (mail-yh0-f70.google.com [209.85.213.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id E1A2523911 for ; Wed, 17 Apr 2013 13:30:40 +0000 (UTC) Received: by mail-yh0-f70.google.com with SMTP id b41sf2460909yha.1 for ; Wed, 17 Apr 2013 06:30:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:mime-version:x-beenthere:x-received:received-spf :x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-received:from:to:cc:subject:date:message-id:x-mailer :x-gm-message-state:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-google-group-id:list-post:list-help:list-archive:list-unsubscribe; bh=KdICglj82y7lS69lH5D91t31yqCb7qsET2w63YWeNGs=; b=B81ThdXHybqeS3tQ278NQvGPqYSBDrIn3cizfSEiobpsVmYVKTfZnSK75RF06+0NdR EKOvg7IvwXhqgmVXVrlFr0lS2etnSxvyy3r+J4daQrFFf4xIkN1zL6aaeE0Uq3AN3ZGe Lp71baw0peqQBXuF/6qV5FqXXWA6AWl9v0eEsj+6FAF0T9HDfoPFaCMEOscvuB2fepVe p5QR0HCR9zo/CbajWVKvorY5/gFw+EZLK4duBHwwNG/F2lrBetlKQsEEUoqVDAZRc7cz D2EN3XLSYSvP+oL7rmbkll+3Ve6c/I1C7ro2LY5eUEIUrEqEhTA+8VlygW/fS0WlgO+w vefQ== X-Received: by 10.236.98.105 with SMTP id u69mr3208365yhf.26.1366205405561; Wed, 17 Apr 2013 06:30:05 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.64.132 with SMTP id o4ls911391qes.11.gmail; Wed, 17 Apr 2013 06:30:05 -0700 (PDT) X-Received: by 10.52.37.109 with SMTP id x13mr4221115vdj.10.1366205405255; Wed, 17 Apr 2013 06:30:05 -0700 (PDT) Received: from mail-vb0-x232.google.com (mail-vb0-x232.google.com [2607:f8b0:400c:c02::232]) by mx.google.com with ESMTPS id ez9si3890253vdb.120.2013.04.17.06.30.05 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 17 Apr 2013 06:30:05 -0700 (PDT) Received-SPF: neutral (google.com: 2607:f8b0:400c:c02::232 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=2607:f8b0:400c:c02::232; Received: by mail-vb0-f50.google.com with SMTP id w15so1249470vbb.37 for ; Wed, 17 Apr 2013 06:30:05 -0700 (PDT) X-Received: by 10.220.175.3 with SMTP id v3mr4836665vcz.8.1366205405093; Wed, 17 Apr 2013 06:30:05 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.58.127.98 with SMTP id nf2csp73643veb; Wed, 17 Apr 2013 06:30:04 -0700 (PDT) X-Received: by 10.68.40.200 with SMTP id z8mr8922999pbk.210.1366205403580; Wed, 17 Apr 2013 06:30:03 -0700 (PDT) Received: from mail-da0-x231.google.com (mail-da0-x231.google.com [2607:f8b0:400e:c00::231]) by mx.google.com with ESMTPS id bf9si6842615pad.110.2013.04.17.06.30.02 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 17 Apr 2013 06:30:03 -0700 (PDT) Received-SPF: neutral (google.com: 2607:f8b0:400e:c00::231 is neither permitted nor denied by best guess record for domain of rajagopal.venkat@linaro.org) client-ip=2607:f8b0:400e:c00::231; Received: by mail-da0-f49.google.com with SMTP id t11so780551daj.8 for ; Wed, 17 Apr 2013 06:30:02 -0700 (PDT) X-Received: by 10.66.251.161 with SMTP id zl1mr8847627pac.54.1366205402815; Wed, 17 Apr 2013 06:30:02 -0700 (PDT) Received: from localhost.localdomain ([101.63.179.42]) by mx.google.com with ESMTPS id t1sm7155869pab.12.2013.04.17.06.29.56 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 17 Apr 2013 06:30:02 -0700 (PDT) From: Rajagopal Venkat To: myungjoo.ham@samsung.com, rjw@sisk.pl, Kevin Hilman , Alan Stern Cc: patches@linaro.org, linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Rajagopal Venkat Subject: [PATCH V3] PM / devfreq: tie suspend/resume to runtime-pm Date: Wed, 17 Apr 2013 18:58:21 +0530 Message-Id: <1366205301-4249-1-git-send-email-rajagopal.venkat@linaro.org> X-Mailer: git-send-email 1.7.10.4 X-Gm-Message-State: ALoCoQmNFVK/hzMg+cxQSh6ejJdUnhYkN6B0zWqhRbECLJgkKX1lHIBJzBF1mb0JBcNB2ZM4peR2 X-Original-Sender: rajagopal.venkat@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 2607:f8b0:400c:c02::232 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Devfreq core runtime suspend/resume of a device is explicitly handled by devfreq driver using devfreq_suspend_device() and devfreq_resume_device() apis typically called from runtime suspend/resume callbacks. This patch aims to take away this from devfreq drivers and handle it from runtime-pm core. So that devfreq core runtime suspend/resume of a device is automatically done with runtime pm suspend/resume. The devfreq drivers shouldn't be concerned on when to suspend/resume the devfreq. This patch is targeted to handle devfreq core load monitoring runtime suspend/resume only. Not the actual hardware itself. All the resources like clocks and regulators must still be handled by device driver using runtime-pm. The sequence of devfreq and device runtime suspend/resume is, pm_runtime_suspend(dev) will first suspend device devfreq (if available) before device is suspended to ensure devfreq load monitoring is stopped and no device resources like clocks are accessed while device suspend is in progress. pm_runtime_resume(dev) will resume device devfreq(if available) after device is resumed to ensure device resources like clocks are ready for use. As devfreq runtime suspend/resume is done automatically from runtime core, this patch removes the existing devfreq_suspend_device() and devfreq_resume_device() apis. Signed-off-by: Rajagopal Venkat ---- Changes from V2: Updated change log to clarify patch deals with runtime suspend/resume Changes from v1: Improved change log and code comments Added NULL check for devfreq runtime-pm callbacks --- drivers/base/power/runtime.c | 21 ++++++++++++- drivers/devfreq/devfreq.c | 69 +++++++++++++++++++++++++++++++++++++++--- include/linux/devfreq.h | 18 +++-------- include/linux/pm.h | 2 ++ 4 files changed, 91 insertions(+), 19 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3148b10..2438abc 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "power.h" static int rpm_resume(struct device *dev, int rpmflags); @@ -406,6 +407,14 @@ static int rpm_suspend(struct device *dev, int rpmflags) __update_runtime_status(dev, RPM_SUSPENDING); + /* + * Try suspending devfreq before device is runtime suspended. + * It wouldn't make sense to continue devfreq load monitoring + * when device is runtime suspended. + */ + if (dev->power.devfreq && dev->power.devfreq->runtime_suspend) + dev->power.devfreq->runtime_suspend(dev); + if (dev->pm_domain) callback = dev->pm_domain->ops.runtime_suspend; else if (dev->type && dev->type->pm) @@ -421,8 +430,12 @@ static int rpm_suspend(struct device *dev, int rpmflags) callback = dev->driver->pm->runtime_suspend; retval = rpm_callback(callback, dev); - if (retval) + if (retval) { + /* Resume back devfreq on device suspend failure */ + if (dev->power.devfreq && dev->power.devfreq->runtime_resume) + dev->power.devfreq->runtime_resume(dev); goto fail; + } no_callback: __update_runtime_status(dev, RPM_SUSPENDED); @@ -661,6 +674,12 @@ static int rpm_resume(struct device *dev, int rpmflags) __update_runtime_status(dev, RPM_ACTIVE); if (parent) atomic_inc(&parent->power.child_count); + /* + * Resume devfreq after runtime resume sequence to ensure + * device resources are available for devfreq load monitoring. + */ + if (dev->power.devfreq && dev->power.devfreq->runtime_resume) + dev->power.devfreq->runtime_resume(dev); } wake_up_all(&dev->power.wait_queue); diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 44c4079..b8dab0d 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "governor.h" static struct class *devfreq_class; @@ -42,6 +43,9 @@ static LIST_HEAD(devfreq_governor_list); static LIST_HEAD(devfreq_list); static DEFINE_MUTEX(devfreq_list_lock); +static void devfreq_runtime_suspend(struct device *dev); +static void devfreq_runtime_resume(struct device *dev); + /** * find_device_devfreq() - find devfreq struct using device pointer * @dev: device pointer used to lookup device devfreq. @@ -387,6 +391,8 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, */ static void _remove_devfreq(struct devfreq *devfreq, bool skip) { + unsigned long flags; + mutex_lock(&devfreq_list_lock); if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { mutex_unlock(&devfreq_list_lock); @@ -400,6 +406,10 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip) devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL); + spin_lock_irqsave(&devfreq->dev.parent->power.lock, flags); + devfreq->dev.parent->power.devfreq = NULL; + spin_unlock_irqrestore(&devfreq->dev.parent->power.lock, flags); + if (devfreq->profile->exit) devfreq->profile->exit(devfreq->dev.parent); @@ -442,6 +452,7 @@ struct devfreq *devfreq_add_device(struct device *dev, { struct devfreq *devfreq; struct devfreq_governor *governor; + unsigned long flags; int err = 0; if (!dev || !profile || !governor_name) { @@ -476,6 +487,12 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->previous_freq = profile->initial_freq; devfreq->data = data; devfreq->nb.notifier_call = devfreq_notifier_call; + devfreq->runtime_suspend = devfreq_runtime_suspend; + devfreq->runtime_resume = devfreq_runtime_resume; + spin_lock_irqsave(&dev->power.lock, flags); + dev->power.devfreq = devfreq; + spin_unlock_irqrestore(&dev->power.lock, flags); + devfreq->trans_table = devm_kzalloc(dev, sizeof(unsigned int) * devfreq->profile->max_state * @@ -549,7 +566,7 @@ EXPORT_SYMBOL(devfreq_remove_device); * (e.g., runtime_suspend, suspend) of the device driver that * holds the devfreq. */ -int devfreq_suspend_device(struct devfreq *devfreq) +static int devfreq_suspend_device(struct devfreq *devfreq) { if (!devfreq) return -EINVAL; @@ -560,7 +577,6 @@ int devfreq_suspend_device(struct devfreq *devfreq) return devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_SUSPEND, NULL); } -EXPORT_SYMBOL(devfreq_suspend_device); /** * devfreq_resume_device() - Resume devfreq of a device. @@ -570,7 +586,7 @@ EXPORT_SYMBOL(devfreq_suspend_device); * (e.g., runtime_resume, resume) of the device driver that * holds the devfreq. */ -int devfreq_resume_device(struct devfreq *devfreq) +static int devfreq_resume_device(struct devfreq *devfreq) { if (!devfreq) return -EINVAL; @@ -581,7 +597,52 @@ int devfreq_resume_device(struct devfreq *devfreq) return devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_RESUME, NULL); } -EXPORT_SYMBOL(devfreq_resume_device); + +/** + * devfreq_runtime_suspend() - Suspend devfreq of a device. + * @dev: the device associated with devfreq + * + * This function is intended to be called by the runtime-pm + * core when the device associated with devfreq is + * runtime suspended. + */ +static void devfreq_runtime_suspend(struct device *dev) +{ + struct devfreq *devfreq; + int err; + + mutex_lock(&devfreq_list_lock); + devfreq = find_device_devfreq(dev); + mutex_unlock(&devfreq_list_lock); + + err = devfreq_suspend_device(devfreq); + if (err) + dev_err(dev, "devfreq runtime suspend failed with (%d) error\n", + err); +} + +/** + * devfreq_runtime_resume() - Resume devfreq of a device. + * @dev: the device associated with devfreq + * + * This function is intended to be called by the runtime-pm + * core when the device associated with devfreq is + * runtime resumed. + */ +static void devfreq_runtime_resume(struct device *dev) +{ + struct devfreq *devfreq; + int err; + + mutex_lock(&devfreq_list_lock); + devfreq = find_device_devfreq(dev); + mutex_unlock(&devfreq_list_lock); + + err = devfreq_resume_device(devfreq); + if (err) + dev_err(dev, "devfreq runtime resume failed with (%d) error\n", + err); +} /** * devfreq_add_governor() - Add devfreq governor diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 5f1ab92..669368b 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -140,6 +140,8 @@ struct devfreq_governor { * @trans_table: Statistics of devfreq transitions * @time_in_state: Statistics of devfreq states * @last_stat_updated: The last time stat updated + * @runtime_suspend: func to runtime suspend devfreq from runtime core + * @runtime_resume: func to runtime resume devfreq from runtime core * * This structure stores the devfreq information for a give device. * @@ -173,6 +175,8 @@ struct devfreq { unsigned int *trans_table; unsigned long *time_in_state; unsigned long last_stat_updated; + void (*runtime_suspend)(struct device *dev); + void (*runtime_resume)(struct device *dev); }; #if defined(CONFIG_PM_DEVFREQ) @@ -182,10 +186,6 @@ extern struct devfreq *devfreq_add_device(struct device *dev, void *data); extern int devfreq_remove_device(struct devfreq *devfreq); -/* Supposed to be called by PM_SLEEP/PM_RUNTIME callbacks */ -extern int devfreq_suspend_device(struct devfreq *devfreq); -extern int devfreq_resume_device(struct devfreq *devfreq); - /* Helper functions for devfreq user device driver with OPP. */ extern struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags); @@ -228,16 +228,6 @@ static inline int devfreq_remove_device(struct devfreq *devfreq) return 0; } -static inline int devfreq_suspend_device(struct devfreq *devfreq) -{ - return 0; -} - -static inline int devfreq_resume_device(struct devfreq *devfreq) -{ - return 0; -} - static inline struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags) { diff --git a/include/linux/pm.h b/include/linux/pm.h index 03d7bb1..734449c 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -40,6 +40,7 @@ extern void (*pm_power_off_prepare)(void); */ struct device; +struct devfreq; #ifdef CONFIG_PM extern const char power_group_name[]; /* = "power" */ @@ -549,6 +550,7 @@ struct dev_pm_info { #endif struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ struct dev_pm_qos *qos; + struct devfreq *devfreq; /* device devfreq */ }; extern void update_pm_runtime_accounting(struct device *dev);