Re: [PATCH RFC 09/18] rust: drm: syncobj: Add DRM Sync Object abstraction

2023-04-06 Thread Asahi Lina

On 05/04/2023 21.33, Daniel Vetter wrote:

On Tue, Mar 07, 2023 at 11:25:34PM +0900, Asahi Lina wrote:

DRM Sync Objects are a container for a DMA fence, and can be waited on
signaled, exported, and imported from userspace. Add a Rust abstraction
so Rust DRM drivers can support this functionality.

Signed-off-by: Asahi Lina 
---
  rust/bindings/bindings_helper.h |  1 +
  rust/helpers.c  | 19 ++
  rust/kernel/drm/mod.rs  |  1 +
  rust/kernel/drm/syncobj.rs  | 77 +
  4 files changed, 98 insertions(+)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 705af292a5b4..b6696011f3a4 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.c b/rust/helpers.c
index 8e906a7a7d8a..11965b1e2f4e 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -20,6 +20,7 @@
  
  #include 

  #include 
+#include 
  #include 
  #include 
  #include 
@@ -461,6 +462,24 @@ __u64 rust_helper_drm_vma_node_offset_addr(struct 
drm_vma_offset_node *node)
  }
  EXPORT_SYMBOL_GPL(rust_helper_drm_vma_node_offset_addr);
  
+void rust_helper_drm_syncobj_get(struct drm_syncobj *obj)

+{
+   drm_syncobj_get(obj);
+}
+EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_get);
+
+void rust_helper_drm_syncobj_put(struct drm_syncobj *obj)
+{
+   drm_syncobj_put(obj);
+}
+EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_put);
+
+struct dma_fence *rust_helper_drm_syncobj_fence_get(struct drm_syncobj 
*syncobj)
+{
+   return drm_syncobj_fence_get(syncobj);
+}
+EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_fence_get);
+
  #ifdef CONFIG_DRM_GEM_SHMEM_HELPER
  
  void rust_helper_drm_gem_shmem_object_free(struct drm_gem_object *obj)

diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs
index 73fab2dee3af..dae98826edfd 100644
--- a/rust/kernel/drm/mod.rs
+++ b/rust/kernel/drm/mod.rs
@@ -8,3 +8,4 @@ pub mod file;
  pub mod gem;
  pub mod ioctl;
  pub mod mm;
+pub mod syncobj;
diff --git a/rust/kernel/drm/syncobj.rs b/rust/kernel/drm/syncobj.rs
new file mode 100644
index ..10eed05eb27a
--- /dev/null
+++ b/rust/kernel/drm/syncobj.rs
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+
+//! DRM Sync Objects
+//!
+//! C header: 
[`include/linux/drm/drm_syncobj.h`](../../../../include/linux/drm/drm_syncobj.h)
+
+use crate::{bindings, dma_fence::*, drm, error::Result, prelude::*};
+
+/// A DRM Sync Object
+///
+/// # Invariants
+/// ptr is a valid pointer to a drm_syncobj and we own a reference to it.
+pub struct SyncObj {
+ptr: *mut bindings::drm_syncobj,
+}
+
+impl SyncObj {
+/// Looks up a sync object by its handle for a given `File`.
+pub fn lookup_handle(file:  drm::file::GenericFile, handle: u32) -> 
Result {
+// SAFETY: The arguments are all valid per the type invariants.
+let ptr = unsafe { bindings::drm_syncobj_find(file.raw() as *mut _, 
handle) };


Just an aside, but the semantics of this are nasty: You're not allowed to
hold any locks while calling this. We have runtime checks for that (if you
enable lockdep), but I don't see any way to encode that on the rust side
and check it at compile time :-/


Oof, yeah, that's not possible today. Maybe in the future though, it's 
similar to the execution context stuff...





+
+if ptr.is_null() {
+Err(ENOENT)
+} else {
+Ok(SyncObj { ptr })
+}
+}
+
+/// Returns the DMA fence associated with this sync object, if any.
+pub fn fence_get() -> Option {
+let fence = unsafe { bindings::drm_syncobj_fence_get(self.ptr) };
+if fence.is_null() {
+None
+} else {
+// SAFETY: The pointer is non-NULL and drm_syncobj_fence_get 
acquired an
+// additional reference.
+Some(unsafe { Fence::from_raw(fence) })
+}
+}
+
+/// Replaces the DMA fence with a new one, or removes it if fence is None.
+pub fn replace_fence(, fence: Option<>) {
+unsafe {
+bindings::drm_syncobj_replace_fence(
+self.ptr,
+fence.map_or(core::ptr::null_mut(), |a| a.raw()),
+)
+};
+}
+
+/// Adds a new timeline point to the syncobj.
+pub fn add_point(, chain: FenceChain, fence: , point: u64) {
+// SAFETY: All arguments should be valid per the respective type 
invariants.
+// This takes over the FenceChain ownership.
+unsafe { bindings::drm_syncobj_add_point(self.ptr, chain.into_raw(), 
fence.raw(), point) };
+}
+}
+
+impl Drop for SyncObj {
+fn drop( self) {
+// SAFETY: We own a reference to this syncobj.
+unsafe { bindings::drm_syncobj_put(self.ptr) };
+}
+}
+
+impl Clone for SyncObj {
+fn clone() -> Self {
+// SAFETY: `ptr` is valid per the type invariant and we 

Re: [PATCH RFC 09/18] rust: drm: syncobj: Add DRM Sync Object abstraction

2023-04-05 Thread Daniel Vetter
On Tue, Mar 07, 2023 at 11:25:34PM +0900, Asahi Lina wrote:
> DRM Sync Objects are a container for a DMA fence, and can be waited on
> signaled, exported, and imported from userspace. Add a Rust abstraction
> so Rust DRM drivers can support this functionality.
> 
> Signed-off-by: Asahi Lina 
> ---
>  rust/bindings/bindings_helper.h |  1 +
>  rust/helpers.c  | 19 ++
>  rust/kernel/drm/mod.rs  |  1 +
>  rust/kernel/drm/syncobj.rs  | 77 
> +
>  4 files changed, 98 insertions(+)
> 
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index 705af292a5b4..b6696011f3a4 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.c b/rust/helpers.c
> index 8e906a7a7d8a..11965b1e2f4e 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -20,6 +20,7 @@
>  
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -461,6 +462,24 @@ __u64 rust_helper_drm_vma_node_offset_addr(struct 
> drm_vma_offset_node *node)
>  }
>  EXPORT_SYMBOL_GPL(rust_helper_drm_vma_node_offset_addr);
>  
> +void rust_helper_drm_syncobj_get(struct drm_syncobj *obj)
> +{
> + drm_syncobj_get(obj);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_get);
> +
> +void rust_helper_drm_syncobj_put(struct drm_syncobj *obj)
> +{
> + drm_syncobj_put(obj);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_put);
> +
> +struct dma_fence *rust_helper_drm_syncobj_fence_get(struct drm_syncobj 
> *syncobj)
> +{
> + return drm_syncobj_fence_get(syncobj);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_fence_get);
> +
>  #ifdef CONFIG_DRM_GEM_SHMEM_HELPER
>  
>  void rust_helper_drm_gem_shmem_object_free(struct drm_gem_object *obj)
> diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs
> index 73fab2dee3af..dae98826edfd 100644
> --- a/rust/kernel/drm/mod.rs
> +++ b/rust/kernel/drm/mod.rs
> @@ -8,3 +8,4 @@ pub mod file;
>  pub mod gem;
>  pub mod ioctl;
>  pub mod mm;
> +pub mod syncobj;
> diff --git a/rust/kernel/drm/syncobj.rs b/rust/kernel/drm/syncobj.rs
> new file mode 100644
> index ..10eed05eb27a
> --- /dev/null
> +++ b/rust/kernel/drm/syncobj.rs
> @@ -0,0 +1,77 @@
> +// SPDX-License-Identifier: GPL-2.0 OR MIT
> +
> +//! DRM Sync Objects
> +//!
> +//! C header: 
> [`include/linux/drm/drm_syncobj.h`](../../../../include/linux/drm/drm_syncobj.h)
> +
> +use crate::{bindings, dma_fence::*, drm, error::Result, prelude::*};
> +
> +/// A DRM Sync Object
> +///
> +/// # Invariants
> +/// ptr is a valid pointer to a drm_syncobj and we own a reference to it.
> +pub struct SyncObj {
> +ptr: *mut bindings::drm_syncobj,
> +}
> +
> +impl SyncObj {
> +/// Looks up a sync object by its handle for a given `File`.
> +pub fn lookup_handle(file:  drm::file::GenericFile, handle: u32) -> 
> Result {
> +// SAFETY: The arguments are all valid per the type invariants.
> +let ptr = unsafe { bindings::drm_syncobj_find(file.raw() as *mut _, 
> handle) };

Just an aside, but the semantics of this are nasty: You're not allowed to
hold any locks while calling this. We have runtime checks for that (if you
enable lockdep), but I don't see any way to encode that on the rust side
and check it at compile time :-/

> +
> +if ptr.is_null() {
> +Err(ENOENT)
> +} else {
> +Ok(SyncObj { ptr })
> +}
> +}
> +
> +/// Returns the DMA fence associated with this sync object, if any.
> +pub fn fence_get() -> Option {
> +let fence = unsafe { bindings::drm_syncobj_fence_get(self.ptr) };
> +if fence.is_null() {
> +None
> +} else {
> +// SAFETY: The pointer is non-NULL and drm_syncobj_fence_get 
> acquired an
> +// additional reference.
> +Some(unsafe { Fence::from_raw(fence) })
> +}
> +}
> +
> +/// Replaces the DMA fence with a new one, or removes it if fence is 
> None.
> +pub fn replace_fence(, fence: Option<>) {
> +unsafe {
> +bindings::drm_syncobj_replace_fence(
> +self.ptr,
> +fence.map_or(core::ptr::null_mut(), |a| a.raw()),
> +)
> +};
> +}
> +
> +/// Adds a new timeline point to the syncobj.
> +pub fn add_point(, chain: FenceChain, fence: , point: u64) {
> +// SAFETY: All arguments should be valid per the respective type 
> invariants.
> +// This takes over the FenceChain ownership.
> +unsafe { bindings::drm_syncobj_add_point(self.ptr, chain.into_raw(), 
> fence.raw(), point) };
> +}
> +}
> +
> +impl Drop for SyncObj {
> +fn drop( self) {
> +// SAFETY: We own a reference to this syncobj.
> +unsafe { bindings::drm_syncobj_put(self.ptr) };
> +}
> +}
> +
> +impl 

[PATCH RFC 09/18] rust: drm: syncobj: Add DRM Sync Object abstraction

2023-03-07 Thread Asahi Lina
DRM Sync Objects are a container for a DMA fence, and can be waited on
signaled, exported, and imported from userspace. Add a Rust abstraction
so Rust DRM drivers can support this functionality.

Signed-off-by: Asahi Lina 
---
 rust/bindings/bindings_helper.h |  1 +
 rust/helpers.c  | 19 ++
 rust/kernel/drm/mod.rs  |  1 +
 rust/kernel/drm/syncobj.rs  | 77 +
 4 files changed, 98 insertions(+)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 705af292a5b4..b6696011f3a4 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.c b/rust/helpers.c
index 8e906a7a7d8a..11965b1e2f4e 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -20,6 +20,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -461,6 +462,24 @@ __u64 rust_helper_drm_vma_node_offset_addr(struct 
drm_vma_offset_node *node)
 }
 EXPORT_SYMBOL_GPL(rust_helper_drm_vma_node_offset_addr);
 
+void rust_helper_drm_syncobj_get(struct drm_syncobj *obj)
+{
+   drm_syncobj_get(obj);
+}
+EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_get);
+
+void rust_helper_drm_syncobj_put(struct drm_syncobj *obj)
+{
+   drm_syncobj_put(obj);
+}
+EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_put);
+
+struct dma_fence *rust_helper_drm_syncobj_fence_get(struct drm_syncobj 
*syncobj)
+{
+   return drm_syncobj_fence_get(syncobj);
+}
+EXPORT_SYMBOL_GPL(rust_helper_drm_syncobj_fence_get);
+
 #ifdef CONFIG_DRM_GEM_SHMEM_HELPER
 
 void rust_helper_drm_gem_shmem_object_free(struct drm_gem_object *obj)
diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs
index 73fab2dee3af..dae98826edfd 100644
--- a/rust/kernel/drm/mod.rs
+++ b/rust/kernel/drm/mod.rs
@@ -8,3 +8,4 @@ pub mod file;
 pub mod gem;
 pub mod ioctl;
 pub mod mm;
+pub mod syncobj;
diff --git a/rust/kernel/drm/syncobj.rs b/rust/kernel/drm/syncobj.rs
new file mode 100644
index ..10eed05eb27a
--- /dev/null
+++ b/rust/kernel/drm/syncobj.rs
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+
+//! DRM Sync Objects
+//!
+//! C header: 
[`include/linux/drm/drm_syncobj.h`](../../../../include/linux/drm/drm_syncobj.h)
+
+use crate::{bindings, dma_fence::*, drm, error::Result, prelude::*};
+
+/// A DRM Sync Object
+///
+/// # Invariants
+/// ptr is a valid pointer to a drm_syncobj and we own a reference to it.
+pub struct SyncObj {
+ptr: *mut bindings::drm_syncobj,
+}
+
+impl SyncObj {
+/// Looks up a sync object by its handle for a given `File`.
+pub fn lookup_handle(file:  drm::file::GenericFile, handle: u32) -> 
Result {
+// SAFETY: The arguments are all valid per the type invariants.
+let ptr = unsafe { bindings::drm_syncobj_find(file.raw() as *mut _, 
handle) };
+
+if ptr.is_null() {
+Err(ENOENT)
+} else {
+Ok(SyncObj { ptr })
+}
+}
+
+/// Returns the DMA fence associated with this sync object, if any.
+pub fn fence_get() -> Option {
+let fence = unsafe { bindings::drm_syncobj_fence_get(self.ptr) };
+if fence.is_null() {
+None
+} else {
+// SAFETY: The pointer is non-NULL and drm_syncobj_fence_get 
acquired an
+// additional reference.
+Some(unsafe { Fence::from_raw(fence) })
+}
+}
+
+/// Replaces the DMA fence with a new one, or removes it if fence is None.
+pub fn replace_fence(, fence: Option<>) {
+unsafe {
+bindings::drm_syncobj_replace_fence(
+self.ptr,
+fence.map_or(core::ptr::null_mut(), |a| a.raw()),
+)
+};
+}
+
+/// Adds a new timeline point to the syncobj.
+pub fn add_point(, chain: FenceChain, fence: , point: u64) {
+// SAFETY: All arguments should be valid per the respective type 
invariants.
+// This takes over the FenceChain ownership.
+unsafe { bindings::drm_syncobj_add_point(self.ptr, chain.into_raw(), 
fence.raw(), point) };
+}
+}
+
+impl Drop for SyncObj {
+fn drop( self) {
+// SAFETY: We own a reference to this syncobj.
+unsafe { bindings::drm_syncobj_put(self.ptr) };
+}
+}
+
+impl Clone for SyncObj {
+fn clone() -> Self {
+// SAFETY: `ptr` is valid per the type invariant and we own a 
reference to it.
+unsafe { bindings::drm_syncobj_get(self.ptr) };
+SyncObj { ptr: self.ptr }
+}
+}
+
+// SAFETY: drm_syncobj operations are internally locked.
+unsafe impl Sync for SyncObj {}
+unsafe impl Send for SyncObj {}

-- 
2.35.1