Commit ebb8cb2b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dma-buf-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sumits/dma-buf

Pull dma-buf updates from Sumit Semwal:

 - use of vma_pages instead of explicit computation

 - DocBook and headerdoc updates for dma-buf

* tag 'dma-buf-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sumits/dma-buf:
  dma-buf: use vma_pages()
  fence: add missing descriptions for fence
  doc: update/fixup dma-buf related DocBook
  reservation: add headerdoc comments
  dma-buf: headerdoc fixes
parents 6b15d665 b02da6f8
...@@ -128,16 +128,44 @@ X!Edrivers/base/interface.c ...@@ -128,16 +128,44 @@ X!Edrivers/base/interface.c
!Edrivers/base/platform.c !Edrivers/base/platform.c
!Edrivers/base/bus.c !Edrivers/base/bus.c
</sect1> </sect1>
<sect1><title>Device Drivers DMA Management</title> <sect1>
<title>Buffer Sharing and Synchronization</title>
<para>
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.
</para>
<para>
This is used, for example, by drm "prime" multi-GPU support, but
is of course not limited to GPU use cases.
</para>
<para>
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.
</para>
<sect2><title>dma-buf</title>
!Edrivers/dma-buf/dma-buf.c !Edrivers/dma-buf/dma-buf.c
!Iinclude/linux/dma-buf.h
</sect2>
<sect2><title>reservation</title>
!Pdrivers/dma-buf/reservation.c Reservation Object Overview
!Edrivers/dma-buf/reservation.c
!Iinclude/linux/reservation.h
</sect2>
<sect2><title>fence</title>
!Edrivers/dma-buf/fence.c !Edrivers/dma-buf/fence.c
!Edrivers/dma-buf/seqno-fence.c
!Iinclude/linux/fence.h !Iinclude/linux/fence.h
!Edrivers/dma-buf/seqno-fence.c
!Iinclude/linux/seqno-fence.h !Iinclude/linux/seqno-fence.h
!Edrivers/dma-buf/reservation.c
!Iinclude/linux/reservation.h
!Edrivers/dma-buf/sync_file.c !Edrivers/dma-buf/sync_file.c
!Iinclude/linux/sync_file.h !Iinclude/linux/sync_file.h
</sect2>
</sect1>
<sect1><title>Device Drivers DMA Management</title>
!Edrivers/base/dma-coherent.c !Edrivers/base/dma-coherent.c
!Edrivers/base/dma-mapping.c !Edrivers/base/dma-mapping.c
</sect1> </sect1>
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/reservation.h> #include <linux/reservation.h>
#include <linux/mm.h>
#include <uapi/linux/dma-buf.h> #include <uapi/linux/dma-buf.h>
...@@ -90,7 +91,7 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) ...@@ -90,7 +91,7 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
dmabuf = file->private_data; dmabuf = file->private_data;
/* check for overflowing the buffer's size */ /* check for overflowing the buffer's size */
if (vma->vm_pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > if (vma->vm_pgoff + vma_pages(vma) >
dmabuf->size >> PAGE_SHIFT) dmabuf->size >> PAGE_SHIFT)
return -EINVAL; return -EINVAL;
...@@ -723,11 +724,11 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, ...@@ -723,11 +724,11 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
return -EINVAL; return -EINVAL;
/* check for offset overflow */ /* check for offset overflow */
if (pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) < pgoff) if (pgoff + vma_pages(vma) < pgoff)
return -EOVERFLOW; return -EOVERFLOW;
/* check for overflowing the buffer's size */ /* check for overflowing the buffer's size */
if (pgoff + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) > if (pgoff + vma_pages(vma) >
dmabuf->size >> PAGE_SHIFT) dmabuf->size >> PAGE_SHIFT)
return -EINVAL; return -EINVAL;
......
...@@ -35,6 +35,17 @@ ...@@ -35,6 +35,17 @@
#include <linux/reservation.h> #include <linux/reservation.h>
#include <linux/export.h> #include <linux/export.h>
/**
* DOC: Reservation Object Overview
*
* 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.
*/
DEFINE_WW_CLASS(reservation_ww_class); DEFINE_WW_CLASS(reservation_ww_class);
EXPORT_SYMBOL(reservation_ww_class); EXPORT_SYMBOL(reservation_ww_class);
...@@ -43,9 +54,17 @@ EXPORT_SYMBOL(reservation_seqcount_class); ...@@ -43,9 +54,17 @@ EXPORT_SYMBOL(reservation_seqcount_class);
const char reservation_seqcount_string[] = "reservation_seqcount"; const char reservation_seqcount_string[] = "reservation_seqcount";
EXPORT_SYMBOL(reservation_seqcount_string); EXPORT_SYMBOL(reservation_seqcount_string);
/*
* Reserve space to add a shared fence to a reservation_object, /**
* must be called with obj->lock held. * reservation_object_reserve_shared - Reserve space to add a shared
* fence to a reservation_object.
* @obj: reservation object
*
* Should be called before reservation_object_add_shared_fence(). Must
* be called with obj->lock held.
*
* RETURNS
* Zero for success, or -errno
*/ */
int reservation_object_reserve_shared(struct reservation_object *obj) int reservation_object_reserve_shared(struct reservation_object *obj)
{ {
...@@ -180,7 +199,11 @@ reservation_object_add_shared_replace(struct reservation_object *obj, ...@@ -180,7 +199,11 @@ reservation_object_add_shared_replace(struct reservation_object *obj,
fence_put(old_fence); fence_put(old_fence);
} }
/* /**
* reservation_object_add_shared_fence - Add a fence to a shared slot
* @obj: the reservation object
* @fence: the shared fence to add
*
* Add a fence to a shared slot, obj->lock must be held, and * Add a fence to a shared slot, obj->lock must be held, and
* reservation_object_reserve_shared_fence has been called. * reservation_object_reserve_shared_fence has been called.
*/ */
...@@ -200,6 +223,13 @@ void reservation_object_add_shared_fence(struct reservation_object *obj, ...@@ -200,6 +223,13 @@ void reservation_object_add_shared_fence(struct reservation_object *obj,
} }
EXPORT_SYMBOL(reservation_object_add_shared_fence); EXPORT_SYMBOL(reservation_object_add_shared_fence);
/**
* reservation_object_add_excl_fence - Add an exclusive fence.
* @obj: the reservation object
* @fence: the shared fence to add
*
* Add a fence to the exclusive slot. The obj->lock must be held.
*/
void reservation_object_add_excl_fence(struct reservation_object *obj, void reservation_object_add_excl_fence(struct reservation_object *obj,
struct fence *fence) struct fence *fence)
{ {
...@@ -233,6 +263,18 @@ void reservation_object_add_excl_fence(struct reservation_object *obj, ...@@ -233,6 +263,18 @@ void reservation_object_add_excl_fence(struct reservation_object *obj,
} }
EXPORT_SYMBOL(reservation_object_add_excl_fence); EXPORT_SYMBOL(reservation_object_add_excl_fence);
/**
* reservation_object_get_fences_rcu - Get an object's shared and exclusive
* fences without update side lock held
* @obj: the reservation object
* @pfence_excl: the returned exclusive fence (or NULL)
* @pshared_count: the number of shared fences returned
* @pshared: the array of shared fence ptrs returned (array is krealloc'd to
* the required size, and must be freed by caller)
*
* RETURNS
* Zero or -errno
*/
int reservation_object_get_fences_rcu(struct reservation_object *obj, int reservation_object_get_fences_rcu(struct reservation_object *obj,
struct fence **pfence_excl, struct fence **pfence_excl,
unsigned *pshared_count, unsigned *pshared_count,
...@@ -319,6 +361,18 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, ...@@ -319,6 +361,18 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
} }
EXPORT_SYMBOL_GPL(reservation_object_get_fences_rcu); EXPORT_SYMBOL_GPL(reservation_object_get_fences_rcu);
/**
* reservation_object_wait_timeout_rcu - Wait on reservation's objects
* shared and/or exclusive fences.
* @obj: the reservation object
* @wait_all: if true, wait on all fences, else wait on just exclusive fence
* @intr: if true, do interruptible wait
* @timeout: timeout value in jiffies or zero to return immediately
*
* RETURNS
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
* greater than zer on success.
*/
long reservation_object_wait_timeout_rcu(struct reservation_object *obj, long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
bool wait_all, bool intr, bool wait_all, bool intr,
unsigned long timeout) unsigned long timeout)
...@@ -416,6 +470,16 @@ reservation_object_test_signaled_single(struct fence *passed_fence) ...@@ -416,6 +470,16 @@ reservation_object_test_signaled_single(struct fence *passed_fence)
return ret; return ret;
} }
/**
* reservation_object_test_signaled_rcu - Test if a reservation object's
* fences have been signaled.
* @obj: the reservation object
* @test_all: if true, test all fences, otherwise only test the exclusive
* fence
*
* RETURNS
* true if all fences signaled, else false
*/
bool reservation_object_test_signaled_rcu(struct reservation_object *obj, bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
bool test_all) bool test_all)
{ {
......
...@@ -112,19 +112,24 @@ struct dma_buf_ops { ...@@ -112,19 +112,24 @@ struct dma_buf_ops {
* @file: file pointer used for sharing buffers across, and for refcounting. * @file: file pointer used for sharing buffers across, and for refcounting.
* @attachments: list of dma_buf_attachment that denotes all devices attached. * @attachments: list of dma_buf_attachment that denotes all devices attached.
* @ops: dma_buf_ops associated with this buffer object. * @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. * @exp_name: name of the exporter; useful for debugging.
* @owner: pointer to exporter module; used for refcounting when exporter is a * @owner: pointer to exporter module; used for refcounting when exporter is a
* kernel module. * kernel module.
* @list_node: node for dma_buf accounting and debugging. * @list_node: node for dma_buf accounting and debugging.
* @priv: exporter specific private data for this buffer object. * @priv: exporter specific private data for this buffer object.
* @resv: reservation object linked to this dma-buf * @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 { struct dma_buf {
size_t size; size_t size;
struct file *file; struct file *file;
struct list_head attachments; struct list_head attachments;
const struct dma_buf_ops *ops; const struct dma_buf_ops *ops;
/* mutex to serialize list manipulation, attach/detach and vmap/unmap */
struct mutex lock; struct mutex lock;
unsigned vmapping_counter; unsigned vmapping_counter;
void *vmap_ptr; void *vmap_ptr;
...@@ -188,9 +193,11 @@ struct dma_buf_export_info { ...@@ -188,9 +193,11 @@ struct dma_buf_export_info {
/** /**
* helper macro for exporters; zeros and fills in most common values * helper macro for exporters; zeros and fills in most common values
*
* @name: export-info name
*/ */
#define DEFINE_DMA_BUF_EXPORT_INFO(a) \ #define DEFINE_DMA_BUF_EXPORT_INFO(name) \
struct dma_buf_export_info a = { .exp_name = KBUILD_MODNAME, \ struct dma_buf_export_info name = { .exp_name = KBUILD_MODNAME, \
.owner = THIS_MODULE } .owner = THIS_MODULE }
/** /**
......
...@@ -49,6 +49,8 @@ struct fence_cb; ...@@ -49,6 +49,8 @@ struct fence_cb;
* @timestamp: Timestamp when the fence was signaled. * @timestamp: Timestamp when the fence was signaled.
* @status: Optional, only valid if < 0, must be set before calling * @status: Optional, only valid if < 0, must be set before calling
* fence_signal, indicates that the fence has completed with an error. * fence_signal, indicates that the fence has completed with an error.
* @child_list: list of children fences
* @active_list: list of active fences
* *
* the flags member must be manipulated and read using the appropriate * the flags member must be manipulated and read using the appropriate
* atomic ops (bit_*), so taking the spinlock will not be needed most * atomic ops (bit_*), so taking the spinlock will not be needed most
......
...@@ -49,12 +49,27 @@ extern struct ww_class reservation_ww_class; ...@@ -49,12 +49,27 @@ extern struct ww_class reservation_ww_class;
extern struct lock_class_key reservation_seqcount_class; extern struct lock_class_key reservation_seqcount_class;
extern const char reservation_seqcount_string[]; extern const char reservation_seqcount_string[];
/**
* struct reservation_object_list - a list of shared fences
* @rcu: for internal use
* @shared_count: table of shared fences
* @shared_max: for growing shared fence table
* @shared: shared fence table
*/
struct reservation_object_list { struct reservation_object_list {
struct rcu_head rcu; struct rcu_head rcu;
u32 shared_count, shared_max; u32 shared_count, shared_max;
struct fence __rcu *shared[]; struct fence __rcu *shared[];
}; };
/**
* struct reservation_object - a reservation object manages fences for a buffer
* @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
*/
struct reservation_object { struct reservation_object {
struct ww_mutex lock; struct ww_mutex lock;
seqcount_t seq; seqcount_t seq;
...@@ -68,6 +83,10 @@ struct reservation_object { ...@@ -68,6 +83,10 @@ struct reservation_object {
#define reservation_object_assert_held(obj) \ #define reservation_object_assert_held(obj) \
lockdep_assert_held(&(obj)->lock.base) lockdep_assert_held(&(obj)->lock.base)
/**
* reservation_object_init - initialize a reservation object
* @obj: the reservation object
*/
static inline void static inline void
reservation_object_init(struct reservation_object *obj) reservation_object_init(struct reservation_object *obj)
{ {
...@@ -79,6 +98,10 @@ reservation_object_init(struct reservation_object *obj) ...@@ -79,6 +98,10 @@ reservation_object_init(struct reservation_object *obj)
obj->staged = NULL; obj->staged = NULL;
} }
/**
* reservation_object_fini - destroys a reservation object
* @obj: the reservation object
*/
static inline void static inline void
reservation_object_fini(struct reservation_object *obj) reservation_object_fini(struct reservation_object *obj)
{ {
...@@ -106,6 +129,14 @@ reservation_object_fini(struct reservation_object *obj) ...@@ -106,6 +129,14 @@ reservation_object_fini(struct reservation_object *obj)
ww_mutex_destroy(&obj->lock); ww_mutex_destroy(&obj->lock);
} }
/**
* reservation_object_get_list - get the reservation object's
* shared fence list, with update-side lock held
* @obj: the reservation object
*
* Returns the shared fence list. Does NOT take references to
* the fence. The obj->lock must be held.
*/
static inline struct reservation_object_list * static inline struct reservation_object_list *
reservation_object_get_list(struct reservation_object *obj) reservation_object_get_list(struct reservation_object *obj)
{ {
...@@ -113,6 +144,17 @@ reservation_object_get_list(struct reservation_object *obj) ...@@ -113,6 +144,17 @@ reservation_object_get_list(struct reservation_object *obj)
reservation_object_held(obj)); reservation_object_held(obj));
} }
/**
* reservation_object_get_excl - get the reservation object's
* exclusive fence, with update-side lock held
* @obj: the reservation object
*
* Returns the exclusive fence (if any). Does NOT take a
* reference. The obj->lock must be held.
*
* RETURNS
* The exclusive fence or NULL
*/
static inline struct fence * static inline struct fence *
reservation_object_get_excl(struct reservation_object *obj) reservation_object_get_excl(struct reservation_object *obj)
{ {
...@@ -120,6 +162,17 @@ reservation_object_get_excl(struct reservation_object *obj) ...@@ -120,6 +162,17 @@ reservation_object_get_excl(struct reservation_object *obj)
reservation_object_held(obj)); reservation_object_held(obj));
} }
/**
* reservation_object_get_excl_rcu - get the reservation object's
* exclusive fence, without lock held.
* @obj: the reservation object
*
* If there is an exclusive fence, this atomically increments it's
* reference count and returns it.
*
* RETURNS
* The exclusive fence or NULL if none
*/
static inline struct fence * static inline struct fence *
reservation_object_get_excl_rcu(struct reservation_object *obj) reservation_object_get_excl_rcu(struct reservation_object *obj)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment