summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/nouveau/nouveau_sync.c
blob: e27101d8689f1da274ebc21cbf1e69b39d57ca72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "vblank.h" /* for DO_USLEEP */

#include "nouveau_context.h"
#include "nouveau_buffers.h"
#include "nouveau_object.h"
#include "nouveau_fifo.h"
#include "nouveau_reg.h"
#include "nouveau_msg.h"
#include "nouveau_sync.h"

nouveau_notifier *
nouveau_notifier_new(GLcontext *ctx, GLuint handle)
{
	nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
	nouveau_notifier *notifier;

	notifier = CALLOC_STRUCT(nouveau_notifier_t);
	if (!notifier)
		return NULL;

	notifier->mem = nouveau_mem_alloc(ctx,
					  NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED,
					  32,
					  0);
	if (!notifier->mem) {
		FREE(notifier);
		return NULL;
	}

	if (!nouveauCreateDmaObject(nmesa, handle, notifier->mem->offset,
						   notifier->mem->size,
						   0 /* NV_DMA_TARGET_FB */,
						   0 /* NV_DMA_ACCESS_RW */)) {
		nouveau_mem_free(ctx, notifier->mem);
		FREE(notifier);
		return NULL;
	}

	notifier->handle = handle;
	return notifier;
}

void
nouveau_notifier_destroy(GLcontext *ctx, nouveau_notifier *notifier)
{
	/*XXX: free DMA object.. */
	nouveau_mem_free(ctx, notifier->mem);
	FREE(notifier);
}

void
nouveau_notifier_reset(nouveau_notifier *notifier)
{
	volatile GLuint *n = notifier->mem->map;

	n[NV_NOTIFY_TIME_0      /4] = 0x00000000;
	n[NV_NOTIFY_TIME_1      /4] = 0x00000000;
	n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
	n[NV_NOTIFY_STATE       /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
				       NV_NOTIFY_STATE_STATUS_SHIFT);
}

GLboolean
nouveau_notifier_wait_status(nouveau_notifier *notifier, GLuint status,
							 GLuint timeout)
{
	volatile GLuint *n = notifier->mem->map;
	unsigned int time = 0;

	while (time <= timeout) {
		if (n[NV_NOTIFY_STATE/4] & NV_NOTIFY_STATE_ERROR_CODE_MASK) {
			MESSAGE("Notifier returned error: 0x%04x\n",
					n[NV_NOTIFY_STATE] &
					NV_NOTIFY_STATE_ERROR_CODE_MASK);
			return GL_FALSE;
		}

		if (((n[NV_NOTIFY_STATE/4] & NV_NOTIFY_STATE_STATUS_MASK) >>
				NV_NOTIFY_STATE_STATUS_SHIFT) == status)
			return GL_TRUE;

		if (timeout) {
			DO_USLEEP(1);
			time++;
		}
	}

	MESSAGE("Notifier timed out\n");
	return GL_FALSE;
}

void
nouveau_notifier_wait_nop(GLcontext *ctx, nouveau_notifier *notifier,
					  GLuint subc)
{
	nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
	GLboolean ret;

	nouveau_notifier_reset(notifier);

	BEGIN_RING_SIZE(subc, NV_NOTIFY, 1);
	OUT_RING       (NV_NOTIFY_STYLE_WRITE_ONLY);
	BEGIN_RING_SIZE(subc, NV_NOP, 1);
	OUT_RING       (0);
	FIRE_RING();

	ret = nouveau_notifier_wait_status(notifier,
					   NV_NOTIFY_STATE_STATUS_COMPLETED,
					   0 /* no timeout */);
	if (ret == GL_FALSE) MESSAGE("wait on notifier failed\n");
}

GLboolean nouveauSyncInitFuncs(GLcontext *ctx)
{
	nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);

	nmesa->syncNotifier = nouveau_notifier_new(ctx, NvSyncNotify);
	if (!nmesa->syncNotifier) {
		MESSAGE("Failed to create channel sync notifier\n");
		return GL_FALSE;
	}

	/* 0x180 is SET_DMA_NOTIFY, should be correct for all supported 3D
	 * object classes
	 */
	BEGIN_RING_CACHE(NvSub3D, 0x180, 1);
	OUT_RING_CACHE  (NvSyncNotify);

	return GL_TRUE;
}