[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <DG721WEFTFZY.2CSCXBQ8H0Y1A@garyguo.net>
Date: Thu, 05 Feb 2026 13:16:35 +0000
From: "Gary Guo" <gary@...yguo.net>
To: "Boris Brezillon" <boris.brezillon@...labora.com>, "Philipp Stanner"
<phasta@...nel.org>
Cc: "David Airlie" <airlied@...il.com>, "Simona Vetter" <simona@...ll.ch>,
"Danilo Krummrich" <dakr@...nel.org>, "Alice Ryhl" <aliceryhl@...gle.com>,
"Gary Guo" <gary@...yguo.net>, "Benno Lossin" <lossin@...nel.org>,
Christian König <christian.koenig@....com>, "Daniel
Almeida" <daniel.almeida@...labora.com>, "Joel Fernandes"
<joelagnelf@...dia.com>, <linux-kernel@...r.kernel.org>,
<dri-devel@...ts.freedesktop.org>, <rust-for-linux@...r.kernel.org>
Subject: Re: [RFC PATCH 2/4] rust: sync: Add dma_fence abstractions
On Thu Feb 5, 2026 at 10:16 AM GMT, Boris Brezillon wrote:
> On Tue, 3 Feb 2026 09:14:01 +0100
> Philipp Stanner <phasta@...nel.org> wrote:
>
>> +/// A synchronization primitive mainly for GPU drivers.
>> +///
>> +/// DmaFences are always reference counted. The typical use case is that one side registers
>> +/// callbacks on the fence which will perform a certain action (such as queueing work) once the
>> +/// other side signals the fence.
>> +///
>> +/// # Examples
>> +///
>> +/// ```
>> +/// use kernel::sync::{Arc, ArcBorrow, DmaFence, DmaFenceCtx, DmaFenceCb, DmaFenceCbFunc};
>> +/// use core::sync::atomic::{self, AtomicBool};
>> +///
>> +/// static mut CHECKER: AtomicBool = AtomicBool::new(false);
>> +///
>> +/// struct CallbackData {
>> +/// i: u32,
>> +/// }
>> +///
>> +/// impl CallbackData {
>> +/// fn new() -> Self {
>> +/// Self { i: 9 }
>> +/// }
>> +/// }
>> +///
>> +/// impl DmaFenceCbFunc for CallbackData {
>> +/// fn callback(cb: Pin<KBox<DmaFenceCb<Self>>>) where Self: Sized {
>> +/// assert_eq!(cb.data.i, 9);
>> +/// // SAFETY: Just to have an easy way for testing. This cannot race with the checker
>> +/// // because the fence signalling callbacks are executed synchronously.
>> +/// unsafe { CHECKER.store(true, atomic::Ordering::Relaxed); }
>> +/// }
>> +/// }
>> +///
>> +/// struct DriverData {
>> +/// i: u32,
>> +/// }
>> +///
>> +/// impl DriverData {
>> +/// fn new() -> Self {
>> +/// Self { i: 5 }
>> +/// }
>> +/// }
>> +///
>> +/// let data = DriverData::new();
>> +/// let fctx = DmaFenceCtx::new()?;
>> +///
>> +/// let mut fence = fctx.as_arc_borrow().new_fence(data)?;
>> +///
>> +/// let cb_data = CallbackData::new();
>> +/// fence.register_callback(cb_data);
>> +/// // fence.begin_signalling();
>> +/// fence.signal()?;
>> +/// // Now check wehether the callback was actually executed.
>> +/// // SAFETY: `fence.signal()` above works sequentially. We just check here whether the signalling
>> +/// // actually did set the boolean correctly.
>> +/// unsafe { assert_eq!(CHECKER.load(atomic::Ordering::Relaxed), true); }
>> +///
>> +/// Ok::<(), Error>(())
>> +/// ```
>> +#[pin_data]
>> +pub struct DmaFence<T> {
>> + /// The actual dma_fence passed to C.
>> + #[pin]
>> + inner: Opaque<bindings::dma_fence>,
>> + /// User data.
>> + #[pin]
>> + data: T,
>
> A DmaFence is a cross-device synchronization mechanism that can (and
> will) cross the driver boundary (one driver can wait on a fence emitted
> by a different driver). As such, I don't think embedding a generic T in
> the DmaFence and considering it's the object being passed around is
> going to work, because, how can one driver know the T chosen by the
> driver that created the fence? If you want to have some fence emitter
> data attached to the DmaFence allocation, you'll need two kind of
> objects:
>
> - one that's type agnostic and on which you can do the callback
> registration/unregistration, signalling checks, and generally all
> type-agnostic operations. That's basically just a wrapper around a
> bindings::dma_fence implementing AlwaysRefCounted.
> - one that has the extra data and fctx, with a way to transmute from a
> generic fence to a implementer specific one in case the driver wants
> to do something special when waiting on its own fences (check done
> with the fence ops in C, I don't know how that translates in rust)
If `data` is moved to the end of struct and `DmaFence<T>` changed to
`DmaFence<T: ?Sized>`, you would also gain the ability to coerce `DmaFence<T>`
to `DmaFence<dyn Trait>`, e.g. `DmaFence<dyn Any>`.
Best,
Gary
>
>> + /// Marks whether the fence is currently in the signalling critical section.
>> + signalling: bool,
>> + /// A boolean needed for the C backend's lockdep guard.
>> + signalling_cookie: bool,
>> + /// A reference to the associated [`DmaFenceCtx`] so that it cannot be dropped while there are
>> + /// still fences around.
>> + fctx: Arc<DmaFenceCtx>,
>> +}
Powered by blists - more mailing lists