From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 597F322F170 for ; Mon, 13 Jan 2025 11:23:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767418; cv=none; b=oOSqBGRRmQ4cqux3tGWRdvOffZMm+4pf4BHoHLRSC6a/VmYPaVTED3JcL6iVezw7S0RkBHCD5JQiU1A+nmGZ1EHUREWKXhQD+fLFNfsZfDGO3rhKaEyi8k/Qrs1EqVkOlM/EmpSwRuZjvU6tmuelTMVQMNFvnJmPQOaTXv0HlvM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767418; c=relaxed/simple; bh=t2NVGvjKSZ8jGPHeqUP8byps2cHUv/LlWtK1ugt6aZ4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=LLohY26aAXQTBiBGbtpUkd9MK3TnAz3YZ48egLnS/QB7JjjJRyYBpEVuaLssrv5d3qSXe6+iAcTi0PfH4ptaeptTNqeidi3htNjudtHaFgOWx9CkoNnjdQT367JI+WyA5jzdv67h5xAudHwBVG7aNaNPgmjdsdRZZYB2NTG0LKQ= 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=qAZOIls4; arc=none smtp.client-ip=209.85.214.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="qAZOIls4" Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-21628b3fe7dso67886865ad.3 for ; Mon, 13 Jan 2025 03:23:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767417; x=1737372217; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IkWjr0H8S/ljloJuoBCwCDqimDzQkeaXdlPta4A4wUg=; b=qAZOIls4V5W4SGXSvGGSzTWCW01R/F5//n8XhLzEJHp5pl3QruA6InJ50MzRrpkqe4 hHVFk4nBLYFBExWQi5EW1Zl55depgJDw+UdT3MPfatamxzC8wA1E1/03Na80nFupocYG uuBFKDKj17lpSxU28XSOVh2+HBX5LbV7pZMmPz8SEw/BTNXFq0E8H1JAbj8qnbtMIlFU aISjzuOyB5AmagXhv5lYG50psmI3eFwl6aUkuCZo9DhTEyqy4nwQ+fT5W4lREyySEUeK wScldyIdpZEYwX7cgaYVJ687nb/mcDk5oBm3wuehCbpwp5+d9LcGvc8nibECkdE+AvCG 850A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767417; x=1737372217; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IkWjr0H8S/ljloJuoBCwCDqimDzQkeaXdlPta4A4wUg=; b=UYawbl+RR4EytrGsI3WXepig9Tuy93I7IUu8BCNjItIZ360bG68RRc15fWdJ+HA3mZ H233n6VohOK3nqK0hNFcJVgwiLzWHyTcU0SyoIgfkZqdEUcDVjc0iVfK8lNRKQTomlkR HTh0rJjxZKDQH0KYBpZbTScWgLjFb9wSt60jyJCMpBm9mqgC5NgFzVDSZBzf85UeGw0n jcSFhNq2A+KJOqCu3itouVJ2Onj0UEKKaBZiJUs0osLxGmdQwEck1aziK/10p07JGQMU iQ156Ieu+4gYylrhFRQVPLrV37P+rkaSBCjbe4jxV/KNmDSH8Ru64XNHBwk6OpM6Nigi 9hlw== X-Forwarded-Encrypted: i=1; AJvYcCVevkvilKPy3JVukX3JFWjSIMhQ4LYwIEmndz/WFRmA+q2QwByElSattrNhSxxyWYsU01pdM1CcyC4hCkE=@vger.kernel.org X-Gm-Message-State: AOJu0YwN3uSvdvQj8gibxeT7ZsRVEamod/pQg1k4fB20YSS8ZEUJlHHx jI10dktQv4XmRn6CEeAmJMVgJl1VKJSB6M+w9SLbepuIsQk8QB06/mX2wAukZds= X-Gm-Gg: ASbGncvd0VHJmC7dkz7apeL6ChSSVUd4AG4adMm3Kjyre/xw2ZONVtyuzYiEzGZO1X+ NW6I3bqt+pq6wFyJL3bR1+D7NuSizn6+vJqmLOvqhl4L2PALIuDsXznYGSyLelJiz3QaLVP/QFx EiNXBzrrnMAuuI5Qpb1nghlzU6+iwJyCNAg2Fcoo7etMas5KY5Vs0Ht0houHQGpYypqrTkEH4Pv eVxNeeBo8X7sY//lYAeor97y2wb45CcMQZgBcuR3E7hqWSdwpos9/fWnKk= X-Google-Smtp-Source: AGHT+IER2IavZa5iXzD4g2K372L5f9GipR0r5PB88XAPUzM7jWJLtQOWBOiD/bbJYuu6z8pO19v2iw== X-Received: by 2002:a05:6a00:846:b0:725:df1a:285 with SMTP id d2e1a72fcca58-72d21f476b9mr26557791b3a.12.1736767416693; Mon, 13 Jan 2025 03:23:36 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72d406587a1sm5844149b3a.105.2025.01.13.03.23.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:23:36 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 01/16] cpufreq: Use enum for cpufreq flags that use BIT() Date: Mon, 13 Jan 2025 16:52:56 +0530 Message-Id: <2916658cf432f924661121a91c3269354dc41853.1736766672.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" The BIT() macro is too complex for Rust's bindgen to interpret as integer constants. This results in many of the cpufreq macros being undefined in Rust auto-generated bindings. By replacing the "#define" macros with an "enum", we ensure that bindgen can properly evaluate these values, enabling their seamless use in Rust code. No intentional functional impact. Suggested-by: Alice Ryhl Signed-off-by: Viresh Kumar --- include/linux/cpufreq.h | 96 ++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 7fe0981a7e46..bd67728081ad 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -292,11 +292,12 @@ static inline void cpufreq_stats_record_transition(st= ruct cpufreq_policy *policy * CPUFREQ DRIVER INTERFACE * *********************************************************************/ =20 -#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ -#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ -#define CPUFREQ_RELATION_C 2 /* closest frequency to target */ -/* relation flags */ -#define CPUFREQ_RELATION_E BIT(2) /* Get if possible an efficient frequenc= y */ +enum { + CPUFREQ_RELATION_L =3D 0, /* lowest frequency at or above target */ + CPUFREQ_RELATION_H =3D BIT(0), /* highest frequency below or at target */ + CPUFREQ_RELATION_C =3D BIT(1), /* closest frequency to target */ + CPUFREQ_RELATION_E =3D BIT(2), /* Get if possible an efficient frequency = */ +}; =20 #define CPUFREQ_RELATION_LE (CPUFREQ_RELATION_L | CPUFREQ_RELATION_E) #define CPUFREQ_RELATION_HE (CPUFREQ_RELATION_H | CPUFREQ_RELATION_E) @@ -418,52 +419,57 @@ struct cpufreq_driver { =20 /* flags */ =20 -/* - * Set by drivers that need to update internal upper and lower boundaries = along - * with the target frequency and so the core and governors should also inv= oke - * the diver if the target frequency does not change, but the policy min o= r max - * may have changed. - */ -#define CPUFREQ_NEED_UPDATE_LIMITS BIT(0) +enum { + /* + * Set by drivers that need to update internal upper and lower + * boundaries along with the target frequency and so the core and + * governors should also invoke the diver if the target frequency does + * not change, but the policy min or max may have changed. + */ + CPUFREQ_NEED_UPDATE_LIMITS =3D BIT(0), =20 -/* loops_per_jiffy or other kernel "constants" aren't affected by frequenc= y transitions */ -#define CPUFREQ_CONST_LOOPS BIT(1) + /* + * loops_per_jiffy or other kernel "constants" aren't affected by + * frequency transitions. + */ + CPUFREQ_CONST_LOOPS =3D BIT(1), =20 -/* - * Set by drivers that want the core to automatically register the cpufreq - * driver as a thermal cooling device. - */ -#define CPUFREQ_IS_COOLING_DEV BIT(2) + /* + * Set by drivers that want the core to automatically register the + * cpufreq driver as a thermal cooling device. + */ + CPUFREQ_IS_COOLING_DEV =3D BIT(2), =20 -/* - * This should be set by platforms having multiple clock-domains, i.e. - * supporting multiple policies. With this sysfs directories of governor w= ould - * be created in cpu/cpu/cpufreq/ directory and so they can use the s= ame - * governor with different tunables for different clusters. - */ -#define CPUFREQ_HAVE_GOVERNOR_PER_POLICY BIT(3) + /* + * This should be set by platforms having multiple clock-domains, i.e. + * supporting multiple policies. With this sysfs directories of governor + * would be created in cpu/cpu/cpufreq/ directory and so they can + * use the same governor with different tunables for different clusters. + */ + CPUFREQ_HAVE_GOVERNOR_PER_POLICY =3D BIT(3), =20 -/* - * Driver will do POSTCHANGE notifications from outside of their ->target() - * routine and so must set cpufreq_driver->flags with this flag, so that c= ore - * can handle them specially. - */ -#define CPUFREQ_ASYNC_NOTIFICATION BIT(4) + /* + * Driver will do POSTCHANGE notifications from outside of their + * ->target() routine and so must set cpufreq_driver->flags with this + * flag, so that core can handle them specially. + */ + CPUFREQ_ASYNC_NOTIFICATION =3D BIT(4), =20 -/* - * Set by drivers which want cpufreq core to check if CPU is running at a - * frequency present in freq-table exposed by the driver. For these driver= s if - * CPU is found running at an out of table freq, we will try to set it to = a freq - * from the table. And if that fails, we will stop further boot process by - * issuing a BUG_ON(). - */ -#define CPUFREQ_NEED_INITIAL_FREQ_CHECK BIT(5) + /* + * Set by drivers which want cpufreq core to check if CPU is running at + * a frequency present in freq-table exposed by the driver. For these + * drivers if CPU is found running at an out of table freq, we will try + * to set it to a freq from the table. And if that fails, we will stop + * further boot process by issuing a BUG_ON(). + */ + CPUFREQ_NEED_INITIAL_FREQ_CHECK =3D BIT(5), =20 -/* - * Set by drivers to disallow use of governors with "dynamic_switching" fl= ag - * set. - */ -#define CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING BIT(6) + /* + * Set by drivers to disallow use of governors with "dynamic_switching" + * flag set. + */ + CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING =3D BIT(6), +}; =20 int cpufreq_register_driver(struct cpufreq_driver *driver_data); void cpufreq_unregister_driver(struct cpufreq_driver *driver_data); --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 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 D1444233D93 for ; Mon, 13 Jan 2025 11:23:40 +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=1736767422; cv=none; b=qqHS6S74amMhV7v3HNyWjA5MbJVYcCoXpMlS/pkkbA9MnLEfKQ4JfnKfmmHqPhheaf0MT9vRnS9hePAxGZUKcWfLa9KV1cygIFqzBjn6lPx1gXb5/WfT8VgoahbPjrdcCn5hcudo+n85DXZTmLc/CAS6zZdvJKowBM56BuKT3gQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767422; c=relaxed/simple; bh=56mpvPQsiCQvJ/qI37RI+kZkMobzbPxSKcp097e99C8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=lD7MmgtyTSQm9aU+bS7HqfFBXCTpvA/yiJGFLYA6q+y0xl5ZnKWJ4fDfJ3O3yxz9X3eO2SS+I52+i4zN9gukbYW2aB3+DZtrUaBzsHU0CtanJkXDUgVWUXEv5yD0dVYlfpnr+ebYFJtyL1pFbdwaJHmZclvL9A5J5JJJ4bC90uw= 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=zoeaKhat; 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="zoeaKhat" Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-21634338cfdso51826295ad.2 for ; Mon, 13 Jan 2025 03:23:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767420; x=1737372220; 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=pmCuXoJnBUxtp5/I8iV1DHcowuAM2GwBiNr+w7VeFWg=; b=zoeaKhatTn+ifIZiMkiG2j3DLP9fbpPpk/U28EA1lb7I2Au78wzJLNSS3m5WKglEd2 9dMU481X27b/tKaZ1JLrX1aw/4YILbogxGzTyXmUkpRFkdiGk/kWhjOBIb5z0cFdtN6o Hiy2mlXsB+f+dIQiq+ZxAie3NmU53tG6uwdi7EhvmZ6yKdqoF3M0x0SG6giN6D3wmHxN i89EHQ2YVicFju0SFWT8mA3piMSCQ+FKuXVXlE5up2ZVkU7wh5Wba3kmk3C1rmkdidyv ejUZMYUK32/rU/ybsMgmHl0KP9s9GZubI2cpdV6+X9QsLVuS+8IM2N2x33cnUfi2zLb/ Elkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767420; x=1737372220; 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=pmCuXoJnBUxtp5/I8iV1DHcowuAM2GwBiNr+w7VeFWg=; b=KV6LK8oeXdaYzVk/aipFiszT3/IGaZ4k2o67VoamVIIoSMX2xh4BzjCYFJCC+vss4L xVJs1WaVHfxzpxu3y2m672EPG2ArXGlB6PwxV9dOkK8FsL9hugjfBK5l7B/0UDEkVCjV H3c9mM8CS/4b9npn67r7bFwWUY9HziuK9WaulDCtMNT7qKzReh5z+JrWJbtWK96QLnk1 N9wCV7RLMb/X6af1fJc9qM3weyUiizDLPfQ1z6N6jNeO7f5KBOW1j2Kmy+C7G+O10AGs LHt87b4z7ETDl0t9XbsHUbdrybs8pY0MAxaDDRC6qXei4D0lLGx+eWVoL8HwcVKDOeyS hdjg== X-Forwarded-Encrypted: i=1; AJvYcCUT4Ecv4NxDMbrp6lFpxf7hkcbZb0I0ziH+ak6J90UfSjo7T264AqKmNGPD6a4lmtNlV3RNddlmYw7r8Zk=@vger.kernel.org X-Gm-Message-State: AOJu0YyThw7wXdMFI+ha/yqZp+GnNmwseaKWXe2eKo9vOnowiWTDVwpx bPiPnsgpJnT4XlR7PS4Mz4kWauJyfwidNPipsekeKXXZpAwvubuGGKKdnk78iA8= X-Gm-Gg: ASbGncsL5aYyvwsGxEU4dqFGe9SWG6kvt028Dm1plC/1r7fQ/SRwhWBy8Ust/+1n+/b sXrlqdOYwXIR2xXWYwzgR8TL4y+6oJakRxc8OqzlyyPePzJOZC5+N4V//AsmfWTyCrxtnmByf1J L/Puli5fiiMqvUl76FTMcfTtTXSXmgTI4iaFlqH2vhXiCxS/eqMrWc/1Lhzf1OP7wshdplToBO7 YSsuVXf1O+wyBBkj5IARdozO+QM53WMskyAb0zGmygnopl5Od3GgnzHYjQ= X-Google-Smtp-Source: AGHT+IEBqAU9m/Dz1cRS0HnmcowXNpNvmSNlZypDvYg39Eu5fhkkroa7r15wE1tObjFtw/U6RyJuJQ== X-Received: by 2002:a17:902:f70f:b0:216:32ea:c84b with SMTP id d9443c01a7336-21a83fc3652mr310297025ad.37.1736767420205; Mon, 13 Jan 2025 03:23:40 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21a9f10f860sm51777815ad.46.2025.01.13.03.23.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:23:39 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Nishanth Menon , Stephen Boyd , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 02/16] PM / OPP: Add reference counting helpers for Rust implementation Date: Mon, 13 Jan 2025 16:52:57 +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" To ensure that resources such as OPP tables or OPP nodes are not freed while in use by the Rust implementation, it is necessary to increment their reference count from Rust code. This commit introduces a new helper function, dev_pm_opp_get_opp_table_ref(), to increment the reference count of an OPP table and declares the existing helper dev_pm_opp_get() in pm_opp.h. Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 17 ++++++++++++----- drivers/opp/opp.h | 1 - include/linux/pm_opp.h | 6 ++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index be3291b53719..73e9a3b2f29b 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1528,11 +1528,6 @@ static struct opp_table *_allocate_opp_table(struct = device *dev, int index) return ERR_PTR(ret); } =20 -void _get_opp_table_kref(struct opp_table *opp_table) -{ - kref_get(&opp_table->kref); -} - static struct opp_table *_update_opp_table_clk(struct device *dev, struct opp_table *opp_table, bool getclk) @@ -1693,6 +1688,17 @@ static void _opp_table_kref_release(struct kref *kre= f) kfree(opp_table); } =20 +void _get_opp_table_kref(struct opp_table *opp_table) +{ + kref_get(&opp_table->kref); +} + +void dev_pm_opp_get_opp_table_ref(struct opp_table *opp_table) +{ + _get_opp_table_kref(opp_table); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_table_ref); + void dev_pm_opp_put_opp_table(struct opp_table *opp_table) { kref_put_mutex(&opp_table->kref, _opp_table_kref_release, @@ -1727,6 +1733,7 @@ void dev_pm_opp_get(struct dev_pm_opp *opp) { kref_get(&opp->kref); } +EXPORT_SYMBOL_GPL(dev_pm_opp_get); =20 void dev_pm_opp_put(struct dev_pm_opp *opp) { diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 430651e7424a..5c7c81190e41 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -250,7 +250,6 @@ struct opp_table { }; =20 /* Routines internal to opp core */ -void dev_pm_opp_get(struct dev_pm_opp *opp); bool _opp_remove_all_static(struct opp_table *opp_table); void _get_opp_table_kref(struct opp_table *opp_table); int _get_opp_count(struct opp_table *opp_table); diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 414146abfe81..c247317aae38 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -100,6 +100,7 @@ struct dev_pm_opp_data { #if defined(CONFIG_PM_OPP) =20 struct opp_table *dev_pm_opp_get_opp_table(struct device *dev); +void dev_pm_opp_get_opp_table_ref(struct opp_table *opp_table); void dev_pm_opp_put_opp_table(struct opp_table *opp_table); =20 unsigned long dev_pm_opp_get_bw(struct dev_pm_opp *opp, bool peak, int ind= ex); @@ -160,6 +161,7 @@ struct dev_pm_opp *dev_pm_opp_find_bw_ceil(struct devic= e *dev, struct dev_pm_opp *dev_pm_opp_find_bw_floor(struct device *dev, unsigned int *bw, int index); =20 +void dev_pm_opp_get(struct dev_pm_opp *opp); void dev_pm_opp_put(struct dev_pm_opp *opp); =20 int dev_pm_opp_add_dynamic(struct device *dev, struct dev_pm_opp_data *opp= ); @@ -205,6 +207,8 @@ static inline struct opp_table *dev_pm_opp_get_opp_tabl= e_indexed(struct device * return ERR_PTR(-EOPNOTSUPP); } =20 +static inline void dev_pm_opp_get_opp_table_ref(struct opp_table *opp_tabl= e) {} + static inline void dev_pm_opp_put_opp_table(struct opp_table *opp_table) {} =20 static inline unsigned long dev_pm_opp_get_bw(struct dev_pm_opp *opp, bool= peak, int index) @@ -341,6 +345,8 @@ static inline struct dev_pm_opp *dev_pm_opp_find_bw_flo= or(struct device *dev, return ERR_PTR(-EOPNOTSUPP); } =20 +static inline void dev_pm_opp_get(struct dev_pm_opp *opp) {} + static inline void dev_pm_opp_put(struct dev_pm_opp *opp) {} =20 static inline int --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 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 C55E422F16E for ; Mon, 13 Jan 2025 11:23:44 +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=1736767426; cv=none; b=Gye6KVxX+dzjPAj1GeVy37fQluZCf78xvPw6BLsCf8v/fSsR5uQhKzfkm4UnFWfm2cEvjY/N6A7NoHfBmBF6AFGQ17iS39eZ2w7BMAoJuIF7kEjHVnPoBc5GJX5jjt00aJSWLwCl+5a1L4xpE+Xold/js40YTfWhGlYqYrP9gDQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767426; c=relaxed/simple; bh=Log7cXXjzMiJkcv5gL5n5WiPvymmPQBug9ZqKR86Yek=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=MExGiOOHEkZq8qKd+2onu5fdgAoQrl6N9l3DgBkow919EsKChuwQyOC5vyAXu8dO+CvJRFMwkwkIn3CC+CsnUSZFkoKvFM4mX++vx5oZ6PyLtBW8X/A4qkW5uNIbnNWlywVEQxYUEUKpjZs0KHQTYNTblpeUNJvGfnKmWk0PmX0= 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=mNDWtdYm; 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="mNDWtdYm" Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-21631789fcdso64510955ad.1 for ; Mon, 13 Jan 2025 03:23:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767424; x=1737372224; 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=tdn4m6dKlofswR8ctFShfrfS5TKeZlPBTra3kXQON/0=; b=mNDWtdYmQwesy81qm8USSreo7D38hLW3H26UTPJDW0KT9V4Xc2yow55rOKD8HrGwKK EA89HIE4gczQjdiWGS5a9AsRpkfk6j0xbI+aYf6jqAsuLfNEcazhlfzwSdE06+WJ96jh UOJdd7UGyVAKCY8h/cHkx6nyFlQOmDH8zV0nCkoL3eMUNVbCWGrO5IOKLEjtMKh2Hqge 1EbsTpNptfIbgBBoWfBocZ78KE/fNrq1JuygiMlnDwefnvKOv8k0/iPgsNQB9Y9TGum8 mIzHEIpT4Dt1F/PCVFV9nQfeMusgo3KKdQR9AU/kLpQkL4oS0WkRL7dkq+EfaXYNKCBV faBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767424; x=1737372224; 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=tdn4m6dKlofswR8ctFShfrfS5TKeZlPBTra3kXQON/0=; b=KFwhQAejqAT/8C248SFHf7Ak/1lGLfUFhdqPLMhn5i2felhrkA7w4nb4tgp20+dCBM iL0Bus/Ryp1og8D0/lg/azPudNTqCPiAW9V5yqEghPlXgfwNSOnd0mGuwM7nLbEqvCkD EoST/eAFobynfc5cchni9mcrh6ImgbE+G9DK4mOX7oCLEjw/q31xzIfROg7Pj6ErQz/h MqoNi5t9kz0TI6L2DmjixjNdiE4e/qhD1dM11SP1kJ0v++4vMLaqdRhCGpJPsABxlK9I h8LuY12ZGwd7ehZYpYZ9ByJydr2B+Op3kfccmVapIxFqpFX0xYtu3Sg6iv5mbG1s+1Q5 UY/w== X-Forwarded-Encrypted: i=1; AJvYcCUC7tObGW2/xBi0gPBWcoDaHE5WYUIXKREJ5G7Cl76TX11QOtE1TiwE6GwszwQr5nYN2VKUMNdf/TmbAWg=@vger.kernel.org X-Gm-Message-State: AOJu0Yxy3P5KHgW3aPx+0+KwjZyH0dGamDqwZncCJiBdVbGfWkZpZv2J hKdQO7v0i96WMvGrL7DCtG4atrbjwsK/GhkjfwNjuJJ58R8pvkyQzzh3br9ADL0= X-Gm-Gg: ASbGncu45sr9WdQC+YWLAYmdJNrIzN895r9eZXpXdnvupNl6MXHXqA13BwEi1S7JPyE WX4d3bWJoUIOX2el0hdsAjgwQWPpUOGrGmpfqFvj0iPUqlqTM4HHXDIu1laG7mLBiSMfMmgCZoS h1R55uVlQOY77ruNH7hICIz1mmUlos8ySAXybHuiniULQSN4g9LLKxVu/g+MYgmO8lM0FeaQpud C4FwxSCRI8BwWgT4SYtRgyJd9yzrq7MXLKNEchYC/qj8AxmnH5usBHxXYI= X-Google-Smtp-Source: AGHT+IF0Y5yG1c5M9n48ix5v1C+TyVEgXKMj6yF6bVdvpXIdxxQSPZGVPl+AyedZLky2FVhj80qa6A== X-Received: by 2002:a05:6a00:3bc9:b0:727:39a4:30cc with SMTP id d2e1a72fcca58-72d30301d86mr19474714b3a.1.1736767424079; Mon, 13 Jan 2025 03:23:44 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72d4067e591sm5677575b3a.126.2025.01.13.03.23.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:23:43 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 03/16] rust: cpu: Add from_cpu() Date: Mon, 13 Jan 2025 16:52:58 +0530 Message-Id: <854f7b8c9cbcc7f38fe5ed548290f41224478b40.1736766672.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 --- rust/bindings/bindings_helper.h | 1 + rust/kernel/cpu.rs | 26 ++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 3 files changed, 28 insertions(+) create mode 100644 rust/kernel/cpu.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index e9fdceb568b8..d63e7f6d10ea 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/cpu.rs b/rust/kernel/cpu.rs new file mode 100644 index 000000000000..422e874627d2 --- /dev/null +++ b/rust/kernel/cpu.rs @@ -0,0 +1,26 @@ +// 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. +pub 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 2d5c3d7d2e21..e9106b29c359 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -39,6 +39,7 @@ pub mod block; #[doc(hidden)] pub mod build_assert; +pub mod cpu; pub mod cred; pub mod device; pub mod device_id; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0A0C623A56D for ; Mon, 13 Jan 2025 11:23:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767429; cv=none; b=nSqDXqa07hpxMNdH6iq7gpv790nTf/Znr6M1jBK+3mDoCr7lGEMUlPnlN+JHl939g9RzRSEAmhaRjqXkkRAqe+msbIPwyNEXKAzoTFX9E2/va6VskcnXo2By1IJGZQ5xIe9NOBdmTjcTRPJfTRi/dikZO+qP2E1Ks4eESWbmZtU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767429; c=relaxed/simple; bh=qFjzLah+7k0bGLsf807G16R7Nl932aHbCVEztV18Qug=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kmnWg1DA4FptWzKzmwDILDsJEBwAD/87hmITG6lDrN/aMp7jJ3XE7hHKSwHUGlQpeh9WJh4kMS2vcUIGFFNfC97XIDOM6UMhsg9MqHyrfFjY2zGZH6Wn/09YRs5Tu4eRk0TIuTqGumtvDfxuu3BObJmk192t73UV7GDeq6wnTWs= 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=whRU9Cfj; arc=none smtp.client-ip=209.85.214.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="whRU9Cfj" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-21675fd60feso94245385ad.2 for ; Mon, 13 Jan 2025 03:23:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767427; x=1737372227; 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=Erl89OKGaS5TERvIe2o6tMzhWrw69h3Z1JOwTaxOJAQ=; b=whRU9CfjTnHWSyizQVtwhP59wdi9PnmXTxU0lGYVZ2iGN3hA10ZihH+eLtxU9PG1XH IH5HRO/Fi4Txp9Kv061J8jDSGnWBFnTnupIRUaxNaOIrUe3hDVa3pHCoKSoWlpOD+BYK 5taBS0fy3OpCTJ1BuhRd2GhQQDuX6X23Yaqa3XetPkLqrFIhCq3VVb0KCh6MrRJN65wx Q9J+IQY4lMrR8fD+lF/i2k7G8oeoiNhe3DxFfDQQwmWZoIgKGcdjEzrudnUfKB6qq2pN NbPg32wBec267vXW7RKS2id8FCkzgr9rSML4d55Fzs3T+dGCieQ5wN+OsuCtisjzkxrY 1/tQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767427; x=1737372227; 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=Erl89OKGaS5TERvIe2o6tMzhWrw69h3Z1JOwTaxOJAQ=; b=M7nLRUGqbo88WewPJ1BZ9Dd3u8FTKitt3tA+jcML82GUmfQuJqjuczMlUmUhGqz+u5 /rjX1t15Zd3vwSWBPMv7vS1cPCbCu6QHJMRv8l/IMb94n/KJumq3XB8jbSF8YmC3N6cO fAWzrkgZy5sEuOMf6E2FzY9nAETe7ZdeRlYFnljAKYWRa8fEOAYhu1dEnOy5Nw+WqNnP 5o1njaWN1p62FF2b1Sq7N+iCfu2IZz2lIyFyBwAsNydaYr7uKaiqUJBNIw6jpSYdNhx4 HL4xb6KCCzBzjC0ITCEUUXk13J1GV3P+ohaQLq8EgU2T7NBQ/+hpwiDDQrOEMNorAZpR Z54Q== X-Forwarded-Encrypted: i=1; AJvYcCUSy29kA4vhA//GK8owotYmbcliGm4sPwhiYkG5yWcMV0WlFB9HmRXYHDG5LsB1ccHVvaTO4M/3VdL5nj8=@vger.kernel.org X-Gm-Message-State: AOJu0Yyd1LROcNW9kiiieNhc2J+7kahnpNA/f+KKf9K2f2KriNe/vMwW 5vskPnCXs1o20Z6G4j7KbKd80jSgdXWITIWbRY6N4hmUMYf1t6Dn23X2JS58KRA= X-Gm-Gg: ASbGncuRYMK6CvqrlcrHU1QEqgK+tWm0A5kw8WAq4H/A7K1jy6U4CUlhLaBvHOSvB42 StRtTycAT4ijFJ384UmUgqLFlfJ0IDP04SIkbr5dKUmp6uSUVSQ72Q6cd7f5RPOGrd/39tUthUV JpQKLdodYMf55sUKleheznZmCBneRcBnnKb/WwsYgnlCyiJAHEbcU9q/L3ZJXfv0Nw14R6jrPzP 1N7kSCYAlIskuT559gQtNYfv6/tJLbdA/e1+CYJ4ek/m/W41R25Yso1ppk= X-Google-Smtp-Source: AGHT+IFwnNOadRELhgUS4RHnfHmljCOFqvDn5NHiGTae6Lam/bomtLxFMSA+qHltYXwddKyNK29zYg== X-Received: by 2002:a17:902:d2d0:b0:216:45b9:439b with SMTP id d9443c01a7336-21a8400a357mr316419915ad.50.1736767427451; Mon, 13 Jan 2025 03:23:47 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21a9f10dddfsm52432345ad.23.2025.01.13.03.23.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:23:47 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Greg Kroah-Hartman , Danilo Krummrich Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH V7 04/16] rust: device: Add property_present() Date: Mon, 13 Jan 2025 16:52:59 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This implements Device::property_present(), which calls C APIs device_property_present() helper. The new helper will be used by Rust based cpufreq drivers. Signed-off-by: Viresh Kumar Acked-by: Greg Kroah-Hartman --- rust/bindings/bindings_helper.h | 1 + rust/kernel/device.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index d63e7f6d10ea..fda1e0d8f376 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index d5e6a19ff6b7..e8c4cda5aacc 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -6,6 +6,7 @@ =20 use crate::{ bindings, + str::CString, types::{ARef, Opaque}, }; use core::{fmt, ptr}; @@ -180,6 +181,12 @@ unsafe fn printk(&self, klevel: &[u8], msg: fmt::Argum= ents<'_>) { ) }; } + + /// Checks if property is present or not. + pub fn property_present(&self, name: &CString) -> bool { + // SAFETY: By the invariant of `CString`, `name` is null-terminate= d. + unsafe { bindings::device_property_present(self.as_raw().cast_cons= t(), name.as_ptr() as *const _) } + } } =20 // SAFETY: Instances of `Device` are always reference-counted. --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.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 CBDF923A575 for ; Mon, 13 Jan 2025 11:23:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767433; cv=none; b=n/wEz5RC78PH9IQOBCmgmtkZTw9jUcd39gBY8DAnAHE7ah5GjzQBnZpObk7VanNOCQl4dbw4gbX2rZc7zLj9YQsCRItFh0727dmBpBlXZl7Qg11rz54LxmIchyG1sepM/JlYnFNKbISTX8icRCUWnraRaz+r6l/lapRiFaPIusk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767433; c=relaxed/simple; bh=zpYDXqsOf66H5oUlZfzc8U4T3Ym6DA5SpJV3ddgDOqM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=WMYjev1zbuQ5QHshyPV+Vw8tcoZtwOwez9ux0dvPa6/TplsJrldeQj2OBml5RnJYGpYRRaoyDLq2QSQkqqmvx/xnDSFMqxuIeS9VqoWZxyCD0/m9oEBWEV/LKFjuyVQM73M/Epn0T5lBY5jKrSzEaa68SQKEP00fgt5z7GRKBbk= 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=bfRBwU6z; arc=none smtp.client-ip=209.85.214.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="bfRBwU6z" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-21670dce0a7so86474585ad.1 for ; Mon, 13 Jan 2025 03:23:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767431; x=1737372231; 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=6pq5lDpyHLAZUwHZL3qfvRqj8bZ5lnU8jFdny8YX3GE=; b=bfRBwU6z8Kn6jFtS42kbw6bXFOLddaA5LWH0bKWeb5vLVwycl94DItaHPlemQ18CKh zrBAKVKpPyNEhvl3wpiHZnbDZN9TOd6cYLwIfcHbyGJVA0NPrr9DPV2YsD3nt+DhS6Cn a3AxVjNvRyneCani2PgMDtFZU44XzJrL+llO7qBYV0kvSwwrkhenDQrKzfrQJaHkGwnW TQoPqGL5PBWxFumNaKMkujGhMMtkWZ9J69+p20VvMqMaicmcFKgosfJcxBmBoWKMjhnC 95xhRvAMxwHeFa0qReX/zJi6LRRhFrJ7n53TArofUsBfJWuWhsW9AoRFgbw/WgxS/T+t 4wIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767431; x=1737372231; 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=6pq5lDpyHLAZUwHZL3qfvRqj8bZ5lnU8jFdny8YX3GE=; b=mL/exquj11mm53fDP9luSYErOrvWimo/J5bjHbz9piBgwmbo5cQ1o7wlhOngW2qGTQ cD7T18w7n3giUfkyt/Nj3Lc7tjTHkYDRLRrUIxiV5eqxhzMeVnq8DUhWSnYtwcT4Kadk ZcHXLoDylaorsAQ6qczjGjF1Ig67B5z1vm0ieOuae7ql8/WS7eYjtOJ0Ngm4phneYvmu jmr05STZn7LLUt5kZ+xAOgOO8+AqKzinuT3VJIF663GucNAngwlXSlXuRuGsRIZMxMW5 kCngPEQU7x8crVAe8vz4cHSrYwJmEKqP0WGUMvW1Jcun8EvrVap65impfUAFSVPCC50x SzvA== X-Forwarded-Encrypted: i=1; AJvYcCVR3uz50iur42AfIQGWzSIKAOB+dkzSkDDAqYo27IXXw8nrofOHiDZKBYIvbtuvpkGA7N1TmkxhcEmPriA=@vger.kernel.org X-Gm-Message-State: AOJu0YyDvGXCmCvOJL2e8dxQgSAerrGcZ9hyxCxUePK2MD4tlY2zJYpD x8R7SoAnsdncRGNx9325EdCAM8M/27VuRusF4KqPIW8hl9ZxdzUu3ZhBS5V57cE= X-Gm-Gg: ASbGncvUJd8b/XgtEJ4mjYzp3Lx5MYkB7oPskFs17afgm/hk2DmHTw8lnabK7nFlZ9o YUk5OWkeZlm1UCzefoF5eWQdJ2VMrKZ8ePsHveyW7o5xGDS65Xe2VqMvp8XQga/vcq2gmxWD1yT OvZDS9KIiQwaFtb4dYx/wrdwbkeYF5/bgAwywKbBALKKIfecwpP6i3HnQaC89ZWvKGgnsUu9tXv ZNKZ/TdQgMbI5Z09UDKJmDxg8FbBHv2NwRTBjQyeU//YwPklS4vJr4oCGU= X-Google-Smtp-Source: AGHT+IEOjxJGVr7HBQVa0jzU1CKfFnjVBIzuSJp/j9DkYQxsSgo0CuPg7K6fdft0Ynvn0NGP+sGtsQ== X-Received: by 2002:a05:6a00:10d2:b0:725:9d70:6ace with SMTP id d2e1a72fcca58-72d21f5c141mr27897173b3a.6.1736767431251; Mon, 13 Jan 2025 03:23:51 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72d40681b3dsm5683664b3a.153.2025.01.13.03.23.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:23:50 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 05/16] rust: Add cpumask helpers Date: Mon, 13 Jan 2025 16:53:00 +0530 Message-Id: <5260b6f0308b67ca5cff002e95108504f04cf923.1736766672.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" In order to prepare for adding Rust abstractions for cpumask, this patch adds cpumask helpers. Signed-off-by: Viresh Kumar --- rust/bindings/bindings_helper.h | 1 + rust/helpers/cpumask.c | 35 +++++++++++++++++++++++++++++++++ rust/helpers/helpers.c | 1 + 3 files changed, 37 insertions(+) create mode 100644 rust/helpers/cpumask.c diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index fda1e0d8f376..59b4bc49d039 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/cpumask.c b/rust/helpers/cpumask.c new file mode 100644 index 000000000000..0b371826a13c --- /dev/null +++ b/rust/helpers/cpumask.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void rust_helper_cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp) +{ + cpumask_set_cpu(cpu, dstp); +} + +void rust_helper_cpumask_clear_cpu(int cpu, struct cpumask *dstp) +{ + cpumask_clear_cpu(cpu, dstp); +} + +void rust_helper_cpumask_setall(struct cpumask *dstp) +{ + cpumask_setall(dstp); +} + +void rust_helper_cpumask_copy(struct cpumask *dstp, const struct cpumask *= srcp) +{ + cpumask_copy(dstp, srcp); +} + +bool rust_helper_zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags) +{ + return zalloc_cpumask_var(mask, flags); +} + +#ifndef CONFIG_CPUMASK_OFFSTACK +void rust_helper_free_cpumask_var(cpumask_var_t mask) +{ + free_cpumask_var(mask); +} +#endif diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 0640b7e115be..de2341cfd917 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -11,6 +11,7 @@ #include "bug.c" #include "build_assert.c" #include "build_bug.c" +#include "cpumask.c" #include "cred.c" #include "device.c" #include "err.c" --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 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 B2E29233122 for ; Mon, 13 Jan 2025 11:23:55 +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=1736767437; cv=none; b=s03aY+isv0+LzKLN3GzJqXUNAE25UzSSYSV2uA373zNfkIoOo/eu0I43JShyGe8GFzGErm2RSM/3+dd3UfbG32ySDMHfczJHsQ68EwuPEKaJ4dha5pofCMY/47j790dJMasyQuqrgB8byAVLSoWjCfHqrIlCd6ZeyEawMlQ9vO8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767437; c=relaxed/simple; bh=fhjAe+tZdJoItHGU3pbD+/oYCE2BaIDZH25E8DWX9nw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=f0wUVWbHU/6Icnx6LUQ4XOmheO26lwnJqyBTsm72jPFK5EniYidquT06PJgVKDguregL07dIEMhhkZ4nxcBdP6YmehMCYj76mycuXVvN+FQk0ScTs3MJkIC0iXKIVX9KE1HB9HXK2bGs7p5Tq8ADODnaKrcJy3HZoI/yPwYFaMQ= 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=QeGxawUt; 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="QeGxawUt" Received: by mail-pl1-f177.google.com with SMTP id d9443c01a7336-2161eb95317so70305285ad.1 for ; Mon, 13 Jan 2025 03:23:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767435; x=1737372235; 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=czbTFxrFTC6BGzHp/oKzcB8oNYeLUKg2TzQ6UGtz5yk=; b=QeGxawUtpUaYPyl8MXwU04iGVaWdgKk9OXtLGWlKFqfNxFgWYcdPpzXrAc4+RrTwzA vY2DoMxneziblh8fGvMg7+rTjXOSI+tcw+iOWE+rKzJkYSJ1Nbv63F909FCLN7h8VNJE IU3nm3Vct7dsE9QqL5ub5CTYRhJU1usDc8G2S19a9kslaSwJ/j8H63vW69yAbzHUI9Uq uBcZqIvFoeCthzObNhs/sCFoTy/fFppGiW8S9hKNne/Qry91FxVorXxBuI9DfwIEmnD2 vTTtyW1+zGeU2uQixeHWQmPLdn5Dqx2m5E/A8/8GkeSNOHQ7gFpj0e71g7jZqrlc5js1 5OHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767435; x=1737372235; 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=czbTFxrFTC6BGzHp/oKzcB8oNYeLUKg2TzQ6UGtz5yk=; b=YpdZTkeIVRpRBrZQF11ZnAQzNPlER4h5zhEEd8TmjEaSzV0efQ1+muOO638aFZV0Ok IGB/Nm824h8y989Ah2kTTbch6Tkh5pf+ZDL67P1XaYw0lfNq81JM4ADkY4X5ViHHpQet UDiedUGwYXk/6ivxg/4S1Tq/Mv29Eue7Y6XlaVhQfW+TnZ+rPNEVzlvM+RxrIHL6tWMf fHqJrgQ5b5CbX+1ufacRH+faMelfap5J+Nn5BwDyGsDQ10X05dhgTjEb3jTdsaSyExxg v/EmB7dqQPtoEr50ACRGpLySH1Y61kOVVrN95JR6zmZ7FZXiXIaFU6MS2tMRH9Ea6BFZ 8k7g== X-Forwarded-Encrypted: i=1; AJvYcCVXvoQmndKPfToggKxfEg1VBaK9F4t5Q+q7QIdREkex1vdE00B6Vox6jLikGMAzgA98l7XQg780Xyg49wI=@vger.kernel.org X-Gm-Message-State: AOJu0YyPvJE7BCVTz5fcqoyAjQoY+RzqTHlj7pHZzXAR4lphr1t1xHv6 n3Z/kV85tajgcgA3p9KtHbl3v+pSIaDvzMN+tToVAw3IT1njC1ZxHtAAm1hxv5s= X-Gm-Gg: ASbGncsqrY8vgietaISMlqSw07lGCA/L5qCwiwGlLF/yBiSNOOESIl6TDjZx+UDh4Wb f1iIfvd4WmiplTEIQ+oLIcaRK68dnz9H7fUG3iK5B1ArE2bnfLJFOxwBnbqUqvAF0Fz2QYOxqBk akv+pd4Vru8Ariud5+Gqa38+owdjMD/GQ4lPvbl113AlsjV5glti5Rz4A0ZUQxmmiU6bcShVfzA a00UELATRTIHUv79MrJquuo6IugiiPl2sHzqud4OGLCKMFdo9uPu20maq0= X-Google-Smtp-Source: AGHT+IGieekbwx3qrgjAyDs5pUfdvjfV28c0KO0g2MvkIOQBBkbaEI8L2WbSDSmjUT3+UgBrDwIJ1Q== X-Received: by 2002:a05:6a21:32a0:b0:1e1:abd6:ca66 with SMTP id adf61e73a8af0-1e88cfdc6f0mr35358105637.24.1736767434793; Mon, 13 Jan 2025 03:23:54 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72d4065a544sm5938475b3a.96.2025.01.13.03.23.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:23:54 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 06/16] rust: Add bindings for cpumask Date: Mon, 13 Jan 2025 16:53:01 +0530 Message-Id: <4f233d3f6d593ba2e1cdde68af44200cae74f6f2.1736766672.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 patch adds basic Rust bindings for struct cpumask. These will be used by Rust based cpufreq / OPP core. Signed-off-by: Viresh Kumar --- rust/kernel/cpumask.rs | 85 ++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 2 files changed, 86 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..e3b15bc12798 --- /dev/null +++ b/rust/kernel/cpumask.rs @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! CPU mask abstractions. +//! +//! C header: [`include/linux/cpumask.h`](srctree/include/linux/cpumask.h) + +use crate::{bindings, error::Result, prelude::ENOMEM}; +use core::ptr; + +/// A simple implementation of `struct cpumask` from the C code. +pub struct Cpumask { + ptr: *mut bindings::cpumask, + owned: bool, +} + +impl Cpumask { + /// Creates empty cpumask. + pub fn new() -> Result { + let mut ptr: *mut bindings::cpumask =3D ptr::null_mut(); + + // SAFETY: Depending on the value of `gfp_flags`, this call may sl= eep. Other than that, it + // is always safe to call this method. + if !unsafe { bindings::zalloc_cpumask_var(&mut ptr, bindings::GFP_= KERNEL) } { + return Err(ENOMEM); + } + + Ok(Self { ptr, owned: true }) + } + + /// Creates a new abstraction instance of an existing `struct cpumask`= pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid, and non-null. + pub unsafe fn get_cpumask(ptr: *mut bindings::cpumask) -> Self { + Self { ptr, owned: false } + } + + /// Obtain the raw `struct cpumask *`. + pub fn as_raw(&mut self) -> *mut bindings::cpumask { + self.ptr + } + + /// Sets CPU in the cpumask. + /// + /// Update the cpumask with a single CPU. + pub fn set(&mut self, cpu: u32) { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_set_cpus()` for any CPU. + unsafe { bindings::cpumask_set_cpu(cpu, self.ptr) }; + } + + /// Clears CPU in the cpumask. + /// + /// Update the cpumask with a single CPU. + pub fn clear(&mut self, cpu: i32) { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_clear_cpu()` for any CPU. + unsafe { bindings::cpumask_clear_cpu(cpu, self.ptr) }; + } + + /// Sets all CPUs in the cpumask. + pub fn set_all(&mut self) { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_setall()`. + unsafe { bindings::cpumask_setall(self.ptr) }; + } + + /// Copies cpumask. + pub fn copy(&self, dstp: &mut Self) { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of `se= lf`. And it is safe to + // call `cpumask_copy()`. + unsafe { bindings::cpumask_copy(dstp.as_raw(), self.ptr) }; + } +} + +impl Drop for Cpumask { + fn drop(&mut self) { + if self.owned { + // SAFETY: `ptr` is guaranteed to be valid for the lifetime of= `self`. And it is safe + // to call `free_cpumask_var()`. + unsafe { bindings::free_cpumask_var(self.ptr) } + } + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index e9106b29c359..2f72e1d8a6b7 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -40,6 +40,7 @@ #[doc(hidden)] pub mod build_assert; pub mod cpu; +pub mod cpumask; pub mod cred; pub mod device; pub mod device_id; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pj1-f50.google.com (mail-pj1-f50.google.com [209.85.216.50]) (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 7D1C523ED50 for ; Mon, 13 Jan 2025 11:24:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767442; cv=none; b=NORBS5Xkw8kZZr0jP3DkKBhjlVuih5eQ0SefB+aCtwXT/w/C7iXPPzQMnwpVMLIcvdqIHwzSesSmMTc9PEcFd6ofKH2EbJCFTv7BTX8TT0vNPr0y7ygqlCGXEf16y9yCIBtILtbIUpv252F9BCP5KXlXuQkM+j42rMaKOP77Y9Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767442; c=relaxed/simple; bh=XP0PNO8G/853ZISR4NFJL60BlTm8G/dA7ahDgJPTbK0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SescKbGK7b0N4gQNeegZKJPuhn1T6NNfn8xgHV5y2KPVQKIl+tuYGBFw3Aiy7M8K8Rnct0/nOcioJS2NLWi9XksiheYA81ab6HqbMH0tkPBA18wtuXW6ZLz8JL0E6khIBJJJbaXHhI4l9+aacBJ1Y1X6gdmcXJ2HhRKLrkkhYjo= 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=pvJ/aNJN; arc=none smtp.client-ip=209.85.216.50 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="pvJ/aNJN" Received: by mail-pj1-f50.google.com with SMTP id 98e67ed59e1d1-2ef6c56032eso5201335a91.2 for ; Mon, 13 Jan 2025 03:24:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767440; x=1737372240; 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=217qCdop/bVuj9XoV8EFEQ4K3BvCuSwvnN0rQfYprBA=; b=pvJ/aNJNM6hWazWxuQNk18EMYgd+DQl6rWe8maE2K6y694RoJQJS3Fw2E48J+Vh/8r 7FfGwN/ihgaV1QDaWWfp+kMOUB29dLZX0DnhwbE79I/jZUIWGyErGh5FXeoGApDnPdZK O8cWXyg838GYNaC2dHu0U0Z5FfOBlS/tWOHnmZJ2ldP+p+/+++J+rreaFfg6ttqEG/OD WTvlVw9BlK0UbpDXoY8vj7qWhMZwwzHLiU2c566Q+NBo2oVBwYH8+6r7E7HpjOMl6ezJ PfcL+tbmtlleGL3K//Qd/jhBIgzUfAKjLGz/3ILSD15hihymIWt57dWFCPmww6Br0S5U Vo4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767440; x=1737372240; 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=217qCdop/bVuj9XoV8EFEQ4K3BvCuSwvnN0rQfYprBA=; b=WPBhHUwn4bUduqovyzKnlbqK3nbzpGVnhnZZUVxfc6kmxX3vANozoK8wJ7d+xywgxN ZfkZa8XIrAJE4MyKOtlt5WvkU27tzC4yTgvTc9rRHB5QgLbQdPfkQshkl8zi5i8e1Ufi FiWnVJj1FLGiyJRpQTOMffahq0Wfh0cQL46AHzmnSOa2kiVihcuSq8K78qYpyE1mdTtc ak6liqRk3yXsWw0pk8UHH4Uk5n/yhuo6c2D80Cq25fV/Ku1/fBbMP1lRTt7s3wDI1gGf m+gtzuium0UuU4Igs0AHkLol1pqXp3a8n71fgS0NhelCFbcjxiLIrVbYUiQDYcsPXlu0 Zm5w== X-Forwarded-Encrypted: i=1; AJvYcCVlO4TBTGyY4y2FM2mABRFuf8AO/G2BsrCZatq/UgBY8BQS+iWap2MdD2kzRXNw/jfDmBZfBBEgcFggIS4=@vger.kernel.org X-Gm-Message-State: AOJu0YzCFgtUEF07fX6Iapj/BJy7yzxPTfuJ+ffoHibmu/1L5Redl+Bv gSWBpUbxo52FhlbRDiIhSzN4tkpIaobis+sdBZuncLfsMeMb2hPEn55/7fIeNgI= X-Gm-Gg: ASbGncuzruBCX6T1NtxG9Nua58ialZImlnsuQj2OYLRrGsD/kiDmF8BFOY6okYCAdKZ IfbZGh/QMf8tpjhZQyD/vf80k+YF4U0B9hljlWx/V892Dm8sqNy8b8sxpeMr0s2dXeYlwv0osbs n5u5wud54iL6jdEaWNP/BTx4c7xOZF0tuNunGCdl/55lzDX6pvoreeGvvag/ojMPnGtk0fUKZLz xFQnUI6PBouZDWHwbYVH71ybS2fCi9MO7F5Oc23yh8FSIpIWTSE3uojlaI= X-Google-Smtp-Source: AGHT+IHWlPorx8XJmvX79gE5sNkxZSUXnp+Pd6+S6Fek2hXtY7a65fTM8Lo2nmZmWQWd7i9agrQzmg== X-Received: by 2002:a17:90b:51c2:b0:2ee:ab29:1a63 with SMTP id 98e67ed59e1d1-2f548ea6331mr27577987a91.3.1736767439700; Mon, 13 Jan 2025 03:23:59 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2f53e1da400sm2352192a91.0.2025.01.13.03.23.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:23:59 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 07/16] rust: Add bare minimal bindings for clk framework Date: Mon, 13 Jan 2025 16:53:02 +0530 Message-Id: <8dd38c6dce256340a5a623503023736f8e9278d8.1736766672.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 adds very basic bindings for the clk framework, implements only clk_get() and clk_put(). These are the bare minimum bindings required for many users and are simple enough to add in the first attempt. These will be used by Rust based cpufreq / OPP core to begin with. Signed-off-by: Viresh Kumar --- rust/bindings/bindings_helper.h | 1 + rust/kernel/clk.rs | 48 +++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 3 files changed, 50 insertions(+) create mode 100644 rust/kernel/clk.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 59b4bc49d039..4eadcf645df0 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs new file mode 100644 index 000000000000..123cdb43b115 --- /dev/null +++ b/rust/kernel/clk.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Clock abstractions. +//! +//! C header: [`include/linux/clk.h`](srctree/include/linux/clk.h) + +use crate::{ + bindings, + device::Device, + error::{from_err_ptr, Result}, + prelude::*, +}; + +use core::ptr; + +/// A simple implementation of `struct clk` from the C code. +#[repr(transparent)] +pub struct Clk(*mut bindings::clk); + +impl Clk { + /// Creates `Clk` instance for a device and a connection id. + pub fn new(dev: &Device, name: Option<&CStr>) -> Result { + let con_id =3D if let Some(name) =3D name { + name.as_ptr() as *const _ + } else { + ptr::null() + }; + + // SAFETY: It is safe to call `clk_get()`, on a device pointer ear= lier received from the C + // code. + Ok(Self(from_err_ptr(unsafe { + bindings::clk_get(dev.as_raw(), con_id) + })?)) + } + + /// Obtain the raw `struct clk *`. + pub fn as_raw(&self) -> *mut bindings::clk { + self.0 + } +} + +impl Drop for Clk { + fn drop(&mut self) { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // relinquish it now. + unsafe { bindings::clk_put(self.0) }; + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 2f72e1d8a6b7..5d43dc5ec9eb 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -39,6 +39,7 @@ pub mod block; #[doc(hidden)] pub mod build_assert; +pub mod clk; pub mod cpu; pub mod cpumask; pub mod cred; --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pj1-f54.google.com (mail-pj1-f54.google.com [209.85.216.54]) (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 591502451E6 for ; Mon, 13 Jan 2025 11:24:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767446; cv=none; b=BpSQB+JJvrM9HMg9DlwWlaCX5lgs+aFM85agPxUmnNOVU3BHEAqCPYI2lfksIBXdU9yAsNBPaRj5AVqJtinpMSaxZskDASeKByPn6I+PvBayf4ZL2gPLceWDzUmRXqb2+Wi5gIprCJEu0QBCJjpiJuoTMb2pjuP53kIfm5bH10U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767446; c=relaxed/simple; bh=/uvDKCjlgOnsUH8C0V/hZTcfvjq6TTMwI45slAFmITI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=EGLbGSiB5eTxCszBX/R/HIq/jfrOd43EfvDKqCDo9h5jRez7I+oP3EWP5SC/uFiOhRZjchlDtU8KmF5DU4eVhMsGHVYNrvRhuNpXLWNMBQKzvDk62qaA2cqanth7O0b1VkH3Hd2xWc+kk0/QLfZfWpfsnNEw4Y44NQupRYLa33E= 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=QF1z3oAj; arc=none smtp.client-ip=209.85.216.54 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="QF1z3oAj" Received: by mail-pj1-f54.google.com with SMTP id 98e67ed59e1d1-2ee9a780de4so5199120a91.3 for ; Mon, 13 Jan 2025 03:24:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767444; x=1737372244; 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=8DT/35uJ0SGSGPotN/aFFV/d+f5sRADYEA7sMqJpaVQ=; b=QF1z3oAj0XoyqVhwpcx088JnPrtdqTQs/WMZLO/Ivn61R0/XhcxhBH5l8RnXMl6+Xj f6wn684JaHY/WDmL0mpyM/jFyaSP3qZt+f7GhHrfdX6gC5/EhDRGBqRMIN9XS44086DA 0LjgD7e4OzB1b71uk90dwyDKYilmJjGHebmOcPZPkhz+sUJZB860uhxN9pSn++oWWsnH Ys65Ur+usMzq5Pl6QZDrEMX0jsreQfnBaVVtG5NijLNfb/okqvu8jaFwZddqSS9gXAG0 483UF4Yq3KdDuBJgOfGj5WkU07kWqYsw475ISKqk7m3N5IyYGR6B54btGs8a6bpJRoX+ aHSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767444; x=1737372244; 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=8DT/35uJ0SGSGPotN/aFFV/d+f5sRADYEA7sMqJpaVQ=; b=Jk7V7b7uPmXrJXDdJKGHUb3uQr2J9K91y1QrPJwDhZndujPYQKxp0aMJgOKYYAZl0P QjRllvNp/n8usS0nhrhquPzWpb1oAnGrCr8CriPRA0Ttn2QJ8uubsybueZ9wvt4WeQfh XWrkZR8qmk59+suIH8eJFinJaT1pSdXerZnoscWemKZrn65bcn+AOZFKhbOhq5/1JwAb tLLIH7XeijsNPha0VJnwayoqJH79xsHv7ZNt12MPO22o0pY/pnI3hOaBnDnsxzkQvpbm vWcI0qjz/OEvKfA3ScMZsThA6HNPKl9JlGvcaM44TFMMZRW8i2QYEqHI0aXiGfbKL0mc bnrA== X-Forwarded-Encrypted: i=1; AJvYcCV+31E/rOzFDDGbiBc54U7C7mHYBmKMbjFa7cMNTn3EIESfEamcX846uEzUAjCJvxr+iRfG8a35N8fWcK4=@vger.kernel.org X-Gm-Message-State: AOJu0YzM4emb8R51aIX8N/CVbh+W1q84WDOFlodIuv7ubcRwPtjU0MSL 9y+ecwhjUhNQP8sU55QQUCC2Tdx1FgM8XZ9UkLahYRZQpisvhIiEPJuC/6wxktA= X-Gm-Gg: ASbGncsruGfVchq946oSOy9FXnnXJKA5TbgbZjOMIAkGa/eziDyN6GZNekJB2rrXsY4 chaYMwYewpfT/JBGJZM6vHKRDPeEGFiZkjJ/Yx25k+Z3gmzscY5LaSuZ9sB7tmIatTDWgL8mzFF gXw/s02jBPDrNH040buzDn2RPHoK4Au6uC3LnTUif/fQziYBLVSAeyGkxyFI2DF4ltDn6rrMGBV E6fq1GpAcPPCI699veo0NpV7OmmisqVGwFRP8u0NszpC4B2S2S6zi7YUIM= X-Google-Smtp-Source: AGHT+IGzJcomzKu3um0t7HxdPCLFlwOxE0siZO+gePGZ/L+Xri4khqzqUGXcTjLI5lYyDPnM+gaq7w== X-Received: by 2002:a17:90b:50c4:b0:2ee:d7d3:3019 with SMTP id 98e67ed59e1d1-2f548ebf4fbmr35219371a91.12.1736767443736; Mon, 13 Jan 2025 03:24:03 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21a9f219f0dsm51767265ad.139.2025.01.13.03.24.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:03 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Viresh Kumar , Nishanth Menon , Stephen Boyd Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Manos Pitsidianakis , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 08/16] rust: Add initial bindings for OPP framework Date: Mon, 13 Jan 2025 16:53:03 +0530 Message-Id: <5f3c7ac94e22c8bda51910360b399439c37babe2.1736766672.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This commit adds initial Rust bindings for the Operating performance points (OPP) core. This adds bindings for struct dev_pm_opp and struct dev_pm_opp_data to begin with. Reviewed-by: Manos Pitsidianakis Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/kernel/lib.rs | 2 + rust/kernel/opp.rs | 189 ++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 rust/kernel/opp.rs diff --git a/MAINTAINERS b/MAINTAINERS index 8ee1c013cd6e..3f9ebca78732 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17707,6 +17707,7 @@ F: Documentation/devicetree/bindings/opp/ F: Documentation/power/opp.rst F: drivers/opp/ F: include/linux/pm_opp.h +F: rust/kernel/opp.rs =20 OPL4 DRIVER M: Clemens Ladisch diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 4eadcf645df0..7f851d5907af 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 5d43dc5ec9eb..d1c0f136952e 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -62,6 +62,8 @@ #[cfg(CONFIG_NET)] pub mod net; pub mod of; +#[cfg(CONFIG_PM_OPP)] +pub mod opp; pub mod page; #[cfg(CONFIG_PCI)] pub mod pci; diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs new file mode 100644 index 000000000000..becb33880c92 --- /dev/null +++ b/rust/kernel/opp.rs @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Operating performance points. +//! +//! This module provides bindings for interacting with the OPP subsystem. +//! +//! C header: [`include/linux/pm_opp.h`](srctree/include/linux/pm_opp.h) + +use crate::{ + bindings, + device::Device, + error::{code::*, to_result, Result}, + types::{ARef, AlwaysRefCounted, Opaque}, +}; + +use core::ptr; + +/// Dynamically created Operating performance point (OPP). +pub struct Token { + dev: ARef, + freq: usize, +} + +impl Token { + /// Adds an OPP dynamically. + pub fn new(dev: &ARef, mut data: Data) -> Result { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_add_dynamic(dev.as_raw(), = &mut data.0) })?; + Ok(Self { + dev: dev.clone(), + freq: data.freq(), + }) + } +} + +impl Drop for Token { + fn drop(&mut self) { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_remove(self.dev.as_raw(), self.freq)= }; + } +} + +/// Equivalent to `struct dev_pm_opp_data` in the C Code. +#[repr(transparent)] +pub struct Data(bindings::dev_pm_opp_data); + +impl Data { + /// Creates new instance of [`Data`]. + pub fn new(freq: usize, u_volt: usize, level: u32, turbo: bool) -> Sel= f { + Self(bindings::dev_pm_opp_data { + turbo, + freq, + u_volt, + level, + }) + } + + /// Adds an OPP dynamically. The OPP is freed once the [`Token`] gets = freed. + pub fn add_opp(self, dev: &ARef) -> Result { + Token::new(dev, self) + } + + fn freq(&self) -> usize { + self.0.freq + } +} + +/// Operating performance point (OPP). +/// +/// Wraps the kernel's `struct dev_pm_opp`. +/// +/// The pointer to `struct dev_pm_opp` is non-null and valid for the lifet= ime of the `OPP` +/// instance. +/// +/// # Invariants +/// +/// Instances of this type are reference-counted. The reference count is i= ncremented by the +/// `dev_pm_opp_get()` function and decremented by `dev_pm_opp_put`. The R= ust type `ARef` +/// represents a pointer that owns a reference count on the OPP. +/// +/// A reference to the `OPP`, `&OPP` isn't refcounted by the Rust code. + +#[repr(transparent)] +pub struct OPP(Opaque); + +// SAFETY: It's OK to send the ownership of `OPP` across thread boundaries. +unsafe impl Send for OPP {} + +// SAFETY: It's OK to access `OPP` through shared references from other th= reads because we're +// either accessing properties that don't change or that are properly sync= hronised by C code. +unsafe impl Sync for OPP {} + +// SAFETY: The type invariants guarantee that [`OPP`] is always refcounted. +unsafe impl AlwaysRefCounted for OPP { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. + unsafe { bindings::dev_pm_opp_get(self.0.get()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is = nonzero. + unsafe { bindings::dev_pm_opp_put(obj.cast().as_ptr()) } + } +} + +impl OPP { + /// Creates an owned reference to a [`OPP`] from a valid pointer. + /// + /// The refcount is incremented by the C code and will be decremented = by `dec_ref()` when the + /// ARef object is dropped. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and the OPP's refcount = is incremented. The + /// caller must also ensure that it doesn't explicitly drop the refcou= nt of the OPP, as the + /// returned ARef object takes over the refcount increment on the unde= rlying object and the + /// same will be dropped along with it. + pub unsafe fn from_raw_opp_owned(ptr: *mut bindings::dev_pm_opp) -> Re= sult> { + let ptr =3D ptr::NonNull::new(ptr).ok_or(ENODEV)?; + + // SAFETY: The safety requirements guarantee the validity of the p= ointer. + Ok(unsafe { ARef::from_raw(ptr.cast()) }) + } + + /// Creates a reference to a [`OPP`] from a valid pointer. + /// + /// The refcount is not updated by the Rust API unless the returned re= ference is converted to + /// an ARef object. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and remains valid for t= he duration of 'a. + pub unsafe fn from_raw_opp<'a>(ptr: *mut bindings::dev_pm_opp) -> Resu= lt<&'a Self> { + // SAFETY: The caller guarantees that the pointer is not dangling = and stays valid for the + // duration of 'a. The cast is okay because `OPP` is `repr(transpa= rent)`. + Ok(unsafe { &*ptr.cast() }) + } + + #[inline] + fn as_raw(&self) -> *mut bindings::dev_pm_opp { + self.0.get() + } + + /// Returns the frequency of an OPP. + pub fn freq(&self, index: Option) -> usize { + let index =3D index.unwrap_or(0); + + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_freq_indexed(self.as_raw(), inde= x) } + } + + /// Returns the voltage of an OPP. + pub fn voltage(&self) -> usize { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_voltage(self.as_raw()) } + } + + /// Returns the level of an OPP. + pub fn level(&self) -> u32 { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_level(self.as_raw()) } + } + + /// Returns the power of an OPP. + pub fn power(&self) -> usize { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_power(self.as_raw()) } + } + + /// Returns the required pstate of an OPP. + pub fn required_pstate(&self, index: u32) -> u32 { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_get_required_pstate(self.as_raw(), i= ndex) } + } + + /// Returns true if the OPP is turbo. + pub fn is_turbo(&self) -> bool { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it. + unsafe { bindings::dev_pm_opp_is_turbo(self.as_raw()) } + } +} --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D173284A5A for ; Mon, 13 Jan 2025 11:24:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767450; cv=none; b=ds+pNy8wNqAB517ACM5bgLIr8E+9ffk/OKrw7673TtJzrrbO70EyrPngIw/kIKNvWkul0plrz1/mUZvOkVhahLM7pYkhbiydcfzzWEp9WjRQc2te2K4GksRXmsDOU3ntB68bLER564+Z3QBjqpKc88GnghX1y44xokpGSqBPWmA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767450; c=relaxed/simple; bh=vsHZhCkGhVZ0mCcuXZBy4kwTUYm334wXEh9JY7v2xKM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=TGJV5k/EljTaauX4LboiLkQOwGY3Jnn72G0SGfzwaNULoL4N2k2CyPcXHdFFKbYxStsWT3xP1Bv30Ge4poAAvvCATdOEwYRVkgRkcTanOaG8LMeBqPDboSIRXjtVEhVTFFa/GA9QrYsa5M+N8J1az2NnzoiVw1kRw3/RCwXa44o= 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=aK7H+I3X; arc=none smtp.client-ip=209.85.214.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="aK7H+I3X" Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-2164b1f05caso70057045ad.3 for ; Mon, 13 Jan 2025 03:24:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767447; x=1737372247; 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=ftCsOZitCmeRyVqQ2YCyIstFqWVeJbqxa6tUfw80DGc=; b=aK7H+I3XSJIYjWTOhYlYUF14mytD/0g6c6C83Z1I21/HwWolexuSGPO8P2Cl0xK4kb 12/JCKtsoMvlHK/q79HYJMIpwfj9OLKr3N4CzjKmFyvNb7YBhiUvgpTzK0pZbQqVI83L DSt7e++8qrLwDlPiIEW1KicX+zbXiD+7qEMaFO8tQwCYkVrxZZjmapNlsnQ3zTpd+t3G Hq2VNGzYAugMjNsqS4aDr7zMfsmdk9gNBtN2M6Cfz5XrGZVryDyAYuYwAbNzlSgxf3Il l2z17ymr5bNds2M2y3AbAMfX6Mc3GLL9Gw8H5F9tPEHmxsdkOFyl8js8MrSnvUuVWAI3 ir0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767447; x=1737372247; 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=ftCsOZitCmeRyVqQ2YCyIstFqWVeJbqxa6tUfw80DGc=; b=ObACo4TOSg+gDy1t1ZNV/A6CeUA7lKyZaLIukE2Bdxc1zwUuxHq2HYs1rXdjp5yfJy tHP2TbPnTdRfZVqAzlB3hzOm8F6c9in5EDpKRUUAIF9qrU09B6y6ORu0Hij9ivnI7bbh l+zLgma5G6Y4nC/Q6s0bPtUoWB8zEFl4+dbAWz6ZM1aFIvuPGU/6bQXF9meUeXHCiN+7 NwDOXpRGx2UVQz6A3dKd+7gq1QsTs4ydYGvaikI4nLFOcDVN/7+0RSy+e4ScA7ip3zTa AUe+rz1znRiTfczoQ8XYxfiN56danIBU6nAf06SsP9RpAoWrnJN2rwiyOY5rsC98D8Bb 7JDQ== X-Forwarded-Encrypted: i=1; AJvYcCWcnTm5OXEVrUnSzCXWtBTBsPvR8rJsCnPJraePSX04lyL4U/ITvGeix9fRy0f0TVE8aYfTj42dROMNzXY=@vger.kernel.org X-Gm-Message-State: AOJu0YzbdssOIag08UV7xGwYlwIA5Jay3qKodcgNoQp9VNc03FuwN94s IZpoILhTcpElP3f25tU7YEj383hMZNgYulUC0p7TPgoi0m3CuqvsFy//6a5pbZM= X-Gm-Gg: ASbGncuMT0zXJ4uPNYsFa9fOIz+NWjs3Dt63Vp1O3AJolzmIvp5sDpEXmj67HXbYQ1l oAe3LElmiC5KwOH76srPQtKlW3R/8BNZLg7TDRXFsk32dC5RJOgxor6bBtUULWfVAgM7IDUBm9s cyAyyepoLgOxintED+7Lrd11xcoVANVYIy2AaGCbxuCngQuV79Y1kEjg/4wZfOBVRGwInaZ2GP7 w8rRqwwfRQZvpDGWiYlivm1nXZfPxG/39WdFH78Kghge1jr77Zf7wdScaM= X-Google-Smtp-Source: AGHT+IHmleW8WQsIyr/tT0LTvcZCq3ZUva4QmBy1v6QT3fROfylP0efo3dalrM+odvmOPxjpmdrwUA== X-Received: by 2002:a05:6a00:22c7:b0:725:c8ea:b320 with SMTP id d2e1a72fcca58-72d21feb16fmr26578518b3a.14.1736767447288; Mon, 13 Jan 2025 03:24:07 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72d40658b64sm5760219b3a.109.2025.01.13.03.24.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:06 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Nishanth Menon , Stephen Boyd , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH V7 09/16] rust: Extend OPP bindings for the OPP table Date: Mon, 13 Jan 2025 16:53:04 +0530 Message-Id: <6ee4476b61fba69b879b98f69668dfe0b993821a.1736766672.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This extends OPP bindings with the bindings for the struct opp_table. Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 383 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 382 insertions(+), 1 deletion(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index becb33880c92..d3b98d9a554e 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -8,8 +8,9 @@ =20 use crate::{ bindings, + cpumask::Cpumask, device::Device, - error::{code::*, to_result, Result}, + error::{code::*, from_err_ptr, to_result, Error, Result}, types::{ARef, AlwaysRefCounted, Opaque}, }; =20 @@ -67,6 +68,386 @@ fn freq(&self) -> usize { } } =20 +/// OPP search types. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum SearchType { + /// Search for exact value. + Exact, + /// Search for highest value less than equal to value. + Floor, + /// Search for lowest value greater than equal to value. + Ceil, +} + +/// Operating performance point (OPP) table. +/// +/// Wraps the kernel's `struct opp_table`. +/// +/// The pointer stored in `Self` is non-null and valid for the lifetime of= the `Table`. +pub struct Table { + ptr: *mut bindings::opp_table, + dev: ARef, + em: bool, + of: bool, + cpumask: Option, +} + +// SAFETY: It is okay to send ownership of `Table` across thread boundarie= s. +unsafe impl Send for Table {} + +// SAFETY: It's OK to access `Table` through shared references from other = threads because we're +// either accessing properties that don't change or that are properly sync= hronised by C code. +unsafe impl Sync for Table {} + +impl Table { + /// Creates a new OPP table instance from raw pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid and non-null. + unsafe fn from_raw_table(ptr: *mut bindings::opp_table, dev: &ARef) -> Self { + // SAFETY: By the safety requirements, ptr is valid and its refcou= nt will be incremented. + unsafe { bindings::dev_pm_opp_get_opp_table_ref(ptr) }; + + Self { + ptr, + dev: dev.clone(), + em: false, + of: false, + cpumask: None, + } + } + + /// Find OPP table from device. + pub fn from_dev(dev: &Device) -> Result { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. Refcount of the OPP table is incremented by the C= code. + let ptr =3D from_err_ptr(unsafe { bindings::dev_pm_opp_get_opp_tab= le(dev.as_raw()) })?; + + Ok(Self { + ptr, + dev: dev.into(), + em: false, + of: false, + cpumask: None, + }) + } + + /// Add device tree based OPP table for the device. + #[cfg(CONFIG_OF)] + pub fn from_of(dev: &ARef, index: i32) -> Result { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. Refcount of the OPP table is incremented by the C= code. + to_result(unsafe { bindings::dev_pm_opp_of_add_table_indexed(dev.a= s_raw(), index) })?; + + // Fetch the newly created table. + let mut table =3D Self::from_dev(dev)?; + table.of =3D true; + + Ok(table) + } + + // Remove device tree based OPP table for the device. + #[cfg(CONFIG_OF)] + fn remove_of(&self) { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. We took the reference earlier from `from_of` earl= ier, it is safe to drop + // the same now. + unsafe { bindings::dev_pm_opp_of_remove_table(self.dev.as_raw()) }; + } + + /// Add device tree based OPP table for CPU devices. + #[cfg(CONFIG_OF)] + pub fn from_of_cpumask(dev: &Device, cpumask: &mut Cpumask) -> Result<= Self> { + // SAFETY: The cpumask is valid and the returned ptr will be owned= by the [`Table`] instance. + to_result(unsafe { bindings::dev_pm_opp_of_cpumask_add_table(cpuma= sk.as_raw()) })?; + + // Fetch the newly created table. + let mut table =3D Self::from_dev(dev)?; + + let mut mask =3D Cpumask::new()?; + cpumask.copy(&mut mask); + table.cpumask =3D Some(mask); + + Ok(table) + } + + // Remove device tree based OPP table for CPU devices. + #[cfg(CONFIG_OF)] + fn remove_of_cpumask(&self, mut cpumask: Cpumask) { + // SAFETY: The cpumask is valid and we took the reference from `fr= om_of_cpumask` earlier, + // it is safe to drop the same now. + unsafe { bindings::dev_pm_opp_of_cpumask_remove_table(cpumask.as_r= aw()) }; + } + + /// Returns the number of OPPs in the table. + pub fn opp_count(&self) -> Result { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + let ret =3D unsafe { bindings::dev_pm_opp_get_opp_count(self.dev.a= s_raw()) }; + if ret < 0 { + Err(Error::from_errno(ret)) + } else { + Ok(ret as u32) + } + } + + /// Returns max clock latency of the OPPs in the table. + pub fn max_clock_latency(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_clock_latency(self.dev.as_ra= w()) } + } + + /// Returns max volt latency of the OPPs in the table. + pub fn max_volt_latency(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_volt_latency(self.dev.as_raw= ()) } + } + + /// Returns max transition latency of the OPPs in the table. + pub fn max_transition_latency(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_max_transition_latency(self.dev.= as_raw()) } + } + + /// Returns the suspend OPP. + pub fn suspend_freq(&self) -> usize { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_get_suspend_opp_freq(self.dev.as_raw= ()) } + } + + /// Synchronizes regulators used by the OPP table. + pub fn sync_regulators(&self) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_sync_regulators(self.dev.a= s_raw()) }) + } + + /// Gets sharing CPUs. + pub fn sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result<()>= { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_get_sharing_cpus(dev.as_raw(), cpumask.as= _raw()) + }) + } + + /// Sets sharing CPUs. + pub fn set_sharing_cpus(&mut self, cpumask: &mut Cpumask) -> Result<()= > { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_set_sharing_cpus(self.dev.as_raw(), cpuma= sk.as_raw()) + })?; + + if let Some(mask) =3D self.cpumask.as_mut() { + // Update the cpumask as this will be used while removing the = table. + cpumask.copy(mask); + } + + Ok(()) + } + + /// Gets sharing CPUs from Device tree. + #[cfg(CONFIG_OF)] + pub fn of_sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result<= ()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_of_get_sharing_cpus(dev.as_raw(), cpumask= .as_raw()) + }) + } + + /// Updates the voltage value for an OPP. + pub fn adjust_voltage( + &self, + freq: usize, + u_volt: usize, + u_volt_min: usize, + u_volt_max: usize, + ) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_adjust_voltage( + self.dev.as_raw(), + freq, + u_volt, + u_volt_min, + u_volt_max, + ) + }) + } + + /// Sets a matching OPP based on frequency. + pub fn set_rate(&self, freq: usize) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_set_rate(self.dev.as_raw()= , freq) }) + } + + /// Sets exact OPP. + pub fn set_opp(&self, opp: &OPP) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_set_opp(self.dev.as_raw(),= opp.as_raw()) }) + } + + /// Finds OPP based on frequency. + pub fn opp_from_freq( + &self, + mut freq: usize, + available: Option, + index: Option, + stype: SearchType, + ) -> Result> { + let rdev =3D self.dev.as_raw(); + let index =3D index.unwrap_or(0); + + let ptr =3D from_err_ptr(match stype { + SearchType::Exact =3D> { + if let Some(available) =3D available { + // SAFETY: The requirements are satisfied by the exist= ence of `Device` and + // its safety requirements. The returned ptr will be o= wned by the new [`OPP`] + // instance. + unsafe { + bindings::dev_pm_opp_find_freq_exact_indexed(rdev,= freq, index, available) + } + } else { + return Err(EINVAL); + } + } + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_freq_ceil_indexed(rdev, &mut fre= q as *mut usize, index) + }, + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_freq_floor_indexed(rdev, &mut fr= eq as *mut usize, index) + }, + })?; + + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp_owned(ptr) } + } + + /// Finds OPP based on level. + pub fn opp_from_level(&self, mut level: u32, stype: SearchType) -> Res= ult> { + let rdev =3D self.dev.as_raw(); + + let ptr =3D from_err_ptr(match stype { + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Exact =3D> unsafe { bindings::dev_pm_opp_find_leve= l_exact(rdev, level) }, + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_level_ceil(rdev, &mut level as *= mut u32) + }, + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_level_floor(rdev, &mut level as = *mut u32) + }, + })?; + + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp_owned(ptr) } + } + + /// Finds OPP based on bandwidth. + pub fn opp_from_bw(&self, mut bw: u32, index: i32, stype: SearchType) = -> Result> { + let rdev =3D self.dev.as_raw(); + + let ptr =3D from_err_ptr(match stype { + // The OPP core doesn't support this yet. + SearchType::Exact =3D> return Err(EINVAL), + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Ceil =3D> unsafe { + bindings::dev_pm_opp_find_bw_ceil(rdev, &mut bw as *mut u3= 2, index) + }, + + // SAFETY: The requirements are satisfied by the existence of = `Device` and its + // safety requirements. The returned ptr will be owned by the = new [`OPP`] instance. + SearchType::Floor =3D> unsafe { + bindings::dev_pm_opp_find_bw_floor(rdev, &mut bw as *mut u= 32, index) + }, + })?; + + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp_owned(ptr) } + } + + /// Enable the OPP. + pub fn enable_opp(&self, freq: usize) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_enable(self.dev.as_raw(), = freq) }) + } + + /// Disable the OPP. + pub fn disable_opp(&self, freq: usize) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { bindings::dev_pm_opp_disable(self.dev.as_raw(),= freq) }) + } + + /// Registers with Energy model. + #[cfg(CONFIG_OF)] + pub fn of_register_em(&mut self, cpumask: &mut Cpumask) -> Result<()> { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_of_register_em(self.dev.as_raw(), cpumask= .as_raw()) + })?; + + self.em =3D true; + Ok(()) + } + + // Unregisters with Energy model. + #[cfg(all(CONFIG_OF, CONFIG_ENERGY_MODEL))] + fn of_unregister_em(&self) { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. We registered with the EM framework earlier, it i= s safe to unregister now. + unsafe { bindings::em_dev_unregister_perf_domain(self.dev.as_raw()= ) }; + } +} + +impl Drop for Table { + fn drop(&mut self) { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe + // to relinquish it now. + unsafe { bindings::dev_pm_opp_put_opp_table(self.ptr) }; + + #[cfg(CONFIG_OF)] + { + #[cfg(CONFIG_ENERGY_MODEL)] + if self.em { + self.of_unregister_em(); + } + + if self.of { + self.remove_of(); + } else if let Some(cpumask) =3D self.cpumask.take() { + self.remove_of_cpumask(cpumask); + } + } + } +} + /// Operating performance point (OPP). /// /// Wraps the kernel's `struct dev_pm_opp`. --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 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 75E683DABE1 for ; Mon, 13 Jan 2025 11:24:11 +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=1736767454; cv=none; b=LgmuVo3pTIiAw14t/gC7VD8Wu/E0mMqynKbq1ufpYVxDN2hqKZnegSM/DHssf4cnA5r2h5+GXdmP2+ZyThqASxnctQKjdE3cwEVwv2S7L/4teo/uGvr8oSAE1uZr2UWE5i6i3FbZLflbh3uZO9CYihxHoCu8rZEyC6ioUXlABZQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767454; c=relaxed/simple; bh=HvTNnupc2EFRJvcBV6gbrEBwWsZdiLH3T39OSFYdg68=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Vpcum3WJJM6LIjSXzqV7z/6Z3+OIprP6wz71npwn0//fzQIRUuf4PmxtMGOGCrSlNMlzPpvBsvl7uo9MxEogmHAr46W7IXcKpQbUL+jD76bWhDjI3tNVs2WyOYaFpHegBJVwOFwQFsr2Jal234EjzZAeOhDXMt3reALAjzoSxNU= 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=NHbLdA3c; 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="NHbLdA3c" Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-216395e151bso49340435ad.0 for ; Mon, 13 Jan 2025 03:24:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767451; x=1737372251; 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=IWWPIaDzJ6TtRNiPxhkMnMASI1Go/QPlOZW3kN1s+RM=; b=NHbLdA3cgyTxTgaphjxzRMtfE5z3gmd9sPuaGPLF4X7qS0gvbKC33NZTzPGNoC8PeH Rmncp3evwKAcO1y5WhDpUzBAIKu3+lKy+sTDz5lbhisFY5XookJA/n0MOb4MXRGklGrc bG4dip1U4vguIN+0n+X0m5RBlGrHxDCR3yFFXrQhjkC10sSv+MOQyZ+erxmoD10Lv/X8 4FpPhhHgnrvU/lVFUV5npWW36Sj4c9U4Rt7dAS5r/WyBsF0tAOCvLvCUqeB+bEo7jwoD VqTVmuk9uTaRbAFZbzvJaMPOnA8cBfo3m3Nc/ihe+dlJt3ji1viic7bdc/KQ6LBkvBEH nczw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767451; x=1737372251; 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=IWWPIaDzJ6TtRNiPxhkMnMASI1Go/QPlOZW3kN1s+RM=; b=MY/OzgGBMvjdq6dNDrK8cLZK6cgpznq0zKzIZmW2hjJPj9Wfb3Zw7Br1KDQpRW21Dk tJLaNScaNfgJL+eyjZf9E6j5v8hcHSE0DZlskKS8GwfRknN25sllrrUOabwSS3Ma6uHl 56b+YrvQqXdmE02YVtNGZCdkGtFqxZAzAmsf9hZra6NS/XPNSVaEYGIr8mGo5Pfb7Eb3 FoVZKhsLeW4xFJZV7p6BdVv4rvYg3BNTyYhzA6LdnYkYDOjkT1i4z+IZPEOTGiqg+qPw Ui+bDQ544weKlT6Ivi3gyG9ETQ0WCgkztZg2XAlLu1P9mWT6tDbMlqWK9GmX39Q7HnR2 m12g== X-Forwarded-Encrypted: i=1; AJvYcCVw+EBPbRThDeaDkp0v3wDkzVpq2TDUNWBWAZX1d8//ZVrlBtIkiqeY4P6A4dEEUvggSWNs9K+GDqxPCF0=@vger.kernel.org X-Gm-Message-State: AOJu0YzdRWVSFvLv2gVKafANSSzcbuPmDkoPq/3agLJT+n2tjWXxLD+j 482rto2TsF9366+o0g46FcWS8s4uurQ1kAa2RXlaoU33vkUp+ajuQFDvrGSU/YY= X-Gm-Gg: ASbGncssfn+RBLosIpBghA8hWq/OmceLzXtbHf1bjkPnvuvORF/+h13T292nG6As9/k Bj8BdhOMQe1+WUWSVLDJbblhb7ik23nF3hwax9F200szPMjYrM8a9rvO3hUcHcLQnvnDNRap/2D KZAtEVBWJXCtuNrYl9ttED4ltCalWjCfeZl5+ZyyB0zPkLd6gYakcnhfQjMl6qF2GwMTyr0Qh7X B5kxRqJWjz8w6UU7kotBSzBknnfH+LMcsqkzgDGJvucoDyA9Rdrmcp2fKw= X-Google-Smtp-Source: AGHT+IGiyKcuVgM1Ys0i/tuRnV6jvK7jW7PsJedRIoMQWDTCXNoVpynGn0EranSE4BEcCImlbEEWdg== X-Received: by 2002:a17:903:4084:b0:215:8fd3:d1b6 with SMTP id d9443c01a7336-21ae88b9d14mr109464815ad.23.1736767450746; Mon, 13 Jan 2025 03:24:10 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21a9f138854sm52030505ad.96.2025.01.13.03.24.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:10 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Nishanth Menon , Stephen Boyd , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , Manos Pitsidianakis , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH V7 10/16] rust: Extend OPP bindings for the configuration options Date: Mon, 13 Jan 2025 16:53:05 +0530 Message-Id: <6a493402c7f856d2e0a9d7d1d296669e4b6a7010.1736766672.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This extends OPP bindings with the bindings for the OPP core configuration options. Reviewed-by: Manos Pitsidianakis Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 262 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 2 deletions(-) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index d3b98d9a554e..22c4d543f456 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -10,11 +10,28 @@ bindings, cpumask::Cpumask, device::Device, - error::{code::*, from_err_ptr, to_result, Error, Result}, + error::{code::*, from_err_ptr, from_result, to_result, Error, Result, = VTABLE_DEFAULT_ERROR}, + prelude::*, + str::CString, types::{ARef, AlwaysRefCounted, Opaque}, }; =20 -use core::ptr; +use core::{marker::PhantomData, ptr}; + +use macros::vtable; + +// Creates a null-terminated slice of pointers to Cstrings. +fn to_c_str_array(names: &[CString]) -> Result> { + // Allocated a null-terminated vector of pointers. + let mut list =3D KVec::with_capacity(names.len() + 1, GFP_KERNEL)?; + + for name in names.iter() { + list.push(name.as_ptr() as _, GFP_KERNEL)?; + } + + list.push(ptr::null(), GFP_KERNEL)?; + Ok(list) +} =20 /// Dynamically created Operating performance point (OPP). pub struct Token { @@ -79,6 +96,247 @@ pub enum SearchType { Ceil, } =20 +/// Implement this trait to provide OPP Configuration callbacks. +#[vtable] +pub trait ConfigOps { + /// Called by the OPP core to configure OPP clks. + fn config_clks(_dev: &Device, _table: &Table, _opp: &OPP, _scaling_dow= n: bool) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Called by the OPP core to configure OPP regulators. + fn config_regulators( + _dev: &Device, + _opp_old: &OPP, + _opp_new: &OPP, + _data: *mut *mut bindings::regulator, + _count: u32, + ) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } +} + +/// Config token returned by the C code. +pub struct ConfigToken(i32); + +impl Drop for ConfigToken { + fn drop(&mut self) { + // SAFETY: Its safe to return the configuration token number previ= ously received from the C + // code. + unsafe { bindings::dev_pm_opp_clear_config(self.0) }; + } +} + +/// Equivalent to `struct dev_pm_opp_config` in the C Code. +#[derive(Default)] +pub struct Config { + clk_names: Option>, + prop_name: Option, + regulator_names: Option>, + supported_hw: Option>, + required_dev: Option>, + required_dev_index: Option, + _data: PhantomData, +} + +impl Config { + /// Creates a new instance of [`Config`]. + pub fn new() -> Self { + Self { + clk_names: None, + prop_name: None, + regulator_names: None, + supported_hw: None, + required_dev: None, + required_dev_index: None, + _data: PhantomData, + } + } + + /// Initializes clock names. + pub fn set_clk_names(mut self, names: KVec) -> Result { + // Already configured. + if self.clk_names.is_some() { + return Err(EBUSY); + } + + if names.is_empty() { + return Err(EINVAL); + } + + self.clk_names =3D Some(names); + Ok(self) + } + + /// Initializes property name. + pub fn set_prop_name(mut self, name: CString) -> Result { + // Already configured. + if self.prop_name.is_some() { + return Err(EBUSY); + } + + self.prop_name =3D Some(name); + Ok(self) + } + + /// Initializes regulator names. + pub fn set_regulator_names(mut self, names: KVec) -> Result { + // Already configured. + if self.regulator_names.is_some() { + return Err(EBUSY); + } + + if names.is_empty() { + return Err(EINVAL); + } + + self.regulator_names =3D Some(names); + + Ok(self) + } + + /// Initializes required devices. + pub fn set_required_dev(mut self, dev: ARef, index: u32) -> Re= sult { + // Already configured. + if self.required_dev.is_some() { + return Err(EBUSY); + } + + self.required_dev =3D Some(dev); + self.required_dev_index =3D Some(index); + Ok(self) + } + + /// Initializes supported hardware. + pub fn set_supported_hw(mut self, hw: KVec) -> Result { + // Already configured. + if self.supported_hw.is_some() { + return Err(EBUSY); + } + + if hw.is_empty() { + return Err(EINVAL); + } + + self.supported_hw =3D Some(hw); + Ok(self) + } + + /// Sets the configuration with the OPP core. + pub fn set(self, dev: &Device) -> Result { + let (_clk_list, clk_names) =3D match &self.clk_names { + Some(x) =3D> { + let list =3D to_c_str_array(x)?; + let ptr =3D list.as_ptr(); + (Some(list), ptr) + } + None =3D> (None, ptr::null()), + }; + + let (_regulator_list, regulator_names) =3D match &self.regulator_n= ames { + Some(x) =3D> { + let list =3D to_c_str_array(x)?; + let ptr =3D list.as_ptr(); + (Some(list), ptr) + } + None =3D> (None, ptr::null()), + }; + + let prop_name =3D match &self.prop_name { + Some(x) =3D> x.as_char_ptr(), + None =3D> ptr::null(), + }; + + let (supported_hw, supported_hw_count) =3D match &self.supported_h= w { + Some(x) =3D> (x.as_ptr(), x.len() as u32), + None =3D> (ptr::null(), 0), + }; + + let (required_dev, required_dev_index) =3D match &self.required_de= v { + Some(x) =3D> (x.as_raw(), self.required_dev_index.unwrap()), + None =3D> (ptr::null_mut(), 0), + }; + + let mut config =3D bindings::dev_pm_opp_config { + clk_names, + config_clks: if T::HAS_CONFIG_CLKS { + Some(Self::config_clks) + } else { + None + }, + prop_name, + regulator_names, + config_regulators: if T::HAS_CONFIG_REGULATORS { + Some(Self::config_regulators) + } else { + None + }, + supported_hw, + supported_hw_count, + + required_dev, + required_dev_index, + }; + + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. The OPP core guarantees to not use fields of `con= fig`, after this call has + // returned and so we don't need to save a copy of them for future= use + let ret =3D unsafe { bindings::dev_pm_opp_set_config(dev.as_raw(),= &mut config) }; + if ret < 0 { + Err(Error::from_errno(ret)) + } else { + Ok(ConfigToken(ret)) + } + } + + // Config's config_clks callback. + extern "C" fn config_clks( + dev: *mut bindings::device, + opp_table: *mut bindings::opp_table, + opp: *mut bindings::dev_pm_opp, + _data: *mut core::ffi::c_void, + scaling_down: bool, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: 'dev' is guaranteed by the C code to be valid. + let dev =3D unsafe { Device::get_device(dev) }; + T::config_clks( + &dev, + // SAFETY: 'opp_table' is guaranteed by the C code to be v= alid. + &unsafe { Table::from_raw_table(opp_table, &dev) }, + // SAFETY: 'opp' is guaranteed by the C code to be valid. + unsafe { OPP::from_raw_opp(opp)? }, + scaling_down, + ) + .map(|()| 0) + }) + } + + // Config's config_regulators callback. + extern "C" fn config_regulators( + dev: *mut bindings::device, + old_opp: *mut bindings::dev_pm_opp, + new_opp: *mut bindings::dev_pm_opp, + regulators: *mut *mut bindings::regulator, + count: core::ffi::c_uint, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: 'dev' is guaranteed by the C code to be valid. + let dev =3D unsafe { Device::get_device(dev) }; + T::config_regulators( + &dev, + // SAFETY: 'old_opp' is guaranteed by the C code to be val= id. + unsafe { OPP::from_raw_opp(old_opp)? }, + // SAFETY: 'new_opp' is guaranteed by the C code to be val= id. + unsafe { OPP::from_raw_opp(new_opp)? }, + regulators, + count, + ) + .map(|()| 0) + }) + } +} + /// Operating performance point (OPP) table. /// /// Wraps the kernel's `struct opp_table`. --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pj1-f47.google.com (mail-pj1-f47.google.com [209.85.216.47]) (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 EC60F3DAC12 for ; Mon, 13 Jan 2025 11:24:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767460; cv=none; b=E9sK3VExxvT1PJpIVo3hCmbXuIPrecV8MeLKEqQ9/a6v+hQiSHRn1KciPtCqiupMGNqgYHLnXMXiB+ofTHWJbxg07wgaS76lZ6OFrt+t2QvPkg22XBayzv78BzX6Lmf5+N+GSEgBe6Mf7WpA1gG7J/dDnXvokaNVIHrd/MqdPRY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767460; c=relaxed/simple; bh=2JkhyINaywtfILSPDjQ4c4dGWRyIRBju4YSZ0W0gffU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Z5vQpPCObVKYkfrNed07AtKhV6ZWMwjDabGGrPZvYv+7EQHEJiCpgLSevGmxZGDaVbW3Wm4zoix8V+cclsa2nAv++jsmW0IXtEPb40qTBPF8PNIxuFX1CaK0DqgClsP8CtobwjEd8fYm6in1gU5H8HcNKuqnZ5mEQS/LNJv/vd0= 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=po6Qqddr; arc=none smtp.client-ip=209.85.216.47 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="po6Qqddr" Received: by mail-pj1-f47.google.com with SMTP id 98e67ed59e1d1-2efd81c7ca4so5481411a91.2 for ; Mon, 13 Jan 2025 03:24:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767456; x=1737372256; 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=WwzrLAB8Dxug2z6b+uwUwN8Azj70Ar3EfIfvsIBOHtw=; b=po6Qqddr7BEQ67aYfi8OPjevKVpkOAO/k60U7UdGykICPo+8cyiJZo9tqyEoLKqtv1 3wIHbdP6GLQRKr9FXaqsi6kHxWgZ97bH25/vAUGq8rg3hq/qqD1kx/3mqXPhIXoMgpLx ePcjBHU99kSBQxvfjW3uxb3C3eTMSzbH4d0MvOyuSa5xJDimGpCsjsCJf+/O/D00xp/n GmjGa0fpSCBXBdNJLkzd/G03hkOirGU7P5rOaUkbl4z4FFvaNv5i8VIn222uy0j/j2VQ uRcns0W86aVS03RLF44atOJ67v7y2QUMtHSMPFhgYlQm0nLyoKjEHSEBX5T8kZ1klF0h cGcQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767456; x=1737372256; 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=WwzrLAB8Dxug2z6b+uwUwN8Azj70Ar3EfIfvsIBOHtw=; b=DlR5R6jB565f8iEAAXTCAr3nROUuykYjpHsGqFWp+56ktSM8QmJpNWvbOth2OWa1hZ Kp+zw3r/RzAmY4LB8dppyhKzzIVMKVakdIBo761pTS4lKjjLL/mfF0xRXX104ucDVvjq Vbudl/i6iqUFnLrFqXYIY2YrS/niAzMM1xb3k2hMJemMhDiAYGSRbH/fShybyUMcBjFt 60iluQvPrdGrW9Ni4bJpxzydhXZz6fls8cdTKvA/wR4lx5v8sQeIBPWum9lc3MTR030g LM9DLBILDWOXCIyDw9ZodZfo3zIhMT06IHd0NDfp+IRZV6DJYlkfwMPpydzntnCCl1Ft kgGQ== X-Forwarded-Encrypted: i=1; AJvYcCVwNict7MjFfMsnLvbzeB5TL9oxY+c4R2jSTl5QhJjuQSRnSvqLAXhbpAIQ1wcT6T4Q8FhC9gXUfhfGijE=@vger.kernel.org X-Gm-Message-State: AOJu0YzxcQyR3zuhqTYeThlKB9kO12X20SkZYzzyLirbwj3gFHu6l5Lw bKtwtw3DvDhiASJuA2nvzRLS9GERMdPTjczj3eO0Xkoxd6rv9e+KeXH4IC5E5Uo= X-Gm-Gg: ASbGnctvhoyYKz0USDlLLF2fNRPTRed3BT+M82a5oPDJcUeCnJ3Dsv/2Js+4sI2R9r0 Oyk+qHdGUwPG94KLrzktA4O2ML8SpeybicqD3BtXcm/CkpjX4UU5YdE9WVvhprPizIsp2SdifcW YlUamma+E0VMwDCCxvt+h1JklrV4HuDJXO/NzfmSBy5vDiHuILqlKDtfvhiRthyQdBlR9n0swZr 0j9qH+6DdFvMwaqRu4mlmR3Z/ZyPwUEyS6AN/RvprNeZ25VhSEsanowEtc= X-Google-Smtp-Source: AGHT+IGSrjWAXG/i1/fxPFQSZ8SgGH6S3WwvH2xeaVLAPlcZxWEtSTFord1i+91CODMVAveRLw497A== X-Received: by 2002:a17:90b:5208:b0:2ef:33a4:ae6e with SMTP id 98e67ed59e1d1-2f548eba9c4mr35243647a91.12.1736767456231; Mon, 13 Jan 2025 03:24:16 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2f53e1d3bd0sm7704068a91.0.2025.01.13.03.24.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:15 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Viresh Kumar Cc: linux-pm@vger.kernel.org, Vincent Guittot , Manos Pitsidianakis , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 11/16] rust: Add initial bindings for cpufreq framework Date: Mon, 13 Jan 2025 16:53:06 +0530 Message-Id: <535b9af357a3e6735bd5543d4cb56e632ba80697.1736766672.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This commit adds initial Rust bindings for the cpufreq core. This adds basic bindings for cpufreq flags, relations and cpufreq table. Reviewed-by: Manos Pitsidianakis Signed-off-by: Viresh Kumar --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/helpers/cpufreq.c | 10 ++ rust/helpers/helpers.c | 1 + rust/kernel/cpufreq.rs | 231 ++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 6 files changed, 246 insertions(+) create mode 100644 rust/helpers/cpufreq.c create mode 100644 rust/kernel/cpufreq.rs diff --git a/MAINTAINERS b/MAINTAINERS index 3f9ebca78732..fb92356efbba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6017,6 +6017,7 @@ F: drivers/cpufreq/ F: include/linux/cpufreq.h F: include/linux/sched/cpufreq.h F: kernel/sched/cpufreq*.c +F: rust/kernel/cpufreq.rs F: tools/testing/selftests/cpufreq/ =20 CPU HOTPLUG diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 7f851d5907af..68bf1bc5bae8 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/cpufreq.c b/rust/helpers/cpufreq.c new file mode 100644 index 000000000000..7c1343c4d65e --- /dev/null +++ b/rust/helpers/cpufreq.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#ifdef CONFIG_CPU_FREQ +void rust_helper_cpufreq_register_em_with_opp(struct cpufreq_policy *polic= y) +{ + cpufreq_register_em_with_opp(policy); +} +#endif diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index de2341cfd917..32d0462219e5 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -11,6 +11,7 @@ #include "bug.c" #include "build_assert.c" #include "build_bug.c" +#include "cpufreq.c" #include "cpumask.c" #include "cred.c" #include "device.c" diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs new file mode 100644 index 000000000000..3dfdf5ccb9b8 --- /dev/null +++ b/rust/kernel/cpufreq.rs @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! CPU frequency scaling. +//! +//! This module provides bindings for interacting with the cpufreq subsyst= em. +//! +//! C header: [`include/linux/cpufreq.h`](srctree/include/linux/cpufreq.h) + +use crate::{ + bindings, + error::{code::*, to_result, Result}, + prelude::*, +}; + +use core::{ + pin::Pin, +}; + +/// Default transition latency value. +pub const ETERNAL_LATENCY: u32 =3D bindings::CPUFREQ_ETERNAL as u32; + +/// Container for cpufreq driver flags. +pub mod flags { + use crate::bindings; + + /// Set by drivers that need to update internal upper and lower bounda= ries along with the + /// target frequency and so the core and governors should also invoke = the driver if the target + /// frequency does not change, but the policy min or max may have chan= ged. + pub const NEED_UPDATE_LIMITS: u16 =3D bindings::CPUFREQ_NEED_UPDATE_LI= MITS as _; + + /// Set by drivers for platforms where loops_per_jiffy or other kernel= "constants" aren't + /// affected by frequency transitions. + pub const CONST_LOOPS: u16 =3D bindings::CPUFREQ_CONST_LOOPS as _; + + /// Set by drivers that want the core to automatically register the cp= ufreq driver as a thermal + /// cooling device. + pub const IS_COOLING_DEV: u16 =3D bindings::CPUFREQ_IS_COOLING_DEV as = _; + + /// Set by drivers for platforms that have multiple clock-domains, i.e= . supporting multiple + /// policies. With this sysfs directories of governor would be created= in cpu/cpuN/cpufreq/ + /// directory and so they can use the same governor with different tun= ables for different + /// clusters. + pub const HAVE_GOVERNOR_PER_POLICY: u16 =3D bindings::CPUFREQ_HAVE_GOV= ERNOR_PER_POLICY as _; + + /// Set by drivers which do POSTCHANGE notifications from outside of t= heir ->target() routine. + pub const ASYNC_NOTIFICATION: u16 =3D bindings::CPUFREQ_ASYNC_NOTIFICA= TION as _; + + /// Set by drivers that want cpufreq core to check if CPU is running a= t a frequency present in + /// freq-table exposed by the driver. For these drivers if CPU is foun= d running at an out of + /// table freq, the cpufreq core will try to change the frequency to a= value from the table. + /// And if that fails, it will stop further boot process by issuing a = BUG_ON(). + pub const NEED_INITIAL_FREQ_CHECK: u16 =3D bindings::CPUFREQ_NEED_INIT= IAL_FREQ_CHECK as _; + + /// Set by drivers to disallow use of governors with "dynamic_switchin= g" flag set. + pub const NO_AUTO_DYNAMIC_SWITCHING: u16 =3D bindings::CPUFREQ_NO_AUTO= _DYNAMIC_SWITCHING as _; +} + +/// CPU frequency selection relations. Each value contains a `bool` argume= nt which corresponds to +/// the Relation being efficient. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Relation { + /// Select the lowest frequency at or above target. + Low(bool), + /// Select the highest frequency below or at target. + High(bool), + /// Select the closest frequency to the target. + Close(bool), +} + +impl Relation { + // Converts from a value compatible with the C code. + fn new(val: u32) -> Result { + let efficient =3D val & bindings::CPUFREQ_RELATION_E !=3D 0; + + Ok(match val & !bindings::CPUFREQ_RELATION_E { + bindings::CPUFREQ_RELATION_L =3D> Self::Low(efficient), + bindings::CPUFREQ_RELATION_H =3D> Self::High(efficient), + bindings::CPUFREQ_RELATION_C =3D> Self::Close(efficient), + _ =3D> return Err(EINVAL), + }) + } + + /// Converts to a value compatible with the C code. + pub fn val(&self) -> u32 { + let (mut val, e) =3D match self { + Self::Low(e) =3D> (bindings::CPUFREQ_RELATION_L, e), + Self::High(e) =3D> (bindings::CPUFREQ_RELATION_H, e), + Self::Close(e) =3D> (bindings::CPUFREQ_RELATION_C, e), + }; + + if *e { + val |=3D bindings::CPUFREQ_RELATION_E; + } + + val + } +} + +/// Equivalent to `struct cpufreq_policy_data` in the C code. +#[repr(transparent)] +pub struct PolicyData(*mut bindings::cpufreq_policy_data); + +impl PolicyData { + /// Creates new instance of [`PolicyData`]. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid and non-null. + pub unsafe fn from_raw_policy_data(ptr: *mut bindings::cpufreq_policy_= data) -> Self { + Self(ptr) + } + + /// Returns the raw pointer to the C structure. + #[inline] + pub fn as_raw(&self) -> *mut bindings::cpufreq_policy_data { + self.0 + } + + /// Provides a wrapper to the generic verify routine. + pub fn generic_verify(&self) -> Result<()> { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it now. + to_result(unsafe { bindings::cpufreq_generic_frequency_table_verif= y(self.as_raw()) }) + } +} + +/// Builder for the `struct cpufreq_frequency_table` in the C code. +#[repr(transparent)] +#[derive(Default)] +pub struct TableBuilder { + entries: KVec, +} + +impl TableBuilder { + /// Creates new instance of [`TableBuilder`]. + pub fn new() -> Self { + Self { + entries: KVec::new(), + } + } + + /// Adds a new entry to the table. + pub fn add(&mut self, frequency: u32, flags: u32, driver_data: u32) ->= Result<()> { + // Adds new entry to the end of the vector. + Ok(self.entries.push( + bindings::cpufreq_frequency_table { + flags, + driver_data, + frequency, + }, + GFP_KERNEL, + )?) + } + + /// Creates [`Table`] from [`TableBuilder`]. + pub fn into_table(mut self) -> Result { + // Add last entry to the table. + self.add(bindings::CPUFREQ_TABLE_END as u32, 0, 0)?; + Table::from_builder(self.entries) + } +} + +/// A simple implementation of the cpufreq table, equivalent to the `struct +/// cpufreq_frequency_table` in the C code. +pub struct Table { + #[allow(dead_code)] + // Dynamically created table. + entries: Option>>, + + // Pointer to the statically or dynamically created table. + ptr: *mut bindings::cpufreq_frequency_table, +} + +impl Table { + /// Creates new instance of [`Table`] from [`TableBuilder`]. + fn from_builder(entries: KVec) -> R= esult { + if entries.is_empty() { + return Err(EINVAL); + } + + // Pin the entries to memory, since we are passing its pointer to = the C code. + let mut entries =3D Pin::new(entries); + + // The pointer is valid until the table gets dropped. + let ptr =3D entries.as_mut_ptr(); + + Ok(Self { + entries: Some(entries), + ptr, + }) + } + + /// Creates new instance of [`Table`] from raw pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid and non-null for the lifet= ime of the [`Table`]. + pub unsafe fn from_raw(ptr: *mut bindings::cpufreq_frequency_table) ->= Self { + Self { + entries: None, + ptr, + } + } + + /// Returns raw pointer to the `struct cpufreq_frequency_table` compat= ible with the C code. + #[inline] + pub fn as_raw(&self) -> *mut bindings::cpufreq_frequency_table { + self.ptr + } + + /// Returns `frequency` at index in the [`Table`]. + pub fn freq(&self, index: usize) -> Result { + // SAFETY: The pointer is guaranteed to be valid for the lifetime = of `self` and `index` is + // guaranteed to be within limits of the frequency table by the C = API. + Ok(unsafe { (*self.ptr.add(index)).frequency }) + } + + /// Returns `flags` at index in the [`Table`]. + pub fn flags(&self, index: usize) -> Result { + // SAFETY: The pointer is guaranteed to be valid for the lifetime = of `self` and `index` is + // guaranteed to be within limits of the frequency table by the C = API. + Ok(unsafe { (*self.ptr.add(index)).flags }) + } + + /// Returns `data` at index in the [`Table`]. + pub fn data(&self, index: usize) -> Result { + // SAFETY: The pointer is guaranteed to be valid for the lifetime = of `self` and `index` is + // guaranteed to be within limits of the frequency table by the C = API. + Ok(unsafe { (*self.ptr.add(index)).driver_data }) + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index d1c0f136952e..2dd134a46285 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -41,6 +41,8 @@ pub mod build_assert; 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 20:51:28 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C38061CAA79 for ; Mon, 13 Jan 2025 11:24:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767462; cv=none; b=b6cboh9YeAEIMwCA9MEfsG1xfq7nVTBTelYOyhPE50hFzC8cvGyWB+8/izfUxm3ac7spgeTwxLfPVhma8RArwSdQNDPy9wAdpwpiUHquO2DsT8dECyRia2qjL6GYJwGfVNkaZzz5AhEG1SvQDl6XqdTRG2IznoYBttoHhCTpuvw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767462; c=relaxed/simple; bh=6eUufuO+qr8rw3xAmaRGavy2ljguk2nZVG/nqhHwfEE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=PCDywAHaZPhA/TxhjefhVDrympHLaXnR1yNqw+MpCp90LDnJKAg73pZU1D9PzwwD0HqLr14Q7w8hGDAfcIuXpfkLyGGpV3GFhUWTXWtZO/29L0VKxZo7BpiFetQqoH/dJcMMcM6Hozexl9qpnhbvdTy1BlGB2HJ9pPtaHWcnrxA= 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=pCNjr59k; arc=none smtp.client-ip=209.85.214.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="pCNjr59k" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2162c0f6a39so90534605ad.0 for ; Mon, 13 Jan 2025 03:24:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767460; x=1737372260; 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=zwXoOBJkAjU4c4qfx40sQTPK06Msu4Zsat+nENe15cc=; b=pCNjr59ktGo2fiYlADUyd99VP569LacaopQXOHQdVd8wmEnjjVJ9MzYznCwgLTrvyY L4v8vgV8nr1Ufl8VtfF0Wt9kug+KFUwCP4BF5vt//whOnRy4M1fcBhmrgj9MGZZVvlR0 M9l8SylecZk5OrAtEx+65BdUT2RgB1ib8N7czCXftCQKmAQEmAoj6DvDQ7wgbGEZWLl1 HMn6B/ooea2tYPYl7X0QpxWCyQnz6VR5aN8G2w7M3trMcZN6sxZSxI8qnRMAiMqsSCHi P9cjCVcDT27c5ACwUu4mzsdaaXTk6WXypGwe7VVwOAjEM1cd2m+S/BYziGvaK/zgqZdU GONw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767460; x=1737372260; 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=zwXoOBJkAjU4c4qfx40sQTPK06Msu4Zsat+nENe15cc=; b=oRcknFxfIpCp4vNrVNUX897ThOuOMOazuoloDpKEAI6ScH0wmXitXjM1Lv+LLiLGF/ kEVjb/m2rhfupe5s80avt9p5Xx+GTHpMa8+6QdswleyzHbR18UOwKr5GiO5Zo1w/grHl M8VT0r/hgfvVhRk5PHhkmbaSGnRZUiF1iW4ffhEzW95kKAzrL6tHrGTBePs/7f12KUpL iN4AGboaHkuK1swdQx1ui9LvsyKFFtKOOXoTJdluZ5JT48IGbKWWRdOD7PiB3RszbOAv md+dWE5d2vozS+g07nxVbQudAQ6fPoSDiDqIb7SwDxrwXBVi3GcRb5Va+sXYsKyklI8p MvrA== X-Forwarded-Encrypted: i=1; AJvYcCXLzIHIEzkIe3aPvtnFsMUi68t3WOcbYsZ9zegvQsi6olBdnQqy7T2+n3zmelPT7DBlvZRC6uxLKrELJtU=@vger.kernel.org X-Gm-Message-State: AOJu0Yx3Z6UtfPkth11ws3K6OdQ0fAkSlkEvCN7LycOuzajKDNeZSZ3F O1vHXg1SRwAynPiU3h6IAiHrB3JkZi6qk7jPZ4NkKgPylvxRtxwav8Y+HSCG/48= X-Gm-Gg: ASbGncsO6jNPWxWQM3B1AT6mVdCcIytFX+MU00rxbSoqXxKDRzfszv2x/NLbEzbyokJ L6+SQCIhfAwtnZgZiGuCDNC+UvYrZ31XqfOkwlmNAZ/NJv8Nu9YvMDSaHF6+ynaUt9oIZpsR0f/ YTW28CH9urecCODY7a8k5lclcKYiFDI4B+GHHj2UlIsS0IozyFdmEjBWRWqGpKsS0zklG/tvfwC RepKshXur8+K3SEDbfrIVCzuLBJXmnsZA9eqsepdmXdVBAVNj23qY0pTnE= X-Google-Smtp-Source: AGHT+IF1jBDNlhS9BCy1e75qQA8jc0azS1BNJz+YKP3r8+t+nCxIjTXNNHlirZyqycQgyWPxMknT9g== X-Received: by 2002:a05:6a20:2d14:b0:1e1:a789:1b4d with SMTP id adf61e73a8af0-1e8b1623c35mr18366709637.15.1736767460050; Mon, 13 Jan 2025 03:24:20 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72d4065c3b4sm5688313b3a.112.2025.01.13.03.24.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:19 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH V7 12/16] rust: Extend cpufreq bindings for policy and driver ops Date: Mon, 13 Jan 2025 16:53:07 +0530 Message-Id: <20f7ea798034674e5be08bd6d92c7d686d93df06.1736766672.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This extends the cpufreq bindings with bindings for cpufreq policy and driver operations. Signed-off-by: Viresh Kumar --- rust/kernel/cpufreq.rs | 357 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 355 insertions(+), 2 deletions(-) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 3dfdf5ccb9b8..8468e12ef1f5 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -7,15 +7,20 @@ //! C header: [`include/linux/cpufreq.h`](srctree/include/linux/cpufreq.h) =20 use crate::{ - bindings, - error::{code::*, to_result, Result}, + bindings, clk, cpumask, + device::Device, + error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR= }, prelude::*, + types::ForeignOwnable, }; =20 use core::{ pin::Pin, + ptr::self, }; =20 +use macros::vtable; + /// Default transition latency value. pub const ETERNAL_LATENCY: u32 =3D bindings::CPUFREQ_ETERNAL as u32; =20 @@ -229,3 +234,351 @@ pub fn data(&self, index: usize) -> Result { Ok(unsafe { (*self.ptr.add(index)).driver_data }) } } + +/// Equivalent to `struct cpufreq_policy` in the C code. +pub struct Policy { + ptr: *mut bindings::cpufreq_policy, + put_cpu: bool, + cpumask: cpumask::Cpumask, +} + +impl Policy { + /// Creates a new instance of [`Policy`]. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid and non-null. + pub unsafe fn from_raw_policy(ptr: *mut bindings::cpufreq_policy) -> S= elf { + Self { + ptr, + put_cpu: false, + // SAFETY: The pointer is guaranteed to be valid for the lifet= ime of `Self`. The `cpus` + // pointer is guaranteed to be valid by the C code. + cpumask: unsafe { cpumask::Cpumask::get_cpumask((*ptr).cpus) }, + } + } + + fn from_cpu(cpu: u32) -> Result { + // SAFETY: It is safe to call `cpufreq_cpu_get()` for any CPU. + let ptr =3D from_err_ptr(unsafe { bindings::cpufreq_cpu_get(cpu) }= )?; + + // SAFETY: The pointer is guaranteed to be valid by the C code. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + policy.put_cpu =3D true; + Ok(policy) + } + + /// Raw pointer to the underlying cpufreq policy. + #[inline] + pub fn as_raw(&self) -> *mut bindings::cpufreq_policy { + self.ptr + } + + fn as_ref(&self) -> &bindings::cpufreq_policy { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence to the pointer. + unsafe { &(*self.ptr) } + } + fn as_mut_ref(&mut self) -> &mut bindings::cpufreq_policy { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence to the pointer. + unsafe { &mut (*self.ptr) } + } + + /// Returns the primary CPU for a cpufreq policy. + pub fn cpu(&self) -> u32 { + self.as_ref().cpu + } + + /// Returns the minimum frequency for a cpufreq policy. + pub fn min(&self) -> u32 { + self.as_ref().min + } + + /// Set the minimum frequency for a cpufreq policy. + pub fn set_min(&mut self, min: u32) -> &mut Self { + self.as_mut_ref().min =3D min; + self + } + + /// Returns the maximum frequency for a cpufreq policy. + pub fn max(&self) -> u32 { + self.as_ref().max + } + + /// Set the maximum frequency for a cpufreq policy. + pub fn set_max(&mut self, max: u32) -> &mut Self { + self.as_mut_ref().max =3D max; + self + } + + /// Returns the current frequency for a cpufreq policy. + pub fn cur(&self) -> u32 { + self.as_ref().cur + } + + /// Sets the suspend frequency for a cpufreq policy. + pub fn set_suspend_freq(&mut self, freq: u32) -> &mut Self { + self.as_mut_ref().suspend_freq =3D freq; + self + } + + /// Returns the suspend frequency for a cpufreq policy. + pub fn suspend_freq(&self) -> u32 { + self.as_ref().suspend_freq + } + + /// Provides a wrapper to the generic suspend routine. + pub fn generic_suspend(&self) -> Result<()> { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it now. + to_result(unsafe { bindings::cpufreq_generic_suspend(self.as_raw()= ) }) + } + + /// Provides a wrapper to the generic get routine. + pub fn generic_get(&self) -> Result { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it now. + Ok(unsafe { bindings::cpufreq_generic_get(self.cpu()) }) + } + + /// Provides a wrapper to the register em with OPP routine. + pub fn register_em_opp(&self) { + // SAFETY: By the type invariants, we know that `self` owns a refe= rence, so it is safe to + // use it now. + unsafe { bindings::cpufreq_register_em_with_opp(self.as_raw()) }; + } + + /// Gets raw pointer to cpufreq policy's CPUs mask. + pub fn cpus(&mut self) -> &mut cpumask::Cpumask { + &mut self.cpumask + } + + /// Sets clock for a cpufreq policy. + pub fn set_clk(&mut self, dev: &Device, name: Option<&CStr>) -> Result= { + let clk =3D clk::Clk::new(dev, name)?; + self.as_mut_ref().clk =3D clk.as_raw(); + Ok(clk) + } + + /// Allows frequency switching code to run on any CPU. + pub fn set_dvfs_possible_from_any_cpu(&mut self) -> &mut Self { + self.as_mut_ref().dvfs_possible_from_any_cpu =3D true; + self + } + + /// Get fast_switch_possible value. + pub fn fast_switch_possible(&self) -> bool { + self.as_ref().fast_switch_possible + } + + /// Enable/disable fast frequency switching. + pub fn set_fast_switch_possible(&mut self, val: bool) -> &mut Self { + self.as_mut_ref().fast_switch_possible =3D val; + self + } + + /// Sets transition latency for a cpufreq policy. + pub fn set_transition_latency(&mut self, latency: u32) -> &mut Self { + self.as_mut_ref().cpuinfo.transition_latency =3D latency; + self + } + + /// Set cpuinfo.min_freq. + pub fn set_cpuinfo_min_freq(&mut self, min_freq: u32) -> &mut Self { + self.as_mut_ref().cpuinfo.min_freq =3D min_freq; + self + } + + /// Set cpuinfo.max_freq. + pub fn set_cpuinfo_max_freq(&mut self, max_freq: u32) -> &mut Self { + self.as_mut_ref().cpuinfo.max_freq =3D max_freq; + self + } + + /// Set transition_delay_us, i.e. time between successive freq. change= requests. + pub fn set_transition_delay_us(&mut self, transition_delay_us: u32) ->= &mut Self { + self.as_mut_ref().transition_delay_us =3D transition_delay_us; + self + } + + /// Returns the cpufreq table for a cpufreq policy. The cpufreq table = is recreated in a + /// light-weight manner from the raw pointer. The table in C code is n= ot freed once this table + /// is dropped. + pub fn freq_table(&self) -> Result
{ + if self.as_ref().freq_table.is_null() { + return Err(EINVAL); + } + + // SAFETY: The `freq_table` is guaranteed to be valid. + Ok(unsafe { Table::from_raw(self.as_ref().freq_table) }) + } + + /// Sets the cpufreq table for a cpufreq policy. + /// + /// The cpufreq driver must guarantee that the frequency table does no= t get freed while it is + /// still being used by the C code. + pub fn set_freq_table(&mut self, table: &Table) -> &mut Self { + self.as_mut_ref().freq_table =3D table.as_raw(); + self + } + + /// Returns the data for a cpufreq policy. + pub fn data(&mut self) -> Option<::Borrowed<'_>>= { + if self.as_ref().driver_data.is_null() { + None + } else { + // SAFETY: The data is earlier set by us from [`set_data()`]. + Some(unsafe { T::borrow(self.as_ref().driver_data) }) + } + } + + // Sets the data for a cpufreq policy. + fn set_data(&mut self, data: T) -> Result<()> { + if self.as_ref().driver_data.is_null() { + // Pass the ownership of the data to the foreign interface. + self.as_mut_ref().driver_data =3D ::into_= foreign(data) as _; + Ok(()) + } else { + Err(EBUSY) + } + } + + // Returns the data for a cpufreq policy. + fn clear_data(&mut self) -> Option { + if self.as_ref().driver_data.is_null() { + None + } else { + let data =3D Some( + // SAFETY: The data is earlier set by us from [`set_data()= `]. It is safe to take + // back the ownership of the data from the foreign interfa= ce. + unsafe { ::from_foreign(self.as_ref()= .driver_data) } + ); + self.as_mut_ref().driver_data =3D ptr::null_mut(); + data + } + } +} + +impl Drop for Policy { + fn drop(&mut self) { + if self.put_cpu { + // SAFETY: By the type invariants, we know that `self` owns a = reference, so it is safe to + // relinquish it now. + unsafe { bindings::cpufreq_cpu_put(self.as_raw()) }; + } + } +} + +/// Operations to be implemented by a cpufreq driver. +#[vtable] +pub trait Driver { + /// Driver specific data. + /// + /// Corresponds to the data retrieved via the kernel's + /// `cpufreq_get_driver_data()` function. + /// + /// Require that `Data` implements `ForeignOwnable`. We guarantee to + /// never move the underlying wrapped data structure. + type Data: ForeignOwnable; + + /// Policy specific data. + /// + /// Require that `PData` implements `ForeignOwnable`. We guarantee to + /// never move the underlying wrapped data structure. + type PData: ForeignOwnable; + + /// Policy's init callback. + fn init(policy: &mut Policy) -> Result; + + /// Policy's exit callback. + fn exit(_policy: &mut Policy, _data: Option) -> Result<()= > { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's online callback. + fn online(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's offline callback. + fn offline(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's suspend callback. + fn suspend(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's resume callback. + fn resume(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's ready callback. + fn ready(_policy: &mut Policy) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's verify callback. + fn verify(data: &mut PolicyData) -> Result<()>; + + /// Policy's setpolicy callback. + fn setpolicy(_policy: &mut Policy) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's target callback. + fn target(_policy: &mut Policy, _target_freq: u32, _relation: Relation= ) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's target_index callback. + fn target_index(_policy: &mut Policy, _index: u32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's fast_switch callback. + fn fast_switch(_policy: &mut Policy, _target_freq: u32) -> u32 { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's adjust_perf callback. + fn adjust_perf(_policy: &mut Policy, _min_perf: usize, _target_perf: u= size, _capacity: usize) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's get_intermediate callback. + fn get_intermediate(_policy: &mut Policy, _index: u32) -> u32 { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's target_intermediate callback. + fn target_intermediate(_policy: &mut Policy, _index: u32) -> Result<()= > { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's get callback. + fn get(_policy: &mut Policy) -> Result { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's update_limits callback. + fn update_limits(_policy: &mut Policy) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's bios_limit callback. + fn bios_limit(_policy: &mut Policy, _limit: &mut u32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's set_boost callback. + fn set_boost(_policy: &mut Policy, _state: i32) -> Result<()> { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Policy's register_em callback. + fn register_em(_policy: &mut Policy) { + build_error!(VTABLE_DEFAULT_ERROR) + } +} --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 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 A211D1CAA8A for ; Mon, 13 Jan 2025 11:24:24 +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=1736767468; cv=none; b=Lrxf7UQKbdBRB7xnkbPsII3JKDKG1RvWECTLpU8GRpIJr1aLo0PUzwlHIWf4KMYYrN/Wpfgtb/Ejf5sr4n+OpioZppskkOb/xnkJ4IsiG8Cj6EEH7iAyzOSU9PlDBbD9wDlWroyW4qcjfB+yNMwhobafPf/7cj1YIbmh3btoYBA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767468; c=relaxed/simple; bh=fmsO+gUs+PaCOyzUqE6A+eHGWzdyvpsE6BHVemBn01I=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=mSbBUu54XCl1yVtBN125w6sC2IDzqpW2lnrhce3SM8ZhAXUukq1aqFJgnnrWZye9rLIeFdQ95GvTFV5FP+uZzSXcd2NdhoEFLwd6/Qr2fMG4nm2flFAGraUWqQ2EZRF7Av7IumKGVT+QsjpGR+q7faVGHX2qcoOplgAHKitKP3I= 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=zvoURDSV; 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="zvoURDSV" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-21a7ed0155cso68974575ad.3 for ; Mon, 13 Jan 2025 03:24:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767464; x=1737372264; 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=Jqj01KGpNi0J5xBTE+Wd2fJArhO2X9pHhv/GKSBCr2Q=; b=zvoURDSVV23i7sIvzmen8y5RTKWoZ3cMG3gfLzzfid3LUgu+Wk5BLHjNA499RTKT47 x4QzxIYyG8JpQAV98jwuYim9wsPzwMzWFdYfg/7MWhrGdtgX2TyTzsMKDhpVrK6CiNDO 0yNeJgfHWWjH2tnzB6NCRfJSJn8vVoT/2UtkxYfxtowloFsFy1TQ4sJ/x56l55SCfGZr dxqLuCtCC9ooSeFcZPcOBY4bsAnlT1S7ex1GOhIUOdk84yDGUo0xK/cdAqbp/IKQmh4t O0zc79aDGyvqY1sjMgiIqz80ea0hYocfy7Mgr6MID+koBzVGzhQdt/A2c5GhP8ex9hq5 gAug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767464; x=1737372264; 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=Jqj01KGpNi0J5xBTE+Wd2fJArhO2X9pHhv/GKSBCr2Q=; b=o++bT0IVvbVV+t9Uq0me1pmK2YQu0UokW81Fp2VgXAcFX2cmhttejkwlz6TZzYzn/+ aMo/nn6h13R2HIMRnc2ICGJcyQ0nA279SsCeHtAV7tgKa1pFlBnvzgTXoScXxefmdZJO deP6LNXXNdC/pTM08gLFBvQUF6ePDyEN4VhRs327qh7/uNWODEEEo78IiD0r2fdRso9B J4XxvTf+0fV7/iSlmfQnW8TXb4TGQcwgrsQcvmFZKkDJeRbmQWg0Bctm0cV6xHVRBO0j GG/aBUP3Q7GKDXEQhRYmGqHsf6lZhgwIo8ow50wP74B2k/yGR/l6kJBnxfdnOjLgRK4b WnPw== X-Forwarded-Encrypted: i=1; AJvYcCWcmZqe8BdDmHLYkJtsuO+SxVcII5nF0mfLKqwPo/eV7b70K4VHLz2x6Ueuzc1VzcEWb2NR9n1FBUYkj7E=@vger.kernel.org X-Gm-Message-State: AOJu0YxRGUcafCHz0vNWCN/8BRDCecCBNTtzZ1tO6qmhuElgP1T9djg+ Thtv0S4moJoJXvACwIJhFtYjJhfl7rojRILkv1cZRSJORWhLTgs5Glnz6HDSmrQ= X-Gm-Gg: ASbGncvLXzQDgMVoOBYoJHWjFyGEHWpt0n3iFdITBw13O5YAfjPOK5yyCF0Ib1DenaH sJu384zmpnGAk2gPRALznbMYShTWxIjGQX8qsZ1s+plEXl3FMk1bykvYRTJPPTQb7O569JTEU23 KIVyEE8JwMTKBTNw34aeR1Wm8LMROhFv8LoFSTNg8yqdho5SMFTy6NVw8W3014GOb70SqSZUPJf Pv7gkUnTaHL2QtyG5xXNW14pQ0njoT+iVzKgc79ZfYq9mwasE1b2S9P2Kk= X-Google-Smtp-Source: AGHT+IF3VnF2HOh2G1jERTpOh24EBzVNaNpYbXGC2liPXlYsq5SBTdEYYq0R/pVu5nzMpPDVkfebpQ== X-Received: by 2002:a05:6a00:32cb:b0:725:df1a:288 with SMTP id d2e1a72fcca58-72d2201c96dmr33506209b3a.24.1736767463835; Mon, 13 Jan 2025 03:24:23 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72d4065a544sm5939301b3a.96.2025.01.13.03.24.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:23 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH V7 13/16] rust: Extend cpufreq bindings for driver registration Date: Mon, 13 Jan 2025 16:53:08 +0530 Message-Id: X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This extends the cpufreq bindings with bindings for registering a driver. Signed-off-by: Viresh Kumar --- rust/kernel/cpufreq.rs | 476 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 474 insertions(+), 2 deletions(-) diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index 8468e12ef1f5..899f5b50eb7c 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -9,14 +9,17 @@ use crate::{ bindings, clk, cpumask, device::Device, - error::{code::*, from_err_ptr, to_result, Result, VTABLE_DEFAULT_ERROR= }, + devres::Devres, + error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_= DEFAULT_ERROR}, prelude::*, types::ForeignOwnable, }; =20 use core::{ + cell::UnsafeCell, + marker::PhantomData, pin::Pin, - ptr::self, + ptr::{self, addr_of_mut}, }; =20 use macros::vtable; @@ -582,3 +585,472 @@ fn register_em(_policy: &mut Policy) { build_error!(VTABLE_DEFAULT_ERROR) } } + +/// Registration of a cpufreq driver. +pub struct Registration { + drv: KBox>, + _p: PhantomData, +} + +// SAFETY: `Registration` doesn't offer any methods or access to fields wh= en shared between threads +// or CPUs, so it is safe to share it. +unsafe impl Sync for Registration {} + +#[allow(clippy::non_send_fields_in_send_ty)] +// SAFETY: Registration with and unregistration from the cpufreq subsystem= can happen from any thread. +// Additionally, `T::Data` (which is dropped during unregistration) is `Se= nd`, so it is okay to move +// `Registration` to different threads. +unsafe impl Send for Registration {} + +impl Registration { + /// Registers a cpufreq driver with the rest of the kernel. + pub fn new(name: &'static CStr, data: T::Data, flags: u16, boost: bool= ) -> Result { + let mut drv =3D KBox::new( + UnsafeCell::new(bindings::cpufreq_driver::default()), + GFP_KERNEL, + )?; + let drv_ref =3D drv.get_mut(); + + // Account for the trailing null character. + let len =3D name.len() + 1; + if len > drv_ref.name.len() { + return Err(EINVAL); + }; + + // SAFETY: `name` is a valid Cstr, and we are copying it to an arr= ay of equal or larger + // size. + let name =3D unsafe { &*(name.as_bytes_with_nul() as *const [u8]) = }; + drv_ref.name[..len].copy_from_slice(name); + + drv_ref.boost_enabled =3D boost; + drv_ref.flags =3D flags; + + // Allocate an array of 3 pointers to be passed to the C code. + let mut attr =3D KBox::new([ptr::null_mut(); 3], GFP_KERNEL)?; + let mut next =3D 0; + + // SAFETY: The C code returns a valid pointer here, which is again= passed to the C code in + // an array. + attr[next] =3D unsafe { + addr_of_mut!(bindings::cpufreq_freq_attr_scaling_available_fre= qs) as *mut _ + }; + next +=3D 1; + + if boost { + // SAFETY: The C code returns a valid pointer here, which is a= gain passed to the C code + // in an array. + attr[next] =3D unsafe { + addr_of_mut!(bindings::cpufreq_freq_attr_scaling_boost_fre= qs) as *mut _ + }; + next +=3D 1; + } + attr[next] =3D ptr::null_mut(); + + // Pass the ownership of the memory block to the C code. This will= be freed when + // the [`Registration`] object goes out of scope. + drv_ref.attr =3D KBox::leak(attr) as *mut _; + + // Initialize mandatory callbacks. + drv_ref.init =3D Some(Self::init_callback); + drv_ref.verify =3D Some(Self::verify_callback); + + // Initialize optional callbacks. + drv_ref.setpolicy =3D if T::HAS_SETPOLICY { + Some(Self::setpolicy_callback) + } else { + None + }; + drv_ref.target =3D if T::HAS_TARGET { + Some(Self::target_callback) + } else { + None + }; + drv_ref.target_index =3D if T::HAS_TARGET_INDEX { + Some(Self::target_index_callback) + } else { + None + }; + drv_ref.fast_switch =3D if T::HAS_FAST_SWITCH { + Some(Self::fast_switch_callback) + } else { + None + }; + drv_ref.adjust_perf =3D if T::HAS_ADJUST_PERF { + Some(Self::adjust_perf_callback) + } else { + None + }; + drv_ref.get_intermediate =3D if T::HAS_GET_INTERMEDIATE { + Some(Self::get_intermediate_callback) + } else { + None + }; + drv_ref.target_intermediate =3D if T::HAS_TARGET_INTERMEDIATE { + Some(Self::target_intermediate_callback) + } else { + None + }; + drv_ref.get =3D if T::HAS_GET { + Some(Self::get_callback) + } else { + None + }; + drv_ref.update_limits =3D if T::HAS_UPDATE_LIMITS { + Some(Self::update_limits_callback) + } else { + None + }; + drv_ref.bios_limit =3D if T::HAS_BIOS_LIMIT { + Some(Self::bios_limit_callback) + } else { + None + }; + drv_ref.online =3D if T::HAS_ONLINE { + Some(Self::online_callback) + } else { + None + }; + drv_ref.offline =3D if T::HAS_OFFLINE { + Some(Self::offline_callback) + } else { + None + }; + drv_ref.exit =3D if T::HAS_EXIT { + Some(Self::exit_callback) + } else { + None + }; + drv_ref.suspend =3D if T::HAS_SUSPEND { + Some(Self::suspend_callback) + } else { + None + }; + drv_ref.resume =3D if T::HAS_RESUME { + Some(Self::resume_callback) + } else { + None + }; + drv_ref.ready =3D if T::HAS_READY { + Some(Self::ready_callback) + } else { + None + }; + drv_ref.set_boost =3D if T::HAS_SET_BOOST { + Some(Self::set_boost_callback) + } else { + None + }; + drv_ref.register_em =3D if T::HAS_REGISTER_EM { + Some(Self::register_em_callback) + } else { + None + }; + + // Set driver data before registering the driver, as the cpufreq c= ore may call few + // callbacks before `cpufreq_register_driver()` returns. + Self::set_data(drv_ref, data)?; + + // SAFETY: It is safe to register the driver with the cpufreq core= in the C code. + to_result(unsafe { bindings::cpufreq_register_driver(drv_ref) })?; + + Ok(Self { + drv, + _p: PhantomData, + }) + } + + /// Same as [Registration::new`], but does not return a `Registration`= instance. + /// Instead the `Registration` is owned by devres and will be revoked = / dropped, once the + /// device is detached. + pub fn new_foreign_owned( + dev: &Device, + name: &'static CStr, + data: T::Data, + flags: u16, + boost: bool, + ) -> Result<()> { + let reg =3D Self::new(name, data, flags, boost)?; + Devres::new_foreign_owned(dev, reg, GFP_KERNEL)?; + Ok(()) + } + + // Sets the data for a cpufreq driver. + fn set_data(drv: &mut bindings::cpufreq_driver, data: T::Data) -> Resu= lt<()> { + if drv.driver_data.is_null() { + // Pass the ownership of the data to the foreign interface. + drv.driver_data =3D ::into_foreign(= data) as _; + Ok(()) + } else { + Err(EBUSY) + } + } + + /// Returns the previous set data for a cpufreq driver. + pub fn data(&mut self) -> Option<::Borrowed= <'static>> { + let drv =3D self.drv.get_mut(); + + if drv.driver_data.is_null() { + None + } else { + // SAFETY: The data is earlier set by us from [`set_data()`]. + Some(unsafe { ::borrow(drv.driver_d= ata) }) + } + } + + // Clears and returns the data for a cpufreq driver. + fn clear_data(&mut self) -> Option { + let drv =3D self.drv.get_mut(); + + if drv.driver_data.is_null() { + None + } else { + // SAFETY: By the type invariants, we know that `self` owns a = reference, so it is safe to + // relinquish it now. + let data =3D Some(unsafe { ::from_f= oreign(drv.driver_data) }); + drv.driver_data =3D ptr::null_mut(); + data + } + } +} + +// cpufreq driver callbacks. +impl Registration { + // Policy's init callback. + extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> cor= e::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + + let data =3D T::init(&mut policy)?; + policy.set_data(data)?; + Ok(0) + }) + } + + // Policy's exit callback. + extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + + let data =3D policy.clear_data(); + let _ =3D T::exit(&mut policy, data); + } + + // Policy's online callback. + extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> c= ore::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::online(&mut policy).map(|()| 0) + }) + } + + // Policy's offline callback. + extern "C" fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> = core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::offline(&mut policy).map(|()| 0) + }) + } + + // Policy's suspend callback. + extern "C" fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> = core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::suspend(&mut policy).map(|()| 0) + }) + } + + // Policy's resume callback. + extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> c= ore::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::resume(&mut policy).map(|()| 0) + }) + } + + // Policy's ready callback. + extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::ready(&mut policy); + } + + // Policy's verify callback. + extern "C" fn verify_callback(ptr: *mut bindings::cpufreq_policy_data)= -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut data =3D unsafe { PolicyData::from_raw_policy_data(ptr= ) }; + T::verify(&mut data).map(|()| 0) + }) + } + + // Policy's setpolicy callback. + extern "C" fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -= > core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::setpolicy(&mut policy).map(|()| 0) + }) + } + + // Policy's target callback. + extern "C" fn target_callback( + ptr: *mut bindings::cpufreq_policy, + target_freq: u32, + relation: u32, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::target(&mut policy, target_freq, Relation::new(relation)?).= map(|()| 0) + }) + } + + // Policy's target_index callback. + extern "C" fn target_index_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::target_index(&mut policy, index).map(|()| 0) + }) + } + + // Policy's fast_switch callback. + extern "C" fn fast_switch_callback( + ptr: *mut bindings::cpufreq_policy, + target_freq: u32, + ) -> core::ffi::c_uint { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::fast_switch(&mut policy, target_freq) + } + + // Policy's adjust_perf callback. + extern "C" fn adjust_perf_callback(cpu: u32, min_perf: usize, target_p= erf: usize, capacity: usize) { + if let Ok(mut policy) =3D Policy::from_cpu(cpu) { + T::adjust_perf(&mut policy, min_perf, target_perf, capacity); + } + } + + // Policy's get_intermediate callback. + extern "C" fn get_intermediate_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> core::ffi::c_uint { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::get_intermediate(&mut policy, index) + } + + // Policy's target_intermediate callback. + extern "C" fn target_intermediate_callback( + ptr: *mut bindings::cpufreq_policy, + index: u32, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::target_intermediate(&mut policy, index).map(|()| 0) + }) + } + + // Policy's get callback. + extern "C" fn get_callback(cpu: u32) -> core::ffi::c_uint { + Policy::from_cpu(cpu).map_or(0, |mut policy| T::get(&mut policy).m= ap_or(0, |f| f)) + } + + // Policy's update_limit callback. + extern "C" fn update_limits_callback(cpu: u32) { + if let Ok(mut policy) =3D Policy::from_cpu(cpu) { + T::update_limits(&mut policy); + } + } + + // Policy's bios_limit callback. + extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> core::= ffi::c_int { + from_result(|| { + let mut policy =3D Policy::from_cpu(cpu as u32)?; + + // SAFETY: The pointer is guaranteed by the C code to be valid. + T::bios_limit(&mut policy, &mut (unsafe { *limit })).map(|()| = 0) + }) + } + + // Policy's set_boost callback. + extern "C" fn set_boost_callback( + ptr: *mut bindings::cpufreq_policy, + state: i32, + ) -> core::ffi::c_int { + from_result(|| { + // SAFETY: `ptr` is valid by the contract with the C code. `po= licy` is alive only for the + // duration of this call, so it is guaranteed to remain alive = for the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::set_boost(&mut policy, state).map(|()| 0) + }) + } + + // Policy's register_em callback. + extern "C" fn register_em_callback(ptr: *mut bindings::cpufreq_policy)= { + // SAFETY: `ptr` is valid by the contract with the C code. `policy= ` is alive only for the + // duration of this call, so it is guaranteed to remain alive for = the lifetime of + // `ptr`. + let mut policy =3D unsafe { Policy::from_raw_policy(ptr) }; + T::register_em(&mut policy); + } +} + +impl Drop for Registration { + // Removes the registration from the kernel if it has completed succes= sfully before. + fn drop(&mut self) { + pr_info!("Registration dropped\n"); + let drv =3D self.drv.get_mut(); + + // SAFETY: The driver was earlier registered from `new()`. + unsafe { bindings::cpufreq_unregister_driver(drv) }; + + // Free the previously leaked memory to the C code. + if !drv.attr.is_null() { + // SAFETY: The pointer was earlier initialized from the result= of `KBox::leak`. + unsafe { drop(KBox::from_raw(drv.attr)) }; + } + + // Free data + drop(self.clear_data()); + } +} --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pl1-f175.google.com (mail-pl1-f175.google.com [209.85.214.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 D3B6522A4E1 for ; Mon, 13 Jan 2025 11:24:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767470; cv=none; b=G3iWF4VNysLNdUbU72TBRuT+WFEGZasxADH8CI2FND2anjHfkI8Po4KqHPoldk6nVYTrxPB+opOzojPFd8GQMhIIc/SEJDZSWrUZZLtRdfA7+hcJI/PSnzkywIv0H0rfnwh5NhU+vmDBqEdDjcwzABv2IVhlq7TbY4e3SMZUkPI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767470; c=relaxed/simple; bh=gXRpq9a3zNo2mqoc+c+AY5iNG67itiGvRui0TBLI65I=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=f/9SkkBz0TJS8Cb+g+q+jPOZOUW5d/BX8PvItINY+GvSJu1MkVJ2cTGcrlHStNbg55DmY3HDZHi6dHT/B5Ndy0cPnyKtsJSwcQMU8amXjQwlEkd3HQIfxlpyzTtKjSJbMUer0VZfICpvV5CIuUKentha4gVwQV47R7EmiqpawQ4= 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=j2nawjd7; arc=none smtp.client-ip=209.85.214.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="j2nawjd7" Received: by mail-pl1-f175.google.com with SMTP id d9443c01a7336-2166f1e589cso85551735ad.3 for ; Mon, 13 Jan 2025 03:24:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767467; x=1737372267; 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=yF4U0fmdhazacnu5TfK3YZgG7bQEU+5HFAz9S6EWr/w=; b=j2nawjd7iYwPuhavM6cRF68mMSrXua7hAHPhY0ZH0QluSLNftg9a6nWmVW4tnkmv+5 1nty+xjQWa+6n37DCzdJ9xtRrwemFAcQJtC8J7li7SiiSDRQTRTX2ReOJTgsvHWKfCTy J2/H0l82kzdjG5ekZ79oKClMibvn2qbaVXB5lA3MVpAxe5C//CdPJJSfd+zJvrhSFMlj raCXTtcKOxFm47LBd0VY6pxXajeRPdDqHzaplPyMMFN0+7eBfS69jjwnhxGGIslEQtSB FPRIHz5fw9P4XmYj+23BEY3xou5IleKKk/tiNBmowwrBzPyanANKEbVP1II6Q3KfxRP5 qg8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767467; x=1737372267; 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=yF4U0fmdhazacnu5TfK3YZgG7bQEU+5HFAz9S6EWr/w=; b=hGMkpbHkBIgmLRacJ30fLlcCThFOPgtts5AbGx+CCiy8nYOUAhzGdoel+kb+29zUYT c8BObUw1d3Kiw8XhEFtvfbYGiwrfv/CRpijBPVTOHUEgO+boG2EUkO322kAybcCJUZVo 44zou+Wm0sslZF3aLxWhCrwaZkBLuuZb5buGeGB1IlkDMNH6IrODQBVnSQozBJQaywaN iPUuMsyavJjGmDiVS/yzNE6TbfkpswgjU2QbYWTeJQqQgVw4btiA92TVdfEgwxuC3STz OjNWgVELOVdKHz2iGWgqVlxHGBejrxwjZ00sZNE3eDjr5sp21d4okn6sK/h97gQis2jG j9LQ== X-Forwarded-Encrypted: i=1; AJvYcCVpsMvhcw8XSAHlmMCCC4Tg9FTtbI1kaUjsKxWfky6l7a1wRfjlcyCio6PAkHMY5I1+L9D2HfQId/Ux7GQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxzAXWl++egqLiMaH41ijyHBdUaxDC4wwhQ97n6AECcmK9RV330 8LTiai6mPKxUSE6AteDU5P0pbPiipsdwgPdaVKFRVlQRiEwKEhGz263OKm1QIWU= X-Gm-Gg: ASbGncuXN57DClbxbYCwaZw2jROEH1WDVTBTM/F3/8y9F0ku9N+HFWSs0Q0xdo/iC9h TH5poKGKcc4nbGsPiqag9XARla2cgWft/bq/hLNmlEvx2DiRmZJJPek6E/hf70JY03boLlo0uQ7 cghNEb69nBGCj9X0DvQ7TTUmxiPOUCIAoDH8wW1TDRDYZYQqfXk3q91zD5T/IJDQLdfS+t92tTC AxTurP6ftnIzUjrheibmcf4CQSrthg6FEjNckoohs9WDr6eEL1Q2k5e5cQ= X-Google-Smtp-Source: AGHT+IEutGiSjaMCxKF1iSM7TvMVcvoFtHqUScWeDq6/12v9Cb/p3VlYB9GXoMrO10PoJYLEx+gU2A== X-Received: by 2002:a17:903:41c3:b0:216:3732:ade3 with SMTP id d9443c01a7336-21a83fc3c07mr308109125ad.35.1736767467225; Mon, 13 Jan 2025 03:24:27 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21a9f233851sm51636465ad.191.2025.01.13.03.24.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:26 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Nishanth Menon , Stephen Boyd , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: Viresh Kumar , linux-pm@vger.kernel.org, Vincent Guittot , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH V7 14/16] rust: Extend OPP bindings with CPU frequency table Date: Mon, 13 Jan 2025 16:53:09 +0530 Message-Id: <47cfb24fd3c7429dc68a023a6b504e37bb13c141.1736766672.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This commit adds bindings for CPUFreq core related API. Signed-off-by: Viresh Kumar --- rust/kernel/opp.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs index 22c4d543f456..147178410c60 100644 --- a/rust/kernel/opp.rs +++ b/rust/kernel/opp.rs @@ -16,6 +16,12 @@ types::{ARef, AlwaysRefCounted, Opaque}, }; =20 +#[cfg(CONFIG_CPU_FREQ)] +use crate::cpufreq; + +#[cfg(CONFIG_CPU_FREQ)] +use core::ops::Deref; + use core::{marker::PhantomData, ptr}; =20 use macros::vtable; @@ -337,6 +343,56 @@ extern "C" fn config_regulators( } } =20 +/// CPU Frequency table created from OPP entries. +#[cfg(CONFIG_CPU_FREQ)] +pub struct FreqTable { + dev: ARef, + table: cpufreq::Table, +} + +#[cfg(CONFIG_CPU_FREQ)] +impl FreqTable { + /// Creates new instance of [`FreqTable`] from raw pointer. + fn new(table: &Table) -> Result { + let mut ptr: *mut bindings::cpufreq_frequency_table =3D ptr::null_= mut(); + + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + to_result(unsafe { + bindings::dev_pm_opp_init_cpufreq_table(table.dev.as_raw(), &m= ut ptr) + })?; + Ok(Self { + dev: table.dev.clone(), + // SAFETY: The `ptr` is guaranteed by the C code to be valid. + table: unsafe { cpufreq::Table::from_raw(ptr) }, + }) + } + + /// Returns reference to the underlying [`cpufreq::Table`]. + pub fn table(&self) -> &cpufreq::Table { + &self.table + } +} + +#[cfg(CONFIG_CPU_FREQ)] +impl Deref for FreqTable { + type Target =3D cpufreq::Table; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.table + } +} + +#[cfg(CONFIG_CPU_FREQ)] +impl Drop for FreqTable { + fn drop(&mut self) { + // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety + // requirements. + unsafe { bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw()= , &mut self.as_raw()) }; + } +} + /// Operating performance point (OPP) table. /// /// Wraps the kernel's `struct opp_table`. @@ -541,6 +597,12 @@ pub fn adjust_voltage( }) } =20 + /// Create cpufreq table from OPP table. + #[cfg(CONFIG_CPU_FREQ)] + pub fn to_cpufreq_table(&mut self) -> Result { + FreqTable::new(self) + } + /// Sets a matching OPP based on frequency. pub fn set_rate(&self, freq: usize) -> Result<()> { // SAFETY: The requirements are satisfied by the existence of `Dev= ice` and its safety --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pl1-f181.google.com (mail-pl1-f181.google.com [209.85.214.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A472A22A4FF for ; Mon, 13 Jan 2025 11:24:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767473; cv=none; b=ACcClzXFggl9jlRgojxNy5fIoCjSaDT9PPmvS29JBjyvZf/2d1jqynPhatVwGxDT18J2D4dqJjXre+OOCHCfPtUK1fSJ+DdstBwSGJSITjcIgnDGOXJ7Uw8eS6+U279j8jp+0MOCURKyDNyAxBDjnejitaY11iys7Obh6VVEZ7k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767473; c=relaxed/simple; bh=4fg2ZGQhlYA8r3JLieZC4cnAZfBC3Xm4Z/gakVH89vk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=NBpqMraiDuIgMYeEEOg6foCmsSgjJsD63/kjYawvMyJmP3qGt3039Wov6WmJAlBCV8GLd1UaGr5KLwTOty35E/fjXxoZ+hJ1DKY8VIU+SEMX7ppdrl9+69Ta0IQgbwViKw9lIBG/swizeNOgTurSYYTg2SnTd2RCPBJ2zD+RArk= 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=CE3lnLRq; arc=none smtp.client-ip=209.85.214.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="CE3lnLRq" Received: by mail-pl1-f181.google.com with SMTP id d9443c01a7336-216426b0865so70469125ad.0 for ; Mon, 13 Jan 2025 03:24:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767471; x=1737372271; 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=ze1PBk/48GQ6DBzWf8nXWZfuqwWl+q48VfNbS3eSzOI=; b=CE3lnLRqHs9Eb9X7xJp74egoqoGopK8sPcTTd7rFl2wDNZ4L3In1wNsVcFmCq0mg+c /SBbpkRbcwJe6mvdIFU5CbmcSRlCO+gXM0WqQTh3dvMR9Ac7YTfG5xkUhv+A7h/YAGpX 3imJ3IdQq02ByE0CRScv6Y2+WisaGXQ1zWnHaVVQi6dSmu2VZhll3a8MNxN0SpRtQ0jc 4UC0yab+n9sFdK9zFAAx2ZnceFsDtun+Xcbb7lwmV8oGvcyITYjqKfmcjk6Z2XaMILYN Q5otramEYCNTpELIfiI+RlnS5iWCuZ/pVVnxH2bS8VvYHE5i2juE9HLZrJG4bbx/BFnO N9WA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767471; x=1737372271; 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=ze1PBk/48GQ6DBzWf8nXWZfuqwWl+q48VfNbS3eSzOI=; b=kO1E2io3Si9uN/Cgt8SGGbF/wpPgR1GR3wns+U3mQa+u41nENGlSaVIlGev4vFBIe0 j1PCxjFKfNWhzJjxX9uwSzST3aLNEHp3VyiC4C3fAks1kitKrFwFpyI3fq3flOQTJPpa 1tUgeI2z4dU1/MG+1stjE51ZWF0wcsVLEZwI4wXAGd3rJMwnm3/3WJRFMPXREJa1zUcu 0iKtn2kkEefSOskhOnIAD63hHrhihWR4MBwGhzjssi8b+TpUx1rsu8GU79DTTJh5+Mmu Jt2Vlx38RKRx6QzIOFj8VYItQ6NtN5W1SbEFueTPV7SutcjK9+/dNuV5IA/R0OuaBV38 KWxQ== X-Forwarded-Encrypted: i=1; AJvYcCWmHr/t1MnS+gi/qkluIMrxoLECQVeaCroQNsWwKNCb+D6ayI9ncRGJmo39k4CaA8AWw6yEhW66ckqNPOk=@vger.kernel.org X-Gm-Message-State: AOJu0YyWJ2dowGwUSg3PC6S7XIyXZR3yW0gVz05W+Xyv/dV1qoenj+dE HytBc9n3xIn1QL8geRGapOtv2sV2jRiph6Nv23Jdi5S4azgWzCyU0E8Nesywil0= X-Gm-Gg: ASbGnctgpl3Qw7xv2fjSgw/7HDALRtgh1RDsaeSPeA5VfJ/JjJrFEQdfrwL47fSNqPI K1iXOFIIbNALCpnAs9NZPPj2+s6cwdPAkcR/VRStxaDk+qHXbQ1A94WL+42SP+QAPvxlwVsZ+02 BnLtH3HgK6bK2kNA0trH/5hHnEBeXD8COqX6eJjxceErctVPWayhQT4bmUbOB6g7huz6gClbvvy Nc0COMAIPo2smusAKS3R9iSxa5HJEQO6e1Bw+tgu6vEz1AX93sPTBl4BY4= X-Google-Smtp-Source: AGHT+IGGqOnEWmNDriR/HLmBnXwApY2rUgwBNSNC9XvMqqfb9u5C7/4ouaI8c61RrPI+L3Fo3BBqXQ== X-Received: by 2002:a17:902:cf0b:b0:215:431f:268a with SMTP id d9443c01a7336-21a83f647e1mr336644375ad.31.1736767471041; Mon, 13 Jan 2025 03:24:31 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21a9f155e00sm51657985ad.103.2025.01.13.03.24.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:30 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 15/16] cpufreq: Add Rust based cpufreq-dt driver Date: Mon, 13 Jan 2025 16:53:10 +0530 Message-Id: <556e67bb5c5954d7f513716fb1bae32d55918742.1736766672.git.viresh.kumar@linaro.org> X-Mailer: git-send-email 2.31.1.272.g89b43f80a514 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This commit adds a Rust based cpufreq-dt driver, which covers most of the functionality of the existing C based driver. Only a handful of things are left, like fetching platform data from cpufreq-dt-platdev.c. This is tested with the help of QEMU for now and switching of frequencies work as expected. Signed-off-by: Viresh Kumar --- drivers/cpufreq/Kconfig | 12 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/rcpufreq_dt.rs | 230 +++++++++++++++++++++++++++++++++ 3 files changed, 243 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 d35a28dd9463..db38d1d5562d 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..9f761082fa14 --- /dev/null +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust based implementation of the cpufreq-dt driver. + +use core::format_args; + +use kernel::{ + c_str, clk, cpu, cpufreq, cpumask::Cpumask, device::Device, + error::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 name_cstr =3D CString::try_from_fmt(fmt!("{}-supply", name)).ok()?; + + if dev.property_present(&name_cstr) { + CString::try_from_fmt(fmt!("{}", name)).ok() + } else { + None + } +} + +// Finds supply name for the CPU from DT. +fn find_supply_names(dev: &Device, cpu: u32) -> Option> { + // Try "cpu0" for older DTs. + let name =3D match cpu { + 0 =3D> find_supply_name_exact(dev, "cpu0"), + _ =3D> None, + } + .or(find_supply_name_exact(dev, "cpu"))?; + + let mut list =3D KVec::with_capacity(1, GFP_KERNEL).ok()?; + list.push(name, GFP_KERNEL).ok()?; + + Some(list) +} + +// Represents the cpufreq dt device. +struct CPUFreqDTDevice { + opp_table: opp::Table, + freq_table: opp::FreqTable, + #[allow(dead_code)] + mask: Cpumask, + #[allow(dead_code)] + token: Option, + #[allow(dead_code)] + clk: clk::Clk, +} + +struct CPUFreqDTDriver { + _pdev: platform::Device, +} + +#[vtable] +impl opp::ConfigOps for CPUFreqDTDriver {} + +#[vtable] +impl cpufreq::Driver for CPUFreqDTDriver { + type Data =3D (); + type PData =3D Arc; + + fn init(policy: &mut cpufreq::Policy) -> Result { + let cpu =3D policy.cpu(); + let dev =3D cpu::from_cpu(cpu)?; + let mut mask =3D Cpumask::new()?; + + mask.set(cpu); + + let token =3D match find_supply_names(dev, cpu) { + Some(names) =3D> Some( + opp::Config::::new() + .set_regulator_names(names)? + .set(dev)?, + ), + _ =3D> None, + }; + + // Get OPP-sharing information from "operating-points-v2" bindings. + let fallback =3D match opp::Table::of_sharing_cpus(dev, &mut mask)= { + Ok(()) =3D> false, + Err(e) =3D> { + if e !=3D ENOENT { + return Err(e); + } + + // "operating-points-v2" not supported. If the platform ha= sn't + // set sharing CPUs, fallback to all CPUs share the `Polic= y` + // for backward compatibility. + opp::Table::sharing_cpus(dev, &mut mask).is_err() + } + }; + + // Initialize OPP tables for all policy cpus. + // + // For platforms not using "operating-points-v2" bindings, we do t= his + // before updating policy cpus. Otherwise, we will end up creating + // duplicate OPPs for the CPUs. + // + // OPPs might be populated at runtime, don't fail for error here u= nless + // it is -EPROBE_DEFER. + let mut opp_table =3D match opp::Table::from_of_cpumask(dev, &mut = mask) { + Ok(table) =3D> table, + Err(e) =3D> { + if e =3D=3D EPROBE_DEFER { + return Err(e); + } + + // The table is added dynamically ? + opp::Table::from_dev(dev)? + } + }; + + // The OPP table must be initialized, statically or dynamically, b= y this point. + opp_table.opp_count()?; + + // Set sharing cpus for fallback scenario. + if fallback { + mask.set_all(); + opp_table.set_sharing_cpus(&mut mask)?; + } + + let mut transition_latency =3D opp_table.max_transition_latency() = as u32; + if transition_latency =3D=3D 0 { + transition_latency =3D cpufreq::ETERNAL_LATENCY; + } + + let freq_table =3D opp_table.to_cpufreq_table()?; + let clk =3D policy + .set_freq_table(freq_table.table()) + .set_dvfs_possible_from_any_cpu() + .set_suspend_freq((opp_table.suspend_freq() / 1000) as u32) + .set_transition_latency(transition_latency) + .set_clk(dev, None)?; + + mask.copy(policy.cpus()); + + Ok(Arc::new( + CPUFreqDTDevice { + opp_table, + freq_table, + mask, + token, + clk, + }, + GFP_KERNEL, + )?) + } + + fn exit(_policy: &mut cpufreq::Policy, _data: Option) -> = Result<()> { + Ok(()) + } + + fn online(_policy: &mut cpufreq::Policy) -> Result<()> { + // We did light-weight tear down earlier, nothing to do here. + Ok(()) + } + + fn offline(_policy: &mut cpufreq::Policy) -> Result<()> { + // Preserve policy->data and don't free resources on light-weight + // tear down. + Ok(()) + } + + fn suspend(policy: &mut cpufreq::Policy) -> Result<()> { + policy.generic_suspend() + } + + fn verify(data: &mut cpufreq::PolicyData) -> Result<()> { + data.generic_verify() + } + + fn target_index(policy: &mut cpufreq::Policy, index: u32) -> Result<()= > { + let data =3D match policy.data::() { + Some(data) =3D> data, + None =3D> return Err(ENOENT), + }; + + let freq =3D data.freq_table.freq(index.try_into().unwrap())? as u= size; + data.opp_table.set_rate(freq * 1000) + } + + fn get(policy: &mut cpufreq::Policy) -> Result { + policy.generic_get() + } + + fn set_boost(_policy: &mut cpufreq::Policy, _state: i32) -> Result<()>= { + Ok(()) + } + + fn register_em(policy: &mut cpufreq::Policy) { + policy.register_em_opp() + } +} + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + ::IdInfo, + [ + (of::DeviceId::new(c_str!("operating-points-v2")), ()) + ] +); + +impl platform::Driver for CPUFreqDTDriver { + type IdInfo =3D (); + const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); + + fn probe(pdev: &mut platform::Device, _id_info: Option<&Self::IdInfo>)= -> Result>> { + cpufreq::Registration::::new_foreign_owned( + pdev.as_ref(), + c_str!("cpufreq-dt"), + (), + cpufreq::flags::NEED_INITIAL_FREQ_CHECK | cpufreq::flags::IS_C= OOLING_DEV, + true, + )?; + + let drvdata =3D KBox::new(Self { _pdev: pdev.clone() }, GFP_KERNEL= )?; + + Ok(drvdata.into()) + } +} + +module_platform_driver! { + type: CPUFreqDTDriver, + name: "cpufreq_dt", + author: "Viresh Kumar ", + description: "Generic CPUFreq DT driver", + license: "GPL v2", +} --=20 2.31.1.272.g89b43f80a514 From nobody Sat Feb 7 20:51:28 2026 Received: from mail-pl1-f176.google.com (mail-pl1-f176.google.com [209.85.214.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EC64C22CF17 for ; Mon, 13 Jan 2025 11:24:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767476; cv=none; b=HbPwWdrlT1Ggdl4xfC7VW0A1Nfi9ihzVTya9g5HeO+jUqX/4oF+o3CmAAC1QRIyIiy/MeNKNErE1s8+gQjSNohug1QTNHCMylXm4jmUeMeU69Evl5oLB+LlMbKq0wEiEg07eQkOGlUuCX1MNhzCbEu8epTWI08k2Jz2NUz3qEec= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736767476; c=relaxed/simple; bh=zAgcTK1vxHH9JbWsGAZBhQO4BNGHJbmi22K+j/HI9GM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kJPNBl43T9n0BkeSRRqZwFN9TyZcECzGson5fhoGWx4jOkBVqXmWqawJJN4l5sgaC2aeZOnkU773vmPYvZJFzhd5mq5AFFC9OyIkXy5q1ZOKkKDR5cvpk3fwFmchb5pPYU3xGtKqzx4s9GQmWJdqxGSSY3Jlo1RTnsrU27r6+6U= 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=Dydf1gl3; arc=none smtp.client-ip=209.85.214.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="Dydf1gl3" Received: by mail-pl1-f176.google.com with SMTP id d9443c01a7336-216426b0865so70469925ad.0 for ; Mon, 13 Jan 2025 03:24:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1736767474; x=1737372274; 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/YD84rEPrBCk3G930SjRh7BJIiSlM7R2s5ncfP28y8=; b=Dydf1gl30EAg5pPV0nDgp+E71jVeAWKNseEBW6GRrLAhPiYcn3hjPfZSaSKsbzXb3i aFEm7cKioJI/XMZ3ZaHioDk28PHbSkRjfXteDIcNOnCUVdj9LG0sAuaRkI1HyJdBjtGD 3jDDbC46Vfotceo38G3OCMbgV8Cf3iWEjxwfUB18KxKF7TlotmP3/SMf5NHR8ymjkZM6 A5mivlqepVFUney8IZ99tptEjV9Yv35DK02vrRmMvezDRN76Lfis+q8Dii7MGt4omnze i21DGgmGJ/HqTWeFPUf0f1l8fVaMrZnv/LvK0htqJBbNRbmepOxrMUjedKtQ/Nmw0U2R PEsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1736767474; x=1737372274; 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/YD84rEPrBCk3G930SjRh7BJIiSlM7R2s5ncfP28y8=; b=uuq8PPf5GpHqvoEvFMjFSDRzpclf0GuCmVjtCbU/pX1fbqHtuF+ObtIHUl5aD4ekhH jt0dqMIiIqb4L7VbPn9NUetsHadrzdNx4VjbjpDPLlqxan+qMQqBb8DYzHJxx9wIlZ7q eMgID81k5LhEvsMuvmP7HNGXdiRHNk6ldAMKYIq2nUndlwwqU1suUGpT0jYOsqQNA/mX jc4r8ZqIl/y0HMcshMwlLoW1Li+O9hOHXpUQMNvLrYF4JQvegak27NARv8VuyZs7rz9I FraN4MxdwkVWi6yVA9J0t26sZJbstVAK2FboUA4qAT9dNwPp9lxkYbKO2D4pMa9QuSN9 urDw== X-Forwarded-Encrypted: i=1; AJvYcCWcoIH1458LPMwJn6Y4V6fu8h3tiLoAR9H2lw+ec0gRR/hF374EwzRebNblbW8ccrjyASZxEdUMotMLhW8=@vger.kernel.org X-Gm-Message-State: AOJu0YzdUAXLrbg6mQ6JRIxUi2xFy1hB7Gq52oRzSmbFrbx6I9AIPVee 2HtSS1Ug092fwmHEMFSClOm5NoRVp8avn1AsVvjHj4c2C9cZ1pZHfCn9Khao3XA= X-Gm-Gg: ASbGncvAEGFf4HEKOKwtb8kAgOvGEj1bQgQ5ZyOWlPw6pGbaOUSoeVBnNxtyxE7snXd svVYcI6HgBIxWYFt6ZSPi0yo8bMEagd3tsYh2ns9guEU0N+vgIvenYTDStdH8Quq7cBi28DCBDE 30JnQeLgusViuxDyIQ5Yua+N6oKggmu0BJ6czp4G4aXmY09fzSnwm4Ww0QMSH6Jm0isaXhEWUKD 1J5DkXDh7yjLzNbXQV61hsQBxDmfPmeOsXddlaygI82N7DiWV/NwokKg8k= X-Google-Smtp-Source: AGHT+IELMOT0PbMKi+46Q87eT/Vfc0JWjP7to1bvIXbajUzFmNLB3hpaOQyToHivf7D0wpdCnj8xQg== X-Received: by 2002:a17:902:f693:b0:215:a179:14d2 with SMTP id d9443c01a7336-21a84009d06mr276039425ad.50.1736767474223; Mon, 13 Jan 2025 03:24:34 -0800 (PST) Received: from localhost ([122.172.84.139]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21a9f155e00sm51658825ad.103.2025.01.13.03.24.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jan 2025 03:24:33 -0800 (PST) From: Viresh Kumar To: "Rafael J. Wysocki" , Viresh Kumar , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Cc: linux-pm@vger.kernel.org, Vincent Guittot , linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH V7 16/16] DO-NOT_MERGE: cpufreq: Rename cpufreq-dt platdev Date: Mon, 13 Jan 2025 16:53:11 +0530 Message-Id: <5c93f6aaff0bcbc907d14d3a74ee5073fa135a07.1736766672.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" The module! implementation in the Rust code expects a module name without a '-' symbol, else it fails to compile with following errors: error: expected one of `:`, `;`, or `=3D`, found `-` --> drivers/cpufreq/rcpufreq_dt.rs:247:1 | 247 | / module_platform_driver! { 248 | | type: CPUFreqDTDriver, 249 | | name: "cpufreq-dt", 250 | | author: "Viresh Kumar ", 251 | | description: "Generic CPUFreq DT driver", 252 | | license: "GPL v2", 253 | | } | |_^ expected one of `:`, `;`, or `=3D` | =3D note: this error originates in the macro `$crate::prelude::module` = which comes from the expansion of the macro `module_platform_driver` (in Ni= ghtly builds, run with -Z macro-backtrace for more info) This must be fixed properly in the Rust code instead. Not to be merged. Not-Signed-off-by: Viresh Kumar --- drivers/cpufreq/cpufreq-dt-platdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq= -dt-platdev.c index 9c198bd4f7e9..263e1e97538d 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -230,7 +230,7 @@ static int __init cpufreq_dt_platdev_init(void) return -ENODEV; =20 create_pdev: - return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt", + return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq_dt", -1, data, sizeof(struct cpufreq_dt_platform_data))); } --=20 2.31.1.272.g89b43f80a514