From nobody Sat Feb 7 17:55:12 2026 Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) (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 E84C7238C0B for ; Fri, 11 Apr 2025 10:59:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369145; cv=none; b=KYkdMyzzeYb4j3DEyvSbyGjlLFFIVo9lb8qlEmXSJF6gxGKtVfZXpXqYMxFK34qsMuaZpwiIzKLBhn2Lj6RsfGLsxaFmFF6B7FaAVM6wInjb0OMBDlQmfGvjgz1pOJs1+MtcSV08tCQV9WtfGNIaDPr77sRbBj55/Wwri35oSic= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369145; c=relaxed/simple; bh=yS8zzoAb1gzolyqRZtRGFelUspFvZ1+mTbeqhW4yRic=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=aLuy7npchiUQ6WPRQaQe1bEC1XkzNeO7cNMK9/DT9shlThFCYRv5G+K59UiEUkYlzQ0B8vpC8g1cwTutBo0asYnRwfY+jqXq1kUSlFs3zk4HdC1mWoFX+AbShn7euSrEfo4XvlTruPCq88CfoivpJfFbrll0UtxWcYxmXPclA78= 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=s4fL1QbZ; arc=none smtp.client-ip=209.85.210.174 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="s4fL1QbZ" Received: by mail-pf1-f174.google.com with SMTP id d2e1a72fcca58-7390d21bb1cso1786202b3a.2 for ; Fri, 11 Apr 2025 03:59:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369143; x=1744973943; 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=P5QmLNWlEhMlbaeU7vUP5c8vKPIyuKJozs3WjW7NYUo=; b=s4fL1QbZ88rgE2W4qUliW4BBCp0K5GqKT2wjxutfN7g3pvg0G90uCcFWg7kF2M3KK4 gbtQ9RjfrrGq+pomf5cYrAVSimECQdsT/SqA20GQSrDEQRUCfd1yZg3lPfm19cARug06 m1Sg9hRV3eZyMIT4QOjlIir4OoZtWstb60/KjKcp3QL4UCk2ErJ30SWrrcJwAY5on+Fd iIaVakybeOZrF3bps/shhUUl5WZFYq5c/U/P+OkF+7UcFmJGG+VNezjpKieRhlukOCzY eMl/EtLbXfOC5wG6fotO3H5jDFtePU8nCeN9Hqrqu/Xg38EXOOK4JvgL7vUSFvKOwOz5 te1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369143; x=1744973943; 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=P5QmLNWlEhMlbaeU7vUP5c8vKPIyuKJozs3WjW7NYUo=; b=N1f+IIBM9cFogc5EONko/XDDiDxpNsKQTCyFCyI/Tk6JNyStrlqdzf1t0FDIT3tYl5 pJojnYh46JAB/rZ/JkSKF0h2WiICwqE7YVUb7tKb81AeEyf48BrB2sm+cMFnN3jFyD74 X1fDulbQbmtRW6IZxfpEvaFqrQG0mYgxFmeeUX612hVDmS0mTU06OTLdDLKey+J17ttG F3efah+cYpE/esJKMP7O7SQOQ3fN3hJ7b63kfLNsGu2LZL/E+EQRZ487KUeKg5rMlp9B /j6ZU+sCxcEtRstPYtbmI31KnoFJLnuR20iJKyq+eWR/Q4s64FU4YCULTjDiQJFWyHtU 0IRw== X-Forwarded-Encrypted: i=1; AJvYcCVBuR7fbWhnpRp8eCs5tgdrV/R8U5Mw1h0mB2TFXhelDpIk5hdVt2CFxQ55LnFt1KXPj6iSDd1xAsO9/0E=@vger.kernel.org X-Gm-Message-State: AOJu0Yynod5hq1GTllPFZ1vxd970w0uLCWiRxAc1KOVxLIxAIEoguiow Ys75WGgA4zYce7Pmfm9RgsZeGAfgbDbYd/R/wVa8aR+Lbh2z73xhZX9bfaJwhqA= X-Gm-Gg: ASbGnctaCVb0NXC0QwW1s/fvCq55O/NI73F7NWXUqCWtnkmodD/8OACg065KGw0BtfC XagMcpTwexiPxsWguMiGgMpTG2SOAuVAbia0IolWWdDEofXzCjdm5ELg0HFmj/MGzuydkUXOpY9 ZzNuf7gJq8ezrKLkqU3kiQ4mPDO0AhfyDgIsHXcws/Mjh0RvvYkviOpBzTafflLORStSy2JhI5t Fxq7oa5qLPa+iKJd/sf6ewrbyU1q5bs8r+HKXwAAy7FGTijstG3sGX1yjL+rBN030PH0O3HvjO2 YCZ5+VktoxDvWBRlj0kLlAWVoVx9Gbc40rpeEiNtxA== X-Google-Smtp-Source: AGHT+IE2OjzWyw13U8ckU/PhF26xnq5qyW/KpQps6B6mpDc5lX3qxmzsxgHjgW2+oCee8Ta27wiyxQ== X-Received: by 2002:a05:6a00:1486:b0:736:5e28:cfba with SMTP id d2e1a72fcca58-73bd126b973mr3107562b3a.18.1744369143132; Fri, 11 Apr 2025 03:59:03 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd2334376sm1179973b3a.165.2025.04.11.03.59.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:02 -0700 (PDT) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Yury Norov , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich 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 , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 01/17] rust: cpumask: Use non-atomic helpers Date: Fri, 11 Apr 2025 16:25:00 +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 cpumask Rust abstractions don't need the atomic variants of helpers for now. Use the non-atomic helpers instead. Signed-off-by: Viresh Kumar --- rust/helpers/cpumask.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/helpers/cpumask.c b/rust/helpers/cpumask.c index 2d380a86c34a..ae964cddbd41 100644 --- a/rust/helpers/cpumask.c +++ b/rust/helpers/cpumask.c @@ -2,14 +2,14 @@ =20 #include =20 -void rust_helper_cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp) +void rust_helper___cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp) { - cpumask_set_cpu(cpu, dstp); + __cpumask_set_cpu(cpu, dstp); } =20 -void rust_helper_cpumask_clear_cpu(int cpu, struct cpumask *dstp) +void rust_helper___cpumask_clear_cpu(int cpu, struct cpumask *dstp) { - cpumask_clear_cpu(cpu, dstp); + __cpumask_clear_cpu(cpu, dstp); } =20 void rust_helper_cpumask_setall(struct cpumask *dstp) --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 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 27F8B284B28 for ; Fri, 11 Apr 2025 10:59:06 +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=1744369148; cv=none; b=nFo73inZ3hxEUhAcItaeXyqqefvLUXcdfNLNZFAkb35guIvXUAMi+im5dxAKu8pZv1PQ9lRw+wkoT1k+cbsh8rm+8QzfYh/TOlUlOIkCuKOFO5ohi+Nu9xKnvrbg75R1QmQbcg53I+Ish+c5Z6EoEN3vXmnEbD/C7tzwHj8gWdQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369148; c=relaxed/simple; bh=Lz8/dlHquQs8+KgJWlTHfeHGDG+b2IGK2cF/V+dR5o0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ul8yJLgmIivDe/F72MkENtYCDVUnIOwIRF5jVD7NR66V5MTZw+gudGbYqHfBlRgHCpKjmFkifxe0q3BhTG/aGzBnulq00kGo4YpEFoUVsWlMnl0JohFjBXn1dxzCFFYZXVzbuKU8cQNe/rMP4vYpxwXnDqB06BaR+K/Oaq8dQG4= 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=V/nZ8B7W; 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="V/nZ8B7W" Received: by mail-pj1-f46.google.com with SMTP id 98e67ed59e1d1-3012a0c8496so1435174a91.2 for ; Fri, 11 Apr 2025 03:59:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369146; x=1744973946; 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=/cw314qO5OzgfErL/PQP5mXU7cjPJv+CNURyMPhNy3E=; b=V/nZ8B7Wdwc5yzPo3fPLqG5IOO865KEst1zoHPUXvJ4QQlfc8rjt8umE16XlMn3Mt5 T9X0uLWMusDiVzg0QekAxOPUQuIcRKz/85VN6iwzKfRxo1+FwNjiy5nAldDtRltkDYoi gwFldS1ra6iLBAEyOUAamPAjqyKqCKxGu+NV6eINHAyTCLjYNHXAcyu5n4EfoDDuaW1I lqL1WPq6/Ek9Uo66w3uprsx6N5DTIdqN53cNBGNIXQiguIKPJs73ATFTMqmTjlV7oaYd jyipxrQUrhbSsI6XAF2X9mArcIksuqUm5TXo6KFVrZiOMyXwXgIwvHtZ/XSe/RA23zAI 8a6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369146; x=1744973946; 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=/cw314qO5OzgfErL/PQP5mXU7cjPJv+CNURyMPhNy3E=; b=pRT+7sTsiW+pOVHyKw96wWG8jWncvoSOUM7i10pRTGO029t/28SRZ3tXIa8LJOyopK VjFWk0FexFqRvFHcygkZfFllBmpPXhinxE3irJIJUPuUCF4AZRogbBhmY3ZYSLmr+TQT GqQc4I6JyBmLH5lffdNG1dPEdHx9ZFBOcKvATRYbBi75uzY/bsdARr0qt9NwOfGkWvFr kHJdpATAm6jDKU5JVLa7iwRovMybbAVgHF1bOKaNO+m4RAtG2sw7fLcr0Ca3sNdZsgp1 i1VBWIaaLdSugBx/2zRzFZUs7YdaFsGE8nGO3iw16ktnxiosDdh/txZQTtNN2N9Frfd2 6KTw== X-Forwarded-Encrypted: i=1; AJvYcCUI00RB4AoyDYPNonEuQimwR3WQRbJ6x8TCRAQ0pyycwobvvnFUrfXqLZsPkA26rNz2JWcP68ZZIO0lnmc=@vger.kernel.org X-Gm-Message-State: AOJu0Yzy7wVh+TWwgvYJJcCatqUKvGGfhsShQHRr72IIineYebdeyL23 Un24JgDHFqy7K1FeqbT6qTmr1AyFsbvVRDec1FQoX5ZD6WyftCvRtBEOOJAsXa8= X-Gm-Gg: ASbGncss2Rvggoydabmcxg7NfbVx7Zld0nlg5Ky59CpYQGeh0ueAv8g+BL7t/aWr7DU FtIkJgRlQsja42q/LV72cvLmE7Bb24FOylkGMbjTyAHjYgytr4Mvj92+mOxOB/o3rFT1kObh7la 8akuXS0o61nE6mH4MkYprm5rGN465bId/CDp/WyRhuQj99wCHXxSRF6Ls5xMBYXRBLLtzbBiErc xL2/gPwIlG7TZxpnXmk22ycDTld6x9NB2aIHNoc2AD0YBB9e4BHyG2kL2sx3R6aGCL7/oU5yLyE kLdqccuqQelc5bLIQDiGoIlnTLXT3GWD26gi1IwmJdkiwirdsGtX X-Google-Smtp-Source: AGHT+IEFxwHKqoOI4yL6xARYViMgwvtWz0BpJSZrfD87BTkTPcEYvJrbdX8FbmAvDOdGi5eq0VSwyA== X-Received: by 2002:a17:90b:5744:b0:2fa:1f1b:3db2 with SMTP id 98e67ed59e1d1-308236723c3mr3321753a91.25.1744369146401; Fri, 11 Apr 2025 03:59:06 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-306dd11e79fsm5408297a91.19.2025.04.11.03.59.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:05 -0700 (PDT) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Yury Norov , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich 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 , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 02/17] rust: cpumask: Add few more helpers Date: Fri, 11 Apr 2025 16:25:01 +0530 Message-Id: <878eb11f74cd320cbb06fb04c8ef655de81dd358.1744366571.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" Add few more cpumask helpers that are required by the Rust abstraction. Signed-off-by: Viresh Kumar --- rust/helpers/cpumask.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rust/helpers/cpumask.c b/rust/helpers/cpumask.c index ae964cddbd41..30fc0bc0c0e8 100644 --- a/rust/helpers/cpumask.c +++ b/rust/helpers/cpumask.c @@ -12,11 +12,26 @@ void rust_helper___cpumask_clear_cpu(int cpu, struct cp= umask *dstp) __cpumask_clear_cpu(cpu, dstp); } =20 +bool rust_helper_cpumask_test_cpu(int cpu, struct cpumask *srcp) +{ + return cpumask_test_cpu(cpu, srcp); +} + void rust_helper_cpumask_setall(struct cpumask *dstp) { cpumask_setall(dstp); } =20 +bool rust_helper_cpumask_empty(struct cpumask *srcp) +{ + return cpumask_empty(srcp); +} + +bool rust_helper_cpumask_full(struct cpumask *srcp) +{ + return cpumask_full(srcp); +} + unsigned int rust_helper_cpumask_weight(struct cpumask *srcp) { return cpumask_weight(srcp); --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 2026 Received: from mail-pf1-f181.google.com (mail-pf1-f181.google.com [209.85.210.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 45FC72989AC for ; Fri, 11 Apr 2025 10:59:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369153; cv=none; b=Y1T8hcXj/6dQd76brcDcmanwN/ZN+p+DtF52u6+rNTHq0KnUlIRVvsV6k3QdrvQhQmuqVBrSCnt5osyf2zK1vxlNOL4IIrNn1zyemGUQ3dBN6vENQm51Jtw496IG57Q/icIUVJqQHn8OJOrbpIyzE/0r8GYK7IsEi3F2fnrZzlI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369153; c=relaxed/simple; bh=3RKsje1PNFnVLXX/G/S0mGGvTG/fkpcBc573XS0cMC8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=N1Nj9Y8ergtQYGEX8JnI8x7qCKyQ1QJiqePKwnhRupVNrJ2XcbEL+umxZhBFHpcYlHVmHaNfNJm9cZOflh1f5jVYdsDZfSl8YADN7Ng2g0338msLHv0qU9OMGgiXPE7wJ1hGW1eI1gQbCRuGDvzg2vwYoC+/7rIoMbBXwZit+uA= 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=mcA34Pzu; arc=none smtp.client-ip=209.85.210.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="mcA34Pzu" Received: by mail-pf1-f181.google.com with SMTP id d2e1a72fcca58-7359aca7ef2so2500662b3a.2 for ; Fri, 11 Apr 2025 03:59:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369150; x=1744973950; 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=edDXYIWfYTwXBeTDJlsnMSAARjZrtAvFKTS5hVZIGiw=; b=mcA34Pzurpur0DDaHADjr7IhnvD/H0ufGUH8ybJ1IoNuIJtcsslT/xhLBi3dghuvEk UvZ1yQkjIhqRji0BBcFKL4fRjBqr1Og9WusuPR/2RITxQrpnHAGAvdCc/b8mmgGYVFD9 Jmtdme9ToN4BljyT+w3oxdgQjXfVYlwqtPg4HIkZlKTzlKAV5VgUzyywDLaqb9bAIq8B G3y12prmyDQNRK3IeWZ+ttCfRp6jiVFVgZXBHaj6zbT0gbWxkTlUm+KICFRtre/CZ34q dEP//J7bv/WHmzmDQXtj52adqG4KL6YvRW0EqMkWLaPORpXSZI0I+1kLAloJCYESWm/w iPBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369150; x=1744973950; 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=edDXYIWfYTwXBeTDJlsnMSAARjZrtAvFKTS5hVZIGiw=; b=ScrNjuNMS9cnUdDG2Gfg8PWxoKryYW6k5otHRR0hCBIIfSHKYtO4KsvR9L7iQYb8Oj Yx8RO5uJQcj4l1ucOfBp/zg6rJEvggrBvGaOKkB09Xf7Q8k3OtJorAFWimXKJRv+OCU6 Zf/AK/CeOar/qyEfLZjT/UBNZWmr38dubmqODNS/rVK0egq6OSwrcoYfYIRmS9XIGTIw i0nfZv76N5C2/tqZ8GJG+xzvBvpc73qThrDac00Dj56lcLjdDBnJTtXm0gisSPHNaUGB AC+KZIKFK/+zRS+ZtvB2NB+QZQa2BMT+WveK3eCCIYpbsHpGUue3ogcNMqUmldF5JJrn JbCw== X-Forwarded-Encrypted: i=1; AJvYcCU/xWiJNkoCnSed/fUsSDTtX4gh+wMCPAVUP8armJzDnR5lmZ20cbCah6FAZDxFDcYJx6IKlIxLdF6BeNM=@vger.kernel.org X-Gm-Message-State: AOJu0Yw9sFEWEg8K5wXk2FZuCn+EE92CfsDlvaBwAMr/DmvJGnbKFkPV ZUpbq4n3AsILG45ShUV5Jnj7UkF9tKybhtzj8ZgioLCA9DJ8SXUhDjxOyFYaf48= X-Gm-Gg: ASbGncvXPxGsS6JKSDsdrRNij0AXB6I8dcYOYY8Z3Zm5fm1YKlOmOihiNlBPMimEet/ 09P+yId4yZ2Im6bjrCNoxcaM8/iy5nXMrU0p799geU84eSg78jgpKmBeMRjF3a5SzOIwwBgFeUe m2bsy9pBcqKRl/y6aR6NkhJ/uBP7qRVtZ1WrDHSHDDigfRtu413DSVnDNRf2W5wMQ5LfLvF7BKt +UEjOEtBazrQJFZ0+avSHY19OV4FG0+pMRDqMB0/tv/c2w4uGAF58FcmmEH4eYf92ylJXA/ehy5 i1PDOqXWutwWIp5zRQKWszKeyZesP6K4SBBl2eNLYA== X-Google-Smtp-Source: AGHT+IHnmO8U1SRyZKo+9xUWfLqZAtCOSfF+JiScx5mOjsMCUB5lZMSIgenh0Na/qgfbZOqoDLyYGA== X-Received: by 2002:aa7:8890:0:b0:736:ab21:8a69 with SMTP id d2e1a72fcca58-73bd0ea93eamr2951177b3a.0.1744369150256; Fri, 11 Apr 2025 03:59:10 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd2198c00sm1234519b3a.10.2025.04.11.03.59.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:09 -0700 (PDT) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Viresh Kumar , Yury Norov , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich 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 , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 03/17] rust: cpumask: Add initial abstractions Date: Fri, 11 Apr 2025 16:25:02 +0530 Message-Id: <9a004e3dff5321dae3b96df2817799daa699ce01.1744366571.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" Add initial Rust abstractions for struct cpumask, covering a subset of its APIs. Additional APIs can be added as needed. These abstractions will be used in upcoming Rust support for cpufreq and OPP frameworks. Signed-off-by: Viresh Kumar --- rust/kernel/cpumask.rs | 328 +++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 2 files changed, 329 insertions(+) create mode 100644 rust/kernel/cpumask.rs diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs new file mode 100644 index 000000000000..a9d22c1d7a5a --- /dev/null +++ b/rust/kernel/cpumask.rs @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! CPU Mask abstractions. +//! +//! C header: [`include/linux/cpumask.h`](srctree/include/linux/cpumask.h) + +use crate::{ + alloc::{AllocError, Flags}, + bindings, + prelude::*, + types::Opaque, +}; + +#[cfg(CONFIG_CPUMASK_OFFSTACK)] +use core::ptr::{self, NonNull}; + +#[cfg(not(CONFIG_CPUMASK_OFFSTACK))] +use core::mem::MaybeUninit; + +use core::ops::{Deref, DerefMut}; + +/// A CPU Mask. +/// +/// Rust abstraction for the C `struct cpumask`. +/// +/// # Invariants +/// +/// A [`Cpumask`] instance always corresponds to a valid C `struct cpumask= `. +/// +/// The callers must ensure that the `struct cpumask` is valid for access = and remains valid for the +/// lifetime of the returned reference. +/// +/// ## Examples +/// +/// The following example demonstrates how to update a [`Cpumask`]. +/// +/// ``` +/// use kernel::bindings; +/// use kernel::cpumask::Cpumask; +/// +/// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: u32, clear_cpu:= i32) { +/// // SAFETY: The `ptr` is valid for writing and remains valid for th= e lifetime of the +/// // returned reference. +/// let mask =3D unsafe { Cpumask::from_raw_mut(ptr) }; +/// +/// mask.set(set_cpu); +/// mask.clear(clear_cpu); +/// } +/// ``` +#[repr(transparent)] +pub struct Cpumask(Opaque); + +impl Cpumask { + /// Creates a mutable reference to an existing `struct cpumask` pointe= r. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid for writing and remains= valid for the lifetime + /// of the returned reference. + pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpumask) -> &'a mut= Self { + // SAFETY: Guaranteed by the safety requirements of the function. + // + // INVARIANT: The caller ensures that `ptr` is valid for writing a= nd remains valid for the + // lifetime of the returned reference. + unsafe { &mut *ptr.cast() } + } + + /// Creates a reference to an existing `struct cpumask` pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid for reading and remains= valid for the lifetime + /// of the returned reference. + pub unsafe fn from_raw<'a>(ptr: *const bindings::cpumask) -> &'a Self { + // SAFETY: Guaranteed by the safety requirements of the function. + // + // INVARIANT: The caller ensures that `ptr` is valid for reading a= nd remains valid for the + // lifetime of the returned reference. + unsafe { &*ptr.cast() } + } + + /// Obtain the raw `struct cpumask` pointer. + pub fn as_raw(&self) -> *mut bindings::cpumask { + self as *const _ as _ + } + + /// Set `cpu` in the cpumask. + /// + /// Equivalent to the kernel's `__cpumask_set_cpu` API. + #[inline] + pub fn set(&mut self, cpu: u32) { + // SAFETY: By the type invariant, `self.as_raw` is a valid argumen= t to `__cpumask_set_cpu`. + unsafe { bindings::__cpumask_set_cpu(cpu, self.as_raw()) }; + } + + /// Clear `cpu` in the cpumask. + /// + /// Equivalent to the kernel's `__cpumask_clear_cpu` API. + #[inline] + pub fn clear(&mut self, cpu: i32) { + // SAFETY: By the type invariant, `self.as_raw` is a valid argumen= t to + // `__cpumask_clear_cpu`. + unsafe { bindings::__cpumask_clear_cpu(cpu, self.as_raw()) }; + } + + /// Test `cpu` in the cpumask. + /// + /// Equivalent to the kernel's `cpumask_test_cpu` API. + #[inline] + pub fn test(&self, cpu: i32) -> bool { + // SAFETY: By the type invariant, `self.as_raw` is a valid argumen= t to `cpumask_test_cpu`. + unsafe { bindings::cpumask_test_cpu(cpu, self.as_raw()) } + } + + /// Set all CPUs in the cpumask. + /// + /// Equivalent to the kernel's `cpumask_setall` API. + #[inline] + pub fn setall(&mut self) { + // SAFETY: By the type invariant, `self.as_raw` is a valid argumen= t to `cpumask_setall`. + unsafe { bindings::cpumask_setall(self.as_raw()) }; + } + + /// Checks if cpumask is empty. + /// + /// Equivalent to the kernel's `cpumask_empty` API. + #[inline] + pub fn empty(&self) -> bool { + // SAFETY: By the type invariant, `self.as_raw` is a valid argumen= t to `cpumask_empty`. + unsafe { bindings::cpumask_empty(self.as_raw()) } + } + + /// Checks if cpumask is full. + /// + /// Equivalent to the kernel's `cpumask_full` API. + #[inline] + pub fn full(&self) -> bool { + // SAFETY: By the type invariant, `self.as_raw` is a valid argumen= t to `cpumask_full`. + unsafe { bindings::cpumask_full(self.as_raw()) } + } + + /// Get weight of the cpumask. + /// + /// Equivalent to the kernel's `cpumask_weight` API. + #[inline] + pub fn weight(&self) -> u32 { + // SAFETY: By the type invariant, `self.as_raw` is a valid argumen= t to `cpumask_weight`. + unsafe { bindings::cpumask_weight(self.as_raw()) } + } + + /// Copy cpumask. + /// + /// Equivalent to the kernel's `cpumask_copy` API. + #[inline] + pub fn copy(&self, dstp: &mut Self) { + // SAFETY: By the type invariant, `Self::as_raw` is a valid argume= nt to `cpumask_copy`. + unsafe { bindings::cpumask_copy(dstp.as_raw(), self.as_raw()) }; + } +} + +/// A CPU Mask pointer. +/// +/// Rust abstraction for the C `struct cpumask_var_t`. +/// +/// # Invariants +/// +/// A [`CpumaskVar`] instance always corresponds to a valid C `struct cpum= ask_var_t`. +/// +/// The callers must ensure that the `struct cpumask_var_t` is valid for a= ccess and remains valid +/// for the lifetime of [`CpumaskVar`]. +/// +/// ## Examples +/// +/// The following example demonstrates how to create and update a [`Cpumas= kVar`]. +/// +/// ``` +/// use kernel::cpumask::CpumaskVar; +/// +/// let mut mask =3D CpumaskVar::new(GFP_KERNEL).unwrap(); +/// +/// assert!(mask.empty()); +/// mask.set(2); +/// assert!(mask.test(2)); +/// mask.set(3); +/// assert!(mask.test(3)); +/// assert_eq!(mask.weight(), 2); +/// +/// let mask2 =3D CpumaskVar::try_clone(&mask).unwrap(); +/// assert!(mask2.test(2)); +/// assert!(mask2.test(3)); +/// assert_eq!(mask2.weight(), 2); +/// ``` +pub struct CpumaskVar { + #[cfg(CONFIG_CPUMASK_OFFSTACK)] + ptr: NonNull, + #[cfg(not(CONFIG_CPUMASK_OFFSTACK))] + mask: Cpumask, +} + +impl CpumaskVar { + /// Creates an initialized instance of the [`CpumaskVar`]. + pub fn new(_flags: Flags) -> Result { + Ok(Self { + #[cfg(CONFIG_CPUMASK_OFFSTACK)] + ptr: { + let mut ptr: *mut bindings::cpumask =3D ptr::null_mut(); + + // SAFETY: Depending on the value of `_flags`, this call m= ay sleep. Other than + // that, it is always safe to call this method. + // + // INVARIANT: The associated memory is freed when the `Cpu= maskVar` goes out of + // scope. + unsafe { bindings::zalloc_cpumask_var(&mut ptr, _flags.as_= raw()) }; + NonNull::new(ptr.cast()).ok_or(AllocError)? + }, + + #[cfg(not(CONFIG_CPUMASK_OFFSTACK))] + // SAFETY: FFI type is valid to be zero-initialized. + // + // INVARIANT: The associated memory is freed when the `Cpumask= Var` goes out of scope. + mask: unsafe { core::mem::zeroed() }, + }) + } + + /// Creates an uninitialized instance of the [`CpumaskVar`]. + /// + /// # Safety + /// + /// The caller must ensure that the returned [`CpumaskVar`] is properl= y initialized before + /// getting used. + unsafe fn new_uninit(_flags: Flags) -> Result { + Ok(Self { + #[cfg(CONFIG_CPUMASK_OFFSTACK)] + ptr: { + let mut ptr: *mut bindings::cpumask =3D ptr::null_mut(); + + // SAFETY: Depending on the value of `_flags`, this call m= ay sleep. Other than + // that, it is always safe to call this method. + // + // INVARIANT: The associated memory is freed when the `Cpu= maskVar` goes out of + // scope. + unsafe { bindings::alloc_cpumask_var(&mut ptr, _flags.as_r= aw()) }; + NonNull::new(ptr.cast()).ok_or(AllocError)? + }, + #[cfg(not(CONFIG_CPUMASK_OFFSTACK))] + // SAFETY: Guaranteed by the safety requirements of the functi= on. + // + // INVARIANT: The associated memory is freed when the `Cpumask= Var` goes out of scope. + mask: unsafe { MaybeUninit::uninit().assume_init() }, + }) + } + + /// Creates a mutable reference to an existing `struct cpumask_var_t` = pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid for writing and remains= valid for the lifetime + /// of the returned reference. + pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpumask_var_t) -> &= 'a mut Self { + // SAFETY: Guaranteed by the safety requirements of the function. + // + // INVARIANT: The caller ensures that `ptr` is valid for writing a= nd remains valid for the + // lifetime of the returned reference. + unsafe { &mut *ptr.cast() } + } + + /// Creates a reference to an existing `struct cpumask_var_t` pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid for reading and remains= valid for the lifetime + /// of the returned reference. + pub unsafe fn from_raw<'a>(ptr: *const bindings::cpumask_var_t) -> &'a= Self { + // SAFETY: Guaranteed by the safety requirements of the function. + // + // INVARIANT: The caller ensures that `ptr` is valid for reading a= nd remains valid for the + // lifetime of the returned reference. + unsafe { &*ptr.cast() } + } + + /// Clones cpumask. + pub fn try_clone(cpumask: &Cpumask) -> Result { + // SAFETY: The returned cpumask_box is initialized right after thi= s call. + let mut cpumask_box =3D unsafe { Self::new_uninit(GFP_KERNEL) }?; + + cpumask.copy(&mut cpumask_box); + Ok(cpumask_box) + } +} + +// Make [`CpumaskVar`] behave like a pointer to [`Cpumask`]. +impl Deref for CpumaskVar { + type Target =3D Cpumask; + + #[cfg(CONFIG_CPUMASK_OFFSTACK)] + fn deref(&self) -> &Self::Target { + // SAFETY: The caller owns CpumaskVar, so it is safe to deref the = cpumask. + unsafe { &*self.ptr.as_ptr() } + } + + #[cfg(not(CONFIG_CPUMASK_OFFSTACK))] + fn deref(&self) -> &Self::Target { + &self.mask + } +} + +impl DerefMut for CpumaskVar { + #[cfg(CONFIG_CPUMASK_OFFSTACK)] + fn deref_mut(&mut self) -> &mut Cpumask { + // SAFETY: The caller owns CpumaskVar, so it is safe to deref the = cpumask. + unsafe { self.ptr.as_mut() } + } + + #[cfg(not(CONFIG_CPUMASK_OFFSTACK))] + fn deref_mut(&mut self) -> &mut Cpumask { + &mut self.mask + } +} + +impl Drop for CpumaskVar { + fn drop(&mut self) { + #[cfg(CONFIG_CPUMASK_OFFSTACK)] + // SAFETY: By the type invariant, `self.as_raw` is a valid argumen= t to `free_cpumask_var`. + unsafe { + bindings::free_cpumask_var(self.as_raw()) + }; + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index de07aadd1ff5..75f78f6bfaa6 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -42,6 +42,7 @@ pub mod block; #[doc(hidden)] pub mod build_assert; +pub mod cpumask; pub mod cred; pub mod device; pub mod device_id; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 2026 Received: from mail-pf1-f172.google.com (mail-pf1-f172.google.com [209.85.210.172]) (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 35CDB298CB4 for ; Fri, 11 Apr 2025 10:59:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369155; cv=none; b=aeEi2qZMbbTXSnGmJRXYBh3kqnb+HVcRcvQIZha5wXdBcDA+uIagGKgOXyZ6G46IR0zOdT6iAND1rsj6nKpxdJDRNpVmBrFjw9uDK54rQDWKQN4Rm5kCoiR/jT/jn2iic5eC2XySLpPfzbVqcuXPExyyCMRRR3ghPQyogOp3LrM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369155; c=relaxed/simple; bh=pRm5rikPg836Cpaht6T2Bti6G/gsdEEiL/oreW2ehWs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=P4pbiG/27hMuzHYg9PdPllTsbHwTgGsya/FSWZBevAjNJItRkTgD3EkuGXCUeznrK4unuSknL8XBaSrpJ0YiBca6hh3kON2jFeVvQlauWcpHBLXVfZt+Jzgz0RjoGZUaU5IwugKCLtsNHhF7XZ5KohGCSUHj+LMaOEr7ZdKA7mo= 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=H1qYXtG2; arc=none smtp.client-ip=209.85.210.172 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="H1qYXtG2" Received: by mail-pf1-f172.google.com with SMTP id d2e1a72fcca58-736aa9d0f2aso2110053b3a.0 for ; Fri, 11 Apr 2025 03:59:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369153; x=1744973953; 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=eaMUD1BDVL417dtmG3+/1YWJeUCWl78+KVSs+NX3TJI=; b=H1qYXtG2w6A9BaStWjrBIEmiaJMoT491tdHxBC94cM/FM1hfGw05kHtxEYk//+wVkW PD4MANlH4dyT503CI/lm/kQwGFL1v7AvDdDIXF8leLKJngjgtYozW/GeVf8zxIxYkbj5 TpCY30DzU40NPzn74YF3l3MSJVT1CrIIgeVocBEQPpUx+UuONzzGif2mX8dGO4Wxr4ZY M24ntogLefdIwgMK+IzE9w+5EJ0mlNLQeXzJbiYRO1RYYs4YkbIEqXk2FSjFW7iuIN9+ L89wd2mXQhdmS6vsLrxotENe6obm8SrzyoWO4rPj/71TgK7BM5vWhI4ujDGK0AQGnYt0 qeUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369153; x=1744973953; 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=eaMUD1BDVL417dtmG3+/1YWJeUCWl78+KVSs+NX3TJI=; b=T6qkTi9ajOMhUCnP+gl0g/WM/I1SXXG2fQ+idPZFJIMBdemwnK/t4DMHJMoChr0ROg va4321vEKDCIKVkfxgoDQomL2Qm0hRVp8qgfhNU87sE4w4wlh8jX0sfW2vlwnhSIBzUv t5zaJPEErS7M4oSWMmECCtnRI2jw0TZNMexou/BCj70ZGjvbFRNLBa0VFHBvTeiCX8as pjU/wSB5HQrJW2U6x+yAqOBEeT424/UrdGh9nvlJL0RyZsT+Z/ukhF07x2c2+P2ATgV/ wIfbEpRJRjNLDcpc0BJ+BNftzldDytMlypcL8CoYq+ujSPV980tfdbYqwuhOaPkH7BZw r9zQ== X-Forwarded-Encrypted: i=1; AJvYcCWLMj9tjZ2Sj6nzk912S9YmkGQJUjHRQXyFbnZd0ANNJTvblLPr5/ANiqhbiiJYy2uhG8GiYLi56tTth64=@vger.kernel.org X-Gm-Message-State: AOJu0Yy9RjX27FJkRkzlyQJk1Eb+yVjYk+2GVzNSG8X9FIm18M9n+4b+ x5bRi/77tWX0qAA41oJ7ksXV57DoHaj9horT3J/PTwnFFlBW5wwKH/7VGoTGsyA= X-Gm-Gg: ASbGncuZLXcJoW94xy5yyKqcWl01hFzCrC5qRPVyeJ3Sy944xi/+6udzr7izIV69VBD Od4F9l9z1gjrneUFUjX+6NhZpfVDUKzxsGCvTKLuLEcrPewSNEH/8vpibyhty59xiV0aWjKFCVk TTP/scijywo1g2suVQvPSnpGKTbwxGsOUq7BSphn0CvDfPHaX/JdwJ3bnccBpOHebEwfDu2edFy uL4+rZmI+Kj8oEaTuPfT6HX+dcjqyaukhEd2LyYZ03ZWQyS6KptneSli55JcuP2jRA2BUPIsqZ+ bbSBuf/Nyq96LCL7Ft9VxA0x8WT1GhgwRSFXXHTsIl3sTtxRnGKS X-Google-Smtp-Source: AGHT+IGwEFN9ddJRuuBdJHj8RuzbOI95LYFz7Xvvsh4FpaazgcpxsU/NNRYSzTHyEh8WHWzJdCHM0Q== X-Received: by 2002:a05:6a21:108f:b0:1ee:dded:e5b with SMTP id adf61e73a8af0-201797b1ec9mr3954789637.24.1744369153569; Fri, 11 Apr 2025 03:59:13 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd233787asm1222223b3a.173.2025.04.11.03.59.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:13 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 04/17] MAINTAINERS: Add entry for Rust cpumask API Date: Fri, 11 Apr 2025 16:25:03 +0530 Message-Id: <69c085aa4ea2418ed400591bf9be22c215a924e6.1744366571.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" Update the MAINTAINERS file to include the Rust abstractions for cpumask API. Yury has indicated that he does not wish to maintain the Rust code but would like to be listed as a reviewer. Signed-off-by: Viresh Kumar Reviewed-by: Yury Norov --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..bd7c54af4fd4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6237,6 +6237,12 @@ L: linux-riscv@lists.infradead.org S: Maintained F: drivers/cpuidle/cpuidle-riscv-sbi.c =20 +CPUMASK API [RUST] +M: Viresh Kumar +R: Yury Norov +S: Maintained +F: rust/kernel/cpumask.rs + CRAMFS FILESYSTEM M: Nicolas Pitre S: Maintained --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 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 08F5B29AAFB for ; Fri, 11 Apr 2025 10:59: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=1744369159; cv=none; b=DTd+QfjNj0UUHIYm24SF96nD+QbfcNZWspkg7kWU1qFvq1wEqICoURgwCWW9XB/4ld0lcr17pUyYShQMCM6aTTVNQNcP+aLDxF792MTsD3+pcYXpGdy1OOqUNNzUrYevqj91Sjm5KFPM6Ml5BhJBOPL60SGF7UWKQpZpm7UBszE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369159; c=relaxed/simple; bh=4HWksdgns8ejVb++Q4NJVdKDSuHEDHdMmvi+j+YhGlo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=jinbEm+Tkj5ZVGxG0/qE6EoUlMPntOEFI/y7Ehk4LJZo4cxrupfc2YBvMHWV0C8pkscWTU2vK+h5kNR8yHF4ebE/xlmZl+yKVDWaJvkLpY3FE8qSmUnr3A4tZF2qBwKnzIxrLV4UXM1Fxv5qyg6sgx6zrPrmkENHVemYR693LU8= 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=W8uqf2zd; 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="W8uqf2zd" Received: by mail-pl1-f179.google.com with SMTP id d9443c01a7336-223fb0f619dso19123685ad.1 for ; Fri, 11 Apr 2025 03:59:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369157; x=1744973957; 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=WNsggH78Gujq22EIg5QA+ygoUlPHiqAj8S6vH5ayXvk=; b=W8uqf2zdbXcIa4+ACQdrVhXrWCZXk6jyA/onIbfexogHthWLxyjlxMepujBcUlbG/W JP3mwJ1tq4x5z6/e/8VrDfOrXmlC1kts9K6gQIOLSugNY66CY0+q1VCnRWCF44cNV8Ie VQtxKNjZEgeKHaKDBHX6CO46gaSj76QaBJKUHOscGLccmtie9lomapIkMlKRFOK39R3N /HWKt+p8T2MFjZeaNglNubJJHCsEJM3gf8JFtmYjkP0DmMaIHfCPrlxX3ySnN3pEawFq P3vTND70cEvJiZrPr2yNTr81LUqG9akHSc2Ni2zhOJUPxdpBNRPXvViRfucx1pabYQsm x1ww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369157; x=1744973957; 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=WNsggH78Gujq22EIg5QA+ygoUlPHiqAj8S6vH5ayXvk=; b=igQrAspWavEk2FaFQf6I0Gop0rFuR77q+WgRj9gFOhZTrCNRxSxjl6pQQo5r8QIWMu 7H8loDL+GwvpqZmrltn2HFTUnoZoVjCt1re0cIcSZ2hDVqod3gbC0RJqMdkTYgltuXgO 5QNQfhYups41lAuhrRvBVJQIyPmUhYnC5O6liUFTHBpT369p4pF+2WGtP8TtXWjqo+XK p/f9jwUSDl/eE78eufVlZr9Gz5Dj+Mb/dG4skC+3Xs5gqOyxaDPZ0358Lsnfidxi+s71 TQu241+eLZggRxKlSb0LxoOz43orgxAAAy86mtDAihzzaSQHZE7avCJhrjL5DiVCEfiG uB2g== X-Forwarded-Encrypted: i=1; AJvYcCUgfbap/p4+GYeZjK4duktF+d8AGXiXExu0u3ZhBsIRQoGr7CDT0BvTacYkEjXGe3zPm/UZU4MUGY4CQFA=@vger.kernel.org X-Gm-Message-State: AOJu0YzOFSS7aICvOJT/fmlRXo1ITv5u07xSKSgJGppmGSTXtg7D8wWZ 01m0MHKCQ/RbHYc+VydWg2xokrdzR8CU//BBj8cVoQSPrjobnAdfBH1ObTta7Rw= X-Gm-Gg: ASbGncuKsww2JfERvp3bc4XQjGRGEe27hMkd8UPuEbw/ziRxIRc485UQ3SxgKTks4wY E3AE56OT2zTviuQJ6BxmgPn1txbRmAbtjr0GMLlicho+tzC59cIVDQqVjBgRaHHDuq7Xc2g1iqj +IfDihokiXeA+r4YCDvFmO7UDgZ5SRB4vhsh1ieG0jtTKxWGiDIfj7cHqar0js9ybcIyt0dpP26 kc0k3dAeW+dD1Kda+ArHBOLP/kdw8eiSbz9b/8E2yWwlq6jDFNiW2VyR3SBnF48wZy8/VpR4L+U 0CGpX6QEeC2gND8kzf7oGH7RRtUqDQXc+6edptXtc/bdynwG9YQe X-Google-Smtp-Source: AGHT+IH9e7cgh40RGHrp6DdyOeOKOuNr9Mg3YeYV53VmI8E16z+vogz/YR9lNX06NEc1ZrK9TH2sfQ== X-Received: by 2002:a17:902:f78c:b0:223:2630:6b82 with SMTP id d9443c01a7336-22bea494e3amr41594895ad.10.1744369157462; Fri, 11 Apr 2025 03:59:17 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7ce07e1sm45797485ad.258.2025.04.11.03.59.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:16 -0700 (PDT) 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 , Danilo Krummrich , 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Daniel Almeida , linux-kernel@vger.kernel.org Subject: [PATCH V9 05/17] rust: clk: Add helpers for Rust code Date: Fri, 11 Apr 2025 16:25:04 +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" Non-trivial C macros and inlined C functions cannot be used directly in the Rust code and are used via functions ("helpers") that wrap those so that they can be called from Rust. In order to prepare for adding Rust abstractions for the clock APIs, add clock helpers required by the Rust implementation. Reviewed-by: Daniel Almeida Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/helpers/clk.c | 66 +++++++++++++++++++++++++++++++++ rust/helpers/helpers.c | 1 + 4 files changed, 69 insertions(+) create mode 100644 rust/helpers/clk.c diff --git a/MAINTAINERS b/MAINTAINERS index bd7c54af4fd4..608689342aaf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5883,6 +5883,7 @@ F: include/dt-bindings/clock/ F: include/linux/clk-pr* F: include/linux/clk/ F: include/linux/of_clk.h +F: rust/helpers/clk.c 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 ab37e1d35c70..f53d6e1a21f2 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/helpers/clk.c b/rust/helpers/clk.c new file mode 100644 index 000000000000..6d04372c9f3b --- /dev/null +++ b/rust/helpers/clk.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +/* + * The "inline" implementation of below helpers are only available when + * CONFIG_HAVE_CLK or CONFIG_HAVE_CLK_PREPARE aren't set. + */ +#ifndef CONFIG_HAVE_CLK +struct clk *rust_helper_clk_get(struct device *dev, const char *id) +{ + return clk_get(dev, id); +} + +void rust_helper_clk_put(struct clk *clk) +{ + clk_put(clk); +} + +int rust_helper_clk_enable(struct clk *clk) +{ + return clk_enable(clk); +} + +void rust_helper_clk_disable(struct clk *clk) +{ + clk_disable(clk); +} + +unsigned long rust_helper_clk_get_rate(struct clk *clk) +{ + return clk_get_rate(clk); +} + +int rust_helper_clk_set_rate(struct clk *clk, unsigned long rate) +{ + return clk_set_rate(clk, rate); +} +#endif + +#ifndef CONFIG_HAVE_CLK_PREPARE +int rust_helper_clk_prepare(struct clk *clk) +{ + return clk_prepare(clk); +} + +void rust_helper_clk_unprepare(struct clk *clk) +{ + clk_unprepare(clk); +} +#endif + +struct clk *rust_helper_clk_get_optional(struct device *dev, const char *i= d) +{ + return clk_get_optional(dev, id); +} + +int rust_helper_clk_prepare_enable(struct clk *clk) +{ + return clk_prepare_enable(clk); +} + +void rust_helper_clk_disable_unprepare(struct clk *clk) +{ + clk_disable_unprepare(clk); +} diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index e1c21eba9b15..ae595c9cd91b 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 "clk.c" #include "cpumask.c" #include "cred.c" #include "device.c" --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 2026 Received: from mail-pf1-f170.google.com (mail-pf1-f170.google.com [209.85.210.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 60DD329B213 for ; Fri, 11 Apr 2025 10:59:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369164; cv=none; b=fAiv+nzz5mz1b/lgH7EOVc8/uT03AgWYPDVL1sNkQBgeQlYw96q+s4qIzKMNe9yOUFxXJnYy1dkzot8SbHtxCymNSkbPeec4u/bfbV+DuweY7bywICc9yMvr9K6TqV0mG/ErFOYCr1qWUG/7TGao/BDxwpaP1rCDqOhTzscGFgU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369164; c=relaxed/simple; bh=mq6O5qS36H3RIwMRrR25gHoIsocZEAS0wWbW0Y6EpWI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=izdn1WOcLhUEGEBc1aYc50fvPXe9EvPBXzc6MufUvwHsWntdVlRHD7/QOHPgcq1Or8kNUi32/ZDG9/U1PUG9bXvA24CBlXnejdWe0x306R3UKCBW8d4yYB54ZPR4pSkBx1F3Gt2SLldxR0zaVM76K6duH/Z1/UacH3CA2sKKsug= 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=cRtW4H0t; arc=none smtp.client-ip=209.85.210.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="cRtW4H0t" Received: by mail-pf1-f170.google.com with SMTP id d2e1a72fcca58-7390d21bb1cso1786381b3a.2 for ; Fri, 11 Apr 2025 03:59:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369161; x=1744973961; 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=P555m9dInNA1dM2vNde2UqRrjVYEkYAH0OSSlbPCy7M=; b=cRtW4H0to3zBYR+aWKHc6l5w/QIKkCQtHpQmev5b2vAiunr8oFoYbjICCUUY+FChiO yIGYAEeVby6st9eZomVJTGtgZiF6EmTKUrxToPbakZA9fi1vhaTF6mObNB9pa3mPzVIF n06c21t7jDubTYEWZNwaFfKHs5zjL6KWJhxp7akOGaQR8NIYebkCf3B1J6hNanqjq6Kf pvnSmEGKPxu3oI7sK9ojWtgV7p4KMGY+xRK7ldBpWdDlWhxZlkFRqoS2ZGbuWhPOrXkN blqhnRr7zHRUKWVdMKe87TzCrtSOEKu9vUeX83bKgqOLS9brMBm/ilyweibN6xX1D1vI gk7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369161; x=1744973961; 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=P555m9dInNA1dM2vNde2UqRrjVYEkYAH0OSSlbPCy7M=; b=HvxtMj61TzfxyvCIOyBkP6u2cZypQamnpeoANuCAdnDgXbYR0Zy0BU2RsOoXL2n76l 2EMge1vJFoF0XKlrvHbPoX7QqCBWl3rnOen/+sMS0BiMuv2ZMEEfwRpNOkpC2w6E1jqn 8ATEAdb7+m54UeInsNVs8xJHJ0/8Mk3H2AbZkZmlGxfvDRMBxAMva53anD/05e0Ap8vM Q2HbpEKoCX8x1RKJEdKOE+FPUg+OEy+gZIiCFzjUBeqk/YZRuaTcmuxb7ZlTsPDvtp66 5ul+GIiR59v38IoutQIN+rubRCClCJqf379nAy8ob0XhLXr8vR8AbEiVRQxMpPrv0reD 8Z3w== X-Forwarded-Encrypted: i=1; AJvYcCXdt4kqypMTJQnqUAFlbsdQIUAiDKRBqyb8UkBvfUcnGto8SLJ/hM0Hj/FCq/3PzwSgZJsY3tmm3Q0r1uc=@vger.kernel.org X-Gm-Message-State: AOJu0YxP9hKN0DFCNLmQPaFeYoxkd4Yz60DpOVshwdIRZvEpAiXA8PKg PzambKrudtQx8ZLWJJ8fibYU0K3SkNTc0Kgx7paQqK09fAXkY0e36L4bAlmyALk= X-Gm-Gg: ASbGnct3ghqCRsSupwaJ8SRbk9j7unqt4BKG7sQgwW6ulNVzwGdP0uzm7wQJgTfzBCI H44jbjOtWQdmHuW/mftjtGx/QrStgVVqLzA4TqI3xYdKQh94vuPUAUArceuUftPupx75vA4cnXe kHIYWcsbGgjhSs6RYJVPb1vLzm2rjl4snzWXLihHL2Hw+Hcqjxubg1s95ig9j4NJ78mlvUZrOMV xPZBs8rwL7i8j07Oms8iVxGJjyjnZWnBxJtgV2Jfyx2KVuvtcGOHXk552X5QihoVLHGC8imkriL C2/N0hDN4CdR/hbZPbkRUAZhsfWV0DY8zyMwFEjSSw== X-Google-Smtp-Source: AGHT+IEkfFwyCe94bOjmjULnv83o+CRuQZhsOYhW5Y6RrKug8u/hshMXoaRE5SJ6RSPLF5S0Ew/TfQ== X-Received: by 2002:a05:6a00:4644:b0:736:9e40:13b1 with SMTP id d2e1a72fcca58-73bd12b1315mr3071528b3a.23.1744369161489; Fri, 11 Apr 2025 03:59:21 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd2198c0bsm1180060b3a.23.2025.04.11.03.59.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:20 -0700 (PDT) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Danilo Krummrich , Michael Turquette , 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Daniel Almeida , linux-kernel@vger.kernel.org Subject: [PATCH V9 06/17] rust: clk: Add initial abstractions Date: Fri, 11 Apr 2025 16:25:05 +0530 Message-Id: <15f1d8ddae565f6060f4fc2d9ee82bc179c81287.1744366571.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" Add initial abstractions for the clk APIs. These provide the minimal functionality needed for common use cases, making them straightforward to introduce in the first iteration. These will be used by Rust based cpufreq / OPP layers to begin with. Tested-by: Daniel Almeida Reviewed-by: Daniel Almeida Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/kernel/clk.rs | 319 +++++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 3 files changed, 322 insertions(+) create mode 100644 rust/kernel/clk.rs diff --git a/MAINTAINERS b/MAINTAINERS index 608689342aaf..12cde55579a0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5884,6 +5884,7 @@ F: include/linux/clk-pr* F: include/linux/clk/ F: include/linux/of_clk.h F: rust/helpers/clk.c +F: rust/kernel/clk.rs X: drivers/clk/clkdev.c =20 COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3) diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs new file mode 100644 index 000000000000..477daa408587 --- /dev/null +++ b/rust/kernel/clk.rs @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Clock abstractions. +//! +//! C header: [`include/linux/clk.h`](srctree/include/linux/clk.h) +//! +//! Reference: + +use crate::{ + bindings, + device::Device, + error::{from_err_ptr, to_result, Result}, + ffi::c_ulong, + prelude::*, +}; + +use core::{ops::Deref, ptr}; + +/// The frequency unit. +/// +/// Represents a frequency in hertz, wrapping a [`c_ulong`] value. +/// +/// ## Examples +/// +/// ``` +/// use kernel::clk::Hertz; +/// +/// let hz =3D 1_000_000_000; +/// let rate =3D Hertz(hz); +/// +/// assert_eq!(rate.as_hz(), hz); +/// assert_eq!(rate, Hertz(hz)); +/// assert_eq!(rate, Hertz::from_khz(hz / 1_000)); +/// assert_eq!(rate, Hertz::from_mhz(hz / 1_000_000)); +/// assert_eq!(rate, Hertz::from_ghz(hz / 1_000_000_000)); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Hertz(pub c_ulong); + +impl Hertz { + /// Create a new instance from kilohertz (kHz) + pub fn from_khz(khz: c_ulong) -> Self { + Self(khz * 1_000) + } + + /// Create a new instance from megahertz (MHz) + pub fn from_mhz(mhz: c_ulong) -> Self { + Self(mhz * 1_000_000) + } + + /// Create a new instance from gigahertz (GHz) + pub fn from_ghz(ghz: c_ulong) -> Self { + Self(ghz * 1_000_000_000) + } + + /// Get the frequency in hertz + pub fn as_hz(&self) -> c_ulong { + self.0 + } + + /// Get the frequency in kilohertz + pub fn as_khz(&self) -> c_ulong { + self.0 / 1_000 + } + + /// Get the frequency in megahertz + pub fn as_mhz(&self) -> c_ulong { + self.0 / 1_000_000 + } + + /// Get the frequency in gigahertz + pub fn as_ghz(&self) -> c_ulong { + self.0 / 1_000_000_000 + } +} + +impl From for c_ulong { + fn from(freq: Hertz) -> Self { + freq.0 + } +} + +/// A reference-counted clock. +/// +/// Rust abstraction for the C [`struct clk`]. +/// +/// # Invariants +/// +/// A [`Clk`] instance holds either a pointer to a valid [`struct clk`] cr= eated by the C portion of +/// the kernel or a NULL pointer. +/// +/// Instances of this type are reference-counted. Calling [`Clk::get`] ens= ures that the allocation +/// remains valid for the lifetime of the [`Clk`]. +/// +/// ## Examples +/// +/// The following example demonstrates how to obtain and configure a clock= for a device. +/// +/// ``` +/// use kernel::c_str; +/// use kernel::clk::{Clk, Hertz}; +/// use kernel::device::Device; +/// use kernel::error::Result; +/// +/// fn configure_clk(dev: &Device) -> Result { +/// let clk =3D Clk::get(dev, Some(c_str!("apb_clk")))?; +/// +/// clk.prepare_enable()?; +/// +/// let expected_rate =3D Hertz::from_ghz(1); +/// +/// if clk.rate() !=3D expected_rate { +/// clk.set_rate(expected_rate)?; +/// } +/// +/// clk.disable_unprepare(); +/// Ok(()) +/// } +/// ``` +/// +/// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html +#[repr(transparent)] +pub struct Clk(*mut bindings::clk); + +impl Clk { + /// Gets [`Clk`] corresponding to a [`Device`] and a connection id. + /// + /// Equivalent to the kernel's [`clk_get`] API. + /// + /// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.cl= k_get + pub fn get(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`] for a valid device point= er. + // + // INVARIANT: The reference-count is decremented when [`Clk`] goes= out of scope. + Ok(Self(from_err_ptr(unsafe { + bindings::clk_get(dev.as_raw(), con_id) + })?)) + } + + /// Obtain the raw [`struct clk`] pointer. + #[inline] + pub fn as_raw(&self) -> *mut bindings::clk { + self.0 + } + + /// Enable the clock. + /// + /// Equivalent to the kernel's [`clk_enable`] API. + /// + /// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c= .clk_enable + #[inline] + pub fn enable(&self) -> Result { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for [`clk_enable`]. + to_result(unsafe { bindings::clk_enable(self.as_raw()) }) + } + + /// Disable the clock. + /// + /// Equivalent to the kernel's [`clk_disable`] API. + /// + /// [`clk_disable`]: https://docs.kernel.org/core-api/kernel-api.html#= c.clk_disable + #[inline] + pub fn disable(&self) { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for [`clk_disable`]. + unsafe { bindings::clk_disable(self.as_raw()) }; + } + + /// Prepare the clock. + /// + /// Equivalent to the kernel's [`clk_prepare`] API. + /// + /// [`clk_prepare`]: https://docs.kernel.org/core-api/kernel-api.html#= c.clk_prepare + #[inline] + pub fn prepare(&self) -> Result { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for [`clk_prepare`]. + to_result(unsafe { bindings::clk_prepare(self.as_raw()) }) + } + + /// Unprepare the clock. + /// + /// Equivalent to the kernel's [`clk_unprepare`] API. + /// + /// [`clk_unprepare`]: https://docs.kernel.org/core-api/kernel-api.htm= l#c.clk_unprepare + #[inline] + pub fn unprepare(&self) { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for [`clk_unprepare`]. + unsafe { bindings::clk_unprepare(self.as_raw()) }; + } + + /// Prepare and enable the clock. + /// + /// Equivalent to calling [`Clk::prepare`] followed by [`Clk::enable`]. + #[inline] + pub fn prepare_enable(&self) -> Result { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for + // [`clk_prepare_enable`]. + to_result(unsafe { bindings::clk_prepare_enable(self.as_raw()) }) + } + + /// Disable and unprepare the clock. + /// + /// Equivalent to calling [`Clk::disable`] followed by [`Clk::unprepar= e`]. + #[inline] + pub fn disable_unprepare(&self) { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for + // [`clk_disable_unprepare`]. + unsafe { bindings::clk_disable_unprepare(self.as_raw()) }; + } + + /// Get clock's rate. + /// + /// Equivalent to the kernel's [`clk_get_rate`] API. + /// + /// [`clk_get_rate`]: https://docs.kernel.org/core-api/kernel-api.html= #c.clk_get_rate + #[inline] + pub fn rate(&self) -> Hertz { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for [`clk_get_rate`]. + Hertz(unsafe { bindings::clk_get_rate(self.as_raw()) }) + } + + /// Set clock's rate. + /// + /// Equivalent to the kernel's [`clk_set_rate`] API. + /// + /// [`clk_set_rate`]: https://docs.kernel.org/core-api/kernel-api.html= #c.clk_set_rate + #[inline] + pub fn set_rate(&self, rate: Hertz) -> Result { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for [`clk_set_rate`]. + to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_h= z()) }) + } +} + +impl Drop for Clk { + fn drop(&mut self) { + // SAFETY: By the type invariants, self.as_raw() is a valid argume= nt for [`clk_put`]. + unsafe { bindings::clk_put(self.as_raw()) }; + } +} + +/// A reference-counted optional clock. +/// +/// A lightweight wrapper around an optional [`Clk`]. An [`OptionalClk`] r= epresents a [`Clk`] that +/// a driver can function without but may improve performance or enable ad= ditional features when +/// available. +/// +/// # Invariants +/// +/// An [`OptionalClk`] instance encapsulates a [`Clk`] with either a valid= [`struct clk`] or `NULL` +/// pointer. +/// +/// Instances of this type are reference-counted. Calling [`OptionalClk::g= et`] ensures that the +/// allocation remains valid for the lifetime of the [`OptionalClk`]. +/// +/// ## Examples +/// +/// The following example demonstrates how to obtain and configure an opti= onal clock for a device. +/// The code functions correctly whether or not the clock is available. +/// +/// ``` +/// use kernel::c_str; +/// use kernel::clk::{OptionalClk, Hertz}; +/// use kernel::device::Device; +/// use kernel::error::Result; +/// +/// fn configure_clk(dev: &Device) -> Result { +/// let clk =3D OptionalClk::get(dev, Some(c_str!("apb_clk")))?; +/// +/// clk.prepare_enable()?; +/// +/// let expected_rate =3D Hertz::from_ghz(1); +/// +/// if clk.rate() !=3D expected_rate { +/// clk.set_rate(expected_rate)?; +/// } +/// +/// clk.disable_unprepare(); +/// Ok(()) +/// } +/// ``` +/// +/// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html +pub struct OptionalClk(Clk); + +impl OptionalClk { + /// Gets [`OptionalClk`] corresponding to a [`Device`] and a connectio= n id. + /// + /// Equivalent to the kernel's [`clk_get_optional`] API. + /// + /// [`clk_get_optional`]: https://docs.kernel.org/core-api/kernel-api.= html#c.clk_get_optional + pub fn get(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_optional`] for a valid dev= ice pointer. + // + // INVARIANT: The reference-count is decremented when [`OptionalCl= k`] goes out of scope. + Ok(Self(Clk(from_err_ptr(unsafe { + bindings::clk_get_optional(dev.as_raw(), con_id) + })?))) + } +} + +// Make [`OptionalClk`] behave like [`Clk`]. +impl Deref for OptionalClk { + type Target =3D Clk; + + fn deref(&self) -> &Clk { + &self.0 + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 75f78f6bfaa6..f4dcfefe94be 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -42,6 +42,8 @@ pub mod block; #[doc(hidden)] pub mod build_assert; +#[cfg(CONFIG_COMMON_CLK)] +pub mod clk; pub mod cpumask; pub mod cred; pub mod device; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 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 7339B29B212 for ; Fri, 11 Apr 2025 10:59: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=1744369167; cv=none; b=kBuD9WjxCVpmXIuKfiKCfHKWxCCogGPN7IQeGNsw6khVeSht1+GUD7jbYE40lSLYQmb84YXPDGinhaVTuSTcpOlv1vzJR+o+DIbmp7TniuJe57pFHGz2kWi7CPosJY0OH3C6nGNu472tXjig/rpItX4iJU2aXnwzDr72TaH1rl4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369167; c=relaxed/simple; bh=RPs39+G/2/WRBdJP3KwTQnQlR3Lp/kvURzUIgtDgvwA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=PNxwpAR6MUdcUjWQlA8/MVzqRBW5oqCB+PNL3ar+JjWhUDxPLH2x8DMHff7ycODeHhrSzLqBXT46VOCW987p5Eo6FkDriTY+0lX7gx4aZ446t5i+tpbbcMCuApgQmBkP1ZyZw0UWI/LXbUGlOTQ8f6fHbAvnU3rf/wOo3lMEVNM= 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=RNVFcHEW; 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="RNVFcHEW" Received: by mail-pl1-f177.google.com with SMTP id d9443c01a7336-22401f4d35aso21267685ad.2 for ; Fri, 11 Apr 2025 03:59:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369165; x=1744973965; 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=06XWI3zWvI8xB81BSzBcpZnXhq7zBjUBfZT4cp51CDs=; b=RNVFcHEWGOgYlNI8KftVur5ayquxbwJHol7kiPbc3tKKgN66bUuTOpoR4GaIVypYaC /RMJN9ISJC7W/aUX+hOXne97e5X8KMABreFSnD+nOJ8zVfI5SWEElhEOOvHjzFpVPtD6 UzKHURwBiXaw+mFx1kAfI1Jc152f9Gj6U2C9ufSVNYpSFdPOIIlyEJuBYK8tAv8VG1Lo oMmyMI1TGk+WT+yh5Uwo8DgXVyjXsOCf6+4UqHfYhxQTWfwv+nr1Q+6ZjXmK1KrXwWX4 hDfu+UgCcNWmFe6iyeo5fI5/io7GB8tW9IAyL5N8oCqEJM7S1VOYvY49djaUFJI56T2W n8qA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369165; x=1744973965; 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=06XWI3zWvI8xB81BSzBcpZnXhq7zBjUBfZT4cp51CDs=; b=DLQJXSkTXTaQ4+A4RrRSB3ITRiCopYPy1Bs6JwNBOb8D5RiNdYrKL0fsdppA/TN1Lm +p4upEnmeeN2+/vX6Uw3/x2GGBmMV0a3crwkZn0CgMPlcadL8o8CBEJJBwN2GtzZGQZM RIq17TcF7EoUfwIWT2nTRnTDSM1tP7PWa45xwkkdZCd4zHyM0h5A/FK9mxeJyIzlbctY 9eLYDpzvakAi1BAygb4+GdjXiXN71K4aW621YWVQt4pNVnrhvCpbvUrz0iBHqCOcxiEa yZ3PKdmRlwlPEJWgZKipyrkV13ykqUgCEXj0JEYCZTT/6/iIna11EdY8b8gauEHO6Klk PbHg== X-Forwarded-Encrypted: i=1; AJvYcCXmMl1Rhti1tMhXmVD2gcxo/Y9+RABtz1caNYB7wqnQDCutJqZBXaiTE5GfEESr1kqzKm8CjchYpDeTW7Y=@vger.kernel.org X-Gm-Message-State: AOJu0YzXEIjE2MqY3/MEe9bVFecpWbdYqBROe6zBM7PWEku6I8Lv9Xbl g7VigPhi+1kTo3z3pJiQLYdrxD1g34qFR53qnCWjhlRq9Pq34gOFIg6WDkaVG0c= X-Gm-Gg: ASbGncsZyYGpf4PZvpTehhwyLxUbD4m/UFlx1hpUIsAw558js4TSSf1yH52YEP10fxi IuFlST7ZuSxwBrTyAwfkjaNW7dNaZkCu60ukM7thjRZSBkn/1WiOPCNtKJzRoe4Co4VG2ljDfMU m8jVo9ugQ+JXoABUdUvY/7onCIgIS61vXvhNVs2w0vygPsSAHGwZLOZxEvEGTVmh/WjVMJlUWWk 6idjIRuYC8urTlOYawg+KNj4j9MNo2rwhl0IS7AgScixWZsyf4YzEY842VBeRRlWWbrswQNcSPc oTeDsLiGIPWFI/HCZ/j9Pyc/P9z++hgwxfPJaaCvWg== X-Google-Smtp-Source: AGHT+IFdC80llUDCc+trbEGjipwqaa3VqSInfFU2yq5qqcipKd6mbFI5BWR0rPyYDQBL1rjnG7EZVQ== X-Received: by 2002:a17:903:2b07:b0:220:c066:94eb with SMTP id d9443c01a7336-22bea4bd7e6mr36916335ad.25.1744369164747; Fri, 11 Apr 2025 03:59:24 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd230f2fcsm1177969b3a.151.2025.04.11.03.59.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:24 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , Anisse Astier , linux-kernel@vger.kernel.org Subject: [PATCH V9 07/17] rust: macros: enable use of hyphens in module names Date: Fri, 11 Apr 2025 16:25:06 +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" 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 '-', and fix line length checkpatch warnings] Signed-off-by: Viresh Kumar --- rust/macros/module.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/rust/macros/module.rs b/rust/macros/module.rs index a9418fbc9b44..27cc72d474f0 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -185,7 +185,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); } @@ -310,14 +312,15 @@ 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 \"# ); @@ -325,7 +328,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. @@ -335,13 +338,13 @@ 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` - // (which delegates to `__init`). + // - furthermore it is only called after `__{name_= identifier}_init` has + // returned `0` (which delegates to `__init`). unsafe {{ __exit() }} }} =20 @@ -381,6 +384,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 17:55:12 2026 Received: from mail-pf1-f169.google.com (mail-pf1-f169.google.com [209.85.210.169]) (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 EDC8929C335 for ; Fri, 11 Apr 2025 10:59:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369170; cv=none; b=pJAGM/UK2dQE2uD18dEaDboXfX1Sve21vzu36OAoSVEYELmt8f1XDac7KM4tNsaozBsaWyZjer/z25smkkHLI0wJpQ2tVdw+xGxLcCxlQkvJtECZA831PHjPKr8MFoTR4MlfLaDQyNPN/UVLRawnRvH2Rg1VEyIuoHO32lB5YjI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369170; c=relaxed/simple; bh=TASzFe4KkdQHPJ8mONPPBe7339nuUPyow0ze0CYWoKE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=JJ4pkCLUhZgqoHHIgCwWTZEdOprXrbRgN5jEavcdQ7t+f80JaloDvqD88HZ/OJo65Mus/6o03EUHlBB0MrrFFaPWDSDLNIMiaDPLPGVQIOWFW34TqPzLfRWJt22HNRvZHqcOS3clrW48UjbcHvRQyKh4z/tpWTBLouJg/wreXeU= 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=K3n0kt4+; arc=none smtp.client-ip=209.85.210.169 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="K3n0kt4+" Received: by mail-pf1-f169.google.com with SMTP id d2e1a72fcca58-7394945d37eso1621904b3a.3 for ; Fri, 11 Apr 2025 03:59:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369168; x=1744973968; 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=9Fe6e6xig4JsW2EGU2g8ZB0kG+/KOTdn8cRbvkRNqmM=; b=K3n0kt4+tsBhgPQDjeYpEsgY82h0BwOkKS9GYFosDQFXx9SaDf26mELPVZ23lIvs5w 9k9k5a31eUpV9FW8HcpM/lUs4mQ6VKxPQ+m5qJmYsJn9DNKleGEE6H67olRcbLjDpDjq FRy7C8QlCuzfseYIg29fMf2MS2gDXzDz7Na6kDdaFChKjk9o6XzDlZcqafc0yvgYbrkH mXYVMDf1mTM1DtciM55aE5EpDn0/vo3ay+0kozZJSgxDrQtrc8Q92t7B5YNBtlsoIX8B 1BfiodGle8E1kasYf7fB6r+GYUbW+lMjVzbBAG/yijXXWdh6GJs6v3qC6aZm1B0kyKB5 IcOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369168; x=1744973968; 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=9Fe6e6xig4JsW2EGU2g8ZB0kG+/KOTdn8cRbvkRNqmM=; b=OGnOPa2Q9s89LnW8oO3EvhpunU321y54MTlEpqtxFdNmj+/uG1dxYvivoflqnV5X0N gB6IZ6kEY8JjxUEg4RgzboilPv0QHaArDR+Vyef3JQNrQqipEnVdvMyzvUqsIpciY5uZ fSYBVgxLDqiRD6HxUO9TfI4YM/ASQOYPS/DEXjAwySZiosRvnX3CI1U3YDHhWumNbh3I BLIpjEnq8Ej+pnZdTf5XTwwzD06Oc0Oa1b6BhrAj/o2E01X4fIICWeTqaGqGnBaiEr38 lrCPT97xEEPNP0udhNObDi5L8GRweyCaqkUIpZY594zvQdo4YRBT6sJb0IfUw3Yz3mJI l9Bw== X-Forwarded-Encrypted: i=1; AJvYcCWu6hOEBLaIAoDYT3y4a7SNiiY0+/lA5q5aw7YdsK9gTXYmJ85XORiLRZxTPzKy2vW2DABOpHwNrflAX8Y=@vger.kernel.org X-Gm-Message-State: AOJu0YyTuE/vLNSuE9NW5lLnufHZHO8BPeqES3dodygguBL+ZPjRh5N/ gqSbbyzPlyBueN7FfobpHSEFLCIqJN+QicgQWtzqji5y5HmvkeV6N/AeBWXPVXc= X-Gm-Gg: ASbGnctASRRCU2c/ignnx7Pak0irH8R3lKyR64HxA/ZDXR4P3XgRmNdkTCy0JzLLGah ohtrJtsGrPbqaWKBEA1qJv8FNpmGPJlUM+xAsPlr3axt/ixbeglQh3X9HvBRL7x0D1/1GVD+qVM iP9P8aAosAK/JnEMM0/bdiqG6LInFVpI4DKxrAJHQjhUxYACera9JtLTcTRaR7zaeQWPGhknvig +kqtA1OWVouziA0LgE79YNFxoiqQTc1gLEP3+X2PYilKrtdwtHnnwi+RgbzmauXunfC7/NSHk3I sYV9VwsiNw5EPkwiGD6hNy8Jg89k04rULiOR+4mhB+pmd01m9MNF X-Google-Smtp-Source: AGHT+IFkRCEV/NTt2biHw/E1GMU+IZP1L1H7t9UuwWWpn6sRLxyupr9IGU4747ikedGlYmnFckPnWw== X-Received: by 2002:a05:6a20:c6c9:b0:1fe:90c5:7ceb with SMTP id adf61e73a8af0-201799964ddmr4296796637.40.1744369168283; Fri, 11 Apr 2025 03:59:28 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-b02a2d3abffsm3792427a12.48.2025.04.11.03.59.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:27 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 08/17] cpufreq: Use enum for cpufreq flags that use BIT() Date: Fri, 11 Apr 2025 16:25:07 +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 400fee6427a5..354ae35fe708 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -298,11 +298,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) @@ -424,52 +425,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 17:55:12 2026 Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com [209.85.214.172]) (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 D7A32238C3B for ; Fri, 11 Apr 2025 10:59:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369175; cv=none; b=lwk0/lzvCtbNO6eY0AZjAxcN5XmoKrvubMB+Umz/tEIYpNpvAMBxqFWigQRq8rLUkEVDFdpgZ1wrPhy+bq7QHvHgNjCm/YQHjV45jeXO7L57jezSPKaUMz/W4bG8qktYMtvxJmsDadcRD8gPgIg1EiGrjrr8oBx/3FNrzvFsfhY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369175; c=relaxed/simple; bh=Byyja/LGiSc3XLWcrkh1dI+1vAbHiMVZxbMK+5UoA5o=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=IIB8tssNsrjY8+PxnoLdR+IRuJMNlT7gGkOc/EUNnY9MqwWEbPDwiZaYUFJFZv30J+1ifbexS+0+93eNI/83crD8WkQGRJ+2pMhyk7fBgglp/sHDpSe+p9UN9LmzHLe9oXWJVuVPBmCvazBqoqI8hN5xDZuwnCVqkD6w2hpGOIw= 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=NviPOeo7; arc=none smtp.client-ip=209.85.214.172 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="NviPOeo7" Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-224100e9a5cso20105975ad.2 for ; Fri, 11 Apr 2025 03:59:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369172; x=1744973972; 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=X+Cdlcrsb0s4b6sV0qOOxY8kfU8SJ6MQU1RsCnBdvL8=; b=NviPOeo7m3bFs5pclrqrdwRClbuZnskMh3kDwmyCLhpG6vx0y5kNuvQy0ptCfR2kIV isIsXyzsUD43cHj4bHOb0gH30PK6Ms1K4KJb5XB0jG4UnYQZI/axscoqEnCgBjoz5v7Q zm/bLEWYGa9uEXQ/Z73wkCSwvs+LWyPeQpabb/BEkVSEGVWr4tMxRw3WlsGzpNfAN6QB PjvYo+FAxeNP4OkWTARWwwtpfwbKdNa3X1lbHLQBViLaCSG3iI070sGCoJvh/0Xu3T5I X1+yH4xM48ZXzADajDpkjisY5Zv/3OVGl34+mIKIdORm8HZBw3kFG1gGeM4Fxae4xUMQ oSuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369172; x=1744973972; 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=X+Cdlcrsb0s4b6sV0qOOxY8kfU8SJ6MQU1RsCnBdvL8=; b=oXttBIi2Evws4sIQDmYuiDhTt0yWcqTNQb9Qsuo3U3tV3eocbzeWJTHw0wYFjmap/s PxoPubpRDRRd/9bQ0dMGnikDW5a6fhzaFdgRZnSCz3RRy2d0vYPWl35wd/W8D1BnJ3oI BK+utun6G9C6mNEa0KO2ILBFpavixWmeSZ1BTELiNcITrrQ9hF/M8tMSTWvNrr//NRz1 DL+IFBDySz0mgMTITyc/44bRmH+k0gej5VMQJOzB5/3rJDZbR8uJ20TusdTj34g5Xr4E oBc5aMD5NqfBZ5Pl3ouSvhPH6J5QfX1sol2suOSjEUWJyU52ANQORZiZl/uaIuMyZpR4 uR5Q== X-Forwarded-Encrypted: i=1; AJvYcCVXh1OSsa5owQjL4Y4z9OCM0jXX5zNoyxtKG8xAg5PShYCYw4VOn8DgBFHt9NLDdx8sxkN5p9yPaA5H6eo=@vger.kernel.org X-Gm-Message-State: AOJu0YxD2WCfPcbFv0Mxet1t78JEewwsBFjyk3GXvnS6rU85pyhNdB+Z WirGNrqjGkYhP7feF1U1xKkOyYw1g/3VUfTv1Q3DoRdDok/82qLxW99K74QFteAH//2L9kjOfps w X-Gm-Gg: ASbGnctOxtK5zMrlScP3m3F06CpIxb2D9ZwAzMOrESbb+CMpbGnglW4HIeRCdlaS+LM gETzvbPEGeOk/NHFvG+CkRBLz53Fk5g9JSEf316d5n/TRkv3y4mlYtqO8Nc14HRo3TVF5M3FJVo CcqZ2/kSlEUXp+7EMqAyhLdIh2fdtIM6HF1DN2Ol3ZRR7bCJ/BPqsLnYFX8w0y0S8dQVinnu1vn 56pSG7k0EE2V0O0Rsmpd5mckqyWfx32nghttFi2/1Ei+6/jsGzCFp/c8UxmVjaIQF2zadgbM8G9 DmM0x8D7hpxgfFZzeKysS6iWtDh4xYF6N884c01gag== X-Google-Smtp-Source: AGHT+IFzxhsDTNlU/qz7rOhat5Sn8AXMBCAAIpk2YH/+AobNOEjEcLNAinjLGlCu2Vf5XXJJin63Pw== X-Received: by 2002:a17:902:e751:b0:224:2715:bf44 with SMTP id d9443c01a7336-22bea4ab7a0mr31283275ad.19.1744369172173; Fri, 11 Apr 2025 03:59:32 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7c95c8esm45981535ad.145.2025.04.11.03.59.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:31 -0700 (PDT) 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 , Danilo Krummrich , 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 09/17] rust: cpu: Add from_cpu() Date: Fri, 11 Apr 2025 16:25:08 +0530 Message-Id: <475bc73d8d11290446a4135af76aea123c6d80ee.1744366571.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 12cde55579a0..475abf72869c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6155,6 +6155,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 f53d6e1a21f2..ac92c67d2c38 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/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 f4dcfefe94be..db372f806875 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -44,6 +44,7 @@ pub mod build_assert; #[cfg(CONFIG_COMMON_CLK)] pub mod clk; +pub mod cpu; pub mod cpumask; pub mod cred; pub mod device; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 2026 Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (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 3A89329CB48 for ; Fri, 11 Apr 2025 10:59:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369180; cv=none; b=uZY6Ym0V6WOVRaoXJ/kbLXiVfdhqHjQ9tPKLOL2nzlxrgXkzX2PJab6RIbjW5lONAlGqhFRIzD302LcuzTKb9i4qjFDOi/PS599/5x7S1SkUecC+Pph7P6NsSI1lvKIAbVsUVJxfFAbrvSa0JuonewDByJJ/HBywcmVa0Jbf4w8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369180; c=relaxed/simple; bh=vlmpgN/zBHIjh2H4c5Ov7dFKqyGVQmpGI3Gd4+3j0tg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=sfyzqOXa5tOLNi8VDW47VBOZpDlsw9qegJ+WJ3sI1/2oB9KFltha+mK1CZsleeaKn2ZF/FpPBJ41bODwM234vgJ4UVpHMYxCYDc7y3UcWWfpubtll85q37nF7B5EUyTzs8v8HliZI83+v0F52mwPfcwoEKN2KKwaLJvSnolOUE4= 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=wUN77Zi/; arc=none smtp.client-ip=209.85.214.171 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="wUN77Zi/" Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-2255003f4c6so20049205ad.0 for ; Fri, 11 Apr 2025 03:59:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369176; x=1744973976; 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=+cztfZQqPxjnqWofE/ChubMPUhatuVM9yTjrRAQzZqY=; b=wUN77Zi/lnLV+KsMX+ulND8m3392RbwtxH1oN8OHPlxL+CcXmz6cqmQCy2oO3y/dqK epYOH6MVn8B6VjWTMsUyD7zp+4hOfxOMMXq7yQuLmgf7knXf7j0/ACzVBXLRo7fupRYD 6if5qltqiJpmrnJB9aJ5dUmIUkOY62bZ7VFYJn2WKKaog1eGupy+zMshfTrcjOHC7xLn FnJ6dndxmhe0kP29FMkNBkoBfjqkhIvkFl0o5+FKoi0jwsSL7aRlOLtI1aW9tmNPz3eP RXp0DQMjiZTdtyYmsYde0EVgMunXdFY0a/BJTA46j4rKG0mByq486tcDDrvGnEb926tJ vjww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369176; x=1744973976; 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=+cztfZQqPxjnqWofE/ChubMPUhatuVM9yTjrRAQzZqY=; b=MEW48DYX71YWRdCJnAhLxsRL7ufqcmy/HOBKPAOUPMV7u0W5ehC2B6SopWYkGRS8PA 8p+Jb5yAs/CtNGBt3bkjvpvpe+5Nb/v7fK7lr0wjqCXJI1S+lucM8RzDr1XvxEexFzwT 4n1Mgivwq3YGsHL6mjzFI7AHqCAdmycgVjNEyLkU7i/kRVMmH7SM/mlq///5n5jVe7K/ +T3LRUJk+5rApbc5PDxHyozrqrW7Dd1iQabkHOfA5BiY//1C03jkwF1df/e8hJx4Fck3 udc1i/aMpla3zITz8OUFrxwR0xBFMr3Wj2rqzsvNUBKMtB+nYED1dedLjvEGCS12ZfqV /yBQ== X-Forwarded-Encrypted: i=1; AJvYcCWD5eZSbvcyZ8K5+T9eQnG+cRLJuOQmJy8wi0XNSrde3dvwFWthGHRg2bNw6/vyai7ivIk+O43FSIhgWVc=@vger.kernel.org X-Gm-Message-State: AOJu0YyNYtDIbCem+28XMXGUKdvpS/VweauS8iJsei+99ibEBLUzw7OW wvuMa2m/Eo844ZIjBsi5LRqoExy+ViwkuLntnBNux/6qv6DYPcn89l+PUMQMeOM= X-Gm-Gg: ASbGnctxm/Thf0GGEA11C4iehl7eqYcM5ei6HH3ejdiMs1/YpRI7GncDv03T1/bS9a6 yq/fAOIS5zKqJC/d0GOsaAnACwybUMTp9YYwEblu5UyWlDDbl4Spfw4tzqrSc/7IPCe4M5fnd/k o8/U3LpOqHGCjsO/9r29GvnrsuGCd0Qinyx5SaOtYDposc/iAUL4yMZbHjR/cFLIar7usN5GBsJ 6hmPRFCkjpjxvdQWxx6qmK/EcSZ+a54SllqLitJEerYnPQlZgqUOyfTUhntb2KeSYwQCRdPHEF1 A16VZSm5Cgu8ALwwibIqeQJ+shlpkHk9zMkItEySig== X-Google-Smtp-Source: AGHT+IFmqnaQpraw9B1lIV1L99oKIJ0I/09pqj887rKhPture77c5UATtCkIfntkMSUO5kQbKWzIZQ== X-Received: by 2002:a17:902:d512:b0:224:721:cc with SMTP id d9443c01a7336-22bea4ab7eemr28839375ad.13.1744369176304; Fri, 11 Apr 2025 03:59:36 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cbee8bsm46104895ad.208.2025.04.11.03.59.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:35 -0700 (PDT) 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 , Danilo Krummrich , 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 10/17] rust: opp: Add initial abstractions for OPP framework Date: Fri, 11 Apr 2025 16:25:09 +0530 Message-Id: <18d082f870b9c0c615fc57b49269c0418dab2ed8.1744366571.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" Introduce initial Rust abstractions for the Operating Performance Points (OPP) framework. This includes bindings for `struct dev_pm_opp` and `struct dev_pm_opp_data`, laying the groundwork for further OPP integration. Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/kernel/lib.rs | 2 + rust/kernel/opp.rs | 300 ++++++++++++++++++++++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 rust/kernel/opp.rs diff --git a/MAINTAINERS b/MAINTAINERS index 475abf72869c..931e418f89ed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18165,6 +18165,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 ac92c67d2c38..529f22891e0b 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index db372f806875..11d333c8c673 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -68,6 +68,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..e4780b41664f --- /dev/null +++ b/rust/kernel/opp.rs @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Operating performance points. +//! +//! This module provides rust abstractions for interacting with the OPP su= bsystem. +//! +//! C header: [`include/linux/pm_opp.h`](srctree/include/linux/pm_opp.h) +//! +//! Reference: + +use crate::{ + bindings, + clk::Hertz, + device::Device, + error::{code::*, to_result, Result}, + ffi::c_ulong, + types::{ARef, AlwaysRefCounted, Opaque}, +}; + +use core::ptr; + +/// The voltage unit. +/// +/// Represents voltage in microvolts, wrapping a [`c_ulong`] value. +/// +/// ## Examples +/// +/// ``` +/// use kernel::opp::MicroVolt; +/// +/// let raw =3D 90500; +/// let volt =3D MicroVolt(raw); +/// +/// assert_eq!(usize::from(volt), raw); +/// assert_eq!(volt, MicroVolt(raw)); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct MicroVolt(pub c_ulong); + +impl From for c_ulong { + #[inline] + fn from(volt: MicroVolt) -> Self { + volt.0 + } +} + +/// The power unit. +/// +/// Represents power in microwatts, wrapping a [`c_ulong`] value. +/// +/// ## Examples +/// +/// ``` +/// use kernel::opp::MicroWatt; +/// +/// let raw =3D 1000000; +/// let power =3D MicroWatt(raw); +/// +/// assert_eq!(usize::from(power), raw); +/// assert_eq!(power, MicroWatt(raw)); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct MicroWatt(pub c_ulong); + +impl From for c_ulong { + #[inline] + fn from(power: MicroWatt) -> Self { + power.0 + } +} + +/// Handle for a dynamically created [`OPP`]. +/// +/// The associated [`OPP`] is automatically removed when the [`Token`] is = dropped. +/// +/// ## Examples +/// +/// The following example demonstrates how to create an [`OPP`] dynamicall= y. +/// +/// ``` +/// use kernel::clk::Hertz; +/// use kernel::device::Device; +/// use kernel::error::Result; +/// use kernel::opp::{Data, MicroVolt, Token}; +/// use kernel::types::ARef; +/// +/// fn create_opp(dev: &ARef, freq: Hertz, volt: MicroVolt, level:= u32) -> Result { +/// let data =3D Data::new(freq, volt, level, false); +/// +/// // OPP is removed once token goes out of scope. +/// data.add_opp(dev) +/// } +/// ``` +pub struct Token { + dev: ARef, + freq: Hertz, +} + +impl Token { + /// Dynamically adds an [`OPP`] and returns a [`Token`] that removes i= t on drop. + fn new(dev: &ARef, mut data: Data) -> Result { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] 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 [`De= vice`] and its safety + // requirements. + unsafe { bindings::dev_pm_opp_remove(self.dev.as_raw(), self.freq.= into()) }; + } +} + +/// OPP data. +/// +/// Rust abstraction for the C `struct dev_pm_opp_data`, used to define op= erating performance +/// points (OPPs) dynamically. +/// +/// ## Examples +/// +/// The following example demonstrates how to create an [`OPP`] with [`Dat= a`]. +/// +/// ``` +/// use kernel::clk::Hertz; +/// use kernel::device::Device; +/// use kernel::error::Result; +/// use kernel::opp::{Data, MicroVolt, Token}; +/// use kernel::types::ARef; +/// +/// fn create_opp(dev: &ARef, freq: Hertz, volt: MicroVolt, level:= u32) -> Result { +/// let data =3D Data::new(freq, volt, level, false); +/// +/// // OPP is removed once token goes out of scope. +/// data.add_opp(dev) +/// } +/// ``` +#[repr(transparent)] +pub struct Data(bindings::dev_pm_opp_data); + +impl Data { + /// Creates a new instance of [`Data`]. + /// + /// This can be used to define a dynamic OPP to be added to a device. + pub fn new(freq: Hertz, volt: MicroVolt, level: u32, turbo: bool) -> S= elf { + Self(bindings::dev_pm_opp_data { + turbo, + freq: freq.into(), + u_volt: volt.into(), + level, + }) + } + + /// Adds an [`OPP`] dynamically. + /// + /// Returns a [`Token`] that ensures the OPP is automatically removed + /// when it goes out of scope. + #[inline] + pub fn add_opp(self, dev: &ARef) -> Result { + Token::new(dev, self) + } + + // Returns the frequency associated with this OPP data. + #[inline] + fn freq(&self) -> Hertz { + Hertz(self.0.freq) + } +} + +/// A reference-counted Operating performance point (OPP). +/// +/// Rust abstraction for the C `struct dev_pm_opp`. +/// +/// # Invariants +/// +/// The pointer stored in `Self` is non-null and valid for the lifetime of= the [`OPP`]. +/// +/// 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 Rus= t 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 cod= e. +#[repr(transparent)] +pub struct OPP(Opaque); + +// SAFETY: It is okay to send the ownership of [`OPP`] across thread bound= aries. +unsafe impl Send for OPP {} + +// SAFETY: It is okay to access [`OPP`] through shared references from oth= er threads 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 refcount of the= [`OPP`] is incremented. + /// The caller must also ensure that it doesn't explicitly drop the re= fcount of the [`OPP`], as + /// the returned [`ARef`] object takes over the refcount increment on = the underlying 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. + // + // INVARIANT: The reference-count is decremented when [`OPP`] goes= out of scope. + 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`. + #[inline] + 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(trans= parent)`. + 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) -> Hertz { + 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. + Hertz(unsafe { bindings::dev_pm_opp_get_freq_indexed(self.as_raw()= , index) }) + } + + /// Returns the voltage of an [`OPP`]. + #[inline] + pub fn voltage(&self) -> MicroVolt { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + MicroVolt(unsafe { bindings::dev_pm_opp_get_voltage(self.as_raw())= }) + } + + /// Returns the level of an [`OPP`]. + #[inline] + 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`]. + #[inline] + pub fn power(&self) -> MicroWatt { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + MicroWatt(unsafe { bindings::dev_pm_opp_get_power(self.as_raw()) }) + } + + /// Returns the required pstate of an [`OPP`]. + #[inline] + 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. + #[inline] + 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 17:55:12 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 C327029DB62 for ; Fri, 11 Apr 2025 10:59:40 +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=1744369184; cv=none; b=V4n+qw9blpnfJBQn0pCpAyKDP39FigkN0wCop9TrTHB9zU30jPi66mtRIYvBCyQJ5z/dkrMLNAX9+1Uu8afsiAWNfPCbNCgjfK5ZKTNheKOQgQR6eStbYv7odp4SObebg7H/MmvUeIxfq8/5MfkKzz3qQcVwgsLMDamcDLYj+9s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369184; c=relaxed/simple; bh=v6QFll9/klY1IijI3W5e++N6keitgxvRHdj/+o5bFOA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=BC6DB4lnus1deCYK+XCUxaOXuHMCfVtLXuwMu1KTV48Q59Vrs0a8dO3DblJH6wH3S/fOsZVOCvtl6/jALAogY0+IJiYte/rj6g0broVlK6NUeYwU3DEjhsen9UyLr++vyFb4p4bgip9KVo10Igao13ZM7zicdFeq1ANKxaWG1Do= 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=NDah7i/d; 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="NDah7i/d" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-22622ddcc35so23510835ad.2 for ; Fri, 11 Apr 2025 03:59:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369180; x=1744973980; 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=QhbWqejZNQm6P0aBusiZGVh4RlUEh1rM32mYI+OrPGo=; b=NDah7i/d2lGlF1JaXRAqmB9m5w6lvNHGuuvxPeVJhgNVesxNZFeMpcJTcsAwulWnFr rTwFMhX2PLoMwToP2el9yIctbjdQesp+x4qys/G+G2ZhAUyTaUqE3DEwobSY+vmFzT1j 4JiLojF+48XOmHGB2/M5JclEOUDY6rZoKxauHunEN0R+tQDx4USkI9k+ldtayZtV6joB WS2EGtdjDWo51sV4VJH9N2wHzWNz+ZQcJ+E6MXjmLyLRUToHNU7TTw9cVctKukymaIcQ APvSoGMhjfwhncsElUkF+nauRpFKxc1zw6IuWNmw30A6oh/f4blEx2OyabYN21D5yXcf dWGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369180; x=1744973980; 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=QhbWqejZNQm6P0aBusiZGVh4RlUEh1rM32mYI+OrPGo=; b=H3o5iSZYLTbUWr69yuRFTLCsxDKGrVL43lm/wBcGezXos2Ga7OyMRwK1JA2etB55TE larGLzciRZxSbulBBPkvMnw7EroJZWd5VjCSQaUqbpKt+CqxnjFbpGcmk+KubyBNB3qX S6ml5R6Ei8WogRh0g/YGz5h59SfQAvnAyocmkA4T2IvSXE269pogAMfnlEj3D5GYB5VK uH29Fgg5bRd0teDTZjm3aWWiO/NXX53fYSu8tYkbTErLSHQ/vUEGdYs6UUecHB2RoaZH fySw2K6b7sm4xZKk2KHoVCOi3CBmXCMYkbbQnKuImTlqRMjoAAtsi5TtyppLJxwXBIuW 5I1g== X-Forwarded-Encrypted: i=1; AJvYcCVeQXwzVq0LaQXVf3+LeQuUzPNQehEgRntnwG+Fz5xd49jcnih8NjNmjwZXSaM/n/8ZkIljZLCUlWMpg3w=@vger.kernel.org X-Gm-Message-State: AOJu0Yzubmy1eZPAcOBIRyXnDjm9uPFRQ5OLVatdTJdTvRtkM0A6IY8K Oxi6mekfMEFQhgKf6vr1zvU1zU7y8rcrg1UE5lIVJ6S0dcm9T0IdPSPmprAZteQ= X-Gm-Gg: ASbGncsbOJGlkWayMW2bqmWoADGWrtp2o1Cn9+MPEmk75+E5jO6fIHKN2AnrCCDfOs2 jJZKcs+Sl0ioxwokaY/8emcX/ZDEV71DIzRdQbSTf/1HSTJDBryJa/TcA0WDCc9HjE9tphDIhwB kxqtQIxpabtxrysvFZQ1bLKGdI5orzrj+rTpIMr7xqJJd/xpFH20AsaV56eEpMaYqdLfu7pa9ua HNGO5tgTRPqS52uRFWMeKaEABTn6Xlz5gTwL0wtxcHjx2uO3W27ag/S3tibN0FWjlGIb2pEHbah v/0NpX33e5Qkr92FC7ULCCpz30yRiJRLW28armqPFQ== X-Google-Smtp-Source: AGHT+IGNPuH6cJTfNjOfoEbs5WUXszgit60bS/Bc3QN65T7yHRlnKlORXUIy3dKlujs451m55yaYUg== X-Received: by 2002:a17:903:1450:b0:223:6180:1bea with SMTP id d9443c01a7336-22bea4ef0b3mr34466755ad.37.1744369180051; Fri, 11 Apr 2025 03:59:40 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7b8bcd7sm46107215ad.88.2025.04.11.03.59.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:39 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 11/17] rust: opp: Add abstractions for the OPP table Date: Fri, 11 Apr 2025 16:25:10 +0530 Message-Id: <1961fd9a4ef44dbda18a63eb832dc3a3176c2314.1744366571.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" Introduce Rust abstractions for `struct opp_table`, enabling access to OPP tables from Rust. Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 495 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 494 insertions(+), 1 deletion(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index e4780b41664f..e074009e4b7a 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -11,8 +11,9 @@ use crate::{ bindings, clk::Hertz, + cpumask::{Cpumask, CpumaskVar}, device::Device, - error::{code::*, to_result, Result}, + error::{code::*, from_err_ptr, to_result, Error, Result}, ffi::c_ulong, types::{ARef, AlwaysRefCounted, Opaque}, }; @@ -172,6 +173,477 @@ fn freq(&self) -> Hertz { } } =20 +/// [`OPP`] search options. +/// +/// ## Examples +/// +/// Defines how to search for an [`OPP`] in a [`Table`] relative to a freq= uency. +/// +/// ``` +/// use kernel::clk::Hertz; +/// use kernel::error::Result; +/// use kernel::opp::{OPP, SearchType, Table}; +/// use kernel::types::ARef; +/// +/// fn find_opp(table: &Table, freq: Hertz) -> Result> { +/// let opp =3D table.opp_from_freq(freq, Some(true), None, SearchType= ::Exact)?; +/// +/// pr_info!("OPP frequency is: {:?}\n", opp.freq(None)); +/// pr_info!("OPP voltage is: {:?}\n", opp.voltage()); +/// pr_info!("OPP level is: {}\n", opp.level()); +/// pr_info!("OPP power is: {:?}\n", opp.power()); +/// +/// Ok(opp) +/// } +/// ``` +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum SearchType { + /// Match the exact frequency. + Exact, + /// Find the highest frequency less than or equal to the given value. + Floor, + /// Find the lowest frequency greater than or equal to the given value. + Ceil, +} + +/// A reference-counted OPP table. +/// +/// Rust abstraction for the C `struct opp_table`. +/// +/// # Invariants +/// +/// The pointer stored in `Self` is non-null and valid for the lifetime of= the [`Table`]. +/// +/// Instances of this type are reference-counted. +/// +/// ## Examples +/// +/// The following example demonstrates how to get OPP [`Table`] for a [`Cp= umask`] and set its +/// frequency. +/// +/// ``` +/// use kernel::clk::Hertz; +/// use kernel::cpumask::Cpumask; +/// use kernel::device::Device; +/// use kernel::error::Result; +/// use kernel::opp::Table; +/// use kernel::types::ARef; +/// +/// fn get_table(dev: &ARef, mask: &mut Cpumask, freq: Hertz) -> R= esult { +/// let mut opp_table =3D Table::from_of_cpumask(dev, mask)?; +/// +/// if opp_table.opp_count()? =3D=3D 0 { +/// return Err(EINVAL); +/// } +/// +/// pr_info!("Max transition latency is: {} ns\n", opp_table.max_trans= ition_latency_ns()); +/// pr_info!("Suspend frequency is: {:?}\n", opp_table.suspend_freq()); +/// +/// opp_table.set_rate(freq)?; +/// Ok(opp_table) +/// } +/// ``` +pub struct Table { + ptr: *mut bindings::opp_table, + dev: ARef, + em: bool, + of: bool, + cpumask_box: Option, +} + +// SAFETY: It is okay to send ownership of [`Table`] across thread boundar= ies. +unsafe impl Send for Table {} + +// SAFETY: It is okay to access [`Table`] through shared references from o= ther threads because +// we're either accessing properties that don't change or that are properl= y synchronised by C code. +unsafe impl Sync for Table {} + +impl Table { + /// Creates a new reference-counted [`Table`] from a 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. + // + // INVARIANT: The reference-count is decremented when [`Table`] go= es out of scope. + unsafe { bindings::dev_pm_opp_get_opp_table_ref(ptr) }; + + Self { + ptr, + dev: dev.clone(), + em: false, + of: false, + cpumask_box: None, + } + } + + /// Creates a new reference-counted [`Table`] instance for a [`Device`= ]. + pub fn from_dev(dev: &Device) -> Result { + // SAFETY: The requirements are satisfied by the existence of the = [`Device`] and its safety + // requirements. + // + // INVARIANT: The reference-count is incremented by the C code and= is decremented when + // [`Table`] goes out of scope. + 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_box: None, + }) + } + + /// Creates a new reference-counted [`Table`] instance for a [`Device`= ] based on device tree + /// entries. + #[cfg(CONFIG_OF)] + pub fn from_of(dev: &ARef, index: i32) -> Result { + // SAFETY: The requirements are satisfied by the existence of the = [`Device`] and its safety + // requirements. + // + // INVARIANT: The reference-count is incremented by the C code and= is decremented when + // [`Table`] goes out of scope. + to_result(unsafe { bindings::dev_pm_opp_of_add_table_indexed(dev.a= s_raw(), index) })?; + + // Get the newly created [`Table`]. + let mut table =3D Self::from_dev(dev)?; + table.of =3D true; + + Ok(table) + } + + // Remove device tree based [`Table`]. + #[cfg(CONFIG_OF)] + #[inline] + fn remove_of(&self) { + // SAFETY: The requirements are satisfied by the existence of the = [`Device`] and its safety + // requirements. We took the reference from [`from_of`] earlier, i= t is safe to drop the + // same now. + unsafe { bindings::dev_pm_opp_of_remove_table(self.dev.as_raw()) }; + } + + /// Creates a new reference-counted [`Table`] instance for a [`Cpumask= `] based on device tree + /// entries. + #[cfg(CONFIG_OF)] + pub fn from_of_cpumask(dev: &Device, cpumask: &mut Cpumask) -> Result<= Self> { + // SAFETY: The cpumask is valid and the returned pointer will be o= wned by the [`Table`] + // instance. + // + // INVARIANT: The reference-count is incremented by the C code and= is decremented when + // [`Table`] goes out of scope. + 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)?; + table.cpumask_box =3D Some(CpumaskVar::try_clone(cpumask)?); + + Ok(table) + } + + // Remove device tree based [`Table`] for a [`Cpumask`]. + #[cfg(CONFIG_OF)] + #[inline] + fn remove_of_cpumask(&self, cpumask: &Cpumask) { + // SAFETY: The cpumask is valid and we took the reference from [`f= rom_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 [`OPP`]s in the [`Table`]. + pub fn opp_count(&self) -> Result { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] 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 (in nanoseconds) of the [`OPP`]s in the = [`Table`]. + #[inline] + pub fn max_clock_latency_ns(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_clock_latency(self.dev.as_ra= w()) } + } + + /// Returns max volt latency (in nanoseconds) of the [`OPP`]s in the [= `Table`]. + #[inline] + pub fn max_volt_latency_ns(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_volt_latency(self.dev.as_raw= ()) } + } + + /// Returns max transition latency (in nanoseconds) of the [`OPP`]s in= the [`Table`]. + #[inline] + pub fn max_transition_latency_ns(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_transition_latency(self.dev.= as_raw()) } + } + + /// Returns the suspend [`OPP`]'s frequency. + #[inline] + pub fn suspend_freq(&self) -> Hertz { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + Hertz(unsafe { bindings::dev_pm_opp_get_suspend_opp_freq(self.dev.= as_raw()) }) + } + + /// Synchronizes regulators used by the [`Table`]. + #[inline] + pub fn sync_regulators(&self) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_sync_regulators(self.dev.a= s_raw()) }) + } + + /// Gets sharing CPUs. + #[inline] + pub fn sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result<()>= { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] 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 [`De= vice`] 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_box.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)] + #[inline] + pub fn of_sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result<= ()> { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] 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`]. + #[inline] + pub fn adjust_voltage( + &self, + freq: Hertz, + volt: MicroVolt, + volt_min: MicroVolt, + volt_max: MicroVolt, + ) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_adjust_voltage( + self.dev.as_raw(), + freq.into(), + volt.into(), + volt_min.into(), + volt_max.into(), + ) + }) + } + + /// Configures device with [`OPP`] matching the frequency value. + #[inline] + pub fn set_rate(&self, freq: Hertz) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_set_rate(self.dev.as_raw()= , freq.into()) }) + } + + /// Configures device with [`OPP`]. + #[inline] + pub fn set_opp(&self, opp: &OPP) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] 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, + freq: Hertz, + available: Option, + index: Option, + stype: SearchType, + ) -> Result> { + let raw_dev =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 pointer will = be owned by the new + // [`OPP`] instance. + unsafe { + bindings::dev_pm_opp_find_freq_exact_indexed( + raw_dev, + freq.into(), + index, + available, + ) + } + } else { + return Err(EINVAL); + } + } + + // SAFETY: The requirements are satisfied by the existence of = [`Device`] and its safety + // requirements. The returned pointer will be owned by the new= [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_freq_ceil_indexed( + raw_dev, + &mut freq.into() as *mut usize, + index, + ) + }, + + // SAFETY: The requirements are satisfied by the existence of = [`Device`] and its safety + // requirements. The returned pointer will be owned by the new= [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_freq_floor_indexed( + raw_dev, + &mut freq.into() 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 raw_dev =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 pointer will be owned by the new= [`OPP`] instance. + SearchType::Exact =3D> unsafe { bindings::dev_pm_opp_find_leve= l_exact(raw_dev, level) }, + + // SAFETY: The requirements are satisfied by the existence of = [`Device`] and its safety + // requirements. The returned pointer will be owned by the new= [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_level_ceil(raw_dev, &mut level a= s *mut u32) + }, + + // SAFETY: The requirements are satisfied by the existence of = [`Device`] and its safety + // requirements. The returned pointer will be owned by the new= [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_level_floor(raw_dev, &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 raw_dev =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 pointer will be owned by the new= [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_bw_ceil(raw_dev, &mut bw as *mut= u32, index) + }, + + // SAFETY: The requirements are satisfied by the existence of = [`Device`] and its safety + // requirements. The returned pointer will be owned by the new= [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_bw_floor(raw_dev, &mut bw as *mu= t u32, index) + }, + })?; + + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp_owned(ptr) } + } + + /// Enables the [`OPP`]. + #[inline] + pub fn enable_opp(&self, freq: Hertz) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_enable(self.dev.as_raw(), = freq.into()) }) + } + + /// Disables the [`OPP`]. + #[inline] + pub fn disable_opp(&self, freq: Hertz) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_disable(self.dev.as_raw(),= freq.into()) }) + } + + /// 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 [`De= vice`] 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))] + #[inline] + fn of_unregister_em(&self) { + // SAFETY: The requirements are satisfied by the existence of [`De= vice`] 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_box.take() { + self.remove_of_cpumask(&cpumask); + } + } + } +} + /// A reference-counted Operating performance point (OPP). /// /// Rust abstraction for the C `struct dev_pm_opp`. @@ -185,6 +657,27 @@ fn freq(&self) -> Hertz { /// represents a pointer that owns a reference count on the [`OPP`]. /// /// A reference to the [`OPP`], &[`OPP`], isn't refcounted by the Rust cod= e. +/// +/// ## Examples +/// +/// The following example demonstrates how to get [`OPP`] corresponding to= a frequency value and +/// configure the device with it. +/// +/// ``` +/// use kernel::clk::Hertz; +/// use kernel::error::Result; +/// use kernel::opp::{SearchType, Table}; +/// +/// fn configure_opp(table: &Table, freq: Hertz) -> Result { +/// let opp =3D table.opp_from_freq(freq, Some(true), None, SearchType= ::Exact)?; +/// +/// if opp.freq(None) !=3D freq { +/// return Err(EINVAL); +/// } +/// +/// table.set_opp(&opp) +/// } +/// ``` #[repr(transparent)] pub struct OPP(Opaque); =20 --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 2026 Received: from mail-pf1-f175.google.com (mail-pf1-f175.google.com [209.85.210.175]) (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 681CC29DB7D for ; Fri, 11 Apr 2025 10:59:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369187; cv=none; b=duoN0vgCvjtWGK1R1x/WyZDYD2JPizhmotfhDTQYUWFXghOCaZvN46Sy+Xsd6m7OJtmKZpF70iIrbjg5dkUEzkfPoyqSvXLfswG87WSeczfziNYQ5h8yoJ2S2zTg62/I/5fi/6gHPpX63QTIf45/yk5nl/zWYEWEvPN56+JQRmM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369187; c=relaxed/simple; bh=5Eq5CK5DJNRSRgLaEHiffky2SmkD7YuvQ0tSFHY4iSU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nSOtsw+OSwvIaLXXGRSNx2XNfIXnO4T7AahlMxXsjT3+FQDa0FZBGwzAqdqCNLBddGSJE9p51mZGAaRdXoBFYCmFXUk9UjhOzrboxqxlGN8Xxq+LYsjh2JBeK3jqxax4ImhCWCYtGDkVKv/sZ3nEtf1VxgVmQJMDEKfnqSFPnas= 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=kKxEENK6; arc=none smtp.client-ip=209.85.210.175 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="kKxEENK6" Received: by mail-pf1-f175.google.com with SMTP id d2e1a72fcca58-736b0c68092so1544749b3a.0 for ; Fri, 11 Apr 2025 03:59:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369184; x=1744973984; 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=ocHLGgroWw9XR29SBCdpCasA3D4zU5sFSewJv0c9Qwc=; b=kKxEENK6p7Yrk6EXbU1sEe85yHO75iAOmM0lZEmVH+7xKGwB3DzmDvzxFJb5FY7OyU S/DSPvXGsmCJ/Ox6S9xj2PuP94KgmZGhuHN4oxzR6G+DVro24956RKcEqd6y7da3n/5Q L7gi70g2YgVOQyvy95lDGk8F1EMvoIH+uADUtcdoHlMyigCPFAW2bKiSPr0P+hFvV7h9 LTPfG6rIExkoPorV4/Wz6JKm3+0i0ygiQAnqZLrbRh5d4lcTmarnWjmlWqclHG8g/9Wf tcOIp9T9gHv29sJcf2fLe9ixNdEzyLHmyFFZMgb2yBQXRGM+h22b1MZKQFlJkrD+dV0d haEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369184; x=1744973984; 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=ocHLGgroWw9XR29SBCdpCasA3D4zU5sFSewJv0c9Qwc=; b=maZrT5CTb5OD1GLQ5x7DorCLpIwwlehisSGwD0gDCQf1aDZHisUt5RBD3WZcgeZeT3 0kH4IUKk0aDsUD4PDNAwsbhR298/WqIoPSBihFCI3V+i9Jhu/H1tudT82HDi7h1sDnxO 9WGZl0OBp/lfYG7ZDgwqwj5qJ7T0sHenh52O2NsQ9fcuLL1atKCRryRNxQY9dWckkIf8 bYcurOExSfhAV+HqPy5t7sK7Yac745hxVZs/RxOHudPGMe9lq/lYIUlFGkvwxvl9vh/Z DiIAZ0zx9ZpDnCElp3Mt/+xstIrRe7ajGp6G1wAam75rMP7FQaiXPSyNo6/D3VJMEqaW rs3Q== X-Forwarded-Encrypted: i=1; AJvYcCUTB2oRl2AYotMjnLio2j7/U5CEdXy7O7S5k+nwqWv2LrrsQ8UFGyNtlseZZ2795409po85A3eq1YqcsM8=@vger.kernel.org X-Gm-Message-State: AOJu0YxIH7FfP/s9rX441QwHivzNCpOsD+08zU96uU7gp668M2Gk2zeG e2WXO5r5dLtKdgZrKG1XULoeOlLdv3HiY1bYiJsVsCy0Gdi4S8uPniHoVHLA1Eg= X-Gm-Gg: ASbGncv4RWDLEGR5Zg4XoUHXCDXCakWodzu1/wMZKgLriqNKfDcg7x+mo7tjPHeWhAb my1C4FB4MOtbFZoqaQMLYtd8V4WJsD/R07VcFd/9Pr72ERVTcxpwINJVX35IJpkBiiezUaeey5Z +af1hb9opGpc0ZV3JgjoRBFa+Q13Ekgbp54bhC/RklO+nd43Y6JERjF3FJJ3Vulz9ULJtj8IbT8 rFJBvCbruQ3JRn7cy0tz3PLXn6287oeZFxkRgicCT616u8toYo+ynrJc+2mbhh4eYwVrvSjWS08 9oO7f0DULGGSftPc5LDkPUiiLgfRlHzHsnduflAQJg== X-Google-Smtp-Source: AGHT+IH1XxwScpzrO8aDsAp9VqOmTRGaFUuE6LCBwuUM+PoiHXy5XopQJocc7OocFzI61WrTtGmv9g== X-Received: by 2002:a05:6a21:8cc5:b0:1f3:40a9:2c36 with SMTP id adf61e73a8af0-201797a079cmr3503827637.10.1744369183576; Fri, 11 Apr 2025 03:59:43 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd2198c17sm1200453b3a.36.2025.04.11.03.59.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:43 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 12/17] rust: opp: Add abstractions for the configuration options Date: Fri, 11 Apr 2025 16:25:11 +0530 Message-Id: <5257b8065580d0218919d160170f301144a8939f.1744366571.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" Introduce Rust abstractions for the OPP core configuration options, enabling safe access to various configurable aspects of the OPP framework. Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 295 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 293 insertions(+), 2 deletions(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index e074009e4b7a..7bf612fa0cc5 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -13,12 +13,29 @@ clk::Hertz, cpumask::{Cpumask, CpumaskVar}, 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}, ffi::c_ulong, + 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 [`Cstring`]s. +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 /// The voltage unit. /// @@ -206,6 +223,280 @@ pub enum SearchType { Ceil, } =20 +/// OPP configuration callbacks. +/// +/// Implement this trait to customize OPP clock and regulator setup for yo= ur device. +#[vtable] +pub trait ConfigOps { + /// This is typically used to scale clocks when transitioning between = OPPs. + #[inline] + fn config_clks(_dev: &Device, _table: &Table, _opp: &OPP, _scaling_dow= n: bool) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// This provides access to the old and new OPPs, allowing for safe re= gulator adjustments. + #[inline] + fn config_regulators( + _dev: &Device, + _opp_old: &OPP, + _opp_new: &OPP, + _data: *mut *mut bindings::regulator, + _count: u32, + ) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } +} + +/// OPP configuration token. +/// +/// Returned by the OPP core when configuration is applied to a [`Device`]= . The associated +/// configuration is automatically cleared when the token is dropped. +pub struct ConfigToken(i32); + +impl Drop for ConfigToken { + fn drop(&mut self) { + // SAFETY: This is the same token value returned by the C code via= `dev_pm_opp_set_config`. + unsafe { bindings::dev_pm_opp_clear_config(self.0) }; + } +} + +/// OPP configurations. +/// +/// Rust abstraction for the C `struct dev_pm_opp_config`. +/// +/// ## Examples +/// +/// The following example demonstrates how to set OPP property-name config= uration for a [`Device`]. +/// +/// ``` +/// use kernel::device::Device; +/// use kernel::error::Result; +/// use kernel::opp::{Config, ConfigOps, ConfigToken}; +/// use kernel::str::CString; +/// use kernel::types::ARef; +/// use kernel::macros::vtable; +/// +/// #[derive(Default)] +/// struct Driver; +/// +/// #[vtable] +/// impl ConfigOps for Driver {} +/// +/// fn configure(dev: &ARef) -> Result { +/// let name =3D CString::try_from_fmt(fmt!("{}", "slow"))?; +/// +/// // The OPP configuration is cleared once the [`ConfigToken`] goes = out of scope. +/// Config::::new() +/// .set_prop_name(name)? +/// .set(dev) +/// } +/// ``` +#[derive(Default)] +pub struct Config +where + T: Default, +{ + clk_names: Option>, + prop_name: Option, + regulator_names: Option>, + supported_hw: Option>, + + // Tuple containing (required device, index) + required_dev: Option<(ARef, u32)>, + _data: PhantomData, +} + +impl Config { + /// Creates a new instance of [`Config`]. + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Initializes clock names. + pub fn set_clk_names(mut self, names: KVec) -> Result { + 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 { + 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 { + 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 { + if self.required_dev.is_some() { + return Err(EBUSY); + } + + self.required_dev =3D Some((dev, index)); + Ok(self) + } + + /// Initializes supported hardware. + pub fn set_supported_hw(mut self, hw: KVec) -> Result { + 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. + /// + /// The returned [`ConfigToken`] will remove the configuration when dr= opped. + 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 self + .prop_name + .as_ref() + .map_or(ptr::null(), |p| p.as_char_ptr()); + + let (supported_hw, supported_hw_count) =3D self + .supported_hw + .as_ref() + .map_or((ptr::null(), 0), |hw| (hw.as_ptr(), hw.len() as u32)); + + let (required_dev, required_dev_index) =3D self + .required_dev + .as_ref() + .map_or((ptr::null_mut(), 0), |(dev, idx)| (dev.as_raw(), *idx= )); + + 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 [`De= vice`] and its safety + // requirements. The OPP core guarantees not to access fields of [= `Config`] after this call + // 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 clk callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn config_clks( + dev: *mut bindings::device, + opp_table: *mut bindings::opp_table, + opp: *mut bindings::dev_pm_opp, + _data: *mut kernel::ffi::c_void, + scaling_down: bool, + ) -> kernel::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 regulator callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + 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: kernel::ffi::c_uint, + ) -> kernel::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) + }) + } +} + /// A reference-counted OPP table. /// /// Rust abstraction for the C `struct opp_table`. --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 2026 Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) (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 F11F12BD595 for ; Fri, 11 Apr 2025 10:59:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369192; cv=none; b=npOucjsx7I6KYFlP1v7KJdDkGIydxfzV0K0sxjaUapRFtmZlBvjRo9Vlfavhzqaciav+jIybFsJjYnLVrJcJaraU4ckP17YRUdg5uACbVX9rDwfQuYfGpvQUCR3WVO6Q7pg3iWww6yorS+iBwBmXGGYX6XmRRjtk/EaFQv3bH1w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369192; c=relaxed/simple; bh=SgA2EjiLOXt6zPhknRFfdFb3bZ3ASN3rkBIwJXUb7j4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=mkICyKYCUCQJkDCbZAtpePnDfnTQow9YpKoOZsiWmvri1w9vSLquOP6l/gQVayk3+dr7awq2THOsgyAWOLi5A6gwXpBPiLCzeCSqV/Dxv1PbaC9pd73j6uwADfqGDGIzyyrqbLpeH1AqqhCNE+h2equdxtuWknsrKnh0eep0+2E= 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=wIhmvIfA; arc=none smtp.client-ip=209.85.210.174 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="wIhmvIfA" Received: by mail-pf1-f174.google.com with SMTP id d2e1a72fcca58-736c3e7b390so1660399b3a.2 for ; Fri, 11 Apr 2025 03:59:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369188; x=1744973988; 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=UiCk9eXA5sDbW+eWFju7laQkDVU7y1GpZogWt6fIoRE=; b=wIhmvIfADpU0BhY1xl42x1ogqfC7LvMJ5aDN6tdPSAc5yG+FiqGV2skKYuDCDDh/oE IpPQPzVJLXR4MKEzZwtvGB0RPiD7/cW+jNOtZKP6odhK5dSKbS75QPWalzrnYX8cwZ8z jMMpRL7kXNSSEz9lDoPutV6qxYntHjcayvNsPd2QrMiO92xqwzjs15vKey8wb8kruBxF VA1XRCsCYPU3Zy1dmUaMBDlfwSoBUtsQsEicaZQWZNY7J2eqQg9K9bqtPt2MKYBSBGQj MSORp1nSuzJmB0eLnDO9wDL2hCXNhCky0f89Xw5vSWF9HFGDXlGGm31w9WoCKXh7Nmcw sAHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369188; x=1744973988; 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=UiCk9eXA5sDbW+eWFju7laQkDVU7y1GpZogWt6fIoRE=; b=TsmY57akOpoGqaaeocRXVEdbQZlMkRuFpRMNPM8AgViciG6KBtNx/0AyFqZlcDE4kR h2TJneLQrupW/sU2gcuSeZ8Jt8hcD5zn6Z9wCHJUtV41AKIO7mdereSrpw8I0TaR5eoG LCubjsrc3jUsLVxG9ilBoYJEyQJNppBb9qCiN2WvmjcUr6huXro/6MvqzgMQv0E6xeUj pJeQQDiH8aUQ6GVJRsXEI3vOABXn32u6ZU3Sas5AhNU2Fo1fwmC/tD5N7hHhNLmlW0lH taU9LLg14LfAVwjOXsWf82+QCweGkdOJQzeyjfKBAxilT2Mb0oS5U3sScBQ66yY91kUb WXHw== X-Forwarded-Encrypted: i=1; AJvYcCWLDZT+D4Jughe+OBUe/VNNgQ+pp5dus/7/f0wOLgk2lgClsD+L2j/4LbkZDsxYbEBcFGaw50346MJ5/OQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yz5mQAGBKKOtRZLs3XuqrQZiFBDw+ykg1DhAV+y9K0KPBwED2SV i41G3EulyjyZmXEUWvznVgzCMs9rz/CezyeEw7gih9kr6Eiiyw9dcXJmf3kbCsE= X-Gm-Gg: ASbGncv5ipREY/JXHuJfejQuiYyGjxam4x5jXVPEM4i7Q8aINzeQOsUEgxzYot49iOl Ks3VZBbqVTwk8H5OqmeAXThQOxhsJ0sC5GM5zy307o4Qao3p/Gr5llu3zdt9UQ+i4urK/kaeP0p qefNiM/3Nl9odhJtwi3LgorC45A4q7sB6GTB/BloekqlvS3FtCgaQ7lL4Yxd2KdnjTfLK/v4DG+ Q51fgbAXWtQvorUdHJEP+yYfg00ZjJFxCHcLRP81qNHfDXfwPvz12HCctXQJ07kO3k1QFKb8Gt/ zTDZEE7WmhG1ZY/ZH5or3gLHe069DkuYran0xedSOg== X-Google-Smtp-Source: AGHT+IHB7NJWuP5C3bZG6BXNbSzjmJ2rwCfuMl9Ghv7r2LQJTr/s6JvFiveArH50OaIxUiQa4HR0nA== X-Received: by 2002:a05:6a00:2284:b0:736:34ca:dee2 with SMTP id d2e1a72fcca58-73bd119993dmr3091351b3a.4.1744369188045; Fri, 11 Apr 2025 03:59:48 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd230e56dsm1216167b3a.135.2025.04.11.03.59.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:47 -0700 (PDT) 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 , Danilo Krummrich , 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 13/17] rust: cpufreq: Add initial abstractions for cpufreq framework Date: Fri, 11 Apr 2025 16:25:12 +0530 Message-Id: <128ea2557facfc0e58ca8981798e5e72e9a5ba82.1744366571.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" Introduce initial Rust abstractions for the cpufreq core. This includes basic representations for cpufreq flags, relation types, and the cpufreq table. 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 | 341 ++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 6 files changed, 356 insertions(+) create mode 100644 rust/helpers/cpufreq.c create mode 100644 rust/kernel/cpufreq.rs diff --git a/MAINTAINERS b/MAINTAINERS index 931e418f89ed..aa56eacbda71 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6142,6 +6142,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 529f22891e0b..7c1d78f68076 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 ae595c9cd91b..df1fcfb3adf3 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -12,6 +12,7 @@ #include "build_assert.c" #include "build_bug.c" #include "clk.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..19bb616d3625 --- /dev/null +++ b/rust/kernel/cpufreq.rs @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! CPU frequency scaling. +//! +//! This module provides rust abstractions for interacting with the cpufre= q subsystem. +//! +//! C header: [`include/linux/cpufreq.h`](srctree/include/linux/cpufreq.h) +//! +//! Reference: + +use crate::{ + bindings, + error::{code::*, to_result, Result}, + ffi::c_ulong, + prelude::*, +}; + +use core::{ + pin::Pin, +}; + +/// Default transition latency value in nanoseconds. +pub const ETERNAL_LATENCY_NS: u32 =3D bindings::CPUFREQ_ETERNAL as u32; + +/// CPU frequency driver flags. +pub mod flags { + use crate::bindings; + + /// Driver needs to update internal limits even if frequency remains u= nchanged. + pub const NEED_UPDATE_LIMITS: u16 =3D bindings::CPUFREQ_NEED_UPDATE_LI= MITS as _; + + /// Platform where constants like `loops_per_jiffy` are unaffected by = frequency changes. + pub const CONST_LOOPS: u16 =3D bindings::CPUFREQ_CONST_LOOPS as _; + + /// Register driver as a thermal cooling device automatically. + pub const IS_COOLING_DEV: u16 =3D bindings::CPUFREQ_IS_COOLING_DEV as = _; + + /// Supports multiple clock domains with per-policy governors in `cpu/= cpuN/cpufreq/`. + pub const HAVE_GOVERNOR_PER_POLICY: u16 =3D bindings::CPUFREQ_HAVE_GOV= ERNOR_PER_POLICY as _; + + /// Allows post-change notifications outside of the `target()` routine. + pub const ASYNC_NOTIFICATION: u16 =3D bindings::CPUFREQ_ASYNC_NOTIFICA= TION as _; + + /// Ensure CPU starts at a valid frequency from the driver's freq-tabl= e. + pub const NEED_INITIAL_FREQ_CHECK: u16 =3D bindings::CPUFREQ_NEED_INIT= IAL_FREQ_CHECK as _; + + /// Disallow governors with `dynamic_switching` capability. + pub const NO_AUTO_DYNAMIC_SWITCHING: u16 =3D bindings::CPUFREQ_NO_AUTO= _DYNAMIC_SWITCHING as _; +} + +/// CPU frequency selection relations. +/// +/// CPU frequency selection relations, each optionally marked as "efficien= t". +#[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 { + // Construct from a C-compatible `u32` value. + 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), + }) + } +} + +impl From for u32 { + // Convert to a C-compatible `u32` value. + fn from(rel: Relation) -> Self { + let (mut val, efficient) =3D match rel { + Relation::Low(e) =3D> (bindings::CPUFREQ_RELATION_L, e), + Relation::High(e) =3D> (bindings::CPUFREQ_RELATION_H, e), + Relation::Close(e) =3D> (bindings::CPUFREQ_RELATION_C, e), + }; + + if efficient { + val |=3D bindings::CPUFREQ_RELATION_E; + } + + val + } +} + +/// Policy data. +/// +/// Rust abstraction for the C `struct cpufreq_policy_data`. +/// +/// # Invariants +/// +/// A [`PolicyData`] instance always corresponds to a valid C `struct cpuf= req_policy_data`. +/// +/// The callers must ensure that the `struct cpufreq_policy_data` is valid= for access and remains +/// valid for the lifetime of the returned reference. +#[repr(transparent)] +pub struct PolicyData(Opaque); + +impl PolicyData { + /// Creates a mutable reference to an existing `struct cpufreq_policy_= data` pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid for writing and remains= valid for the lifetime + /// of the returned reference. + #[inline] + pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpufreq_policy_data= ) -> &'a mut Self { + // SAFETY: Guaranteed by the safety requirements of the function. + // + // INVARIANT: The caller ensures that `ptr` is valid for writing a= nd remains valid for the + // lifetime of the returned reference. + unsafe { &mut *ptr.cast() } + } + + /// Returns a raw pointer to the underlying C `cpufreq_policy_data`. + #[inline] + pub fn as_raw(&self) -> *mut bindings::cpufreq_policy_data { + self as *const _ as _ + } + + /// Wrapper for `cpufreq_generic_frequency_table_verify`. + #[inline] + pub fn generic_verify(&self) -> Result<()> { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid. + to_result(unsafe { bindings::cpufreq_generic_frequency_table_verif= y(self.as_raw()) }) + } +} + +/// CPU frequency table. +/// +/// Rust abstraction for the C `struct cpufreq_frequency_table`. +/// +/// # Invariants +/// +/// A [`Table`] instance always corresponds to a valid C `struct cpufreq_f= requency_table`. +/// +/// The callers must ensure that the `struct cpufreq_frequency_table` is v= alid for access and +/// remains valid for the lifetime of the returned reference. +/// +/// ## Examples +/// +/// The following example demonstrates how to read a frequency value from = [`Table`]. +/// +/// ``` +/// use kernel::cpufreq::Policy; +/// +/// fn show_freq(policy: &Policy) { +/// let table =3D policy.freq_table().unwrap(); +/// +/// // SAFETY: The index values passed are correct. +/// unsafe { +/// pr_info!("The frequency at index 0 is: {:?}\n", table.freq(0).= unwrap()); +/// pr_info!("The flags at index 0 is: {}\n", table.flags(0)); +/// pr_info!("The data at index 0 is: {}\n", table.data(0)); +/// } +/// } +/// ``` +#[allow(dead_code)] +#[repr(transparent)] +pub struct Table(Opaque); + +impl Table { + /// Creates a reference to an existing C `struct cpufreq_frequency_tab= le` pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid for reading and remains= valid for the lifetime + /// of the returned reference. + #[inline] + pub unsafe fn from_raw<'a>(ptr: *const bindings::cpufreq_frequency_tab= le) -> &'a Self { + // SAFETY: Guaranteed by the safety requirements of the function. + // + // INVARIANT: The caller ensures that `ptr` is valid for reading a= nd remains valid for the + // lifetime of the returned reference. + unsafe { &*ptr.cast() } + } + + /// Returns the raw mutable pointer to the C `struct cpufreq_frequency= _table`. + #[inline] + pub fn as_raw(&self) -> *mut bindings::cpufreq_frequency_table { + self as *const _ as _ + } + + /// Returns frequency at `index` in the [`Table`]. + /// + /// # Safety + /// + /// The caller must ensure that `index` corresponds to a valid table e= ntry. + #[inline] + pub unsafe fn freq(&self, index: usize) -> Result { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid and `index` is + // guaranteed to be valid by the safety requirements of the functi= on. + Ok(Hertz::from_khz(unsafe { + (*self.as_raw().add(index)).frequency.try_into()? + })) + } + + /// Returns flags at `index` in the [`Table`]. + /// + /// # Safety + /// + /// The caller must ensure that `index` corresponds to a valid table e= ntry. + #[inline] + pub unsafe fn flags(&self, index: usize) -> u32 { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid and `index` is + // guaranteed to be valid by the safety requirements of the functi= on. + unsafe { (*self.as_raw().add(index)).flags } + } + + /// Returns data at `index` in the [`Table`]. + /// + /// # Safety + /// + /// The caller must ensure that `index` corresponds to a valid table e= ntry. + #[inline] + pub unsafe fn data(&self, index: usize) -> u32 { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid and `index` is + // guaranteed to be valid by the safety requirements of the functi= on. + unsafe { (*self.as_raw().add(index)).driver_data } + } +} + +/// CPU frequency table owned and pinned in memory, created from a [`Table= Builder`]. +pub struct TableBox { + #[allow(dead_code)] + entries: Pin>, +} + +impl TableBox { + /// Constructs a new [`TableBox`] from a [`KVec`] of entries. + /// + /// # Errors + /// + /// Returns `EINVAL` if the entries list is empty. + #[inline] + fn new(entries: KVec) -> Result { + if entries.is_empty() { + return Err(EINVAL); + } + + Ok(Self { + // Pin the entries to memory, since we are passing its pointer= to the C code. + entries: Pin::new(entries), + }) + } + + /// Returns a raw pointer to the underlying C `cpufreq_frequency_table= `. + #[inline] + fn as_raw(&self) -> *const bindings::cpufreq_frequency_table { + // The pointer is valid until the table gets dropped. + self.entries.as_ptr() + } +} + +impl Deref for TableBox { + type Target =3D Table; + + fn deref(&self) -> &Self::Target { + // SAFETY: The caller owns TableBox, it is safe to deref. + unsafe { Self::Target::from_raw(self.as_raw()) } + } +} + +/// CPU frequency table builder. +/// +/// This is used by the CPU frequency drivers to build a frequency table d= ynamically. +/// +/// ## Examples +/// +/// The following example demonstrates how to create a CPU frequency table. +/// +/// ``` +/// use kernel::cpufreq::TableBuilder; +/// use kernel::clk::Hertz; +/// +/// let mut builder =3D TableBuilder::new(); +/// +/// // Adds few entries to the table. +/// builder.add(Hertz::from_mhz(700), 0, 1).unwrap(); +/// builder.add(Hertz::from_mhz(800), 2, 3).unwrap(); +/// builder.add(Hertz::from_mhz(900), 4, 5).unwrap(); +/// builder.add(Hertz::from_ghz(1), 6, 7).unwrap(); +/// +/// let table =3D builder.to_table().unwrap(); +/// +/// // SAFETY: The index values passed are correct. +/// unsafe { +/// assert_eq!(table.freq(0), Ok(Hertz::from_mhz(700))); +/// assert_eq!(table.flags(0), 0); +/// assert_eq!(table.data(0), 1); +/// +/// assert_eq!(table.freq(2), Ok(Hertz::from_mhz(900))); +/// assert_eq!(table.flags(2), 4); +/// assert_eq!(table.data(2), 5); +/// } +/// ``` +#[derive(Default)] +#[repr(transparent)] +pub struct TableBuilder { + entries: KVec, +} + +impl TableBuilder { + /// Creates a new instance of [`TableBuilder`]. + #[inline] + pub fn new() -> Self { + Self { + entries: KVec::new(), + } + } + + /// Adds a new entry to the table. + pub fn add(&mut self, freq: Hertz, flags: u32, driver_data: u32) -> Re= sult<()> { + // Adds the new entry at the end of the vector. + Ok(self.entries.push( + bindings::cpufreq_frequency_table { + flags, + driver_data, + frequency: freq.as_khz() as u32, + }, + GFP_KERNEL, + )?) + } + + /// Consumes the [`TableBuilder`] and returns [`TableBox`]. + pub fn to_table(mut self) -> Result { + // Add last entry to the table. + self.add(Hertz(c_ulong::MAX), 0, 0)?; + + TableBox::new(self.entries) + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 11d333c8c673..871fcdc09b35 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -45,6 +45,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 17:55:12 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 B506029DB7D for ; Fri, 11 Apr 2025 10:59:52 +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=1744369194; cv=none; b=ik10He/8BSu2Jpp2T493mykOUj2Wv+9jdZ6FJQuGwQqRNBr71zITMuS34oVasfIEq5Fpd+CKOVq2DZVKxDN3UJdVdN4bNqTqKCSZGVNDm9vjiQLi5y3w/T9U8iy3mm5i7g6RtJTHXvd15hYefcYQGzRY2FoTDQrds9f15DcwZPQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369194; c=relaxed/simple; bh=ve4uaTlnpOk59FdaBaj9fjJnck3Vslx0Y5m1STEhIVU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=jaDlKYiU08jPxVOYToFPnxz0DtQqzqxuSXFYBqdk6z05bQ7qPr+0Kp0NTsSSw+WxV7rvbyfj3QQpPEpo2/jQCkz7ugFh3wwhZMOz1UQBe/EyzaoHN9JfDJPXaSOKKGwAX9tlSAv1qCIvt4Gplz3X9LqMtvK1iC2vUirSzDEI5P4= 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=ekDGQ6tz; 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="ekDGQ6tz" Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-225df540edcso29967815ad.0 for ; Fri, 11 Apr 2025 03:59:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369192; x=1744973992; 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=ZwItONSje7IwudOg4/U5GXZJbPWqvM1n8G6qlnqWHvg=; b=ekDGQ6tzQoj2wO/pxz51ld/mcgOq48XaaSGdc/+lBGklDeR8PSnRhowCGB/GKpfAm5 GoTqavZEumeSeT7p1vWlR/fqqt6/5XOJJWXJT5ZrizvhGru/17qtqaQaDEeoVak0Clfs LwaL6L4nvJ+GsfN04ZgXNtnxhO1IwEi0pCw4474EyoXZ2cXkfCq1ajydDRssbwLgDAz7 /G296n3sZN7X/n9uxh2y6mhYvmO+toV2VUmJmpOWGfsDgN2k2Q6QZmPztKa1GfCh5OFE P3+S1e4uFTIVYk9Kj3FzpnYmGR+/h+btOLZd5276IYKXIt8hSy9Om/pOs9QHWgbpMFsK THAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369192; x=1744973992; 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=ZwItONSje7IwudOg4/U5GXZJbPWqvM1n8G6qlnqWHvg=; b=RlRQPkBPZGww4u2ORtFb/O4uG67+LMbC6Bmfx/ffsGM5NfS0I/HF8EvzG63V6IWfP+ I4aCWxOQlfNZJ69SfrABz5++Ias5Xkh0Ok5B6cntZVEzUXETyAk7WvbeNAyFt+fsAqOq bm9WW1Kc/W1H03QUcOdWO8X/GEMgLMS5qtuwZ2wH1buD29WNPsJG9cct3B3gIYJyAv7y cjB3cFAL8vSOPFijSeWgkQg6N2Gh86Ben726ItKdQsw5KOBCcgYq7tIUcQzF6HOKBdk6 SaWbgXyhCXjku8rIjx063zCn49QKLdJz/nVxR4OkL/6tF6AYE4aV0xAq0D6vYrhnHjmG mOTw== X-Forwarded-Encrypted: i=1; AJvYcCW8EDgNHqOZPshylh+mow+8rTkGE6S9sw9es/NyvnqdxijnJqLqwv0Apks983HWGVl5nhTvAakpKUzzPvk=@vger.kernel.org X-Gm-Message-State: AOJu0YwTU1GD1bTDUA77yoWnw1w9i25OO8x8mOrMrIjAX+GRkpU4vaNZ vzvmpvP0Tc0vVmKLjsfYXYg5ye2VhaWu+TapFDjjoKEFa/qx9Qo2OnTgmE3ZmJM= X-Gm-Gg: ASbGncuus+QXqn0/7epAhv073UlQO74pKJSIwN/lxKswAy/7U0s15V17zv00bje9/SW /em6CgIYqsmSZj33rd2bPiYonleG9WEeEaQ4dv8X3AVb2qSI8saeXdEtgt1xanIi9daClscyicT 1QtrR52PU+qzr0ytUIru96PHN34kKsEwJ+7tnCIjV/F6v2YXbzceMw/P+85sPNUzTSna7xMhHOE H7+Z6HX5k5P6o83q8yxNXXMlQtSjb8ewgw8cXe1VnIXzjPg1lr3JGC0L5oGCXqyWm79YxZpBOmp 2/VjKjSL3rdMygx4kZeUdgaeDjQ2EOq6eVZXDx8tAg== X-Google-Smtp-Source: AGHT+IHomEwFL2gHvxrxNHMQWNlcLnq5Zomdcm07JpmqvC/LUe0dEuJJbzq+96IF9UMnhFMOjwOvCQ== X-Received: by 2002:a17:903:3c64:b0:223:3eed:f680 with SMTP id d9443c01a7336-22b7eaa35e1mr99860315ad.18.1744369191767; Fri, 11 Apr 2025 03:59:51 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7ccb57fsm46002545ad.229.2025.04.11.03.59.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:51 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 14/17] rust: cpufreq: Extend abstractions for policy and driver ops Date: Fri, 11 Apr 2025 16:25:13 +0530 Message-Id: <38807a42b5ee71c31ff5dd342ff6b5202c86a46e.1744366572.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" Extend the cpufreq abstractions to include support for policy handling and driver operations. Signed-off-by: Viresh Kumar --- rust/kernel/cpufreq.rs | 455 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 454 insertions(+), 1 deletion(-) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 19bb616d3625..3e9ded655d46 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -10,15 +10,24 @@ =20 use crate::{ bindings, - error::{code::*, to_result, Result}, + clk::{Clk, Hertz}, + cpumask, + device::Device, + error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR= }, ffi::c_ulong, prelude::*, + types::ForeignOwnable, + types::Opaque, }; =20 use core::{ + ops::{Deref, DerefMut}, pin::Pin, + ptr::self, }; =20 +use macros::vtable; + /// Default transition latency value in nanoseconds. pub const ETERNAL_LATENCY_NS: u32 =3D bindings::CPUFREQ_ETERNAL as u32; =20 @@ -339,3 +348,447 @@ pub fn to_table(mut self) -> Result { TableBox::new(self.entries) } } + +/// CPU frequency policy. +/// +/// Rust abstraction for the C `struct cpufreq_policy`. +/// +/// # Invariants +/// +/// A [`Policy`] instance always corresponds to a valid C `struct cpufreq_= policy`. +/// +/// The callers must ensure that the `struct cpufreq_policy` is valid for = access and remains valid +/// for the lifetime of the returned reference. +/// +/// ## Examples +/// +/// The following example demonstrates how to create a CPU frequency table. +/// +/// ``` +/// use kernel::cpufreq::{ETERNAL_LATENCY_NS, Policy}; +/// +/// fn update_policy(policy: &mut Policy) { +/// policy +/// .set_dvfs_possible_from_any_cpu(true) +/// .set_fast_switch_possible(true) +/// .set_transition_latency_ns(ETERNAL_LATENCY_NS); +/// +/// pr_info!("The policy details are: {:?}\n", (policy.cpu(), policy.c= ur())); +/// } +/// ``` +#[repr(transparent)] +pub struct Policy(Opaque); + +impl Policy { + /// Creates a reference to an existing `struct cpufreq_policy` pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid for reading and remains= valid for the lifetime + /// of the returned reference. + #[inline] + pub unsafe fn from_raw<'a>(ptr: *const bindings::cpufreq_policy) -> &'= a Self { + // SAFETY: Guaranteed by the safety requirements of the function. + // + // INVARIANT: The caller ensures that `ptr` is valid for reading a= nd remains valid for the + // lifetime of the returned reference. + unsafe { &*ptr.cast() } + } + + /// Creates a mutable reference to an existing `struct cpufreq_policy`= pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid for writing and remains= valid for the lifetime + /// of the returned reference. + #[inline] + pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpufreq_policy) -> = &'a mut Self { + // SAFETY: Guaranteed by the safety requirements of the function. + // + // INVARIANT: The caller ensures that `ptr` is valid for writing a= nd remains valid for the + // lifetime of the returned reference. + unsafe { &mut *ptr.cast() } + } + + // Returns a raw mutable pointer to the C `struct cpufreq_policy`. + #[inline] + fn as_raw(&self) -> *mut bindings::cpufreq_policy { + self as *const _ as _ + } + + #[inline] + fn as_ref(&self) -> &bindings::cpufreq_policy { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid. + unsafe { &*self.as_raw() } + } + + #[inline] + fn as_mut_ref(&mut self) -> &mut bindings::cpufreq_policy { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid. + unsafe { &mut *self.as_raw() } + } + + /// Returns the primary CPU for the [`Policy`]. + #[inline] + pub fn cpu(&self) -> u32 { + self.as_ref().cpu + } + + /// Returns the minimum frequency for the [`Policy`]. + #[inline] + pub fn min(&self) -> Hertz { + Hertz::from_khz(self.as_ref().min as usize) + } + + /// Set the minimum frequency for the [`Policy`]. + #[inline] + pub fn set_min(&mut self, min: Hertz) -> &mut Self { + self.as_mut_ref().min =3D min.as_khz() as u32; + self + } + + /// Returns the maximum frequency for the [`Policy`]. + #[inline] + pub fn max(&self) -> Hertz { + Hertz::from_khz(self.as_ref().max as usize) + } + + /// Set the maximum frequency for the [`Policy`]. + #[inline] + pub fn set_max(&mut self, max: Hertz) -> &mut Self { + self.as_mut_ref().max =3D max.as_khz() as u32; + self + } + + /// Returns the current frequency for the [`Policy`]. + #[inline] + pub fn cur(&self) -> Hertz { + Hertz::from_khz(self.as_ref().cur as usize) + } + + /// Returns the suspend frequency for the [`Policy`]. + #[inline] + pub fn suspend_freq(&self) -> Hertz { + Hertz::from_khz(self.as_ref().suspend_freq as usize) + } + + /// Sets the suspend frequency for the [`Policy`]. + #[inline] + pub fn set_suspend_freq(&mut self, freq: Hertz) -> &mut Self { + self.as_mut_ref().suspend_freq =3D freq.as_khz() as u32; + self + } + + /// Provides a wrapper to the generic suspend routine. + #[inline] + pub fn generic_suspend(&mut self) -> Result<()> { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid. + to_result(unsafe { bindings::cpufreq_generic_suspend(self.as_mut_r= ef()) }) + } + + /// Provides a wrapper to the generic get routine. + #[inline] + pub fn generic_get(&self) -> Result { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid. + Ok(unsafe { bindings::cpufreq_generic_get(self.cpu()) }) + } + + /// Provides a wrapper to the register with energy model using the OPP= core. + #[cfg(CONFIG_PM_OPP)] + #[inline] + pub fn register_em_opp(&mut self) { + // SAFETY: By the type invariant, the pointer stored in `self` is = valid. + unsafe { bindings::cpufreq_register_em_with_opp(self.as_mut_ref())= }; + } + + /// Gets [`cpumask::Cpumask`] for a cpufreq [`Policy`]. + #[inline] + pub fn cpus(&mut self) -> &mut cpumask::Cpumask { + // SAFETY: The pointer to `cpus` is valid for writing and remains = valid for the lifetime of + // the returned reference. + unsafe { cpumask::CpumaskVar::from_raw_mut(&mut self.as_mut_ref().= cpus) } + } + + /// Sets clock for the [`Policy`]. + /// + /// # Safety + /// + /// The caller must guarantee that the returned [`Clk`] is not dropped= while it is getting used + /// by the C code. + pub unsafe fn set_clk(&mut self, dev: &Device, name: Option<&CStr>) ->= Result { + let clk =3D Clk::get(dev, name)?; + self.as_mut_ref().clk =3D clk.as_raw(); + Ok(clk) + } + + /// Allows / disallows frequency switching code to run on any CPU. + #[inline] + pub fn set_dvfs_possible_from_any_cpu(&mut self, val: bool) -> &mut Se= lf { + self.as_mut_ref().dvfs_possible_from_any_cpu =3D val; + self + } + + /// Returns if fast switching of frequencies is possible or not. + #[inline] + pub fn fast_switch_possible(&self) -> bool { + self.as_ref().fast_switch_possible + } + + /// Enables / disables fast frequency switching. + #[inline] + 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 (in nanoseconds) for the [`Policy`]. + #[inline] + pub fn set_transition_latency_ns(&mut self, latency_ns: u32) -> &mut S= elf { + self.as_mut_ref().cpuinfo.transition_latency =3D latency_ns; + self + } + + /// Sets cpuinfo `min_freq`. + #[inline] + pub fn set_cpuinfo_min_freq(&mut self, min_freq: Hertz) -> &mut Self { + self.as_mut_ref().cpuinfo.min_freq =3D min_freq.as_khz() as u32; + self + } + + /// Sets cpuinfo `max_freq`. + #[inline] + pub fn set_cpuinfo_max_freq(&mut self, max_freq: Hertz) -> &mut Self { + self.as_mut_ref().cpuinfo.max_freq =3D max_freq.as_khz() as u32; + self + } + + /// Set `transition_delay_us`, i.e. the minimum time between successiv= e frequency change + /// requests. + #[inline] + 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 reference to the CPU frequency [`Table`] for the [`Policy`= ]. + pub fn freq_table(&self) -> Result<&Table> { + if self.as_ref().freq_table.is_null() { + return Err(EINVAL); + } + + // SAFETY: The `freq_table` is guaranteed to be valid for reading = and remains valid for the + // lifetime of the returned reference. + Ok(unsafe { Table::from_raw(self.as_ref().freq_table) }) + } + + /// Sets the CPU frequency [`Table`] for the [`Policy`]. + /// + /// # Safety + /// + /// The caller must guarantee that the [`Table`] is not dropped while = it is getting used by the + /// C code. + #[inline] + pub unsafe fn set_freq_table(&mut self, table: &Table) -> &mut Self { + self.as_mut_ref().freq_table =3D table.as_raw(); + self + } + + /// Returns the [`Policy`]'s private data. + pub fn data(&mut self) -> Option<::Borrowed<'_>>= { + if self.as_ref().driver_data.is_null() { + None + } else { + // SAFETY: The data is earlier set from [`set_data`]. + Some(unsafe { T::borrow(self.as_ref().driver_data) }) + } + } + + // Sets the private data of the [`Policy`] using a foreign-ownable wra= pper. + // + // # Errors + // + // Returns `EBUSY` if private data is already set. + fn set_data(&mut self, data: T) -> Result<()> { + if self.as_ref().driver_data.is_null() { + // Transfer the ownership of the data to the foreign interface. + self.as_mut_ref().driver_data =3D ::into_= foreign(data) as _; + Ok(()) + } else { + Err(EBUSY) + } + } + + // Clears and returns ownership of the private data. + 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 + } + } +} + +// CPU frequency policy created from a CPU number. +// +// This struct represents the CPU frequency policy obtained for a specific= CPU, providing safe +// access to the underlying `cpufreq_policy` and ensuring proper cleanup w= hen the `PolicyCpu` is +// dropped. +struct PolicyCpu<'a>(&'a mut Policy); + +impl<'a> PolicyCpu<'a> { + fn from_cpu(cpu: u32) -> Result { + // SAFETY: It is safe to call `cpufreq_cpu_get` for any valid CPU. + let ptr =3D from_err_ptr(unsafe { bindings::cpufreq_cpu_get(cpu) }= )?; + + Ok(Self( + // SAFETY: The `ptr` is guaranteed to be valid and remains val= id for the lifetime of + // the returned reference. + unsafe { Policy::from_raw_mut(ptr) }, + )) + } +} + +impl<'a> Deref for PolicyCpu<'a> { + type Target =3D Policy; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + +impl<'a> DerefMut for PolicyCpu<'a> { + fn deref_mut(&mut self) -> &mut Policy { + self.0 + } +} + +impl<'a> Drop for PolicyCpu<'a> { + fn drop(&mut self) { + // SAFETY: The underlying pointer is guaranteed to be valid for th= e lifetime of `self`. + unsafe { bindings::cpufreq_cpu_put(self.0.as_raw()) }; + } +} + +/// CPU frequency driver. +/// +/// Implement this trait to provide a CPU frequency driver and its callbac= ks. +/// +/// Reference: +#[vtable] +pub trait Driver { + /// Driver specific data. + /// + /// Corresponds to the data retrieved via the kernel's `cpufreq_get_dr= iver_data` function. + /// + /// Require `Data` to implement `ForeignOwnable`. We guarantee to neve= r 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; + + /// Driver's `init` callback. + fn init(policy: &mut Policy) -> Result; + + /// Driver's `exit` callback. + fn exit(_policy: &mut Policy, _data: Option) -> Result<()= > { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `online` callback. + fn online(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `offline` callback. + fn offline(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `suspend` callback. + fn suspend(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `resume` callback. + fn resume(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `ready` callback. + fn ready(_policy: &mut Policy) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `verify` callback. + fn verify(data: &mut PolicyData) -> Result<()>; + + /// Driver's `setpolicy` callback. + fn setpolicy(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `target` callback. + fn target(_policy: &mut Policy, _target_freq: u32, _relation: Relation= ) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `target_index` callback. + fn target_index(_policy: &mut Policy, _index: u32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `fast_switch` callback. + fn fast_switch(_policy: &mut Policy, _target_freq: u32) -> u32 { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `adjust_perf` callback. + fn adjust_perf(_policy: &mut Policy, _min_perf: usize, _target_perf: u= size, _capacity: usize) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `get_intermediate` callback. + fn get_intermediate(_policy: &mut Policy, _index: u32) -> u32 { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `target_intermediate` callback. + fn target_intermediate(_policy: &mut Policy, _index: u32) -> Result<()= > { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `get` callback. + fn get(_policy: &mut Policy) -> Result { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `update_limits` callback. + fn update_limits(_policy: &mut Policy) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `bios_limit` callback. + fn bios_limit(_policy: &mut Policy, _limit: &mut u32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver's `set_boost` callback. + fn set_boost(_policy: &mut Policy, _state: i32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Driver'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 17:55:12 2026 Received: from mail-pf1-f176.google.com (mail-pf1-f176.google.com [209.85.210.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 6B5852BE7A8 for ; Fri, 11 Apr 2025 10:59:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369198; cv=none; b=mqq2NMdgav2KTt1yx8qW3FhRr1PZvBpbfW4dpyAmwun0Ae3SBdnDb7VXhQvLVYXooua83nxhsFHKxk63tH1oy/CLUVuQgZIE0gyAISTxKp834LCOM2Z2JeQ4ZL/aO+oEMwPMd2aO+4SdIRfmRxb6QSw52UdjIjHS/Wgl6/NZsus= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369198; c=relaxed/simple; bh=x9ocZuCMF6s1tLJISfuyOmdKP9oOJA6RAJRtbMhG13w=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=hG7fIY/bhvu/M1ElqaQjGp0a9v+rWlI3WveB/vN+w/nMSOwgssl0mkZdrjx82/Zgvhj9u3S5ik8OjObd51jL4Xu4btPlZ8t4cj3k4ANqiavHFhwJbfEq+LN+dW4e7MUmFJRh6JSuF/hLWaS/5MJiUbfLgGZNxxHFWbw4/YVY8cE= 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=RKiz/d2g; arc=none smtp.client-ip=209.85.210.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="RKiz/d2g" Received: by mail-pf1-f176.google.com with SMTP id d2e1a72fcca58-736c1138ae5so1825111b3a.3 for ; Fri, 11 Apr 2025 03:59:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369196; x=1744973996; 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=8icndP/zvg1XI2+CBWAxu2KWgnBqQFP1Hmt5Q3cH4NQ=; b=RKiz/d2gCQT0s82PQvVOOUSxPOzKBP6CRu/jQZSmQQmNklutc5MDp20PHBp70FCrb4 p2vWAI0gAsjUwpOkro1tOFL/FfnFGjrCKSwTbjfaGP21NW86R3f5MSOUpUYINqfFttrs pRQfuXN0SD0uiGawJivS0RohKy1JnadUJ3MLixwm/HDICVQ3fZrjBsyGII11sO/QnWI/ uaI9urpUOjeuhjVJyKXczRvZoZiEqj/qf8eo1xbBUk31cKFiWrzUbdyjBeSwRYpijoKe fx4K/MV56YbWAK5AALzfc+DTcRD0P+kO7yw/lv/OrzQp1RtSQrzebuu0RD9vguGs5Ars tqyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369196; x=1744973996; 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=8icndP/zvg1XI2+CBWAxu2KWgnBqQFP1Hmt5Q3cH4NQ=; b=iJ/kugnF7SY/XoYseZW0flQzqZUoKftlK6QMUxr1ajg1nqgAxiollT9nKt58h2KCDC ubOCtMRCYMkQoMkQYc3Y2grGF2QYdK85V11PltDUEmZsZj9fFq9+Q6riuHQNsmhNCwcd iUTqNcYEaBlmN8eBkCxYbsRJnLFbstfa/I73/gQblqf/VXabtG5IyL/OeOgeJj/+//Gb wM/Jl6gCA6ip40uwn1bh0F/OlQPVJ2kWqcTu7ifExWcrZn0lii95kf3izeBv3xzoLmjJ rchUGLgg+yQP8lUjW/p7K4+wSTLGno4XzpWqRXrG22MxQjCDD9yX8QM4qO5u6v3LczGJ i6xw== X-Forwarded-Encrypted: i=1; AJvYcCUFRbgOv0yL4DtoDzKH6EYkvz02jqXkrreQzeifQ/BnsX+E6iB05qJOMij5inJkOV392P29sTztY10JRUU=@vger.kernel.org X-Gm-Message-State: AOJu0Yz2nCSMVZu51qu7sCsjpj2BiW7v/YUtVY9ZRNfSkW7vduOycjLL s5r0wtLfOmMy7QKcDHcsgQeLoKShq+R23QJWvTGu0ZmLzM1U9aPNtGZz+paED04= X-Gm-Gg: ASbGncudG4X5NhnlkzjlUYBBttHuhZXGXqMMv1Aiv9rvkuSEeqNxCc4e98AerVwzOQW 0901bDBjV7Tc7EwGpVqKJS0rJrCkWT0tcO+tT7g0HzBhEGjGuDGvjqvCXSZzGtYzXgtxyFkggdK O0AnGqkRdffpPpWLTp/7dd7nywJRXpN9Fhm0tQhHQWS9/9LLwV5c2+3WIXTPoncga0okVc7UMAg X0RrGJpXpjgP2i+ssA26qByK94xjYBffaAX0/ryhjD/hn/GVZkdvnT0infXz2REKJU13h2cpsDm MUMWBIf+f0Vx2CfqSVhVqI10DAZtz41NHbtlSn9oNQ== X-Google-Smtp-Source: AGHT+IHOlqPXQbP/NH5YoopqX8rs99m8OO1ecidoEx4lWwHl9VBhh51/az5okTqwk9eilX+LPwMurg== X-Received: by 2002:a05:6a00:1147:b0:736:a638:7f9e with SMTP id d2e1a72fcca58-73bd11dc3bamr4082106b3a.8.1744369195524; Fri, 11 Apr 2025 03:59:55 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-73bd21c62f7sm1226889b3a.65.2025.04.11.03.59.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:54 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 15/17] rust: cpufreq: Extend abstractions for driver registration Date: Fri, 11 Apr 2025 16:25:14 +0530 Message-Id: <2f7a1331ad513b94fb47c05bf1d0f5c3fa803858.1744366572.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" Extend the cpufreq abstractions to support driver registration from Rust. Signed-off-by: Viresh Kumar --- rust/kernel/cpufreq.rs | 530 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 528 insertions(+), 2 deletions(-) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 3e9ded655d46..4194b9558413 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -13,7 +13,8 @@ clk::{Clk, Hertz}, 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}, ffi::c_ulong, prelude::*, types::ForeignOwnable, @@ -21,9 +22,11 @@ }; =20 use core::{ + cell::UnsafeCell, + marker::PhantomData, ops::{Deref, DerefMut}, pin::Pin, - ptr::self, + ptr, }; =20 use macros::vtable; @@ -792,3 +795,526 @@ fn register_em(_policy: &mut Policy) { build_error!(VTABLE_DEFAULT_ERROR) } } + +/// CPU frequency driver Registration. +/// +/// ## Examples +/// +/// The following example demonstrates how to register a cpufreq driver. +/// +/// ``` +/// use kernel::{ +/// c_str, +/// cpu, cpufreq, +/// device::Device, +/// macros::vtable, +/// sync::Arc, +/// }; +/// struct FooDevice; +/// +/// #[derive(Default)] +/// struct FooDriver; +/// +/// #[vtable] +/// impl cpufreq::Driver for FooDriver { +/// type Data =3D (); +/// type PData =3D Arc; +/// +/// fn init(policy: &mut cpufreq::Policy) -> Result { +/// // Initialize here +/// Ok(Arc::new(FooDevice, GFP_KERNEL)?) +/// } +/// +/// fn exit(_policy: &mut cpufreq::Policy, _data: Option)= -> Result<()> { +/// 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) -> Resul= t<()> { +/// // Update CPU frequency +/// Ok(()) +/// } +/// +/// fn get(policy: &mut cpufreq::Policy) -> Result { +/// policy.generic_get() +/// } +/// } +/// +/// fn foo_probe(dev: &Device) { +/// cpufreq::Registration::::new_foreign_owned( +/// dev, +/// c_str!("cpufreq-foo"), +/// (), +/// cpufreq::flags::NEED_INITIAL_FREQ_CHECK | cpufreq::flags::IS_C= OOLING_DEV, +/// true, +/// ).unwrap(); +/// } +/// ``` +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 CPU frequency driver with the cpufreq core. + pub fn new(name: &'static CStr, data: T::Data, flags: u16, boost: bool= ) -> Result { + // Required due to Rust 1.82's stricter handling of `unsafe` in mu= table statics. The + // `unsafe` blocks aren't required anymore with later versions. + #![allow(unused_unsafe)] + + 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 byte. + 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 a= rray 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; + + // Initialize mandatory callbacks. + drv_ref.init =3D Some(Self::init_callback); + drv_ref.verify =3D Some(Self::verify_callback); + + // Initialize optional callbacks based on the traits of `T`. + 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 calls 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 kernel 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 [`Registratio= n`] instance. + /// + /// Instead the [`Registration`] is owned by [`Devres`] and will be re= voked / dropped, once the + /// device is detached. + pub fn new_foreign_owned( + dev: &Device, + name: &'static CStr, + data: T::Data, + flags: u16, + boost: bool, + ) -> Result<()> { + Devres::new_foreign_owned(dev, Self::new(name, data, flags, boost)= ?, GFP_KERNEL)?; + Ok(()) + } + + // Sets the `Data` for the CPU frequency driver. + fn set_data(drv: &mut bindings::cpufreq_driver, data: T::Data) -> Resu= lt<()> { + if drv.driver_data.is_null() { + // Transfer the ownership of the data to the C code. + drv.driver_data =3D ::into_foreign(= data) as _; + Ok(()) + } else { + Err(EBUSY) + } + } + + /// Returns borrowed `Data` previously set for the CPU frequency drive= r. + 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 the CPU frequency driver. + fn clear_data(&mut self) -> Option { + 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`. + let data =3D Some(unsafe { ::from_f= oreign(drv.driver_data) }); + drv.driver_data =3D ptr::null_mut(); + data + } + } +} + +// CPU frequency driver callbacks. +impl Registration { + // Driver's `init` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> ker= nel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + + let data =3D T::init(policy)?; + policy.set_data(data)?; + Ok(0) + }) + } + + // Driver's `exit` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) { + // SAFETY: The `ptr` is guaranteed to be valid by the contract wit= h the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + + let data =3D policy.clear_data(); + let _ =3D T::exit(policy, data); + } + + // Driver's `online` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> k= ernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::online(policy).map(|()| 0) + }) + } + + // Driver's `offline` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> = kernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::offline(policy).map(|()| 0) + }) + } + + // Driver's `suspend` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> = kernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::suspend(policy).map(|()| 0) + }) + } + + // Driver's `resume` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> k= ernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::resume(policy).map(|()| 0) + }) + } + + // Driver's `ready` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) { + // SAFETY: The `ptr` is guaranteed to be valid by the contract wit= h the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::ready(policy); + } + + // Driver's `verify` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn verify_callback(ptr: *mut bindings::cpufreq_policy_data)= -> kernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let data =3D unsafe { PolicyData::from_raw_mut(ptr) }; + T::verify(data).map(|()| 0) + }) + } + + // Driver's `setpolicy` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -= > kernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::setpolicy(policy).map(|()| 0) + }) + } + + // Driver's `target` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn target_callback( + ptr: *mut bindings::cpufreq_policy, + target_freq: u32, + relation: u32, + ) -> kernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::target(policy, target_freq, Relation::new(relation)?).map(|= ()| 0) + }) + } + + // Driver's `target_index` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn target_index_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> kernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::target_index(policy, index).map(|()| 0) + }) + } + + // Driver's `fast_switch` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn fast_switch_callback( + ptr: *mut bindings::cpufreq_policy, + target_freq: u32, + ) -> kernel::ffi::c_uint { + // SAFETY: The `ptr` is guaranteed to be valid by the contract wit= h the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::fast_switch(policy, target_freq) + } + + // Driver'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 PolicyCpu::from_cpu(cpu) { + T::adjust_perf(&mut policy, min_perf, target_perf, capacity); + } + } + + // Driver's `get_intermediate` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn get_intermediate_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> kernel::ffi::c_uint { + // SAFETY: The `ptr` is guaranteed to be valid by the contract wit= h the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::get_intermediate(policy, index) + } + + // Driver's `target_intermediate` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn target_intermediate_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> kernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::target_intermediate(policy, index).map(|()| 0) + }) + } + + // Driver's `get` callback. + extern "C" fn get_callback(cpu: u32) -> kernel::ffi::c_uint { + PolicyCpu::from_cpu(cpu).map_or(0, |mut policy| T::get(&mut policy= ).map_or(0, |f| f)) + } + + // Driver's `update_limit` callback. + extern "C" fn update_limits_callback(cpu: u32) { + if let Ok(mut policy) =3D PolicyCpu::from_cpu(cpu) { + T::update_limits(&mut policy); + } + } + + // Driver's `bios_limit` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> kernel= ::ffi::c_int { + from_result(|| { + let mut policy =3D PolicyCpu::from_cpu(cpu as u32)?; + + // SAFETY: `limit` is guaranteed by the C code to be valid. + T::bios_limit(&mut policy, &mut (unsafe { *limit })).map(|()| = 0) + }) + } + + // Driver's `set_boost` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn set_boost_callback( + ptr: *mut bindings::cpufreq_policy, + state: i32, + ) -> kernel::ffi::c_int { + from_result(|| { + // SAFETY: The `ptr` is guaranteed to be valid by the contract= with the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::set_boost(policy, state).map(|()| 0) + }) + } + + // Driver's `register_em` callback. + // + // SAFETY: Called from C. Inputs must be valid pointers. + extern "C" fn register_em_callback(ptr: *mut bindings::cpufreq_policy)= { + // SAFETY: The `ptr` is guaranteed to be valid by the contract wit= h the C code for the + // lifetime of `policy`. + let policy =3D unsafe { Policy::from_raw_mut(ptr) }; + T::register_em(policy); + } +} + +impl Drop for Registration { + // Removes the `Registration` from the kernel, if it has initialized s= uccessfully earlier. + fn drop(&mut self) { + let drv =3D self.drv.get_mut(); + + // SAFETY: The driver was earlier registered from `new`. + unsafe { bindings::cpufreq_unregister_driver(drv) }; + + // Free data + drop(self.clear_data()); + } +} --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 2026 Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) (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 6ADE02BE7CB for ; Fri, 11 Apr 2025 10:59:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369200; cv=none; b=fTLThDBpOlnVsJqhZwMsnOyEHIfgPbblsNPYyUcjkoJBr+GOHPa5hMobt/ATvtkvqrD2g9tZokIHYYJpCybyfOk0zrOkuQ6XY3dE600bBC07F3YqPdtY4eUmzb5qhzHx2w81bfZTlmHtztX6ZxcUJ+LK83Mf18RMNnAAXcm/3T0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369200; c=relaxed/simple; bh=YfkEvdysLwoMmcnG/s03bKY53YATs71FlnrnNvf18rM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Hrg4hgz3pvNLftsltZC9caS+vz/tRgKqHkICbQjn7dWgwXQP9pA+D1P9lHvNTM18BVm3/ZcPkplyq1ChK7GnQWCGEpdBSMNw1lZBQd+bpN22YqES3MxgYLX3EPWON02LtwBFuduzDWTmdK1JSe4Rxvg64Su+15UqXXcNDXkoeW4= 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=EYCOf8aO; arc=none smtp.client-ip=209.85.210.174 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="EYCOf8aO" Received: by mail-pf1-f174.google.com with SMTP id d2e1a72fcca58-7370a2d1981so1413265b3a.2 for ; Fri, 11 Apr 2025 03:59:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369199; x=1744973999; 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=5O39+KsHhbO3NhJV0D2xQKPBr7meyvBFEMUfJdpqZjU=; b=EYCOf8aODVPPX0FhyvlNF0SbvElYhQcTGPVQu+VmwhlXimf7KyaYCjHb+TQpZAqOKa 7D93GW/X+8CmOxCLxqSI4dzA8bNjDdvRvaUgbfdFbw7HikZfGY0a6q0J1CFEi2GMUC12 aBCKFldhqhgMuQptseEFCcCVAlB+zHY/u5G5lB2ey2b3BKfnFatsH5U7Wp4jyrAOPwsN sjoIUNwWyaMPssPXg50UZW3tTOv5+L34UWJWGF4EOaCHfBP8PMQbuCEwgnn7wRWoG2Hb wNV8IhDfi6UDXVDqUhCm00CkseGCwrmfao4DhWa3ZPyAkM7oF0C4YAt6Vo7cuvOg1T7z Tu/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369199; x=1744973999; 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=5O39+KsHhbO3NhJV0D2xQKPBr7meyvBFEMUfJdpqZjU=; b=sWpEYXbhwvv5hGCG6RiWOzic7wfpy2xR8X9ygNOqQk00Xtle6kKYVw5z7jB3kUyTz1 KfJRW9UXO4SFjeh+2VLNvFNjDIqsATv3B4SgSi0UdamfYkA7ryWwfK/HVxjSTtfPnojb wdWPB9Ek1jxGKLifqkaltu7hdA5Fy5v/R4L0j3NXLMbyHSBojgSLOM3kwkR6rYHUvLhu hv2Qi8oDYmnpendwPSYX3hPf+/grqMtyUlFtvrohIsDZ1JSsLhX2k2JggDyz252u177L bVzt2gHKFsOZiG0ZfmKeRevJP7Iz91JSGe6OBJ0N6tvI5svzEiYW4UMCKnKiwpHYXZu2 z8fg== X-Forwarded-Encrypted: i=1; AJvYcCX60Rm3Tuh16k+Qk2CfsiIxpA+mDDZUaQ+5jZlQ97my8/yHvuEA7T/6mHTZoWHMPZrbPVQ4+2t5RxFhne0=@vger.kernel.org X-Gm-Message-State: AOJu0YysXHjuqFEXnfJodYQ5smbqlTphXgSWtT0rp0ovhusRcP/l5ezO L4HGP3B3gn3gQBARoy90mIYhG8Pc/Da4iPBYzwTouea1GXFW/Jlb98h8d0XmOuw= X-Gm-Gg: ASbGncvWBPJCZrIGkTlM9xQ4gGH+ieZgvxFcgQ5dvibmLvdBgaKGSbfGVhEAFtCAQyj EPiBf7b6IBv4L/nXLEYtz3PEgVoG+AB9cCrK9aTTRddr0sykicaQhHEZPPknLNiS9+qujuLn1gR AO6/PCdAbqWyQwuMs7356vT9AEB8xDsmIc5t7oBA3F9UIHuA+RH3jsFxr49+3CjBZ1NwapqZ2UM 48RhCaudjgGJqeB/Hy0rMdDGavhARSraTmKwq8CMBJWTYEXSBQLCi8hTgb04bZDQAYSe9YvTLQd XhfLI4YX8LB8z5kl6mW12VOuKkYDJfcJm+vJ1ifgxA== X-Google-Smtp-Source: AGHT+IFUZzi3or0+gmBFWhEoaT6J6YgEu6VDaT3zpSxk4MU/e2d8OAjpgFPpre9Wl18Dad1dznFhiQ== X-Received: by 2002:a17:90b:5188:b0:301:98fc:9b51 with SMTP id 98e67ed59e1d1-3082365a310mr3170141a91.5.1744369198940; Fri, 11 Apr 2025 03:59:58 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-306df08f63bsm5260842a91.24.2025.04.11.03.59.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 03:59:58 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 16/17] rust: opp: Extend OPP abstractions with cpufreq support Date: Fri, 11 Apr 2025 16:25:15 +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" Extend the OPP abstractions to include support for interacting with the cpufreq core, including the ability to retrieve frequency tables from OPP table. Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index 7bf612fa0cc5..a46ac28d4464 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -20,6 +20,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; @@ -497,6 +503,60 @@ extern "C" fn config_regulators( } } =20 +/// OPP frequency table. +/// +/// A [`cpufreq::Table`] created from [`Table`]. +#[cfg(CONFIG_CPU_FREQ)] +pub struct FreqTable { + dev: ARef, + ptr: *mut bindings::cpufreq_frequency_table, +} + +#[cfg(CONFIG_CPU_FREQ)] +impl FreqTable { + /// Creates a new instance of [`FreqTable`] from [`Table`]. + 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 [`De= vice`] 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(), + ptr, + }) + } + + // Returns a reference to the underlying [`cpufreq::Table`]. + #[inline] + fn table(&self) -> &cpufreq::Table { + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + unsafe { cpufreq::Table::from_raw(self.ptr) } + } +} + +#[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 pointer was created via `dev_pm_opp_init_cpufreq_ta= ble`, and is only freed + // here. + unsafe { bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw()= , &mut self.as_raw()) }; + } +} + /// A reference-counted OPP table. /// /// Rust abstraction for the C `struct opp_table`. @@ -752,6 +812,13 @@ pub fn adjust_voltage( }) } =20 + /// Creates [`FreqTable`] from [`Table`]. + #[cfg(CONFIG_CPU_FREQ)] + #[inline] + pub fn cpufreq_table(&mut self) -> Result { + FreqTable::new(self) + } + /// Configures device with [`OPP`] matching the frequency value. #[inline] pub fn set_rate(&self, freq: Hertz) -> Result<()> { --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 17:55:12 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 B8CA32BEC43 for ; Fri, 11 Apr 2025 11:00:03 +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=1744369205; cv=none; b=JbRCBe7niWlZB6eM+9t0xVKEWMv8s2gkBNnE8F4WJzroXX94D8aPVyFB5YSrIWAi69hU77VzN8yq3IEzMKlLq9a7xBAlIDsqeOUu3ZlcO6RCTRnMNicksLoVKv9+XUv+a+wge98f/q4h9zGE2ZOH7AjPgIBbhk28sNKDYLjyu30= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744369205; c=relaxed/simple; bh=pWo35UcpFfXt0lltVDkHvDrvwug3xEzrt77oiEiP7XI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=C50pe8qqRof3nCAcDUU2HOIZV8R6nWiW3J7YHZg4bLEQJyR/IhT34M4PLOpFit2g4N7yvK6nyxqj8OO6oZwXBiExOiT6AROGpFprfYq36A/ZL89V6ILAa4+9l43QazeqzOrRAgupkIETTCJxbWwEOYbSh+3zRn8Uv5HTSLUPznI= 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=xmb9Upzf; 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="xmb9Upzf" Received: by mail-pl1-f177.google.com with SMTP id d9443c01a7336-227a8cdd241so21744015ad.3 for ; Fri, 11 Apr 2025 04:00:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1744369203; x=1744974003; 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=4mNVvyernaxT52HQcm+4cNUWaUzVLRpgc/yTn2bSQaE=; b=xmb9UpzfcIDoUm86ZJ00J+nBYQkL0d42SvqYHpzbnt3ceJMZK+vlEsuPKVJc4yBUdA Wx5SnU1XCHqEKvdq+7ZTLEP2JMZcVUtdBjygJQFlP2HAKz1MEhAZmeJKT+eyO5KWKhmZ B+3QT8PgNgCTPy4I1rnQHkO2+Vdy9hxgjhItDmRwBeRqP8oYz9LGSIPEDtxSmwOtIsHi FXKncbaHFGkUoelPnAe+4CFzLvLZ2jMLzU94UG739x08TfQFMXUGlpg3jW00txnFra3f 8K+XVRBP3STBMxq+PuiEWE9ifBPLQpuOc9jZQtfgdpqvBIRQWEiCnbvhFKDYUHLJOfnV QPhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744369203; x=1744974003; 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=4mNVvyernaxT52HQcm+4cNUWaUzVLRpgc/yTn2bSQaE=; b=fr0rBIymXOpQQnM7SIYoJcWSBxdjGVFSp77R41yhyFFPLzILlnvHFbGqLQgYBymGjY TO9egszXnicKfTmxRfNayMRH1N/0mATOK7Su4mCHfj0egHydJlHd0yeVLG6MPbHiQOMS a0VPeNDmnQB5g+QeHy7ENTmNR04u4+peJhv8o5l299adFUWhPSN7ZBZk9rgv8P9pFktg NTqcc+sVZhch4jyvP9Jhc82S5gltayWvEsC016UpW+qg54bzL7ZT4yGZ3MRHmb5rszZz AppjyCSPb9MJWF/KeRC6uNBLHb9l/e/7Z6LUsOPbhtZ7kdSzDJ+5g68+WfBVF6vZTuDX eXHQ== X-Forwarded-Encrypted: i=1; AJvYcCVbPjD4ox6Yl+Of4yNVYFHrk8T+V2eIEHu44eRQJN0VpYqLOmNYUAj3DBmsU1azqthDqzzTVG8ETGVR0H8=@vger.kernel.org X-Gm-Message-State: AOJu0YyUUtbQs5QI7fw/lagh7qXwOKIrFC4Xay99KIrhDOM5AFf5fYAm r9shDBw7geoTX91VbWm2NHLOb9aWAgIhrOkritbMiJdrMdHTck3JgowbbCIHpiU= X-Gm-Gg: ASbGncvGbOf2gcEzU8mWYQ1AFGdCqF4WzkKypsDf+hkGbfyVZ9oXIdNKlon+Zr7M13s 6FspxKQ85sgUibu1PZeVHvxU9FbxDz7jaDYp+67ZpZOqBjHNaCT/IM2nBbiI2buVOqVOfowl9SG U9G+c40ERWFdppIEWp0InC7zpS8IGJqADu0ykcQ72v/SMzsoOJKj/XaAPYSkR61u0fHjKUk/mRV 77zjpAHdnrqakBL2FzA32xCw7+PDvRqAOn6DaA7JPe6t4Pq7D1JRk98Wv5zawhRa3vN4jAfuQ+7 Tmbi25cSWKHzUWo39lbrq5yNgBKJt4A//0zO2xgZmw== X-Google-Smtp-Source: AGHT+IHE8HlOfRWkUJ6bGufM5iixKyxjSNZZ9SqxCniqwDGeJ+fDGcaMFZXytSiHOOkDy5nU5HRnVw== X-Received: by 2002:a17:903:2a8f:b0:21f:1bd:efd4 with SMTP id d9443c01a7336-22bea4ab8bemr35593525ad.19.1744369202779; Fri, 11 Apr 2025 04:00:02 -0700 (PDT) Received: from localhost ([122.172.83.32]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22ac7cafdaasm46053495ad.165.2025.04.11.04.00.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Apr 2025 04:00:02 -0700 (PDT) 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 , Danilo Krummrich 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 , Yury Norov , Burak Emir , Rasmus Villemoes , Russell King , linux-clk@vger.kernel.org, Michael Turquette , linux-kernel@vger.kernel.org Subject: [PATCH V9 17/17] cpufreq: Add Rust-based cpufreq-dt driver Date: Fri, 11 Apr 2025 16:25:16 +0530 Message-Id: <0bb160bbbc11d7b9249e064cdaec48dfc4380d90.1744366572.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" Introduce a Rust-based implementation of the cpufreq-dt driver, covering most of the functionality provided by the existing C version. Some features, such as retrieving platform data from `cpufreq-dt-platdev.c`, are still pending. The driver has been tested with QEMU, and frequency scaling works as expected. Signed-off-by: Viresh Kumar --- drivers/cpufreq/Kconfig | 12 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/rcpufreq_dt.rs | 236 +++++++++++++++++++++++++++++++++ 3 files changed, 249 insertions(+) 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 22ab45209f9b..d38526b8e063 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..751be33c0218 --- /dev/null +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust based implementation of the cpufreq-dt driver. + +use kernel::{ + c_str, + clk::Clk, + cpu, cpufreq, + cpumask::CpumaskVar, + device::{Core, Device}, + error::code::*, + 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 prop_name =3D CString::try_from_fmt(fmt!("{}-supply", name)).ok()?; + dev.property_present(&prop_name) + .then(|| CString::try_from_fmt(fmt!("{name}")).ok()) + .flatten() +} + +// Finds supply name for the CPU from DT. +fn find_supply_names(dev: &Device, cpu: u32) -> Option> { + // Try "cpu0" for older DTs, fallback to "cpu". + let name =3D (cpu =3D=3D 0) + .then(|| find_supply_name_exact(dev, "cpu0")) + .flatten() + .or_else(|| 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: CpumaskVar, + #[allow(dead_code)] + token: Option, + #[allow(dead_code)] + clk: Clk, +} + +#[derive(Default)] +struct CPUFreqDTDriver; + +#[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 during init; it won't get h= ot-unplugged. The cpufreq + // core registers 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 CpumaskVar::new(GFP_KERNEL)?; + + mask.set(cpu); + + let token =3D find_supply_names(dev, cpu) + .map(|names| { + opp::Config::::new() + .set_regulator_names(names)? + .set(dev) + }) + .transpose()?; + + // 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) if e =3D=3D ENOENT =3D> { + // "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() + } + Err(e) =3D> return Err(e), + }; + + // 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.setall(); + opp_table.set_sharing_cpus(&mut mask)?; + } + + let mut transition_latency =3D opp_table.max_transition_latency_ns= () as u32; + if transition_latency =3D=3D 0 { + transition_latency =3D cpufreq::ETERNAL_LATENCY_NS; + } + + policy + .set_dvfs_possible_from_any_cpu(true) + .set_suspend_freq(opp_table.suspend_freq()) + .set_transition_latency_ns(transition_latency); + + let freq_table =3D opp_table.cpufreq_table()?; + // SAFETY: The `freq_table` is not dropped while it is getting use= d by the C code. + unsafe { policy.set_freq_table(&freq_table) }; + + // SAFETY: The returned `clk` is not dropped while it is getting u= sed by the C code. + let clk =3D unsafe { policy.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 Some(data) =3D policy.data::() else { + return Err(ENOENT); + }; + + // SAFETY: `index` is guaranteed to be valid by the C API. + let freq =3D unsafe { data.freq_table.freq(index.try_into()?)? }; + data.opp_table.set_rate(freq) + } + + 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: &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 {}, GFP_KERNEL)?; + + Ok(drvdata.into()) + } +} + +module_platform_driver! { + type: CPUFreqDTDriver, + name: "cpufreq-dt", + author: "Viresh Kumar ", + description: "Generic CPUFreq DT driver", + license: "GPL v2", +} --=20 2.31.1.272.g89b43f80a514