summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/gk20a.c
diff options
context:
space:
mode:
authorDavid Nieto <dmartineznie@nvidia.com>2017-03-13 23:23:03 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-03-25 05:06:55 -0400
commite0f2afe5eb43fb32490ccabd504879c3e3e54623 (patch)
treed227311914fd44e88e1ab13b652870c0fa772cf1 /drivers/gpu/nvgpu/gk20a/gk20a.c
parentb48186488d0108dee7b3fb755b2d99f4652780df (diff)
gpu: nvgpu: refactor teardown to support unbind
This change refactors the teardown in remove to ensure that it is possible to unload the driver while leaving fds open. This is achieved by making sure that the SW state is kept alive till all fds are closed and by checking that subsequent calls to ioctls after the teardown fail. Normally, this would be achieved ny calls into gk20a_busy(), but in kickoff we dont call into that to reduce latency, so we need to check the driver status directly, and also in some of the functions as we need to make sure the ioctl does not dereference the device or platform struct bug 200277762 JIRA: EVLR-1023 Change-Id: I163e47a08c29d4d5b3ab79f0eb531ef234f40bde Signed-off-by: David Nieto <dmartineznie@nvidia.com> Reviewed-on: http://git-master/r/1320219 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com> Reviewed-by: Shreshtha Sahu <ssahu@nvidia.com> Reviewed-by: Vijayakumar Subbu <vsubbu@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.c44
1 files changed, 26 insertions, 18 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c
index 2046c08e..694f0e93 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.c
@@ -334,26 +334,14 @@ static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id)
334 return g->ops.mc.isr_thread_stall(g); 334 return g->ops.mc.isr_thread_stall(g);
335} 335}
336 336
337void gk20a_remove_support(struct device *dev) 337void gk20a_remove_support(struct gk20a *g)
338{ 338{
339 struct gk20a *g = get_gk20a(dev);
340
341#ifdef CONFIG_TEGRA_COMMON 339#ifdef CONFIG_TEGRA_COMMON
342 tegra_unregister_idle_unidle(); 340 tegra_unregister_idle_unidle();
343#endif 341#endif
344 if (g->dbg_regops_tmp_buf) 342 if (g->dbg_regops_tmp_buf)
345 kfree(g->dbg_regops_tmp_buf); 343 kfree(g->dbg_regops_tmp_buf);
346 344
347 nvgpu_wait_for_deferred_interrupts(g);
348
349 gk20a_channel_cancel_pending_sema_waits(g);
350
351 if (g->nonstall_work_queue) {
352 cancel_work_sync(&g->nonstall_fn_work);
353 destroy_workqueue(g->nonstall_work_queue);
354 g->nonstall_work_queue = NULL;
355 }
356
357 if (g->pmu.remove_support) 345 if (g->pmu.remove_support)
358 g->pmu.remove_support(&g->pmu); 346 g->pmu.remove_support(&g->pmu);
359 347
@@ -1251,6 +1239,11 @@ static int gk20a_probe(struct platform_device *dev)
1251 if (gk20a->irq_stall != gk20a->irq_nonstall) 1239 if (gk20a->irq_stall != gk20a->irq_nonstall)
1252 disable_irq(gk20a->irq_nonstall); 1240 disable_irq(gk20a->irq_nonstall);
1253 1241
1242 /*
1243 * is_fmodel needs to be in gk20a struct for deferred teardown
1244 */
1245 gk20a->is_fmodel = platform->is_fmodel;
1246
1254 err = gk20a_init_support(dev); 1247 err = gk20a_init_support(dev);
1255 if (err) 1248 if (err)
1256 return err; 1249 return err;
@@ -1297,11 +1290,6 @@ static int __exit gk20a_remove(struct platform_device *pdev)
1297 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ)) 1290 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ))
1298 gk20a_scale_exit(dev); 1291 gk20a_scale_exit(dev);
1299 1292
1300 if (g->remove_support)
1301 g->remove_support(dev);
1302
1303 gk20a_ce_destroy(g);
1304
1305#ifdef CONFIG_ARCH_TEGRA_18x_SOC 1293#ifdef CONFIG_ARCH_TEGRA_18x_SOC
1306 nvgpu_clk_arb_cleanup_arbiter(g); 1294 nvgpu_clk_arb_cleanup_arbiter(g);
1307#endif 1295#endif
@@ -1390,7 +1378,21 @@ void gk20a_busy_noresume(struct device *dev)
1390void gk20a_driver_start_unload(struct gk20a *g) 1378void gk20a_driver_start_unload(struct gk20a *g)
1391{ 1379{
1392 gk20a_dbg(gpu_dbg_shutdown, "Driver is now going down!\n"); 1380 gk20a_dbg(gpu_dbg_shutdown, "Driver is now going down!\n");
1381
1382 down_write(&g->busy_lock);
1393 g->driver_is_dying = 1; 1383 g->driver_is_dying = 1;
1384 up_write(&g->busy_lock);
1385
1386 gk20a_wait_for_idle(g->dev);
1387
1388 nvgpu_wait_for_deferred_interrupts(g);
1389 gk20a_channel_cancel_pending_sema_waits(g);
1390
1391 if (g->nonstall_work_queue) {
1392 cancel_work_sync(&g->nonstall_fn_work);
1393 destroy_workqueue(g->nonstall_work_queue);
1394 g->nonstall_work_queue = NULL;
1395 }
1394} 1396}
1395 1397
1396int gk20a_wait_for_idle(struct device *dev) 1398int gk20a_wait_for_idle(struct device *dev)
@@ -1859,6 +1861,12 @@ static void gk20a_free_cb(struct kref *refcount)
1859 struct gk20a, refcount); 1861 struct gk20a, refcount);
1860 1862
1861 gk20a_dbg(gpu_dbg_shutdown, "Freeing GK20A struct!"); 1863 gk20a_dbg(gpu_dbg_shutdown, "Freeing GK20A struct!");
1864
1865 gk20a_ce_destroy(g);
1866
1867 if (g->remove_support)
1868 g->remove_support(g);
1869
1862 kfree(g); 1870 kfree(g);
1863} 1871}
1864 1872