blob: a1835d710f73539184603feb6e56a94881177444 [file] [log] [blame]
Ben Skeggs6ee73862009-12-11 19:24:15 +10001/*
2 * Copyright (C) 2007 Ben Skeggs.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27#include "drmP.h"
28#include "drm.h"
29
Marcin Slusarzbd35fe52011-03-09 14:22:19 +010030#include <linux/ktime.h>
31#include <linux/hrtimer.h>
32
Ben Skeggs6ee73862009-12-11 19:24:15 +100033#include "nouveau_drv.h"
Ben Skeggs02a841d2012-07-04 23:44:54 +100034#include <core/ramht.h>
Ben Skeggsd375e7d52012-04-30 13:30:00 +100035#include "nouveau_fence.h"
Ben Skeggs20abd162012-04-30 11:33:43 -050036#include "nouveau_software.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +100037#include "nouveau_dma.h"
38
Ben Skeggs5e120f62012-04-30 13:55:29 +100039void
40nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
41{
42 struct nouveau_fence *fence, *fnext;
43 spin_lock(&fctx->lock);
44 list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
45 if (fence->work)
46 fence->work(fence->priv, false);
47 fence->channel = NULL;
48 list_del(&fence->head);
49 nouveau_fence_unref(&fence);
50 }
51 spin_unlock(&fctx->lock);
52}
53
54void
55nouveau_fence_context_new(struct nouveau_fence_chan *fctx)
56{
Ben Skeggsf589be82012-07-22 11:55:54 +100057 INIT_LIST_HEAD(&fctx->flip);
Ben Skeggs5e120f62012-04-30 13:55:29 +100058 INIT_LIST_HEAD(&fctx->pending);
59 spin_lock_init(&fctx->lock);
60}
Ben Skeggs6ee73862009-12-11 19:24:15 +100061
Ben Skeggs6ee73862009-12-11 19:24:15 +100062void
63nouveau_fence_update(struct nouveau_channel *chan)
64{
Francisco Jerez27307232010-09-21 18:57:11 +020065 struct drm_device *dev = chan->dev;
Ben Skeggse193b1d2012-07-19 10:51:42 +100066 struct drm_nouveau_private *dev_priv = dev->dev_private;
67 struct nouveau_fence_priv *priv = dev_priv->fence.func;
68 struct nouveau_fence_chan *fctx = chan->fence;
Ben Skeggs5e120f62012-04-30 13:55:29 +100069 struct nouveau_fence *fence, *fnext;
Ben Skeggs6ee73862009-12-11 19:24:15 +100070
Ben Skeggs5e120f62012-04-30 13:55:29 +100071 spin_lock(&fctx->lock);
72 list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
73 if (priv->read(chan) < fence->sequence)
Ben Skeggsb08abd42012-03-21 13:51:03 +100074 break;
75
Ben Skeggsb08abd42012-03-21 13:51:03 +100076 if (fence->work)
Francisco Jerez8ac38912010-09-21 20:49:39 +020077 fence->work(fence->priv, true);
Ben Skeggs5e120f62012-04-30 13:55:29 +100078 fence->channel = NULL;
79 list_del(&fence->head);
Ben Skeggsd375e7d52012-04-30 13:30:00 +100080 nouveau_fence_unref(&fence);
Ben Skeggs6ee73862009-12-11 19:24:15 +100081 }
Ben Skeggs5e120f62012-04-30 13:55:29 +100082 spin_unlock(&fctx->lock);
Ben Skeggs6ee73862009-12-11 19:24:15 +100083}
84
85int
Ben Skeggsd375e7d52012-04-30 13:30:00 +100086nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
Ben Skeggs6ee73862009-12-11 19:24:15 +100087{
Francisco Jerez27307232010-09-21 18:57:11 +020088 struct drm_device *dev = chan->dev;
Ben Skeggse193b1d2012-07-19 10:51:42 +100089 struct drm_nouveau_private *dev_priv = dev->dev_private;
90 struct nouveau_fence_priv *priv = dev_priv->fence.func;
91 struct nouveau_fence_chan *fctx = chan->fence;
Ben Skeggs6ee73862009-12-11 19:24:15 +100092 int ret;
93
Ben Skeggs5e120f62012-04-30 13:55:29 +100094 fence->channel = chan;
95 fence->timeout = jiffies + (3 * DRM_HZ);
96 fence->sequence = ++fctx->sequence;
Ben Skeggs6ee73862009-12-11 19:24:15 +100097
Ben Skeggs5e120f62012-04-30 13:55:29 +100098 ret = priv->emit(fence);
99 if (!ret) {
100 kref_get(&fence->kref);
101 spin_lock(&fctx->lock);
102 list_add_tail(&fence->head, &fctx->pending);
103 spin_unlock(&fctx->lock);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000104 }
105
Ben Skeggs5e120f62012-04-30 13:55:29 +1000106 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000107}
108
Ben Skeggs6ee73862009-12-11 19:24:15 +1000109bool
Ben Skeggsd375e7d52012-04-30 13:30:00 +1000110nouveau_fence_done(struct nouveau_fence *fence)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000111{
Ben Skeggsd375e7d52012-04-30 13:30:00 +1000112 if (fence->channel)
113 nouveau_fence_update(fence->channel);
114 return !fence->channel;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000115}
116
117int
Ben Skeggs875ac342012-04-30 12:51:48 +1000118nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000119{
Marcin Slusarzbd35fe52011-03-09 14:22:19 +0100120 unsigned long sleep_time = NSEC_PER_MSEC / 1000;
121 ktime_t t;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000122 int ret = 0;
123
Ben Skeggsd375e7d52012-04-30 13:30:00 +1000124 while (!nouveau_fence_done(fence)) {
125 if (fence->timeout && time_after_eq(jiffies, fence->timeout)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000126 ret = -EBUSY;
127 break;
128 }
129
Ben Skeggs875ac342012-04-30 12:51:48 +1000130 __set_current_state(intr ? TASK_INTERRUPTIBLE :
131 TASK_UNINTERRUPTIBLE);
Marcin Slusarzbd35fe52011-03-09 14:22:19 +0100132 if (lazy) {
133 t = ktime_set(0, sleep_time);
134 schedule_hrtimeout(&t, HRTIMER_MODE_REL);
135 sleep_time *= 2;
136 if (sleep_time > NSEC_PER_MSEC)
137 sleep_time = NSEC_PER_MSEC;
138 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000139
140 if (intr && signal_pending(current)) {
Ben Skeggs9ddc8c52009-12-15 11:04:25 +1000141 ret = -ERESTARTSYS;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000142 break;
143 }
144 }
145
146 __set_current_state(TASK_RUNNING);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000147 return ret;
148}
149
Ben Skeggs5e120f62012-04-30 13:55:29 +1000150int
151nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan)
152{
Ben Skeggs5e120f62012-04-30 13:55:29 +1000153 struct drm_device *dev = chan->dev;
Ben Skeggse193b1d2012-07-19 10:51:42 +1000154 struct drm_nouveau_private *dev_priv = dev->dev_private;
155 struct nouveau_fence_priv *priv = dev_priv->fence.func;
Ben Skeggs906c0332012-05-04 16:25:47 +1000156 struct nouveau_channel *prev;
Ben Skeggs5e120f62012-04-30 13:55:29 +1000157 int ret = 0;
158
Ben Skeggs906c0332012-05-04 16:25:47 +1000159 prev = fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
160 if (prev) {
161 if (unlikely(prev != chan && !nouveau_fence_done(fence))) {
162 ret = priv->sync(fence, prev, chan);
163 if (unlikely(ret))
164 ret = nouveau_fence_wait(fence, true, false);
165 }
166 nouveau_channel_put_unlocked(&prev);
Ben Skeggs5e120f62012-04-30 13:55:29 +1000167 }
168
169 return ret;
170}
171
Ben Skeggsd375e7d52012-04-30 13:30:00 +1000172static void
173nouveau_fence_del(struct kref *kref)
174{
175 struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref);
176 kfree(fence);
177}
178
179void
180nouveau_fence_unref(struct nouveau_fence **pfence)
181{
182 if (*pfence)
183 kref_put(&(*pfence)->kref, nouveau_fence_del);
184 *pfence = NULL;
185}
186
187struct nouveau_fence *
188nouveau_fence_ref(struct nouveau_fence *fence)
189{
190 kref_get(&fence->kref);
191 return fence;
192}
193
194int
195nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence)
196{
197 struct nouveau_fence *fence;
198 int ret = 0;
199
Ben Skeggse193b1d2012-07-19 10:51:42 +1000200 if (unlikely(!chan->fence))
Ben Skeggs5e120f62012-04-30 13:55:29 +1000201 return -ENODEV;
202
Ben Skeggsd375e7d52012-04-30 13:30:00 +1000203 fence = kzalloc(sizeof(*fence), GFP_KERNEL);
204 if (!fence)
205 return -ENOMEM;
206 kref_init(&fence->kref);
207
208 if (chan) {
209 ret = nouveau_fence_emit(fence, chan);
210 if (ret)
211 nouveau_fence_unref(&fence);
212 }
213
214 *pfence = fence;
215 return ret;
216}