diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-04-30 12:33:43 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-05-24 02:55:41 -0400 |
commit | 20abd1634a6e2eedb84ca977adea56b8aa06cc3e (patch) | |
tree | 32eca9cf843cf2aa5163b15e76f833691eb306a2 /drivers/gpu | |
parent | 2cda7f4c5e83925fe687f63625893e033358de4e (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>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_channel.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_object.c | 150 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_software.h | 68 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_graph.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_software.c | 153 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv10_graph.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv20_graph.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv40_graph.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_graph.c | 72 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_software.c | 190 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_fifo.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_software.c | 106 |
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 | ||
32 | static int | 33 | static int |
33 | nouveau_channel_pushbuf_init(struct nouveau_channel *chan) | 34 | nouveau_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 | |||
547 | nouveau_finish_page_flip(struct nouveau_channel *chan, | 549 | nouveau_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 | |||
167 | int | 137 | int |
168 | nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, | 138 | nouveau_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 | |||
392 | void | 334 | void |
393 | nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class, | 335 | nv50_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 | */ | ||
594 | static int | ||
595 | nouveau_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 | |||
619 | int | 485 | int |
620 | nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class) | 486 | nouveau_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 | |||
4 | struct nouveau_software_priv { | ||
5 | struct nouveau_exec_engine base; | ||
6 | struct list_head vblank; | ||
7 | }; | ||
8 | |||
9 | struct 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 | |||
20 | static inline void | ||
21 | nouveau_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 | |||
37 | static inline void | ||
38 | nouveau_software_context_new(struct nouveau_software_chan *pch) | ||
39 | { | ||
40 | INIT_LIST_HEAD(&pch->flip); | ||
41 | } | ||
42 | |||
43 | static inline void | ||
44 | nouveau_software_create(struct nouveau_software_priv *psw) | ||
45 | { | ||
46 | INIT_LIST_HEAD(&psw->vblank); | ||
47 | } | ||
48 | |||
49 | static inline u16 | ||
50 | nouveau_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 | |||
64 | int nv04_software_create(struct drm_device *); | ||
65 | int nv50_software_create(struct drm_device *); | ||
66 | int 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 | ||
43 | static void nouveau_stub_takedown(struct drm_device *dev) {} | 44 | static void nouveau_stub_takedown(struct drm_device *dev) {} |
44 | static int nouveau_stub_init(struct drm_device *dev) { return 0; } | 45 | static 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 | ||
553 | static int | ||
554 | nv04_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 | |||
561 | int | ||
562 | nv04_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 | |||
31 | struct nv04_software_priv { | ||
32 | struct nouveau_software_priv base; | ||
33 | }; | ||
34 | |||
35 | struct nv04_software_chan { | ||
36 | struct nouveau_software_chan base; | ||
37 | }; | ||
38 | |||
39 | static int | ||
40 | mthd_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 | |||
46 | static int | ||
47 | mthd_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 | |||
61 | static int | ||
62 | nv04_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 | |||
76 | static void | ||
77 | nv04_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 | |||
84 | static int | ||
85 | nv04_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 | |||
103 | static int | ||
104 | nv04_software_init(struct drm_device *dev, int engine) | ||
105 | { | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int | ||
110 | nv04_software_fini(struct drm_device *dev, int engine, bool suspend) | ||
111 | { | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static void | ||
116 | nv04_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 | |||
124 | int | ||
125 | nv04_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, | |||
645 | static void | 645 | static void |
646 | nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc) | 646 | nv50_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 | ||
38 | struct nv50_display_crtc { | 39 | struct 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 | ||
336 | static int | ||
337 | nv50_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 | |||
354 | static int | ||
355 | nv50_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 | |||
365 | static int | ||
366 | nv50_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 | |||
373 | static int | ||
374 | nv50_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 | |||
391 | static int | ||
392 | nv50_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 | |||
400 | static void | 336 | static void |
401 | nv50_graph_tlb_flush(struct drm_device *dev, int engine) | 337 | nv50_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 | |||
30 | struct nv50_software_priv { | ||
31 | struct nouveau_software_priv base; | ||
32 | }; | ||
33 | |||
34 | struct nv50_software_chan { | ||
35 | struct nouveau_software_chan base; | ||
36 | struct { | ||
37 | struct nouveau_gpuobj *object; | ||
38 | } vblank; | ||
39 | }; | ||
40 | |||
41 | static int | ||
42 | mthd_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 | |||
59 | static int | ||
60 | mthd_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 | |||
71 | static int | ||
72 | mthd_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 | |||
79 | static int | ||
80 | mthd_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 | |||
96 | static int | ||
97 | mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) | ||
98 | { | ||
99 | nouveau_finish_page_flip(chan, NULL); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int | ||
104 | nv50_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 | |||
119 | static void | ||
120 | nv50_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 | |||
127 | static int | ||
128 | nv50_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 | |||
146 | static int | ||
147 | nv50_software_init(struct drm_device *dev, int engine) | ||
148 | { | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int | ||
153 | nv50_software_fini(struct drm_device *dev, int engine, bool suspend) | ||
154 | { | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static void | ||
159 | nv50_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 | |||
167 | int | ||
168 | nv50_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 | ||
284 | error: | 283 | error: |
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 | |||
30 | struct nvc0_software_priv { | ||
31 | struct nouveau_software_priv base; | ||
32 | }; | ||
33 | |||
34 | struct nvc0_software_chan { | ||
35 | struct nouveau_software_chan base; | ||
36 | }; | ||
37 | |||
38 | static int | ||
39 | nvc0_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 | |||
52 | static void | ||
53 | nvc0_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 | |||
60 | static int | ||
61 | nvc0_software_object_new(struct nouveau_channel *chan, int engine, | ||
62 | u32 handle, u16 class) | ||
63 | { | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | nvc0_software_init(struct drm_device *dev, int engine) | ||
69 | { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int | ||
74 | nvc0_software_fini(struct drm_device *dev, int engine, bool suspend) | ||
75 | { | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static void | ||
80 | nvc0_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 | |||
88 | int | ||
89 | nvc0_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 | } | ||