Buffer Sharing and Synchronization

The dma-buf subsystem provides the framework for sharing buffers for hardware (DMA) access across multiple device drivers and subsystems, and for synchronizing asynchronous hardware access.

This is used, for example, by drm “prime” multi-GPU support, but is of course not limited to GPU use cases.

The three main components of this are: (1) dma-buf, representing a sg_table and exposed to userspace as a file descriptor to allow passing between devices, (2) fence, which provides a mechanism to signal when one device as finished access, and (3) reservation, which manages the shared or exclusive fence(s) associated with the buffer.

Shared DMA Buffers

struct dma_buf * dma_buf_export(const struct dma_buf_export_info * exp_info)

Creates a new dma_buf, and associates an anon file with this buffer, so it can be exported. Also connect the allocator specific data and ops to the buffer. Additionally, provide a name string for exporter; useful in debugging.

Parameters

const struct dma_buf_export_info * exp_info
[in] holds all the export related information provided by the exporter. see struct dma_buf_export_info for further details.

Description

Returns, on success, a newly created dma_buf object, which wraps the supplied private data and operations for dma_buf_ops. On either missing ops, or error in allocating struct dma_buf, will return negative error.

int dma_buf_fd(struct dma_buf * dmabuf, int flags)

returns a file descriptor for the given dma_buf

Parameters

struct dma_buf * dmabuf
[in] pointer to dma_buf for which fd is required.
int flags
[in] flags to give to fd

Description

On success, returns an associated ‘fd’. Else, returns error.

struct dma_buf * dma_buf_get(int fd)

returns the dma_buf structure related to an fd

Parameters

int fd
[in] fd associated with the dma_buf to be returned

Description

On success, returns the dma_buf structure associated with an fd; uses file’s refcounting done by fget to increase refcount. returns ERR_PTR otherwise.

void dma_buf_put(struct dma_buf * dmabuf)

decreases refcount of the buffer

Parameters

struct dma_buf * dmabuf
[in] buffer to reduce refcount of

Description

Uses file’s refcounting done implicitly by fput()

struct dma_buf_attachment * dma_buf_attach(struct dma_buf * dmabuf, struct device * dev)

Add the device to dma_buf’s attachments list; optionally, calls attach() of dma_buf_ops to allow device-specific attach functionality

Parameters

struct dma_buf * dmabuf
[in] buffer to attach device to.
struct device * dev
[in] device to be attached.

Description

Returns struct dma_buf_attachment * for this attachment; returns ERR_PTR on error.

void dma_buf_detach(struct dma_buf * dmabuf, struct dma_buf_attachment * attach)

Remove the given attachment from dmabuf’s attachments list; optionally calls detach() of dma_buf_ops for device-specific detach

Parameters

struct dma_buf * dmabuf
[in] buffer to detach from.
struct dma_buf_attachment * attach
[in] attachment to be detached; is free’d after this call.
struct sg_table * dma_buf_map_attachment(struct dma_buf_attachment * attach, enum dma_data_direction direction)

Returns the scatterlist table of the attachment; mapped into _device_ address space. Is a wrapper for map_dma_buf() of the dma_buf_ops.

Parameters

struct dma_buf_attachment * attach
[in] attachment whose scatterlist is to be returned
enum dma_data_direction direction
[in] direction of DMA transfer

Description

Returns sg_table containing the scatterlist to be returned; returns ERR_PTR on error.

void dma_buf_unmap_attachment(struct dma_buf_attachment * attach, struct sg_table * sg_table, enum dma_data_direction direction)

unmaps and decreases usecount of the buffer;might deallocate the scatterlist associated. Is a wrapper for unmap_dma_buf() of dma_buf_ops.

Parameters

struct dma_buf_attachment * attach
[in] attachment to unmap buffer from
struct sg_table * sg_table
[in] scatterlist info of the buffer to unmap
enum dma_data_direction direction
[in] direction of DMA transfer
int dma_buf_begin_cpu_access(struct dma_buf * dmabuf, enum dma_data_direction direction)

Must be called before accessing a dma_buf from the cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific preparations. Coherency is only guaranteed in the specified range for the specified access direction.

Parameters

struct dma_buf * dmabuf
[in] buffer to prepare cpu access for.
enum dma_data_direction direction
[in] length of range for cpu access.

Description

Can return negative error values, returns 0 on success.

int dma_buf_end_cpu_access(struct dma_buf * dmabuf, enum dma_data_direction direction)

Must be called after accessing a dma_buf from the cpu in the kernel context. Calls end_cpu_access to allow exporter-specific actions. Coherency is only guaranteed in the specified range for the specified access direction.

Parameters

struct dma_buf * dmabuf
[in] buffer to complete cpu access for.
enum dma_data_direction direction
[in] length of range for cpu access.

Description

Can return negative error values, returns 0 on success.

void * dma_buf_kmap_atomic(struct dma_buf * dmabuf, unsigned long page_num)

Map a page of the buffer object into kernel address space. The same restrictions as for kmap_atomic and friends apply.

Parameters

struct dma_buf * dmabuf
[in] buffer to map page from.
unsigned long page_num
[in] page in PAGE_SIZE units to map.

Description

This call must always succeed, any necessary preparations that might fail need to be done in begin_cpu_access.

void dma_buf_kunmap_atomic(struct dma_buf * dmabuf, unsigned long page_num, void * vaddr)

Unmap a page obtained by dma_buf_kmap_atomic.

Parameters

struct dma_buf * dmabuf
[in] buffer to unmap page from.
unsigned long page_num
[in] page in PAGE_SIZE units to unmap.
void * vaddr
[in] kernel space pointer obtained from dma_buf_kmap_atomic.

Description

This call must always succeed.

void * dma_buf_kmap(struct dma_buf * dmabuf, unsigned long page_num)

Map a page of the buffer object into kernel address space. The same restrictions as for kmap and friends apply.

Parameters

struct dma_buf * dmabuf
[in] buffer to map page from.
unsigned long page_num
[in] page in PAGE_SIZE units to map.

Description

This call must always succeed, any necessary preparations that might fail need to be done in begin_cpu_access.

void dma_buf_kunmap(struct dma_buf * dmabuf, unsigned long page_num, void * vaddr)

Unmap a page obtained by dma_buf_kmap.

Parameters

struct dma_buf * dmabuf
[in] buffer to unmap page from.
unsigned long page_num
[in] page in PAGE_SIZE units to unmap.
void * vaddr
[in] kernel space pointer obtained from dma_buf_kmap.

Description

This call must always succeed.

int dma_buf_mmap(struct dma_buf * dmabuf, struct vm_area_struct * vma, unsigned long pgoff)

Setup up a userspace mmap with the given vma

Parameters

struct dma_buf * dmabuf
[in] buffer that should back the vma
struct vm_area_struct * vma
[in] vma for the mmap
unsigned long pgoff
[in] offset in pages where this mmap should start within the dma-buf buffer.

Description

This function adjusts the passed in vma so that it points at the file of the dma_buf operation. It also adjusts the starting pgoff and does bounds checking on the size of the vma. Then it calls the exporters mmap function to set up the mapping.

Can return negative error values, returns 0 on success.

void * dma_buf_vmap(struct dma_buf * dmabuf)

Create virtual mapping for the buffer object into kernel address space. Same restrictions as for vmap and friends apply.

Parameters

struct dma_buf * dmabuf
[in] buffer to vmap

Description

This call may fail due to lack of virtual mapping address space. These calls are optional in drivers. The intended use for them is for mapping objects linear in kernel space for high use objects. Please attempt to use kmap/kunmap before thinking about these interfaces.

Returns NULL on error.

void dma_buf_vunmap(struct dma_buf * dmabuf, void * vaddr)

Unmap a vmap obtained by dma_buf_vmap.

Parameters

struct dma_buf * dmabuf
[in] buffer to vunmap
void * vaddr
[in] vmap to vunmap
struct dma_buf_ops

operations possible on struct dma_buf

Definition

struct dma_buf_ops {
  int (* attach) (struct dma_buf *, struct device *,struct dma_buf_attachment *);
  void (* detach) (struct dma_buf *, struct dma_buf_attachment *);
  struct sg_table * (* map_dma_buf) (struct dma_buf_attachment *,enum dma_data_direction);
  void (* unmap_dma_buf) (struct dma_buf_attachment *,struct sg_table *,enum dma_data_direction);
  void (* release) (struct dma_buf *);
  int (* begin_cpu_access) (struct dma_buf *, enum dma_data_direction);
  int (* end_cpu_access) (struct dma_buf *, enum dma_data_direction);
  void *(* kmap_atomic) (struct dma_buf *, unsigned long);
  void (* kunmap_atomic) (struct dma_buf *, unsigned long, void *);
  void *(* kmap) (struct dma_buf *, unsigned long);
  void (* kunmap) (struct dma_buf *, unsigned long, void *);
  int (* mmap) (struct dma_buf *, struct vm_area_struct *vma);
  void *(* vmap) (struct dma_buf *);
  void (* vunmap) (struct dma_buf *, void *vaddr);
};

Members

attach
[optional] allows different devices to ‘attach’ themselves to the given buffer. It might return -EBUSY to signal that backing storage is already allocated and incompatible with the requirements of requesting device.
detach
[optional] detach a given device from this buffer.
map_dma_buf
returns list of scatter pages allocated, increases usecount of the buffer. Requires atleast one attach to be called before. Returned sg list should already be mapped into _device_ address space. This call may sleep. May also return -EINTR. Should return -EINVAL if attach hasn’t been called yet.
unmap_dma_buf
decreases usecount of buffer, might deallocate scatter pages.
release
release this buffer; to be called after the last dma_buf_put.
begin_cpu_access
[optional] called before cpu access to invalidate cpu caches and allocate backing storage (if not yet done) respectively pin the object into memory.
end_cpu_access
[optional] called after cpu access to flush caches.
kmap_atomic
maps a page from the buffer into kernel address space, users may not block until the subsequent unmap call. This callback must not sleep.
kunmap_atomic
[optional] unmaps a atomically mapped page from the buffer. This Callback must not sleep.
kmap
maps a page from the buffer into kernel address space.
kunmap
[optional] unmaps a page from the buffer.
mmap
used to expose the backing storage to userspace. Note that the mapping needs to be coherent - if the exporter doesn’t directly support this, it needs to fake coherency by shooting down any ptes when transitioning away from the cpu domain.
vmap
[optional] creates a virtual mapping for the buffer into kernel address space. Same restrictions as for vmap and friends apply.
vunmap
[optional] unmaps a vmap from the buffer
struct dma_buf

shared buffer object

Definition

struct dma_buf {
  size_t size;
  struct file * file;
  struct list_head attachments;
  const struct dma_buf_ops * ops;
  struct mutex lock;
  unsigned vmapping_counter;
  void * vmap_ptr;
  const char * exp_name;
  struct module * owner;
  struct list_head list_node;
  void * priv;
  struct reservation_object * resv;
  wait_queue_head_t poll;
  struct dma_buf_poll_cb_t cb_excl;
  struct dma_buf_poll_cb_t cb_shared;
};

Members

size
size of the buffer
file
file pointer used for sharing buffers across, and for refcounting.
attachments
list of dma_buf_attachment that denotes all devices attached.
ops
dma_buf_ops associated with this buffer object.
lock
used internally to serialize list manipulation, attach/detach and vmap/unmap
vmapping_counter
used internally to refcnt the vmaps
vmap_ptr
the current vmap ptr if vmapping_counter > 0
exp_name
name of the exporter; useful for debugging.
owner
pointer to exporter module; used for refcounting when exporter is a kernel module.
list_node
node for dma_buf accounting and debugging.
priv
exporter specific private data for this buffer object.
resv
reservation object linked to this dma-buf
poll
for userspace poll support
cb_excl
for userspace poll support
cb_shared
for userspace poll support
struct dma_buf_attachment

holds device-buffer attachment data

Definition

struct dma_buf_attachment {
  struct dma_buf * dmabuf;
  struct device * dev;
  struct list_head node;
  void * priv;
};

Members

dmabuf
buffer for this attachment.
dev
device attached to the buffer.
node
list of dma_buf_attachment.
priv
exporter specific attachment data.

Description

This structure holds the attachment information between the dma_buf buffer and its user device(s). The list contains one attachment struct per device attached to the buffer.

struct dma_buf_export_info

holds information needed to export a dma_buf

Definition

struct dma_buf_export_info {
  const char * exp_name;
  struct module * owner;
  const struct dma_buf_ops * ops;
  size_t size;
  int flags;
  struct reservation_object * resv;
  void * priv;
};

Members

exp_name
name of the exporter - useful for debugging.
owner
pointer to exporter module - used for refcounting kernel module
ops
Attach allocator-defined dma buf ops to the new buffer
size
Size of the buffer
flags
mode flags for the file
resv
reservation-object, NULL to allocate default one
priv
Attach private data of allocator to this buffer

Description

This structure holds the information required to export the buffer. Used with dma_buf_export() only.

DEFINE_DMA_BUF_EXPORT_INFO(name)

Parameters

name
export-info name
void get_dma_buf(struct dma_buf * dmabuf)

convenience wrapper for get_file.

Parameters

struct dma_buf * dmabuf
[in] pointer to dma_buf

Description

Increments the reference count on the dma-buf, needed in case of drivers that either need to create additional references to the dmabuf on the kernel side. For example, an exporter that needs to keep a dmabuf ptr so that subsequent exports don’t create a new dmabuf.

Reservation Objects

The reservation object provides a mechanism to manage shared and exclusive fences associated with a buffer. A reservation object can have attached one exclusive fence (normally associated with write operations) or N shared fences (read operations). The RCU mechanism is used to protect read access to fences from locked write-side updates.

int reservation_object_reserve_shared(struct reservation_object * obj)

Reserve space to add a shared fence to a reservation_object.

Parameters

struct reservation_object * obj
reservation object

Description

Should be called before reservation_object_add_shared_fence(). Must be called with obj->lock held.

RETURNS Zero for success, or -errno

void reservation_object_add_shared_fence(struct reservation_object * obj, struct dma_fence * fence)

Add a fence to a shared slot

Parameters

struct reservation_object * obj
the reservation object
struct dma_fence * fence
the shared fence to add

Description

Add a fence to a shared slot, obj->lock must be held, and reservation_object_reserve_shared() has been called.

void reservation_object_add_excl_fence(struct reservation_object * obj, struct dma_fence * fence)

Add an exclusive fence.

Parameters

struct reservation_object * obj
the reservation object
struct dma_fence * fence
the shared fence to add

Description

Add a fence to the exclusive slot. The obj->lock must be held.

int reservation_object_get_fences_rcu(struct reservation_object * obj, struct dma_fence ** pfence_excl, unsigned * pshared_count, struct dma_fence *** pshared)

Get an object’s shared and exclusive fences without update side lock held

Parameters

struct reservation_object * obj
the reservation object
struct dma_fence ** pfence_excl
the returned exclusive fence (or NULL)
unsigned * pshared_count
the number of shared fences returned
struct dma_fence *** pshared
the array of shared fence ptrs returned (array is krealloc’d to the required size, and must be freed by caller)

Description

RETURNS Zero or -errno

long reservation_object_wait_timeout_rcu(struct reservation_object * obj, bool wait_all, bool intr, unsigned long timeout)

Wait on reservation’s objects shared and/or exclusive fences.

Parameters

struct reservation_object * obj
the reservation object
bool wait_all
if true, wait on all fences, else wait on just exclusive fence
bool intr
if true, do interruptible wait
unsigned long timeout
timeout value in jiffies or zero to return immediately

Description

RETURNS Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or greater than zer on success.

bool reservation_object_test_signaled_rcu(struct reservation_object * obj, bool test_all)

Test if a reservation object’s fences have been signaled.

Parameters

struct reservation_object * obj
the reservation object
bool test_all
if true, test all fences, otherwise only test the exclusive fence

Description

RETURNS true if all fences signaled, else false

struct reservation_object_list

a list of shared fences

Definition

struct reservation_object_list {
  struct rcu_head rcu;
  u32 shared_count;
  u32 shared_max;
  struct dma_fence __rcu * shared[];
};

Members

rcu
for internal use
shared_count
table of shared fences
shared_max
for growing shared fence table
shared[]
shared fence table
struct reservation_object

a reservation object manages fences for a buffer

Definition

struct reservation_object {
  struct ww_mutex lock;
  seqcount_t seq;
  struct dma_fence __rcu * fence_excl;
  struct reservation_object_list __rcu * fence;
  struct reservation_object_list * staged;
};

Members

lock
update side lock
seq
sequence count for managing RCU read-side synchronization
fence_excl
the exclusive fence, if there is one currently
fence
list of current shared fences
staged
staged copy of shared fences for RCU updates
void reservation_object_init(struct reservation_object * obj)

initialize a reservation object

Parameters

struct reservation_object * obj
the reservation object
void reservation_object_fini(struct reservation_object * obj)

destroys a reservation object

Parameters

struct reservation_object * obj
the reservation object
struct reservation_object_list * reservation_object_get_list(struct reservation_object * obj)

get the reservation object’s shared fence list, with update-side lock held

Parameters

struct reservation_object * obj
the reservation object

Description

Returns the shared fence list. Does NOT take references to the fence. The obj->lock must be held.

struct dma_fence * reservation_object_get_excl(struct reservation_object * obj)

get the reservation object’s exclusive fence, with update-side lock held

Parameters

struct reservation_object * obj
the reservation object

Description

Returns the exclusive fence (if any). Does NOT take a reference. The obj->lock must be held.

RETURNS The exclusive fence or NULL

struct dma_fence * reservation_object_get_excl_rcu(struct reservation_object * obj)

get the reservation object’s exclusive fence, without lock held.

Parameters

struct reservation_object * obj
the reservation object

Description

If there is an exclusive fence, this atomically increments it’s reference count and returns it.

RETURNS The exclusive fence or NULL if none

DMA Fences

u64 dma_fence_context_alloc(unsigned num)

allocate an array of fence contexts

Parameters

unsigned num
[in] amount of contexts to allocate

Description

This function will return the first index of the number of fences allocated. The fence context is used for setting fence->context to a unique number.

int dma_fence_signal_locked(struct dma_fence * fence)

signal completion of a fence

Parameters

struct dma_fence * fence
the fence to signal

Description

Signal completion for software callbacks on a fence, this will unblock dma_fence_wait() calls and run all the callbacks added with dma_fence_add_callback(). Can be called multiple times, but since a fence can only go from unsignaled to signaled state, it will only be effective the first time.

Unlike dma_fence_signal, this function must be called with fence->lock held.

int dma_fence_signal(struct dma_fence * fence)

signal completion of a fence

Parameters

struct dma_fence * fence
the fence to signal

Description

Signal completion for software callbacks on a fence, this will unblock dma_fence_wait() calls and run all the callbacks added with dma_fence_add_callback(). Can be called multiple times, but since a fence can only go from unsignaled to signaled state, it will only be effective the first time.

signed long dma_fence_wait_timeout(struct dma_fence * fence, bool intr, signed long timeout)

sleep until the fence gets signaled or until timeout elapses

Parameters

struct dma_fence * fence
[in] the fence to wait on
bool intr
[in] if true, do an interruptible wait
signed long timeout
[in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT

Description

Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or the remaining timeout in jiffies on success. Other error values may be returned on custom implementations.

Performs a synchronous wait on this fence. It is assumed the caller directly or indirectly (buf-mgr between reservation and committing) holds a reference to the fence, otherwise the fence might be freed before return, resulting in undefined behavior.

void dma_fence_enable_sw_signaling(struct dma_fence * fence)

enable signaling on fence

Parameters

struct dma_fence * fence
[in] the fence to enable

Description

this will request for sw signaling to be enabled, to make the fence complete as soon as possible

int dma_fence_add_callback(struct dma_fence * fence, struct dma_fence_cb * cb, dma_fence_func_t func)

add a callback to be called when the fence is signaled

Parameters

struct dma_fence * fence
[in] the fence to wait on
struct dma_fence_cb * cb
[in] the callback to register
dma_fence_func_t func
[in] the function to call

Description

cb will be initialized by dma_fence_add_callback, no initialization by the caller is required. Any number of callbacks can be registered to a fence, but a callback can only be registered to one fence at a time.

Note that the callback can be called from an atomic context. If fence is already signaled, this function will return -ENOENT (and not call the callback)

Add a software callback to the fence. Same restrictions apply to refcount as it does to dma_fence_wait, however the caller doesn’t need to keep a refcount to fence afterwards: when software access is enabled, the creator of the fence is required to keep the fence alive until after it signals with dma_fence_signal. The callback itself can be called from irq context.

bool dma_fence_remove_callback(struct dma_fence * fence, struct dma_fence_cb * cb)

remove a callback from the signaling list

Parameters

struct dma_fence * fence
[in] the fence to wait on
struct dma_fence_cb * cb
[in] the callback to remove

Description

Remove a previously queued callback from the fence. This function returns true if the callback is successfully removed, or false if the fence has already been signaled.

WARNING: Cancelling a callback should only be done if you really know what you’re doing, since deadlocks and race conditions could occur all too easily. For this reason, it should only ever be done on hardware lockup recovery, with a reference held to the fence.

signed long dma_fence_default_wait(struct dma_fence * fence, bool intr, signed long timeout)

default sleep until the fence gets signaled or until timeout elapses

Parameters

struct dma_fence * fence
[in] the fence to wait on
bool intr
[in] if true, do an interruptible wait
signed long timeout
[in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT

Description

Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or the remaining timeout in jiffies on success. If timeout is zero the value one is returned if the fence is already signaled for consistency with other functions taking a jiffies timeout.

signed long dma_fence_wait_any_timeout(struct dma_fence ** fences, uint32_t count, bool intr, signed long timeout, uint32_t * idx)

sleep until any fence gets signaled or until timeout elapses

Parameters

struct dma_fence ** fences
[in] array of fences to wait on
uint32_t count
[in] number of fences to wait on
bool intr
[in] if true, do an interruptible wait
signed long timeout
[in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT
uint32_t * idx
[out] the first signaled fence index, meaningful only on positive return

Description

Returns -EINVAL on custom fence wait implementation, -ERESTARTSYS if interrupted, 0 if the wait timed out, or the remaining timeout in jiffies on success.

Synchronous waits for the first fence in the array to be signaled. The caller needs to hold a reference to all fences in the array, otherwise a fence might be freed before return, resulting in undefined behavior.

void dma_fence_init(struct dma_fence * fence, const struct dma_fence_ops * ops, spinlock_t * lock, u64 context, unsigned seqno)

Initialize a custom fence.

Parameters

struct dma_fence * fence
[in] the fence to initialize
const struct dma_fence_ops * ops
[in] the dma_fence_ops for operations on this fence
spinlock_t * lock
[in] the irqsafe spinlock to use for locking this fence
u64 context
[in] the execution context this fence is run on
unsigned seqno
[in] a linear increasing sequence number for this context

Description

Initializes an allocated fence, the caller doesn’t have to keep its refcount after committing with this fence, but it will need to hold a refcount again if dma_fence_ops.enable_signaling gets called. This can be used for other implementing other types of fence.

context and seqno are used for easy comparison between fences, allowing to check which fence is later by simply using dma_fence_later.

struct dma_fence

software synchronization primitive

Definition

struct dma_fence {
  struct kref refcount;
  const struct dma_fence_ops * ops;
  struct rcu_head rcu;
  struct list_head cb_list;
  spinlock_t * lock;
  u64 context;
  unsigned seqno;
  unsigned long flags;
  ktime_t timestamp;
  int status;
};

Members

refcount
refcount for this fence
ops
dma_fence_ops associated with this fence
rcu
used for releasing fence with kfree_rcu
cb_list
list of all callbacks to call
lock
spin_lock_irqsave used for locking
context
execution context this fence belongs to, returned by dma_fence_context_alloc()
seqno
the sequence number of this fence inside the execution context, can be compared to decide which fence would be signaled later.
flags
A mask of DMA_FENCE_FLAG_* defined below
timestamp
Timestamp when the fence was signaled.
status
Optional, only valid if < 0, must be set before calling dma_fence_signal, indicates that the fence has completed with an error.

Description

the flags member must be manipulated and read using the appropriate atomic ops (bit_*), so taking the spinlock will not be needed most of the time.

DMA_FENCE_FLAG_SIGNALED_BIT - fence is already signaled DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT - enable_signaling might have been called DMA_FENCE_FLAG_USER_BITS - start of the unused bits, can be used by the implementer of the fence for its own purposes. Can be used in different ways by different fence implementers, so do not rely on this.

Since atomic bitops are used, this is not guaranteed to be the case. Particularly, if the bit was set, but dma_fence_signal was called right before this bit was set, it would have been able to set the DMA_FENCE_FLAG_SIGNALED_BIT, before enable_signaling was called. Adding a check for DMA_FENCE_FLAG_SIGNALED_BIT after setting DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT closes this race, and makes sure that after dma_fence_signal was called, any enable_signaling call will have either been completed, or never called at all.

struct dma_fence_cb

callback for dma_fence_add_callback

Definition

struct dma_fence_cb {
  struct list_head node;
  dma_fence_func_t func;
};

Members

node
used by dma_fence_add_callback to append this struct to fence::cb_list
func
dma_fence_func_t to call

Description

This struct will be initialized by dma_fence_add_callback, additional data can be passed along by embedding dma_fence_cb in another struct.

struct dma_fence_ops

operations implemented for fence

Definition

struct dma_fence_ops {
  const char * (* get_driver_name) (struct dma_fence *fence);
  const char * (* get_timeline_name) (struct dma_fence *fence);
  bool (* enable_signaling) (struct dma_fence *fence);
  bool (* signaled) (struct dma_fence *fence);
  signed long (* wait) (struct dma_fence *fence,bool intr, signed long timeout);
  void (* release) (struct dma_fence *fence);
  int (* fill_driver_data) (struct dma_fence *fence, void *data, int size);
  void (* fence_value_str) (struct dma_fence *fence, char *str, int size);
  void (* timeline_value_str) (struct dma_fence *fence,char *str, int size);
};

Members

get_driver_name
returns the driver name.
get_timeline_name
return the name of the context this fence belongs to.
enable_signaling
enable software signaling of fence.
signaled
[optional] peek whether the fence is signaled, can be null.
wait
custom wait implementation, or dma_fence_default_wait.
release
[optional] called on destruction of fence, can be null
fill_driver_data
[optional] callback to fill in free-form debug info Returns amount of bytes filled, or -errno.
fence_value_str
[optional] fills in the value of the fence as a string
timeline_value_str
[optional] fills in the current value of the timeline as a string

Description

Notes on enable_signaling: For fence implementations that have the capability for hw->hw signaling, they can implement this op to enable the necessary irqs, or insert commands into cmdstream, etc. This is called in the first wait() or add_callback() path to let the fence implementation know that there is another driver waiting on the signal (ie. hw->sw case).

This function can be called called from atomic context, but not from irq context, so normal spinlocks can be used.

A return value of false indicates the fence already passed, or some failure occurred that made it impossible to enable signaling. True indicates successful enabling.

fence->status may be set in enable_signaling, but only when false is returned.

Calling dma_fence_signal before enable_signaling is called allows for a tiny race window in which enable_signaling is called during, before, or after dma_fence_signal. To fight this, it is recommended that before enable_signaling returns true an extra reference is taken on the fence, to be released when the fence is signaled. This will mean dma_fence_signal will still be called twice, but the second time will be a noop since it was already signaled.

Notes on signaled: May set fence->status if returning true.

Notes on wait: Must not be NULL, set to dma_fence_default_wait for default implementation. the dma_fence_default_wait implementation should work for any fence, as long as enable_signaling works correctly.

Must return -ERESTARTSYS if the wait is intr = true and the wait was interrupted, and remaining jiffies if fence has signaled, or 0 if wait timed out. Can also return other error values on custom implementations, which should be treated as if the fence is signaled. For example a hardware lockup could be reported like that.

Notes on release: Can be NULL, this function allows additional commands to run on destruction of the fence. Can be called from irq context. If pointer is set to NULL, kfree will get called instead.

void dma_fence_put(struct dma_fence * fence)

decreases refcount of the fence

Parameters

struct dma_fence * fence
[in] fence to reduce refcount of
struct dma_fence * dma_fence_get(struct dma_fence * fence)

increases refcount of the fence

Parameters

struct dma_fence * fence
[in] fence to increase refcount of

Description

Returns the same fence, with refcount increased by 1.

struct dma_fence * dma_fence_get_rcu(struct dma_fence * fence)

get a fence from a reservation_object_list with rcu read lock

Parameters

struct dma_fence * fence
[in] fence to increase refcount of

Description

Function returns NULL if no refcount could be obtained, or the fence.

struct dma_fence * dma_fence_get_rcu_safe(struct dma_fence *__rcu * fencep)

acquire a reference to an RCU tracked fence

Parameters

struct dma_fence *__rcu * fencep
[in] pointer to fence to increase refcount of

Description

Function returns NULL if no refcount could be obtained, or the fence. This function handles acquiring a reference to a fence that may be reallocated within the RCU grace period (such as with SLAB_DESTROY_BY_RCU), so long as the caller is using RCU on the pointer to the fence.

An alternative mechanism is to employ a seqlock to protect a bunch of fences, such as used by struct reservation_object. When using a seqlock, the seqlock must be taken before and checked after a reference to the fence is acquired (as shown here).

The caller is required to hold the RCU read lock.

bool dma_fence_is_signaled_locked(struct dma_fence * fence)

Return an indication if the fence is signaled yet.

Parameters

struct dma_fence * fence
[in] the fence to check

Description

Returns true if the fence was already signaled, false if not. Since this function doesn’t enable signaling, it is not guaranteed to ever return true if dma_fence_add_callback, dma_fence_wait or dma_fence_enable_sw_signaling haven’t been called before.

This function requires fence->lock to be held.

bool dma_fence_is_signaled(struct dma_fence * fence)

Return an indication if the fence is signaled yet.

Parameters

struct dma_fence * fence
[in] the fence to check

Description

Returns true if the fence was already signaled, false if not. Since this function doesn’t enable signaling, it is not guaranteed to ever return true if dma_fence_add_callback, dma_fence_wait or dma_fence_enable_sw_signaling haven’t been called before.

It’s recommended for seqno fences to call dma_fence_signal when the operation is complete, it makes it possible to prevent issues from wraparound between time of issue and time of use by checking the return value of this function before calling hardware-specific wait instructions.

bool dma_fence_is_later(struct dma_fence * f1, struct dma_fence * f2)

return if f1 is chronologically later than f2

Parameters

struct dma_fence * f1
[in] the first fence from the same context
struct dma_fence * f2
[in] the second fence from the same context

Description

Returns true if f1 is chronologically later than f2. Both fences must be from the same context, since a seqno is not re-used across contexts.

struct dma_fence * dma_fence_later(struct dma_fence * f1, struct dma_fence * f2)

return the chronologically later fence

Parameters

struct dma_fence * f1
[in] the first fence from the same context
struct dma_fence * f2
[in] the second fence from the same context

Description

Returns NULL if both fences are signaled, otherwise the fence that would be signaled last. Both fences must be from the same context, since a seqno is not re-used across contexts.

signed long dma_fence_wait(struct dma_fence * fence, bool intr)

sleep until the fence gets signaled

Parameters

struct dma_fence * fence
[in] the fence to wait on
bool intr
[in] if true, do an interruptible wait

Description

This function will return -ERESTARTSYS if interrupted by a signal, or 0 if the fence was signaled. Other error values may be returned on custom implementations.

Performs a synchronous wait on this fence. It is assumed the caller directly or indirectly holds a reference to the fence, otherwise the fence might be freed before return, resulting in undefined behavior.

Seqno Hardware Fences

struct seqno_fence * to_seqno_fence(struct dma_fence * fence)

cast a fence to a seqno_fence

Parameters

struct dma_fence * fence
fence to cast to a seqno_fence

Description

Returns NULL if the fence is not a seqno_fence, or the seqno_fence otherwise.

void seqno_fence_init(struct seqno_fence * fence, spinlock_t * lock, struct dma_buf * sync_buf, uint32_t context, uint32_t seqno_ofs, uint32_t seqno, enum seqno_fence_condition cond, const struct dma_fence_ops * ops)

initialize a seqno fence

Parameters

struct seqno_fence * fence
seqno_fence to initialize
spinlock_t * lock
pointer to spinlock to use for fence
struct dma_buf * sync_buf
buffer containing the memory location to signal on
uint32_t context
the execution context this fence is a part of
uint32_t seqno_ofs
the offset within sync_buf
uint32_t seqno
the sequence # to signal on
enum seqno_fence_condition cond
fence wait condition
const struct dma_fence_ops * ops
the fence_ops for operations on this seqno fence

Description

This function initializes a struct seqno_fence with passed parameters, and takes a reference on sync_buf which is released on fence destruction.

A seqno_fence is a dma_fence which can complete in software when enable_signaling is called, but it also completes when (s32)((sync_buf)[seqno_ofs] - seqno) >= 0 is true

The seqno_fence will take a refcount on the sync_buf until it’s destroyed, but actual lifetime of sync_buf may be longer if one of the callers take a reference to it.

Certain hardware have instructions to insert this type of wait condition in the command stream, so no intervention from software would be needed. This type of fence can be destroyed before completed, however a reference on the sync_buf dma-buf can be taken. It is encouraged to re-use the same dma-buf for sync_buf, since mapping or unmapping the sync_buf to the device’s vm can be expensive.

It is recommended for creators of seqno_fence to call dma_fence_signal() before destruction. This will prevent possible issues from wraparound at time of issue vs time of check, since users can check dma_fence_is_signaled() before submitting instructions for the hardware to wait on the fence. However, when ops.enable_signaling is not called, it doesn’t have to be done as soon as possible, just before there’s any real danger of seqno wraparound.

DMA Fence Array

struct dma_fence_array * dma_fence_array_create(int num_fences, struct dma_fence ** fences, u64 context, unsigned seqno, bool signal_on_any)

Create a custom fence array

Parameters

int num_fences
[in] number of fences to add in the array
struct dma_fence ** fences
[in] array containing the fences
u64 context
[in] fence context to use
unsigned seqno
[in] sequence number to use
bool signal_on_any
[in] signal on any fence in the array

Description

Allocate a dma_fence_array object and initialize the base fence with dma_fence_init(). In case of error it returns NULL.

The caller should allocate the fences array with num_fences size and fill it with the fences it wants to add to the object. Ownership of this array is taken and dma_fence_put() is used on each fence on release.

If signal_on_any is true the fence array signals if any fence in the array signals, otherwise it signals when all fences in the array signal.

struct dma_fence_array_cb

callback helper for fence array

Definition

struct dma_fence_array_cb {
  struct dma_fence_cb cb;
  struct dma_fence_array * array;
};

Members

cb
fence callback structure for signaling
array
reference to the parent fence array object
struct dma_fence_array

fence to represent an array of fences

Definition

struct dma_fence_array {
  struct dma_fence base;
  spinlock_t lock;
  unsigned num_fences;
  atomic_t num_pending;
  struct dma_fence ** fences;
};

Members

base
fence base class
lock
spinlock for fence handling
num_fences
number of fences in the array
num_pending
fences in the array still pending
fences
array of the fences
bool dma_fence_is_array(struct dma_fence * fence)

check if a fence is from the array subsclass

Parameters

struct dma_fence * fence
fence to test

Description

Return true if it is a dma_fence_array and false otherwise.

struct dma_fence_array * to_dma_fence_array(struct dma_fence * fence)

cast a fence to a dma_fence_array

Parameters

struct dma_fence * fence
fence to cast to a dma_fence_array

Description

Returns NULL if the fence is not a dma_fence_array, or the dma_fence_array otherwise.

DMA Fence uABI/Sync File

struct sync_file * sync_file_create(struct dma_fence * fence)

creates a sync file

Parameters

struct dma_fence * fence
fence to add to the sync_fence

Description

Creates a sync_file containg fence. Once this is called, the sync_file takes ownership of fence. The sync_file can be released with fput(sync_file->file). Returns the sync_file or NULL in case of error.

struct dma_fence * sync_file_get_fence(int fd)

get the fence related to the sync_file fd

Parameters

int fd
sync_file fd to get the fence from

Description

Ensures fd references a valid sync_file and returns a fence that represents all fence in the sync_file. On error NULL is returned.

struct sync_file

sync file to export to the userspace

Definition

struct sync_file {
  struct file * file;
  struct kref kref;
  char name[32];
#ifdef CONFIG_DEBUG_FS
  struct list_head sync_file_list;
#endif
  wait_queue_head_t wq;
  struct dma_fence * fence;
  struct dma_fence_cb cb;
};

Members

file
file representing this fence
kref
reference count on fence.
name[32]
name of sync_file. Useful for debugging
sync_file_list
membership in global file list
wq
wait queue for fence signaling
fence
fence with the fences in the sync_file
cb
fence callback information