[PATCH] drm/amdgpu: S3 resume fail on Polaris10

Christian König deathsimple at vodafone.de
Thu Jul 14 08:40:40 UTC 2016


Am 14.07.2016 um 07:48 schrieb jimqu:
> Sometimes, driver can not return from fence waiting when doing VCE ring
> ib test. The issue is a asic special and random issue. so adjust VCE suspend
> and resume sequence.
>
> Change-Id: I60d4ce413d787ae70e5c785aa5ac45d6644fbf69
> Signed-off-by: JimQu <Jim.Qu at amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 144 +++++++++++++++++++++++-----------
>   1 file changed, 99 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
> index 30e8099..0f7957a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
> @@ -43,6 +43,7 @@
>   #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0	0x8616
>   #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1	0x8617
>   #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2	0x8618
> +#define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK	0x02
>   
>   #define VCE_V3_0_FW_SIZE	(384 * 1024)
>   #define VCE_V3_0_STACK_SIZE	(64 * 1024)
> @@ -51,6 +52,7 @@
>   static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx);
>   static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev);
>   static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev);
> +static int vce_v3_0_wait_for_idle(void *handle);
>   
>   /**
>    * vce_v3_0_ring_get_rptr - get read pointer
> @@ -205,6 +207,32 @@ static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
>   	vce_v3_0_override_vce_clock_gating(adev, false);
>   }
>   
> +static int vce_v3_0_firmware_loaded(struct amdgpu_device *adev)
> +{
> +	int i, j;
> +
> +	for (i = 0; i < 10; ++i) {
> +		uint32_t status;
> +		for (j = 0; j < 100; ++j) {
> +			status = RREG32(mmVCE_STATUS);
> +			if (status & VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK)
> +				return 0;
> +			mdelay(10);
> +		}
> +
> +		DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
> +		WREG32_P(mmVCE_SOFT_RESET,
> +			VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
> +			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
> +		mdelay(10);
> +		WREG32_P(mmVCE_SOFT_RESET, 0,
> +			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
> +		mdelay(10);
> +	}
> +
> +	return -1;

While at it you should probably return a better error code here.

Something like -ETIMEDOUT or -EBUSY should do.

> +}
> +
>   /**
>    * vce_v3_0_start - start VCE block
>    *
> @@ -215,11 +243,27 @@ static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev,
>   static int vce_v3_0_start(struct amdgpu_device *adev)
>   {
>   	struct amdgpu_ring *ring;
> -	int idx, i, j, r;
> +	int idx, r;
>   
>   	mutex_lock(&adev->grbm_idx_mutex);
>   	for (idx = 0; idx < 2; ++idx) {
>   
> +		ring = &adev->vce.ring[idx];
> +
> +		if (idx == 0) {
> +			WREG32(mmVCE_RB_RPTR, ring->wptr);
> +			WREG32(mmVCE_RB_WPTR, ring->wptr);
> +			WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
> +			WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
> +			WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
> +		} else {
> +			WREG32(mmVCE_RB_RPTR2, ring->wptr);
> +			WREG32(mmVCE_RB_WPTR2, ring->wptr);
> +			WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
> +			WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
> +			WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
> +		}
> +

The ring index is independent from the instance, so this is clearly 
incorrect.

If the ring buffer needs to be initialized before the firmware starts 
(which makes sense) then just move the register writes before the loop.

Apart from that looks good to me.

Regards,
Christian.

>   		if (adev->vce.harvest_config & (1 << idx))
>   			continue;
>   
> @@ -233,48 +277,24 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
>   
>   		vce_v3_0_mc_resume(adev, idx);
>   
> -		/* set BUSY flag */
> -		WREG32_P(mmVCE_STATUS, 1, ~1);
> +		WREG32_P(mmVCE_STATUS, VCE_STATUS__JOB_BUSY_MASK,
> +		         ~VCE_STATUS__JOB_BUSY_MASK);
> +
>   		if (adev->asic_type >= CHIP_STONEY)
>   			WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
>   		else
>   			WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
>   				~VCE_VCPU_CNTL__CLK_EN_MASK);
>   
> -		WREG32_P(mmVCE_SOFT_RESET,
> -			 VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
> -			 ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
> -
> -		mdelay(100);
> -
>   		WREG32_P(mmVCE_SOFT_RESET, 0,
>   			~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
>   
> -		for (i = 0; i < 10; ++i) {
> -			uint32_t status;
> -			for (j = 0; j < 100; ++j) {
> -				status = RREG32(mmVCE_STATUS);
> -				if (status & 2)
> -					break;
> -				mdelay(10);
> -			}
> -			r = 0;
> -			if (status & 2)
> -				break;
> -
> -			DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
> -			WREG32_P(mmVCE_SOFT_RESET,
> -				VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
> -				~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
> -			mdelay(10);
> -			WREG32_P(mmVCE_SOFT_RESET, 0,
> -				~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
> -			mdelay(10);
> -			r = -1;
> -		}
> +		mdelay(100);
> +
> +		r = vce_v3_0_firmware_loaded(adev);
>   
>   		/* clear BUSY flag */
> -		WREG32_P(mmVCE_STATUS, 0, ~1);
> +		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
>   
>   		/* Set Clock-Gating off */
>   		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
> @@ -290,19 +310,46 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
>   	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
>   	mutex_unlock(&adev->grbm_idx_mutex);
>   
> -	ring = &adev->vce.ring[0];
> -	WREG32(mmVCE_RB_RPTR, ring->wptr);
> -	WREG32(mmVCE_RB_WPTR, ring->wptr);
> -	WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
> -	WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
> -	WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
> +	return 0;
> +}
>   
> -	ring = &adev->vce.ring[1];
> -	WREG32(mmVCE_RB_RPTR2, ring->wptr);
> -	WREG32(mmVCE_RB_WPTR2, ring->wptr);
> -	WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
> -	WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
> -	WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
> +static int vce_v3_0_stop(struct amdgpu_device *adev)
> +{
> +	int idx;
> +
> +	mutex_lock(&adev->grbm_idx_mutex);
> +	for (idx = 0; idx < 2; ++idx) {
> +		if (adev->vce.harvest_config & (1 << idx))
> +			continue;
> +
> +		if (idx == 0)
> +			WREG32_P(mmGRBM_GFX_INDEX, 0,
> +				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
> +		else
> +			WREG32_P(mmGRBM_GFX_INDEX,
> +				GRBM_GFX_INDEX__VCE_INSTANCE_MASK,
> +				~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
> +
> +		if (adev->asic_type >= CHIP_STONEY)
> +			WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
> +		else
> +			WREG32_P(mmVCE_VCPU_CNTL, 0,
> +				~VCE_VCPU_CNTL__CLK_EN_MASK);
> +		/* hold on ECPU */
> +		WREG32_P(mmVCE_SOFT_RESET,
> +			 VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
> +			 ~VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK);
> +
> +		/* clear BUSY flag */
> +		WREG32_P(mmVCE_STATUS, 0, ~VCE_STATUS__JOB_BUSY_MASK);
> +
> +		/* Set Clock-Gating off */
> +		if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
> +			vce_v3_0_set_vce_sw_clock_gating(adev, false);
> +	}
> +
> +	WREG32_P(mmGRBM_GFX_INDEX, 0, ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
> +	mutex_unlock(&adev->grbm_idx_mutex);
>   
>   	return 0;
>   }
> @@ -441,7 +488,14 @@ static int vce_v3_0_hw_init(void *handle)
>   
>   static int vce_v3_0_hw_fini(void *handle)
>   {
> -	return 0;
> +	int r;
> +	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
> +
> +	r = vce_v3_0_wait_for_idle(handle);
> +	if (r)
> +		return r;
> +
> +	return vce_v3_0_stop(adev);
>   }
>   
>   static int vce_v3_0_suspend(void *handle)



More information about the amd-gfx mailing list