From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f181.google.com (mail-pl1-f181.google.com [209.85.214.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3701B22759D for ; Thu, 6 Feb 2025 09:28:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834140; cv=none; b=DFGiFIDcCgSkFoUkslksvTZWMc5FWGFH3yqnNdAKo1O9N+8jApChsEkgzFPB7PjRJxG6T1YHa2I322EXvIfd+iVABigLJ8NlBfiJzo2agC5URXHmrYHrJaqLSC4WdquSoHGqwipReT4LJ98ow6/RPg8FkHVJSaNQ6/3nlGdcNqg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834140; c=relaxed/simple; bh=Ot/T0jCd4T7tNCR433fIHwM84YOZJZy/rRbe6ZLnftM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rodr4etFpV9XgsXusizpuJgYbK4YXd2pzJ8oFyFfaMqZ1e34sFYhHYKIdWqtBYm0gB8DMq7VRhUN+FPl13rfFW6PFC3ljXsS6AeJrrtraYDazlgQwaw71d4WdSu4BQ0GEcytyVw1u83fjukWK4P45gl+trK9vMzL+DfD759hcP0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=zUoR3pTF; arc=none smtp.client-ip=209.85.214.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="zUoR3pTF" Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-21f40deb941so2737075ad.2 for ; Thu, 06 Feb 2025 01:28:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834137; x=1739438937; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=H9/+ITx7jdgxCni5rtLO0HfiqPVNFjTWeSm9ZunqSOA=; b=zUoR3pTF6YmbxQRUQ8Ws3B0zZbQMmK0CTochc8/i7A/gnubm0ADABBO9+k7MXWRqAS urZGm2dDo2ZZePeWLFvvihxJ1TYZzJZJ3HjMW5+DO27fr8/V/NtablMOmIyPK+WAMOuD 084PT5xrhzqYZMelFQWI7MTZY/unlUScwFsjzqR6k2MYKqRhr7Q/9NvJvhQGyE82J6dU 4FmZ+hDMzSoPcOy1IoFb/d9Npmy74SBGSrvoLxtoMmbda9Vb0fA83qWGT8YnODCzsF3n nKPoUKXyCjMoUpvxK4tFr1r4azrehnKIQBe/prHlKI2kNAkKN3Ba5YB78ILHlnMVw7eV 51GQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834137; x=1739438937; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=H9/+ITx7jdgxCni5rtLO0HfiqPVNFjTWeSm9ZunqSOA=; b=PKLaBWirsmZZwoF1UaJunahnMiVtRRA5E6vIOHn26AUV/fG5c0j7CP4+b5wux1y9XF lsLbCDrZza7EUCPH2u+gwzV83S7ufcqoC9ODD1c4L8NbtxOATiwBnwS0eUeK+gtKUAEm GjRcvmAFecG1Ac/XoJF5Q1ddblCOkhJq8tUJaGn8qeV7iY/VlRCnWkz7HLD0MY/rO5Fe WRkx5OF9W8bzxHJNJBy8W4H+58nFCAgohsTKmQk+O7ulu/bvem0/pFgkX63ApLzeZuPM a7jwvzkKB31n4AJ5wIIqv6GgshYJVVSpmPxOv++b6Vyt5bksJESqA2Sdj1lXYgpsJSYv zeBQ== X-Forwarded-Encrypted: i=1; AJvYcCXGID3wr4Vd8SvjtjZiFvtBfB7DqWrw4+kro1i2AHi0JUSYzLUqKTfDPoSWO+qrdRzCE/HWm3P1VOY4V8k=@vger.kernel.org X-Gm-Message-State: AOJu0YzkfN561HfoPhbZonIyMwaZi5aup34YztD76Vn4sWaPBKFOIDZx VE3zuOWJHZZO4D3e292kDZwvszXwhA26OFRViUWrs/LBjTzyjAJ0dQ5MXXI0gsY= X-Gm-Gg: ASbGnctYrumC7u1AfiIDZm4e/VSBIL2a74LxVMYcF+yJtnUpvoSjkPjC4dESyS/le2d TRaBl5BbtbbsZlCji8smYVhZMZT+MiUOjeCE3wdpuZhXUnsZkiKMb8+cKCy+AS7iphqHgiUIxgt Apx05AQur94e5J0SLPo4DsetNorXELKH8LvwCc/3NJ53Tf7Kq2O7CZxCmZR4xkhNf7fVj6RYxOl Yc1OfXU4rNZBQXxwOmHwAz/kiSJBkpbVj43G/RfAbw1nGcINGCnTL3Z1EkNXdtg3IGRPi6LYHPh lYax4BihK+uXu9ZfAA== X-Google-Smtp-Source: AGHT+IGJC2iQJEI3sTGW6GjKdvP/nRc87YJ1GkI47hpYxHY8P6Qy5pjuZWMZBFlY67UgbnD1fdAThg== X-Received: by 2002:a17:903:41c1:b0:21e:ff3a:7593 with SMTP id d9443c01a7336-21f17dde2d4mr80139535ad.6.1738834137385; Thu, 06 Feb 2025 01:28:57 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21f3653b02dsm8145955ad.74.2025.02.06.01.28.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:28:56 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , Anisse Astier , linux-kernel@vger.kernel.org Subject: [PATCH V8 01/14] rust: macros: enable use of hyphens in module names Date: Thu, 6 Feb 2025 14:58:22 +0530 Message-Id: <99ca28045252ba77c302d74e57c2976e60744c4d.1738832118.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Anisse Astier Some modules might need naming that contains hyphens "-" to match the auto-probing by name in the platform devices that comes from the device tree. But rust identifiers cannot contain hyphens, so replace the module name by an underscore anywhere we'd use it as an identifier. Signed-off-by: Anisse Astier Reviewed-by: Alice Ryhl [Viresh: Replace "-" with '-'] Signed-off-by: Viresh Kumar --- rust/macros/module.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/rust/macros/module.rs b/rust/macros/module.rs index cdf94f4982df..2e740bbdb598 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -182,7 +182,9 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { =20 let info =3D ModuleInfo::parse(&mut it); =20 - let mut modinfo =3D ModInfoBuilder::new(info.name.as_ref()); + /* Rust does not allow hyphens in identifiers, use underscore instead = */ + let name_identifier =3D info.name.replace('-', "_"); + let mut modinfo =3D ModInfoBuilder::new(name_identifier.as_ref()); if let Some(author) =3D info.author { modinfo.emit("author", &author); } @@ -298,14 +300,14 @@ mod __module_init {{ #[doc(hidden)] #[link_section =3D \"{initcall_section}\"] #[used] - pub static __{name}_initcall: extern \"C\" fn() -> ker= nel::ffi::c_int =3D __{name}_init; + pub static __{name_identifier}_initcall: extern \"C\" = fn() -> kernel::ffi::c_int =3D __{name_identifier}_init; =20 #[cfg(not(MODULE))] #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)] core::arch::global_asm!( r#\".section \"{initcall_section}\", \"a\" - __{name}_initcall: - .long __{name}_init - . + __{name_identifier}_initcall: + .long __{name_identifier}_init - . .previous \"# ); @@ -313,7 +315,7 @@ mod __module_init {{ #[cfg(not(MODULE))] #[doc(hidden)] #[no_mangle] - pub extern \"C\" fn __{name}_init() -> kernel::ffi::c_= int {{ + pub extern \"C\" fn __{name_identifier}_init() -> kern= el::ffi::c_int {{ // SAFETY: This function is inaccessible to the ou= tside due to the double // module wrapping it. It is called exactly once b= y the C side via its // placement above in the initcall section. @@ -323,12 +325,12 @@ mod __module_init {{ #[cfg(not(MODULE))] #[doc(hidden)] #[no_mangle] - pub extern \"C\" fn __{name}_exit() {{ + pub extern \"C\" fn __{name_identifier}_exit() {{ // SAFETY: // - This function is inaccessible to the outside = due to the double // module wrapping it. It is called exactly once= by the C side via its // unique name, - // - furthermore it is only called after `__{name}= _init` has returned `0` + // - furthermore it is only called after `__{name_= identifier}_init` has returned `0` // (which delegates to `__init`). unsafe {{ __exit() }} }} @@ -369,6 +371,7 @@ unsafe fn __exit() {{ ", type_ =3D info.type_, name =3D info.name, + name_identifier =3D name_identifier, modinfo =3D modinfo.buffer, initcall_section =3D ".initcall6.init" ) --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9D28722ACF1 for ; Thu, 6 Feb 2025 09:29:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834143; cv=none; b=SQ0L6mdIFavHgRrGTD57j6ENart1G97KBgwthQmdBa1HE9lSA/LFtybczAfIOchE4CYNw3UFlTDFkJd5C8jOydQcXtoY2huI0ugWf6ZsrcBc7+EXFyX4cbtKNzpFtu3fe4iUC3PpZVQp/C8WyrSB9Gi8dd/o368s9r5WSBPrX+U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834143; c=relaxed/simple; bh=t2NVGvjKSZ8jGPHeqUP8byps2cHUv/LlWtK1ugt6aZ4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=bi4ZquqiTtf2dKjpQTfyzYwZ+IWNkkBdTk9yMO/9f5/WAUFMW9V0FImfOhOaartViQGWc0Fk689YyAtdcJUSQLKCotMb6jlf72dI8wLJP7ANCK2F5StHgPNdf1Iy/vceewdUZD9Gdj7cr6HcZWxdBCXtJ1/fT8otjRKFwQfafsY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=QpzFPYDs; arc=none smtp.client-ip=209.85.214.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="QpzFPYDs" Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-2164b662090so13687775ad.1 for ; Thu, 06 Feb 2025 01:29:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834141; x=1739438941; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IkWjr0H8S/ljloJuoBCwCDqimDzQkeaXdlPta4A4wUg=; b=QpzFPYDs5uF7AGEy9d5dgcKHK5ELcTQ8G/LPO9gDyiwUBfHK1CaceSUUG4Yzz42/AV NyQfgdK2EMYBqcKOKZbq+a5xBFf26hpPxGHLO9u63HJINmwT8Mv/tLkbmlMzEF7vgiAm ODMkzU7HNLqwfrjc8uGn+3vvqoHPDENCILq9YEdXIPy0Ixlrq1xwr0oBVuIww8b/cP0Q J+d4Qxk4XB+96S1QORQNHFOpwVxBYN6VL307QPfe9GXSO6VETUe+yj869/f+uyfj9YT3 PHkzPyeUbpmQD9e34sVKqIIuiqVxAgZlGlQW8fX2g4L0YLe3tLOEHWgxCrYntLcjGY8A 8vgw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834141; x=1739438941; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IkWjr0H8S/ljloJuoBCwCDqimDzQkeaXdlPta4A4wUg=; b=MtAFTTQTrH5TaGhlgvZuYS4ZWpNukvjhcbF3ReZFxgGBm0xuFSbprNKtpGhDpmeiwC d0wd5ncJzc36PkGy5hf9gTvi7VnFHO6cUo+tdZe+NZZxwlNT6ziYH7cHiGxS/eq3G2ij UXQUCZGDKSZOlGAI147SSKKKYgj918TeJ3oawj0pRIV97Ya7P1qMKQi0PrNwaC+3nRVc MIlbD3iDxj2acgTSYTn5JljltKGyEG+tet8noaHVjXfzRHicm8AIQxg9RWY2cMPqVGCh zLqAsohf7+I/Zx+D8fqxyB6F472SL6Y1/WbQkAnro5+6ySrPGcZ5fQv7Jk2p2hY8hACl z8Xg== X-Forwarded-Encrypted: i=1; AJvYcCXYwaon0KQIh0NoW9xxvb8lSmH9nI/1TKZZTCoU8OE7KGUYspm6Gso+I1UU7gTJXsj1PXSoiaFtTUIDbdw=@vger.kernel.org X-Gm-Message-State: AOJu0YwX0gUnL3Oi0yw2Adm30EIXahlqysqAA7ZLPQrTd08+wVdF8o1r zZ7llYz9mdZs1M+vqMUpjnO5UmGC3dKXmK5fih7Lx03hXfjLmEI+QCdbV7vG3OU= X-Gm-Gg: ASbGncs4CQ6y5wuD16q08J+61+jraIfcwT51TiElSfFJUg8ZUXYLKG2unm7pRe0OeVE Sav+1aYZBNleRCD0U/9GUoXbkGvav70m9L325Y+ALX0+SGd9EbxMaG+oIv85usWZGZpEv3u72o3 gd1oqtJeGH8mFBXjnXbKSycjd05ugx8E3f1zg7y5etp4YiKF8ZrDGTDjHruWfYV+PZh7mLulgBQ zjSsdGtRSxOkIrAwcCVLemQQg0Ul4vUhXkYozDiVSeCEPDty3l5YRknLDVKxa4wl1TDb/0wosMq ZBD4G/cMpPd6YBmPrg== X-Google-Smtp-Source: AGHT+IH1/6xK/rRw8mY8TBJIKn2KcQgONJf1mDB8CNf90rvvV01LuVGRr4XBp/OKymX25kOUJ+f8Qw== X-Received: by 2002:a17:903:244e:b0:21f:b6f:3f34 with SMTP id d9443c01a7336-21f17df36a4mr89345215ad.15.1738834140797; Thu, 06 Feb 2025 01:29:00 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21f368bae51sm7952415ad.234.2025.02.06.01.28.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:00 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 02/14] cpufreq: Use enum for cpufreq flags that use BIT() Date: Thu, 6 Feb 2025 14:58:23 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The BIT() macro is too complex for Rust's bindgen to interpret as integer constants. This results in many of the cpufreq macros being undefined in Rust auto-generated bindings. By replacing the "#define" macros with an "enum", we ensure that bindgen can properly evaluate these values, enabling their seamless use in Rust code. No intentional functional impact. Suggested-by: Alice Ryhl Signed-off-by: Viresh Kumar --- include/linux/cpufreq.h | 96 ++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 7fe0981a7e46..bd67728081ad 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -292,11 +292,12 @@ static inline void cpufreq_stats_record_transition(st= ruct cpufreq_policy *policy * CPUFREQ DRIVER INTERFACE * *********************************************************************/ =20 -#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ -#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ -#define CPUFREQ_RELATION_C 2 /* closest frequency to target */ -/* relation flags */ -#define CPUFREQ_RELATION_E BIT(2) /* Get if possible an efficient frequenc= y */ +enum { + CPUFREQ_RELATION_L =3D 0, /* lowest frequency at or above target */ + CPUFREQ_RELATION_H =3D BIT(0), /* highest frequency below or at target */ + CPUFREQ_RELATION_C =3D BIT(1), /* closest frequency to target */ + CPUFREQ_RELATION_E =3D BIT(2), /* Get if possible an efficient frequency = */ +}; =20 #define CPUFREQ_RELATION_LE (CPUFREQ_RELATION_L | CPUFREQ_RELATION_E) #define CPUFREQ_RELATION_HE (CPUFREQ_RELATION_H | CPUFREQ_RELATION_E) @@ -418,52 +419,57 @@ struct cpufreq_driver { =20 /* flags */ =20 -/* - * Set by drivers that need to update internal upper and lower boundaries = along - * with the target frequency and so the core and governors should also inv= oke - * the diver if the target frequency does not change, but the policy min o= r max - * may have changed. - */ -#define CPUFREQ_NEED_UPDATE_LIMITS BIT(0) +enum { + /* + * Set by drivers that need to update internal upper and lower + * boundaries along with the target frequency and so the core and + * governors should also invoke the diver if the target frequency does + * not change, but the policy min or max may have changed. + */ + CPUFREQ_NEED_UPDATE_LIMITS =3D BIT(0), =20 -/* loops_per_jiffy or other kernel "constants" aren't affected by frequenc= y transitions */ -#define CPUFREQ_CONST_LOOPS BIT(1) + /* + * loops_per_jiffy or other kernel "constants" aren't affected by + * frequency transitions. + */ + CPUFREQ_CONST_LOOPS =3D BIT(1), =20 -/* - * Set by drivers that want the core to automatically register the cpufreq - * driver as a thermal cooling device. - */ -#define CPUFREQ_IS_COOLING_DEV BIT(2) + /* + * Set by drivers that want the core to automatically register the + * cpufreq driver as a thermal cooling device. + */ + CPUFREQ_IS_COOLING_DEV =3D BIT(2), =20 -/* - * This should be set by platforms having multiple clock-domains, i.e. - * supporting multiple policies. With this sysfs directories of governor w= ould - * be created in cpu/cpu/cpufreq/ directory and so they can use the s= ame - * governor with different tunables for different clusters. - */ -#define CPUFREQ_HAVE_GOVERNOR_PER_POLICY BIT(3) + /* + * This should be set by platforms having multiple clock-domains, i.e. + * supporting multiple policies. With this sysfs directories of governor + * would be created in cpu/cpu/cpufreq/ directory and so they can + * use the same governor with different tunables for different clusters. + */ + CPUFREQ_HAVE_GOVERNOR_PER_POLICY =3D BIT(3), =20 -/* - * Driver will do POSTCHANGE notifications from outside of their ->target() - * routine and so must set cpufreq_driver->flags with this flag, so that c= ore - * can handle them specially. - */ -#define CPUFREQ_ASYNC_NOTIFICATION BIT(4) + /* + * Driver will do POSTCHANGE notifications from outside of their + * ->target() routine and so must set cpufreq_driver->flags with this + * flag, so that core can handle them specially. + */ + CPUFREQ_ASYNC_NOTIFICATION =3D BIT(4), =20 -/* - * Set by drivers which want cpufreq core to check if CPU is running at a - * frequency present in freq-table exposed by the driver. For these driver= s if - * CPU is found running at an out of table freq, we will try to set it to = a freq - * from the table. And if that fails, we will stop further boot process by - * issuing a BUG_ON(). - */ -#define CPUFREQ_NEED_INITIAL_FREQ_CHECK BIT(5) + /* + * Set by drivers which want cpufreq core to check if CPU is running at + * a frequency present in freq-table exposed by the driver. For these + * drivers if CPU is found running at an out of table freq, we will try + * to set it to a freq from the table. And if that fails, we will stop + * further boot process by issuing a BUG_ON(). + */ + CPUFREQ_NEED_INITIAL_FREQ_CHECK =3D BIT(5), =20 -/* - * Set by drivers to disallow use of governors with "dynamic_switching" fl= ag - * set. - */ -#define CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING BIT(6) + /* + * Set by drivers to disallow use of governors with "dynamic_switching" + * flag set. + */ + CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING =3D BIT(6), +}; =20 int cpufreq_register_driver(struct cpufreq_driver *driver_data); void cpufreq_unregister_driver(struct cpufreq_driver *driver_data); --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f177.google.com (mail-pl1-f177.google.com [209.85.214.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B6E0A22D4C3 for ; Thu, 6 Feb 2025 09:29:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834147; cv=none; b=h5VBA0QzuFluF/1OJwUFckz60Mj7MuSeRksoO/SQykBepcoQCuTMlKWfm/aQKNP8RdbZfvmq71SgC64W1F8bFUkkt9OWu6tU/a+0rI5shmtiIAo6FNzRN0emIm7D+9J9nizxW15aBsNiqt3xDYhoSR3LVuBXQ2ftnbDT+Xg0Fc4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834147; c=relaxed/simple; bh=hNxUaqce8sjnkwzAQlWMlhW9DvX+XlFNHHx9DRtSdzs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=jTb2IlJ/xD9Ud4ZrVShanZsF5BzCJ5ymT4aaLQpvZ/ieMW+AmJ1HTs+LbNhzqkwbzKBmRUU4T6EcS5GtAPU3/C6vrc4RGUTyWMSO1vIOAdp6DDaKXR5BsjkP4ipi8JSrrA1rH13olRqiqNtyQddLeToEvLB/KjAAi2rbzzBMD8M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=GJwe2eN9; arc=none smtp.client-ip=209.85.214.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="GJwe2eN9" Received: by mail-pl1-f177.google.com with SMTP id d9443c01a7336-21c2f1b610dso17518845ad.0 for ; Thu, 06 Feb 2025 01:29:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834145; x=1739438945; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=2G2VXwMXVVwTjOULFIF4Y5hQffUd1BBYLZ5S5agX+0E=; b=GJwe2eN9R6OS5SV+yyTFO9EaC9rcaVkKbk1AbGKR/GRW0MAQtw/AP5VuDnq7I16ceR Gg2u92epq0vMtGdRboNkMm1AXjOKDdVqDloKntpGvuRWcPY+U7iK+/pjwxA2kkRz0r/O 2tv39HFfoHKReiXN9HkQDCiL/pOFvl/aDR1cM/t+MFUZwRJ2BiiMxDMboDzaF+77mpU4 IpY/yOdUD3lv4IRB7lEmagk+LAQ/ntV0Myk0j8bCBXKkuSROMa1Iwc4mLupSViXvG8Qp 3gzTGMAp07WeYyhYh1hZbSgYYQvd3lIIKWPNw/S57tx0ruOy0NnVAsf8Lc2hBgNuXcVp bN1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834145; x=1739438945; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2G2VXwMXVVwTjOULFIF4Y5hQffUd1BBYLZ5S5agX+0E=; b=P+V2oReofAezmCxkJMUKml2WGxwfBjsZ6qRvJu7158sIBsdYO8+QOIbbSGOjmaTtxq d+R/g1FKnt6ioeFYpslnOFL/1Tge/ZIO7gh/cLmxNoY3MEU8VMFIBhfhNJdwIJJmOe6v UsGKRHR0FAGgOsYczupaaNiaNbVfv2QilxE8VMuP3LiqThptQvlPnIle5VXzxfrmKMUc YItnOXuVqOf1r+qUkYR29iKL3W99+bvO38egd5w7r2clWyyTNz5tfzlJKuTTAn4uRLLm 7M/KRDZRJWsjoBEIwyc6bxiCINTlALlqQch4g76SufAlcubbUfTQT1+7ZFmaIE3JltT2 LcgA== X-Forwarded-Encrypted: i=1; AJvYcCXN0OrpzRtkQRI/Jc2J9N7/s/5qmMEZ2c0leUIgZe86/eh5WzLhCjcBaXw9mcuzuMCt8NVbteeF/oNstVc=@vger.kernel.org X-Gm-Message-State: AOJu0YwLjQwrEV81dJxZRYW04QnLUtduDbzxDz2hlaQU/hfOOPgz7c8h D3rx5wg8OMJkVrGcYvJ1JGQDPjzmSeCpBOiWxaO7GfOzU9VqIurtlWlQCmlFYkGQqWbmv7Gwb/I i X-Gm-Gg: ASbGncufuKZwBITm1DicSN7+z+TADtYxWIIvTvNJJngw4TzJpsk7pq4AyFOX8DttdvY gFdyxh6Y0cpM+C+s85rG5ggCOmIHNGoxae/gWxvlrRpVfoxZBdDs45W7bN23lU9KQ1STHI1JNp4 8m9OZRLWIiYdA55C1pRDpn18oZhrijCPcbt53Q0fW+LG5UufK6GugKJXndhM2QgfWUMUO5HYwuX 1hlhcZ2Olp+N3Cd/huop6Wh06nDscAqLGTWXggeDaQZ7FOBHpWrv50N78RsAE5Pyt1kDY2piSRN BFynUq/jj2n32wwWDg== X-Google-Smtp-Source: AGHT+IERZaH/yV6NhctlMcXLudgaGLxhDTf+gOxPascB2hUakJ8YcCEV+KZm6lvDnBVxg1aOgdZhiA== X-Received: by 2002:a17:903:8c4:b0:215:a3fd:61f5 with SMTP id d9443c01a7336-21f17dde0c8mr99801325ad.5.1738834144997; Thu, 06 Feb 2025 01:29:04 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21f3683ddc0sm8071205ad.123.2025.02.06.01.29.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:04 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Thomas Gleixner , Peter Zijlstra Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 03/14] rust: cpu: Add from_cpu() Date: Thu, 6 Feb 2025 14:58:24 +0530 Message-Id: <35ef3767cb9e65cb4c95df7ed50c6f3f6190066e.1738832118.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This implements cpu::from_cpu(), which returns a reference to Device for a CPU. The C struct is created at initialization time for CPUs and is never freed and so ARef isn't returned from this function. The new helper will be used by Rust based cpufreq drivers. Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/kernel/cpu.rs | 31 +++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 4 files changed, 34 insertions(+) create mode 100644 rust/kernel/cpu.rs diff --git a/MAINTAINERS b/MAINTAINERS index 896a307fa065..ee6709599df5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6034,6 +6034,7 @@ F: include/linux/cpuhotplug.h F: include/linux/smpboot.h F: kernel/cpu.c F: kernel/smpboot.* +F: rust/kernel/cpu.rs =20 CPU IDLE TIME MANAGEMENT FRAMEWORK M: "Rafael J. Wysocki" diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 55354e4dec14..fda1e0d8f376 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/cpu.rs b/rust/kernel/cpu.rs new file mode 100644 index 000000000000..3054165d3818 --- /dev/null +++ b/rust/kernel/cpu.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Generic CPU definitions. +//! +//! C header: [`include/linux/cpu.h`](srctree/include/linux/cpu.h) + +use crate::{bindings, device::Device, error::Result, prelude::ENODEV}; + +/// Creates a new instance of CPU's device. +/// +/// # Safety +/// +/// Reference counting is not implemented for the CPU device in the C code= . When a CPU is +/// hot-unplugged, the corresponding CPU device is unregistered, but its a= ssociated memory +/// is not freed. +/// +/// Callers must ensure that the CPU device is not used after it has been = unregistered. +/// This can be achieved, for example, by registering a CPU hotplug notifi= er and removing +/// any references to the CPU device within the notifier's callback. +pub unsafe fn from_cpu(cpu: u32) -> Result<&'static Device> { + // SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, = is a valid pointer to + // a `struct device` and is never freed by the C code. + let ptr =3D unsafe { bindings::get_cpu_device(cpu) }; + if ptr.is_null() { + return Err(ENODEV); + } + + // SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, = is a valid pointer to + // a `struct device` and is never freed by the C code. + Ok(unsafe { Device::as_ref(ptr) }) +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 496ed32b0911..415c500212dd 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -40,6 +40,7 @@ pub mod block; #[doc(hidden)] pub mod build_assert; +pub mod cpu; pub mod cred; pub mod device; pub mod device_id; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DBE6622D4FD for ; Thu, 6 Feb 2025 09:29:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834152; cv=none; b=oaqcdSCcmnOeTSg/g9gBqPi13i+pgR8RhGulkCZRD0oBAiM/Avjdsl5lcqGgDnsUIGIZQjUzzgdQqKDoaH4XDcDeq5HQN9lfjxetT4iHdCog0qvmJo7vkEou/U2YlNUcGPBeYx3HAvKPi4rT9RApQX33o+K3Lcngsi99FZ1VcQQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834152; c=relaxed/simple; bh=N5KuSHGuim/2ltuf1CgPtREiUHrSzunHBtCeRYx+xXs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Jbbzs6b3DXJj9mm3NMtaMUOcJW4AVQsz49PH+XpZYHm4WoUjKwbEv+EgujOmg+M2r/TG5siOHBtHcEKrs73H/wRYelt0J69DvitWUrbf8jKgL61KOzxPDbI4lLIY9TvvzygH+Dmd6WHIs1f/gdLo1RJWJDSNlqeHzkwLLS9rOsY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=sc77Q82G; arc=none smtp.client-ip=209.85.214.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="sc77Q82G" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2163dc5155fso12915315ad.0 for ; Thu, 06 Feb 2025 01:29:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834149; x=1739438949; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=mnnLlALAvod9HBe452p93Qf9oTal7xzFyAI477ScgZM=; b=sc77Q82GSplB60NLau89LR+M2b6Blb8An7/PuaqQytPQbrvV8RreaRXa3K4CrVrXwM EvLhxFhV1AjDeXHvFyCuTb8Pkysh3w1CFadPv1W8H+3NzekGaouLlP2zahkmqKNlaTAS aocz2PKJ5iJay0chM/YwdGJymhpNY6pa/fX3yB1c/r8OzDE5z8xbidnT8JsD/Y4tOcZ0 fw5yzBx4LBxBs5MWz8LbkhVHlmh1W58mbZxbx9eFutpohMhSG9VAf6MAg3YlTqb1rZ6G XEw96wB30BNF5EUVrNUk8AmNThbXy5SdEDtxvwqdQwJnraN/AGCoup7954Nxc7C/gs2X 3VhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834149; x=1739438949; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=mnnLlALAvod9HBe452p93Qf9oTal7xzFyAI477ScgZM=; b=uxg9OfwgmPF8RwHQBzZnnZxV83hRE9nJtZE/u+aGsaGetxG6jvv43Q5CqjjlI7rvF6 mu1ZujSlx02UscXWyhOGQiF06v/ZfVykW4kAFuqx5KpM8N0omt/GbTDeb3pNyb0pQGX8 Y9TCOEYaH0TGYAuWtdRRbptLwSkxLIw3LGmUPSrUFby6C+C7MCSoy+MiU38DWiLKAoOG CZRzLSXa8slZjvg/MZo+p930wNOnumFTEDm0DtEtitQUPFpvWgA0IDbDTObC5a9Qk8fH uTi+93dA53Z+WpGmHj0VNuNI82dQIyyALiX7WImNHdhrLxIg4wIt0OVfBo033ev6tM5h hOgQ== X-Forwarded-Encrypted: i=1; AJvYcCW5LLIglHYDBs2ABU2H7Ff/9S+7J7sTFFZ2+V3n5LfC98qIvZ10UE70PzX38qXVkw1dvBqhTohJmzC69Fo=@vger.kernel.org X-Gm-Message-State: AOJu0Yx4o0z2ZaTlXLpGfVDVs2hdFx8+BU/ctErbQGj0dfzmVp/nZGd6 96Ov/kv0FXfBnraSVnVn5wWsCKGBLy2LEGVxgQode/PihM/D04Xhx9hvoUa2iac= X-Gm-Gg: ASbGncuLt8tv6cK50Z3Ns7jjGlswpZeHm74bTNd297emDWHH8Vcbk1roLHU6eAOyRSQ dFO0o/aTGUPPSsDNHaU+ErJ6l4Q4iOiK0/rSPKMP3XikbhbDNIELz/9HPeYmtJUC+iwfBMXo8fK 5Sv8w+ReGHm9Z0GZgSx9yDoS8rUNlyUlfFFqx8DUNL+fT0K5VIRotzOS0hu3/YqXELm5Wiff+Yj KX1eNFV/4wIYvSFFPbBEzbo9mLukP+JL5ILQ+tasiMew1oc4Wtfpo0U0WEhjIJi/Jw31sNAgC/f Z7IyX2E0uRQWh49uHQ== X-Google-Smtp-Source: AGHT+IFhy+AgYokZxM3HWCBUPc9xYncGxlqmLNHYEWBcgsKtPNb/mhJ3KsrxJ6CgY09YEPKvYF5m8g== X-Received: by 2002:a17:902:ce87:b0:215:5ea2:6544 with SMTP id d9443c01a7336-21f17dd685bmr96867085ad.7.1738834149070; Thu, 06 Feb 2025 01:29:09 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21f368ce622sm7994205ad.241.2025.02.06.01.29.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:08 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Yury Norov , Rasmus Villemoes Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 04/14] rust: Add cpumask helpers Date: Thu, 6 Feb 2025 14:58:25 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In order to prepare for adding Rust abstractions for cpumask, this patch adds cpumask helpers. Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/helpers/cpumask.c | 40 +++++++++++++++++++++++++++++++++ rust/helpers/helpers.c | 1 + 4 files changed, 43 insertions(+) create mode 100644 rust/helpers/cpumask.c diff --git a/MAINTAINERS b/MAINTAINERS index ee6709599df5..bfc1bf2ebd77 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4021,6 +4021,7 @@ F: lib/cpumask_kunit.c F: lib/find_bit.c F: lib/find_bit_benchmark.c F: lib/test_bitmap.c +F: rust/helpers/cpumask.c F: tools/include/linux/bitfield.h F: tools/include/linux/bitmap.h F: tools/include/linux/bits.h diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index fda1e0d8f376..59b4bc49d039 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/cpumask.c b/rust/helpers/cpumask.c new file mode 100644 index 000000000000..49267ad33b3c --- /dev/null +++ b/rust/helpers/cpumask.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void rust_helper_cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp) +{ + cpumask_set_cpu(cpu, dstp); +} + +void rust_helper_cpumask_clear_cpu(int cpu, struct cpumask *dstp) +{ + cpumask_clear_cpu(cpu, dstp); +} + +void rust_helper_cpumask_setall(struct cpumask *dstp) +{ + cpumask_setall(dstp); +} + +unsigned int rust_helper_cpumask_weight(struct cpumask *srcp) +{ + return cpumask_weight(srcp); +} + +void rust_helper_cpumask_copy(struct cpumask *dstp, const struct cpumask *= srcp) +{ + cpumask_copy(dstp, srcp); +} + +bool rust_helper_zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags) +{ + return zalloc_cpumask_var(mask, flags); +} + +#ifndef CONFIG_CPUMASK_OFFSTACK +void rust_helper_free_cpumask_var(cpumask_var_t mask) +{ + free_cpumask_var(mask); +} +#endif diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 0640b7e115be..de2341cfd917 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -11,6 +11,7 @@ #include "bug.c" #include "build_assert.c" #include "build_bug.c" +#include "cpumask.c" #include "cred.c" #include "device.c" #include "err.c" --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pj1-f46.google.com (mail-pj1-f46.google.com [209.85.216.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC0C422DF91 for ; Thu, 6 Feb 2025 09:29:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834155; cv=none; b=e8wlibKM7fM+dmkXTOdGN4puVtYdY0nfs9Epp6fpJsP4t2Lk3AA8MkhlRIVa6bf3tde7Vy2wvhTzqSN9TBJOyH81vqIUGxkamYbiQxj1f7Wfi3i4Lv1M1kMkQjd8nEGggz2vFDk1lXR4xs93yCdlLlhSdepJh8SI5a2TUAA7vIs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834155; c=relaxed/simple; bh=MHUCeyWGdx4+O3tnwVilY3SO1wVVguCwKtOWnA285dU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=abTuM/XKJs8OXNOCIVeQet/EXhx+7E4mMW4QaHpb/nZKIw7JyaVRxVF+iW+CJRarbpBUOgpQbEbvLjOVFXhaCRzyTPlGmRH/a8dYCFKbIGNz1Vl9zIKHQAA5OvWqqODM/EpkUU0+kHBydijLX1yoUsR1BBNUbHvCHtqTxLBtPbA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=o42qFJG6; arc=none smtp.client-ip=209.85.216.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="o42qFJG6" Received: by mail-pj1-f46.google.com with SMTP id 98e67ed59e1d1-2f9cd8ecbceso1244155a91.0 for ; Thu, 06 Feb 2025 01:29:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834153; x=1739438953; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rVs26K7IXsmnaOMuPyO8w7b9kowAGAQ924n9Jrfg/D0=; b=o42qFJG6IeOO+/its2C7fFn34N1uoc3D2vfglSSmlHbkOiJfwBw9ncik9C0/CzAazY axzbpqxFevsWvSLAFSlxa5qd0xGaU6ds+rmAEKO5LTdmwdmCVyLLpjf/J0qIGj+n0x9+ BB6AlQ21KGMiccn89K3dIEu5i8cljCGyONXVisCuv5nBBkxymLUxMGmW7UMYxxQTBbrY mvUzEGSN1PU7/+PE8CD6Gi3uRimsAvdNe1RyutkyeAnrORvmmn/TqWsAJFoitORlPVf3 nVqhmZaForxUY8xjr4peswh/grWR1TRa1ceQBgHwOde82fXMpZuJhvBMbCqfqzgCjc04 Z1LA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834153; x=1739438953; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rVs26K7IXsmnaOMuPyO8w7b9kowAGAQ924n9Jrfg/D0=; b=Kp66QSmSAuQsTxV9RTaiKTlVkNa58uZ4pGUULD8xU9CzAc4UcqrwVVeoJbXJEDVcdq N9OWYSk6w7QItMGHlyBEAVyCXanO/OoHqqIN5z1lY7jZiWBlemPZVsKC5gymphsYwaEn UJmi4uPeujhRtBY53/fYZVja6MtB/M/QzdnUoonGuPhC/3EgI85BejdcdVcTtup/0FSB GiseUxE8JW4LPdT2cLXpB7RhvQRh/2QfOVnEdV+V5NKIiia3evIdhXlxH+rI3T9/qhDr BVe3w+bfXyAZCMAG8MmUgdmeTf7JazQcd+hFmrf+H4eotUja15TIKG8A8ky36GMYrbCS vC/Q== X-Forwarded-Encrypted: i=1; AJvYcCXifkIIPegJU9tXMhpj97l/gTv0Tip8CMB3wORaYkKBGJOF99x6eblDXQvKNhN4Vx3Oq5Lzoth5UQXFyq8=@vger.kernel.org X-Gm-Message-State: AOJu0YxCfFbBm+EDS5Rg8LQf0X5CWa+1pXUMCo3+hWXCRAMxGpSIpaJ8 +tgf2lkPLLrwq8BRlex2DPlzG06fY7Wrge9FseNKXxYtasgTxdvRIEbgBgpi7Yg= X-Gm-Gg: ASbGncuShS7iAvg0T7iVt9TYDXA5pM70ayglzYP+NBo0CeNX0EqT5PIq2dD31Pdzzqu 8lDe26g2bmiem8v4/bURY8viLeuWb334lIx/uMiEPi04NT6dkEDggxA5Ts86PP6yWyQGrGSOyPu /RN/awH9YF3U5x8lwxCzVKcveHxZ9biVIS3vnKA73YZdvgyiLfFLFwwtTg2d63Rq90h9FnbJJv1 qqXG8RzHcKDFPpaXGBXLT/KjRv6c4+RqEivA83XUtosTIkDbSkSgHb8G3EOzbUm9PHmSfxHEiuq 1RH2xq0WbB6zKI5WjA== X-Google-Smtp-Source: AGHT+IGnyPwyaOO7/lgpcYGVnoHbX60CW7ZMAJ7F4lxcsN/sc25hvQOSIHnC4nQu7UJd993EFWvnJQ== X-Received: by 2002:a17:90b:5109:b0:2ee:b0b0:8e02 with SMTP id 98e67ed59e1d1-2f9e080f2femr9401731a91.28.1738834152989; Thu, 06 Feb 2025 01:29:12 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fa09a1848asm889701a91.12.2025.02.06.01.29.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:12 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Yury Norov , Rasmus Villemoes , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 05/14] rust: Add bindings for cpumask Date: Thu, 6 Feb 2025 14:58:26 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch adds basic Rust bindings for struct cpumask. These will be used by Rust based cpufreq / OPP core. Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/kernel/cpumask.rs | 138 +++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 3 files changed, 140 insertions(+) create mode 100644 rust/kernel/cpumask.rs diff --git a/MAINTAINERS b/MAINTAINERS index bfc1bf2ebd77..ff4511914e0a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4022,6 +4022,7 @@ F: lib/find_bit.c F: lib/find_bit_benchmark.c F: lib/test_bitmap.c F: rust/helpers/cpumask.c +F: rust/kernel/cpumask.rs F: tools/include/linux/bitfield.h F: tools/include/linux/bitmap.h F: tools/include/linux/bits.h diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs new file mode 100644 index 000000000000..b0be8c75a2c2 --- /dev/null +++ b/rust/kernel/cpumask.rs @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! CPU mask abstractions. +//! +//! C header: [`include/linux/cpumask.h`](srctree/include/linux/cpumask.h) + +use crate::{bindings, error::Result, prelude::ENOMEM}; + +#[cfg(not(CONFIG_CPUMASK_OFFSTACK))] +use crate::prelude::{KBox, GFP_KERNEL}; + +#[cfg(CONFIG_CPUMASK_OFFSTACK)] +use core::ptr; + +/// A simple implementation of `struct cpumask` from the C code. +pub struct Cpumask { + ptr: *mut bindings::cpumask, + owned: bool, +} + +impl Cpumask { + /// Creates empty cpumask. + #[cfg(CONFIG_CPUMASK_OFFSTACK)] + pub fn new() -> Result { + let mut ptr: *mut bindings::cpumask =3D ptr::null_mut(); + + // SAFETY: Depending on the value of `gfp_flags`, this call may sl= eep. Other than that, it + // is always safe to call this method. + if !unsafe { bindings::zalloc_cpumask_var(&mut ptr, bindings::GFP_= KERNEL) } { + return Err(ENOMEM); + } + + Ok(Self { ptr, owned: true }) + } + + /// Creates empty cpumask. + #[cfg(not(CONFIG_CPUMASK_OFFSTACK))] + pub fn new() -> Result { + let ptr =3D KBox::into_raw(KBox::new([bindings::cpumask::default()= ; 1], GFP_KERNEL)?); + + // SAFETY: Depending on the value of `gfp_flags`, this call may sl= eep. Other than that, it + // is always safe to call this method. + if !unsafe { bindings::zalloc_cpumask_var(ptr, bindings::GFP_KERNE= L) } { + return Err(ENOMEM); + } + + Ok(Self { + ptr: ptr as *mut _, + owned: true, + }) + } + + /// Creates a new abstraction instance of an existing `struct cpumask`= pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid, and non-null. + #[cfg(CONFIG_CPUMASK_OFFSTACK)] + pub unsafe fn get_cpumask(ptr: &mut *mut bindings::cpumask) -> Self { + Self { + ptr: *ptr, + owned: false, + } + } + + /// Creates a new abstraction instance of an existing `struct cpumask`= pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid, and non-null. + #[cfg(not(CONFIG_CPUMASK_OFFSTACK))] + pub unsafe fn get_cpumask(ptr: &mut bindings::cpumask_var_t) -> Self { + Self { + ptr: ptr as *mut _, + owned: false, + } + } + + /// Obtain the raw `struct cpumask *`. + pub fn as_raw(&mut self) -> *mut bindings::cpumask { + self.ptr + } + + /// Sets CPU in the cpumask. + /// + /// Update the cpumask with a single CPU. + pub fn set(&mut self, cpu: u32) { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_set_cpus()` for any CPU. + unsafe { bindings::cpumask_set_cpu(cpu, self.ptr) }; + } + + /// Clears CPU in the cpumask. + /// + /// Update the cpumask with a single CPU. + pub fn clear(&mut self, cpu: i32) { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_clear_cpu()` for any CPU. + unsafe { bindings::cpumask_clear_cpu(cpu, self.ptr) }; + } + + /// Sets all CPUs in the cpumask. + pub fn set_all(&mut self) { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_setall()`. + unsafe { bindings::cpumask_setall(self.ptr) }; + } + + /// Gets weight of a cpumask. + pub fn weight(&self) -> u32 { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_weight()`. + unsafe { bindings::cpumask_weight(self.ptr) } + } + + /// Copies cpumask. + pub fn copy(&self, dstp: &mut Self) { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_copy()`. + unsafe { bindings::cpumask_copy(dstp.as_raw(), self.ptr) }; + } +} + +impl Drop for Cpumask { + fn drop(&mut self) { + if self.owned { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of= `self`. And it is safe + // to call `free_cpumask_var()`. + unsafe { bindings::free_cpumask_var(self.ptr) } + + #[cfg(not(CONFIG_CPUMASK_OFFSTACK))] + // SAFETY: The pointer was earlier initialized from the result= of `KBox::into_raw()`. + unsafe { + drop(KBox::from_raw(self.ptr)) + }; + } + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 415c500212dd..ccbf7fa087a0 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -41,6 +41,7 @@ #[doc(hidden)] pub mod build_assert; pub mod cpu; +pub mod cpumask; pub mod cred; pub mod device; pub mod device_id; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f179.google.com (mail-pl1-f179.google.com [209.85.214.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CAB3922DFB4 for ; Thu, 6 Feb 2025 09:29:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834159; cv=none; b=b3tW0LAUQ5kSgif49w7MCFjf4/cK6mguiP0E6k0ho8c04cLqKgl3uOnnx20WREEbfRms+cEjWLwvzbiEYO8DvPfpmhmcqvynCv6SSrIuOZBi4aHgOxKiMMo85fVyRsZrYJG8GIFeLiI+zz+4LYR0ZndlnpTUOSXDDTvKdvlSwBs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834159; c=relaxed/simple; bh=3cYUP4ZgznWOZmDbqnOVZhRLIIwxzB7xzdnixIMBEUE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=XX2pTf+Of58NEP5e7IdsH9v6paXzBv5y0LhL2B/UYIQfb4sGxeEugHsGX8YBGYukhTSaxjNOf9nnghceMKkeJzuEoEme+e1gHzxGzdF8kgFDE5rNpwtdmQx7lWVWWyhLCW6mpjumoTUDh8BlTR+iyDu13cdk7f/6bAMxEEaOiEE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=ldcr8WEo; arc=none smtp.client-ip=209.85.214.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="ldcr8WEo" Received: by mail-pl1-f179.google.com with SMTP id d9443c01a7336-21c2f1b610dso17524325ad.0 for ; Thu, 06 Feb 2025 01:29:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834157; x=1739438957; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=X0B68fWX1cr1APKh0mAnlDXaXZbPEk2ia+lGAswFIw0=; b=ldcr8WEos3NDA7dj1Oeid0prRSIBJF9qx3xZabZ46t62pnQzRJrlneNzKQ1S3x4Kej GD29HX29Pp5ZeoeAHJgZuIx3HtwH9ejufb3UDfzcn9+vRV99zRYqNAxuafPbzNbkBZTE lr3CmhMWRNp64M9xuTN5sAAURXygFppkwFjSGUDC++BXUZUc34UaRhPDfS4/2VRfrJs/ 0hZMdmgYZ3WS+YEwzS+E09ua6+w9wkzWjvHIb0SCfye221+5N2pUOWkLWG6dJIM0fZuz fkD4DhvL5veiE7m9dbFmzubHpRSQV4uFa4vAECPsw1Y1CQ+pd6XpGzvrWgTN5hKhNO7X QQpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834157; x=1739438957; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=X0B68fWX1cr1APKh0mAnlDXaXZbPEk2ia+lGAswFIw0=; b=Nr4I5Cc01djB5X2vhWe+LmbK1m/PxuBLzVFJEG674MJLPHK5mAD9rwe8e5C3CwOOEM yyropfl/nSfXuEITc+8HSqMkt0zTnChBKFcBnjBh1ZTVYNfc5cQeVX6fXW6jWUZtKAtE mwxsoFJvneWIe8n3NL/hwpMU+xDU77KRUwNO2PNVmoa5mAY747fVBubGPMjr+MtR5Afj DVyW7WyCN1d26AKQ3bz4nK2Q/TQCSuyAz+Wh4Acbz/aeQ5g6wgA0SnQoW+pCF+IxSJzH mKhqCmghT2t7lmL4oCcmnO06BxSg/9qotq4WbVwA0r/jNSSlcpKnnfIyNNnbOjXHiaoc srIA== X-Forwarded-Encrypted: i=1; AJvYcCVgJ8XBRmTUlXZTpi2fP5LpInewPX0XgnJ3GVWsz3HG1h2TPqqRjJPD83ARd9rf7sk7iA8TTdHbQyo0WNM=@vger.kernel.org X-Gm-Message-State: AOJu0Yz5o/D2uGw8U2oDriGssfaVRw0PCzLiaJyLXocW0/mZfy//Vo/r XH7/sgGZqiFJTOP6HDQrHhR3XwYp/sKAKxVqIDc6RFlj9JvMlrOlbs1K0vIvTUM= X-Gm-Gg: ASbGnctQYFXtZv/BZ5XPlGG2OE0OjHOLlE4PjS3MHB1fSzeyGIv4vBkXUctYenQLUzw DXSVmrHAJdRM1+m70IUyHwlKOvaXXcPGC2L/BmUCR7zvXED6f+/X6sFaR9CgG3CDMB1QIYCMxLT XuFJecL3+NhjN9Af5JFkguUxi8+eEinOVbJApm8Ewu9ilaLMUVsui8pzzOxd2yp5Pu6Y8gksKnZ LWdyp9PfoliIEUS0T5YE/7z2Kx6K+n0Dr5eqJDJzHj9BKmtNyEOmbpk5EVyLqep7KAbiq8caWkN p7FoDsHXMjX+JcLRyA== X-Google-Smtp-Source: AGHT+IElDAOxzrGahKe43tZNe0gD8sTNEOXo/yB4R0zYTSZc3KLuS4C5s8EHFmMR+PrUabkKHjkhcg== X-Received: by 2002:a17:902:ec87:b0:216:5e6e:68cb with SMTP id d9443c01a7336-21f17df5c3amr101820155ad.16.1738834157071; Thu, 06 Feb 2025 01:29:17 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21f3653baa8sm8255655ad.73.2025.02.06.01.29.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:16 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Michael Turquette , Stephen Boyd Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org, linux-clk@vger.kernel.org Subject: [PATCH V8 06/14] rust: Add bare minimal bindings for clk framework Date: Thu, 6 Feb 2025 14:58:27 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This adds very basic bindings for the clk framework, implements only clk_get() and clk_put(). These are the bare minimum bindings required for many users and are simple enough to add in the first attempt. These will be used by Rust based cpufreq / OPP core to begin with. Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/kernel/clk.rs | 48 +++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 ++ 4 files changed, 52 insertions(+) create mode 100644 rust/kernel/clk.rs diff --git a/MAINTAINERS b/MAINTAINERS index ff4511914e0a..604717065476 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5780,6 +5780,7 @@ F: include/dt-bindings/clock/ F: include/linux/clk-pr* F: include/linux/clk/ F: include/linux/of_clk.h +F: rust/kernel/clk.rs X: drivers/clk/clkdev.c =20 COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 59b4bc49d039..4eadcf645df0 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs new file mode 100644 index 000000000000..123cdb43b115 --- /dev/null +++ b/rust/kernel/clk.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Clock abstractions. +//! +//! C header: [`include/linux/clk.h`](srctree/include/linux/clk.h) + +use crate::{ + bindings, + device::Device, + error::{from_err_ptr, Result}, + prelude::*, +}; + +use core::ptr; + +/// A simple implementation of `struct clk` from the C code. +#[repr(transparent)] +pub struct Clk(*mut bindings::clk); + +impl Clk { + /// Creates `Clk` instance for a device and a connection id. + pub fn new(dev: &Device, name: Option<&CStr>) -> Result { + let con_id =3D if let Some(name) =3D name { + name.as_ptr() as *const _ + } else { + ptr::null() + }; + + // SAFETY: It is safe to call `clk_get()`, on a device pointer ear= lier received from the C + // code. + Ok(Self(from_err_ptr(unsafe { + bindings::clk_get(dev.as_raw(), con_id) + })?)) + } + + /// Obtain the raw `struct clk *`. + pub fn as_raw(&self) -> *mut bindings::clk { + self.0 + } +} + +impl Drop for Clk { + fn drop(&mut self) { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // relinquish it now. + unsafe { bindings::clk_put(self.0) }; + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index ccbf7fa087a0..77d3b1f82154 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -40,6 +40,8 @@ pub mod block; #[doc(hidden)] pub mod build_assert; +#[cfg(CONFIG_COMMON_CLK)] +pub mod clk; pub mod cpu; pub mod cpumask; pub mod cred; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f180.google.com (mail-pl1-f180.google.com [209.85.214.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A6AB3226175 for ; Thu, 6 Feb 2025 09:29:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834163; cv=none; b=BAfBsId9rHpr4AmIAQtaD7DVN1MonX2LegolXZ8mM5QLXp1zf8jYUhjSeqD4YaLWxrYXq5T5WLM6NPbo0PYBJkRnRRKKbZ2zMYH8D4fggUiUtA92UJomqvErbQjLgmtY9P9DsS4es5Uptji5BxWVquCBZRRC6mUOjtmlxwzWxF0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834163; c=relaxed/simple; bh=bPUupsLrIu41ca6hGCG0wALTX0HU8RTO1Tyl+R7nuzo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SIXy9rjuVi5ZmOpDPA6g1uuTKL4NBs2CBKff72nrTEkYx65f6tmamkDxORdBkS+R8rhY7R5Idp10S6btW9QgxJ3iVXIPq9NO3LPRlbklKNvZQO4FxZu3mIhjXPjoN2XIihs4Y18WN7i4N04zsEjKa6MEoLTGU5VSVu1aZEhmlLI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=Lm/Ns4dq; arc=none smtp.client-ip=209.85.214.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="Lm/Ns4dq" Received: by mail-pl1-f180.google.com with SMTP id d9443c01a7336-21f3e2b4eceso4166245ad.2 for ; Thu, 06 Feb 2025 01:29:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834161; x=1739438961; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HLPBv8n1rYnynPBOyeV9rCbHyxpotow0FwOsn2TAncA=; b=Lm/Ns4dqsdB0dwgmSg5i7fTwR1O77q6JMtlOemIy4E00l+8/rslXGF1rIEFbPKIFMD 9CcKieC9aVMCc7EGh/u/JjAJjcZOoU65gadeWqDcsznN+MOjSg73doSVZsLmSsqYYfDz MokEPus3IJJVqWMvVoLi3UT0O8iTHstSmxy7srtg0S/nH1zgxk+ofb6/q/vejKhLz607 51SvoZM6LN+EGAsnFUzz4eiSyLFzEXutABBMbBWiM+i0+eLRVXvdFtMozOmHauf8meeE ssWe45iTMaD79xLZgxFrBTBiSynxf2/+ukBWOCDlxL7dUoDW7sxYdwLYVelM1MY8HwFx Uj0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834161; x=1739438961; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=HLPBv8n1rYnynPBOyeV9rCbHyxpotow0FwOsn2TAncA=; b=F08VWuTI1nU8/bqNoGyvDOuAWFuYnJgJZJIGrH6+dA0/Ye2HjYcRJ4stkHjNubY2oo KKcWAgmoQ6XQoj9dRU2qwOYRD5vFxmjv29NqEk0OZenDO+gR3R6Z6nIw9GVbTNewjg4c +pcTjFbEAL9XjNdLoCYkSVC00Ad8hl52tAYr4W3KMGcAOGrjvIj1EqWwbTGCfz/Q7654 PZDeoni2ThOHjceNPkpQy2tH+rpnNSxtiuFQLk9h2bMvp64gqFX9FJnB/dQ1Ia2vYMU3 MbLfYEO+r0KO0D3cWiyJa2+TadRi3kOdc6POnFLnvRJ514rCzoUjI02ww2OOxVJfjIJ0 hxbQ== X-Forwarded-Encrypted: i=1; AJvYcCXmB/2l+h6E40Fc+TZ7V94k5m1PHZ9edd8qNVNLXH8Hh9wybrbi9POVdNhDnSb/XHOuN18rVyJl0lqZGdM=@vger.kernel.org X-Gm-Message-State: AOJu0YyfWO+5POWgSdscqpsgZviAac/siG3HvUEncWCJp9gxENxfWTkm lJ9b3hNZwH2LznE0ZqYO3LeH7OB1RqKZhMywlb67l6M5zfBxcdoOEnTumBpTAkQ= X-Gm-Gg: ASbGncsZc3oPdKkmJFL8K55p+P0njnGqAalb4dKZyMKBkfItTp4oDrVXt2ccFDSS2gx s0yH6yt479w+Dkv/w8ZZpddY3sCIq9WeuX6W6TOV7iVqy9S75TSyd8/N/14gYZygIow3HcaVjKp kuf1XB8RJJo8E1zwX7DbkI6af8uL5eTywkZ8SCpvu4miv9yPVVzrHgDCek81hLb80KCE7Phy5PC zPxioDkcXr4IWR/9IMfqnkw+n2KY23tlS7vLidnvc61lHDZ6zus2raok4jzeyIYIuENS4SKdzR8 2fXYVgiVxNhcz1z+/w== X-Google-Smtp-Source: AGHT+IE/W0NhCGRwbtqLAwKKUgdYRFcvvn5hRH/Tb4ko9jZOCyaNyJuBFvVBTRIS/Hx2rkjxNWoO9g== X-Received: by 2002:a17:902:fc86:b0:215:5625:885b with SMTP id d9443c01a7336-21f17edb780mr104861365ad.52.1738834161000; Thu, 06 Feb 2025 01:29:21 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21f368aac7fsm8129745ad.221.2025.02.06.01.29.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:20 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Viresh Kumar , Nishanth Menon , Stephen Boyd Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 07/14] rust: Add initial bindings for OPP framework Date: Thu, 6 Feb 2025 14:58:28 +0530 Message-Id: <62c57b517a3503dee94f83f3fc284d69fb65ca1a.1738832119.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This commit adds initial Rust bindings for the Operating performance points (OPP) core. This adds bindings for struct dev_pm_opp and struct dev_pm_opp_data to begin with. Reviewed-by: Manos Pitsidianakis Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/kernel/lib.rs | 2 + rust/kernel/opp.rs | 189 ++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 rust/kernel/opp.rs diff --git a/MAINTAINERS b/MAINTAINERS index 604717065476..cda0d2b74e29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17732,6 +17732,7 @@ F: Documentation/devicetree/bindings/opp/ F: Documentation/power/opp.rst F: drivers/opp/ F: include/linux/pm_opp.h +F: rust/kernel/opp.rs =20 OPL4 DRIVER M: Clemens Ladisch diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 4eadcf645df0..7f851d5907af 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 77d3b1f82154..8956f78a2805 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -64,6 +64,8 @@ #[cfg(CONFIG_NET)] pub mod net; pub mod of; +#[cfg(CONFIG_PM_OPP)] +pub mod opp; pub mod page; #[cfg(CONFIG_PCI)] pub mod pci; diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs new file mode 100644 index 000000000000..becb33880c92 --- /dev/null +++ b/rust/kernel/opp.rs @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Operating performance points. +//! +//! This module provides bindings for interacting with the OPP subsystem. +//! +//! C header: [`include/linux/pm_opp.h`](srctree/include/linux/pm_opp.h) + +use crate::{ + bindings, + device::Device, + error::{code::*, to_result, Result}, + types::{ARef, AlwaysRefCounted, Opaque}, +}; + +use core::ptr; + +/// Dynamically created Operating performance point (OPP). +pub struct Token { + dev: ARef, + freq: usize, +} + +impl Token { + /// Adds an OPP dynamically. + pub fn new(dev: &ARef, mut data: Data) -> Result { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_add_dynamic(dev.as_raw(), = &mut data.0) })?; + Ok(Self { + dev: dev.clone(), + freq: data.freq(), + }) + } +} + +impl Drop for Token { + fn drop(&mut self) { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_remove(self.dev.as_raw(), self.freq)= }; + } +} + +/// Equivalent to `struct dev_pm_opp_data` in the C Code. +#[repr(transparent)] +pub struct Data(bindings::dev_pm_opp_data); + +impl Data { + /// Creates new instance of [`Data`]. + pub fn new(freq: usize, u_volt: usize, level: u32, turbo: bool) -> Sel= f { + Self(bindings::dev_pm_opp_data { + turbo, + freq, + u_volt, + level, + }) + } + + /// Adds an OPP dynamically. The OPP is freed once the [`Token`] gets = freed. + pub fn add_opp(self, dev: &ARef) -> Result { + Token::new(dev, self) + } + + fn freq(&self) -> usize { + self.0.freq + } +} + +/// Operating performance point (OPP). +/// +/// Wraps the kernel's `struct dev_pm_opp`. +/// +/// The pointer to `struct dev_pm_opp` is non-null and valid for the lifet= ime of the `OPP` +/// instance. +/// +/// # Invariants +/// +/// Instances of this type are reference-counted. The reference count is i= ncremented by the +/// `dev_pm_opp_get()` function and decremented by `dev_pm_opp_put`. The R= ust type `ARef` +/// represents a pointer that owns a reference count on the OPP. +/// +/// A reference to the `OPP`, `&OPP` isn't refcounted by the Rust code. + +#[repr(transparent)] +pub struct OPP(Opaque); + +// SAFETY: It's OK to send the ownership of `OPP` across thread boundaries. +unsafe impl Send for OPP {} + +// SAFETY: It's OK to access `OPP` through shared references from other th= reads because we're +// either accessing properties that don't change or that are properly sync= hronised by C code. +unsafe impl Sync for OPP {} + +// SAFETY: The type invariants guarantee that [`OPP`] is always refcounted. +unsafe impl AlwaysRefCounted for OPP { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. + unsafe { bindings::dev_pm_opp_get(self.0.get()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is = nonzero. + unsafe { bindings::dev_pm_opp_put(obj.cast().as_ptr()) } + } +} + +impl OPP { + /// Creates an owned reference to a [`OPP`] from a valid pointer. + /// + /// The refcount is incremented by the C code and will be decremented = by `dec_ref()` when the + /// ARef object is dropped. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and the OPP's refcount = is incremented. The + /// caller must also ensure that it doesn't explicitly drop the refcou= nt of the OPP, as the + /// returned ARef object takes over the refcount increment on the unde= rlying object and the + /// same will be dropped along with it. + pub unsafe fn from_raw_opp_owned(ptr: *mut bindings::dev_pm_opp) -> Re= sult> { + let ptr =3D ptr::NonNull::new(ptr).ok_or(ENODEV)?; + + // SAFETY: The safety requirements guarantee the validity of the p= ointer. + Ok(unsafe { ARef::from_raw(ptr.cast()) }) + } + + /// Creates a reference to a [`OPP`] from a valid pointer. + /// + /// The refcount is not updated by the Rust API unless the returned re= ference is converted to + /// an ARef object. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and remains valid for t= he duration of 'a. + pub unsafe fn from_raw_opp<'a>(ptr: *mut bindings::dev_pm_opp) -> Resu= lt<&'a Self> { + // SAFETY: The caller guarantees that the pointer is not dangling = and stays valid for the + // duration of 'a. The cast is okay because `OPP` is `repr(transpa= rent)`. + Ok(unsafe { &*ptr.cast() }) + } + + #[inline] + fn as_raw(&self) -> *mut bindings::dev_pm_opp { + self.0.get() + } + + /// Returns the frequency of an OPP. + pub fn freq(&self, index: Option) -> usize { + let index =3D index.unwrap_or(0); + + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_freq_indexed(self.as_raw(), inde= x) } + } + + /// Returns the voltage of an OPP. + pub fn voltage(&self) -> usize { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_voltage(self.as_raw()) } + } + + /// Returns the level of an OPP. + pub fn level(&self) -> u32 { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_level(self.as_raw()) } + } + + /// Returns the power of an OPP. + pub fn power(&self) -> usize { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_power(self.as_raw()) } + } + + /// Returns the required pstate of an OPP. + pub fn required_pstate(&self, index: u32) -> u32 { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_required_pstate(self.as_raw(), i= ndex) } + } + + /// Returns true if the OPP is turbo. + pub fn is_turbo(&self) -> bool { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_is_turbo(self.as_raw()) } + } +} --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f177.google.com (mail-pl1-f177.google.com [209.85.214.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8310022F14E for ; Thu, 6 Feb 2025 09:29:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834167; cv=none; b=V7VJQsPKe4ZK46fRzW/hX3WIxX5Wche9axJfciCoHDRIIabovo0hfJHBbqn4I2cAmGY+o4UpB/80THeIjdmCIgwDwO0EPey6ZPXTssX4bflxs/VCfslaBEE5vGPC1rKwhH70nmW9GSWbJsZPyStbb8MfbHhClwS28BJgXLSyqKc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834167; c=relaxed/simple; bh=Oa2XFgSHeunQUvvePEymJCrKZVVgYdxYRhH8wlmfyPc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=H+5pxn2ZNWdJ9hV/Jh4P09fShL+kNYixsMcEE26UJnOUrMpqZKK6x5Ngc+kfwUtEjKw4ENY9ZB9HezVoLfucqM9YrW0GpO7TZhvIvRcNxOJbdsYM1T/b5oZArU0lGj2O0yYrBxz2w1iLVUDJuCjvPQuw3AeH1RzLG7PMKp2cHtI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=pHageWcl; arc=none smtp.client-ip=209.85.214.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="pHageWcl" Received: by mail-pl1-f177.google.com with SMTP id d9443c01a7336-21f40deb941so2748545ad.2 for ; Thu, 06 Feb 2025 01:29:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834165; x=1739438965; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=2le/vHJEXggx9Bs0rUuIVJtSrtEWf3xR+mhgiTrMzXc=; b=pHageWcll7aCohUppAziwRtNXQcE21aWQxRVk+lBHK4jvrRbkJHQ1Ek8HxtHNU/uKm oY2oHUSfe4mdlSFyCnPvy7v8wq9cEnnSiLCMf2eGR+T7X987EcVxXkRg5hGwWcGMbFn6 qwVrGJBqrgbvL/hrqAVQQRlurr7DGbnArZb8r7ANVSKuMWFzOal4w7UH30nqmo2u8Yfg pwJRdf4gbLwNmVHAeMYzwTJ9uMUthFH5DSqD4+DrLYe3Roct8g3CNfzUSiSn3VHNvfAr igLVMPQKc9VG1i4X8g9LyyoEZg9hmNwJDOr5KO1MuSexFKHLXnDTK8NNWA+EXPH6vyuW MqsQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834165; x=1739438965; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2le/vHJEXggx9Bs0rUuIVJtSrtEWf3xR+mhgiTrMzXc=; b=HQI2Fau4QWYzwHL5kLXATKiRRpI0/0Ay1DURq33v0zF8w8GZ72NylMEEdISvcqz8Ce ICN6IRJEpxBwPO5Ml7QEO+uLvX7Dgucr9U+vJRqHwqP7luPTz9fklcG6P9Z1ml6mFGYK UbYFZmBZVEi47fOOAnmm+YX0C9c1SzzYBwyQIt1t/dq414VHcEsrrhX9yLgaaSlPTQux mUkKPwpAydp3QtYH5AK16EZ1A78V5NIZixC2GFTrXnyl+JPIIsrLHV5k/rwrwCqlD6gT +P8AYBG2NXUjrGlYgJd+G1482RKEMdTiuvPv87Guc2MRoskxLcJPZO8FoQbO+CFYKgA+ 93Kg== X-Forwarded-Encrypted: i=1; AJvYcCUcJ9tdoj0lyYvG3U1SxDvd+YsiyRkKMR7SUCbb3fYC17XyW4B3NAqVtevotv0TSZ46n/b8Rg4lIPBQ7UY=@vger.kernel.org X-Gm-Message-State: AOJu0YxszDw5+ylZEJEdFXaZt1YpoNKKZ/ljeeFWRSX+drzH0cPgzOCJ Q8pDX4RH7YE5gHAzkoiFQyWnTofUJ60Ygo/RTUJg4oPsbssumyRlkZhqRitSlyo= X-Gm-Gg: ASbGncvJbMjBEwgx/I+GK60g2d+APu4zPBMTlLl2qa8g2bBNoOidKawNnE6WLLpXgiD x2Drajs5iwkzQNhYXonGdlW6h9f+BxZSamiPj+RX2ZCmw7/jUuIFvV7lKoZIWcDJLukdYbeayEy RVOQji8QQPwXXUyT5+suXuXe4W9d+khrz+Z0ji8mYFuBfXZXYU59CAL9g4kTJzVEjcnjIr8/hnm awPUPFeO8e8U3DjIb+N1XB0nWwYnYZ0+fNEhtBpYYqEBQFX31Kmm6GjFmektp3b+ZLUB6XK5YeC vwheE4Gl2ebChzq99g== X-Google-Smtp-Source: AGHT+IE8FkDTE8Y0kYGkWDg9FsTO+r75g3OEwtTMrWsDV3pD2JpFL7oND4Nj0xfIcPFIIU2ypRG81w== X-Received: by 2002:a17:902:f54b:b0:21f:1553:12b5 with SMTP id d9443c01a7336-21f17ec7bcemr112589125ad.36.1738834164608; Thu, 06 Feb 2025 01:29:24 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21f3650cde8sm8291475ad.45.2025.02.06.01.29.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:24 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Viresh Kumar , Nishanth Menon , Stephen Boyd , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 08/14] rust: Extend OPP bindings for the OPP table Date: Thu, 6 Feb 2025 14:58:29 +0530 Message-Id: <3be7d783c3447cc62725fdd9fbd6d34166c796cb.1738832119.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This extends OPP bindings with the bindings for the struct opp_table. Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 382 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 381 insertions(+), 1 deletion(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index becb33880c92..c0daeadfb188 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -8,8 +8,9 @@ =20 use crate::{ bindings, + cpumask::Cpumask, device::Device, - error::{code::*, to_result, Result}, + error::{code::*, from_err_ptr, to_result, Error, Result}, types::{ARef, AlwaysRefCounted, Opaque}, }; =20 @@ -67,6 +68,385 @@ fn freq(&self) -> usize { } } =20 +/// OPP search types. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum SearchType { + /// Search for exact value. + Exact, + /// Search for highest value less than equal to value. + Floor, + /// Search for lowest value greater than equal to value. + Ceil, +} + +/// Operating performance point (OPP) table. +/// +/// Wraps the kernel's `struct opp_table`. +/// +/// The pointer stored in `Self` is non-null and valid for the lifetime of= the `Table`. +pub struct Table { + ptr: *mut bindings::opp_table, + dev: ARef, + em: bool, + of: bool, + cpumask: Option, +} + +// SAFETY: It is okay to send ownership of `Table` across thread boundarie= s. +unsafe impl Send for Table {} + +// SAFETY: It's OK to access `Table` through shared references from other = threads because we're +// either accessing properties that don't change or that are properly sync= hronised by C code. +unsafe impl Sync for Table {} + +impl Table { + /// Creates a new OPP table instance from raw pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid and non-null. + unsafe fn from_raw_table(ptr: *mut bindings::opp_table, dev: &ARef) -> Self { + // SAFETY: By the safety requirements, ptr is valid and its refcou= nt will be incremented. + unsafe { bindings::dev_pm_opp_get_opp_table_ref(ptr) }; + + Self { + ptr, + dev: dev.clone(), + em: false, + of: false, + cpumask: None, + } + } + + /// Find OPP table from device. + pub fn from_dev(dev: &Device) -> Result { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. Refcount of the OPP table is incremented by the C= code. + let ptr =3D from_err_ptr(unsafe { bindings::dev_pm_opp_get_opp_tab= le(dev.as_raw()) })?; + + Ok(Self { + ptr, + dev: dev.into(), + em: false, + of: false, + cpumask: None, + }) + } + + /// Add device tree based OPP table for the device. + #[cfg(CONFIG_OF)] + pub fn from_of(dev: &ARef, index: i32) -> Result { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. Refcount of the OPP table is incremented by the C= code. + to_result(unsafe { bindings::dev_pm_opp_of_add_table_indexed(dev.a= s_raw(), index) })?; + + // Fetch the newly created table. + let mut table =3D Self::from_dev(dev)?; + table.of =3D true; + + Ok(table) + } + + // Remove device tree based OPP table for the device. + #[cfg(CONFIG_OF)] + fn remove_of(&self) { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. We took the reference earlier from `from_of` earl= ier, it is safe to drop + // the same now. + unsafe { bindings::dev_pm_opp_of_remove_table(self.dev.as_raw()) }; + } + + /// Add device tree based OPP table for CPU devices. + #[cfg(CONFIG_OF)] + pub fn from_of_cpumask(dev: &Device, cpumask: &mut Cpumask) -> Result<= Self> { + // SAFETY: The cpumask is valid and the returned ptr will be owned= by the [`Table`] + // instance. + to_result(unsafe { bindings::dev_pm_opp_of_cpumask_add_table(cpuma= sk.as_raw()) })?; + + // Fetch the newly created table. + let mut table =3D Self::from_dev(dev)?; + + let mut mask =3D Cpumask::new()?; + cpumask.copy(&mut mask); + table.cpumask =3D Some(mask); + + Ok(table) + } + + // Remove device tree based OPP table for CPU devices. + #[cfg(CONFIG_OF)] + fn remove_of_cpumask(&self, mut cpumask: Cpumask) { + // SAFETY: The cpumask is valid and we took the reference from `fr= om_of_cpumask` earlier, + // it is safe to drop the same now. + unsafe { bindings::dev_pm_opp_of_cpumask_remove_table(cpumask.as_r= aw()) }; + } + + /// Returns the number of OPPs in the table. + pub fn opp_count(&self) -> Result { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + let ret =3D unsafe { bindings::dev_pm_opp_get_opp_count(self.dev.a= s_raw()) }; + if ret < 0 { + Err(Error::from_errno(ret)) + } else { + Ok(ret as u32) + } + } + + /// Returns max clock latency of the OPPs in the table. + pub fn max_clock_latency(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_clock_latency(self.dev.as_ra= w()) } + } + + /// Returns max volt latency of the OPPs in the table. + pub fn max_volt_latency(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_volt_latency(self.dev.as_raw= ()) } + } + + /// Returns max transition latency of the OPPs in the table. + pub fn max_transition_latency(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_transition_latency(self.dev.= as_raw()) } + } + + /// Returns the suspend OPP. + pub fn suspend_freq(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_suspend_opp_freq(self.dev.as_raw= ()) } + } + + /// Synchronizes regulators used by the OPP table. + pub fn sync_regulators(&self) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_sync_regulators(self.dev.a= s_raw()) }) + } + + /// Gets sharing CPUs. + pub fn sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result<()>= { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_get_sharing_cpus(dev.as_ra= w(), cpumask.as_raw()) }) + } + + /// Sets sharing CPUs. + pub fn set_sharing_cpus(&mut self, cpumask: &mut Cpumask) -> Result<()= > { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_set_sharing_cpus(self.dev.as_raw(), cpuma= sk.as_raw()) + })?; + + if let Some(mask) =3D self.cpumask.as_mut() { + // Update the cpumask as this will be used while removing the = table. + cpumask.copy(mask); + } + + Ok(()) + } + + /// Gets sharing CPUs from Device tree. + #[cfg(CONFIG_OF)] + pub fn of_sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result<= ()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_of_get_sharing_cpus(dev.as_raw(), cpumask= .as_raw()) + }) + } + + /// Updates the voltage value for an OPP. + pub fn adjust_voltage( + &self, + freq: usize, + u_volt: usize, + u_volt_min: usize, + u_volt_max: usize, + ) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_adjust_voltage( + self.dev.as_raw(), + freq, + u_volt, + u_volt_min, + u_volt_max, + ) + }) + } + + /// Sets a matching OPP based on frequency. + pub fn set_rate(&self, freq: usize) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_set_rate(self.dev.as_raw()= , freq) }) + } + + /// Sets exact OPP. + pub fn set_opp(&self, opp: &OPP) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_set_opp(self.dev.as_raw(),= opp.as_raw()) }) + } + + /// Finds OPP based on frequency. + pub fn opp_from_freq( + &self, + mut freq: usize, + available: Option, + index: Option, + stype: SearchType, + ) -> Result> { + let rdev =3D self.dev.as_raw(); + let index =3D index.unwrap_or(0); + + let ptr =3D from_err_ptr(match stype { + SearchType::Exact =3D> { + if let Some(available) =3D available { + // SAFETY: The requirements are satisfied by the exist= ence of `Device` and + // its safety requirements. The returned ptr will be o= wned by the new [`OPP`] + // instance. + unsafe { + bindings::dev_pm_opp_find_freq_exact_indexed(rdev,= freq, index, available) + } + } else { + return Err(EINVAL); + } + } + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_freq_ceil_indexed(rdev, &mut fre= q as *mut usize, index) + }, + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_freq_floor_indexed(rdev, &mut fr= eq as *mut usize, index) + }, + })?; + + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp_owned(ptr) } + } + + /// Finds OPP based on level. + pub fn opp_from_level(&self, mut level: u32, stype: SearchType) -> Res= ult> { + let rdev =3D self.dev.as_raw(); + + let ptr =3D from_err_ptr(match stype { + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Exact =3D> unsafe { bindings::dev_pm_opp_find_leve= l_exact(rdev, level) }, + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_level_ceil(rdev, &mut level as *= mut u32) + }, + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_level_floor(rdev, &mut level as = *mut u32) + }, + })?; + + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp_owned(ptr) } + } + + /// Finds OPP based on bandwidth. + pub fn opp_from_bw(&self, mut bw: u32, index: i32, stype: SearchType) = -> Result> { + let rdev =3D self.dev.as_raw(); + + let ptr =3D from_err_ptr(match stype { + // The OPP core doesn't support this yet. + SearchType::Exact =3D> return Err(EINVAL), + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_bw_ceil(rdev, &mut bw as *mut u3= 2, index) + }, + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_bw_floor(rdev, &mut bw as *mut u= 32, index) + }, + })?; + + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp_owned(ptr) } + } + + /// Enable the OPP. + pub fn enable_opp(&self, freq: usize) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_enable(self.dev.as_raw(), = freq) }) + } + + /// Disable the OPP. + pub fn disable_opp(&self, freq: usize) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_disable(self.dev.as_raw(),= freq) }) + } + + /// Registers with Energy model. + #[cfg(CONFIG_OF)] + pub fn of_register_em(&mut self, cpumask: &mut Cpumask) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_of_register_em(self.dev.as_raw(), cpumask= .as_raw()) + })?; + + self.em =3D true; + Ok(()) + } + + // Unregisters with Energy model. + #[cfg(all(CONFIG_OF, CONFIG_ENERGY_MODEL))] + fn of_unregister_em(&self) { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. We registered with the EM framework earlier, it i= s safe to unregister now. + unsafe { bindings::em_dev_unregister_perf_domain(self.dev.as_raw()= ) }; + } +} + +impl Drop for Table { + fn drop(&mut self) { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe + // to relinquish it now. + unsafe { bindings::dev_pm_opp_put_opp_table(self.ptr) }; + + #[cfg(CONFIG_OF)] + { + #[cfg(CONFIG_ENERGY_MODEL)] + if self.em { + self.of_unregister_em(); + } + + if self.of { + self.remove_of(); + } else if let Some(cpumask) =3D self.cpumask.take() { + self.remove_of_cpumask(cpumask); + } + } + } +} + /// Operating performance point (OPP). /// /// Wraps the kernel's `struct dev_pm_opp`. --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C777A22F16B for ; Thu, 6 Feb 2025 09:29:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834170; cv=none; b=JyqIc7wBtdLvFmEYNWCwfFEx5/6F84hRzx+iyMTimWAEsWsHWQWKYkO/3Bae71Pc8jrRQMh1N9bbsY0ljq73O9uzD30nyCUe67prHwnK4qCf0Zhlnv7oWWMzv6kJT9gEH3f/cY/FR89t32I9ZJDunlBuM8ZCMek0xRpRifIN0S0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834170; c=relaxed/simple; bh=Btyip5cttvaDpQ47Hobx3+HFANarQIo3DBo0MaIGqeo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=oT4Bpo3QfShOVbyqX+6M3O1BM45Get/pKoCucNrovIq4B7bszPml7TyrNugIOPTStbbobkWywrvZlgGmi87AN49LVSH2HCQ424GO0fMh0dOi71oERiVnDJm4JTnMbs8Z+T5enPDXEltvUmJnL741+F2Tcu8MjGkjJO3twtR8w28= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=u1LDwLou; arc=none smtp.client-ip=209.85.214.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="u1LDwLou" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-21f21cc7af5so9178965ad.2 for ; Thu, 06 Feb 2025 01:29:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834168; x=1739438968; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=SCUMLmrIOnRhbVUxbyJm2yfzH22vl8wPDByGbPiWd2g=; b=u1LDwLou7bY0gbt3sI7wKyY873eAsAJyJtEaPltZHeMETsh3CPeRNci3ZrT/HzcI7h bJ+6BfrbvVj/p9RenwbTBpyIJ6RiuYBaW5b+0kXWM1uI4RHERj7UENOH5hhrkc9SbVX3 e6+mX2QiJYzGxrB3qb97uYrFlYEXQN1hVuNnpW2XxyET/nOnRw4gzccCA6eZlUrV9zsn JpOHvs7e7TVjwyRXq8o6yhmeRgVK69xmXiimow6POEwyVN00bdI/GMuupyoKnnO4gNt/ cgBSqKzKH/PeXAT59g6z7+DoiihZzOfgGdMii+PIfhQUOxT+wgnLzxZcgwWIZrzNvyiN qYXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834168; x=1739438968; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=SCUMLmrIOnRhbVUxbyJm2yfzH22vl8wPDByGbPiWd2g=; b=AJj9DutctiiTZSYwRhQGO715EdsUqyqF/w+pmvsVedOlKXQZw/VCF6PpMPPtgobXdC ysi2LhV/7riRJLCnPnfbfhaEii1n7hXa59D5BeTHsJowk3M6F5TJ+HBpwV8lACdzgpNr EuuAyWc+ztzGeQH7S0kTqoK+EpM7jTIOfh7MBmC7U0AupV5uHStj6tde869ZUCUDSDvu b9+d05Pr+x8Wceub0YYmepvJBJfOuROFagdKkfdbEBUGqPpXgADqSbh1WkOWq/2cW+vt c68aSxVCvX9nM/7o1lTF1YvlHf0pgPPffW9rit9bnExxdwah0MfXNYOi1la7eQkTJudf XsXg== X-Forwarded-Encrypted: i=1; AJvYcCWLF9KIitTuF8g0DM4AufNmDHOSFb2/08/y6qA7gjAVNujGD+VAoHHIzlP2CvuQuw3aRcdyk8r7pzrCMQ0=@vger.kernel.org X-Gm-Message-State: AOJu0YxtjC062WLMmab7SPmkD+ujPNCk14rzPzvHxVozjm2cacOxumKH 99PeIjnJ90h65aBndmBnZJviuVgVFV067u6mAxGeyovhIdjNxDT1KvkEAKRwE/E= X-Gm-Gg: ASbGncu190j5iIwyxG1gXfZSZDrKLv9OiGrE+oLBPX55yw+uG1nlQUsWbJ28KibiZ5x qw7Jzx5YnSR+NOvBgtDfDlD/Lxmps/Su0OfY13Kb98ciEpokhjRBheF9P5Wyv+FtmbfIMjWKOgt VQCdHM2ZT4fBODzEe1cAKOXV7rKBUkI3q3NZpvKnFTBPEK0Vgx74Scfzmi/x0mFy2qZ/b22IKKC Bi1qRICy0vUzikWWuj95fiabKfk8xZ1InsHYnxq7HPxWNjZdb5+z9IDwQf4eKzZ1alr1APrEhJA qwPjNO8Cg6wt56/PZw== X-Google-Smtp-Source: AGHT+IHmOhiNOHtcB647gHK2pP1h0sRGNI8hEpCMxo+dj0zatC2leoJLviSo0fMpbheyGPKxBwoovQ== X-Received: by 2002:a05:6a21:8dca:b0:1e1:ae4a:1d42 with SMTP id adf61e73a8af0-1ede88ad419mr13625445637.31.1738834168119; Thu, 06 Feb 2025 01:29:28 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-ad51aeb8d09sm822696a12.15.2025.02.06.01.29.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:27 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Viresh Kumar , Nishanth Menon , Stephen Boyd , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 09/14] rust: Extend OPP bindings for the configuration options Date: Thu, 6 Feb 2025 14:58:30 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This extends OPP bindings with the bindings for the OPP core configuration options. Reviewed-by: Manos Pitsidianakis Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 262 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 2 deletions(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index c0daeadfb188..8028245e94aa 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -10,11 +10,28 @@ bindings, cpumask::Cpumask, device::Device, - error::{code::*, from_err_ptr, to_result, Error, Result}, + error::{code::*, from_err_ptr, from_result, to_result, Error, Result, = VTABLE_DEFAULT_ERROR}, + prelude::*, + str::CString, types::{ARef, AlwaysRefCounted, Opaque}, }; =20 -use core::ptr; +use core::{marker::PhantomData, ptr}; + +use macros::vtable; + +// Creates a null-terminated slice of pointers to Cstrings. +fn to_c_str_array(names: &[CString]) -> Result> { + // Allocated a null-terminated vector of pointers. + let mut list =3D KVec::with_capacity(names.len() + 1, GFP_KERNEL)?; + + for name in names.iter() { + list.push(name.as_ptr() as _, GFP_KERNEL)?; + } + + list.push(ptr::null(), GFP_KERNEL)?; + Ok(list) +} =20 /// Dynamically created Operating performance point (OPP). pub struct Token { @@ -79,6 +96,247 @@ pub enum SearchType { Ceil, } =20 +/// Implement this trait to provide OPP Configuration callbacks. +#[vtable] +pub trait ConfigOps { + /// Called by the OPP core to configure OPP clks. + fn config_clks(_dev: &Device, _table: &Table, _opp: &OPP, _scaling_dow= n: bool) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Called by the OPP core to configure OPP regulators. + fn config_regulators( + _dev: &Device, + _opp_old: &OPP, + _opp_new: &OPP, + _data: *mut *mut bindings::regulator, + _count: u32, + ) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } +} + +/// Config token returned by the C code. +pub struct ConfigToken(i32); + +impl Drop for ConfigToken { + fn drop(&mut self) { + // SAFETY: Its safe to return the configuration token number previ= ously received from the C + // code. + unsafe { bindings::dev_pm_opp_clear_config(self.0) }; + } +} + +/// Equivalent to `struct dev_pm_opp_config` in the C Code. +#[derive(Default)] +pub struct Config { + clk_names: Option>, + prop_name: Option, + regulator_names: Option>, + supported_hw: Option>, + required_dev: Option>, + required_dev_index: Option, + _data: PhantomData, +} + +impl Config { + /// Creates a new instance of [`Config`]. + pub fn new() -> Self { + Self { + clk_names: None, + prop_name: None, + regulator_names: None, + supported_hw: None, + required_dev: None, + required_dev_index: None, + _data: PhantomData, + } + } + + /// Initializes clock names. + pub fn set_clk_names(mut self, names: KVec) -> Result { + // Already configured. + if self.clk_names.is_some() { + return Err(EBUSY); + } + + if names.is_empty() { + return Err(EINVAL); + } + + self.clk_names =3D Some(names); + Ok(self) + } + + /// Initializes property name. + pub fn set_prop_name(mut self, name: CString) -> Result { + // Already configured. + if self.prop_name.is_some() { + return Err(EBUSY); + } + + self.prop_name =3D Some(name); + Ok(self) + } + + /// Initializes regulator names. + pub fn set_regulator_names(mut self, names: KVec) -> Result { + // Already configured. + if self.regulator_names.is_some() { + return Err(EBUSY); + } + + if names.is_empty() { + return Err(EINVAL); + } + + self.regulator_names =3D Some(names); + + Ok(self) + } + + /// Initializes required devices. + pub fn set_required_dev(mut self, dev: ARef, index: u32) -> Re= sult { + // Already configured. + if self.required_dev.is_some() { + return Err(EBUSY); + } + + self.required_dev =3D Some(dev); + self.required_dev_index =3D Some(index); + Ok(self) + } + + /// Initializes supported hardware. + pub fn set_supported_hw(mut self, hw: KVec) -> Result { + // Already configured. + if self.supported_hw.is_some() { + return Err(EBUSY); + } + + if hw.is_empty() { + return Err(EINVAL); + } + + self.supported_hw =3D Some(hw); + Ok(self) + } + + /// Sets the configuration with the OPP core. + pub fn set(self, dev: &Device) -> Result { + let (_clk_list, clk_names) =3D match &self.clk_names { + Some(x) =3D> { + let list =3D to_c_str_array(x)?; + let ptr =3D list.as_ptr(); + (Some(list), ptr) + } + None =3D> (None, ptr::null()), + }; + + let (_regulator_list, regulator_names) =3D match &self.regulator_n= ames { + Some(x) =3D> { + let list =3D to_c_str_array(x)?; + let ptr =3D list.as_ptr(); + (Some(list), ptr) + } + None =3D> (None, ptr::null()), + }; + + let prop_name =3D match &self.prop_name { + Some(x) =3D> x.as_char_ptr(), + None =3D> ptr::null(), + }; + + let (supported_hw, supported_hw_count) =3D match &self.supported_h= w { + Some(x) =3D> (x.as_ptr(), x.len() as u32), + None =3D> (ptr::null(), 0), + }; + + let (required_dev, required_dev_index) =3D match &self.required_de= v { + Some(x) =3D> (x.as_raw(), self.required_dev_index.unwrap()), + None =3D> (ptr::null_mut(), 0), + }; + + let mut config =3D bindings::dev_pm_opp_config { + clk_names, + config_clks: if T::HAS_CONFIG_CLKS { + Some(Self::config_clks) + } else { + None + }, + prop_name, + regulator_names, + config_regulators: if T::HAS_CONFIG_REGULATORS { + Some(Self::config_regulators) + } else { + None + }, + supported_hw, + supported_hw_count, + + required_dev, + required_dev_index, + }; + + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. The OPP core guarantees to not use fields of `con= fig`, after this call has + // returned and so we don't need to save a copy of them for future= use + let ret =3D unsafe { bindings::dev_pm_opp_set_config(dev.as_raw(),= &mut config) }; + if ret < 0 { + Err(Error::from_errno(ret)) + } else { + Ok(ConfigToken(ret)) + } + } + + // Config's config_clks callback. + extern "C" fn config_clks( + dev: *mut bindings::device, + opp_table: *mut bindings::opp_table, + opp: *mut bindings::dev_pm_opp, + _data: *mut core::ffi::c_void, + scaling_down: bool, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: 'dev' is guaranteed by the C code to be valid. + let dev =3D unsafe { Device::get_device(dev) }; + T::config_clks( + &dev, + // SAFETY: 'opp_table' is guaranteed by the C code to be v= alid. + &unsafe { Table::from_raw_table(opp_table, &dev) }, + // SAFETY: 'opp' is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp(opp)? }, + scaling_down, + ) + .map(|()| 0) + }) + } + + // Config's config_regulators callback. + extern "C" fn config_regulators( + dev: *mut bindings::device, + old_opp: *mut bindings::dev_pm_opp, + new_opp: *mut bindings::dev_pm_opp, + regulators: *mut *mut bindings::regulator, + count: core::ffi::c_uint, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: 'dev' is guaranteed by the C code to be valid. + let dev =3D unsafe { Device::get_device(dev) }; + T::config_regulators( + &dev, + // SAFETY: 'old_opp' is guaranteed by the C code to be val= id. + unsafe { OPP::from_raw_opp(old_opp)? }, + // SAFETY: 'new_opp' is guaranteed by the C code to be val= id. + unsafe { OPP::from_raw_opp(new_opp)? }, + regulators, + count, + ) + .map(|()| 0) + }) + } +} + /// Operating performance point (OPP) table. /// /// Wraps the kernel's `struct opp_table`. --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f182.google.com (mail-pl1-f182.google.com [209.85.214.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 44C2A22F38F for ; Thu, 6 Feb 2025 09:29:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834175; cv=none; b=bEo97p8z4pfRUHCi3T5DUNyacF7uGthWSMZQCzHWEqZpTC+o5a3m6HEIkLEshrfNIJVwrehSJthK7RAVOuLDhbNaantjj/AvH7pk26yOcJVWEK10t7Dd9b2N85OvsFdmbz9IU/ThP/B1+FkxA16cUZ+AnfMuysMmSAdncHjaHX4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834175; c=relaxed/simple; bh=tnICjcIhVFFy17Cq4G+BHstf/G1WFVbXzocDK31tTZ8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YGbaAajeIyka5G+inCLQth00K4GGXxLcy0otWycfPPVSOcQGWRhm6amirdVBpukSLT0IrC1R4WxUfxNrl4Lz4aEGqGzu/P+27A9Rx7ffhV2sx+BeSUoJlAeH9l6KrAcO1m4eZmEZSNKzvsqvDz8vdyH4G6PWFZ9TAjsWAoDULIc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=y+hIGgs5; arc=none smtp.client-ip=209.85.214.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="y+hIGgs5" Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-21f11b0e580so14002505ad.1 for ; Thu, 06 Feb 2025 01:29:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834172; x=1739438972; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ssve9dmZgI6qS1KPS1tMtwF1lG6DTg964KCzf8z+2OY=; b=y+hIGgs5xX+L7rZHUvsInfj2z9m7DybqhCwxTMaF+1lW5jaFxf0kMtdaucru1YBzi5 FL9tzPDESeL3dA3fE3SEENf9aCWRB1a5OodfZban85mun2hu6xWWICzagzUUTeVKQQ4S JZP1SnnSPAbMnkk0tPf9n060hHxamGV15plwVZzG3kaUO3L+VP9FkegbDRzVcqM+Qd+p HotlUhe46yeFHCmoGA+EtMGHB/uX2sD4srgEqcoua2DC7H6cBjkHsQ/pvqhbaFChVhM1 i66wxU+G13rfxhV0SiLmGOQC40bvUjIbGu2CZrMuIktgixnseiOoWnEL4RC9wGJ2e0St iymw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834172; x=1739438972; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ssve9dmZgI6qS1KPS1tMtwF1lG6DTg964KCzf8z+2OY=; b=EV2VrtkheXoHBse1oMNUDKW/ctqYIFtggERvWd/im8heZsrnW5LI1HjMOBBRso4CQB M4BDM3bHltJRwmEeVodIM+L+kNqFyl+SmyaLxAnjJ/awBi2HwvkqbPXWv94Wp7ogcdco 7A5uDlVnJmY0Hqo7WiGRjkDW7GxxsRhpDw+GGIUd8xBU9z0IENyi/f4xxPcuiR6vMvNQ eqIDygbrDYDep4CcjQey+mLcytnUjJc18zeAV1kllJnQAIzanhWQxFj7GcRFQm47a8hn bdfQQfCO9uAXuw3esVtvLg4fFpl4XBQvIFFj0ZWfeP63oI2ScyX4Y9eLEKFG4XQoA/th 56MQ== X-Forwarded-Encrypted: i=1; AJvYcCUEm+R8cKpFoXyX+5XS6BorGpCf/pWxgyfvZO9Mxzsr3nebgNfIfIotNpzN3m+wKMG5WwgPLvakt7VBuDM=@vger.kernel.org X-Gm-Message-State: AOJu0Yw70Eosbe6sLL5V54J8qrQOdGr51YDnZc9AaTP1aY69KCk7DFJh 95aE1t7R/WxjqEfcjRUiligaYoL06L/V8TGbPJrSwscF8pMPH4fZHD14BrgtNX0= X-Gm-Gg: ASbGncuUbgar8rQRwxM4Lrn7SDpHn2PMGSz+ti8fJny78tvuBta765MtufA3qieWz2I REIfAmzINJqyDALewrlp2FG3IN9/w4DfNdGHOymHDp5fHkyoD1XTptguvWC/9G0jZ02mk7dOlBJ zw7j6ugJ9jhVvV9R3fxE4kjdVkLzgsyYlIfrlv3t355KWsRY7kbJQLmKdNWz3LO31XTAiBplcvD h7u7BQipN8ScrHS3mV7exKJLsw3WYEfbFyB29baJ/YVt7vajW9AKX+mhKV9yLCLA4/61X3eLyBL aI99Bg8m9oLQyY2Ugw== X-Google-Smtp-Source: AGHT+IHmkA9y1OofEwZ0TlDzuR/nVNF/oPVAK27Xb6GbzCKrWlWgxuFLMMtmHljRUa/MOaRJPGT9iA== X-Received: by 2002:a05:6a00:2908:b0:72d:8fa2:9998 with SMTP id d2e1a72fcca58-7303513ac4amr10286481b3a.14.1738834172363; Thu, 06 Feb 2025 01:29:32 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73048ad26c5sm854293b3a.46.2025.02.06.01.29.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:31 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Viresh Kumar Cc: linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 10/14] rust: Add initial bindings for cpufreq framework Date: Thu, 6 Feb 2025 14:58:31 +0530 Message-Id: <4dd915bf503b77166b134e4b3dfeed389b1a5bcf.1738832119.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This commit adds initial Rust bindings for the cpufreq core. This adds basic bindings for cpufreq flags, relations and cpufreq table. Reviewed-by: Manos Pitsidianakis Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/helpers/cpufreq.c | 10 ++ rust/helpers/helpers.c | 1 + rust/kernel/cpufreq.rs | 228 ++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 6 files changed, 243 insertions(+) create mode 100644 rust/helpers/cpufreq.c create mode 100644 rust/kernel/cpufreq.rs diff --git a/MAINTAINERS b/MAINTAINERS index cda0d2b74e29..f0270ceb82d9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6024,6 +6024,7 @@ F: drivers/cpufreq/ F: include/linux/cpufreq.h F: include/linux/sched/cpufreq.h F: kernel/sched/cpufreq*.c +F: rust/kernel/cpufreq.rs F: tools/testing/selftests/cpufreq/ =20 CPU HOTPLUG diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 7f851d5907af..68bf1bc5bae8 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/cpufreq.c b/rust/helpers/cpufreq.c new file mode 100644 index 000000000000..7c1343c4d65e --- /dev/null +++ b/rust/helpers/cpufreq.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#ifdef CONFIG_CPU_FREQ +void rust_helper_cpufreq_register_em_with_opp(struct cpufreq_policy *polic= y) +{ + cpufreq_register_em_with_opp(policy); +} +#endif diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index de2341cfd917..32d0462219e5 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -11,6 +11,7 @@ #include "bug.c" #include "build_assert.c" #include "build_bug.c" +#include "cpufreq.c" #include "cpumask.c" #include "cred.c" #include "device.c" diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs new file mode 100644 index 000000000000..4546a70c7063 --- /dev/null +++ b/rust/kernel/cpufreq.rs @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! CPU frequency scaling. +//! +//! This module provides bindings for interacting with the cpufreq subsyst= em. +//! +//! C header: [`include/linux/cpufreq.h`](srctree/include/linux/cpufreq.h) + +use crate::{ + bindings, + error::{code::*, to_result, Result}, + prelude::*, +}; + +use core::{ + pin::Pin, +}; + +/// Default transition latency value. +pub const ETERNAL_LATENCY: u32 =3D bindings::CPUFREQ_ETERNAL as u32; + +/// Container for cpufreq driver flags. +pub mod flags { + use crate::bindings; + + /// Set by drivers that need to update internal upper and lower bounda= ries along with the + /// target frequency and so the core and governors should also invoke = the driver if the target + /// frequency does not change, but the policy min or max may have chan= ged. + pub const NEED_UPDATE_LIMITS: u16 =3D bindings::CPUFREQ_NEED_UPDATE_LI= MITS as _; + + /// Set by drivers for platforms where loops_per_jiffy or other kernel= "constants" aren't + /// affected by frequency transitions. + pub const CONST_LOOPS: u16 =3D bindings::CPUFREQ_CONST_LOOPS as _; + + /// Set by drivers that want the core to automatically register the cp= ufreq driver as a thermal + /// cooling device. + pub const IS_COOLING_DEV: u16 =3D bindings::CPUFREQ_IS_COOLING_DEV as = _; + + /// Set by drivers for platforms that have multiple clock-domains, i.e= . supporting multiple + /// policies. With this sysfs directories of governor would be created= in cpu/cpuN/cpufreq/ + /// directory and so they can use the same governor with different tun= ables for different + /// clusters. + pub const HAVE_GOVERNOR_PER_POLICY: u16 =3D bindings::CPUFREQ_HAVE_GOV= ERNOR_PER_POLICY as _; + + /// Set by drivers which do POSTCHANGE notifications from outside of t= heir ->target() routine. + pub const ASYNC_NOTIFICATION: u16 =3D bindings::CPUFREQ_ASYNC_NOTIFICA= TION as _; + + /// Set by drivers that want cpufreq core to check if CPU is running a= t a frequency present in + /// freq-table exposed by the driver. For these drivers if CPU is foun= d running at an out of + /// table freq, the cpufreq core will try to change the frequency to a= value from the table. + /// And if that fails, it will stop further boot process by issuing a = BUG_ON(). + pub const NEED_INITIAL_FREQ_CHECK: u16 =3D bindings::CPUFREQ_NEED_INIT= IAL_FREQ_CHECK as _; + + /// Set by drivers to disallow use of governors with "dynamic_switchin= g" flag set. + pub const NO_AUTO_DYNAMIC_SWITCHING: u16 =3D bindings::CPUFREQ_NO_AUTO= _DYNAMIC_SWITCHING as _; +} + +/// CPU frequency selection relations. Each value contains a `bool` argume= nt which corresponds to +/// the Relation being efficient. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Relation { + /// Select the lowest frequency at or above target. + Low(bool), + /// Select the highest frequency below or at target. + High(bool), + /// Select the closest frequency to the target. + Close(bool), +} + +impl Relation { + // Converts from a value compatible with the C code. + fn new(val: u32) -> Result { + let efficient =3D val & bindings::CPUFREQ_RELATION_E !=3D 0; + + Ok(match val & !bindings::CPUFREQ_RELATION_E { + bindings::CPUFREQ_RELATION_L =3D> Self::Low(efficient), + bindings::CPUFREQ_RELATION_H =3D> Self::High(efficient), + bindings::CPUFREQ_RELATION_C =3D> Self::Close(efficient), + _ =3D> return Err(EINVAL), + }) + } + + /// Converts to a value compatible with the C code. + pub fn val(&self) -> u32 { + let (mut val, e) =3D match self { + Self::Low(e) =3D> (bindings::CPUFREQ_RELATION_L, e), + Self::High(e) =3D> (bindings::CPUFREQ_RELATION_H, e), + Self::Close(e) =3D> (bindings::CPUFREQ_RELATION_C, e), + }; + + if *e { + val |=3D bindings::CPUFREQ_RELATION_E; + } + + val + } +} + +/// Equivalent to `struct cpufreq_policy_data` in the C code. +#[repr(transparent)] +pub struct PolicyData(*mut bindings::cpufreq_policy_data); + +impl PolicyData { + /// Creates new instance of [`PolicyData`]. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid and non-null. + pub unsafe fn from_raw_policy_data(ptr: *mut bindings::cpufreq_policy_= data) -> Self { + Self(ptr) + } + + /// Returns the raw pointer to the C structure. + #[inline] + pub fn as_raw(&self) -> *mut bindings::cpufreq_policy_data { + self.0 + } + + /// Provides a wrapper to the generic verify routine. + pub fn generic_verify(&self) -> Result<()> { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it now. + to_result(unsafe { bindings::cpufreq_generic_frequency_table_verif= y(self.as_raw()) }) + } +} + +/// Builder for the `struct cpufreq_frequency_table` in the C code. +#[repr(transparent)] +#[derive(Default)] +pub struct TableBuilder { + entries: KVec, +} + +impl TableBuilder { + /// Creates new instance of [`TableBuilder`]. + pub fn new() -> Self { + Self { + entries: KVec::new(), + } + } + + /// Adds a new entry to the table. + pub fn add(&mut self, frequency: u32, flags: u32, driver_data: u32) ->= Result<()> { + // Adds new entry to the end of the vector. + Ok(self.entries.push( + bindings::cpufreq_frequency_table { + flags, + driver_data, + frequency, + }, + GFP_KERNEL, + )?) + } + + /// Creates [`Table`] from [`TableBuilder`]. + pub fn into_table(mut self) -> Result { + // Add last entry to the table. + self.add(bindings::CPUFREQ_TABLE_END as u32, 0, 0)?; + Table::from_builder(self.entries) + } +} + +/// A simple implementation of the cpufreq table, equivalent to the `struct +/// cpufreq_frequency_table` in the C code. +pub struct Table { + #[allow(dead_code)] + // Dynamically created table. + entries: Option>>, + + // Pointer to the statically or dynamically created table. + ptr: *mut bindings::cpufreq_frequency_table, +} + +impl Table { + /// Creates new instance of [`Table`] from [`TableBuilder`]. + fn from_builder(entries: KVec) -> R= esult { + if entries.is_empty() { + return Err(EINVAL); + } + + // Pin the entries to memory, since we are passing its pointer to = the C code. + let mut entries =3D Pin::new(entries); + + // The pointer is valid until the table gets dropped. + let ptr =3D entries.as_mut_ptr(); + + Ok(Self { + entries: Some(entries), + ptr, + }) + } + + /// Creates new instance of [`Table`] from raw pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid and non-null for the lifet= ime of the [`Table`]. + pub unsafe fn from_raw(ptr: *mut bindings::cpufreq_frequency_table) ->= Self { + Self { entries: None, ptr } + } + + /// Returns raw pointer to the `struct cpufreq_frequency_table` compat= ible with the C code. + #[inline] + pub fn as_raw(&self) -> *mut bindings::cpufreq_frequency_table { + self.ptr + } + + /// Returns `frequency` at index in the [`Table`]. + pub fn freq(&self, index: usize) -> Result { + // SAFETY: The pointer is guaranteed to be valid for the lifetime = of `self` and `index` is + // guaranteed to be within limits of the frequency table by the C = API. + Ok(unsafe { (*self.ptr.add(index)).frequency }) + } + + /// Returns `flags` at index in the [`Table`]. + pub fn flags(&self, index: usize) -> Result { + // SAFETY: The pointer is guaranteed to be valid for the lifetime = of `self` and `index` is + // guaranteed to be within limits of the frequency table by the C = API. + Ok(unsafe { (*self.ptr.add(index)).flags }) + } + + /// Returns `data` at index in the [`Table`]. + pub fn data(&self, index: usize) -> Result { + // SAFETY: The pointer is guaranteed to be valid for the lifetime = of `self` and `index` is + // guaranteed to be within limits of the frequency table by the C = API. + Ok(unsafe { (*self.ptr.add(index)).driver_data }) + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 8956f78a2805..2a42e21d57f2 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -43,6 +43,8 @@ #[cfg(CONFIG_COMMON_CLK)] pub mod clk; pub mod cpu; +#[cfg(CONFIG_CPU_FREQ)] +pub mod cpufreq; pub mod cpumask; pub mod cred; pub mod device; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0CAB122F3B6 for ; Thu, 6 Feb 2025 09:29:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834178; cv=none; b=MtqQkbbBTqdNANuAywbWs2zNpm/gaoymJbVx6suXFRNJGp/gzcen0RJz/POJRV5t2COEkcVXo1GJ2+2P+APDr/qR7cqVvrBxyQa4aATWPPAXfwSULrVRUfeg8Lv/tJEOeiaP/MHgsZdlqwd0lXZk4kQlP+A+CddjynkyjdCzTsU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834178; c=relaxed/simple; bh=hzuNhO1Q3IkyXCT/x1RQcToG9eFKeb1mwBR+qRFJhIU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=i330e4YRRwCN22N6RkXn5WvKFRKoa3JNzq6FwG4qC8A4OB1zJOHuUMtFxMJ8eAet1zJNrtUh42lEU3KIex4dNLsnJgynclyzSIOL9HLHXrbzFxErt7l8ByzDy/reh7FKXgmEluCJxOj5zdk0nQLm+TDvMa9Q1PXh9FfcDqxUwmI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=YrnBv0uV; arc=none smtp.client-ip=209.85.214.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="YrnBv0uV" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-21f0bc811dbso26495415ad.1 for ; Thu, 06 Feb 2025 01:29:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834176; x=1739438976; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BewoLF4XXJE59tcPINPOfVWWxQlIhp/bpFbTZBnmMRo=; b=YrnBv0uV3Yx55AZ0z2c3aNCCjwz2vbhEYI9GyJEyLpwU7TdDTe+f1s1VR8VbVhphbI ZTKLRtbouMd0Oy6a02qtOg1LMqoCjyJIqMdFkG8ETjOloWLhXZZzI4k/K+TPeST+4qEz lwfPIIIUELVLZxSfLcYtDQ/NATLxIjrWGxhfcosO3iiwJHZAl/NTZkkN2bWE3E/JWotP APfWJarrCgzFMPbhoos8sKOej1osj9Cc3erZJlPQb8v9pIzsGO9M5ScqTv8zEARBM+78 WfPXwW/R2eJAO9c3iFT6ep52sGU+oRbatoBmm9xM44tgVa+CtSsv3aC9FNB6FsT34Cxe VOTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834176; x=1739438976; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BewoLF4XXJE59tcPINPOfVWWxQlIhp/bpFbTZBnmMRo=; b=C41mqbBkChOUCeEJ1D60egNntU5B6/UthQ1XA0mm+9ann2rg8SMTxkhYcMVXrFKyMf SjmGuTZbrNS7maxnEwHj4iemStUvkvgbHXUSwzqIbtvds9Md0r8sxeTDgGusT4f3H/QM 5eUybC2teI95dmtX5ojuJIQE8u0VDyZdusQ9FmBFpj9fo2WzHPb2ECY4zsdofXJuGXx1 Ot9eY3njfBDjeOMJH25s7WJDSFCjMS1ShoQcz646RjlPW2bFhTAISEXmzjZsKjJgUFzD /oyiQR3EjqrwhDP4US3bd+AaEBrUGy/KfPe34doWHx67FyXv6OgdrAg9SuKkrRdYPLrS HnHQ== X-Forwarded-Encrypted: i=1; AJvYcCXUdlMGAjHcvqeLzGAGSF04vuk02lpi1NrnutaSQfeOkDvQr0P2gq7t8gLBH2fH5H3w8B81GwczjFGR2eE=@vger.kernel.org X-Gm-Message-State: AOJu0YysGJ7oCNhczbOe8L/Lv3gw2V4DhSnQ4KAlKgItc3EDG0PHRdiH AmOklwXK/yrutG9Aq41RZVS6AAUo/oHOIv1tIEWWJWBaelGGLbtmnEq2F+EL8uE= X-Gm-Gg: ASbGncsdsElqTASG+535FQj6ZepOlgmPEsXRBpuG/UUJxaGpc6z/MdsYkG+1ZwTXlWB eB4egerdRZcxgqBKNUNmuQE7/MD72xfbjVHgEko2ddfB4FSEwjgSlrXK24SAjteIQiJCZuyxBVa CgRHtvCboCcARI/ofNhNoJ6kGUj4fvtW1ehMHBkuABIZMlrDzr2qKH79F6QSLKp0oHjfL066P2h YvSN46plHfiOsYovXSHQYQjyOxW6U8zFqvuarHlLrfAIuT/S3Lkrh2uhlJ2FTkWH65ylvvIscvq Wix//lFNi29DEU2lpQ== X-Google-Smtp-Source: AGHT+IHyxQAOrCYMKMTrZjWvo9bFWT1K8eOlTJFH1d5xana7tiWBgQrQ4rVBlR8ev+13dQ3LVmaKDg== X-Received: by 2002:a05:6a21:900b:b0:1e0:c166:18ba with SMTP id adf61e73a8af0-1edf367d34bmr4946817637.12.1738834176089; Thu, 06 Feb 2025 01:29:36 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73048a9d350sm877632b3a.11.2025.02.06.01.29.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:35 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 11/14] rust: Extend cpufreq bindings for policy and driver ops Date: Thu, 6 Feb 2025 14:58:32 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This extends the cpufreq bindings with bindings for cpufreq policy and driver operations. Signed-off-by: Viresh Kumar --- rust/kernel/cpufreq.rs | 357 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 355 insertions(+), 2 deletions(-) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 4546a70c7063..63ea816017c0 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -7,15 +7,20 @@ //! C header: [`include/linux/cpufreq.h`](srctree/include/linux/cpufreq.h) =20 use crate::{ - bindings, - error::{code::*, to_result, Result}, + bindings, clk, cpumask, + device::Device, + error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR= }, prelude::*, + types::ForeignOwnable, }; =20 use core::{ pin::Pin, + ptr::self, }; =20 +use macros::vtable; + /// Default transition latency value. pub const ETERNAL_LATENCY: u32 =3D bindings::CPUFREQ_ETERNAL as u32; =20 @@ -226,3 +231,351 @@ pub fn data(&self, index: usize) -> Result { Ok(unsafe { (*self.ptr.add(index)).driver_data }) } } + +/// Equivalent to `struct cpufreq_policy` in the C code. +pub struct Policy { + ptr: *mut bindings::cpufreq_policy, + put_cpu: bool, + cpumask: cpumask::Cpumask, +} + +impl Policy { + /// Creates a new instance of [`Policy`]. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid and non-null. + pub unsafe fn from_raw_policy(ptr: *mut bindings::cpufreq_policy) -> S= elf { + Self { + ptr, + put_cpu: false, + // SAFETY: The pointer is guaranteed to be valid for the lifet= ime of `Self`. The `cpus` + // pointer is guaranteed to be valid by the C code. + cpumask: unsafe { cpumask::Cpumask::get_cpumask(&mut ((*ptr).c= pus)) }, + } + } + + fn from_cpu(cpu: u32) -> Result { + // SAFETY: It is safe to call `cpufreq_cpu_get()` for any CPU. + let ptr =3D from_err_ptr(unsafe { bindings::cpufreq_cpu_get(cpu) }= )?; + + // SAFETY: The pointer is guaranteed to be valid by the C code. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + policy.put_cpu =3D true; + Ok(policy) + } + + /// Raw pointer to the underlying cpufreq policy. + #[inline] + pub fn as_raw(&self) -> *mut bindings::cpufreq_policy { + self.ptr + } + + fn as_ref(&self) -> &bindings::cpufreq_policy { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence to the pointer. + unsafe { &(*self.ptr) } + } + fn as_mut_ref(&mut self) -> &mut bindings::cpufreq_policy { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence to the pointer. + unsafe { &mut (*self.ptr) } + } + + /// Returns the primary CPU for a cpufreq policy. + pub fn cpu(&self) -> u32 { + self.as_ref().cpu + } + + /// Returns the minimum frequency for a cpufreq policy. + pub fn min(&self) -> u32 { + self.as_ref().min + } + + /// Set the minimum frequency for a cpufreq policy. + pub fn set_min(&mut self, min: u32) -> &mut Self { + self.as_mut_ref().min =3D min; + self + } + + /// Returns the maximum frequency for a cpufreq policy. + pub fn max(&self) -> u32 { + self.as_ref().max + } + + /// Set the maximum frequency for a cpufreq policy. + pub fn set_max(&mut self, max: u32) -> &mut Self { + self.as_mut_ref().max =3D max; + self + } + + /// Returns the current frequency for a cpufreq policy. + pub fn cur(&self) -> u32 { + self.as_ref().cur + } + + /// Sets the suspend frequency for a cpufreq policy. + pub fn set_suspend_freq(&mut self, freq: u32) -> &mut Self { + self.as_mut_ref().suspend_freq =3D freq; + self + } + + /// Returns the suspend frequency for a cpufreq policy. + pub fn suspend_freq(&self) -> u32 { + self.as_ref().suspend_freq + } + + /// Provides a wrapper to the generic suspend routine. + pub fn generic_suspend(&self) -> Result<()> { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it now. + to_result(unsafe { bindings::cpufreq_generic_suspend(self.as_raw()= ) }) + } + + /// Provides a wrapper to the generic get routine. + pub fn generic_get(&self) -> Result { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it now. + Ok(unsafe { bindings::cpufreq_generic_get(self.cpu()) }) + } + + /// Provides a wrapper to the register em with OPP routine. + pub fn register_em_opp(&self) { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it now. + unsafe { bindings::cpufreq_register_em_with_opp(self.as_raw()) }; + } + + /// Gets raw pointer to cpufreq policy's CPUs mask. + pub fn cpus(&mut self) -> &mut cpumask::Cpumask { + &mut self.cpumask + } + + /// Sets clock for a cpufreq policy. + pub fn set_clk(&mut self, dev: &Device, name: Option<&CStr>) -> Result= { + let clk =3D clk::Clk::new(dev, name)?; + self.as_mut_ref().clk =3D clk.as_raw(); + Ok(clk) + } + + /// Allows frequency switching code to run on any CPU. + pub fn set_dvfs_possible_from_any_cpu(&mut self) -> &mut Self { + self.as_mut_ref().dvfs_possible_from_any_cpu =3D true; + self + } + + /// Get fast_switch_possible value. + pub fn fast_switch_possible(&self) -> bool { + self.as_ref().fast_switch_possible + } + + /// Enable/disable fast frequency switching. + pub fn set_fast_switch_possible(&mut self, val: bool) -> &mut Self { + self.as_mut_ref().fast_switch_possible =3D val; + self + } + + /// Sets transition latency for a cpufreq policy. + pub fn set_transition_latency(&mut self, latency: u32) -> &mut Self { + self.as_mut_ref().cpuinfo.transition_latency =3D latency; + self + } + + /// Set cpuinfo.min_freq. + pub fn set_cpuinfo_min_freq(&mut self, min_freq: u32) -> &mut Self { + self.as_mut_ref().cpuinfo.min_freq =3D min_freq; + self + } + + /// Set cpuinfo.max_freq. + pub fn set_cpuinfo_max_freq(&mut self, max_freq: u32) -> &mut Self { + self.as_mut_ref().cpuinfo.max_freq =3D max_freq; + self + } + + /// Set transition_delay_us, i.e. time between successive freq. change= requests. + pub fn set_transition_delay_us(&mut self, transition_delay_us: u32) ->= &mut Self { + self.as_mut_ref().transition_delay_us =3D transition_delay_us; + self + } + + /// Returns the cpufreq table for a cpufreq policy. The cpufreq table = is recreated in a + /// light-weight manner from the raw pointer. The table in C code is n= ot freed once this table + /// is dropped. + pub fn freq_table(&self) -> Result
{ + if self.as_ref().freq_table.is_null() { + return Err(EINVAL); + } + + // SAFETY: The `freq_table` is guaranteed to be valid. + Ok(unsafe { Table::from_raw(self.as_ref().freq_table) }) + } + + /// Sets the cpufreq table for a cpufreq policy. + /// + /// The cpufreq driver must guarantee that the frequency table does no= t get freed while it is + /// still being used by the C code. + pub fn set_freq_table(&mut self, table: &Table) -> &mut Self { + self.as_mut_ref().freq_table =3D table.as_raw(); + self + } + + /// Returns the data for a cpufreq policy. + pub fn data(&mut self) -> Option<::Borrowed<'_>>= { + if self.as_ref().driver_data.is_null() { + None + } else { + // SAFETY: The data is earlier set by us from [`set_data()`]. + Some(unsafe { T::borrow(self.as_ref().driver_data) }) + } + } + + // Sets the data for a cpufreq policy. + fn set_data(&mut self, data: T) -> Result<()> { + if self.as_ref().driver_data.is_null() { + // Pass the ownership of the data to the foreign interface. + self.as_mut_ref().driver_data =3D ::into_= foreign(data) as _; + Ok(()) + } else { + Err(EBUSY) + } + } + + // Returns the data for a cpufreq policy. + fn clear_data(&mut self) -> Option { + if self.as_ref().driver_data.is_null() { + None + } else { + let data =3D Some( + // SAFETY: The data is earlier set by us from [`set_data()= `]. It is safe to take + // back the ownership of the data from the foreign interfa= ce. + unsafe { ::from_foreign(self.as_ref()= .driver_data) }, + ); + self.as_mut_ref().driver_data =3D ptr::null_mut(); + data + } + } +} + +impl Drop for Policy { + fn drop(&mut self) { + if self.put_cpu { + // SAFETY: By the type invariants, we know that `self` owns a = reference, so it is safe + // to relinquish it now. + unsafe { bindings::cpufreq_cpu_put(self.as_raw()) }; + } + } +} + +/// Operations to be implemented by a cpufreq driver. +#[vtable] +pub trait Driver { + /// Driver specific data. + /// + /// Corresponds to the data retrieved via the kernel's + /// `cpufreq_get_driver_data()` function. + /// + /// Require that `Data` implements `ForeignOwnable`. We guarantee to + /// never move the underlying wrapped data structure. + type Data: ForeignOwnable; + + /// Policy specific data. + /// + /// Require that `PData` implements `ForeignOwnable`. We guarantee to + /// never move the underlying wrapped data structure. + type PData: ForeignOwnable; + + /// Policy's init callback. + fn init(policy: &mut Policy) -> Result; + + /// Policy's exit callback. + fn exit(_policy: &mut Policy, _data: Option) -> Result<()= > { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's online callback. + fn online(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's offline callback. + fn offline(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's suspend callback. + fn suspend(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's resume callback. + fn resume(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's ready callback. + fn ready(_policy: &mut Policy) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's verify callback. + fn verify(data: &mut PolicyData) -> Result<()>; + + /// Policy's setpolicy callback. + fn setpolicy(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's target callback. + fn target(_policy: &mut Policy, _target_freq: u32, _relation: Relation= ) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's target_index callback. + fn target_index(_policy: &mut Policy, _index: u32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's fast_switch callback. + fn fast_switch(_policy: &mut Policy, _target_freq: u32) -> u32 { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's adjust_perf callback. + fn adjust_perf(_policy: &mut Policy, _min_perf: usize, _target_perf: u= size, _capacity: usize) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's get_intermediate callback. + fn get_intermediate(_policy: &mut Policy, _index: u32) -> u32 { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's target_intermediate callback. + fn target_intermediate(_policy: &mut Policy, _index: u32) -> Result<()= > { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's get callback. + fn get(_policy: &mut Policy) -> Result { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's update_limits callback. + fn update_limits(_policy: &mut Policy) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's bios_limit callback. + fn bios_limit(_policy: &mut Policy, _limit: &mut u32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's set_boost callback. + fn set_boost(_policy: &mut Policy, _state: i32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's register_em callback. + fn register_em(_policy: &mut Policy) { + build_error!(VTABLE_DEFAULT_ERROR) + } +} --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pj1-f42.google.com (mail-pj1-f42.google.com [209.85.216.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54630226874 for ; Thu, 6 Feb 2025 09:29:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834183; cv=none; b=VbnogK+4ImTCT2OmqMMUV9dVGF0dHZpF2wmXgO3dJ88lZEbiZAn3e6w1mbf5UPPIDkETAZWBBtZBsauK0Zmg7dimugGNCSzwZkiKeQagnD2xzNpIAqT2mrGzaOG2XuVUjhyskT9cF3zWtUeMafaWpWSyNmpuvQoHcmu/drxnFAI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834183; c=relaxed/simple; bh=l/VIi63UGc+3u6vflgZumPAhzfpIgDQMkROcsChH9BE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YYhd4M7NDpAGh68KvJrhFWBqnNhj2WIp8ap5jQFDSrhphc5zVYr8ruiORJX5lQUJGV6NkFV9ggh23u+tGV+MDI4WXUl3ueejaBKXq9wU2TWVqHGJxK3iy+42y+BOhdqXSyiL1gaKE3yOPDWinLlhLJrYxMCVi/6l6za/XSMN3tk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=j56OlRHB; arc=none smtp.client-ip=209.85.216.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="j56OlRHB" Received: by mail-pj1-f42.google.com with SMTP id 98e67ed59e1d1-2f9ef7a3c3cso2063590a91.1 for ; Thu, 06 Feb 2025 01:29:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834180; x=1739438980; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=W6Z09wEUbdjhQQCnF4pncU5PBUEGY4K3sFzwx7fQzBM=; b=j56OlRHBbO31lKVuDT3GyLfYUebuhFd6+etnIW6OjTwS23d4ySTOUAVUulz6yrGY7A UYordM6URjWAGx1UmqVpmnY+JIA/jgzztt2xSoHC3D0BS60bh7h7dF27Ct5nkFcfh+SN YOhbRm8rFZsxsNS5MhaYOBm9bGLI0ZPuJU46PP9x38sdgFEsFZRV3xqCxAXLfvLfedvA 3qVufLtWBs3kQnHWxkL3TwmyejvqokKqL/9MWTaOmtGehHoGhn0ZPZhBCuQfhaCDaXKg aV8DyObtAw9hpk3iwJ07p6K1nPDcRffa4e9ctaMJkSdlpYAQSmlz8ggjCn4rer01qtGf QpSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834180; x=1739438980; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=W6Z09wEUbdjhQQCnF4pncU5PBUEGY4K3sFzwx7fQzBM=; b=rkEYhuq6yCV2Htjg/i3O6M6C/PZ5qaY7ZUqyR4vndMEIaBQ+J/b8owPnCS9JGZH650 7k7OC/M6+riExdS9q+bX3C7ljVcE28ZK35pNmqu9X6lk6JG0zwYmGntjbAjzNcE2D7ZH JdJPJjgj7w7whDHVd39jh/BBmQPm+1RXvuBu2wdwiHCc+jBO0bkcDdVec4vnN3biL+IC 4tSscmfKXnArgRn7mGOhsaRgpyx9/R6JN4zoY0b6tDjPo4GlFgPLKQpMn2ie3QNLqTu7 g2QxPVQRE0yF0FB4jjthorOMK+7GGEpkbbEMXh3vDT0azfiNblzpHx88etcB/nj8FGrb PAsw== X-Forwarded-Encrypted: i=1; AJvYcCWSZFvux+XPfiCmRxWo1DiS1vv8nE3S1iNd6hm2BlmzrA7w66Ux+LzXy2oof1bRlLEt4cT1g62QhQNtsVw=@vger.kernel.org X-Gm-Message-State: AOJu0Yy9B8wI8CDOLpLJDr/Yp8kDADbYz7Fx7m01YCEBuwhWIcJBzzqj okevzMKo7ctldP0xI6E5L+GNA/AeiWvkafrgpyRsQlfh4YovuzCqMdJ6sMw7/7k= X-Gm-Gg: ASbGncu5AAP6VPNLFQlyF+5UKzMvT/FyrFfB8/clz1P2GJ0QARBIHTK+WGVbJ5wT2P2 tkKkVhmEGOy/Lj7x5h6iqLqb9b4noNu1gUY9l05Iai4DEvVIp7Ir8Xxs7vrof9HoLp7TuXOAS4P NmDkiFwbpXEzCsJIKP+ca+VXd/1FLUjEsNee+TFyUdWjNwkRYhIyoXoNsojGa06GYFgJebRP6Qw E8k5sJ79sktYFv+CPpiz/LAo5fAc9CM1+yMYQaHZnp4+B0HRRMg3E5B1EBFlCnyoedm5L0sv8xV Dvdg3j9zJWzouEUrWg== X-Google-Smtp-Source: AGHT+IGvzDmiMJGRpepS/9/HxxBD6K4uQOyrmZ5Z/P0VpVjMavBRgfYTNtKdzE8d9q/kFMstDAByZQ== X-Received: by 2002:a17:90b:3b41:b0:2f7:4c7a:b5f with SMTP id 98e67ed59e1d1-2f9ff786427mr4766379a91.2.1738834179821; Thu, 06 Feb 2025 01:29:39 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2fa09b3f803sm872055a91.32.2025.02.06.01.29.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:39 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 12/14] rust: Extend cpufreq bindings for driver registration Date: Thu, 6 Feb 2025 14:58:33 +0530 Message-Id: <5860ff88ff81d09838f7786507ec47a33cf16158.1738832119.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This extends the cpufreq bindings with bindings for registering a driver. Signed-off-by: Viresh Kumar --- rust/kernel/cpufreq.rs | 475 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 473 insertions(+), 2 deletions(-) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 63ea816017c0..f92259d339d3 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -9,14 +9,17 @@ use crate::{ bindings, clk, cpumask, device::Device, - error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR= }, + devres::Devres, + error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_= DEFAULT_ERROR}, prelude::*, types::ForeignOwnable, }; =20 use core::{ + cell::UnsafeCell, + marker::PhantomData, pin::Pin, - ptr::self, + ptr::{self, addr_of_mut}, }; =20 use macros::vtable; @@ -579,3 +582,471 @@ fn register_em(_policy: &mut Policy) { build_error!(VTABLE_DEFAULT_ERROR) } } + +/// Registration of a cpufreq driver. +pub struct Registration { + drv: KBox>, + _p: PhantomData, +} + +// SAFETY: `Registration` doesn't offer any methods or access to fields wh= en shared between threads +// or CPUs, so it is safe to share it. +unsafe impl Sync for Registration {} + +#[allow(clippy::non_send_fields_in_send_ty)] +// SAFETY: Registration with and unregistration from the cpufreq subsystem= can happen from any +// thread. Additionally, `T::Data` (which is dropped during unregistratio= n) is `Send`, so it is +// okay to move `Registration` to different threads. +unsafe impl Send for Registration {} + +impl Registration { + /// Registers a cpufreq driver with the rest of the kernel. + pub fn new(name: &'static CStr, data: T::Data, flags: u16, boost: bool= ) -> Result { + let mut drv =3D KBox::new( + UnsafeCell::new(bindings::cpufreq_driver::default()), + GFP_KERNEL, + )?; + let drv_ref =3D drv.get_mut(); + + // Account for the trailing null character. + let len =3D name.len() + 1; + if len > drv_ref.name.len() { + return Err(EINVAL); + }; + + // SAFETY: `name` is a valid Cstr, and we are copying it to an arr= ay of equal or larger + // size. + let name =3D unsafe { &*(name.as_bytes_with_nul() as *const [u8]) = }; + drv_ref.name[..len].copy_from_slice(name); + + drv_ref.boost_enabled =3D boost; + drv_ref.flags =3D flags; + + // Allocate an array of 3 pointers to be passed to the C code. + let mut attr =3D KBox::new([ptr::null_mut(); 3], GFP_KERNEL)?; + let mut next =3D 0; + + // SAFETY: The C code returns a valid pointer here, which is again= passed to the C code in + // an array. + attr[next] =3D + unsafe { addr_of_mut!(bindings::cpufreq_freq_attr_scaling_avai= lable_freqs) as *mut _ }; + next +=3D 1; + + if boost { + // SAFETY: The C code returns a valid pointer here, which is a= gain passed to the C code + // in an array. + attr[next] =3D + unsafe { addr_of_mut!(bindings::cpufreq_freq_attr_scaling_= boost_freqs) as *mut _ }; + next +=3D 1; + } + attr[next] =3D ptr::null_mut(); + + // Pass the ownership of the memory block to the C code. This will= be freed when + // the [`Registration`] object goes out of scope. + drv_ref.attr =3D KBox::leak(attr) as *mut _; + + // Initialize mandatory callbacks. + drv_ref.init =3D Some(Self::init_callback); + drv_ref.verify =3D Some(Self::verify_callback); + + // Initialize optional callbacks. + drv_ref.setpolicy =3D if T::HAS_SETPOLICY { + Some(Self::setpolicy_callback) + } else { + None + }; + drv_ref.target =3D if T::HAS_TARGET { + Some(Self::target_callback) + } else { + None + }; + drv_ref.target_index =3D if T::HAS_TARGET_INDEX { + Some(Self::target_index_callback) + } else { + None + }; + drv_ref.fast_switch =3D if T::HAS_FAST_SWITCH { + Some(Self::fast_switch_callback) + } else { + None + }; + drv_ref.adjust_perf =3D if T::HAS_ADJUST_PERF { + Some(Self::adjust_perf_callback) + } else { + None + }; + drv_ref.get_intermediate =3D if T::HAS_GET_INTERMEDIATE { + Some(Self::get_intermediate_callback) + } else { + None + }; + drv_ref.target_intermediate =3D if T::HAS_TARGET_INTERMEDIATE { + Some(Self::target_intermediate_callback) + } else { + None + }; + drv_ref.get =3D if T::HAS_GET { + Some(Self::get_callback) + } else { + None + }; + drv_ref.update_limits =3D if T::HAS_UPDATE_LIMITS { + Some(Self::update_limits_callback) + } else { + None + }; + drv_ref.bios_limit =3D if T::HAS_BIOS_LIMIT { + Some(Self::bios_limit_callback) + } else { + None + }; + drv_ref.online =3D if T::HAS_ONLINE { + Some(Self::online_callback) + } else { + None + }; + drv_ref.offline =3D if T::HAS_OFFLINE { + Some(Self::offline_callback) + } else { + None + }; + drv_ref.exit =3D if T::HAS_EXIT { + Some(Self::exit_callback) + } else { + None + }; + drv_ref.suspend =3D if T::HAS_SUSPEND { + Some(Self::suspend_callback) + } else { + None + }; + drv_ref.resume =3D if T::HAS_RESUME { + Some(Self::resume_callback) + } else { + None + }; + drv_ref.ready =3D if T::HAS_READY { + Some(Self::ready_callback) + } else { + None + }; + drv_ref.set_boost =3D if T::HAS_SET_BOOST { + Some(Self::set_boost_callback) + } else { + None + }; + drv_ref.register_em =3D if T::HAS_REGISTER_EM { + Some(Self::register_em_callback) + } else { + None + }; + + // Set driver data before registering the driver, as the cpufreq c= ore may call few + // callbacks before `cpufreq_register_driver()` returns. + Self::set_data(drv_ref, data)?; + + // SAFETY: It is safe to register the driver with the cpufreq core= in the C code. + to_result(unsafe { bindings::cpufreq_register_driver(drv_ref) })?; + + Ok(Self { + drv, + _p: PhantomData, + }) + } + + /// Same as [Registration::new`], but does not return a `Registration`= instance. + /// Instead the `Registration` is owned by devres and will be revoked = / dropped, once the + /// device is detached. + pub fn new_foreign_owned( + dev: &Device, + name: &'static CStr, + data: T::Data, + flags: u16, + boost: bool, + ) -> Result<()> { + let reg =3D Self::new(name, data, flags, boost)?; + Devres::new_foreign_owned(dev, reg, GFP_KERNEL)?; + Ok(()) + } + + // Sets the data for a cpufreq driver. + fn set_data(drv: &mut bindings::cpufreq_driver, data: T::Data) -> Resu= lt<()> { + if drv.driver_data.is_null() { + // Pass the ownership of the data to the foreign interface. + drv.driver_data =3D ::into_foreign(= data) as _; + Ok(()) + } else { + Err(EBUSY) + } + } + + /// Returns the previous set data for a cpufreq driver. + pub fn data(&mut self) -> Option<::Borrowed= <'static>> { + let drv =3D self.drv.get_mut(); + + if drv.driver_data.is_null() { + None + } else { + // SAFETY: The data is earlier set by us from [`set_data()`]. + Some(unsafe { ::borrow(drv.driver_d= ata) }) + } + } + + // Clears and returns the data for a cpufreq driver. + fn clear_data(&mut self) -> Option { + let drv =3D self.drv.get_mut(); + + if drv.driver_data.is_null() { + None + } else { + // SAFETY: By the type invariants, we know that `self` owns a = reference, so it is safe + // to relinquish it now. + let data =3D Some(unsafe { ::from_f= oreign(drv.driver_data) }); + drv.driver_data =3D ptr::null_mut(); + data + } + } +} + +// cpufreq driver callbacks. +impl Registration { + // Policy's init callback. + extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> cor= e::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + + let data =3D T::init(&mut policy)?; + policy.set_data(data)?; + Ok(0) + }) + } + + // Policy's exit callback. + extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + + let data =3D policy.clear_data(); + let _ =3D T::exit(&mut policy, data); + } + + // Policy's online callback. + extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> c= ore::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::online(&mut policy).map(|()| 0) + }) + } + + // Policy's offline callback. + extern "C" fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> = core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::offline(&mut policy).map(|()| 0) + }) + } + + // Policy's suspend callback. + extern "C" fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> = core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::suspend(&mut policy).map(|()| 0) + }) + } + + // Policy's resume callback. + extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> c= ore::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::resume(&mut policy).map(|()| 0) + }) + } + + // Policy's ready callback. + extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::ready(&mut policy); + } + + // Policy's verify callback. + extern "C" fn verify_callback(ptr: *mut bindings::cpufreq_policy_data)= -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut data =3D unsafe { PolicyData::from_raw_policy_data(ptr= ) }; + T::verify(&mut data).map(|()| 0) + }) + } + + // Policy's setpolicy callback. + extern "C" fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -= > core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::setpolicy(&mut policy).map(|()| 0) + }) + } + + // Policy's target callback. + extern "C" fn target_callback( + ptr: *mut bindings::cpufreq_policy, + target_freq: u32, + relation: u32, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::target(&mut policy, target_freq, Relation::new(relation)?).= map(|()| 0) + }) + } + + // Policy's target_index callback. + extern "C" fn target_index_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::target_index(&mut policy, index).map(|()| 0) + }) + } + + // Policy's fast_switch callback. + extern "C" fn fast_switch_callback( + ptr: *mut bindings::cpufreq_policy, + target_freq: u32, + ) -> core::ffi::c_uint { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::fast_switch(&mut policy, target_freq) + } + + // Policy's adjust_perf callback. + extern "C" fn adjust_perf_callback( + cpu: u32, + min_perf: usize, + target_perf: usize, + capacity: usize, + ) { + if let Ok(mut policy) =3D Policy::from_cpu(cpu) { + T::adjust_perf(&mut policy, min_perf, target_perf, capacity); + } + } + + // Policy's get_intermediate callback. + extern "C" fn get_intermediate_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> core::ffi::c_uint { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::get_intermediate(&mut policy, index) + } + + // Policy's target_intermediate callback. + extern "C" fn target_intermediate_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::target_intermediate(&mut policy, index).map(|()| 0) + }) + } + + // Policy's get callback. + extern "C" fn get_callback(cpu: u32) -> core::ffi::c_uint { + Policy::from_cpu(cpu).map_or(0, |mut policy| T::get(&mut policy).m= ap_or(0, |f| f)) + } + + // Policy's update_limit callback. + extern "C" fn update_limits_callback(cpu: u32) { + if let Ok(mut policy) =3D Policy::from_cpu(cpu) { + T::update_limits(&mut policy); + } + } + + // Policy's bios_limit callback. + extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> core::= ffi::c_int { + from_result(|| { + let mut policy =3D Policy::from_cpu(cpu as u32)?; + + // SAFETY: The pointer is guaranteed by the C code to be valid. + T::bios_limit(&mut policy, &mut (unsafe { *limit })).map(|()| = 0) + }) + } + + // Policy's set_boost callback. + extern "C" fn set_boost_callback( + ptr: *mut bindings::cpufreq_policy, + state: i32, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for + // the duration of this call, so it is guaranteed to remain al= ive for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::set_boost(&mut policy, state).map(|()| 0) + }) + } + + // Policy's register_em callback. + extern "C" fn register_em_callback(ptr: *mut bindings::cpufreq_policy)= { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::register_em(&mut policy); + } +} + +impl Drop for Registration { + // Removes the registration from the kernel if it has completed succes= sfully before. + fn drop(&mut self) { + pr_info!("Registration dropped\n"); + let drv =3D self.drv.get_mut(); + + // SAFETY: The driver was earlier registered from `new()`. + unsafe { bindings::cpufreq_unregister_driver(drv) }; + + // Free the previously leaked memory to the C code. + if !drv.attr.is_null() { + // SAFETY: The pointer was earlier initialized from the result= of `KBox::leak`. + unsafe { drop(KBox::from_raw(drv.attr)) }; + } + + // Free data + drop(self.clear_data()); + } +} --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pl1-f173.google.com (mail-pl1-f173.google.com [209.85.214.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0532A22FE19 for ; Thu, 6 Feb 2025 09:29:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834186; cv=none; b=iiP3KEaQSEgTVyBpR11qKRxx1lm1ZTgmn2P4xD2ouyk+0TPrZMJ++j5CK07xvFT4tkGgIdmbZxPsHGt38vUl2VXwSiiJwekHyrJOMdwYXdpOMms/gthIddgc2kU/lgdpQ6T2F3WqhFGog3gTk6Q7RaLF3oLIVVuVN7xHkL2tNz8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834186; c=relaxed/simple; bh=6Nr6juVTcJnK5KJdfVIW7dgp4mA/0Bv/HaCQhKWQ1L8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=D+pCovgCk/RcAMTaOVvW5gz4jYFxTzu2tiatgxDjoCzpTYZFfQwp9w00uRenj07blmOOR5OMYRXC/eEaIyTjV9oS9gC45ZvNVD/479UXkIM2/3l2EGzDzFmXW5wYJxgnvLAKnWtNSCBeOg9TZwoDiK32U/5+QLwEy0miSxBlIMk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=KvhZ2EcZ; arc=none smtp.client-ip=209.85.214.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="KvhZ2EcZ" Received: by mail-pl1-f173.google.com with SMTP id d9443c01a7336-21f40deb941so2753995ad.2 for ; Thu, 06 Feb 2025 01:29:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834183; x=1739438983; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Q7GVksBxvKvwIJslQZYHPVaVtikmNSrbgR1tm3RBWUA=; b=KvhZ2EcZwvUuhxtx2+tAV4tI4wJXGSUSnm+dMFMj6Q6RsEjGY0T3xNOGLZ+uo6gDdf M+kvhYUlQiKV8GOcJO1OME4oyes4pBQeJdgixCsVFjcU5VRcSL5lRzA/NToGRpWhvj2+ fJTEQdyDSYTggC3PXegB9nuy6hF1Igm1pdkZK9Y/moSqGE0DrE9uVBXqj7G9SCIDg2uB NDFougi7F0n93TStKRtEqlGpgd76C2pjHH30efWxYAwe5BLwOO4gKk8TCubMkwmdvPSB R2Nhg+aEpJpqx5HVQN459D+0+k+4cvN8Hsi4vdaXctoCg5de7jFfYgq7PcdRbZbIL83D 2PbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834183; x=1739438983; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Q7GVksBxvKvwIJslQZYHPVaVtikmNSrbgR1tm3RBWUA=; b=uENp0Fzl2ze9und4QiNYfTmLL1Wl7V9vkfCnP4PL6YpOVIMdV30JFDoY3dVcmSz+pe mF1exP3HZj0XgNwE1/miEysWqpRxkkBjQn7yVhZ/0Bp4EqalPHKtXUSq3/rQvdZYV8Y0 /nbP8fRtkMB1yPx89cDIwcseFSQyP6oxWcMC8fR6vwUm1GJuXqpI5elJGmidxpmSNmNU QcstPSLD2VPwEnMH+cc+shuzH9JdJnfmZ0pM7hkro2KZiJ+TzK8DYMHMaQB0YDg4eP2r 07HsmdG+egK1pp6ieqoFco+MiXPDgx1rgHVc9InUD47dPylR4qJX1aP5ITRf0ByZWe4d xweA== X-Forwarded-Encrypted: i=1; AJvYcCUpnTQ7PJ+1BBPn24mG2aBy5AtNQjQCAml9OwxkcJd0roYSZJ5d8yMqfl3Y0pIu+fZoCB41PXL5BSuANQY=@vger.kernel.org X-Gm-Message-State: AOJu0YyzMavI6uMZncfBQDm+SspruNLjdyHwRucgBq07SZ4hlYSo6/tH oBtsdaa621cpB52LkKjHVPb15aQLvpHQvv3820rzGroxT+ob/QQEnaaYcgWXcKg= X-Gm-Gg: ASbGncutf0YP4WvcJbENVRi00sW1QmjWAU/0RgJW/5R228UsgULJ574gSyCctc+P18P ct82FCTIVyxT/vbQTc+LCIuRAS0s8HeCLPc4RXsOOSo4qaIgXqQUm7TMpaP4g1Uc9w+Z6Fu4LJc M6sv5QtW5NDxkI+kxPKeZoFAU0CRjfEmj+NFJB3yDTP+Uxu9AqU8zJky6iiBGGZjLQuvBQG0g/c KASgWsniGGS5/vW5ztbkt4TAgzh/p3BF4FlPoueHxo6kUnyLgM6WkfKj7/0T+uwHMlFyWo+5TOJ V/vHMLhCV1GemRqbqQ== X-Google-Smtp-Source: AGHT+IGILzk1MC7IIM8lCYB+bVOwC6qPckXvdAEjdQCycRHBampUmw7KPycs3BkF8bGTuy8Qvqtp5g== X-Received: by 2002:a17:902:f54b:b0:21f:1553:12b5 with SMTP id d9443c01a7336-21f17ec7bcemr112601805ad.36.1738834183178; Thu, 06 Feb 2025 01:29:43 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21f3683d5a5sm8089985ad.128.2025.02.06.01.29.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:42 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Viresh Kumar , Nishanth Menon , Stephen Boyd , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 13/14] rust: Extend OPP bindings with CPU frequency table Date: Thu, 6 Feb 2025 14:58:34 +0530 Message-Id: <5dc8ce40dd0e0ce7defb002e7f6e614d5d8a5c18.1738832119.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This commit adds bindings for CPUFreq core related API. Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index 8028245e94aa..4030953c2001 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -16,6 +16,12 @@ types::{ARef, AlwaysRefCounted, Opaque}, }; =20 +#[cfg(CONFIG_CPU_FREQ)] +use crate::cpufreq; + +#[cfg(CONFIG_CPU_FREQ)] +use core::ops::Deref; + use core::{marker::PhantomData, ptr}; =20 use macros::vtable; @@ -337,6 +343,56 @@ extern "C" fn config_regulators( } } =20 +/// CPU Frequency table created from OPP entries. +#[cfg(CONFIG_CPU_FREQ)] +pub struct FreqTable { + dev: ARef, + table: cpufreq::Table, +} + +#[cfg(CONFIG_CPU_FREQ)] +impl FreqTable { + /// Creates new instance of [`FreqTable`] from raw pointer. + fn new(table: &Table) -> Result { + let mut ptr: *mut bindings::cpufreq_frequency_table =3D ptr::null_= mut(); + + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_init_cpufreq_table(table.dev.as_raw(), &m= ut ptr) + })?; + Ok(Self { + dev: table.dev.clone(), + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + table: unsafe { cpufreq::Table::from_raw(ptr) }, + }) + } + + /// Returns reference to the underlying [`cpufreq::Table`]. + pub fn table(&self) -> &cpufreq::Table { + &self.table + } +} + +#[cfg(CONFIG_CPU_FREQ)] +impl Deref for FreqTable { + type Target =3D cpufreq::Table; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.table + } +} + +#[cfg(CONFIG_CPU_FREQ)] +impl Drop for FreqTable { + fn drop(&mut self) { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw()= , &mut self.as_raw()) }; + } +} + /// Operating performance point (OPP) table. /// /// Wraps the kernel's `struct opp_table`. @@ -540,6 +596,12 @@ pub fn adjust_voltage( }) } =20 + /// Create cpufreq table from OPP table. + #[cfg(CONFIG_CPU_FREQ)] + pub fn to_cpufreq_table(&mut self) -> Result { + FreqTable::new(self) + } + /// Sets a matching OPP based on frequency. pub fn set_rate(&self, freq: usize) -> Result<()> { // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 22:40:06 2026 Received: from mail-pj1-f49.google.com (mail-pj1-f49.google.com [209.85.216.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 30055230982 for ; Thu, 6 Feb 2025 09:29:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834191; cv=none; b=cVDEIl9VBqbtMptt0TqtoKsKYXaac84Jem6ms/vkDFD2IpBMvHnyWKWJSOf4rEFc/R62wn37czOHlNcIUYEuGPtPgUhv+TkarFl/sCnE7FrJW2I2/mh1sGTG7bWg6vTptFDKMR9Gty0jidrIRRntoC6TjoLmFsc1mXl4gyY9VDQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738834191; c=relaxed/simple; bh=lQwGxkeDyLZl4gzxKTY+sfg/kgWYDadG6FIOwNqQWm8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=AHLWgsd9KHUCIuLzK0GJhU44qo0TL56qjARIKU+a0atAFnWWtxAvO5sLAJTjxhaooLxkux/NEgKdAhaiSrtEmheqV40qDMgbOu7+1L9yAXFSGU0tLhICYmhun6cBoX6ek5zDUuhhBz7oJU31VlCPqkaU0zK9+prAgtzonomtlJk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=u9GXNw4R; arc=none smtp.client-ip=209.85.216.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="u9GXNw4R" Received: by mail-pj1-f49.google.com with SMTP id 98e67ed59e1d1-2f9c69aefdbso1261934a91.2 for ; Thu, 06 Feb 2025 01:29:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738834187; x=1739438987; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=u3kmMrnO07/rY8kDURhyasWYzOo/7PtXahiPnASlEac=; b=u9GXNw4RMZ0Dk0GqRASj9PFgIrNS32tRoQhnMwUj184G5nhPZ/O86D+lp/edk07w9n kUOHc0ksNfx/+ZX1sCs32U9jUDB02/tYq2s6VJQe1Djnylhq7ebOni4Z7EwGtydnOTRr toar/ivIQwXMmmFZ7fgtqN2zCRnjU0QNuDLpdtXp3xocEzmfEsKOo6LhqRO3P1CM0sJK KxiU5Apj6sTQ4Ch9Lay9nzINZOLiJ22sgn49lEW5dVr8jAYcmT9+V9RpEjfh+ynkUJZk mg5YdnAdn/HE1gjnWxosNNM0H0HwLSUGWnh3IngmJi49jmmSnAE2Sdz/rAnQKoBQO8rQ 0dlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738834187; x=1739438987; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=u3kmMrnO07/rY8kDURhyasWYzOo/7PtXahiPnASlEac=; b=TCQ4SXbrLl5GBW2D9m6Tw7t95u+HcVevxbT3abBX+LYhq7LE0OCCx1fr2sguy2NK2j nu/FIUw3lFxfM5PTnenCmkSXvarGAnFdcVr5pwaVVdDgAkdE76YlfZ38P6WrDeoESEPS ykeaAwNoLdXYiNU/CMwu/pA44hNbCVCxL0i0QMBESuirjw8ssyxf/Ak4cEwNK3086++y mhsktimnJR/oS6rXFLIOJq9v3nN6icATvYcmkJq0AS56Vu8epoEoyNx/XmdsjR5BB+Qo kUcefpqDsJGqEShrm1LKLSGs9A+S28bEhXL999/m/nvRYLSVvwXyeN9WQ6S8tvlgUIuT tluA== X-Forwarded-Encrypted: i=1; AJvYcCWX9253x0z3wc4HmXZ3MXUiQZru0cEN2PAy+d7MzRCAH4fX1FYtNN+bwnn4E9atC5gzj62jXfrNht3gXX4=@vger.kernel.org X-Gm-Message-State: AOJu0Yx5Rrnb1vjaOi4EZ6JcKNjYhqjHTVUqq5Y5RLxL8lPauwDmNDhW Lc73J11AHjzg4jqu6k/VQGwKin24jmaXusrb1PEic3pjTRuhaYkqOAZHpwh85Pk= X-Gm-Gg: ASbGncuaudLpCwX8pQHHmb6eRMcGrmfj+dadfUhB2iGur8LWJfwAPt4tDFR2RBKT2lF IUFffu+A6Oi4XBmA5D/lDtxXAxq2y7LvGhVvjChpBTZ8SZr+tVR0xVdwR6X2rM3jt8WoTDE/Fh2 K1Zq81pBGKonNNsbKspGeldqfgn7m+j80nLiNDDoh9gC7ufDX/05sGSuNjWHqH68ohQRx3Ksabg A5RtWuSBgRjM97sS0kma47g2qm3gTIey/aWfHXBxq71OcH5skuE/nBlRkEmdh0q5eoRm84oVHpz E5LQYjruvogTBgc7+A== X-Google-Smtp-Source: AGHT+IGkNEhqQ7+Hl8c3zRCkviXXDjX9Vvx04qeZh3UAEF2BzHwjV8tkWb9YU/Rv9U3rFPCfG1+Zfw== X-Received: by 2002:a05:6a00:2287:b0:725:e499:5b86 with SMTP id d2e1a72fcca58-7303521977bmr9464530b3a.20.1738834187287; Thu, 06 Feb 2025 01:29:47 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73048ae7e54sm855752b3a.76.2025.02.06.01.29.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 01:29:46 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , Stephen Boyd , Nishanth Menon , rust-for-linux@vger.kernel.org, Manos Pitsidianakis , Erik Schilling , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Joakim Bech , Rob Herring , linux-kernel@vger.kernel.org Subject: [PATCH V8 14/14] cpufreq: Add Rust based cpufreq-dt driver Date: Thu, 6 Feb 2025 14:58:35 +0530 Message-Id: <3054a0eb12330914cd6165ad460d9844ee8c19e2.1738832119.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This commit adds a Rust based cpufreq-dt driver, which covers most of the functionality of the existing C based driver. Only a handful of things are left, like fetching platform data from cpufreq-dt-platdev.c. This is tested with the help of QEMU for now and switching of frequencies work as expected. Signed-off-by: Viresh Kumar --- drivers/cpufreq/Kconfig | 12 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/rcpufreq_dt.rs | 238 +++++++++++++++++++++++++++++++++ rust/kernel/cpufreq.rs | 10 +- 4 files changed, 257 insertions(+), 4 deletions(-) create mode 100644 drivers/cpufreq/rcpufreq_dt.rs diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index d64b07ec48e5..78702a08364f 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -217,6 +217,18 @@ config CPUFREQ_DT =20 If in doubt, say N. =20 +config CPUFREQ_DT_RUST + tristate "Rust based Generic DT based cpufreq driver" + depends on HAVE_CLK && OF && RUST + select CPUFREQ_DT_PLATDEV + select PM_OPP + help + This adds a Rust based generic DT based cpufreq driver for frequency + management. It supports both uniprocessor (UP) and symmetric + multiprocessor (SMP) systems. + + If in doubt, say N. + config CPUFREQ_VIRT tristate "Virtual cpufreq driver" depends on GENERIC_ARCH_TOPOLOGY diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 890fff99f37d..7fa29bdec3c7 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_COMMON) +=3D cpufreq_governor.o obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET) +=3D cpufreq_governor_attr_set.o =20 obj-$(CONFIG_CPUFREQ_DT) +=3D cpufreq-dt.o +obj-$(CONFIG_CPUFREQ_DT_RUST) +=3D rcpufreq_dt.o obj-$(CONFIG_CPUFREQ_DT_PLATDEV) +=3D cpufreq-dt-platdev.o obj-$(CONFIG_CPUFREQ_VIRT) +=3D virtual-cpufreq.o =20 diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs new file mode 100644 index 000000000000..461e88006ed9 --- /dev/null +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust based implementation of the cpufreq-dt driver. + +use core::format_args; + +use kernel::{ + c_str, clk, cpu, cpufreq, cpumask::Cpumask, device::Device, error::cod= e::*, fmt, + macros::vtable, module_platform_driver, of, opp, platform, prelude::*,= str::CString, sync::Arc, +}; + +// Finds exact supply name from the OF node. +fn find_supply_name_exact(dev: &Device, name: &str) -> Option { + let name_cstr =3D CString::try_from_fmt(fmt!("{}-supply", name)).ok()?; + + if dev.property_present(&name_cstr) { + CString::try_from_fmt(fmt!("{}", name)).ok() + } else { + None + } +} + +// Finds supply name for the CPU from DT. +fn find_supply_names(dev: &Device, cpu: u32) -> Option> { + // Try "cpu0" for older DTs. + let name =3D match cpu { + 0 =3D> find_supply_name_exact(dev, "cpu0"), + _ =3D> None, + } + .or(find_supply_name_exact(dev, "cpu"))?; + + let mut list =3D KVec::with_capacity(1, GFP_KERNEL).ok()?; + list.push(name, GFP_KERNEL).ok()?; + + Some(list) +} + +// Represents the cpufreq dt device. +struct CPUFreqDTDevice { + opp_table: opp::Table, + freq_table: opp::FreqTable, + #[allow(dead_code)] + mask: Cpumask, + #[allow(dead_code)] + token: Option, + #[allow(dead_code)] + clk: clk::Clk, +} + +struct CPUFreqDTDriver { + _pdev: platform::Device, +} + +#[vtable] +impl opp::ConfigOps for CPUFreqDTDriver {} + +#[vtable] +impl cpufreq::Driver for CPUFreqDTDriver { + type Data =3D (); + type PData =3D Arc; + + fn init(policy: &mut cpufreq::Policy) -> Result { + let cpu =3D policy.cpu(); + // SAFETY: The CPU device is only used from the init() callback du= ring which the CPU can't + // get hot-unplugged. Also the cpufreq core in C library, register= s with CPU notifiers and + // the cpufreq core/driver won't use the CPU device, once the CPU = is hot-unplugged. + let dev =3D unsafe { cpu::from_cpu(cpu)? }; + let mut mask =3D Cpumask::new()?; + + mask.set(cpu); + + let token =3D match find_supply_names(dev, cpu) { + Some(names) =3D> Some( + opp::Config::::new() + .set_regulator_names(names)? + .set(dev)?, + ), + _ =3D> None, + }; + + // Get OPP-sharing information from "operating-points-v2" bindings. + let fallback =3D match opp::Table::of_sharing_cpus(dev, &mut mask)= { + Ok(()) =3D> false, + Err(e) =3D> { + if e !=3D ENOENT { + return Err(e); + } + + // "operating-points-v2" not supported. If the platform ha= sn't + // set sharing CPUs, fallback to all CPUs share the `Polic= y` + // for backward compatibility. + opp::Table::sharing_cpus(dev, &mut mask).is_err() + } + }; + + // Initialize OPP tables for all policy cpus. + // + // For platforms not using "operating-points-v2" bindings, we do t= his + // before updating policy cpus. Otherwise, we will end up creating + // duplicate OPPs for the CPUs. + // + // OPPs might be populated at runtime, don't fail for error here u= nless + // it is -EPROBE_DEFER. + let mut opp_table =3D match opp::Table::from_of_cpumask(dev, &mut = mask) { + Ok(table) =3D> table, + Err(e) =3D> { + if e =3D=3D EPROBE_DEFER { + return Err(e); + } + + // The table is added dynamically ? + opp::Table::from_dev(dev)? + } + }; + + // The OPP table must be initialized, statically or dynamically, b= y this point. + opp_table.opp_count()?; + + // Set sharing cpus for fallback scenario. + if fallback { + mask.set_all(); + opp_table.set_sharing_cpus(&mut mask)?; + } + + let mut transition_latency =3D opp_table.max_transition_latency() = as u32; + if transition_latency =3D=3D 0 { + transition_latency =3D cpufreq::ETERNAL_LATENCY; + } + + let freq_table =3D opp_table.to_cpufreq_table()?; + let clk =3D policy + .set_freq_table(freq_table.table()) + .set_dvfs_possible_from_any_cpu() + .set_suspend_freq((opp_table.suspend_freq() / 1000) as u32) + .set_transition_latency(transition_latency) + .set_clk(dev, None)?; + + mask.copy(policy.cpus()); + + Ok(Arc::new( + CPUFreqDTDevice { + opp_table, + freq_table, + mask, + token, + clk, + }, + GFP_KERNEL, + )?) + } + + fn exit(_policy: &mut cpufreq::Policy, _data: Option) -> = Result<()> { + Ok(()) + } + + fn online(_policy: &mut cpufreq::Policy) -> Result<()> { + // We did light-weight tear down earlier, nothing to do here. + Ok(()) + } + + fn offline(_policy: &mut cpufreq::Policy) -> Result<()> { + // Preserve policy->data and don't free resources on light-weight + // tear down. + Ok(()) + } + + fn suspend(policy: &mut cpufreq::Policy) -> Result<()> { + policy.generic_suspend() + } + + fn verify(data: &mut cpufreq::PolicyData) -> Result<()> { + data.generic_verify() + } + + fn target_index(policy: &mut cpufreq::Policy, index: u32) -> Result<()= > { + let data =3D match policy.data::() { + Some(data) =3D> data, + None =3D> return Err(ENOENT), + }; + + let freq =3D data.freq_table.freq(index.try_into().unwrap())? as u= size; + data.opp_table.set_rate(freq * 1000) + } + + fn get(policy: &mut cpufreq::Policy) -> Result { + policy.generic_get() + } + + fn set_boost(_policy: &mut cpufreq::Policy, _state: i32) -> Result<()>= { + Ok(()) + } + + fn register_em(policy: &mut cpufreq::Policy) { + policy.register_em_opp() + } +} + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + ::IdInfo, + [(of::DeviceId::new(c_str!("operating-points-v2")), ())] +); + +impl platform::Driver for CPUFreqDTDriver { + type IdInfo =3D (); + const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); + + fn probe( + pdev: &mut platform::Device, + _id_info: Option<&Self::IdInfo>, + ) -> Result>> { + cpufreq::Registration::::new_foreign_owned( + pdev.as_ref(), + c_str!("cpufreq-dt"), + (), + cpufreq::flags::NEED_INITIAL_FREQ_CHECK | cpufreq::flags::IS_C= OOLING_DEV, + true, + )?; + + let drvdata =3D KBox::new( + Self { + _pdev: pdev.clone(), + }, + GFP_KERNEL, + )?; + + Ok(drvdata.into()) + } +} + +module_platform_driver! { + type: CPUFreqDTDriver, + name: "cpufreq-dt", + author: "Viresh Kumar ", + description: "Generic CPUFreq DT driver", + license: "GPL v2", +} diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index f92259d339d3..ecf7c6e2cb89 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -628,15 +628,17 @@ pub fn new(name: &'static CStr, data: T::Data, flags:= u16, boost: bool) -> Resul =20 // SAFETY: The C code returns a valid pointer here, which is again= passed to the C code in // an array. - attr[next] =3D - unsafe { addr_of_mut!(bindings::cpufreq_freq_attr_scaling_avai= lable_freqs) as *mut _ }; + attr[next] =3D unsafe { + addr_of_mut!(bindings::cpufreq_freq_attr_scaling_available_fre= qs) as *mut _ + }; next +=3D 1; =20 if boost { // SAFETY: The C code returns a valid pointer here, which is a= gain passed to the C code // in an array. - attr[next] =3D - unsafe { addr_of_mut!(bindings::cpufreq_freq_attr_scaling_= boost_freqs) as *mut _ }; + attr[next] =3D unsafe { + addr_of_mut!(bindings::cpufreq_freq_attr_scaling_boost_fre= qs) as *mut _ + }; next +=3D 1; } attr[next] =3D ptr::null_mut(); --=20 2.31.1.272.g89b43f80a514