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
26 #include "nouveau_drmif.h"
27 #include "nouveau_dma.h"
28 #include "nouveau_local.h"
31 nouveau_fence_new(struct nouveau_channel
*chan
, struct nouveau_fence
**fence
)
33 struct nouveau_fence_priv
*nvfence
;
35 if (!chan
|| !fence
|| *fence
)
38 nvfence
= calloc(1, sizeof(struct nouveau_fence_priv
));
41 nvfence
->base
.channel
= chan
;
42 nvfence
->refcount
= 1;
44 *fence
= &nvfence
->base
;
49 nouveau_fence_ref(struct nouveau_fence
*ref
, struct nouveau_fence
**fence
)
51 struct nouveau_fence_priv
*nvfence
;
53 if (!ref
|| !fence
|| *fence
)
55 nvfence
= nouveau_fence(ref
);
58 *fence
= &nvfence
->base
;
63 nouveau_fence_del(struct nouveau_fence
**fence
)
65 struct nouveau_fence_priv
*nvfence
;
67 if (!fence
|| !*fence
)
69 nvfence
= nouveau_fence(*fence
);
72 if (--nvfence
->refcount
<= 0) {
73 if (nvfence
->emitted
&& !nvfence
->signalled
)
74 nouveau_fence_wait((void *)&nvfence
);
80 nouveau_fence_signal_cb(struct nouveau_fence
*fence
, void (*func
)(void *),
83 struct nouveau_fence_priv
*nvfence
= nouveau_fence(fence
);
84 struct nouveau_fence_cb
*cb
;
86 if (!nvfence
|| !func
)
89 cb
= malloc(sizeof(struct nouveau_fence_cb
));
95 cb
->next
= nvfence
->signal_cb
;
96 nvfence
->signal_cb
= cb
;
101 nouveau_fence_emit(struct nouveau_fence
*fence
)
103 struct nouveau_channel_priv
*nvchan
= nouveau_channel(fence
->channel
);
104 struct nouveau_fence_priv
*nvfence
= nouveau_fence(fence
);
106 nvfence
->emitted
= 1;
107 nvfence
->sequence
= ++nvchan
->fence_sequence
;
108 if (nvfence
->sequence
== 0xffffffff)
109 NOUVEAU_ERR("AII wrap unhandled\n");
111 /*XXX: assumes subc 0 is populated */
112 if (nvchan
->dma
.free
< 2)
113 WAIT_RING_CH(&nvchan
->base
, 2);
114 nvchan
->dma
.free
-= 2;
115 #ifdef NOUVEAU_DMA_DEBUG
116 nvchan
->dma
.push_free
+= 2;
118 OUT_RING_CH(&nvchan
->base
, 0x00040050);
119 OUT_RING_CH(&nvchan
->base
, nvfence
->sequence
);
121 if (nvchan
->fence_tail
) {
122 nouveau_fence(nvchan
->fence_tail
)->next
= fence
;
124 nvchan
->fence_head
= fence
;
126 nvchan
->fence_tail
= fence
;
130 nouveau_fence_flush(struct nouveau_channel
*chan
)
132 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
133 uint32_t sequence
= *nvchan
->ref_cnt
;
135 while (nvchan
->fence_head
) {
136 struct nouveau_fence
*fence
= NULL
;
137 struct nouveau_fence_priv
*nvfence
;
139 nouveau_fence_ref(nvchan
->fence_head
, &fence
);
140 nvfence
= nouveau_fence(nvchan
->fence_head
);
142 if (nvfence
->sequence
> sequence
) {
143 nouveau_fence_del(&fence
);
147 nvchan
->fence_head
= nvfence
->next
;
148 if (nvchan
->fence_head
== NULL
)
149 nvchan
->fence_tail
= NULL
;
150 nvfence
->signalled
= 1;
152 while (nvfence
->signal_cb
) {
153 struct nouveau_fence_cb
*cb
= nvfence
->signal_cb
;
154 nvfence
->signal_cb
= cb
->next
;
159 nouveau_fence_del(&fence
);
164 nouveau_fence_wait(struct nouveau_fence
**fence
)
166 struct nouveau_fence_priv
*nvfence
;
168 if (!fence
|| !*fence
)
170 nvfence
= nouveau_fence(*fence
);
172 if (nvfence
->emitted
) {
173 while (!nvfence
->signalled
)
174 nouveau_fence_flush(nvfence
->base
.channel
);
176 nouveau_fence_del(fence
);