diff mbox series

[RFC,1/9] rust: dma_resv: add DMA Reservation abstraction

Message ID 20230317121213.93991-2-mcanal@igalia.com (mailing list archive)
State New, archived
Headers show
Series Rust version of the VGEM driver | expand

Commit Message

Maíra Canal March 17, 2023, 12:12 p.m. UTC
The DMA reservation object provides a mechanism to manage a container
of dma_fence object associated with a resource. So, add an abstraction
to allow Rust drivers to interact with this subsystem.

Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
 rust/bindings/bindings_helper.h |  1 +
 rust/helpers.c                  | 19 +++++++++
 rust/kernel/dma_resv.rs         | 75 +++++++++++++++++++++++++++++++++
 rust/kernel/lib.rs              |  1 +
 4 files changed, 96 insertions(+)
 create mode 100644 rust/kernel/dma_resv.rs
diff mbox series

Patch

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 3fcf3ee330ad..1bf6d762d36e 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -19,6 +19,7 @@ 
 #include <linux/dma-fence.h>
 #include <linux/dma-fence-chain.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma-resv.h>
 #include <linux/fs.h>
 #include <linux/iosys-map.h>
 #include <linux/io-pgtable.h>
diff --git a/rust/helpers.c b/rust/helpers.c
index 7cded4a36375..18c0c434ad73 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -25,6 +25,7 @@ 
 #include <linux/build_bug.h>
 #include <linux/device.h>
 #include <linux/dma-fence.h>
+#include <linux/dma-resv.h>
 #include <linux/dma-fence-chain.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
@@ -437,6 +438,24 @@  void rust_helper_dma_fence_set_error(struct dma_fence *fence, int error)
 }
 EXPORT_SYMBOL_GPL(rust_helper_dma_fence_set_error);
 
+enum dma_resv_usage rust_helper_dma_resv_usage_rw(bool write)
+{
+	return dma_resv_usage_rw(write);
+}
+EXPORT_SYMBOL_GPL(rust_helper_dma_resv_usage_rw);
+
+int rust_helper_dma_resv_lock(struct dma_resv *obj, struct ww_acquire_ctx *ctx)
+{
+	return dma_resv_lock(obj, ctx);
+}
+EXPORT_SYMBOL_GPL(rust_helper_dma_resv_lock);
+
+void rust_helper_dma_resv_unlock(struct dma_resv *obj)
+{
+	dma_resv_unlock(obj);
+}
+EXPORT_SYMBOL_GPL(rust_helper_dma_resv_unlock);
+
 #endif
 
 #ifdef CONFIG_DRM
diff --git a/rust/kernel/dma_resv.rs b/rust/kernel/dma_resv.rs
new file mode 100644
index 000000000000..5e45aad4ae75
--- /dev/null
+++ b/rust/kernel/dma_resv.rs
@@ -0,0 +1,75 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+
+//! DMA resv abstraction
+//!
+//! C header: [`include/linux/dma-resv.h`](../../include/linux/dma-resv.h)
+
+use crate::bindings;
+use crate::dma_fence::RawDmaFence;
+use crate::error::{Error, Result};
+
+/// A generic DMA Resv Object
+///
+/// # Invariants
+/// ptr is a valid pointer to a dma_resv and we own a reference to it.
+pub struct DmaResv {
+    ptr: *mut bindings::dma_resv,
+}
+
+impl DmaResv {
+    /// Create a new DmaResv object from a raw pointer to a dma_resv.
+    ///
+    /// # Safety
+    /// The caller must own a reference to the dma_resv, which is transferred to the new object.
+    pub unsafe fn from_raw(ptr: *mut bindings::dma_resv) -> Self {
+        Self { ptr }
+    }
+
+    /// Returns the implicit synchronization usage for write or read accesses.
+    pub fn usage_rw(&self, write: bool) -> bindings::dma_resv_usage {
+        // SAFETY: write is a valid bool.
+        unsafe { bindings::dma_resv_usage_rw(write) }
+    }
+
+    /// Reserve space to add fences to a dma_resv object.
+    pub fn reserve_fences(&self, num_fences: u32) -> Result {
+        // SAFETY: We own a reference to this dma_resv.
+        let ret = unsafe { bindings::dma_resv_reserve_fences(self.ptr, num_fences) };
+
+        if ret != 0 {
+            return Err(Error::from_kernel_errno(ret));
+        }
+        Ok(())
+    }
+
+    /// Add a fence to the dma_resv object
+    pub fn add_fences(
+        &self,
+        fence: &dyn RawDmaFence,
+        num_fences: u32,
+        usage: bindings::dma_resv_usage,
+    ) -> Result {
+        // SAFETY: We own a reference to this dma_resv.
+        unsafe { bindings::dma_resv_lock(self.ptr, core::ptr::null_mut()) };
+
+        let ret = self.reserve_fences(num_fences);
+        if ret.is_ok() {
+            // SAFETY: ptr is locked with dma_resv_lock(), and dma_resv_reserve_fences()
+            // has been called.
+            unsafe {
+                bindings::dma_resv_add_fence(self.ptr, fence.raw(), usage);
+            }
+        }
+
+        // SAFETY: We own a reference to this dma_resv.
+        unsafe { bindings::dma_resv_unlock(self.ptr) };
+
+        ret
+    }
+
+    /// Test if a reservation object’s fences have been signaled.
+    pub fn test_signaled(&self, usage: bindings::dma_resv_usage) -> bool {
+        // SAFETY: We own a reference to this dma_resv.
+        unsafe { bindings::dma_resv_test_signaled(self.ptr, usage) }
+    }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index ba18deedf6b6..b9fbb07d0bdc 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -38,6 +38,7 @@  pub mod delay;
 pub mod device;
 #[cfg(CONFIG_DMA_SHARED_BUFFER)]
 pub mod dma_fence;
+pub mod dma_resv;
 pub mod driver;
 #[cfg(CONFIG_DRM = "y")]
 pub mod drm;