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