This software methods interface will allow the userspace to tie monitoring of performance counters to the command stream.
Signed-off-by: Samuel Pitoiset <samuel.pitoi...@gmail.com> --- drm/nouveau/nvkm/engine/sw/nv50.c | 160 ++++++++++++++++++++++++++++++++++++++ drm/nouveau/nvkm/engine/sw/nv50.h | 6 ++ 2 files changed, 166 insertions(+) diff --git a/drm/nouveau/nvkm/engine/sw/nv50.c b/drm/nouveau/nvkm/engine/sw/nv50.c index b7c0227..b5f8263 100644 --- a/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drm/nouveau/nvkm/engine/sw/nv50.c @@ -29,7 +29,9 @@ #include <engine/disp.h> #include <subdev/bar.h> +#include <nvif/class.h> #include <nvif/event.h> +#include <nvif/ioctl.h> /******************************************************************************* * software object classes @@ -80,6 +82,14 @@ nv50_priv_ctxdma_wr32(struct nv50_sw_chan *chan, u64 offset, u32 value) } } +static u64 +nv50_priv_pm_get_offset(struct nv50_sw_chan *chan, u32 sequence) +{ + u32 max_queries = chan->pm.max_queries; + u32 ring_size = chan->pm.ring_size; + return (1 + (sequence % ring_size) * max_queries * 3) * 4; +} + static int nv50_sw_mthd_dma_vblsem(struct nvkm_object *object, u32 mthd, void *args, u32 size) @@ -128,13 +138,163 @@ nv50_sw_mthd_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) return -EINVAL; } +static int +nv50_sw_mthd_dma_pm(struct nvkm_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); + return nv50_priv_ctxdma_get(chan, *(u32 *)args, &chan->pm.ctxdma); +} + +static int +nv50_sw_mthd_pm_ring_size(struct nvkm_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); + chan->pm.ring_size = *(u32 *)args; + return 0; +} + +static int +nv50_sw_mthd_pm_max_queries(struct nvkm_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); + chan->pm.max_queries = *(u32 *)args; + return 0; +} + +static int +nv50_sw_mthd_pm_mthd_init(struct nvkm_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); + struct nvkm_fifo_chan *fifo = (void *)nv_object(chan)->parent; + struct nvkm_handle *handle; + struct nvkm_object *namedb; + int ret = -EINVAL; + + namedb = nv_object(fifo)->parent; + while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) + namedb = namedb->parent; + + handle = nvkm_namedb_get(nv_namedb(namedb), *(u32 *)args); + if (!handle) + return -ENOENT; + + if (nv_iclass(handle->object, NVIF_IOCTL_NEW_V0_PERFMON)) { + struct nvkm_object *object = handle->object; + struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs; + struct nvif_perfdom_init args = {}; + + ret = ofuncs->mthd(object, NVIF_PERFDOM_V0_INIT, + &args, sizeof(args)); + } + nvkm_namedb_put(handle); + return ret; +} + +static int +nv50_sw_mthd_pm_mthd_sample(struct nvkm_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); + struct nvkm_fifo_chan *fifo = (void *)nv_object(chan)->parent; + struct nvkm_handle *handle; + struct nvkm_object *namedb; + int ret = -EINVAL; + + namedb = nv_object(fifo)->parent; + while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) + namedb = namedb->parent; + + handle = nvkm_namedb_get(nv_namedb(namedb), *(u32 *)args); + if (!handle) + return -ENOENT; + + if (nv_iclass(handle->object, NVIF_IOCTL_NEW_V0_PERFMON)) { + struct nvkm_object *object = handle->object; + struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs; + struct nvif_perfdom_sample args = {}; + + ret = ofuncs->mthd(object, NVIF_PERFDOM_V0_SAMPLE, + &args, sizeof(args)); + } + nvkm_namedb_put(handle); + return ret; +} + +static int +nv50_sw_mthd_pm_mthd_read(struct nvkm_object *object, u32 mthd, + void *args, u32 size) +{ + struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); + struct nvkm_fifo_chan *fifo = (void *)nv_object(chan)->parent; + struct nvkm_handle *handle; + struct nvkm_object *namedb; + u32 seq = *(u32 *)args; + int ret = -ENOENT; + u64 offset; + int i; + + nv50_priv_ctxdma_flush(chan, chan->vblank.channel, chan->pm.ctxdma); + offset = nv50_priv_pm_get_offset(chan, seq); + + namedb = nv_object(fifo)->parent; + while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) + namedb = namedb->parent; + + /* XXX: Any ideas to improve this ? */ + read_lock(&nv_namedb(namedb)->lock); + list_for_each_entry(handle, &nv_namedb(namedb)->list, node) { + struct nvif_perfdom_read_v0 args = {}; + struct nvkm_object *object; + struct nvkm_ofuncs *ofuncs; + + if (handle == NULL) + break; + + if (nv_iclass(handle->object, NVIF_IOCTL_NEW_V0_PERFMON) + != NVIF_IOCTL_NEW_V0_PERFMON) + continue; + + object = handle->object; + ofuncs = object->oclass->ofuncs; + ret = ofuncs->mthd(object, NVIF_PERFDOM_V0_READ, + &args, sizeof(args)); + if (ret && ret != -EAGAIN) { + nv_error(object, "failed to read perfdom object: %x\n", + handle->name); + break; + } + + nv50_priv_ctxdma_wr32(chan, offset, handle->name); + for (i = 0; i < 4; i++) { + nv50_priv_ctxdma_wr32(chan, offset + 4 * (i + 1), + args.ctr[i]); + } + nv50_priv_ctxdma_wr32(chan, offset + 20, args.clk); + offset += 24; + } + read_unlock(&nv_namedb(namedb)->lock); + + nv50_priv_ctxdma_wr32(chan, 0x0, seq); + return ret; +} + static struct nvkm_omthds nv50_sw_omthds[] = { { 0x018c, 0x018c, nv50_sw_mthd_dma_vblsem }, + { 0x0190, 0x0190, nv50_sw_mthd_dma_pm }, { 0x0400, 0x0400, nv50_sw_mthd_vblsem_offset }, { 0x0404, 0x0404, nv50_sw_mthd_vblsem_value }, { 0x0408, 0x0408, nv50_sw_mthd_vblsem_release }, { 0x0500, 0x0500, nv50_sw_mthd_flip }, + { 0x0600, 0x0600, nv50_sw_mthd_pm_ring_size }, + { 0x0604, 0x0604, nv50_sw_mthd_pm_max_queries }, + { 0x0608, 0x0608, nv50_sw_mthd_pm_mthd_init }, + { 0x060c, 0x060c, nv50_sw_mthd_pm_mthd_sample }, + { 0x0700, 0x0700, nv50_sw_mthd_pm_mthd_read }, {} }; diff --git a/drm/nouveau/nvkm/engine/sw/nv50.h b/drm/nouveau/nvkm/engine/sw/nv50.h index d8adc11..48860d3 100644 --- a/drm/nouveau/nvkm/engine/sw/nv50.h +++ b/drm/nouveau/nvkm/engine/sw/nv50.h @@ -31,6 +31,12 @@ struct nv50_sw_chan { u64 offset; u32 value; } vblank; + + struct { + u32 ctxdma; + u32 ring_size; + u32 max_queries; + } pm; }; int nv50_sw_context_ctor(struct nvkm_object *, -- 2.4.2 _______________________________________________ Nouveau mailing list Nouveau@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/nouveau