From 2219f38727ffa17291e15c1898bd3e65f43d09fd Mon Sep 17 00:00:00 2001 From: Deepak Nibade Date: Tue, 7 Jun 2016 13:20:05 +0530 Subject: 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 Reviewed-on: http://git-master/r/1160035 Reviewed-by: Terje Bergstrom Tested-by: Terje Bergstrom --- drivers/gpu/nvgpu/gk20a/gk20a.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/nvgpu/gk20a/gk20a.c') diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index d21d0527..714b494f 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c @@ -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; + + ret = g->ops.mc.isr_nonstall(g); + if (ret == IRQ_WAKE_THREAD) { + /* balanced in gk20a_intr_thread_nonstall() */ + gk20a_busy_noresume(g->dev); + } - return g->ops.mc.isr_nonstall(g); + 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 -- cgit v1.2.2