From patchwork Sun Sep 24 20:00:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 114146 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp1853938qgf; Sun, 24 Sep 2017 13:00:53 -0700 (PDT) X-Received: by 10.84.132.104 with SMTP id 95mr5549999ple.231.1506283253335; Sun, 24 Sep 2017 13:00:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506283253; cv=none; d=google.com; s=arc-20160816; b=nmhUH5vN8X0Q0MUyEuG2UVAOC7vSAT4frH+u69tYf49GvUEKWCDyuiORrstfCi5WcX yavP2arsiqWkUbt5sc+YahLW8uDSN4VYB/i+mwAIMEGDI0EwTWwNYW7Y0d7t0X2/mc2Z zu5Hzki7bPKyHv2rhs7Kd6LuEfqFN/Mdax63t+ZpP+QjUyYbtpxgGt0KBvwEAkSJ8Hfr JSVVEYKhFZjB7Q1F/OARLOqOK2THqCKrdY80ceUwa5B0qHv3EoxvjXp/rHxRP8bYBmGv tAYQ4rT6bNHXSU8AbjAaDZSlz1PFKD3Y1Z/xe+uVR2Zhz2t62QoZnq54ZsinAKafpRqw JdlQ== 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=iaE7PxSH5wW5fB975G6L2rlKMRUJ2aj/nK+NcjD57mg=; b=Fu73VGwVmAXOPwt7oA1MtU4+t+U9trSelZt6T3772dvNztHsj7TNq7K+qLGRiuS0UL U8qwfARQXElE38KDr1epB11NiOu+Bxptdb8H0pOQz9PZc2GRdtX1u0oEQzxPH/+tq54m rf3NHbIIKhLiQdnMoS84GMKR8PB8EWJiKQsotoKmbjt9sfmsvkaBXq1TqVBkRsgKdwHd zypaV3HEdwX14cJ+7N1pG13d/R6sS+aOYv7LFguYYs5ZMB7SIW78WtOY0dzen2yJnKbu 112x20TfTMzLmjNIBCBLdTEejilWKj9zlSv4Y1hGF9G1cJvtx8KrPNyWxZ6c7guk5ftD w2uw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=oAURrvBr; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d9si2938674pfl.0.2017.09.24.13.00.53; Sun, 24 Sep 2017 13:00:53 -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=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=oAURrvBr; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752965AbdIXUAu (ORCPT + 26 others); Sun, 24 Sep 2017 16:00:50 -0400 Received: from mail-wr0-f170.google.com ([209.85.128.170]:53883 "EHLO mail-wr0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752919AbdIXUAp (ORCPT ); Sun, 24 Sep 2017 16:00:45 -0400 Received: by mail-wr0-f170.google.com with SMTP id l22so4666469wrc.10 for ; Sun, 24 Sep 2017 13:00:44 -0700 (PDT) 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=iaE7PxSH5wW5fB975G6L2rlKMRUJ2aj/nK+NcjD57mg=; b=oAURrvBrRY+aufJBijJ+60azHbweBGJBy1TDLstdy7/leTAnsoXJPt22D1NxRWuOz9 S17soN64MMFJrUGze2K+WeCCsrCYucu5k4WGYJ/GmhM/QIPPKObjcp+aVawSJGW5VsHO e0ANgqwbM9JzSB8vgICADjgATJegaD1u4ofdPQr+gAcEXLXghBlu2rjcjSOS1LFiWsU8 gZ2bvnnVTwkBKHikTYjmNtAQrQj5Apw+91bhCM0v/UaU0JHwNlcdnazlVa3X6PFUculZ 80UXPyNHsyFNbY0roez/9qg4nU23WGwRMnBVQK7V7ABy1bYCdABx8g7YWLUNcXkHePki +ygg== 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=iaE7PxSH5wW5fB975G6L2rlKMRUJ2aj/nK+NcjD57mg=; b=ozZ0r6QQASwQTNj6eGE8zIlmd2XQFGTOKBvR+1bTIrwO4RbSlvGbAiU82wzueMSiyz Mra5TlY/9n5pQ5yCV+mAS9W0PE8pLuGosOmZedEO6yrM2NTAYaJzcYxFWwD3FV66/luS KULfWSv60NLK3pagPOqB/NKxZQGxRqMvDHKG1YTC8M4i9Zgo63dzGbJu0IYUNMMRLAEV VMJfRY6V145Qr9jrqlCnvcebtP/GTl5Up/zLv+oEBir9huOkN3rgLUlgOZSD4OD0kScg pft8RGTwF72ee98qFpmYnIfYmgkyJW9eW3pkoGnciIycY0ulD1cK/coeC3PjGY4UoAwB MF2g== X-Gm-Message-State: AHPjjUik/LJxl/FbaVcSqCiO+C1iJ4YaDggDG8byfrrvP/6MsECh1EPw 4h/qaQO/xEtdgXlQwEUmjqPC5w== X-Google-Smtp-Source: AOwi7QAIdzcewS8LJenfZ9F93CaRvBssCD7f/y4C5GgKuNNUADaPmJAaOBEvR2cAkqceVobf+We5FA== X-Received: by 10.223.160.170 with SMTP id m39mr3894501wrm.174.1506283243813; Sun, 24 Sep 2017 13:00:43 -0700 (PDT) Received: from localhost.localdomain (cag06-3-82-243-161-21.fbx.proxad.net. [82.243.161.21]) by smtp.googlemail.com with ESMTPSA id j5sm6786144wmg.8.2017.09.24.13.00.42 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 24 Sep 2017 13:00:43 -0700 (PDT) From: Jerome Brunet To: Stephen Boyd , Michael Turquette Cc: Jerome Brunet , linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org, Russell King , Linus Walleij , Quentin Schulz , Kevin Hilman Subject: [PATCH v4 06/10] clk: add clock protection mechanism to clk core Date: Sun, 24 Sep 2017 22:00:26 +0200 Message-Id: <20170924200030.6227-7-jbrunet@baylibre.com> X-Mailer: git-send-email 2.13.5 In-Reply-To: <20170924200030.6227-1-jbrunet@baylibre.com> References: <20170924200030.6227-1-jbrunet@baylibre.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The patch adds clk_core_protect and clk_core_unprotect to the internal CCF API. These functions allow to set a new constraint along the clock tree to prevent any change, even indirect, which may result in rate change or glitch. Signed-off-by: Jerome Brunet --- drivers/clk/clk.c | 119 ++++++++++++++++++++++++++++++++++++++++--- include/linux/clk-provider.h | 1 + 2 files changed, 113 insertions(+), 7 deletions(-) -- 2.13.5 diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 44022299741a..9d371088bb24 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -60,6 +60,7 @@ struct clk_core { bool orphan; unsigned int enable_count; unsigned int prepare_count; + unsigned int protect_count; unsigned long min_rate; unsigned long max_rate; unsigned long accuracy; @@ -148,6 +149,11 @@ static void clk_enable_unlock(unsigned long flags) spin_unlock_irqrestore(&enable_lock, flags); } +static bool clk_core_rate_is_protected(struct clk_core *core) +{ + return core->protect_count; +} + static bool clk_core_is_prepared(struct clk_core *core) { /* @@ -328,6 +334,11 @@ bool clk_hw_is_prepared(const struct clk_hw *hw) return clk_core_is_prepared(hw->core); } +bool clk_hw_rate_is_protected(const struct clk_hw *hw) +{ + return clk_core_rate_is_protected(hw->core); +} + bool clk_hw_is_enabled(const struct clk_hw *hw) { return clk_core_is_enabled(hw->core); @@ -466,6 +477,68 @@ EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest); /*** clk api ***/ +static void clk_core_rate_unprotect(struct clk_core *core) +{ + lockdep_assert_held(&prepare_lock); + + if (!core) + return; + + if (WARN_ON(core->protect_count == 0)) + return; + + if (--core->protect_count > 0) + return; + + clk_core_rate_unprotect(core->parent); +} + +static int clk_core_rate_nuke_protect(struct clk_core *core) +{ + int ret; + + lockdep_assert_held(&prepare_lock); + + if (!core) + return -EINVAL; + + if (core->protect_count == 0) + return 0; + + ret = core->protect_count; + core->protect_count = 1; + clk_core_rate_unprotect(core); + + return ret; +} + +static void clk_core_rate_protect(struct clk_core *core) +{ + lockdep_assert_held(&prepare_lock); + + if (!core) + return; + + if (core->protect_count == 0) + clk_core_rate_protect(core->parent); + + core->protect_count++; +} + +static void clk_core_rate_restore_protect(struct clk_core *core, int count) +{ + lockdep_assert_held(&prepare_lock); + + if (!core) + return; + + if (count == 0) + return; + + clk_core_rate_protect(core); + core->protect_count = count; +} + static void clk_core_unprepare(struct clk_core *core) { lockdep_assert_held(&prepare_lock); @@ -843,7 +916,9 @@ static int clk_core_determine_round_nolock(struct clk_core *core, if (!core) return 0; - if (core->ops->determine_rate) { + if (clk_core_rate_is_protected(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, @@ -1585,7 +1660,7 @@ static void clk_change_rate(struct clk_core *core) static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core, unsigned long req_rate) { - int ret; + int ret, cnt; struct clk_rate_request req; lockdep_assert_held(&prepare_lock); @@ -1593,11 +1668,19 @@ static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core, if (!core) return 0; + /* simulate what the rate would be if it could be freely set */ + cnt = clk_core_rate_nuke_protect(core); + if (cnt < 0) + return cnt; + clk_core_get_boundaries(core, &req.min_rate, &req.max_rate); req.rate = req_rate; ret = clk_core_round_rate_nolock(core, &req); + /* restore the protection */ + clk_core_rate_restore_protect(core, cnt); + return ret ? 0 : req.rate; } @@ -1616,6 +1699,10 @@ static int clk_core_set_rate_nolock(struct clk_core *core, if (rate == clk_core_get_rate_nolock(core)) return 0; + /* fail on a direct rate set of a protected provider */ + if (clk_core_rate_is_protected(core)) + return -EBUSY; + if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count) return -EBUSY; @@ -1853,6 +1940,9 @@ static int clk_core_set_parent_nolock(struct clk_core *core, if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count) return -EBUSY; + if (clk_core_rate_is_protected(core)) + return -EBUSY; + /* try finding the new parent index */ if (parent) { p_index = clk_fetch_parent_index(core, parent); @@ -1927,6 +2017,9 @@ static int clk_core_set_phase_nolock(struct clk_core *core, int degrees) if (!core) return 0; + if (clk_core_rate_is_protected(core)) + return -EBUSY; + trace_clk_set_phase(core, degrees); if (core->ops->set_phase) @@ -2057,11 +2150,12 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, if (!c) return; - seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n", + seq_printf(s, "%*s%-*s %11d %12d %12d %11lu %10lu %-3d\n", level * 3 + 1, "", 30 - level * 3, c->name, - c->enable_count, c->prepare_count, clk_core_get_rate(c), - clk_core_get_accuracy(c), clk_core_get_phase(c)); + c->enable_count, c->prepare_count, c->protect_count, + clk_core_get_rate(c), clk_core_get_accuracy(c), + clk_core_get_phase(c)); } static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, @@ -2083,8 +2177,8 @@ static int clk_summary_show(struct seq_file *s, void *data) struct clk_core *c; struct hlist_head **lists = (struct hlist_head **)s->private; - seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n"); - seq_puts(s, "----------------------------------------------------------------------------------------\n"); + seq_puts(s, " clock enable_cnt prepare_cnt protect_cnt rate accuracy phase\n"); + seq_puts(s, "----------------------------------------------------------------------------------------------------\n"); clk_prepare_lock(); @@ -2119,6 +2213,7 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) seq_printf(s, "\"%s\": { ", c->name); seq_printf(s, "\"enable_count\": %d,", c->enable_count); seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); + seq_printf(s, "\"protect_count\": %d,", c->protect_count); seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); seq_printf(s, "\"phase\": %d", clk_core_get_phase(c)); @@ -2249,6 +2344,11 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) if (!d) goto err_out; + d = debugfs_create_u32("clk_protect_count", S_IRUGO, core->dentry, + (u32 *)&core->protect_count); + if (!d) + goto err_out; + d = debugfs_create_u32("clk_notifier_count", S_IRUGO, core->dentry, (u32 *)&core->notifier_count); if (!d) @@ -2812,6 +2912,11 @@ void clk_unregister(struct clk *clk) if (clk->core->prepare_count) pr_warn("%s: unregistering prepared clock: %s\n", __func__, clk->core->name); + + if (clk->core->protect_count) + pr_warn("%s: unregistering protected clock: %s\n", + __func__, clk->core->name); + kref_put(&clk->core->ref, __clk_release); unlock: clk_prepare_unlock(); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5100ec1b5d55..2a225a820cfe 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -744,6 +744,7 @@ unsigned long clk_hw_get_rate(const struct clk_hw *hw); unsigned long __clk_get_flags(struct clk *clk); unsigned long clk_hw_get_flags(const struct clk_hw *hw); bool clk_hw_is_prepared(const struct clk_hw *hw); +bool clk_hw_rate_is_protected(const struct clk_hw *hw); bool clk_hw_is_enabled(const struct clk_hw *hw); bool __clk_is_enabled(struct clk *clk); struct clk *__clk_lookup(const char *name);