[PATCH 130/156] drm/nouveau/nvif: rework disp "new chan" apis
Ben Skeggs
bskeggs at nvidia.com
Tue Apr 16 23:39:36 UTC 2024
- transition from "ioctl" interfaces
Signed-off-by: Ben Skeggs <bskeggs at 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
More information about the Nouveau
mailing list