From patchwork Thu Mar 2 17:38:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 9601887 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2A4596016C for ; Fri, 3 Mar 2017 01:19:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1C603285CC for ; Fri, 3 Mar 2017 01:19:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 10FE0285CE; Fri, 3 Mar 2017 01:19:52 +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=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID 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 4F4D1285CD for ; Fri, 3 Mar 2017 01:19:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751534AbdCCBTu (ORCPT ); Thu, 2 Mar 2017 20:19:50 -0500 Received: from mail-wr0-f172.google.com ([209.85.128.172]:34103 "EHLO mail-wr0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751635AbdCCBTs (ORCPT ); Thu, 2 Mar 2017 20:19:48 -0500 Received: by mail-wr0-f172.google.com with SMTP id l37so64283181wrc.1 for ; Thu, 02 Mar 2017 17:18:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Au1uD/J5gjMh4Us+wPeOvKYnAtcCFmq6aKB/UtHrUYg=; b=IqDCCaX5JKOrUDAz7DDXsgJclwmfQmkjCBAWBPL4k3ZsYtFe9gKFg4Bhx/8K9YNP7w vQWbCaZf1VEtMR5fpsUtwnUGTowOSe+O5cxdUuzIjk7utSo+zGtjZC73R6+gqQYtwP3R z47DIBZQBSK6xyzlrZPzUEBCcVSbxN3Vl5yV0BDdO98M/avhHZwgUW8nKhJBBW9eMGUH teG8xznRufEKBxbWN4IauXriep/8+vr4WPHNg2wUtnaCW1gdYS3RbqanZjxiYl0hlzAm XId02spJYEYtcaU3XOA012XMdjOnv0DNaA1FAc1y+EP0COfQUFgbUwvlI/Dvkkd/xz+M MYng== 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=Au1uD/J5gjMh4Us+wPeOvKYnAtcCFmq6aKB/UtHrUYg=; b=JeedsRkoG6+zr0DHawM70QkHR98eX0rucDvcOEKnpUeSaOYUxpzsWM4u5X+7WoPE9+ M91WOXvH9n2vcAeXDj0fFFVJ5Gh+MWujAaOeofP+XgokMppak6Yx4NJ6W35exxYXc8l0 agfJE8DsUXXgEGixLQmd3RTZzEz82OtgytS+078+wqDYmJzG6m9zltHKb5HVJYuY39r0 kPOxLVoYebVAzj8GL7N8IAjC+ZwtT1gaoNJetTHIxjBqiT2j+AwwDQdcNJEz1+XOjr0y rVBGEde7Nkw3jVaPlktPZFgwfZOwKMPl2srNXNwdnnfseAYJWD9wWMf4bANf72Hc9sT/ tE9A== X-Gm-Message-State: AMke39kO/N/G6p87cx9pO7q1GdnX4HLTbRa9X2IAl5l/1V1etdAchk+2ExaoXX31PSkj1CTe X-Received: by 10.223.135.8 with SMTP id a8mr15226627wra.162.1488476323716; Thu, 02 Mar 2017 09:38:43 -0800 (PST) Received: from localhost.localdomain ([90.63.244.31]) by smtp.googlemail.com with ESMTPSA id u11sm239093wrb.45.2017.03.02.09.38.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 02 Mar 2017 09:38:43 -0800 (PST) From: Jerome Brunet To: Michael Turquette , Stephen Boyd Cc: Jerome Brunet , linux-clk@vger.kernel.org, Kevin Hilman , Neil Armstrong Subject: [RFC 1/2] clk: fix CLK_SET_RATE_GATE on parent clocks Date: Thu, 2 Mar 2017 18:38:34 +0100 Message-Id: <20170302173835.18313-2-jbrunet@baylibre.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170302173835.18313-1-jbrunet@baylibre.com> References: <20170302173835.18313-1-jbrunet@baylibre.com> Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP CLK_SET_RATE_GATE flag will only prevent a consumer from directly changing the rate on the clock (if the clock is the leaf when calling clk_set_rate). However the clock rate can be changed without being gated if it is a parent of the leaf. In addition, other child clocks depending on the rate of parent clock might not appreciate. To address this issue, if the clock is busy, this patch stops the tree walk while calculating the new rates, and return the current rate as if it was fixed clock. Signed-off-by: Jerome Brunet --- drivers/clk/clk.c | 56 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0fb39fe217d1..6fe2ea81a9af 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -172,6 +172,14 @@ static bool clk_core_is_enabled(struct clk_core *core) return core->ops->is_enabled(core->hw); } +static bool clk_core_rate_can_change(struct clk_core *core) +{ + if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count) + return false; + + return true; +} + /*** helper functions ***/ const char *__clk_get_name(const struct clk *clk) @@ -833,11 +841,32 @@ static int clk_disable_unused(void) } late_initcall_sync(clk_disable_unused); +static int clk_core_round_rate_query(struct clk_core *core, + struct clk_rate_request *req) +{ + long rate; + + if (!clk_core_rate_can_change(core)) { + req->rate = core->rate; + } else if (core->ops->determine_rate) { + return core->ops->determine_rate(core->hw, req); + } else if (core->ops->round_rate) { + rate = core->ops->round_rate(core->hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + } else { + return -EINVAL; + } + + return 0; +} static int clk_core_round_rate_nolock(struct clk_core *core, struct clk_rate_request *req) { struct clk_core *parent; - long rate; lockdep_assert_held(&prepare_lock); @@ -853,15 +882,8 @@ static int clk_core_round_rate_nolock(struct clk_core *core, req->best_parent_rate = 0; } - if (core->ops->determine_rate) { - return core->ops->determine_rate(core->hw, req); - } else if (core->ops->round_rate) { - rate = core->ops->round_rate(core->hw, req->rate, - &req->best_parent_rate); - if (rate < 0) - return rate; - - req->rate = rate; + if (core->ops->determine_rate || core->ops->round_rate) { + return clk_core_round_rate_query(core, req); } else if (core->flags & CLK_SET_RATE_PARENT) { return clk_core_round_rate_nolock(parent, req); } else { @@ -1353,8 +1375,7 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, clk_core_get_boundaries(core, &min_rate, &max_rate); - /* find the closest rate and parent clk/rate */ - if (core->ops->determine_rate) { + if (core->ops->determine_rate || core->ops->round_rate) { struct clk_rate_request req; req.rate = rate; @@ -1368,22 +1389,17 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, req.best_parent_rate = 0; } - ret = core->ops->determine_rate(core->hw, &req); + ret = clk_core_round_rate_query(core, &req); if (ret < 0) return NULL; best_parent_rate = req.best_parent_rate; new_rate = req.rate; parent = req.best_parent_hw ? req.best_parent_hw->core : NULL; - } else if (core->ops->round_rate) { - ret = core->ops->round_rate(core->hw, rate, - &best_parent_rate); - if (ret < 0) - return NULL; - new_rate = ret; if (new_rate < min_rate || new_rate > max_rate) return NULL; + } else if (!parent || !(core->flags & CLK_SET_RATE_PARENT)) { /* pass-through clock without adjustable parent */ core->new_rate = core->rate; @@ -1571,7 +1587,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core, if (rate == clk_core_get_rate_nolock(core)) return 0; - if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count) + if (!clk_core_rate_can_change(core)) return -EBUSY; /* calculate new rates and get the topmost changed clock */