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 | |
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>
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/ce2_gk20a.c | 6 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/ce2_gk20a.h | 3 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 22 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | 3 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c | 24 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 44 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 7 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/mm_gk20a.c | 21 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/pci.c | 11 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/vgpu/vgpu.c | 11 |
10 files changed, 91 insertions, 61 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/ce2_gk20a.c b/drivers/gpu/nvgpu/gk20a/ce2_gk20a.c index 921ee6f8..5dfd2309 100644 --- a/drivers/gpu/nvgpu/gk20a/ce2_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/ce2_gk20a.c | |||
@@ -690,6 +690,12 @@ void gk20a_ce_delete_context(struct device *dev, | |||
690 | u32 ce_ctx_id) | 690 | u32 ce_ctx_id) |
691 | { | 691 | { |
692 | struct gk20a *g = gk20a_from_dev(dev); | 692 | struct gk20a *g = gk20a_from_dev(dev); |
693 | gk20a_ce_delete_context_priv(g, ce_ctx_id); | ||
694 | } | ||
695 | |||
696 | void gk20a_ce_delete_context_priv(struct gk20a *g, | ||
697 | u32 ce_ctx_id) | ||
698 | { | ||
693 | struct gk20a_ce_app *ce_app = &g->ce_app; | 699 | struct gk20a_ce_app *ce_app = &g->ce_app; |
694 | struct gk20a_gpu_ctx *ce_ctx, *ce_ctx_save; | 700 | struct gk20a_gpu_ctx *ce_ctx, *ce_ctx_save; |
695 | 701 | ||
diff --git a/drivers/gpu/nvgpu/gk20a/ce2_gk20a.h b/drivers/gpu/nvgpu/gk20a/ce2_gk20a.h index 5cdd233e..7ecf130f 100644 --- a/drivers/gpu/nvgpu/gk20a/ce2_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/ce2_gk20a.h | |||
@@ -144,9 +144,12 @@ int gk20a_ce_execute_ops(struct device *dev, | |||
144 | struct gk20a_fence *gk20a_fence_in, | 144 | struct gk20a_fence *gk20a_fence_in, |
145 | u32 submit_flags, | 145 | u32 submit_flags, |
146 | struct gk20a_fence **gk20a_fence_out); | 146 | struct gk20a_fence **gk20a_fence_out); |
147 | void gk20a_ce_delete_context_priv(struct gk20a *g, | ||
148 | u32 ce_ctx_id); | ||
147 | void gk20a_ce_delete_context(struct device *dev, | 149 | void gk20a_ce_delete_context(struct device *dev, |
148 | u32 ce_ctx_id); | 150 | u32 ce_ctx_id); |
149 | 151 | ||
152 | |||
150 | #ifdef CONFIG_DEBUG_FS | 153 | #ifdef CONFIG_DEBUG_FS |
151 | /* CE app debugfs api */ | 154 | /* CE app debugfs api */ |
152 | void gk20a_ce_debugfs_init(struct device *dev); | 155 | void gk20a_ce_debugfs_init(struct device *dev); |
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 0249a1c6..d0d38f83 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |||
@@ -122,7 +122,8 @@ static struct channel_gk20a *allocate_channel(struct fifo_gk20a *f) | |||
122 | static void free_channel(struct fifo_gk20a *f, | 122 | static void free_channel(struct fifo_gk20a *f, |
123 | struct channel_gk20a *ch) | 123 | struct channel_gk20a *ch) |
124 | { | 124 | { |
125 | struct gk20a_platform *platform = gk20a_get_platform(f->g->dev); | 125 | struct gk20a_platform *platform; |
126 | struct gk20a *g = f->g; | ||
126 | 127 | ||
127 | trace_gk20a_release_used_channel(ch->hw_chid); | 128 | trace_gk20a_release_used_channel(ch->hw_chid); |
128 | /* refcount is zero here and channel is in a freed/dead state */ | 129 | /* refcount is zero here and channel is in a freed/dead state */ |
@@ -132,10 +133,18 @@ static void free_channel(struct fifo_gk20a *f, | |||
132 | f->used_channels--; | 133 | f->used_channels--; |
133 | nvgpu_mutex_release(&f->free_chs_mutex); | 134 | nvgpu_mutex_release(&f->free_chs_mutex); |
134 | 135 | ||
135 | if (platform->aggressive_sync_destroy_thresh && | 136 | /* |
137 | * On teardown it is not possible to dereference platform, but ignoring | ||
138 | * this is fine then because no new channels would be created. | ||
139 | */ | ||
140 | if (!g->driver_is_dying) { | ||
141 | platform = gk20a_get_platform(g->dev); | ||
142 | |||
143 | if (platform->aggressive_sync_destroy_thresh && | ||
136 | (f->used_channels < | 144 | (f->used_channels < |
137 | platform->aggressive_sync_destroy_thresh)) | 145 | platform->aggressive_sync_destroy_thresh)) |
138 | platform->aggressive_sync_destroy = false; | 146 | platform->aggressive_sync_destroy = false; |
147 | } | ||
139 | } | 148 | } |
140 | 149 | ||
141 | int channel_gk20a_commit_va(struct channel_gk20a *c) | 150 | int channel_gk20a_commit_va(struct channel_gk20a *c) |
@@ -3016,7 +3025,12 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, | |||
3016 | bool need_deferred_cleanup = false; | 3025 | bool need_deferred_cleanup = false; |
3017 | struct nvgpu_gpfifo __user *user_gpfifo = args ? | 3026 | struct nvgpu_gpfifo __user *user_gpfifo = args ? |
3018 | (struct nvgpu_gpfifo __user *)(uintptr_t)args->gpfifo : NULL; | 3027 | (struct nvgpu_gpfifo __user *)(uintptr_t)args->gpfifo : NULL; |
3019 | struct gk20a_platform *platform = gk20a_get_platform(d); | 3028 | struct gk20a_platform *platform; |
3029 | |||
3030 | if (g->driver_is_dying) | ||
3031 | return -ENODEV; | ||
3032 | |||
3033 | platform = gk20a_get_platform(d); | ||
3020 | 3034 | ||
3021 | if (c->has_timedout) | 3035 | if (c->has_timedout) |
3022 | return -ETIMEDOUT; | 3036 | return -ETIMEDOUT; |
diff --git a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c index c87226c8..1ae42337 100644 --- a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | |||
@@ -1344,8 +1344,7 @@ static int nvgpu_gpu_set_therm_alert_limit(struct gk20a *g, | |||
1344 | long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 1344 | long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1345 | { | 1345 | { |
1346 | struct gk20a_ctrl_priv *priv = filp->private_data; | 1346 | struct gk20a_ctrl_priv *priv = filp->private_data; |
1347 | struct device *dev = priv->dev; | 1347 | struct gk20a *g = priv->g; |
1348 | struct gk20a *g = get_gk20a(dev); | ||
1349 | struct nvgpu_gpu_zcull_get_ctx_size_args *get_ctx_size_args; | 1348 | struct nvgpu_gpu_zcull_get_ctx_size_args *get_ctx_size_args; |
1350 | struct nvgpu_gpu_zcull_get_info_args *get_info_args; | 1349 | struct nvgpu_gpu_zcull_get_info_args *get_info_args; |
1351 | struct nvgpu_gpu_zbc_set_table_args *set_table_args; | 1350 | struct nvgpu_gpu_zbc_set_table_args *set_table_args; |
diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c index db534318..165bcf46 100644 --- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c | |||
@@ -665,7 +665,7 @@ static int nvgpu_dbg_gpu_ioctl_timeout(struct dbg_session_gk20a *dbg_s, | |||
665 | struct nvgpu_dbg_gpu_timeout_args *args) | 665 | struct nvgpu_dbg_gpu_timeout_args *args) |
666 | { | 666 | { |
667 | int err; | 667 | int err; |
668 | struct gk20a *g = get_gk20a(dbg_s->dev); | 668 | struct gk20a *g = dbg_s->g; |
669 | 669 | ||
670 | gk20a_dbg_fn("powergate mode = %d", args->enable); | 670 | gk20a_dbg_fn("powergate mode = %d", args->enable); |
671 | 671 | ||
@@ -680,7 +680,7 @@ static void nvgpu_dbg_gpu_ioctl_get_timeout(struct dbg_session_gk20a *dbg_s, | |||
680 | struct nvgpu_dbg_gpu_timeout_args *args) | 680 | struct nvgpu_dbg_gpu_timeout_args *args) |
681 | { | 681 | { |
682 | int status; | 682 | int status; |
683 | struct gk20a *g = get_gk20a(dbg_s->dev); | 683 | struct gk20a *g = dbg_s->g; |
684 | 684 | ||
685 | nvgpu_mutex_acquire(&g->dbg_sessions_lock); | 685 | nvgpu_mutex_acquire(&g->dbg_sessions_lock); |
686 | status = g->timeouts_enabled; | 686 | status = g->timeouts_enabled; |
@@ -711,7 +711,7 @@ static int nvgpu_dbg_gpu_ioctl_read_single_sm_error_state( | |||
711 | struct dbg_session_gk20a *dbg_s, | 711 | struct dbg_session_gk20a *dbg_s, |
712 | struct nvgpu_dbg_gpu_read_single_sm_error_state_args *args) | 712 | struct nvgpu_dbg_gpu_read_single_sm_error_state_args *args) |
713 | { | 713 | { |
714 | struct gk20a *g = get_gk20a(dbg_s->dev); | 714 | struct gk20a *g = dbg_s->g; |
715 | struct gr_gk20a *gr = &g->gr; | 715 | struct gr_gk20a *gr = &g->gr; |
716 | struct nvgpu_dbg_gpu_sm_error_state_record *sm_error_state; | 716 | struct nvgpu_dbg_gpu_sm_error_state_record *sm_error_state; |
717 | u32 sm_id; | 717 | u32 sm_id; |
@@ -750,7 +750,7 @@ static int nvgpu_dbg_gpu_ioctl_clear_single_sm_error_state( | |||
750 | struct dbg_session_gk20a *dbg_s, | 750 | struct dbg_session_gk20a *dbg_s, |
751 | struct nvgpu_dbg_gpu_clear_single_sm_error_state_args *args) | 751 | struct nvgpu_dbg_gpu_clear_single_sm_error_state_args *args) |
752 | { | 752 | { |
753 | struct gk20a *g = get_gk20a(dbg_s->dev); | 753 | struct gk20a *g = dbg_s->g; |
754 | struct gr_gk20a *gr = &g->gr; | 754 | struct gr_gk20a *gr = &g->gr; |
755 | u32 sm_id; | 755 | u32 sm_id; |
756 | struct channel_gk20a *ch; | 756 | struct channel_gk20a *ch; |
@@ -781,7 +781,7 @@ static int nvgpu_dbg_gpu_ioctl_write_single_sm_error_state( | |||
781 | struct dbg_session_gk20a *dbg_s, | 781 | struct dbg_session_gk20a *dbg_s, |
782 | struct nvgpu_dbg_gpu_write_single_sm_error_state_args *args) | 782 | struct nvgpu_dbg_gpu_write_single_sm_error_state_args *args) |
783 | { | 783 | { |
784 | struct gk20a *g = get_gk20a(dbg_s->dev); | 784 | struct gk20a *g = dbg_s->g; |
785 | struct gr_gk20a *gr = &g->gr; | 785 | struct gr_gk20a *gr = &g->gr; |
786 | u32 sm_id; | 786 | u32 sm_id; |
787 | struct channel_gk20a *ch; | 787 | struct channel_gk20a *ch; |
@@ -952,7 +952,7 @@ long gk20a_dbg_gpu_dev_ioctl(struct file *filp, unsigned int cmd, | |||
952 | unsigned long arg) | 952 | unsigned long arg) |
953 | { | 953 | { |
954 | struct dbg_session_gk20a *dbg_s = filp->private_data; | 954 | struct dbg_session_gk20a *dbg_s = filp->private_data; |
955 | struct gk20a *g = get_gk20a(dbg_s->dev); | 955 | struct gk20a *g = dbg_s->g; |
956 | u8 buf[NVGPU_DBG_GPU_IOCTL_MAX_ARG_SIZE]; | 956 | u8 buf[NVGPU_DBG_GPU_IOCTL_MAX_ARG_SIZE]; |
957 | int err = 0; | 957 | int err = 0; |
958 | 958 | ||
@@ -1141,7 +1141,7 @@ static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s, | |||
1141 | bool is_pg_disabled = false; | 1141 | bool is_pg_disabled = false; |
1142 | 1142 | ||
1143 | struct device *dev = dbg_s->dev; | 1143 | struct device *dev = dbg_s->dev; |
1144 | struct gk20a *g = get_gk20a(dbg_s->dev); | 1144 | struct gk20a *g = dbg_s->g; |
1145 | struct channel_gk20a *ch; | 1145 | struct channel_gk20a *ch; |
1146 | 1146 | ||
1147 | gk20a_dbg_fn("%d ops, max fragment %d", args->num_ops, g->dbg_regops_tmp_buf_ops); | 1147 | gk20a_dbg_fn("%d ops, max fragment %d", args->num_ops, g->dbg_regops_tmp_buf_ops); |
@@ -1257,7 +1257,7 @@ static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s, | |||
1257 | static int dbg_set_powergate(struct dbg_session_gk20a *dbg_s, u32 powermode) | 1257 | static int dbg_set_powergate(struct dbg_session_gk20a *dbg_s, u32 powermode) |
1258 | { | 1258 | { |
1259 | int err = 0; | 1259 | int err = 0; |
1260 | struct gk20a *g = get_gk20a(dbg_s->dev); | 1260 | struct gk20a *g = dbg_s->g; |
1261 | 1261 | ||
1262 | /* This function must be called with g->dbg_sessions_lock held */ | 1262 | /* This function must be called with g->dbg_sessions_lock held */ |
1263 | 1263 | ||
@@ -1360,7 +1360,7 @@ static int nvgpu_ioctl_powergate_gk20a(struct dbg_session_gk20a *dbg_s, | |||
1360 | struct nvgpu_dbg_gpu_powergate_args *args) | 1360 | struct nvgpu_dbg_gpu_powergate_args *args) |
1361 | { | 1361 | { |
1362 | int err; | 1362 | int err; |
1363 | struct gk20a *g = get_gk20a(dbg_s->dev); | 1363 | struct gk20a *g = dbg_s->g; |
1364 | gk20a_dbg_fn("%s powergate mode = %d", | 1364 | gk20a_dbg_fn("%s powergate mode = %d", |
1365 | dev_name(dbg_s->dev), args->mode); | 1365 | dev_name(dbg_s->dev), args->mode); |
1366 | 1366 | ||
@@ -1374,7 +1374,7 @@ static int nvgpu_dbg_gpu_ioctl_smpc_ctxsw_mode(struct dbg_session_gk20a *dbg_s, | |||
1374 | struct nvgpu_dbg_gpu_smpc_ctxsw_mode_args *args) | 1374 | struct nvgpu_dbg_gpu_smpc_ctxsw_mode_args *args) |
1375 | { | 1375 | { |
1376 | int err; | 1376 | int err; |
1377 | struct gk20a *g = get_gk20a(dbg_s->dev); | 1377 | struct gk20a *g = dbg_s->g; |
1378 | struct channel_gk20a *ch_gk20a; | 1378 | struct channel_gk20a *ch_gk20a; |
1379 | 1379 | ||
1380 | gk20a_dbg_fn("%s smpc ctxsw mode = %d", | 1380 | gk20a_dbg_fn("%s smpc ctxsw mode = %d", |
@@ -1416,7 +1416,7 @@ static int nvgpu_dbg_gpu_ioctl_hwpm_ctxsw_mode(struct dbg_session_gk20a *dbg_s, | |||
1416 | struct nvgpu_dbg_gpu_hwpm_ctxsw_mode_args *args) | 1416 | struct nvgpu_dbg_gpu_hwpm_ctxsw_mode_args *args) |
1417 | { | 1417 | { |
1418 | int err; | 1418 | int err; |
1419 | struct gk20a *g = get_gk20a(dbg_s->dev); | 1419 | struct gk20a *g = dbg_s->g; |
1420 | struct channel_gk20a *ch_gk20a; | 1420 | struct channel_gk20a *ch_gk20a; |
1421 | 1421 | ||
1422 | gk20a_dbg_fn("%s pm ctxsw mode = %d", | 1422 | gk20a_dbg_fn("%s pm ctxsw mode = %d", |
@@ -1468,7 +1468,7 @@ static int nvgpu_dbg_gpu_ioctl_suspend_resume_sm( | |||
1468 | struct dbg_session_gk20a *dbg_s, | 1468 | struct dbg_session_gk20a *dbg_s, |
1469 | struct nvgpu_dbg_gpu_suspend_resume_all_sms_args *args) | 1469 | struct nvgpu_dbg_gpu_suspend_resume_all_sms_args *args) |
1470 | { | 1470 | { |
1471 | struct gk20a *g = get_gk20a(dbg_s->dev); | 1471 | struct gk20a *g = dbg_s->g; |
1472 | struct channel_gk20a *ch; | 1472 | struct channel_gk20a *ch; |
1473 | int err = 0, action = args->mode; | 1473 | int err = 0, action = args->mode; |
1474 | 1474 | ||
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 | ||
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 30f1b371..f4ca5649 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h | |||
@@ -877,6 +877,9 @@ struct gk20a { | |||
877 | atomic_t nonstall_ops; | 877 | atomic_t nonstall_ops; |
878 | struct work_struct nonstall_fn_work; | 878 | struct work_struct nonstall_fn_work; |
879 | struct workqueue_struct *nonstall_work_queue; | 879 | struct workqueue_struct *nonstall_work_queue; |
880 | |||
881 | bool is_fmodel; | ||
882 | |||
880 | struct kref refcount; | 883 | struct kref refcount; |
881 | 884 | ||
882 | struct resource *reg_mem; | 885 | struct resource *reg_mem; |
@@ -987,7 +990,7 @@ struct gk20a { | |||
987 | bool global_profiler_reservation_held; | 990 | bool global_profiler_reservation_held; |
988 | int profiler_reservation_count; | 991 | int profiler_reservation_count; |
989 | 992 | ||
990 | void (*remove_support)(struct device *); | 993 | void (*remove_support)(struct gk20a *); |
991 | 994 | ||
992 | u64 pg_ingating_time_us; | 995 | u64 pg_ingating_time_us; |
993 | u64 pg_ungating_time_us; | 996 | u64 pg_ungating_time_us; |
@@ -1455,7 +1458,7 @@ extern struct class nvgpu_class; | |||
1455 | 1458 | ||
1456 | int gk20a_pm_init(struct device *dev); | 1459 | int gk20a_pm_init(struct device *dev); |
1457 | int gk20a_pm_finalize_poweron(struct device *dev); | 1460 | int gk20a_pm_finalize_poweron(struct device *dev); |
1458 | void gk20a_remove_support(struct device *dev); | 1461 | void gk20a_remove_support(struct gk20a *g); |
1459 | 1462 | ||
1460 | static inline struct tsg_gk20a *tsg_gk20a_from_ch(struct channel_gk20a *ch) | 1463 | static inline struct tsg_gk20a *tsg_gk20a_from_ch(struct channel_gk20a *ch) |
1461 | { | 1464 | { |
diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c index 7b08387e..9e6dc74c 100644 --- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c | |||
@@ -809,7 +809,7 @@ static void gk20a_remove_mm_ce_support(struct mm_gk20a *mm) | |||
809 | struct gk20a *g = gk20a_from_mm(mm); | 809 | struct gk20a *g = gk20a_from_mm(mm); |
810 | 810 | ||
811 | if (mm->vidmem.ce_ctx_id != (u32)~0) | 811 | if (mm->vidmem.ce_ctx_id != (u32)~0) |
812 | gk20a_ce_delete_context(g->dev, mm->vidmem.ce_ctx_id); | 812 | gk20a_ce_delete_context_priv(g, mm->vidmem.ce_ctx_id); |
813 | 813 | ||
814 | mm->vidmem.ce_ctx_id = (u32)~0; | 814 | mm->vidmem.ce_ctx_id = (u32)~0; |
815 | 815 | ||
@@ -1220,11 +1220,10 @@ static int alloc_gmmu_pages(struct vm_gk20a *vm, u32 order, | |||
1220 | u32 num_pages = 1 << order; | 1220 | u32 num_pages = 1 << order; |
1221 | u32 len = num_pages * PAGE_SIZE; | 1221 | u32 len = num_pages * PAGE_SIZE; |
1222 | int err; | 1222 | int err; |
1223 | struct gk20a_platform *platform = dev_get_drvdata(g->dev); | ||
1224 | 1223 | ||
1225 | gk20a_dbg_fn(""); | 1224 | gk20a_dbg_fn(""); |
1226 | 1225 | ||
1227 | if (platform->is_fmodel) | 1226 | if (g->is_fmodel) |
1228 | return alloc_gmmu_phys_pages(vm, order, entry); | 1227 | return alloc_gmmu_phys_pages(vm, order, entry); |
1229 | 1228 | ||
1230 | /* | 1229 | /* |
@@ -1250,7 +1249,6 @@ void free_gmmu_pages(struct vm_gk20a *vm, | |||
1250 | struct gk20a_mm_entry *entry) | 1249 | struct gk20a_mm_entry *entry) |
1251 | { | 1250 | { |
1252 | struct gk20a *g = gk20a_from_vm(vm); | 1251 | struct gk20a *g = gk20a_from_vm(vm); |
1253 | struct gk20a_platform *platform = dev_get_drvdata(g->dev); | ||
1254 | 1252 | ||
1255 | gk20a_dbg_fn(""); | 1253 | gk20a_dbg_fn(""); |
1256 | 1254 | ||
@@ -1260,7 +1258,7 @@ void free_gmmu_pages(struct vm_gk20a *vm, | |||
1260 | if (entry->woffset) /* fake shadow mem */ | 1258 | if (entry->woffset) /* fake shadow mem */ |
1261 | return; | 1259 | return; |
1262 | 1260 | ||
1263 | if (platform->is_fmodel) { | 1261 | if (g->is_fmodel) { |
1264 | free_gmmu_phys_pages(vm, entry); | 1262 | free_gmmu_phys_pages(vm, entry); |
1265 | return; | 1263 | return; |
1266 | } | 1264 | } |
@@ -1270,11 +1268,9 @@ void free_gmmu_pages(struct vm_gk20a *vm, | |||
1270 | 1268 | ||
1271 | int map_gmmu_pages(struct gk20a *g, struct gk20a_mm_entry *entry) | 1269 | int map_gmmu_pages(struct gk20a *g, struct gk20a_mm_entry *entry) |
1272 | { | 1270 | { |
1273 | struct gk20a_platform *platform = dev_get_drvdata(g->dev); | ||
1274 | |||
1275 | gk20a_dbg_fn(""); | 1271 | gk20a_dbg_fn(""); |
1276 | 1272 | ||
1277 | if (platform->is_fmodel) | 1273 | if (g->is_fmodel) |
1278 | return map_gmmu_phys_pages(entry); | 1274 | return map_gmmu_phys_pages(entry); |
1279 | 1275 | ||
1280 | if (IS_ENABLED(CONFIG_ARM64)) { | 1276 | if (IS_ENABLED(CONFIG_ARM64)) { |
@@ -1296,11 +1292,9 @@ int map_gmmu_pages(struct gk20a *g, struct gk20a_mm_entry *entry) | |||
1296 | 1292 | ||
1297 | void unmap_gmmu_pages(struct gk20a *g, struct gk20a_mm_entry *entry) | 1293 | void unmap_gmmu_pages(struct gk20a *g, struct gk20a_mm_entry *entry) |
1298 | { | 1294 | { |
1299 | struct gk20a_platform *platform = dev_get_drvdata(g->dev); | ||
1300 | |||
1301 | gk20a_dbg_fn(""); | 1295 | gk20a_dbg_fn(""); |
1302 | 1296 | ||
1303 | if (platform->is_fmodel) { | 1297 | if (g->is_fmodel) { |
1304 | unmap_gmmu_phys_pages(entry); | 1298 | unmap_gmmu_phys_pages(entry); |
1305 | return; | 1299 | return; |
1306 | } | 1300 | } |
@@ -4070,6 +4064,7 @@ static void gk20a_vm_remove_support_nofree(struct vm_gk20a *vm) | |||
4070 | struct mapped_buffer_node *mapped_buffer; | 4064 | struct mapped_buffer_node *mapped_buffer; |
4071 | struct vm_reserved_va_node *va_node, *va_node_tmp; | 4065 | struct vm_reserved_va_node *va_node, *va_node_tmp; |
4072 | struct rb_node *node; | 4066 | struct rb_node *node; |
4067 | struct gk20a *g = vm->mm->g; | ||
4073 | 4068 | ||
4074 | gk20a_dbg_fn(""); | 4069 | gk20a_dbg_fn(""); |
4075 | 4070 | ||
@@ -4078,7 +4073,7 @@ static void gk20a_vm_remove_support_nofree(struct vm_gk20a *vm) | |||
4078 | * pool involves unmapping a GMMU mapping which means aquiring the | 4073 | * pool involves unmapping a GMMU mapping which means aquiring the |
4079 | * update_gmmu_lock. | 4074 | * update_gmmu_lock. |
4080 | */ | 4075 | */ |
4081 | if (!gk20a_platform_has_syncpoints(gk20a_from_vm(vm)->dev)) { | 4076 | if (!(g->gpu_characteristics.flags & NVGPU_GPU_FLAGS_HAS_SYNCPOINTS)) { |
4082 | if (vm->sema_pool) { | 4077 | if (vm->sema_pool) { |
4083 | nvgpu_semaphore_pool_unmap(vm->sema_pool, vm); | 4078 | nvgpu_semaphore_pool_unmap(vm->sema_pool, vm); |
4084 | nvgpu_semaphore_pool_put(vm->sema_pool); | 4079 | nvgpu_semaphore_pool_put(vm->sema_pool); |
@@ -4172,7 +4167,7 @@ static int gk20a_init_sema_pool(struct vm_gk20a *vm) | |||
4172 | /* | 4167 | /* |
4173 | * Don't waste the memory on semaphores if we don't need them. | 4168 | * Don't waste the memory on semaphores if we don't need them. |
4174 | */ | 4169 | */ |
4175 | if (gk20a_platform_has_syncpoints(g->dev)) | 4170 | if (g->gpu_characteristics.flags & NVGPU_GPU_FLAGS_HAS_SYNCPOINTS) |
4176 | return 0; | 4171 | return 0; |
4177 | 4172 | ||
4178 | if (vm->sema_pool) | 4173 | if (vm->sema_pool) |
diff --git a/drivers/gpu/nvgpu/pci.c b/drivers/gpu/nvgpu/pci.c index 114e9af7..a7899f7e 100644 --- a/drivers/gpu/nvgpu/pci.c +++ b/drivers/gpu/nvgpu/pci.c | |||
@@ -393,6 +393,11 @@ static int nvgpu_pci_probe(struct pci_dev *pdev, | |||
393 | } | 393 | } |
394 | disable_irq(g->irq_stall); | 394 | disable_irq(g->irq_stall); |
395 | 395 | ||
396 | /* | ||
397 | * is_fmodel needs to be in gk20a struct for deferred teardown | ||
398 | */ | ||
399 | g->is_fmodel = platform->is_fmodel; | ||
400 | |||
396 | err = nvgpu_pci_init_support(pdev); | 401 | err = nvgpu_pci_init_support(pdev); |
397 | if (err) | 402 | if (err) |
398 | return err; | 403 | return err; |
@@ -426,7 +431,6 @@ static void nvgpu_pci_remove(struct pci_dev *pdev) | |||
426 | struct gk20a *g = get_gk20a(&pdev->dev); | 431 | struct gk20a *g = get_gk20a(&pdev->dev); |
427 | 432 | ||
428 | gk20a_dbg(gpu_dbg_shutdown, "Removing nvgpu driver!\n"); | 433 | gk20a_dbg(gpu_dbg_shutdown, "Removing nvgpu driver!\n"); |
429 | gk20a_driver_start_unload(g); | ||
430 | 434 | ||
431 | if (g->irqs_enabled) | 435 | if (g->irqs_enabled) |
432 | disable_irq(g->irq_stall); | 436 | disable_irq(g->irq_stall); |
@@ -445,7 +449,7 @@ static void nvgpu_pci_remove(struct pci_dev *pdev) | |||
445 | * Wait for the driver to finish up all the IOCTLs it's working on | 449 | * Wait for the driver to finish up all the IOCTLs it's working on |
446 | * before cleaning up the driver's data structures. | 450 | * before cleaning up the driver's data structures. |
447 | */ | 451 | */ |
448 | gk20a_wait_for_idle(&pdev->dev); | 452 | gk20a_driver_start_unload(g); |
449 | gk20a_dbg(gpu_dbg_shutdown, "Driver idle.\n"); | 453 | gk20a_dbg(gpu_dbg_shutdown, "Driver idle.\n"); |
450 | 454 | ||
451 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC | 455 | #ifdef CONFIG_ARCH_TEGRA_18x_SOC |
@@ -455,9 +459,6 @@ static void nvgpu_pci_remove(struct pci_dev *pdev) | |||
455 | gk20a_user_deinit(g->dev, &nvgpu_pci_class); | 459 | gk20a_user_deinit(g->dev, &nvgpu_pci_class); |
456 | gk20a_dbg(gpu_dbg_shutdown, "User de-init done.\b"); | 460 | gk20a_dbg(gpu_dbg_shutdown, "User de-init done.\b"); |
457 | 461 | ||
458 | if (g->remove_support) | ||
459 | g->remove_support(g->dev); | ||
460 | |||
461 | debugfs_remove_recursive(platform->debugfs); | 462 | debugfs_remove_recursive(platform->debugfs); |
462 | debugfs_remove_recursive(platform->debugfs_alias); | 463 | debugfs_remove_recursive(platform->debugfs_alias); |
463 | 464 | ||
diff --git a/drivers/gpu/nvgpu/vgpu/vgpu.c b/drivers/gpu/nvgpu/vgpu/vgpu.c index 72606952..df793be7 100644 --- a/drivers/gpu/nvgpu/vgpu/vgpu.c +++ b/drivers/gpu/nvgpu/vgpu/vgpu.c | |||
@@ -191,10 +191,9 @@ static int vgpu_intr_thread(void *dev_id) | |||
191 | return 0; | 191 | return 0; |
192 | } | 192 | } |
193 | 193 | ||
194 | static void vgpu_remove_support(struct device *dev) | 194 | static void vgpu_remove_support(struct gk20a *g) |
195 | { | 195 | { |
196 | struct gk20a *g = get_gk20a(dev); | 196 | struct vgpu_priv_data *priv = vgpu_get_priv_data_from_dev(g->dev); |
197 | struct vgpu_priv_data *priv = vgpu_get_priv_data_from_dev(dev); | ||
198 | struct tegra_vgpu_intr_msg msg; | 197 | struct tegra_vgpu_intr_msg msg; |
199 | int err; | 198 | int err; |
200 | 199 | ||
@@ -265,7 +264,7 @@ static int vgpu_init_support(struct platform_device *pdev) | |||
265 | return 0; | 264 | return 0; |
266 | 265 | ||
267 | fail: | 266 | fail: |
268 | vgpu_remove_support(&pdev->dev); | 267 | vgpu_remove_support(g); |
269 | return err; | 268 | return err; |
270 | } | 269 | } |
271 | 270 | ||
@@ -571,6 +570,8 @@ int vgpu_probe(struct platform_device *pdev) | |||
571 | platform->vgpu_priv = priv; | 570 | platform->vgpu_priv = priv; |
572 | gk20a->dev = dev; | 571 | gk20a->dev = dev; |
573 | 572 | ||
573 | gk20a->is_fmodel = platform->is_fmodel; | ||
574 | |||
574 | nvgpu_kmem_init(gk20a); | 575 | nvgpu_kmem_init(gk20a); |
575 | 576 | ||
576 | err = gk20a_user_init(dev, INTERFACE_NAME, &nvgpu_class); | 577 | err = gk20a_user_init(dev, INTERFACE_NAME, &nvgpu_class); |
@@ -653,7 +654,7 @@ int vgpu_remove(struct platform_device *pdev) | |||
653 | 654 | ||
654 | vgpu_pm_qos_remove(dev); | 655 | vgpu_pm_qos_remove(dev); |
655 | if (g->remove_support) | 656 | if (g->remove_support) |
656 | g->remove_support(dev); | 657 | g->remove_support(g); |
657 | 658 | ||
658 | vgpu_comm_deinit(); | 659 | vgpu_comm_deinit(); |
659 | gk20a_sched_ctrl_cleanup(g); | 660 | gk20a_sched_ctrl_cleanup(g); |