msm: kgsl: Resolve a potential race in the interrupt handler
In the GPU interrupt handler we attempt to clear the ts_cmp_enable
for the active context so that future interrupts are skipped until
someone needs one again. If for some reason the interrupt handler
is delayed then there is a possiblity that the "current" context in
the GPU isn't the one that fired the interrupt. In that case we
could be accidently clearing a ts_cmp_enable for a context that
needs it. Instead of clearing in the interrupt handler clear it
from the GPU so we can be sure we got the right context.
As a bonus pushing this logic to the GPU side lets us get rid of
some extra register reads/writes in the interrupt handlers.
Change-Id: Ic0dedbadbf350f7c4866092fa0686f9b42f3cd33
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 7e993a20..179027c 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -564,10 +564,9 @@
total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
/* 2 dwords to store the start of command sequence */
total_sizedwords += 2;
- /*
- * Add CP_COND_EXEC commands to generate CP_INTERRUPT only
- */
- total_sizedwords += context ? 7 : 0;
+
+ /* Add CP_COND_EXEC commands to generate CP_INTERRUPT */
+ total_sizedwords += context ? 13 : 0;
if (adreno_is_a3xx(adreno_dev))
total_sizedwords += 7;
@@ -696,7 +695,25 @@
context_id, ref_wait_ts)) >> 2);
GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
/* # of conditional command DWORDs */
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 2);
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, 8);
+
+ /* Clear the ts_cmp_enable for the context */
+ GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_MEM_WRITE, 2));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+ KGSL_MEMSTORE_OFFSET(
+ context_id, ts_cmp_enable));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+
+ /* Clear the ts_cmp_enable for the global timestamp */
+ GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_MEM_WRITE, 2));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+ KGSL_MEMSTORE_OFFSET(
+ KGSL_MEMSTORE_GLOBAL, ts_cmp_enable));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+
+ /* Trigger the interrupt */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_INTERRUPT, 1));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);