1 /*	$NetBSD: nouveau_nv84_fence.c,v 1.2 2015/02/25 14:57:04 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2012 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors: Ben Skeggs
25  */
26 
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: nouveau_nv84_fence.c,v 1.2 2015/02/25 14:57:04 riastradh Exp $");
29 
30 #include <core/object.h>
31 #include <core/client.h>
32 #include <core/class.h>
33 
34 #include <engine/fifo.h>
35 
36 #include "nouveau_drm.h"
37 #include "nouveau_dma.h"
38 #include "nouveau_fence.h"
39 
40 #include "nv50_display.h"
41 
42 u64
nv84_fence_crtc(struct nouveau_channel * chan,int crtc)43 nv84_fence_crtc(struct nouveau_channel *chan, int crtc)
44 {
45 	struct nv84_fence_chan *fctx = chan->fence;
46 	return fctx->dispc_vma[crtc].offset;
47 }
48 
49 static int
nv84_fence_emit32(struct nouveau_channel * chan,u64 virtual,u32 sequence)50 nv84_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
51 {
52 	int ret = RING_SPACE(chan, 8);
53 	if (ret == 0) {
54 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
55 		OUT_RING  (chan, chan->vram);
56 		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5);
57 		OUT_RING  (chan, upper_32_bits(virtual));
58 		OUT_RING  (chan, lower_32_bits(virtual));
59 		OUT_RING  (chan, sequence);
60 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
61 		OUT_RING  (chan, 0x00000000);
62 		FIRE_RING (chan);
63 	}
64 	return ret;
65 }
66 
67 static int
nv84_fence_sync32(struct nouveau_channel * chan,u64 virtual,u32 sequence)68 nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
69 {
70 	int ret = RING_SPACE(chan, 7);
71 	if (ret == 0) {
72 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
73 		OUT_RING  (chan, chan->vram);
74 		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
75 		OUT_RING  (chan, upper_32_bits(virtual));
76 		OUT_RING  (chan, lower_32_bits(virtual));
77 		OUT_RING  (chan, sequence);
78 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL);
79 		FIRE_RING (chan);
80 	}
81 	return ret;
82 }
83 
84 static int
nv84_fence_emit(struct nouveau_fence * fence)85 nv84_fence_emit(struct nouveau_fence *fence)
86 {
87 	struct nouveau_channel *chan = fence->channel;
88 	struct nv84_fence_chan *fctx = chan->fence;
89 	struct nouveau_fifo_chan *fifo = (void *)chan->object;
90 	u64 addr = fifo->chid * 16;
91 
92 	if (fence->sysmem)
93 		addr += fctx->vma_gart.offset;
94 	else
95 		addr += fctx->vma.offset;
96 
97 	return fctx->base.emit32(chan, addr, fence->sequence);
98 }
99 
100 static int
nv84_fence_sync(struct nouveau_fence * fence,struct nouveau_channel * prev,struct nouveau_channel * chan)101 nv84_fence_sync(struct nouveau_fence *fence,
102 		struct nouveau_channel *prev, struct nouveau_channel *chan)
103 {
104 	struct nv84_fence_chan *fctx = chan->fence;
105 	struct nouveau_fifo_chan *fifo = (void *)prev->object;
106 	u64 addr = fifo->chid * 16;
107 
108 	if (fence->sysmem)
109 		addr += fctx->vma_gart.offset;
110 	else
111 		addr += fctx->vma.offset;
112 
113 	return fctx->base.sync32(chan, addr, fence->sequence);
114 }
115 
116 static u32
nv84_fence_read(struct nouveau_channel * chan)117 nv84_fence_read(struct nouveau_channel *chan)
118 {
119 	struct nouveau_fifo_chan *fifo = (void *)chan->object;
120 	struct nv84_fence_priv *priv = chan->drm->fence;
121 	return nouveau_bo_rd32(priv->bo, fifo->chid * 16/4);
122 }
123 
124 static void
nv84_fence_context_del(struct nouveau_channel * chan)125 nv84_fence_context_del(struct nouveau_channel *chan)
126 {
127 	struct drm_device *dev = chan->drm->dev;
128 	struct nv84_fence_priv *priv = chan->drm->fence;
129 	struct nv84_fence_chan *fctx = chan->fence;
130 	int i;
131 
132 	for (i = 0; i < dev->mode_config.num_crtc; i++) {
133 		struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
134 		nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
135 	}
136 
137 	nouveau_bo_vma_del(priv->bo, &fctx->vma_gart);
138 	nouveau_bo_vma_del(priv->bo, &fctx->vma);
139 	nouveau_fence_context_del(&fctx->base);
140 	chan->fence = NULL;
141 	kfree(fctx);
142 }
143 
144 int
nv84_fence_context_new(struct nouveau_channel * chan)145 nv84_fence_context_new(struct nouveau_channel *chan)
146 {
147 	struct nouveau_fifo_chan *fifo = (void *)chan->object;
148 	struct nouveau_client *client = nouveau_client(fifo);
149 	struct nv84_fence_priv *priv = chan->drm->fence;
150 	struct nv84_fence_chan *fctx;
151 	int ret, i;
152 
153 	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
154 	if (!fctx)
155 		return -ENOMEM;
156 
157 	nouveau_fence_context_new(&fctx->base);
158 	fctx->base.emit = nv84_fence_emit;
159 	fctx->base.sync = nv84_fence_sync;
160 	fctx->base.read = nv84_fence_read;
161 	fctx->base.emit32 = nv84_fence_emit32;
162 	fctx->base.sync32 = nv84_fence_sync32;
163 
164 	ret = nouveau_bo_vma_add(priv->bo, client->vm, &fctx->vma);
165 	if (ret == 0) {
166 		ret = nouveau_bo_vma_add(priv->bo_gart, client->vm,
167 					&fctx->vma_gart);
168 	}
169 
170 	/* map display semaphore buffers into channel's vm */
171 	for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
172 		struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i);
173 		ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]);
174 	}
175 
176 	nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000);
177 
178 	if (ret)
179 		nv84_fence_context_del(chan);
180 	return ret;
181 }
182 
183 static bool
nv84_fence_suspend(struct nouveau_drm * drm)184 nv84_fence_suspend(struct nouveau_drm *drm)
185 {
186 	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
187 	struct nv84_fence_priv *priv = drm->fence;
188 	int i;
189 
190 	priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32));
191 	if (priv->suspend) {
192 		for (i = 0; i <= pfifo->max; i++)
193 			priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4);
194 	}
195 
196 	return priv->suspend != NULL;
197 }
198 
199 static void
nv84_fence_resume(struct nouveau_drm * drm)200 nv84_fence_resume(struct nouveau_drm *drm)
201 {
202 	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
203 	struct nv84_fence_priv *priv = drm->fence;
204 	int i;
205 
206 	if (priv->suspend) {
207 		for (i = 0; i <= pfifo->max; i++)
208 			nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]);
209 		vfree(priv->suspend);
210 		priv->suspend = NULL;
211 	}
212 }
213 
214 static void
nv84_fence_destroy(struct nouveau_drm * drm)215 nv84_fence_destroy(struct nouveau_drm *drm)
216 {
217 	struct nv84_fence_priv *priv = drm->fence;
218 
219 #ifdef __NetBSD__
220 	spin_lock_destroy(&priv->base.waitlock);
221 	DRM_DESTROY_WAITQUEUE(&priv->base.waitqueue);
222 #endif
223 
224 	nouveau_bo_unmap(priv->bo_gart);
225 	if (priv->bo_gart)
226 		nouveau_bo_unpin(priv->bo_gart);
227 	nouveau_bo_ref(NULL, &priv->bo_gart);
228 	nouveau_bo_unmap(priv->bo);
229 	if (priv->bo)
230 		nouveau_bo_unpin(priv->bo);
231 	nouveau_bo_ref(NULL, &priv->bo);
232 	drm->fence = NULL;
233 	kfree(priv);
234 }
235 
236 int
nv84_fence_create(struct nouveau_drm * drm)237 nv84_fence_create(struct nouveau_drm *drm)
238 {
239 	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
240 	struct nv84_fence_priv *priv;
241 	int ret;
242 
243 	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
244 	if (!priv)
245 		return -ENOMEM;
246 
247 	priv->base.dtor = nv84_fence_destroy;
248 	priv->base.suspend = nv84_fence_suspend;
249 	priv->base.resume = nv84_fence_resume;
250 	priv->base.context_new = nv84_fence_context_new;
251 	priv->base.context_del = nv84_fence_context_del;
252 
253 #ifdef __NetBSD__
254 	spin_lock_init(&priv->base.waitlock);
255 	DRM_INIT_WAITQUEUE(&priv->base.waitqueue, "nvfenceq");
256 #else
257 	init_waitqueue_head(&priv->base.waiting);
258 #endif
259 	priv->base.uevent = true;
260 
261 	ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0,
262 			     TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo);
263 	if (ret == 0) {
264 		ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
265 		if (ret == 0) {
266 			ret = nouveau_bo_map(priv->bo);
267 			if (ret)
268 				nouveau_bo_unpin(priv->bo);
269 		}
270 		if (ret)
271 			nouveau_bo_ref(NULL, &priv->bo);
272 	}
273 
274 	if (ret == 0)
275 		ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0,
276 				     TTM_PL_FLAG_TT, 0, 0, NULL,
277 				     &priv->bo_gart);
278 	if (ret == 0) {
279 		ret = nouveau_bo_pin(priv->bo_gart, TTM_PL_FLAG_TT);
280 		if (ret == 0) {
281 			ret = nouveau_bo_map(priv->bo_gart);
282 			if (ret)
283 				nouveau_bo_unpin(priv->bo_gart);
284 		}
285 		if (ret)
286 			nouveau_bo_ref(NULL, &priv->bo_gart);
287 	}
288 
289 	if (ret)
290 		nv84_fence_destroy(drm);
291 	return ret;
292 }
293