This commit implements reserving (take the profiling ownership)
and releasing (release the profiling ownership) of PMC.

A reservation can also be cleared by AMDGPU_PROFILER_CLEAR_RESERVATION
in case the owner can no longer release it, e.g., it crashes.

Releasing is separated from reserving path by design,
because the ownership needs to be kept during set_perfcount
to avoid racings.

Signed-off-by: Zhu Lingshan <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c      |  1 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c | 73 +++++++++++++++++++-
 drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h |  3 +
 3 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index a98c4a47e196..3dc563a64639 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2988,6 +2988,7 @@ static int amdgpu_drm_release(struct inode *inode, struct 
file *filp)
                amdgpu_evf_mgr_flush_suspend(&fpriv->evf_mgr);
                amdgpu_userq_mgr_fini(&fpriv->userq_mgr);
                amdgpu_evf_mgr_fini(&fpriv->evf_mgr);
+               amdgpu_profiler_release_device(drm_to_adev(dev), file_priv);
                drm_dev_exit(idx);
        }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c
index feff37279575..6464af0d1b10 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c
@@ -29,6 +29,54 @@
 #include "amdgpu_userq.h"
 #include "amdgpu_profiler.h"
 
+static int amdgpu_profiler_reserve_device(struct amdgpu_device *adev,
+                                         struct drm_file *filp)
+{
+       int ret;
+
+       mutex_lock(&adev->pmc_profiler.lock);
+
+       if (!adev->pmc_profiler.owner) {
+               adev->pmc_profiler.owner = filp;
+               ret = 0;
+       } else if (adev->pmc_profiler.owner == filp)
+               ret = -EALREADY;
+       else
+               ret = -EPERM;
+
+       mutex_unlock(&adev->pmc_profiler.lock);
+
+       return ret;
+}
+
+int amdgpu_profiler_release_device(struct amdgpu_device *adev,
+                                  struct drm_file *filp)
+{
+       int ret;
+
+       mutex_lock(&adev->pmc_profiler.lock);
+
+       if (adev->pmc_profiler.owner == filp) {
+               adev->pmc_profiler.owner = NULL;
+               ret = 0;
+       } else
+               ret = -EPERM;
+
+       mutex_unlock(&adev->pmc_profiler.lock);
+
+       return ret;
+}
+
+/* Clear the reservation in case the owner that can no longer release
+ * the device, this function does not take the reserveion, nor touch the PMC 
state.
+ */
+static void amdgpu_profiler_clear_reservation(struct amdgpu_device *adev)
+{
+       mutex_lock(&adev->pmc_profiler.lock);
+       adev->pmc_profiler.owner = NULL;
+       mutex_unlock(&adev->pmc_profiler.lock);
+}
+
 static int amdgpu_profiler_check_access(struct drm_device *dev)
 {
        if (!perfmon_capable())
@@ -40,6 +88,29 @@ static int amdgpu_profiler_check_access(struct drm_device 
*dev)
        return 0;
 }
 
+static int amdgpu_profiler_reserve(struct drm_device *dev, struct drm_file 
*filp,
+                                  u8 reserve)
+{
+       struct amdgpu_device *adev = drm_to_adev(dev);
+       int ret;
+
+       ret = amdgpu_profiler_check_access(dev);
+       if (ret)
+               return ret;
+
+       switch (reserve) {
+       case AMDGPU_PROFILER_RELEASE:
+               return amdgpu_profiler_release_device(adev, filp);
+       case AMDGPU_PROFILER_RESERVE:
+               return amdgpu_profiler_reserve_device(adev, filp);
+       case AMDGPU_PROFILER_CLEAR_RESERVATION:
+               amdgpu_profiler_clear_reservation(adev);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
 static int amdgpu_profiler_pmc(struct drm_device *dev, struct drm_file *filp,
                               bool enable)
 {
@@ -61,7 +132,7 @@ int amdgpu_profiler_ioctl(struct drm_device *dev, void 
*data, struct drm_file *f
                args->version = AMDGPU_PROFILER_VERSION_NUM;
                return 0;
        case AMDGPU_PROFILER_OP_RESERVE:
-               return -EOPNOTSUPP;
+               return amdgpu_profiler_reserve(dev, filp, args->reserve);
        case AMDGPU_PROFILER_OP_PMC:
                return amdgpu_profiler_pmc(dev, filp, args->perfcount_enable);
        default:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h
index c27b5f9b3ff0..048ce84f0ef2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h
@@ -28,6 +28,9 @@
 #include <drm/drm_device.h>
 #include <drm/drm_file.h>
 
+struct amdgpu_device;
+
+int amdgpu_profiler_release_device(struct amdgpu_device *adev, struct drm_file 
*filp);
 int amdgpu_profiler_ioctl(struct drm_device *dev, void *data, struct drm_file 
*filp);
 
 #endif /* __AMDGPU_PROFILER_H__ */
-- 
2.55.0

Reply via email to