OSDN Git Service

drm/nouveau/kms/nv04-nv4x: move a bunch of pre-nv50 page flip code to dispnv04
authorBen Skeggs <bskeggs@redhat.com>
Tue, 12 Feb 2019 12:28:13 +0000 (22:28 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 19 Feb 2019 22:59:59 +0000 (08:59 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/dispnv04/crtc.c
drivers/gpu/drm/nouveau/dispnv04/disp.c
drivers/gpu/drm/nouveau/dispnv04/disp.h
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_display.h
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fence.h

index 2c569e2..f22f010 100644 (file)
@@ -40,6 +40,7 @@
 #include "nvreg.h"
 #include "nouveau_fbcon.h"
 #include "disp.h"
+#include "nouveau_dma.h"
 
 #include <subdev/bios/pll.h>
 #include <subdev/clk.h>
@@ -1077,12 +1078,223 @@ nouveau_crtc_set_config(struct drm_mode_set *set,
        return ret;
 }
 
+struct nv04_page_flip_state {
+       struct list_head head;
+       struct drm_pending_vblank_event *event;
+       struct drm_crtc *crtc;
+       int bpp, pitch;
+       u64 offset;
+};
+
+static int
+nv04_finish_page_flip(struct nouveau_channel *chan,
+                     struct nv04_page_flip_state *ps)
+{
+       struct nouveau_fence_chan *fctx = chan->fence;
+       struct nouveau_drm *drm = chan->drm;
+       struct drm_device *dev = drm->dev;
+       struct nv04_page_flip_state *s;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       if (list_empty(&fctx->flip)) {
+               NV_ERROR(drm, "unexpected pageflip\n");
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+               return -EINVAL;
+       }
+
+       s = list_first_entry(&fctx->flip, struct nv04_page_flip_state, head);
+       if (s->event) {
+               drm_crtc_arm_vblank_event(s->crtc, s->event);
+       } else {
+               /* Give up ownership of vblank for page-flipped crtc */
+               drm_crtc_vblank_put(s->crtc);
+       }
+
+       list_del(&s->head);
+       if (ps)
+               *ps = *s;
+       kfree(s);
+
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+       return 0;
+}
+
+int
+nv04_flip_complete(struct nvif_notify *notify)
+{
+       struct nouveau_cli *cli = (void *)notify->object->client;
+       struct nouveau_drm *drm = cli->drm;
+       struct nouveau_channel *chan = drm->channel;
+       struct nv04_page_flip_state state;
+
+       if (!nv04_finish_page_flip(chan, &state)) {
+               nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc),
+                                state.offset + state.crtc->y *
+                                state.pitch + state.crtc->x *
+                                state.bpp / 8);
+       }
+
+       return NVIF_NOTIFY_KEEP;
+}
+
+static int
+nv04_page_flip_emit(struct nouveau_channel *chan,
+                   struct nouveau_bo *old_bo,
+                   struct nouveau_bo *new_bo,
+                   struct nv04_page_flip_state *s,
+                   struct nouveau_fence **pfence)
+{
+       struct nouveau_fence_chan *fctx = chan->fence;
+       struct nouveau_drm *drm = chan->drm;
+       struct drm_device *dev = drm->dev;
+       unsigned long flags;
+       int ret;
+
+       /* Queue it to the pending list */
+       spin_lock_irqsave(&dev->event_lock, flags);
+       list_add_tail(&s->head, &fctx->flip);
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       /* Synchronize with the old framebuffer */
+       ret = nouveau_fence_sync(old_bo, chan, false, false);
+       if (ret)
+               goto fail;
+
+       /* Emit the pageflip */
+       ret = RING_SPACE(chan, 2);
+       if (ret)
+               goto fail;
+
+       BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
+       OUT_RING  (chan, 0x00000000);
+       FIRE_RING (chan);
+
+       ret = nouveau_fence_new(chan, false, pfence);
+       if (ret)
+               goto fail;
+
+       return 0;
+fail:
+       spin_lock_irqsave(&dev->event_lock, flags);
+       list_del(&s->head);
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+       return ret;
+}
+
+static int
+nv04_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
+                   struct drm_pending_vblank_event *event, u32 flags,
+                   struct drm_modeset_acquire_ctx *ctx)
+{
+       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->primary->fb)->nvbo;
+       struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
+       struct nv04_page_flip_state *s;
+       struct nouveau_channel *chan;
+       struct nouveau_cli *cli;
+       struct nouveau_fence *fence;
+       struct nv04_display *dispnv04 = nv04_display(dev);
+       int head = nouveau_crtc(crtc)->index;
+       int ret;
+
+       chan = drm->channel;
+       if (!chan)
+               return -ENODEV;
+       cli = (void *)chan->user.client;
+
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       if (new_bo != old_bo) {
+               ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true);
+               if (ret)
+                       goto fail_free;
+       }
+
+       mutex_lock(&cli->mutex);
+       ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL);
+       if (ret)
+               goto fail_unpin;
+
+       /* synchronise rendering channel with the kernel's channel */
+       ret = nouveau_fence_sync(new_bo, chan, false, true);
+       if (ret) {
+               ttm_bo_unreserve(&new_bo->bo);
+               goto fail_unpin;
+       }
+
+       if (new_bo != old_bo) {
+               ttm_bo_unreserve(&new_bo->bo);
+
+               ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL);
+               if (ret)
+                       goto fail_unpin;
+       }
+
+       /* Initialize a page flip struct */
+       *s = (struct nv04_page_flip_state)
+               { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0],
+                 new_bo->bo.offset };
+
+       /* Keep vblanks on during flip, for the target crtc of this flip */
+       drm_crtc_vblank_get(crtc);
+
+       /* Emit a page flip */
+       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 = nv04_page_flip_emit(chan, old_bo, new_bo, s, &fence);
+       if (ret)
+               goto fail_unreserve;
+       mutex_unlock(&cli->mutex);
+
+       /* Update the crtc struct and cleanup */
+       crtc->primary->fb = fb;
+
+       nouveau_bo_fence(old_bo, fence, false);
+       ttm_bo_unreserve(&old_bo->bo);
+       if (old_bo != new_bo)
+               nouveau_bo_unpin(old_bo);
+       nouveau_fence_unref(&fence);
+       return 0;
+
+fail_unreserve:
+       drm_crtc_vblank_put(crtc);
+       ttm_bo_unreserve(&old_bo->bo);
+fail_unpin:
+       mutex_unlock(&cli->mutex);
+       if (old_bo != new_bo)
+               nouveau_bo_unpin(new_bo);
+fail_free:
+       kfree(s);
+       return ret;
+}
+
 static const struct drm_crtc_funcs nv04_crtc_funcs = {
        .cursor_set = nv04_crtc_cursor_set,
        .cursor_move = nv04_crtc_cursor_move,
        .gamma_set = nv_crtc_gamma_set,
        .set_config = nouveau_crtc_set_config,
-       .page_flip = nouveau_crtc_page_flip,
+       .page_flip = nv04_crtc_page_flip,
        .destroy = nv_crtc_destroy,
 };
 
index f2abae3..bda02f6 100644 (file)
 #include "nouveau_encoder.h"
 #include "nouveau_connector.h"
 
+#include <nvif/if0004.h>
+
 static void
 nv04_display_fini(struct drm_device *dev)
 {
+       struct nv04_display *disp = nv04_display(dev);
+
+       /* Disable flip completion events. */
+       nvif_notify_put(&disp->flip);
+
        /* Disable vblank interrupts. */
        NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
        if (nv_two_heads(dev))
@@ -43,6 +50,7 @@ nv04_display_fini(struct drm_device *dev)
 static int
 nv04_display_init(struct drm_device *dev)
 {
+       struct nv04_display *disp = nv04_display(dev);
        struct nouveau_encoder *encoder;
        struct nouveau_crtc *crtc;
 
@@ -60,6 +68,8 @@ nv04_display_init(struct drm_device *dev)
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head)
                encoder->enc_save(&encoder->base.base);
 
+       /* Enable flip completion events. */
+       nvif_notify_get(&disp->flip);
        return 0;
 }
 
@@ -80,6 +90,8 @@ nv04_display_destroy(struct drm_device *dev)
 
        nouveau_hw_save_vga_fonts(dev, 0);
 
+       nvif_notify_fini(&disp->flip);
+
        nouveau_display(dev)->priv = NULL;
        kfree(disp);
 
@@ -113,6 +125,13 @@ nv04_display_create(struct drm_device *dev)
        /* Pre-nv50 doesn't support atomic, so don't expose the ioctls */
        dev->driver->driver_features &= ~DRIVER_ATOMIC;
 
+       /* Request page flip completion event. */
+       if (drm->nvsw.client) {
+               nvif_notify_init(&drm->nvsw, nv04_flip_complete,
+                                false, NV04_NVSW_NTFY_UEVENT,
+                                NULL, 0, 0, &disp->flip);
+       }
+
        nouveau_hw_save_vga_fonts(dev, 1);
 
        nv04_crtc_create(dev, 0);
index 91bbc0c..c6ed20a 100644 (file)
@@ -82,6 +82,7 @@ struct nv04_display {
        uint32_t saved_vga_font[4][16384];
        uint32_t dac_users[4];
        struct nouveau_bo *image[2];
+       struct nvif_notify flip;
 };
 
 static inline struct nv04_display *
@@ -173,4 +174,5 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table,
        );
 }
 
+int nv04_flip_complete(struct nvif_notify *);
 #endif
index 56b6ac1..1acf035 100644 (file)
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_probe_helper.h>
 
-#include <nvif/class.h>
-
 #include "nouveau_fbcon.h"
-#include "dispnv04/hw.h"
 #include "nouveau_crtc.h"
-#include "nouveau_dma.h"
 #include "nouveau_gem.h"
 #include "nouveau_connector.h"
 #include "nv50_display.h"
 
-#include "nouveau_fence.h"
-
+#include <nvif/class.h>
 #include <nvif/cl0046.h>
 #include <nvif/event.h>
 
@@ -415,7 +410,6 @@ int
 nouveau_display_init(struct drm_device *dev)
 {
        struct nouveau_display *disp = nouveau_display(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
        struct drm_connector *connector;
        struct drm_connector_list_iter conn_iter;
        int ret;
@@ -437,8 +431,6 @@ nouveau_display_init(struct drm_device *dev)
        }
        drm_connector_list_iter_end(&conn_iter);
 
-       /* enable flip completion events */
-       nvif_notify_get(&drm->flip);
        return ret;
 }
 
@@ -457,9 +449,6 @@ nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
                        drm_helper_force_disable_all(dev);
        }
 
-       /* disable flip completion events */
-       nvif_notify_put(&drm->flip);
-
        /* disable hotplug interrupts */
        drm_connector_list_iter_begin(dev, &conn_iter);
        nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
@@ -738,208 +727,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
        }
 }
 
-static int
-nouveau_page_flip_emit(struct nouveau_channel *chan,
-                      struct nouveau_bo *old_bo,
-                      struct nouveau_bo *new_bo,
-                      struct nouveau_page_flip_state *s,
-                      struct nouveau_fence **pfence)
-{
-       struct nouveau_fence_chan *fctx = chan->fence;
-       struct nouveau_drm *drm = chan->drm;
-       struct drm_device *dev = drm->dev;
-       unsigned long flags;
-       int ret;
-
-       /* Queue it to the pending list */
-       spin_lock_irqsave(&dev->event_lock, flags);
-       list_add_tail(&s->head, &fctx->flip);
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-
-       /* Synchronize with the old framebuffer */
-       ret = nouveau_fence_sync(old_bo, chan, false, false);
-       if (ret)
-               goto fail;
-
-       /* Emit the pageflip */
-       ret = RING_SPACE(chan, 2);
-       if (ret)
-               goto fail;
-
-       BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
-       OUT_RING  (chan, 0x00000000);
-       FIRE_RING (chan);
-
-       ret = nouveau_fence_new(chan, false, pfence);
-       if (ret)
-               goto fail;
-
-       return 0;
-fail:
-       spin_lock_irqsave(&dev->event_lock, flags);
-       list_del(&s->head);
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-       return ret;
-}
-
-int
-nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-                      struct drm_pending_vblank_event *event, u32 flags,
-                      struct drm_modeset_acquire_ctx *ctx)
-{
-       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->primary->fb)->nvbo;
-       struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
-       struct nouveau_page_flip_state *s;
-       struct nouveau_channel *chan;
-       struct nouveau_cli *cli;
-       struct nouveau_fence *fence;
-       struct nv04_display *dispnv04 = nv04_display(dev);
-       int head = nouveau_crtc(crtc)->index;
-       int ret;
-
-       chan = drm->channel;
-       if (!chan)
-               return -ENODEV;
-       cli = (void *)chan->user.client;
-
-       s = kzalloc(sizeof(*s), GFP_KERNEL);
-       if (!s)
-               return -ENOMEM;
-
-       if (new_bo != old_bo) {
-               ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM, true);
-               if (ret)
-                       goto fail_free;
-       }
-
-       mutex_lock(&cli->mutex);
-       ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL);
-       if (ret)
-               goto fail_unpin;
-
-       /* synchronise rendering channel with the kernel's channel */
-       ret = nouveau_fence_sync(new_bo, chan, false, true);
-       if (ret) {
-               ttm_bo_unreserve(&new_bo->bo);
-               goto fail_unpin;
-       }
-
-       if (new_bo != old_bo) {
-               ttm_bo_unreserve(&new_bo->bo);
-
-               ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL);
-               if (ret)
-                       goto fail_unpin;
-       }
-
-       /* Initialize a page flip struct */
-       *s = (struct nouveau_page_flip_state)
-               { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0],
-                 new_bo->bo.offset };
-
-       /* Keep vblanks on during flip, for the target crtc of this flip */
-       drm_crtc_vblank_get(crtc);
-
-       /* Emit a page flip */
-       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);
-       if (ret)
-               goto fail_unreserve;
-       mutex_unlock(&cli->mutex);
-
-       /* Update the crtc struct and cleanup */
-       crtc->primary->fb = fb;
-
-       nouveau_bo_fence(old_bo, fence, false);
-       ttm_bo_unreserve(&old_bo->bo);
-       if (old_bo != new_bo)
-               nouveau_bo_unpin(old_bo);
-       nouveau_fence_unref(&fence);
-       return 0;
-
-fail_unreserve:
-       drm_crtc_vblank_put(crtc);
-       ttm_bo_unreserve(&old_bo->bo);
-fail_unpin:
-       mutex_unlock(&cli->mutex);
-       if (old_bo != new_bo)
-               nouveau_bo_unpin(new_bo);
-fail_free:
-       kfree(s);
-       return ret;
-}
-
-int
-nouveau_finish_page_flip(struct nouveau_channel *chan,
-                        struct nouveau_page_flip_state *ps)
-{
-       struct nouveau_fence_chan *fctx = chan->fence;
-       struct nouveau_drm *drm = chan->drm;
-       struct drm_device *dev = drm->dev;
-       struct nouveau_page_flip_state *s;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->event_lock, flags);
-
-       if (list_empty(&fctx->flip)) {
-               NV_ERROR(drm, "unexpected pageflip\n");
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-               return -EINVAL;
-       }
-
-       s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
-       if (s->event) {
-               drm_crtc_arm_vblank_event(s->crtc, s->event);
-       } else {
-               /* Give up ownership of vblank for page-flipped crtc */
-               drm_crtc_vblank_put(s->crtc);
-       }
-
-       list_del(&s->head);
-       if (ps)
-               *ps = *s;
-       kfree(s);
-
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-       return 0;
-}
-
-int
-nouveau_flip_complete(struct nvif_notify *notify)
-{
-       struct nouveau_drm *drm = container_of(notify, typeof(*drm), flip);
-       struct nouveau_channel *chan = drm->channel;
-       struct nouveau_page_flip_state state;
-
-       if (!nouveau_finish_page_flip(chan, &state)) {
-               nv_set_crtc_base(drm->dev, drm_crtc_index(state.crtc),
-                                state.offset + state.crtc->y *
-                                state.pitch + state.crtc->x *
-                                state.bpp / 8);
-       }
-
-       return NVIF_NOTIFY_KEEP;
-}
-
 int
 nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
                            struct drm_mode_create_dumb *args)
index eb77e41..2676876 100644 (file)
@@ -25,14 +25,6 @@ int nouveau_framebuffer_new(struct drm_device *,
                            const struct drm_mode_fb_cmd2 *,
                            struct nouveau_bo *, struct nouveau_framebuffer **);
 
-struct nouveau_page_flip_state {
-       struct list_head head;
-       struct drm_pending_vblank_event *event;
-       struct drm_crtc *crtc;
-       int bpp, pitch;
-       u64 offset;
-};
-
 struct nouveau_display {
        void *priv;
        void (*dtor)(struct drm_device *);
@@ -71,13 +63,6 @@ bool  nouveau_display_scanoutpos(struct drm_device *, unsigned int,
                                 bool, int *, int *, ktime_t *,
                                 ktime_t *, const struct drm_display_mode *);
 
-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_modeset_acquire_ctx *ctx);
-int  nouveau_finish_page_flip(struct nouveau_channel *,
-                             struct nouveau_page_flip_state *);
-
 int  nouveau_display_dumb_create(struct drm_file *, struct drm_device *,
                                 struct drm_mode_create_dumb *args);
 int  nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *,
index 2c665f9..4ee530c 100644 (file)
@@ -44,7 +44,6 @@
 #include <nvif/class.h>
 #include <nvif/cl0002.h>
 #include <nvif/cla06f.h>
-#include <nvif/if0004.h>
 
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
@@ -288,7 +287,6 @@ nouveau_accel_fini(struct nouveau_drm *drm)
        nouveau_channel_idle(drm->channel);
        nvif_object_fini(&drm->ntfy);
        nvkm_gpuobj_del(&drm->notify);
-       nvif_notify_fini(&drm->flip);
        nvif_object_fini(&drm->nvsw);
        nouveau_channel_del(&drm->channel);
 
@@ -412,17 +410,6 @@ nouveau_accel_init(struct nouveau_drm *drm)
                                BEGIN_NV04(drm->channel, NvSubSw, 0, 1);
                                OUT_RING  (drm->channel, drm->nvsw.handle);
                        }
-
-                       ret = nvif_notify_init(&drm->nvsw,
-                                              nouveau_flip_complete,
-                                              false, NV04_NVSW_NTFY_UEVENT,
-                                              NULL, 0, 0, &drm->flip);
-                       if (ret == 0)
-                               ret = nvif_notify_get(&drm->flip);
-                       if (ret) {
-                               nouveau_accel_fini(drm);
-                               return;
-                       }
                }
 
                if (ret) {
index d20b9ba..0ea79c0 100644 (file)
@@ -181,7 +181,6 @@ struct nouveau_drm {
        struct nouveau_fbdev *fbcon;
        struct nvif_object nvsw;
        struct nvif_object ntfy;
-       struct nvif_notify flip;
 
        /* nv10-nv40 tiling regions */
        struct {
index b999e60..ad27cae 100644 (file)
@@ -82,8 +82,6 @@ int nv50_fence_create(struct nouveau_drm *);
 int nv84_fence_create(struct nouveau_drm *);
 int nvc0_fence_create(struct nouveau_drm *);
 
-int nouveau_flip_complete(struct nvif_notify *);
-
 struct nv84_fence_chan {
        struct nouveau_fence_chan base;
        struct nouveau_vma *vma;