summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
diff options
context:
space:
mode:
authorDeepak Nibade <dnibade@nvidia.com>2014-06-11 07:15:54 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:10:16 -0400
commite6eb4b59f6e8753c64133a4b86c6278ceef98e93 (patch)
tree9c718a8a033e559daf4fc90cee2bc4429c788c32 /drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
parent6f492c3834fe18fe3d00d0024b8178250bed7276 (diff)
gpu: nvgpu: add kernel APIs for TSG support
Add support to create/destroy TSGs using node "/dev/nvhost-tsg-gpu" Provide below IOCTLs to bind/unbind channels to/from TSGs : NVGPU_TSG_IOCTL_BIND_CHANNEL NVGPU_TSG_IOCTL_UNBIND_CHANNEL Bug 1470692 Change-Id: Iaf9f16a522379eb943906624548f8d28fc6d4486 Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Signed-off-by: Deepak Nibade <dnibade@nvidia.com> Reviewed-on: http://git-master/r/416610
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/tsg_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/tsg_gk20a.c261
1 files changed, 261 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
new file mode 100644
index 00000000..d9e10d30
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.c
@@ -0,0 +1,261 @@
1/*
2 * Copyright (c) 2014, 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 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/fs.h>
18#include <linux/file.h>
19#include <linux/cdev.h>
20#include <linux/uaccess.h>
21#include <linux/nvhost.h>
22#include <linux/nvhost_gpu_ioctl.h>
23#include <linux/anon_inodes.h>
24
25#include "gk20a.h"
26
27bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch)
28{
29 return !(ch->tsgid == NVGPU_INVALID_TSG_ID);
30}
31
32/*
33 * API to add channel to runnable list of TSG.
34 *
35 * After this call, a channel will be scheduled as TSG channel
36 * in runlist
37 */
38int gk20a_bind_runnable_channel_to_tsg(struct channel_gk20a *ch, int tsgid)
39{
40 struct gk20a *g = ch->g;
41 struct tsg_gk20a *tsg = NULL;
42
43 if (ch->tsgid != tsgid)
44 return -EINVAL;
45
46 tsg = &g->fifo.tsg[tsgid];
47
48 mutex_lock(&tsg->ch_list_lock);
49 list_add_tail(&ch->ch_entry, &tsg->ch_runnable_list);
50 tsg->num_runnable_channels += 1;
51 mutex_unlock(&tsg->ch_list_lock);
52
53 return 0;
54}
55
56int gk20a_unbind_channel_from_tsg(struct channel_gk20a *ch, int tsgid)
57{
58 struct gk20a *g = ch->g;
59 struct tsg_gk20a *tsg = NULL;
60
61 if (ch->tsgid != tsgid)
62 return -EINVAL;
63
64 tsg = &g->fifo.tsg[tsgid];
65
66 mutex_lock(&tsg->ch_list_lock);
67 list_del_init(&ch->ch_entry);
68 tsg->num_runnable_channels -= 1;
69 mutex_unlock(&tsg->ch_list_lock);
70
71 return 0;
72}
73
74/*
75 * API to mark channel as part of TSG
76 *
77 * Note that channel is not runnable when we bind it to TSG
78 */
79static int nvgpu_tsg_bind_channel(struct tsg_gk20a *tsg, int ch_fd)
80{
81 struct file *f = fget(ch_fd);
82 struct channel_gk20a *ch = f->private_data;
83
84 /* check if channel is already bound to some TSG */
85 if (gk20a_is_channel_marked_as_tsg(ch))
86 return -EINVAL;
87
88 ch->tsgid = tsg->tsgid;
89
90 gk20a_dbg(gpu_dbg_fn, "BIND tsg:%d channel:%d\n",
91 tsg->tsgid, ch->hw_chid);
92
93 fput(f);
94
95 return 0;
96}
97
98static int nvgpu_tsg_unbind_channel(struct tsg_gk20a *tsg, int ch_fd)
99{
100 /* We do not support explicitly unbinding channel from TSG.
101 * Channel will be unbounded from TSG when it is closed.
102 */
103 return 0;
104}
105
106int gk20a_init_tsg_support(struct gk20a *g, u32 tsgid)
107{
108 struct tsg_gk20a *tsg = NULL;
109
110 if (tsgid < 0 || tsgid >= g->fifo.num_channels)
111 return -EINVAL;
112
113 tsg = &g->fifo.tsg[tsgid];
114
115 tsg->in_use = false;
116 tsg->tsgid = tsgid;
117
118 INIT_LIST_HEAD(&tsg->ch_runnable_list);
119 mutex_init(&tsg->ch_list_lock);
120
121 return 0;
122}
123
124static void release_used_tsg(struct fifo_gk20a *f, struct tsg_gk20a *tsg)
125{
126 mutex_lock(&f->tsg_inuse_mutex);
127 f->tsg[tsg->tsgid].in_use = false;
128 mutex_unlock(&f->tsg_inuse_mutex);
129}
130
131static struct tsg_gk20a *acquire_unused_tsg(struct fifo_gk20a *f)
132{
133 struct tsg_gk20a *tsg = NULL;
134 int tsgid;
135
136 mutex_lock(&f->tsg_inuse_mutex);
137 for (tsgid = 0; tsgid < f->num_channels; tsgid++) {
138 if (!f->tsg[tsgid].in_use) {
139 f->tsg[tsgid].in_use = true;
140 tsg = &f->tsg[tsgid];
141 break;
142 }
143 }
144 mutex_unlock(&f->tsg_inuse_mutex);
145
146 return tsg;
147}
148
149int gk20a_tsg_dev_open(struct inode *inode, struct file *filp)
150{
151 struct tsg_gk20a *tsg;
152 struct gk20a *g;
153 struct device *dev;
154
155 g = container_of(inode->i_cdev,
156 struct gk20a, tsg.cdev);
157 dev = dev_from_gk20a(g);
158
159 gk20a_dbg(gpu_dbg_fn, "tsg: %s", dev_name(dev));
160
161 tsg = acquire_unused_tsg(&g->fifo);
162 if (!tsg)
163 return -ENOMEM;
164
165 tsg->g = g;
166 tsg->num_runnable_channels = 0;
167
168 filp->private_data = tsg;
169
170 gk20a_dbg(gpu_dbg_fn, "tsg opened %d\n", tsg->tsgid);
171
172 return 0;
173}
174
175int gk20a_tsg_dev_release(struct inode *inode, struct file *filp)
176{
177 struct tsg_gk20a *tsg = filp->private_data;
178 struct gk20a *g = container_of(inode->i_cdev,
179 struct gk20a, tsg.cdev);
180
181 if (tsg->num_runnable_channels) {
182 gk20a_err(dev_from_gk20a(g),
183 "Trying to free TSG %d with active channels %d\n",
184 tsg->tsgid, tsg->num_runnable_channels);
185 return -EBUSY;
186 }
187
188 release_used_tsg(&g->fifo, tsg);
189
190 gk20a_dbg(gpu_dbg_fn, "tsg released %d\n", tsg->tsgid);
191
192 return 0;
193}
194
195long gk20a_tsg_dev_ioctl(struct file *filp, unsigned int cmd,
196 unsigned long arg)
197{
198 struct tsg_gk20a *tsg = filp->private_data;
199 struct gk20a *g = tsg->g;
200 u8 __maybe_unused buf[NVGPU_TSG_IOCTL_MAX_ARG_SIZE];
201 int err = 0;
202
203 gk20a_dbg(gpu_dbg_fn, "");
204
205 if ((_IOC_TYPE(cmd) != NVGPU_TSG_IOCTL_MAGIC) ||
206 (_IOC_NR(cmd) == 0) ||
207 (_IOC_NR(cmd) > NVGPU_TSG_IOCTL_LAST))
208 return -EFAULT;
209
210 BUG_ON(_IOC_SIZE(cmd) > NVGPU_TSG_IOCTL_MAX_ARG_SIZE);
211
212 if (_IOC_DIR(cmd) & _IOC_WRITE) {
213 if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
214 return -EFAULT;
215 }
216
217 if (!g->gr.sw_ready) {
218 err = gk20a_busy(g->dev);
219 if (err)
220 return err;
221
222 gk20a_idle(g->dev);
223 }
224
225 switch (cmd) {
226 case NVGPU_TSG_IOCTL_BIND_CHANNEL:
227 {
228 int ch_fd = *(int *)buf;
229 if (ch_fd < 0) {
230 err = -EINVAL;
231 break;
232 }
233 err = nvgpu_tsg_bind_channel(tsg, ch_fd);
234 break;
235 }
236
237 case NVGPU_TSG_IOCTL_UNBIND_CHANNEL:
238 {
239 int ch_fd = *(int *)buf;
240 if (ch_fd < 0) {
241 err = -EINVAL;
242 break;
243 }
244 err = nvgpu_tsg_unbind_channel(tsg, ch_fd);
245 break;
246 }
247
248 default:
249 gk20a_err(dev_from_gk20a(g),
250 "unrecognized tsg gpu ioctl cmd: 0x%x",
251 cmd);
252 err = -ENOTTY;
253 break;
254 }
255
256 if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
257 err = copy_to_user((void __user *)arg,
258 buf, _IOC_SIZE(cmd));
259
260 return err;
261}