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@xxxxxxx> > --- > 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); > }; > > _______________________________________________ amd-gfx mailing list amd-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/amd-gfx