summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorThomas Fleury <tfleury@nvidia.com>2016-05-10 12:05:45 -0400
committerVijayakumar Subbu <vsubbu@nvidia.com>2016-07-19 02:12:51 -0400
commitc8ffe0fdecfa110a9f9beb1b7e0298d3c3c64cc2 (patch)
tree08054741c436ab6a783e710a9efa87fc7a0b71df /drivers/gpu
parent90988af81237d3b56c063b750c32efcbee9ab9cc (diff)
gpu: nvgpu: add sched control API
Added a dedicated device node to allow an app manager to control TSG scheduling parameters: - Get list of TSGs - Get list of recent TSGs - Get list of TSGs per pid - Get TSG current scheduling parameters - Set TSG timeslice - Set TSG runlist interleave Jira VFND-1586 Change-Id: I014c9d1534bce0eaea6c25ad114cf0cff317af79 Signed-off-by: Thomas Fleury <tfleury@nvidia.com> Reviewed-on: http://git-master/r/1160384 (cherry picked from commit 75ca739517cc7f7f76714b5f6a1a57c39b8cb38e) Reviewed-on: http://git-master/r/1167021 Reviewed-by: Richard Zhao <rizhao@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Alex Waterman <alexw@nvidia.com> Reviewed-by: Vijayakumar Subbu <vsubbu@nvidia.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/nvgpu/Makefile1
-rw-r--r--drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c11
-rw-r--r--drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c7
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.c32
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h9
-rw-r--r--drivers/gpu/nvgpu/gk20a/sched_gk20a.c603
-rw-r--r--drivers/gpu/nvgpu/gk20a/sched_gk20a.h52
-rw-r--r--drivers/gpu/nvgpu/gk20a/tsg_gk20a.c115
-rw-r--r--drivers/gpu/nvgpu/gk20a/tsg_gk20a.h4
-rw-r--r--drivers/gpu/nvgpu/vgpu/vgpu.c2
10 files changed, 801 insertions, 35 deletions
diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile
index 1bc2b9cc..0fdd2e28 100644
--- a/drivers/gpu/nvgpu/Makefile
+++ b/drivers/gpu/nvgpu/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_GK20A) := nvgpu.o
26 26
27nvgpu-y := \ 27nvgpu-y := \
28 gk20a/gk20a.o \ 28 gk20a/gk20a.o \
29 gk20a/sched_gk20a.o \
29 gk20a/as_gk20a.o \ 30 gk20a/as_gk20a.o \
30 gk20a/ctrl_gk20a.o \ 31 gk20a/ctrl_gk20a.o \
31 gk20a/ce2_gk20a.o \ 32 gk20a/ce2_gk20a.o \
diff --git a/drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c b/drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c
index d435bf79..d43c06be 100644
--- a/drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/ctxsw_trace_gk20a.c
@@ -677,22 +677,13 @@ void gk20a_ctxsw_trace_tsg_reset(struct gk20a *g, struct tsg_gk20a *tsg)
677 .vmid = 0, 677 .vmid = 0,
678 .tag = NVGPU_CTXSW_TAG_ENGINE_RESET, 678 .tag = NVGPU_CTXSW_TAG_ENGINE_RESET,
679 .context_id = 0, 679 .context_id = 0,
680 .pid = 0, 680 .pid = tsg->tgid,
681 }; 681 };
682 struct channel_gk20a *ch;
683 682
684 if (!g->ctxsw_trace) 683 if (!g->ctxsw_trace)
685 return; 684 return;
686 685
687 g->ops.read_ptimer(g, &entry.timestamp); 686 g->ops.read_ptimer(g, &entry.timestamp);
688 mutex_lock(&tsg->ch_list_lock);
689 if (!list_empty(&tsg->ch_list)) {
690 ch = list_entry(tsg->ch_list.next,
691 struct channel_gk20a, ch_entry);
692 entry.pid = ch->pid;
693 }
694 mutex_unlock(&tsg->ch_list_lock);
695
696 gk20a_ctxsw_trace_write(g, &entry); 687 gk20a_ctxsw_trace_write(g, &entry);
697 gk20a_ctxsw_trace_wake_up(g, 0); 688 gk20a_ctxsw_trace_wake_up(g, 0);
698#endif 689#endif
diff --git a/drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c b/drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c
index 69e2b409..15e645f2 100644
--- a/drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/fecs_trace_gk20a.c
@@ -596,6 +596,7 @@ static int gk20a_fecs_trace_bind_channel(struct gk20a *g,
596 struct gk20a_fecs_trace *trace = g->fecs_trace; 596 struct gk20a_fecs_trace *trace = g->fecs_trace;
597 struct mem_desc *mem = &ch_ctx->gr_ctx->mem; 597 struct mem_desc *mem = &ch_ctx->gr_ctx->mem;
598 u32 context_ptr = gk20a_fecs_trace_fecs_context_ptr(ch); 598 u32 context_ptr = gk20a_fecs_trace_fecs_context_ptr(ch);
599 pid_t pid;
599 600
600 gk20a_dbg(gpu_dbg_fn|gpu_dbg_ctxsw, 601 gk20a_dbg(gpu_dbg_fn|gpu_dbg_ctxsw,
601 "hw_chid=%d context_ptr=%x inst_block=%llx", 602 "hw_chid=%d context_ptr=%x inst_block=%llx",
@@ -630,7 +631,11 @@ static int gk20a_fecs_trace_bind_channel(struct gk20a *g,
630 GK20A_FECS_TRACE_NUM_RECORDS)); 631 GK20A_FECS_TRACE_NUM_RECORDS));
631 632
632 gk20a_mem_end(g, mem); 633 gk20a_mem_end(g, mem);
633 gk20a_fecs_trace_hash_add(g, context_ptr, ch->pid); 634 if (gk20a_is_channel_marked_as_tsg(ch))
635 pid = tsg_gk20a_from_ch(ch)->tgid;
636 else
637 pid = ch->pid;
638 gk20a_fecs_trace_hash_add(g, context_ptr, pid);
634 639
635 return 0; 640 return 0;
636} 641}
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c
index 9255c847..822cd3ff 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.c
@@ -246,6 +246,18 @@ static const struct file_operations gk20a_ctxsw_ops = {
246 .mmap = gk20a_ctxsw_dev_mmap, 246 .mmap = gk20a_ctxsw_dev_mmap,
247}; 247};
248 248
249static const struct file_operations gk20a_sched_ops = {
250 .owner = THIS_MODULE,
251 .release = gk20a_sched_dev_release,
252 .open = gk20a_sched_dev_open,
253#ifdef CONFIG_COMPAT
254 .compat_ioctl = gk20a_sched_dev_ioctl,
255#endif
256 .unlocked_ioctl = gk20a_sched_dev_ioctl,
257 .poll = gk20a_sched_dev_poll,
258 .read = gk20a_sched_dev_read,
259};
260
249static inline void sim_writel(struct gk20a *g, u32 r, u32 v) 261static inline void sim_writel(struct gk20a *g, u32 r, u32 v)
250{ 262{
251 writel(v, g->sim.regs+r); 263 writel(v, g->sim.regs+r);
@@ -965,6 +977,12 @@ int gk20a_pm_finalize_poweron(struct device *dev)
965 if (err) 977 if (err)
966 gk20a_warn(dev, "could not initialize ctxsw tracing"); 978 gk20a_warn(dev, "could not initialize ctxsw tracing");
967 979
980 err = gk20a_sched_ctrl_init(g);
981 if (err) {
982 gk20a_err(dev, "failed to init sched control");
983 goto done;
984 }
985
968 /* Restore the debug setting */ 986 /* Restore the debug setting */
969 g->ops.mm.set_debug_mode(g, g->mmu_debug_ctrl); 987 g->ops.mm.set_debug_mode(g, g->mmu_debug_ctrl);
970 988
@@ -1101,6 +1119,11 @@ void gk20a_user_deinit(struct device *dev, struct class *class)
1101 cdev_del(&g->ctxsw.cdev); 1119 cdev_del(&g->ctxsw.cdev);
1102 } 1120 }
1103 1121
1122 if (g->sched.node) {
1123 device_destroy(&nvgpu_class, g->sched.cdev.dev);
1124 cdev_del(&g->sched.cdev);
1125 }
1126
1104 if (g->cdev_region) 1127 if (g->cdev_region)
1105 unregister_chrdev_region(g->cdev_region, GK20A_NUM_CDEVS); 1128 unregister_chrdev_region(g->cdev_region, GK20A_NUM_CDEVS);
1106} 1129}
@@ -1170,6 +1193,12 @@ int gk20a_user_init(struct device *dev, const char *interface_name,
1170 goto fail; 1193 goto fail;
1171#endif 1194#endif
1172 1195
1196 err = gk20a_create_device(dev, devno++, interface_name, "-sched",
1197 &g->sched.cdev, &g->sched.node,
1198 &gk20a_sched_ops,
1199 class);
1200 if (err)
1201 goto fail;
1173 1202
1174 return 0; 1203 return 0;
1175fail: 1204fail:
@@ -1632,6 +1661,7 @@ static int gk20a_probe(struct platform_device *dev)
1632 gk20a_alloc_debugfs_init(dev); 1661 gk20a_alloc_debugfs_init(dev);
1633 gk20a_mm_debugfs_init(&dev->dev); 1662 gk20a_mm_debugfs_init(&dev->dev);
1634 gk20a_fifo_debugfs_init(&dev->dev); 1663 gk20a_fifo_debugfs_init(&dev->dev);
1664 gk20a_sched_debugfs_init(&dev->dev);
1635#endif 1665#endif
1636 1666
1637 gk20a_init_gr(gk20a); 1667 gk20a_init_gr(gk20a);
@@ -1655,6 +1685,8 @@ static int __exit gk20a_remove(struct platform_device *pdev)
1655 1685
1656 gk20a_ctxsw_trace_cleanup(g); 1686 gk20a_ctxsw_trace_cleanup(g);
1657 1687
1688 gk20a_sched_ctrl_cleanup(g);
1689
1658 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ)) 1690 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ))
1659 gk20a_scale_exit(dev); 1691 gk20a_scale_exit(dev);
1660 1692
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index c5da68cc..8aa8689b 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -52,6 +52,7 @@ struct acr_desc;
52#include "acr.h" 52#include "acr.h"
53#include "cde_gk20a.h" 53#include "cde_gk20a.h"
54#include "debug_gk20a.h" 54#include "debug_gk20a.h"
55#include "sched_gk20a.h"
55 56
56/* PTIMER_REF_FREQ_HZ corresponds to a period of 32 nanoseconds. 57/* PTIMER_REF_FREQ_HZ corresponds to a period of 32 nanoseconds.
57 32 ns is the resolution of ptimer. */ 58 32 ns is the resolution of ptimer. */
@@ -817,6 +818,11 @@ struct gk20a {
817 struct device *node; 818 struct device *node;
818 } ctxsw; 819 } ctxsw;
819 820
821 struct {
822 struct cdev cdev;
823 struct device *node;
824 } sched;
825
820 struct mutex client_lock; 826 struct mutex client_lock;
821 int client_refcount; /* open channels and ctrl nodes */ 827 int client_refcount; /* open channels and ctrl nodes */
822 828
@@ -847,6 +853,8 @@ struct gk20a {
847 struct gk20a_ctxsw_trace *ctxsw_trace; 853 struct gk20a_ctxsw_trace *ctxsw_trace;
848 struct gk20a_fecs_trace *fecs_trace; 854 struct gk20a_fecs_trace *fecs_trace;
849 855
856 struct gk20a_sched_ctrl sched_ctrl;
857
850 struct device_dma_parameters dma_parms; 858 struct device_dma_parameters dma_parms;
851 859
852 struct gk20a_cde_app cde_app; 860 struct gk20a_cde_app cde_app;
@@ -925,6 +933,7 @@ enum gk20a_dbg_categories {
925 gpu_dbg_cde = BIT(10), /* cde info messages */ 933 gpu_dbg_cde = BIT(10), /* cde info messages */
926 gpu_dbg_cde_ctx = BIT(11), /* cde context usage messages */ 934 gpu_dbg_cde_ctx = BIT(11), /* cde context usage messages */
927 gpu_dbg_ctxsw = BIT(12), /* ctxsw tracing */ 935 gpu_dbg_ctxsw = BIT(12), /* ctxsw tracing */
936 gpu_dbg_sched = BIT(13), /* sched control tracing */
928 gpu_dbg_mem = BIT(31), /* memory accesses, very verbose */ 937 gpu_dbg_mem = BIT(31), /* memory accesses, very verbose */
929}; 938};
930 939
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}
diff --git a/drivers/gpu/nvgpu/gk20a/sched_gk20a.h b/drivers/gpu/nvgpu/gk20a/sched_gk20a.h
new file mode 100644
index 00000000..8f533056
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/sched_gk20a.h
@@ -0,0 +1,52 @@
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#ifndef __SCHED_GK20A_H
15#define __SCHED_GK20A_H
16
17struct gk20a;
18struct gpu_ops;
19struct tsg_gk20a;
20
21struct gk20a_sched_ctrl {
22 struct gk20a *g;
23
24 struct mutex control_lock;
25 bool control_locked;
26 bool sw_ready;
27 struct mutex status_lock;
28 struct mutex busy_lock;
29
30 u64 status;
31
32 size_t bitmap_size;
33 u64 *active_tsg_bitmap;
34 u64 *recent_tsg_bitmap;
35
36 wait_queue_head_t readout_wq;
37};
38
39int gk20a_sched_dev_release(struct inode *inode, struct file *filp);
40int gk20a_sched_dev_open(struct inode *inode, struct file *filp);
41long gk20a_sched_dev_ioctl(struct file *, unsigned int, unsigned long);
42ssize_t gk20a_sched_dev_read(struct file *, char __user *, size_t, loff_t *);
43unsigned int gk20a_sched_dev_poll(struct file *, struct poll_table_struct *);
44
45void gk20a_sched_ctrl_tsg_added(struct gk20a *, struct tsg_gk20a *);
46void gk20a_sched_ctrl_tsg_removed(struct gk20a *, struct tsg_gk20a *);
47int gk20a_sched_ctrl_init(struct gk20a *);
48
49void gk20a_sched_debugfs_init(struct device *dev);
50void gk20a_sched_ctrl_cleanup(struct gk20a *g);
51
52#endif /* __SCHED_GK20A_H */
diff --git a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
index 0fa93da9..af8f0f7b 100644
--- a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
@@ -338,7 +338,7 @@ static int gk20a_tsg_event_id_ctrl(struct gk20a *g, struct tsg_gk20a *tsg,
338 return err; 338 return err;
339} 339}
340 340
341static int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level) 341int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level)
342{ 342{
343 struct gk20a *g = tsg->g; 343 struct gk20a *g = tsg->g;
344 int ret; 344 int ret;
@@ -349,6 +349,8 @@ static int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level)
349 case NVGPU_RUNLIST_INTERLEAVE_LEVEL_HIGH: 349 case NVGPU_RUNLIST_INTERLEAVE_LEVEL_HIGH:
350 ret = g->ops.fifo.set_runlist_interleave(g, tsg->tsgid, 350 ret = g->ops.fifo.set_runlist_interleave(g, tsg->tsgid,
351 true, 0, level); 351 true, 0, level);
352 if (!ret)
353 tsg->interleave_level = level;
352 break; 354 break;
353 default: 355 default:
354 ret = -EINVAL; 356 ret = -EINVAL;
@@ -358,7 +360,7 @@ static int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level)
358 return ret ? ret : g->ops.fifo.update_runlist(g, tsg->runlist_id, ~0, true, true); 360 return ret ? ret : g->ops.fifo.update_runlist(g, tsg->runlist_id, ~0, true, true);
359} 361}
360 362
361static int gk20a_tsg_set_timeslice(struct tsg_gk20a *tsg, u32 timeslice) 363int gk20a_tsg_set_timeslice(struct tsg_gk20a *tsg, u32 timeslice)
362{ 364{
363 struct gk20a *g = tsg->g; 365 struct gk20a *g = tsg->g;
364 366
@@ -369,6 +371,8 @@ static int gk20a_tsg_set_timeslice(struct tsg_gk20a *tsg, u32 timeslice)
369 gk20a_channel_get_timescale_from_timeslice(g, timeslice, 371 gk20a_channel_get_timescale_from_timeslice(g, timeslice,
370 &tsg->timeslice_timeout, &tsg->timeslice_scale); 372 &tsg->timeslice_timeout, &tsg->timeslice_scale);
371 373
374 tsg->timeslice_us = timeslice;
375
372 return g->ops.fifo.update_runlist(g, tsg->runlist_id, ~0, true, true); 376 return g->ops.fifo.update_runlist(g, tsg->runlist_id, ~0, true, true);
373} 377}
374 378
@@ -421,11 +425,14 @@ int gk20a_tsg_open(struct gk20a *g, struct file *filp)
421 tsg->timeslice_timeout = 0; 425 tsg->timeslice_timeout = 0;
422 tsg->timeslice_scale = 0; 426 tsg->timeslice_scale = 0;
423 tsg->runlist_id = ~0; 427 tsg->runlist_id = ~0;
428 tsg->tgid = current->tgid;
424 429
425 filp->private_data = tsg; 430 filp->private_data = tsg;
426 431
427 gk20a_dbg(gpu_dbg_fn, "tsg opened %d\n", tsg->tsgid); 432 gk20a_dbg(gpu_dbg_fn, "tsg opened %d\n", tsg->tsgid);
428 433
434 gk20a_sched_ctrl_tsg_added(g, tsg);
435
429 return 0; 436 return 0;
430} 437}
431 438
@@ -456,6 +463,7 @@ static void gk20a_tsg_release(struct kref *ref)
456 tsg->vm = NULL; 463 tsg->vm = NULL;
457 } 464 }
458 465
466 gk20a_sched_ctrl_tsg_removed(g, tsg);
459 release_used_tsg(&g->fifo, tsg); 467 release_used_tsg(&g->fifo, tsg);
460 468
461 tsg->runlist_id = ~0; 469 tsg->runlist_id = ~0;
@@ -470,6 +478,81 @@ int gk20a_tsg_dev_release(struct inode *inode, struct file *filp)
470 return 0; 478 return 0;
471} 479}
472 480
481static int gk20a_tsg_ioctl_set_priority(struct gk20a *g,
482 struct tsg_gk20a *tsg, struct nvgpu_set_priority_args *arg)
483{
484 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
485 int err;
486
487 mutex_lock(&sched->control_lock);
488 if (sched->control_locked) {
489 err = -EPERM;
490 goto done;
491 }
492
493 err = gk20a_busy(g->dev);
494 if (err) {
495 gk20a_err(dev_from_gk20a(g), "failed to power on gpu");
496 goto done;
497 }
498
499 err = gk20a_tsg_set_priority(g, tsg, arg->priority);
500
501 gk20a_idle(g->dev);
502done:
503 mutex_unlock(&sched->control_lock);
504 return err;
505}
506
507static int gk20a_tsg_ioctl_set_runlist_interleave(struct gk20a *g,
508 struct tsg_gk20a *tsg, struct nvgpu_runlist_interleave_args *arg)
509{
510 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
511 int err;
512
513 mutex_lock(&sched->control_lock);
514 if (sched->control_locked) {
515 err = -EPERM;
516 goto done;
517 }
518 err = gk20a_busy(g->dev);
519 if (err) {
520 gk20a_err(dev_from_gk20a(g), "failed to power on gpu");
521 goto done;
522 }
523
524 err = gk20a_tsg_set_runlist_interleave(tsg, arg->level);
525
526 gk20a_idle(g->dev);
527done:
528 mutex_unlock(&sched->control_lock);
529 return err;
530}
531
532static int gk20a_tsg_ioctl_set_timeslice(struct gk20a *g,
533 struct tsg_gk20a *tsg, struct nvgpu_timeslice_args *arg)
534{
535 struct gk20a_sched_ctrl *sched = &g->sched_ctrl;
536 int err;
537
538 mutex_lock(&sched->control_lock);
539 if (sched->control_locked) {
540 err = -EPERM;
541 goto done;
542 }
543 err = gk20a_busy(g->dev);
544 if (err) {
545 gk20a_err(dev_from_gk20a(g), "failed to power on gpu");
546 goto done;
547 }
548 err = gk20a_tsg_set_timeslice(tsg, arg->timeslice_us);
549 gk20a_idle(g->dev);
550done:
551 mutex_unlock(&sched->control_lock);
552 return err;
553}
554
555
473long gk20a_tsg_dev_ioctl(struct file *filp, unsigned int cmd, 556long gk20a_tsg_dev_ioctl(struct file *filp, unsigned int cmd,
474 unsigned long arg) 557 unsigned long arg)
475{ 558{
@@ -561,8 +644,8 @@ long gk20a_tsg_dev_ioctl(struct file *filp, unsigned int cmd,
561 644
562 case NVGPU_IOCTL_TSG_SET_PRIORITY: 645 case NVGPU_IOCTL_TSG_SET_PRIORITY:
563 { 646 {
564 err = gk20a_tsg_set_priority(g, tsg, 647 err = gk20a_tsg_ioctl_set_priority(g, tsg,
565 ((struct nvgpu_set_priority_args *)buf)->priority); 648 (struct nvgpu_set_priority_args *)buf);
566 break; 649 break;
567 } 650 }
568 651
@@ -574,30 +657,14 @@ long gk20a_tsg_dev_ioctl(struct file *filp, unsigned int cmd,
574 } 657 }
575 658
576 case NVGPU_IOCTL_TSG_SET_RUNLIST_INTERLEAVE: 659 case NVGPU_IOCTL_TSG_SET_RUNLIST_INTERLEAVE:
577 { 660 err = gk20a_tsg_ioctl_set_runlist_interleave(g, tsg,
578 err = gk20a_busy(g->dev); 661 (struct nvgpu_runlist_interleave_args *)buf);
579 if (err) {
580 gk20a_err(dev_from_gk20a(g),
581 "failed to host gk20a for ioctl cmd: 0x%x", cmd);
582 return err;
583 }
584 err = gk20a_tsg_set_runlist_interleave(tsg,
585 ((struct nvgpu_runlist_interleave_args *)buf)->level);
586 gk20a_idle(g->dev);
587 break; 662 break;
588 }
589 663
590 case NVGPU_IOCTL_TSG_SET_TIMESLICE: 664 case NVGPU_IOCTL_TSG_SET_TIMESLICE:
591 { 665 {
592 err = gk20a_busy(g->dev); 666 err = gk20a_tsg_ioctl_set_timeslice(g, tsg,
593 if (err) { 667 (struct nvgpu_timeslice_args *)buf);
594 gk20a_err(dev_from_gk20a(g),
595 "failed to host gk20a for ioctl cmd: 0x%x", cmd);
596 return err;
597 }
598 err = g->ops.fifo.tsg_set_timeslice(tsg,
599 ((struct nvgpu_timeslice_args *)buf)->timeslice_us);
600 gk20a_idle(g->dev);
601 break; 668 break;
602 } 669 }
603 670
diff --git a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h
index 57414690..2819dd1c 100644
--- a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h
@@ -56,6 +56,7 @@ struct tsg_gk20a {
56 struct mutex event_id_list_lock; 56 struct mutex event_id_list_lock;
57 57
58 u32 runlist_id; 58 u32 runlist_id;
59 pid_t tgid;
59}; 60};
60 61
61int gk20a_enable_tsg(struct tsg_gk20a *tsg); 62int gk20a_enable_tsg(struct tsg_gk20a *tsg);
@@ -66,5 +67,8 @@ int gk20a_tsg_unbind_channel(struct channel_gk20a *ch);
66 67
67void gk20a_tsg_event_id_post_event(struct tsg_gk20a *tsg, 68void gk20a_tsg_event_id_post_event(struct tsg_gk20a *tsg,
68 int event_id); 69 int event_id);
70int gk20a_tsg_set_runlist_interleave(struct tsg_gk20a *tsg, u32 level);
71int gk20a_tsg_set_timeslice(struct tsg_gk20a *tsg, u32 timeslice);
72
69 73
70#endif /* __TSG_GK20A_H_ */ 74#endif /* __TSG_GK20A_H_ */
diff --git a/drivers/gpu/nvgpu/vgpu/vgpu.c b/drivers/gpu/nvgpu/vgpu/vgpu.c
index dc7c4320..a00d52de 100644
--- a/drivers/gpu/nvgpu/vgpu/vgpu.c
+++ b/drivers/gpu/nvgpu/vgpu/vgpu.c
@@ -427,6 +427,7 @@ int vgpu_pm_finalize_poweron(struct device *dev)
427 } 427 }
428 428
429 gk20a_ctxsw_trace_init(g); 429 gk20a_ctxsw_trace_init(g);
430 gk20a_sched_ctrl_init(g);
430 gk20a_channel_resume(g); 431 gk20a_channel_resume(g);
431 432
432done: 433done:
@@ -600,6 +601,7 @@ int vgpu_remove(struct platform_device *pdev)
600 g->remove_support(dev); 601 g->remove_support(dev);
601 602
602 vgpu_comm_deinit(); 603 vgpu_comm_deinit();
604 gk20a_sched_ctrl_cleanup(g);
603 gk20a_user_deinit(dev, &nvgpu_class); 605 gk20a_user_deinit(dev, &nvgpu_class);
604 gk20a_get_platform(dev)->g = NULL; 606 gk20a_get_platform(dev)->g = NULL;
605 kfree(g); 607 kfree(g);