From patchwork Wed Sep 12 08:28:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 10597053 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E2F2814DB for ; Wed, 12 Sep 2018 08:30:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D141329501 for ; Wed, 12 Sep 2018 08:30:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C523929976; Wed, 12 Sep 2018 08:30:18 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,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 3035E298C5 for ; Wed, 12 Sep 2018 08:30:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728166AbeILNdn (ORCPT ); Wed, 12 Sep 2018 09:33:43 -0400 Received: from mail-pf1-f193.google.com ([209.85.210.193]:45004 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727825AbeILNdn (ORCPT ); Wed, 12 Sep 2018 09:33:43 -0400 Received: by mail-pf1-f193.google.com with SMTP id k21-v6so637393pff.11 for ; Wed, 12 Sep 2018 01:30:15 -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; bh=jLrWZpb9Eb/sZJFwJhTGcqYIBmyIgGhRRYN0pKoqWKA=; b=YmHC1PAZOI5n6UI3VqrIHJ4p8xgMRpVnossmXm8Jle2pHl8PWXHaj36llHqDYiN2KB PTWnzcUG1cnAl/2AFFfkwKAffo6T1wja42+n6Z4OYgZnY2X4/TwfpsqJTujtGzdHsiqk DgbbHt4Xdmuum/ttnLST2kp98td8CPkDEc4Mc= 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=jLrWZpb9Eb/sZJFwJhTGcqYIBmyIgGhRRYN0pKoqWKA=; b=uK+Jy9rPVE8FAKGTJF6ycT/Xk6s1e7xG6+5hGFCWIUzoUe+ktbykTnLY6YJxB05Pc2 fLXaqLOylxTZUx/wU4BNZSkaPa3m5cXP08vW4/ml+y8tp/x8OM7Pth2TIM250dJJVicZ MlGBq8XeLfjAG7MDogx+APS3MBN7EwhyCQccUKKKC+t6lCtu2W8g4ugJMchre1hut+gk XiRu1ogAJVtxj1N4BLSln21VqB648HgOVPAyRK6y1vX9McFMZaQdyrs6P3scgeOwE1bd DK0sznPuosJTRoaBzXgK8MoN1acy/W/LgU4YLm5raO4uhWiPwkMPtWwY6yqrQ3SNyzWW F+wQ== X-Gm-Message-State: APzg51A6Vi9bvYTowmFyfxdSOOxhmuOK8R1Go29s2P03a4Rbze+LHaFI oJrHH2YWhst4Yiq/PLyaMnKJMg== X-Google-Smtp-Source: ANB0VdbXDZ7ee+VR8DIJ4YuVJd0a0kDQhzPkPFw73FFOtpVCGx7K31bV36yNiil4zJPdy/vfCKHZKQ== X-Received: by 2002:a62:5543:: with SMTP id j64-v6mr926879pfb.188.1536741015294; Wed, 12 Sep 2018 01:30:15 -0700 (PDT) Received: from localhost ([122.171.64.45]) by smtp.gmail.com with ESMTPSA id j16-v6sm1432654pfk.125.2018.09.12.01.30.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 12 Sep 2018 01:30:14 -0700 (PDT) From: Viresh Kumar To: niklas.cassel@linaro.org, Viresh Kumar , Nishanth Menon , Stephen Boyd Cc: Viresh Kumar , Rafael Wysocki , linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org Subject: [PATCH 09/11] OPP: Use a single mechanism to free the OPP table Date: Wed, 12 Sep 2018 13:58:48 +0530 Message-Id: X-Mailer: git-send-email 2.18.0.rc1.242.g61856ae69a2c In-Reply-To: References: 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 Currently there are two separate ways to free the OPP table based on how it is created in the first place. We call _dev_pm_opp_remove_table() to free the static and/or dynamic OPP, OPP list devices, etc. This is done for the case where the OPP table is added while initializing the OPPs, like via the path dev_pm_opp_of_add_table(). We also call dev_pm_opp_put_opp_table() in some cases which eventually frees the OPP table structure once the reference count reaches 0. This is used by the first case as well as other cases like dev_pm_opp_set_regulators() where the OPPs aren't necessarily initialized at this point. This whole thing is a bit unclear and messy and obstruct any further cleanup/fixup of OPP core. This patch tries to streamline this by keeping a single path for OPP table destruction, i.e. dev_pm_opp_put_opp_table(). All the cleanup happens in _opp_table_kref_release() now after the reference count reaches 0. _dev_pm_opp_remove_table() is removed as it isn't required anymore. We don't drop the reference to the OPP table after creating it from _of_add_opp_table_v{1|2}() anymore and the same is dropped only when we try to remove them. Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 54 ++++++++++++++-------------------------------- drivers/opp/of.c | 32 +++++++++++++++------------ drivers/opp/opp.h | 2 +- 3 files changed, 35 insertions(+), 53 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 2319ad4a0177..d3e33fd32694 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -867,23 +867,24 @@ struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev, static void _opp_table_kref_release(struct kref *kref) { struct opp_table *opp_table = container_of(kref, struct opp_table, kref); - struct opp_device *opp_dev; + struct opp_device *opp_dev, *temp; /* Release clk */ if (!IS_ERR(opp_table->clk)) clk_put(opp_table->clk); - /* - * No need to take opp_table->lock here as we are guaranteed that no - * references to the OPP table are taken at this point. - */ - opp_dev = list_first_entry(&opp_table->dev_list, struct opp_device, - node); + WARN_ON(!list_empty(&opp_table->opp_list)); - _remove_opp_dev(opp_dev, opp_table); + list_for_each_entry_safe(opp_dev, temp, &opp_table->dev_list, node) { + /* + * The OPP table is getting removed, drop the performance state + * constraints. + */ + if (opp_table->genpd_performance_state) + dev_pm_genpd_set_performance_state((struct device *)(opp_dev->dev), 0); - /* dev_list must be empty now */ - WARN_ON(!list_empty(&opp_table->dev_list)); + _remove_opp_dev(opp_dev, opp_table); + } mutex_destroy(&opp_table->lock); list_del(&opp_table->node); @@ -1758,33 +1759,6 @@ int dev_pm_opp_unregister_notifier(struct device *dev, } EXPORT_SYMBOL(dev_pm_opp_unregister_notifier); -/* - * Free OPPs either created using static entries present in DT. - */ -void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev) -{ - /* Protect dev_list */ - mutex_lock(&opp_table->lock); - - /* Find if opp_table manages a single device */ - if (list_is_singular(&opp_table->dev_list)) { - /* Free static OPPs */ - _put_opp_list_kref(opp_table); - - /* - * The OPP table is getting removed, drop the performance state - * constraints. - */ - if (opp_table->genpd_performance_state) - dev_pm_genpd_set_performance_state(dev, 0); - } else { - _put_opp_list_kref(opp_table); - _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table); - } - - mutex_unlock(&opp_table->lock); -} - void _dev_pm_opp_find_and_remove_table(struct device *dev) { struct opp_table *opp_table; @@ -1802,8 +1776,12 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev) return; } - _dev_pm_opp_remove_table(opp_table, dev); + _put_opp_list_kref(opp_table); + + /* Drop reference taken by _find_opp_table() */ + dev_pm_opp_put_opp_table(opp_table); + /* Drop reference taken while the OPP table was added */ dev_pm_opp_put_opp_table(opp_table); } diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 9c98682af374..a5cba0234220 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -407,14 +407,17 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np, opp_table = _managed_opp(opp_np); if (opp_table) { /* OPPs are already managed */ - if (!_add_opp_dev(dev, opp_table)) + if (!_add_opp_dev(dev, opp_table)) { ret = -ENOMEM; - else if (!opp_table->parsed_static_opps) - goto initialize_static_opps; - else + goto put_opp_table; + } + + if (opp_table->parsed_static_opps) { kref_get(&opp_table->list_kref); + return 0; + } - goto put_opp_table; + goto initialize_static_opps; } opp_table = dev_pm_opp_get_opp_table_indexed(dev, index); @@ -432,17 +435,15 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np, if (ret) { dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, ret); - _dev_pm_opp_remove_table(opp_table, dev); of_node_put(np); - goto put_opp_table; + goto put_list_kref; } } /* There should be one of more OPP defined */ if (WARN_ON(!count)) { ret = -ENOENT; - _put_opp_list_kref(opp_table); - goto put_opp_table; + goto put_list_kref; } list_for_each_entry(opp, &opp_table->opp_list, node) @@ -453,8 +454,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np, dev_err(dev, "Not all nodes have performance state set (%d: %d)\n", count, pstate_count); ret = -ENOENT; - _dev_pm_opp_remove_table(opp_table, dev); - goto put_opp_table; + goto put_list_kref; } if (pstate_count) @@ -462,6 +462,10 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np, opp_table->parsed_static_opps = true; + return 0; + +put_list_kref: + _put_opp_list_kref(opp_table); put_opp_table: dev_pm_opp_put_opp_table(opp_table); @@ -507,13 +511,13 @@ static int _of_add_opp_table_v1(struct device *dev) if (ret) { dev_err(dev, "%s: Failed to add OPP %ld (%d)\n", __func__, freq, ret); - _dev_pm_opp_remove_table(opp_table, dev); - break; + _put_opp_list_kref(opp_table); + dev_pm_opp_put_opp_table(opp_table); + return ret; } nr -= 2; } - dev_pm_opp_put_opp_table(opp_table); return ret; } diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 3b1d94748a4d..b260fb7b307a 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -190,11 +190,11 @@ struct opp_table { /* Routines internal to opp core */ void dev_pm_opp_get(struct dev_pm_opp *opp); +void _opp_remove_all_static(struct opp_table *opp_table); void _get_opp_table_kref(struct opp_table *opp_table); int _get_opp_count(struct opp_table *opp_table); struct opp_table *_find_opp_table(struct device *dev); struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); -void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev); void _dev_pm_opp_find_and_remove_table(struct device *dev); struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); void _opp_free(struct dev_pm_opp *opp);