From patchwork Thu Nov 27 03:24:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 41589 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ee0-f70.google.com (mail-ee0-f70.google.com [74.125.83.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 5B59325E74 for ; Thu, 27 Nov 2014 03:24:50 +0000 (UTC) Received: by mail-ee0-f70.google.com with SMTP id b57sf2650920eek.9 for ; Wed, 26 Nov 2014 19:24:49 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:in-reply-to:references :sender:precedence:list-id:x-original-sender :x-original-authentication-results:mailing-list:list-post:list-help :list-archive:list-unsubscribe; bh=mTD/XStjLM+Yq7xcVlfjB5jeuOpEbvkD2KY2UVHb9GU=; b=Td6Dj1IfTDuP0bWoA2OBOXtXNao4dOQpoy0aGxNrZDrwatHsbAHb/nsbiWuA2JSTzx NjXFhfGEvXJBVMBiKtz3N0fR/PCw15kJlZXzbL02T8j29oyGIJpMxRMTmywooSuLcy1N /av7IdytiZfWvrtsMucSqNyURhxbvIoUN7sAf2kEtvw5gxhhpdnSc5ZGJJP47RY6lBOH hvJHgV3rYGlFmR41PU1nSZgCSVC4kS4ZKEm8zCkMGLRsLLCSGiOUWXBJaJsfbJNsG4wu ko+19Ix2bG/88UKVsCYMigv5YtBeqlft2Skcm8Dk0kYquKxzxnFMoV+qpF9eUTOcPK++ tLYA== X-Gm-Message-State: ALoCoQn3kBGfB7gFygIRXknAeEQOslIy6xFOv+i9wg8Kuimk1C/IT9zJSBUvGplSYuGBZ4B8UEzH X-Received: by 10.180.101.40 with SMTP id fd8mr250518wib.5.1417058689505; Wed, 26 Nov 2014 19:24:49 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.36.138 with SMTP id q10ls786130laj.83.gmail; Wed, 26 Nov 2014 19:24:49 -0800 (PST) X-Received: by 10.152.42.132 with SMTP id o4mr3984929lal.72.1417058689344; Wed, 26 Nov 2014 19:24:49 -0800 (PST) Received: from mail-la0-f49.google.com (mail-la0-f49.google.com. [209.85.215.49]) by mx.google.com with ESMTPS id i3si1066561laa.67.2014.11.26.19.24.49 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 26 Nov 2014 19:24:49 -0800 (PST) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.49 as permitted sender) client-ip=209.85.215.49; Received: by mail-la0-f49.google.com with SMTP id hs14so3439374lab.22 for ; Wed, 26 Nov 2014 19:24:49 -0800 (PST) X-Received: by 10.112.14.69 with SMTP id n5mr36859084lbc.34.1417058689162; Wed, 26 Nov 2014 19:24:49 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.184.201 with SMTP id ew9csp738418lbc; Wed, 26 Nov 2014 19:24:48 -0800 (PST) X-Received: by 10.70.134.36 with SMTP id ph4mr11288884pdb.29.1417058687179; Wed, 26 Nov 2014 19:24:47 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id bz1si3994085pdb.123.2014.11.26.19.24.46 for ; Wed, 26 Nov 2014 19:24:47 -0800 (PST) Received-SPF: none (google.com: linux-pm-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752887AbaK0DYp (ORCPT + 12 others); Wed, 26 Nov 2014 22:24:45 -0500 Received: from mail-pa0-f54.google.com ([209.85.220.54]:39952 "EHLO mail-pa0-f54.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752681AbaK0DYp (ORCPT ); Wed, 26 Nov 2014 22:24:45 -0500 Received: by mail-pa0-f54.google.com with SMTP id fb1so4140098pad.13 for ; Wed, 26 Nov 2014 19:24:44 -0800 (PST) X-Received: by 10.70.37.79 with SMTP id w15mr13138241pdj.43.1417058684445; Wed, 26 Nov 2014 19:24:44 -0800 (PST) Received: from localhost ([122.167.111.40]) by mx.google.com with ESMTPSA id pk1sm5568407pdb.78.2014.11.26.19.24.42 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Wed, 26 Nov 2014 19:24:43 -0800 (PST) From: Viresh Kumar To: Rafael Wysocki Cc: linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org, stefan.wahren@i2se.com, nm@ti.com, linux-arm-kernel@lists.infradead.org, sudeep.holla@arm.com, paulmck@linux.vnet.ibm.com, Viresh Kumar Subject: [PATCH V2 4/8] opp: Introduce APIs to remove OPPs Date: Thu, 27 Nov 2014 08:54:06 +0530 Message-Id: <9a64eb3d9d11ff7379b7eb6d9207625175f28e47.1417058376.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.0.3.693.g996b0fd In-Reply-To: References: In-Reply-To: <1407c1d67e546a09f5dd122de943de45bcd3c846.1417058376.git.viresh.kumar@linaro.org> References: <1407c1d67e546a09f5dd122de943de45bcd3c846.1417058376.git.viresh.kumar@linaro.org> Sender: linux-pm-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: viresh.kumar@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.49 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , OPPs are created statically (from DT) or dynamically. Currently we don't free OPPs that are created statically, when the module unloads. And so if the module is inserted back again, we get warning for duplicate OPPs as the same were already present. Also, there might be a need to remove dynamic OPPs in future and so API for that is also added. This patch adds helper APIs to remove/free existing static and dynamic OPPs. Because the OPPs are used both under RCU and SRCU, we have to wait for grace period of both. And so are using kfree_rcu() from within call_srcu(). Signed-off-by: Viresh Kumar --- V1->V2: - Use kfree_rcu() instead of kfree() as OPP is accessed under rcu locks as well and so we should wait for its grace period as well. - Another patch which fixes a potential bug, 5/8. Must be applied after this patch and before the original 5/8. Total of 9 patches now. drivers/base/power/opp.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 12 +++++- 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index b249b01..977474a 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -79,6 +79,7 @@ struct dev_pm_opp { * however addition is possible and is secured by dev_opp_list_lock * @dev: device pointer * @srcu_head: notifier head to notify the OPP availability changes. + * @rcu_head: RCU callback head used for deferred freeing * @opp_list: list of opps * * This is an internal data structure maintaining the link to opps attached to @@ -90,6 +91,7 @@ struct device_opp { struct device *dev; struct srcu_notifier_head srcu_head; + struct rcu_head rcu_head; struct list_head opp_list; }; @@ -498,6 +500,76 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) } EXPORT_SYMBOL_GPL(dev_pm_opp_add); +static void kfree_opp_rcu(struct rcu_head *head) +{ + struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head); + + kfree_rcu(opp, rcu_head); +} + +static void kfree_device_rcu(struct rcu_head *head) +{ + struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head); + + kfree(device_opp); +} + +void __dev_pm_opp_remove(struct device_opp *dev_opp, struct dev_pm_opp *opp) +{ + /* + * Notify the changes in the availability of the operable + * frequency/voltage list. + */ + srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); + list_del_rcu(&opp->node); + call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu); + + if (list_empty(&dev_opp->opp_list)) { + list_del_rcu(&dev_opp->node); + call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head, + kfree_device_rcu); + } +} + +/** + * dev_pm_opp_remove() - Remove an OPP from OPP list + * @dev: device for which we do this operation + * @freq: OPP to remove with matching 'freq' + * + * This function removes an opp from the opp list. + */ +void dev_pm_opp_remove(struct device *dev, unsigned long freq) +{ + struct dev_pm_opp *opp; + struct device_opp *dev_opp; + bool found = false; + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + dev_opp = find_device_opp(dev); + if (IS_ERR(dev_opp)) + goto unlock; + + list_for_each_entry(opp, &dev_opp->opp_list, node) { + if (opp->rate == freq) { + found = true; + break; + } + } + + if (!found) { + dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n", + __func__, freq); + goto unlock; + } + + __dev_pm_opp_remove(dev_opp, opp); +unlock: + mutex_unlock(&dev_opp_list_lock); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_remove); + /** * opp_set_availability() - helper to set the availability of an opp * @dev: device for which we do this operation @@ -687,4 +759,34 @@ int of_init_opp_table(struct device *dev) return 0; } EXPORT_SYMBOL_GPL(of_init_opp_table); + +/** + * of_free_opp_table() - Free OPP table entries created from static DT entries + * @dev: device pointer used to lookup device OPPs. + * + * Free OPPs created using static entries present in DT. + */ +void of_free_opp_table(struct device *dev) +{ + struct device_opp *dev_opp = find_device_opp(dev); + struct dev_pm_opp *opp, *tmp; + + /* Check for existing list for 'dev' */ + dev_opp = find_device_opp(dev); + if (WARN(IS_ERR(dev_opp), "%s: dev_opp: %ld\n", dev_name(dev), + PTR_ERR(dev_opp))) + return; + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + /* Free static OPPs */ + list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) { + if (!opp->dynamic) + __dev_pm_opp_remove(dev_opp, opp); + } + + mutex_unlock(&dev_opp_list_lock); +} +EXPORT_SYMBOL_GPL(of_free_opp_table); #endif diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 0330217..cec2d45 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -21,7 +21,7 @@ struct dev_pm_opp; struct device; enum dev_pm_opp_event { - OPP_EVENT_ADD, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE, + OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE, }; #if defined(CONFIG_PM_OPP) @@ -44,6 +44,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt); +void dev_pm_opp_remove(struct device *dev, unsigned long freq); int dev_pm_opp_enable(struct device *dev, unsigned long freq); @@ -90,6 +91,10 @@ static inline int dev_pm_opp_add(struct device *dev, unsigned long freq, return -EINVAL; } +static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq) +{ +} + static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq) { return 0; @@ -109,11 +114,16 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier( #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) int of_init_opp_table(struct device *dev); +void of_free_opp_table(struct device *dev); #else static inline int of_init_opp_table(struct device *dev) { return -EINVAL; } + +static inline void of_free_opp_table(struct device *dev) +{ +} #endif #endif /* __LINUX_OPP_H__ */