gpu: nvgpu: take power refcount in ISR

We sometimes see race conditions where power refcount
is zero during ISR or bottom half.
If bottom half calls gk20a_busy(), it will lead to
boot up of GPU, but it is also possible that we are
already trying to poweroff GPU since power refcount
is zero

Fix this by taking a power refcount with gk20a_busy_noresume()
in ISR and then dropping this refcount at the end of
bottom half
Add new API gk20a_idle_nosuspend() to drop a refcount
without initiating suspend

Bug 200198908
Bug 1770522

Change-Id: Iec3d4dc8d468f49b71919d2bbc327da48b97bcab
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1160035
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
Deepak Nibade
2016-06-07 13:20:05 +05:30
committed by Terje Bergstrom
parent 6299b00beb
commit 2219f38727
2 changed files with 38 additions and 4 deletions

View File

@@ -545,15 +545,29 @@ int gk20a_sim_esc_read(struct gk20a *g, char *path, u32 index, u32 count, u32 *d
static irqreturn_t gk20a_intr_isr_stall(int irq, void *dev_id)
{
struct gk20a *g = dev_id;
irqreturn_t ret;
return g->ops.mc.isr_stall(g);
ret = g->ops.mc.isr_stall(g);
if (ret == IRQ_WAKE_THREAD) {
/* balanced in gk20a_intr_thread_stall() */
gk20a_busy_noresume(g->dev);
}
return ret;
}
static irqreturn_t gk20a_intr_isr_nonstall(int irq, void *dev_id)
{
struct gk20a *g = dev_id;
irqreturn_t ret;
return g->ops.mc.isr_nonstall(g);
ret = g->ops.mc.isr_nonstall(g);
if (ret == IRQ_WAKE_THREAD) {
/* balanced in gk20a_intr_thread_nonstall() */
gk20a_busy_noresume(g->dev);
}
return ret;
}
void gk20a_pbus_isr(struct gk20a *g)
@@ -593,13 +607,27 @@ void gk20a_pbus_isr(struct gk20a *g)
static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id)
{
struct gk20a *g = dev_id;
return g->ops.mc.isr_thread_stall(g);
irqreturn_t ret;
ret = g->ops.mc.isr_thread_stall(g);
/* refcount taken in gk20a_intr_isr_stall() */
gk20a_idle_nosuspend(g->dev);
return ret;
}
static irqreturn_t gk20a_intr_thread_nonstall(int irq, void *dev_id)
{
struct gk20a *g = dev_id;
return g->ops.mc.isr_thread_nonstall(g);
irqreturn_t ret;
ret = g->ops.mc.isr_thread_nonstall(g);
/* refcount taken in gk20a_intr_isr_nonstall() */
gk20a_idle_nosuspend(g->dev);
return ret;
}
void gk20a_remove_support(struct device *dev)
@@ -1842,6 +1870,11 @@ fail:
return ret < 0 ? ret : 0;
}
void gk20a_idle_nosuspend(struct device *dev)
{
pm_runtime_put_noidle(dev);
}
void gk20a_idle(struct device *dev)
{
#ifdef CONFIG_PM

View File

@@ -1060,6 +1060,7 @@ void gk20a_remove_sysfs(struct device *dev);
void gk20a_busy_noresume(struct device *dev);
int __must_check gk20a_busy(struct device *dev);
void gk20a_idle_nosuspend(struct device *dev);
void gk20a_idle(struct device *dev);
void gk20a_disable(struct gk20a *g, u32 units);
void gk20a_enable(struct gk20a *g, u32 units);