diff options
author | Inki Dae <inki.dae@samsung.com> | 2013-08-09 15:38:34 +0900 |
---|---|---|
committer | Marek Szyprowski <m.szyprowski@samsung.com> | 2014-05-15 07:21:41 +0200 |
commit | e317b76581483822f47fea5e41df967466dd3e2d (patch) | |
tree | 7a9649623002fcbae35521f93ffc22812daf9cfd /drivers/base | |
parent | d20403a6b26c3324717ab3737e0923cfd3bbd2d6 (diff) | |
download | linux-3.10-e317b76581483822f47fea5e41df967466dd3e2d.tar.gz linux-3.10-e317b76581483822f47fea5e41df967466dd3e2d.tar.bz2 linux-3.10-e317b76581483822f47fea5e41df967466dd3e2d.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/base')
-rw-r--r-- | drivers/base/dma-buf.c | 48 | ||||
-rw-r--r-- | drivers/base/dmabuf-sync.c | 18 |
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); |