blob: 002eecb3934e43931b51db6e7f0263eca51e7a42 [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
18#include "msm_drv.h"
19#include "msm_fence.h"
20#include "msm_gpu.h"
21
22static inline bool fence_completed(struct drm_device *dev, uint32_t fence)
23{
24 struct msm_drm_private *priv = dev->dev_private;
25 return (int32_t)(priv->completed_fence - fence) >= 0;
26}
27
28int msm_wait_fence(struct drm_device *dev, uint32_t fence,
29 ktime_t *timeout , bool interruptible)
30{
31 struct msm_drm_private *priv = dev->dev_private;
32 int ret;
33
34 if (!priv->gpu)
35 return 0;
36
37 if (fence > priv->gpu->submitted_fence) {
38 DRM_ERROR("waiting on invalid fence: %u (of %u)\n",
39 fence, priv->gpu->submitted_fence);
40 return -EINVAL;
41 }
42
43 if (!timeout) {
44 /* no-wait: */
45 ret = fence_completed(dev, fence) ? 0 : -EBUSY;
46 } else {
Rob Clark340ff412016-03-16 14:57:22 -040047 unsigned long remaining_jiffies = timeout_to_jiffies(timeout);
Rob Clarkfde5de62016-03-15 15:35:08 -040048
49 if (interruptible)
50 ret = wait_event_interruptible_timeout(priv->fence_event,
51 fence_completed(dev, fence),
52 remaining_jiffies);
53 else
54 ret = wait_event_timeout(priv->fence_event,
55 fence_completed(dev, fence),
56 remaining_jiffies);
57
58 if (ret == 0) {
59 DBG("timeout waiting for fence: %u (completed: %u)",
60 fence, priv->completed_fence);
61 ret = -ETIMEDOUT;
62 } else if (ret != -ERESTARTSYS) {
63 ret = 0;
64 }
65 }
66
67 return ret;
68}
69
70int msm_queue_fence_cb(struct drm_device *dev,
71 struct msm_fence_cb *cb, uint32_t fence)
72{
73 struct msm_drm_private *priv = dev->dev_private;
74 int ret = 0;
75
76 mutex_lock(&dev->struct_mutex);
77 if (!list_empty(&cb->work.entry)) {
78 ret = -EINVAL;
79 } else if (fence > priv->completed_fence) {
80 cb->fence = fence;
81 list_add_tail(&cb->work.entry, &priv->fence_cbs);
82 } else {
83 queue_work(priv->wq, &cb->work);
84 }
85 mutex_unlock(&dev->struct_mutex);
86
87 return ret;
88}
89
90/* called from workqueue */
91void msm_update_fence(struct drm_device *dev, uint32_t fence)
92{
93 struct msm_drm_private *priv = dev->dev_private;
94
95 mutex_lock(&dev->struct_mutex);
96 priv->completed_fence = max(fence, priv->completed_fence);
97
98 while (!list_empty(&priv->fence_cbs)) {
99 struct msm_fence_cb *cb;
100
101 cb = list_first_entry(&priv->fence_cbs,
102 struct msm_fence_cb, work.entry);
103
104 if (cb->fence > priv->completed_fence)
105 break;
106
107 list_del_init(&cb->work.entry);
108 queue_work(priv->wq, &cb->work);
109 }
110
111 mutex_unlock(&dev->struct_mutex);
112
113 wake_up_all(&priv->fence_event);
114}
115
116void __msm_fence_worker(struct work_struct *work)
117{
118 struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work);
119 cb->func(cb);
120}