2 * Copyright (C) 2007 Ben Skeggs.
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:
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.
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.
29 #include <linux/ktime.h>
30 #include <linux/hrtimer.h>
32 #include "nouveau_drm.h"
33 #include "nouveau_dma.h"
34 #include "nouveau_fence.h"
36 #include <engine/fifo.h>
39 struct work_struct base
;
40 struct list_head head
;
46 nouveau_fence_signal(struct nouveau_fence
*fence
)
48 struct fence_work
*work
, *temp
;
50 list_for_each_entry_safe(work
, temp
, &fence
->work
, head
) {
51 schedule_work(&work
->base
);
52 list_del(&work
->head
);
55 fence
->channel
= NULL
;
56 list_del(&fence
->head
);
60 nouveau_fence_context_del(struct nouveau_fence_chan
*fctx
)
62 struct nouveau_fence
*fence
, *fnext
;
63 spin_lock(&fctx
->lock
);
64 list_for_each_entry_safe(fence
, fnext
, &fctx
->pending
, head
) {
65 nouveau_fence_signal(fence
);
67 spin_unlock(&fctx
->lock
);
71 nouveau_fence_context_new(struct nouveau_fence_chan
*fctx
)
73 INIT_LIST_HEAD(&fctx
->flip
);
74 INIT_LIST_HEAD(&fctx
->pending
);
75 spin_lock_init(&fctx
->lock
);
79 nouveau_fence_work_handler(struct work_struct
*kwork
)
81 struct fence_work
*work
= container_of(kwork
, typeof(*work
), base
);
82 work
->func(work
->data
);
87 nouveau_fence_work(struct nouveau_fence
*fence
,
88 void (*func
)(void *), void *data
)
90 struct nouveau_channel
*chan
= fence
->channel
;
91 struct nouveau_fence_chan
*fctx
;
92 struct fence_work
*work
= NULL
;
94 if (nouveau_fence_done(fence
)) {
100 work
= kmalloc(sizeof(*work
), GFP_KERNEL
);
102 WARN_ON(nouveau_fence_wait(fence
, false, false));
107 spin_lock(&fctx
->lock
);
108 if (!fence
->channel
) {
109 spin_unlock(&fctx
->lock
);
115 INIT_WORK(&work
->base
, nouveau_fence_work_handler
);
118 list_add(&work
->head
, &fence
->work
);
119 spin_unlock(&fctx
->lock
);
123 nouveau_fence_update(struct nouveau_channel
*chan
)
125 struct nouveau_fence_chan
*fctx
= chan
->fence
;
126 struct nouveau_fence
*fence
, *fnext
;
128 spin_lock(&fctx
->lock
);
129 list_for_each_entry_safe(fence
, fnext
, &fctx
->pending
, head
) {
130 if (fctx
->read(chan
) < fence
->sequence
)
133 nouveau_fence_signal(fence
);
134 nouveau_fence_unref(&fence
);
136 spin_unlock(&fctx
->lock
);
140 nouveau_fence_emit(struct nouveau_fence
*fence
, struct nouveau_channel
*chan
)
142 struct nouveau_fence_chan
*fctx
= chan
->fence
;
145 fence
->channel
= chan
;
146 fence
->timeout
= jiffies
+ (15 * DRM_HZ
);
147 fence
->sequence
= ++fctx
->sequence
;
149 ret
= fctx
->emit(fence
);
151 kref_get(&fence
->kref
);
152 spin_lock(&fctx
->lock
);
153 list_add_tail(&fence
->head
, &fctx
->pending
);
154 spin_unlock(&fctx
->lock
);
161 nouveau_fence_done(struct nouveau_fence
*fence
)
164 nouveau_fence_update(fence
->channel
);
165 return !fence
->channel
;
168 struct nouveau_fence_uevent
{
169 struct nouveau_eventh handler
;
170 struct nouveau_fence_priv
*priv
;
174 nouveau_fence_wait_uevent_handler(struct nouveau_eventh
*event
, int index
)
176 struct nouveau_fence_uevent
*uevent
=
177 container_of(event
, struct nouveau_fence_uevent
, handler
);
178 wake_up_all(&uevent
->priv
->waiting
);
179 return NVKM_EVENT_KEEP
;
183 nouveau_fence_wait_uevent(struct nouveau_fence
*fence
, bool intr
)
186 struct nouveau_channel
*chan
= fence
->channel
;
187 struct nouveau_fifo
*pfifo
= nouveau_fifo(chan
->drm
->device
);
188 struct nouveau_fence_priv
*priv
= chan
->drm
->fence
;
189 struct nouveau_fence_uevent uevent
= {
190 .handler
.func
= nouveau_fence_wait_uevent_handler
,
195 nouveau_event_get(pfifo
->uevent
, 0, &uevent
.handler
);
197 if (fence
->timeout
) {
198 unsigned long timeout
= fence
->timeout
- jiffies
;
200 if (time_before(jiffies
, fence
->timeout
)) {
202 ret
= wait_event_interruptible_timeout(
204 nouveau_fence_done(fence
),
207 ret
= wait_event_timeout(priv
->waiting
,
208 nouveau_fence_done(fence
),
214 fence
->timeout
= jiffies
+ ret
;
215 if (time_after_eq(jiffies
, fence
->timeout
))
220 ret
= wait_event_interruptible(priv
->waiting
,
221 nouveau_fence_done(fence
));
223 wait_event(priv
->waiting
, nouveau_fence_done(fence
));
227 nouveau_event_put(pfifo
->uevent
, 0, &uevent
.handler
);
228 if (unlikely(ret
< 0))
235 nouveau_fence_wait(struct nouveau_fence
*fence
, bool lazy
, bool intr
)
237 struct nouveau_channel
*chan
= fence
->channel
;
238 struct nouveau_fence_priv
*priv
= chan
? chan
->drm
->fence
: NULL
;
239 unsigned long sleep_time
= NSEC_PER_MSEC
/ 1000;
243 while (priv
&& priv
->uevent
&& lazy
&& !nouveau_fence_done(fence
)) {
244 ret
= nouveau_fence_wait_uevent(fence
, intr
);
249 while (!nouveau_fence_done(fence
)) {
250 if (fence
->timeout
&& time_after_eq(jiffies
, fence
->timeout
)) {
255 __set_current_state(intr
? TASK_INTERRUPTIBLE
:
256 TASK_UNINTERRUPTIBLE
);
258 t
= ktime_set(0, sleep_time
);
259 schedule_hrtimeout(&t
, HRTIMER_MODE_REL
);
261 if (sleep_time
> NSEC_PER_MSEC
)
262 sleep_time
= NSEC_PER_MSEC
;
265 if (intr
&& signal_pending(current
)) {
271 __set_current_state(TASK_RUNNING
);
276 nouveau_fence_sync(struct nouveau_fence
*fence
, struct nouveau_channel
*chan
)
278 struct nouveau_fence_chan
*fctx
= chan
->fence
;
279 struct nouveau_channel
*prev
;
282 prev
= fence
? fence
->channel
: NULL
;
284 if (unlikely(prev
!= chan
&& !nouveau_fence_done(fence
))) {
285 ret
= fctx
->sync(fence
, prev
, chan
);
287 ret
= nouveau_fence_wait(fence
, true, false);
295 nouveau_fence_del(struct kref
*kref
)
297 struct nouveau_fence
*fence
= container_of(kref
, typeof(*fence
), kref
);
302 nouveau_fence_unref(struct nouveau_fence
**pfence
)
305 kref_put(&(*pfence
)->kref
, nouveau_fence_del
);
309 struct nouveau_fence
*
310 nouveau_fence_ref(struct nouveau_fence
*fence
)
312 kref_get(&fence
->kref
);
317 nouveau_fence_new(struct nouveau_channel
*chan
, bool sysmem
,
318 struct nouveau_fence
**pfence
)
320 struct nouveau_fence
*fence
;
323 if (unlikely(!chan
->fence
))
326 fence
= kzalloc(sizeof(*fence
), GFP_KERNEL
);
330 INIT_LIST_HEAD(&fence
->work
);
331 fence
->sysmem
= sysmem
;
332 kref_init(&fence
->kref
);
334 ret
= nouveau_fence_emit(fence
, chan
);
336 nouveau_fence_unref(&fence
);