100a23bdaSmrg/*
200a23bdaSmrg * Copyright (C) 2017 Etnaviv Project
300a23bdaSmrg * Copyright (C) 2017 Zodiac Inflight Innovations
400a23bdaSmrg *
500a23bdaSmrg * Permission is hereby granted, free of charge, to any person obtaining a
600a23bdaSmrg * copy of this software and associated documentation files (the "Software"),
700a23bdaSmrg * to deal in the Software without restriction, including without limitation
800a23bdaSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
900a23bdaSmrg * and/or sell copies of the Software, and to permit persons to whom the
1000a23bdaSmrg * Software is furnished to do so, subject to the following conditions:
1100a23bdaSmrg *
1200a23bdaSmrg * The above copyright notice and this permission notice (including the next
1300a23bdaSmrg * paragraph) shall be included in all copies or substantial portions of the
1400a23bdaSmrg * Software.
1500a23bdaSmrg *
1600a23bdaSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1700a23bdaSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1800a23bdaSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1900a23bdaSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2000a23bdaSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2100a23bdaSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2200a23bdaSmrg * SOFTWARE.
2300a23bdaSmrg *
2400a23bdaSmrg * Authors:
2500a23bdaSmrg *    Christian Gmeiner <christian.gmeiner@gmail.com>
2600a23bdaSmrg */
2700a23bdaSmrg
2800a23bdaSmrg#include "etnaviv_priv.h"
2900a23bdaSmrg
3000a23bdaSmrgstatic int etna_perfmon_query_signals(struct etna_perfmon *pm, struct etna_perfmon_domain *dom)
3100a23bdaSmrg{
3200a23bdaSmrg	struct etna_device *dev = pm->pipe->gpu->dev;
3300a23bdaSmrg	struct drm_etnaviv_pm_signal req = {
3400a23bdaSmrg		.pipe = pm->pipe->id,
3500a23bdaSmrg		.domain = dom->id
3600a23bdaSmrg	};
3700a23bdaSmrg
3800a23bdaSmrg	do {
3900a23bdaSmrg		struct etna_perfmon_signal *sig;
4000a23bdaSmrg		int ret;
4100a23bdaSmrg
4200a23bdaSmrg		ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_PM_QUERY_SIG, &req, sizeof(req));
4300a23bdaSmrg		if (ret)
4400a23bdaSmrg			break;
4500a23bdaSmrg
4600a23bdaSmrg		sig = calloc(1, sizeof(*sig));
4700a23bdaSmrg		if (!sig)
4800a23bdaSmrg			return -ENOMEM;
4900a23bdaSmrg
5000a23bdaSmrg		INFO_MSG("perfmon signal:");
5100a23bdaSmrg		INFO_MSG("id         = %d", req.id);
5200a23bdaSmrg		INFO_MSG("name       = %s", req.name);
5300a23bdaSmrg
5400a23bdaSmrg		sig->domain = dom;
5500a23bdaSmrg		sig->signal = req.id;
5600a23bdaSmrg		strncpy(sig->name, req.name, sizeof(sig->name));
5700a23bdaSmrg		list_addtail(&sig->head, &dom->signals);
5800a23bdaSmrg	} while (req.iter != 0xffff);
5900a23bdaSmrg
6000a23bdaSmrg	return 0;
6100a23bdaSmrg}
6200a23bdaSmrg
6300a23bdaSmrgstatic int etna_perfmon_query_domains(struct etna_perfmon *pm)
6400a23bdaSmrg{
6500a23bdaSmrg	struct etna_device *dev = pm->pipe->gpu->dev;
6600a23bdaSmrg	struct drm_etnaviv_pm_domain req = {
6700a23bdaSmrg		.pipe = pm->pipe->id
6800a23bdaSmrg	};
6900a23bdaSmrg
7000a23bdaSmrg	do {
7100a23bdaSmrg		struct etna_perfmon_domain *dom;
7200a23bdaSmrg		int ret;
7300a23bdaSmrg
7400a23bdaSmrg		ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_PM_QUERY_DOM, &req, sizeof(req));
7500a23bdaSmrg		if (ret)
7600a23bdaSmrg			break;
7700a23bdaSmrg
7800a23bdaSmrg		dom = calloc(1, sizeof(*dom));
7900a23bdaSmrg		if (!dom)
8000a23bdaSmrg			return -ENOMEM;
8100a23bdaSmrg
8200a23bdaSmrg		list_inithead(&dom->signals);
8300a23bdaSmrg		dom->id = req.id;
8400a23bdaSmrg		strncpy(dom->name, req.name, sizeof(dom->name));
8500a23bdaSmrg		list_addtail(&dom->head, &pm->domains);
8600a23bdaSmrg
8700a23bdaSmrg		INFO_MSG("perfmon domain:");
8800a23bdaSmrg		INFO_MSG("id         = %d", req.id);
8900a23bdaSmrg		INFO_MSG("name       = %s", req.name);
9000a23bdaSmrg		INFO_MSG("nr_signals = %d", req.nr_signals);
9100a23bdaSmrg
9200a23bdaSmrg		/* Query all available signals for this domain. */
9300a23bdaSmrg		if (req.nr_signals > 0) {
9400a23bdaSmrg			ret = etna_perfmon_query_signals(pm, dom);
9500a23bdaSmrg			if (ret)
9600a23bdaSmrg				return ret;
9700a23bdaSmrg		}
9800a23bdaSmrg	} while (req.iter != 0xff);
9900a23bdaSmrg
10000a23bdaSmrg	return 0;
10100a23bdaSmrg}
10200a23bdaSmrg
10300a23bdaSmrgstatic void etna_perfmon_free_signals(struct etna_perfmon_domain *dom)
10400a23bdaSmrg{
10500a23bdaSmrg	struct etna_perfmon_signal *sig, *next;
10600a23bdaSmrg
10700a23bdaSmrg	LIST_FOR_EACH_ENTRY_SAFE(sig, next, &dom->signals, head) {
10800a23bdaSmrg		list_del(&sig->head);
10900a23bdaSmrg		free(sig);
11000a23bdaSmrg	}
11100a23bdaSmrg}
11200a23bdaSmrg
11300a23bdaSmrgstatic void etna_perfmon_free_domains(struct etna_perfmon *pm)
11400a23bdaSmrg{
11500a23bdaSmrg	struct etna_perfmon_domain *dom, *next;
11600a23bdaSmrg
11700a23bdaSmrg	LIST_FOR_EACH_ENTRY_SAFE(dom, next, &pm->domains, head) {
11800a23bdaSmrg		etna_perfmon_free_signals(dom);
11900a23bdaSmrg		list_del(&dom->head);
12000a23bdaSmrg		free(dom);
12100a23bdaSmrg	}
12200a23bdaSmrg}
12300a23bdaSmrg
1247cdc0497Smrgdrm_public struct etna_perfmon *etna_perfmon_create(struct etna_pipe *pipe)
12500a23bdaSmrg{
12600a23bdaSmrg	struct etna_perfmon *pm;
12700a23bdaSmrg	int ret;
12800a23bdaSmrg
12900a23bdaSmrg	pm = calloc(1, sizeof(*pm));
13000a23bdaSmrg	if (!pm) {
13100a23bdaSmrg		ERROR_MSG("allocation failed");
13200a23bdaSmrg		return NULL;
13300a23bdaSmrg	}
13400a23bdaSmrg
13500a23bdaSmrg	list_inithead(&pm->domains);
13600a23bdaSmrg	pm->pipe = pipe;
13700a23bdaSmrg
13800a23bdaSmrg	/* query all available domains and sources for this device */
13900a23bdaSmrg	ret = etna_perfmon_query_domains(pm);
14000a23bdaSmrg	if (ret)
14100a23bdaSmrg		goto fail;
14200a23bdaSmrg
14300a23bdaSmrg	return pm;
14400a23bdaSmrg
14500a23bdaSmrgfail:
14600a23bdaSmrg	etna_perfmon_del(pm);
14700a23bdaSmrg	return NULL;
14800a23bdaSmrg}
14900a23bdaSmrg
1507cdc0497Smrgdrm_public void etna_perfmon_del(struct etna_perfmon *pm)
15100a23bdaSmrg{
15200a23bdaSmrg	if (!pm)
15300a23bdaSmrg		return;
15400a23bdaSmrg
15500a23bdaSmrg	etna_perfmon_free_domains(pm);
15600a23bdaSmrg	free(pm);
15700a23bdaSmrg}
15800a23bdaSmrg
1597cdc0497Smrgdrm_public struct etna_perfmon_domain *etna_perfmon_get_dom_by_name(struct etna_perfmon *pm, const char *name)
16000a23bdaSmrg{
16100a23bdaSmrg	struct etna_perfmon_domain *dom;
16200a23bdaSmrg
16300a23bdaSmrg	if (pm) {
16400a23bdaSmrg		LIST_FOR_EACH_ENTRY(dom, &pm->domains, head) {
16500a23bdaSmrg			if (!strcmp(dom->name, name))
16600a23bdaSmrg				return dom;
16700a23bdaSmrg		}
16800a23bdaSmrg	}
16900a23bdaSmrg
17000a23bdaSmrg	return NULL;
17100a23bdaSmrg}
17200a23bdaSmrg
1737cdc0497Smrgdrm_public struct etna_perfmon_signal *etna_perfmon_get_sig_by_name(struct etna_perfmon_domain *dom, const char *name)
17400a23bdaSmrg{
17500a23bdaSmrg	struct etna_perfmon_signal *signal;
17600a23bdaSmrg
17700a23bdaSmrg	if (dom) {
17800a23bdaSmrg		LIST_FOR_EACH_ENTRY(signal, &dom->signals, head) {
17900a23bdaSmrg			if (!strcmp(signal->name, name))
18000a23bdaSmrg				return signal;
18100a23bdaSmrg		}
18200a23bdaSmrg	}
18300a23bdaSmrg
18400a23bdaSmrg	return NULL;
18500a23bdaSmrg}
186