File Index
Files and directories
Sign in
FILE

etnaviv_perfmon.c

File preview with syntax highlighting.

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