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