Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/freedreno/perfcntrs/freedreno_dt.c
4565 views
1
/*
2
* Copyright © 2021 Google, Inc.
3
* All Rights Reserved.
4
*
5
* Permission is hereby granted, free of charge, to any person obtaining a
6
* copy of this software and associated documentation files (the "Software"),
7
* to deal in the Software without restriction, including without limitation
8
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
* and/or sell copies of the Software, and to permit persons to whom the
10
* Software is furnished to do so, subject to the following conditions:
11
*
12
* The above copyright notice and this permission notice (including the next
13
* paragraph) shall be included in all copies or substantial portions of the
14
* Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
* OTHER DEALINGS IN THE SOFTWARE.
23
*/
24
25
#include <fcntl.h>
26
#include <ftw.h>
27
#include <inttypes.h>
28
#include <stdint.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <unistd.h>
33
#include <arpa/inet.h>
34
#include <sys/mman.h>
35
#include <sys/stat.h>
36
#include <sys/types.h>
37
38
#include "util/macros.h"
39
#include "util/os_file.h"
40
41
#include "freedreno_dt.h"
42
43
static struct {
44
char *dtnode;
45
int address_cells, size_cells;
46
uint64_t base;
47
uint32_t size;
48
uint32_t min_freq;
49
uint32_t max_freq;
50
} dev;
51
52
/*
53
* code to find stuff in /proc/device-tree:
54
*
55
* NOTE: if we sampled the counters from the cmdstream, we could avoid needing
56
* /dev/mem and /proc/device-tree crawling. OTOH when the GPU is heavily loaded
57
* we would be competing with whatever else is using the GPU.
58
*/
59
60
static void *
61
readdt(const char *node)
62
{
63
char *path;
64
void *buf;
65
size_t sz;
66
67
(void)asprintf(&path, "%s/%s", dev.dtnode, node);
68
buf = os_read_file(path, &sz);
69
free(path);
70
71
return buf;
72
}
73
74
static int
75
find_freqs_fn(const char *fpath, const struct stat *sb, int typeflag,
76
struct FTW *ftwbuf)
77
{
78
const char *fname = fpath + ftwbuf->base;
79
size_t sz;
80
81
if (strcmp(fname, "qcom,gpu-freq") == 0) {
82
uint32_t *buf = (uint32_t *)os_read_file(fpath, &sz);
83
uint32_t freq = ntohl(buf[0]);
84
free(buf);
85
dev.max_freq = MAX2(dev.max_freq, freq);
86
dev.min_freq = MIN2(dev.min_freq, freq);
87
}
88
89
return 0;
90
}
91
92
static void
93
find_freqs(void)
94
{
95
char *path;
96
97
dev.min_freq = ~0;
98
dev.max_freq = 0;
99
100
(void)asprintf(&path, "%s/%s", dev.dtnode, "qcom,gpu-pwrlevels");
101
102
nftw(path, find_freqs_fn, 64, 0);
103
104
free(path);
105
}
106
107
static const char *compatibles[] = {
108
"qcom,adreno-3xx",
109
"qcom,kgsl-3d0",
110
"amd,imageon",
111
"qcom,adreno",
112
};
113
114
/**
115
* compatstrs is a list of compatible strings separated by null, ie.
116
*
117
* compatible = "qcom,adreno-630.2", "qcom,adreno";
118
*
119
* would result in "qcom,adreno-630.2\0qcom,adreno\0"
120
*/
121
static bool
122
match_compatible(char *compatstrs, int sz)
123
{
124
while (sz > 0) {
125
char *compatible = compatstrs;
126
127
for (unsigned i = 0; i < ARRAY_SIZE(compatibles); i++) {
128
if (strcmp(compatible, compatibles[i]) == 0) {
129
return true;
130
}
131
}
132
133
compatstrs += strlen(compatible) + 1;
134
sz -= strlen(compatible) + 1;
135
}
136
return false;
137
}
138
139
static int
140
find_device_fn(const char *fpath, const struct stat *sb, int typeflag,
141
struct FTW *ftwbuf)
142
{
143
const char *fname = fpath + ftwbuf->base;
144
size_t sz;
145
146
if (strcmp(fname, "compatible") == 0) {
147
char *str = os_read_file(fpath, &sz);
148
if (match_compatible(str, sz)) {
149
int dlen = strlen(fpath) - strlen("/compatible");
150
dev.dtnode = malloc(dlen + 1);
151
memcpy(dev.dtnode, fpath, dlen);
152
dev.dtnode[dlen] = '\0';
153
printf("found dt node: %s\n", dev.dtnode);
154
155
char buf[dlen + sizeof("/../#address-cells") + 1];
156
size_t sz;
157
int *val;
158
159
sprintf(buf, "%s/../#address-cells", dev.dtnode);
160
val = (int *)os_read_file(buf, &sz);
161
dev.address_cells = ntohl(*val);
162
free(val);
163
164
sprintf(buf, "%s/../#size-cells", dev.dtnode);
165
val = (int *)os_read_file(buf, &sz);
166
dev.size_cells = ntohl(*val);
167
free(val);
168
169
printf("#address-cells=%d, #size-cells=%d\n", dev.address_cells,
170
dev.size_cells);
171
}
172
free(str);
173
}
174
if (dev.dtnode) {
175
/* we found it! */
176
return 1;
177
}
178
return 0;
179
}
180
181
static bool
182
find_device(void)
183
{
184
int ret;
185
uint32_t *buf, *b;
186
187
if (dev.dtnode)
188
return true;
189
190
ret = nftw("/proc/device-tree/", find_device_fn, 64, 0);
191
if (ret < 0)
192
return false;
193
194
if (!dev.dtnode)
195
return false;
196
197
b = buf = readdt("reg");
198
199
if (dev.address_cells == 2) {
200
uint32_t u[2] = {ntohl(buf[0]), ntohl(buf[1])};
201
dev.base = (((uint64_t)u[0]) << 32) | u[1];
202
buf += 2;
203
} else {
204
dev.base = ntohl(buf[0]);
205
buf += 1;
206
}
207
208
if (dev.size_cells == 2) {
209
uint32_t u[2] = {ntohl(buf[0]), ntohl(buf[1])};
210
dev.size = (((uint64_t)u[0]) << 32) | u[1];
211
buf += 2;
212
} else {
213
dev.size = ntohl(buf[0]);
214
buf += 1;
215
}
216
217
free(b);
218
219
printf("i/o region at %08" PRIx64 " (size: %x)\n", dev.base, dev.size);
220
221
find_freqs();
222
223
printf("min_freq=%u, max_freq=%u\n", dev.min_freq, dev.max_freq);
224
225
return true;
226
}
227
228
bool
229
fd_dt_find_freqs(uint32_t *min_freq, uint32_t *max_freq)
230
{
231
if (!find_device())
232
return false;
233
234
*min_freq = dev.min_freq;
235
*max_freq = dev.max_freq;
236
237
return true;
238
}
239
240
void *
241
fd_dt_find_io(void)
242
{
243
if (!find_device())
244
return NULL;
245
246
int fd = open("/dev/mem", O_RDWR | O_SYNC);
247
if (fd < 0)
248
return NULL;
249
250
void *io =
251
mmap(0, dev.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, dev.base);
252
close(fd);
253
if (io == MAP_FAILED)
254
return NULL;
255
256
return io;
257
}
258
259