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.
30 #include <linux/ktime.h>
31 #include <linux/hrtimer.h>
33 #include "nouveau_drv.h"
34 #include "nouveau_ramht.h"
35 #include "nouveau_fence.h"
36 #include "nouveau_software.h"
37 #include "nouveau_dma.h"
40 nouveau_fence_context_del(struct nouveau_fence_chan
*fctx
)
42 struct nouveau_fence
*fence
, *fnext
;
43 spin_lock(&fctx
->lock
);
44 list_for_each_entry_safe(fence
, fnext
, &fctx
->pending
, head
) {
46 fence
->work(fence
->priv
, false);
47 fence
->channel
= NULL
;
48 list_del(&fence
->head
);
49 nouveau_fence_unref(&fence
);
51 spin_unlock(&fctx
->lock
);
55 nouveau_fence_context_new(struct nouveau_fence_chan
*fctx
)
57 INIT_LIST_HEAD(&fctx
->pending
);
58 spin_lock_init(&fctx
->lock
);
62 nouveau_fence_update(struct nouveau_channel
*chan
)
64 struct drm_device
*dev
= chan
->dev
;
65 struct nouveau_fence_priv
*priv
= nv_engine(dev
, NVOBJ_ENGINE_FENCE
);
66 struct nouveau_fence_chan
*fctx
= chan
->engctx
[NVOBJ_ENGINE_FENCE
];
67 struct nouveau_fence
*fence
, *fnext
;
69 spin_lock(&fctx
->lock
);
70 list_for_each_entry_safe(fence
, fnext
, &fctx
->pending
, head
) {
71 if (priv
->read(chan
) < fence
->sequence
)
75 fence
->work(fence
->priv
, true);
76 fence
->channel
= NULL
;
77 list_del(&fence
->head
);
78 nouveau_fence_unref(&fence
);
80 spin_unlock(&fctx
->lock
);
84 nouveau_fence_emit(struct nouveau_fence
*fence
, struct nouveau_channel
*chan
)
86 struct drm_device
*dev
= chan
->dev
;
87 struct nouveau_fence_priv
*priv
= nv_engine(dev
, NVOBJ_ENGINE_FENCE
);
88 struct nouveau_fence_chan
*fctx
= chan
->engctx
[NVOBJ_ENGINE_FENCE
];
91 fence
->channel
= chan
;
92 fence
->timeout
= jiffies
+ (3 * DRM_HZ
);
93 fence
->sequence
= ++fctx
->sequence
;
95 ret
= priv
->emit(fence
);
97 kref_get(&fence
->kref
);
98 spin_lock(&fctx
->lock
);
99 list_add_tail(&fence
->head
, &fctx
->pending
);
100 spin_unlock(&fctx
->lock
);
107 nouveau_fence_done(struct nouveau_fence
*fence
)
110 nouveau_fence_update(fence
->channel
);
111 return !fence
->channel
;
115 nouveau_fence_wait(struct nouveau_fence
*fence
, bool lazy
, bool intr
)
117 unsigned long sleep_time
= NSEC_PER_MSEC
/ 1000;
121 while (!nouveau_fence_done(fence
)) {
122 if (fence
->timeout
&& time_after_eq(jiffies
, fence
->timeout
)) {
127 __set_current_state(intr
? TASK_INTERRUPTIBLE
:
128 TASK_UNINTERRUPTIBLE
);
130 t
= ktime_set(0, sleep_time
);
131 schedule_hrtimeout(&t
, HRTIMER_MODE_REL
);
133 if (sleep_time
> NSEC_PER_MSEC
)
134 sleep_time
= NSEC_PER_MSEC
;
137 if (intr
&& signal_pending(current
)) {
143 __set_current_state(TASK_RUNNING
);
148 nouveau_fence_sync(struct nouveau_fence
*fence
, struct nouveau_channel
*chan
)
150 struct drm_device
*dev
= chan
->dev
;
151 struct nouveau_fence_priv
*priv
= nv_engine(dev
, NVOBJ_ENGINE_FENCE
);
152 struct nouveau_channel
*prev
;
155 prev
= fence
? nouveau_channel_get_unlocked(fence
->channel
) : NULL
;
157 if (unlikely(prev
!= chan
&& !nouveau_fence_done(fence
))) {
158 ret
= priv
->sync(fence
, prev
, chan
);
160 ret
= nouveau_fence_wait(fence
, true, false);
162 nouveau_channel_put_unlocked(&prev
);
169 nouveau_fence_del(struct kref
*kref
)
171 struct nouveau_fence
*fence
= container_of(kref
, typeof(*fence
), kref
);
176 nouveau_fence_unref(struct nouveau_fence
**pfence
)
179 kref_put(&(*pfence
)->kref
, nouveau_fence_del
);
183 struct nouveau_fence
*
184 nouveau_fence_ref(struct nouveau_fence
*fence
)
186 kref_get(&fence
->kref
);
191 nouveau_fence_new(struct nouveau_channel
*chan
, struct nouveau_fence
**pfence
)
193 struct nouveau_fence
*fence
;
196 if (unlikely(!chan
->engctx
[NVOBJ_ENGINE_FENCE
]))
199 fence
= kzalloc(sizeof(*fence
), GFP_KERNEL
);
202 kref_init(&fence
->kref
);
205 ret
= nouveau_fence_emit(fence
, chan
);
207 nouveau_fence_unref(&fence
);