diff --git a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h index 8b6de266c..61fe4fb58 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h @@ -1787,6 +1787,7 @@ int gk20a_wait_for_idle(struct gk20a *g); int gk20a_init_gpu_characteristics(struct gk20a *g); +bool gk20a_check_poweron(struct gk20a *g); int gk20a_prepare_poweroff(struct gk20a *g); int gk20a_finalize_poweron(struct gk20a *g); diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c index 6fa154215..271c5d92d 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_ctrl.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -596,19 +597,46 @@ static int gk20a_ctrl_get_fbp_l2_masks( static int nvgpu_gpu_ioctl_l2_fb_ops(struct gk20a *g, struct nvgpu_gpu_l2_fb_args *args) { - int err = 0; + int ret; + bool always_poweron; if ((!args->l2_flush && !args->fb_flush) || (!args->l2_flush && args->l2_invalidate)) return -EINVAL; + /* Handle this case for joint rails or DGPU */ + always_poweron = (!nvgpu_is_enabled(g, NVGPU_CAN_RAILGATE) || + !pm_runtime_enabled(dev_from_gk20a(g))); + + /* In case of not always power_on, exit if g->power_on is false */ + if (!always_poweron && !gk20a_check_poweron(g)) { + return 0; + } + + /* There is a small window between a call to gk20a_idle() has occured + * and railgate being actually triggered(setting g->power_on = false), + * when l2_flush can race with railgate. Its better to take a busy_lock + * to prevent the gk20a_idle() from proceeding. There is a very small + * chance that gk20a_idle() might begin before gk20a_busy(). Having + * a locked access to g->power_on further reduces the probability of + * gk20a_idle() being triggered before gk20a_busy() + */ + ret = gk20a_busy(g); + + if (ret != 0) { + nvgpu_err(g, "failed to take power ref"); + return ret; + } + if (args->l2_flush) g->ops.mm.l2_flush(g, args->l2_invalidate ? true : false); if (args->fb_flush) g->ops.mm.fb_flush(g); - return err; + gk20a_idle(g); + + return 0; } static int nvgpu_gpu_ioctl_set_mmu_debug_mode( diff --git a/drivers/gpu/nvgpu/os/linux/module.c b/drivers/gpu/nvgpu/os/linux/module.c index 18345adad..5627abfd1 100644 --- a/drivers/gpu/nvgpu/os/linux/module.c +++ b/drivers/gpu/nvgpu/os/linux/module.c @@ -107,10 +107,7 @@ struct device_node *nvgpu_get_node(struct gk20a *g) void gk20a_busy_noresume(struct gk20a *g) { - int ret = pm_runtime_get_if_in_use(dev_from_gk20a(g)); - - if (ret <= 0) - pm_runtime_get_noresume(dev_from_gk20a(g)); + pm_runtime_get_noresume(dev_from_gk20a(g)); } /* @@ -262,6 +259,17 @@ int nvgpu_finalize_poweron_linux(struct nvgpu_os_linux *l) return 0; } +bool gk20a_check_poweron(struct gk20a *g) +{ + bool ret; + + nvgpu_mutex_acquire(&g->power_lock); + ret = g->power_on; + nvgpu_mutex_release(&g->power_lock); + + return ret; +} + int gk20a_pm_finalize_poweron(struct device *dev) { struct gk20a *g = get_gk20a(dev); diff --git a/drivers/gpu/nvgpu/os/posix/nvgpu.c b/drivers/gpu/nvgpu/os/posix/nvgpu.c index 2f84dc6eb..e485ed736 100644 --- a/drivers/gpu/nvgpu/os/posix/nvgpu.c +++ b/drivers/gpu/nvgpu/os/posix/nvgpu.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -92,6 +93,11 @@ void gk20a_idle_nosuspend(struct gk20a *g) { } +bool gk20a_check_poweron(struct gk20a *g) +{ + return false; +} + int gk20a_busy(struct gk20a *g) { nvgpu_atomic_inc(&g->usage_count);