summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2013-08-09 15:38:34 +0900
committerChanho Park <chanho61.park@samsung.com>2014-11-18 11:43:58 +0900
commit9d1dcc047ae45a49c36953b7e848be65a1aa25c4 (patch)
treedf7efbf479a3edd5797c6b697b957e94c9e3a2bf /drivers
parent98585a741414043e53e91bb3ecb05a37f34f7eb9 (diff)
downloadlinux-3.10-9d1dcc047ae45a49c36953b7e848be65a1aa25c4.tar.gz
linux-3.10-9d1dcc047ae45a49c36953b7e848be65a1aa25c4.tar.bz2
linux-3.10-9d1dcc047ae45a49c36953b7e848be65a1aa25c4.zip
dmabuf-sync: add select system call support.
This patch implements select system call for DMA BUF module and adds related codes to dmabuf sync framework. The purpose of this feature is to wait for the completion of DMA or CPU access to a dmabuf without that caller locks the dmabuf again after the completion. This feature is useful when caller wants to be aware of the completion of DMA access to a shared dmabuf, and the caller doesn't use interfaces for the DMA device driver. Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/dma-buf.c48
-rw-r--r--drivers/base/dmabuf-sync.c18
2 files changed, 66 insertions, 0 deletions
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index e1b85835030..53ade7b1652 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -29,6 +29,7 @@
#include <linux/export.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/poll.h>
#include <linux/dmabuf-sync.h>
static inline int is_dma_buf_file(struct file *);
@@ -80,6 +81,52 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
return dmabuf->ops->mmap(dmabuf, vma);
}
+static unsigned int dma_buf_poll(struct file *filp,
+ struct poll_table_struct *poll)
+{
+ struct dma_buf *dmabuf;
+ struct dmabuf_sync_reservation *robj;
+ int ret = 0;
+
+ if (!is_dma_buf_file(filp))
+ return POLLERR;
+
+ dmabuf = filp->private_data;
+ if (!dmabuf || !dmabuf->sync)
+ return POLLERR;
+
+ robj = dmabuf->sync;
+
+ mutex_lock(&robj->lock);
+
+ robj->polled = true;
+
+ /*
+ * CPU or DMA access to this buffer has been completed, and
+ * the blocked task has been waked up. Return poll event
+ * so that the task can get out of select().
+ */
+ if (robj->poll_event) {
+ robj->poll_event = false;
+ mutex_unlock(&robj->lock);
+ return POLLIN | POLLOUT;
+ }
+
+ /*
+ * There is no anyone accessing this buffer so just return POLLERR.
+ */
+ if (!robj->locked) {
+ mutex_unlock(&robj->lock);
+ return POLLERR;
+ }
+
+ poll_wait(filp, &robj->poll_wait, poll);
+
+ mutex_unlock(&robj->lock);
+
+ return ret;
+}
+
static int dma_buf_lock(struct file *file, int cmd, struct file_lock *fl)
{
struct dma_buf *dmabuf;
@@ -115,6 +162,7 @@ static int dma_buf_lock(struct file *file, int cmd, struct file_lock *fl)
static const struct file_operations dma_buf_fops = {
.release = dma_buf_release,
.mmap = dma_buf_mmap_internal,
+ .poll = dma_buf_poll,
.lock = dma_buf_lock,
};
diff --git a/drivers/base/dmabuf-sync.c b/drivers/base/dmabuf-sync.c
index abfd8e3f009..dab5b32a833 100644
--- a/drivers/base/dmabuf-sync.c
+++ b/drivers/base/dmabuf-sync.c
@@ -63,6 +63,12 @@ static void dmabuf_sync_timeout_worker(struct work_struct *work)
continue;
}
+ if (sobj->robj->polled) {
+ sobj->robj->poll_event = true;
+ sobj->robj->polled = false;
+ wake_up_interruptible(&sobj->robj->poll_wait);
+ }
+
if (atomic_add_unless(&sobj->robj->shared_cnt, -1, 1)) {
mutex_unlock(&sobj->robj->lock);
continue;
@@ -277,6 +283,12 @@ static void dmabuf_sync_unlock_objs(struct dmabuf_sync *sync,
list_for_each_entry(sobj, &sync->syncs, head) {
mutex_lock(&sobj->robj->lock);
+ if (sobj->robj->polled) {
+ sobj->robj->poll_event = true;
+ sobj->robj->polled = false;
+ wake_up_interruptible(&sobj->robj->poll_wait);
+ }
+
if (atomic_add_unless(&sobj->robj->shared_cnt, -1, 1)) {
mutex_unlock(&sobj->robj->lock);
continue;
@@ -624,6 +636,12 @@ void dmabuf_sync_single_unlock(struct dma_buf *dmabuf)
mutex_lock(&robj->lock);
+ if (robj->polled) {
+ robj->poll_event = true;
+ robj->polled = false;
+ wake_up_interruptible(&robj->poll_wait);
+ }
+
if (atomic_add_unless(&robj->shared_cnt, -1 , 1)) {
mutex_unlock(&robj->lock);
dma_buf_put(dmabuf);