summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nvkm/engine/pm
diff options
context:
space:
mode:
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>2015-06-07 22:40:26 +0200
committerBen Skeggs <bskeggs@redhat.com>2015-08-28 12:39:59 +1000
commit0f3804360dd4f88332b9c0b2d7cb4c1f30893cc7 (patch)
tree8132e2f021d8d89456acc627c432e226aa3832f5 /drivers/gpu/drm/nouveau/nvkm/engine/pm
parent3bfdde178a959cb5e490e4a3a2433c95a9a1af26 (diff)
drm/nouveau/pm: allow to configure domains instead of simple counters
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.pitoiset@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/pm')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c208
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c10
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h10
4 files changed, 129 insertions, 109 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
index 5dbb3b4e2ebb..8960bf4ff459 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
+++ b/drivers/gpu/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/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c
index 41350d6199a5..edab97aa918e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c
+++ b/drivers/gpu/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/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
index 603874ec0fba..1c6d1ca4799e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
+++ b/drivers/gpu/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/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
index 4ed77ff4922c..38adeb731b96 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
+++ b/drivers/gpu/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[];
};