summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2013-08-30 15:56:59 +0900
committerMyungJoo Ham <myungjoo.ham@samsung.com>2013-11-15 13:51:53 +0900
commitf3dce49058a1c4650cafabf425c03bbaa8369ae1 (patch)
treebf9cd10c7dbb969529bf413a232c21d505a8921b /include
parent1b4c39a6c58a18bba523be996b80022c4d08ced6 (diff)
downloadlinux-3.10-f3dce49058a1c4650cafabf425c03bbaa8369ae1.tar.gz
linux-3.10-f3dce49058a1c4650cafabf425c03bbaa8369ae1.tar.bz2
linux-3.10-f3dce49058a1c4650cafabf425c03bbaa8369ae1.zip
dmabuf-sync: update it to patch v8
- Consider the write-and-then-read ordering. The ordering issue means that a task don't take a lock to the dmabuf so this task would be stalled even though this task requested a lock to the dmabuf between other task unlocked and tries to lock the dmabuf again. For this, it addes a wait event mechanism using only generic APIs, wait_event_timeout and wake_up functions. The below is how to handle the ordering issue using this mechanism: 1. Check if there is a sync object added prior to current task's one. 2. If exists, it unlocks the dmabuf so that other task can take a lock to the dmabuf first. 3. Wait for the wake up event from other task: current task will be waked up when other task unlocks the dmabuf. 4. Take a lock to the dmabuf again. - Update Document - Code cleanups. Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'include')
-rw-r--r--include/linux/dmabuf-sync.h93
1 files changed, 80 insertions, 13 deletions
diff --git a/include/linux/dmabuf-sync.h b/include/linux/dmabuf-sync.h
index 9a3afc4870a..6577af8067d 100644
--- a/include/linux/dmabuf-sync.h
+++ b/include/linux/dmabuf-sync.h
@@ -14,12 +14,58 @@
#include <linux/sched.h>
#include <linux/dma-buf.h>
+#define DMABUF_SYNC_NAME_SIZE 64
+
+/*
+ * Status to a dmabuf_sync object.
+ *
+ * @DMABUF_SYNC_GOT: Indicate that one more dmabuf objects have been added
+ * to a sync's list.
+ * @DMABUF_SYNC_LOCKED: Indicate that all dmabuf objects in a sync's list
+ * have been locked.
+ */
enum dmabuf_sync_status {
DMABUF_SYNC_GOT = 1,
DMABUF_SYNC_LOCKED,
};
+/*
+ * A structure for dmabuf_sync_reservation.
+ *
+ * @syncs: A list head to sync object and this is global to system.
+ * This contains sync objects of tasks that requested a lock
+ * to this dmabuf.
+ * @sync_lock: This provides read or write lock to a dmabuf.
+ * Except in the below cases, a task will be blocked if the task
+ * tries to lock a dmabuf for CPU or DMA access when other task
+ * already locked the dmabuf.
+ *
+ * Before After
+ * --------------------------
+ * CPU read CPU read
+ * CPU read DMA read
+ * DMA read CPU read
+ * DMA read DMA read
+ *
+ * @lock: Protecting a dmabuf_sync_reservation object.
+ * @poll_wait: A wait queue object to poll a dmabuf object.
+ * @poll_event: Indicate whether a dmabuf object - being polled -
+ * was unlocked or not. If true, a blocked task will be out
+ * of select system call.
+ * @poll: Indicate whether the polling to a dmabuf object was requested
+ * or not by userspace.
+ * @shared_cnt: Shared count to a dmabuf object.
+ * @accessed_type: Indicate how and who a dmabuf object was accessed by.
+ * One of the below types could be set.
+ * DMA_BUF_ACCESS_R -> CPU access for read.
+ * DMA_BUF_ACCRSS_W -> CPU access for write.
+ * DMA_BUF_ACCESS_R | DMA_BUF_ACCESS_DMA -> DMA access for read.
+ * DMA_BUF_ACCESS_W | DMA_BUF_ACCESS_DMA -> DMA access for write.
+ * @locked: Indicate whether a dmabuf object has been locked or not.
+ *
+ */
struct dmabuf_sync_reservation {
+ struct list_head syncs;
struct ww_mutex sync_lock;
struct mutex lock;
wait_queue_head_t poll_wait;
@@ -33,17 +79,36 @@ struct dmabuf_sync_reservation {
/*
* A structure for dmabuf_sync_object.
*
- * @head: A list head to be added to syncs list.
+ * @head: A list head to be added to dmabuf_sync's syncs.
+ * @r_head: A list head to be added to dmabuf_sync_reservation's syncs.
* @robj: A reservation_object object.
* @dma_buf: A dma_buf object.
+ * @task: An address value to current task.
+ * This is used to indicate who is a owner of a sync object.
+ * @wq: A wait queue head.
+ * This is used to guarantee that a task can take a lock to a dmabuf
+ * if the task requested a lock to the dmabuf prior to other task.
+ * For more details, see dmabuf_sync_wait_prev_objs function.
+ * @refcnt: A reference count to a sync object.
* @access_type: Indicate how a current task tries to access
- * a given buffer.
+ * a given buffer, and one of the below types could be set.
+ * DMA_BUF_ACCESS_R -> CPU access for read.
+ * DMA_BUF_ACCRSS_W -> CPU access for write.
+ * DMA_BUF_ACCESS_R | DMA_BUF_ACCESS_DMA -> DMA access for read.
+ * DMA_BUF_ACCESS_W | DMA_BUF_ACCESS_DMA -> DMA access for write.
+ * @waiting: Indicate whether current task is waiting for the wake up event
+ * from other task or not.
*/
struct dmabuf_sync_object {
struct list_head head;
+ struct list_head r_head;
struct dmabuf_sync_reservation *robj;
struct dma_buf *dmabuf;
+ unsigned long task;
+ wait_queue_head_t wq;
+ atomic_t refcnt;
unsigned int access_type;
+ unsigned int waiting;
};
struct dmabuf_sync_priv_ops {
@@ -54,8 +119,9 @@ struct dmabuf_sync_priv_ops {
* A structure for dmabuf_sync.
*
* @syncs: A list head to sync object and this is global to system.
+ * This contains sync objects of dmabuf_sync owner.
* @list: A list entry used as committed list node
- * @lock: A mutex lock to current sync object.
+ * @lock: Protecting a dmabuf_sync object.
* @ctx: A current context for ww mutex.
* @work: A work struct to release resources at timeout.
* @priv: A private data.
@@ -71,7 +137,7 @@ struct dmabuf_sync {
struct work_struct work;
void *priv;
struct dmabuf_sync_priv_ops *ops;
- char name[64];
+ char name[DMABUF_SYNC_NAME_SIZE];
struct timer_list timer;
unsigned int status;
};
@@ -94,6 +160,7 @@ static inline void dmabuf_sync_reservation_init(struct dma_buf *dmabuf)
mutex_init(&obj->lock);
atomic_set(&obj->shared_cnt, 1);
+ INIT_LIST_HEAD(&obj->syncs);
init_waitqueue_head(&obj->poll_wait);
}
@@ -112,29 +179,29 @@ static inline void dmabuf_sync_reservation_fini(struct dma_buf *dmabuf)
kfree(obj);
}
-extern bool is_dmabuf_sync_supported(void);
+bool dmabuf_sync_is_supported(void);
-extern struct dmabuf_sync *dmabuf_sync_init(const char *name,
+struct dmabuf_sync *dmabuf_sync_init(const char *name,
struct dmabuf_sync_priv_ops *ops,
void *priv);
-extern void dmabuf_sync_fini(struct dmabuf_sync *sync);
+void dmabuf_sync_fini(struct dmabuf_sync *sync);
-extern int dmabuf_sync_lock(struct dmabuf_sync *sync);
+int dmabuf_sync_lock(struct dmabuf_sync *sync);
-extern int dmabuf_sync_unlock(struct dmabuf_sync *sync);
+int dmabuf_sync_unlock(struct dmabuf_sync *sync);
int dmabuf_sync_single_lock(struct dma_buf *dmabuf, unsigned int type,
bool wait);
void dmabuf_sync_single_unlock(struct dma_buf *dmabuf);
-extern int dmabuf_sync_get(struct dmabuf_sync *sync, void *sync_buf,
+int dmabuf_sync_get(struct dmabuf_sync *sync, void *sync_buf,
unsigned int type);
-extern void dmabuf_sync_put(struct dmabuf_sync *sync, struct dma_buf *dmabuf);
+void dmabuf_sync_put(struct dmabuf_sync *sync, struct dma_buf *dmabuf);
-extern void dmabuf_sync_put_all(struct dmabuf_sync *sync);
+void dmabuf_sync_put_all(struct dmabuf_sync *sync);
#else
@@ -142,7 +209,7 @@ static inline void dmabuf_sync_reservation_init(struct dma_buf *dmabuf) { }
static inline void dmabuf_sync_reservation_fini(struct dma_buf *dmabuf) { }
-static inline bool is_dmabuf_sync_supported(void) { return false; }
+static inline bool dmabuf_sync_is_supported(void) { return false; }
static inline struct dmabuf_sync *dmabuf_sync_init(const char *name,
struct dmabuf_sync_priv_ops *ops,