Merge branch 'master' of git+ssh://keithw@git.freedesktop.org/git/mesa/mesa into...
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_sync.c
1 #include "vblank.h" /* for DO_USLEEP */
2
3 #include "nouveau_context.h"
4 #include "nouveau_buffers.h"
5 #include "nouveau_object.h"
6 #include "nouveau_fifo.h"
7 #include "nouveau_reg.h"
8 #include "nouveau_msg.h"
9 #include "nouveau_sync.h"
10
11 nouveau_notifier *
12 nouveau_notifier_new(GLcontext *ctx, GLuint handle)
13 {
14 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
15 nouveau_notifier *notifier;
16
17 notifier = CALLOC_STRUCT(nouveau_notifier_t);
18 if (!notifier)
19 return NULL;
20
21 notifier->mem = nouveau_mem_alloc(ctx,
22 NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED,
23 32,
24 0);
25 if (!notifier->mem) {
26 FREE(notifier);
27 return NULL;
28 }
29
30 if (!nouveauCreateDmaObject(nmesa, handle, notifier->mem->offset,
31 notifier->mem->size,
32 0 /* NV_DMA_TARGET_FB */,
33 0 /* NV_DMA_ACCESS_RW */)) {
34 nouveau_mem_free(ctx, notifier->mem);
35 FREE(notifier);
36 return NULL;
37 }
38
39 notifier->handle = handle;
40 return notifier;
41 }
42
43 void
44 nouveau_notifier_destroy(GLcontext *ctx, nouveau_notifier *notifier)
45 {
46 /*XXX: free DMA object.. */
47 nouveau_mem_free(ctx, notifier->mem);
48 FREE(notifier);
49 }
50
51 void
52 nouveau_notifier_reset(nouveau_notifier *notifier)
53 {
54 volatile GLuint *n = notifier->mem->map;
55
56 n[NV_NOTIFY_TIME_0 /4] = 0x00000000;
57 n[NV_NOTIFY_TIME_1 /4] = 0x00000000;
58 n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
59 n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
60 NV_NOTIFY_STATE_STATUS_SHIFT);
61 }
62
63 GLboolean
64 nouveau_notifier_wait_status(nouveau_notifier *notifier, GLuint status,
65 GLuint timeout)
66 {
67 volatile GLuint *n = notifier->mem->map;
68 unsigned int time = 0;
69
70 while (time <= timeout) {
71 if (n[NV_NOTIFY_STATE/4] & NV_NOTIFY_STATE_ERROR_CODE_MASK) {
72 MESSAGE("Notifier returned error: 0x%04x\n",
73 n[NV_NOTIFY_STATE] &
74 NV_NOTIFY_STATE_ERROR_CODE_MASK);
75 return GL_FALSE;
76 }
77
78 if (((n[NV_NOTIFY_STATE/4] & NV_NOTIFY_STATE_STATUS_MASK) >>
79 NV_NOTIFY_STATE_STATUS_SHIFT) == status)
80 return GL_TRUE;
81
82 if (timeout) {
83 DO_USLEEP(1);
84 time++;
85 }
86 }
87
88 MESSAGE("Notifier timed out\n");
89 return GL_FALSE;
90 }
91
92 void
93 nouveau_notifier_wait_nop(GLcontext *ctx, nouveau_notifier *notifier,
94 GLuint subc)
95 {
96 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
97 GLboolean ret;
98
99 nouveau_notifier_reset(notifier);
100
101 BEGIN_RING_SIZE(subc, NV_NOTIFY, 1);
102 OUT_RING (NV_NOTIFY_STYLE_WRITE_ONLY);
103 BEGIN_RING_SIZE(subc, NV_NOP, 1);
104 OUT_RING (0);
105 FIRE_RING();
106
107 ret = nouveau_notifier_wait_status(notifier,
108 NV_NOTIFY_STATE_STATUS_COMPLETED,
109 0 /* no timeout */);
110 if (ret == GL_FALSE) MESSAGE("wait on notifier failed\n");
111 }
112
113 GLboolean nouveauSyncInitFuncs(GLcontext *ctx)
114 {
115 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
116
117 nmesa->syncNotifier = nouveau_notifier_new(ctx, NvSyncNotify);
118 if (!nmesa->syncNotifier) {
119 MESSAGE("Failed to create channel sync notifier\n");
120 return GL_FALSE;
121 }
122
123 /* 0x180 is SET_DMA_NOTIFY, should be correct for all supported 3D
124 * object classes
125 */
126 BEGIN_RING_CACHE(NvSub3D, 0x180, 1);
127 OUT_RING_CACHE (NvSyncNotify);
128 #ifdef ALLOW_MULTI_SUBCHANNEL
129 BEGIN_RING_SIZE(NvSubMemFormat,
130 NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
131 OUT_RING (NvSyncNotify);
132 #endif
133
134 return GL_TRUE;
135 }
136