17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2017 Etnaviv Project
37ec681f3Smrg * Copyright (C) 2017 Zodiac Inflight Innovations
47ec681f3Smrg *
57ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
67ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
77ec681f3Smrg * to deal in the Software without restriction, including without limitation
87ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
97ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
107ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
117ec681f3Smrg *
127ec681f3Smrg * The above copyright notice and this permission notice (including the next
137ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
147ec681f3Smrg * Software.
157ec681f3Smrg *
167ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
177ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
197ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
207ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
217ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
227ec681f3Smrg * SOFTWARE.
237ec681f3Smrg *
247ec681f3Smrg * Authors:
257ec681f3Smrg *    Christian Gmeiner <christian.gmeiner@gmail.com>
267ec681f3Smrg */
277ec681f3Smrg
287ec681f3Smrg#include "etnaviv_priv.h"
297ec681f3Smrg
307ec681f3Smrgstatic int etna_perfmon_query_signals(struct etna_perfmon *pm, struct etna_perfmon_domain *dom)
317ec681f3Smrg{
327ec681f3Smrg	struct etna_device *dev = pm->pipe->gpu->dev;
337ec681f3Smrg	struct drm_etnaviv_pm_signal req = {
347ec681f3Smrg		.pipe = pm->pipe->id,
357ec681f3Smrg		.domain = dom->id
367ec681f3Smrg	};
377ec681f3Smrg
387ec681f3Smrg	do {
397ec681f3Smrg		struct etna_perfmon_signal *sig;
407ec681f3Smrg		int ret;
417ec681f3Smrg
427ec681f3Smrg		ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_PM_QUERY_SIG, &req, sizeof(req));
437ec681f3Smrg		if (ret)
447ec681f3Smrg			break;
457ec681f3Smrg
467ec681f3Smrg		sig = calloc(1, sizeof(*sig));
477ec681f3Smrg		if (!sig)
487ec681f3Smrg			return -ENOMEM;
497ec681f3Smrg
507ec681f3Smrg		DEBUG_MSG("perfmon signal:");
517ec681f3Smrg		DEBUG_MSG("id         = %d", req.id);
527ec681f3Smrg		DEBUG_MSG("name       = %s", req.name);
537ec681f3Smrg
547ec681f3Smrg		sig->domain = dom;
557ec681f3Smrg		sig->signal = req.id;
567ec681f3Smrg		strncpy(sig->name, req.name, sizeof(sig->name));
577ec681f3Smrg		list_addtail(&sig->head, &dom->signals);
587ec681f3Smrg	} while (req.iter != 0xffff);
597ec681f3Smrg
607ec681f3Smrg	return 0;
617ec681f3Smrg}
627ec681f3Smrg
637ec681f3Smrgstatic int etna_perfmon_query_domains(struct etna_perfmon *pm)
647ec681f3Smrg{
657ec681f3Smrg	struct etna_device *dev = pm->pipe->gpu->dev;
667ec681f3Smrg	struct drm_etnaviv_pm_domain req = {
677ec681f3Smrg		.pipe = pm->pipe->id
687ec681f3Smrg	};
697ec681f3Smrg
707ec681f3Smrg	do {
717ec681f3Smrg		struct etna_perfmon_domain *dom;
727ec681f3Smrg		int ret;
737ec681f3Smrg
747ec681f3Smrg		ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_PM_QUERY_DOM, &req, sizeof(req));
757ec681f3Smrg		if (ret)
767ec681f3Smrg			break;
777ec681f3Smrg
787ec681f3Smrg		dom = calloc(1, sizeof(*dom));
797ec681f3Smrg		if (!dom)
807ec681f3Smrg			return -ENOMEM;
817ec681f3Smrg
827ec681f3Smrg		list_inithead(&dom->signals);
837ec681f3Smrg		dom->id = req.id;
847ec681f3Smrg		strncpy(dom->name, req.name, sizeof(dom->name));
857ec681f3Smrg		list_addtail(&dom->head, &pm->domains);
867ec681f3Smrg
877ec681f3Smrg		DEBUG_MSG("perfmon domain:");
887ec681f3Smrg		DEBUG_MSG("id         = %d", req.id);
897ec681f3Smrg		DEBUG_MSG("name       = %s", req.name);
907ec681f3Smrg		DEBUG_MSG("nr_signals = %d", req.nr_signals);
917ec681f3Smrg
927ec681f3Smrg		/* Query all available signals for this domain. */
937ec681f3Smrg		if (req.nr_signals > 0) {
947ec681f3Smrg			ret = etna_perfmon_query_signals(pm, dom);
957ec681f3Smrg			if (ret)
967ec681f3Smrg				return ret;
977ec681f3Smrg		}
987ec681f3Smrg	} while (req.iter != 0xff);
997ec681f3Smrg
1007ec681f3Smrg	return 0;
1017ec681f3Smrg}
1027ec681f3Smrg
1037ec681f3Smrgstatic void etna_perfmon_free_signals(struct etna_perfmon_domain *dom)
1047ec681f3Smrg{
1057ec681f3Smrg	struct etna_perfmon_signal *sig, *next;
1067ec681f3Smrg
1077ec681f3Smrg	LIST_FOR_EACH_ENTRY_SAFE(sig, next, &dom->signals, head) {
1087ec681f3Smrg		list_del(&sig->head);
1097ec681f3Smrg		free(sig);
1107ec681f3Smrg	}
1117ec681f3Smrg}
1127ec681f3Smrg
1137ec681f3Smrgstatic void etna_perfmon_free_domains(struct etna_perfmon *pm)
1147ec681f3Smrg{
1157ec681f3Smrg	struct etna_perfmon_domain *dom, *next;
1167ec681f3Smrg
1177ec681f3Smrg	LIST_FOR_EACH_ENTRY_SAFE(dom, next, &pm->domains, head) {
1187ec681f3Smrg		etna_perfmon_free_signals(dom);
1197ec681f3Smrg		list_del(&dom->head);
1207ec681f3Smrg		free(dom);
1217ec681f3Smrg	}
1227ec681f3Smrg}
1237ec681f3Smrg
1247ec681f3Smrgstruct etna_perfmon *etna_perfmon_create(struct etna_pipe *pipe)
1257ec681f3Smrg{
1267ec681f3Smrg	struct etna_perfmon *pm;
1277ec681f3Smrg	int ret;
1287ec681f3Smrg
1297ec681f3Smrg	pm = calloc(1, sizeof(*pm));
1307ec681f3Smrg	if (!pm) {
1317ec681f3Smrg		ERROR_MSG("allocation failed");
1327ec681f3Smrg		return NULL;
1337ec681f3Smrg	}
1347ec681f3Smrg
1357ec681f3Smrg	list_inithead(&pm->domains);
1367ec681f3Smrg	pm->pipe = pipe;
1377ec681f3Smrg
1387ec681f3Smrg	/* query all available domains and sources for this device */
1397ec681f3Smrg	ret = etna_perfmon_query_domains(pm);
1407ec681f3Smrg	if (ret)
1417ec681f3Smrg		goto fail;
1427ec681f3Smrg
1437ec681f3Smrg	return pm;
1447ec681f3Smrg
1457ec681f3Smrgfail:
1467ec681f3Smrg	etna_perfmon_del(pm);
1477ec681f3Smrg	return NULL;
1487ec681f3Smrg}
1497ec681f3Smrg
1507ec681f3Smrgvoid etna_perfmon_del(struct etna_perfmon *pm)
1517ec681f3Smrg{
1527ec681f3Smrg	if (!pm)
1537ec681f3Smrg		return;
1547ec681f3Smrg
1557ec681f3Smrg	etna_perfmon_free_domains(pm);
1567ec681f3Smrg	free(pm);
1577ec681f3Smrg}
1587ec681f3Smrg
1597ec681f3Smrgstruct etna_perfmon_domain *etna_perfmon_get_dom_by_name(struct etna_perfmon *pm, const char *name)
1607ec681f3Smrg{
1617ec681f3Smrg	struct etna_perfmon_domain *dom;
1627ec681f3Smrg
1637ec681f3Smrg	if (pm) {
1647ec681f3Smrg		LIST_FOR_EACH_ENTRY(dom, &pm->domains, head) {
1657ec681f3Smrg			if (!strcmp(dom->name, name))
1667ec681f3Smrg				return dom;
1677ec681f3Smrg		}
1687ec681f3Smrg	}
1697ec681f3Smrg
1707ec681f3Smrg	return NULL;
1717ec681f3Smrg}
1727ec681f3Smrg
1737ec681f3Smrgstruct etna_perfmon_signal *etna_perfmon_get_sig_by_name(struct etna_perfmon_domain *dom, const char *name)
1747ec681f3Smrg{
1757ec681f3Smrg	struct etna_perfmon_signal *signal;
1767ec681f3Smrg
1777ec681f3Smrg	if (dom) {
1787ec681f3Smrg		LIST_FOR_EACH_ENTRY(signal, &dom->signals, head) {
1797ec681f3Smrg			if (!strcmp(signal->name, name))
1807ec681f3Smrg				return signal;
1817ec681f3Smrg		}
1827ec681f3Smrg	}
1837ec681f3Smrg
1847ec681f3Smrg	return NULL;
1857ec681f3Smrg}
186