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