summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2017-10-17 13:44:51 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-10-20 13:05:29 -0400
commitd7fe2fbacb06e95f921f27f99f457904a0c3a57a (patch)
tree4125b78771bfdb56b55b2681f10bfc4aff85dc47 /drivers/gpu/nvgpu/gk20a/sched_gk20a.c
parenta2c9c6ba0573bde2d4eada8a39d4e97f9749eef1 (diff)
gpu: nvgpu: Move sched to be Linux specific
Move sched parameter APIs to be Linux specific implementation. At the same time the sched_ctrl fields were moved to nvgpu_os_linux. JIRA NVGPU-259 Change-Id: I2397e2602e1c4783f2bebf3aec462634b7f86d4a Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1580649 GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/sched_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/sched_gk20a.c660
1 files changed, 0 insertions, 660 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/sched_gk20a.c b/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
deleted file mode 100644
index a77536af..00000000
--- a/drivers/gpu/nvgpu/gk20a/sched_gk20a.c
+++ /dev/null
@@ -1,660 +0,0 @@
1/*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <asm/barrier.h>
24#include <linux/wait.h>
25#include <linux/uaccess.h>
26#include <linux/poll.h>
27#include <uapi/linux/nvgpu.h>
28
29#include <nvgpu/kmem.h>
30#include <nvgpu/log.h>
31#include <nvgpu/bug.h>
32
33#include "ctxsw_trace_gk20a.h"
34#include "gk20a.h"
35#include "gr_gk20a.h"
36#include "sched_gk20a.h"
37#include "common/linux/os_linux.h"
38
39#include <nvgpu/hw/gk20a/hw_ctxsw_prog_gk20a.h>
40#include <nvgpu/hw/gk20a/hw_gr_gk20a.h>
41
42ssize_t gk20a_sched_dev_read(struct file *filp, char __user *buf,
43 size_t size, loff_t *off)
44{
45 struct gk20a_sched_ctrl *sched = filp->private_data;
46 struct nvgpu_sched_event_arg event = { 0 };
47 int err;
48
49 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched,
50 "filp=%p buf=%p size=%zu", filp, buf, size);
51
52 if (size < sizeof(event))
53 return -EINVAL;
54 size = sizeof(event);
55
56 nvgpu_mutex_acquire(&sched->status_lock);
57 while (!sched->status) {
58 nvgpu_mutex_release(&sched->status_lock);
59 if (filp->f_flags & O_NONBLOCK)
60 return -EAGAIN;
61 err = NVGPU_COND_WAIT_INTERRUPTIBLE(&sched->readout_wq,
62 sched->status, 0);
63 if (err)
64 return err;
65 nvgpu_mutex_acquire(&sched->status_lock);
66 }
67
68 event.reserved = 0;
69 event.status = sched->status;
70
71 if (copy_to_user(buf, &event, size)) {
72 nvgpu_mutex_release(&sched->status_lock);
73 return -EFAULT;
74 }
75
76 sched->status = 0;
77
78 nvgpu_mutex_release(&sched->status_lock);
79
80 return size;
81}
82
83unsigned int gk20a_sched_dev_poll(struct file *filp, poll_table *wait)
84{
85 struct gk20a_sched_ctrl *sched = filp->private_data;
86 unsigned int mask = 0;
87
88 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "");
89
90 nvgpu_mutex_acquire(&sched->status_lock);
91 poll_wait(filp, &sched->readout_wq.wq, wait);
92 if (sched->status)
93 mask |= POLLIN | POLLRDNORM;
94 nvgpu_mutex_release(&sched->status_lock);
95
96 return mask;
97}
98
99static int gk20a_sched_dev_ioctl_get_tsgs(struct gk20a_sched_ctrl *sched,
100 struct nvgpu_sched_get_tsgs_args *arg)
101{
102 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "size=%u buffer=%llx",
103 arg->size, arg->buffer);
104
105 if ((arg->size < sched->bitmap_size) || (!arg->buffer)) {
106 arg->size = sched->bitmap_size;
107 return -ENOSPC;
108 }
109
110 nvgpu_mutex_acquire(&sched->status_lock);
111 if (copy_to_user((void __user *)(uintptr_t)arg->buffer,
112 sched->active_tsg_bitmap, sched->bitmap_size)) {
113 nvgpu_mutex_release(&sched->status_lock);
114 return -EFAULT;
115 }
116 nvgpu_mutex_release(&sched->status_lock);
117
118 return 0;
119}
120
121static int gk20a_sched_dev_ioctl_get_recent_tsgs(struct gk20a_sched_ctrl *sched,
122 struct nvgpu_sched_get_tsgs_args *arg)
123{
124 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "size=%u buffer=%llx",
125 arg->size, arg->buffer);
126
127 if ((arg->size < sched->bitmap_size) || (!arg->buffer)) {
128 arg->size = sched->bitmap_size;
129 return -ENOSPC;
130 }
131
132 nvgpu_mutex_acquire(&sched->status_lock);
133 if (copy_to_user((void __user *)(uintptr_t)arg->buffer,
134 sched->recent_tsg_bitmap, sched->bitmap_size)) {
135 nvgpu_mutex_release(&sched->status_lock);
136 return -EFAULT;
137 }
138
139 memset(sched->recent_tsg_bitmap, 0, sched->bitmap_size);
140 nvgpu_mutex_release(&sched->status_lock);
141
142 return 0;
143}
144
145static int gk20a_sched_dev_ioctl_get_tsgs_by_pid(struct gk20a_sched_ctrl *sched,
146 struct nvgpu_sched_get_tsgs_by_pid_args *arg)
147{
148 struct fifo_gk20a *f = &sched->g->fifo;
149 struct tsg_gk20a *tsg;
150 u64 *bitmap;
151 unsigned int tsgid;
152 /* pid at user level corresponds to kernel tgid */
153 pid_t tgid = (pid_t)arg->pid;
154 int err = 0;
155
156 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "pid=%d size=%u buffer=%llx",
157 (pid_t)arg->pid, arg->size, arg->buffer);
158
159 if ((arg->size < sched->bitmap_size) || (!arg->buffer)) {
160 arg->size = sched->bitmap_size;
161 return -ENOSPC;
162 }
163
164 bitmap = nvgpu_kzalloc(sched->g, sched->bitmap_size);
165 if (!bitmap)
166 return -ENOMEM;
167
168 nvgpu_mutex_acquire(&sched->status_lock);
169 for (tsgid = 0; tsgid < f->num_channels; tsgid++) {
170 if (NVGPU_SCHED_ISSET(tsgid, sched->active_tsg_bitmap)) {
171 tsg = &f->tsg[tsgid];
172 if (tsg->tgid == tgid)
173 NVGPU_SCHED_SET(tsgid, bitmap);
174 }
175 }
176 nvgpu_mutex_release(&sched->status_lock);
177
178 if (copy_to_user((void __user *)(uintptr_t)arg->buffer,
179 bitmap, sched->bitmap_size))
180 err = -EFAULT;
181
182 nvgpu_kfree(sched->g, bitmap);
183
184 return err;
185}
186
187static int gk20a_sched_dev_ioctl_get_params(struct gk20a_sched_ctrl *sched,
188 struct nvgpu_sched_tsg_get_params_args *arg)
189{
190 struct gk20a *g = sched->g;
191 struct fifo_gk20a *f = &g->fifo;
192 struct tsg_gk20a *tsg;
193 u32 tsgid = arg->tsgid;
194
195 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsgid);
196
197 if (tsgid >= f->num_channels)
198 return -EINVAL;
199
200 tsg = &f->tsg[tsgid];
201 if (!nvgpu_ref_get_unless_zero(&tsg->refcount))
202 return -ENXIO;
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 nvgpu_ref_put(&tsg->refcount, gk20a_tsg_release);
219
220 return 0;
221}
222
223static int gk20a_sched_dev_ioctl_tsg_set_timeslice(
224 struct gk20a_sched_ctrl *sched,
225 struct nvgpu_sched_tsg_timeslice_args *arg)
226{
227 struct gk20a *g = sched->g;
228 struct fifo_gk20a *f = &g->fifo;
229 struct tsg_gk20a *tsg;
230 u32 tsgid = arg->tsgid;
231 int err;
232
233 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsgid);
234
235 if (tsgid >= f->num_channels)
236 return -EINVAL;
237
238 tsg = &f->tsg[tsgid];
239 if (!nvgpu_ref_get_unless_zero(&tsg->refcount))
240 return -ENXIO;
241
242 err = gk20a_busy(g);
243 if (err)
244 goto done;
245
246 err = gk20a_tsg_set_timeslice(tsg, arg->timeslice);
247
248 gk20a_idle(g);
249
250done:
251 nvgpu_ref_put(&tsg->refcount, gk20a_tsg_release);
252
253 return err;
254}
255
256static int gk20a_sched_dev_ioctl_tsg_set_runlist_interleave(
257 struct gk20a_sched_ctrl *sched,
258 struct nvgpu_sched_tsg_runlist_interleave_args *arg)
259{
260 struct gk20a *g = sched->g;
261 struct fifo_gk20a *f = &g->fifo;
262 struct tsg_gk20a *tsg;
263 u32 tsgid = arg->tsgid;
264 int err;
265
266 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsgid);
267
268 if (tsgid >= f->num_channels)
269 return -EINVAL;
270
271 tsg = &f->tsg[tsgid];
272 if (!nvgpu_ref_get_unless_zero(&tsg->refcount))
273 return -ENXIO;
274
275 err = gk20a_busy(g);
276 if (err)
277 goto done;
278
279 err = gk20a_tsg_set_runlist_interleave(tsg, arg->runlist_interleave);
280
281 gk20a_idle(g);
282
283done:
284 nvgpu_ref_put(&tsg->refcount, gk20a_tsg_release);
285
286 return err;
287}
288
289static int gk20a_sched_dev_ioctl_lock_control(struct gk20a_sched_ctrl *sched)
290{
291 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "");
292
293 nvgpu_mutex_acquire(&sched->control_lock);
294 sched->control_locked = true;
295 nvgpu_mutex_release(&sched->control_lock);
296 return 0;
297}
298
299static int gk20a_sched_dev_ioctl_unlock_control(struct gk20a_sched_ctrl *sched)
300{
301 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "");
302
303 nvgpu_mutex_acquire(&sched->control_lock);
304 sched->control_locked = false;
305 nvgpu_mutex_release(&sched->control_lock);
306 return 0;
307}
308
309static int gk20a_sched_dev_ioctl_get_api_version(struct gk20a_sched_ctrl *sched,
310 struct nvgpu_sched_api_version_args *args)
311{
312 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "");
313
314 args->version = NVGPU_SCHED_API_VERSION;
315 return 0;
316}
317
318static int gk20a_sched_dev_ioctl_get_tsg(struct gk20a_sched_ctrl *sched,
319 struct nvgpu_sched_tsg_refcount_args *arg)
320{
321 struct gk20a *g = sched->g;
322 struct fifo_gk20a *f = &g->fifo;
323 struct tsg_gk20a *tsg;
324 u32 tsgid = arg->tsgid;
325
326 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsgid);
327
328 if (tsgid >= f->num_channels)
329 return -EINVAL;
330
331 tsg = &f->tsg[tsgid];
332 if (!nvgpu_ref_get_unless_zero(&tsg->refcount))
333 return -ENXIO;
334
335 nvgpu_mutex_acquire(&sched->status_lock);
336 if (NVGPU_SCHED_ISSET(tsgid, sched->ref_tsg_bitmap)) {
337 nvgpu_warn(g, "tsgid=%d already referenced", tsgid);
338 /* unlock status_lock as gk20a_tsg_release locks it */
339 nvgpu_mutex_release(&sched->status_lock);
340 nvgpu_ref_put(&tsg->refcount, gk20a_tsg_release);
341 return -ENXIO;
342 }
343
344 /* keep reference on TSG, will be released on
345 * NVGPU_SCHED_IOCTL_PUT_TSG ioctl, or close
346 */
347 NVGPU_SCHED_SET(tsgid, sched->ref_tsg_bitmap);
348 nvgpu_mutex_release(&sched->status_lock);
349
350 return 0;
351}
352
353static int gk20a_sched_dev_ioctl_put_tsg(struct gk20a_sched_ctrl *sched,
354 struct nvgpu_sched_tsg_refcount_args *arg)
355{
356 struct gk20a *g = sched->g;
357 struct fifo_gk20a *f = &g->fifo;
358 struct tsg_gk20a *tsg;
359 u32 tsgid = arg->tsgid;
360
361 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsgid);
362
363 if (tsgid >= f->num_channels)
364 return -EINVAL;
365
366 nvgpu_mutex_acquire(&sched->status_lock);
367 if (!NVGPU_SCHED_ISSET(tsgid, sched->ref_tsg_bitmap)) {
368 nvgpu_mutex_release(&sched->status_lock);
369 nvgpu_warn(g, "tsgid=%d not previously referenced", tsgid);
370 return -ENXIO;
371 }
372 NVGPU_SCHED_CLR(tsgid, sched->ref_tsg_bitmap);
373 nvgpu_mutex_release(&sched->status_lock);
374
375 tsg = &f->tsg[tsgid];
376 nvgpu_ref_put(&tsg->refcount, gk20a_tsg_release);
377
378 return 0;
379}
380
381int gk20a_sched_dev_open(struct inode *inode, struct file *filp)
382{
383 struct nvgpu_os_linux *l = container_of(inode->i_cdev,
384 struct nvgpu_os_linux, sched.cdev);
385 struct gk20a *g;
386 struct gk20a_sched_ctrl *sched;
387 int err = 0;
388
389 g = gk20a_get(&l->g);
390 if (!g)
391 return -ENODEV;
392 sched = &g->sched_ctrl;
393
394 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "g=%p", g);
395
396 if (!sched->sw_ready) {
397 err = gk20a_busy(g);
398 if (err)
399 goto free_ref;
400
401 gk20a_idle(g);
402 }
403
404 if (!nvgpu_mutex_tryacquire(&sched->busy_lock)) {
405 err = -EBUSY;
406 goto free_ref;
407 }
408
409 memcpy(sched->recent_tsg_bitmap, sched->active_tsg_bitmap,
410 sched->bitmap_size);
411 memset(sched->ref_tsg_bitmap, 0, sched->bitmap_size);
412
413 filp->private_data = sched;
414 gk20a_dbg(gpu_dbg_sched, "filp=%p sched=%p", filp, sched);
415
416free_ref:
417 if (err)
418 gk20a_put(g);
419 return err;
420}
421
422long gk20a_sched_dev_ioctl(struct file *filp, unsigned int cmd,
423 unsigned long arg)
424{
425 struct gk20a_sched_ctrl *sched = filp->private_data;
426 struct gk20a *g = sched->g;
427 u8 buf[NVGPU_CTXSW_IOCTL_MAX_ARG_SIZE];
428 int err = 0;
429
430 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "nr=%d", _IOC_NR(cmd));
431
432 if ((_IOC_TYPE(cmd) != NVGPU_SCHED_IOCTL_MAGIC) ||
433 (_IOC_NR(cmd) == 0) ||
434 (_IOC_NR(cmd) > NVGPU_SCHED_IOCTL_LAST) ||
435 (_IOC_SIZE(cmd) > NVGPU_SCHED_IOCTL_MAX_ARG_SIZE))
436 return -EINVAL;
437
438 memset(buf, 0, sizeof(buf));
439 if (_IOC_DIR(cmd) & _IOC_WRITE) {
440 if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
441 return -EFAULT;
442 }
443
444 switch (cmd) {
445 case NVGPU_SCHED_IOCTL_GET_TSGS:
446 err = gk20a_sched_dev_ioctl_get_tsgs(sched,
447 (struct nvgpu_sched_get_tsgs_args *)buf);
448 break;
449 case NVGPU_SCHED_IOCTL_GET_RECENT_TSGS:
450 err = gk20a_sched_dev_ioctl_get_recent_tsgs(sched,
451 (struct nvgpu_sched_get_tsgs_args *)buf);
452 break;
453 case NVGPU_SCHED_IOCTL_GET_TSGS_BY_PID:
454 err = gk20a_sched_dev_ioctl_get_tsgs_by_pid(sched,
455 (struct nvgpu_sched_get_tsgs_by_pid_args *)buf);
456 break;
457 case NVGPU_SCHED_IOCTL_TSG_GET_PARAMS:
458 err = gk20a_sched_dev_ioctl_get_params(sched,
459 (struct nvgpu_sched_tsg_get_params_args *)buf);
460 break;
461 case NVGPU_SCHED_IOCTL_TSG_SET_TIMESLICE:
462 err = gk20a_sched_dev_ioctl_tsg_set_timeslice(sched,
463 (struct nvgpu_sched_tsg_timeslice_args *)buf);
464 break;
465 case NVGPU_SCHED_IOCTL_TSG_SET_RUNLIST_INTERLEAVE:
466 err = gk20a_sched_dev_ioctl_tsg_set_runlist_interleave(sched,
467 (struct nvgpu_sched_tsg_runlist_interleave_args *)buf);
468 break;
469 case NVGPU_SCHED_IOCTL_LOCK_CONTROL:
470 err = gk20a_sched_dev_ioctl_lock_control(sched);
471 break;
472 case NVGPU_SCHED_IOCTL_UNLOCK_CONTROL:
473 err = gk20a_sched_dev_ioctl_unlock_control(sched);
474 break;
475 case NVGPU_SCHED_IOCTL_GET_API_VERSION:
476 err = gk20a_sched_dev_ioctl_get_api_version(sched,
477 (struct nvgpu_sched_api_version_args *)buf);
478 break;
479 case NVGPU_SCHED_IOCTL_GET_TSG:
480 err = gk20a_sched_dev_ioctl_get_tsg(sched,
481 (struct nvgpu_sched_tsg_refcount_args *)buf);
482 break;
483 case NVGPU_SCHED_IOCTL_PUT_TSG:
484 err = gk20a_sched_dev_ioctl_put_tsg(sched,
485 (struct nvgpu_sched_tsg_refcount_args *)buf);
486 break;
487 default:
488 nvgpu_log_info(g, "unrecognized gpu ioctl cmd: 0x%x", cmd);
489 err = -ENOTTY;
490 }
491
492 /* Some ioctls like NVGPU_SCHED_IOCTL_GET_TSGS might be called on
493 * purpose with NULL buffer and/or zero size to discover TSG bitmap
494 * size. We need to update user arguments in this case too, even
495 * if we return an error.
496 */
497 if ((!err || (err == -ENOSPC)) && (_IOC_DIR(cmd) & _IOC_READ)) {
498 if (copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd)))
499 err = -EFAULT;
500 }
501
502 return err;
503}
504
505int gk20a_sched_dev_release(struct inode *inode, struct file *filp)
506{
507 struct gk20a_sched_ctrl *sched = filp->private_data;
508 struct gk20a *g = sched->g;
509 struct fifo_gk20a *f = &g->fifo;
510 struct tsg_gk20a *tsg;
511 unsigned int tsgid;
512
513 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "sched: %p", sched);
514
515 /* release any reference to TSGs */
516 for (tsgid = 0; tsgid < f->num_channels; tsgid++) {
517 if (NVGPU_SCHED_ISSET(tsgid, sched->ref_tsg_bitmap)) {
518 tsg = &f->tsg[tsgid];
519 nvgpu_ref_put(&tsg->refcount, gk20a_tsg_release);
520 }
521 }
522
523 /* unlock control */
524 nvgpu_mutex_acquire(&sched->control_lock);
525 sched->control_locked = false;
526 nvgpu_mutex_release(&sched->control_lock);
527
528 nvgpu_mutex_release(&sched->busy_lock);
529 gk20a_put(g);
530 return 0;
531}
532
533void gk20a_sched_ctrl_tsg_added(struct gk20a *g, struct tsg_gk20a *tsg)
534{
535 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
536 int err;
537
538 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsg->tsgid);
539
540 if (!sched->sw_ready) {
541 err = gk20a_busy(g);
542 if (err) {
543 WARN_ON(err);
544 return;
545 }
546
547 gk20a_idle(g);
548 }
549
550 nvgpu_mutex_acquire(&sched->status_lock);
551 NVGPU_SCHED_SET(tsg->tsgid, sched->active_tsg_bitmap);
552 NVGPU_SCHED_SET(tsg->tsgid, sched->recent_tsg_bitmap);
553 sched->status |= NVGPU_SCHED_STATUS_TSG_OPEN;
554 nvgpu_mutex_release(&sched->status_lock);
555 nvgpu_cond_signal_interruptible(&sched->readout_wq);
556}
557
558void gk20a_sched_ctrl_tsg_removed(struct gk20a *g, struct tsg_gk20a *tsg)
559{
560 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
561
562 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "tsgid=%u", tsg->tsgid);
563
564 nvgpu_mutex_acquire(&sched->status_lock);
565 NVGPU_SCHED_CLR(tsg->tsgid, sched->active_tsg_bitmap);
566
567 /* clear recent_tsg_bitmap as well: if app manager did not
568 * notice that TSG was previously added, no need to notify it
569 * if the TSG has been released in the meantime. If the
570 * TSG gets reallocated, app manager will be notified as usual.
571 */
572 NVGPU_SCHED_CLR(tsg->tsgid, sched->recent_tsg_bitmap);
573
574 /* do not set event_pending, we only want to notify app manager
575 * when TSGs are added, so that it can apply sched params
576 */
577 nvgpu_mutex_release(&sched->status_lock);
578}
579
580int gk20a_sched_ctrl_init(struct gk20a *g)
581{
582 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
583 struct fifo_gk20a *f = &g->fifo;
584 int err;
585
586 if (sched->sw_ready)
587 return 0;
588
589 sched->g = g;
590 sched->bitmap_size = roundup(f->num_channels, 64) / 8;
591 sched->status = 0;
592
593 gk20a_dbg(gpu_dbg_fn | gpu_dbg_sched, "g=%p sched=%p size=%zu",
594 g, sched, sched->bitmap_size);
595
596 sched->active_tsg_bitmap = nvgpu_kzalloc(g, sched->bitmap_size);
597 if (!sched->active_tsg_bitmap)
598 return -ENOMEM;
599
600 sched->recent_tsg_bitmap = nvgpu_kzalloc(g, sched->bitmap_size);
601 if (!sched->recent_tsg_bitmap) {
602 err = -ENOMEM;
603 goto free_active;
604 }
605
606 sched->ref_tsg_bitmap = nvgpu_kzalloc(g, sched->bitmap_size);
607 if (!sched->ref_tsg_bitmap) {
608 err = -ENOMEM;
609 goto free_recent;
610 }
611
612 nvgpu_cond_init(&sched->readout_wq);
613
614 err = nvgpu_mutex_init(&sched->status_lock);
615 if (err)
616 goto free_ref;
617
618 err = nvgpu_mutex_init(&sched->control_lock);
619 if (err)
620 goto free_status_lock;
621
622 err = nvgpu_mutex_init(&sched->busy_lock);
623 if (err)
624 goto free_control_lock;
625
626 sched->sw_ready = true;
627
628 return 0;
629
630free_control_lock:
631 nvgpu_mutex_destroy(&sched->control_lock);
632free_status_lock:
633 nvgpu_mutex_destroy(&sched->status_lock);
634free_ref:
635 nvgpu_kfree(g, sched->ref_tsg_bitmap);
636free_recent:
637 nvgpu_kfree(g, sched->recent_tsg_bitmap);
638free_active:
639 nvgpu_kfree(g, sched->active_tsg_bitmap);
640
641 return err;
642}
643
644void gk20a_sched_ctrl_cleanup(struct gk20a *g)
645{
646 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
647
648 nvgpu_kfree(g, sched->active_tsg_bitmap);
649 nvgpu_kfree(g, sched->recent_tsg_bitmap);
650 nvgpu_kfree(g, sched->ref_tsg_bitmap);
651 sched->active_tsg_bitmap = NULL;
652 sched->recent_tsg_bitmap = NULL;
653 sched->ref_tsg_bitmap = NULL;
654
655 nvgpu_mutex_destroy(&sched->status_lock);
656 nvgpu_mutex_destroy(&sched->control_lock);
657 nvgpu_mutex_destroy(&sched->busy_lock);
658
659 sched->sw_ready = false;
660}