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