xref: /aosp_15_r20/external/mesa3d/src/freedreno/perfcntrs/freedreno_dt.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2021 Google, Inc.
3  * All Rights Reserved.
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include <fcntl.h>
8 #include <ftw.h>
9 #include <inttypes.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <arpa/inet.h>
16 #include <sys/mman.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 
20 #include "util/macros.h"
21 #include "util/os_file.h"
22 
23 #include "freedreno_dt.h"
24 
25 static struct {
26    char *dtnode;
27    int address_cells, size_cells;
28    uint64_t base;
29    uint32_t size;
30    uint32_t min_freq;
31    uint32_t max_freq;
32 } dev;
33 
34 /*
35  * code to find stuff in /proc/device-tree:
36  *
37  * NOTE: if we sampled the counters from the cmdstream, we could avoid needing
38  * /dev/mem and /proc/device-tree crawling.  OTOH when the GPU is heavily loaded
39  * we would be competing with whatever else is using the GPU.
40  */
41 
42 static void *
readdt(const char * node)43 readdt(const char *node)
44 {
45    char *path;
46    void *buf;
47    size_t sz;
48 
49    (void)asprintf(&path, "%s/%s", dev.dtnode, node);
50    buf = os_read_file(path, &sz);
51    free(path);
52 
53    return buf;
54 }
55 
56 static int
find_freqs_fn(const char * fpath,const struct stat * sb,int typeflag,struct FTW * ftwbuf)57 find_freqs_fn(const char *fpath, const struct stat *sb, int typeflag,
58               struct FTW *ftwbuf)
59 {
60    const char *fname = fpath + ftwbuf->base;
61    size_t sz;
62 
63    if (strcmp(fname, "qcom,gpu-freq") == 0) {
64       uint32_t *buf = (uint32_t *)os_read_file(fpath, &sz);
65       uint32_t freq = ntohl(buf[0]);
66       free(buf);
67       dev.max_freq = MAX2(dev.max_freq, freq);
68       dev.min_freq = MIN2(dev.min_freq, freq);
69    }
70 
71    return 0;
72 }
73 
74 static void
find_freqs(void)75 find_freqs(void)
76 {
77    char *path;
78 
79    dev.min_freq = ~0;
80    dev.max_freq = 0;
81 
82    (void)asprintf(&path, "%s/%s", dev.dtnode, "qcom,gpu-pwrlevels");
83 
84    nftw(path, find_freqs_fn, 64, 0);
85 
86    free(path);
87 }
88 
89 static const char *compatibles[] = {
90    "qcom,adreno-3xx",
91    "qcom,kgsl-3d0",
92    "amd,imageon",
93    "qcom,adreno",
94 };
95 
96 /**
97  * compatstrs is a list of compatible strings separated by null, ie.
98  *
99  *       compatible = "qcom,adreno-630.2", "qcom,adreno";
100  *
101  * would result in "qcom,adreno-630.2\0qcom,adreno\0"
102  */
103 static bool
match_compatible(char * compatstrs,int sz)104 match_compatible(char *compatstrs, int sz)
105 {
106    while (sz > 0) {
107       char *compatible = compatstrs;
108 
109       for (unsigned i = 0; i < ARRAY_SIZE(compatibles); i++) {
110          if (strcmp(compatible, compatibles[i]) == 0) {
111             return true;
112          }
113       }
114 
115       compatstrs += strlen(compatible) + 1;
116       sz -= strlen(compatible) + 1;
117    }
118    return false;
119 }
120 
121 static int
find_device_fn(const char * fpath,const struct stat * sb,int typeflag,struct FTW * ftwbuf)122 find_device_fn(const char *fpath, const struct stat *sb, int typeflag,
123                struct FTW *ftwbuf)
124 {
125    const char *fname = fpath + ftwbuf->base;
126    size_t sz;
127 
128    if (strcmp(fname, "compatible") == 0) {
129       char *str = os_read_file(fpath, &sz);
130       if (match_compatible(str, sz)) {
131          int dlen = strlen(fpath) - strlen("/compatible");
132          dev.dtnode = malloc(dlen + 1);
133          memcpy(dev.dtnode, fpath, dlen);
134          dev.dtnode[dlen] = '\0';
135          printf("found dt node: %s\n", dev.dtnode);
136 
137          char buf[dlen + sizeof("/../#address-cells") + 1];
138          size_t sz;
139          int *val;
140 
141          sprintf(buf, "%s/../#address-cells", dev.dtnode);
142          val = (int *)os_read_file(buf, &sz);
143          dev.address_cells = ntohl(*val);
144          free(val);
145 
146          sprintf(buf, "%s/../#size-cells", dev.dtnode);
147          val = (int *)os_read_file(buf, &sz);
148          dev.size_cells = ntohl(*val);
149          free(val);
150 
151          printf("#address-cells=%d, #size-cells=%d\n", dev.address_cells,
152                 dev.size_cells);
153       }
154       free(str);
155    }
156    if (dev.dtnode) {
157       /* we found it! */
158       return 1;
159    }
160    return 0;
161 }
162 
163 static bool
find_device(void)164 find_device(void)
165 {
166    int ret;
167    uint32_t *buf, *b;
168 
169    if (dev.dtnode)
170       return true;
171 
172    ret = nftw("/proc/device-tree/", find_device_fn, 64, 0);
173    if (ret < 0)
174       return false;
175 
176    if (!dev.dtnode)
177       return false;
178 
179    b = buf = readdt("reg");
180 
181    if (dev.address_cells == 2) {
182       uint32_t u[2] = {ntohl(buf[0]), ntohl(buf[1])};
183       dev.base = (((uint64_t)u[0]) << 32) | u[1];
184       buf += 2;
185    } else {
186       dev.base = ntohl(buf[0]);
187       buf += 1;
188    }
189 
190    if (dev.size_cells == 2) {
191       uint32_t u[2] = {ntohl(buf[0]), ntohl(buf[1])};
192       dev.size = (((uint64_t)u[0]) << 32) | u[1];
193       buf += 2;
194    } else {
195       dev.size = ntohl(buf[0]);
196       buf += 1;
197    }
198 
199    free(b);
200 
201    printf("i/o region at %08" PRIx64 " (size: %x)\n", dev.base, dev.size);
202 
203    find_freqs();
204 
205    printf("min_freq=%u, max_freq=%u\n", dev.min_freq, dev.max_freq);
206 
207    return true;
208 }
209 
210 bool
fd_dt_find_freqs(uint32_t * min_freq,uint32_t * max_freq)211 fd_dt_find_freqs(uint32_t *min_freq, uint32_t *max_freq)
212 {
213    if (!find_device())
214       return false;
215 
216    *min_freq = dev.min_freq;
217    *max_freq = dev.max_freq;
218 
219    return true;
220 }
221 
222 void *
fd_dt_find_io(void)223 fd_dt_find_io(void)
224 {
225    if (!find_device())
226       return NULL;
227 
228    int fd = open("/dev/mem", O_RDWR | O_SYNC);
229    if (fd < 0)
230       return NULL;
231 
232    void *io =
233       mmap(0, dev.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, dev.base);
234    close(fd);
235    if (io == MAP_FAILED)
236       return NULL;
237 
238    return io;
239 }
240