diff options
-rw-r--r-- | drivers/gpu/nvgpu/common/nvgpu_common.c | 2 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/as_gk20a.c | 11 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 35 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | 18 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c | 18 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c | 10 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 64 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/sched_gk20a.c | 23 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/tsg_gk20a.c | 38 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/pci.c | 3 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/vgpu/vgpu.c | 5 |
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 | ||
99 | release_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 | ||
1245 | channel_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 | ||
1415 | fail_busy: | 1423 | fail_busy: |
1416 | kfree(priv); | 1424 | kfree(priv); |
1425 | free_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); |
3634 | clean_up: | 3653 | clean_up: |
3635 | put_unused_fd(local_fd); | 3654 | put_unused_fd(local_fd); |
3655 | free_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 | 86 | free_ref: | |
87 | if (err) | ||
88 | gk20a_put(g); | ||
84 | return err; | 89 | return err; |
85 | } | 90 | } |
86 | int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp) | 91 | int 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 | ||
326 | idle: | 332 | idle: |
327 | gk20a_idle(g->dev); | 333 | gk20a_idle(g->dev); |
328 | 334 | free_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); |
134 | err_free_session: | 138 | err_free_session: |
135 | kfree(dbg_session); | 139 | kfree(dbg_session); |
140 | free_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 | */ | ||
2280 | static 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 | */ | ||
2297 | struct 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 | */ | ||
2323 | void 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 | |||
2277 | MODULE_LICENSE("GPL v2"); | 2339 | MODULE_LICENSE("GPL v2"); |
2278 | module_init(gk20a_init); | 2340 | module_init(gk20a_init); |
2279 | module_exit(gk20a_exit); | 2341 | module_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 | ||
1469 | void nvgpu_wait_for_deferred_interrupts(struct gk20a *g); | 1470 | void nvgpu_wait_for_deferred_interrupts(struct gk20a *g); |
1470 | 1471 | ||
1472 | struct gk20a * __must_check gk20a_get(struct gk20a *g); | ||
1473 | void gk20a_put(struct gk20a *g); | ||
1474 | |||
1471 | #ifdef CONFIG_DEBUG_FS | 1475 | #ifdef CONFIG_DEBUG_FS |
1472 | int gk20a_railgating_debugfs_init(struct device *dev); | 1476 | int 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; | 410 | free_ref: |
411 | if (err) | ||
412 | gk20a_put(g); | ||
413 | return err; | ||
404 | } | 414 | } |
405 | 415 | ||
406 | long gk20a_sched_dev_ioctl(struct file *filp, unsigned int cmd, | 416 | long 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); |
316 | clean_up: | 324 | clean_up: |
317 | put_unused_fd(local_fd); | 325 | put_unused_fd(local_fd); |
326 | free_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 | ||
459 | clean_up: | 476 | clean_up: |
460 | kref_put(&tsg->refcount, gk20a_tsg_release); | 477 | kref_put(&tsg->refcount, gk20a_tsg_release); |
478 | free_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 | ||
510 | int gk20a_tsg_dev_release(struct inode *inode, struct file *filp) | 530 | int 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 | ||
487 | static struct pci_driver nvgpu_pci_driver = { | 488 | static 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 | } |