summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu
diff options
context:
space:
mode:
authorKonsta Holtta <kholtta@nvidia.com>2015-01-29 03:35:04 -0500
committerDan Willemsen <dwillemsen@nvidia.com>2015-04-04 21:08:27 -0400
commite1ae4e3053d5860d671e3264a467ade376828784 (patch)
treef9e728b8f195962a2dbcb18546523ae3ccf4d4cd /drivers/gpu/nvgpu
parent593c7a3f3027cf95e1b35f9acb8b3d0dc45f24e4 (diff)
gpu: nvgpu: protect channel ioctls with a mutex
Add a big mutex for protecting the channel during ioctls, in case the userspace uses the same channel from several threads at once. The lock is taken during all operations except CHANNEL_WAIT, which could deadlock. Bug 1603482 Change-Id: Ibed962eadc9f00645abd54413dde9aaee00377ab Signed-off-by: Konsta Holtta <kholtta@nvidia.com> Reviewed-on: http://git-master/r/678871 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c47
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.h3
2 files changed, 37 insertions, 13 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index b126f31a..62092930 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -1592,11 +1592,19 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
1592 /* Make sure we have enough space for gpfifo entries. If not, 1592 /* Make sure we have enough space for gpfifo entries. If not,
1593 * wait for signals from completed submits */ 1593 * wait for signals from completed submits */
1594 if (gp_free_count(c) < num_entries + extra_entries) { 1594 if (gp_free_count(c) < num_entries + extra_entries) {
1595 /* we can get here via locked ioctl and other paths too */
1596 int locked_path = mutex_is_locked(&c->ioctl_lock);
1597 if (locked_path)
1598 mutex_unlock(&c->ioctl_lock);
1599
1595 trace_gk20a_gpfifo_submit_wait_for_space(c->g->dev->name); 1600 trace_gk20a_gpfifo_submit_wait_for_space(c->g->dev->name);
1596 err = wait_event_interruptible(c->submit_wq, 1601 err = wait_event_interruptible(c->submit_wq,
1597 get_gp_free_count(c) >= num_entries + extra_entries || 1602 get_gp_free_count(c) >= num_entries + extra_entries ||
1598 c->has_timedout); 1603 c->has_timedout);
1599 trace_gk20a_gpfifo_submit_wait_for_space_done(c->g->dev->name); 1604 trace_gk20a_gpfifo_submit_wait_for_space_done(c->g->dev->name);
1605
1606 if (locked_path)
1607 mutex_lock(&c->ioctl_lock);
1600 } 1608 }
1601 1609
1602 if (c->has_timedout) { 1610 if (c->has_timedout) {
@@ -1765,6 +1773,7 @@ int gk20a_init_channel_support(struct gk20a *g, u32 chid)
1765 c->in_use = false; 1773 c->in_use = false;
1766 c->hw_chid = chid; 1774 c->hw_chid = chid;
1767 c->bound = false; 1775 c->bound = false;
1776 mutex_init(&c->ioctl_lock);
1768 mutex_init(&c->jobs_lock); 1777 mutex_init(&c->jobs_lock);
1769 mutex_init(&c->submit_lock); 1778 mutex_init(&c->submit_lock);
1770 INIT_LIST_HEAD(&c->jobs); 1779 INIT_LIST_HEAD(&c->jobs);
@@ -2270,6 +2279,10 @@ long gk20a_channel_ioctl(struct file *filp,
2270 return -EFAULT; 2279 return -EFAULT;
2271 } 2280 }
2272 2281
2282 /* protect our sanity for threaded userspace - most of the channel is
2283 * not thread safe */
2284 mutex_lock(&ch->ioctl_lock);
2285
2273 switch (cmd) { 2286 switch (cmd) {
2274 case NVGPU_IOCTL_CHANNEL_OPEN: 2287 case NVGPU_IOCTL_CHANNEL_OPEN:
2275 err = gk20a_channel_open_ioctl(ch->g, 2288 err = gk20a_channel_open_ioctl(ch->g,
@@ -2283,7 +2296,7 @@ long gk20a_channel_ioctl(struct file *filp,
2283 dev_err(&dev->dev, 2296 dev_err(&dev->dev,
2284 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2297 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2285 __func__, cmd); 2298 __func__, cmd);
2286 return err; 2299 break;
2287 } 2300 }
2288 err = ch->g->ops.gr.alloc_obj_ctx(ch, 2301 err = ch->g->ops.gr.alloc_obj_ctx(ch,
2289 (struct nvgpu_alloc_obj_ctx_args *)buf); 2302 (struct nvgpu_alloc_obj_ctx_args *)buf);
@@ -2295,7 +2308,7 @@ long gk20a_channel_ioctl(struct file *filp,
2295 dev_err(&dev->dev, 2308 dev_err(&dev->dev,
2296 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2309 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2297 __func__, cmd); 2310 __func__, cmd);
2298 return err; 2311 break;
2299 } 2312 }
2300 err = ch->g->ops.gr.free_obj_ctx(ch, 2313 err = ch->g->ops.gr.free_obj_ctx(ch,
2301 (struct nvgpu_free_obj_ctx_args *)buf); 2314 (struct nvgpu_free_obj_ctx_args *)buf);
@@ -2307,7 +2320,7 @@ long gk20a_channel_ioctl(struct file *filp,
2307 dev_err(&dev->dev, 2320 dev_err(&dev->dev,
2308 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2321 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2309 __func__, cmd); 2322 __func__, cmd);
2310 return err; 2323 break;
2311 } 2324 }
2312 err = gk20a_alloc_channel_gpfifo(ch, 2325 err = gk20a_alloc_channel_gpfifo(ch,
2313 (struct nvgpu_alloc_gpfifo_args *)buf); 2326 (struct nvgpu_alloc_gpfifo_args *)buf);
@@ -2323,10 +2336,18 @@ long gk20a_channel_ioctl(struct file *filp,
2323 dev_err(&dev->dev, 2336 dev_err(&dev->dev,
2324 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2337 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2325 __func__, cmd); 2338 __func__, cmd);
2326 return err; 2339 break;
2327 } 2340 }
2341
2342 /* waiting is thread-safe, not dropping this mutex could
2343 * deadlock in certain conditions */
2344 mutex_unlock(&ch->ioctl_lock);
2345
2328 err = gk20a_channel_wait(ch, 2346 err = gk20a_channel_wait(ch,
2329 (struct nvgpu_wait_args *)buf); 2347 (struct nvgpu_wait_args *)buf);
2348
2349 mutex_lock(&ch->ioctl_lock);
2350
2330 gk20a_idle(dev); 2351 gk20a_idle(dev);
2331 break; 2352 break;
2332 case NVGPU_IOCTL_CHANNEL_ZCULL_BIND: 2353 case NVGPU_IOCTL_CHANNEL_ZCULL_BIND:
@@ -2335,7 +2356,7 @@ long gk20a_channel_ioctl(struct file *filp,
2335 dev_err(&dev->dev, 2356 dev_err(&dev->dev,
2336 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2357 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2337 __func__, cmd); 2358 __func__, cmd);
2338 return err; 2359 break;
2339 } 2360 }
2340 err = gk20a_channel_zcull_bind(ch, 2361 err = gk20a_channel_zcull_bind(ch,
2341 (struct nvgpu_zcull_bind_args *)buf); 2362 (struct nvgpu_zcull_bind_args *)buf);
@@ -2347,7 +2368,7 @@ long gk20a_channel_ioctl(struct file *filp,
2347 dev_err(&dev->dev, 2368 dev_err(&dev->dev,
2348 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2369 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2349 __func__, cmd); 2370 __func__, cmd);
2350 return err; 2371 break;
2351 } 2372 }
2352 err = gk20a_init_error_notifier(ch, 2373 err = gk20a_init_error_notifier(ch,
2353 (struct nvgpu_set_error_notifier *)buf); 2374 (struct nvgpu_set_error_notifier *)buf);
@@ -2360,7 +2381,7 @@ long gk20a_channel_ioctl(struct file *filp,
2360 dev_err(&dev->dev, 2381 dev_err(&dev->dev,
2361 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2382 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2362 __func__, cmd); 2383 __func__, cmd);
2363 return err; 2384 break;
2364 } 2385 }
2365 err = gk20a_channel_cycle_stats(ch, 2386 err = gk20a_channel_cycle_stats(ch,
2366 (struct nvgpu_cycle_stats_args *)buf); 2387 (struct nvgpu_cycle_stats_args *)buf);
@@ -2399,7 +2420,7 @@ long gk20a_channel_ioctl(struct file *filp,
2399 dev_err(&dev->dev, 2420 dev_err(&dev->dev,
2400 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2421 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2401 __func__, cmd); 2422 __func__, cmd);
2402 return err; 2423 break;
2403 } 2424 }
2404 gk20a_channel_set_priority(ch, 2425 gk20a_channel_set_priority(ch,
2405 ((struct nvgpu_set_priority_args *)buf)->priority); 2426 ((struct nvgpu_set_priority_args *)buf)->priority);
@@ -2411,7 +2432,7 @@ long gk20a_channel_ioctl(struct file *filp,
2411 dev_err(&dev->dev, 2432 dev_err(&dev->dev,
2412 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2433 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2413 __func__, cmd); 2434 __func__, cmd);
2414 return err; 2435 break;
2415 } 2436 }
2416 /* enable channel */ 2437 /* enable channel */
2417 gk20a_writel(ch->g, ccsr_channel_r(ch->hw_chid), 2438 gk20a_writel(ch->g, ccsr_channel_r(ch->hw_chid),
@@ -2425,7 +2446,7 @@ long gk20a_channel_ioctl(struct file *filp,
2425 dev_err(&dev->dev, 2446 dev_err(&dev->dev,
2426 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2447 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2427 __func__, cmd); 2448 __func__, cmd);
2428 return err; 2449 break;
2429 } 2450 }
2430 /* disable channel */ 2451 /* disable channel */
2431 gk20a_writel(ch->g, ccsr_channel_r(ch->hw_chid), 2452 gk20a_writel(ch->g, ccsr_channel_r(ch->hw_chid),
@@ -2439,7 +2460,7 @@ long gk20a_channel_ioctl(struct file *filp,
2439 dev_err(&dev->dev, 2460 dev_err(&dev->dev,
2440 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2461 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2441 __func__, cmd); 2462 __func__, cmd);
2442 return err; 2463 break;
2443 } 2464 }
2444 err = gk20a_fifo_preempt(ch->g, ch); 2465 err = gk20a_fifo_preempt(ch->g, ch);
2445 gk20a_idle(dev); 2466 gk20a_idle(dev);
@@ -2450,7 +2471,7 @@ long gk20a_channel_ioctl(struct file *filp,
2450 dev_err(&dev->dev, 2471 dev_err(&dev->dev,
2451 "%s: failed to host gk20a for ioctl cmd: 0x%x", 2472 "%s: failed to host gk20a for ioctl cmd: 0x%x",
2452 __func__, cmd); 2473 __func__, cmd);
2453 return err; 2474 break;
2454 } 2475 }
2455 err = gk20a_fifo_force_reset_ch(ch, true); 2476 err = gk20a_fifo_force_reset_ch(ch, true);
2456 gk20a_idle(dev); 2477 gk20a_idle(dev);
@@ -2470,5 +2491,7 @@ long gk20a_channel_ioctl(struct file *filp,
2470 2491
2471 gk20a_dbg_fn("end"); 2492 gk20a_dbg_fn("end");
2472 2493
2494 mutex_unlock(&ch->ioctl_lock);
2495
2473 return err; 2496 return err;
2474} 2497}
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
index c028e3b1..034de53f 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * GK20A graphics channel 2 * GK20A graphics channel
3 * 3 *
4 * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved. 4 * Copyright (c) 2011-2015, 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,
@@ -84,6 +84,7 @@ struct channel_gk20a {
84 bool first_init; 84 bool first_init;
85 bool vpr; 85 bool vpr;
86 pid_t pid; 86 pid_t pid;
87 struct mutex ioctl_lock;
87 88
88 int tsgid; 89 int tsgid;
89 struct list_head ch_entry; /* channel's entry in TSG */ 90 struct list_head ch_entry; /* channel's entry in TSG */