Report the correct perfmon domains and signals depending
on the supported feature flags.

Reported-by: Dan Carpenter <dan.carpen...@oracle.com>
Fixes: 9e2c2e273012 ("drm/etnaviv: add infrastructure to query perf counter")
Cc: sta...@vger.kernel.org
Signed-off-by: Christian Gmeiner <christian.gmei...@gmail.com>

---
Changes V1 -> V2:
  - Handle domain == NULL case better to get rid of BUG_ON(..) usage.
---
 drivers/gpu/drm/etnaviv/etnaviv_perfmon.c | 59 ++++++++++++++++++++---
 1 file changed, 52 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c 
b/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c
index 8adbf2861bff..e6795bafcbb9 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c
@@ -32,6 +32,7 @@ struct etnaviv_pm_domain {
 };
 
 struct etnaviv_pm_domain_meta {
+       unsigned int feature;
        const struct etnaviv_pm_domain *domains;
        u32 nr_domains;
 };
@@ -410,36 +411,78 @@ static const struct etnaviv_pm_domain doms_vg[] = {
 
 static const struct etnaviv_pm_domain_meta doms_meta[] = {
        {
+               .feature = chipFeatures_PIPE_3D,
                .nr_domains = ARRAY_SIZE(doms_3d),
                .domains = &doms_3d[0]
        },
        {
+               .feature = chipFeatures_PIPE_2D,
                .nr_domains = ARRAY_SIZE(doms_2d),
                .domains = &doms_2d[0]
        },
        {
+               .feature = chipFeatures_PIPE_VG,
                .nr_domains = ARRAY_SIZE(doms_vg),
                .domains = &doms_vg[0]
        }
 };
 
+static unsigned int num_pm_domains(const struct etnaviv_gpu *gpu)
+{
+       unsigned int num = 0, i;
+
+       for (i = 0; i < ARRAY_SIZE(doms_meta); i++) {
+               const struct etnaviv_pm_domain_meta *meta = &doms_meta[i];
+
+               if (gpu->identity.features & meta->feature)
+                       num += meta->nr_domains;
+       }
+
+       return num;
+}
+
+static const struct etnaviv_pm_domain *pm_domain(const struct etnaviv_gpu *gpu,
+       unsigned int index)
+{
+       const struct etnaviv_pm_domain *domain = NULL;
+       unsigned int offset = 0, i;
+
+       for (i = 0; i < ARRAY_SIZE(doms_meta); i++) {
+               const struct etnaviv_pm_domain_meta *meta = &doms_meta[i];
+
+               if (!(gpu->identity.features & meta->feature))
+                       continue;
+
+               if (meta->nr_domains < (index - offset)) {
+                       offset += meta->nr_domains;
+                       continue;
+               }
+
+               domain = meta->domains + (index - offset);
+       }
+
+       return domain;
+}
+
 int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu,
        struct drm_etnaviv_pm_domain *domain)
 {
-       const struct etnaviv_pm_domain_meta *meta = &doms_meta[domain->pipe];
+       const unsigned int nr_domains = num_pm_domains(gpu);
        const struct etnaviv_pm_domain *dom;
 
-       if (domain->iter >= meta->nr_domains)
+       if (domain->iter >= nr_domains)
                return -EINVAL;
 
-       dom = meta->domains + domain->iter;
+       dom = pm_domain(gpu, domain->iter);
+       if (!dom)
+               return -EINVAL;
 
        domain->id = domain->iter;
        domain->nr_signals = dom->nr_signals;
        strncpy(domain->name, dom->name, sizeof(domain->name));
 
        domain->iter++;
-       if (domain->iter == meta->nr_domains)
+       if (domain->iter == nr_domains)
                domain->iter = 0xff;
 
        return 0;
@@ -448,14 +491,16 @@ int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu,
 int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu,
        struct drm_etnaviv_pm_signal *signal)
 {
-       const struct etnaviv_pm_domain_meta *meta = &doms_meta[signal->pipe];
+       const unsigned int nr_domains = num_pm_domains(gpu);
        const struct etnaviv_pm_domain *dom;
        const struct etnaviv_pm_signal *sig;
 
-       if (signal->domain >= meta->nr_domains)
+       if (signal->domain >= nr_domains)
                return -EINVAL;
 
-       dom = meta->domains + signal->domain;
+       dom = pm_domain(gpu, signal->domain);
+       if (!dom)
+               return -EINVAL;
 
        if (signal->iter >= dom->nr_signals)
                return -EINVAL;
-- 
2.24.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to