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