[PATCH] drm/amd/amdgpu: workaround for UVD busy status

Liu, Leo Leo.Liu at amd.com
Wed Aug 14 16:58:58 UTC 2019


On 2019-08-14 7:11 a.m., Kenneth Feng wrote:
> On Vega20, tools depends on UVD_STATUS.VCPU_REPORT bit0
> to decide if UVD instances are in busy state or idle state.
> This workaround fixes the issue that tools always fetch the
> UVD instances state as busy state no matter if there is a UVD work.

The VCPU_REPORT is really for FW to report status to driver, not the 
other way around. Sounds to me this is a FW bug.

Regards,

Leo


>
> Signed-off-by: Kenneth Feng <kenneth.feng at amd.com>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu.h        |  3 +++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 23 +++++++++++++++++++++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c    | 30 ++++++++++++++++++++++++++++--
>   drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c      | 19 +++++++++++++++++++
>   drivers/gpu/drm/amd/include/amd_shared.h   |  1 +
>   5 files changed, 74 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 4d096ff..6e5a41b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -259,6 +259,9 @@ int amdgpu_device_ip_set_clockgating_state(void *dev,
>   int amdgpu_device_ip_set_powergating_state(void *dev,
>   					   enum amd_ip_block_type block_type,
>   					   enum amd_powergating_state state);
> +int amdgpu_device_ip_set_instance_state(void *dev,
> +					   enum amd_ip_block_type block_type,
> +					   bool busy_state, int inst);
>   void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
>   					    u32 *flags);
>   int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index 93ed3cb..e65e251 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -1127,6 +1127,29 @@ int amdgpu_device_ip_set_powergating_state(void *dev,
>   	return r;
>   }
>   
> +int amdgpu_device_ip_set_instance_state(void *dev,
> +					   enum amd_ip_block_type block_type,
> +					   bool busy_state, int inst)
> +{
> +	struct amdgpu_device *adev = dev;
> +	int i, r = 0;
> +
> +	for (i = 0; i < adev->num_ip_blocks; i++) {
> +		if (!adev->ip_blocks[i].status.valid)
> +			continue;
> +		if (adev->ip_blocks[i].version->type != block_type)
> +			continue;
> +		if (!adev->ip_blocks[i].version->funcs->set_instance_state)
> +			continue;
> +		r = adev->ip_blocks[i].version->funcs->set_instance_state(
> +			(void *)adev, busy_state, inst);
> +		if (r)
> +			DRM_ERROR("set_instance_state of IP block <%s> failed %d\n",
> +				  adev->ip_blocks[i].version->funcs->name, r);
> +	}
> +	return r;
> +}
> +
>   /**
>    * amdgpu_device_ip_get_clockgating_state - get the CG state
>    *
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
> index 4e5d13e4..d3496ab 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
> @@ -1180,13 +1180,22 @@ static void amdgpu_uvd_idle_work_handler(struct work_struct *work)
>   	struct amdgpu_device *adev =
>   		container_of(work, struct amdgpu_device, uvd.idle_work.work);
>   	unsigned fences = 0, i, j;
> +	unsigned *fences_inst = (unsigned *)kzalloc(adev->uvd.num_uvd_inst*sizeof(unsigned), GFP_KERNEL);
>   
>   	for (i = 0; i < adev->uvd.num_uvd_inst; ++i) {
>   		if (adev->uvd.harvest_config & (1 << i))
>   			continue;
> -		fences += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring);
> +		fences_inst[i] = amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring);
> +		fences += fences_inst[i];
>   		for (j = 0; j < adev->uvd.num_enc_rings; ++j) {
> -			fences += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring_enc[j]);
> +			fences_inst[i] += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring_enc[j]);
> +			fences += fences_inst[i];
> +		}
> +		/* workaround for the tools to show UVD busy status */
> +		if (fences_inst[i] == 0) {
> +			amdgpu_device_ip_set_instance_state(adev, AMD_IP_BLOCK_TYPE_UVD,
> +							       false, i);
> +			printk("Kenneth - set instance idle!\n");
>   		}
>   	}
>   
> @@ -1210,10 +1219,27 @@ void amdgpu_uvd_ring_begin_use(struct amdgpu_ring *ring)
>   {
>   	struct amdgpu_device *adev = ring->adev;
>   	bool set_clocks;
> +	unsigned i,j;
> +	unsigned *fences_inst = (unsigned *)kzalloc(adev->uvd.num_uvd_inst*sizeof(unsigned), GFP_KERNEL);
>   
>   	if (amdgpu_sriov_vf(adev))
>   		return;
>   
> +	for (i = 0; i < adev->uvd.num_uvd_inst; ++i) {
> +		printk("Kenneth - run after set_clock!\n");
> +		if (adev->uvd.harvest_config & (1 << i))
> +			continue;
> +		fences_inst[i] = amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring);
> +		for (j = 0; j < adev->uvd.num_enc_rings; ++j)
> +			fences_inst[i] += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring_enc[j]);
> +		/* workaround for the tools to show UVD busy */
> +		if (fences_inst[i] != 0) {
> +			amdgpu_device_ip_set_instance_state(adev, AMD_IP_BLOCK_TYPE_UVD,
> +						       true, i);
> +			printk("Kenneth - run in setting instance state!\n");
> +		}
> +	}
> +
>   	set_clocks = !cancel_delayed_work_sync(&adev->uvd.idle_work);
>   	if (set_clocks) {
>   		if (adev->pm.dpm_enabled) {
> diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
> index 2f3d4e8..bf0f33a 100644
> --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c
> @@ -1738,6 +1738,24 @@ static int uvd_v7_0_set_clockgating_state(void *handle,
>   	return 0;
>   }
>   
> +/* workaround for tools to fetch the UVD busy status */
> +static int uvd_v7_0_set_instance_state(void *handle, bool busy_state, int inst)
> +{
> +	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
> +
> +	if(inst >= adev->uvd.num_uvd_inst)
> +		return -EINVAL;
> +
> +	if(busy_state)
> +		WREG32_P(SOC15_REG_OFFSET(UVD, inst, mmUVD_STATUS), (1 << UVD_STATUS__VCPU_REPORT__SHIFT),
> +				~(1 << UVD_STATUS__VCPU_REPORT__SHIFT));
> +	else
> +		WREG32_P(SOC15_REG_OFFSET(UVD, inst, mmUVD_STATUS), 0,
> +				~(1 << UVD_STATUS__VCPU_REPORT__SHIFT));
> +
> +	return 0;
> +}
> +
>   const struct amd_ip_funcs uvd_v7_0_ip_funcs = {
>   	.name = "uvd_v7_0",
>   	.early_init = uvd_v7_0_early_init,
> @@ -1756,6 +1774,7 @@ const struct amd_ip_funcs uvd_v7_0_ip_funcs = {
>   	.post_soft_reset = NULL /* uvd_v7_0_post_soft_reset */,
>   	.set_clockgating_state = uvd_v7_0_set_clockgating_state,
>   	.set_powergating_state = NULL /* uvd_v7_0_set_powergating_state */,
> +	.set_instance_state = uvd_v7_0_set_instance_state,
>   };
>   
>   static const struct amdgpu_ring_funcs uvd_v7_0_ring_vm_funcs = {
> diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
> index 779c9e7..8cc54c9 100644
> --- a/drivers/gpu/drm/amd/include/amd_shared.h
> +++ b/drivers/gpu/drm/amd/include/amd_shared.h
> @@ -198,6 +198,7 @@ struct amd_ip_funcs {
>   	void (*get_clockgating_state)(void *handle, u32 *flags);
>   	/** @enable_umd_pstate: enable UMD powerstate */
>   	int (*enable_umd_pstate)(void *handle, enum amd_dpm_forced_level *level);
> +	int (*set_instance_state)(void *handle, bool busy_state, int inst);
>   };
>   
>   


More information about the amd-gfx mailing list