aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-11-14 21:24:40 -0500
committerDave Airlie <airlied@redhat.com>2013-11-14 21:24:40 -0500
commit0846c728e20a0cd1e43fb75a3015f3b176a26466 (patch)
treea65d8b3a8c4860f79f9bf634d13ff3405fb5e217
parentad40f83f5a89f6d723fd4db424b531f8dd7d3b49 (diff)
parentd2c7ab32ceb0737c1aba84765c555e0f73d3c935 (diff)
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next
- Page flipping fixes, with support for syncing them to vblank (finally...). - Misc other general fixes * 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: drm/nouveau: do not map evicted vram buffers in nouveau_bo_vma_add drm/nvc0-/gr: shift wrapping bug in nvc0_grctx_generate_r406800 drm/nouveau/pwr: fix missing mutex unlock in a failure path drm/nv40/therm: fix slowing down fan when pstate undefined drm/nv11-: synchronise flips to vblank, unless async flip requested drm/nvc0-: remove nasty fifo swmthd hack for flip completion method drm/nv10-: we no longer need to create nvsw object on user channels drm/nouveau: always queue flips relative to kernel channel activity drm/nouveau: there is no need to reserve/fence the new fb when flipping drm/nouveau: when bailing out of a pushbuf ioctl, do not remove previous fence drm/nouveau: allow nouveau_fence_ref() to be a noop drm/nvc8/mc: msi rearm is via the nvc0 method
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nvc0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/base.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/base.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c16
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c78
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.h7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c27
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c9
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fbcon.c6
16 files changed, 105 insertions, 86 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
index 606598f226fc..8d06eef2b9ee 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
@@ -256,7 +256,7 @@ nvc0_identify(struct nouveau_device *device)
256 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; 256 device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
257 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; 257 device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
258 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; 258 device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
259 device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; 259 device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass;
260 device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; 260 device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
261 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; 261 device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
262 device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; 262 device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
index e21453a94971..9ac94d4e5646 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
@@ -494,13 +494,6 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
494 u32 mthd = (addr & 0x00003ffc); 494 u32 mthd = (addr & 0x00003ffc);
495 u32 show = stat; 495 u32 show = stat;
496 496
497 if (stat & 0x00200000) {
498 if (mthd == 0x0054) {
499 if (!nvc0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
500 show &= ~0x00200000;
501 }
502 }
503
504 if (stat & 0x00800000) { 497 if (stat & 0x00800000) {
505 if (!nvc0_fifo_swmthd(priv, chid, mthd, data)) 498 if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
506 show &= ~0x00800000; 499 show &= ~0x00800000;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index fcd449e5aba7..04f412922d2d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -481,13 +481,6 @@ nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit)
481 u32 mthd = (addr & 0x00003ffc); 481 u32 mthd = (addr & 0x00003ffc);
482 u32 show = stat; 482 u32 show = stat;
483 483
484 if (stat & 0x00200000) {
485 if (mthd == 0x0054) {
486 if (!nve0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
487 show &= ~0x00200000;
488 }
489 }
490
491 if (stat & 0x00800000) { 484 if (stat & 0x00800000) {
492 if (!nve0_fifo_swmthd(priv, chid, mthd, data)) 485 if (!nve0_fifo_swmthd(priv, chid, mthd, data))
493 show &= ~0x00800000; 486 show &= ~0x00800000;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
index 64dca260912f..fe67415c3e17 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
@@ -1039,7 +1039,7 @@ nvc0_grctx_generate_r406800(struct nvc0_graph_priv *priv)
1039 } while (!tpcnr[gpc]); 1039 } while (!tpcnr[gpc]);
1040 tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; 1040 tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
1041 1041
1042 tpc_set |= 1 << ((gpc * 8) + tpc); 1042 tpc_set |= 1ULL << ((gpc * 8) + tpc);
1043 } 1043 }
1044 1044
1045 nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); 1045 nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set));
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
index 9908f1f05a00..d4fd3bc9c66f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
@@ -32,6 +32,11 @@ nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2],
32 struct nouveau_subdev *subdev = nv_subdev(ppwr); 32 struct nouveau_subdev *subdev = nv_subdev(ppwr);
33 u32 addr; 33 u32 addr;
34 34
35 /* wait for a free slot in the fifo */
36 addr = nv_rd32(ppwr, 0x10a4a0);
37 if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8))
38 return -EBUSY;
39
35 /* we currently only support a single process at a time waiting 40 /* we currently only support a single process at a time waiting
36 * on a synchronous reply, take the PPWR mutex and tell the 41 * on a synchronous reply, take the PPWR mutex and tell the
37 * receive handler what we're waiting for 42 * receive handler what we're waiting for
@@ -42,11 +47,6 @@ nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2],
42 ppwr->recv.process = process; 47 ppwr->recv.process = process;
43 } 48 }
44 49
45 /* wait for a free slot in the fifo */
46 addr = nv_rd32(ppwr, 0x10a4a0);
47 if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8))
48 return -EBUSY;
49
50 /* acquire data segment access */ 50 /* acquire data segment access */
51 do { 51 do {
52 nv_wr32(ppwr, 0x10a580, 0x00000001); 52 nv_wr32(ppwr, 0x10a580, 0x00000001);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
index 21b2b3021fad..80e584a1bd1c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
@@ -117,7 +117,8 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
117 priv->fan->bios.linear_max_temp) { 117 priv->fan->bios.linear_max_temp) {
118 duty = nouveau_therm_update_linear(therm); 118 duty = nouveau_therm_update_linear(therm);
119 } else { 119 } else {
120 duty = priv->cstate; 120 if (priv->cstate)
121 duty = priv->cstate;
121 poll = false; 122 poll = false;
122 } 123 }
123 immd = false; 124 immd = false;
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 3621e7f23477..6828d81ed7b9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -298,7 +298,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
298 else 298 else
299 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; 299 init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
300 300
301 if (device->card_type < NV_C0) { 301 if (device->card_type < NV_10) {
302 init->subchan[0].handle = 0x00000000; 302 init->subchan[0].handle = 0x00000000;
303 init->subchan[0].grclass = 0x0000; 303 init->subchan[0].grclass = 0x0000;
304 init->subchan[1].handle = NvSw; 304 init->subchan[1].handle = NvSw;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 949ab0cbc4ab..c0fde6b9393c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -98,12 +98,7 @@ nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile,
98 98
99 if (tile) { 99 if (tile) {
100 spin_lock(&drm->tile.lock); 100 spin_lock(&drm->tile.lock);
101 if (fence) { 101 tile->fence = nouveau_fence_ref(fence);
102 /* Mark it as pending. */
103 tile->fence = fence;
104 nouveau_fence_ref(fence);
105 }
106
107 tile->used = false; 102 tile->used = false;
108 spin_unlock(&drm->tile.lock); 103 spin_unlock(&drm->tile.lock);
109 } 104 }
@@ -1462,14 +1457,12 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
1462void 1457void
1463nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) 1458nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence)
1464{ 1459{
1460 struct nouveau_fence *new_fence = nouveau_fence_ref(fence);
1465 struct nouveau_fence *old_fence = NULL; 1461 struct nouveau_fence *old_fence = NULL;
1466 1462
1467 if (likely(fence))
1468 nouveau_fence_ref(fence);
1469
1470 spin_lock(&nvbo->bo.bdev->fence_lock); 1463 spin_lock(&nvbo->bo.bdev->fence_lock);
1471 old_fence = nvbo->bo.sync_obj; 1464 old_fence = nvbo->bo.sync_obj;
1472 nvbo->bo.sync_obj = fence; 1465 nvbo->bo.sync_obj = new_fence;
1473 spin_unlock(&nvbo->bo.bdev->fence_lock); 1466 spin_unlock(&nvbo->bo.bdev->fence_lock);
1474 1467
1475 nouveau_fence_unref(&old_fence); 1468 nouveau_fence_unref(&old_fence);
@@ -1552,7 +1545,8 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
1552 1545
1553 if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) 1546 if (nvbo->bo.mem.mem_type == TTM_PL_VRAM)
1554 nouveau_vm_map(vma, nvbo->bo.mem.mm_node); 1547 nouveau_vm_map(vma, nvbo->bo.mem.mm_node);
1555 else if (nvbo->bo.mem.mem_type == TTM_PL_TT) { 1548 else if (nvbo->bo.mem.mem_type == TTM_PL_TT &&
1549 nvbo->page_shift == vma->vm->vmm->spg_shift) {
1556 if (node->sg) 1550 if (node->sg)
1557 nouveau_vm_map_sg_table(vma, 0, size, node); 1551 nouveau_vm_map_sg_table(vma, 0, size, node);
1558 else 1552 else
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index e84f4c32331b..cc5152be2cf1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -346,22 +346,17 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
346 for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) 346 for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
347 OUT_RING(chan, 0x00000000); 347 OUT_RING(chan, 0x00000000);
348 348
349 /* allocate software object class (used for fences on <= nv05, and 349 /* allocate software object class (used for fences on <= nv05) */
350 * to signal flip completion), bind it to a subchannel. 350 if (device->card_type < NV_10) {
351 */
352 if ((device->card_type < NV_E0) || gart /* nve0: want_nvsw */) {
353 ret = nouveau_object_new(nv_object(client), chan->handle, 351 ret = nouveau_object_new(nv_object(client), chan->handle,
354 NvSw, nouveau_abi16_swclass(chan->drm), 352 NvSw, 0x006e, NULL, 0, &object);
355 NULL, 0, &object);
356 if (ret) 353 if (ret)
357 return ret; 354 return ret;
358 355
359 swch = (void *)object->parent; 356 swch = (void *)object->parent;
360 swch->flip = nouveau_flip_complete; 357 swch->flip = nouveau_flip_complete;
361 swch->flip_data = chan; 358 swch->flip_data = chan;
362 }
363 359
364 if (device->card_type < NV_C0) {
365 ret = RING_SPACE(chan, 2); 360 ret = RING_SPACE(chan, 2);
366 if (ret) 361 if (ret)
367 return ret; 362 return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 44642d9094e6..7809d92183c4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -26,7 +26,6 @@
26 26
27#include <drm/drmP.h> 27#include <drm/drmP.h>
28#include <drm/drm_crtc_helper.h> 28#include <drm/drm_crtc_helper.h>
29#include <drm/ttm/ttm_execbuf_util.h>
30 29
31#include "nouveau_fbcon.h" 30#include "nouveau_fbcon.h"
32#include "dispnv04/hw.h" 31#include "dispnv04/hw.h"
@@ -399,6 +398,11 @@ nouveau_display_create(struct drm_device *dev)
399 dev->mode_config.preferred_depth = 24; 398 dev->mode_config.preferred_depth = 24;
400 dev->mode_config.prefer_shadow = 1; 399 dev->mode_config.prefer_shadow = 1;
401 400
401 if (nv_device(drm->device)->chipset < 0x11)
402 dev->mode_config.async_page_flip = false;
403 else
404 dev->mode_config.async_page_flip = true;
405
402 drm_kms_helper_poll_init(dev); 406 drm_kms_helper_poll_init(dev);
403 drm_kms_helper_poll_disable(dev); 407 drm_kms_helper_poll_disable(dev);
404 408
@@ -555,19 +559,15 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
555 goto fail; 559 goto fail;
556 560
557 /* Emit the pageflip */ 561 /* Emit the pageflip */
558 ret = RING_SPACE(chan, 3); 562 ret = RING_SPACE(chan, 2);
559 if (ret) 563 if (ret)
560 goto fail; 564 goto fail;
561 565
562 if (nv_device(drm->device)->card_type < NV_C0) { 566 if (nv_device(drm->device)->card_type < NV_C0)
563 BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); 567 BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
564 OUT_RING (chan, 0x00000000); 568 else
565 OUT_RING (chan, 0x00000000); 569 BEGIN_NVC0(chan, FermiSw, NV_SW_PAGE_FLIP, 1);
566 } else { 570 OUT_RING (chan, 0x00000000);
567 BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
568 OUT_RING (chan, 0);
569 BEGIN_IMC0(chan, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000);
570 }
571 FIRE_RING (chan); 571 FIRE_RING (chan);
572 572
573 ret = nouveau_fence_new(chan, false, pfence); 573 ret = nouveau_fence_new(chan, false, pfence);
@@ -584,22 +584,16 @@ fail:
584 584
585int 585int
586nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, 586nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
587 struct drm_pending_vblank_event *event, 587 struct drm_pending_vblank_event *event, u32 flags)
588 uint32_t page_flip_flags)
589{ 588{
589 const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
590 struct drm_device *dev = crtc->dev; 590 struct drm_device *dev = crtc->dev;
591 struct nouveau_drm *drm = nouveau_drm(dev); 591 struct nouveau_drm *drm = nouveau_drm(dev);
592 struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo; 592 struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
593 struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; 593 struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
594 struct nouveau_page_flip_state *s; 594 struct nouveau_page_flip_state *s;
595 struct nouveau_channel *chan = NULL; 595 struct nouveau_channel *chan = drm->channel;
596 struct nouveau_fence *fence; 596 struct nouveau_fence *fence;
597 struct ttm_validate_buffer resv[2] = {
598 { .bo = &old_bo->bo },
599 { .bo = &new_bo->bo },
600 };
601 struct ww_acquire_ctx ticket;
602 LIST_HEAD(res);
603 int ret; 597 int ret;
604 598
605 if (!drm->channel) 599 if (!drm->channel)
@@ -609,26 +603,22 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
609 if (!s) 603 if (!s)
610 return -ENOMEM; 604 return -ENOMEM;
611 605
612 /* Choose the channel the flip will be handled in */ 606 /* synchronise rendering channel with the kernel's channel */
613 spin_lock(&old_bo->bo.bdev->fence_lock); 607 spin_lock(&new_bo->bo.bdev->fence_lock);
614 fence = new_bo->bo.sync_obj; 608 fence = nouveau_fence_ref(new_bo->bo.sync_obj);
615 if (fence) 609 spin_unlock(&new_bo->bo.bdev->fence_lock);
616 chan = fence->channel; 610 ret = nouveau_fence_sync(fence, chan);
617 if (!chan) 611 if (ret)
618 chan = drm->channel; 612 return ret;
619 spin_unlock(&old_bo->bo.bdev->fence_lock);
620 613
621 if (new_bo != old_bo) { 614 if (new_bo != old_bo) {
622 ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); 615 ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
623 if (ret) 616 if (ret)
624 goto fail_free; 617 goto fail_free;
625
626 list_add(&resv[1].head, &res);
627 } 618 }
628 list_add(&resv[0].head, &res);
629 619
630 mutex_lock(&chan->cli->mutex); 620 mutex_lock(&chan->cli->mutex);
631 ret = ttm_eu_reserve_buffers(&ticket, &res); 621 ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL);
632 if (ret) 622 if (ret)
633 goto fail_unpin; 623 goto fail_unpin;
634 624
@@ -640,12 +630,29 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
640 630
641 /* Emit a page flip */ 631 /* Emit a page flip */
642 if (nv_device(drm->device)->card_type >= NV_50) { 632 if (nv_device(drm->device)->card_type >= NV_50) {
643 ret = nv50_display_flip_next(crtc, fb, chan, 0); 633 ret = nv50_display_flip_next(crtc, fb, chan, swap_interval);
644 if (ret) 634 if (ret)
645 goto fail_unreserve; 635 goto fail_unreserve;
646 } else { 636 } else {
647 struct nv04_display *dispnv04 = nv04_display(dev); 637 struct nv04_display *dispnv04 = nv04_display(dev);
648 nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]); 638 int head = nouveau_crtc(crtc)->index;
639
640 if (swap_interval) {
641 ret = RING_SPACE(chan, 8);
642 if (ret)
643 goto fail_unreserve;
644
645 BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1);
646 OUT_RING (chan, 0);
647 BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1);
648 OUT_RING (chan, head);
649 BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1);
650 OUT_RING (chan, 0);
651 BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1);
652 OUT_RING (chan, 0);
653 }
654
655 nouveau_bo_ref(new_bo, &dispnv04->image[head]);
649 } 656 }
650 657
651 ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); 658 ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
@@ -656,14 +663,15 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
656 /* Update the crtc struct and cleanup */ 663 /* Update the crtc struct and cleanup */
657 crtc->fb = fb; 664 crtc->fb = fb;
658 665
659 ttm_eu_fence_buffer_objects(&ticket, &res, fence); 666 nouveau_bo_fence(old_bo, fence);
667 ttm_bo_unreserve(&old_bo->bo);
660 if (old_bo != new_bo) 668 if (old_bo != new_bo)
661 nouveau_bo_unpin(old_bo); 669 nouveau_bo_unpin(old_bo);
662 nouveau_fence_unref(&fence); 670 nouveau_fence_unref(&fence);
663 return 0; 671 return 0;
664 672
665fail_unreserve: 673fail_unreserve:
666 ttm_eu_backoff_reservation(&ticket, &res); 674 ttm_bo_unreserve(&old_bo->bo);
667fail_unpin: 675fail_unpin:
668 mutex_unlock(&chan->cli->mutex); 676 mutex_unlock(&chan->cli->mutex);
669 if (old_bo != new_bo) 677 if (old_bo != new_bo)
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index 690d5930ce32..984004d66a6d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -51,9 +51,11 @@ enum {
51 NvSubCtxSurf2D = 0, 51 NvSubCtxSurf2D = 0,
52 NvSubSw = 1, 52 NvSubSw = 1,
53 NvSubImageBlit = 2, 53 NvSubImageBlit = 2,
54 NvSub2D = 3,
55 NvSubGdiRect = 3, 54 NvSubGdiRect = 3,
56 NvSubCopy = 4, 55
56 NvSub2D = 3, /* DO NOT CHANGE - hardcoded for kepler gr fifo */
57 NvSubCopy = 4, /* DO NOT CHANGE - hardcoded for kepler gr fifo */
58 FermiSw = 5, /* DO NOT CHANGE (well.. 6/7 will work...) */
57}; 59};
58 60
59/* Object handles. */ 61/* Object handles. */
@@ -194,7 +196,6 @@ WIND_RING(struct nouveau_channel *chan)
194#define NV84_SUBCHAN_UEVENT 0x00000020 196#define NV84_SUBCHAN_UEVENT 0x00000020
195#define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024 197#define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024
196#define NV10_SUBCHAN_REF_CNT 0x00000050 198#define NV10_SUBCHAN_REF_CNT 0x00000050
197#define NVSW_SUBCHAN_PAGE_FLIP 0x00000054
198#define NV11_SUBCHAN_DMA_SEMAPHORE 0x00000060 199#define NV11_SUBCHAN_DMA_SEMAPHORE 0x00000060
199#define NV11_SUBCHAN_SEMAPHORE_OFFSET 0x00000064 200#define NV11_SUBCHAN_SEMAPHORE_OFFSET 0x00000064
200#define NV11_SUBCHAN_SEMAPHORE_ACQUIRE 0x00000068 201#define NV11_SUBCHAN_SEMAPHORE_ACQUIRE 0x00000068
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 2418b0de589e..7a3759f1c41a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -37,6 +37,7 @@
37#include <engine/device.h> 37#include <engine/device.h>
38#include <engine/disp.h> 38#include <engine/disp.h>
39#include <engine/fifo.h> 39#include <engine/fifo.h>
40#include <engine/software.h>
40 41
41#include <subdev/vm.h> 42#include <subdev/vm.h>
42 43
@@ -191,6 +192,32 @@ nouveau_accel_init(struct nouveau_drm *drm)
191 return; 192 return;
192 } 193 }
193 194
195 ret = nouveau_object_new(nv_object(drm), NVDRM_CHAN, NVDRM_NVSW,
196 nouveau_abi16_swclass(drm), NULL, 0, &object);
197 if (ret == 0) {
198 struct nouveau_software_chan *swch = (void *)object->parent;
199 ret = RING_SPACE(drm->channel, 2);
200 if (ret == 0) {
201 if (device->card_type < NV_C0) {
202 BEGIN_NV04(drm->channel, NvSubSw, 0, 1);
203 OUT_RING (drm->channel, NVDRM_NVSW);
204 } else
205 if (device->card_type < NV_E0) {
206 BEGIN_NVC0(drm->channel, FermiSw, 0, 1);
207 OUT_RING (drm->channel, 0x001f0000);
208 }
209 }
210 swch = (void *)object->parent;
211 swch->flip = nouveau_flip_complete;
212 swch->flip_data = drm->channel;
213 }
214
215 if (ret) {
216 NV_ERROR(drm, "failed to allocate software object, %d\n", ret);
217 nouveau_accel_fini(drm);
218 return;
219 }
220
194 if (device->card_type < NV_C0) { 221 if (device->card_type < NV_C0) {
195 ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0, 222 ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0,
196 &drm->notify); 223 &drm->notify);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index 71ed2dadae61..4b0fb6c66be9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -56,6 +56,7 @@ enum nouveau_drm_handle {
56 NVDRM_CONTROL = 0xdddddddc, 56 NVDRM_CONTROL = 0xdddddddc,
57 NVDRM_PUSH = 0xbbbb0000, /* |= client chid */ 57 NVDRM_PUSH = 0xbbbb0000, /* |= client chid */
58 NVDRM_CHAN = 0xcccc0000, /* |= client chid */ 58 NVDRM_CHAN = 0xcccc0000, /* |= client chid */
59 NVDRM_NVSW = 0x55550000,
59}; 60};
60 61
61struct nouveau_cli { 62struct nouveau_cli {
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 34b82711e7c8..40cf52e6d6d2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -306,7 +306,8 @@ nouveau_fence_unref(struct nouveau_fence **pfence)
306struct nouveau_fence * 306struct nouveau_fence *
307nouveau_fence_ref(struct nouveau_fence *fence) 307nouveau_fence_ref(struct nouveau_fence *fence)
308{ 308{
309 kref_get(&fence->kref); 309 if (fence)
310 kref_get(&fence->kref);
310 return fence; 311 return fence;
311} 312}
312 313
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 418a6177a653..78a27f8ad7d9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -106,8 +106,7 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
106 106
107 if (mapped) { 107 if (mapped) {
108 spin_lock(&nvbo->bo.bdev->fence_lock); 108 spin_lock(&nvbo->bo.bdev->fence_lock);
109 if (nvbo->bo.sync_obj) 109 fence = nouveau_fence_ref(nvbo->bo.sync_obj);
110 fence = nouveau_fence_ref(nvbo->bo.sync_obj);
111 spin_unlock(&nvbo->bo.bdev->fence_lock); 110 spin_unlock(&nvbo->bo.bdev->fence_lock);
112 } 111 }
113 112
@@ -309,7 +308,8 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence,
309 list_for_each_safe(entry, tmp, list) { 308 list_for_each_safe(entry, tmp, list) {
310 nvbo = list_entry(entry, struct nouveau_bo, entry); 309 nvbo = list_entry(entry, struct nouveau_bo, entry);
311 310
312 nouveau_bo_fence(nvbo, fence); 311 if (likely(fence))
312 nouveau_bo_fence(nvbo, fence);
313 313
314 if (unlikely(nvbo->validate_mapped)) { 314 if (unlikely(nvbo->validate_mapped)) {
315 ttm_bo_kunmap(&nvbo->kmap); 315 ttm_bo_kunmap(&nvbo->kmap);
@@ -438,8 +438,7 @@ validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo)
438 int ret = 0; 438 int ret = 0;
439 439
440 spin_lock(&nvbo->bo.bdev->fence_lock); 440 spin_lock(&nvbo->bo.bdev->fence_lock);
441 if (nvbo->bo.sync_obj) 441 fence = nouveau_fence_ref(nvbo->bo.sync_obj);
442 fence = nouveau_fence_ref(nvbo->bo.sync_obj);
443 spin_unlock(&nvbo->bo.bdev->fence_lock); 442 spin_unlock(&nvbo->bo.bdev->fence_lock);
444 443
445 if (fence) { 444 if (fence) {
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index 77dcc9c50777..8fe32bbed99a 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -255,6 +255,12 @@ nv04_fbcon_accel_init(struct fb_info *info)
255 OUT_RING(chan, NvCtxSurf2D); 255 OUT_RING(chan, NvCtxSurf2D);
256 BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1); 256 BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1);
257 OUT_RING(chan, 3); 257 OUT_RING(chan, 3);
258 if (device->chipset >= 0x11 /*XXX: oclass == 0x009f*/) {
259 BEGIN_NV04(chan, NvSubImageBlit, 0x0120, 3);
260 OUT_RING(chan, 0);
261 OUT_RING(chan, 1);
262 OUT_RING(chan, 2);
263 }
258 264
259 BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1); 265 BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1);
260 OUT_RING(chan, NvGdiRect); 266 OUT_RING(chan, NvGdiRect);