Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux...
authorDave Airlie <airlied@redhat.com>
Fri, 15 Nov 2013 02:24:40 +0000 (12:24 +1000)
committerDave Airlie <airlied@redhat.com>
Fri, 15 Nov 2013 02:24:40 +0000 (12:24 +1000)
- 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

16 files changed:
drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
drivers/gpu/drm/nouveau/core/subdev/therm/base.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_dma.h
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nv04_fbcon.c

index 606598f226fc27ce69b85ce2cd00280a237839ef..8d06eef2b9ee02f7b3d895c8d7a37bfd6e022924 100644 (file)
@@ -256,7 +256,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
index e21453a949710f4eb82747d7f1d9c1f2eede55ec..9ac94d4e5646d2cd24579f3b47777f2e17f5e9fe 100644 (file)
@@ -494,13 +494,6 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
        u32 mthd = (addr & 0x00003ffc);
        u32 show = stat;
 
-       if (stat & 0x00200000) {
-               if (mthd == 0x0054) {
-                       if (!nvc0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
-                               show &= ~0x00200000;
-               }
-       }
-
        if (stat & 0x00800000) {
                if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
                        show &= ~0x00800000;
index fcd449e5aba7b775816b5c506690b96ecbac1605..04f412922d2d43f5a5fbce11185fc2f9f4196e7e 100644 (file)
@@ -481,13 +481,6 @@ nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit)
        u32 mthd = (addr & 0x00003ffc);
        u32 show = stat;
 
-       if (stat & 0x00200000) {
-               if (mthd == 0x0054) {
-                       if (!nve0_fifo_swmthd(priv, chid, 0x0500, 0x00000000))
-                               show &= ~0x00200000;
-               }
-       }
-
        if (stat & 0x00800000) {
                if (!nve0_fifo_swmthd(priv, chid, mthd, data))
                        show &= ~0x00800000;
index 64dca260912ff645c8dce1a338c56cb9ceadd1ef..fe67415c3e175ce17de2be2e8ba7e03570d97cf7 100644 (file)
@@ -1039,7 +1039,7 @@ nvc0_grctx_generate_r406800(struct nvc0_graph_priv *priv)
                        } while (!tpcnr[gpc]);
                        tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
 
-                       tpc_set |= 1 << ((gpc * 8) + tpc);
+                       tpc_set |= 1ULL << ((gpc * 8) + tpc);
                }
 
                nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set));
index 9908f1f05a00f4f3937eb6bd29b555b274d814da..d4fd3bc9c66f3904303acb165544a928b9c68885 100644 (file)
@@ -32,6 +32,11 @@ nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2],
        struct nouveau_subdev *subdev = nv_subdev(ppwr);
        u32 addr;
 
+       /* wait for a free slot in the fifo */
+       addr  = nv_rd32(ppwr, 0x10a4a0);
+       if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8))
+               return -EBUSY;
+
        /* we currently only support a single process at a time waiting
         * on a synchronous reply, take the PPWR mutex and tell the
         * receive handler what we're waiting for
@@ -42,11 +47,6 @@ nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2],
                ppwr->recv.process = process;
        }
 
-       /* wait for a free slot in the fifo */
-       addr  = nv_rd32(ppwr, 0x10a4a0);
-       if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8))
-               return -EBUSY;
-
        /* acquire data segment access */
        do {
                nv_wr32(ppwr, 0x10a580, 0x00000001);
index 21b2b3021fadf0f49f1e0b8775acb6ffb264561a..80e584a1bd1cf4e4d6a32a8e3cbfd79739acd1e3 100644 (file)
@@ -117,7 +117,8 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
                    priv->fan->bios.linear_max_temp) {
                        duty = nouveau_therm_update_linear(therm);
                } else {
-                       duty = priv->cstate;
+                       if (priv->cstate)
+                               duty = priv->cstate;
                        poll = false;
                }
                immd = false;
index 3621e7f23477da53b7af04edc60af11fe6f5d1ee..6828d81ed7b99daea875ffd06c4dd399d4aa05dd 100644 (file)
@@ -298,7 +298,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
        else
                init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
 
-       if (device->card_type < NV_C0) {
+       if (device->card_type < NV_10) {
                init->subchan[0].handle = 0x00000000;
                init->subchan[0].grclass = 0x0000;
                init->subchan[1].handle = NvSw;
index 949ab0cbc4aba904c9d692c15c998b19b9589a3c..c0fde6b9393cb24fa602e838fdf145657d059d05 100644 (file)
@@ -98,12 +98,7 @@ nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile,
 
        if (tile) {
                spin_lock(&drm->tile.lock);
-               if (fence) {
-                       /* Mark it as pending. */
-                       tile->fence = fence;
-                       nouveau_fence_ref(fence);
-               }
-
+               tile->fence = nouveau_fence_ref(fence);
                tile->used = false;
                spin_unlock(&drm->tile.lock);
        }
@@ -1462,14 +1457,12 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
 void
 nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence)
 {
+       struct nouveau_fence *new_fence = nouveau_fence_ref(fence);
        struct nouveau_fence *old_fence = NULL;
 
-       if (likely(fence))
-               nouveau_fence_ref(fence);
-
        spin_lock(&nvbo->bo.bdev->fence_lock);
        old_fence = nvbo->bo.sync_obj;
-       nvbo->bo.sync_obj = fence;
+       nvbo->bo.sync_obj = new_fence;
        spin_unlock(&nvbo->bo.bdev->fence_lock);
 
        nouveau_fence_unref(&old_fence);
@@ -1552,7 +1545,8 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
 
        if (nvbo->bo.mem.mem_type == TTM_PL_VRAM)
                nouveau_vm_map(vma, nvbo->bo.mem.mm_node);
-       else if (nvbo->bo.mem.mem_type == TTM_PL_TT) {
+       else if (nvbo->bo.mem.mem_type == TTM_PL_TT &&
+                nvbo->page_shift == vma->vm->vmm->spg_shift) {
                if (node->sg)
                        nouveau_vm_map_sg_table(vma, 0, size, node);
                else
index e84f4c32331bf291f7cd3eeb3f253cd8fd543f37..cc5152be2cf121a0901d323bf41b57886b56b27a 100644 (file)
@@ -346,22 +346,17 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
        for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
                OUT_RING(chan, 0x00000000);
 
-       /* allocate software object class (used for fences on <= nv05, and
-        * to signal flip completion), bind it to a subchannel.
-        */
-       if ((device->card_type < NV_E0) || gart /* nve0: want_nvsw */) {
+       /* allocate software object class (used for fences on <= nv05) */
+       if (device->card_type < NV_10) {
                ret = nouveau_object_new(nv_object(client), chan->handle,
-                                        NvSw, nouveau_abi16_swclass(chan->drm),
-                                        NULL, 0, &object);
+                                        NvSw, 0x006e, NULL, 0, &object);
                if (ret)
                        return ret;
 
                swch = (void *)object->parent;
                swch->flip = nouveau_flip_complete;
                swch->flip_data = chan;
-       }
 
-       if (device->card_type < NV_C0) {
                ret = RING_SPACE(chan, 2);
                if (ret)
                        return ret;
index 44642d9094e688679eb3337b5bdb5b0c8038885a..7809d92183c4236c9f1f937ea6cde6a39e780063 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
-#include <drm/ttm/ttm_execbuf_util.h>
 
 #include "nouveau_fbcon.h"
 #include "dispnv04/hw.h"
@@ -399,6 +398,11 @@ nouveau_display_create(struct drm_device *dev)
        dev->mode_config.preferred_depth = 24;
        dev->mode_config.prefer_shadow = 1;
 
+       if (nv_device(drm->device)->chipset < 0x11)
+               dev->mode_config.async_page_flip = false;
+       else
+               dev->mode_config.async_page_flip = true;
+
        drm_kms_helper_poll_init(dev);
        drm_kms_helper_poll_disable(dev);
 
@@ -555,19 +559,15 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
                goto fail;
 
        /* Emit the pageflip */
-       ret = RING_SPACE(chan, 3);
+       ret = RING_SPACE(chan, 2);
        if (ret)
                goto fail;
 
-       if (nv_device(drm->device)->card_type < NV_C0) {
+       if (nv_device(drm->device)->card_type < NV_C0)
                BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
-               OUT_RING  (chan, 0x00000000);
-               OUT_RING  (chan, 0x00000000);
-       } else {
-               BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
-               OUT_RING  (chan, 0);
-               BEGIN_IMC0(chan, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000);
-       }
+       else
+               BEGIN_NVC0(chan, FermiSw, NV_SW_PAGE_FLIP, 1);
+       OUT_RING  (chan, 0x00000000);
        FIRE_RING (chan);
 
        ret = nouveau_fence_new(chan, false, pfence);
@@ -584,22 +584,16 @@ fail:
 
 int
 nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-                      struct drm_pending_vblank_event *event,
-                      uint32_t page_flip_flags)
+                      struct drm_pending_vblank_event *event, u32 flags)
 {
+       const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
        struct drm_device *dev = crtc->dev;
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
        struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
        struct nouveau_page_flip_state *s;
-       struct nouveau_channel *chan = NULL;
+       struct nouveau_channel *chan = drm->channel;
        struct nouveau_fence *fence;
-       struct ttm_validate_buffer resv[2] = {
-               { .bo = &old_bo->bo },
-               { .bo = &new_bo->bo },
-       };
-       struct ww_acquire_ctx ticket;
-       LIST_HEAD(res);
        int ret;
 
        if (!drm->channel)
@@ -609,26 +603,22 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        if (!s)
                return -ENOMEM;
 
-       /* Choose the channel the flip will be handled in */
-       spin_lock(&old_bo->bo.bdev->fence_lock);
-       fence = new_bo->bo.sync_obj;
-       if (fence)
-               chan = fence->channel;
-       if (!chan)
-               chan = drm->channel;
-       spin_unlock(&old_bo->bo.bdev->fence_lock);
+       /* synchronise rendering channel with the kernel's channel */
+       spin_lock(&new_bo->bo.bdev->fence_lock);
+       fence = nouveau_fence_ref(new_bo->bo.sync_obj);
+       spin_unlock(&new_bo->bo.bdev->fence_lock);
+       ret = nouveau_fence_sync(fence, chan);
+       if (ret)
+               return ret;
 
        if (new_bo != old_bo) {
                ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
                if (ret)
                        goto fail_free;
-
-               list_add(&resv[1].head, &res);
        }
-       list_add(&resv[0].head, &res);
 
        mutex_lock(&chan->cli->mutex);
-       ret = ttm_eu_reserve_buffers(&ticket, &res);
+       ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL);
        if (ret)
                goto fail_unpin;
 
@@ -640,12 +630,29 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 
        /* Emit a page flip */
        if (nv_device(drm->device)->card_type >= NV_50) {
-               ret = nv50_display_flip_next(crtc, fb, chan, 0);
+               ret = nv50_display_flip_next(crtc, fb, chan, swap_interval);
                if (ret)
                        goto fail_unreserve;
        } else {
                struct nv04_display *dispnv04 = nv04_display(dev);
-               nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]);
+               int head = nouveau_crtc(crtc)->index;
+
+               if (swap_interval) {
+                       ret = RING_SPACE(chan, 8);
+                       if (ret)
+                               goto fail_unreserve;
+
+                       BEGIN_NV04(chan, NvSubImageBlit, 0x012c, 1);
+                       OUT_RING  (chan, 0);
+                       BEGIN_NV04(chan, NvSubImageBlit, 0x0134, 1);
+                       OUT_RING  (chan, head);
+                       BEGIN_NV04(chan, NvSubImageBlit, 0x0100, 1);
+                       OUT_RING  (chan, 0);
+                       BEGIN_NV04(chan, NvSubImageBlit, 0x0130, 1);
+                       OUT_RING  (chan, 0);
+               }
+
+               nouveau_bo_ref(new_bo, &dispnv04->image[head]);
        }
 
        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,
        /* Update the crtc struct and cleanup */
        crtc->fb = fb;
 
-       ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+       nouveau_bo_fence(old_bo, fence);
+       ttm_bo_unreserve(&old_bo->bo);
        if (old_bo != new_bo)
                nouveau_bo_unpin(old_bo);
        nouveau_fence_unref(&fence);
        return 0;
 
 fail_unreserve:
-       ttm_eu_backoff_reservation(&ticket, &res);
+       ttm_bo_unreserve(&old_bo->bo);
 fail_unpin:
        mutex_unlock(&chan->cli->mutex);
        if (old_bo != new_bo)
index 690d5930ce32225a382a472ebc90ac4b0fdb972b..984004d66a6d313d1934230bc654c091a77b5f8f 100644 (file)
@@ -51,9 +51,11 @@ enum {
        NvSubCtxSurf2D  = 0,
        NvSubSw         = 1,
        NvSubImageBlit  = 2,
-       NvSub2D         = 3,
        NvSubGdiRect    = 3,
-       NvSubCopy       = 4,
+
+       NvSub2D         = 3, /* DO NOT CHANGE - hardcoded for kepler gr fifo */
+       NvSubCopy       = 4, /* DO NOT CHANGE - hardcoded for kepler gr fifo */
+       FermiSw         = 5, /* DO NOT CHANGE (well.. 6/7 will work...) */
 };
 
 /* Object handles. */
@@ -194,7 +196,6 @@ WIND_RING(struct nouveau_channel *chan)
 #define NV84_SUBCHAN_UEVENT                                          0x00000020
 #define NV84_SUBCHAN_WRCACHE_FLUSH                                   0x00000024
 #define NV10_SUBCHAN_REF_CNT                                         0x00000050
-#define NVSW_SUBCHAN_PAGE_FLIP                                       0x00000054
 #define NV11_SUBCHAN_DMA_SEMAPHORE                                   0x00000060
 #define NV11_SUBCHAN_SEMAPHORE_OFFSET                                0x00000064
 #define NV11_SUBCHAN_SEMAPHORE_ACQUIRE                               0x00000068
index 2418b0de589eb631b4fc7e3297c78bdce5557e45..7a3759f1c41a67bac6b48cdcfd5b10b5ac30ae39 100644 (file)
@@ -37,6 +37,7 @@
 #include <engine/device.h>
 #include <engine/disp.h>
 #include <engine/fifo.h>
+#include <engine/software.h>
 
 #include <subdev/vm.h>
 
@@ -191,6 +192,32 @@ nouveau_accel_init(struct nouveau_drm *drm)
                return;
        }
 
+       ret = nouveau_object_new(nv_object(drm), NVDRM_CHAN, NVDRM_NVSW,
+                                nouveau_abi16_swclass(drm), NULL, 0, &object);
+       if (ret == 0) {
+               struct nouveau_software_chan *swch = (void *)object->parent;
+               ret = RING_SPACE(drm->channel, 2);
+               if (ret == 0) {
+                       if (device->card_type < NV_C0) {
+                               BEGIN_NV04(drm->channel, NvSubSw, 0, 1);
+                               OUT_RING  (drm->channel, NVDRM_NVSW);
+                       } else
+                       if (device->card_type < NV_E0) {
+                               BEGIN_NVC0(drm->channel, FermiSw, 0, 1);
+                               OUT_RING  (drm->channel, 0x001f0000);
+                       }
+               }
+               swch = (void *)object->parent;
+               swch->flip = nouveau_flip_complete;
+               swch->flip_data = drm->channel;
+       }
+
+       if (ret) {
+               NV_ERROR(drm, "failed to allocate software object, %d\n", ret);
+               nouveau_accel_fini(drm);
+               return;
+       }
+
        if (device->card_type < NV_C0) {
                ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0,
                                        &drm->notify);
index 71ed2dadae61cc7f6e1789fbf58b318538694d49..4b0fb6c66be918857bc6529b3a7c5a7c7a49a498 100644 (file)
@@ -56,6 +56,7 @@ enum nouveau_drm_handle {
        NVDRM_CONTROL = 0xdddddddc,
        NVDRM_PUSH    = 0xbbbb0000, /* |= client chid */
        NVDRM_CHAN    = 0xcccc0000, /* |= client chid */
+       NVDRM_NVSW    = 0x55550000,
 };
 
 struct nouveau_cli {
index 34b82711e7c810d96d624d7a7ec362c7f633e285..40cf52e6d6d21ffb818f70b2b01be3b5f5e02b95 100644 (file)
@@ -306,7 +306,8 @@ nouveau_fence_unref(struct nouveau_fence **pfence)
 struct nouveau_fence *
 nouveau_fence_ref(struct nouveau_fence *fence)
 {
-       kref_get(&fence->kref);
+       if (fence)
+               kref_get(&fence->kref);
        return fence;
 }
 
index 418a6177a65330a5074a16565cce9a40784f3c01..78a27f8ad7d97be653a63506bb60bd9c7b518252 100644 (file)
@@ -106,8 +106,7 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
 
        if (mapped) {
                spin_lock(&nvbo->bo.bdev->fence_lock);
-               if (nvbo->bo.sync_obj)
-                       fence = nouveau_fence_ref(nvbo->bo.sync_obj);
+               fence = nouveau_fence_ref(nvbo->bo.sync_obj);
                spin_unlock(&nvbo->bo.bdev->fence_lock);
        }
 
@@ -309,7 +308,8 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence,
        list_for_each_safe(entry, tmp, list) {
                nvbo = list_entry(entry, struct nouveau_bo, entry);
 
-               nouveau_bo_fence(nvbo, fence);
+               if (likely(fence))
+                       nouveau_bo_fence(nvbo, fence);
 
                if (unlikely(nvbo->validate_mapped)) {
                        ttm_bo_kunmap(&nvbo->kmap);
@@ -438,8 +438,7 @@ validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo)
        int ret = 0;
 
        spin_lock(&nvbo->bo.bdev->fence_lock);
-       if (nvbo->bo.sync_obj)
-               fence = nouveau_fence_ref(nvbo->bo.sync_obj);
+       fence = nouveau_fence_ref(nvbo->bo.sync_obj);
        spin_unlock(&nvbo->bo.bdev->fence_lock);
 
        if (fence) {
index 77dcc9c50777377945cf6cee1867ab12c0a7cc8e..8fe32bbed99a8352eec8cef3a53bf77d0fc07662 100644 (file)
@@ -255,6 +255,12 @@ nv04_fbcon_accel_init(struct fb_info *info)
        OUT_RING(chan, NvCtxSurf2D);
        BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1);
        OUT_RING(chan, 3);
+       if (device->chipset >= 0x11 /*XXX: oclass == 0x009f*/) {
+               BEGIN_NV04(chan, NvSubImageBlit, 0x0120, 3);
+               OUT_RING(chan, 0);
+               OUT_RING(chan, 1);
+               OUT_RING(chan, 2);
+       }
 
        BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1);
        OUT_RING(chan, NvGdiRect);