1/*
2 * Copyright (c) 2017 Etnaviv Project
3 * Copyright (C) 2017 Zodiac Inflight Innovations
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Christian Gmeiner <christian.gmeiner@gmail.com>
26 */
27
28#include "util/u_inlines.h"
29#include "util/u_memory.h"
30
31#include "etnaviv_context.h"
32#include "etnaviv_query_pm.h"
33#include "etnaviv_screen.h"
34
35struct etna_perfmon_source
36{
37   const char *domain;
38   const char *signal;
39};
40
41struct etna_perfmon_config
42{
43   const char *name;
44   unsigned type;
45   unsigned group_id;
46   const struct etna_perfmon_source *source;
47};
48
49static const char *group_names[] = {
50   [ETNA_QUERY_HI_GROUP_ID] = "HI",
51   [ETNA_QUERY_PE_GROUP_ID] = "PE",
52   [ETNA_QUERY_SH_GROUP_ID] = "SH",
53   [ETNA_QUERY_PA_GROUP_ID] = "PA",
54   [ETNA_QUERY_SE_GROUP_ID] = "SE",
55   [ETNA_QUERY_RA_GROUP_ID] = "RA",
56   [ETNA_QUERY_TX_GROUP_ID] = "TX",
57   [ETNA_QUERY_MC_GROUP_ID] = "MC",
58};
59
60static const struct etna_perfmon_config query_config[] = {
61   {
62      .name = "hi-total-cycles",
63      .type = ETNA_QUERY_HI_TOTAL_CYCLES,
64      .group_id = ETNA_QUERY_HI_GROUP_ID,
65      .source = (const struct etna_perfmon_source[]) {
66         { "HI", "TOTAL_CYCLES" }
67      }
68   },
69   {
70      .name = "hi-idle-cycles",
71      .type = ETNA_QUERY_HI_IDLE_CYCLES,
72      .group_id = ETNA_QUERY_HI_GROUP_ID,
73      .source = (const struct etna_perfmon_source[]) {
74         { "HI", "IDLE_CYCLES" }
75      }
76   },
77   {
78      .name = "hi-axi-cycles-read-request-stalled",
79      .type = ETNA_QUERY_HI_AXI_CYCLES_READ_REQUEST_STALLED,
80      .group_id = ETNA_QUERY_HI_GROUP_ID,
81      .source = (const struct etna_perfmon_source[]) {
82         { "HI", "AXI_CYCLES_READ_REQUEST_STALLED" }
83      }
84   },
85   {
86      .name = "hi-axi-cycles-write-request-stalled",
87      .type = ETNA_QUERY_HI_AXI_CYCLES_WRITE_REQUEST_STALLED,
88      .group_id = ETNA_QUERY_HI_GROUP_ID,
89      .source = (const struct etna_perfmon_source[]) {
90         { "HI", "AXI_CYCLES_WRITE_REQUEST_STALLED" }
91      }
92   },
93   {
94      .name = "hi-axi-cycles-write-data-stalled",
95      .type = ETNA_QUERY_HI_AXI_CYCLES_WRITE_DATA_STALLED,
96      .group_id = ETNA_QUERY_HI_GROUP_ID,
97      .source = (const struct etna_perfmon_source[]) {
98         { "HI", "AXI_CYCLES_WRITE_DATA_STALLED" }
99      }
100   },
101   {
102      .name = "pe-pixel-count-killed-by-color-pipe",
103      .type = ETNA_QUERY_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE,
104      .group_id = ETNA_QUERY_PE_GROUP_ID,
105      .source = (const struct etna_perfmon_source[]) {
106         { "PE", "PIXEL_COUNT_KILLED_BY_COLOR_PIPE" }
107      }
108   },
109   {
110      .name = "pe-pixel-count-killed-by-depth-pipe",
111      .type = ETNA_QUERY_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE,
112      .group_id = ETNA_QUERY_PE_GROUP_ID,
113      .source = (const struct etna_perfmon_source[]) {
114         { "PE", "PIXEL_COUNT_KILLED_BY_DEPTH_PIPE" }
115      }
116   },
117   {
118      .name = "pe-pixel-count-drawn-by-color-pipe",
119      .type = ETNA_QUERY_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE,
120      .group_id = ETNA_QUERY_PE_GROUP_ID,
121      .source = (const struct etna_perfmon_source[]) {
122         { "PE", "PIXEL_COUNT_DRAWN_BY_COLOR_PIPE" }
123      }
124   },
125   {
126      .name = "pe-pixel-count-drawn-by-depth-pipe",
127      .type = ETNA_QUERY_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE,
128      .group_id = ETNA_QUERY_PE_GROUP_ID,
129      .source = (const struct etna_perfmon_source[]) {
130         { "PE", "PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE" }
131      }
132   },
133   {
134      .name = "sh-shader-cycles",
135      .type = ETNA_QUERY_SH_SHADER_CYCLES,
136      .group_id = ETNA_QUERY_SH_GROUP_ID,
137      .source = (const struct etna_perfmon_source[]) {
138         { "SH", "SHADER_CYCLES" }
139      }
140   },
141   {
142      .name = "sh-ps-inst-counter",
143      .type = ETNA_QUERY_SH_PS_INST_COUNTER,
144      .group_id = ETNA_QUERY_SH_GROUP_ID,
145      .source = (const struct etna_perfmon_source[]) {
146         { "SH", "PS_INST_COUNTER" }
147      }
148   },
149   {
150      .name = "sh-rendered-pixel-counter",
151      .type = ETNA_QUERY_SH_RENDERED_PIXEL_COUNTER,
152      .group_id = ETNA_QUERY_SH_GROUP_ID,
153      .source = (const struct etna_perfmon_source[]) {
154         { "SH", "RENDERED_PIXEL_COUNTER" }
155      }
156   },
157   {
158      .name = "sh-vs-inst-counter",
159      .type = ETNA_QUERY_SH_VS_INST_COUNTER,
160      .group_id = ETNA_QUERY_SH_GROUP_ID,
161      .source = (const struct etna_perfmon_source[]) {
162         { "SH", "VS_INST_COUNTER" }
163      }
164   },
165   {
166      .name = "sh-rendered-vertice-counter",
167      .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
168      .group_id = ETNA_QUERY_SH_GROUP_ID,
169      .source = (const struct etna_perfmon_source[]) {
170         { "SH", "RENDERED_VERTICE_COUNTER" }
171      }
172   },
173   {
174      .name = "sh-vtx-branch-inst-counter",
175      .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
176      .group_id = ETNA_QUERY_SH_GROUP_ID,
177      .source = (const struct etna_perfmon_source[]) {
178         { "SH", "VTX_BRANCH_INST_COUNTER" }
179      }
180   },
181   {
182      .name = "sh-vtx-texld-inst-counter",
183      .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
184      .group_id = ETNA_QUERY_SH_GROUP_ID,
185      .source = (const struct etna_perfmon_source[]) {
186         { "SH", "VTX_TEXLD_INST_COUNTER" }
187      }
188   },
189   {
190      .name = "sh-plx-branch-inst-counter",
191      .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
192      .group_id = ETNA_QUERY_SH_GROUP_ID,
193      .source = (const struct etna_perfmon_source[]) {
194         { "SH", "PXL_BRANCH_INST_COUNTER" }
195      }
196   },
197   {
198      .name = "sh-plx-texld-inst-counter",
199      .type = ETNA_QUERY_SH_RENDERED_VERTICE_COUNTER,
200      .group_id = ETNA_QUERY_SH_GROUP_ID,
201      .source = (const struct etna_perfmon_source[]) {
202         { "SH", "PXL_TEXLD_INST_COUNTER" }
203      }
204   },
205   {
206      .name = "pa-input-vtx-counter",
207      .type = ETNA_QUERY_PA_INPUT_VTX_COUNTER,
208      .group_id = ETNA_QUERY_PA_GROUP_ID,
209      .source = (const struct etna_perfmon_source[]) {
210         { "PA", "INPUT_VTX_COUNTER" }
211      }
212   },
213   {
214      .name = "pa-input-prim-counter",
215      .type = ETNA_QUERY_PA_INPUT_PRIM_COUNTER,
216      .group_id = ETNA_QUERY_PA_GROUP_ID,
217      .source = (const struct etna_perfmon_source[]) {
218         { "PA", "INPUT_PRIM_COUNTER" }
219      }
220   },
221   {
222      .name = "pa-output-prim-counter",
223      .type = ETNA_QUERY_PA_OUTPUT_PRIM_COUNTER,
224      .group_id = ETNA_QUERY_PA_GROUP_ID,
225      .source = (const struct etna_perfmon_source[]) {
226         { "PA", "OUTPUT_PRIM_COUNTER" }
227      }
228   },
229   {
230      .name = "pa-depth-clipped-counter",
231      .type = ETNA_QUERY_PA_DEPTH_CLIPPED_COUNTER,
232      .group_id = ETNA_QUERY_PA_GROUP_ID,
233      .source = (const struct etna_perfmon_source[]) {
234         { "PA", "DEPTH_CLIPPED_COUNTER" }
235      }
236   },
237   {
238      .name = "pa-trivial-rejected-counter",
239      .type = ETNA_QUERY_PA_TRIVIAL_REJECTED_COUNTER,
240      .group_id = ETNA_QUERY_PA_GROUP_ID,
241      .source = (const struct etna_perfmon_source[]) {
242         { "PA", "TRIVIAL_REJECTED_COUNTER" }
243      }
244   },
245   {
246      .name = "pa-culled-counter",
247      .type = ETNA_QUERY_PA_CULLED_COUNTER,
248      .group_id = ETNA_QUERY_PA_GROUP_ID,
249      .source = (const struct etna_perfmon_source[]) {
250         { "PA", "CULLED_COUNTER" }
251      }
252   },
253   {
254      .name = "se-culled-triangle-count",
255      .type = ETNA_QUERY_SE_CULLED_TRIANGLE_COUNT,
256      .group_id = ETNA_QUERY_SE_GROUP_ID,
257      .source = (const struct etna_perfmon_source[]) {
258         { "SE", "CULLED_TRIANGLE_COUNT" }
259      }
260   },
261   {
262      .name = "se-culled-lines-count",
263      .type = ETNA_QUERY_SE_CULLED_LINES_COUNT,
264      .group_id = ETNA_QUERY_SE_GROUP_ID,
265      .source = (const struct etna_perfmon_source[]) {
266         { "SE", "CULLED_LINES_COUNT" }
267      }
268   },
269   {
270      .name = "ra-valid-pixel-count",
271      .type = ETNA_QUERY_RA_VALID_PIXEL_COUNT,
272      .group_id = ETNA_QUERY_RA_GROUP_ID,
273      .source = (const struct etna_perfmon_source[]) {
274         { "RA", "VALID_PIXEL_COUNT" }
275      }
276   },
277   {
278      .name = "ra-total-quad-count",
279      .type = ETNA_QUERY_RA_TOTAL_QUAD_COUNT,
280      .group_id = ETNA_QUERY_RA_GROUP_ID,
281      .source = (const struct etna_perfmon_source[]) {
282         { "RA", "TOTAL_QUAD_COUNT" }
283      }
284   },
285   {
286      .name = "ra-valid-quad-count-after-early-z",
287      .type = ETNA_QUERY_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z,
288      .group_id = ETNA_QUERY_RA_GROUP_ID,
289      .source = (const struct etna_perfmon_source[]) {
290         { "RA", "VALID_QUAD_COUNT_AFTER_EARLY_Z" }
291      }
292   },
293   {
294      .name = "ra-total-primitive-count",
295      .type = ETNA_QUERY_RA_TOTAL_PRIMITIVE_COUNT,
296      .group_id = ETNA_QUERY_RA_GROUP_ID,
297      .source = (const struct etna_perfmon_source[]) {
298         { "RA", "TOTAL_PRIMITIVE_COUNT" }
299      }
300   },
301   {
302      .name = "ra-pipe-cache-miss-counter",
303      .type = ETNA_QUERY_RA_PIPE_CACHE_MISS_COUNTER,
304      .group_id = ETNA_QUERY_RA_GROUP_ID,
305      .source = (const struct etna_perfmon_source[]) {
306         { "RA", "PIPE_CACHE_MISS_COUNTER" }
307      }
308   },
309   {
310      .name = "ra-prefetch-cache-miss-counter",
311      .type = ETNA_QUERY_RA_PREFETCH_CACHE_MISS_COUNTER,
312      .group_id = ETNA_QUERY_RA_GROUP_ID,
313      .source = (const struct etna_perfmon_source[]) {
314         { "RA", "PREFETCH_CACHE_MISS_COUNTER" }
315      }
316   },
317   {
318      .name = "ra-pculled-quad-count",
319      .type = ETNA_QUERY_RA_CULLED_QUAD_COUNT,
320      .group_id = ETNA_QUERY_RA_GROUP_ID,
321      .source = (const struct etna_perfmon_source[]) {
322         { "RA", "CULLED_QUAD_COUNT" }
323      }
324   },
325   {
326      .name = "tx-total-bilinear-requests",
327      .type = ETNA_QUERY_TX_TOTAL_BILINEAR_REQUESTS,
328      .group_id = ETNA_QUERY_TX_GROUP_ID,
329      .source = (const struct etna_perfmon_source[]) {
330         { "TX", "TOTAL_BILINEAR_REQUESTS" }
331      }
332   },
333   {
334      .name = "tx-total-trilinear-requests",
335      .type = ETNA_QUERY_TX_TOTAL_TRILINEAR_REQUESTS,
336      .group_id = ETNA_QUERY_TX_GROUP_ID,
337      .source = (const struct etna_perfmon_source[]) {
338         { "TX", "TOTAL_TRILINEAR_REQUESTS" }
339      }
340   },
341   {
342      .name = "tx-total-discarded-texture-requests",
343      .type = ETNA_QUERY_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS,
344      .group_id = ETNA_QUERY_TX_GROUP_ID,
345      .source = (const struct etna_perfmon_source[]) {
346         { "TX", "TOTAL_DISCARDED_TEXTURE_REQUESTS" }
347      }
348   },
349   {
350      .name = "tx-total-texture-requests",
351      .type = ETNA_QUERY_TX_TOTAL_TEXTURE_REQUESTS,
352      .group_id = ETNA_QUERY_TX_GROUP_ID,
353      .source = (const struct etna_perfmon_source[]) {
354         { "TX", "TOTAL_TEXTURE_REQUESTS" }
355      }
356   },
357   {
358      .name = "tx-mem-read-count",
359      .type = ETNA_QUERY_TX_MEM_READ_COUNT,
360      .group_id = ETNA_QUERY_TX_GROUP_ID,
361      .source = (const struct etna_perfmon_source[]) {
362         { "TX", "MEM_READ_COUNT" }
363      }
364   },
365   {
366      .name = "tx-mem-read-in-8b-count",
367      .type = ETNA_QUERY_TX_MEM_READ_IN_8B_COUNT,
368      .group_id = ETNA_QUERY_TX_GROUP_ID,
369      .source = (const struct etna_perfmon_source[]) {
370         { "TX", "MEM_READ_IN_8B_COUNT" }
371      }
372   },
373   {
374      .name = "tx-cache-miss-count",
375      .type = ETNA_QUERY_TX_CACHE_MISS_COUNT,
376      .group_id = ETNA_QUERY_TX_GROUP_ID,
377      .source = (const struct etna_perfmon_source[]) {
378         { "TX", "CACHE_MISS_COUNT" }
379      }
380   },
381   {
382      .name = "tx-cache-hit-texel-count",
383      .type = ETNA_QUERY_TX_CACHE_HIT_TEXEL_COUNT,
384      .group_id = ETNA_QUERY_TX_GROUP_ID,
385      .source = (const struct etna_perfmon_source[]) {
386         { "TX", "CACHE_HIT_TEXEL_COUNT" }
387      }
388   },
389   {
390      .name = "tx-cache-miss-texel-count",
391      .type = ETNA_QUERY_TX_CACHE_MISS_TEXEL_COUNT,
392      .group_id = ETNA_QUERY_TX_GROUP_ID,
393      .source = (const struct etna_perfmon_source[]) {
394         { "TX", "CACHE_MISS_TEXEL_COUNT" }
395      }
396   },
397   {
398      .name = "mc-total-read-req-8b-from-pipeline",
399      .type = ETNA_QUERY_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE,
400      .group_id = ETNA_QUERY_MC_GROUP_ID,
401      .source = (const struct etna_perfmon_source[]) {
402         { "MC", "TOTAL_READ_REQ_8B_FROM_PIPELINE" }
403      }
404   },
405   {
406      .name = "mc-total-read-req-8b-from-ip",
407      .type = ETNA_QUERY_MC_TOTAL_READ_REQ_8B_FROM_IP,
408      .group_id = ETNA_QUERY_MC_GROUP_ID,
409      .source = (const struct etna_perfmon_source[]) {
410         { "MC", "TOTAL_READ_REQ_8B_FROM_IP" }
411      }
412   },
413   {
414      .name = "mc-total-write-req-8b-from-pipeline",
415      .type = ETNA_QUERY_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE,
416      .group_id = ETNA_QUERY_MC_GROUP_ID,
417      .source = (const struct etna_perfmon_source[]) {
418         { "MC", "TOTAL_WRITE_REQ_8B_FROM_PIPELINE" }
419      }
420   }
421};
422
423static const struct etna_perfmon_config *
424etna_pm_query_config(unsigned type)
425{
426   for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++)
427      if (query_config[i].type == type)
428         return &query_config[i];
429
430   return NULL;
431}
432
433static struct etna_perfmon_signal *
434etna_pm_query_signal(struct etna_perfmon *perfmon,
435                     const struct etna_perfmon_source *source)
436{
437   struct etna_perfmon_domain *domain;
438
439   domain = etna_perfmon_get_dom_by_name(perfmon, source->domain);
440   if (!domain)
441      return NULL;
442
443   return etna_perfmon_get_sig_by_name(domain, source->signal);
444}
445
446static inline bool
447etna_pm_cfg_supported(struct etna_perfmon *perfmon,
448                      const struct etna_perfmon_config *cfg)
449{
450   struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
451
452   return !!signal;
453}
454
455static inline void
456etna_pm_add_signal(struct etna_pm_query *pq, struct etna_perfmon *perfmon,
457                   const struct etna_perfmon_config *cfg)
458{
459   struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
460
461   pq->signal = signal;
462}
463
464static bool
465realloc_query_bo(struct etna_context *ctx, struct etna_pm_query *pq)
466{
467   if (pq->bo)
468      etna_bo_del(pq->bo);
469
470   pq->bo = etna_bo_new(ctx->screen->dev, 64, DRM_ETNA_GEM_CACHE_WC);
471   if (unlikely(!pq->bo))
472      return false;
473
474   pq->data = etna_bo_map(pq->bo);
475
476   return true;
477}
478
479static void
480etna_pm_query_get(struct etna_cmd_stream *stream, struct etna_query *q,
481                  unsigned flags)
482{
483   struct etna_pm_query *pq = etna_pm_query(q);
484   unsigned offset;
485   assert(flags);
486
487   if (flags == ETNA_PM_PROCESS_PRE)
488      offset = 2;
489   else
490      offset = 3;
491
492   struct etna_perf p = {
493      .flags = flags,
494      .sequence = pq->sequence,
495      .bo = pq->bo,
496      .signal = pq->signal,
497      .offset = offset
498   };
499
500   etna_cmd_stream_perf(stream, &p);
501}
502
503static inline void
504etna_pm_query_update(struct etna_query *q)
505{
506   struct etna_pm_query *pq = etna_pm_query(q);
507
508   if (pq->data[0] == pq->sequence)
509      pq->ready = true;
510}
511
512static void
513etna_pm_destroy_query(struct etna_context *ctx, struct etna_query *q)
514{
515   struct etna_pm_query *pq = etna_pm_query(q);
516
517   etna_bo_del(pq->bo);
518   FREE(pq);
519}
520
521static boolean
522etna_pm_begin_query(struct etna_context *ctx, struct etna_query *q)
523{
524   struct etna_pm_query *pq = etna_pm_query(q);
525
526   pq->ready = false;
527   pq->sequence++;
528
529   etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_PRE);
530
531   return true;
532}
533
534static void
535etna_pm_end_query(struct etna_context *ctx, struct etna_query *q)
536{
537   etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_POST);
538}
539
540static boolean
541etna_pm_get_query_result(struct etna_context *ctx, struct etna_query *q,
542                         boolean wait, union pipe_query_result *result)
543{
544   struct etna_pm_query *pq = etna_pm_query(q);
545
546   etna_pm_query_update(q);
547
548   if (!pq->ready) {
549      if (!wait)
550         return false;
551
552      if (!etna_bo_cpu_prep(pq->bo, DRM_ETNA_PREP_READ))
553         return false;
554
555      pq->ready = true;
556      etna_bo_cpu_fini(pq->bo);
557   }
558
559   result->u32 = pq->data[2] - pq->data[1];
560
561   return true;
562}
563
564static const struct etna_query_funcs hw_query_funcs = {
565   .destroy_query = etna_pm_destroy_query,
566   .begin_query = etna_pm_begin_query,
567   .end_query = etna_pm_end_query,
568   .get_query_result = etna_pm_get_query_result,
569};
570
571struct etna_query *
572etna_pm_create_query(struct etna_context *ctx, unsigned query_type)
573{
574   struct etna_perfmon *perfmon = ctx->screen->perfmon;
575   const struct etna_perfmon_config *cfg;
576   struct etna_pm_query *pq;
577   struct etna_query *q;
578
579   cfg = etna_pm_query_config(query_type);
580   if (!cfg)
581      return NULL;
582
583   if (!etna_pm_cfg_supported(perfmon, cfg))
584      return NULL;
585
586   pq = CALLOC_STRUCT(etna_pm_query);
587   if (!pq)
588      return NULL;
589
590   if (!realloc_query_bo(ctx, pq)) {
591      FREE(pq);
592      return NULL;
593   }
594
595   q = &pq->base;
596   q->funcs = &hw_query_funcs;
597   q->type = query_type;
598
599   etna_pm_add_signal(pq, perfmon, cfg);
600
601   return q;
602}
603
604void
605etna_pm_query_setup(struct etna_screen *screen)
606{
607   screen->perfmon = etna_perfmon_create(screen->pipe);
608
609   if (!screen->perfmon)
610      return;
611
612   for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++) {
613      const struct etna_perfmon_config *cfg = &query_config[i];
614
615      if (!etna_pm_cfg_supported(screen->perfmon, cfg))
616         continue;
617
618      util_dynarray_append(&screen->supported_pm_queries, unsigned, i);
619   }
620}
621
622int
623etna_pm_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
624                              struct pipe_driver_query_info *info)
625{
626   const struct etna_screen *screen = etna_screen(pscreen);
627   const unsigned num = screen->supported_pm_queries.size / sizeof(unsigned);
628   unsigned i;
629
630   if (!info)
631      return num;
632
633   if (index >= num)
634      return 0;
635
636   i = *util_dynarray_element(&screen->supported_pm_queries, unsigned, index);
637   assert(i < ARRAY_SIZE(query_config));
638
639   info->name = query_config[i].name;
640   info->query_type = query_config[i].type;
641   info->group_id = query_config[i].group_id;
642
643   return 1;
644}
645
646static
647unsigned query_count(unsigned group)
648{
649   unsigned count = 0;
650
651   for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++)
652      if (query_config[i].group_id == group)
653         count++;
654
655   assert(count);
656
657   return count;
658}
659
660int
661etna_pm_get_driver_query_group_info(struct pipe_screen *pscreen,
662                                    unsigned index,
663                                    struct pipe_driver_query_group_info *info)
664{
665   if (!info)
666      return ARRAY_SIZE(group_names);
667
668   if (index >= ARRAY_SIZE(group_names))
669      return 0;
670
671   unsigned count = query_count(index);
672
673   info->name = group_names[index];
674   info->max_active_queries = count;
675   info->num_queries = count;
676
677   return 1;
678}
679