Mesa (master): freedreno: Split out devicetree helpers

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Mar 22 21:01:34 UTC 2021


Module: Mesa
Branch: master
Commit: e7202e889ba6ec4dbb846cb163c0b07f99cf2f38
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=e7202e889ba6ec4dbb846cb163c0b07f99cf2f38

Author: Rob Clark <robdclark at chromium.org>
Date:   Thu Mar 18 13:51:40 2021 -0700

freedreno: Split out devicetree helpers

The freedreno pps datasource is going to need the same, so split out
helpers that can be re-used.

Signed-off-by: Rob Clark <robdclark at chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9758>

---

 src/freedreno/perfcntrs/fdperf.c       | 185 +-----------------------
 src/freedreno/perfcntrs/freedreno_dt.c | 255 +++++++++++++++++++++++++++++++++
 src/freedreno/perfcntrs/freedreno_dt.h |  48 +++++++
 src/freedreno/perfcntrs/meson.build    |   2 +
 4 files changed, 310 insertions(+), 180 deletions(-)

diff --git a/src/freedreno/perfcntrs/fdperf.c b/src/freedreno/perfcntrs/fdperf.c
index 8aec968e93c..a84786695ca 100644
--- a/src/freedreno/perfcntrs/fdperf.c
+++ b/src/freedreno/perfcntrs/fdperf.c
@@ -22,22 +22,14 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include <arpa/inet.h>
 #include <assert.h>
-#include <ctype.h>
 #include <err.h>
-#include <fcntl.h>
-#include <ftw.h>
 #include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdint.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
 #include <time.h>
-#include <unistd.h>
 #include <curses.h>
 #include <libconfig.h>
 #include <inttypes.h>
@@ -48,6 +40,7 @@
 
 #include "util/os_file.h"
 
+#include "freedreno_dt.h"
 #include "freedreno_perfcntr.h"
 
 #define MAX_CNTR_PER_GROUP 24
@@ -82,10 +75,6 @@ struct counter_group {
 };
 
 static struct {
-	char *dtnode;
-	int address_cells, size_cells;
-	uint64_t base;
-	uint32_t size;
 	void *io;
 	uint32_t chipid;
 	uint32_t min_freq;
@@ -126,146 +115,10 @@ delta(uint32_t a, uint32_t b)
 		return b - a;
 }
 
-/*
- * code to find stuff in /proc/device-tree:
- *
- * NOTE: if we sampled the counters from the cmdstream, we could avoid needing
- * /dev/mem and /proc/device-tree crawling.  OTOH when the GPU is heavily loaded
- * we would be competing with whatever else is using the GPU.
- */
-
-static void *
-readdt(const char *node)
-{
-	char *path;
-	void *buf;
-	size_t sz;
-
-	(void) asprintf(&path, "%s/%s", dev.dtnode, node);
-	buf = os_read_file(path, &sz);
-	free(path);
-
-	return buf;
-}
-
-static int
-find_freqs_fn(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
-{
-	const char *fname = fpath + ftwbuf->base;
-	size_t sz;
-
-	if (strcmp(fname, "qcom,gpu-freq") == 0) {
-		uint32_t *buf = (uint32_t *)os_read_file(fpath, &sz);
-		uint32_t freq = ntohl(buf[0]);
-		free(buf);
-		dev.max_freq = MAX2(dev.max_freq, freq);
-		dev.min_freq = MIN2(dev.min_freq, freq);
-	}
-
-	return 0;
-}
-
-static void
-find_freqs(void)
-{
-	char *path;
-	int ret;
-
-	dev.min_freq = ~0;
-	dev.max_freq = 0;
-
-	(void) asprintf(&path, "%s/%s", dev.dtnode, "qcom,gpu-pwrlevels");
-
-	ret = nftw(path, find_freqs_fn, 64, 0);
-	if (ret < 0)
-		err(1, "could not find power levels");
-
-	free(path);
-}
-
-static const char * compatibles[] = {
-		"qcom,adreno-3xx",
-		"qcom,kgsl-3d0",
-		"amd,imageon",
-		"qcom,adreno",
-};
-
-/**
- * compatstrs is a list of compatible strings separated by null, ie.
- *
- *       compatible = "qcom,adreno-630.2", "qcom,adreno";
- *
- * would result in "qcom,adreno-630.2\0qcom,adreno\0"
- */
-static bool match_compatible(char *compatstrs, int sz)
-{
-	while (sz > 0) {
-		char *compatible = compatstrs;
-
-		for (unsigned i = 0; i < ARRAY_SIZE(compatibles); i++) {
-			if (strcmp(compatible, compatibles[i]) == 0) {
-				return true;
-			}
-		}
-
-		compatstrs += strlen(compatible) + 1;
-		sz -= strlen(compatible) + 1;
-	}
-	return false;
-}
-
-static int
-find_device_fn(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
-{
-	const char *fname = fpath + ftwbuf->base;
-	size_t sz;
-
-	if (strcmp(fname, "compatible") == 0) {
-		char *str = os_read_file(fpath, &sz);
-		if (match_compatible(str, sz)) {
-			int dlen = strlen(fpath) - strlen("/compatible");
-			dev.dtnode = malloc(dlen + 1);
-			memcpy(dev.dtnode, fpath, dlen);
-			printf("found dt node: %s\n", dev.dtnode);
-
-			char buf[dlen + sizeof("/../#address-cells") + 1];
-			size_t sz;
-			int *val;
-
-			sprintf(buf, "%s/../#address-cells", dev.dtnode);
-			val = (int *)os_read_file(buf, &sz);
-			dev.address_cells = ntohl(*val);
-			free(val);
-
-			sprintf(buf, "%s/../#size-cells", dev.dtnode);
-			val = (int *)os_read_file(buf, &sz);
-			dev.size_cells = ntohl(*val);
-			free(val);
-
-			printf("#address-cells=%d, #size-cells=%d\n",
-					dev.address_cells, dev.size_cells);
-		}
-		free(str);
-	}
-	if (dev.dtnode) {
-		/* we found it! */
-		return 1;
-	}
-	return 0;
-}
-
 static void
 find_device(void)
 {
 	int ret, fd;
-	uint32_t *buf, *b;
-
-	ret = nftw("/proc/device-tree/", find_device_fn, 64, 0);
-	if (ret < 0)
-		err(1, "could not find adreno gpu");
-
-	if (!dev.dtnode)
-		errx(1, "could not find qcom,adreno-3xx node");
 
 	fd = drmOpenWithType("msm", NULL, DRM_NODE_RENDER);
 	if (fd < 0)
@@ -289,37 +142,14 @@ find_device(void)
 		((chipid) >> 0) & 0xff
 	printf("device: a%"CHIP_FMT"\n", CHIP_ARGS(dev.chipid));
 
-	b = buf = readdt("reg");
-
-	if (dev.address_cells == 2) {
-		uint32_t u[2] = { ntohl(buf[0]), ntohl(buf[1]) };
-		dev.base = (((uint64_t)u[0]) << 32) | u[1];
-		buf += 2;
-	} else {
-		dev.base = ntohl(buf[0]);
-		buf += 1;
-	}
-
-	if (dev.size_cells == 2) {
-		uint32_t u[2] = { ntohl(buf[0]), ntohl(buf[1]) };
-		dev.size = (((uint64_t)u[0]) << 32) | u[1];
-		buf += 2;
-	} else {
-		dev.size = ntohl(buf[0]);
-		buf += 1;
-	}
-
-	free(b);
-
-	printf("i/o region at %08"PRIx64" (size: %x)\n", dev.base, dev.size);
-
 	/* try MAX_FREQ first as that will work regardless of old dt
 	 * dt bindings vs upstream bindings:
 	 */
 	ret = fd_pipe_get_param(dev.pipe, FD_MAX_FREQ, &val);
 	if (ret) {
 		printf("falling back to parsing DT bindings for freq\n");
-		find_freqs();
+		if (!fd_dt_find_freqs(&dev.min_freq, &dev.max_freq))
+			err(1, "could not find GPU freqs");
 	} else {
 		dev.min_freq = 0;
 		dev.max_freq = val;
@@ -327,13 +157,8 @@ find_device(void)
 
 	printf("min_freq=%u, max_freq=%u\n", dev.min_freq, dev.max_freq);
 
-	fd = open("/dev/mem", O_RDWR | O_SYNC);
-	if (fd < 0)
-		err(1, "could not open /dev/mem");
-
-	dev.io = mmap(0, dev.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, dev.base);
-	if (dev.io == MAP_FAILED) {
-		close(fd);
+	dev.io = fd_dt_find_io();
+	if (!dev.io) {
 		err(1, "could not map device");
 	}
 }
diff --git a/src/freedreno/perfcntrs/freedreno_dt.c b/src/freedreno/perfcntrs/freedreno_dt.c
new file mode 100644
index 00000000000..4dba61854bb
--- /dev/null
+++ b/src/freedreno/perfcntrs/freedreno_dt.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright © 2021 Google, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "util/macros.h"
+#include "util/os_file.h"
+
+#include "freedreno_dt.h"
+
+static struct {
+	char *dtnode;
+	int address_cells, size_cells;
+	uint64_t base;
+	uint32_t size;
+	uint32_t min_freq;
+	uint32_t max_freq;
+} dev;
+
+
+/*
+ * code to find stuff in /proc/device-tree:
+ *
+ * NOTE: if we sampled the counters from the cmdstream, we could avoid needing
+ * /dev/mem and /proc/device-tree crawling.  OTOH when the GPU is heavily loaded
+ * we would be competing with whatever else is using the GPU.
+ */
+
+static void *
+readdt(const char *node)
+{
+	char *path;
+	void *buf;
+	size_t sz;
+
+	(void) asprintf(&path, "%s/%s", dev.dtnode, node);
+	buf = os_read_file(path, &sz);
+	free(path);
+
+	return buf;
+}
+
+static int
+find_freqs_fn(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
+{
+	const char *fname = fpath + ftwbuf->base;
+	size_t sz;
+
+	if (strcmp(fname, "qcom,gpu-freq") == 0) {
+		uint32_t *buf = (uint32_t *)os_read_file(fpath, &sz);
+		uint32_t freq = ntohl(buf[0]);
+		free(buf);
+		dev.max_freq = MAX2(dev.max_freq, freq);
+		dev.min_freq = MIN2(dev.min_freq, freq);
+	}
+
+	return 0;
+}
+
+static void
+find_freqs(void)
+{
+	char *path;
+
+	dev.min_freq = ~0;
+	dev.max_freq = 0;
+
+	(void) asprintf(&path, "%s/%s", dev.dtnode, "qcom,gpu-pwrlevels");
+
+	nftw(path, find_freqs_fn, 64, 0);
+
+	free(path);
+}
+
+static const char * compatibles[] = {
+		"qcom,adreno-3xx",
+		"qcom,kgsl-3d0",
+		"amd,imageon",
+		"qcom,adreno",
+};
+
+/**
+ * compatstrs is a list of compatible strings separated by null, ie.
+ *
+ *       compatible = "qcom,adreno-630.2", "qcom,adreno";
+ *
+ * would result in "qcom,adreno-630.2\0qcom,adreno\0"
+ */
+static bool match_compatible(char *compatstrs, int sz)
+{
+	while (sz > 0) {
+		char *compatible = compatstrs;
+
+		for (unsigned i = 0; i < ARRAY_SIZE(compatibles); i++) {
+			if (strcmp(compatible, compatibles[i]) == 0) {
+				return true;
+			}
+		}
+
+		compatstrs += strlen(compatible) + 1;
+		sz -= strlen(compatible) + 1;
+	}
+	return false;
+}
+
+static int
+find_device_fn(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
+{
+	const char *fname = fpath + ftwbuf->base;
+	size_t sz;
+
+	if (strcmp(fname, "compatible") == 0) {
+		char *str = os_read_file(fpath, &sz);
+		if (match_compatible(str, sz)) {
+			int dlen = strlen(fpath) - strlen("/compatible");
+			dev.dtnode = malloc(dlen + 1);
+			memcpy(dev.dtnode, fpath, dlen);
+			dev.dtnode[dlen] = '\0';
+			printf("found dt node: %s\n", dev.dtnode);
+
+			char buf[dlen + sizeof("/../#address-cells") + 1];
+			size_t sz;
+			int *val;
+
+			sprintf(buf, "%s/../#address-cells", dev.dtnode);
+			val = (int *)os_read_file(buf, &sz);
+			dev.address_cells = ntohl(*val);
+			free(val);
+
+			sprintf(buf, "%s/../#size-cells", dev.dtnode);
+			val = (int *)os_read_file(buf, &sz);
+			dev.size_cells = ntohl(*val);
+			free(val);
+
+			printf("#address-cells=%d, #size-cells=%d\n",
+					dev.address_cells, dev.size_cells);
+		}
+		free(str);
+	}
+	if (dev.dtnode) {
+		/* we found it! */
+		return 1;
+	}
+	return 0;
+}
+
+static bool
+find_device(void)
+{
+	int ret;
+	uint32_t *buf, *b;
+
+	if (dev.dtnode)
+		return true;
+
+	ret = nftw("/proc/device-tree/", find_device_fn, 64, 0);
+	if (ret < 0)
+		return false;
+
+	if (!dev.dtnode)
+		return false;
+
+	b = buf = readdt("reg");
+
+	if (dev.address_cells == 2) {
+		uint32_t u[2] = { ntohl(buf[0]), ntohl(buf[1]) };
+		dev.base = (((uint64_t)u[0]) << 32) | u[1];
+		buf += 2;
+	} else {
+		dev.base = ntohl(buf[0]);
+		buf += 1;
+	}
+
+	if (dev.size_cells == 2) {
+		uint32_t u[2] = { ntohl(buf[0]), ntohl(buf[1]) };
+		dev.size = (((uint64_t)u[0]) << 32) | u[1];
+		buf += 2;
+	} else {
+		dev.size = ntohl(buf[0]);
+		buf += 1;
+	}
+
+	free(b);
+
+	printf("i/o region at %08"PRIx64" (size: %x)\n", dev.base, dev.size);
+
+	find_freqs();
+
+	printf("min_freq=%u, max_freq=%u\n", dev.min_freq, dev.max_freq);
+
+	return true;
+}
+
+bool
+fd_dt_find_freqs(uint32_t *min_freq, uint32_t *max_freq)
+{
+	if (!find_device())
+		return false;
+
+	*min_freq = dev.min_freq;
+	*max_freq = dev.max_freq;
+
+	return true;
+}
+
+void *
+fd_dt_find_io(void)
+{
+	if (!find_device())
+		return NULL;
+
+	int fd = open("/dev/mem", O_RDWR | O_SYNC);
+	if (fd < 0)
+		return NULL;
+
+	void *io = mmap(0, dev.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, dev.base);
+	if (io == MAP_FAILED) {
+		close(fd);
+		return NULL;
+	}
+
+	return io;
+}
diff --git a/src/freedreno/perfcntrs/freedreno_dt.h b/src/freedreno/perfcntrs/freedreno_dt.h
new file mode 100644
index 00000000000..c08916e68c2
--- /dev/null
+++ b/src/freedreno/perfcntrs/freedreno_dt.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2021 Google, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef FREEDRENO_DT_H_
+#define FREEDRENO_DT_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A helper for extracting information about the GPU from devicetree, and
+ * mapping it's i/o space, etc.
+ *
+ * Note, not-reentrant (due to use of nftw(), etc).
+ */
+
+bool fd_dt_find_freqs(uint32_t *min_freq, uint32_t *max_freq);
+void * fd_dt_find_io(void);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* FREEDRENO_DT_H_ */
diff --git a/src/freedreno/perfcntrs/meson.build b/src/freedreno/perfcntrs/meson.build
index 48370a32b7d..be55df14171 100644
--- a/src/freedreno/perfcntrs/meson.build
+++ b/src/freedreno/perfcntrs/meson.build
@@ -22,6 +22,8 @@ libfreedreno_perfcntrs_files = files(
   'fd2_perfcntr.c',
   'fd5_perfcntr.c',
   'fd6_perfcntr.c',
+  'freedreno_dt.c',
+  'freedreno_dt.h',
   'freedreno_perfcntr.c',
   'freedreno_perfcntr.h',
 )



More information about the mesa-commit mailing list