From patchwork Thu Feb 7 12:22:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 10801015 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 2AE5317FB for ; Thu, 7 Feb 2019 12:23:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 19EC62D197 for ; Thu, 7 Feb 2019 12:23:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0D8C82D1A4; Thu, 7 Feb 2019 12:23:02 +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 AF7D42D19B for ; Thu, 7 Feb 2019 12:23:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727078AbfBGMXA (ORCPT ); Thu, 7 Feb 2019 07:23:00 -0500 Received: from mailout2.w1.samsung.com ([210.118.77.12]:55632 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726792AbfBGMW7 (ORCPT ); Thu, 7 Feb 2019 07:22:59 -0500 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20190207122257euoutp02cbfebf6b5bd20ea9d4ed0f3cc5f3c4f1~BFGZ5fANu2881428814euoutp02H; Thu, 7 Feb 2019 12:22:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20190207122257euoutp02cbfebf6b5bd20ea9d4ed0f3cc5f3c4f1~BFGZ5fANu2881428814euoutp02H DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1549542177; bh=kUWpkcVUcFwPK5XCeCJZ6CkDivsKpEZ5CoD7EVd/0M0=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=AaogncLy2WC6gEpHaOVPS3Fxjx6jYCPDBAr9Uy2WvjELI+f1T/HYTGx0B8VCWvJDO /ObSFbk+L3p/sGrSKB1w77swcpIvK1PhCnJPVWgFZac+56enaprgB+JXc1AkYh7AAc ReDhfDvaTPAXVhDn8wptcjBm1i+62HFjMc08WLqg= Received: from eusmges1new.samsung.com (unknown [203.254.199.242]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20190207122256eucas1p28a198b56a9a4a7925cf73a42ff389cab~BFGZcFbnL3266632666eucas1p2H; Thu, 7 Feb 2019 12:22:56 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges1new.samsung.com (EUCPMTA) with SMTP id 79.11.04441.0232C5C5; Thu, 7 Feb 2019 12:22:56 +0000 (GMT) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20190207122255eucas1p1444023f01217a43cfb958fe0bd48ef4d~BFGYwQHup0912409124eucas1p1Y; Thu, 7 Feb 2019 12:22:55 +0000 (GMT) X-AuditID: cbfec7f2-5e3ff70000001159-3b-5c5c23209155 Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 91.26.04128.F132C5C5; Thu, 7 Feb 2019 12:22:55 +0000 (GMT) Received: from AMDC2765.digital.local ([106.116.147.25]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0PMK00LA22DUXV40@eusync1.samsung.com>; Thu, 07 Feb 2019 12:22:55 +0000 (GMT) From: Marek Szyprowski To: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org Cc: Marek Szyprowski , linux-samsung-soc@vger.kernel.org, Viresh Kumar , "Rafael J . Wysocki" , Nishanth Menon , Stephen Boyd , Bartlomiej Zolnierkiewicz , Dave Gerlach , Wolfram Sang Subject: [PATCH 1/2] cpufreq: dt/ti/opp: move regulators initialization to the drivers Date: Thu, 07 Feb 2019 13:22:26 +0100 Message-id: <20190207122227.19873-2-m.szyprowski@samsung.com> X-Mailer: git-send-email 2.17.1 In-reply-to: <20190207122227.19873-1-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrDIsWRmVeSWpSXmKPExsWy7djP87oKyjExBvseiVhsnLGe1eLm1w5W i8u75rBZfO49wmgx4/w+Jou1R+6yW7z5cZbJ4szpS6wW/65tZLHY+NXDYuWJWcwO3B6bVnWy edy5tofNY8vVdhaPvi2rGD1OnnrC4nH8xnYmj8+b5ALYo7hsUlJzMstSi/TtErgyHt07y17Q 7VEx8eUVpgbGpdZdjJwcEgImEpcPvWXvYuTiEBJYwSjRN/E2lPOZUeLQtjPsMFWLN95ihUgs Y5S4eX8hVFUDk8Sb+beZQKrYBAwlut52sYHYIgJWEi/aX4EVMQs8YZLYeeMn2ChhgQiJbd8n g9ksAqoSN6ZdA7I5OHgFbCX6jwZCbJOXWL3hADOIzSlgJ9F0+jLYZgmBDWwSF//eZoMocpFY 8HIuI4QtI3F5cjcLRFEzo0T7jFnsEE4Po8TWOTugOqwlDh+/yApiMwvwSUzaNp0ZZLOEAK9E R5sQRImHxKS+21B/TmSU2PT6KtsERokFjAyrGMVTS4tz01OLDfNSy/WKE3OLS/PS9ZLzczcx AuP09L/jn3Ywfr2UdIhRgINRiYc34FZUjBBrYllxZe4hRgkOZiURXjG5mBgh3pTEyqrUovz4 otKc1OJDjNIcLErivNUMD6KFBNITS1KzU1MLUotgskwcnFINjKm/vqzZ/Wjur92P/I5JlHxV n6y5qMc330XP/fzZLeqP2QVl/UOn6mZvsViSNbnfTVwyf0l6zZxpj/uPcFdekjwtejdiyvQG fbU5/ooTvhT897ItsNlXva6Qy3jrl89tWkwON3t27+nv4DaawFc3PWuz7uQZ14tDj+qu8Fve 90hK2mbz3+SPZUosxRmJhlrMRcWJAIFsLqvPAgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrCLMWRmVeSWpSXmKPExsVy+t/xy7ryyjExBtuPmllsnLGe1eLm1w5W i8u75rBZfO49wmgx4/w+Jou1R+6yW7z5cZbJ4szpS6wW/65tZLHY+NXDYuWJWcwO3B6bVnWy edy5tofNY8vVdhaPvi2rGD1OnnrC4nH8xnYmj8+b5ALYo7hsUlJzMstSi/TtErgyHt07y17Q 7VEx8eUVpgbGpdZdjJwcEgImEos33mLtYuTiEBJYwihx59ApZginiUli4q87bCBVbAKGEl1v u8BsEQEriRftr9hBipgFnjBJPHiwlgkkISwQIdG16SM7iM0ioCpxY9o1IJuDg1fAVqL/aCDE NnmJ1RsOMIPYnAJ2Ek2nL7OC2EJAJXv+dLFMYORZwMiwilEktbQ4Nz232EivODG3uDQvXS85 P3cTIzDsth37uWUHY9e74EOMAhyMSjy8P65HxQixJpYVV+YeYpTgYFYS4RWTi4kR4k1JrKxK LcqPLyrNSS0+xCjNwaIkznveoDJKSCA9sSQ1OzW1ILUIJsvEwSnVwOg0Kd98nnZSaMNM1T9/ 6+Muztsfs3yGn3Igs6bz75rFnp+/7dRpzX7lvijnd2m65sy9t2b23RVukgxN3SuxK21erXlV o5hyPFNsy/9DAhXX1x+Q3JvkVNfUvqgk53LPKua1Cps7j0nmvWfyqHHrygp5eOVES2fRlcUc QSaNmf873DWWTPxWp8RSnJFoqMVcVJwIAC+PtUQ3AgAA X-CMS-MailID: 20190207122255eucas1p1444023f01217a43cfb958fe0bd48ef4d CMS-TYPE: 201P X-CMS-RootMailID: 20190207122255eucas1p1444023f01217a43cfb958fe0bd48ef4d References: <20190207122227.19873-1-m.szyprowski@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP dev_pm_opp_set_regulators() helper is used to assign the regulators to the used operation points. This helper however only got the names of the passed regulators and performs their initialization on its own. Change this by requiring proper regulator objects and move regulator gathering to the client drivers. This will be later needed to avoid regulator initialization in forbidden context (i.e. during early system resume, when no irqs are available yet). Both clients of the dev_pm_opp_set_regulators() function are adapted to the new signature. ti-cpufreq driver is also marked with 'suppress_bind_attrs', as it really doesn't properly support driver removal. Signed-off-by: Marek Szyprowski --- drivers/cpufreq/cpufreq-dt.c | 39 ++++++++++++++++++++++----------- drivers/cpufreq/ti-cpufreq.c | 42 ++++++++++++++++++++++++++++++------ drivers/opp/core.c | 40 ++++------------------------------ include/linux/pm_opp.h | 2 +- 4 files changed, 67 insertions(+), 56 deletions(-) diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 36a011ea0039..02a344e9d818 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -30,6 +30,7 @@ struct private_data { struct opp_table *opp_table; struct device *cpu_dev; const char *reg_name; + struct regulator *reg; bool have_static_opps; }; @@ -153,6 +154,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) struct cpufreq_frequency_table *freq_table; struct opp_table *opp_table = NULL; struct private_data *priv; + struct regulator *reg; struct device *cpu_dev; struct clk *cpu_clk; unsigned int transition_latency; @@ -188,27 +190,34 @@ static int cpufreq_init(struct cpufreq_policy *policy) fallback = true; } + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out_put_clk; + } + /* - * OPP layer will be taking care of regulators now, but it needs to know - * the name of the regulator first. + * OPP layer will be taking care of regulators. */ name = find_supply_name(cpu_dev); if (name) { - opp_table = dev_pm_opp_set_regulators(cpu_dev, &name, 1); + reg = regulator_get_optional(cpu_dev, name); + ret = PTR_ERR_OR_ZERO(reg); + if (ret) { + dev_err(cpu_dev, "Failed to get regulator for cpu%d: %d\n", + policy->cpu, ret); + goto out_free_priv; + } + priv->reg = reg; + opp_table = dev_pm_opp_set_regulators(cpu_dev, &priv->reg, 1); if (IS_ERR(opp_table)) { ret = PTR_ERR(opp_table); dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n", policy->cpu, ret); - goto out_put_clk; + goto out_put_regulator; } } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto out_put_regulator; - } - priv->reg_name = name; priv->opp_table = opp_table; @@ -287,10 +296,14 @@ static int cpufreq_init(struct cpufreq_policy *policy) out_free_opp: if (priv->have_static_opps) dev_pm_opp_of_cpumask_remove_table(policy->cpus); - kfree(priv); -out_put_regulator: +out_put_opp_regulator: if (name) dev_pm_opp_put_regulators(opp_table); +out_put_regulator: + if (priv->reg) + regulator_put(priv->reg); +out_free_priv: + kfree(priv); out_put_clk: clk_put(cpu_clk); @@ -306,6 +319,8 @@ static int cpufreq_exit(struct cpufreq_policy *policy) dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); if (priv->reg_name) dev_pm_opp_put_regulators(priv->opp_table); + if (priv->reg) + regulator_put(priv->reg); clk_put(policy->clk); kfree(priv); diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index 22b53bf26817..623ae7fa34f9 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #define REVISION_MASK 0xF @@ -213,13 +214,43 @@ static const struct of_device_id *ti_cpufreq_match_node(void) return match; } +#define TI_MULTIREGULATOR_COUNT 2 +static struct regulator *multi_regulators[TI_MULTIREGULATOR_COUNT]; + +static int ti_setup_multi_regulators(struct device *cpu_dev) +{ + struct opp_table *ti_opp_table; + int ret = 0; + + multi_regulators[0] = regulator_get(cpu_dev, "vdd"); + if (IS_ERR(multi_regulators[0])) + return PTR_ERR(multi_regulators[0]); + multi_regulators[1] = regulator_get(cpu_dev, "vbb"); + if (IS_ERR(multi_regulators[1])) { + ret = PTR_ERR(multi_regulators[1]); + goto free0; + } + + ti_opp_table = dev_pm_opp_set_regulators(cpu_dev, multi_regulators, + TI_MULTIREGULATOR_COUNT); + if (IS_ERR(ti_opp_table)) { + ret = PTR_ERR(ti_opp_table); + goto free1; + } + return 0; +free1: + regulator_put(multi_regulators[1]); +free0: + regulator_put(multi_regulators[0]); + return ret; +} + static int ti_cpufreq_probe(struct platform_device *pdev) { u32 version[VERSION_COUNT]; const struct of_device_id *match; struct opp_table *ti_opp_table; struct ti_cpufreq_data *opp_data; - const char * const reg_names[] = {"vdd", "vbb"}; int ret; match = dev_get_platdata(&pdev->dev); @@ -273,14 +304,10 @@ static int ti_cpufreq_probe(struct platform_device *pdev) } opp_data->opp_table = ti_opp_table; - if (opp_data->soc_data->multi_regulator) { - ti_opp_table = dev_pm_opp_set_regulators(opp_data->cpu_dev, - reg_names, - ARRAY_SIZE(reg_names)); - if (IS_ERR(ti_opp_table)) { + ret = ti_setup_multi_regulators(opp_data->cpu_dev); + if (ret) { dev_pm_opp_put_supported_hw(opp_data->opp_table); - ret = PTR_ERR(ti_opp_table); goto fail_put_node; } } @@ -316,6 +343,7 @@ static struct platform_driver ti_cpufreq_driver = { .driver = { .name = "ti-cpufreq", }, + .suppress_bind_attrs = true, }; builtin_platform_driver(ti_cpufreq_driver); diff --git a/drivers/opp/core.c b/drivers/opp/core.c index d7f97167cac3..fc143a38fe8d 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1477,11 +1477,10 @@ static void _free_set_opp_data(struct opp_table *opp_table) * This must be called before any OPPs are initialized for the device. */ struct opp_table *dev_pm_opp_set_regulators(struct device *dev, - const char * const names[], + struct regulator **regulators, unsigned int count) { struct opp_table *opp_table; - struct regulator *reg; int ret, i; opp_table = dev_pm_opp_get_opp_table(dev); @@ -1498,41 +1497,14 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev, if (opp_table->regulators) return opp_table; - opp_table->regulators = kmalloc_array(count, - sizeof(*opp_table->regulators), - GFP_KERNEL); - if (!opp_table->regulators) { - ret = -ENOMEM; - goto err; - } - - for (i = 0; i < count; i++) { - reg = regulator_get_optional(dev, names[i]); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - if (ret != -EPROBE_DEFER) - dev_err(dev, "%s: no regulator (%s) found: %d\n", - __func__, names[i], ret); - goto free_regulators; - } - - opp_table->regulators[i] = reg; - } - + opp_table->regulators = regulators; opp_table->regulator_count = count; /* Allocate block only once to pass to set_opp() routines */ ret = _allocate_set_opp_data(opp_table); - if (ret) - goto free_regulators; - - return opp_table; - -free_regulators: - while (i != 0) - regulator_put(opp_table->regulators[--i]); + if (ret == 0) + return opp_table; - kfree(opp_table->regulators); opp_table->regulators = NULL; opp_table->regulator_count = -1; err: @@ -1556,12 +1528,8 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table) /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); - for (i = opp_table->regulator_count - 1; i >= 0; i--) - regulator_put(opp_table->regulators[i]); - _free_set_opp_data(opp_table); - kfree(opp_table->regulators); opp_table->regulators = NULL; opp_table->regulator_count = -1; diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 24c757a32a7b..3cf24c2c4969 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -123,7 +123,7 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *ver void dev_pm_opp_put_supported_hw(struct opp_table *opp_table); struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name); void dev_pm_opp_put_prop_name(struct opp_table *opp_table); -struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count); +struct opp_table *dev_pm_opp_set_regulators(struct device *dev, struct regulator **regulators, unsigned int count); void dev_pm_opp_put_regulators(struct opp_table *opp_table); struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name); void dev_pm_opp_put_clkname(struct opp_table *opp_table); From patchwork Thu Feb 7 12:22:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 10801021 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 9B30317FB for ; Thu, 7 Feb 2019 12:23:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8BA782D197 for ; Thu, 7 Feb 2019 12:23:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7F83B2D1B7; Thu, 7 Feb 2019 12:23:10 +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=unavailable 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 BCBDD2D19B for ; Thu, 7 Feb 2019 12:23:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727102AbfBGMXB (ORCPT ); Thu, 7 Feb 2019 07:23:01 -0500 Received: from mailout1.w1.samsung.com ([210.118.77.11]:51046 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726727AbfBGMXA (ORCPT ); Thu, 7 Feb 2019 07:23:00 -0500 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20190207122257euoutp01cfe018eaf0473717aa51a5a9468f79f2~BFGalF60H0320903209euoutp015; Thu, 7 Feb 2019 12:22:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20190207122257euoutp01cfe018eaf0473717aa51a5a9468f79f2~BFGalF60H0320903209euoutp015 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1549542178; bh=XArvbsYXEnjax1JLElH4k/WeKMEkmmiOtD/osJ7OZLA=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=FjepVlNr4q5ZXBzJyjI/ws9587/t9znWglAdT4pKEAJqXmlXt482vxbasVz1sxP0m MgcEYJtjtCYHiHalGj8QmGnZSV+QP+7ypOgT4RwDY8TKoHA5d8lUi1UwOBXNLDXl8l h0UM3fEsK2kl590LRIqx6hiZSHo00s7B3OLd5pNc= Received: from eusmges3new.samsung.com (unknown [203.254.199.245]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20190207122257eucas1p2ec05c30a94b005524b868e40e3ddfbad~BFGZ6Z2x63057630576eucas1p2M; Thu, 7 Feb 2019 12:22:57 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges3new.samsung.com (EUCPMTA) with SMTP id 5E.2C.04806.0232C5C5; Thu, 7 Feb 2019 12:22:56 +0000 (GMT) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20190207122256eucas1p17e8742176bda911263d2d14d2797a886~BFGZTRuaF0917109171eucas1p1I; Thu, 7 Feb 2019 12:22:56 +0000 (GMT) X-AuditID: cbfec7f5-34dff700000012c6-6e-5c5c232052fc Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 92.26.04128.0232C5C5; Thu, 7 Feb 2019 12:22:56 +0000 (GMT) Received: from AMDC2765.digital.local ([106.116.147.25]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0PMK00LA22DUXV40@eusync1.samsung.com>; Thu, 07 Feb 2019 12:22:56 +0000 (GMT) From: Marek Szyprowski To: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org Cc: Marek Szyprowski , linux-samsung-soc@vger.kernel.org, Viresh Kumar , "Rafael J . Wysocki" , Nishanth Menon , Stephen Boyd , Bartlomiej Zolnierkiewicz , Dave Gerlach , Wolfram Sang Subject: [PATCH 2/2] cpufreq: dt: rework resources initialization Date: Thu, 07 Feb 2019 13:22:27 +0100 Message-id: <20190207122227.19873-3-m.szyprowski@samsung.com> X-Mailer: git-send-email 2.17.1 In-reply-to: <20190207122227.19873-1-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrOIsWRmVeSWpSXmKPExsWy7djP87oKyjExBstPmFlsnLGe1eLm1w5W i8u75rBZfO49wmgx4/w+Jou1R+6yW7z5cZbJ4szpS6wW/65tZLHY+NXDYuWJWcwO3B6bVnWy edy5tofNY8vVdhaPvi2rGD1OnnrC4nH8xnYmj8+b5ALYo7hsUlJzMstSi/TtErgytkzawVjQ E1TxZ7V4A+MD5y5GTg4JAROJNTd2MHcxcnEICaxglFi8YxEzSEJI4DOjxJVf1TBFB24uY4SI L2OUaGkPg2hoYJLYtnYWE0iCTcBQouttFxuILSJgJfGi/RU7SBGzwBMmiZ03fgI5HBzCAo4S 9yd6gJgsAqoSP5Zmgpi8ArYSj64XQqySl1i94QDYCZwCdhJNpy+zgkyRENjCJvHlz0RWiCIX iZUrlzBC2DISlyd3s0AUNTNKtM+YxQ7h9DBKbJ2zgw2iylri8PGLYN3MAnwSk7ZNZwbZLCHA K9HRJgRR4iHRv72PBeKxiYwSdxdMY5zAKLGAkWEVo3hqaXFuemqxcV5quV5xYm5xaV66XnJ+ 7iZGYHSe/nf86w7GfX+SDjEKcDAq8fAG3IqKEWJNLCuuzD3EKMHBrCTCKyYXEyPEm5JYWZVa lB9fVJqTWnyIUZqDRUmct5rhQbSQQHpiSWp2ampBahFMlomDU6qBMflzhIapffbEX5venFkY vf6swt1mLsM1dSc7Pm5fr3vj6KfZHz0k1WLmfJ3YwzF9faYIQ3KZ47ZXbm9Z6vKnpyt0rVQt EJ2V8r+zITvY7lK7rYP/L6E7q/tWz1Vtccw5XXR3+qTJTBbrhF4wPjJgUAuf/F/x1akft3Wf T/vrcGDt4eP7hT0cOpRYijMSDbWYi4oTAU4D7PbKAgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrILMWRmVeSWpSXmKPExsVy+t/xy7oKyjExBncfS1psnLGe1eLm1w5W i8u75rBZfO49wmgx4/w+Jou1R+6yW7z5cZbJ4szpS6wW/65tZLHY+NXDYuWJWcwO3B6bVnWy edy5tofNY8vVdhaPvi2rGD1OnnrC4nH8xnYmj8+b5ALYo7hsUlJzMstSi/TtErgytkzawVjQ E1TxZ7V4A+MD5y5GTg4JAROJAzeXMXYxcnEICSxhlPh3ZSMrhNPEJHGm5SU7SBWbgKFE19su NhBbRMBK4kX7K3aQImaBJ0wSDx6sZepi5OAQFnCUuD/RA8RkEVCV+LE0E8TkFbCVeHS9EGKX vMTqDQeYQWxOATuJptOXWUFsIaCSPX+6WCYw8ixgZFjFKJJaWpybnltspFecmFtcmpeul5yf u4kRGHDbjv3csoOx613wIUYBDkYlHt4f16NihFgTy4orcw8xSnAwK4nwisnFxAjxpiRWVqUW 5ccXleakFh9ilOZgURLnPW9QGSUkkJ5YkpqdmlqQWgSTZeLglGpg1BFsDDN+MDlVT2bCfP9N vE4zfrOcm7nFkP190sE66xLf/Onaz4vjY1duiRG4sCQ88ZDjNkYupq1nJFb2NU3ksdjSa3vs 2PFcrZIrtrfDv8w6/ezzfP4PlzKZGg8cTXn099ce1r+iEzt65u80CLH++yq7c8rzFvN1e/z5 dzqd+Gtw5uTyhRNPiSixFGckGmoxFxUnAgCHBNpUNAIAAA== X-CMS-MailID: 20190207122256eucas1p17e8742176bda911263d2d14d2797a886 CMS-TYPE: 201P X-CMS-RootMailID: 20190207122256eucas1p17e8742176bda911263d2d14d2797a886 References: <20190207122227.19873-1-m.szyprowski@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP All resources needed for driver operation (clocks and regulators) are now gathered in driver ->probe() and kept for the whole driver lifetime. This allows to get rid of the re-acquiring resources always in ->init() callback, which might be called in a context not approperiate for such operation. This fixes following warning during system suspend/resume cycle on Samsung Exynos based Odroid XU3/XU4 boards: --->8--- Enabling non-boot CPUs ... CPU1 is up CPU2 is up CPU3 is up ------------[ cut here ]------------ WARNING: CPU: 4 PID: 29 at drivers/i2c/i2c-core-base.c:1869 __i2c_transfer+0x6f8/0xa50 Modules linked in: CPU: 4 PID: 29 Comm: cpuhp/4 Tainted: G W 5.0.0-rc4-next-20190131-00024-g54b06b29cc65 #5324 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x90/0xc8) [] (dump_stack) from [] (__warn+0xf8/0x124) [] (__warn) from [] (warn_slowpath_null+0x40/0x48) [] (warn_slowpath_null) from [] (__i2c_transfer+0x6f8/0xa50) [] (__i2c_transfer) from [] (i2c_transfer+0x70/0xe4) [] (i2c_transfer) from [] (regmap_i2c_read+0x48/0x64) [] (regmap_i2c_read) from [] (_regmap_raw_read+0xf8/0x450) [] (_regmap_raw_read) from [] (_regmap_bus_read+0x38/0x68) [] (_regmap_bus_read) from [] (_regmap_read+0x60/0x250) [] (_regmap_read) from [] (regmap_read+0x3c/0x5c) [] (regmap_read) from [] (regulator_is_enabled_regmap+0x20/0x90) [] (regulator_is_enabled_regmap) from [] (_regulator_is_enabled+0x34/0x40) [] (_regulator_is_enabled) from [] (create_regulator+0x1a4/0x25c) [] (create_regulator) from [] (_regulator_get+0xe4/0x278) [] (_regulator_get) from [] (dev_pm_opp_set_regulators+0xa0/0x1c0) [] (dev_pm_opp_set_regulators) from [] (cpufreq_init+0x98/0x2d0) [] (cpufreq_init) from [] (cpufreq_online+0xc8/0x71c) [] (cpufreq_online) from [] (cpuhp_cpufreq_online+0x8/0x10) [] (cpuhp_cpufreq_online) from [] (cpuhp_invoke_callback+0xf4/0xebc) [] (cpuhp_invoke_callback) from [] (cpuhp_thread_fun+0x1d8/0x320) [] (cpuhp_thread_fun) from [] (smpboot_thread_fn+0x194/0x340) [] (smpboot_thread_fn) from [] (kthread+0x124/0x160) [] (kthread) from [] (ret_from_fork+0x14/0x20) Exception stack(0xe897dfb0 to 0xe897dff8) dfa0: 00000000 00000000 00000000 00000000 dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 irq event stamp: 3865 hardirqs last enabled at (3873): [] vprintk_emit+0x228/0x2a4 hardirqs last disabled at (3880): [] vprintk_emit+0x12c/0x2a4 softirqs last enabled at (3052): [] __do_softirq+0x3a4/0x66c softirqs last disabled at (3043): [] irq_exit+0x140/0x168 ---[ end trace db48b455d924fec2 ]--- CPU4 is up CPU5 is up CPU6 is up CPU7 is up --->8--- Signed-off-by: Marek Szyprowski --- drivers/cpufreq/cpufreq-dt.c | 134 ++++++++++++++--------------------- 1 file changed, 52 insertions(+), 82 deletions(-) diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 02a344e9d818..ef17bf29dc7c 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -29,11 +29,13 @@ struct private_data { struct opp_table *opp_table; struct device *cpu_dev; - const char *reg_name; + struct clk *clk; struct regulator *reg; bool have_static_opps; }; +static struct private_data *priv_data; + static struct freq_attr *cpufreq_dt_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, NULL, /* Extra space for boost-attr if required */ @@ -94,7 +96,7 @@ static const char *find_supply_name(struct device *dev) return name; } -static int resources_available(void) +static int get_cpu_resources(struct private_data *priv, unsigned int cpu) { struct device *cpu_dev; struct regulator *cpu_reg; @@ -102,9 +104,9 @@ static int resources_available(void) int ret = 0; const char *name; - cpu_dev = get_cpu_device(0); + cpu_dev = get_cpu_device(cpu); if (!cpu_dev) { - pr_err("failed to get cpu0 device\n"); + pr_err("failed to get cpu%d device\n", cpu); return -ENODEV; } @@ -123,12 +125,10 @@ static int resources_available(void) return ret; } - clk_put(cpu_clk); - name = find_supply_name(cpu_dev); /* Platform doesn't require regulator */ if (!name) - return 0; + goto no_regulator; cpu_reg = regulator_get_optional(cpu_dev, name); ret = PTR_ERR_OR_ZERO(cpu_reg); @@ -138,48 +138,42 @@ static int resources_available(void) * not yet registered, we should try defering probe. */ if (ret == -EPROBE_DEFER) - dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n"); + dev_dbg(cpu_dev, "regulator not ready, retry\n"); else - dev_dbg(cpu_dev, "no regulator for cpu0: %d\n", ret); - - return ret; + dev_dbg(cpu_dev, "no regulator for cpu: %d\n", ret); + goto free; } - - regulator_put(cpu_reg); +no_regulator: + priv->cpu_dev = cpu_dev; + priv->clk = cpu_clk; + priv->reg = cpu_reg; return 0; +free: + clk_put(cpu_clk); + return ret; +} + +static void put_cpu_resources(struct private_data *priv) +{ + clk_put(priv->clk); + regulator_put(priv->reg); } static int cpufreq_init(struct cpufreq_policy *policy) { struct cpufreq_frequency_table *freq_table; struct opp_table *opp_table = NULL; - struct private_data *priv; - struct regulator *reg; - struct device *cpu_dev; - struct clk *cpu_clk; + struct private_data *priv = &priv_data[policy->cpu]; + struct device *cpu_dev = priv->cpu_dev; unsigned int transition_latency; bool fallback = false; - const char *name; int ret; - cpu_dev = get_cpu_device(policy->cpu); - if (!cpu_dev) { - pr_err("failed to get cpu%d device\n", policy->cpu); - return -ENODEV; - } - - cpu_clk = clk_get(cpu_dev, NULL); - if (IS_ERR(cpu_clk)) { - ret = PTR_ERR(cpu_clk); - dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret); - return ret; - } - /* Get OPP-sharing information from "operating-points-v2" bindings */ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); if (ret) { if (ret != -ENOENT) - goto out_put_clk; + return ret; /* * operating-points-v2 not supported, fallback to old method of @@ -190,35 +184,18 @@ static int cpufreq_init(struct cpufreq_policy *policy) fallback = true; } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto out_put_clk; - } - /* * OPP layer will be taking care of regulators. */ - name = find_supply_name(cpu_dev); - if (name) { - reg = regulator_get_optional(cpu_dev, name); - ret = PTR_ERR_OR_ZERO(reg); - if (ret) { - dev_err(cpu_dev, "Failed to get regulator for cpu%d: %d\n", - policy->cpu, ret); - goto out_free_priv; - } - priv->reg = reg; + if (priv->reg) { opp_table = dev_pm_opp_set_regulators(cpu_dev, &priv->reg, 1); if (IS_ERR(opp_table)) { ret = PTR_ERR(opp_table); - dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n", - policy->cpu, ret); - goto out_put_regulator; + dev_err(cpu_dev, "Failed to set regulator for cpu: %d\n", + ret); + return ret; } } - - priv->reg_name = name; priv->opp_table = opp_table; /* @@ -264,11 +241,9 @@ static int cpufreq_init(struct cpufreq_policy *policy) goto out_free_opp; } - priv->cpu_dev = cpu_dev; policy->driver_data = priv; - policy->clk = cpu_clk; + policy->clk = priv->clk; policy->freq_table = freq_table; - policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; /* Support turbo/boost mode */ @@ -296,16 +271,8 @@ static int cpufreq_init(struct cpufreq_policy *policy) out_free_opp: if (priv->have_static_opps) dev_pm_opp_of_cpumask_remove_table(policy->cpus); -out_put_opp_regulator: - if (name) - dev_pm_opp_put_regulators(opp_table); -out_put_regulator: if (priv->reg) - regulator_put(priv->reg); -out_free_priv: - kfree(priv); -out_put_clk: - clk_put(cpu_clk); + dev_pm_opp_put_regulators(opp_table); return ret; } @@ -317,13 +284,8 @@ static int cpufreq_exit(struct cpufreq_policy *policy) dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); if (priv->have_static_opps) dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); - if (priv->reg_name) - dev_pm_opp_put_regulators(priv->opp_table); if (priv->reg) - regulator_put(priv->reg); - - clk_put(policy->clk); - kfree(priv); + dev_pm_opp_put_regulators(priv->opp_table); return 0; } @@ -344,18 +306,21 @@ static struct cpufreq_driver dt_cpufreq_driver = { static int dt_cpufreq_probe(struct platform_device *pdev) { struct cpufreq_dt_platform_data *data = dev_get_platdata(&pdev->dev); - int ret; + int i, ret; - /* - * All per-cluster (CPUs sharing clock/voltages) initialization is done - * from ->init(). In probe(), we just need to make sure that clk and - * regulators are available. Else defer probe and retry. - * - * FIXME: Is checking this only for CPU0 sufficient ? - */ - ret = resources_available(); - if (ret) - return ret; + priv_data = devm_kcalloc(&pdev->dev, num_possible_cpus(), + sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + + for (i = 0; i < num_possible_cpus(); i++) { + ret = get_cpu_resources(&priv_data[i], i); + if (ret) { + while (i-- > 0) + put_cpu_resources(&priv_data[i]); + return ret; + } + } if (data) { if (data->have_governor_per_policy) @@ -375,7 +340,12 @@ static int dt_cpufreq_probe(struct platform_device *pdev) static int dt_cpufreq_remove(struct platform_device *pdev) { + int i; + cpufreq_unregister_driver(&dt_cpufreq_driver); + for (i = 0; i < num_possible_cpus(); i++) + put_cpu_resources(&priv_data[i]); + return 0; }