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