Skip to content

Commit

Permalink
drm/amdgpu: Fix CP_HQD_PQ_WPTR initialization on KFD HQD load
Browse files Browse the repository at this point in the history
The return value from copy_from_user() was interpreted as the opposite
of its intended meaning. This caused PQ_WPTR to be populated with the
uninitialized value from shadow_wptr, causing intermittent HIQ hangs.

Always initialize PQ_WPTR to zero if a shadow write pointer is not
available. Also check for NULL as this may be mapped in userspace
but has a specific meaning when passed to hqd_load().

Change-Id: I3ced7765659a043a53b8123bace0e6288a23b59d
Signed-off-by: Jay Cornwall <jay.cornwall@amd.com>
Reviewed-by: David Ogbeide <davidboyowa.ogbeide@amd.com>
  • Loading branch information
Jay Cornwall authored and Gerrit Code Review committed May 2, 2016
1 parent 3c396d2 commit b3c5e1b
Showing 2 changed files with 10 additions and 11 deletions.
8 changes: 4 additions & 4 deletions drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
Original file line number Diff line number Diff line change
@@ -416,12 +416,13 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
uint32_t page_table_base)
{
struct amdgpu_device *adev = get_amdgpu_device(kgd);
uint32_t wptr_shadow, is_wptr_shadow_valid;
struct cik_mqd *m;
uint32_t wptr_shadow = 0, is_wptr_shadow_valid = 0;

m = get_mqd(mqd);

is_wptr_shadow_valid = !get_user(wptr_shadow, wptr);
if (wptr != NULL)
is_wptr_shadow_valid = !get_user(wptr_shadow, wptr);

acquire_queue(kgd, pipe_id, queue_id);

@@ -475,8 +476,7 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,

WREG32(mmCP_HQD_IQ_RPTR, m->cp_hqd_iq_rptr);

if (is_wptr_shadow_valid)
WREG32(mmCP_HQD_PQ_WPTR, wptr_shadow);
WREG32(mmCP_HQD_PQ_WPTR, (is_wptr_shadow_valid ? wptr_shadow : 0));

WREG32(mmCP_HQD_ACTIVE, m->cp_hqd_active);
release_queue(kgd);
13 changes: 6 additions & 7 deletions drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
Original file line number Diff line number Diff line change
@@ -322,13 +322,15 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
uint32_t queue_id, uint32_t __user *wptr,
uint32_t page_table_base)
{
struct vi_mqd *m;
uint32_t shadow_wptr, valid_wptr;
struct amdgpu_device *adev = get_amdgpu_device(kgd);
struct vi_mqd *m;
uint32_t wptr_shadow = 0, is_wptr_shadow_valid = 0;

m = get_mqd(mqd);

valid_wptr = copy_from_user(&shadow_wptr, wptr, sizeof(shadow_wptr));
if (wptr != NULL)
is_wptr_shadow_valid = !get_user(wptr_shadow, wptr);

acquire_queue(kgd, pipe_id, queue_id);

WREG32(mmCOMPUTE_STATIC_THREAD_MGMT_SE0,
@@ -354,10 +356,7 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR, m->cp_hqd_pq_rptr_report_addr_lo);
WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR_HI,
m->cp_hqd_pq_rptr_report_addr_hi);

if (valid_wptr > 0)
WREG32(mmCP_HQD_PQ_WPTR, shadow_wptr);

WREG32(mmCP_HQD_PQ_WPTR, (is_wptr_shadow_valid ? wptr_shadow : 0));
WREG32(mmCP_HQD_PQ_CONTROL, m->cp_hqd_pq_control);
WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, m->cp_hqd_pq_doorbell_control);

0 comments on commit b3c5e1b

Please sign in to comment.