xref: /linux/drivers/gpu/drm/nouveau/nouveau_chan.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * Copyright 2012 Red Hat Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Ben Skeggs
23  */
24 
25 #include <nvif/os.h>
26 #include <nvif/class.h>
27 #include <nvif/ioctl.h>
28 
29 /*XXX*/
30 #include <core/client.h>
31 
32 #include "nouveau_drm.h"
33 #include "nouveau_dma.h"
34 #include "nouveau_bo.h"
35 #include "nouveau_chan.h"
36 #include "nouveau_fence.h"
37 #include "nouveau_abi16.h"
38 
39 MODULE_PARM_DESC(vram_pushbuf, "Create DMA push buffers in VRAM");
40 int nouveau_vram_pushbuf;
41 module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
42 
43 int
44 nouveau_channel_idle(struct nouveau_channel *chan)
45 {
46 	if (likely(chan && chan->fence)) {
47 		struct nouveau_cli *cli = (void *)chan->user.client;
48 		struct nouveau_fence *fence = NULL;
49 		int ret;
50 
51 		ret = nouveau_fence_new(chan, false, &fence);
52 		if (!ret) {
53 			ret = nouveau_fence_wait(fence, false, false);
54 			nouveau_fence_unref(&fence);
55 		}
56 
57 		if (ret) {
58 			NV_PRINTK(err, cli, "failed to idle channel "
59 					    "0x%08x [%s]\n",
60 				  chan->user.handle,
61 				  nvxx_client(&cli->base)->name);
62 			return ret;
63 		}
64 	}
65 	return 0;
66 }
67 
68 void
69 nouveau_channel_del(struct nouveau_channel **pchan)
70 {
71 	struct nouveau_channel *chan = *pchan;
72 	if (chan) {
73 		if (chan->fence)
74 			nouveau_fence(chan->drm)->context_del(chan);
75 		nvif_object_fini(&chan->nvsw);
76 		nvif_object_fini(&chan->gart);
77 		nvif_object_fini(&chan->vram);
78 		nvif_object_fini(&chan->user);
79 		nvif_object_fini(&chan->push.ctxdma);
80 		nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma);
81 		nouveau_bo_unmap(chan->push.buffer);
82 		if (chan->push.buffer && chan->push.buffer->pin_refcnt)
83 			nouveau_bo_unpin(chan->push.buffer);
84 		nouveau_bo_ref(NULL, &chan->push.buffer);
85 		kfree(chan);
86 	}
87 	*pchan = NULL;
88 }
89 
90 static int
91 nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
92 		     u32 handle, u32 size, struct nouveau_channel **pchan)
93 {
94 	struct nouveau_cli *cli = (void *)device->object.client;
95 	struct nvkm_mmu *mmu = nvxx_mmu(device);
96 	struct nv_dma_v0 args = {};
97 	struct nouveau_channel *chan;
98 	u32 target;
99 	int ret;
100 
101 	chan = *pchan = kzalloc(sizeof(*chan), GFP_KERNEL);
102 	if (!chan)
103 		return -ENOMEM;
104 
105 	chan->device = device;
106 	chan->drm = drm;
107 
108 	/* allocate memory for dma push buffer */
109 	target = TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED;
110 	if (nouveau_vram_pushbuf)
111 		target = TTM_PL_FLAG_VRAM;
112 
113 	ret = nouveau_bo_new(drm->dev, size, 0, target, 0, 0, NULL, NULL,
114 			    &chan->push.buffer);
115 	if (ret == 0) {
116 		ret = nouveau_bo_pin(chan->push.buffer, target, false);
117 		if (ret == 0)
118 			ret = nouveau_bo_map(chan->push.buffer);
119 	}
120 
121 	if (ret) {
122 		nouveau_channel_del(pchan);
123 		return ret;
124 	}
125 
126 	/* create dma object covering the *entire* memory space that the
127 	 * pushbuf lives in, this is because the GEM code requires that
128 	 * we be able to call out to other (indirect) push buffers
129 	 */
130 	chan->push.vma.offset = chan->push.buffer->bo.offset;
131 
132 	if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
133 		ret = nouveau_bo_vma_add(chan->push.buffer, cli->vm,
134 					&chan->push.vma);
135 		if (ret) {
136 			nouveau_channel_del(pchan);
137 			return ret;
138 		}
139 
140 		args.target = NV_DMA_V0_TARGET_VM;
141 		args.access = NV_DMA_V0_ACCESS_VM;
142 		args.start = 0;
143 		args.limit = cli->vm->mmu->limit - 1;
144 	} else
145 	if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
146 		if (device->info.family == NV_DEVICE_INFO_V0_TNT) {
147 			/* nv04 vram pushbuf hack, retarget to its location in
148 			 * the framebuffer bar rather than direct vram access..
149 			 * nfi why this exists, it came from the -nv ddx.
150 			 */
151 			args.target = NV_DMA_V0_TARGET_PCI;
152 			args.access = NV_DMA_V0_ACCESS_RDWR;
153 			args.start = nvxx_device(device)->func->
154 				resource_addr(nvxx_device(device), 1);
155 			args.limit = args.start + device->info.ram_user - 1;
156 		} else {
157 			args.target = NV_DMA_V0_TARGET_VRAM;
158 			args.access = NV_DMA_V0_ACCESS_RDWR;
159 			args.start = 0;
160 			args.limit = device->info.ram_user - 1;
161 		}
162 	} else {
163 		if (chan->drm->agp.bridge) {
164 			args.target = NV_DMA_V0_TARGET_AGP;
165 			args.access = NV_DMA_V0_ACCESS_RDWR;
166 			args.start = chan->drm->agp.base;
167 			args.limit = chan->drm->agp.base +
168 				     chan->drm->agp.size - 1;
169 		} else {
170 			args.target = NV_DMA_V0_TARGET_VM;
171 			args.access = NV_DMA_V0_ACCESS_RDWR;
172 			args.start = 0;
173 			args.limit = mmu->limit - 1;
174 		}
175 	}
176 
177 	ret = nvif_object_init(&device->object, NVDRM_PUSH |
178 			       (handle & 0xffff), NV_DMA_FROM_MEMORY,
179 			       &args, sizeof(args), &chan->push.ctxdma);
180 	if (ret) {
181 		nouveau_channel_del(pchan);
182 		return ret;
183 	}
184 
185 	return 0;
186 }
187 
188 static int
189 nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
190 		    u32 handle, u32 engine, struct nouveau_channel **pchan)
191 {
192 	static const u16 oclasses[] = { MAXWELL_CHANNEL_GPFIFO_A,
193 					KEPLER_CHANNEL_GPFIFO_A,
194 					FERMI_CHANNEL_GPFIFO,
195 					G82_CHANNEL_GPFIFO,
196 					NV50_CHANNEL_GPFIFO,
197 					0 };
198 	const u16 *oclass = oclasses;
199 	union {
200 		struct nv50_channel_gpfifo_v0 nv50;
201 		struct fermi_channel_gpfifo_v0 fermi;
202 		struct kepler_channel_gpfifo_a_v0 kepler;
203 	} args;
204 	struct nouveau_channel *chan;
205 	u32 size;
206 	int ret;
207 
208 	/* allocate dma push buffer */
209 	ret = nouveau_channel_prep(drm, device, handle, 0x12000, &chan);
210 	*pchan = chan;
211 	if (ret)
212 		return ret;
213 
214 	/* create channel object */
215 	do {
216 		if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
217 			args.kepler.version = 0;
218 			args.kepler.engine  = engine;
219 			args.kepler.ilength = 0x02000;
220 			args.kepler.ioffset = 0x10000 + chan->push.vma.offset;
221 			args.kepler.vm = 0;
222 			size = sizeof(args.kepler);
223 		} else
224 		if (oclass[0] >= FERMI_CHANNEL_GPFIFO) {
225 			args.fermi.version = 0;
226 			args.fermi.ilength = 0x02000;
227 			args.fermi.ioffset = 0x10000 + chan->push.vma.offset;
228 			args.fermi.vm = 0;
229 			size = sizeof(args.fermi);
230 		} else {
231 			args.nv50.version = 0;
232 			args.nv50.ilength = 0x02000;
233 			args.nv50.ioffset = 0x10000 + chan->push.vma.offset;
234 			args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma);
235 			args.nv50.vm = 0;
236 			size = sizeof(args.nv50);
237 		}
238 
239 		ret = nvif_object_init(&device->object, handle, *oclass++,
240 				       &args, size, &chan->user);
241 		if (ret == 0) {
242 			if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A)
243 				chan->chid = args.kepler.chid;
244 			else
245 			if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO)
246 				chan->chid = args.fermi.chid;
247 			else
248 				chan->chid = args.nv50.chid;
249 			return ret;
250 		}
251 	} while (*oclass);
252 
253 	nouveau_channel_del(pchan);
254 	return ret;
255 }
256 
257 static int
258 nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device,
259 		    u32 handle, struct nouveau_channel **pchan)
260 {
261 	static const u16 oclasses[] = { NV40_CHANNEL_DMA,
262 					NV17_CHANNEL_DMA,
263 					NV10_CHANNEL_DMA,
264 					NV03_CHANNEL_DMA,
265 					0 };
266 	const u16 *oclass = oclasses;
267 	struct nv03_channel_dma_v0 args;
268 	struct nouveau_channel *chan;
269 	int ret;
270 
271 	/* allocate dma push buffer */
272 	ret = nouveau_channel_prep(drm, device, handle, 0x10000, &chan);
273 	*pchan = chan;
274 	if (ret)
275 		return ret;
276 
277 	/* create channel object */
278 	args.version = 0;
279 	args.pushbuf = nvif_handle(&chan->push.ctxdma);
280 	args.offset = chan->push.vma.offset;
281 
282 	do {
283 		ret = nvif_object_init(&device->object, handle, *oclass++,
284 				       &args, sizeof(args), &chan->user);
285 		if (ret == 0) {
286 			chan->chid = args.chid;
287 			return ret;
288 		}
289 	} while (ret && *oclass);
290 
291 	nouveau_channel_del(pchan);
292 	return ret;
293 }
294 
295 static int
296 nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
297 {
298 	struct nvif_device *device = chan->device;
299 	struct nouveau_cli *cli = (void *)chan->user.client;
300 	struct nvkm_mmu *mmu = nvxx_mmu(device);
301 	struct nv_dma_v0 args = {};
302 	int ret, i;
303 
304 	nvif_object_map(&chan->user);
305 
306 	/* allocate dma objects to cover all allowed vram, and gart */
307 	if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
308 		if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
309 			args.target = NV_DMA_V0_TARGET_VM;
310 			args.access = NV_DMA_V0_ACCESS_VM;
311 			args.start = 0;
312 			args.limit = cli->vm->mmu->limit - 1;
313 		} else {
314 			args.target = NV_DMA_V0_TARGET_VRAM;
315 			args.access = NV_DMA_V0_ACCESS_RDWR;
316 			args.start = 0;
317 			args.limit = device->info.ram_user - 1;
318 		}
319 
320 		ret = nvif_object_init(&chan->user, vram, NV_DMA_IN_MEMORY,
321 				       &args, sizeof(args), &chan->vram);
322 		if (ret)
323 			return ret;
324 
325 		if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
326 			args.target = NV_DMA_V0_TARGET_VM;
327 			args.access = NV_DMA_V0_ACCESS_VM;
328 			args.start = 0;
329 			args.limit = cli->vm->mmu->limit - 1;
330 		} else
331 		if (chan->drm->agp.bridge) {
332 			args.target = NV_DMA_V0_TARGET_AGP;
333 			args.access = NV_DMA_V0_ACCESS_RDWR;
334 			args.start = chan->drm->agp.base;
335 			args.limit = chan->drm->agp.base +
336 				     chan->drm->agp.size - 1;
337 		} else {
338 			args.target = NV_DMA_V0_TARGET_VM;
339 			args.access = NV_DMA_V0_ACCESS_RDWR;
340 			args.start = 0;
341 			args.limit = mmu->limit - 1;
342 		}
343 
344 		ret = nvif_object_init(&chan->user, gart, NV_DMA_IN_MEMORY,
345 				       &args, sizeof(args), &chan->gart);
346 		if (ret)
347 			return ret;
348 	}
349 
350 	/* initialise dma tracking parameters */
351 	switch (chan->user.oclass & 0x00ff) {
352 	case 0x006b:
353 	case 0x006e:
354 		chan->user_put = 0x40;
355 		chan->user_get = 0x44;
356 		chan->dma.max = (0x10000 / 4) - 2;
357 		break;
358 	default:
359 		chan->user_put = 0x40;
360 		chan->user_get = 0x44;
361 		chan->user_get_hi = 0x60;
362 		chan->dma.ib_base =  0x10000 / 4;
363 		chan->dma.ib_max  = (0x02000 / 8) - 1;
364 		chan->dma.ib_put  = 0;
365 		chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
366 		chan->dma.max = chan->dma.ib_base;
367 		break;
368 	}
369 
370 	chan->dma.put = 0;
371 	chan->dma.cur = chan->dma.put;
372 	chan->dma.free = chan->dma.max - chan->dma.cur;
373 
374 	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
375 	if (ret)
376 		return ret;
377 
378 	for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
379 		OUT_RING(chan, 0x00000000);
380 
381 	/* allocate software object class (used for fences on <= nv05) */
382 	if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) {
383 		ret = nvif_object_init(&chan->user, 0x006e,
384 				       NVIF_IOCTL_NEW_V0_SW_NV04,
385 				       NULL, 0, &chan->nvsw);
386 		if (ret)
387 			return ret;
388 
389 		ret = RING_SPACE(chan, 2);
390 		if (ret)
391 			return ret;
392 
393 		BEGIN_NV04(chan, NvSubSw, 0x0000, 1);
394 		OUT_RING  (chan, chan->nvsw.handle);
395 		FIRE_RING (chan);
396 	}
397 
398 	/* initialise synchronisation */
399 	return nouveau_fence(chan->drm)->context_new(chan);
400 }
401 
402 int
403 nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
404 		    u32 handle, u32 arg0, u32 arg1,
405 		    struct nouveau_channel **pchan)
406 {
407 	struct nouveau_cli *cli = (void *)device->object.client;
408 	bool super;
409 	int ret;
410 
411 	/* hack until fencenv50 is fixed, and agp access relaxed */
412 	super = cli->base.super;
413 	cli->base.super = true;
414 
415 	ret = nouveau_channel_ind(drm, device, handle, arg0, pchan);
416 	if (ret) {
417 		NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret);
418 		ret = nouveau_channel_dma(drm, device, handle, pchan);
419 		if (ret) {
420 			NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret);
421 			goto done;
422 		}
423 	}
424 
425 	ret = nouveau_channel_init(*pchan, arg0, arg1);
426 	if (ret) {
427 		NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret);
428 		nouveau_channel_del(pchan);
429 	}
430 
431 done:
432 	cli->base.super = super;
433 	return ret;
434 }
435