aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-04-30 12:33:43 -0400
committerBen Skeggs <bskeggs@redhat.com>2012-05-24 02:55:41 -0400
commit20abd1634a6e2eedb84ca977adea56b8aa06cc3e (patch)
tree32eca9cf843cf2aa5163b15e76f833691eb306a2
parent2cda7f4c5e83925fe687f63625893e033358de4e (diff)
drm/nouveau: create real execution engine for software object class
Just a cleanup more or less, and to remove the need for special handling of software objects. This removes a heap of documentation on dma/graph object formats. The info is very out of date with our current understanding, and is far better documented in rnndb in envytools git. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/Makefile1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c150
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_software.h68
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c21
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c26
-rw-r--r--drivers/gpu/drm/nouveau/nv04_software.c153
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.h1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c72
-rw-r--r--drivers/gpu/drm/nouveau/nv50_software.c190
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fifo.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_software.c106
19 files changed, 567 insertions, 282 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index f7103b26ed43..ba3e57c7892d 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -18,6 +18,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
18 nv50_fb.o nvc0_fb.o \ 18 nv50_fb.o nvc0_fb.o \
19 nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \ 19 nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
20 nve0_fifo.o \ 20 nve0_fifo.o \
21 nv04_software.o nv50_software.o nvc0_software.o \
21 nv04_graph.o nv10_graph.o nv20_graph.o \ 22 nv04_graph.o nv10_graph.o nv20_graph.o \
22 nv40_graph.o nv50_graph.o nvc0_graph.o nve0_graph.o \ 23 nv40_graph.o nv50_graph.o nvc0_graph.o nve0_graph.o \
23 nv40_grctx.o nv50_grctx.o nvc0_grctx.o nve0_grctx.o \ 24 nv40_grctx.o nv50_grctx.o nvc0_grctx.o nve0_grctx.o \
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 730bbb249b01..26c08e9b4a33 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -28,6 +28,7 @@
28#include "nouveau_drm.h" 28#include "nouveau_drm.h"
29#include "nouveau_dma.h" 29#include "nouveau_dma.h"
30#include "nouveau_ramht.h" 30#include "nouveau_ramht.h"
31#include "nouveau_software.h"
31 32
32static int 33static int
33nouveau_channel_pushbuf_init(struct nouveau_channel *chan) 34nouveau_channel_pushbuf_init(struct nouveau_channel *chan)
@@ -155,8 +156,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
155 } 156 }
156 157
157 NV_DEBUG(dev, "initialising channel %d\n", chan->id); 158 NV_DEBUG(dev, "initialising channel %d\n", chan->id);
158 INIT_LIST_HEAD(&chan->nvsw.vbl_wait);
159 INIT_LIST_HEAD(&chan->nvsw.flip);
160 INIT_LIST_HEAD(&chan->fence.pending); 159 INIT_LIST_HEAD(&chan->fence.pending);
161 spin_lock_init(&chan->fence.lock); 160 spin_lock_init(&chan->fence.lock);
162 161
@@ -213,6 +212,12 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
213 OUT_RING (chan, 0x00000000); 212 OUT_RING (chan, 0x00000000);
214 FIRE_RING(chan); 213 FIRE_RING(chan);
215 214
215 ret = nouveau_gpuobj_gr_new(chan, NvSw, nouveau_software_class(dev));
216 if (ret) {
217 nouveau_channel_put(&chan);
218 return ret;
219 }
220
216 ret = nouveau_fence_channel_init(chan); 221 ret = nouveau_fence_channel_init(chan);
217 if (ret) { 222 if (ret) {
218 nouveau_channel_put(&chan); 223 nouveau_channel_put(&chan);
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 980b3e187b72..a13f2516d52f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -33,6 +33,7 @@
33#include "nouveau_crtc.h" 33#include "nouveau_crtc.h"
34#include "nouveau_dma.h" 34#include "nouveau_dma.h"
35#include "nouveau_connector.h" 35#include "nouveau_connector.h"
36#include "nouveau_software.h"
36#include "nouveau_gpio.h" 37#include "nouveau_gpio.h"
37#include "nv50_display.h" 38#include "nv50_display.h"
38 39
@@ -432,6 +433,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
432 struct nouveau_page_flip_state *s, 433 struct nouveau_page_flip_state *s,
433 struct nouveau_fence **pfence) 434 struct nouveau_fence **pfence)
434{ 435{
436 struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW];
435 struct drm_nouveau_private *dev_priv = chan->dev->dev_private; 437 struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
436 struct drm_device *dev = chan->dev; 438 struct drm_device *dev = chan->dev;
437 unsigned long flags; 439 unsigned long flags;
@@ -439,7 +441,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
439 441
440 /* Queue it to the pending list */ 442 /* Queue it to the pending list */
441 spin_lock_irqsave(&dev->event_lock, flags); 443 spin_lock_irqsave(&dev->event_lock, flags);
442 list_add_tail(&s->head, &chan->nvsw.flip); 444 list_add_tail(&s->head, &swch->flip);
443 spin_unlock_irqrestore(&dev->event_lock, flags); 445 spin_unlock_irqrestore(&dev->event_lock, flags);
444 446
445 /* Synchronize with the old framebuffer */ 447 /* Synchronize with the old framebuffer */
@@ -547,20 +549,20 @@ int
547nouveau_finish_page_flip(struct nouveau_channel *chan, 549nouveau_finish_page_flip(struct nouveau_channel *chan,
548 struct nouveau_page_flip_state *ps) 550 struct nouveau_page_flip_state *ps)
549{ 551{
552 struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW];
550 struct drm_device *dev = chan->dev; 553 struct drm_device *dev = chan->dev;
551 struct nouveau_page_flip_state *s; 554 struct nouveau_page_flip_state *s;
552 unsigned long flags; 555 unsigned long flags;
553 556
554 spin_lock_irqsave(&dev->event_lock, flags); 557 spin_lock_irqsave(&dev->event_lock, flags);
555 558
556 if (list_empty(&chan->nvsw.flip)) { 559 if (list_empty(&swch->flip)) {
557 NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id); 560 NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
558 spin_unlock_irqrestore(&dev->event_lock, flags); 561 spin_unlock_irqrestore(&dev->event_lock, flags);
559 return -EINVAL; 562 return -EINVAL;
560 } 563 }
561 564
562 s = list_first_entry(&chan->nvsw.flip, 565 s = list_first_entry(&swch->flip, struct nouveau_page_flip_state, head);
563 struct nouveau_page_flip_state, head);
564 if (s->event) { 566 if (s->event) {
565 struct drm_pending_vblank_event *e = s->event; 567 struct drm_pending_vblank_event *e = s->event;
566 struct timeval now; 568 struct timeval now;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 87619a94fa42..8b0e07740291 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -296,14 +296,6 @@ struct nouveau_channel {
296 uint32_t sw_subchannel[8]; 296 uint32_t sw_subchannel[8];
297 297
298 struct nouveau_vma dispc_vma[4]; 298 struct nouveau_vma dispc_vma[4];
299 struct {
300 struct nouveau_gpuobj *vblsem;
301 uint32_t vblsem_head;
302 uint32_t vblsem_offset;
303 uint32_t vblsem_rval;
304 struct list_head vbl_wait;
305 struct list_head flip;
306 } nvsw;
307 299
308 struct { 300 struct {
309 bool active; 301 bool active;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index ff5969d057ea..aca4719c287f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -32,6 +32,7 @@
32 32
33#include "nouveau_drv.h" 33#include "nouveau_drv.h"
34#include "nouveau_ramht.h" 34#include "nouveau_ramht.h"
35#include "nouveau_software.h"
35#include "nouveau_dma.h" 36#include "nouveau_dma.h"
36 37
37#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10) 38#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
@@ -503,11 +504,6 @@ nouveau_fence_channel_init(struct nouveau_channel *chan)
503 int ret; 504 int ret;
504 505
505 if (dev_priv->card_type < NV_C0) { 506 if (dev_priv->card_type < NV_C0) {
506 /* Create an NV_SW object for various sync purposes */
507 ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW);
508 if (ret)
509 return ret;
510
511 ret = RING_SPACE(chan, 2); 507 ret = RING_SPACE(chan, 2);
512 if (ret) 508 if (ret)
513 return ret; 509 return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index cc419fae794b..637636b55c73 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -35,6 +35,7 @@
35#include "nouveau_drv.h" 35#include "nouveau_drv.h"
36#include "nouveau_drm.h" 36#include "nouveau_drm.h"
37#include "nouveau_ramht.h" 37#include "nouveau_ramht.h"
38#include "nouveau_software.h"
38#include "nouveau_vm.h" 39#include "nouveau_vm.h"
39#include "nv50_display.h" 40#include "nv50_display.h"
40 41
@@ -133,37 +134,6 @@ nouveau_gpuobj_mthd_call2(struct drm_device *dev, int chid,
133 return ret; 134 return ret;
134} 135}
135 136
136/* NVidia uses context objects to drive drawing operations.
137
138 Context objects can be selected into 8 subchannels in the FIFO,
139 and then used via DMA command buffers.
140
141 A context object is referenced by a user defined handle (CARD32). The HW
142 looks up graphics objects in a hash table in the instance RAM.
143
144 An entry in the hash table consists of 2 CARD32. The first CARD32 contains
145 the handle, the second one a bitfield, that contains the address of the
146 object in instance RAM.
147
148 The format of the second CARD32 seems to be:
149
150 NV4 to NV30:
151
152 15: 0 instance_addr >> 4
153 17:16 engine (here uses 1 = graphics)
154 28:24 channel id (here uses 0)
155 31 valid (use 1)
156
157 NV40:
158
159 15: 0 instance_addr >> 4 (maybe 19-0)
160 21:20 engine (here uses 1 = graphics)
161 I'm unsure about the other bits, but using 0 seems to work.
162
163 The key into the hash table depends on the object handle and channel id and
164 is given as:
165*/
166
167int 137int
168nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, 138nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
169 uint32_t size, int align, uint32_t flags, 139 uint32_t size, int align, uint32_t flags,
@@ -361,34 +331,6 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
361 return 0; 331 return 0;
362} 332}
363 333
364/*
365 DMA objects are used to reference a piece of memory in the
366 framebuffer, PCI or AGP address space. Each object is 16 bytes big
367 and looks as follows:
368
369 entry[0]
370 11:0 class (seems like I can always use 0 here)
371 12 page table present?
372 13 page entry linear?
373 15:14 access: 0 rw, 1 ro, 2 wo
374 17:16 target: 0 NV memory, 1 NV memory tiled, 2 PCI, 3 AGP
375 31:20 dma adjust (bits 0-11 of the address)
376 entry[1]
377 dma limit (size of transfer)
378 entry[X]
379 1 0 readonly, 1 readwrite
380 31:12 dma frame address of the page (bits 12-31 of the address)
381 entry[N]
382 page table terminator, same value as the first pte, as does nvidia
383 rivatv uses 0xffffffff
384
385 Non linear page tables need a list of frame addresses afterwards,
386 the rivatv project has some info on this.
387
388 The method below creates a DMA object in instance RAM and returns a handle
389 to it that can be used to set up context objects.
390*/
391
392void 334void
393nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class, 335nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class,
394 u64 base, u64 size, int target, int access, 336 u64 base, u64 size, int target, int access,
@@ -540,82 +482,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
540 return 0; 482 return 0;
541} 483}
542 484
543/* Context objects in the instance RAM have the following structure.
544 * On NV40 they are 32 byte long, on NV30 and smaller 16 bytes.
545
546 NV4 - NV30:
547
548 entry[0]
549 11:0 class
550 12 chroma key enable
551 13 user clip enable
552 14 swizzle enable
553 17:15 patch config:
554 scrcopy_and, rop_and, blend_and, scrcopy, srccopy_pre, blend_pre
555 18 synchronize enable
556 19 endian: 1 big, 0 little
557 21:20 dither mode
558 23 single step enable
559 24 patch status: 0 invalid, 1 valid
560 25 context_surface 0: 1 valid
561 26 context surface 1: 1 valid
562 27 context pattern: 1 valid
563 28 context rop: 1 valid
564 29,30 context beta, beta4
565 entry[1]
566 7:0 mono format
567 15:8 color format
568 31:16 notify instance address
569 entry[2]
570 15:0 dma 0 instance address
571 31:16 dma 1 instance address
572 entry[3]
573 dma method traps
574
575 NV40:
576 No idea what the exact format is. Here's what can be deducted:
577
578 entry[0]:
579 11:0 class (maybe uses more bits here?)
580 17 user clip enable
581 21:19 patch config
582 25 patch status valid ?
583 entry[1]:
584 15:0 DMA notifier (maybe 20:0)
585 entry[2]:
586 15:0 DMA 0 instance (maybe 20:0)
587 24 big endian
588 entry[3]:
589 15:0 DMA 1 instance (maybe 20:0)
590 entry[4]:
591 entry[5]:
592 set to 0?
593*/
594static int
595nouveau_gpuobj_sw_new(struct nouveau_channel *chan, u32 handle, u16 class)
596{
597 struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
598 struct nouveau_gpuobj *gpuobj;
599 int ret;
600
601 gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
602 if (!gpuobj)
603 return -ENOMEM;
604 gpuobj->dev = chan->dev;
605 gpuobj->engine = NVOBJ_ENGINE_SW;
606 gpuobj->class = class;
607 kref_init(&gpuobj->refcount);
608 gpuobj->cinst = 0x40;
609
610 spin_lock(&dev_priv->ramin_lock);
611 list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
612 spin_unlock(&dev_priv->ramin_lock);
613
614 ret = nouveau_ramht_insert(chan, handle, gpuobj);
615 nouveau_gpuobj_ref(NULL, &gpuobj);
616 return ret;
617}
618
619int 485int
620nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class) 486nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
621{ 487{
@@ -632,9 +498,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
632 if (oc->id != class) 498 if (oc->id != class)
633 continue; 499 continue;
634 500
635 if (oc->engine == NVOBJ_ENGINE_SW)
636 return nouveau_gpuobj_sw_new(chan, handle, class);
637
638 if (!chan->engctx[oc->engine]) { 501 if (!chan->engctx[oc->engine]) {
639 ret = eng->context_new(chan, oc->engine); 502 ret = eng->context_new(chan, oc->engine);
640 if (ret) 503 if (ret)
@@ -956,6 +819,17 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
956 if (init->handle == ~0) 819 if (init->handle == ~0)
957 return -EINVAL; 820 return -EINVAL;
958 821
822 /* compatibility with userspace that assumes 506e for all chipsets */
823 if (init->class == 0x506e) {
824 init->class = nouveau_software_class(dev);
825 if (init->class == 0x906e)
826 return 0;
827 } else
828 if (init->class == 0x906e) {
829 NV_ERROR(dev, "906e not supported yet\n");
830 return -EINVAL;
831 }
832
959 chan = nouveau_channel_get(file_priv, init->channel); 833 chan = nouveau_channel_get(file_priv, init->channel);
960 if (IS_ERR(chan)) 834 if (IS_ERR(chan))
961 return PTR_ERR(chan); 835 return PTR_ERR(chan);
diff --git a/drivers/gpu/drm/nouveau/nouveau_software.h b/drivers/gpu/drm/nouveau/nouveau_software.h
new file mode 100644
index 000000000000..fe30a8f47f8c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_software.h
@@ -0,0 +1,68 @@
1#ifndef __NOUVEAU_SOFTWARE_H__
2#define __NOUVEAU_SOFTWARE_H__
3
4struct nouveau_software_priv {
5 struct nouveau_exec_engine base;
6 struct list_head vblank;
7};
8
9struct nouveau_software_chan {
10 struct list_head flip;
11 struct {
12 struct list_head list;
13 struct nouveau_bo *bo;
14 u32 offset;
15 u32 value;
16 u32 head;
17 } vblank;
18};
19
20static inline void
21nouveau_software_vblank(struct drm_device *dev, int crtc)
22{
23 struct nouveau_software_priv *psw = nv_engine(dev, NVOBJ_ENGINE_SW);
24 struct nouveau_software_chan *pch, *tmp;
25
26 list_for_each_entry_safe(pch, tmp, &psw->vblank, vblank.list) {
27 if (pch->vblank.head != crtc)
28 continue;
29
30 nouveau_bo_wr32(pch->vblank.bo, pch->vblank.offset,
31 pch->vblank.value);
32 list_del(&pch->vblank.list);
33 drm_vblank_put(dev, crtc);
34 }
35}
36
37static inline void
38nouveau_software_context_new(struct nouveau_software_chan *pch)
39{
40 INIT_LIST_HEAD(&pch->flip);
41}
42
43static inline void
44nouveau_software_create(struct nouveau_software_priv *psw)
45{
46 INIT_LIST_HEAD(&psw->vblank);
47}
48
49static inline u16
50nouveau_software_class(struct drm_device *dev)
51{
52 struct drm_nouveau_private *dev_priv = dev->dev_private;
53 if (dev_priv->card_type <= NV_04)
54 return 0x006e;
55 if (dev_priv->card_type <= NV_40)
56 return 0x016e;
57 if (dev_priv->card_type <= NV_50)
58 return 0x506e;
59 if (dev_priv->card_type <= NV_E0)
60 return 0x906e;
61 return 0x0000;
62}
63
64int nv04_software_create(struct drm_device *);
65int nv50_software_create(struct drm_device *);
66int nvc0_software_create(struct drm_device *);
67
68#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index e76edb51373d..ed83c425fcf3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -39,6 +39,7 @@
39#include "nouveau_gpio.h" 39#include "nouveau_gpio.h"
40#include "nouveau_pm.h" 40#include "nouveau_pm.h"
41#include "nv50_display.h" 41#include "nv50_display.h"
42#include "nouveau_software.h"
42 43
43static void nouveau_stub_takedown(struct drm_device *dev) {} 44static void nouveau_stub_takedown(struct drm_device *dev) {}
44static int nouveau_stub_init(struct drm_device *dev) { return 0; } 45static int nouveau_stub_init(struct drm_device *dev) { return 0; }
@@ -767,6 +768,26 @@ nouveau_card_init(struct drm_device *dev)
767 if (!dev_priv->noaccel) { 768 if (!dev_priv->noaccel) {
768 switch (dev_priv->card_type) { 769 switch (dev_priv->card_type) {
769 case NV_04: 770 case NV_04:
771 case NV_10:
772 case NV_20:
773 case NV_30:
774 case NV_40:
775 nv04_software_create(dev);
776 break;
777 case NV_50:
778 nv50_software_create(dev);
779 break;
780 case NV_C0:
781 case NV_D0:
782 case NV_E0:
783 nvc0_software_create(dev);
784 break;
785 default:
786 break;
787 }
788
789 switch (dev_priv->card_type) {
790 case NV_04:
770 nv04_graph_create(dev); 791 nv04_graph_create(dev);
771 break; 792 break;
772 case NV_10: 793 case NV_10:
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index dbdea8ed3925..442b4df44fad 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -550,28 +550,6 @@ nv04_graph_fini(struct drm_device *dev, int engine, bool suspend)
550 return 0; 550 return 0;
551} 551}
552 552
553static int
554nv04_graph_mthd_set_ref(struct nouveau_channel *chan,
555 u32 class, u32 mthd, u32 data)
556{
557 atomic_set(&chan->fence.last_sequence_irq, data);
558 return 0;
559}
560
561int
562nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
563 u32 class, u32 mthd, u32 data)
564{
565 struct drm_device *dev = chan->dev;
566 struct nouveau_page_flip_state s;
567
568 if (!nouveau_finish_page_flip(chan, &s))
569 nv_set_crtc_base(dev, s.crtc,
570 s.offset + s.y * s.pitch + s.x * s.bpp / 8);
571
572 return 0;
573}
574
575/* 553/*
576 * Software methods, why they are needed, and how they all work: 554 * Software methods, why they are needed, and how they all work:
577 * 555 *
@@ -1345,9 +1323,5 @@ nv04_graph_create(struct drm_device *dev)
1345 NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d); 1323 NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d);
1346 NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation); 1324 NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation);
1347 1325
1348 /* nvsw */
1349 NVOBJ_CLASS(dev, 0x506e, SW);
1350 NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
1351 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
1352 return 0; 1326 return 0;
1353} 1327}
diff --git a/drivers/gpu/drm/nouveau/nv04_software.c b/drivers/gpu/drm/nouveau/nv04_software.c
new file mode 100644
index 000000000000..d37de6e3c3b2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv04_software.c
@@ -0,0 +1,153 @@
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 "drmP.h"
26#include "nouveau_drv.h"
27#include "nouveau_ramht.h"
28#include "nouveau_software.h"
29#include "nouveau_hw.h"
30
31struct nv04_software_priv {
32 struct nouveau_software_priv base;
33};
34
35struct nv04_software_chan {
36 struct nouveau_software_chan base;
37};
38
39static int
40mthd_fence(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
41{
42 atomic_set(&chan->fence.last_sequence_irq, data);
43 return 0;
44}
45
46static int
47mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
48{
49
50 struct nouveau_page_flip_state state;
51
52 if (!nouveau_finish_page_flip(chan, &state)) {
53 nv_set_crtc_base(chan->dev, state.crtc, state.offset +
54 state.y * state.pitch +
55 state.x * state.bpp / 8);
56 }
57
58 return 0;
59}
60
61static int
62nv04_software_context_new(struct nouveau_channel *chan, int engine)
63{
64 struct nv04_software_chan *pch;
65
66 pch = kzalloc(sizeof(*pch), GFP_KERNEL);
67 if (!pch)
68 return -ENOMEM;
69
70 nouveau_software_context_new(&pch->base);
71 atomic_set(&chan->fence.last_sequence_irq, 0);
72 chan->engctx[engine] = pch;
73 return 0;
74}
75
76static void
77nv04_software_context_del(struct nouveau_channel *chan, int engine)
78{
79 struct nv04_software_chan *pch = chan->engctx[engine];
80 chan->engctx[engine] = NULL;
81 kfree(pch);
82}
83
84static int
85nv04_software_object_new(struct nouveau_channel *chan, int engine,
86 u32 handle, u16 class)
87{
88 struct drm_device *dev = chan->dev;
89 struct nouveau_gpuobj *obj = NULL;
90 int ret;
91
92 ret = nouveau_gpuobj_new(dev, chan, 16, 16, 0, &obj);
93 if (ret)
94 return ret;
95 obj->engine = 0;
96 obj->class = class;
97
98 ret = nouveau_ramht_insert(chan, handle, obj);
99 nouveau_gpuobj_ref(NULL, &obj);
100 return ret;
101}
102
103static int
104nv04_software_init(struct drm_device *dev, int engine)
105{
106 return 0;
107}
108
109static int
110nv04_software_fini(struct drm_device *dev, int engine, bool suspend)
111{
112 return 0;
113}
114
115static void
116nv04_software_destroy(struct drm_device *dev, int engine)
117{
118 struct nv04_software_priv *psw = nv_engine(dev, engine);
119
120 NVOBJ_ENGINE_DEL(dev, SW);
121 kfree(psw);
122}
123
124int
125nv04_software_create(struct drm_device *dev)
126{
127 struct drm_nouveau_private *dev_priv = dev->dev_private;
128 struct nv04_software_priv *psw;
129
130 psw = kzalloc(sizeof(*psw), GFP_KERNEL);
131 if (!psw)
132 return -ENOMEM;
133
134 psw->base.base.destroy = nv04_software_destroy;
135 psw->base.base.init = nv04_software_init;
136 psw->base.base.fini = nv04_software_fini;
137 psw->base.base.context_new = nv04_software_context_new;
138 psw->base.base.context_del = nv04_software_context_del;
139 psw->base.base.object_new = nv04_software_object_new;
140 nouveau_software_create(&psw->base);
141
142 NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
143 if (dev_priv->card_type <= NV_04) {
144 NVOBJ_CLASS(dev, 0x006e, SW);
145 NVOBJ_MTHD (dev, 0x006e, 0x0150, mthd_fence);
146 NVOBJ_MTHD (dev, 0x006e, 0x0500, mthd_flip);
147 } else {
148 NVOBJ_CLASS(dev, 0x016e, SW);
149 NVOBJ_MTHD (dev, 0x016e, 0x0500, mthd_flip);
150 }
151
152 return 0;
153}
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index 7255e4a4d3f3..10c0eb5d4233 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -1153,10 +1153,6 @@ nv10_graph_create(struct drm_device *dev)
1153 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); 1153 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
1154 nouveau_irq_register(dev, 12, nv10_graph_isr); 1154 nouveau_irq_register(dev, 12, nv10_graph_isr);
1155 1155
1156 /* nvsw */
1157 NVOBJ_CLASS(dev, 0x506e, SW);
1158 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
1159
1160 NVOBJ_CLASS(dev, 0x0030, GR); /* null */ 1156 NVOBJ_CLASS(dev, 0x0030, GR); /* null */
1161 NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ 1157 NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
1162 NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ 1158 NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index 183e37512ef9..385e2b49a554 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -796,10 +796,6 @@ nv20_graph_create(struct drm_device *dev)
796 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); 796 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
797 nouveau_irq_register(dev, 12, nv20_graph_isr); 797 nouveau_irq_register(dev, 12, nv20_graph_isr);
798 798
799 /* nvsw */
800 NVOBJ_CLASS(dev, 0x506e, SW);
801 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
802
803 NVOBJ_CLASS(dev, 0x0030, GR); /* null */ 799 NVOBJ_CLASS(dev, 0x0030, GR); /* null */
804 NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ 800 NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
805 NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ 801 NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index 6d8147b07c83..03837200762d 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -439,7 +439,6 @@ nv40_graph_create(struct drm_device *dev)
439 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); 439 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
440 nouveau_irq_register(dev, 12, nv40_graph_isr); 440 nouveau_irq_register(dev, 12, nv40_graph_isr);
441 441
442 NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
443 NVOBJ_CLASS(dev, 0x0030, GR); /* null */ 442 NVOBJ_CLASS(dev, 0x0030, GR); /* null */
444 NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */ 443 NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
445 NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */ 444 NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
@@ -462,8 +461,5 @@ nv40_graph_create(struct drm_device *dev)
462 else 461 else
463 NVOBJ_CLASS(dev, 0x4097, GR); 462 NVOBJ_CLASS(dev, 0x4097, GR);
464 463
465 /* nvsw */
466 NVOBJ_CLASS(dev, 0x506e, SW);
467 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
468 return 0; 464 return 0;
469} 465}
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index b526e3f61c17..362a4d7cd566 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -645,20 +645,7 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
645static void 645static void
646nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc) 646nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
647{ 647{
648 struct drm_nouveau_private *dev_priv = dev->dev_private; 648 nouveau_software_vblank(dev, crtc);
649 struct nouveau_channel *chan, *tmp;
650
651 list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting,
652 nvsw.vbl_wait) {
653 if (chan->nvsw.vblsem_head != crtc)
654 continue;
655
656 nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset,
657 chan->nvsw.vblsem_rval);
658 list_del(&chan->nvsw.vbl_wait);
659 drm_vblank_put(dev, crtc);
660 }
661
662 drm_handle_vblank(dev, crtc); 649 drm_handle_vblank(dev, crtc);
663} 650}
664 651
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index 5d3dd14d2837..e9db9b97f041 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -33,6 +33,7 @@
33#include "nouveau_dma.h" 33#include "nouveau_dma.h"
34#include "nouveau_reg.h" 34#include "nouveau_reg.h"
35#include "nouveau_crtc.h" 35#include "nouveau_crtc.h"
36#include "nouveau_software.h"
36#include "nv50_evo.h" 37#include "nv50_evo.h"
37 38
38struct nv50_display_crtc { 39struct nv50_display_crtc {
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index 2698d80c8eb2..a46e060eb399 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -333,70 +333,6 @@ nv50_graph_context_switch(struct drm_device *dev)
333 NV40_PGRAPH_INTR_EN) | NV_PGRAPH_INTR_CONTEXT_SWITCH); 333 NV40_PGRAPH_INTR_EN) | NV_PGRAPH_INTR_CONTEXT_SWITCH);
334} 334}
335 335
336static int
337nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan,
338 u32 class, u32 mthd, u32 data)
339{
340 struct nouveau_gpuobj *gpuobj;
341
342 gpuobj = nouveau_ramht_find(chan, data);
343 if (!gpuobj)
344 return -ENOENT;
345
346 if (nouveau_notifier_offset(gpuobj, NULL))
347 return -EINVAL;
348
349 chan->nvsw.vblsem = gpuobj;
350 chan->nvsw.vblsem_offset = ~0;
351 return 0;
352}
353
354static int
355nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan,
356 u32 class, u32 mthd, u32 data)
357{
358 if (nouveau_notifier_offset(chan->nvsw.vblsem, &data))
359 return -ERANGE;
360
361 chan->nvsw.vblsem_offset = data >> 2;
362 return 0;
363}
364
365static int
366nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan,
367 u32 class, u32 mthd, u32 data)
368{
369 chan->nvsw.vblsem_rval = data;
370 return 0;
371}
372
373static int
374nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan,
375 u32 class, u32 mthd, u32 data)
376{
377 struct drm_device *dev = chan->dev;
378 struct drm_nouveau_private *dev_priv = dev->dev_private;
379
380 if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1)
381 return -EINVAL;
382
383 drm_vblank_get(dev, data);
384
385 chan->nvsw.vblsem_head = data;
386 list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting);
387
388 return 0;
389}
390
391static int
392nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
393 u32 class, u32 mthd, u32 data)
394{
395 nouveau_finish_page_flip(chan, NULL);
396 return 0;
397}
398
399
400static void 336static void
401nv50_graph_tlb_flush(struct drm_device *dev, int engine) 337nv50_graph_tlb_flush(struct drm_device *dev, int engine)
402{ 338{
@@ -1018,14 +954,6 @@ nv50_graph_create(struct drm_device *dev)
1018 954
1019 nouveau_irq_register(dev, 12, nv50_graph_isr); 955 nouveau_irq_register(dev, 12, nv50_graph_isr);
1020 956
1021 /* NVSW really doesn't live here... */
1022 NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
1023 NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
1024 NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
1025 NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
1026 NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
1027 NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
1028
1029 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base); 957 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
1030 NVOBJ_CLASS(dev, 0x0030, GR); /* null */ 958 NVOBJ_CLASS(dev, 0x0030, GR); /* null */
1031 NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */ 959 NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
diff --git a/drivers/gpu/drm/nouveau/nv50_software.c b/drivers/gpu/drm/nouveau/nv50_software.c
new file mode 100644
index 000000000000..0e64d80d5363
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_software.c
@@ -0,0 +1,190 @@
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 "drmP.h"
26#include "nouveau_drv.h"
27#include "nouveau_ramht.h"
28#include "nouveau_software.h"
29
30struct nv50_software_priv {
31 struct nouveau_software_priv base;
32};
33
34struct nv50_software_chan {
35 struct nouveau_software_chan base;
36 struct {
37 struct nouveau_gpuobj *object;
38 } vblank;
39};
40
41static int
42mthd_dma_vblsem(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
43{
44 struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
45 struct nouveau_gpuobj *gpuobj;
46
47 gpuobj = nouveau_ramht_find(chan, data);
48 if (!gpuobj)
49 return -ENOENT;
50
51 if (nouveau_notifier_offset(gpuobj, NULL))
52 return -EINVAL;
53
54 pch->vblank.object = gpuobj;
55 pch->base.vblank.offset = ~0;
56 return 0;
57}
58
59static int
60mthd_vblsem_offset(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
61{
62 struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
63
64 if (nouveau_notifier_offset(pch->vblank.object, &data))
65 return -ERANGE;
66
67 pch->base.vblank.offset = data >> 2;
68 return 0;
69}
70
71static int
72mthd_vblsem_value(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
73{
74 struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
75 pch->base.vblank.value = data;
76 return 0;
77}
78
79static int
80mthd_vblsem_release(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
81{
82 struct nv50_software_priv *psw = nv_engine(chan->dev, NVOBJ_ENGINE_SW);
83 struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
84 struct drm_device *dev = chan->dev;
85
86 if (!pch->vblank.object || pch->base.vblank.offset == ~0 || data > 1)
87 return -EINVAL;
88
89 drm_vblank_get(dev, data);
90
91 pch->base.vblank.head = data;
92 list_add(&pch->base.vblank.list, &psw->base.vblank);
93 return 0;
94}
95
96static int
97mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
98{
99 nouveau_finish_page_flip(chan, NULL);
100 return 0;
101}
102
103static int
104nv50_software_context_new(struct nouveau_channel *chan, int engine)
105{
106 struct nv50_software_chan *pch;
107
108 pch = kzalloc(sizeof(*pch), GFP_KERNEL);
109 if (!pch)
110 return -ENOMEM;
111
112 nouveau_software_context_new(&pch->base);
113 pch->base.vblank.bo = chan->notifier_bo;
114
115 chan->engctx[engine] = pch;
116 return 0;
117}
118
119static void
120nv50_software_context_del(struct nouveau_channel *chan, int engine)
121{
122 struct nv50_software_chan *pch = chan->engctx[engine];
123 chan->engctx[engine] = NULL;
124 kfree(pch);
125}
126
127static int
128nv50_software_object_new(struct nouveau_channel *chan, int engine,
129 u32 handle, u16 class)
130{
131 struct drm_device *dev = chan->dev;
132 struct nouveau_gpuobj *obj = NULL;
133 int ret;
134
135 ret = nouveau_gpuobj_new(dev, chan, 16, 16, 0, &obj);
136 if (ret)
137 return ret;
138 obj->engine = 0;
139 obj->class = class;
140
141 ret = nouveau_ramht_insert(chan, handle, obj);
142 nouveau_gpuobj_ref(NULL, &obj);
143 return ret;
144}
145
146static int
147nv50_software_init(struct drm_device *dev, int engine)
148{
149 return 0;
150}
151
152static int
153nv50_software_fini(struct drm_device *dev, int engine, bool suspend)
154{
155 return 0;
156}
157
158static void
159nv50_software_destroy(struct drm_device *dev, int engine)
160{
161 struct nv50_software_priv *psw = nv_engine(dev, engine);
162
163 NVOBJ_ENGINE_DEL(dev, SW);
164 kfree(psw);
165}
166
167int
168nv50_software_create(struct drm_device *dev)
169{
170 struct nv50_software_priv *psw = kzalloc(sizeof(*psw), GFP_KERNEL);
171 if (!psw)
172 return -ENOMEM;
173
174 psw->base.base.destroy = nv50_software_destroy;
175 psw->base.base.init = nv50_software_init;
176 psw->base.base.fini = nv50_software_fini;
177 psw->base.base.context_new = nv50_software_context_new;
178 psw->base.base.context_del = nv50_software_context_del;
179 psw->base.base.object_new = nv50_software_object_new;
180 nouveau_software_create(&psw->base);
181
182 NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
183 NVOBJ_CLASS(dev, 0x506e, SW);
184 NVOBJ_MTHD (dev, 0x506e, 0x018c, mthd_dma_vblsem);
185 NVOBJ_MTHD (dev, 0x506e, 0x0400, mthd_vblsem_offset);
186 NVOBJ_MTHD (dev, 0x506e, 0x0404, mthd_vblsem_value);
187 NVOBJ_MTHD (dev, 0x506e, 0x0408, mthd_vblsem_release);
188 NVOBJ_MTHD (dev, 0x506e, 0x0500, mthd_flip);
189 return 0;
190}
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
index 50d68a7a1379..f47f39645c3e 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -278,7 +278,6 @@ nvc0_fifo_create(struct drm_device *dev)
278 goto error; 278 goto error;
279 279
280 nouveau_irq_register(dev, 8, nvc0_fifo_isr); 280 nouveau_irq_register(dev, 8, nvc0_fifo_isr);
281 NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
282 return 0; 281 return 0;
283 282
284error: 283error:
diff --git a/drivers/gpu/drm/nouveau/nvc0_software.c b/drivers/gpu/drm/nouveau/nvc0_software.c
new file mode 100644
index 000000000000..a1b43f580995
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_software.c
@@ -0,0 +1,106 @@
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 "drmP.h"
26#include "nouveau_drv.h"
27#include "nouveau_ramht.h"
28#include "nouveau_software.h"
29
30struct nvc0_software_priv {
31 struct nouveau_software_priv base;
32};
33
34struct nvc0_software_chan {
35 struct nouveau_software_chan base;
36};
37
38static int
39nvc0_software_context_new(struct nouveau_channel *chan, int engine)
40{
41 struct nvc0_software_chan *pch;
42
43 pch = kzalloc(sizeof(*pch), GFP_KERNEL);
44 if (!pch)
45 return -ENOMEM;
46
47 nouveau_software_context_new(&pch->base);
48 chan->engctx[engine] = pch;
49 return 0;
50}
51
52static void
53nvc0_software_context_del(struct nouveau_channel *chan, int engine)
54{
55 struct nvc0_software_chan *pch = chan->engctx[engine];
56 chan->engctx[engine] = NULL;
57 kfree(pch);
58}
59
60static int
61nvc0_software_object_new(struct nouveau_channel *chan, int engine,
62 u32 handle, u16 class)
63{
64 return 0;
65}
66
67static int
68nvc0_software_init(struct drm_device *dev, int engine)
69{
70 return 0;
71}
72
73static int
74nvc0_software_fini(struct drm_device *dev, int engine, bool suspend)
75{
76 return 0;
77}
78
79static void
80nvc0_software_destroy(struct drm_device *dev, int engine)
81{
82 struct nvc0_software_priv *psw = nv_engine(dev, engine);
83
84 NVOBJ_ENGINE_DEL(dev, SW);
85 kfree(psw);
86}
87
88int
89nvc0_software_create(struct drm_device *dev)
90{
91 struct nvc0_software_priv *psw = kzalloc(sizeof(*psw), GFP_KERNEL);
92 if (!psw)
93 return -ENOMEM;
94
95 psw->base.base.destroy = nvc0_software_destroy;
96 psw->base.base.init = nvc0_software_init;
97 psw->base.base.fini = nvc0_software_fini;
98 psw->base.base.context_new = nvc0_software_context_new;
99 psw->base.base.context_del = nvc0_software_context_del;
100 psw->base.base.object_new = nvc0_software_object_new;
101 nouveau_software_create(&psw->base);
102
103 NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
104 NVOBJ_CLASS(dev, 0x906e, SW);
105 return 0;
106}