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: Deepak Kumar <dkumar@codeaurora.org>
This commit is contained in:
Deepak Kumar 2017-01-03 21:49:03 +05:30 committed by Gerrit - the friendly Code Review server
parent 314869eb56
commit 3a798eea0b
2 changed files with 23 additions and 3 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -592,6 +592,9 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
unsigned int status = 0, tmp, int_bit; unsigned int status = 0, tmp, int_bit;
int i; int i;
atomic_inc(&adreno_dev->pending_irq_refcnt);
smp_mb__after_atomic();
adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status); adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);
/* /*
@ -630,6 +633,10 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device)
adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD, adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD,
int_bit); int_bit);
smp_mb__before_atomic();
atomic_dec(&adreno_dev->pending_irq_refcnt);
smp_mb__after_atomic();
return ret; return ret;
} }
@ -2030,7 +2037,18 @@ inline unsigned int adreno_irq_pending(struct adreno_device *adreno_dev)
adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status); 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;
} }

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -351,6 +351,7 @@ struct adreno_gpu_core {
* @ram_cycles_lo: Number of DDR clock cycles for the monitor session * @ram_cycles_lo: Number of DDR clock cycles for the monitor session
* @perfctr_pwr_lo: Number of cycles VBIF is stalled by DDR * @perfctr_pwr_lo: Number of cycles VBIF is stalled by DDR
* @halt: Atomic variable to check whether the GPU is currently halted * @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 * @ctx_d_debugfs: Context debugfs node
* @pwrctrl_flag: Flag to hold adreno specific power attributes * @pwrctrl_flag: Flag to hold adreno specific power attributes
* @profile_buffer: Memdesc holding the drawobj profiling buffer * @profile_buffer: Memdesc holding the drawobj profiling buffer
@ -408,6 +409,7 @@ struct adreno_device {
unsigned int starved_ram_lo; unsigned int starved_ram_lo;
unsigned int perfctr_pwr_lo; unsigned int perfctr_pwr_lo;
atomic_t halt; atomic_t halt;
atomic_t pending_irq_refcnt;
struct dentry *ctx_d_debugfs; struct dentry *ctx_d_debugfs;
unsigned long pwrctrl_flag; unsigned long pwrctrl_flag;