summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Nieto <dmartineznie@nvidia.com>2017-02-13 14:22:59 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2017-03-20 19:39:55 -0400
commit74fe1caa2b56aab24c17ad4dd2524128fc237894 (patch)
tree0793bb92b67d64690658f3f7cd1a8e1ea93206ba
parent469308becaff326da02fcf791e803e812e1cf9f8 (diff)
gpu: nvgpu: Add refcounting to driver fds
The main driver structure is not refcounted properly, so when the driver unload, file desciptors associated to the driver are kept open with dangling references to the main object. This change adds referencing to the gk20a structure. bug 200277762 JIRA: EVLR-1023 Change-Id: Id892e9e1677a344789e99bf649088c076f0bf8de Signed-off-by: David Nieto <dmartineznie@nvidia.com> Reviewed-on: http://git-master/r/1317420 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r--drivers/gpu/nvgpu/common/nvgpu_common.c2
-rw-r--r--drivers/gpu/nvgpu/gk20a/as_gk20a.c11
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c35
-rw-r--r--drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c18
-rw-r--r--drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c18
-rw-r--r--drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c10
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.c64
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h4
-rw-r--r--drivers/gpu/nvgpu/gk20a/sched_gk20a.c23
-rw-r--r--drivers/gpu/nvgpu/gk20a/tsg_gk20a.c38
-rw-r--r--drivers/gpu/nvgpu/pci.c3
-rw-r--r--drivers/gpu/nvgpu/vgpu/vgpu.c5
12 files changed, 190 insertions, 41 deletions
diff --git a/drivers/gpu/nvgpu/common/nvgpu_common.c b/drivers/gpu/nvgpu/common/nvgpu_common.c
index 16640aa6..f1109684 100644
--- a/drivers/gpu/nvgpu/common/nvgpu_common.c
+++ b/drivers/gpu/nvgpu/common/nvgpu_common.c
@@ -172,6 +172,8 @@ int nvgpu_probe(struct gk20a *g,
172 172
173 g->remove_support = gk20a_remove_support; 173 g->remove_support = gk20a_remove_support;
174 174
175 kref_init(&g->refcount);
176
175 return 0; 177 return 0;
176} 178}
177 179
diff --git a/drivers/gpu/nvgpu/gk20a/as_gk20a.c b/drivers/gpu/nvgpu/gk20a/as_gk20a.c
index e4bd8b73..a3c8c1ec 100644
--- a/drivers/gpu/nvgpu/gk20a/as_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/as_gk20a.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * GK20A Address Spaces 2 * GK20A Address Spaces
3 * 3 *
4 * Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved. 4 * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify it 6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License, 7 * under the terms and conditions of the GNU General Public License,
@@ -46,6 +46,9 @@ int gk20a_as_alloc_share(struct gk20a_as *as,
46 int err = 0; 46 int err = 0;
47 47
48 gk20a_dbg_fn(""); 48 gk20a_dbg_fn("");
49 g = gk20a_get(g);
50 if (!g)
51 return -ENODEV;
49 52
50 *out = NULL; 53 *out = NULL;
51 as_share = kzalloc(sizeof(*as_share), GFP_KERNEL); 54 as_share = kzalloc(sizeof(*as_share), GFP_KERNEL);
@@ -85,15 +88,19 @@ int gk20a_as_release_share(struct gk20a_as_share *as_share)
85 gk20a_dbg_fn(""); 88 gk20a_dbg_fn("");
86 89
87 err = gk20a_busy(g->dev); 90 err = gk20a_busy(g->dev);
91
88 if (err) 92 if (err)
89 return err; 93 goto release_fail;
90 94
91 err = gk20a_vm_release_share(as_share); 95 err = gk20a_vm_release_share(as_share);
92 96
93 gk20a_idle(g->dev); 97 gk20a_idle(g->dev);
94 98
99release_fail:
95 release_as_share_id(as_share->as, as_share->id); 100 release_as_share_id(as_share->as, as_share->id);
101 gk20a_put(g);
96 kfree(as_share); 102 kfree(as_share);
103
97 return err; 104 return err;
98} 105}
99 106
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index 73cc18d2..c09539ff 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -1234,7 +1234,7 @@ int gk20a_channel_release(struct inode *inode, struct file *filp)
1234 err = gk20a_busy(g->dev); 1234 err = gk20a_busy(g->dev);
1235 if (err) { 1235 if (err) {
1236 gk20a_err(dev_from_gk20a(g), "failed to release a channel!"); 1236 gk20a_err(dev_from_gk20a(g), "failed to release a channel!");
1237 return err; 1237 goto channel_release;
1238 } 1238 }
1239 1239
1240 trace_gk20a_channel_release(dev_name(g->dev)); 1240 trace_gk20a_channel_release(dev_name(g->dev));
@@ -1242,6 +1242,8 @@ int gk20a_channel_release(struct inode *inode, struct file *filp)
1242 gk20a_channel_close(ch); 1242 gk20a_channel_close(ch);
1243 gk20a_idle(g->dev); 1243 gk20a_idle(g->dev);
1244 1244
1245channel_release:
1246 gk20a_put(g);
1245 kfree(filp->private_data); 1247 kfree(filp->private_data);
1246 filp->private_data = NULL; 1248 filp->private_data = NULL;
1247 return 0; 1249 return 0;
@@ -1382,11 +1384,17 @@ static int __gk20a_channel_open(struct gk20a *g, struct file *filp, s32 runlist_
1382 1384
1383 gk20a_dbg_fn(""); 1385 gk20a_dbg_fn("");
1384 1386
1387 g = gk20a_get(g);
1388 if (!g)
1389 return -ENODEV;
1390
1385 trace_gk20a_channel_open(dev_name(g->dev)); 1391 trace_gk20a_channel_open(dev_name(g->dev));
1386 1392
1387 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1393 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1388 if (!priv) 1394 if (!priv) {
1389 return -ENOMEM; 1395 err = -ENOMEM;
1396 goto free_ref;
1397 }
1390 1398
1391 err = gk20a_busy(g->dev); 1399 err = gk20a_busy(g->dev);
1392 if (err) { 1400 if (err) {
@@ -1414,6 +1422,8 @@ static int __gk20a_channel_open(struct gk20a *g, struct file *filp, s32 runlist_
1414 1422
1415fail_busy: 1423fail_busy:
1416 kfree(priv); 1424 kfree(priv);
1425free_ref:
1426 gk20a_put(g);
1417 return err; 1427 return err;
1418} 1428}
1419 1429
@@ -3509,6 +3519,7 @@ static int gk20a_event_id_release(struct inode *inode, struct file *filp)
3509 } 3519 }
3510 3520
3511 nvgpu_mutex_destroy(&event_id_data->lock); 3521 nvgpu_mutex_destroy(&event_id_data->lock);
3522 gk20a_put(g);
3512 kfree(event_id_data); 3523 kfree(event_id_data);
3513 filp->private_data = NULL; 3524 filp->private_data = NULL;
3514 3525
@@ -3573,20 +3584,28 @@ static int gk20a_channel_event_id_enable(struct channel_gk20a *ch,
3573 int event_id, 3584 int event_id,
3574 int *fd) 3585 int *fd)
3575{ 3586{
3587 struct gk20a *g;
3576 int err = 0; 3588 int err = 0;
3577 int local_fd; 3589 int local_fd;
3578 struct file *file; 3590 struct file *file;
3579 char *name; 3591 char *name;
3580 struct gk20a_event_id_data *event_id_data; 3592 struct gk20a_event_id_data *event_id_data;
3581 3593
3594 g = gk20a_get(ch->g);
3595 if (!g)
3596 return -ENODEV;
3597
3582 err = gk20a_channel_get_event_data_from_id(ch, 3598 err = gk20a_channel_get_event_data_from_id(ch,
3583 event_id, &event_id_data); 3599 event_id, &event_id_data);
3584 if (err == 0) /* We already have event enabled */ 3600 if (err == 0) {
3585 return -EINVAL; 3601 /* We already have event enabled */
3602 err = -EINVAL;
3603 goto free_ref;
3604 }
3586 3605
3587 err = get_unused_fd_flags(O_RDWR); 3606 err = get_unused_fd_flags(O_RDWR);
3588 if (err < 0) 3607 if (err < 0)
3589 return err; 3608 goto free_ref;
3590 local_fd = err; 3609 local_fd = err;
3591 3610
3592 name = kasprintf(GFP_KERNEL, "nvgpu-event%d-fd%d", 3611 name = kasprintf(GFP_KERNEL, "nvgpu-event%d-fd%d",
@@ -3605,7 +3624,7 @@ static int gk20a_channel_event_id_enable(struct channel_gk20a *ch,
3605 err = -ENOMEM; 3624 err = -ENOMEM;
3606 goto clean_up_file; 3625 goto clean_up_file;
3607 } 3626 }
3608 event_id_data->g = ch->g; 3627 event_id_data->g = g;
3609 event_id_data->id = ch->hw_chid; 3628 event_id_data->id = ch->hw_chid;
3610 event_id_data->is_tsg = false; 3629 event_id_data->is_tsg = false;
3611 event_id_data->event_id = event_id; 3630 event_id_data->event_id = event_id;
@@ -3633,6 +3652,8 @@ clean_up_file:
3633 fput(file); 3652 fput(file);
3634clean_up: 3653clean_up:
3635 put_unused_fd(local_fd); 3654 put_unused_fd(local_fd);
3655free_ref:
3656 gk20a_put(g);
3636 return err; 3657 return err;
3637} 3658}
3638 3659
diff --git a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c
index 753623fa..e6626c4a 100644
--- a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c
@@ -55,10 +55,15 @@ int gk20a_ctrl_dev_open(struct inode *inode, struct file *filp)
55 55
56 g = container_of(inode->i_cdev, 56 g = container_of(inode->i_cdev,
57 struct gk20a, ctrl.cdev); 57 struct gk20a, ctrl.cdev);
58 g = gk20a_get(g);
59 if (!g)
60 return -ENODEV;
58 61
59 priv = kzalloc(sizeof(struct gk20a_ctrl_priv), GFP_KERNEL); 62 priv = kzalloc(sizeof(struct gk20a_ctrl_priv), GFP_KERNEL);
60 if (!priv) 63 if (!priv) {
61 return -ENOMEM; 64 err = -ENOMEM;
65 goto free_ref;
66 }
62 filp->private_data = priv; 67 filp->private_data = priv;
63 priv->dev = g->dev; 68 priv->dev = g->dev;
64 /* 69 /*
@@ -71,16 +76,16 @@ int gk20a_ctrl_dev_open(struct inode *inode, struct file *filp)
71 if (!g->gr.sw_ready) { 76 if (!g->gr.sw_ready) {
72 err = gk20a_busy(g->dev); 77 err = gk20a_busy(g->dev);
73 if (err) 78 if (err)
74 return err; 79 goto free_ref;
75 gk20a_idle(g->dev); 80 gk20a_idle(g->dev);
76 } 81 }
77 82
78#ifdef CONFIG_ARCH_TEGRA_18x_SOC 83#ifdef CONFIG_ARCH_TEGRA_18x_SOC
79 err = nvgpu_clk_arb_init_session(g, &priv->clk_session); 84 err = nvgpu_clk_arb_init_session(g, &priv->clk_session);
80 if (err)
81 return err;
82#endif 85#endif
83 86free_ref:
87 if (err)
88 gk20a_put(g);
84 return err; 89 return err;
85} 90}
86int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp) 91int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp)
@@ -95,6 +100,7 @@ int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp)
95 nvgpu_clk_arb_release_session(g, priv->clk_session); 100 nvgpu_clk_arb_release_session(g, priv->clk_session);
96#endif 101#endif
97 102
103 gk20a_put(g);
98 kfree(priv); 104 kfree(priv);
99 105
100 return 0; 106 return 0;
diff --git a/drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c b/drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c
index e33477f6..4ad2abd6 100644
--- a/drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c
@@ -276,14 +276,20 @@ int gk20a_ctxsw_dev_open(struct inode *inode, struct file *filp)
276 const int vmid = 0; 276 const int vmid = 0;
277 277
278 g = container_of(inode->i_cdev, struct gk20a, ctxsw.cdev); 278 g = container_of(inode->i_cdev, struct gk20a, ctxsw.cdev);
279 g = gk20a_get(g);
280 if (!g)
281 return -ENODEV;
282
279 gk20a_dbg(gpu_dbg_fn|gpu_dbg_ctxsw, "g=%p", g); 283 gk20a_dbg(gpu_dbg_fn|gpu_dbg_ctxsw, "g=%p", g);
280 284
281 if (!capable(CAP_SYS_ADMIN)) 285 if (!capable(CAP_SYS_ADMIN)) {
282 return -EPERM; 286 err = -EPERM;
287 goto free_ref;
288 }
283 289
284 err = gk20a_busy(g->dev); 290 err = gk20a_busy(g->dev);
285 if (err) 291 if (err)
286 return err; 292 goto free_ref;
287 293
288 trace = g->ctxsw_trace; 294 trace = g->ctxsw_trace;
289 if (!trace) { 295 if (!trace) {
@@ -325,7 +331,9 @@ done:
325 331
326idle: 332idle:
327 gk20a_idle(g->dev); 333 gk20a_idle(g->dev);
328 334free_ref:
335 if (err)
336 gk20a_put(g);
329 return err; 337 return err;
330} 338}
331 339
@@ -346,7 +354,7 @@ int gk20a_ctxsw_dev_release(struct inode *inode, struct file *filp)
346 dev->g->ops.fecs_trace.free_user_buffer(dev->g); 354 dev->g->ops.fecs_trace.free_user_buffer(dev->g);
347 dev->hdr = NULL; 355 dev->hdr = NULL;
348 } 356 }
349 357 gk20a_put(g);
350 return 0; 358 return 0;
351} 359}
352 360
diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
index 821951ad..7eb742ed 100644
--- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
@@ -101,13 +101,17 @@ static int gk20a_dbg_gpu_do_dev_open(struct inode *inode,
101 else 101 else
102 g = container_of(inode->i_cdev, 102 g = container_of(inode->i_cdev,
103 struct gk20a, prof.cdev); 103 struct gk20a, prof.cdev);
104 g = gk20a_get(g);
105 if (!g)
106 return -ENODEV;
107
104 dev = g->dev; 108 dev = g->dev;
105 109
106 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "dbg session: %s", dev_name(dev)); 110 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "dbg session: %s", dev_name(dev));
107 111
108 err = alloc_session(&dbg_session); 112 err = alloc_session(&dbg_session);
109 if (err) 113 if (err)
110 return err; 114 goto free_ref;
111 115
112 filp->private_data = dbg_session; 116 filp->private_data = dbg_session;
113 dbg_session->dev = dev; 117 dbg_session->dev = dev;
@@ -133,6 +137,8 @@ err_destroy_lock:
133 nvgpu_mutex_destroy(&dbg_session->ch_list_lock); 137 nvgpu_mutex_destroy(&dbg_session->ch_list_lock);
134err_free_session: 138err_free_session:
135 kfree(dbg_session); 139 kfree(dbg_session);
140free_ref:
141 gk20a_put(g);
136 return err; 142 return err;
137} 143}
138 144
@@ -494,6 +500,8 @@ int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp)
494 nvgpu_mutex_destroy(&dbg_s->ioctl_lock); 500 nvgpu_mutex_destroy(&dbg_s->ioctl_lock);
495 501
496 kfree(dbg_s); 502 kfree(dbg_s);
503 gk20a_put(g);
504
497 return 0; 505 return 0;
498} 506}
499 507
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c
index 30c0f2fb..1d6fb0e9 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.c
@@ -1712,7 +1712,7 @@ static int __exit gk20a_remove(struct platform_device *pdev)
1712 platform->remove(dev); 1712 platform->remove(dev);
1713 1713
1714 set_gk20a(pdev, NULL); 1714 set_gk20a(pdev, NULL);
1715 kfree(g); 1715 gk20a_put(g);
1716 1716
1717 gk20a_dbg_fn("removed"); 1717 gk20a_dbg_fn("removed");
1718 1718
@@ -2274,6 +2274,68 @@ int gk20a_read_ptimer(struct gk20a *g, u64 *value)
2274 return -EBUSY; 2274 return -EBUSY;
2275} 2275}
2276 2276
2277/*
2278 * Free the gk20a struct.
2279 */
2280static void gk20a_free_cb(struct kref *refcount)
2281{
2282 struct gk20a *g = container_of(refcount,
2283 struct gk20a, refcount);
2284
2285 gk20a_dbg(gpu_dbg_shutdown, "Freeing GK20A struct!");
2286 kfree(g);
2287}
2288
2289/**
2290 * gk20a_get() - Increment ref count on driver
2291 *
2292 * @g The driver to increment
2293 * This will fail if the driver is in the process of being released. In that
2294 * case it will return NULL. Otherwise a pointer to the driver passed in will
2295 * be returned.
2296 */
2297struct gk20a * __must_check gk20a_get(struct gk20a *g)
2298{
2299 int success;
2300
2301 /*
2302 * Handle the possibility we are still freeing the gk20a struct while
2303 * gk20a_get() is called. Unlikely but plausible race condition. Ideally
2304 * the code will never be in such a situation that this race is
2305 * possible.
2306 */
2307 success = kref_get_unless_zero(&g->refcount);
2308
2309 gk20a_dbg(gpu_dbg_shutdown, "GET: refs currently %d %s",
2310 atomic_read(&g->refcount.refcount), success ? "" : "(FAILED)");
2311
2312 return success ? g : NULL;
2313}
2314
2315/**
2316 * gk20a_put() - Decrement ref count on driver
2317 *
2318 * @g - The driver to decrement
2319 *
2320 * Decrement the driver ref-count. If neccesary also free the underlying driver
2321 * memory
2322 */
2323void gk20a_put(struct gk20a *g)
2324{
2325 /*
2326 * Note - this is racy, two instances of this could run before the
2327 * actual kref_put(0 runs, you could see something like:
2328 *
2329 * ... PUT: refs currently 2
2330 * ... PUT: refs currently 2
2331 * ... Freeing GK20A struct!
2332 */
2333 gk20a_dbg(gpu_dbg_shutdown, "PUT: refs currently %d",
2334 atomic_read(&g->refcount.refcount));
2335
2336 kref_put(&g->refcount, gk20a_free_cb);
2337}
2338
2277MODULE_LICENSE("GPL v2"); 2339MODULE_LICENSE("GPL v2");
2278module_init(gk20a_init); 2340module_init(gk20a_init);
2279module_exit(gk20a_exit); 2341module_exit(gk20a_exit);
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index a4f0799a..3ba05e84 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -857,6 +857,7 @@ struct gk20a {
857 atomic_t nonstall_ops; 857 atomic_t nonstall_ops;
858 struct work_struct nonstall_fn_work; 858 struct work_struct nonstall_fn_work;
859 struct workqueue_struct *nonstall_work_queue; 859 struct workqueue_struct *nonstall_work_queue;
860 struct kref refcount;
860 861
861 struct resource *reg_mem; 862 struct resource *reg_mem;
862 void __iomem *regs; 863 void __iomem *regs;
@@ -1468,6 +1469,9 @@ static inline void gk20a_channel_trace_sched_param(
1468 1469
1469void nvgpu_wait_for_deferred_interrupts(struct gk20a *g); 1470void nvgpu_wait_for_deferred_interrupts(struct gk20a *g);
1470 1471
1472struct gk20a * __must_check gk20a_get(struct gk20a *g);
1473void gk20a_put(struct gk20a *g);
1474
1471#ifdef CONFIG_DEBUG_FS 1475#ifdef CONFIG_DEBUG_FS
1472int gk20a_railgating_debugfs_init(struct device *dev); 1476int gk20a_railgating_debugfs_init(struct device *dev);
1473#endif 1477#endif
diff --git a/drivers/gpu/nvgpu/gk20a/sched_gk20a.c b/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
index 6fdc2774..a73e7993 100644
--- a/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
@@ -377,21 +377,28 @@ int gk20a_sched_dev_open(struct inode *inode, struct file *filp)
377{ 377{
378 struct gk20a *g = container_of(inode->i_cdev, 378 struct gk20a *g = container_of(inode->i_cdev,
379 struct gk20a, sched.cdev); 379 struct gk20a, sched.cdev);
380 struct gk20a_sched_ctrl *sched = &g->sched_ctrl; 380 struct gk20a_sched_ctrl *sched;
381 int err; 381 int err = 0;
382
383 g = gk20a_get(g);
384 if (!g)
385 return -ENODEV;
386 sched = &g->sched_ctrl;
382 387
383 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "g=%p", g); 388 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "g=%p", g);
384 389
385 if (!sched->sw_ready) { 390 if (!sched->sw_ready) {
386 err = gk20a_busy(g->dev); 391 err = gk20a_busy(g->dev);
387 if (err) 392 if (err)
388 return err; 393 goto free_ref;
389 394
390 gk20a_idle(g->dev); 395 gk20a_idle(g->dev);
391 } 396 }
392 397
393 if (!nvgpu_mutex_tryacquire(&sched->busy_lock)) 398 if (!nvgpu_mutex_tryacquire(&sched->busy_lock)) {
394 return -EBUSY; 399 err = -EBUSY;
400 goto free_ref;
401 }
395 402
396 memcpy(sched->recent_tsg_bitmap, sched->active_tsg_bitmap, 403 memcpy(sched->recent_tsg_bitmap, sched->active_tsg_bitmap,
397 sched->bitmap_size); 404 sched->bitmap_size);
@@ -400,7 +407,10 @@ int gk20a_sched_dev_open(struct inode *inode, struct file *filp)
400 filp->private_data = sched; 407 filp->private_data = sched;
401 gk20a_dbg(gpu_dbg_sched, "filp=%p sched=%p", filp, sched); 408 gk20a_dbg(gpu_dbg_sched, "filp=%p sched=%p", filp, sched);
402 409
403 return 0; 410free_ref:
411 if (err)
412 gk20a_put(g);
413 return err;
404} 414}
405 415
406long gk20a_sched_dev_ioctl(struct file *filp, unsigned int cmd, 416long gk20a_sched_dev_ioctl(struct file *filp, unsigned int cmd,
@@ -511,6 +521,7 @@ int gk20a_sched_dev_release(struct inode *inode, struct file *filp)
511 nvgpu_mutex_release(&sched->control_lock); 521 nvgpu_mutex_release(&sched->control_lock);
512 522
513 nvgpu_mutex_release(&sched->busy_lock); 523 nvgpu_mutex_release(&sched->busy_lock);
524 gk20a_put(g);
514 return 0; 525 return 0;
515} 526}
516 527
diff --git a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
index e1424f2b..270fed85 100644
--- a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
@@ -259,15 +259,23 @@ static int gk20a_tsg_event_id_enable(struct tsg_gk20a *tsg,
259 struct file *file; 259 struct file *file;
260 char *name; 260 char *name;
261 struct gk20a_event_id_data *event_id_data; 261 struct gk20a_event_id_data *event_id_data;
262 struct gk20a *g;
263
264 g = gk20a_get(tsg->g);
265 if (!g)
266 return -ENODEV;
262 267
263 err = gk20a_tsg_get_event_data_from_id(tsg, 268 err = gk20a_tsg_get_event_data_from_id(tsg,
264 event_id, &event_id_data); 269 event_id, &event_id_data);
265 if (err == 0) /* We already have event enabled */ 270 if (err == 0) {
266 return -EINVAL; 271 /* We already have event enabled */
272 err = -EINVAL;
273 goto free_ref;
274 }
267 275
268 err = get_unused_fd_flags(O_RDWR); 276 err = get_unused_fd_flags(O_RDWR);
269 if (err < 0) 277 if (err < 0)
270 return err; 278 goto free_ref;
271 local_fd = err; 279 local_fd = err;
272 280
273 name = kasprintf(GFP_KERNEL, "nvgpu-event%d-fd%d", 281 name = kasprintf(GFP_KERNEL, "nvgpu-event%d-fd%d",
@@ -286,7 +294,7 @@ static int gk20a_tsg_event_id_enable(struct tsg_gk20a *tsg,
286 err = -ENOMEM; 294 err = -ENOMEM;
287 goto clean_up_file; 295 goto clean_up_file;
288 } 296 }
289 event_id_data->g = tsg->g; 297 event_id_data->g = g;
290 event_id_data->id = tsg->tsgid; 298 event_id_data->id = tsg->tsgid;
291 event_id_data->is_tsg = true; 299 event_id_data->is_tsg = true;
292 event_id_data->event_id = event_id; 300 event_id_data->event_id = event_id;
@@ -315,6 +323,8 @@ clean_up_file:
315 fput(file); 323 fput(file);
316clean_up: 324clean_up:
317 put_unused_fd(local_fd); 325 put_unused_fd(local_fd);
326free_ref:
327 gk20a_put(g);
318 return err; 328 return err;
319} 329}
320 330
@@ -410,18 +420,25 @@ int gk20a_tsg_open(struct gk20a *g, struct file *filp)
410 struct device *dev; 420 struct device *dev;
411 int err; 421 int err;
412 422
423 g = gk20a_get(g);
424 if (!g)
425 return -ENODEV;
426
413 dev = dev_from_gk20a(g); 427 dev = dev_from_gk20a(g);
414 428
415 gk20a_dbg(gpu_dbg_fn, "tsg: %s", dev_name(dev)); 429 gk20a_dbg(gpu_dbg_fn, "tsg: %s", dev_name(dev));
416 430
417 priv = kmalloc(sizeof(*priv), GFP_KERNEL); 431 priv = kmalloc(sizeof(*priv), GFP_KERNEL);
418 if (!priv) 432 if (!priv) {
419 return -ENOMEM; 433 err = -ENOMEM;
434 goto free_ref;
435 }
420 436
421 tsg = acquire_unused_tsg(&g->fifo); 437 tsg = acquire_unused_tsg(&g->fifo);
422 if (!tsg) { 438 if (!tsg) {
423 kfree(priv); 439 kfree(priv);
424 return -ENOMEM; 440 err = -ENOMEM;
441 goto free_ref;
425 } 442 }
426 443
427 tsg->g = g; 444 tsg->g = g;
@@ -458,6 +475,8 @@ int gk20a_tsg_open(struct gk20a *g, struct file *filp)
458 475
459clean_up: 476clean_up:
460 kref_put(&tsg->refcount, gk20a_tsg_release); 477 kref_put(&tsg->refcount, gk20a_tsg_release);
478free_ref:
479 gk20a_put(g);
461 return err; 480 return err;
462} 481}
463 482
@@ -505,16 +524,13 @@ void gk20a_tsg_release(struct kref *ref)
505 tsg->runlist_id = ~0; 524 tsg->runlist_id = ~0;
506 525
507 gk20a_dbg(gpu_dbg_fn, "tsg released %d\n", tsg->tsgid); 526 gk20a_dbg(gpu_dbg_fn, "tsg released %d\n", tsg->tsgid);
527 gk20a_put(g);
508} 528}
509 529
510int gk20a_tsg_dev_release(struct inode *inode, struct file *filp) 530int gk20a_tsg_dev_release(struct inode *inode, struct file *filp)
511{ 531{
512 struct tsg_private *priv = filp->private_data; 532 struct tsg_private *priv = filp->private_data;
513 struct tsg_gk20a *tsg = priv->tsg; 533 struct tsg_gk20a *tsg = priv->tsg;
514 struct gk20a *g = priv->g;
515
516 if (g->driver_is_dying)
517 return -ENODEV;
518 534
519 kref_put(&tsg->refcount, gk20a_tsg_release); 535 kref_put(&tsg->refcount, gk20a_tsg_release);
520 kfree(priv); 536 kfree(priv);
diff --git a/drivers/gpu/nvgpu/pci.c b/drivers/gpu/nvgpu/pci.c
index 7ef626c2..0ed621ce 100644
--- a/drivers/gpu/nvgpu/pci.c
+++ b/drivers/gpu/nvgpu/pci.c
@@ -481,7 +481,8 @@ static void nvgpu_pci_remove(struct pci_dev *pdev)
481 481
482 enable_irq(g->irq_stall); 482 enable_irq(g->irq_stall);
483 483
484 kfree(g); 484 gk20a_get_platform(&pdev->dev)->g = NULL;
485 gk20a_put(g);
485} 486}
486 487
487static struct pci_driver nvgpu_pci_driver = { 488static struct pci_driver nvgpu_pci_driver = {
diff --git a/drivers/gpu/nvgpu/vgpu/vgpu.c b/drivers/gpu/nvgpu/vgpu/vgpu.c
index d5eb05ac..a97c179f 100644
--- a/drivers/gpu/nvgpu/vgpu/vgpu.c
+++ b/drivers/gpu/nvgpu/vgpu/vgpu.c
@@ -638,6 +638,8 @@ int vgpu_probe(struct platform_device *pdev)
638 vgpu_create_sysfs(dev); 638 vgpu_create_sysfs(dev);
639 gk20a_init_gr(gk20a); 639 gk20a_init_gr(gk20a);
640 640
641 kref_init(&gk20a->refcount);
642
641 return 0; 643 return 0;
642} 644}
643 645
@@ -656,6 +658,7 @@ int vgpu_remove(struct platform_device *pdev)
656 gk20a_user_deinit(dev, &nvgpu_class); 658 gk20a_user_deinit(dev, &nvgpu_class);
657 vgpu_remove_sysfs(dev); 659 vgpu_remove_sysfs(dev);
658 gk20a_get_platform(dev)->g = NULL; 660 gk20a_get_platform(dev)->g = NULL;
659 kfree(g); 661 gk20a_put(g);
662
660 return 0; 663 return 0;
661} 664}