drm/nouveau/pm: allow the userspace to schedule hardware counters
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Sun, 7 Jun 2015 20:40:25 +0000 (22:40 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 28 Aug 2015 02:39:59 +0000 (12:39 +1000)
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 <samuel.pitoiset@gmail.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvif/class.h
drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h

index d85fb0d..528eac8 100644 (file)
@@ -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 {
 };
index ec02abf..5dbb3b4 100644 (file)
@@ -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];
index f954c98..4ed77ff 100644 (file)
@@ -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;