- transition from "ioctl" interfaces

Signed-off-by: Ben Skeggs <bske...@nvidia.com>
---
 drivers/gpu/drm/nouveau/dispnv50/base507c.c   |  21 +-
 drivers/gpu/drm/nouveau/dispnv50/core.c       |   6 +-
 drivers/gpu/drm/nouveau/dispnv50/core.h       |   4 +-
 drivers/gpu/drm/nouveau/dispnv50/core507d.c   |  27 ++-
 drivers/gpu/drm/nouveau/dispnv50/core907d.c   |   2 +-
 drivers/gpu/drm/nouveau/dispnv50/crc.c        |   2 +-
 drivers/gpu/drm/nouveau/dispnv50/curs507a.c   |  33 +--
 drivers/gpu/drm/nouveau/dispnv50/cursc37a.c   |  12 +-
 drivers/gpu/drm/nouveau/dispnv50/disp.c       | 217 +-----------------
 drivers/gpu/drm/nouveau/dispnv50/disp.h       |  18 --
 drivers/gpu/drm/nouveau/dispnv50/oimm507b.c   |  20 +-
 drivers/gpu/drm/nouveau/dispnv50/ovly507e.c   |  21 +-
 drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c   |  20 +-
 drivers/gpu/drm/nouveau/dispnv50/wndw.c       |  14 +-
 drivers/gpu/drm/nouveau/dispnv50/wndw.h       |  10 +-
 drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c   |  21 +-
 .../gpu/drm/nouveau/include/nvif/dispchan.h   |  21 ++
 .../gpu/drm/nouveau/include/nvif/driverif.h   |  15 ++
 drivers/gpu/drm/nouveau/include/nvif/if0014.h |  13 --
 drivers/gpu/drm/nouveau/include/nvif/push.h   |   5 +-
 drivers/gpu/drm/nouveau/nouveau_chan.c        |   3 +-
 drivers/gpu/drm/nouveau/nvif/Kbuild           |   1 +
 drivers/gpu/drm/nouveau/nvif/dispchan.c       | 205 +++++++++++++++++
 .../gpu/drm/nouveau/nvkm/engine/disp/chan.c   | 132 ++++-------
 .../gpu/drm/nouveau/nvkm/engine/disp/chan.h   |   4 -
 .../gpu/drm/nouveau/nvkm/engine/disp/uchan.h  |  10 +
 .../gpu/drm/nouveau/nvkm/engine/disp/udisp.c  | 139 +++++++----
 27 files changed, 528 insertions(+), 468 deletions(-)
 create mode 100644 drivers/gpu/drm/nouveau/include/nvif/dispchan.h
 delete mode 100644 drivers/gpu/drm/nouveau/include/nvif/if0014.h
 create mode 100644 drivers/gpu/drm/nouveau/nvif/dispchan.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/uchan.h

diff --git a/drivers/gpu/drm/nouveau/dispnv50/base507c.c 
b/drivers/gpu/drm/nouveau/dispnv50/base507c.c
index 0b6fb663d78e..875c013c39b0 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/base507c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base507c.c
@@ -21,7 +21,6 @@
  */
 #include "base.h"
 
-#include <nvif/if0014.h>
 #include <nvif/push507c.h>
 #include <nvif/timer.h>
 
@@ -304,10 +303,7 @@ base507c_new_(const struct nv50_wndw_func *func, const u32 
*format,
              struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
              struct nv50_wndw **pwndw)
 {
-       struct nvif_disp_chan_v0 args = {
-               .id = head,
-       };
-       struct nv50_disp *disp50 = nv50_disp(drm->dev);
+       struct nvif_disp *disp = nv50_disp(drm->dev)->disp;
        struct nv50_wndw *wndw;
        int ret;
 
@@ -317,9 +313,18 @@ base507c_new_(const struct nv50_wndw_func *func, const u32 
*format,
        if (*pwndw = wndw, ret)
                return ret;
 
-       ret = nv50_dmac_create(drm,
-                              &oclass, head, &args, sizeof(args),
-                              disp50->sync->offset, &wndw->wndw);
+       ret = nvif_dispchan_ctor(disp, "kmsChanBase", head, oclass, &drm->mmu, 
&wndw->wndw);
+       if (ret)
+               goto done;
+
+       ret = disp->impl->chan.base.new(disp->priv, head, 
wndw->wndw.push.mem.priv,
+                                       &wndw->wndw.impl, &wndw->wndw.priv,
+                                       nvif_handle(&wndw->wndw.object));
+       if (ret)
+               goto done;
+
+       ret = nvif_dispchan_oneinit(&wndw->wndw);
+done:
        if (ret) {
                NV_ERROR(drm, "base%04x allocation failed: %d\n", oclass, ret);
                return ret;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/core.c 
b/drivers/gpu/drm/nouveau/dispnv50/core.c
index 7d5438355715..98ccb67fc95b 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/core.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/core.c
@@ -34,7 +34,7 @@ nv50_core_del(struct nv50_core **pcore)
        if (core) {
                nvif_object_dtor(&core->sync);
                nvif_object_dtor(&core->vram);
-               nv50_dmac_destroy(&core->chan);
+               nvif_dispchan_dtor(&core->chan);
                kfree(*pcore);
                *pcore = NULL;
        }
@@ -75,7 +75,7 @@ nv50_core_new(struct nouveau_drm *drm, struct nv50_core 
**pcore)
        if (ret)
                return ret;
 
-       ret = nvif_object_ctor(&core->chan.base.user, "kmsCoreSyncCtxdma", 
NV50_DISP_HANDLE_SYNCBUF,
+       ret = nvif_object_ctor(&core->chan.object, "kmsCoreSyncCtxdma", 
NV50_DISP_HANDLE_SYNCBUF,
                               NV_DMA_IN_MEMORY,
                               (&(struct nv_dma_v0) {
                                        .target = NV_DMA_V0_TARGET_VRAM,
@@ -87,7 +87,7 @@ nv50_core_new(struct nouveau_drm *drm, struct nv50_core 
**pcore)
        if (ret)
                return ret;
 
-       ret = nvif_object_ctor(&core->chan.base.user, "kmsCoreVramCtxdma", 
NV50_DISP_HANDLE_VRAM,
+       ret = nvif_object_ctor(&core->chan.object, "kmsCoreVramCtxdma", 
NV50_DISP_HANDLE_VRAM,
                               NV_DMA_IN_MEMORY,
                               (&(struct nv_dma_v0) {
                                        .target = NV_DMA_V0_TARGET_VRAM,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/core.h 
b/drivers/gpu/drm/nouveau/dispnv50/core.h
index a967c66dc7a2..1343a1d224c0 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/core.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/core.h
@@ -5,9 +5,11 @@
 #include "crc.h"
 #include <nouveau_encoder.h>
 
+#include <nvif/dispchan.h>
+
 struct nv50_core {
        const struct nv50_core_func *func;
-       struct nv50_dmac chan;
+       struct nvif_dispchan chan;
 
        struct nvif_object vram;
        struct nvif_object sync;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/core507d.c 
b/drivers/gpu/drm/nouveau/dispnv50/core507d.c
index c6eee88ae99a..dab9fb984765 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/core507d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/core507d.c
@@ -22,7 +22,6 @@
 #include "core.h"
 #include "head.h"
 
-#include <nvif/if0014.h>
 #include <nvif/push507c.h>
 #include <nvif/timer.h>
 
@@ -115,7 +114,7 @@ core507d_caps_init(struct nouveau_drm *drm, struct 
nv50_disp *disp)
        if (ret < 0)
                return ret;
 
-       time = nvif_msec(core->chan.base.device, 2000ULL,
+       time = nvif_msec(core->chan.disp->device, 2000ULL,
                         if (NVBO_TD32(bo, NV50_DISP_CORE_NTFY,
                                       NV_DISP_CORE_NOTIFIER_1, CAPABILITIES_1, 
DONE, ==, TRUE))
                                 break;
@@ -157,8 +156,7 @@ int
 core507d_new_(const struct nv50_core_func *func, struct nouveau_drm *drm,
              s32 oclass, struct nv50_core **pcore)
 {
-       struct nvif_disp_chan_v0 args = {};
-       struct nv50_disp *disp = nv50_disp(drm->dev);
+       struct nvif_disp *disp = nv50_disp(drm->dev)->disp;
        struct nv50_core *core;
        int ret;
 
@@ -166,15 +164,22 @@ core507d_new_(const struct nv50_core_func *func, struct 
nouveau_drm *drm,
                return -ENOMEM;
        core->func = func;
 
-       ret = nv50_dmac_create(drm,
-                              &oclass, 0, &args, sizeof(args),
-                              disp->sync->offset, &core->chan);
-       if (ret) {
+       ret = nvif_dispchan_ctor(disp, "kmsChanCore", 0, oclass, &drm->mmu, 
&core->chan);
+       if (ret)
+               goto done;
+
+       ret = disp->impl->chan.core.new(disp->priv, core->chan.push.mem.priv,
+                                       &core->chan.impl, &core->chan.priv,
+                                       nvif_handle(&core->chan.object));
+       if (ret)
+               goto done;
+
+       ret = nvif_dispchan_oneinit(&core->chan);
+done:
+       if (ret)
                NV_ERROR(drm, "core%04x allocation failed: %d\n", oclass, ret);
-               return ret;
-       }
 
-       return 0;
+       return ret;
 }
 
 int
diff --git a/drivers/gpu/drm/nouveau/dispnv50/core907d.c 
b/drivers/gpu/drm/nouveau/dispnv50/core907d.c
index 8564d4dffaff..0bff54ca5ba1 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/core907d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/core907d.c
@@ -44,7 +44,7 @@ core907d_caps_init(struct nouveau_drm *drm, struct nv50_disp 
*disp)
        if (ret < 0)
                return ret;
 
-       time = nvif_msec(core->chan.base.device, 2000ULL,
+       time = nvif_msec(core->chan.disp->device, 2000ULL,
                         if (NVBO_TD32(bo, NV50_DISP_CORE_NTFY,
                                       NV907D_CORE_NOTIFIER_3, CAPABILITIES_4, 
DONE, ==, TRUE))
                                 break;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c 
b/drivers/gpu/drm/nouveau/dispnv50/crc.c
index 9482e69c3647..72ce4ada284f 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/crc.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c
@@ -507,7 +507,7 @@ nv50_crc_ctx_init(struct nv50_head *head, struct nvif_mmu 
*mmu,
        if (ret)
                return ret;
 
-       ret = nvif_object_ctor(&core->chan.base.user, "kmsCrcNtfyCtxDma",
+       ret = nvif_object_ctor(&core->chan.object, "kmsCrcNtfyCtxDma",
                               NV50_DISP_HANDLE_CRC_CTX(head, idx),
                               NV_DMA_IN_MEMORY,
                               (&(struct nv_dma_v0) {
diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c 
b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c
index 7292d1554dba..8017cd0bd636 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c
@@ -23,7 +23,6 @@
 #include "core.h"
 #include "head.h"
 
-#include <nvif/if0014.h>
 #include <nvif/timer.h>
 
 #include <nvhw/class/cl507a.h>
@@ -35,7 +34,7 @@ bool
 curs507a_space(struct nv50_wndw *wndw)
 {
        nvif_msec(&nouveau_drm(wndw->plane.dev)->client.device, 100,
-               if (NVIF_TV32(&wndw->wimm.base.user, NV507A, FREE, COUNT, >=, 
4))
+               if (NVIF_TV32(&wndw->wimm, NV507A, FREE, COUNT, >=, 4))
                        return true;
        );
 
@@ -46,10 +45,10 @@ curs507a_space(struct nv50_wndw *wndw)
 static int
 curs507a_update(struct nv50_wndw *wndw, u32 *interlock)
 {
-       struct nvif_object *user = &wndw->wimm.base.user;
-       int ret = nvif_chan_wait(&wndw->wimm, 1);
+       struct nvif_dispchan *chan = &wndw->wimm;
+       int ret = nvif_chan_wait(chan, 1);
        if (ret == 0) {
-               NVIF_WR32(user, NV507A, UPDATE,
+               NVIF_WR32(chan, NV507A, UPDATE,
                          NVDEF(NV507A, UPDATE, INTERLOCK_WITH_CORE, DISABLE));
        }
        return ret;
@@ -58,10 +57,10 @@ curs507a_update(struct nv50_wndw *wndw, u32 *interlock)
 static int
 curs507a_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
-       struct nvif_object *user = &wndw->wimm.base.user;
-       int ret = nvif_chan_wait(&wndw->wimm, 1);
+       struct nvif_dispchan *chan = &wndw->wimm;
+       int ret = nvif_chan_wait(chan, 1);
        if (ret == 0) {
-               NVIF_WR32(user, NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT,
+               NVIF_WR32(chan, NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT,
                          NVVAL(NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT, X, 
asyw->point.x) |
                          NVVAL(NV507A, SET_CURSOR_HOT_SPOT_POINT_OUT, Y, 
asyw->point.y));
        }
@@ -170,10 +169,7 @@ curs507a_new_(const struct nv50_wimm_func *func, struct 
nouveau_drm *drm,
              int head, s32 oclass, u32 interlock_data,
              struct nv50_wndw **pwndw)
 {
-       struct nvif_disp_chan_v0 args = {
-               .id = head,
-       };
-       struct nv50_disp *disp = nv50_disp(drm->dev);
+       struct nvif_disp *disp = nv50_disp(drm->dev)->disp;
        struct nv50_wndw *wndw;
        int ret;
 
@@ -183,14 +179,21 @@ curs507a_new_(const struct nv50_wimm_func *func, struct 
nouveau_drm *drm,
        if (*pwndw = wndw, ret)
                return ret;
 
-       ret = nvif_object_ctor(&disp->disp->object, "kmsCurs", 0, oclass,
-                              &args, sizeof(args), &wndw->wimm.base.user);
+       ret = nvif_dispchan_ctor(disp, "kmsChanCurs", wndw->id, oclass, NULL, 
&wndw->wimm);
+       if (ret)
+               goto done;
+
+       ret = disp->impl->chan.curs.new(disp->priv, wndw->id, &wndw->wimm.impl, 
&wndw->wimm.priv);
+       if (ret)
+               goto done;
+
+       ret = nvif_dispchan_oneinit(&wndw->wimm);
+done:
        if (ret) {
                NV_ERROR(drm, "curs%04x allocation failed: %d\n", oclass, ret);
                return ret;
        }
 
-       nvif_object_map(&wndw->wimm.base.user, NULL, 0);
        wndw->immd = func;
        wndw->ctxdma.parent = NULL;
        return nv50_wndw_ctor(wndw);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/cursc37a.c 
b/drivers/gpu/drm/nouveau/dispnv50/cursc37a.c
index e39d08698c63..e2c28c5716a6 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/cursc37a.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/cursc37a.c
@@ -27,20 +27,20 @@
 static int
 cursc37a_update(struct nv50_wndw *wndw, u32 *interlock)
 {
-       struct nvif_object *user = &wndw->wimm.base.user;
-       int ret = nvif_chan_wait(&wndw->wimm, 1);
+       struct nvif_dispchan *chan = &wndw->wimm;
+       int ret = nvif_chan_wait(chan, 1);
        if (ret == 0)
-               NVIF_WR32(user, NVC37A, UPDATE, 0x00000001);
+               NVIF_WR32(chan, NVC37A, UPDATE, 0x00000001);
        return ret;
 }
 
 static int
 cursc37a_point(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
-       struct nvif_object *user = &wndw->wimm.base.user;
-       int ret = nvif_chan_wait(&wndw->wimm, 1);
+       struct nvif_dispchan *chan = &wndw->wimm;
+       int ret = nvif_chan_wait(chan, 1);
        if (ret == 0) {
-               NVIF_WR32(user, NVC37A, SET_CURSOR_HOT_SPOT_POINT_OUT(0),
+               NVIF_WR32(chan, NVC37A, SET_CURSOR_HOT_SPOT_POINT_OUT(0),
                          NVVAL(NVC37A, SET_CURSOR_HOT_SPOT_POINT_OUT, X, 
asyw->point.x) |
                          NVVAL(NVC37A, SET_CURSOR_HOT_SPOT_POINT_OUT, Y, 
asyw->point.y));
        }
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c 
b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 5e12de0aabb6..7762469af47b 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -50,7 +50,6 @@
 #include <nvif/class.h>
 #include <nvif/cl0002.h>
 #include <nvif/event.h>
-#include <nvif/if0014.h>
 #include <nvif/timer.h>
 
 #include <nvhw/class/cl507c.h>
@@ -68,220 +67,6 @@
 #include "nouveau_fence.h"
 #include "nv50_display.h"
 
-/******************************************************************************
- * EVO channel
- *****************************************************************************/
-
-static int
-nv50_chan_create(struct nvif_device *device, struct nvif_object *disp,
-                const s32 *oclass, u8 head, void *data, u32 size,
-                struct nv50_chan *chan)
-{
-       struct nvif_sclass *sclass;
-       int ret, i, n;
-
-       chan->device = device;
-
-       ret = n = nvif_object_sclass_get(disp, &sclass);
-       if (ret < 0)
-               return ret;
-
-       while (oclass[0]) {
-               for (i = 0; i < n; i++) {
-                       if (sclass[i].oclass == oclass[0]) {
-                               ret = nvif_object_ctor(disp, "kmsChan", 0,
-                                                      oclass[0], data, size,
-                                                      &chan->user);
-                               if (ret == 0) {
-                                       ret = nvif_object_map(&chan->user, 
NULL, 0);
-                                       if (ret)
-                                               nvif_object_dtor(&chan->user);
-                               }
-                               nvif_object_sclass_put(&sclass);
-                               return ret;
-                       }
-               }
-               oclass++;
-       }
-
-       nvif_object_sclass_put(&sclass);
-       return -ENOSYS;
-}
-
-static void
-nv50_chan_destroy(struct nv50_chan *chan)
-{
-       nvif_object_dtor(&chan->user);
-}
-
-/******************************************************************************
- * DMA EVO channel
- *****************************************************************************/
-
-void
-nv50_dmac_destroy(struct nv50_dmac *dmac)
-{
-       nv50_chan_destroy(&dmac->base);
-
-       nvif_mem_unmap_dtor(&dmac->push.mem, &dmac->push.map);
-}
-
-static void
-nv50_dmac_kick(struct nvif_push *push)
-{
-       struct nv50_dmac *dmac = container_of(push, typeof(*dmac), push);
-
-       push->hw.cur = push->cur - (u32 __iomem *)dmac->push.map.ptr;
-       if (push->hw.put != push->hw.cur) {
-               /* Push buffer fetches are not coherent with BAR1, we need to 
ensure
-                * writes have been flushed right through to VRAM before 
writing PUT.
-                */
-               if (dmac->push.mem.type & NVIF_MEM_VRAM) {
-                       struct nvif_device *device = dmac->base.device;
-                       nvif_wr32(&device->object, 0x070000, 0x00000001);
-                       nvif_msec(device, 2000,
-                               if (!(nvif_rd32(&device->object, 0x070000) & 
0x00000002))
-                                       break;
-                       );
-               }
-
-               NVIF_WV32(&dmac->base.user, NV507C, PUT, PTR, push->hw.cur);
-               push->hw.put = push->hw.cur;
-       }
-
-       push->bgn = push->cur;
-}
-
-static int
-nv50_dmac_free(struct nv50_dmac *dmac)
-{
-       struct nvif_push *push = &dmac->push;
-       u32 get = NVIF_RV32(&dmac->base.user, NV507C, GET, PTR);
-       if (get > push->hw.cur) /* NVIDIA stay 5 away from GET, do the same. */
-               return get - push->hw.cur - 5;
-       return push->hw.max - push->hw.cur;
-}
-
-static int
-nv50_dmac_wind(struct nv50_dmac *dmac)
-{
-       struct nvif_push *push = &dmac->push;
-
-       /* Wait for GET to depart from the beginning of the push buffer to
-        * prevent writing PUT == GET, which would be ignored by HW.
-        */
-       u32 get = NVIF_RV32(&dmac->base.user, NV507C, GET, PTR);
-       if (get == 0) {
-               /* Corner-case, HW idle, but non-committed work pending. */
-               if (push->hw.put == 0)
-                       nv50_dmac_kick(&dmac->push);
-
-               if (nvif_msec(dmac->base.device, 2000,
-                       if (NVIF_TV32(&dmac->base.user, NV507C, GET, PTR, >, 0))
-                               break;
-               ) < 0)
-                       return -ETIMEDOUT;
-       }
-
-       PUSH_RSVD(&dmac->push, PUSH_JUMP(&dmac->push, 0));
-       push->hw.cur = 0;
-       return 0;
-}
-
-static int
-nv50_dmac_wait(struct nvif_push *push, u32 size)
-{
-       struct nv50_dmac *dmac = container_of(push, typeof(*dmac), push);
-       int free;
-
-       if (WARN_ON(size > push->hw.max))
-               return -EINVAL;
-
-       push->hw.cur = push->cur - (u32 __iomem *)dmac->push.map.ptr;
-       if (push->hw.cur + size >= push->hw.max) {
-               int ret = nv50_dmac_wind(dmac);
-               if (ret)
-                       return ret;
-
-               push->cur = dmac->push.map.ptr;
-               push->cur = push->cur + push->hw.cur;
-               nv50_dmac_kick(push);
-       }
-
-       if (nvif_msec(dmac->base.device, 2000,
-               if ((free = nv50_dmac_free(dmac)) >= size)
-                       break;
-       ) < 0) {
-               WARN_ON(1);
-               return -ETIMEDOUT;
-       }
-
-       push->bgn = dmac->push.map.ptr;
-       push->bgn = push->bgn + push->hw.cur;
-       push->cur = push->bgn;
-       push->end = push->cur + free;
-       return 0;
-}
-
-MODULE_PARM_DESC(kms_vram_pushbuf, "Place EVO/NVD push buffers in VRAM 
(default: auto)");
-static int nv50_dmac_vram_pushbuf = -1;
-module_param_named(kms_vram_pushbuf, nv50_dmac_vram_pushbuf, int, 0400);
-
-int
-nv50_dmac_create(struct nouveau_drm *drm,
-                const s32 *oclass, u8 head, void *data, u32 size, s64 syncbuf,
-                struct nv50_dmac *dmac)
-{
-       struct nvif_device *device = &drm->device;
-       struct nvif_object *disp = &drm->display->disp.object;
-       struct nvif_disp_chan_v0 *args = data;
-       u8 type = NVIF_MEM_COHERENT;
-       int ret;
-
-       /* Pascal added support for 47-bit physical addresses, but some
-        * parts of EVO still only accept 40-bit PAs.
-        *
-        * To avoid issues on systems with large amounts of RAM, and on
-        * systems where an IOMMU maps pages at a high address, we need
-        * to allocate push buffers in VRAM instead.
-        *
-        * This appears to match NVIDIA's behaviour on Pascal.
-        */
-       if ((nv50_dmac_vram_pushbuf > 0) ||
-           (nv50_dmac_vram_pushbuf < 0 && device->info.family == 
NV_DEVICE_INFO_V0_PASCAL))
-               type |= NVIF_MEM_VRAM;
-
-       ret = nvif_mem_ctor_map(&drm->mmu, "kmsChanPush", type, 0x1000,
-                               &dmac->push.mem, &dmac->push.map);
-       if (ret)
-               return ret;
-
-       dmac->push.wait = nv50_dmac_wait;
-       dmac->push.kick = nv50_dmac_kick;
-       dmac->push.bgn = dmac->push.map.ptr;
-       dmac->push.cur = dmac->push.bgn;
-       dmac->push.end = dmac->push.bgn;
-       dmac->push.hw.max = 0x1000/4 - 1;
-
-       /* EVO channels are affected by a HW bug where the last 12 DWORDs
-        * of the push buffer aren't able to be used safely.
-        */
-       if (disp->oclass < GV100_DISP)
-               dmac->push.hw.max -= 12;
-
-       args->pushbuf = nvif_handle(&dmac->push.mem.object);
-
-       ret = nv50_chan_create(device, disp, oclass, head, data, size,
-                              &dmac->base);
-       if (ret)
-               return ret;
-
-       if (syncbuf < 0)
-               return 0;
-
-       return ret;
-}
-
 /******************************************************************************
  * Output path helpers
  *****************************************************************************/
@@ -2088,7 +1873,7 @@ nv50_disp_atomic_commit_core(struct drm_atomic_state 
*state, u32 *interlock)
        core->func->ntfy_init(disp->sync, NV50_DISP_CORE_NTFY);
        core->func->update(core, interlock, true);
        if (core->func->ntfy_wait_done(disp->sync, NV50_DISP_CORE_NTFY,
-                                      disp->core->chan.base.device))
+                                      disp->core->chan.disp->device))
                NV_ERROR(drm, "core notifier timeout\n");
 
        for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) {
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h 
b/drivers/gpu/drm/nouveau/dispnv50/disp.h
index 39aaa385cd6a..db9e4e5070a3 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h
@@ -1,8 +1,6 @@
 #ifndef __NV50_KMS_H__
 #define __NV50_KMS_H__
 #include <linux/workqueue.h>
-#include <nvif/mem.h>
-#include <nvif/push.h>
 
 #include "nouveau_display.h"
 
@@ -54,17 +52,6 @@ void corec37d_ntfy_init(struct nouveau_bo *, u32);
 
 void head907d_olut_load(struct drm_color_lut *, int size, void __iomem *);
 
-struct nv50_chan {
-       struct nvif_object user;
-       struct nvif_device *device;
-};
-
-struct nv50_dmac {
-       struct nv50_chan base;
-
-       struct nvif_push push;
-};
-
 struct nv50_outp_atom {
        struct list_head head;
 
@@ -81,11 +68,6 @@ struct nv50_outp_atom {
        } set, clr;
 };
 
-int nv50_dmac_create(struct nouveau_drm *,
-                    const s32 *oclass, u8 head, void *data, u32 size,
-                    s64 syncbuf, struct nv50_dmac *dmac);
-void nv50_dmac_destroy(struct nv50_dmac *);
-
 /*
  * For normal encoders this just returns the encoder. For active MST encoders,
  * this returns the real outp that's driving displays on the topology.
diff --git a/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c 
b/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c
index 752318cf3cf1..05b0d42c85c6 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c
@@ -21,26 +21,28 @@
  */
 #include "oimm.h"
 
-#include <nvif/if0014.h>
-
 static int
 oimm507b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
               s32 oclass, struct nv50_wndw *wndw)
 {
-       struct nvif_disp_chan_v0 args = {
-               .id = wndw->id,
-       };
-       struct nv50_disp *disp = nv50_disp(drm->dev);
+       struct nvif_disp *disp = nv50_disp(drm->dev)->disp;
        int ret;
 
-       ret = nvif_object_ctor(&disp->disp->object, "kmsOvim", 0, oclass,
-                              &args, sizeof(args), &wndw->wimm.base.user);
+       ret = nvif_dispchan_ctor(disp, "kmsChanOvim", wndw->id, oclass, NULL, 
&wndw->wimm);
+       if (ret)
+               goto done;
+
+       ret = disp->impl->chan.oimm.new(disp->priv, wndw->id, &wndw->wimm.impl, 
&wndw->wimm.priv);
+       if (ret)
+               goto done;
+
+       ret = nvif_dispchan_oneinit(&wndw->wimm);
+done:
        if (ret) {
                NV_ERROR(drm, "oimm%04x allocation failed: %d\n", oclass, ret);
                return ret;
        }
 
-       nvif_object_map(&wndw->wimm.base.user, NULL, 0);
        wndw->immd = func;
        return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c 
b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
index 4e109c5b5a1b..458c6f9e63f0 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
@@ -25,7 +25,6 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fourcc.h>
 
-#include <nvif/if0014.h>
 #include <nvif/push507c.h>
 
 #include <nvhw/class/cl507e.h>
@@ -145,10 +144,7 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 
*format,
              struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
              struct nv50_wndw **pwndw)
 {
-       struct nvif_disp_chan_v0 args = {
-               .id = head,
-       };
-       struct nv50_disp *disp = nv50_disp(drm->dev);
+       struct nvif_disp *disp = nv50_disp(drm->dev)->disp;
        struct nv50_wndw *wndw;
        int ret;
 
@@ -159,9 +155,18 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 
*format,
        if (*pwndw = wndw, ret)
                return ret;
 
-       ret = nv50_dmac_create(drm,
-                              &oclass, 0, &args, sizeof(args),
-                              disp->sync->offset, &wndw->wndw);
+       ret = nvif_dispchan_ctor(disp, "kmsChanOvly", wndw->id, oclass, 
&drm->mmu, &wndw->wndw);
+       if (ret)
+               goto done;
+
+       ret = disp->impl->chan.ovly.new(disp->priv, wndw->id, 
wndw->wndw.push.mem.priv,
+                                       &wndw->wndw.impl, &wndw->wndw.priv,
+                                       nvif_handle(&wndw->wndw.object));
+       if (ret)
+               goto done;
+
+       ret = nvif_dispchan_oneinit(&wndw->wndw);
+done:
        if (ret) {
                NV_ERROR(drm, "ovly%04x allocation failed: %d\n", oclass, ret);
                return ret;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c 
b/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
index 7985da61aaac..2f4f0ad89b5e 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
@@ -23,7 +23,6 @@
 #include "atom.h"
 #include "wndw.h"
 
-#include <nvif/if0014.h>
 #include <nvif/pushc37b.h>
 
 #include <nvhw/class/clc37b.h>
@@ -68,14 +67,21 @@ static int
 wimmc37b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
               s32 oclass, struct nv50_wndw *wndw)
 {
-       struct nvif_disp_chan_v0 args = {
-               .id = wndw->id,
-       };
+       struct nvif_disp *disp = nv50_disp(drm->dev)->disp;
        int ret;
 
-       ret = nv50_dmac_create(drm,
-                              &oclass, 0, &args, sizeof(args), -1,
-                              &wndw->wimm);
+       ret = nvif_dispchan_ctor(disp, "kmsChanWimm", wndw->id, oclass, 
&drm->mmu, &wndw->wimm);
+       if (ret)
+               goto done;
+
+       ret = disp->impl->chan.wimm.new(disp->priv, wndw->id, 
wndw->wimm.push.mem.priv,
+                                       &wndw->wimm.impl, &wndw->wimm.priv,
+                                       nvif_handle(&wndw->wimm.object));
+       if (ret)
+               goto done;
+
+       ret = nvif_dispchan_oneinit(&wndw->wimm);
+done:
        if (ret) {
                NV_ERROR(drm, "wimm%04x allocation failed: %d\n", oclass, ret);
                return ret;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c 
b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index 6fb6d2252e15..9cab8d20bc68 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -118,7 +118,7 @@ nv50_wndw_wait_armed(struct nv50_wndw *wndw, struct 
nv50_wndw_atom *asyw)
        if (asyw->set.ntfy) {
                return wndw->func->ntfy_wait_begun(disp->sync,
                                                   asyw->ntfy.offset,
-                                                  wndw->wndw.base.device);
+                                                  wndw->wndw.disp->device);
        }
        return 0;
 }
@@ -644,11 +644,11 @@ nv50_wndw_destroy(struct drm_plane *plane)
                nv50_wndw_ctxdma_del(ctxdma);
        }
 
-       nv50_dmac_destroy(&wndw->wimm);
+       nvif_dispchan_dtor(&wndw->wimm);
 
        nvif_object_dtor(&wndw->vram);
        nvif_object_dtor(&wndw->sync);
-       nv50_dmac_destroy(&wndw->wndw);
+       nvif_dispchan_dtor(&wndw->wndw);
 
        nv50_lut_fini(&wndw->ilut);
 
@@ -702,10 +702,10 @@ nv50_wndw_ctor(struct nv50_wndw *wndw)
        struct nv50_disp *disp = nv50_disp(wndw->plane.dev);
        int ret;
 
-       if (!nvif_object_constructed(&wndw->wndw.base.user))
+       if (!wndw->wndw.impl)
                return 0;
 
-       ret = nvif_object_ctor(&wndw->wndw.base.user, "kmsWndwSyncCtxDma", 
NV50_DISP_HANDLE_SYNCBUF,
+       ret = nvif_object_ctor(&wndw->wndw.object, "kmsWndwSyncCtxDma", 
NV50_DISP_HANDLE_SYNCBUF,
                               NV_DMA_IN_MEMORY,
                               (&(struct nv_dma_v0) {
                                        .target = NV_DMA_V0_TARGET_VRAM,
@@ -717,7 +717,7 @@ nv50_wndw_ctor(struct nv50_wndw *wndw)
        if (ret)
                return ret;
 
-       ret = nvif_object_ctor(&wndw->wndw.base.user, "kmsWndwVramCtxDma", 
NV50_DISP_HANDLE_VRAM,
+       ret = nvif_object_ctor(&wndw->wndw.object, "kmsWndwVramCtxDma", 
NV50_DISP_HANDLE_VRAM,
                               NV_DMA_IN_MEMORY,
                               (&(struct nv_dma_v0) {
                                        .target = NV_DMA_V0_TARGET_VRAM,
@@ -754,7 +754,7 @@ nv50_wndw_prep(const struct nv50_wndw_func *func, struct 
drm_device *dev,
        wndw->interlock.type = interlock_type;
        wndw->interlock.data = interlock_data;
 
-       wndw->ctxdma.parent = &wndw->wndw.base.user;
+       wndw->ctxdma.parent = &wndw->wndw.object;
        INIT_LIST_HEAD(&wndw->ctxdma.list);
 
        for (nformat = 0; format[nformat]; nformat++);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h 
b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
index 66a06e20a6a0..68092e6445fa 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
@@ -5,6 +5,8 @@
 #include "atom.h"
 #include "lut.h"
 
+#include <nvif/dispchan.h>
+
 struct nv50_wndw_ctxdma {
        struct list_head head;
        struct nvif_object object;
@@ -25,8 +27,8 @@ struct nv50_wndw {
 
        struct nv50_lut ilut;
 
-       struct nv50_dmac wndw;
-       struct nv50_dmac wimm;
+       struct nvif_dispchan wndw;
+       struct nvif_dispchan wimm;
 
        struct nvif_object vram;
        struct nvif_object sync;
@@ -104,9 +106,9 @@ extern const struct nv50_wimm_func curs507a;
 bool curs507a_space(struct nv50_wndw *);
 
 static inline __must_check int
-nvif_chan_wait(struct nv50_dmac *dmac, u32 size)
+nvif_chan_wait(struct nvif_dispchan *chan, u32 size)
 {
-       struct nv50_wndw *wndw = container_of(dmac, typeof(*wndw), wimm);
+       struct nv50_wndw *wndw = container_of(chan, typeof(*wndw), wimm);
        return curs507a_space(wndw) ? 0 : -ETIMEDOUT;
 }
 
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c 
b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
index 5029dfd98443..17751110edae 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
@@ -25,7 +25,6 @@
 #include <drm/drm_atomic_helper.h>
 #include <nouveau_bo.h>
 
-#include <nvif/if0014.h>
 #include <nvif/pushc37b.h>
 
 #include <nvhw/class/clc37e.h>
@@ -350,10 +349,7 @@ wndwc37e_new_(const struct nv50_wndw_func *func, struct 
nouveau_drm *drm,
              enum drm_plane_type type, int index, s32 oclass, u32 heads,
              struct nv50_wndw **pwndw)
 {
-       struct nvif_disp_chan_v0 args = {
-               .id = index,
-       };
-       struct nv50_disp *disp = nv50_disp(drm->dev);
+       struct nvif_disp *disp = nv50_disp(drm->dev)->disp;
        struct nv50_wndw *wndw;
        int ret;
 
@@ -363,9 +359,18 @@ wndwc37e_new_(const struct nv50_wndw_func *func, struct 
nouveau_drm *drm,
        if (*pwndw = wndw, ret)
                return ret;
 
-       ret = nv50_dmac_create(drm,
-                              &oclass, 0, &args, sizeof(args),
-                              disp->sync->offset, &wndw->wndw);
+       ret = nvif_dispchan_ctor(disp, "kmsChanWndw", wndw->id, oclass, 
&drm->mmu, &wndw->wndw);
+       if (ret)
+               goto done;
+
+       ret = disp->impl->chan.wndw.new(disp->priv, wndw->id, 
wndw->wndw.push.mem.priv,
+                                       &wndw->wndw.impl, &wndw->wndw.priv,
+                                       nvif_handle(&wndw->wndw.object));
+       if (ret)
+               goto done;
+
+       ret = nvif_dispchan_oneinit(&wndw->wndw);
+done:
        if (ret) {
                NV_ERROR(drm, "qndw%04x allocation failed: %d\n", oclass, ret);
                return ret;
diff --git a/drivers/gpu/drm/nouveau/include/nvif/dispchan.h 
b/drivers/gpu/drm/nouveau/include/nvif/dispchan.h
new file mode 100644
index 000000000000..b1d3503e054c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/dispchan.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVIF_DISPCHAN_H__
+#define __NVIF_DISPCHAN_H__
+#include "disp.h"
+#include "push.h"
+
+struct nvif_dispchan {
+       const struct nvif_disp_chan_impl *impl;
+       struct nvif_disp_chan_priv *priv;
+       struct nvif_object object;
+       struct nvif_map map;
+
+       struct nvif_disp *disp;
+       struct nvif_push push;
+};
+
+int nvif_dispchan_ctor(struct nvif_disp *, const char *name, u32 handle, s32 
oclass,
+                      struct nvif_mmu *, struct nvif_dispchan *);
+int nvif_dispchan_oneinit(struct nvif_dispchan *);
+void nvif_dispchan_dtor(struct nvif_dispchan *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/driverif.h 
b/drivers/gpu/drm/nouveau/include/nvif/driverif.h
index e66d29b3db63..60a3529a6594 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/driverif.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/driverif.h
@@ -17,6 +17,7 @@ struct nvif_disp_caps_priv;
 struct nvif_conn_priv;
 struct nvif_outp_priv;
 struct nvif_head_priv;
+struct nvif_disp_chan_priv;
 
 struct nvif_driver {
        const char *name;
@@ -360,6 +361,11 @@ struct nvif_head_impl {
                      const struct nvif_event_impl **, struct nvif_event_priv 
**);
 };
 
+struct nvif_disp_chan_impl {
+       void (*del)(struct nvif_disp_chan_priv *);
+       struct nvif_mapinfo map;
+};
+
 struct nvif_disp_impl {
        void (*del)(struct nvif_disp_priv *);
 
@@ -390,14 +396,23 @@ struct nvif_disp_impl {
        struct {
                struct nvif_disp_impl_core {
                        s32 oclass;
+                       int (*new)(struct nvif_disp_priv *, struct 
nvif_mem_priv *,
+                                  const struct nvif_disp_chan_impl **,
+                                  struct nvif_disp_chan_priv **, u64 handle);
                } core;
 
                struct nvif_disp_impl_dmac {
                        s32 oclass;
+                       int (*new)(struct nvif_disp_priv *, u8 id, struct 
nvif_mem_priv *,
+                                  const struct nvif_disp_chan_impl **,
+                                  struct nvif_disp_chan_priv **, u64 handle);
                } base, ovly, wndw, wimm;
 
                struct nvif_disp_impl_pioc {
                        s32 oclass;
+                       int (*new)(struct nvif_disp_priv *, u8 id,
+                                  const struct nvif_disp_chan_impl **,
+                                  struct nvif_disp_chan_priv **);
                } curs, oimm;
        } chan;
 };
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0014.h 
b/drivers/gpu/drm/nouveau/include/nvif/if0014.h
deleted file mode 100644
index be0362805106..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/if0014.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_IF0014_H__
-#define __NVIF_IF0014_H__
-
-union nvif_disp_chan_args {
-       struct nvif_disp_chan_v0 {
-               __u8  version;
-               __u8  id;
-               __u8  pad02[6];
-               __u64 pushbuf;
-       } v0;
-};
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/push.h 
b/drivers/gpu/drm/nouveau/include/nvif/push.h
index 8817947a2ea0..275bade7fab9 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/push.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/push.h
@@ -42,7 +42,7 @@ struct nvif_push {
        u32 *end;
 
        int (*wait)(struct nvif_push *push, u32 size);
-       void (*kick)(struct nvif_push *push);
+       int (*kick)(struct nvif_push *push);
 };
 
 static inline __must_check int
@@ -62,8 +62,7 @@ PUSH_WAIT(struct nvif_push *push, u32 size)
 static inline int
 PUSH_KICK(struct nvif_push *push)
 {
-       push->kick(push);
-       return 0;
+       return push->kick(push);
 }
 
 #ifdef CONFIG_NOUVEAU_DEBUG_PUSH
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c 
b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 27c477ed6b9b..771a4b4b3f1d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -117,13 +117,14 @@ nouveau_channel_del(struct nouveau_channel **pchan)
        *pchan = NULL;
 }
 
-static void
+static int
 nouveau_channel_kick(struct nvif_push *push)
 {
        struct nouveau_channel *chan = container_of(push, typeof(*chan), 
chan.push);
        chan->dma.cur = chan->dma.cur + (chan->chan.push.cur - 
chan->chan.push.bgn);
        FIRE_RING(chan);
        chan->chan.push.bgn = chan->chan.push.cur;
+       return 0;
 }
 
 static int
diff --git a/drivers/gpu/drm/nouveau/nvif/Kbuild 
b/drivers/gpu/drm/nouveau/nvif/Kbuild
index b7963a39dd91..8e3ed36df6b3 100644
--- a/drivers/gpu/drm/nouveau/nvif/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvif/Kbuild
@@ -4,6 +4,7 @@ nvif-y += nvif/client.o
 nvif-y += nvif/conn.o
 nvif-y += nvif/device.o
 nvif-y += nvif/disp.o
+nvif-y += nvif/dispchan.o
 nvif-y += nvif/driver.o
 nvif-y += nvif/event.o
 nvif-y += nvif/fifo.o
diff --git a/drivers/gpu/drm/nouveau/nvif/dispchan.c 
b/drivers/gpu/drm/nouveau/nvif/dispchan.c
new file mode 100644
index 000000000000..fc4f50da1a43
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvif/dispchan.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <nvif/dispchan.h>
+#include <nvif/device.h>
+#include <nvif/driverif.h>
+#include <nvif/push507c.h>
+#include <nvif/timer.h>
+
+#include <nvif/class.h>
+#include <nvhw/class/cl507c.h>
+
+static int
+nvif_dispchan_kick(struct nvif_push *push)
+{
+       struct nvif_dispchan *chan = container_of(push, typeof(*chan), push);
+
+       push->hw.cur = push->cur - (u32 __iomem *)chan->push.map.ptr;
+       if (push->hw.put != push->hw.cur) {
+               /* Push buffer fetches are not coherent with BAR1, we need to 
ensure
+                * writes have been flushed right through to VRAM before 
writing PUT.
+                */
+               if (chan->push.mem.type & NVIF_MEM_VRAM) {
+                       struct nvif_device *device = chan->disp->device;
+
+                       nvif_wr32(&device->object, 0x070000, 0x00000001);
+                       nvif_msec(device, 2000,
+                               if (!(nvif_rd32(&device->object, 0x070000) & 
0x00000002))
+                                       break;
+                       );
+               }
+
+               NVIF_WV32(chan, NV507C, PUT, PTR, push->hw.cur);
+               push->hw.put = push->hw.cur;
+       }
+
+       push->bgn = push->cur;
+       return 0;
+}
+
+static int
+nvif_dispchan_free(struct nvif_dispchan *chan)
+{
+       struct nvif_push *push = &chan->push;
+       u32 get;
+
+       get = NVIF_RV32(chan, NV507C, GET, PTR);
+       if (get > push->hw.cur) /* NVIDIA stay 5 away from GET, do the same. */
+               return get - push->hw.cur - 5;
+
+       return push->hw.max - push->hw.cur;
+}
+
+static int
+nvif_dispchan_wind(struct nvif_dispchan *chan)
+{
+       struct nvif_push *push = &chan->push;
+
+       /* Wait for GET to depart from the beginning of the push buffer to
+        * prevent writing PUT == GET, which would be ignored by HW.
+        */
+       u32 get = NVIF_RV32(chan, NV507C, GET, PTR);
+       if (get == 0) {
+               /* Corner-case, HW idle, but non-committed work pending. */
+               if (push->hw.put == 0)
+                       nvif_dispchan_kick(&chan->push);
+
+               if (nvif_msec(chan->disp->device, 2000,
+                       if (NVIF_TV32(chan, NV507C, GET, PTR, >, 0))
+                               break;
+               ) < 0)
+                       return -ETIMEDOUT;
+       }
+
+       PUSH_RSVD(&chan->push, PUSH_JUMP(&chan->push, 0));
+       push->hw.cur = 0;
+       return 0;
+}
+
+static int
+nvif_dispchan_wait(struct nvif_push *push, u32 size)
+{
+       struct nvif_dispchan *chan = container_of(push, typeof(*chan), push);
+       int free;
+
+       if (WARN_ON(size > push->hw.max))
+               return -EINVAL;
+
+       push->hw.cur = push->cur - (u32 __iomem *)chan->push.map.ptr;
+       if (push->hw.cur + size >= push->hw.max) {
+               int ret = nvif_dispchan_wind(chan);
+               if (ret)
+                       return ret;
+
+               push->cur = chan->push.map.ptr;
+               push->cur = push->cur + push->hw.cur;
+               nvif_dispchan_kick(push);
+       }
+
+       if (nvif_msec(chan->disp->device, 2000,
+               if ((free = nvif_dispchan_free(chan)) >= size)
+                       break;
+       ) < 0) {
+               WARN_ON(1);
+               return -ETIMEDOUT;
+       }
+
+       push->bgn = chan->push.map.ptr;
+       push->bgn = push->bgn + push->hw.cur;
+       push->cur = push->bgn;
+       push->end = push->cur + free;
+       return 0;
+}
+
+void
+nvif_dispchan_dtor(struct nvif_dispchan *chan)
+{
+       if (chan->impl) {
+               chan->impl->del(chan->priv);
+               chan->impl = NULL;
+       }
+
+       nvif_mem_unmap_dtor(&chan->push.mem, &chan->push.map);
+}
+
+int
+nvif_dispchan_oneinit(struct nvif_dispchan *chan)
+{
+       int ret;
+
+       ret = nvif_object_map_cpu(&chan->object, &chan->impl->map, &chan->map);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int
+nvif_dispchan_ctor(struct nvif_disp *disp, const char *name, u32 handle, s32 
oclass,
+                  struct nvif_mmu *mmu, struct nvif_dispchan *chan)
+{
+       u8 type = NVIF_MEM_COHERENT;
+       int ret;
+
+       /* PIO channels don't need a push buffer. */
+       chan->push.mem.impl = NULL;
+       chan->impl = NULL;
+       if (!mmu)
+               goto done;
+
+       /* Pascal added support for 47-bit physical addresses, but some
+        * parts of EVO still only accept 40-bit PAs.
+        *
+        * To avoid issues on systems with large amounts of RAM, and on
+        * systems where an IOMMU maps pages at a high address, we need
+        * to allocate push buffers in VRAM instead.
+        *
+        * This appears to match NVIDIA's behaviour on Pascal.
+        */
+       if (disp->device->impl->family == NVIF_DEVICE_PASCAL)
+               type |= NVIF_MEM_VRAM;
+
+       ret = nvif_mem_ctor_map(mmu, "nvifDispChanPush", type, 0x1000,
+                               &chan->push.mem, &chan->push.map);
+       if (ret)
+               return ret;
+
+       chan->push.hw.cur = 0;
+       chan->push.hw.put = 0;
+       chan->push.hw.max = 0x1000/4 - 1;
+       chan->push.bgn = chan->push.map.ptr;
+       chan->push.cur = chan->push.bgn;
+       chan->push.end = chan->push.bgn;
+       chan->push.wait = nvif_dispchan_wait;
+       chan->push.kick = nvif_dispchan_kick;
+
+       /* EVO channels are affected by a HW bug where the last 12 DWORDs
+        * of the push buffer aren't able to be used safely.
+        */
+       if (disp->object.oclass < GV100_DISP)
+               chan->push.hw.max -= 12;
+
+done:
+       nvif_object_ctor(&disp->object, name ?: "nvifDispChan", handle, oclass, 
&chan->object);
+       chan->disp = disp;
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
index 86938c633272..3a0366420248 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
@@ -19,17 +19,17 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  */
-#include "chan.h"
+#include "uchan.h"
 
 #include <core/oproxy.h>
 #include <core/ramht.h>
 #include <subdev/mmu.h>
 
-#include <nvif/if0014.h>
-
 struct nvif_disp_chan_priv {
        struct nvkm_object object;
        struct nvkm_disp_chan chan;
+
+       struct nvif_disp_chan_impl impl;
 };
 
 static int
@@ -49,20 +49,6 @@ nvkm_disp_chan_ntfy(struct nvkm_object *object, u32 type, 
struct nvkm_event **pe
        return -EINVAL;
 }
 
-static int
-nvkm_disp_chan_map(struct nvkm_object *object, void *argv, u32 argc,
-                  enum nvkm_object_map *type, u64 *addr, u64 *size)
-{
-       struct nvif_disp_chan_priv *uchan = container_of(object, 
typeof(*uchan), object);
-       struct nvkm_disp_chan *chan = &uchan->chan;
-       struct nvkm_device *device = chan->disp->engine.subdev.device;
-       const u64 base = device->func->resource_addr(device, 0);
-
-       *type = NVKM_OBJECT_MAP_IO;
-       *addr = base + chan->func->user(chan, size);
-       return 0;
-}
-
 struct nvkm_disp_chan_object {
        struct nvkm_oproxy oproxy;
        struct nvkm_disp *disp;
@@ -136,6 +122,20 @@ nvkm_disp_chan_child_get(struct nvkm_object *object, int 
index, struct nvkm_ocla
        return -EINVAL;
 }
 
+static void
+nvkm_disp_chan_del(struct nvif_disp_chan_priv *uchan)
+{
+       struct nvkm_object *object = &uchan->object;
+
+       nvkm_object_fini(object, false);
+       nvkm_object_del(&object);
+}
+
+static const struct nvif_disp_chan_impl
+nvkm_disp_chan_impl = {
+       .del = nvkm_disp_chan_del,
+};
+
 static int
 nvkm_disp_chan_fini(struct nvkm_object *object, bool suspend)
 {
@@ -179,42 +179,20 @@ nvkm_disp_chan = {
        .init = nvkm_disp_chan_init,
        .fini = nvkm_disp_chan_fini,
        .ntfy = nvkm_disp_chan_ntfy,
-       .map = nvkm_disp_chan_map,
        .sclass = nvkm_disp_chan_child_get,
 };
 
-static int
-nvkm_disp_chan_new_(struct nvkm_disp *disp, int nr, const struct nvkm_oclass 
*oclass,
-                   void *argv, u32 argc, struct nvkm_object **pobject)
+int
+nvkm_disp_chan_new(struct nvkm_disp *disp, const struct nvkm_disp_func_chan 
*func, u8 id,
+                  struct nvkm_memory *memory, const struct nvif_disp_chan_impl 
**pimpl,
+                  struct nvif_disp_chan_priv **ppriv, struct nvkm_object 
**pobject)
 {
-       const struct nvkm_disp_func_chan *chans[] = {
-               &disp->func->user.core,
-               &disp->func->user.base,
-               &disp->func->user.ovly,
-               &disp->func->user.wndw,
-               &disp->func->user.wimm,
-               &disp->func->user.curs,
-               &disp->func->user.oimm,
-       };
-       const struct nvkm_disp_chan_user *user = NULL;
+       struct nvkm_device *device = disp->engine.subdev.device;
        struct nvif_disp_chan_priv *uchan;
        struct nvkm_disp_chan *chan;
-       union nvif_disp_chan_args *args = argv;
-       int ret, i;
-
-       for (i = 0; i < ARRAY_SIZE(chans); i++) {
-               if (chans[i]->oclass == oclass->base.oclass) {
-                       user = chans[i]->chan;
-                       break;
-               }
-       }
-
-       if (WARN_ON(!user))
-               return -EINVAL;
+       int ret;
 
-       if (argc != sizeof(args->v0) || args->v0.version != 0)
-               return -ENOSYS;
-       if (args->v0.id >= nr || !args->v0.pushbuf != !user->func->push)
+       if (!memory != !func->chan->func->push)
                return -EINVAL;
 
        uchan = kzalloc(sizeof(*uchan), GFP_KERNEL);
@@ -222,13 +200,13 @@ nvkm_disp_chan_new_(struct nvkm_disp *disp, int nr, const 
struct nvkm_oclass *oc
                return -ENOMEM;
        chan = &uchan->chan;
 
-       nvkm_object_ctor(&nvkm_disp_chan, oclass, &uchan->object);
-       chan->func = user->func;
-       chan->mthd = user->mthd;
+       nvkm_object_ctor(&nvkm_disp_chan, &(struct nvkm_oclass) {}, 
&uchan->object);
+       chan->func = func->chan->func;
+       chan->mthd = func->chan->mthd;
        chan->disp = disp;
-       chan->chid.ctrl = user->ctrl + args->v0.id;
-       chan->chid.user = user->user + args->v0.id;
-       chan->head = args->v0.id;
+       chan->chid.ctrl = func->chan->ctrl + id;
+       chan->chid.user = func->chan->user + id;
+       chan->head = id;
 
        spin_lock(&disp->user.lock);
        if (disp->chan[chan->chid.user]) {
@@ -237,48 +215,36 @@ nvkm_disp_chan_new_(struct nvkm_disp *disp, int nr, const 
struct nvkm_oclass *oc
                return -EBUSY;
        }
        disp->chan[chan->chid.user] = chan;
-       chan->user.oclass = oclass->base.oclass;
+       chan->user.oclass = func->oclass;
        spin_unlock(&disp->user.lock);
 
        *pobject = &uchan->object;
 
+       uchan->impl = nvkm_disp_chan_impl;
+       uchan->impl.map.type = NVIF_MAP_IO;
+       uchan->impl.map.handle = device->func->resource_addr(device, 0);
+       uchan->impl.map.handle += chan->func->user(chan, 
&uchan->impl.map.length);
+
        if (chan->func->push) {
-               chan->memory = 
nvkm_umem_search(disp->engine.subdev.device->mmu, uchan->object.client, 
args->v0.pushbuf);
-               if (IS_ERR(chan->memory))
-                       return PTR_ERR(chan->memory);
+               chan->memory = nvkm_memory_ref(memory);
 
                ret = chan->func->push(chan);
-               if (ret)
+               if (ret) {
+                       nvkm_object_del(pobject);
                        return ret;
+               }
        }
 
-       return 0;
-}
-
-#include "udisp.h"
-int
-nvkm_disp_wndw_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-                  struct nvkm_object **pobject)
-{
-       struct nvkm_disp *disp = container_of(oclass->parent, struct 
nvif_disp_priv, object)->disp;
-
-       return nvkm_disp_chan_new_(disp, disp->wndw.nr, oclass, argv, argc, 
pobject);
-}
-
-int
-nvkm_disp_chan_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-                  struct nvkm_object **pobject)
-{
-       struct nvkm_disp *disp = container_of(oclass->parent, struct 
nvif_disp_priv, object)->disp;
+       ret = nvkm_disp_chan_init(&uchan->object);
+       if (ret)
+               goto done;
 
-       return nvkm_disp_chan_new_(disp, disp->head.nr, oclass, argv, argc, 
pobject);
-}
+       *pimpl = &uchan->impl;
+       *ppriv = uchan;
 
-int
-nvkm_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-                  struct nvkm_object **pobject)
-{
-       struct nvkm_disp *disp = container_of(oclass->parent, struct 
nvif_disp_priv, object)->disp;
+done:
+       if (ret)
+               nvkm_disp_chan_del(uchan);
 
-       return nvkm_disp_chan_new_(disp, 1, oclass, argv, argc, pobject);
+       return ret;
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
index 8c212dde036f..b7d7c435b1e2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
@@ -29,10 +29,6 @@ struct nvkm_disp_chan {
        } user;
 };
 
-int nvkm_disp_core_new(const struct nvkm_oclass *, void *, u32, struct 
nvkm_object **);
-int nvkm_disp_chan_new(const struct nvkm_oclass *, void *, u32, struct 
nvkm_object **);
-int nvkm_disp_wndw_new(const struct nvkm_oclass *, void *, u32, struct 
nvkm_object **);
-
 struct nvkm_disp_chan_func {
        int (*push)(struct nvkm_disp_chan *);
        int (*init)(struct nvkm_disp_chan *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uchan.h 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uchan.h
new file mode 100644
index 000000000000..f682d2d5e6d3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uchan.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVKM_UDISP_CHAN_H__
+#define __NVKM_UDISP_CHAN_H__
+#include "chan.h"
+#include <nvif/driverif.h>
+
+int nvkm_disp_chan_new(struct nvkm_disp *disp, const struct 
nvkm_disp_func_chan *, u8 id,
+                      struct nvkm_memory *, const struct nvif_disp_chan_impl 
**,
+                      struct nvif_disp_chan_priv **, struct nvkm_object **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
index dc23fad17b81..bc15fe149a86 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
@@ -21,61 +21,112 @@
  */
 #include "udisp.h"
 #include "ucaps.h"
-#include "chan.h"
+#include "uchan.h"
 #include "uconn.h"
 #include "uhead.h"
 #include "uoutp.h"
+#include <subdev/mmu/umem.h>
 
-#include <nvif/class.h>
+static int
+nvkm_udisp_chan_new(struct nvif_disp_priv *udisp, const struct 
nvkm_disp_func_chan *func,
+                   u8 nr, u8 id, struct nvif_mem_priv *umem,
+                   const struct nvif_disp_chan_impl **pimpl, struct 
nvif_disp_chan_priv **ppriv,
+                   u64 handle)
+{
+       struct nvkm_memory *memory = NULL;
+       struct nvkm_object *object;
+       int ret;
+
+       if (id >= nr)
+               return -EINVAL;
+
+       if (umem)
+               memory = nvkm_umem_ref(umem);
+
+       ret = nvkm_disp_chan_new(udisp->disp, func, id, memory, pimpl, ppriv, 
&object);
+       nvkm_memory_unref(&memory);
+       if (ret)
+               return ret;
+
+       if (handle)
+               return nvkm_object_link_rb(udisp->object.client, 
&udisp->object, handle, object);
+
+       nvkm_object_link(&udisp->object, object);
+       return 0;
+}
 
 static int
-nvkm_udisp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass 
*sclass)
+nvkm_udisp_oimm_new(struct nvif_disp_priv *udisp, u8 id,
+                   const struct nvif_disp_chan_impl **pimpl, struct 
nvif_disp_chan_priv **ppriv)
 {
-       struct nvkm_disp *disp = container_of(object, struct nvif_disp_priv, 
object)->disp;
+       struct nvkm_disp *disp = udisp->disp;
 
-       if (disp->func->user.core.oclass && index-- == 0) {
-               sclass->base = (struct nvkm_sclass) { 0, 0, 
disp->func->user.core.oclass };
-               sclass->ctor = nvkm_disp_core_new;
-               return 0;
-       }
+       return nvkm_udisp_chan_new(udisp, &disp->func->user.oimm, 
disp->head.nr, id, NULL,
+                                  pimpl, ppriv, 0);
+}
 
-       if (disp->func->user.base.oclass && index-- == 0) {
-               sclass->base = (struct nvkm_sclass) { 0, 0, 
disp->func->user.base.oclass };
-               sclass->ctor = nvkm_disp_chan_new;
-               return 0;
-       }
+static int
+nvkm_udisp_curs_new(struct nvif_disp_priv *udisp, u8 id,
+                   const struct nvif_disp_chan_impl **pimpl, struct 
nvif_disp_chan_priv **ppriv)
+{
+       struct nvkm_disp *disp = udisp->disp;
 
-       if (disp->func->user.ovly.oclass && index-- == 0) {
-               sclass->base = (struct nvkm_sclass) { 0, 0, 
disp->func->user.ovly.oclass };
-               sclass->ctor = nvkm_disp_chan_new;
-               return 0;
-       }
+       return nvkm_udisp_chan_new(udisp, &disp->func->user.curs, 
disp->head.nr, id, NULL,
+                                  pimpl, ppriv, 0);
+}
 
-       if (disp->func->user.curs.oclass && index-- == 0) {
-               sclass->base = (struct nvkm_sclass) { 0, 0, 
disp->func->user.curs.oclass };
-               sclass->ctor = nvkm_disp_chan_new;
-               return 0;
-       }
+static int
+nvkm_udisp_wimm_new(struct nvif_disp_priv *udisp, u8 id, struct nvif_mem_priv 
*umem,
+                   const struct nvif_disp_chan_impl **pimpl, struct 
nvif_disp_chan_priv **ppriv,
+                   u64 handle)
+{
+       struct nvkm_disp *disp = udisp->disp;
 
-       if (disp->func->user.oimm.oclass && index-- == 0) {
-               sclass->base = (struct nvkm_sclass) { 0, 0, 
disp->func->user.oimm.oclass };
-               sclass->ctor = nvkm_disp_chan_new;
-               return 0;
-       }
+       return nvkm_udisp_chan_new(udisp, &disp->func->user.wimm, 
disp->wndw.nr, id, umem,
+                                  pimpl, ppriv, 0);
+}
 
-       if (disp->func->user.wndw.oclass && index-- == 0) {
-               sclass->base = (struct nvkm_sclass) { 0, 0, 
disp->func->user.wndw.oclass };
-               sclass->ctor = nvkm_disp_wndw_new;
-               return 0;
-       }
+static int
+nvkm_udisp_wndw_new(struct nvif_disp_priv *udisp, u8 id, struct nvif_mem_priv 
*umem,
+                   const struct nvif_disp_chan_impl **pimpl, struct 
nvif_disp_chan_priv **ppriv,
+                   u64 handle)
+{
+       struct nvkm_disp *disp = udisp->disp;
 
-       if (disp->func->user.wimm.oclass && index-- == 0) {
-               sclass->base = (struct nvkm_sclass) { 0, 0, 
disp->func->user.wimm.oclass };
-               sclass->ctor = nvkm_disp_wndw_new;
-               return 0;
-       }
+       return nvkm_udisp_chan_new(udisp, &disp->func->user.wndw, 
disp->wndw.nr, id, umem,
+                                  pimpl, ppriv, handle);
+}
+
+static int
+nvkm_udisp_ovly_new(struct nvif_disp_priv *udisp, u8 id, struct nvif_mem_priv 
*umem,
+                   const struct nvif_disp_chan_impl **pimpl, struct 
nvif_disp_chan_priv **ppriv,
+                   u64 handle)
+{
+       struct nvkm_disp *disp = udisp->disp;
+
+       return nvkm_udisp_chan_new(udisp, &disp->func->user.ovly, 
disp->head.nr, id, umem,
+                                  pimpl, ppriv, handle);
+}
+
+static int
+nvkm_udisp_base_new(struct nvif_disp_priv *udisp, u8 id, struct nvif_mem_priv 
*umem,
+                   const struct nvif_disp_chan_impl **pimpl, struct 
nvif_disp_chan_priv **ppriv,
+                   u64 handle)
+{
+       struct nvkm_disp *disp = udisp->disp;
+
+       return nvkm_udisp_chan_new(udisp, &disp->func->user.base, 
disp->head.nr, id, umem,
+                                  pimpl, ppriv, handle);
+}
+
+static int
+nvkm_udisp_core_new(struct nvif_disp_priv *udisp, struct nvif_mem_priv *umem,
+                   const struct nvif_disp_chan_impl **pimpl, struct 
nvif_disp_chan_priv **ppriv,
+                   u64 handle)
+{
+       struct nvkm_disp *disp = udisp->disp;
 
-       return -EINVAL;
+       return nvkm_udisp_chan_new(udisp, &disp->func->user.core, 1, 0, umem, 
pimpl, ppriv, handle);
 }
 
 static int
@@ -173,7 +224,6 @@ nvkm_udisp_dtor(struct nvkm_object *object)
 static const struct nvkm_object_func
 nvkm_udisp = {
        .dtor = nvkm_udisp_dtor,
-       .sclass = nvkm_udisp_sclass,
 };
 
 int
@@ -227,17 +277,24 @@ nvkm_udisp_new(struct nvkm_device *device, const struct 
nvif_disp_impl **pimpl,
 
        if (disp->func->user.core.oclass) {
                udisp->impl.chan.core.oclass = disp->func->user.core.oclass;
+               udisp->impl.chan.core.new = nvkm_udisp_core_new;
                udisp->impl.chan.curs.oclass = disp->func->user.curs.oclass;
+               udisp->impl.chan.curs.new = nvkm_udisp_curs_new;
 
                if (!disp->func->user.wndw.oclass) {
                        /* EVO */
                        udisp->impl.chan.base.oclass = 
disp->func->user.base.oclass;
+                       udisp->impl.chan.base.new = nvkm_udisp_base_new;
                        udisp->impl.chan.ovly.oclass = 
disp->func->user.ovly.oclass;
+                       udisp->impl.chan.ovly.new = nvkm_udisp_ovly_new;
                        udisp->impl.chan.oimm.oclass = 
disp->func->user.oimm.oclass;
+                       udisp->impl.chan.oimm.new = nvkm_udisp_oimm_new;
                } else {
                        /* NVDisplay (GV100-) */
                        udisp->impl.chan.wndw.oclass = 
disp->func->user.wndw.oclass;
+                       udisp->impl.chan.wndw.new = nvkm_udisp_wndw_new;
                        udisp->impl.chan.wimm.oclass = 
disp->func->user.wimm.oclass;
+                       udisp->impl.chan.wimm.new = nvkm_udisp_wimm_new;
                }
        }
 
-- 
2.41.0

Reply via email to