2 * Copyright 2007 Nouveau Project
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 #include "nouveau_private.h"
29 #include "nouveau_dma.h"
32 nouveau_fence_del_unsignalled(struct nouveau_fence
*fence
)
34 struct nouveau_channel_priv
*nvchan
= nouveau_channel(fence
->channel
);
35 struct nouveau_fence
*le
;
37 if (nvchan
->fence_head
== fence
) {
38 nvchan
->fence_head
= nouveau_fence(fence
)->next
;
39 if (nvchan
->fence_head
== NULL
)
40 nvchan
->fence_tail
= NULL
;
44 le
= nvchan
->fence_head
;
45 while (le
&& nouveau_fence(le
)->next
!= fence
)
46 le
= nouveau_fence(le
)->next
;
47 assert(le
&& nouveau_fence(le
)->next
== fence
);
48 nouveau_fence(le
)->next
= nouveau_fence(fence
)->next
;
49 if (nvchan
->fence_tail
== fence
)
50 nvchan
->fence_tail
= le
;
54 nouveau_fence_del(struct nouveau_fence
**fence
)
56 struct nouveau_fence_priv
*nvfence
;
58 if (!fence
|| !*fence
)
60 nvfence
= nouveau_fence(*fence
);
63 if (--nvfence
->refcount
)
66 if (nvfence
->emitted
&& !nvfence
->signalled
) {
67 if (nvfence
->signal_cb
) {
69 nouveau_fence_wait((void *)&nvfence
);
73 nouveau_fence_del_unsignalled(&nvfence
->base
);
79 nouveau_fence_new(struct nouveau_channel
*chan
, struct nouveau_fence
**fence
)
81 struct nouveau_fence_priv
*nvfence
;
83 if (!chan
|| !fence
|| *fence
)
86 nvfence
= calloc(1, sizeof(struct nouveau_fence_priv
));
89 nvfence
->base
.channel
= chan
;
90 nvfence
->refcount
= 1;
92 *fence
= &nvfence
->base
;
97 nouveau_fence_ref(struct nouveau_fence
*ref
, struct nouveau_fence
**fence
)
103 nouveau_fence(ref
)->refcount
++;
106 nouveau_fence_del(fence
);
113 nouveau_fence_signal_cb(struct nouveau_fence
*fence
, void (*func
)(void *),
116 struct nouveau_fence_priv
*nvfence
= nouveau_fence(fence
);
117 struct nouveau_fence_cb
*cb
;
119 if (!nvfence
|| !func
)
122 cb
= malloc(sizeof(struct nouveau_fence_cb
));
128 cb
->next
= nvfence
->signal_cb
;
129 nvfence
->signal_cb
= cb
;
134 nouveau_fence_emit(struct nouveau_fence
*fence
)
136 struct nouveau_channel_priv
*nvchan
= nouveau_channel(fence
->channel
);
137 struct nouveau_fence_priv
*nvfence
= nouveau_fence(fence
);
139 nvfence
->emitted
= 1;
140 nvfence
->sequence
= ++nvchan
->fence_sequence
;
141 if (nvfence
->sequence
== 0xffffffff)
142 printf("AII wrap unhandled\n");
144 if (!nvchan
->fence_ntfy
) {
145 /*XXX: assumes subc 0 is populated */
146 nouveau_dma_space(fence
->channel
, 2);
147 nouveau_dma_out (fence
->channel
, 0x00040050);
148 nouveau_dma_out (fence
->channel
, nvfence
->sequence
);
150 nouveau_dma_kickoff(fence
->channel
);
152 if (nvchan
->fence_tail
) {
153 nouveau_fence(nvchan
->fence_tail
)->next
= fence
;
155 nvchan
->fence_head
= fence
;
157 nvchan
->fence_tail
= fence
;
161 nouveau_fence_flush_seq(struct nouveau_channel
*chan
, uint32_t sequence
)
163 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
165 while (nvchan
->fence_head
) {
166 struct nouveau_fence_priv
*nvfence
;
168 nvfence
= nouveau_fence(nvchan
->fence_head
);
169 if (nvfence
->sequence
> sequence
)
171 nouveau_fence_del_unsignalled(&nvfence
->base
);
172 nvfence
->signalled
= 1;
174 if (nvfence
->signal_cb
) {
175 struct nouveau_fence
*fence
= NULL
;
177 nouveau_fence_ref(&nvfence
->base
, &fence
);
179 while (nvfence
->signal_cb
) {
180 struct nouveau_fence_cb
*cb
;
182 cb
= nvfence
->signal_cb
;
183 nvfence
->signal_cb
= cb
->next
;
188 nouveau_fence_ref(NULL
, &fence
);
194 nouveau_fence_flush(struct nouveau_channel
*chan
)
196 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
198 if (!nvchan
->fence_ntfy
)
199 nouveau_fence_flush_seq(chan
, *nvchan
->ref_cnt
);
203 nouveau_fence_wait(struct nouveau_fence
**fence
)
205 struct nouveau_fence_priv
*nvfence
;
206 struct nouveau_channel_priv
*nvchan
;
211 nvfence
= nouveau_fence(*fence
);
214 nvchan
= nouveau_channel(nvfence
->base
.channel
);
216 if (nvfence
->emitted
) {
217 if (!nvfence
->signalled
&& nvchan
->fence_ntfy
) {
218 struct nouveau_channel
*chan
= &nvchan
->base
;
221 /*XXX: NV04/NV05: Full sync + flush all fences */
222 nouveau_notifier_reset(nvchan
->fence_ntfy
, 0);
223 BEGIN_RING(chan
, nvchan
->fence_grobj
, 0x0104, 1);
225 BEGIN_RING(chan
, nvchan
->fence_grobj
, 0x0100, 1);
228 ret
= nouveau_notifier_wait_status(nvchan
->fence_ntfy
,
233 nouveau_fence_flush_seq(chan
, nvchan
->fence_sequence
);
236 while (!nvfence
->signalled
)
237 nouveau_fence_flush(nvfence
->base
.channel
);
240 nouveau_fence_ref(NULL
, fence
);