nouveau: nuke subchan auto-assign.
[mesa.git] / src / mesa / drivers / dri / nouveau_winsys / nouveau_fence.c
1 /*
2 * Copyright 2007 Nouveau Project
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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
20 * SOFTWARE.
21 */
22
23 #include <stdlib.h>
24 #include <errno.h>
25
26 #include "nouveau_drmif.h"
27 #include "nouveau_dma.h"
28 #include "nouveau_local.h"
29
30 int
31 nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **fence)
32 {
33 struct nouveau_fence_priv *nvfence;
34
35 if (!chan || !fence || *fence)
36 return -EINVAL;
37
38 nvfence = calloc(1, sizeof(struct nouveau_fence_priv));
39 if (!nvfence)
40 return -ENOMEM;
41 nvfence->base.channel = chan;
42 nvfence->refcount = 1;
43
44 *fence = &nvfence->base;
45 return 0;
46 }
47
48 int
49 nouveau_fence_ref(struct nouveau_fence *ref, struct nouveau_fence **fence)
50 {
51 struct nouveau_fence_priv *nvfence;
52
53 if (!ref || !fence || *fence)
54 return -EINVAL;
55 nvfence = nouveau_fence(ref);
56 nvfence->refcount++;
57
58 *fence = &nvfence->base;
59 return 0;
60 }
61
62 void
63 nouveau_fence_del(struct nouveau_fence **fence)
64 {
65 struct nouveau_fence_priv *nvfence;
66
67 if (!fence || !*fence)
68 return;
69 nvfence = nouveau_fence(*fence);
70 *fence = NULL;
71
72 if (--nvfence->refcount <= 0) {
73 if (nvfence->emitted && !nvfence->signalled)
74 nouveau_fence_wait((void *)&nvfence);
75 free(nvfence);
76 }
77 }
78
79 int
80 nouveau_fence_signal_cb(struct nouveau_fence *fence, void (*func)(void *),
81 void *priv)
82 {
83 struct nouveau_fence_priv *nvfence = nouveau_fence(fence);
84 struct nouveau_fence_cb *cb;
85
86 if (!nvfence || !func)
87 return -EINVAL;
88
89 cb = malloc(sizeof(struct nouveau_fence_cb));
90 if (!cb)
91 return -ENOMEM;
92
93 cb->func = func;
94 cb->priv = priv;
95 cb->next = nvfence->signal_cb;
96 nvfence->signal_cb = cb;
97 return 0;
98 }
99
100 void
101 nouveau_fence_emit(struct nouveau_fence *fence)
102 {
103 struct nouveau_channel_priv *nvchan = nouveau_channel(fence->channel);
104 struct nouveau_fence_priv *nvfence = nouveau_fence(fence);
105
106 nvfence->emitted = 1;
107 nvfence->sequence = ++nvchan->fence_sequence;
108 if (nvfence->sequence == 0xffffffff)
109 NOUVEAU_ERR("AII wrap unhandled\n");
110
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;
117 #endif
118 OUT_RING_CH(&nvchan->base, 0x00040050);
119 OUT_RING_CH(&nvchan->base, nvfence->sequence);
120
121 if (nvchan->fence_tail) {
122 nouveau_fence(nvchan->fence_tail)->next = fence;
123 } else {
124 nvchan->fence_head = fence;
125 }
126 nvchan->fence_tail = fence;
127 }
128
129 void
130 nouveau_fence_flush(struct nouveau_channel *chan)
131 {
132 struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
133 uint32_t sequence = *nvchan->ref_cnt;
134
135 while (nvchan->fence_head) {
136 struct nouveau_fence *fence = NULL;
137 struct nouveau_fence_priv *nvfence;
138
139 nouveau_fence_ref(nvchan->fence_head, &fence);
140 nvfence = nouveau_fence(nvchan->fence_head);
141
142 if (nvfence->sequence > sequence) {
143 nouveau_fence_del(&fence);
144 break;
145 }
146
147 nvchan->fence_head = nvfence->next;
148 if (nvchan->fence_head == NULL)
149 nvchan->fence_tail = NULL;
150 nvfence->signalled = 1;
151
152 while (nvfence->signal_cb) {
153 struct nouveau_fence_cb *cb = nvfence->signal_cb;
154 nvfence->signal_cb = cb->next;
155 cb->func(cb->priv);
156 free(cb);
157 }
158
159 nouveau_fence_del(&fence);
160 }
161 }
162
163 int
164 nouveau_fence_wait(struct nouveau_fence **fence)
165 {
166 struct nouveau_fence_priv *nvfence;
167
168 if (!fence || !*fence)
169 return -EINVAL;
170 nvfence = nouveau_fence(*fence);
171
172 if (nvfence->emitted) {
173 while (!nvfence->signalled)
174 nouveau_fence_flush(nvfence->base.channel);
175 }
176 nouveau_fence_del(fence);
177
178 return 0;
179 }
180