summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/sched_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/sched_gk20a.c603
1 files changed, 603 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/sched_gk20a.c b/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
new file mode 100644
index 00000000..bcbbbe8b
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
@@ -0,0 +1,603 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include <asm/barrier.h>
15#include <linux/slab.h>
16#include <linux/kthread.h>
17#include <linux/circ_buf.h>
18#include <linux/delay.h>
19#include <linux/jiffies.h>
20#include <linux/wait.h>
21#include <linux/ktime.h>
22#include <linux/nvgpu.h>
23#include <linux/hashtable.h>
24#include <linux/debugfs.h>
25#include <linux/log2.h>
26#include <uapi/linux/nvgpu.h>
27#include "ctxsw_trace_gk20a.h"
28#include "gk20a.h"
29#include "gr_gk20a.h"
30#include "hw_ctxsw_prog_gk20a.h"
31#include "hw_gr_gk20a.h"
32#include "sched_gk20a.h"
33
34ssize_t gk20a_sched_dev_read(struct file *filp, char __user *buf,
35 size_t size, loff_t *off)
36{
37 struct gk20a_sched_ctrl *sched = filp->private_data;
38 struct nvgpu_sched_event_arg event = { 0 };
39 int err;
40
41 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched,
42 "filp=%p buf=%p size=%zu", filp, buf, size);
43
44 if (size < sizeof(event))
45 return -EINVAL;
46 size = sizeof(event);
47
48 mutex_lock(&sched->status_lock);
49 while (!sched->status) {
50 mutex_unlock(&sched->status_lock);
51 if (filp->f_flags & O_NONBLOCK)
52 return -EAGAIN;
53 err = wait_event_interruptible(sched->readout_wq,
54 sched->status);
55 if (err)
56 return err;
57 mutex_lock(&sched->status_lock);
58 }
59
60 event.reserved = 0;
61 event.status = sched->status;
62
63 if (copy_to_user(buf, &event, size)) {
64 mutex_unlock(&sched->status_lock);
65 return -EFAULT;
66 }
67
68 sched->status = 0;
69
70 mutex_unlock(&sched->status_lock);
71
72 return size;
73}
74
75unsigned int gk20a_sched_dev_poll(struct file *filp, poll_table *wait)
76{
77 struct gk20a_sched_ctrl *sched = filp->private_data;
78 unsigned int mask = 0;
79
80 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "");
81
82 mutex_lock(&sched->status_lock);
83 poll_wait(filp, &sched->readout_wq, wait);
84 if (sched->status)
85 mask |= POLLIN | POLLRDNORM;
86 mutex_unlock(&sched->status_lock);
87
88 return mask;
89}
90
91static int gk20a_sched_dev_ioctl_get_tsgs(struct gk20a_sched_ctrl *sched,
92 struct nvgpu_sched_get_tsgs_args *arg)
93{
94 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "size=%u buffer=%llx",
95 arg->size, arg->buffer);
96
97 if ((arg->size < sched->bitmap_size) || (!arg->buffer)) {
98 arg->size = sched->bitmap_size;
99 return -ENOSPC;
100 }
101
102 mutex_lock(&sched->status_lock);
103 if (copy_to_user((void __user *)(uintptr_t)arg->buffer,
104 sched->active_tsg_bitmap, sched->bitmap_size)) {
105 mutex_unlock(&sched->status_lock);
106 return -EFAULT;
107 }
108
109 memset(sched->recent_tsg_bitmap, 0, sched->bitmap_size);
110 mutex_unlock(&sched->status_lock);
111
112 return 0;
113}
114
115static int gk20a_sched_dev_ioctl_get_recent_tsgs(struct gk20a_sched_ctrl *sched,
116 struct nvgpu_sched_get_tsgs_args *arg)
117{
118 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "size=%u buffer=%llx",
119 arg->size, arg->buffer);
120
121 if ((arg->size < sched->bitmap_size) || (!arg->buffer)) {
122 arg->size = sched->bitmap_size;
123 return -ENOSPC;
124 }
125
126 mutex_lock(&sched->status_lock);
127 if (copy_to_user((void __user *)(uintptr_t)arg->buffer,
128 sched->recent_tsg_bitmap, sched->bitmap_size)) {
129 mutex_unlock(&sched->status_lock);
130 return -EFAULT;
131 }
132
133 memset(sched->recent_tsg_bitmap, 0, sched->bitmap_size);
134 mutex_unlock(&sched->status_lock);
135
136 return 0;
137}
138
139static int gk20a_sched_dev_ioctl_get_tsgs_by_pid(struct gk20a_sched_ctrl *sched,
140 struct nvgpu_sched_get_tsgs_by_pid_args *arg)
141{
142 struct fifo_gk20a *f = &sched->g->fifo;
143 struct tsg_gk20a *tsg;
144 u64 *bitmap;
145 int tsgid;
146 /* pid at user level corresponds to kernel tgid */
147 pid_t tgid = (pid_t)arg->pid;
148 int err = 0;
149
150 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "pid=%d size=%u buffer=%llx",
151 (pid_t)arg->pid, arg->size, arg->buffer);
152
153 if ((arg->size < sched->bitmap_size) || (!arg->buffer)) {
154 arg->size = sched->bitmap_size;
155 return -ENOSPC;
156 }
157
158 bitmap = kzalloc(sched->bitmap_size, GFP_KERNEL);
159 if (!bitmap)
160 return -ENOMEM;
161
162 mutex_lock(&f->tsg_inuse_mutex);
163 for (tsgid = 0; tsgid < f->num_channels; tsgid++) {
164 tsg = &f->tsg[tsgid];
165 if ((tsg->in_use) && (tsg->tgid == tgid))
166 NVGPU_SCHED_SET(tsgid, bitmap);
167 }
168 mutex_unlock(&f->tsg_inuse_mutex);
169
170 if (copy_to_user((void __user *)(uintptr_t)arg->buffer,
171 bitmap, sched->bitmap_size))
172 err = -EFAULT;
173
174 kfree(bitmap);
175
176 return err;
177}
178
179static int gk20a_sched_dev_ioctl_get_params(struct gk20a_sched_ctrl *sched,
180 struct nvgpu_sched_tsg_get_params_args *arg)
181{
182 struct gk20a *g = sched->g;
183 struct fifo_gk20a *f = &g->fifo;
184 struct tsg_gk20a *tsg;
185 u32 tsgid = arg->tsgid;
186 int err = -ENXIO;
187
188 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsgid);
189
190 if (tsgid >= f->num_channels)
191 return -EINVAL;
192
193 mutex_lock(&f->tsg_inuse_mutex);
194 tsg = &f->tsg[tsgid];
195 if (!tsg->in_use)
196 goto unlock_in_use;
197
198 mutex_lock(&sched->status_lock);
199 if (!NVGPU_SCHED_ISSET(tsgid, sched->active_tsg_bitmap)) {
200 gk20a_dbg(gpu_dbg_sched, "tsgid=%u not active", tsgid);
201 goto unlock_status;
202 }
203
204 arg->pid = tsg->tgid; /* kernel tgid corresponds to user pid */
205 arg->runlist_interleave = tsg->interleave_level;
206 arg->timeslice = tsg->timeslice_us;
207
208 if (tsg->tsg_gr_ctx) {
209 arg->graphics_preempt_mode =
210 tsg->tsg_gr_ctx->graphics_preempt_mode;
211 arg->compute_preempt_mode =
212 tsg->tsg_gr_ctx->compute_preempt_mode;
213 } else {
214 arg->graphics_preempt_mode = 0;
215 arg->compute_preempt_mode = 0;
216 }
217
218 err = 0;
219
220unlock_status:
221 mutex_unlock(&sched->status_lock);
222
223unlock_in_use:
224 mutex_unlock(&f->tsg_inuse_mutex);
225
226 return err;
227}
228
229static int gk20a_sched_dev_ioctl_tsg_set_timeslice(
230 struct gk20a_sched_ctrl *sched,
231 struct nvgpu_sched_tsg_timeslice_args *arg)
232{
233 struct gk20a *g = sched->g;
234 struct fifo_gk20a *f = &g->fifo;
235 struct tsg_gk20a *tsg;
236 u32 tsgid = arg->tsgid;
237 int err = -ENXIO;
238
239 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsgid);
240
241 if (tsgid >= f->num_channels)
242 return -EINVAL;
243
244 mutex_lock(&f->tsg_inuse_mutex);
245 tsg = &f->tsg[tsgid];
246 if (!tsg->in_use)
247 goto unlock_in_use;
248
249 mutex_lock(&sched->status_lock);
250 if (NVGPU_SCHED_ISSET(tsgid, sched->recent_tsg_bitmap)) {
251 gk20a_dbg(gpu_dbg_sched, "tsgid=%u was re-allocated", tsgid);
252 goto unlock_status;
253 }
254
255 err = gk20a_busy(g->dev);
256 if (err)
257 goto unlock_status;
258
259 err = gk20a_tsg_set_timeslice(tsg, arg->timeslice);
260
261 gk20a_idle(g->dev);
262
263unlock_status:
264 mutex_unlock(&sched->status_lock);
265
266unlock_in_use:
267 mutex_unlock(&f->tsg_inuse_mutex);
268
269 return err;
270}
271
272static int gk20a_sched_dev_ioctl_tsg_set_runlist_interleave(
273 struct gk20a_sched_ctrl *sched,
274 struct nvgpu_sched_tsg_runlist_interleave_args *arg)
275{
276 struct gk20a *g = sched->g;
277 struct fifo_gk20a *f = &g->fifo;
278 struct tsg_gk20a *tsg;
279 u32 tsgid = arg->tsgid;
280 int err = -ENXIO;
281
282 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsgid);
283
284 if (tsgid >= f->num_channels)
285 return -EINVAL;
286
287 mutex_lock(&f->tsg_inuse_mutex);
288 tsg = &f->tsg[tsgid];
289 if (!tsg->in_use)
290 goto unlock_in_use;
291
292 mutex_lock(&sched->status_lock);
293 if (NVGPU_SCHED_ISSET(tsgid, sched->recent_tsg_bitmap)) {
294 gk20a_dbg(gpu_dbg_sched, "tsgid=%u was re-allocated", tsgid);
295 goto unlock_status;
296 }
297
298 err = gk20a_busy(g->dev);
299 if (err)
300 goto unlock_status;
301
302 err = gk20a_tsg_set_runlist_interleave(tsg, arg->runlist_interleave);
303
304 gk20a_idle(g->dev);
305
306unlock_status:
307 mutex_unlock(&sched->status_lock);
308
309unlock_in_use:
310 mutex_unlock(&f->tsg_inuse_mutex);
311
312 return err;
313}
314
315static int gk20a_sched_dev_ioctl_lock_control(struct gk20a_sched_ctrl *sched)
316{
317 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "");
318
319 mutex_lock(&sched->control_lock);
320 sched->control_locked = true;
321 mutex_unlock(&sched->control_lock);
322 return 0;
323}
324
325static int gk20a_sched_dev_ioctl_unlock_control(struct gk20a_sched_ctrl *sched)
326{
327 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "");
328
329 mutex_lock(&sched->control_lock);
330 sched->control_locked = false;
331 mutex_unlock(&sched->control_lock);
332 return 0;
333}
334
335int gk20a_sched_dev_open(struct inode *inode, struct file *filp)
336{
337 struct gk20a *g = container_of(inode->i_cdev,
338 struct gk20a, sched.cdev);
339 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
340 int err;
341
342 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "g=%p", g);
343
344 if (!sched->sw_ready) {
345 err = gk20a_busy(g->dev);
346 if (err)
347 return err;
348
349 gk20a_idle(g->dev);
350 }
351
352 if (!mutex_trylock(&sched->busy_lock))
353 return -EBUSY;
354
355 memcpy(sched->recent_tsg_bitmap, sched->active_tsg_bitmap,
356 sched->bitmap_size);
357
358 filp->private_data = sched;
359 gk20a_dbg(gpu_dbg_sched, "filp=%p sched=%p", filp, sched);
360
361 return 0;
362}
363
364long gk20a_sched_dev_ioctl(struct file *filp, unsigned int cmd,
365 unsigned long arg)
366{
367 struct gk20a_sched_ctrl *sched = filp->private_data;
368 struct gk20a *g = sched->g;
369 u8 buf[NVGPU_CTXSW_IOCTL_MAX_ARG_SIZE];
370 int err = 0;
371
372 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "nr=%d", _IOC_NR(cmd));
373
374 if ((_IOC_TYPE(cmd) != NVGPU_SCHED_IOCTL_MAGIC) ||
375 (_IOC_NR(cmd) == 0) ||
376 (_IOC_NR(cmd) > NVGPU_SCHED_IOCTL_LAST) ||
377 (_IOC_SIZE(cmd) > NVGPU_SCHED_IOCTL_MAX_ARG_SIZE))
378 return -EINVAL;
379
380 memset(buf, 0, sizeof(buf));
381 if (_IOC_DIR(cmd) & _IOC_WRITE) {
382 if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
383 return -EFAULT;
384 }
385
386 switch (cmd) {
387 case NVGPU_SCHED_IOCTL_GET_TSGS:
388 err = gk20a_sched_dev_ioctl_get_tsgs(sched,
389 (struct nvgpu_sched_get_tsgs_args *)buf);
390 break;
391 case NVGPU_SCHED_IOCTL_GET_RECENT_TSGS:
392 err = gk20a_sched_dev_ioctl_get_recent_tsgs(sched,
393 (struct nvgpu_sched_get_tsgs_args *)buf);
394 break;
395 case NVGPU_SCHED_IOCTL_GET_TSGS_BY_PID:
396 err = gk20a_sched_dev_ioctl_get_tsgs_by_pid(sched,
397 (struct nvgpu_sched_get_tsgs_by_pid_args *)buf);
398 break;
399 case NVGPU_SCHED_IOCTL_TSG_GET_PARAMS:
400 err = gk20a_sched_dev_ioctl_get_params(sched,
401 (struct nvgpu_sched_tsg_get_params_args *)buf);
402 break;
403 case NVGPU_SCHED_IOCTL_TSG_SET_TIMESLICE:
404 err = gk20a_sched_dev_ioctl_tsg_set_timeslice(sched,
405 (struct nvgpu_sched_tsg_timeslice_args *)buf);
406 break;
407 case NVGPU_SCHED_IOCTL_TSG_SET_RUNLIST_INTERLEAVE:
408 err = gk20a_sched_dev_ioctl_tsg_set_runlist_interleave(sched,
409 (struct nvgpu_sched_tsg_runlist_interleave_args *)buf);
410 break;
411 case NVGPU_SCHED_IOCTL_LOCK_CONTROL:
412 err = gk20a_sched_dev_ioctl_lock_control(sched);
413 break;
414 case NVGPU_SCHED_IOCTL_UNLOCK_CONTROL:
415 err = gk20a_sched_dev_ioctl_unlock_control(sched);
416 break;
417 default:
418 dev_dbg(dev_from_gk20a(g), "unrecognized gpu ioctl cmd: 0x%x",
419 cmd);
420 err = -ENOTTY;
421 }
422
423 /* Some ioctls like NVGPU_SCHED_IOCTL_GET_TSGS might be called on
424 * purpose with NULL buffer and/or zero size to discover TSG bitmap
425 * size. We need to update user arguments in this case too, even
426 * if we return an error.
427 */
428 if ((!err || (err == -ENOSPC)) && (_IOC_DIR(cmd) & _IOC_READ)) {
429 if (copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd)))
430 err = -EFAULT;
431 }
432
433 return err;
434}
435
436int gk20a_sched_dev_release(struct inode *inode, struct file *filp)
437{
438 struct gk20a_sched_ctrl *sched = filp->private_data;
439
440 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "sched: %p", sched);
441
442 /* unlock control */
443 mutex_lock(&sched->control_lock);
444 sched->control_locked = false;
445 mutex_unlock(&sched->control_lock);
446
447 mutex_unlock(&sched->busy_lock);
448 return 0;
449}
450
451#ifdef CONFIG_DEBUG_FS
452static int gk20a_sched_debugfs_show(struct seq_file *s, void *unused)
453{
454 struct device *dev = s->private;
455 struct gk20a *g = gk20a_get_platform(dev)->g;
456 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
457
458 int n = sched->bitmap_size / sizeof(u64);
459 int i;
460 int err;
461
462 err = gk20a_busy(g->dev);
463 if (err)
464 return err;
465
466 seq_printf(s, "control_locked=%d\n", sched->control_locked);
467 seq_printf(s, "busy=%d\n", mutex_is_locked(&sched->busy_lock));
468 seq_printf(s, "bitmap_size=%zu\n", sched->bitmap_size);
469
470 mutex_lock(&sched->status_lock);
471
472 seq_puts(s, "active_tsg_bitmap\n");
473 for (i = 0; i < n; i++)
474 seq_printf(s, "\t0x%016llx\n", sched->active_tsg_bitmap[i]);
475
476 seq_puts(s, "recent_tsg_bitmap\n");
477 for (i = 0; i < n; i++)
478 seq_printf(s, "\t0x%016llx\n", sched->recent_tsg_bitmap[i]);
479
480 mutex_unlock(&sched->status_lock);
481
482 gk20a_idle(g->dev);
483
484 return 0;
485}
486
487static int gk20a_sched_debugfs_open(struct inode *inode, struct file *file)
488{
489 return single_open(file, gk20a_sched_debugfs_show, inode->i_private);
490}
491
492static const struct file_operations gk20a_sched_debugfs_fops = {
493 .open = gk20a_sched_debugfs_open,
494 .read = seq_read,
495 .llseek = seq_lseek,
496 .release = single_release,
497};
498
499void gk20a_sched_debugfs_init(struct device *dev)
500{
501 struct gk20a_platform *platform = dev_get_drvdata(dev);
502
503 debugfs_create_file("sched_ctrl", S_IRUGO, platform->debugfs,
504 dev, &gk20a_sched_debugfs_fops);
505}
506#endif /* CONFIG_DEBUG_FS */
507
508void gk20a_sched_ctrl_tsg_added(struct gk20a *g, struct tsg_gk20a *tsg)
509{
510 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
511 int err;
512
513 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsg->tsgid);
514
515 if (!sched->sw_ready) {
516 err = gk20a_busy(g->dev);
517 if (err) {
518 WARN_ON(err);
519 return;
520 }
521
522 gk20a_idle(g->dev);
523 }
524
525 mutex_lock(&sched->status_lock);
526 NVGPU_SCHED_SET(tsg->tsgid, sched->active_tsg_bitmap);
527 NVGPU_SCHED_SET(tsg->tsgid, sched->recent_tsg_bitmap);
528 sched->status |= NVGPU_SCHED_STATUS_TSG_OPEN;
529 mutex_unlock(&sched->status_lock);
530 wake_up_interruptible(&sched->readout_wq);
531}
532
533void gk20a_sched_ctrl_tsg_removed(struct gk20a *g, struct tsg_gk20a *tsg)
534{
535 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
536
537 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsg->tsgid);
538
539 mutex_lock(&sched->status_lock);
540 NVGPU_SCHED_CLR(tsg->tsgid, sched->active_tsg_bitmap);
541
542 /* clear recent_tsg_bitmap as well: if app manager did not
543 * notice that TSG was previously added, no need to notify it
544 * if the TSG has been released in the meantime. If the
545 * TSG gets reallocated, app manager will be notified as usual.
546 */
547 NVGPU_SCHED_CLR(tsg->tsgid, sched->recent_tsg_bitmap);
548
549 /* do not set event_pending, we only want to notify app manager
550 * when TSGs are added, so that it can apply sched params
551 */
552 mutex_unlock(&sched->status_lock);
553}
554
555int gk20a_sched_ctrl_init(struct gk20a *g)
556{
557 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
558 struct fifo_gk20a *f = &g->fifo;
559
560 if (sched->sw_ready)
561 return 0;
562
563 sched->g = g;
564 sched->bitmap_size = roundup(f->num_channels, 64) / 8;
565 sched->status = 0;
566
567 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "g=%p sched=%p size=%zu",
568 g, sched, sched->bitmap_size);
569
570 sched->active_tsg_bitmap = kzalloc(sched->bitmap_size, GFP_KERNEL);
571 if (!sched->active_tsg_bitmap)
572 goto fail_active;
573
574 sched->recent_tsg_bitmap = kzalloc(sched->bitmap_size, GFP_KERNEL);
575 if (!sched->recent_tsg_bitmap)
576 goto fail_recent;
577
578 init_waitqueue_head(&sched->readout_wq);
579 mutex_init(&sched->status_lock);
580 mutex_init(&sched->control_lock);
581 mutex_init(&sched->busy_lock);
582
583 sched->sw_ready = true;
584
585 return 0;
586
587fail_recent:
588 kfree(sched->active_tsg_bitmap);
589
590fail_active:
591 return -ENOMEM;
592}
593
594void gk20a_sched_ctrl_cleanup(struct gk20a *g)
595{
596 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
597
598 kfree(sched->active_tsg_bitmap);
599 kfree(sched->recent_tsg_bitmap);
600 sched->active_tsg_bitmap = NULL;
601 sched->recent_tsg_bitmap = NULL;
602 sched->sw_ready = false;
603}