blob: e658aa2dbe672edbbf941ac9bdf4f9a852d44cce [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);
91 gpuobj->flags = flags;
92 gpuobj->im_channel = chan;
93
94 list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
95
96 /* Choose between global instmem heap, and per-channel private
97 * instmem heap. On <NV50 allow requests for private instmem
98 * to be satisfied from global heap if no per-channel area
99 * available.
100 */
101 if (chan) {
Ben Skeggs816544b2010-07-08 13:15:05 +1000102 NV_DEBUG(dev, "channel heap\n");
103 pramin = &chan->ramin_heap;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000104 } else {
105 NV_DEBUG(dev, "global heap\n");
Ben Skeggsb833ac22010-06-01 15:32:24 +1000106 pramin = &dev_priv->ramin_heap;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000107
Ben Skeggs6ee73862009-12-11 19:24:15 +1000108 ret = engine->instmem.populate(dev, gpuobj, &size);
109 if (ret) {
110 nouveau_gpuobj_del(dev, &gpuobj);
111 return ret;
112 }
113 }
114
115 /* Allocate a chunk of the PRAMIN aperture */
Ben Skeggsb833ac22010-06-01 15:32:24 +1000116 gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
117 if (gpuobj->im_pramin)
118 gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
119
Ben Skeggs6ee73862009-12-11 19:24:15 +1000120 if (!gpuobj->im_pramin) {
121 nouveau_gpuobj_del(dev, &gpuobj);
122 return -ENOMEM;
123 }
124
125 if (!chan) {
126 ret = engine->instmem.bind(dev, gpuobj);
127 if (ret) {
128 nouveau_gpuobj_del(dev, &gpuobj);
129 return ret;
130 }
131 }
132
133 if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
134 int i;
135
Ben Skeggs6ee73862009-12-11 19:24:15 +1000136 for (i = 0; i < gpuobj->im_pramin->size; i += 4)
137 nv_wo32(dev, gpuobj, i/4, 0);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000138 engine->instmem.flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000139 }
140
141 *gpuobj_ret = gpuobj;
142 return 0;
143}
144
145int
146nouveau_gpuobj_early_init(struct drm_device *dev)
147{
148 struct drm_nouveau_private *dev_priv = dev->dev_private;
149
150 NV_DEBUG(dev, "\n");
151
152 INIT_LIST_HEAD(&dev_priv->gpuobj_list);
153
154 return 0;
155}
156
157int
158nouveau_gpuobj_init(struct drm_device *dev)
159{
160 struct drm_nouveau_private *dev_priv = dev->dev_private;
161 int ret;
162
163 NV_DEBUG(dev, "\n");
164
165 if (dev_priv->card_type < NV_50) {
166 ret = nouveau_gpuobj_new_fake(dev,
167 dev_priv->ramht_offset, ~0, dev_priv->ramht_size,
168 NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS,
169 &dev_priv->ramht, NULL);
170 if (ret)
171 return ret;
172 }
173
174 return 0;
175}
176
177void
178nouveau_gpuobj_takedown(struct drm_device *dev)
179{
180 struct drm_nouveau_private *dev_priv = dev->dev_private;
181
182 NV_DEBUG(dev, "\n");
183
184 nouveau_gpuobj_del(dev, &dev_priv->ramht);
185}
186
187void
188nouveau_gpuobj_late_takedown(struct drm_device *dev)
189{
190 struct drm_nouveau_private *dev_priv = dev->dev_private;
191 struct nouveau_gpuobj *gpuobj = NULL;
192 struct list_head *entry, *tmp;
193
194 NV_DEBUG(dev, "\n");
195
196 list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) {
197 gpuobj = list_entry(entry, struct nouveau_gpuobj, list);
198
199 NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n",
200 gpuobj, gpuobj->refcount);
201 gpuobj->refcount = 0;
202 nouveau_gpuobj_del(dev, &gpuobj);
203 }
204}
205
206int
207nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
208{
209 struct drm_nouveau_private *dev_priv = dev->dev_private;
210 struct nouveau_engine *engine = &dev_priv->engine;
211 struct nouveau_gpuobj *gpuobj;
212 int i;
213
214 NV_DEBUG(dev, "gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
215
216 if (!dev_priv || !pgpuobj || !(*pgpuobj))
217 return -EINVAL;
218 gpuobj = *pgpuobj;
219
220 if (gpuobj->refcount != 0) {
221 NV_ERROR(dev, "gpuobj refcount is %d\n", gpuobj->refcount);
222 return -EINVAL;
223 }
224
225 if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000226 for (i = 0; i < gpuobj->im_pramin->size; i += 4)
227 nv_wo32(dev, gpuobj, i/4, 0);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000228 engine->instmem.flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000229 }
230
231 if (gpuobj->dtor)
232 gpuobj->dtor(dev, gpuobj);
233
234 if (gpuobj->im_backing && !(gpuobj->flags & NVOBJ_FLAG_FAKE))
235 engine->instmem.clear(dev, gpuobj);
236
237 if (gpuobj->im_pramin) {
238 if (gpuobj->flags & NVOBJ_FLAG_FAKE)
239 kfree(gpuobj->im_pramin);
240 else
Ben Skeggsb833ac22010-06-01 15:32:24 +1000241 drm_mm_put_block(gpuobj->im_pramin);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000242 }
243
244 list_del(&gpuobj->list);
245
246 *pgpuobj = NULL;
247 kfree(gpuobj);
248 return 0;
249}
250
251static int
252nouveau_gpuobj_instance_get(struct drm_device *dev,
253 struct nouveau_channel *chan,
254 struct nouveau_gpuobj *gpuobj, uint32_t *inst)
255{
256 struct drm_nouveau_private *dev_priv = dev->dev_private;
257 struct nouveau_gpuobj *cpramin;
258
259 /* <NV50 use PRAMIN address everywhere */
260 if (dev_priv->card_type < NV_50) {
261 *inst = gpuobj->im_pramin->start;
262 return 0;
263 }
264
265 if (chan && gpuobj->im_channel != chan) {
266 NV_ERROR(dev, "Channel mismatch: obj %d, ref %d\n",
267 gpuobj->im_channel->id, chan->id);
268 return -EINVAL;
269 }
270
271 /* NV50 channel-local instance */
272 if (chan) {
273 cpramin = chan->ramin->gpuobj;
274 *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start;
275 return 0;
276 }
277
278 /* NV50 global (VRAM) instance */
279 if (!gpuobj->im_channel) {
280 /* ...from global heap */
281 if (!gpuobj->im_backing) {
282 NV_ERROR(dev, "AII, no VRAM backing gpuobj\n");
283 return -EINVAL;
284 }
285 *inst = gpuobj->im_backing_start;
286 return 0;
287 } else {
288 /* ...from local heap */
289 cpramin = gpuobj->im_channel->ramin->gpuobj;
290 *inst = cpramin->im_backing_start +
291 (gpuobj->im_pramin->start - cpramin->im_pramin->start);
292 return 0;
293 }
294
295 return -EINVAL;
296}
297
298int
299nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
300 uint32_t handle, struct nouveau_gpuobj *gpuobj,
301 struct nouveau_gpuobj_ref **ref_ret)
302{
303 struct drm_nouveau_private *dev_priv = dev->dev_private;
304 struct nouveau_gpuobj_ref *ref;
305 uint32_t instance;
306 int ret;
307
308 NV_DEBUG(dev, "ch%d h=0x%08x gpuobj=%p\n",
309 chan ? chan->id : -1, handle, gpuobj);
310
311 if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
312 return -EINVAL;
313
314 if (!chan && !ref_ret)
315 return -EINVAL;
316
317 if (gpuobj->engine == NVOBJ_ENGINE_SW && !gpuobj->im_pramin) {
318 /* sw object */
319 instance = 0x40;
320 } else {
321 ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance);
322 if (ret)
323 return ret;
324 }
325
326 ref = kzalloc(sizeof(*ref), GFP_KERNEL);
327 if (!ref)
328 return -ENOMEM;
329 INIT_LIST_HEAD(&ref->list);
330 ref->gpuobj = gpuobj;
331 ref->channel = chan;
332 ref->instance = instance;
333
334 if (!ref_ret) {
335 ref->handle = handle;
336
337 ret = nouveau_ramht_insert(dev, ref);
338 if (ret) {
339 kfree(ref);
340 return ret;
341 }
342 } else {
343 ref->handle = ~0;
344 *ref_ret = ref;
345 }
346
347 ref->gpuobj->refcount++;
348 return 0;
349}
350
351int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref)
352{
353 struct nouveau_gpuobj_ref *ref;
354
355 NV_DEBUG(dev, "ref %p\n", pref ? *pref : NULL);
356
357 if (!dev || !pref || *pref == NULL)
358 return -EINVAL;
359 ref = *pref;
360
361 if (ref->handle != ~0)
362 nouveau_ramht_remove(dev, ref);
363
364 if (ref->gpuobj) {
365 ref->gpuobj->refcount--;
366
367 if (ref->gpuobj->refcount == 0) {
368 if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS))
369 nouveau_gpuobj_del(dev, &ref->gpuobj);
370 }
371 }
372
373 *pref = NULL;
374 kfree(ref);
375 return 0;
376}
377
378int
379nouveau_gpuobj_new_ref(struct drm_device *dev,
380 struct nouveau_channel *oc, struct nouveau_channel *rc,
381 uint32_t handle, uint32_t size, int align,
382 uint32_t flags, struct nouveau_gpuobj_ref **ref)
383{
384 struct nouveau_gpuobj *gpuobj = NULL;
385 int ret;
386
387 ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj);
388 if (ret)
389 return ret;
390
391 ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref);
392 if (ret) {
393 nouveau_gpuobj_del(dev, &gpuobj);
394 return ret;
395 }
396
397 return 0;
398}
399
400int
401nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
402 struct nouveau_gpuobj_ref **ref_ret)
403{
404 struct nouveau_gpuobj_ref *ref;
405 struct list_head *entry, *tmp;
406
407 list_for_each_safe(entry, tmp, &chan->ramht_refs) {
408 ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
409
410 if (ref->handle == handle) {
411 if (ref_ret)
412 *ref_ret = ref;
413 return 0;
414 }
415 }
416
417 return -EINVAL;
418}
419
420int
421nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
422 uint32_t b_offset, uint32_t size,
423 uint32_t flags, struct nouveau_gpuobj **pgpuobj,
424 struct nouveau_gpuobj_ref **pref)
425{
426 struct drm_nouveau_private *dev_priv = dev->dev_private;
427 struct nouveau_gpuobj *gpuobj = NULL;
428 int i;
429
430 NV_DEBUG(dev,
431 "p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n",
432 p_offset, b_offset, size, flags);
433
434 gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
435 if (!gpuobj)
436 return -ENOMEM;
437 NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
438 gpuobj->im_channel = NULL;
439 gpuobj->flags = flags | NVOBJ_FLAG_FAKE;
440
441 list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
442
443 if (p_offset != ~0) {
Ben Skeggsb833ac22010-06-01 15:32:24 +1000444 gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
Ben Skeggs6ee73862009-12-11 19:24:15 +1000445 GFP_KERNEL);
446 if (!gpuobj->im_pramin) {
447 nouveau_gpuobj_del(dev, &gpuobj);
448 return -ENOMEM;
449 }
450 gpuobj->im_pramin->start = p_offset;
451 gpuobj->im_pramin->size = size;
452 }
453
454 if (b_offset != ~0) {
455 gpuobj->im_backing = (struct nouveau_bo *)-1;
456 gpuobj->im_backing_start = b_offset;
457 }
458
459 if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000460 for (i = 0; i < gpuobj->im_pramin->size; i += 4)
461 nv_wo32(dev, gpuobj, i/4, 0);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000462 dev_priv->engine.instmem.flush(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000463 }
464
465 if (pref) {
466 i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref);
467 if (i) {
468 nouveau_gpuobj_del(dev, &gpuobj);
469 return i;
470 }
471 }
472
473 if (pgpuobj)
474 *pgpuobj = gpuobj;
475 return 0;
476}
477
478
479static uint32_t
480nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
481{
482 struct drm_nouveau_private *dev_priv = dev->dev_private;
483
484 /*XXX: dodgy hack for now */
485 if (dev_priv->card_type >= NV_50)
486 return 24;
487 if (dev_priv->card_type >= NV_40)
488 return 32;
489 return 16;
490}
491
492/*
493 DMA objects are used to reference a piece of memory in the
494 framebuffer, PCI or AGP address space. Each object is 16 bytes big
495 and looks as follows:
496
497 entry[0]
498 11:0 class (seems like I can always use 0 here)
499 12 page table present?
500 13 page entry linear?
501 15:14 access: 0 rw, 1 ro, 2 wo
502 17:16 target: 0 NV memory, 1 NV memory tiled, 2 PCI, 3 AGP
503 31:20 dma adjust (bits 0-11 of the address)
504 entry[1]
505 dma limit (size of transfer)
506 entry[X]
507 1 0 readonly, 1 readwrite
508 31:12 dma frame address of the page (bits 12-31 of the address)
509 entry[N]
510 page table terminator, same value as the first pte, as does nvidia
511 rivatv uses 0xffffffff
512
513 Non linear page tables need a list of frame addresses afterwards,
514 the rivatv project has some info on this.
515
516 The method below creates a DMA object in instance RAM and returns a handle
517 to it that can be used to set up context objects.
518*/
519int
520nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
521 uint64_t offset, uint64_t size, int access,
522 int target, struct nouveau_gpuobj **gpuobj)
523{
524 struct drm_device *dev = chan->dev;
525 struct drm_nouveau_private *dev_priv = dev->dev_private;
526 struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
527 int ret;
528
529 NV_DEBUG(dev, "ch%d class=0x%04x offset=0x%llx size=0x%llx\n",
530 chan->id, class, offset, size);
531 NV_DEBUG(dev, "access=%d target=%d\n", access, target);
532
533 switch (target) {
534 case NV_DMA_TARGET_AGP:
535 offset += dev_priv->gart_info.aper_base;
536 break;
537 default:
538 break;
539 }
540
541 ret = nouveau_gpuobj_new(dev, chan,
542 nouveau_gpuobj_class_instmem_size(dev, class),
543 16, NVOBJ_FLAG_ZERO_ALLOC |
544 NVOBJ_FLAG_ZERO_FREE, gpuobj);
545 if (ret) {
546 NV_ERROR(dev, "Error creating gpuobj: %d\n", ret);
547 return ret;
548 }
549
Ben Skeggs6ee73862009-12-11 19:24:15 +1000550 if (dev_priv->card_type < NV_50) {
551 uint32_t frame, adjust, pte_flags = 0;
552
553 if (access != NV_DMA_ACCESS_RO)
554 pte_flags |= (1<<1);
555 adjust = offset & 0x00000fff;
556 frame = offset & ~0x00000fff;
557
558 nv_wo32(dev, *gpuobj, 0, ((1<<12) | (1<<13) |
559 (adjust << 20) |
560 (access << 14) |
561 (target << 16) |
562 class));
563 nv_wo32(dev, *gpuobj, 1, size - 1);
564 nv_wo32(dev, *gpuobj, 2, frame | pte_flags);
565 nv_wo32(dev, *gpuobj, 3, frame | pte_flags);
566 } 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
578 nv_wo32(dev, *gpuobj, 0, flags0 | class);
579 nv_wo32(dev, *gpuobj, 1, lower_32_bits(limit));
580 nv_wo32(dev, *gpuobj, 2, lower_32_bits(offset));
581 nv_wo32(dev, *gpuobj, 3, ((upper_32_bits(limit) & 0xff) << 24) |
582 (upper_32_bits(offset) & 0xff));
583 nv_wo32(dev, *gpuobj, 5, flags5);
584 }
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) {
702 nv_wo32(dev, *gpuobj, 0, class);
703 nv_wo32(dev, *gpuobj, 5, 0x00010000);
704 } else {
705 switch (class) {
706 case NV_CLASS_NULL:
707 nv_wo32(dev, *gpuobj, 0, 0x00001030);
708 nv_wo32(dev, *gpuobj, 1, 0xFFFFFFFF);
709 break;
710 default:
711 if (dev_priv->card_type >= NV_40) {
712 nv_wo32(dev, *gpuobj, 0, class);
713#ifdef __BIG_ENDIAN
714 nv_wo32(dev, *gpuobj, 2, 0x01000000);
715#endif
716 } else {
717#ifdef __BIG_ENDIAN
718 nv_wo32(dev, *gpuobj, 0, class | 0x00080000);
719#else
720 nv_wo32(dev, *gpuobj, 0, class);
721#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) {
839 nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000);
840 nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe);
841 }
842
843 pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 2;
844 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 Skeggs6ee73862009-12-11 19:24:15 +1000849 nv_wo32(dev, chan->vm_pd, pde++,
850 chan->vm_gart_pt->instance | 0x03);
851 nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
852
853 pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 2;
854 for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
855 ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
856 dev_priv->vm_vram_pt[i],
857 &chan->vm_vram_pt[i]);
Ben Skeggsf56cb862010-07-08 11:29:10 +1000858 if (ret)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000859 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000860
861 nv_wo32(dev, chan->vm_pd, pde++,
862 chan->vm_vram_pt[i]->instance | 0x61);
863 nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
864 }
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 Skeggs6ee73862009-12-11 19:24:15 +1000999 for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
1000 gpuobj->im_backing_suspend[i] = nv_ro32(dev, 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 Skeggs6ee73862009-12-11 19:24:15 +10001045 for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
1046 nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]);
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}