Browse Source

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
Linus Torvalds 9 years ago
parent
commit
ebb8cb2bae

+ 32 - 4
Documentation/DocBook/device-drivers.tmpl

@@ -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>

+ 4 - 3
drivers/dma-buf/dma-buf.c

@@ -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)
 	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,
 		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;
 
 

+ 68 - 4
drivers/dma-buf/reservation.c

@@ -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);
 
 
 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 @@ done:
 		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,
 }
 }
 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,
 }
 }
 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 @@ unlock:
 }
 }
 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)
 	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)
 {
 {

+ 10 - 3
include/linux/dma-buf.h

@@ -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 {
 
 
 /**
 /**
  * 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)	\
-	struct dma_buf_export_info a = { .exp_name = KBUILD_MODNAME, \
+#define DEFINE_DMA_BUF_EXPORT_INFO(name)	\
+	struct dma_buf_export_info name = { .exp_name = KBUILD_MODNAME, \
 					 .owner = THIS_MODULE }
 					 .owner = THIS_MODULE }
 
 
 /**
 /**

+ 2 - 0
include/linux/fence.h

@@ -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

+ 53 - 0
include/linux/reservation.h

@@ -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 {
 #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)
 	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)
 	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)
 					 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)
 					 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)
 {
 {