428b19b46eac13fe22daae103daf7e6f821740cd
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_sync.c
1 /*
2 * Copyright (C) 2007 Ben Skeggs.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 #include "vblank.h" /* for DO_USLEEP */
29
30 #include "nouveau_context.h"
31 #include "nouveau_buffers.h"
32 #include "nouveau_object.h"
33 #include "nouveau_fifo.h"
34 #include "nouveau_reg.h"
35 #include "nouveau_msg.h"
36 #include "nouveau_sync.h"
37
38 nouveau_notifier *
39 nouveau_notifier_new(GLcontext *ctx, GLuint handle, GLuint count)
40 {
41 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
42 nouveau_notifier *notifier;
43
44 #ifdef NOUVEAU_RING_DEBUG
45 return NULL;
46 #endif
47
48 notifier = CALLOC_STRUCT(nouveau_notifier_t);
49 if (!notifier)
50 return NULL;
51
52 notifier->mem = nouveau_mem_alloc(ctx,
53 NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED,
54 count * NV_NOTIFIER_SIZE,
55 0);
56 if (!notifier->mem) {
57 FREE(notifier);
58 return NULL;
59 }
60
61 if (!nouveauCreateDmaObjectFromMem(nmesa, handle, NV_DMA_IN_MEMORY,
62 notifier->mem,
63 NOUVEAU_MEM_ACCESS_RW)) {
64 nouveau_mem_free(ctx, notifier->mem);
65 FREE(notifier);
66 return NULL;
67 }
68
69 notifier->handle = handle;
70 return notifier;
71 }
72
73 void
74 nouveau_notifier_destroy(GLcontext *ctx, nouveau_notifier *notifier)
75 {
76 /*XXX: free DMA object.. */
77 nouveau_mem_free(ctx, notifier->mem);
78 FREE(notifier);
79 }
80
81 void
82 nouveau_notifier_reset(nouveau_notifier *notifier, GLuint id)
83 {
84 volatile GLuint *n = notifier->mem->map + (id * NV_NOTIFIER_SIZE);
85
86 #ifdef NOUVEAU_RING_DEBUG
87 return;
88 #endif
89
90 n[NV_NOTIFY_TIME_0 /4] = 0x00000000;
91 n[NV_NOTIFY_TIME_1 /4] = 0x00000000;
92 n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
93 n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
94 NV_NOTIFY_STATE_STATUS_SHIFT);
95 }
96
97 GLuint
98 nouveau_notifier_status(nouveau_notifier *notifier, GLuint id)
99 {
100 volatile GLuint *n = notifier->mem->map + (id * NV_NOTIFIER_SIZE);
101
102 return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
103 }
104
105 GLuint
106 nouveau_notifier_return_val(nouveau_notifier *notifier, GLuint id)
107 {
108 volatile GLuint *n = notifier->mem->map + (id * NV_NOTIFIER_SIZE);
109
110 return n[NV_NOTIFY_RETURN_VALUE/4];
111 }
112
113 GLboolean
114 nouveau_notifier_wait_status(nouveau_notifier *notifier, GLuint id,
115 GLuint status, GLuint timeout)
116 {
117 volatile GLuint *n = notifier->mem->map + (id * NV_NOTIFIER_SIZE);
118 unsigned int time = 0;
119
120 #ifdef NOUVEAU_RING_DEBUG
121 return GL_TRUE;
122 #endif
123
124 while (time <= timeout) {
125 if (n[NV_NOTIFY_STATE/4] & NV_NOTIFY_STATE_ERROR_CODE_MASK) {
126 MESSAGE("Notifier returned error: 0x%04x\n",
127 n[NV_NOTIFY_STATE] &
128 NV_NOTIFY_STATE_ERROR_CODE_MASK);
129 return GL_FALSE;
130 }
131
132 if (((n[NV_NOTIFY_STATE/4] & NV_NOTIFY_STATE_STATUS_MASK) >>
133 NV_NOTIFY_STATE_STATUS_SHIFT) == status)
134 return GL_TRUE;
135
136 if (timeout) {
137 DO_USLEEP(1);
138 time++;
139 }
140 }
141
142 MESSAGE("Notifier timed out\n");
143 return GL_FALSE;
144 }
145
146 void
147 nouveau_notifier_wait_nop(GLcontext *ctx, nouveau_notifier *notifier,
148 GLuint subc)
149 {
150 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
151 GLboolean ret;
152
153 nouveau_notifier_reset(notifier, 0);
154
155 BEGIN_RING_SIZE(subc, NV_NOTIFY, 1);
156 OUT_RING (NV_NOTIFY_STYLE_WRITE_ONLY);
157 BEGIN_RING_SIZE(subc, NV_NOP, 1);
158 OUT_RING (0);
159 FIRE_RING();
160
161 ret = nouveau_notifier_wait_status(notifier, 0,
162 NV_NOTIFY_STATE_STATUS_COMPLETED,
163 0 /* no timeout */);
164 if (ret == GL_FALSE) MESSAGE("wait on notifier failed\n");
165 }
166
167 GLboolean nouveauSyncInitFuncs(GLcontext *ctx)
168 {
169 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
170
171 #ifdef NOUVEAU_RING_DEBUG
172 return GL_TRUE;
173 #endif
174
175 nmesa->syncNotifier = nouveau_notifier_new(ctx, NvSyncNotify, 1);
176 if (!nmesa->syncNotifier) {
177 MESSAGE("Failed to create channel sync notifier\n");
178 return GL_FALSE;
179 }
180
181 /* 0x180 is SET_DMA_NOTIFY, should be correct for all supported 3D
182 * object classes
183 */
184 BEGIN_RING_CACHE(NvSub3D, 0x180, 1);
185 OUT_RING_CACHE (NvSyncNotify);
186 #ifdef ALLOW_MULTI_SUBCHANNEL
187 BEGIN_RING_SIZE(NvSubMemFormat,
188 NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
189 OUT_RING (NvSyncNotify);
190 #endif
191
192 return GL_TRUE;
193 }
194