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
