Don't wake the GPU when opening the device. Delay amdgpu_fpriv (and
with it VM) initialization until the first IOCTL that wakes the GPU
anyway, unless it is already active.

Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2295
Signed-off-by: Philipp Zabel <philipp.za...@gmail.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h         |  4 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c |  3 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c     | 11 +++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c  |  3 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c     | 66 ++++++++++++++++++++---------
 5 files changed, 68 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index a1737556a77eb..e33c90c44697e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -508,6 +508,8 @@ struct amdgpu_fpriv {
 
        /** GPU partition selection */
        uint32_t                xcp_id;
+       struct mutex            init_lock;
+       bool                    initialized;
 };
 
 int amdgpu_file_to_fpriv(struct file *filp, struct amdgpu_fpriv **fpriv);
@@ -1617,6 +1619,8 @@ extern const int amdgpu_max_kms_ioctl;
 int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags);
 void amdgpu_driver_unload_kms(struct drm_device *dev);
 int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv);
+int amdgpu_driver_init_fpriv(struct drm_device *dev, struct drm_file 
*file_priv,
+                            struct amdgpu_fpriv *fpriv);
 void amdgpu_driver_postclose_kms(struct drm_device *dev,
                                 struct drm_file *file_priv);
 void amdgpu_driver_release_kms(struct drm_device *dev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index 0e6e2e2acf5b5..2b6cb3b1ca276 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -1784,6 +1784,9 @@ static int amdgpu_debugfs_vm_info_show(struct seq_file 
*m, void *unused)
                struct amdgpu_vm *vm = &fpriv->vm;
                struct amdgpu_task_info *ti;
 
+               if (!fpriv->initialized)
+                       continue;
+
                ti = amdgpu_vm_get_task_info_vm(vm);
                if (ti) {
                        seq_printf(m, "pid:%d\tProcess:%s ----------\n", 
ti->task.pid, ti->process_name);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 34b9d63a86227..732f398922da5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2967,6 +2967,7 @@ long amdgpu_drm_ioctl(struct file *filp,
                      unsigned int cmd, unsigned long arg)
 {
        struct drm_file *file_priv = filp->private_data;
+       struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
        struct drm_device *dev;
        long ret;
        bool wake = true;
@@ -2984,10 +2985,17 @@ long amdgpu_drm_ioctl(struct file *filp,
                ret = pm_runtime_get_sync(dev->dev);
                if (ret < 0)
                        goto out;
+
+               if (unlikely(!fpriv->initialized)) {
+                       ret = amdgpu_driver_init_fpriv(dev, file_priv, fpriv);
+                       if (ret < 0)
+                               goto out_suspend;
+               }
        }
 
        ret = drm_ioctl(filp, cmd, arg);
 
+out_suspend:
        if (wake)
                pm_runtime_mark_last_busy(dev->dev);
 out:
@@ -3017,6 +3025,9 @@ static int amdgpu_flush(struct file *f, fl_owner_t id)
        struct amdgpu_fpriv *fpriv = file_priv->driver_priv;
        long timeout = MAX_WAIT_SCHED_ENTITY_Q_EMPTY;
 
+       if (!fpriv->initialized)
+               return 0;
+
        timeout = amdgpu_ctx_mgr_entity_flush(&fpriv->ctx_mgr, timeout);
        timeout = amdgpu_vm_wait_idle(&fpriv->vm, timeout);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c
index 91d638098889d..e13024bcd8bd1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c
@@ -73,6 +73,9 @@ void amdgpu_show_fdinfo(struct drm_printer *p, struct 
drm_file *file)
        };
        unsigned int hw_ip, i;
 
+       if (!fpriv->initialized)
+               return;
+
        amdgpu_vm_get_memory(vm, stats);
        amdgpu_ctx_mgr_usage(&fpriv->ctx_mgr, usage);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 8a76960803c65..60f36e03def2a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -1382,7 +1382,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct 
drm_file *file_priv)
 {
        struct amdgpu_device *adev = drm_to_adev(dev);
        struct amdgpu_fpriv *fpriv;
-       int r, pasid;
+       int r;
 
        /* Ensure IB tests are run on ring */
        flush_delayed_work(&adev->delayed_init_work);
@@ -1395,16 +1395,45 @@ int amdgpu_driver_open_kms(struct drm_device *dev, 
struct drm_file *file_priv)
 
        file_priv->driver_priv = NULL;
 
-       r = pm_runtime_get_sync(dev->dev);
+       fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
+       if (unlikely(!fpriv))
+               return -ENOMEM;
+
+       mutex_init(&fpriv->init_lock);
+
+       r = pm_runtime_get_if_active(dev->dev);
        if (r < 0)
-               goto pm_put;
+               goto error_free;
 
-       fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
-       if (unlikely(!fpriv)) {
-               r = -ENOMEM;
-               goto out_suspend;
+       if (r == 1) {
+               r = amdgpu_driver_init_fpriv(dev, file_priv, fpriv);
+
+               pm_runtime_mark_last_busy(dev->dev);
+               pm_runtime_put_autosuspend(dev->dev);
+
+               if (r < 0)
+                       goto error_free;
        }
 
+       file_priv->driver_priv = fpriv;
+       return 0;
+
+error_free:
+       kfree(fpriv);
+
+       return r;
+}
+
+int amdgpu_driver_init_fpriv(struct drm_device *dev, struct drm_file 
*file_priv,
+                            struct amdgpu_fpriv *fpriv)
+{
+       struct amdgpu_device *adev = drm_to_adev(dev);
+       int r, pasid;
+
+       mutex_lock(&fpriv->init_lock);
+       if (fpriv->initialized)
+               goto out_unlock;
+
        pasid = amdgpu_pasid_alloc(16);
        if (pasid < 0) {
                dev_warn(adev->dev, "No more PASIDs available!");
@@ -1457,8 +1486,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct 
drm_file *file_priv)
 
        amdgpu_ctx_mgr_init(&fpriv->ctx_mgr, adev);
 
-       file_priv->driver_priv = fpriv;
-       goto out_suspend;
+       fpriv->initialized = true;
+       goto out_unlock;
 
 error_vm:
        amdgpu_vm_fini(adev, &fpriv->vm);
@@ -1469,13 +1498,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev, 
struct drm_file *file_priv)
                amdgpu_vm_set_pasid(adev, &fpriv->vm, 0);
        }
 
-       kfree(fpriv);
-
-out_suspend:
-       pm_runtime_mark_last_busy(dev->dev);
-pm_put:
-       pm_runtime_put_autosuspend(dev->dev);
-
+out_unlock:
+       mutex_unlock(&fpriv->init_lock);
        return r;
 }
 
@@ -1500,6 +1524,9 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
        if (!fpriv)
                return;
 
+       if (!fpriv->initialized)
+               goto out_free;
+
        pm_runtime_get_sync(dev->dev);
 
        if (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_UVD) != NULL)
@@ -1537,11 +1564,12 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
        idr_destroy(&fpriv->bo_list_handles);
        mutex_destroy(&fpriv->bo_list_lock);
 
-       kfree(fpriv);
-       file_priv->driver_priv = NULL;
-
        pm_runtime_mark_last_busy(dev->dev);
        pm_runtime_put_autosuspend(dev->dev);
+
+out_free:
+       kfree(fpriv);
+       file_priv->driver_priv = NULL;
 }
 
 

-- 
2.50.1

Reply via email to