Commit 7a7cbf2a authored by Eric Anholt's avatar Eric Anholt Committed by Rob Clark
Browse files

drm/msm: Fix race of GPU init vs timestamp power management.



We were using the same force-poweron bit in the two codepaths, so they
could race to have one of them lose GPU power early.

freedreno CI was seeing intermittent errors like:
[drm:_a6xx_gmu_set_oob] *ERROR* Timeout waiting for GMU OOB set GPU_SET: 0x0
and this issue could have contributed to it.

Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Fixes: 4b565ca5 ("drm/msm: Add A6XX device support")
Reviewed-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 68e4f01f
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -264,6 +264,16 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
		}
		name = "GPU_SET";
		break;
	case GMU_OOB_PERFCOUNTER_SET:
		if (gmu->legacy) {
			request = GMU_OOB_PERFCOUNTER_REQUEST;
			ack = GMU_OOB_PERFCOUNTER_ACK;
		} else {
			request = GMU_OOB_PERFCOUNTER_REQUEST_NEW;
			ack = GMU_OOB_PERFCOUNTER_ACK_NEW;
		}
		name = "PERFCOUNTER";
		break;
	case GMU_OOB_BOOT_SLUMBER:
		request = GMU_OOB_BOOT_SLUMBER_REQUEST;
		ack = GMU_OOB_BOOT_SLUMBER_ACK;
@@ -301,9 +311,14 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
{
	if (!gmu->legacy) {
		WARN_ON(state != GMU_OOB_GPU_SET);
		if (state == GMU_OOB_GPU_SET) {
			gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
				1 << GMU_OOB_GPU_SET_CLEAR_NEW);
		} else {
			WARN_ON(state != GMU_OOB_PERFCOUNTER_SET);
			gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
				1 << GMU_OOB_PERFCOUNTER_CLEAR_NEW);
		}
		return;
	}

@@ -312,6 +327,10 @@ void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state)
		gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
			1 << GMU_OOB_GPU_SET_CLEAR);
		break;
	case GMU_OOB_PERFCOUNTER_SET:
		gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
			1 << GMU_OOB_PERFCOUNTER_CLEAR);
		break;
	case GMU_OOB_BOOT_SLUMBER:
		gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET,
			1 << GMU_OOB_BOOT_SLUMBER_CLEAR);
+8 −0
Original line number Diff line number Diff line
@@ -156,6 +156,7 @@ enum a6xx_gmu_oob_state {
	GMU_OOB_BOOT_SLUMBER = 0,
	GMU_OOB_GPU_SET,
	GMU_OOB_DCVS_SET,
	GMU_OOB_PERFCOUNTER_SET,
};

/* These are the interrupt / ack bits for each OOB request that are set
@@ -190,6 +191,13 @@ enum a6xx_gmu_oob_state {
#define GMU_OOB_GPU_SET_ACK_NEW		31
#define GMU_OOB_GPU_SET_CLEAR_NEW	31

#define GMU_OOB_PERFCOUNTER_REQUEST	17
#define GMU_OOB_PERFCOUNTER_ACK		25
#define GMU_OOB_PERFCOUNTER_CLEAR	25

#define GMU_OOB_PERFCOUNTER_REQUEST_NEW	28
#define GMU_OOB_PERFCOUNTER_ACK_NEW	30
#define GMU_OOB_PERFCOUNTER_CLEAR_NEW	30

void a6xx_hfi_init(struct a6xx_gmu *gmu);
int a6xx_hfi_start(struct a6xx_gmu *gmu, int boot_state);
+2 −2
Original line number Diff line number Diff line
@@ -1172,12 +1172,12 @@ static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
	struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu);

	/* Force the GPU power on so we can read this register */
	a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET);
	a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);

	*value = gpu_read64(gpu, REG_A6XX_RBBM_PERFCTR_CP_0_LO,
		REG_A6XX_RBBM_PERFCTR_CP_0_HI);

	a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET);
	a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET);
	return 0;
}