From 21d60ec6782e5d442152114f55ae8b7e1efe806c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 27 Jul 2017 09:28:53 -0400 Subject: [PATCH 2/2] drm/amdgpu: add a device_shutdown function Rather than piggybacking on the suspend code, add a proper shutdown function. This calls hw_fini rather than suspend and also clears the asic_init completed flags in the bios scratch registers which will force asic_init to run again on the next driver load. bug: https://bugs.freedesktop.org/show_bug.cgi?id=101946 Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 47 +++++++++++++++++++++++++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 51d1364..e077d9f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1909,9 +1909,9 @@ void amdgpu_driver_lastclose_kms(struct drm_device *dev); int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv); void amdgpu_driver_postclose_kms(struct drm_device *dev, struct drm_file *file_priv); -int amdgpu_suspend(struct amdgpu_device *adev); int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon); int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon); +int amdgpu_device_shutdown(struct amdgpu_device *adev); u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe); int amdgpu_enable_vblank_kms(struct drm_device *dev, unsigned int pipe); void amdgpu_disable_vblank_kms(struct drm_device *dev, unsigned int pipe); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 15f5586..0103f17 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1873,7 +1873,7 @@ static void amdgpu_late_init_func_handler(struct work_struct *work) amdgpu_late_set_cg_state(adev); } -int amdgpu_suspend(struct amdgpu_device *adev) +static int amdgpu_suspend(struct amdgpu_device *adev) { int i, r; @@ -1914,6 +1914,51 @@ int amdgpu_suspend(struct amdgpu_device *adev) return 0; } +int amdgpu_device_shutdown(struct amdgpu_device *adev) +{ + int i, r; + + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_request_full_gpu(adev, false); + + /* ungate SMC block first */ + r = amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC, + AMD_CG_STATE_UNGATE); + if (r) { + DRM_ERROR("set_clockgating_state(ungate) SMC failed %d\n", r); + } + + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { + if (!adev->ip_blocks[i].status.valid) + continue; + /* ungate blocks so that suspend can properly shut them down */ + if (i != AMD_IP_BLOCK_TYPE_SMC) { + r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev, + AMD_CG_STATE_UNGATE); + if (r) { + DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + } + } + /* XXX handle errors */ + r = adev->ip_blocks[i].version->funcs->hw_fini(adev); + /* XXX handle errors */ + if (r) { + DRM_ERROR("suspend of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + } + } + + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_release_full_gpu(adev, false); + + /* force asic_init to run the next time the driver loads */ + if (adev->asic_type >= CHIP_BONAIRE) + amdgpu_atombios_scratch_force_asic_init(adev); + + return 0; +} + static int amdgpu_sriov_reinit_early(struct amdgpu_device *adev) { int i, r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index b3d7beb..fec99e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -616,7 +616,7 @@ amdgpu_pci_shutdown(struct pci_dev *pdev) * unfortunately we can't detect certain * hypervisors so just do this all the time. */ - amdgpu_suspend(adev); + amdgpu_device_shutdown(adev); } static int amdgpu_pmops_suspend(struct device *dev) -- 2.5.5