[PATCH 4/4] drm/amd/powerplay: Prevent UVD powerdown before init

Tom St Denis tstdenis82 at gmail.com
Tue Jul 26 15:38:32 UTC 2016


Because of the ip_blocks init order powerplay would power down
the UVD block before UVD start is called.  This results in a VCPU
hang.

This patch prevents power down before UVD is initialized.

Also correct the power up order so clocking is set after power
is ungated.

With this applied comparable clock/power behaviour to powerplay=0 with
DPM is observed.

Signed-off-by: Tom St Denis <tom.stdenis at amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h                |  6 ++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c            |  5 -----
 drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c              |  8 ++++---
 drivers/gpu/drm/amd/amdgpu/vi.c                    | 12 ++++-------
 .../drm/amd/powerplay/hwmgr/cz_clockpowergating.c  | 25 ++++++++++++++++++----
 drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c     |  7 ++++++
 6 files changed, 43 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index d0460ea2f85b..5616b16e6c0a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1692,6 +1692,7 @@ struct amdgpu_uvd {
 	uint32_t                srbm_soft_reset;
 	int			cg_state, pg_state;
 	struct mutex            pg_lock;
+	bool			is_init;
 };
 
 /*
@@ -2518,5 +2519,10 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev );
 static inline int amdgpu_dm_display_resume(struct amdgpu_device *adev) { return 0; }
 #endif
 
+struct amdgpu_cgs_device {
+	struct cgs_device base;
+	struct amdgpu_device *adev;
+};
+
 #include "amdgpu_object.h"
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
index ee95e950a19b..d553e399a835 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
@@ -33,11 +33,6 @@
 #include "atom.h"
 #include "amdgpu_ucode.h"
 
-struct amdgpu_cgs_device {
-	struct cgs_device base;
-	struct amdgpu_device *adev;
-};
-
 #define CGS_FUNC_ADEV							\
 	struct amdgpu_device *adev =					\
 		((struct amdgpu_cgs_device *)cgs_device)->adev
diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
index 422d5300b92e..3b93327c5e25 100644
--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
@@ -389,9 +389,9 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
 	uint32_t mp_swap_cntl;
 	int i, j, r;
 
-	/* is power gated? then we can't start (TODO: re-enable power) */
-	if (adev->uvd.pg_state)
-		return -EINVAL;
+	/* is power gated? then we can't start but don't return an error */
+	if (adev->uvd.is_init && adev->uvd.pg_state)
+		return 0;
 
 	/* set CG state to -1 for unset */
 	adev->uvd.cg_state = -1;
@@ -662,6 +662,8 @@ static int uvd_v6_0_ring_test_ring(struct amdgpu_ring *ring)
 			  ring->idx, tmp);
 		r = -EINVAL;
 	}
+	if (!r)
+		adev->uvd.is_init = true;
 	return r;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
index 78fea940d120..f4fdde0641b0 100644
--- a/drivers/gpu/drm/amd/amdgpu/vi.c
+++ b/drivers/gpu/drm/amd/amdgpu/vi.c
@@ -1583,10 +1583,8 @@ static int vi_common_early_init(void *handle)
 		if (adev->rev_id != 0x00) {
 			adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
 				AMD_PG_SUPPORT_GFX_SMG |
-				AMD_PG_SUPPORT_GFX_PIPELINE;
-			/* powerplay UVD PG doesn't work yet */
-			if (!amdgpu_powerplay)
-				adev->pg_flags |= AMD_PG_SUPPORT_UVD;
+				AMD_PG_SUPPORT_GFX_PIPELINE |
+				AMD_PG_SUPPORT_UVD;
 		}
 		adev->external_rev_id = adev->rev_id + 0x1;
 		break;
@@ -1608,10 +1606,8 @@ static int vi_common_early_init(void *handle)
 			AMD_CG_SUPPORT_SDMA_LS;
 		adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG |
 			AMD_PG_SUPPORT_GFX_SMG |
-			AMD_PG_SUPPORT_GFX_PIPELINE;
-		/* powerplay UVD PG doesn't work yet */
-		if (!amdgpu_powerplay)
-			adev->pg_flags |= AMD_PG_SUPPORT_UVD;
+			AMD_PG_SUPPORT_GFX_PIPELINE |
+			AMD_PG_SUPPORT_UVD;
 		adev->external_rev_id = adev->rev_id + 0x1;
 		break;
 	default:
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
index 2da548f6337e..baa7366fad53 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
@@ -21,9 +21,13 @@
  *
  */
 
+#include "amdgpu.h"
 #include "hwmgr.h"
 #include "cz_clockpowergating.h"
 #include "cz_ppsmc.h"
+#include "cgs_linux.h"
+#include "uvd/uvd_6_0_d.h"
+#include "uvd/uvd_6_0_sh_mask.h"
 
 /* PhyID -> Status Mapping in DDI_PHY_GEN_STATUS
     0    GFX0L (3:0),                  (27:24),
@@ -160,12 +164,24 @@ int cz_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable)
 int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
 {
 	struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
+	struct amdgpu_cgs_device *cgs_dev = hwmgr->device;
+	struct amdgpu_device *adev = cgs_dev->adev;
 
-	if (cz_hwmgr->uvd_power_gated == bgate)
+	if (!adev->uvd.is_init)
 		return 0;
 
+	mutex_lock(&adev->uvd.pg_lock);
+
+	if (cz_hwmgr->uvd_power_gated == bgate) {
+		mutex_unlock(&adev->uvd.pg_lock);
+		return 0;
+	}
+
+	adev->uvd.pg_state = bgate;
 	cz_hwmgr->uvd_power_gated = bgate;
 
+	WREG32(mmUVD_POWER_STATUS, UVD_POWER_STATUS__UVD_PG_EN_MASK);
+
 	if (bgate) {
 		cgs_set_clockgating_state(hwmgr->device,
 						AMD_IP_BLOCK_TYPE_UVD,
@@ -177,14 +193,15 @@ int cz_dpm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
 		cz_dpm_powerdown_uvd(hwmgr);
 	} else {
 		cz_dpm_powerup_uvd(hwmgr);
-		cgs_set_clockgating_state(hwmgr->device,
-						AMD_IP_BLOCK_TYPE_UVD,
-						AMD_PG_STATE_GATE);
 		cgs_set_powergating_state(hwmgr->device,
 						AMD_IP_BLOCK_TYPE_UVD,
 						AMD_CG_STATE_UNGATE);
+		cgs_set_clockgating_state(hwmgr->device,
+						AMD_IP_BLOCK_TYPE_UVD,
+						AMD_PG_STATE_GATE);
 		cz_dpm_update_uvd_dpm(hwmgr, false);
 	}
+	mutex_unlock(&adev->uvd.pg_lock);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
index 9bf622e123b6..bed0013674a1 100644
--- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
+++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
@@ -39,6 +39,7 @@
 #include "power_state.h"
 #include "cz_clockpowergating.h"
 #include "pp_debug.h"
+#include "amdgpu.h"
 
 #define ixSMUSVI_NB_CURRENTVID 0xD8230044
 #define CURRENT_NB_VID_MASK 0xff000000
@@ -1356,6 +1357,12 @@ static int cz_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
 
 int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr)
 {
+	struct amdgpu_cgs_device *cgs_dev = hwmgr->device;
+	struct amdgpu_device *adev = cgs_dev->adev;
+
+	if (!adev->uvd.is_init)
+		return 0;
+
 	if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 					 PHM_PlatformCaps_UVDPowerGating))
 		return smum_send_msg_to_smc(hwmgr->smumgr,
-- 
2.9.2



More information about the amd-gfx mailing list