Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 273c571f authored by Deepak Kumar's avatar Deepak Kumar Committed by Lynus Vaz
Browse files

msm: kgsl: refcount irq to avoid racing against idle check



Current irq handler clears the pending interrupt bits in interrupt
status register before serving the interrupts. This leads to a race
condition with the idle check which checks the interrupt status
register to determine whether any interrupt is pending or not. As
the interrupt status register is already cleared, idle check goes
ahead and switch off the GPU clocks even when irq is yet to be served
causing NOC errors.

This change refcounts each irq handler call and uses this reference
count to determine if any irq is still pending or not along with
interrupt status register to avoid this race condition.

Change-Id: I030d52c52055f836ea4c7519ce2d8db94a2a09a0
Signed-off-by: default avatarDeepak Kumar <dkumar@codeaurora.org>
Signed-off-by: default avatarLynus Vaz <lvaz@codeaurora.org>
parent 802bc162
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -599,6 +599,10 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
	unsigned int status = 0, tmp, int_bit;
	int i;

	atomic_inc(&adreno_dev->pending_irq_refcnt);
	/* Ensure this increment is done before the IRQ status is updated */
	smp_mb__after_atomic();

	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);

	/*
@@ -637,6 +641,12 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
		adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD,
				int_bit);

	/* Make sure the regwrites are done before the decrement */
	smp_mb__before_atomic();
	atomic_dec(&adreno_dev->pending_irq_refcnt);
	/* Ensure other CPUs see the decrement */
	smp_mb__after_atomic();

	return ret;

}
@@ -2086,7 +2096,18 @@ inline unsigned int adreno_irq_pending(struct adreno_device *adreno_dev)

	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);

	return (status & gpudev->irq->mask) ? 1 : 0;
	/*
	 * IRQ handler clears the RBBM INT0 status register immediately
	 * entering the ISR before actually serving the interrupt because
	 * of this we can't rely only on RBBM INT0 status only.
	 * Use pending_irq_refcnt along with RBBM INT0 to correctly
	 * determine whether any IRQ is pending or not.
	 */
	if ((status & gpudev->irq->mask) ||
		atomic_read(&adreno_dev->pending_irq_refcnt))
		return 1;
	else
		return 0;
}


+2 −0
Original line number Diff line number Diff line
@@ -375,6 +375,7 @@ struct adreno_gpu_core {
 * @ram_cycles_lo: Number of DDR clock cycles for the monitor session
 * @perfctr_pwr_lo: Number of cycles VBIF is stalled by DDR
 * @halt: Atomic variable to check whether the GPU is currently halted
 * @pending_irq_refcnt: Atomic variable to keep track of running IRQ handlers
 * @ctx_d_debugfs: Context debugfs node
 * @pwrctrl_flag: Flag to hold adreno specific power attributes
 * @profile_buffer: Memdesc holding the drawobj profiling buffer
@@ -425,6 +426,7 @@ struct adreno_device {
	unsigned int starved_ram_lo;
	unsigned int perfctr_pwr_lo;
	atomic_t halt;
	atomic_t pending_irq_refcnt;
	struct dentry *ctx_d_debugfs;
	unsigned long pwrctrl_flag;