Skip to content

Commit

Permalink
drm/msm: a6xx: Use WHERE_AM_I for eligible targets
Browse files Browse the repository at this point in the history
Support the WHERE_AM_I opcode for the A618, A630 and A640 GPUs if the
microcode supports it. The WHERE_AM_I opcode allows the RPTR shadow
to be updated in priviliged memory which protects the shadow from being
read or written from user submissions.

A650 already supports extended APRIV have built in hardware support for
to access privilged memory from the CP and can go back to using the
hardware RPTR shadow feature.

Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@chromium.org>
  • Loading branch information
Jordan Crouse authored and Rob Clark committed Sep 15, 2020
1 parent 8907afb commit d3a569f
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 3 deletions.
87 changes: 84 additions & 3 deletions drivers/gpu/drm/msm/adreno/a6xx_gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,20 @@ bool a6xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring)

static void a6xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);
uint32_t wptr;
unsigned long flags;

/* Expanded APRIV doesn't need to issue the WHERE_AM_I opcode */
if (a6xx_gpu->has_whereami && !adreno_gpu->base.hw_apriv) {
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);

OUT_PKT7(ring, CP_WHERE_AM_I, 2);
OUT_RING(ring, lower_32_bits(shadowptr(a6xx_gpu, ring)));
OUT_RING(ring, upper_32_bits(shadowptr(a6xx_gpu, ring)));
}

spin_lock_irqsave(&ring->lock, flags);

/* Copy the shadow to the actual register */
Expand Down Expand Up @@ -508,6 +519,30 @@ static int a6xx_cp_init(struct msm_gpu *gpu)
return a6xx_idle(gpu, ring) ? 0 : -EINVAL;
}

static void a6xx_ucode_check_version(struct a6xx_gpu *a6xx_gpu,
struct drm_gem_object *obj)
{
u32 *buf = msm_gem_get_vaddr_active(obj);

if (IS_ERR(buf))
return;

/*
* If the lowest nibble is 0xa that is an indication that this microcode
* has been patched. The actual version is in dword [3] but we only care
* about the patchlevel which is the lowest nibble of dword [3]
*
* Otherwise check that the firmware is greater than or equal to 1.90
* which was the first version that had this fix built in
*/
if (((buf[0] & 0xf) == 0xa) && (buf[2] & 0xf) >= 1)
a6xx_gpu->has_whereami = true;
else if ((buf[0] & 0xfff) > 0x190)
a6xx_gpu->has_whereami = true;

msm_gem_put_vaddr(obj);
}

static int a6xx_ucode_init(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
Expand All @@ -528,6 +563,7 @@ static int a6xx_ucode_init(struct msm_gpu *gpu)
}

msm_gem_object_set_name(a6xx_gpu->sqe_bo, "sqefw");
a6xx_ucode_check_version(a6xx_gpu, a6xx_gpu->sqe_bo);
}

gpu_write64(gpu, REG_A6XX_CP_SQE_INSTR_BASE_LO,
Expand Down Expand Up @@ -743,8 +779,37 @@ static int a6xx_hw_init(struct msm_gpu *gpu)
gpu_write64(gpu, REG_A6XX_CP_RB_BASE, REG_A6XX_CP_RB_BASE_HI,
gpu->rb[0]->iova);

gpu_write(gpu, REG_A6XX_CP_RB_CNTL,
MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
/* Targets that support extended APRIV can use the RPTR shadow from
* hardware but all the other ones need to disable the feature. Targets
* that support the WHERE_AM_I opcode can use that instead
*/
if (adreno_gpu->base.hw_apriv)
gpu_write(gpu, REG_A6XX_CP_RB_CNTL, MSM_GPU_RB_CNTL_DEFAULT);
else
gpu_write(gpu, REG_A6XX_CP_RB_CNTL,
MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);

/*
* Expanded APRIV and targets that support WHERE_AM_I both need a
* privileged buffer to store the RPTR shadow
*/

if (adreno_gpu->base.hw_apriv || a6xx_gpu->has_whereami) {
if (!a6xx_gpu->shadow_bo) {
a6xx_gpu->shadow = msm_gem_kernel_new_locked(gpu->dev,
sizeof(u32) * gpu->nr_rings,
MSM_BO_UNCACHED | MSM_BO_MAP_PRIV,
gpu->aspace, &a6xx_gpu->shadow_bo,
&a6xx_gpu->shadow_iova);

if (IS_ERR(a6xx_gpu->shadow))
return PTR_ERR(a6xx_gpu->shadow);
}

gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR_LO,
REG_A6XX_CP_RB_RPTR_ADDR_HI,
shadowptr(a6xx_gpu, gpu->rb[0]));
}

/* Always come up on rb 0 */
a6xx_gpu->cur_ring = gpu->rb[0];
Expand Down Expand Up @@ -1033,6 +1098,11 @@ static void a6xx_destroy(struct msm_gpu *gpu)
drm_gem_object_put(a6xx_gpu->sqe_bo);
}

if (a6xx_gpu->shadow_bo) {
msm_gem_unpin_iova(a6xx_gpu->shadow_bo, gpu->aspace);
drm_gem_object_put(a6xx_gpu->shadow_bo);
}

a6xx_gmu_remove(a6xx_gpu);

adreno_gpu_cleanup(adreno_gpu);
Expand Down Expand Up @@ -1081,6 +1151,17 @@ a6xx_create_private_address_space(struct msm_gpu *gpu)
"gpu", 0x100000000ULL, 0x1ffffffffULL);
}

static uint32_t a6xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);

if (adreno_gpu->base.hw_apriv || a6xx_gpu->has_whereami)
return a6xx_gpu->shadow[ring->id];

return ring->memptrs->rptr = gpu_read(gpu, REG_A6XX_CP_RB_RPTR);
}

static const struct adreno_gpu_funcs funcs = {
.base = {
.get_param = adreno_get_param,
Expand All @@ -1089,7 +1170,6 @@ static const struct adreno_gpu_funcs funcs = {
.pm_resume = a6xx_pm_resume,
.recover = a6xx_recover,
.submit = a6xx_submit,
.flush = a6xx_flush,
.active_ring = a6xx_active_ring,
.irq = a6xx_irq,
.destroy = a6xx_destroy,
Expand All @@ -1105,6 +1185,7 @@ static const struct adreno_gpu_funcs funcs = {
#endif
.create_address_space = adreno_iommu_create_address_space,
.create_private_address_space = a6xx_create_private_address_space,
.get_rptr = a6xx_get_rptr,
},
.get_timestamp = a6xx_get_timestamp,
};
Expand Down
9 changes: 9 additions & 0 deletions drivers/gpu/drm/msm/adreno/a6xx_gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ struct a6xx_gpu {
struct msm_file_private *cur_ctx;

struct a6xx_gmu gmu;

struct drm_gem_object *shadow_bo;
uint64_t shadow_iova;
uint32_t *shadow;

bool has_whereami;
};

#define to_a6xx_gpu(x) container_of(x, struct a6xx_gpu, base)
Expand Down Expand Up @@ -51,6 +57,9 @@ static inline bool a6xx_has_gbif(struct adreno_gpu *gpu)
return true;
}

#define shadowptr(_a6xx_gpu, _ring) ((_a6xx_gpu)->shadow_iova + \
((_ring)->id * sizeof(uint32_t)))

int a6xx_gmu_resume(struct a6xx_gpu *gpu);
int a6xx_gmu_stop(struct a6xx_gpu *gpu);

Expand Down

0 comments on commit d3a569f

Please sign in to comment.