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 <samuel.pitoiset@gmail.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Samuel Pitoiset 2015-06-07 22:40:17 +02:00 committed by Ben Skeggs
parent 44d9de58ea
commit 45f0f94db2
2 changed files with 96 additions and 1 deletions

View File

@ -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;

View File

@ -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: