diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/dma-buf | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/dma-buf')
-rw-r--r-- | kernel/drivers/dma-buf/dma-buf.c | 19 | ||||
-rw-r--r-- | kernel/drivers/dma-buf/fence.c | 98 | ||||
-rw-r--r-- | kernel/drivers/dma-buf/reservation.c | 9 | ||||
-rw-r--r-- | kernel/drivers/dma-buf/seqno-fence.c | 8 |
4 files changed, 127 insertions, 7 deletions
diff --git a/kernel/drivers/dma-buf/dma-buf.c b/kernel/drivers/dma-buf/dma-buf.c index c5a9138a6..155c14649 100644 --- a/kernel/drivers/dma-buf/dma-buf.c +++ b/kernel/drivers/dma-buf/dma-buf.c @@ -29,6 +29,7 @@ #include <linux/anon_inodes.h> #include <linux/export.h> #include <linux/debugfs.h> +#include <linux/module.h> #include <linux/seq_file.h> #include <linux/poll.h> #include <linux/reservation.h> @@ -72,6 +73,7 @@ static int dma_buf_release(struct inode *inode, struct file *file) if (dmabuf->resv == (struct reservation_object *)&dmabuf[1]) reservation_object_fini(dmabuf->resv); + module_put(dmabuf->owner); kfree(dmabuf); return 0; } @@ -285,6 +287,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) struct reservation_object *resv = exp_info->resv; struct file *file; size_t alloc_size = sizeof(struct dma_buf); + if (!exp_info->resv) alloc_size += sizeof(struct reservation_object); else @@ -302,14 +305,20 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) return ERR_PTR(-EINVAL); } + if (!try_module_get(exp_info->owner)) + return ERR_PTR(-ENOENT); + dmabuf = kzalloc(alloc_size, GFP_KERNEL); - if (dmabuf == NULL) + if (!dmabuf) { + module_put(exp_info->owner); return ERR_PTR(-ENOMEM); + } dmabuf->priv = exp_info->priv; dmabuf->ops = exp_info->ops; dmabuf->size = exp_info->size; dmabuf->exp_name = exp_info->exp_name; + dmabuf->owner = exp_info->owner; init_waitqueue_head(&dmabuf->poll); dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll; dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0; @@ -545,7 +554,8 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len, return -EINVAL; if (dmabuf->ops->begin_cpu_access) - ret = dmabuf->ops->begin_cpu_access(dmabuf, start, len, direction); + ret = dmabuf->ops->begin_cpu_access(dmabuf, start, + len, direction); return ret; } @@ -649,7 +659,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap); * @dmabuf: [in] buffer that should back the vma * @vma: [in] vma for the mmap * @pgoff: [in] offset in pages where this mmap should start within the - * dma-buf buffer. + * dma-buf buffer. * * This function adjusts the passed in vma so that it points at the file of the * dma_buf operation. It also adjusts the starting pgoff and does bounds @@ -826,6 +836,7 @@ static int dma_buf_describe(struct seq_file *s) static int dma_buf_show(struct seq_file *s, void *unused) { void (*func)(struct seq_file *) = s->private; + func(s); return 0; } @@ -847,7 +858,9 @@ static struct dentry *dma_buf_debugfs_dir; static int dma_buf_init_debugfs(void) { int err = 0; + dma_buf_debugfs_dir = debugfs_create_dir("dma_buf", NULL); + if (IS_ERR(dma_buf_debugfs_dir)) { err = PTR_ERR(dma_buf_debugfs_dir); dma_buf_debugfs_dir = NULL; diff --git a/kernel/drivers/dma-buf/fence.c b/kernel/drivers/dma-buf/fence.c index 50ef8bd87..7b05dbe9b 100644 --- a/kernel/drivers/dma-buf/fence.c +++ b/kernel/drivers/dma-buf/fence.c @@ -397,6 +397,104 @@ out: } EXPORT_SYMBOL(fence_default_wait); +static bool +fence_test_signaled_any(struct fence **fences, uint32_t count) +{ + int i; + + for (i = 0; i < count; ++i) { + struct fence *fence = fences[i]; + if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) + return true; + } + return false; +} + +/** + * fence_wait_any_timeout - sleep until any fence gets signaled + * or until timeout elapses + * @fences: [in] array of fences to wait on + * @count: [in] number of fences to wait on + * @intr: [in] if true, do an interruptible wait + * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT + * + * Returns -EINVAL on custom fence wait implementation, -ERESTARTSYS if + * interrupted, 0 if the wait timed out, or the remaining timeout in jiffies + * on success. + * + * Synchronous waits for the first fence in the array to be signaled. The + * caller needs to hold a reference to all fences in the array, otherwise a + * fence might be freed before return, resulting in undefined behavior. + */ +signed long +fence_wait_any_timeout(struct fence **fences, uint32_t count, + bool intr, signed long timeout) +{ + struct default_wait_cb *cb; + signed long ret = timeout; + unsigned i; + + if (WARN_ON(!fences || !count || timeout < 0)) + return -EINVAL; + + if (timeout == 0) { + for (i = 0; i < count; ++i) + if (fence_is_signaled(fences[i])) + return 1; + + return 0; + } + + cb = kcalloc(count, sizeof(struct default_wait_cb), GFP_KERNEL); + if (cb == NULL) { + ret = -ENOMEM; + goto err_free_cb; + } + + for (i = 0; i < count; ++i) { + struct fence *fence = fences[i]; + + if (fence->ops->wait != fence_default_wait) { + ret = -EINVAL; + goto fence_rm_cb; + } + + cb[i].task = current; + if (fence_add_callback(fence, &cb[i].base, + fence_default_wait_cb)) { + /* This fence is already signaled */ + goto fence_rm_cb; + } + } + + while (ret > 0) { + if (intr) + set_current_state(TASK_INTERRUPTIBLE); + else + set_current_state(TASK_UNINTERRUPTIBLE); + + if (fence_test_signaled_any(fences, count)) + break; + + ret = schedule_timeout(ret); + + if (ret > 0 && intr && signal_pending(current)) + ret = -ERESTARTSYS; + } + + __set_current_state(TASK_RUNNING); + +fence_rm_cb: + while (i-- > 0) + fence_remove_callback(fences[i], &cb[i].base); + +err_free_cb: + kfree(cb); + + return ret; +} +EXPORT_SYMBOL(fence_wait_any_timeout); + /** * fence_init - Initialize a custom fence. * @fence: [in] the fence to initialize diff --git a/kernel/drivers/dma-buf/reservation.c b/kernel/drivers/dma-buf/reservation.c index 39920d77f..c0bd5722c 100644 --- a/kernel/drivers/dma-buf/reservation.c +++ b/kernel/drivers/dma-buf/reservation.c @@ -337,7 +337,8 @@ retry: rcu_read_lock(); if (wait_all) { - struct reservation_object_list *fobj = rcu_dereference(obj->fence); + struct reservation_object_list *fobj = + rcu_dereference(obj->fence); if (fobj) shared_count = fobj->shared_count; @@ -429,7 +430,8 @@ retry: if (test_all) { unsigned i; - struct reservation_object_list *fobj = rcu_dereference(obj->fence); + struct reservation_object_list *fobj = + rcu_dereference(obj->fence); if (fobj) shared_count = fobj->shared_count; @@ -462,7 +464,8 @@ retry: goto unlock_retry; if (fence_excl) { - ret = reservation_object_test_signaled_single(fence_excl); + ret = reservation_object_test_signaled_single( + fence_excl); if (ret < 0) goto unlock_retry; } diff --git a/kernel/drivers/dma-buf/seqno-fence.c b/kernel/drivers/dma-buf/seqno-fence.c index 7d12a39a4..71127f8f1 100644 --- a/kernel/drivers/dma-buf/seqno-fence.c +++ b/kernel/drivers/dma-buf/seqno-fence.c @@ -24,24 +24,28 @@ static const char *seqno_fence_get_driver_name(struct fence *fence) { struct seqno_fence *seqno_fence = to_seqno_fence(fence); + return seqno_fence->ops->get_driver_name(fence); } static const char *seqno_fence_get_timeline_name(struct fence *fence) { struct seqno_fence *seqno_fence = to_seqno_fence(fence); + return seqno_fence->ops->get_timeline_name(fence); } static bool seqno_enable_signaling(struct fence *fence) { struct seqno_fence *seqno_fence = to_seqno_fence(fence); + return seqno_fence->ops->enable_signaling(fence); } static bool seqno_signaled(struct fence *fence) { struct seqno_fence *seqno_fence = to_seqno_fence(fence); + return seqno_fence->ops->signaled && seqno_fence->ops->signaled(fence); } @@ -56,9 +60,11 @@ static void seqno_release(struct fence *fence) fence_free(&f->base); } -static signed long seqno_wait(struct fence *fence, bool intr, signed long timeout) +static signed long seqno_wait(struct fence *fence, bool intr, + signed long timeout) { struct seqno_fence *f = to_seqno_fence(fence); + return f->ops->wait(fence, intr, timeout); } |