From nobody Tue Apr 7 11:28:58 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED2443C7DEE for ; Fri, 13 Mar 2026 16:44:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773420255; cv=none; b=l6wb8nSv4o2nLbNjs+KJ8e9GFq1E1aRRmUfEmQWNKn0lLR8tv8mN7xL6sxQe3MMi6mxrNgCAV9p99YrUux73Gk97u0uIBRg9k9QoQnGH7kNT5XZ/+HZ/6JWSUgpai2YDTlAuARxEJG1+A2HoT4gfqogtzHuSSDEzlmoTSFJm/zE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773420255; c=relaxed/simple; bh=3HZ34b5RxjZz3yxu8VhkXggn5qS1EdNU7N/d70jV8Lo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Yg9aRgb1HYTBgHbBaJAtBAPWr8klOvX7GpNp3VsgvqnCq+lt8zLNh69/V0P6N2lrC7tkXkRjCRcnUyqtiJtlMFXz9lYm28heQNs6J7CBP73/SkAd9QSHiXP7W89S0rzbLspxAxgskpokEm2tEnCdqRw+ElASkNibu7s222xv6aM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Kvs4LssY; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=uBhCtgrb; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Kvs4LssY"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="uBhCtgrb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1773420251; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0MzZNWt8SDmgVcI7d1QBn6un9/v91BS/JCKV7h/4LU0=; b=Kvs4LssYQa5sdlQuUp2lY8aXt143LclGFCeFYUW5tKf9GP8tyMy4woqJ3ojaSNtl2zTN6A L7umbyooqBxknDDs6yY4HJosN8uGmceXSFCnQb6K7kt/J/ElbEcF6SPsQ1ei6wIp1LcGiI EfHm3LlUKl2ZWyx53Acw3LGxaIcxu2g= Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-54-zMjGLPbjOzGFwYoSnsU5VA-1; Fri, 13 Mar 2026 12:44:10 -0400 X-MC-Unique: zMjGLPbjOzGFwYoSnsU5VA-1 X-Mimecast-MFC-AGG-ID: zMjGLPbjOzGFwYoSnsU5VA_1773420250 Received: by mail-qk1-f197.google.com with SMTP id af79cd13be357-8cd849cd562so1468322485a.0 for ; Fri, 13 Mar 2026 09:44:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1773420250; x=1774025050; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=0MzZNWt8SDmgVcI7d1QBn6un9/v91BS/JCKV7h/4LU0=; b=uBhCtgrb9cZ4119fUGZ6Is+A1lr7ZNBpFgBOMpF5Qkr/4INpAu3nv9ugGmQjWxvaM4 hZhSNDPqV+fIEevkkUQzLpoAcFtPA6JG5d/UmZVB/3TtatG0PyKfpHucmN2HuaXAK+0V UADumFFfEflf056Y9pXU6BAqZiKesQYOViKMMDXbSIzusLcHmaduPkT3tvDAdEyLV27e R7CuwvHCP0lwWTqQPeOSVJTMrLMJ7fHczzaSWBFOeCpR+dfh1B015gGrlXkaoBkljcjT MU8gPRN8qzJznznlf2OHPZwSofkCHrSnvW5chFC2L5lBI4uMONtdnGLlz2xTkj+iSYEv eqfg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773420250; x=1774025050; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=0MzZNWt8SDmgVcI7d1QBn6un9/v91BS/JCKV7h/4LU0=; b=s/8OfIHKgDDw0b4b1dT/SyyelKp9xfb4KHcOs7NNLWQOlRPsFA6YXKBEKoocImL+O6 Z8bw6n1J7CyySga6DSYYemTn1KgDbnbfcLUnyw7ned3l3OOQRd4YEnG5DwhUK1z9NJjm /7+oFZrbsEL2tNBaAomJt/uBHAM2a7NJFYWeMNJfgvGUA+YgJsko4KS7K3Lem+IeBVIf +5NTxG94xyPCNTP/hEbnvsC+7BpXVzwuTMCu/jPIbeb6+Dri4Hd9kDYH9gKuU0wLzUiG KAWbcnO66NEs+tGF2tTzC6c9R/wzUiLUQ4fyvNa77DWrsdZW4sqVeKYdcrcxiCoieWzQ ogzg== X-Forwarded-Encrypted: i=1; AJvYcCUSkd3b/6ovF5qsUzWPIeqO/LJPPTTVlUi4DQ5hFRg0GROhKEyKNKYuCjdTLn3qW5dLSO2PAPWSALUzX+U=@vger.kernel.org X-Gm-Message-State: AOJu0YzYbggFbD/XXP2Tcl/6OPXThdnF0dd+TU0hgaHzc+H7Xwc+vUQm DQHaM5kW7TRbiwOHlt2dPkQ8J/7keIVNrukjC9dUnZfLyuXzuo0YIxoFUHzwBwZi7aQZpfR07rH WngEM9ZVtPdnfjY+2wlHEYAaQ72BmziPBdtH/qSc0R9C0loIrFdDLQ6FeYcg+pyPJ9bbGZGy0Yw == X-Gm-Gg: ATEYQzzap3PBN+43VdQdNexKgEEyjhBNh91hFWORd8KQsJvzqfpywiI2VhVyU9k0DYY yqBBjYAKpDQloBjj68kIIDk+kl6MUKDfIArLWT23ms6Jm4PklJhaAluAR3JCtJa6M5TKi4Q5+NK LlUU9vge0oTNwg6jTdS/ScuTvb2HWsxvuyVJ8+VCz3HaC+Xj7U+guKy04mlRNC9K9MkiPsqyaSm JKV/5O+TUYKfrgrjeNyTuHd2G41cPCUb9ZKx2e0E7PySG/+58EW7aVxDK3KLgs8MeIv38HfR/vF mHv9DTobofprEi9uIh9H07WFTodGN8C1I0TqnKqvao3h+qdZjd+FqG7k/7zpicu8XBKXD3vGnn8 ThuhXlO9OC81k707m+fXI3Sm7gt9XvFWn6N61ZEGBg6npFXP8iIkUxeFHxz9x X-Received: by 2002:a05:620a:448c:b0:8cd:8751:2b26 with SMTP id af79cd13be357-8cdb5ba2501mr537404885a.58.1773420250206; Fri, 13 Mar 2026 09:44:10 -0700 (PDT) X-Received: by 2002:a05:620a:448c:b0:8cd:8751:2b26 with SMTP id af79cd13be357-8cdb5ba2501mr537402385a.58.1773420249790; Fri, 13 Mar 2026 09:44:09 -0700 (PDT) Received: from [192.168.1.3] (c-73-183-52-120.hsd1.pa.comcast.net. [73.183.52.120]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8cda215c2a9sm587964785a.46.2026.03.13.09.44.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 13 Mar 2026 09:44:09 -0700 (PDT) From: Brian Masney Date: Fri, 13 Mar 2026 12:43:12 -0400 Subject: [PATCH v6 5/7] clk: introduce new flag CLK_V2_RATE_NEGOTIATION for sensitive clocks Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260313-clk-scaling-v6-5-ce89968c5247@redhat.com> References: <20260313-clk-scaling-v6-0-ce89968c5247@redhat.com> In-Reply-To: <20260313-clk-scaling-v6-0-ce89968c5247@redhat.com> To: Michael Turquette , Stephen Boyd , Maxime Ripard , Alberto Ruiz Cc: linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Masney X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7718; i=bmasney@redhat.com; s=20250903; h=from:subject:message-id; bh=3HZ34b5RxjZz3yxu8VhkXggn5qS1EdNU7N/d70jV8Lo=; b=owGbwMvMwCW2/dJd9di6A+2Mp9WSGDK32J1ZtXDtV+ve6dXSq3iMeJLiF8t8YNzTscN05YRoe 8FunvfLOkpZGMS4GGTFFFmW5BoVRKSusr13R5MFZg4rE8gQBi5OAZiI8WyGfzorb0x6m/pjweLz c/guFJV/22vtsXw2n7Zg3Y23l9nk3G8zMjTJSVy+IfAyZYX/YZaUrBuiHOeu8HmxW2bOusflmOu czQsA X-Developer-Key: i=bmasney@redhat.com; a=openpgp; fpr=A46D32705865AA3DDEDC2904B7D2DD275D7EC087 As demonstrated by the kunit tests, clk_calc_subtree() in the clk core can overwrite a sibling clk with the parent rate. Clocks that are used for some subsystems like DRM and sound are particularly sensitive to this issue. I consider this to be a logic bug in the clk subsystem, however this functionality has existed since the clk core was introduced with commit b2476490ef11 ("clk: introduce the common clock framework"), and some boards are unknowingly dependent on this behavior. Let's add support for a v2 rate negotiation logic that addresses the logic error. Clks can opt into this new behavior by adding the flag CLK_V2_RATE_NEGOTIATION, or globally on all clks with the kernel parameter clk_v2_rate_negotiation. Link: https://lore.kernel.org/linux-clk/aUSWU7UymULCXOeF@redhat.com/ Link: https://lpc.events/event/19/contributions/2152/ Signed-off-by: Brian Masney --- drivers/clk/clk.c | 70 ++++++++++++++++++++++++++++++++++++----= ---- include/linux/clk-provider.h | 3 ++ 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 051fe755e3bf1b0a06db254b92f8a02889456db9..64c6de5ff5df2117b8d1aca663d= 40b41d974bf92 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -886,6 +886,43 @@ unsigned long clk_hw_get_children_lcm(struct clk_hw *h= w, struct clk_hw *requesti } EXPORT_SYMBOL_GPL(clk_hw_get_children_lcm); =20 +static bool clk_v2_rate_negotiation_enabled; +static int __init clk_v2_rate_negotiation_setup(char *__unused) +{ + clk_v2_rate_negotiation_enabled =3D true; + return 1; +} +__setup("clk_v2_rate_negotiation", clk_v2_rate_negotiation_setup); + +/** + * clk_has_v2_rate_negotiation - Check if a clk should use v2 rate negotia= tion + * @core: The clock core to check + * + * This function recursively checks if the clk or any of its descendants h= ave + * the CLK_V2_RATE_NEGOTIATION flag set. The v2 behavior can also be enabl= ed + * globally by adding clk_v2_rate_negotiation to the kernel command line. + * + * Returns: true if the v2 logic should be used; false otherwise + */ +bool clk_has_v2_rate_negotiation(const struct clk_core *core) +{ + struct clk_core *child; + + if (clk_v2_rate_negotiation_enabled) + return true; + + if (core->flags & CLK_V2_RATE_NEGOTIATION) + return true; + + hlist_for_each_entry(child, &core->children, child_node) { + if (clk_has_v2_rate_negotiation(child)) + return true; + } + + return false; +} +EXPORT_SYMBOL_GPL(clk_has_v2_rate_negotiation); + /* * __clk_mux_determine_rate - clk_ops::determine_rate implementation for a= mux type clk * @hw: mux type clk to determine rate on @@ -2293,7 +2330,8 @@ static int __clk_speculate_rates(struct clk_core *cor= e, } =20 static void clk_calc_subtree(struct clk_core *core, unsigned long new_rate, - struct clk_core *new_parent, u8 p_index) + struct clk_core *new_parent, u8 p_index, + struct clk_core *initiating_clk) { struct clk_core *child; =20 @@ -2306,8 +2344,12 @@ static void clk_calc_subtree(struct clk_core *core, = unsigned long new_rate, new_parent->new_child =3D core; =20 hlist_for_each_entry(child, &core->children, child_node) { - child->new_rate =3D clk_recalc(child, new_rate); - clk_calc_subtree(child, child->new_rate, NULL, 0); + if (child !=3D initiating_clk && clk_has_v2_rate_negotiation(child)) + child->new_rate =3D child->rate; + else + child->new_rate =3D clk_recalc(child, new_rate); + + clk_calc_subtree(child, child->new_rate, NULL, 0, initiating_clk); } } =20 @@ -2316,7 +2358,8 @@ static void clk_calc_subtree(struct clk_core *core, u= nsigned long new_rate, * changed. */ static struct clk_core *clk_calc_new_rates(struct clk_core *core, - unsigned long rate) + unsigned long rate, + struct clk_core *initiating_clk) { struct clk_core *top =3D core; struct clk_core *old_parent, *parent; @@ -2364,7 +2407,7 @@ static struct clk_core *clk_calc_new_rates(struct clk= _core *core, return NULL; } else { /* pass-through clock with adjustable parent */ - top =3D clk_calc_new_rates(parent, rate); + top =3D clk_calc_new_rates(parent, rate, initiating_clk); new_rate =3D parent->new_rate; goto out; } @@ -2389,10 +2432,10 @@ static struct clk_core *clk_calc_new_rates(struct c= lk_core *core, =20 if ((core->flags & CLK_SET_RATE_PARENT) && parent && best_parent_rate !=3D parent->rate) - top =3D clk_calc_new_rates(parent, best_parent_rate); + top =3D clk_calc_new_rates(parent, best_parent_rate, initiating_clk); =20 out: - clk_calc_subtree(core, new_rate, parent, p_index); + clk_calc_subtree(core, new_rate, parent, p_index, initiating_clk); =20 return top; } @@ -2440,7 +2483,7 @@ static struct clk_core *clk_propagate_rate_change(str= uct clk_core *core, * walk down a subtree and set the new rates notifying the rate * change on the way */ -static void clk_change_rate(struct clk_core *core) +static void clk_change_rate(struct clk_core *core, struct clk_core *initia= ting_clk) { struct clk_core *child; struct hlist_node *tmp; @@ -2509,7 +2552,7 @@ static void clk_change_rate(struct clk_core *core) __clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate); =20 if (core->flags & CLK_RECALC_NEW_RATES) - (void)clk_calc_new_rates(core, core->new_rate); + (void)clk_calc_new_rates(core, core->new_rate, initiating_clk); =20 /* * Use safe iteration, as change_rate can actually swap parents @@ -2519,12 +2562,12 @@ static void clk_change_rate(struct clk_core *core) /* Skip children who will be reparented to another clock */ if (child->new_parent && child->new_parent !=3D core) continue; - clk_change_rate(child); + clk_change_rate(child, initiating_clk); } =20 /* handle the new child who might not be in core->children yet */ if (core->new_child) - clk_change_rate(core->new_child); + clk_change_rate(core->new_child, initiating_clk); =20 clk_pm_runtime_put(core); } @@ -2580,7 +2623,7 @@ static int clk_core_set_rate_nolock(struct clk_core *= core, return -EBUSY; =20 /* calculate new rates and get the topmost changed clock */ - top =3D clk_calc_new_rates(core, req_rate); + top =3D clk_calc_new_rates(core, req_rate, core); if (!top) return -EINVAL; =20 @@ -2599,7 +2642,7 @@ static int clk_core_set_rate_nolock(struct clk_core *= core, } =20 /* change the rates */ - clk_change_rate(top); + clk_change_rate(top, core); =20 core->req_rate =3D req_rate; err: @@ -3586,6 +3629,7 @@ static const struct { ENTRY(CLK_IS_CRITICAL), ENTRY(CLK_OPS_PARENT_ENABLE), ENTRY(CLK_DUTY_CYCLE_PARENT), + ENTRY(CLK_V2_RATE_NEGOTIATION), #undef ENTRY }; =20 diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 2699b9759e13d0c1f0b54f4fa4f7f7bdd42e8dde..e0fc0bd347e5920e999ac96dbed= 9fc247f9443fa 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -32,6 +32,8 @@ #define CLK_OPS_PARENT_ENABLE BIT(12) /* duty cycle call may be forwarded to the parent clock */ #define CLK_DUTY_CYCLE_PARENT BIT(13) +/* clock participates in v2 rate negotiation */ +#define CLK_V2_RATE_NEGOTIATION BIT(14) =20 struct clk; struct clk_hw; @@ -1432,6 +1434,7 @@ void clk_hw_set_rate_range(struct clk_hw *hw, unsigne= d long min_rate, unsigned long max_rate); unsigned long clk_hw_get_children_lcm(struct clk_hw *hw, struct clk_hw *re= questing_hw, unsigned long requesting_rate); +bool clk_has_v2_rate_negotiation(const struct clk_core *core); =20 static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) { --=20 2.53.0