[Nouveau] [PATCH RFC 20/20] sw/nv50: add and interface for controlling performance counters
Samuel Pitoiset
samuel.pitoiset at gmail.com
Sun Jun 7 13:40:30 PDT 2015
This software methods interface will allow the userspace to tie
monitoring of performance counters to the command stream.
Signed-off-by: Samuel Pitoiset <samuel.pitoiset at 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
More information about the Nouveau
mailing list