From 3bfdde178a959cb5e490e4a3a2433c95a9a1af26 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:25 +0200 Subject: [PATCH] drm/nouveau/pm: allow the userspace to schedule hardware counters This adds a new method NVIF_PERFCTR_V0_INIT which starts a batch of hardware counters for sampling. This will allow the userspace to start a monitoring session using the INIT method and to stop it with SAMPLE, for example before and after a frame is rendered. This commit temporarily breaks nv_perfmon but this is going to be fixed with the upcoming patch. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 8 ++- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 64 ++++++++++++------- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 1 + 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index d85fb0d945e8..528eac8c8403 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -300,8 +300,12 @@ struct nvif_perfctr_v0 { __u8 pad06[4]; }; -#define NVIF_PERFCTR_V0_SAMPLE 0x00 -#define NVIF_PERFCTR_V0_READ 0x01 +#define NVIF_PERFCTR_V0_INIT 0x00 +#define NVIF_PERFCTR_V0_SAMPLE 0x01 +#define NVIF_PERFCTR_V0_READ 0x02 + +struct nvif_perfctr_init { +}; struct nvif_perfctr_sample { }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index ec02abfd86b0..5dbb3b4e2ebb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -306,6 +306,36 @@ nvkm_perfmon_ofuncs = { /******************************************************************************* * Perfctr object classes ******************************************************************************/ +static int +nvkm_perfctr_init(struct nvkm_object *object, void *data, u32 size) +{ + union { + struct nvif_perfctr_init none; + } *args = data; + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfctr *ctr = (void *)object; + struct nvkm_perfdom *dom = ctr->dom; + int ret; + + nv_ioctl(object, "perfctr init size %d\n", size); + if (nvif_unvers(args->none)) { + nv_ioctl(object, "perfctr init\n"); + } else + return ret; + + ctr->slot = ffs(dom->quad) - 1; + if (ctr->slot < 0) { + /* no free slots are available */ + return -EINVAL; + } + dom->quad &= ~(QUAD_FREE << ctr->slot); + dom->func->init(ppm, dom, ctr); + + /* start next batch of counters for sampling */ + dom->func->next(ppm, dom); + return 0; +} + static int nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) { @@ -313,7 +343,7 @@ nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) struct nvif_perfctr_sample none; } *args = data; struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfctr *ctr, *tmp; + struct nvkm_perfctr *ctr; struct nvkm_perfdom *dom; int ret; @@ -328,32 +358,15 @@ nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) /* sample previous batch of counters */ if (dom->quad != QUAD_MASK) { dom->func->next(ppm, dom); - tmp = NULL; - while (!list_empty(&dom->list)) { - ctr = list_first_entry(&dom->list, - typeof(*ctr), head); - if (ctr->slot < 0) break; - if ( tmp && tmp == ctr) break; - if (!tmp) tmp = ctr; + + /* read counter values */ + list_for_each_entry(ctr, &dom->list, head) { dom->func->read(ppm, dom, ctr); - ctr->slot = -1; - list_move_tail(&ctr->head, &dom->list); + ctr->slot = -1; } - } - - dom->quad = QUAD_MASK; - /* setup next batch of counters for sampling */ - list_for_each_entry(ctr, &dom->list, head) { - ctr->slot = ffs(dom->quad) - 1; - if (ctr->slot < 0) - break; - dom->quad &= ~(QUAD_FREE << ctr->slot); - dom->func->init(ppm, dom, ctr); + dom->quad = QUAD_MASK; } - - if (dom->quad != QUAD_MASK) - dom->func->next(ppm, dom); } return 0; @@ -386,6 +399,8 @@ static int nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { switch (mthd) { + case NVIF_PERFCTR_V0_INIT: + return nvkm_perfctr_init(object, data, size); case NVIF_PERFCTR_V0_SAMPLE: return nvkm_perfctr_sample(object, data, size); case NVIF_PERFCTR_V0_READ: @@ -400,6 +415,8 @@ static void nvkm_perfctr_dtor(struct nvkm_object *object) { struct nvkm_perfctr *ctr = (void *)object; + if (ctr->dom) + ctr->dom->quad |= (QUAD_FREE << ctr->slot); if (ctr->head.next) list_del(&ctr->head); nvkm_object_destroy(&ctr->base); @@ -441,6 +458,7 @@ nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + ctr->dom = dom; ctr->slot = -1; ctr->logic_op = args->v0.logic_op; ctr->signal[0] = sig[0]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index f954c9868594..4ed77ff4922c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -6,6 +6,7 @@ struct nvkm_perfctr { struct nvkm_object base; struct list_head head; struct nvkm_perfsig *signal[4]; + struct nvkm_perfdom *dom; int slot; u32 logic_op; u32 clk; -- 2.20.1