Configuring counters from the userspace require the kernel to handle some
logic related to performance counters. Basically, it has to find a free
slot to assign a counter, to handle extra counting modes like B4/B6 and it
must return and error when it can't configure a counter.

In my opinion, the kernel should not handle all of that logic but it
should only write the configuration sent by the userspace without
checking anything. In other words, it should overwrite the configuration
even if it's already counting and do not return any errors.

This patch allows the userspace to configure a domain instead of
separate counters. This has the advantage to move all of the logic to
the userspace.

Signed-off-by: Samuel Pitoiset <samuel.pitoi...@gmail.com>
---
 bin/nv_perfmon.c                   | 193 ++++++++++++++++++++++++++--------
 drm/nouveau/include/nvif/class.h   |  30 +++---
 drm/nouveau/include/nvif/ioctl.h   |   2 +-
 drm/nouveau/nvkm/engine/pm/base.c  | 208 +++++++++++++++++++++----------------
 drm/nouveau/nvkm/engine/pm/gf100.c |  10 +-
 drm/nouveau/nvkm/engine/pm/nv40.c  |  10 +-
 drm/nouveau/nvkm/engine/pm/priv.h  |  10 +-
 7 files changed, 293 insertions(+), 170 deletions(-)

diff --git a/bin/nv_perfmon.c b/bin/nv_perfmon.c
index 50c7777..47b2fef 100644
--- a/bin/nv_perfmon.c
+++ b/bin/nv_perfmon.c
@@ -248,7 +248,8 @@ ui_menu_win = {
 
 struct ui_perfmon_dom {
        struct list_head head;
-       struct list_head list;
+       struct list_head signals;
+       struct list_head perfdoms;
        u8 id;
 };
 
@@ -260,22 +261,27 @@ struct ui_perfmon_sig {
 
 struct ui_main {
        struct list_head head;
-       u32 handle;
-       struct nvif_object object;
-       const char *name;
+       struct ui_perfmon_sig *sig;
        u32 clk;
        u32 ctr;
        u64 incr;
 };
 
+struct ui_perfdom {
+       struct nvif_object object;
+       struct list_head head;
+       struct ui_main *ctr[4];
+       u32 handle;
+};
+
 static struct list_head ui_main_list = LIST_HEAD_INIT(ui_main_list);
 static struct list_head ui_doms_list = LIST_HEAD_INIT(ui_doms_list);
+static struct list_head ui_perfdom_list = LIST_HEAD_INIT(ui_perfdom_list);
 static u32 ui_main_handle = 0xc0000000;
 
 static void
 ui_main_remove(struct ui_main *item)
 {
-       nvif_object_fini(&item->object);
        list_del(&item->head);
        free(item);
 }
@@ -303,7 +309,7 @@ ui_perfmon_query_signals(struct nvif_object *perfmon,
                        sig->signal = args.signal;
                        sig->name = malloc(sizeof(args.name));
                        strncpy(sig->name, args.name, sizeof(args.name));
-                       list_add_tail(&sig->head, &dom->list);
+                       list_add_tail(&sig->head, &dom->signals);
 
                        args.iter = prev_iter;
                        ret = nvif_mthd(perfmon, NVIF_PERFMON_V0_QUERY_SIGNAL,
@@ -331,7 +337,8 @@ ui_perfmon_query_domains(struct nvif_object *perfmon)
                if (prev_iter) {
                        dom = calloc(1, sizeof(*dom));
                        dom->id = args.id;
-                       INIT_LIST_HEAD(&dom->list);
+                       INIT_LIST_HEAD(&dom->signals);
+                       INIT_LIST_HEAD(&dom->perfdoms);
                        list_add_tail(&dom->head, &ui_doms_list);
 
                        args.iter = prev_iter;
@@ -346,6 +353,49 @@ ui_perfmon_query_domains(struct nvif_object *perfmon)
 }
 
 static void
+ui_perfdom_init(struct ui_perfdom *dom)
+{
+       struct nvif_perfdom_init args = {};
+       int ret;
+
+       ret = nvif_mthd(&dom->object, NVIF_PERFDOM_V0_INIT,
+                       &args, sizeof(args));
+       assert(ret == 0);
+}
+
+static void
+ui_perfdom_sample(struct ui_perfdom *dom)
+{
+       struct nvif_perfdom_sample args = {};
+       int ret;
+
+       ret = nvif_mthd(&dom->object, NVIF_PERFDOM_V0_SAMPLE,
+                       &args, sizeof(args));
+       assert(ret == 0);
+}
+
+static void
+ui_perfdom_read(struct ui_perfdom *dom)
+{
+       struct nvif_perfdom_read_v0 args = {};
+       int ret, i;
+
+       ret = nvif_mthd(&dom->object, NVIF_PERFDOM_V0_READ,
+                       &args, sizeof(args));
+       assert(ret == 0 || ret == -EAGAIN);
+
+       if (ret == 0) {
+               for (i = 0; i < 4; i++) {
+                       if (!dom->ctr[i])
+                               continue;
+                       dom->ctr[i]->ctr   = args.ctr[i];
+                       dom->ctr[i]->incr += args.ctr[i];
+                       dom->ctr[i]->clk   = args.clk;
+               }
+       }
+}
+
+static void
 ui_perfmon_init(void)
 {
        struct nvif_object perfmon;
@@ -362,17 +412,37 @@ ui_perfmon_init(void)
 }
 
 static void
+ui_perfmon_free_signals(struct ui_perfmon_dom *dom)
+{
+       struct ui_perfmon_sig *sig, *next;
+
+       list_for_each_entry_safe(sig, next, &dom->signals, head) {
+               list_del(&sig->head);
+               free(sig->name);
+               free(sig);
+       }
+}
+
+static void
+ui_perfmon_free_perfdoms(struct ui_perfmon_dom *dom)
+{
+       struct ui_perfdom *perfdom, *next;
+
+       list_for_each_entry_safe(perfdom, next, &dom->perfdoms, head) {
+               nvif_object_fini(&perfdom->object);
+               list_del(&perfdom->head);
+               free(perfdom);
+       }
+}
+
+static void
 ui_perfmon_fini(void)
 {
-       struct ui_perfmon_dom *dom, *next_dom;
-       struct ui_perfmon_sig *sig, *next_sig;
-
-       list_for_each_entry_safe(dom, next_dom, &ui_doms_list, head) {
-               list_for_each_entry_safe(sig, next_sig, &dom->list, head) {
-                       list_del(&sig->head);
-                       free(sig->name);
-                       free(sig);
-               }
+       struct ui_perfmon_dom *dom, *next;
+
+       list_for_each_entry_safe(dom, next, &ui_doms_list, head) {
+               ui_perfmon_free_perfdoms(dom);
+               ui_perfmon_free_signals(dom);
                list_del(&dom->head);
                free(dom);
        }
@@ -384,31 +454,62 @@ ui_main_select(void)
        struct ui_main *item, *temp;
        struct ui_perfmon_dom *dom;
        struct ui_perfmon_sig *sig;
+       struct ui_perfdom *perfdom;
        int ret;
+       int i;
 
        list_for_each_entry_safe(item, temp, &ui_main_list, head) {
                ui_main_remove(item);
        }
 
        list_for_each_entry(dom, &ui_doms_list, head) {
-               list_for_each_entry(sig, &dom->list, head) {
-                       struct nvif_perfctr_v0 args = {
-                               .logic_op = 0xaaaa,
-                               .domain = dom->id,
-                       };
+               list_for_each_entry(sig, &dom->signals, head) {
+                       bool found = false;
 
                        item = calloc(1, sizeof(*item));
-                       item->handle = ui_main_handle++;
-                       item->name = sig->name;
+                       item->sig = sig;
+                       list_add_tail(&item->head, &ui_main_list);
+
+                       /* find a slot */
+                       list_for_each_entry(perfdom, &dom->perfdoms, head) {
+                               for (i = 0; i < 4; i++) {
+                                       if (!perfdom->ctr[i]) {
+                                               perfdom->ctr[i] = item;
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if (!found) {
+                               /* no free slots, create a new perfdom */
+                               perfdom = calloc(1, sizeof(*perfdom));
+                               perfdom->handle = ui_main_handle++;
+                               perfdom->ctr[0] = item;
+                               list_add_tail(&perfdom->head, &dom->perfdoms);
+                       }
+               }
+
+               /* init perfdom objects */
+               list_for_each_entry(perfdom, &dom->perfdoms, head) {
+                       struct nvif_perfdom_v0 args = {};
+                       int i;
+
+                       args.domain = dom->id;
+                       for (i = 0; i < 4; i++) {
+                               struct ui_main *ctr = perfdom->ctr[i];
+                               if (!ctr)
+                                       continue;
+                               args.ctr[i].signal[0] = ctr->sig->signal;
+                               args.ctr[i].logic_op  = 0xaaaa;
+                       }
 
-                       args.signal[0] = sig->signal;
                        ret = nvif_object_init(nvif_object(device), NULL,
-                                              item->handle,
-                                              NVIF_IOCTL_NEW_V0_PERFCTR,
+                                              perfdom->handle,
+                                              NVIF_IOCTL_NEW_V0_PERFDOM,
                                               &args, sizeof(args),
-                                              &item->object);
+                                              &perfdom->object);
                        assert(ret == 0);
-                       list_add_tail(&item->head, &ui_main_list);
                }
        }
 }
@@ -416,34 +517,34 @@ ui_main_select(void)
 static void
 ui_main_alarm_handler(int signal)
 {
-       struct ui_main *item;
+       struct ui_perfmon_dom *dom;
+       struct ui_perfdom *perfdom;
        bool sampled = false;
 
        if (list_empty(&ui_main_list))
                ui_main_select();
 
-       list_for_each_entry(item, &ui_main_list, head) {
-               struct nvif_perfctr_read_v0 args = {};
-               int ret;
+       list_for_each_entry(dom, &ui_doms_list, head) {
+               if (list_empty(&dom->perfdoms))
+                       continue;
 
-               if (!sampled) {
-                       struct nvif_perfctr_sample args = {};
+               perfdom = list_first_entry(&dom->perfdoms,
+                                          typeof(*perfdom), head);
 
-                       ret = nvif_mthd(&item->object, NVIF_PERFCTR_V0_SAMPLE,
-                                       &args, sizeof(args));
-                       assert(ret == 0);
+               /* sample previous batch of counters */
+               if (!sampled) {
+                       ui_perfdom_sample(perfdom);
                        sampled = true;
                }
 
-               ret = nvif_mthd(&item->object, NVIF_PERFCTR_V0_READ,
-                               &args, sizeof(args));
-               assert(ret == 0 || ret == -EAGAIN);
+               /* read previous batch of counters */
+               ui_perfdom_read(perfdom);
 
-               if (ret == 0) {
-                       item->clk = args.clk;
-                       item->ctr = args.ctr;
-               }
-               item->incr += item->ctr;
+               /* setup next batch of counters for sampling */
+               list_move_tail(&perfdom->head, &dom->perfdoms);
+               perfdom = list_first_entry(&dom->perfdoms,
+                                          typeof(*perfdom), head);
+               ui_perfdom_init(perfdom);
        }
 }
 
@@ -485,7 +586,7 @@ ui_main_redraw(struct ui_table *t)
 
        y = 2;
        list_for_each_entry_from(item, &ui_main_list, head) {
-               set_field_buffer(f[0], 0, item->name);
+               set_field_buffer(f[0], 0, item->sig->name);
                set_field_userptr(f[0], item);
                field_opts_on(f[0], O_VISIBLE | O_ACTIVE);
 
diff --git a/drm/nouveau/include/nvif/class.h b/drm/nouveau/include/nvif/class.h
index 528eac8..1a76a7f 100644
--- a/drm/nouveau/include/nvif/class.h
+++ b/drm/nouveau/include/nvif/class.h
@@ -287,34 +287,36 @@ struct nvif_perfmon_query_source_v0 {
 
 
 
/*******************************************************************************
- * perfctr
+ * perfdom
  
******************************************************************************/
 
-struct nvif_perfctr_v0 {
+struct nvif_perfdom_v0 {
        __u8  version;
        __u8  domain;
-       __u8  pad02[2];
-       __u16 logic_op;
-       __u8  pad04[2];
-       __u8  signal[4];
-       __u8  pad06[4];
+       __u8  mode;
+       __u8  pad03[1];
+       struct {
+               __u8  signal[4];
+               __u16 logic_op;
+       } ctr[4];
 };
 
-#define NVIF_PERFCTR_V0_INIT                                               0x00
-#define NVIF_PERFCTR_V0_SAMPLE                                             0x01
-#define NVIF_PERFCTR_V0_READ                                               0x02
+#define NVIF_PERFDOM_V0_INIT                                               0x00
+#define NVIF_PERFDOM_V0_SAMPLE                                             0x01
+#define NVIF_PERFDOM_V0_READ                                               0x02
 
-struct nvif_perfctr_init {
+struct nvif_perfdom_init {
 };
 
-struct nvif_perfctr_sample {
+struct nvif_perfdom_sample {
 };
 
-struct nvif_perfctr_read_v0 {
+struct nvif_perfdom_read_v0 {
        __u8  version;
        __u8  pad01[7];
-       __u32 ctr;
+       __u32 ctr[4];
        __u32 clk;
+       __u8  pad04[4];
 };
 
 
diff --git a/drm/nouveau/include/nvif/ioctl.h b/drm/nouveau/include/nvif/ioctl.h
index 517cd27..2eb9b89 100644
--- a/drm/nouveau/include/nvif/ioctl.h
+++ b/drm/nouveau/include/nvif/ioctl.h
@@ -50,7 +50,7 @@ struct nvif_ioctl_new_v0 {
        __u32 handle;
 /* these class numbers are made up by us, and not nvidia-assigned */
 #define NVIF_IOCTL_NEW_V0_PERFMON                                    0x0000ffff
-#define NVIF_IOCTL_NEW_V0_PERFCTR                                    0x0000fffe
+#define NVIF_IOCTL_NEW_V0_PERFDOM                                    0x0000fffe
 #define NVIF_IOCTL_NEW_V0_CONTROL                                    0x0000fffd
        __u32 oclass;
        __u8  data[];           /* class data (class.h) */
diff --git a/drm/nouveau/nvkm/engine/pm/base.c 
b/drm/nouveau/nvkm/engine/pm/base.c
index 5dbb3b4..8960bf4 100644
--- a/drm/nouveau/nvkm/engine/pm/base.c
+++ b/drm/nouveau/nvkm/engine/pm/base.c
@@ -31,9 +31,6 @@
 #include <nvif/ioctl.h>
 #include <nvif/unpack.h>
 
-#define QUAD_MASK 0x0f
-#define QUAD_FREE 0x01
-
 static u8
 nvkm_pm_count_perfdom(struct nvkm_pm *ppm)
 {
@@ -304,32 +301,27 @@ nvkm_perfmon_ofuncs = {
 };
 
 
/*******************************************************************************
- * Perfctr object classes
+ * Perfdom object classes
  
******************************************************************************/
 static int
-nvkm_perfctr_init(struct nvkm_object *object, void *data, u32 size)
+nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size)
 {
        union {
-               struct nvif_perfctr_init none;
+               struct nvif_perfdom_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;
+       struct nvkm_perfdom *dom = (void *)object;
+       int ret, i;
 
-       nv_ioctl(object, "perfctr init size %d\n", size);
+       nv_ioctl(object, "perfdom init size %d\n", size);
        if (nvif_unvers(args->none)) {
-               nv_ioctl(object, "perfctr init\n");
+               nv_ioctl(object, "perfdom 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);
+       for (i = 0; i < 4; i++)
+               if (dom->ctr[i])
+                       dom->func->init(ppm, dom, dom->ctr[i]);
 
        /* start next batch of counters for sampling */
        dom->func->next(ppm, dom);
@@ -337,74 +329,70 @@ nvkm_perfctr_init(struct nvkm_object *object, void *data, 
u32 size)
 }
 
 static int
-nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size)
+nvkm_perfdom_sample(struct nvkm_object *object, void *data, u32 size)
 {
        union {
-               struct nvif_perfctr_sample none;
+               struct nvif_perfdom_sample none;
        } *args = data;
        struct nvkm_pm *ppm = (void *)object->engine;
-       struct nvkm_perfctr *ctr;
        struct nvkm_perfdom *dom;
        int ret;
 
-       nv_ioctl(object, "perfctr sample size %d\n", size);
+       nv_ioctl(object, "perfdom sample size %d\n", size);
        if (nvif_unvers(args->none)) {
-               nv_ioctl(object, "perfctr sample\n");
+               nv_ioctl(object, "perfdom sample\n");
        } else
                return ret;
        ppm->sequence++;
 
-       list_for_each_entry(dom, &ppm->domains, head) {
-               /* sample previous batch of counters */
-               if (dom->quad != QUAD_MASK) {
-                       dom->func->next(ppm, dom);
-
-                       /* read counter values */
-                       list_for_each_entry(ctr, &dom->list, head) {
-                               dom->func->read(ppm, dom, ctr);
-                               ctr->slot = -1;
-                       }
-
-                       dom->quad = QUAD_MASK;
-               }
-       }
+       /* sample previous batch of counters */
+       list_for_each_entry(dom, &ppm->domains, head)
+               dom->func->next(ppm, dom);
 
        return 0;
 }
 
 static int
-nvkm_perfctr_read(struct nvkm_object *object, void *data, u32 size)
+nvkm_perfdom_read(struct nvkm_object *object, void *data, u32 size)
 {
        union {
-               struct nvif_perfctr_read_v0 v0;
+               struct nvif_perfdom_read_v0 v0;
        } *args = data;
-       struct nvkm_perfctr *ctr = (void *)object;
-       int ret;
+       struct nvkm_pm *ppm = (void *)object->engine;
+       struct nvkm_perfdom *dom = (void *)object;
+       int ret, i;
 
-       nv_ioctl(object, "perfctr read size %d\n", size);
+       nv_ioctl(object, "perfdom read size %d\n", size);
        if (nvif_unpack(args->v0, 0, 0, false)) {
-               nv_ioctl(object, "perfctr read vers %d\n", args->v0.version);
+               nv_ioctl(object, "perfdom read vers %d\n", args->v0.version);
        } else
                return ret;
 
-       if (!ctr->clk)
+       for (i = 0; i < 4; i++) {
+               if (dom->ctr[i])
+                       dom->func->read(ppm, dom, dom->ctr[i]);
+       }
+
+       if (!dom->clk)
                return -EAGAIN;
 
-       args->v0.clk = ctr->clk;
-       args->v0.ctr = ctr->ctr;
+       for (i = 0; i < 4; i++)
+               if (dom->ctr[i])
+                       args->v0.ctr[i] = dom->ctr[i]->ctr;
+       args->v0.clk = dom->clk;
        return 0;
 }
 
 static int
-nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+nvkm_perfdom_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:
-               return nvkm_perfctr_read(object, data, size);
+       case NVIF_PERFDOM_V0_INIT:
+               return nvkm_perfdom_init(object, data, size);
+       case NVIF_PERFDOM_V0_SAMPLE:
+               return nvkm_perfdom_sample(object, data, size);
+       case NVIF_PERFDOM_V0_READ:
+               return nvkm_perfdom_read(object, data, size);
        default:
                break;
        }
@@ -412,70 +400,107 @@ nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, 
void *data, u32 size)
 }
 
 static void
-nvkm_perfctr_dtor(struct nvkm_object *object)
+nvkm_perfdom_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);
+       struct nvkm_perfdom *dom = (void *)object;
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               struct nvkm_perfctr *ctr = dom->ctr[i];
+               if (ctr && ctr->head.next)
+                       list_del(&ctr->head);
+               kfree(ctr);
+       }
+       nvkm_object_destroy(&dom->base);
 }
 
 static int
-nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot,
+                struct nvkm_perfsig *signal[4], uint16_t logic_op,
+                struct nvkm_perfctr **pctr)
+{
+       struct nvkm_perfctr *ctr;
+       int i;
+
+       if (!dom)
+               return -EINVAL;
+
+       ctr = *pctr = kzalloc(sizeof(*ctr), GFP_KERNEL);
+       if (!ctr)
+               return -ENOMEM;
+
+       ctr->logic_op = logic_op;
+       ctr->slot     = slot;
+       for (i = 0; i < 4; i++) {
+               if (signal[i])
+                       ctr->signal[i] = signal[i] - dom->signal;
+       }
+       list_add_tail(&ctr->head, &dom->list);
+
+       return 0;
+}
+
+static int
+nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
                  struct nvkm_oclass *oclass, void *data, u32 size,
                  struct nvkm_object **pobject)
 {
        union {
-               struct nvif_perfctr_v0 v0;
+               struct nvif_perfdom_v0 v0;
        } *args = data;
        struct nvkm_pm *ppm = (void *)engine;
-       struct nvkm_perfdom *dom = NULL;
-       struct nvkm_perfsig *sig[4] = {};
-       struct nvkm_perfctr *ctr;
-       int ret, i;
+       struct nvkm_perfdom *sdom = NULL;
+       struct nvkm_perfctr *ctr[4] = {};
+       struct nvkm_perfdom *dom;
+       int c, s;
+       int ret;
 
-       nv_ioctl(parent, "create perfctr size %d\n", size);
+       nv_ioctl(parent, "create perfdom size %d\n", size);
        if (nvif_unpack(args->v0, 0, 0, false)) {
-               nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n",
-                        args->v0.version, args->v0.logic_op);
+               nv_ioctl(parent, "create perfdom vers %d dom %d mode %02x\n",
+                        args->v0.version, args->v0.domain, args->v0.mode);
        } else
                return ret;
 
-       for (i = 0; i < ARRAY_SIZE(args->v0.signal); i++) {
-               sig[i] = nvkm_perfsig_find(ppm, args->v0.domain,
-                                          args->v0.signal[i], &dom);
-               if (args->v0.signal[i] && !sig[i])
-                       return -EINVAL;
+       for (c = 0; c < ARRAY_SIZE(args->v0.ctr); c++) {
+               struct nvkm_perfsig *sig[4] = {};
+               for (s = 0; s < ARRAY_SIZE(args->v0.ctr[c].signal); s++) {
+                       sig[s] = nvkm_perfsig_find(ppm, args->v0.domain,
+                                                  args->v0.ctr[c].signal[s],
+                                                  &sdom);
+                       if (args->v0.ctr[c].signal[s] && !sig[s])
+                               return -EINVAL;
+               }
+
+               ret = nvkm_perfctr_new(sdom, c, sig,
+                                      args->v0.ctr[c].logic_op, &ctr[c]);
+               if (ret)
+                       return ret;
        }
 
-       if (!dom)
+       if (!sdom)
                return -EINVAL;
 
-       ret = nvkm_object_create(parent, engine, oclass, 0, &ctr);
-       *pobject = nv_object(ctr);
+       ret = nvkm_object_create(parent, engine, oclass, 0, &dom);
+       *pobject = nv_object(dom);
        if (ret)
                return ret;
 
-       ctr->dom = dom;
-       ctr->slot = -1;
-       ctr->logic_op = args->v0.logic_op;
-       ctr->signal[0] = sig[0];
-       ctr->signal[1] = sig[1];
-       ctr->signal[2] = sig[2];
-       ctr->signal[3] = sig[3];
-       list_add_tail(&ctr->head, &dom->list);
+       dom->func = sdom->func;
+       dom->addr = sdom->addr;
+       dom->mode = args->v0.mode;
+       for (c = 0; c < ARRAY_SIZE(ctr); c++)
+               dom->ctr[c] = ctr[c];
        return 0;
 }
 
 static struct nvkm_ofuncs
-nvkm_perfctr_ofuncs = {
-       .ctor = nvkm_perfctr_ctor,
-       .dtor = nvkm_perfctr_dtor,
+nvkm_perfdom_ofuncs = {
+       .ctor = nvkm_perfdom_ctor,
+       .dtor = nvkm_perfdom_dtor,
        .init = nvkm_object_init,
        .fini = nvkm_object_fini,
-       .mthd = nvkm_perfctr_mthd,
+       .mthd = nvkm_perfdom_mthd,
 };
 
 struct nvkm_oclass
@@ -484,8 +509,8 @@ nvkm_pm_sclass[] = {
          .handle = NVIF_IOCTL_NEW_V0_PERFMON,
          .ofuncs = &nvkm_perfmon_ofuncs,
        },
-       { .handle = NVIF_IOCTL_NEW_V0_PERFCTR,
-         .ofuncs = &nvkm_perfctr_ofuncs,
+       { .handle = NVIF_IOCTL_NEW_V0_PERFDOM,
+         .ofuncs = &nvkm_perfdom_ofuncs,
        },
        {},
 };
@@ -640,7 +665,6 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 
mask,
                        INIT_LIST_HEAD(&dom->list);
                        dom->func = sdom->func;
                        dom->addr = addr;
-                       dom->quad = QUAD_MASK;
                        dom->signal_nr = sdom->signal_nr;
 
                        ssig = (sdom++)->signal;
diff --git a/drm/nouveau/nvkm/engine/pm/gf100.c 
b/drm/nouveau/nvkm/engine/pm/gf100.c
index 41350d6..edab97a 100644
--- a/drm/nouveau/nvkm/engine/pm/gf100.c
+++ b/drm/nouveau/nvkm/engine/pm/gf100.c
@@ -48,12 +48,10 @@ gf100_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom 
*dom,
        u32 src = 0x00000000;
        int i;
 
-       for (i = 0; i < 4; i++) {
-               if (ctr->signal[i])
-                       src |= (ctr->signal[i] - dom->signal) << (i * 8);
-       }
+       for (i = 0; i < 4; i++)
+               src |= ctr->signal[i] << (i * 8);
 
-       nv_wr32(priv, dom->addr + 0x09c, 0x00040002);
+       nv_wr32(priv, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3));
        nv_wr32(priv, dom->addr + 0x100, 0x00000000);
        nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src);
        nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log);
@@ -72,7 +70,7 @@ gf100_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom 
*dom,
        case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break;
        case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break;
        }
-       cntr->base.clk = nv_rd32(priv, dom->addr + 0x070);
+       dom->clk = nv_rd32(priv, dom->addr + 0x070);
 }
 
 static void
diff --git a/drm/nouveau/nvkm/engine/pm/nv40.c 
b/drm/nouveau/nvkm/engine/pm/nv40.c
index 603874e..1c6d1ca 100644
--- a/drm/nouveau/nvkm/engine/pm/nv40.c
+++ b/drm/nouveau/nvkm/engine/pm/nv40.c
@@ -33,12 +33,10 @@ nv40_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom 
*dom,
        u32 src = 0x00000000;
        int i;
 
-       for (i = 0; i < 4; i++) {
-               if (ctr->signal[i])
-                       src |= (ctr->signal[i] - dom->signal) << (i * 8);
-       }
+       for (i = 0; i < 4; i++)
+               src |= ctr->signal[i] << (i * 8);
 
-       nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001);
+       nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001 | (dom->mode << 4));
        nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src);
        nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log);
 }
@@ -56,7 +54,7 @@ nv40_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom 
*dom,
        case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break;
        case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break;
        }
-       cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr);
+       dom->clk = nv_rd32(priv, 0x00a600 + dom->addr);
 }
 
 static void
diff --git a/drm/nouveau/nvkm/engine/pm/priv.h 
b/drm/nouveau/nvkm/engine/pm/priv.h
index 4ed77ff..38adeb7 100644
--- a/drm/nouveau/nvkm/engine/pm/priv.h
+++ b/drm/nouveau/nvkm/engine/pm/priv.h
@@ -3,13 +3,10 @@
 #include <engine/pm.h>
 
 struct nvkm_perfctr {
-       struct nvkm_object base;
        struct list_head head;
-       struct nvkm_perfsig *signal[4];
-       struct nvkm_perfdom *dom;
+       u8  signal[4];
        int slot;
        u32 logic_op;
-       u32 clk;
        u32 ctr;
 };
 
@@ -63,12 +60,15 @@ struct nvkm_specdom {
 };
 
 struct nvkm_perfdom {
+       struct nvkm_object base;
        struct list_head head;
        struct list_head list;
        const struct nvkm_funcdom *func;
+       struct nvkm_perfctr *ctr[4];
        char name[32];
        u32 addr;
-       u8  quad;
+       u8  mode;
+       u32 clk;
        u16 signal_nr;
        struct nvkm_perfsig signal[];
 };
-- 
2.4.2

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

Reply via email to