xref: /linux/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c (revision e3b9f1e81de2083f359bacd2a94bf1c024f2ede0)
1 /*
2  * Copyright (C) 2017 Etnaviv Project
3  * Copyright (C) 2017 Zodiac Inflight Innovations
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "etnaviv_gpu.h"
19 #include "etnaviv_perfmon.h"
20 #include "state_hi.xml.h"
21 
22 struct etnaviv_pm_domain;
23 
24 struct etnaviv_pm_signal {
25 	char name[64];
26 	u32 data;
27 
28 	u32 (*sample)(struct etnaviv_gpu *gpu,
29 	              const struct etnaviv_pm_domain *domain,
30 	              const struct etnaviv_pm_signal *signal);
31 };
32 
33 struct etnaviv_pm_domain {
34 	char name[64];
35 
36 	/* profile register */
37 	u32 profile_read;
38 	u32 profile_config;
39 
40 	u8 nr_signals;
41 	const struct etnaviv_pm_signal *signal;
42 };
43 
44 struct etnaviv_pm_domain_meta {
45 	const struct etnaviv_pm_domain *domains;
46 	u32 nr_domains;
47 };
48 
49 static u32 simple_reg_read(struct etnaviv_gpu *gpu,
50 	const struct etnaviv_pm_domain *domain,
51 	const struct etnaviv_pm_signal *signal)
52 {
53 	return gpu_read(gpu, signal->data);
54 }
55 
56 static u32 perf_reg_read(struct etnaviv_gpu *gpu,
57 	const struct etnaviv_pm_domain *domain,
58 	const struct etnaviv_pm_signal *signal)
59 {
60 	gpu_write(gpu, domain->profile_config, signal->data);
61 
62 	return gpu_read(gpu, domain->profile_read);
63 }
64 
65 static u32 pipe_reg_read(struct etnaviv_gpu *gpu,
66 	const struct etnaviv_pm_domain *domain,
67 	const struct etnaviv_pm_signal *signal)
68 {
69 	u32 clock = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL);
70 	u32 value = 0;
71 	unsigned i;
72 
73 	for (i = 0; i < gpu->identity.pixel_pipes; i++) {
74 		clock &= ~(VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK);
75 		clock |= VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(i);
76 		gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
77 		gpu_write(gpu, domain->profile_config, signal->data);
78 		value += gpu_read(gpu, domain->profile_read);
79 	}
80 
81 	/* switch back to pixel pipe 0 to prevent GPU hang */
82 	clock &= ~(VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK);
83 	clock |= VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(0);
84 	gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock);
85 
86 	return value;
87 }
88 
89 static const struct etnaviv_pm_domain doms_3d[] = {
90 	{
91 		.name = "HI",
92 		.profile_read = VIVS_MC_PROFILE_HI_READ,
93 		.profile_config = VIVS_MC_PROFILE_CONFIG2,
94 		.nr_signals = 5,
95 		.signal = (const struct etnaviv_pm_signal[]) {
96 			{
97 				"TOTAL_CYCLES",
98 				VIVS_HI_PROFILE_TOTAL_CYCLES,
99 				&simple_reg_read
100 			},
101 			{
102 				"IDLE_CYCLES",
103 				VIVS_HI_PROFILE_IDLE_CYCLES,
104 				&simple_reg_read
105 			},
106 			{
107 				"AXI_CYCLES_READ_REQUEST_STALLED",
108 				VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED,
109 				&perf_reg_read
110 			},
111 			{
112 				"AXI_CYCLES_WRITE_REQUEST_STALLED",
113 				VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED,
114 				&perf_reg_read
115 			},
116 			{
117 				"AXI_CYCLES_WRITE_DATA_STALLED",
118 				VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED,
119 				&perf_reg_read
120 			}
121 		}
122 	},
123 	{
124 		.name = "PE",
125 		.profile_read = VIVS_MC_PROFILE_PE_READ,
126 		.profile_config = VIVS_MC_PROFILE_CONFIG0,
127 		.nr_signals = 5,
128 		.signal = (const struct etnaviv_pm_signal[]) {
129 			{
130 				"PIXEL_COUNT_KILLED_BY_COLOR_PIPE",
131 				VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE,
132 				&pipe_reg_read
133 			},
134 			{
135 				"PIXEL_COUNT_KILLED_BY_DEPTH_PIPE",
136 				VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE,
137 				&pipe_reg_read
138 			},
139 			{
140 				"PIXEL_COUNT_DRAWN_BY_COLOR_PIPE",
141 				VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE,
142 				&pipe_reg_read
143 			},
144 			{
145 				"PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE",
146 				VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE,
147 				&pipe_reg_read
148 			}
149 		}
150 	},
151 	{
152 		.name = "SH",
153 		.profile_read = VIVS_MC_PROFILE_SH_READ,
154 		.profile_config = VIVS_MC_PROFILE_CONFIG0,
155 		.nr_signals = 9,
156 		.signal = (const struct etnaviv_pm_signal[]) {
157 			{
158 				"SHADER_CYCLES",
159 				VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES,
160 				&perf_reg_read
161 			},
162 			{
163 				"PS_INST_COUNTER",
164 				VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER,
165 				&perf_reg_read
166 			},
167 			{
168 				"RENDERED_PIXEL_COUNTER",
169 				VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER,
170 				&perf_reg_read
171 			},
172 			{
173 				"VS_INST_COUNTER",
174 				VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER,
175 				&pipe_reg_read
176 			},
177 			{
178 				"RENDERED_VERTICE_COUNTER",
179 				VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER,
180 				&pipe_reg_read
181 			},
182 			{
183 				"VTX_BRANCH_INST_COUNTER",
184 				VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER,
185 				&pipe_reg_read
186 			},
187 			{
188 				"VTX_TEXLD_INST_COUNTER",
189 				VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER,
190 				&pipe_reg_read
191 			},
192 			{
193 				"PXL_BRANCH_INST_COUNTER",
194 				VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER,
195 				&pipe_reg_read
196 			},
197 			{
198 				"PXL_TEXLD_INST_COUNTER",
199 				VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER,
200 				&pipe_reg_read
201 			}
202 		}
203 	},
204 	{
205 		.name = "PA",
206 		.profile_read = VIVS_MC_PROFILE_PA_READ,
207 		.profile_config = VIVS_MC_PROFILE_CONFIG1,
208 		.nr_signals = 6,
209 		.signal = (const struct etnaviv_pm_signal[]) {
210 			{
211 				"INPUT_VTX_COUNTER",
212 				VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER,
213 				&perf_reg_read
214 			},
215 			{
216 				"INPUT_PRIM_COUNTER",
217 				VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER,
218 				&perf_reg_read
219 			},
220 			{
221 				"OUTPUT_PRIM_COUNTER",
222 				VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER,
223 				&perf_reg_read
224 			},
225 			{
226 				"DEPTH_CLIPPED_COUNTER",
227 				VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER,
228 				&pipe_reg_read
229 			},
230 			{
231 				"TRIVIAL_REJECTED_COUNTER",
232 				VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER,
233 				&pipe_reg_read
234 			},
235 			{
236 				"CULLED_COUNTER",
237 				VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER,
238 				&pipe_reg_read
239 			}
240 		}
241 	},
242 	{
243 		.name = "SE",
244 		.profile_read = VIVS_MC_PROFILE_SE_READ,
245 		.profile_config = VIVS_MC_PROFILE_CONFIG1,
246 		.nr_signals = 2,
247 		.signal = (const struct etnaviv_pm_signal[]) {
248 			{
249 				"CULLED_TRIANGLE_COUNT",
250 				VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT,
251 				&perf_reg_read
252 			},
253 			{
254 				"CULLED_LINES_COUNT",
255 				VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT,
256 				&perf_reg_read
257 			}
258 		}
259 	},
260 	{
261 		.name = "RA",
262 		.profile_read = VIVS_MC_PROFILE_RA_READ,
263 		.profile_config = VIVS_MC_PROFILE_CONFIG1,
264 		.nr_signals = 7,
265 		.signal = (const struct etnaviv_pm_signal[]) {
266 			{
267 				"VALID_PIXEL_COUNT",
268 				VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT,
269 				&perf_reg_read
270 			},
271 			{
272 				"TOTAL_QUAD_COUNT",
273 				VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT,
274 				&perf_reg_read
275 			},
276 			{
277 				"VALID_QUAD_COUNT_AFTER_EARLY_Z",
278 				VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z,
279 				&perf_reg_read
280 			},
281 			{
282 				"TOTAL_PRIMITIVE_COUNT",
283 				VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT,
284 				&perf_reg_read
285 			},
286 			{
287 				"PIPE_CACHE_MISS_COUNTER",
288 				VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER,
289 				&perf_reg_read
290 			},
291 			{
292 				"PREFETCH_CACHE_MISS_COUNTER",
293 				VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER,
294 				&perf_reg_read
295 			},
296 			{
297 				"CULLED_QUAD_COUNT",
298 				VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT,
299 				&perf_reg_read
300 			}
301 		}
302 	},
303 	{
304 		.name = "TX",
305 		.profile_read = VIVS_MC_PROFILE_TX_READ,
306 		.profile_config = VIVS_MC_PROFILE_CONFIG1,
307 		.nr_signals = 9,
308 		.signal = (const struct etnaviv_pm_signal[]) {
309 			{
310 				"TOTAL_BILINEAR_REQUESTS",
311 				VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS,
312 				&perf_reg_read
313 			},
314 			{
315 				"TOTAL_TRILINEAR_REQUESTS",
316 				VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS,
317 				&perf_reg_read
318 			},
319 			{
320 				"TOTAL_DISCARDED_TEXTURE_REQUESTS",
321 				VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS,
322 				&perf_reg_read
323 			},
324 			{
325 				"TOTAL_TEXTURE_REQUESTS",
326 				VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS,
327 				&perf_reg_read
328 			},
329 			{
330 				"MEM_READ_COUNT",
331 				VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT,
332 				&perf_reg_read
333 			},
334 			{
335 				"MEM_READ_IN_8B_COUNT",
336 				VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT,
337 				&perf_reg_read
338 			},
339 			{
340 				"CACHE_MISS_COUNT",
341 				VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT,
342 				&perf_reg_read
343 			},
344 			{
345 				"CACHE_HIT_TEXEL_COUNT",
346 				VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT,
347 				&perf_reg_read
348 			},
349 			{
350 				"CACHE_MISS_TEXEL_COUNT",
351 				VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT,
352 				&perf_reg_read
353 			}
354 		}
355 	},
356 	{
357 		.name = "MC",
358 		.profile_read = VIVS_MC_PROFILE_MC_READ,
359 		.profile_config = VIVS_MC_PROFILE_CONFIG2,
360 		.nr_signals = 3,
361 		.signal = (const struct etnaviv_pm_signal[]) {
362 			{
363 				"TOTAL_READ_REQ_8B_FROM_PIPELINE",
364 				VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE,
365 				&perf_reg_read
366 			},
367 			{
368 				"TOTAL_READ_REQ_8B_FROM_IP",
369 				VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP,
370 				&perf_reg_read
371 			},
372 			{
373 				"TOTAL_WRITE_REQ_8B_FROM_PIPELINE",
374 				VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE,
375 				&perf_reg_read
376 			}
377 		}
378 	}
379 };
380 
381 static const struct etnaviv_pm_domain doms_2d[] = {
382 	{
383 		.name = "PE",
384 		.profile_read = VIVS_MC_PROFILE_PE_READ,
385 		.profile_config = VIVS_MC_PROFILE_CONFIG0,
386 		.nr_signals = 1,
387 		.signal = (const struct etnaviv_pm_signal[]) {
388 			{
389 				"PIXELS_RENDERED_2D",
390 				VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D,
391 				&pipe_reg_read
392 			}
393 		}
394 	}
395 };
396 
397 static const struct etnaviv_pm_domain doms_vg[] = {
398 };
399 
400 static const struct etnaviv_pm_domain_meta doms_meta[] = {
401 	{
402 		.nr_domains = ARRAY_SIZE(doms_3d),
403 		.domains = &doms_3d[0]
404 	},
405 	{
406 		.nr_domains = ARRAY_SIZE(doms_2d),
407 		.domains = &doms_2d[0]
408 	},
409 	{
410 		.nr_domains = ARRAY_SIZE(doms_vg),
411 		.domains = &doms_vg[0]
412 	}
413 };
414 
415 int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu,
416 	struct drm_etnaviv_pm_domain *domain)
417 {
418 	const struct etnaviv_pm_domain_meta *meta = &doms_meta[domain->pipe];
419 	const struct etnaviv_pm_domain *dom;
420 
421 	if (domain->iter >= meta->nr_domains)
422 		return -EINVAL;
423 
424 	dom = meta->domains + domain->iter;
425 
426 	domain->id = domain->iter;
427 	domain->nr_signals = dom->nr_signals;
428 	strncpy(domain->name, dom->name, sizeof(domain->name));
429 
430 	domain->iter++;
431 	if (domain->iter == meta->nr_domains)
432 		domain->iter = 0xff;
433 
434 	return 0;
435 }
436 
437 int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu,
438 	struct drm_etnaviv_pm_signal *signal)
439 {
440 	const struct etnaviv_pm_domain_meta *meta = &doms_meta[signal->pipe];
441 	const struct etnaviv_pm_domain *dom;
442 	const struct etnaviv_pm_signal *sig;
443 
444 	if (signal->domain >= meta->nr_domains)
445 		return -EINVAL;
446 
447 	dom = meta->domains + signal->domain;
448 
449 	if (signal->iter > dom->nr_signals)
450 		return -EINVAL;
451 
452 	sig = &dom->signal[signal->iter];
453 
454 	signal->id = signal->iter;
455 	strncpy(signal->name, sig->name, sizeof(signal->name));
456 
457 	signal->iter++;
458 	if (signal->iter == dom->nr_signals)
459 		signal->iter = 0xffff;
460 
461 	return 0;
462 }
463 
464 int etnaviv_pm_req_validate(const struct drm_etnaviv_gem_submit_pmr *r,
465 	u32 exec_state)
466 {
467 	const struct etnaviv_pm_domain_meta *meta = &doms_meta[exec_state];
468 	const struct etnaviv_pm_domain *dom;
469 
470 	if (r->domain >= meta->nr_domains)
471 		return -EINVAL;
472 
473 	dom = meta->domains + r->domain;
474 
475 	if (r->signal > dom->nr_signals)
476 		return -EINVAL;
477 
478 	return 0;
479 }
480 
481 void etnaviv_perfmon_process(struct etnaviv_gpu *gpu,
482 	const struct etnaviv_perfmon_request *pmr, u32 exec_state)
483 {
484 	const struct etnaviv_pm_domain_meta *meta = &doms_meta[exec_state];
485 	const struct etnaviv_pm_domain *dom;
486 	const struct etnaviv_pm_signal *sig;
487 	u32 *bo = pmr->bo_vma;
488 	u32 val;
489 
490 	dom = meta->domains + pmr->domain;
491 	sig = &dom->signal[pmr->signal];
492 	val = sig->sample(gpu, dom, sig);
493 
494 	*(bo + pmr->offset) = val;
495 }
496