From patchwork Fri Jun 29 06:19:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Viresh Kumar X-Patchwork-Id: 140500 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp450912ljj; Thu, 28 Jun 2018 23:20:15 -0700 (PDT) X-Google-Smtp-Source: AAOMgpc0JU4OTUoj9QlNrr9F9+Tla7vnuHzlbgV5yxAOPUsDdC0IQLO8UNqitc88qh/3P3ivQbe+ X-Received: by 2002:a62:c918:: with SMTP id k24-v6mr13120171pfg.160.1530253215710; Thu, 28 Jun 2018 23:20:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530253215; cv=none; d=google.com; s=arc-20160816; b=sXHy/tN1MM9Q4KboRQtXSqUUFMcUkk0BrBVqF1Kl92smvwIjAlkRlHhX0zg5I+hZlK jFJmw0O8l1+XZA04uZg/fL85raiztx4OcUiKcTgbTYO1oYWWrmGrhPeZ0T57jUZSvs5z Ph26mKpLssu4gtPtVEPbFxuZCSjc3/iRTTBiuLdQYe2BLoaopPWn6SxZjOy7VjkZraOr DUryUFnHw53YDOpjV8O/+fKDI6OvxCmEIdPQ7uXUxgM667maaFcmG2hmzPnzxQ6tuWD0 TSSpEfZm7SOzW9vGvoSz0mJOZUVNrj4vqo41eY88t6waE44352z62+grCh9U6WmySrUN 2aiA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=8ZM+uZPd8Ym3pQOe6pOL3GJlnsslpoljPMAp53e4UWo=; b=bkBKp9xUTVO3+kxTeVqwCz/GKDTgu9Qaf5V/6QuDl3qa1plBNe5Q0glC58f5aXDhIr TsoeVCR2jBZxORH/RsRrXZpquTE3Tz7EcLbVWWdIDldOpbwadL7ofaaYRFENUsdVCWkh sKncwIOb7HHccic8XsuDUCGk+OTXUxNqTMVJbQsQF6SUDlpv3PZXr709T1gzmGWPUTZr r5WYk11FIUhF6sxMLNXI0A25i3AMnVrY3oHFX7+QAL3fnPBQ/jVyFiB3Hniw4jXRx9Gl T11RRZydKLM3JHutUQM55c/sl+9tMqmTpUbI1/tZApG2tVfRseP3XlJ+1C8TBAneNEnQ 9eSw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b="E/K/Bfc5"; 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 f35-v6si8318665plh.193.2018.06.28.23.20.15; Thu, 28 Jun 2018 23:20:15 -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="E/K/Bfc5"; 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 S1754721AbeF2GUM (ORCPT + 31 others); Fri, 29 Jun 2018 02:20:12 -0400 Received: from mail-pl0-f68.google.com ([209.85.160.68]:42151 "EHLO mail-pl0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754309AbeF2GUI (ORCPT ); Fri, 29 Jun 2018 02:20:08 -0400 Received: by mail-pl0-f68.google.com with SMTP id y15-v6so2084245pll.9 for ; Thu, 28 Jun 2018 23:20:08 -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=8ZM+uZPd8Ym3pQOe6pOL3GJlnsslpoljPMAp53e4UWo=; b=E/K/Bfc58WsPRsVPdtRUpuKj5af2XXijVbChI8wWM6Ve7j4yEbTlSQUmxAlCnbnzh6 uOE/KC38oQgZomN6G+iLXF5xJMvsdOF+aI9HiGmEbIuofD0uWp+Bi7g8tUTUEeZSjuVg xgva+EZoXV5Hw/DtuLnMhsVD4+YxVBpokyAiQ= 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=8ZM+uZPd8Ym3pQOe6pOL3GJlnsslpoljPMAp53e4UWo=; b=T48J+MlQxk5o7wDTJB135jzCXJEHInS6TTj2OxKLnQSsyEDPslVRbqq/nzqykxwUMr oBy2SyNZ/wzQcfzcW0s8rSMjGSZzQMJNYhje9peRKUg44/aTBeAxdbf5QqiptS9JI4HG 7Aejkir3WXrJJAi5vcrA9vEjx0SIc0uTYyI5ZBU1VIXgvXLQtbuyUqNeb31P3vEUGpbB 5vFDrg5S1A27+EqMAztOScpFuzXWBm621rd+3AmlY6VlYVF+J0Z0bKwbin8TSkQxzIAy iXHME+osZfRwWk82tPgrLWoHRz6HthitXBzBEuuDH8TAbd9LA3/j+u21ZxnsqxMuoNMO WocQ== X-Gm-Message-State: APt69E3UKewPJ1++OHdHQNgOVlRneaeL05FSulqVpckyJmxZ6QPKLJ9j wx6LcRHgBkC3yMQSMUrWwOnIRw== X-Received: by 2002:a17:902:342:: with SMTP id 60-v6mr13596219pld.311.1530253207686; Thu, 28 Jun 2018 23:20:07 -0700 (PDT) Received: from localhost ([122.172.117.17]) by smtp.gmail.com with ESMTPSA id u21-v6sm7386537pfi.30.2018.06.28.23.20.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 28 Jun 2018 23:20:07 -0700 (PDT) From: Viresh Kumar To: Rafael Wysocki , ulf.hansson@linaro.org, Viresh Kumar , Nishanth Menon , Stephen Boyd Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Rajendra Nayak , linux-kernel@vger.kernel.org Subject: [PATCH 04/10] OPP: Populate required opp tables from "required-opps" property Date: Fri, 29 Jun 2018 11:49:34 +0530 Message-Id: X-Mailer: git-send-email 2.18.0.rc1.242.g61856ae69a2c In-Reply-To: References: 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. Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 2 + drivers/opp/of.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ drivers/opp/opp.h | 8 +++ 3 files changed, 148 insertions(+) -- 2.18.0.rc1.242.g61856ae69a2c diff --git a/drivers/opp/core.c b/drivers/opp/core.c index c0c657fdbf33..22c927c5e4ea 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -863,6 +863,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; + _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 218b8997d817..b639195a1e3d 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -70,6 +70,138 @@ static struct opp_table *_managed_opp(const struct device_node *np) return managed_table; } +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 *_get_required_opp_table(struct device_node *np) +{ + struct opp_table *opp_table, *required_opp_table = NULL; + struct dev_pm_opp *opp; + + lockdep_assert_held(&opp_table_lock); + + list_for_each_entry(opp_table, &opp_tables, node) { + mutex_lock(&opp_table->lock); + + list_for_each_entry(opp, &opp_table->opp_list, node) { + if (opp->np == np) { + /* Found required OPP table */ + if (opp_table->is_genpd) { + required_opp_table = opp_table; + break; + } + + /* + * We only support OPP of genpd's in the + * "required-opps" for now, as we don't know how + * to do DVFS for any other use cases. Error out + * if the required OPP doesn't belong to a + * genpd. + */ + pr_err("%s: required-opp doesn't belong to genpd: %pOF\n", + __func__, opp->np); + break; + } + } + + mutex_unlock(&opp_table->lock); + + if (!required_opp_table) + continue; + + _get_opp_table_kref(required_opp_table); + + return required_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] = _get_required_opp_table(required_np); + of_node_put(required_np); + + if (IS_ERR(required_opp_tables[i])) + 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) { struct device_node *np, *opp_np; @@ -103,9 +235,15 @@ void _of_init_opp_table(struct opp_table *opp_table, struct device *dev) else opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE; + _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 3cd3b7b167b5..fea70c71cc99 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -131,6 +131,9 @@ enum opp_table_access { * @clock_latency_ns_max: Max clock latency in nanoseconds. * @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. @@ -168,6 +171,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; @@ -203,8 +209,10 @@ struct opp_table *_add_opp_table(struct device *dev); #ifdef CONFIG_OF void _of_init_opp_table(struct opp_table *opp_table, struct device *dev); +void _of_clear_opp_table(struct opp_table *opp_table); #else static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev) {} +static inline void _of_clear_opp_table(struct opp_table *opp_table) {} #endif #ifdef CONFIG_DEBUG_FS