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