blob: 52db13cd75b2dbd8d0e44b05be441baa9f3a49c3 [file] [log] [blame]
Ben Skeggs6ee73862009-12-11 19:24:15 +10001/*
2 * Copyright (C) 2006 Ben Skeggs.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28/*
29 * Authors:
30 * Ben Skeggs <darktama@iinet.net.au>
31 */
32
33#include "drmP.h"
34#include "drm.h"
35#include "nouveau_drv.h"
36#include "nouveau_drm.h"
Ben Skeggs479dcae2010-09-01 15:24:28 +100037#include "nouveau_ramht.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +100038
39/* NVidia uses context objects to drive drawing operations.
40
41 Context objects can be selected into 8 subchannels in the FIFO,
42 and then used via DMA command buffers.
43
44 A context object is referenced by a user defined handle (CARD32). The HW
45 looks up graphics objects in a hash table in the instance RAM.
46
47 An entry in the hash table consists of 2 CARD32. The first CARD32 contains
48 the handle, the second one a bitfield, that contains the address of the
49 object in instance RAM.
50
51 The format of the second CARD32 seems to be:
52
53 NV4 to NV30:
54
55 15: 0 instance_addr >> 4
56 17:16 engine (here uses 1 = graphics)
57 28:24 channel id (here uses 0)
58 31 valid (use 1)
59
60 NV40:
61
62 15: 0 instance_addr >> 4 (maybe 19-0)
63 21:20 engine (here uses 1 = graphics)
64 I'm unsure about the other bits, but using 0 seems to work.
65
66 The key into the hash table depends on the object handle and channel id and
67 is given as:
68*/
Ben Skeggs6ee73862009-12-11 19:24:15 +100069
70int
71nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
72 uint32_t size, int align, uint32_t flags,
73 struct nouveau_gpuobj **gpuobj_ret)
74{
75 struct drm_nouveau_private *dev_priv = dev->dev_private;
76 struct nouveau_engine *engine = &dev_priv->engine;
77 struct nouveau_gpuobj *gpuobj;
Ben Skeggsb833ac22010-06-01 15:32:24 +100078 struct drm_mm *pramin = NULL;
Ben Skeggs6ee73862009-12-11 19:24:15 +100079 int ret;
80
81 NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
82 chan ? chan->id : -1, size, align, flags);
83
84 if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL)
85 return -EINVAL;
86
87 gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
88 if (!gpuobj)
89 return -ENOMEM;
90 NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
Ben Skeggsb3beb162010-09-01 15:24:29 +100091 gpuobj->dev = dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +100092 gpuobj->flags = flags;
93 gpuobj->im_channel = chan;
94
95 list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
96
97 /* Choose between global instmem heap, and per-channel private
98 * instmem heap. On <NV50 allow requests for private instmem
99 * to be satisfied from global heap if no per-channel area
100 * available.
101 */
102 if (chan) {
Ben Skeggs816544b2010-07-08 13:15:05 +1000103 NV_DEBUG(dev, "channel heap\n");
104 pramin = &chan->ramin_heap;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000105 } else {
106 NV_DEBUG(dev, "global heap\n");
Ben Skeggsb833ac22010-06-01 15:32:24 +1000107 pramin = &dev_priv->ramin_heap;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000108
Ben Skeggs6ee73862009-12-11 19:24:15 +1000109 ret = engine->instmem.populate(dev, gpuobj, &size);
110 if (ret) {
111 nouveau_gpuobj_del(dev, &gpuobj);
112 return ret;
113 }
114 }
115
116 /* Allocate a chunk of the PRAMIN aperture */
Ben Skeggsb833ac22010-06-01 15:32:24 +1000117 gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
118 if (gpuobj->im_pramin)
119 gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
120
Ben Skeggs6ee73862009-12-11 19:24:15 +1000121 if (!gpuobj->im_pramin) {
122 nouveau_gpuobj_del(dev, &gpuobj);
123 return -ENOMEM;
124 }
125
126 if (!chan) {
127 ret = engine->instmem.bind(dev, gpuobj);
128 if (ret) {
129 nouveau_gpuobj_del(dev, &gpuobj);
130 return ret;
131 }
132 }
133
134 if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
135 int i;
136
Ben Skeggs6ee73862009-12-11 19:24:15 +1000137 for (i = 0; i < gpuobj->im_pramin->size; i += 4)
Ben Skeggsb3beb162010-09-01 15:24:29 +1000138 nv_wo32(gpuobj, i, 0);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000139 engine->instmem.flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000140 }
141
142 *gpuobj_ret = gpuobj;
143 return 0;
144}
145
146int
147nouveau_gpuobj_early_init(struct drm_device *dev)
148{
149 struct drm_nouveau_private *dev_priv = dev->dev_private;
150
151 NV_DEBUG(dev, "\n");
152
153 INIT_LIST_HEAD(&dev_priv->gpuobj_list);
154
155 return 0;
156}
157
158int
159nouveau_gpuobj_init(struct drm_device *dev)
160{
161 struct drm_nouveau_private *dev_priv = dev->dev_private;
162 int ret;
163
164 NV_DEBUG(dev, "\n");
165
166 if (dev_priv->card_type < NV_50) {
167 ret = nouveau_gpuobj_new_fake(dev,
168 dev_priv->ramht_offset, ~0, dev_priv->ramht_size,
169 NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS,
170 &dev_priv->ramht, NULL);
171 if (ret)
172 return ret;
173 }
174
175 return 0;
176}
177
178void
179nouveau_gpuobj_takedown(struct drm_device *dev)
180{
181 struct drm_nouveau_private *dev_priv = dev->dev_private;
182
183 NV_DEBUG(dev, "\n");
184
185 nouveau_gpuobj_del(dev, &dev_priv->ramht);
186}
187
188void
189nouveau_gpuobj_late_takedown(struct drm_device *dev)
190{
191 struct drm_nouveau_private *dev_priv = dev->dev_private;
192 struct nouveau_gpuobj *gpuobj = NULL;
193 struct list_head *entry, *tmp;
194
195 NV_DEBUG(dev, "\n");
196
197 list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) {
198 gpuobj = list_entry(entry, struct nouveau_gpuobj, list);
199
200 NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n",
201 gpuobj, gpuobj->refcount);
202 gpuobj->refcount = 0;
203 nouveau_gpuobj_del(dev, &gpuobj);
204 }
205}
206
207int
208nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
209{
210 struct drm_nouveau_private *dev_priv = dev->dev_private;
211 struct nouveau_engine *engine = &dev_priv->engine;
212 struct nouveau_gpuobj *gpuobj;
213 int i;
214
215 NV_DEBUG(dev, "gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
216
217 if (!dev_priv || !pgpuobj || !(*pgpuobj))
218 return -EINVAL;
219 gpuobj = *pgpuobj;
220
221 if (gpuobj->refcount != 0) {
222 NV_ERROR(dev, "gpuobj refcount is %d\n", gpuobj->refcount);
223 return -EINVAL;
224 }
225
226 if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000227 for (i = 0; i < gpuobj->im_pramin->size; i += 4)
Ben Skeggsb3beb162010-09-01 15:24:29 +1000228 nv_wo32(gpuobj, i, 0);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000229 engine->instmem.flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000230 }
231
232 if (gpuobj->dtor)
233 gpuobj->dtor(dev, gpuobj);
234
235 if (gpuobj->im_backing && !(gpuobj->flags & NVOBJ_FLAG_FAKE))
236 engine->instmem.clear(dev, gpuobj);
237
238 if (gpuobj->im_pramin) {
239 if (gpuobj->flags & NVOBJ_FLAG_FAKE)
240 kfree(gpuobj->im_pramin);
241 else
Ben Skeggsb833ac22010-06-01 15:32:24 +1000242 drm_mm_put_block(gpuobj->im_pramin);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000243 }
244
245 list_del(&gpuobj->list);
246
247 *pgpuobj = NULL;
248 kfree(gpuobj);
249 return 0;
250}
251
252static int
253nouveau_gpuobj_instance_get(struct drm_device *dev,
254 struct nouveau_channel *chan,
255 struct nouveau_gpuobj *gpuobj, uint32_t *inst)
256{
257 struct drm_nouveau_private *dev_priv = dev->dev_private;
258 struct nouveau_gpuobj *cpramin;
259
260 /* <NV50 use PRAMIN address everywhere */
261 if (dev_priv->card_type < NV_50) {
262 *inst = gpuobj->im_pramin->start;
263 return 0;
264 }
265
266 if (chan && gpuobj->im_channel != chan) {
267 NV_ERROR(dev, "Channel mismatch: obj %d, ref %d\n",
268 gpuobj->im_channel->id, chan->id);
269 return -EINVAL;
270 }
271
272 /* NV50 channel-local instance */
273 if (chan) {
274 cpramin = chan->ramin->gpuobj;
275 *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start;
276 return 0;
277 }
278
279 /* NV50 global (VRAM) instance */
280 if (!gpuobj->im_channel) {
281 /* ...from global heap */
282 if (!gpuobj->im_backing) {
283 NV_ERROR(dev, "AII, no VRAM backing gpuobj\n");
284 return -EINVAL;
285 }
286 *inst = gpuobj->im_backing_start;
287 return 0;
288 } else {
289 /* ...from local heap */
290 cpramin = gpuobj->im_channel->ramin->gpuobj;
291 *inst = cpramin->im_backing_start +
292 (gpuobj->im_pramin->start - cpramin->im_pramin->start);
293 return 0;
294 }
295
296 return -EINVAL;
297}
298
299int
300nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
301 uint32_t handle, struct nouveau_gpuobj *gpuobj,
302 struct nouveau_gpuobj_ref **ref_ret)
303{
304 struct drm_nouveau_private *dev_priv = dev->dev_private;
305 struct nouveau_gpuobj_ref *ref;
306 uint32_t instance;
307 int ret;
308
309 NV_DEBUG(dev, "ch%d h=0x%08x gpuobj=%p\n",
310 chan ? chan->id : -1, handle, gpuobj);
311
312 if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
313 return -EINVAL;
314
315 if (!chan && !ref_ret)
316 return -EINVAL;
317
318 if (gpuobj->engine == NVOBJ_ENGINE_SW && !gpuobj->im_pramin) {
319 /* sw object */
320 instance = 0x40;
321 } else {
322 ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance);
323 if (ret)
324 return ret;
325 }
326
327 ref = kzalloc(sizeof(*ref), GFP_KERNEL);
328 if (!ref)
329 return -ENOMEM;
330 INIT_LIST_HEAD(&ref->list);
331 ref->gpuobj = gpuobj;
332 ref->channel = chan;
333 ref->instance = instance;
334
335 if (!ref_ret) {
336 ref->handle = handle;
337
338 ret = nouveau_ramht_insert(dev, ref);
339 if (ret) {
340 kfree(ref);
341 return ret;
342 }
343 } else {
344 ref->handle = ~0;
345 *ref_ret = ref;
346 }
347
348 ref->gpuobj->refcount++;
349 return 0;
350}
351
352int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref)
353{
354 struct nouveau_gpuobj_ref *ref;
355
356 NV_DEBUG(dev, "ref %p\n", pref ? *pref : NULL);
357
358 if (!dev || !pref || *pref == NULL)
359 return -EINVAL;
360 ref = *pref;
361
362 if (ref->handle != ~0)
363 nouveau_ramht_remove(dev, ref);
364
365 if (ref->gpuobj) {
366 ref->gpuobj->refcount--;
367
368 if (ref->gpuobj->refcount == 0) {
369 if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS))
370 nouveau_gpuobj_del(dev, &ref->gpuobj);
371 }
372 }
373
374 *pref = NULL;
375 kfree(ref);
376 return 0;
377}
378
379int
380nouveau_gpuobj_new_ref(struct drm_device *dev,
381 struct nouveau_channel *oc, struct nouveau_channel *rc,
382 uint32_t handle, uint32_t size, int align,
383 uint32_t flags, struct nouveau_gpuobj_ref **ref)
384{
385 struct nouveau_gpuobj *gpuobj = NULL;
386 int ret;
387
388 ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj);
389 if (ret)
390 return ret;
391
392 ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref);
393 if (ret) {
394 nouveau_gpuobj_del(dev, &gpuobj);
395 return ret;
396 }
397
398 return 0;
399}
400
401int
402nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
403 struct nouveau_gpuobj_ref **ref_ret)
404{
405 struct nouveau_gpuobj_ref *ref;
406 struct list_head *entry, *tmp;
407
408 list_for_each_safe(entry, tmp, &chan->ramht_refs) {
409 ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
410
411 if (ref->handle == handle) {
412 if (ref_ret)
413 *ref_ret = ref;
414 return 0;
415 }
416 }
417
418 return -EINVAL;
419}
420
421int
422nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
423 uint32_t b_offset, uint32_t size,
424 uint32_t flags, struct nouveau_gpuobj **pgpuobj,
425 struct nouveau_gpuobj_ref **pref)
426{
427 struct drm_nouveau_private *dev_priv = dev->dev_private;
428 struct nouveau_gpuobj *gpuobj = NULL;
429 int i;
430
431 NV_DEBUG(dev,
432 "p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n",
433 p_offset, b_offset, size, flags);
434
435 gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
436 if (!gpuobj)
437 return -ENOMEM;
438 NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
Ben Skeggsb3beb162010-09-01 15:24:29 +1000439 gpuobj->dev = dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000440 gpuobj->im_channel = NULL;
441 gpuobj->flags = flags | NVOBJ_FLAG_FAKE;
442
443 list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
444
445 if (p_offset != ~0) {
Ben Skeggsb833ac22010-06-01 15:32:24 +1000446 gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
Ben Skeggs6ee73862009-12-11 19:24:15 +1000447 GFP_KERNEL);
448 if (!gpuobj->im_pramin) {
449 nouveau_gpuobj_del(dev, &gpuobj);
450 return -ENOMEM;
451 }
452 gpuobj->im_pramin->start = p_offset;
453 gpuobj->im_pramin->size = size;
454 }
455
456 if (b_offset != ~0) {
457 gpuobj->im_backing = (struct nouveau_bo *)-1;
458 gpuobj->im_backing_start = b_offset;
459 }
460
461 if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000462 for (i = 0; i < gpuobj->im_pramin->size; i += 4)
Ben Skeggsb3beb162010-09-01 15:24:29 +1000463 nv_wo32(gpuobj, i, 0);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000464 dev_priv->engine.instmem.flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000465 }
466
467 if (pref) {
468 i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref);
469 if (i) {
470 nouveau_gpuobj_del(dev, &gpuobj);
471 return i;
472 }
473 }
474
475 if (pgpuobj)
476 *pgpuobj = gpuobj;
477 return 0;
478}
479
480
481static uint32_t
482nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
483{
484 struct drm_nouveau_private *dev_priv = dev->dev_private;
485
486 /*XXX: dodgy hack for now */
487 if (dev_priv->card_type >= NV_50)
488 return 24;
489 if (dev_priv->card_type >= NV_40)
490 return 32;
491 return 16;
492}
493
494/*
495 DMA objects are used to reference a piece of memory in the
496 framebuffer, PCI or AGP address space. Each object is 16 bytes big
497 and looks as follows:
498
499 entry[0]
500 11:0 class (seems like I can always use 0 here)
501 12 page table present?
502 13 page entry linear?
503 15:14 access: 0 rw, 1 ro, 2 wo
504 17:16 target: 0 NV memory, 1 NV memory tiled, 2 PCI, 3 AGP
505 31:20 dma adjust (bits 0-11 of the address)
506 entry[1]
507 dma limit (size of transfer)
508 entry[X]
509 1 0 readonly, 1 readwrite
510 31:12 dma frame address of the page (bits 12-31 of the address)
511 entry[N]
512 page table terminator, same value as the first pte, as does nvidia
513 rivatv uses 0xffffffff
514
515 Non linear page tables need a list of frame addresses afterwards,
516 the rivatv project has some info on this.
517
518 The method below creates a DMA object in instance RAM and returns a handle
519 to it that can be used to set up context objects.
520*/
521int
522nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
523 uint64_t offset, uint64_t size, int access,
524 int target, struct nouveau_gpuobj **gpuobj)
525{
526 struct drm_device *dev = chan->dev;
527 struct drm_nouveau_private *dev_priv = dev->dev_private;
528 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
529 int ret;
530
531 NV_DEBUG(dev, "ch%d class=0x%04x offset=0x%llx size=0x%llx\n",
532 chan->id, class, offset, size);
533 NV_DEBUG(dev, "access=%d target=%d\n", access, target);
534
535 switch (target) {
536 case NV_DMA_TARGET_AGP:
537 offset += dev_priv->gart_info.aper_base;
538 break;
539 default:
540 break;
541 }
542
543 ret = nouveau_gpuobj_new(dev, chan,
544 nouveau_gpuobj_class_instmem_size(dev, class),
545 16, NVOBJ_FLAG_ZERO_ALLOC |
546 NVOBJ_FLAG_ZERO_FREE, gpuobj);
547 if (ret) {
548 NV_ERROR(dev, "Error creating gpuobj: %d\n", ret);
549 return ret;
550 }
551
Ben Skeggs6ee73862009-12-11 19:24:15 +1000552 if (dev_priv->card_type < NV_50) {
553 uint32_t frame, adjust, pte_flags = 0;
554
555 if (access != NV_DMA_ACCESS_RO)
556 pte_flags |= (1<<1);
557 adjust = offset & 0x00000fff;
558 frame = offset & ~0x00000fff;
559
Ben Skeggsb3beb162010-09-01 15:24:29 +1000560 nv_wo32(*gpuobj, 0, ((1<<12) | (1<<13) | (adjust << 20) |
561 (access << 14) | (target << 16) |
562 class));
563 nv_wo32(*gpuobj, 4, size - 1);
564 nv_wo32(*gpuobj, 8, frame | pte_flags);
565 nv_wo32(*gpuobj, 12, frame | pte_flags);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000566 } else {
567 uint64_t limit = offset + size - 1;
568 uint32_t flags0, flags5;
569
570 if (target == NV_DMA_TARGET_VIDMEM) {
571 flags0 = 0x00190000;
572 flags5 = 0x00010000;
573 } else {
574 flags0 = 0x7fc00000;
575 flags5 = 0x00080000;
576 }
577
Ben Skeggsb3beb162010-09-01 15:24:29 +1000578 nv_wo32(*gpuobj, 0, flags0 | class);
579 nv_wo32(*gpuobj, 4, lower_32_bits(limit));
580 nv_wo32(*gpuobj, 8, lower_32_bits(offset));
581 nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) |
582 (upper_32_bits(offset) & 0xff));
583 nv_wo32(*gpuobj, 20, flags5);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000584 }
585
Ben Skeggsf56cb862010-07-08 11:29:10 +1000586 instmem->flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000587
588 (*gpuobj)->engine = NVOBJ_ENGINE_SW;
589 (*gpuobj)->class = class;
590 return 0;
591}
592
593int
594nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan,
595 uint64_t offset, uint64_t size, int access,
596 struct nouveau_gpuobj **gpuobj,
597 uint32_t *o_ret)
598{
599 struct drm_device *dev = chan->dev;
600 struct drm_nouveau_private *dev_priv = dev->dev_private;
601 int ret;
602
603 if (dev_priv->gart_info.type == NOUVEAU_GART_AGP ||
604 (dev_priv->card_type >= NV_50 &&
605 dev_priv->gart_info.type == NOUVEAU_GART_SGDMA)) {
606 ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
607 offset + dev_priv->vm_gart_base,
608 size, access, NV_DMA_TARGET_AGP,
609 gpuobj);
610 if (o_ret)
611 *o_ret = 0;
612 } else
613 if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) {
614 *gpuobj = dev_priv->gart_info.sg_ctxdma;
615 if (offset & ~0xffffffffULL) {
616 NV_ERROR(dev, "obj offset exceeds 32-bits\n");
617 return -EINVAL;
618 }
619 if (o_ret)
620 *o_ret = (uint32_t)offset;
621 ret = (*gpuobj != NULL) ? 0 : -EINVAL;
622 } else {
623 NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type);
624 return -EINVAL;
625 }
626
627 return ret;
628}
629
630/* Context objects in the instance RAM have the following structure.
631 * On NV40 they are 32 byte long, on NV30 and smaller 16 bytes.
632
633 NV4 - NV30:
634
635 entry[0]
636 11:0 class
637 12 chroma key enable
638 13 user clip enable
639 14 swizzle enable
640 17:15 patch config:
641 scrcopy_and, rop_and, blend_and, scrcopy, srccopy_pre, blend_pre
642 18 synchronize enable
643 19 endian: 1 big, 0 little
644 21:20 dither mode
645 23 single step enable
646 24 patch status: 0 invalid, 1 valid
647 25 context_surface 0: 1 valid
648 26 context surface 1: 1 valid
649 27 context pattern: 1 valid
650 28 context rop: 1 valid
651 29,30 context beta, beta4
652 entry[1]
653 7:0 mono format
654 15:8 color format
655 31:16 notify instance address
656 entry[2]
657 15:0 dma 0 instance address
658 31:16 dma 1 instance address
659 entry[3]
660 dma method traps
661
662 NV40:
663 No idea what the exact format is. Here's what can be deducted:
664
665 entry[0]:
666 11:0 class (maybe uses more bits here?)
667 17 user clip enable
668 21:19 patch config
669 25 patch status valid ?
670 entry[1]:
671 15:0 DMA notifier (maybe 20:0)
672 entry[2]:
673 15:0 DMA 0 instance (maybe 20:0)
674 24 big endian
675 entry[3]:
676 15:0 DMA 1 instance (maybe 20:0)
677 entry[4]:
678 entry[5]:
679 set to 0?
680*/
681int
682nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
683 struct nouveau_gpuobj **gpuobj)
684{
685 struct drm_device *dev = chan->dev;
686 struct drm_nouveau_private *dev_priv = dev->dev_private;
687 int ret;
688
689 NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class);
690
691 ret = nouveau_gpuobj_new(dev, chan,
692 nouveau_gpuobj_class_instmem_size(dev, class),
693 16,
694 NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
695 gpuobj);
696 if (ret) {
697 NV_ERROR(dev, "Error creating gpuobj: %d\n", ret);
698 return ret;
699 }
700
Ben Skeggs6ee73862009-12-11 19:24:15 +1000701 if (dev_priv->card_type >= NV_50) {
Ben Skeggsb3beb162010-09-01 15:24:29 +1000702 nv_wo32(*gpuobj, 0, class);
703 nv_wo32(*gpuobj, 20, 0x00010000);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000704 } else {
705 switch (class) {
706 case NV_CLASS_NULL:
Ben Skeggsb3beb162010-09-01 15:24:29 +1000707 nv_wo32(*gpuobj, 0, 0x00001030);
708 nv_wo32(*gpuobj, 4, 0xFFFFFFFF);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000709 break;
710 default:
711 if (dev_priv->card_type >= NV_40) {
Ben Skeggsb3beb162010-09-01 15:24:29 +1000712 nv_wo32(*gpuobj, 0, class);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000713#ifdef __BIG_ENDIAN
Ben Skeggsb3beb162010-09-01 15:24:29 +1000714 nv_wo32(*gpuobj, 8, 0x01000000);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000715#endif
716 } else {
717#ifdef __BIG_ENDIAN
Ben Skeggsb3beb162010-09-01 15:24:29 +1000718 nv_wo32(*gpuobj, 0, class | 0x00080000);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000719#else
Ben Skeggsb3beb162010-09-01 15:24:29 +1000720 nv_wo32(*gpuobj, 0, class);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000721#endif
722 }
723 }
724 }
Ben Skeggsf56cb862010-07-08 11:29:10 +1000725 dev_priv->engine.instmem.flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000726
727 (*gpuobj)->engine = NVOBJ_ENGINE_GR;
728 (*gpuobj)->class = class;
729 return 0;
730}
731
Francisco Jerezf03a3142009-12-26 02:42:45 +0100732int
Ben Skeggs6ee73862009-12-11 19:24:15 +1000733nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
734 struct nouveau_gpuobj **gpuobj_ret)
735{
Marcin Slusarzdd19e442010-01-30 15:41:00 +0100736 struct drm_nouveau_private *dev_priv;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000737 struct nouveau_gpuobj *gpuobj;
738
739 if (!chan || !gpuobj_ret || *gpuobj_ret != NULL)
740 return -EINVAL;
Marcin Slusarzdd19e442010-01-30 15:41:00 +0100741 dev_priv = chan->dev->dev_private;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000742
743 gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
744 if (!gpuobj)
745 return -ENOMEM;
746 gpuobj->engine = NVOBJ_ENGINE_SW;
747 gpuobj->class = class;
748
749 list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
750 *gpuobj_ret = gpuobj;
751 return 0;
752}
753
754static int
755nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
756{
757 struct drm_device *dev = chan->dev;
758 struct drm_nouveau_private *dev_priv = dev->dev_private;
759 struct nouveau_gpuobj *pramin = NULL;
760 uint32_t size;
761 uint32_t base;
762 int ret;
763
764 NV_DEBUG(dev, "ch%d\n", chan->id);
765
766 /* Base amount for object storage (4KiB enough?) */
767 size = 0x1000;
768 base = 0;
769
770 /* PGRAPH context */
Ben Skeggs816544b2010-07-08 13:15:05 +1000771 size += dev_priv->engine.graph.grctx_size;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000772
773 if (dev_priv->card_type == NV_50) {
774 /* Various fixed table thingos */
775 size += 0x1400; /* mostly unknown stuff */
776 size += 0x4000; /* vm pd */
777 base = 0x6000;
778 /* RAMHT, not sure about setting size yet, 32KiB to be safe */
779 size += 0x8000;
780 /* RAMFC */
781 size += 0x1000;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000782 }
783
Ben Skeggs6ee73862009-12-11 19:24:15 +1000784 ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
785 &chan->ramin);
786 if (ret) {
787 NV_ERROR(dev, "Error allocating channel PRAMIN: %d\n", ret);
788 return ret;
789 }
790 pramin = chan->ramin->gpuobj;
791
Ben Skeggsb833ac22010-06-01 15:32:24 +1000792 ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000793 if (ret) {
794 NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
795 nouveau_gpuobj_ref_del(dev, &chan->ramin);
796 return ret;
797 }
798
799 return 0;
800}
801
802int
803nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
804 uint32_t vram_h, uint32_t tt_h)
805{
806 struct drm_device *dev = chan->dev;
807 struct drm_nouveau_private *dev_priv = dev->dev_private;
808 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
809 struct nouveau_gpuobj *vram = NULL, *tt = NULL;
810 int ret, i;
811
812 INIT_LIST_HEAD(&chan->ramht_refs);
813
814 NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
815
Ben Skeggs816544b2010-07-08 13:15:05 +1000816 /* Allocate a chunk of memory for per-channel object storage */
817 ret = nouveau_gpuobj_channel_init_pramin(chan);
818 if (ret) {
819 NV_ERROR(dev, "init pramin\n");
820 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000821 }
822
823 /* NV50 VM
824 * - Allocate per-channel page-directory
825 * - Map GART and VRAM into the channel's address space at the
826 * locations determined during init.
827 */
828 if (dev_priv->card_type >= NV_50) {
829 uint32_t vm_offset, pde;
830
Ben Skeggs6ee73862009-12-11 19:24:15 +1000831 vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
832 vm_offset += chan->ramin->gpuobj->im_pramin->start;
833
834 ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
835 0, &chan->vm_pd, NULL);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000836 if (ret)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000837 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000838 for (i = 0; i < 0x4000; i += 8) {
Ben Skeggsb3beb162010-09-01 15:24:29 +1000839 nv_wo32(chan->vm_pd, i + 0, 0x00000000);
840 nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000841 }
842
Ben Skeggsb3beb162010-09-01 15:24:29 +1000843 pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000844 ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
845 dev_priv->gart_info.sg_ctxdma,
846 &chan->vm_gart_pt);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000847 if (ret)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000848 return ret;
Ben Skeggsb3beb162010-09-01 15:24:29 +1000849 nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->instance | 3);
850 nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000851
Ben Skeggsb3beb162010-09-01 15:24:29 +1000852 pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000853 for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
854 ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
855 dev_priv->vm_vram_pt[i],
856 &chan->vm_vram_pt[i]);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000857 if (ret)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000858 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000859
Ben Skeggsb3beb162010-09-01 15:24:29 +1000860 nv_wo32(chan->vm_pd, pde + 0,
861 chan->vm_vram_pt[i]->instance | 0x61);
862 nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
863 pde += 8;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000864 }
865
Ben Skeggsf56cb862010-07-08 11:29:10 +1000866 instmem->flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000867 }
868
869 /* RAMHT */
870 if (dev_priv->card_type < NV_50) {
871 ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->ramht,
872 &chan->ramht);
873 if (ret)
874 return ret;
875 } else {
876 ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0,
877 0x8000, 16,
878 NVOBJ_FLAG_ZERO_ALLOC,
879 &chan->ramht);
880 if (ret)
881 return ret;
882 }
883
884 /* VRAM ctxdma */
885 if (dev_priv->card_type >= NV_50) {
886 ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
887 0, dev_priv->vm_end,
888 NV_DMA_ACCESS_RW,
889 NV_DMA_TARGET_AGP, &vram);
890 if (ret) {
891 NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
892 return ret;
893 }
894 } else {
895 ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
896 0, dev_priv->fb_available_size,
897 NV_DMA_ACCESS_RW,
898 NV_DMA_TARGET_VIDMEM, &vram);
899 if (ret) {
900 NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
901 return ret;
902 }
903 }
904
905 ret = nouveau_gpuobj_ref_add(dev, chan, vram_h, vram, NULL);
906 if (ret) {
907 NV_ERROR(dev, "Error referencing VRAM ctxdma: %d\n", ret);
908 return ret;
909 }
910
911 /* TT memory ctxdma */
912 if (dev_priv->card_type >= NV_50) {
913 tt = vram;
914 } else
915 if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
916 ret = nouveau_gpuobj_gart_dma_new(chan, 0,
917 dev_priv->gart_info.aper_size,
918 NV_DMA_ACCESS_RW, &tt, NULL);
919 } else {
920 NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type);
921 ret = -EINVAL;
922 }
923
924 if (ret) {
925 NV_ERROR(dev, "Error creating TT ctxdma: %d\n", ret);
926 return ret;
927 }
928
929 ret = nouveau_gpuobj_ref_add(dev, chan, tt_h, tt, NULL);
930 if (ret) {
931 NV_ERROR(dev, "Error referencing TT ctxdma: %d\n", ret);
932 return ret;
933 }
934
935 return 0;
936}
937
938void
939nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
940{
941 struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
942 struct drm_device *dev = chan->dev;
943 struct list_head *entry, *tmp;
944 struct nouveau_gpuobj_ref *ref;
945 int i;
946
947 NV_DEBUG(dev, "ch%d\n", chan->id);
948
949 if (!chan->ramht_refs.next)
950 return;
951
952 list_for_each_safe(entry, tmp, &chan->ramht_refs) {
953 ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
954
955 nouveau_gpuobj_ref_del(dev, &ref);
956 }
957
958 nouveau_gpuobj_ref_del(dev, &chan->ramht);
959
960 nouveau_gpuobj_del(dev, &chan->vm_pd);
961 nouveau_gpuobj_ref_del(dev, &chan->vm_gart_pt);
962 for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
963 nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
964
Ben Skeggsb833ac22010-06-01 15:32:24 +1000965 if (chan->ramin_heap.free_stack.next)
966 drm_mm_takedown(&chan->ramin_heap);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000967 if (chan->ramin)
968 nouveau_gpuobj_ref_del(dev, &chan->ramin);
969
970}
971
972int
973nouveau_gpuobj_suspend(struct drm_device *dev)
974{
975 struct drm_nouveau_private *dev_priv = dev->dev_private;
976 struct nouveau_gpuobj *gpuobj;
977 int i;
978
979 if (dev_priv->card_type < NV_50) {
980 dev_priv->susres.ramin_copy = vmalloc(dev_priv->ramin_rsvd_vram);
981 if (!dev_priv->susres.ramin_copy)
982 return -ENOMEM;
983
984 for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4)
985 dev_priv->susres.ramin_copy[i/4] = nv_ri32(dev, i);
986 return 0;
987 }
988
989 list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
990 if (!gpuobj->im_backing || (gpuobj->flags & NVOBJ_FLAG_FAKE))
991 continue;
992
993 gpuobj->im_backing_suspend = vmalloc(gpuobj->im_pramin->size);
994 if (!gpuobj->im_backing_suspend) {
995 nouveau_gpuobj_resume(dev);
996 return -ENOMEM;
997 }
998
Ben Skeggsb3beb162010-09-01 15:24:29 +1000999 for (i = 0; i < gpuobj->im_pramin->size; i += 4)
1000 gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i);
Ben Skeggs6ee73862009-12-11 19:24:15 +10001001 }
1002
1003 return 0;
1004}
1005
1006void
1007nouveau_gpuobj_suspend_cleanup(struct drm_device *dev)
1008{
1009 struct drm_nouveau_private *dev_priv = dev->dev_private;
1010 struct nouveau_gpuobj *gpuobj;
1011
1012 if (dev_priv->card_type < NV_50) {
1013 vfree(dev_priv->susres.ramin_copy);
1014 dev_priv->susres.ramin_copy = NULL;
1015 return;
1016 }
1017
1018 list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
1019 if (!gpuobj->im_backing_suspend)
1020 continue;
1021
1022 vfree(gpuobj->im_backing_suspend);
1023 gpuobj->im_backing_suspend = NULL;
1024 }
1025}
1026
1027void
1028nouveau_gpuobj_resume(struct drm_device *dev)
1029{
1030 struct drm_nouveau_private *dev_priv = dev->dev_private;
1031 struct nouveau_gpuobj *gpuobj;
1032 int i;
1033
1034 if (dev_priv->card_type < NV_50) {
1035 for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4)
1036 nv_wi32(dev, i, dev_priv->susres.ramin_copy[i/4]);
1037 nouveau_gpuobj_suspend_cleanup(dev);
1038 return;
1039 }
1040
1041 list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
1042 if (!gpuobj->im_backing_suspend)
1043 continue;
1044
Ben Skeggsb3beb162010-09-01 15:24:29 +10001045 for (i = 0; i < gpuobj->im_pramin->size; i += 4)
1046 nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]);
Ben Skeggsf56cb862010-07-08 11:29:10 +10001047 dev_priv->engine.instmem.flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +10001048 }
1049
1050 nouveau_gpuobj_suspend_cleanup(dev);
1051}
1052
1053int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
1054 struct drm_file *file_priv)
1055{
1056 struct drm_nouveau_private *dev_priv = dev->dev_private;
1057 struct drm_nouveau_grobj_alloc *init = data;
1058 struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
1059 struct nouveau_pgraph_object_class *grc;
1060 struct nouveau_gpuobj *gr = NULL;
1061 struct nouveau_channel *chan;
1062 int ret;
1063
Ben Skeggs6ee73862009-12-11 19:24:15 +10001064 NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan);
1065
1066 if (init->handle == ~0)
1067 return -EINVAL;
1068
1069 grc = pgraph->grclass;
1070 while (grc->id) {
1071 if (grc->id == init->class)
1072 break;
1073 grc++;
1074 }
1075
1076 if (!grc->id) {
1077 NV_ERROR(dev, "Illegal object class: 0x%x\n", init->class);
1078 return -EPERM;
1079 }
1080
1081 if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0)
1082 return -EEXIST;
1083
1084 if (!grc->software)
1085 ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr);
1086 else
1087 ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr);
1088
1089 if (ret) {
1090 NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n",
1091 ret, init->channel, init->handle);
1092 return ret;
1093 }
1094
1095 ret = nouveau_gpuobj_ref_add(dev, chan, init->handle, gr, NULL);
1096 if (ret) {
1097 NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n",
1098 ret, init->channel, init->handle);
1099 nouveau_gpuobj_del(dev, &gr);
1100 return ret;
1101 }
1102
1103 return 0;
1104}
1105
1106int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
1107 struct drm_file *file_priv)
1108{
1109 struct drm_nouveau_gpuobj_free *objfree = data;
1110 struct nouveau_gpuobj_ref *ref;
1111 struct nouveau_channel *chan;
1112 int ret;
1113
Ben Skeggs6ee73862009-12-11 19:24:15 +10001114 NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
1115
1116 ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);
1117 if (ret)
1118 return ret;
1119 nouveau_gpuobj_ref_del(dev, &ref);
1120
1121 return 0;
1122}
Ben Skeggsb3beb162010-09-01 15:24:29 +10001123
1124u32
1125nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
1126{
1127 struct drm_device *dev = gpuobj->dev;
1128 return nv_ri32(dev, gpuobj->im_pramin->start + offset);
1129}
1130
1131void
1132nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val)
1133{
1134 struct drm_device *dev = gpuobj->dev;
1135 nv_wi32(dev, gpuobj->im_pramin->start + offset, val);
1136}