aboutsummaryrefslogtreecommitdiffstats
path: root/queue-6.15/rust-devres-implement-devres-access.patch
diff options
Diffstat (limited to 'queue-6.15/rust-devres-implement-devres-access.patch')
-rw-r--r--queue-6.15/rust-devres-implement-devres-access.patch93
1 files changed, 93 insertions, 0 deletions
diff --git a/queue-6.15/rust-devres-implement-devres-access.patch b/queue-6.15/rust-devres-implement-devres-access.patch
new file mode 100644
index 0000000000..3dd47d42b3
--- /dev/null
+++ b/queue-6.15/rust-devres-implement-devres-access.patch
@@ -0,0 +1,93 @@
+From e9ec190d9683bcc4b1fe276c640b18cebd1bba45 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 28 Apr 2025 16:00:28 +0200
+Subject: rust: devres: implement Devres::access()
+
+From: Danilo Krummrich <dakr@kernel.org>
+
+[ Upstream commit f301cb978c068faa8fcd630be2cb317a2d0ec063 ]
+
+Implement a direct accessor for the data stored within the Devres for
+cases where we can prove that we own a reference to a Device<Bound>
+(i.e. a bound device) of the same device that was used to create the
+corresponding Devres container.
+
+Usually, when accessing the data stored within a Devres container, it is
+not clear whether the data has been revoked already due to the device
+being unbound and, hence, we have to try whether the access is possible
+and subsequently keep holding the RCU read lock for the duration of the
+access.
+
+However, when we can prove that we hold a reference to Device<Bound>
+matching the device the Devres container has been created with, we can
+guarantee that the device is not unbound for the duration of the
+lifetime of the Device<Bound> reference and, hence, it is not possible
+for the data within the Devres container to be revoked.
+
+Therefore, in this case, we can bypass the atomic check and the RCU read
+lock, which is a great optimization and simplification for drivers.
+
+Reviewed-by: Christian Schrefl <chrisi.schrefl@gmail.com>
+Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
+Acked-by: Boqun Feng <boqun.feng@gmail.com>
+Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com>
+Link: https://lore.kernel.org/r/20250428140137.468709-3-dakr@kernel.org
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Stable-dep-of: 20c96ed278e3 ("rust: devres: do not dereference to the internal Revocable")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ rust/kernel/devres.rs | 38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
+index f3a4e3383b8d2..acb8e1d13ddd9 100644
+--- a/rust/kernel/devres.rs
++++ b/rust/kernel/devres.rs
+@@ -196,6 +196,44 @@ pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result {
+
+ Ok(())
+ }
++
++ /// Obtain `&'a T`, bypassing the [`Revocable`].
++ ///
++ /// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting
++ /// a `&'a Device<Bound>` of the same [`Device`] this [`Devres`] instance has been created with.
++ ///
++ /// # Errors
++ ///
++ /// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance
++ /// has been created with.
++ ///
++ /// # Example
++ ///
++ /// ```no_run
++ /// # use kernel::{device::Core, devres::Devres, pci};
++ ///
++ /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result {
++ /// let bar = devres.access(dev.as_ref())?;
++ ///
++ /// let _ = bar.read32(0x0);
++ ///
++ /// // might_sleep()
++ ///
++ /// bar.write32(0x42, 0x0);
++ ///
++ /// Ok(())
++ /// }
++ /// ```
++ pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> {
++ if self.0.dev.as_raw() != dev.as_raw() {
++ return Err(EINVAL);
++ }
++
++ // SAFETY: `dev` being the same device as the device this `Devres` has been created for
++ // proves that `self.0.data` hasn't been revoked and is guaranteed to not be revoked as
++ // long as `dev` lives; `dev` lives at least as long as `self`.
++ Ok(unsafe { self.deref().access() })
++ }
+ }
+
+ impl<T> Deref for Devres<T> {
+--
+2.39.5
+