From nobody Thu Apr 9 15:46:39 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 3665C2ECE91 for ; Fri, 6 Mar 2026 23:23:03 +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=1772839384; cv=none; b=FUPJhDe375pr12kR7qkZnWLPrkNlAC/azrXZoMxj6kUhf+A4AvFig9PIU+RJRKh23X2CY2RG4Qn6FIMzi87ApZV3gMqubtU8nAQMVKE5I4olbRDIURCLtqyWXBVe5V8aVEfDB0ufNmAKBst2VBa8zYnwhkv6GU+vnueXL/idHSw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772839384; c=relaxed/simple; bh=WQLAr55kMecfPqec87OVnHmOAlkPNngSPXs8OouyW28=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=W0GI7gF6A39G0mCoZL16Rb+OsRg7+9NkKOGMt9R4p0NVN7yOT6wSvHXVThWIle06bCxctf4PV+Dwsi00eIsZ6iIluOTAqHmTwpv2MHnOYZEx/JrC8HmfOMDiW5/o4d8Se4/xunpV3ZlCeSkVzAACCnD3t4GzsnwGwkOTeF9pDZA= 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=LB13DKuU; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=F/2AJ/nd; 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="LB13DKuU"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="F/2AJ/nd" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1772839382; 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=vu4zCv4Hf4czVfbvGOCZFUJkIycNVAEZUx405+keqXw=; b=LB13DKuU/+d8WAzgXy0ylwCkWEI64vmkTRCsn1dgzLkr0c+6AP89CBQlEDqZ5Ir3HpBl/W 1mry4IxNjfuACb3kBF1voRco9rzeQUs7PlKBaE87lvnekXpgAlyWWWjZEmTyA21od62CQm MCYtmKvHgNtcHT1U6XfaQDMVyEHf53Q= Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-196-X67qnzBwPE2Mtd4TCTKsWg-1; Fri, 06 Mar 2026 18:23:01 -0500 X-MC-Unique: X67qnzBwPE2Mtd4TCTKsWg-1 X-Mimecast-MFC-AGG-ID: X67qnzBwPE2Mtd4TCTKsWg_1772839381 Received: by mail-qk1-f199.google.com with SMTP id af79cd13be357-8cb42f56c4aso5509431385a.3 for ; Fri, 06 Mar 2026 15:23:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1772839381; x=1773444181; 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=vu4zCv4Hf4czVfbvGOCZFUJkIycNVAEZUx405+keqXw=; b=F/2AJ/ndwd0Lo4ajRAvJAWaymukhnkh6WRrZDULYji70VihllBMWMaOh31nOCRH9ue rQcIVVr0zSRnzVwdy5buLobkuo5NAY3Zf2uLtBJg7PW8oScdjOKm0Si8SOvf3z+Nz+qF fkG7g8ihH4UUhXMIuCzi0Ka8hA0WxYQyB9Gb+mjyM4K9ne7VoWtWs1dSrG7Pvk3XK3ns n4Odgyw5ZGmfn1/Y2Qy+VMNWVdthSLQKEzqJ///HKQm689WpQndHk3aoVJ9ZMp8rEFhs 08qhQWpFM5pv8Bo4+WKd5jIX/ymT4AUxzKuIBmcaW5XNZroRddPpZ+n4/npx31UsTqbX tZPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772839381; x=1773444181; 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=vu4zCv4Hf4czVfbvGOCZFUJkIycNVAEZUx405+keqXw=; b=a5rwjJiqlpOwqGch2rNg75ofj0MbPFLC75UttdQ7O4rtuhRiHGNXwYr0JxYr6K0PRi PqHEAKdcl2SCN6YQ9owt+NZt88PDHIQtNfpl7C3PSX609tOT5TDb9QHzTTehbhUvcVBv mOfEqNQuMjVIKLI9YksfF2v6FHI8iLy64PPCaZHSJO/EdEzlr3Ddps9zpTaRik9ojgbc Uoj6ieJ3f0wuShZpYOAIzYyJqlspe66GmDy4k+xV/Wq3TD6fh72z4JqCdmRXF8KLElpS zIvCHJZo+FuCTETSrDT9oxJ33cNUlFmTFpCe6Zv6gsub7mW15XzdyNQpuBhaHCX/CBpX hurQ== X-Forwarded-Encrypted: i=1; AJvYcCVYXKxvVePgAVok5RjT6vcOB0wpzvEw8Gkdwez+KR5OUre2G64hDA92ot6pW3EyqcJGyJjtQXj4qIJrjiw=@vger.kernel.org X-Gm-Message-State: AOJu0Yzw6DvTqtZ0mzUv8pp4IzfnLO4pYMj8M/Qel7MuNag1PnNAMJMB QGcSkQyegLol+g3vne/IXd7nYycy8ZEZk0H+mekbuVZwocn3kfee2Vpx3vWICZijRlSQNbQpx0r mm09aPomtbEV66DaWXxzY10jyCwyzkfKj03QQOQYU0c/S+v2ClboV/6M+WULM/p8xvQ== X-Gm-Gg: ATEYQzwZrtz0Mg643mICZR0AYDbnVXBx5V/S2Ct6Se5MwutxI+eNlrR6aA8uKFNNBSj 3EgcnghnceJdwY9FHTQfw/48qs8gvyBIWofRITHr3INN9VPJ9XIZNr3L+LpllzWaWxHIgF4FhJe 3O3tzzLaqQsuq/dUeSLR2h0i8yZFauqnmEHbgkTWIjzdnNaIDe9jTH2x6hPNH60jANT69VdRiRA nQh/r/Q20y3RSyjGOY1E90KQ/ca9M2qaFxIAFC+v3aJ4Z8SuCHfyNTxHXtCQbvsswMoNX6Lsupq B11J9f3D0y2wb2mMzZzQ4NrBscI5fFlUg0tq0khASd8n0yWtCF4oD0RaUBfHlMx0uDexpRFPwB/ pbIDtocXmxoG3m2WaSVxirp4Wx1MH X-Received: by 2002:a05:620a:4450:b0:8c9:eada:f3f with SMTP id af79cd13be357-8cd6d4d5f88mr480408885a.67.1772839380892; Fri, 06 Mar 2026 15:23:00 -0800 (PST) X-Received: by 2002:a05:620a:4450:b0:8c9:eada:f3f with SMTP id af79cd13be357-8cd6d4d5f88mr480406185a.67.1772839380517; Fri, 06 Mar 2026 15:23:00 -0800 (PST) Received: from [10.125.247.224] ([2600:382:772b:4f24:8140:d6ff:f19a:7e11]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8cd6f4856cesm203119585a.10.2026.03.06.15.22.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Mar 2026 15:22:59 -0800 (PST) From: Brian Masney Date: Fri, 06 Mar 2026 18:21:36 -0500 Subject: [PATCH RFC v5 1/4] clk: test: introduce clk_dummy_div for a mock divider 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: <20260306-clk-scaling-v5-1-d21b84ee6f27@redhat.com> References: <20260306-clk-scaling-v5-0-d21b84ee6f27@redhat.com> In-Reply-To: <20260306-clk-scaling-v5-0-d21b84ee6f27@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=2075; i=bmasney@redhat.com; s=20250903; h=from:subject:message-id; bh=WQLAr55kMecfPqec87OVnHmOAlkPNngSPXs8OouyW28=; b=owGbwMvMwCW2/dJd9di6A+2Mp9WSGDJXJ547mXbc9Jrfs+X/ppcermdO03h32X+zhc/6tm63l 2JK0/d+7ihlYRDjYpAVU2RZkmtUEJG6yvbeHU0WmDmsTCBDGLg4BWAik3YwMszacLveaWGawg7h Zl8VprR9fKvKrn/ru9v/3bf975aSvaaMDF8mtAvJ2ObdfiYUrywocbbBuzfsy9Gz0yPkXX/ft+a dwgoA X-Developer-Key: i=bmasney@redhat.com; a=openpgp; fpr=A46D32705865AA3DDEDC2904B7D2DD275D7EC087 This is used to mock up a divider in the clk kunit tests. Signed-off-by: Brian Masney --- drivers/clk/clk_test.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index a268d7b5d4cb28ec1f029f828c31107f8e130556..88e35f4419c958983578750356a= 97c0a45effb55 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -136,6 +136,50 @@ static const struct clk_ops clk_dummy_single_parent_op= s =3D { .get_parent =3D clk_dummy_single_get_parent, }; =20 +/* 4 ought to be enough for anybody */ +#define CLK_DUMMY_DIV_WIDTH 4 +#define CLK_DUMMY_DIV_FLAGS (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLO= SEST) + +struct clk_dummy_div { + struct clk_hw hw; + unsigned int div; +}; + +static unsigned long clk_dummy_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_dummy_div *div =3D container_of(hw, struct clk_dummy_div, hw); + + return divider_recalc_rate(hw, parent_rate, div->div, NULL, + CLK_DUMMY_DIV_FLAGS, CLK_DUMMY_DIV_WIDTH); +} + +static int clk_dummy_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && req->best_parent_rat= e < req->rate) + return -EINVAL; + + return divider_determine_rate(hw, req, NULL, CLK_DUMMY_DIV_WIDTH, CLK_DUM= MY_DIV_FLAGS); +} + +static int clk_dummy_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_dummy_div *div =3D container_of(hw, struct clk_dummy_div, hw); + + div->div =3D divider_get_val(rate, parent_rate, NULL, CLK_DUMMY_DIV_WIDTH, + CLK_DUMMY_DIV_FLAGS); + + return 0; +} + +static const struct clk_ops clk_dummy_div_ops =3D { + .recalc_rate =3D clk_dummy_div_recalc_rate, + .determine_rate =3D clk_dummy_div_determine_rate, + .set_rate =3D clk_dummy_div_set_rate, +}; + struct clk_multiple_parent_ctx { struct clk_dummy_context parents_ctx[2]; struct clk_hw hw; --=20 2.53.0 From nobody Thu Apr 9 15:46:39 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.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 7544A3783A3 for ; Fri, 6 Mar 2026 23:23:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772839390; cv=none; b=JLWXAnnjEMg2T1/nJ/QvtQQtU98GQLVR1chJlSZOQVtZI1M5yfipayGuIxvjEoNUZ11sDvXzD1hhh3B64Yp2eAynshIO5Q3FJu370DCz728ES/Xokh5vbEQfyidLrBouV2yGE1okCgus071PDr8YfPOrVIIitDr/HPfMET/CsWg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772839390; c=relaxed/simple; bh=3ug+1P6t81GTxtoTxctcDdKNVy3s+p28sSKw7y50KiM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sGhmC7VJvDmvg4/sIdpKyBKV7f6Z2LN5dDsfJ1o4FJG76L/L0ZMHkKLXLPco9IIgrsstXbvlmEHOlUN80KhUp7/bJ2/Ub7ERZBSrmMKXBwQrWLIE/ZoUWbDXaQWjnZXFLFYRHmGyQ0CodkiZtwf8HRv3dDd5ZftP5e9cIsQnl5g= 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=B456P87c; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=LKWX6FyY; arc=none smtp.client-ip=170.10.129.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="B456P87c"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="LKWX6FyY" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1772839385; 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=uK84bcQp3JfYVn07vCaAW1q8GicwEaH6/Et7bq0fcCw=; b=B456P87cf+pxnmcyzB9bsG8lHNxk0A4l7pgbbt4tvCE33WYgusPMAvlGgifjbcEOrKE8lz Nud4TaCDWuX5k3gI4aX+zAwjv4Zi80wPEa6XCr4fVtLsq1q/dOYvsD9KopINTRfqxnV4HR ND/2JB7QQeAy/v08xPdnyMXyevbQVR8= Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-3-NHvnhdVWMsuPGJ0S_mGMjA-1; Fri, 06 Mar 2026 18:23:04 -0500 X-MC-Unique: NHvnhdVWMsuPGJ0S_mGMjA-1 X-Mimecast-MFC-AGG-ID: NHvnhdVWMsuPGJ0S_mGMjA_1772839384 Received: by mail-qk1-f198.google.com with SMTP id af79cd13be357-8cb5359e9d3so5763478685a.2 for ; Fri, 06 Mar 2026 15:23:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1772839384; x=1773444184; 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=uK84bcQp3JfYVn07vCaAW1q8GicwEaH6/Et7bq0fcCw=; b=LKWX6FyYQuaN0v0qaI+itle1tlgZm/n0+vV+bpZjdPAkg/eiCw5aLOJkrZ9G0g8nys MwdWPBuNxYK3rEdFjH5uVw0N6lFuQd38ftRA+fQSASyuP2nhp19QzO7FLac4jCVDfOkD Ps2gEc6HdKxjFor3NJNwkiZCOZUX3bxveZHL5cJmaV7QDEJn+rA2g9XdNpMgIjBYSIGq Sc41N36v755UGo+oKQjvqoZztrjjFSTC34RfbX9BdMEdhkUXEsDF1hzXrpXgmoDtxYLU HWtIZ1EyE+nNGjj9QUexqo+5zLnO+GqQ3NXl4GheCSy6fptrf1s40HF5ZwBdpdVfU1vB ahAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772839384; x=1773444184; 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=uK84bcQp3JfYVn07vCaAW1q8GicwEaH6/Et7bq0fcCw=; b=tn9g28JOA8lzWaEO/INp/FqDDiG4QdIgOu1bi2zNrnWK4Mveda10nkPouB6LXRd1PH 4LHTWizs9C5hs7oC0YLf0FXzoxYd09VzpEeNyKXGtoLd/4nE7IJaPRYJecNN52oq2oHB e0TjEbMi2RSg1x/zCsmmGbhi5BM9VZfOL7rVEyr8mGrgwZ32sQuuO1anRLnuu/5xXcDs 7BFyroL2UnHwH4tVCHtleLhlr7A6T/qD1sevVQe9h24iWLIVM83MRddE0BIX8tnltOA9 eLUYinxSMll5+QF7qrvs087ZKDVOT/Ty3GugG0vNrUo538ykSoI+oHyu7KKndrhLFwbU GMvw== X-Forwarded-Encrypted: i=1; AJvYcCWA7O3+i+rYRI/TI3njr5DZj7xgQENd/sDlStuWCyjcbniZyr2uoy2Pp+m+w2/+GRqoeCljUlnHXRIDxDc=@vger.kernel.org X-Gm-Message-State: AOJu0YzyToMjGf62T04cT+7HgARCrmG9S7CoSp0D2Wn5SzqdqI0yVZp3 pzJGTGIwSVfxBb2hZhB0sWDzoEQxpwQ8v7ADKy2qz5fs7QWCll6h0tpvvfdF/s7bofXedYOahUM 71CqZuhiXWTJGp+SBk1v//xqx9PaPsY3duBdMmJB6l1GLwGcaZsnUqkiSOd0QOnNG5Q== X-Gm-Gg: ATEYQzw2yWkm97yOH22q2et5YpAOOtZXgsEnQxi3WxjDH7jxnpbUViCqVfY+XPe3kN0 Ppw+e1DA44DvcoEYzwqSblo+wT8ZWFdJ3z7pX46V0TA2kHSRdqPrYzrAyain35rSq3+PAE+yFOe q7F/NyG33kJWEWNPiJhjtD7c+X8B3cu1aFAgL2+Z1qpj0wrWh9HDLyI80nFsRWTIf6kYx3KsKxO ICfleCG/FP18cFQ41D/mJXlTokazYLMORnLTll57SoCwuNZzohDzOIt//nIHYuz/SLysTah310V +e3l7fcanWEOEEuBqUhS8gcQhpCG1lg/Xkjk2hlMv/qASQBwLRqv2fKqKiDbapIjRDemhXknGtx UTLWmMbS3WUm22cKaIvPMmzL/Qjly X-Received: by 2002:a05:620a:3911:b0:8ca:4288:b179 with SMTP id af79cd13be357-8cd6d33640cmr484143285a.5.1772839383795; Fri, 06 Mar 2026 15:23:03 -0800 (PST) X-Received: by 2002:a05:620a:3911:b0:8ca:4288:b179 with SMTP id af79cd13be357-8cd6d33640cmr484140385a.5.1772839383358; Fri, 06 Mar 2026 15:23:03 -0800 (PST) Received: from [10.125.247.224] ([2600:382:772b:4f24:8140:d6ff:f19a:7e11]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8cd6f4856cesm203119585a.10.2026.03.06.15.23.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Mar 2026 15:23:02 -0800 (PST) From: Brian Masney Date: Fri, 06 Mar 2026 18:21:37 -0500 Subject: [PATCH RFC v5 2/4] clk: test: introduce test suite for sibling rate changes on a divider 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: <20260306-clk-scaling-v5-2-d21b84ee6f27@redhat.com> References: <20260306-clk-scaling-v5-0-d21b84ee6f27@redhat.com> In-Reply-To: <20260306-clk-scaling-v5-0-d21b84ee6f27@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=8192; i=bmasney@redhat.com; s=20250903; h=from:subject:message-id; bh=3ug+1P6t81GTxtoTxctcDdKNVy3s+p28sSKw7y50KiM=; b=owGbwMvMwCW2/dJd9di6A+2Mp9WSGDJXJ55jMTQpt9ktd+/ey1MfX985XhAhxfFXuSnUc2lAZ PdzyZjfHaUsDGJcDLJiiixLco0KIlJX2d67o8kCM4eVCWQIAxenAEyk1IuRoX1x9sPAfzYzw4s7 y0pPFLCsrZXselGgoXzlDQ/LsqUdIgz/LFRKtLfHLVi0Tfg0682cIwaaT50itV0iqlpOLeCTFOP iBwA= X-Developer-Key: i=bmasney@redhat.com; a=openpgp; fpr=A46D32705865AA3DDEDC2904B7D2DD275D7EC087 Introduce a test suite that creates a parent with two divider-only children, and add kunit tests that document the current behavior when a sibling clk can unknowingly change the rate of another clk. Some boards are unknowingly dependent on this behavior, and per discussions at the 2025 Linux Plumbers Conference in Tokyo, we can't break the existing behavior. So let's add kunit tests with the current behavior so that we can be made aware if that functionality changes in the future. 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_test.c | 174 +++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 174 insertions(+) diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index 88e35f4419c958983578750356a97c0a45effb55..97cbf9dd16ee504d7687d8f0729= b6e6e22a21afb 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -652,6 +652,179 @@ clk_multiple_parents_mux_test_suite =3D { .test_cases =3D clk_multiple_parents_mux_test_cases, }; =20 +struct clk_rate_change_sibling_div_div_context { + struct clk_dummy_context parent; + struct clk_dummy_div child1, child2; + struct clk *parent_clk, *child1_clk, *child2_clk; +}; + +struct clk_rate_change_sibling_div_div_test_param { + const char *desc; + const struct clk_ops *ops; +}; + +static const struct clk_rate_change_sibling_div_div_test_param +clk_rate_change_sibling_div_div_test_regular_ops_params[] =3D { + { .desc =3D "regular_ops", .ops =3D &clk_dummy_div_ops }, +}; + +KUNIT_ARRAY_PARAM_DESC(clk_rate_change_sibling_div_div_test_regular_ops, + clk_rate_change_sibling_div_div_test_regular_ops_params, desc) + +static int clk_rate_change_sibling_div_div_test_init(struct kunit *test) +{ + const struct clk_rate_change_sibling_div_div_test_param *param =3D test->= param_value; + struct clk_rate_change_sibling_div_div_context *ctx; + int ret; + + ctx =3D kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + test->priv =3D ctx; + + ctx->parent.hw.init =3D CLK_HW_INIT_NO_PARENT("parent", &clk_dummy_rate_o= ps, 0); + ctx->parent.rate =3D 24 * HZ_PER_MHZ; + ret =3D clk_hw_register_kunit(test, NULL, &ctx->parent.hw); + if (ret) + return ret; + + ctx->child1.hw.init =3D CLK_HW_INIT_HW("child1", &ctx->parent.hw, + param->ops, CLK_SET_RATE_PARENT); + ctx->child1.div =3D 1; + ret =3D clk_hw_register_kunit(test, NULL, &ctx->child1.hw); + if (ret) + return ret; + + ctx->child2.hw.init =3D CLK_HW_INIT_HW("child2", &ctx->parent.hw, + param->ops, CLK_SET_RATE_PARENT); + ctx->child2.div =3D 1; + ret =3D clk_hw_register_kunit(test, NULL, &ctx->child2.hw); + if (ret) + return ret; + + ctx->parent_clk =3D clk_hw_get_clk(&ctx->parent.hw, NULL); + ctx->child1_clk =3D clk_hw_get_clk(&ctx->child1.hw, NULL); + ctx->child2_clk =3D clk_hw_get_clk(&ctx->child2.hw, NULL); + + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), 24 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), 24 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), 24 * HZ_PER_MHZ); + + return 0; +} + +static void clk_rate_change_sibling_div_div_test_exit(struct kunit *test) +{ + struct clk_rate_change_sibling_div_div_context *ctx =3D test->priv; + + clk_put(ctx->parent_clk); + clk_put(ctx->child1_clk); + clk_put(ctx->child2_clk); +} + +/* + * Test that, for a parent with two divider-only children with CLK_SET_RAT= E_PARENT set + * and one requests a rate compatible with the existing parent rate, the p= arent and + * sibling rates are not affected. + */ +static void clk_test_rate_change_sibling_div_div_1(struct kunit *test) +{ + struct clk_rate_change_sibling_div_div_context *ctx =3D test->priv; + int ret; + + ret =3D clk_set_rate(ctx->child1_clk, 6 * HZ_PER_MHZ); + KUNIT_ASSERT_EQ(test, ret, 0); + + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), 24 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), 6 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child1.div, 4); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), 24 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child2.div, 1); +} + +/* + * Test that, for a parent with two divider-only children with CLK_SET_RAT= E_PARENT + * set and one requests a rate incompatible with the existing parent rate,= the + * sibling rate is also affected. This preserves existing behavior in the = clk + * core that some drivers may be unknowingly dependent on. + */ +static void clk_test_rate_change_sibling_div_div_2(struct kunit *test) +{ + struct clk_rate_change_sibling_div_div_context *ctx =3D test->priv; + int ret; + + ret =3D clk_set_rate(ctx->child1_clk, 48 * HZ_PER_MHZ); + KUNIT_ASSERT_EQ(test, ret, 0); + + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child1.div, 1); + + /* + * The sibling's rate is changed from 24 to 48 MHz. This keeps the + * long-standing behavior of the clk core that some drivers may be + * unknowingly dependent on. + */ + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child2.div, 1); +} + +/* + * Test that, for a parent with two divider-only children with CLK_SET_RAT= E_PARENT + * set and one requests a rate incompatible with the existing parent rate,= the + * sibling rate is also affected. This preserves existing behavior in the = clk + * core that some drivers may be unknowingly dependent on. + */ +static void clk_test_rate_change_sibling_div_div_3(struct kunit *test) +{ + struct clk_rate_change_sibling_div_div_context *ctx =3D test->priv; + int ret; + + ret =3D clk_set_rate(ctx->child1_clk, 32 * HZ_PER_MHZ); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret =3D clk_set_rate(ctx->child2_clk, 48 * HZ_PER_MHZ); + KUNIT_ASSERT_EQ(test, ret, 0); + + /* + * The last sibling rate change is the one that was successful, and + * wins. The parent, and two children are all changed to 48 MHz. This + * keeps the long-standing behavior of the clk core that some drivers + * may be unknowingly dependent on. + * + * In the case where the parent needs to be 96 MHz, and the children + * need to be at 32 MHz / 48 MHz, then that logic needs to exist in + * the clk provider for the relevant clks. + */ + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child1.div, 1); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child2.div, 1); +} + +static struct kunit_case clk_rate_change_sibling_div_div_cases[] =3D { + KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_1, + clk_rate_change_sibling_div_div_test_regular_ops_gen_params), + KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_2, + clk_rate_change_sibling_div_div_test_regular_ops_gen_params), + KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_3, + clk_rate_change_sibling_div_div_test_regular_ops_gen_params), + {} +}; + +/* + * Test suite that creates a parent with two divider-only children, and + * documents the behavior of what happens to the sibling clock when one ch= ild + * changes its rate. + */ +static struct kunit_suite clk_rate_change_sibling_div_div_test_suite =3D { + .name =3D "clk-rate-change-sibling-div-div", + .init =3D clk_rate_change_sibling_div_div_test_init, + .exit =3D clk_rate_change_sibling_div_div_test_exit, + .test_cases =3D clk_rate_change_sibling_div_div_cases, +}; + static int clk_orphan_transparent_multiple_parent_mux_test_init(struct kunit *test) { @@ -3592,6 +3765,7 @@ kunit_test_suites( &clk_leaf_mux_set_rate_parent_test_suite, &clk_test_suite, &clk_multiple_parents_mux_test_suite, + &clk_rate_change_sibling_div_div_test_suite, &clk_mux_no_reparent_test_suite, &clk_mux_notifier_test_suite, &clk_orphan_transparent_multiple_parent_mux_test_suite, --=20 2.53.0 From nobody Thu Apr 9 15:46:39 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 65BD32ECE91 for ; Fri, 6 Mar 2026 23:23:09 +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=1772839391; cv=none; b=FYaHVU5E5mz7QqQ10bUiY6RKrHcUoAvnwdcnaGzzY4hxIgsJAvPjQ2JCfY3tNGjJtgz/8Mr8sX1fAV/X4cu3/eUXgyZTcmw5GfpcTWtsP63OupSxIU/8Tk0QGfxbXNXLAFhNAspYYqixRAxoQgRoJTr25HwYW83BbOrqwVXviJc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772839391; c=relaxed/simple; bh=kwejKjuYY4XenvDpzzbyRDggruiFrCZ5PscbhpIwrS0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=etnk6fsdN/40w3WjkxAUjyk/m0KD0BwOKPxUGsbwm8/36JRZOfdn7HczC8AS4dE28bQ445CLz0BhD4gkxBJtH93XOEeoQZF81GjathE/03KHBhpTgJuNl0o4mB+ElG0uqDf8RCLqErou0KWtEgYmHq3s8uTp1vE/GyaQ3f/etnI= 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=CdZdS0YN; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=Je1s2md7; 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="CdZdS0YN"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="Je1s2md7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1772839388; 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=OppYOjvwaN4z3cxzeUtBRU+DjHN0TKViDHEHlur24l0=; b=CdZdS0YNWGraGk4fBIphPiiYirQXx33P4vSEnhONVimafTK0Y90diGcCxe58C6OCpes+BC lX61vBjIXCXls9cdHKRmr63UjWlUEz7BQMEpyf5qm38ARUUM0PbEteoxwdlRW2AD0CGgmk iytF2Xa4nu+51rJ7RAp7Ewv6OLrEKxw= Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-310-78INEr7NOhitRiTiRCsIjQ-1; Fri, 06 Mar 2026 18:23:07 -0500 X-MC-Unique: 78INEr7NOhitRiTiRCsIjQ-1 X-Mimecast-MFC-AGG-ID: 78INEr7NOhitRiTiRCsIjQ_1772839387 Received: by mail-qk1-f200.google.com with SMTP id af79cd13be357-8cb52a9c0eeso7166826885a.2 for ; Fri, 06 Mar 2026 15:23:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1772839387; x=1773444187; 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=OppYOjvwaN4z3cxzeUtBRU+DjHN0TKViDHEHlur24l0=; b=Je1s2md7AsZMVngEn6P2eWr6e+fcQXB5rKXR30BGX3d3uC6qdIO1PWlxMpjKxH55oW 5kArylNDC5TWkPEfTU3lBZbhCWWsMwsd5xs9vHMQkyyNugRzbwxbWmHHUj/TuzTuDHWI zf/roNEY6mCiAJwrdZHc1ntfkBh9mGcumapxX8S+jb8oqOHeh6u1Lu+hEFLjoLNuYj9P gNvY8vhKYlFI+4KmfMwC3AwFm8LrdlxQuh7mZajA6st7F50Y6VpQ1oVFYQ+twYov4hIr dSLVtyh+buJXXqgsdJK3+jLABG8l5sO+FEDZFBAiSsSDiycMjM8D9WDQI7eX16ja2Rqt NUVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772839387; x=1773444187; 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=OppYOjvwaN4z3cxzeUtBRU+DjHN0TKViDHEHlur24l0=; b=XbQ9l4aBwCatHRZ9ho0W6UyvDa/CVm11eww2iVV7Le4lOWYtd0REuku7mCyVBnmajA rzDtNZj+SK5EVI9lUVpEu0qImqNX2WoNKIIfpTjyqC0TV2OO3Zuxyb0jUgDaZv/uegpY i47oMFtl72zU09t8fSB2KVUJEQUcdje7rM3sc9ncTylyjnI4SB9t4X7YLdQGcC6YtHX7 CMa7KqsHd+5i1ElxT4oMvFHH+mj+x3TCHQM977cfliS2/ToAw6sCbgpQt504I5sZ/aU/ pxYU9Wgv8hs/aTORNvZAQVS3meLBM2N/xO5Rs68Ojzvk+nIAQL8ZIFfYbzMl/+3ySvO7 WbZA== X-Forwarded-Encrypted: i=1; AJvYcCVmoT20DMJ4d4g+ByMgB5iN+PXBSyvWwGgqFko0RyqU9lKJ965kmLIJySJHQaoU/iBYpPr8URECtB0xXUQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yy/CYEUWvdRXgNRMbVSzhPp3ZqrN5Hbhif4jBnCv0moGURo8heC XFOk1nciAdexS5TRtn5ObCRyd1rQx4oWU6l2x/SspA+crGH9GJkwvekJ/38YKiEe2MyVIYi48bN r2Zar9bFdMprQktqIXQvyAcdny1PxFhJCMsWZcuDQqHTJem4wHrXEXq5XQqhdJAKLAw== X-Gm-Gg: ATEYQzyA2v3vVZ3A9M14Q8lRDvy6Y2uUBXBldrUi+CyP4ANqP8DG6TP6W9fEVt/6cUk 3zTU7oBxnN82qBG/2kJfFC+3oqX/SsOBqPaZJN23u4NyCCF/6kq0OU/IGXx339l0zx0tfffrWoX Txfr8Zha27ExVnmT0Xp/C3vm29zilQBiOPmB4/vSzRrMnqkIZub8A4DIWDzihSaek8/GTmvSHAS 07M7nh05IjlCHZrF2dLrkkKg7Kz4cgTYSA9v52U8draJKtny8azh/kEsJcmBtMBJUjSUYzXWKA9 g3NLN21vESfpk5sVn3hOxne7L521LdmTPcyaH4jFhFcpeW4lEYCzHlvIhgy0CT6cVAU/UqjoG3i f2KrGhVpxs0nYfYZReQe2sgZ3sgxG X-Received: by 2002:a05:620a:190d:b0:8c7:139a:bf66 with SMTP id af79cd13be357-8cd6d4b4e6amr546280285a.50.1772839386922; Fri, 06 Mar 2026 15:23:06 -0800 (PST) X-Received: by 2002:a05:620a:190d:b0:8c7:139a:bf66 with SMTP id af79cd13be357-8cd6d4b4e6amr546277785a.50.1772839386494; Fri, 06 Mar 2026 15:23:06 -0800 (PST) Received: from [10.125.247.224] ([2600:382:772b:4f24:8140:d6ff:f19a:7e11]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8cd6f4856cesm203119585a.10.2026.03.06.15.23.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Mar 2026 15:23:05 -0800 (PST) From: Brian Masney Date: Fri, 06 Mar 2026 18:21:38 -0500 Subject: [PATCH RFC v5 3/4] clk: add support for coordinated rate changes from the providers 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: <20260306-clk-scaling-v5-3-d21b84ee6f27@redhat.com> References: <20260306-clk-scaling-v5-0-d21b84ee6f27@redhat.com> In-Reply-To: <20260306-clk-scaling-v5-0-d21b84ee6f27@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=13700; i=bmasney@redhat.com; s=20250903; h=from:subject:message-id; bh=kwejKjuYY4XenvDpzzbyRDggruiFrCZ5PscbhpIwrS0=; b=owGbwMvMwCW2/dJd9di6A+2Mp9WSGDJXJ57PPuvv++N9M/fbpR4e3BX1y7uevdiSnJgq7Bpp/ N80uFyho5SFQYyLQVZMkWVJrlFBROoq23t3NFlg5rAygQxh4OIUgIm0tDMy/Ku8KrP+i59/d9Gh B4edtG9O47ii81E3Skl91+6aFekSMxn+B1neavnDst1VVeyXCcMXt6UbOGv2Lryyr7rm3q9qfaU nvAA= X-Developer-Key: i=bmasney@redhat.com; a=openpgp; fpr=A46D32705865AA3DDEDC2904B7D2DD275D7EC087 Some clock topologies require multiple clocks to change rates in a specific sequence to maintain stability and avoid glitches. For example, sibling clocks derived from a shared parent may need coordinated updates to prevent output disruption. The existing rate change propagation mechanism changes clocks recursively from parent to children, but doesn't provide a way for providers to explicitly control the order of rate changes across multiple clocks or coordinate updates among siblings. At the moment, changes to sibling clocks can unknowingly affect the rate of other clocks in the tree, and some boards are unknowingly dependent on this behavior. Let's add infrastructure to the clk core so that clks can opt into a new way to allow changing the rates of multiple clks by: - Add a CLK_V2_RATE_NEGOTIATION flag for clks that want to participate in this new negotiation logic. - A clk provider calls clk_hw_get_v2_stable_clks() to get the list of clks with this set as part of the planning phase. - It is up the to clk provider to determine what the new parent rate should be for that part of the clk subtree. - The clk provider calls clk_hw_add_coordinated_rate_changes() for any clks that should have also their rate changed. It is up to the provider to provide the correct order that the clks should be changed. - The clk core executes the rate changes serially in the order specified by the provider. If the change list is empty, then the behavior falls back to the existing propagation mechanism to maintain compatibility with existing clk drivers. 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 | 207 +++++++++++++++++++++++++++++++++++++++= ---- include/linux/clk-provider.h | 39 +++++++- 2 files changed, 229 insertions(+), 17 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 47093cda9df32223c1120c3710261296027c4cd3..c8ff31a6799c75746f2e4095cc3= ff77fdbbdf6ef 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -838,6 +838,111 @@ void clk_hw_set_rate_range(struct clk_hw *hw, unsigne= d long min_rate, } EXPORT_SYMBOL_GPL(clk_hw_set_rate_range); =20 +static int __clk_hw_get_v2_stable_clks(struct clk_hw *hw, + struct clk_hw *requesting_hw, + unsigned long requesting_rate, + struct list_head *stable_clks) +{ + struct clk_core *child; + int ret; + + if (hw->core->flags & CLK_V2_RATE_NEGOTIATION) { + struct clk_rate_change *clk_node; + + clk_node =3D kzalloc_obj(*clk_node); + if (!clk_node) + return -ENOMEM; + + clk_node->hw =3D hw; + clk_node->current_rate =3D clk_hw_get_rate(hw); + + if (hw =3D=3D requesting_hw) + clk_node->target_rate =3D requesting_rate; + else + clk_node->target_rate =3D clk_hw_get_rate(hw); + + clk_node->new_parent_index =3D 0; + list_add_tail(&clk_node->node, stable_clks); + } + + hlist_for_each_entry(child, &hw->core->children, child_node) { + ret =3D __clk_hw_get_v2_stable_clks(child->hw, requesting_hw, + requesting_rate, + stable_clks); + if (ret) + return ret; + } + + return 0; +} + +int clk_hw_get_v2_stable_clks(struct clk_rate_request *req, struct clk_hw = *parent_hw, + struct list_head *stable_clks) +{ + return __clk_hw_get_v2_stable_clks(parent_hw, req->core->hw, req->rate, + stable_clks); +} +EXPORT_SYMBOL_GPL(clk_hw_get_v2_stable_clks); + +void clk_hw_free_rate_changes(struct list_head *stable_clks) +{ + struct clk_rate_change *clk_node, *tmp; + + list_for_each_entry_safe(clk_node, tmp, stable_clks, node) { + list_del(&clk_node->node); + kfree(clk_node); + } +} +EXPORT_SYMBOL_GPL(clk_hw_free_rate_changes); + +static int clk_hw_add_rate_change(struct clk_rate_request *req, struct clk= _hw *hw, + unsigned long old_rate, unsigned long new_rate, + u8 new_parent_index) +{ + struct clk_rate_change *change; + + change =3D kzalloc_obj(*change); + if (!change) + return -ENOMEM; + + change->hw =3D hw; + change->current_rate =3D old_rate; + change->target_rate =3D new_rate; + change->new_parent_index =3D new_parent_index; + list_add_tail(&change->node, &req->ordered_rate_changes); + + return 0; +} + +int clk_hw_add_coordinated_rate_changes(struct clk_rate_request *req, + struct clk_hw *parent_hw, + unsigned long parent_old_rate, + unsigned long parent_new_rate, + struct list_head *stable_clks) +{ + struct clk_rate_change *clk_node; + int ret; + + ret =3D clk_hw_add_rate_change(req, parent_hw, parent_old_rate, + parent_new_rate, 0); + if (ret) + goto out_free; + + list_for_each_entry(clk_node, stable_clks, node) { + ret =3D clk_hw_add_rate_change(req, clk_node->hw, + clk_node->current_rate, + clk_node->target_rate, 0); + if (ret) + goto out_free; + } + + ret =3D 0; +out_free: + clk_hw_free_rate_changes(stable_clks); + return ret; +} +EXPORT_SYMBOL_GPL(clk_hw_add_coordinated_rate_changes); + /* * __clk_mux_determine_rate - clk_ops::determine_rate implementation for a= mux type clk * @hw: mux type clk to determine rate on @@ -1615,6 +1720,7 @@ static void clk_core_init_rate_req(struct clk_core * = const core, return; =20 memset(req, 0, sizeof(*req)); + INIT_LIST_HEAD(&req->ordered_rate_changes); req->max_rate =3D ULONG_MAX; =20 if (!core) @@ -2268,7 +2374,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 list_head *ordered_rate_changes) { struct clk_core *top =3D core; struct clk_core *old_parent, *parent; @@ -2308,6 +2415,12 @@ static struct clk_core *clk_calc_new_rates(struct cl= k_core *core, new_rate =3D req.rate; parent =3D req.best_parent_hw ? req.best_parent_hw->core : NULL; =20 + /* Clock provider populated coordinated rate changes */ + if (ordered_rate_changes && !list_empty(&req.ordered_rate_changes)) { + /* Transfer ownership of the list to caller */ + list_splice_init(&req.ordered_rate_changes, ordered_rate_changes); + } + if (new_rate < min_rate || new_rate > max_rate) return NULL; } else if (!parent || !(core->flags & CLK_SET_RATE_PARENT)) { @@ -2316,7 +2429,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, NULL); new_rate =3D parent->new_rate; goto out; } @@ -2341,7 +2454,7 @@ static struct clk_core *clk_calc_new_rates(struct clk= _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, NULL); =20 out: clk_calc_subtree(core, new_rate, parent, p_index); @@ -2461,7 +2574,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, NULL); =20 /* * Use safe iteration, as change_rate can actually swap parents @@ -2511,9 +2624,58 @@ static unsigned long clk_core_req_round_rate_nolock(= struct clk_core *core, return ret ? 0 : req.rate; } =20 +static int clk_apply_coordinated_rate_changes(struct clk_rate_request *req) +{ + struct clk_rate_change *change; + int ret; + + /* + * FIXME: There's currently no mechanism to roll back in case of an + * error. This can leave the clock tree in an inconsistent state. + */ + list_for_each_entry(change, &req->ordered_rate_changes, node) { + struct clk_hw *hw =3D change->hw; + + if (!hw || !hw->core) + continue; + + if (change->new_parent_index && hw->core->ops->set_parent) { + ret =3D hw->core->ops->set_parent(hw, change->new_parent_index); + if (ret) + return ret; + } + + if (hw->core->ops->set_rate) { + unsigned long parent_rate =3D 0; + + if (hw->core->parent) + parent_rate =3D hw->core->parent->rate; + + ret =3D hw->core->ops->set_rate(hw, change->target_rate, parent_rate); + if (ret) + return ret; + + hw->core->rate =3D change->target_rate; + } + } + + return 0; +} + +static void clk_rate_request_cleanup(struct clk_rate_request *req) +{ + struct clk_rate_change *change, *tmp; + + list_for_each_entry_safe(change, tmp, &req->ordered_rate_changes, node) { + list_del(&change->node); + kfree(change); + } +} + static int clk_core_set_rate_nolock(struct clk_core *core, unsigned long req_rate) { + struct clk_rate_request rate_req; struct clk_core *top, *fail_clk; unsigned long rate; int ret; @@ -2521,6 +2683,8 @@ static int clk_core_set_rate_nolock(struct clk_core *= core, if (!core) return 0; =20 + clk_core_init_rate_req(core, &rate_req, req_rate); + rate =3D clk_core_req_round_rate_nolock(core, req_rate); =20 /* bail early if nothing to do */ @@ -2532,7 +2696,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, &rate_req.ordered_rate_changes= ); if (!top) return -EINVAL; =20 @@ -2540,22 +2704,33 @@ static int clk_core_set_rate_nolock(struct clk_core= *core, if (ret) return ret; =20 - /* notify that we are about to change rates */ - fail_clk =3D clk_propagate_rate_change(top, PRE_RATE_CHANGE); - if (fail_clk) { - pr_debug("%s: failed to set %s rate\n", __func__, - fail_clk->name); - clk_propagate_rate_change(top, ABORT_RATE_CHANGE); - ret =3D -EBUSY; - goto err; - } + if (!list_empty(&rate_req.ordered_rate_changes)) { + /* Apply coordinated rate changes in order */ + ret =3D clk_apply_coordinated_rate_changes(&rate_req); + if (ret) { + pr_debug("%s: failed to apply coordinated rate changes\n", __func__); + goto err; + } + } else { + /* Use traditional rate change propagation */ + /* notify that we are about to change rates */ + fail_clk =3D clk_propagate_rate_change(top, PRE_RATE_CHANGE); + if (fail_clk) { + pr_debug("%s: failed to set %s rate\n", __func__, + fail_clk->name); + clk_propagate_rate_change(top, ABORT_RATE_CHANGE); + ret =3D -EBUSY; + goto err; + } =20 - /* change the rates */ - clk_change_rate(top); + /* change the rates */ + clk_change_rate(top); + } =20 core->req_rate =3D req_rate; err: clk_pm_runtime_put(core); + clk_rate_request_cleanup(&rate_req); =20 return ret; } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 630705a47129453c241f1b1755f2c2f2a7ed8f77..26ab04196411f96dcb5d7c91c06= ce3ca4117ca50 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; @@ -53,7 +55,10 @@ struct dentry; * requested constraints. * @best_parent_hw: The most appropriate parent clock that fulfills the * requested constraints. - * + * @ordered_rate_changes: Execution list of rate changes for coordinated u= pdates. + * Clock providers populate this list when they need to + * update multiple clocks in a specific order to maintain + * rate stability for all consumers. */ struct clk_rate_request { struct clk_core *core; @@ -62,6 +67,7 @@ struct clk_rate_request { unsigned long max_rate; unsigned long best_parent_rate; struct clk_hw *best_parent_hw; + struct list_head ordered_rate_changes; }; =20 void clk_hw_init_rate_request(const struct clk_hw *hw, @@ -1437,6 +1443,37 @@ static inline void __clk_hw_set_clk(struct clk_hw *d= st, struct clk_hw *src) dst->core =3D src->core; } =20 +/** + * struct clk_rate_change - Describes a clock rate change + * + * Used in both planning and execution phases of coordinated rate changes. + * During planning, collects information about sibling clocks. During exec= ution, + * contains the final rate change instructions to apply. + * + * @hw: The clock hardware that needs to change rate + * @current_rate: The current rate of this clock + * @target_rate: The target rate for this clock + * @new_parent_index: The index of the new parent (for muxes), or 0 + * @node: List node for chaining entries + */ +struct clk_rate_change { + struct clk_hw *hw; + unsigned long current_rate; + unsigned long target_rate; + u8 new_parent_index; + struct list_head node; +}; + +int clk_hw_get_v2_stable_clks(struct clk_rate_request *req, + struct clk_hw *parent_hw, + struct list_head *stable_clks); +void clk_hw_free_rate_changes(struct list_head *stable_clks); +int clk_hw_add_coordinated_rate_changes(struct clk_rate_request *req, + struct clk_hw *parent_hw, + unsigned long parent_old_rate, + unsigned long parent_new_rate, + struct list_head *stable_clks); + static inline long divider_round_rate(struct clk_hw *hw, unsigned long rat= e, unsigned long *prate, const struct clk_div_table *table, --=20 2.53.0 From nobody Thu Apr 9 15:46:39 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.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 44AA7371CED for ; Fri, 6 Mar 2026 23:23:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772839392; cv=none; b=kErxn8xiOgm6IRDXKqSGH/GEOchyop13oZPir2PzsITbexsWV5empCYrg7OQkhrG+djaKuoqpCjGU/ShksZMgv/y70Ik8rrjnmyXV6sBW3vOPHeLj8736ZbvB4zjeerEdKDTJ2/qGBI+Ta5HdDR9+HzWeRSwKgOnFLRrC/yRfh0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772839392; c=relaxed/simple; bh=tN+bOgbqEUSD/fsXM/J/vYjHKbj8iy+6blJ/Y2IT5dY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fIY//b9ll2A4FurkHAj/P6ACeE/vkH7Mgzn+gNfRK94akPVno3lq6MeVCAEEQg2nylnMgNGF7/mFqCHZZ746kJCaP3j5hsZ2dknLuEAdTm5HNOoxpYOBpwIhQIT4MrO0S+kBxDXdE/30yS4Yv1uFSWmax/L08JGQgFnd7iwGB8M= 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=cqWu9zzo; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=GZ1IsHoR; arc=none smtp.client-ip=170.10.129.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="cqWu9zzo"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="GZ1IsHoR" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1772839390; 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=hJPXcds69fedxlOSd+bpeGywbazK6qaqr8rOBwqfWwQ=; b=cqWu9zzoJl4ThyXMmJHp7KdJnsLgKM7ZiwRz8UW6z/LHMIgyJGeGa8ZQ4/iIbjtKm4l6M4 DWSQwkXJUDCB/wXciP0LqhQIm90qXFWYEb1iS0dI7SBa0kdvoe76duwpQa+9RERgYekQU3 dcOcR3b94kLbveZ7amC+J3Hf7239+5s= 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-447-F0L1KSnMMp6ACV7bmJ7Bzg-1; Fri, 06 Mar 2026 18:23:09 -0500 X-MC-Unique: F0L1KSnMMp6ACV7bmJ7Bzg-1 X-Mimecast-MFC-AGG-ID: F0L1KSnMMp6ACV7bmJ7Bzg_1772839389 Received: by mail-qk1-f197.google.com with SMTP id af79cd13be357-8cb4d191ef1so1321591385a.0 for ; Fri, 06 Mar 2026 15:23:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1772839388; x=1773444188; 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=hJPXcds69fedxlOSd+bpeGywbazK6qaqr8rOBwqfWwQ=; b=GZ1IsHoRyTnekFaSQ/FiIpqd5Vmstid95FVDjWRV38q4b+7kl4VggAL2TCO+lhUaOn 4FhlONRnBF13yFPoXErAS034F3O1MWhxxV3RQQaEto8g69OVPqCq8uyCvCEqjJltpczD D5TYLRa8DPwkr9oJXgnBtFJZJ/bPiGIA8cSwwNpp9wQ4oIFzSZ6c01JCwkeoF8siLr9t EVMv6JXsn2ptVP+hPkifKA7mBtOtZsmssVyYSrZ06YIAo492iW5s9PzeCFKdx0LmXiie sqcip/bS508evHY2H7yiTcFQfy/mWMNLXwCRdxXjvsGTzovdx89+S85Oq1WTeSndnUdV xv+A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772839388; x=1773444188; 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=hJPXcds69fedxlOSd+bpeGywbazK6qaqr8rOBwqfWwQ=; b=mkwBZ3XNxJQgbWVTWgyavW5jmKeSTNFIB0kFaPOEsnMPFufNUT1VBj0y+gYX8MSVwg T1SEkxfMoKkIzzmZRrA861IPzL6c9JokOiWMuBAa1U7D7wITNty6DIWXbcwq4CCbomMW Ucs197Rm2ft0Sazs38AmQoW3hqlHYEJDHUNtiuyRaiJnQeEcUCf6xrDQPvYPR062c+ja MN+UFHbcl2K5wTqoyLd937anJapQZ9UsJ3Vb6yJXjTjEcRTA1BHprccaBpGgmAAE0z/F rTTLilWw8W/isxzaw29F2duBxCg/UKgGTMSYuQ7hTkH7wJDAwsiZYVx87SD/6qu/KDa3 lq6A== X-Forwarded-Encrypted: i=1; AJvYcCUXPGj6r1kZUAjD+3dYTtVNRg8hGz7aCqXXMm08a9dvg1rYLA/AaNwPF0FdY94h3L1Jz/G326dI61rC2L4=@vger.kernel.org X-Gm-Message-State: AOJu0YzQSI74v9sSICxvfoMJJJMG7CSs6Np029usYpPn6Uq+pq3US4I+ HxJA60MOKdDv2nbwunWB/xIVpHn7WqlO/IvGauWkH6vNQ3dloVShg5NnKMPq67XNxmC+wigSJ3z 5S53ScTAvvafkXKDLHjQwi5axiMFRJEOIYgxfSXqYVEoaYwGqZQ3sQazoT24AnTlZ1A== X-Gm-Gg: ATEYQzy/jCQhRt9A+j3q/0kpAniRXUCV5lC00KcnRq9d2mb6lsMyiaQ2oBAQs6PZmAo vTzfOdLVQcHvF9GLOVizbsk7/FrDaXHNkuUjmbcsccEr7pblhvlLdVfAcr0JB1hs7VkjyrBVder X/somYMRLSnsKuuX9AVoDOgJp17uCHZHBRu2fLLxN9nGVzzO5X306AAF/VcXgMbQ2Ogfxx9uZ4z oHh1ZD7PkXm7nT7OTwgFBMTe+nF/gITj64JRLaDj4KIxDkHvqN1COoGFbIgtYN6ZjG2PuR3eTwd kR0JAG+U0ZbVXaf05csPnkhchXas+Tb2l4bdWAjm20W+EQWNlxCMdDN1vaTiSU0rfwi7k0i7CLk 5IFye7EIEEuR3idDGBg7IDUMx+Rgr X-Received: by 2002:a05:620a:2541:b0:8cd:7835:880f with SMTP id af79cd13be357-8cd7835892cmr36506985a.82.1772839388553; Fri, 06 Mar 2026 15:23:08 -0800 (PST) X-Received: by 2002:a05:620a:2541:b0:8cd:7835:880f with SMTP id af79cd13be357-8cd7835892cmr36504085a.82.1772839388080; Fri, 06 Mar 2026 15:23:08 -0800 (PST) Received: from [10.125.247.224] ([2600:382:772b:4f24:8140:d6ff:f19a:7e11]) by smtp.gmail.com with ESMTPSA id af79cd13be357-8cd6f4856cesm203119585a.10.2026.03.06.15.23.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Mar 2026 15:23:07 -0800 (PST) From: Brian Masney Date: Fri, 06 Mar 2026 18:21:39 -0500 Subject: [PATCH RFC v5 4/4] clk: test: add kunit test for coordinated rate change 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: <20260306-clk-scaling-v5-4-d21b84ee6f27@redhat.com> References: <20260306-clk-scaling-v5-0-d21b84ee6f27@redhat.com> In-Reply-To: <20260306-clk-scaling-v5-0-d21b84ee6f27@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=6335; i=bmasney@redhat.com; s=20250903; h=from:subject:message-id; bh=tN+bOgbqEUSD/fsXM/J/vYjHKbj8iy+6blJ/Y2IT5dY=; b=owGbwMvMwCW2/dJd9di6A+2Mp9WSGDJXJ14QWF75ZNM0gdfn3S98N8/ZqHtcMmWlVv3v0MbKi NC7r+e+6ChlYRDjYpAVU2RZkmtUEJG6yvbeHU0WmDmsTCBDGLg4BWAiEy8wMtxdkrlqf9u0cv9n e5+/avPMYQvUFTk+VaGo9Jiu1IllKb0M/4z6ctIYFrYbKBycyusXb7BJa0nLp79PfKpjdSpvP7m QzwUA X-Developer-Key: i=bmasney@redhat.com; a=openpgp; fpr=A46D32705865AA3DDEDC2904B7D2DD275D7EC087 Add kunit tests to demonstrate how to use the coordinated rate change clk APIs, and to validate that they are working as expected. 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_test.c | 103 +++++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index 97cbf9dd16ee504d7687d8f0729b6e6e22a21afb..886190408545635926689046f62= 37260303b2271 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include =20 @@ -180,6 +181,46 @@ static const struct clk_ops clk_dummy_div_ops =3D { .set_rate =3D clk_dummy_div_set_rate, }; =20 +static int clk_dummy_div_coordinating_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_hw *parent_hw =3D clk_hw_get_parent(hw); + struct clk_rate_change *child_node; + unsigned long lcm_rate =3D 0; + LIST_HEAD(stable_clks); + int ret; + + ret =3D clk_hw_get_v2_stable_clks(req, parent_hw, &stable_clks); + if (ret) + return ret; + + list_for_each_entry(child_node, &stable_clks, node) { + if (child_node->target_rate =3D=3D 0) + continue; + if (lcm_rate =3D=3D 0) + lcm_rate =3D child_node->target_rate; + else + lcm_rate =3D lcm(lcm_rate, child_node->target_rate); + } + + ret =3D clk_hw_add_coordinated_rate_changes(req, parent_hw, + clk_hw_get_rate(parent_hw), + lcm_rate, &stable_clks); + if (ret) + return ret; + + req->best_parent_rate =3D lcm_rate; + req->best_parent_hw =3D parent_hw; + + return 0; +} + +static const struct clk_ops clk_dummy_div_coordinating_ops =3D { + .recalc_rate =3D clk_dummy_div_recalc_rate, + .determine_rate =3D clk_dummy_div_coordinating_determine_rate, + .set_rate =3D clk_dummy_div_set_rate, +}; + struct clk_multiple_parent_ctx { struct clk_dummy_context parents_ctx[2]; struct clk_hw hw; @@ -671,6 +712,14 @@ clk_rate_change_sibling_div_div_test_regular_ops_param= s[] =3D { KUNIT_ARRAY_PARAM_DESC(clk_rate_change_sibling_div_div_test_regular_ops, clk_rate_change_sibling_div_div_test_regular_ops_params, desc) =20 +static const struct clk_rate_change_sibling_div_div_test_param +clk_rate_change_sibling_div_div_test_coord_ops_params[] =3D { + { .desc =3D "coordinating_ops", .ops =3D &clk_dummy_div_coordinating_ops = }, +}; + +KUNIT_ARRAY_PARAM_DESC(clk_rate_change_sibling_div_div_test_coord_ops, + clk_rate_change_sibling_div_div_test_coord_ops_params, desc) + static int clk_rate_change_sibling_div_div_test_init(struct kunit *test) { const struct clk_rate_change_sibling_div_div_test_param *param =3D test->= param_value; @@ -689,14 +738,16 @@ static int clk_rate_change_sibling_div_div_test_init(= struct kunit *test) return ret; =20 ctx->child1.hw.init =3D CLK_HW_INIT_HW("child1", &ctx->parent.hw, - param->ops, CLK_SET_RATE_PARENT); + param->ops, + CLK_SET_RATE_PARENT | CLK_V2_RATE_NEGOTIATION); ctx->child1.div =3D 1; ret =3D clk_hw_register_kunit(test, NULL, &ctx->child1.hw); if (ret) return ret; =20 ctx->child2.hw.init =3D CLK_HW_INIT_HW("child2", &ctx->parent.hw, - param->ops, CLK_SET_RATE_PARENT); + param->ops, + CLK_SET_RATE_PARENT | CLK_V2_RATE_NEGOTIATION); ctx->child2.div =3D 1; ret =3D clk_hw_register_kunit(test, NULL, &ctx->child2.hw); if (ret) @@ -803,6 +854,48 @@ static void clk_test_rate_change_sibling_div_div_3(str= uct kunit *test) KUNIT_EXPECT_EQ(test, ctx->child2.div, 1); } =20 +static void clk_test_rate_change_sibling_div_div_4(struct kunit *test) +{ + struct clk_rate_change_sibling_div_div_context *ctx =3D test->priv; + int ret; + + ret =3D clk_set_rate(ctx->child1_clk, 48 * HZ_PER_MHZ); + KUNIT_ASSERT_EQ(test, ret, 0); + + /* + * With coordinated rate changes, the parent should be at 48 MHz, + * child1 at 48 MHz (div=3D1), and child2 at 24 MHz (div=3D2). Child2's + * keeps the same frequency, and the divider is changed from 1 to 2. + */ + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child1.div, 1); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), 24 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child2.div, 2); +} + +static void clk_test_rate_change_sibling_div_div_5(struct kunit *test) +{ + struct clk_rate_change_sibling_div_div_context *ctx =3D test->priv; + int ret; + + ret =3D clk_set_rate(ctx->child1_clk, 32 * HZ_PER_MHZ); + KUNIT_ASSERT_EQ(test, ret, 0); + + ret =3D clk_set_rate(ctx->child2_clk, 48 * HZ_PER_MHZ); + KUNIT_ASSERT_EQ(test, ret, 0); + + /* + * With coordinated rate changes, the parent should be at 96 MHz, + * child1 at 32 MHz (div=3D3), and child2 at 48 MHz (div=3D2). + */ + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->parent_clk), 96 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child1_clk), 32 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child1.div, 3); + KUNIT_EXPECT_EQ(test, clk_get_rate(ctx->child2_clk), 48 * HZ_PER_MHZ); + KUNIT_EXPECT_EQ(test, ctx->child2.div, 2); +} + static struct kunit_case clk_rate_change_sibling_div_div_cases[] =3D { KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_1, clk_rate_change_sibling_div_div_test_regular_ops_gen_params), @@ -810,6 +903,12 @@ static struct kunit_case clk_rate_change_sibling_div_d= iv_cases[] =3D { clk_rate_change_sibling_div_div_test_regular_ops_gen_params), KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_3, clk_rate_change_sibling_div_div_test_regular_ops_gen_params), + KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_1, + clk_rate_change_sibling_div_div_test_coord_ops_gen_params), + KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_4, + clk_rate_change_sibling_div_div_test_coord_ops_gen_params), + KUNIT_CASE_PARAM(clk_test_rate_change_sibling_div_div_5, + clk_rate_change_sibling_div_div_test_coord_ops_gen_params), {} }; =20 --=20 2.53.0