The IDR interface is deprecated and the XArray API is the recommended
replacement. Replace the per-file IDR used to track perfmons with an
XArray. This allows us to remove the external mutex that protects the
IDR.

While here, introduce the v3d_perfmon_delete() helper to consolidate
the perfmon cleanup logic used by both v3d_perfmon_close_file() and
v3d_perfmon_destroy_ioctl().

Signed-off-by: Maíra Canal <[email protected]>
---
 drivers/gpu/drm/v3d/v3d_drv.h     |  5 +--
 drivers/gpu/drm/v3d/v3d_perfmon.c | 55 +++++++++++--------------------
 2 files changed, 21 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
index 99a39329bb85..314213c26710 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -220,10 +220,7 @@ v3d_has_csd(struct v3d_dev *v3d)
 struct v3d_file_priv {
        struct v3d_dev *v3d;
 
-       struct {
-               struct idr idr;
-               struct mutex lock;
-       } perfmon;
+       struct xarray perfmons;
 
        struct drm_sched_entity sched_entity[V3D_MAX_QUEUES];
 
diff --git a/drivers/gpu/drm/v3d/v3d_perfmon.c 
b/drivers/gpu/drm/v3d/v3d_perfmon.c
index 9a3fe5255874..41325ffc7f43 100644
--- a/drivers/gpu/drm/v3d/v3d_perfmon.c
+++ b/drivers/gpu/drm/v3d/v3d_perfmon.c
@@ -290,24 +290,23 @@ struct v3d_perfmon *v3d_perfmon_find(struct v3d_file_priv 
*v3d_priv, int id)
 {
        struct v3d_perfmon *perfmon;
 
-       mutex_lock(&v3d_priv->perfmon.lock);
-       perfmon = idr_find(&v3d_priv->perfmon.idr, id);
+       xa_lock(&v3d_priv->perfmons);
+       perfmon = xa_load(&v3d_priv->perfmons, id);
        v3d_perfmon_get(perfmon);
-       mutex_unlock(&v3d_priv->perfmon.lock);
+       xa_unlock(&v3d_priv->perfmons);
 
        return perfmon;
 }
 
 void v3d_perfmon_open_file(struct v3d_file_priv *v3d_priv)
 {
-       mutex_init(&v3d_priv->perfmon.lock);
-       idr_init_base(&v3d_priv->perfmon.idr, 1);
+       xa_init_flags(&v3d_priv->perfmons, XA_FLAGS_ALLOC1);
 }
 
-static int v3d_perfmon_idr_del(int id, void *elem, void *data)
+static void v3d_perfmon_delete(struct v3d_file_priv *v3d_priv,
+                              struct v3d_perfmon *perfmon)
 {
-       struct v3d_perfmon *perfmon = elem;
-       struct v3d_dev *v3d = (struct v3d_dev *)data;
+       struct v3d_dev *v3d = v3d_priv->v3d;
 
        /* If the active perfmon is being destroyed, stop it first */
        if (perfmon == v3d->active_perfmon)
@@ -317,19 +316,17 @@ static int v3d_perfmon_idr_del(int id, void *elem, void 
*data)
        cmpxchg(&v3d->global_perfmon, perfmon, NULL);
 
        v3d_perfmon_put(perfmon);
-
-       return 0;
 }
 
 void v3d_perfmon_close_file(struct v3d_file_priv *v3d_priv)
 {
-       struct v3d_dev *v3d = v3d_priv->v3d;
+       struct v3d_perfmon *perfmon;
+       unsigned long id;
 
-       mutex_lock(&v3d_priv->perfmon.lock);
-       idr_for_each(&v3d_priv->perfmon.idr, v3d_perfmon_idr_del, v3d);
-       idr_destroy(&v3d_priv->perfmon.idr);
-       mutex_unlock(&v3d_priv->perfmon.lock);
-       mutex_destroy(&v3d_priv->perfmon.lock);
+       xa_for_each(&v3d_priv->perfmons, id, perfmon)
+               v3d_perfmon_delete(v3d_priv, perfmon);
+
+       xa_destroy(&v3d_priv->perfmons);
 }
 
 int v3d_perfmon_create_ioctl(struct drm_device *dev, void *data,
@@ -341,6 +338,7 @@ int v3d_perfmon_create_ioctl(struct drm_device *dev, void 
*data,
        struct v3d_perfmon *perfmon;
        unsigned int i;
        int ret;
+       u32 id;
 
        /* Number of monitored counters cannot exceed HW limits. */
        if (req->ncounters > DRM_V3D_MAX_PERF_COUNTERS ||
@@ -366,18 +364,16 @@ int v3d_perfmon_create_ioctl(struct drm_device *dev, void 
*data,
        refcount_set(&perfmon->refcnt, 1);
        mutex_init(&perfmon->lock);
 
-       mutex_lock(&v3d_priv->perfmon.lock);
-       ret = idr_alloc(&v3d_priv->perfmon.idr, perfmon, V3D_PERFMONID_MIN,
-                       V3D_PERFMONID_MAX, GFP_KERNEL);
-       mutex_unlock(&v3d_priv->perfmon.lock);
-
+       ret = xa_alloc(&v3d_priv->perfmons, &id, perfmon,
+                      XA_LIMIT(V3D_PERFMONID_MIN, V3D_PERFMONID_MAX),
+                      GFP_KERNEL);
        if (ret < 0) {
                mutex_destroy(&perfmon->lock);
                kfree(perfmon);
                return ret;
        }
 
-       req->id = ret;
+       req->id = id;
 
        return 0;
 }
@@ -387,24 +383,13 @@ int v3d_perfmon_destroy_ioctl(struct drm_device *dev, 
void *data,
 {
        struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
        struct drm_v3d_perfmon_destroy *req = data;
-       struct v3d_dev *v3d = v3d_priv->v3d;
        struct v3d_perfmon *perfmon;
 
-       mutex_lock(&v3d_priv->perfmon.lock);
-       perfmon = idr_remove(&v3d_priv->perfmon.idr, req->id);
-       mutex_unlock(&v3d_priv->perfmon.lock);
-
+       perfmon = xa_erase(&v3d_priv->perfmons, req->id);
        if (!perfmon)
                return -EINVAL;
 
-       /* If the active perfmon is being destroyed, stop it first */
-       if (perfmon == v3d->active_perfmon)
-               v3d_perfmon_stop(v3d, perfmon, false);
-
-       /* If the global perfmon is being destroyed, set it to NULL */
-       cmpxchg(&v3d->global_perfmon, perfmon, NULL);
-
-       v3d_perfmon_put(perfmon);
+       v3d_perfmon_delete(v3d_priv, perfmon);
 
        return 0;
 }
-- 
2.52.0

Reply via email to