diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index 2310b81c9..c72b87351 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c @@ -164,6 +164,32 @@ static inline u32 sim_readl(struct gk20a *g, u32 r) return readl(g->sim.regs+r); } +/* + * Locks out the driver from accessing GPU registers. This prevents access to + * thse registers after the GPU has been clock or power gated. This should help + * find annoying bugs where register reads and writes are silently dropped + * after the GPU has been turned off. On older chips these reads and writes can + * also lock the entire CPU up. + */ +int gk20a_lockout_registers(struct gk20a *g) +{ + g->regs = NULL; + g->bar1 = NULL; + + return 0; +} + +/* + * Undoes gk20a_lockout_registers(). + */ +int gk20a_restore_registers(struct gk20a *g) +{ + g->regs = g->regs_saved; + g->bar1 = g->bar1_saved; + + return 0; +} + static void kunmap_and_free_iopage(void **kvaddr, struct page **page) { if (*kvaddr) { @@ -676,6 +702,9 @@ static int gk20a_init_support(struct platform_device *dev) goto fail; } + g->regs_saved = g->regs; + g->bar1_saved = g->bar1; + /* Get interrupt numbers */ g->irq_nonstall = platform_get_irq(dev, 1); if (g->irq_stall < 0 || g->irq_nonstall < 0) { @@ -786,6 +815,9 @@ static int gk20a_pm_prepare_poweroff(struct device *dev) g->power_on = false; + /* Stop CPU from accessing the GPU registers. */ + gk20a_lockout_registers(g); + return ret; } @@ -820,6 +852,10 @@ static int gk20a_pm_finalize_poweron(struct device *dev) trace_gk20a_finalize_poweron(dev_name(dev)); + err = gk20a_restore_registers(g); + if (err) + return err; + nice_value = task_nice(current); set_user_nice(current, -20); diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 991891c5c..3871eb17f 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h @@ -232,9 +232,11 @@ struct gk20a { struct resource *reg_mem; void __iomem *regs; + void __iomem *regs_saved; struct resource *bar1_mem; void __iomem *bar1; + void __iomem *bar1_saved; bool power_on; @@ -487,6 +489,9 @@ static inline void gk20a_mem_wr32(void *ptr, int w, u32 data) } /* register accessors */ +int gk20a_lockout_registers(struct gk20a *g); +int gk20a_restore_registers(struct gk20a *g); + static inline void gk20a_writel(struct gk20a *g, u32 r, u32 v) { gk20a_dbg(gpu_dbg_reg, " r=0x%x v=0x%x", r, v);