diff options
author | David Nieto <dmartineznie@nvidia.com> | 2017-03-13 23:23:03 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-03-25 05:06:55 -0400 |
commit | e0f2afe5eb43fb32490ccabd504879c3e3e54623 (patch) | |
tree | d227311914fd44e88e1ab13b652870c0fa772cf1 /drivers/gpu/nvgpu/gk20a/gk20a.c | |
parent | b48186488d0108dee7b3fb755b2d99f4652780df (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.c | 44 |
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 | ||
337 | void gk20a_remove_support(struct device *dev) | 337 | void 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) | |||
1390 | void gk20a_driver_start_unload(struct gk20a *g) | 1378 | void 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 | ||
1396 | int gk20a_wait_for_idle(struct device *dev) | 1398 | int 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 | ||