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

Reply via email to