msm: kgsl: Ensure the GMU does not go to sleep in ISR

Poke the GMU keep alive register inside the ISR to ensure the
GMU does not power down. There might be additional GMU status
register reads in the ISR. Unpoke the GMU keep alive register
before exiting the ISR (unless snapshot is to occur). If snapshot
should occur, let the snapshot unpoke the keep alive register
after it is done snapshotting.

Change-Id: Ib722f3fcbe027e0b561a4e4fdbda03d38c1faeb4
Signed-off-by: Carter Cooper <ccooper@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index ebaa1a9..fbf0e7b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -609,6 +609,14 @@
 	/* Ensure this increment is done before the IRQ status is updated */
 	smp_mb__after_atomic();
 
+	/*
+	 * On A6xx, the GPU can power down once the INT_0_STATUS is read
+	 * below. But there still might be some register reads required
+	 * so force the GMU/GPU into KEEPALIVE mode until done with the ISR.
+	 */
+	if (gpudev->gpu_keepalive)
+		gpudev->gpu_keepalive(adreno_dev, true);
+
 	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);
 
 	/*
@@ -647,6 +655,13 @@
 		adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD,
 				int_bit);
 
+	/* Turn off the KEEPALIVE vote from earlier unless hard fault set */
+	if (gpudev->gpu_keepalive) {
+		/* If hard fault, then let snapshot turn off the keepalive */
+		if (!(adreno_gpu_fault(adreno_dev) & ADRENO_HARD_FAULT))
+			gpudev->gpu_keepalive(adreno_dev, false);
+	}
+
 	/* Make sure the regwrites are done before the decrement */
 	smp_mb__before_atomic();
 	atomic_dec(&adreno_dev->pending_irq_refcnt);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 0d83b29..1827ae5 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -855,6 +855,8 @@
 				unsigned int clear_mask);
 	void (*oob_clear)(struct adreno_device *adreno_dev,
 				unsigned int clear_mask);
+	void (*gpu_keepalive)(struct adreno_device *adreno_dev,
+			bool state);
 	int (*rpmh_gpu_pwrctrl)(struct adreno_device *, unsigned int ops,
 				unsigned int arg1, unsigned int arg2);
 	bool (*hw_isidle)(struct adreno_device *);
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 14ace33..9e66ce1 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -980,6 +980,18 @@
 	trace_kgsl_gmu_oob_clear(clear_mask);
 }
 
+/*
+ * a6xx_gpu_keepalive() - GMU reg write to request GPU stays on
+ * @adreno_dev: Pointer to the adreno device that has the GMU
+ * @state: State to set: true is ON, false is OFF
+ */
+static inline void a6xx_gpu_keepalive(struct adreno_device *adreno_dev,
+		bool state)
+{
+	adreno_write_gmureg(adreno_dev,
+			ADRENO_REG_GMU_PWR_COL_KEEPALIVE, state);
+}
+
 #define SPTPRAC_POWERON_CTRL_MASK	0x00778000
 #define SPTPRAC_POWEROFF_CTRL_MASK	0x00778001
 #define SPTPRAC_POWEROFF_STATUS_MASK	BIT(2)
@@ -2309,6 +2321,7 @@
 	.llc_enable_overrides = a6xx_llc_enable_overrides,
 	.oob_set = a6xx_oob_set,
 	.oob_clear = a6xx_oob_clear,
+	.gpu_keepalive = a6xx_gpu_keepalive,
 	.rpmh_gpu_pwrctrl = a6xx_rpmh_gpu_pwrctrl,
 	.hw_isidle = a6xx_hw_isidle, /* Replaced by NULL if GMU is disabled */
 	.wait_for_gmu_idle = a6xx_wait_for_gmu_idle,
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 1cb0259..b831d0d 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2049,6 +2049,7 @@
 static int dispatcher_do_fault(struct adreno_device *adreno_dev)
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
 	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
 	struct adreno_dispatcher_drawqueue *dispatch_q = NULL, *dispatch_q_temp;
 	struct adreno_ringbuffer *rb;
@@ -2148,6 +2149,10 @@
 
 	do_header_and_snapshot(device, hung_rb, cmdobj);
 
+	/* Turn off the KEEPALIVE vote from the ISR for hard fault */
+	if (gpudev->gpu_keepalive && fault & ADRENO_HARD_FAULT)
+		gpudev->gpu_keepalive(adreno_dev, false);
+
 	/* Terminate the stalled transaction and resume the IOMMU */
 	if (fault & ADRENO_IOMMU_PAGE_FAULT)
 		kgsl_mmu_pagefault_resume(&device->mmu);