nouveau: Wait on notifier to check for completion of previous commands.
[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, NOUVEAU_MEM_FB, 32, 0);
22 if (!notifier->mem) {
23 FREE(notifier);
24 return NULL;
25 }
26
27 if (!nouveauCreateDmaObject(nmesa, handle, notifier->mem->offset,
28 notifier->mem->size,
29 0 /* NV_DMA_TARGET_FB */,
30 0 /* NV_DMA_ACCESS_RW */)) {
31 nouveau_mem_free(ctx, notifier->mem);
32 FREE(notifier);
33 return NULL;
34 }
35
36 notifier->handle = handle;
37 return notifier;
38 }
39
40 void
41 nouveau_notifier_destroy(GLcontext *ctx, nouveau_notifier *notifier)
42 {
43 /*XXX: free DMA object.. */
44 nouveau_mem_free(ctx, notifier->mem);
45 FREE(notifier);
46 }
47
48 void
49 nouveau_notifier_reset(nouveau_notifier *notifier)
50 {
51 volatile GLuint *n = notifier->mem->map;
52
53 n[NV_NOTIFY_TIME_0 /4] = 0x00000000;
54 n[NV_NOTIFY_TIME_1 /4] = 0x00000000;
55 n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
56 n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
57 NV_NOTIFY_STATE_STATUS_SHIFT);
58 }
59
60 GLboolean
61 nouveau_notifier_wait_status(nouveau_notifier *notifier, GLuint status,
62 GLuint timeout)
63 {
64 volatile GLuint *n = notifier->mem->map;
65 unsigned int time = 0;
66
67 while (time <= timeout) {
68 if (n[NV_NOTIFY_STATE] & NV_NOTIFY_STATE_ERROR_CODE_MASK) {
69 MESSAGE("Notifier returned error: 0x%04x\n",
70 n[NV_NOTIFY_STATE] &
71 NV_NOTIFY_STATE_ERROR_CODE_MASK);
72 return GL_FALSE;
73 }
74
75 if (((n[NV_NOTIFY_STATE] & NV_NOTIFY_STATE_STATUS_MASK) >>
76 NV_NOTIFY_STATE_STATUS_SHIFT) == status)
77 return GL_TRUE;
78
79 if (timeout) {
80 DO_USLEEP(1);
81 time++;
82 }
83 }
84
85 MESSAGE("Notifier timed out\n");
86 return GL_FALSE;
87 }
88
89 void
90 nouveau_notifier_wait_nop(GLcontext *ctx, nouveau_notifier *notifier,
91 GLuint subc)
92 {
93 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
94 GLboolean ret;
95
96 nouveau_notifier_reset(notifier);
97
98 BEGIN_RING_SIZE(subc, NV_NOTIFY, 1);
99 OUT_RING (NV_NOTIFY_STYLE_WRITE_ONLY);
100 BEGIN_RING_SIZE(subc, NV_NOP, 1);
101 OUT_RING (0);
102
103 ret = nouveau_notifier_wait_status(notifier,
104 NV_NOTIFY_STATE_STATUS_COMPLETED,
105 0 /* no timeout */);
106 if (ret) MESSAGE("wait on notifier failed\n");
107 }
108
109 GLboolean nouveauSyncInitFuncs(GLcontext *ctx)
110 {
111 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
112
113 nmesa->syncNotifier = nouveau_notifier_new(ctx, NvSyncNotify);
114 if (!nmesa->syncNotifier) {
115 MESSAGE("Failed to create channel sync notifier\n");
116 return GL_FALSE;
117 }
118
119 /* 0x180 is SET_DMA_NOTIFY, should be correct for all supported 3D
120 * object classes
121 */
122 BEGIN_RING_CACHE(NvSub3D, 0x180, 1);
123 OUT_RING_CACHE (NvSyncNotify);
124
125 return GL_TRUE;
126 }
127