From 45f0f94db285009a41a94e069618ea9bb269af84 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:17 +0200 Subject: [PATCH] drm/nouveau/pm: implement NVIF_PERFMON_V0_QUERY_DOMAIN method This allows to query the number of available domains, including the number of hardware counter and the number of signals per domain. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 11 ++- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 86 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 11935a048744..0b28929f5be6 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -251,7 +251,16 @@ struct gf110_dma_v0 { * perfmon ******************************************************************************/ -#define NVIF_PERFMON_V0_QUERY_SIGNAL 0x00 +#define NVIF_PERFMON_V0_QUERY_DOMAIN 0x00 +#define NVIF_PERFMON_V0_QUERY_SIGNAL 0x01 + +struct nvif_perfmon_query_domain_v0 { + __u8 version; + __u8 id; + __u8 counter_nr; + __u8 iter; + __u32 signal_nr; +}; struct nvif_perfmon_query_signal_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 2f851473cecf..3d9bcbc1064c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -34,6 +34,45 @@ #define QUAD_MASK 0x0f #define QUAD_FREE 0x01 +static u8 +nvkm_pm_count_perfdom(struct nvkm_pm *ppm) +{ + struct nvkm_perfdom *dom; + u8 domain_nr = 0; + + list_for_each_entry(dom, &ppm->domains, head) + domain_nr++; + return domain_nr; +} + +static u32 +nvkm_perfdom_count_perfsig(struct nvkm_perfdom *dom) +{ + u32 signal_nr = 0; + int i; + + if (dom) { + for (i = 0; i < dom->signal_nr; i++) { + if (dom->signal[i].name) + signal_nr++; + } + } + return signal_nr; +} + +static struct nvkm_perfdom * +nvkm_perfdom_find(struct nvkm_pm *ppm, int di) +{ + struct nvkm_perfdom *dom; + int tmp = 0; + + list_for_each_entry(dom, &ppm->domains, head) { + if (tmp++ == di) + return dom; + } + return NULL; +} + static struct nvkm_perfsig * nvkm_perfsig_find_(struct nvkm_perfdom *dom, const char *name, u32 size) { @@ -82,6 +121,51 @@ nvkm_perfsig_find(struct nvkm_pm *ppm, const char *name, u32 size, /******************************************************************************* * Perfmon object classes ******************************************************************************/ +static int +nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) +{ + union { + struct nvif_perfmon_query_domain_v0 v0; + } *args = data; + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfdom *dom; + u8 domain_nr; + int di, ret; + + nv_ioctl(object, "perfmon query domain size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "perfmon domain vers %d iter %02x\n", + args->v0.version, args->v0.iter); + di = (args->v0.iter & 0xff) - 1; + } else + return ret; + + domain_nr = nvkm_pm_count_perfdom(ppm); + if (di >= (int)domain_nr) + return -EINVAL; + + if (di >= 0) { + dom = nvkm_perfdom_find(ppm, di); + if (dom == NULL) + return -EINVAL; + + args->v0.id = di; + args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom); + + /* Currently only global counters (PCOUNTER) are implemented + * but this will be different for local counters (MP). */ + args->v0.counter_nr = 4; + } + + if (++di < domain_nr) { + args->v0.iter = ++di; + return 0; + } + + args->v0.iter = 0xff; + return 0; +} + static int nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) { @@ -145,6 +229,8 @@ static int nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { switch (mthd) { + case NVIF_PERFMON_V0_QUERY_DOMAIN: + return nvkm_perfmon_mthd_query_domain(object, data, size); case NVIF_PERFMON_V0_QUERY_SIGNAL: return nvkm_perfmon_mthd_query_signal(object, data, size); default: