blob: f0ed6a680653c18dc43eab00c89511abfe878da7 [file] [log] [blame]
Rob Clarkfde5de62016-03-15 15:35:08 -04001/*
2 * Copyright (C) 2013-2016 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
Rob Clarkca762a82016-03-15 17:22:13 -040018#include <linux/fence.h>
19
Rob Clarkfde5de62016-03-15 15:35:08 -040020#include "msm_drv.h"
21#include "msm_fence.h"
Rob Clarkfde5de62016-03-15 15:35:08 -040022
Rob Clarkca762a82016-03-15 17:22:13 -040023
24struct msm_fence_context *
25msm_fence_context_alloc(struct drm_device *dev, const char *name)
Rob Clarkfde5de62016-03-15 15:35:08 -040026{
Rob Clarkca762a82016-03-15 17:22:13 -040027 struct msm_fence_context *fctx;
28
29 fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
30 if (!fctx)
31 return ERR_PTR(-ENOMEM);
32
33 fctx->dev = dev;
34 fctx->name = name;
35 init_waitqueue_head(&fctx->event);
36 INIT_LIST_HEAD(&fctx->fence_cbs);
37
38 return fctx;
Rob Clarkfde5de62016-03-15 15:35:08 -040039}
40
Rob Clarkca762a82016-03-15 17:22:13 -040041void msm_fence_context_free(struct msm_fence_context *fctx)
Rob Clarkfde5de62016-03-15 15:35:08 -040042{
Rob Clarkca762a82016-03-15 17:22:13 -040043 kfree(fctx);
44}
45
46static inline bool fence_completed(struct msm_fence_context *fctx, uint32_t fence)
47{
48 return (int32_t)(fctx->completed_fence - fence) >= 0;
49}
50
51int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence,
52 ktime_t *timeout, bool interruptible)
53{
Rob Clarkfde5de62016-03-15 15:35:08 -040054 int ret;
55
Rob Clarkca762a82016-03-15 17:22:13 -040056 if (fence > fctx->last_fence) {
57 DRM_ERROR("%s: waiting on invalid fence: %u (of %u)\n",
58 fctx->name, fence, fctx->last_fence);
Rob Clarkfde5de62016-03-15 15:35:08 -040059 return -EINVAL;
60 }
61
62 if (!timeout) {
63 /* no-wait: */
Rob Clarkca762a82016-03-15 17:22:13 -040064 ret = fence_completed(fctx, fence) ? 0 : -EBUSY;
Rob Clarkfde5de62016-03-15 15:35:08 -040065 } else {
Rob Clark340ff412016-03-16 14:57:22 -040066 unsigned long remaining_jiffies = timeout_to_jiffies(timeout);
Rob Clarkfde5de62016-03-15 15:35:08 -040067
68 if (interruptible)
Rob Clarkca762a82016-03-15 17:22:13 -040069 ret = wait_event_interruptible_timeout(fctx->event,
70 fence_completed(fctx, fence),
Rob Clarkfde5de62016-03-15 15:35:08 -040071 remaining_jiffies);
72 else
Rob Clarkca762a82016-03-15 17:22:13 -040073 ret = wait_event_timeout(fctx->event,
74 fence_completed(fctx, fence),
Rob Clarkfde5de62016-03-15 15:35:08 -040075 remaining_jiffies);
76
77 if (ret == 0) {
78 DBG("timeout waiting for fence: %u (completed: %u)",
Rob Clarkca762a82016-03-15 17:22:13 -040079 fence, fctx->completed_fence);
Rob Clarkfde5de62016-03-15 15:35:08 -040080 ret = -ETIMEDOUT;
81 } else if (ret != -ERESTARTSYS) {
82 ret = 0;
83 }
84 }
85
86 return ret;
87}
88
Rob Clarkca762a82016-03-15 17:22:13 -040089int msm_queue_fence_cb(struct msm_fence_context *fctx,
Rob Clarkfde5de62016-03-15 15:35:08 -040090 struct msm_fence_cb *cb, uint32_t fence)
91{
Rob Clarkca762a82016-03-15 17:22:13 -040092 struct msm_drm_private *priv = fctx->dev->dev_private;
Rob Clarkfde5de62016-03-15 15:35:08 -040093 int ret = 0;
94
Rob Clarkca762a82016-03-15 17:22:13 -040095 mutex_lock(&fctx->dev->struct_mutex);
Rob Clarkfde5de62016-03-15 15:35:08 -040096 if (!list_empty(&cb->work.entry)) {
97 ret = -EINVAL;
Rob Clarkca762a82016-03-15 17:22:13 -040098 } else if (fence > fctx->completed_fence) {
Rob Clarkfde5de62016-03-15 15:35:08 -040099 cb->fence = fence;
Rob Clarkca762a82016-03-15 17:22:13 -0400100 list_add_tail(&cb->work.entry, &fctx->fence_cbs);
Rob Clarkfde5de62016-03-15 15:35:08 -0400101 } else {
102 queue_work(priv->wq, &cb->work);
103 }
Rob Clarkca762a82016-03-15 17:22:13 -0400104 mutex_unlock(&fctx->dev->struct_mutex);
Rob Clarkfde5de62016-03-15 15:35:08 -0400105
106 return ret;
107}
108
109/* called from workqueue */
Rob Clarkca762a82016-03-15 17:22:13 -0400110void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence)
Rob Clarkfde5de62016-03-15 15:35:08 -0400111{
Rob Clarkca762a82016-03-15 17:22:13 -0400112 struct msm_drm_private *priv = fctx->dev->dev_private;
Rob Clarkfde5de62016-03-15 15:35:08 -0400113
Rob Clarkca762a82016-03-15 17:22:13 -0400114 mutex_lock(&fctx->dev->struct_mutex);
115 fctx->completed_fence = max(fence, fctx->completed_fence);
Rob Clarkfde5de62016-03-15 15:35:08 -0400116
Rob Clarkca762a82016-03-15 17:22:13 -0400117 while (!list_empty(&fctx->fence_cbs)) {
Rob Clarkfde5de62016-03-15 15:35:08 -0400118 struct msm_fence_cb *cb;
119
Rob Clarkca762a82016-03-15 17:22:13 -0400120 cb = list_first_entry(&fctx->fence_cbs,
Rob Clarkfde5de62016-03-15 15:35:08 -0400121 struct msm_fence_cb, work.entry);
122
Rob Clarkca762a82016-03-15 17:22:13 -0400123 if (cb->fence > fctx->completed_fence)
Rob Clarkfde5de62016-03-15 15:35:08 -0400124 break;
125
126 list_del_init(&cb->work.entry);
127 queue_work(priv->wq, &cb->work);
128 }
129
Rob Clarkca762a82016-03-15 17:22:13 -0400130 mutex_unlock(&fctx->dev->struct_mutex);
Rob Clarkfde5de62016-03-15 15:35:08 -0400131
Rob Clarkca762a82016-03-15 17:22:13 -0400132 wake_up_all(&fctx->event);
Rob Clarkfde5de62016-03-15 15:35:08 -0400133}
134
135void __msm_fence_worker(struct work_struct *work)
136{
137 struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work);
138 cb->func(cb);
139}