From patchwork Thu Oct 25 05:52:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 149515 Delivered-To: patch@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp913588ljp; Wed, 24 Oct 2018 22:53:33 -0700 (PDT) X-Google-Smtp-Source: AJdET5di5kKUP0AOIB6FFqHaSGztwBzj7ZFtCpOt3sno5yF/SiEkBcHJZKeTOrVKwspS5ZW3L+qU X-Received: by 2002:a17:902:2805:: with SMTP id e5-v6mr185239plb.169.1540446813828; Wed, 24 Oct 2018 22:53:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1540446813; cv=none; d=google.com; s=arc-20160816; b=XJ/GPxcPMXI8H828r4sduSfwZDUTBVE4c/sNFLRlMpGevfLt+pLpHaiqLngNXyDOAG zjefndmOP6Hd1CXd2sQLC4vuleHwD7JMM1AZvIY2kqJeugRqnMKptYIDYtOSsGcuw+kz FEmkH3RBF1+ckcWqaLLsa6OcW41oIqoDgj6PXrimr+a1OQBXxrKUVXoUvCTbDa4lH6lg oK0GFerZU3kwn98xtp9doQ0bFpncU6BWvhbNawRApsd8y3N/nK0bB0DD7ESJ/3Aszyve k1GPeAYSC9e0zoWtNH16l7Wwy1WWx5xDcRoI8MaakbVBA5qAQNMA5P1ZlVQIWyyDVwmc 08rw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=F8xBBQz3Vz3UwvoiZVxTM/564LZrnNByj53ag4krqco=; b=sezWD3Q4KsTARJqICQCRlMmZ0eOmMSQciY0BKPLS3thbipx4ki3o4agw7lMtbHAfjO Iu4VsptgSSsvqeIK0ZR/usr04xBUq08RAtAZ7BwL2J/jo91o6jg3xutpSGbvdSb0W8Ey 6zmSaFekpLTQ79fUkkumh7vsmG2nNfkSh0UusGSZcka/aiRPILeNvmyx7ZtpM39vVvfk H9aepHhjjEy6laa8MWbFq3QGuS9sGi6Qu58gzOEDXG48tp3Ut+9wI05Ah7kw8pBVDY1N f9V9GjKgoZJbg8fr6/hIjl+3odwnbO0+RtfYNQ3FRmRIj7mYrAoAk1sEihF/LWG5g88/ fqog== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=K3rHbutL; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i198-v6si7443500pgd.17.2018.10.24.22.53.33; Wed, 24 Oct 2018 22:53:33 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=K3rHbutL; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727461AbeJYOYk (ORCPT + 32 others); Thu, 25 Oct 2018 10:24:40 -0400 Received: from mail-pg1-f194.google.com ([209.85.215.194]:32802 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727398AbeJYOYj (ORCPT ); Thu, 25 Oct 2018 10:24:39 -0400 Received: by mail-pg1-f194.google.com with SMTP id z2-v6so3500451pgp.0 for ; Wed, 24 Oct 2018 22:53:29 -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 :mime-version:content-transfer-encoding; bh=F8xBBQz3Vz3UwvoiZVxTM/564LZrnNByj53ag4krqco=; b=K3rHbutL1/HAKJ2lweceEiVcP69NSP4LXIqIF0iFslTDVYygiTACPcAfmmXXfmHdlM 4xUUmkH49Qhloy/zycCOZgM6OdO/1nv13Fyv1hWx8Oz9HdNINpWeWAspNGghQYE2wO8m Xk7i90qPObNraHpIX1+ut4cziLDaJC2Udko2U= 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:mime-version:content-transfer-encoding; bh=F8xBBQz3Vz3UwvoiZVxTM/564LZrnNByj53ag4krqco=; b=gzMJtEFo5KwsuyRvKNLOW3mG9he6OZwJZNyLuYumTGO8fBDSK/SQIBmk/uGsT+9ozg 6PGIdCc5DRz8ZwlfSz/nOZIhWEjLrwgV6lhu9ckgbWYJm3FmbKHMC+n+G0hIzOOMNYEa 2zrhXnDbTUBLXyNY6xde9eIviPYuiLrsgZdQCHO3hf5z+OC9RyBHNzYlru0FbTykFkjm 2kS4elro5ymBkT++dhlFLM862ZGccWWKm03HG4LMYullU4rGlL6JMJgaWRaCFBAOP2b8 CcZk7UPKfSJLLgDizWLfQNu/ZBjgKns4basjTE8X/BBg8Y3W/ExW1b8ZNd1KbIBHtyHG ZaSQ== X-Gm-Message-State: AGRZ1gKw0pUKaDWFAY8sozww9OosrMZJIc7OV9o8iJQh4LrQ8EN8TGV/ KShFHHFNfRc2j2xQZodN7//sCQ== X-Received: by 2002:a63:ac46:: with SMTP id z6mr209602pgn.162.1540446808933; Wed, 24 Oct 2018 22:53:28 -0700 (PDT) Received: from localhost ([122.172.217.9]) by smtp.gmail.com with ESMTPSA id v26-v6sm8243825pfg.43.2018.10.24.22.53.27 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 24 Oct 2018 22:53:28 -0700 (PDT) From: Viresh Kumar To: ulf.hansson@linaro.org, Viresh Kumar , Nishanth Menon , Stephen Boyd Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Rafael Wysocki , niklas.cassel@linaro.org, rnayak@codeaurora.org, linux-kernel@vger.kernel.org Subject: [PATCH V3 04/10] OPP: Populate required opp tables from "required-opps" property Date: Thu, 25 Oct 2018 11:22:41 +0530 Message-Id: <345bedbbf99afac2f1c961bcbe87f7b6f53b4f8b.1540446493.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.19.1.568.g152ad8e3369a In-Reply-To: References: MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The current implementation works only for the case where a single phandle is present in the "required-opps" property, while DT allows multiple phandles to be present there. This patch adds new infrastructure to parse all the phandles present in "required-opps" property and save pointers of the required OPP's OPP tables. These will be used by later commits. Reviewed-by: Ulf Hansson Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 2 + drivers/opp/of.c | 147 +++++++++++++++++++++++++++++++++++++++++++++ drivers/opp/opp.h | 8 +++ 3 files changed, 157 insertions(+) -- 2.19.1.568.g152ad8e3369a diff --git a/drivers/opp/core.c b/drivers/opp/core.c index ebb3b648e0fd..85174a5c4850 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -901,6 +901,8 @@ 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, *temp; + _of_clear_opp_table(opp_table); + /* Release clk */ if (!IS_ERR(opp_table->clk)) clk_put(opp_table->clk); diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 5f114cd3d88c..b5605196122a 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -73,6 +73,147 @@ struct opp_table *_managed_opp(struct device *dev, int index) return managed_table; } +/* The caller must call dev_pm_opp_put() after the OPP is used */ +static struct dev_pm_opp *_find_opp_of_np(struct opp_table *opp_table, + struct device_node *opp_np) +{ + struct dev_pm_opp *opp; + + lockdep_assert_held(&opp_table_lock); + + mutex_lock(&opp_table->lock); + + list_for_each_entry(opp, &opp_table->opp_list, node) { + if (opp->np == opp_np) { + dev_pm_opp_get(opp); + mutex_unlock(&opp_table->lock); + return opp; + } + } + + mutex_unlock(&opp_table->lock); + + return NULL; +} + +static struct device_node *of_parse_required_opp(struct device_node *np, + int index) +{ + struct device_node *required_np; + + required_np = of_parse_phandle(np, "required-opps", index); + if (unlikely(!required_np)) { + pr_err("%s: Unable to parse required-opps: %pOF, index: %d\n", + __func__, np, index); + } + + return required_np; +} + +/* The caller must call dev_pm_opp_put_opp_table() after the table is used */ +static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np) +{ + struct opp_table *opp_table; + struct dev_pm_opp *opp; + + lockdep_assert_held(&opp_table_lock); + + list_for_each_entry(opp_table, &opp_tables, node) { + opp = _find_opp_of_np(opp_table, opp_np); + if (opp) { + dev_pm_opp_put(opp); + _get_opp_table_kref(opp_table); + return opp_table; + } + } + + return ERR_PTR(-ENODEV); +} + +/* Free resources previously acquired by _opp_table_alloc_required_tables() */ +static void _opp_table_free_required_tables(struct opp_table *opp_table) +{ + struct opp_table **required_opp_tables = opp_table->required_opp_tables; + int i; + + if (!required_opp_tables) + return; + + for (i = 0; i < opp_table->required_opp_count; i++) { + if (IS_ERR_OR_NULL(required_opp_tables[i])) + break; + + dev_pm_opp_put_opp_table(required_opp_tables[i]); + } + + kfree(required_opp_tables); + + opp_table->required_opp_count = 0; + opp_table->required_opp_tables = NULL; +} + +/* + * Populate all devices and opp tables which are part of "required-opps" list. + * Checking only the first OPP node should be enough. + */ +static void _opp_table_alloc_required_tables(struct opp_table *opp_table, + struct device *dev, + struct device_node *opp_np) +{ + struct opp_table **required_opp_tables; + struct device_node *required_np, *np; + int count, i; + + /* Traversing the first OPP node is all we need */ + np = of_get_next_available_child(opp_np, NULL); + if (!np) { + dev_err(dev, "Empty OPP table\n"); + return; + } + + count = of_count_phandle_with_args(np, "required-opps", NULL); + if (!count) + goto put_np; + + required_opp_tables = kcalloc(count, sizeof(*required_opp_tables), + GFP_KERNEL); + if (!required_opp_tables) + goto put_np; + + opp_table->required_opp_tables = required_opp_tables; + opp_table->required_opp_count = count; + + for (i = 0; i < count; i++) { + required_np = of_parse_required_opp(np, i); + if (!required_np) + goto free_required_tables; + + required_opp_tables[i] = _find_table_of_opp_np(required_np); + of_node_put(required_np); + + if (IS_ERR(required_opp_tables[i])) + goto free_required_tables; + + /* + * We only support genpd's OPPs in the "required-opps" for now, + * as we don't know how much about other cases. Error out if the + * required OPP doesn't belong to a genpd. + */ + if (!required_opp_tables[i]->is_genpd) { + dev_err(dev, "required-opp doesn't belong to genpd: %pOF\n", + required_np); + goto free_required_tables; + } + } + + goto put_np; + +free_required_tables: + _opp_table_free_required_tables(opp_table); +put_np: + of_node_put(np); +} + void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) { @@ -109,9 +250,15 @@ void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, opp_table->np = opp_np; + _opp_table_alloc_required_tables(opp_table, dev, opp_np); of_node_put(opp_np); } +void _of_clear_opp_table(struct opp_table *opp_table) +{ + _opp_table_free_required_tables(opp_table); +} + static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table, struct device_node *np) { diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index cdb0c2b095e2..024e1be23d37 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -133,6 +133,9 @@ enum opp_table_access { * @parsed_static_opps: True if OPPs are initialized from DT. * @shared_opp: OPP is shared between multiple devices. * @suspend_opp: Pointer to OPP to be used during device suspend. + * @required_opp_tables: List of device OPP tables that are required by OPPs in + * this table. + * @required_opp_count: Number of required devices. * @supported_hw: Array of version number to support. * @supported_hw_count: Number of elements in supported_hw array. * @prop_name: A name to postfix to many DT properties, while parsing them. @@ -172,6 +175,9 @@ struct opp_table { enum opp_table_access shared_opp; struct dev_pm_opp *suspend_opp; + struct opp_table **required_opp_tables; + unsigned int required_opp_count; + unsigned int *supported_hw; unsigned int supported_hw_count; const char *prop_name; @@ -208,9 +214,11 @@ void _put_opp_list_kref(struct opp_table *opp_table); #ifdef CONFIG_OF void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index); +void _of_clear_opp_table(struct opp_table *opp_table); struct opp_table *_managed_opp(struct device *dev, int index); #else static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {} +static inline void _of_clear_opp_table(struct opp_table *opp_table) {} static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; } #endif