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@xxxxxxxxxx> --- 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 --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; -- 2.39.2