[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