summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu
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
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')
-rw-r--r--drivers/gpu/nvgpu/gk20a/Makefile3
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c3
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.h3
-rw-r--r--drivers/gpu/nvgpu/gk20a/fifo_gk20a.c4
-rw-r--r--drivers/gpu/nvgpu/gk20a/fifo_gk20a.h4
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.c23
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h6
-rw-r--r--drivers/gpu/nvgpu/gk20a/tsg_gk20a.c261
-rw-r--r--drivers/gpu/nvgpu/gk20a/tsg_gk20a.h44
9 files changed, 349 insertions, 2 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/Makefile b/drivers/gpu/nvgpu/gk20a/Makefile
index a0fc9f60..d234db50 100644
--- a/drivers/gpu/nvgpu/gk20a/Makefile
+++ b/drivers/gpu/nvgpu/gk20a/Makefile
@@ -33,7 +33,8 @@ nvgpu-y := \
33 hal.o \ 33 hal.o \
34 hal_gk20a.o \ 34 hal_gk20a.o \
35 gk20a_allocator.o \ 35 gk20a_allocator.o \
36 platform_gk20a_generic.o 36 platform_gk20a_generic.o \
37 tsg_gk20a.o
37nvgpu-$(CONFIG_TEGRA_GK20A) += platform_gk20a_tegra.o 38nvgpu-$(CONFIG_TEGRA_GK20A) += platform_gk20a_tegra.o
38nvgpu-$(CONFIG_SYNC) += sync_gk20a.o 39nvgpu-$(CONFIG_SYNC) += sync_gk20a.o
39 40
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index 486e815c..ef7195a7 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -747,6 +747,9 @@ static struct channel_gk20a *gk20a_open_new_channel(struct gk20a *g)
747 g->ops.fifo.bind_channel(ch); 747 g->ops.fifo.bind_channel(ch);
748 ch->pid = current->pid; 748 ch->pid = current->pid;
749 749
750 /* By default, channel is regular (non-TSG) channel */
751 ch->tsgid = NVGPU_INVALID_TSG_ID;
752
750 /* reset timeout counter and update timestamp */ 753 /* reset timeout counter and update timestamp */
751 ch->timeout_accumulated_ms = 0; 754 ch->timeout_accumulated_ms = 0;
752 ch->timeout_gpfifo_get = 0; 755 ch->timeout_gpfifo_get = 0;
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
index 36697e02..4d236a70 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
@@ -83,6 +83,9 @@ struct channel_gk20a {
83 bool vpr; 83 bool vpr;
84 pid_t pid; 84 pid_t pid;
85 85
86 int tsgid;
87 struct list_head ch_entry; /* channel's entry in TSG */
88
86 struct list_head jobs; 89 struct list_head jobs;
87 struct mutex jobs_lock; 90 struct mutex jobs_lock;
88 struct mutex submit_lock; 91 struct mutex submit_lock;
diff --git a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c
index 3c0611e6..e9febb77 100644
--- a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.c
@@ -538,6 +538,8 @@ static int gk20a_init_fifo_setup_sw(struct gk20a *g)
538 538
539 f->channel = kzalloc(f->num_channels * sizeof(*f->channel), 539 f->channel = kzalloc(f->num_channels * sizeof(*f->channel),
540 GFP_KERNEL); 540 GFP_KERNEL);
541 f->tsg = kzalloc(f->num_channels * sizeof(*f->tsg),
542 GFP_KERNEL);
541 f->pbdma_map = kzalloc(f->num_pbdma * sizeof(*f->pbdma_map), 543 f->pbdma_map = kzalloc(f->num_pbdma * sizeof(*f->pbdma_map),
542 GFP_KERNEL); 544 GFP_KERNEL);
543 f->engine_info = kzalloc(f->max_engines * sizeof(*f->engine_info), 545 f->engine_info = kzalloc(f->max_engines * sizeof(*f->engine_info),
@@ -566,8 +568,10 @@ static int gk20a_init_fifo_setup_sw(struct gk20a *g)
566 f->userd.gpu_va + chid * f->userd_entry_size; 568 f->userd.gpu_va + chid * f->userd_entry_size;
567 569
568 gk20a_init_channel_support(g, chid); 570 gk20a_init_channel_support(g, chid);
571 gk20a_init_tsg_support(g, chid);
569 } 572 }
570 mutex_init(&f->ch_inuse_mutex); 573 mutex_init(&f->ch_inuse_mutex);
574 mutex_init(&f->tsg_inuse_mutex);
571 575
572 f->remove_support = gk20a_remove_fifo_support; 576 f->remove_support = gk20a_remove_fifo_support;
573 577
diff --git a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h
index 8a4e0a8f..f94fce02 100644
--- a/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/fifo_gk20a.h
@@ -22,6 +22,7 @@
22#define __FIFO_GK20A_H__ 22#define __FIFO_GK20A_H__
23 23
24#include "channel_gk20a.h" 24#include "channel_gk20a.h"
25#include "tsg_gk20a.h"
25 26
26#define MAX_RUNLIST_BUFFERS 2 27#define MAX_RUNLIST_BUFFERS 2
27 28
@@ -111,6 +112,9 @@ struct fifo_gk20a {
111 struct channel_gk20a *channel; 112 struct channel_gk20a *channel;
112 struct mutex ch_inuse_mutex; /* protect unused chid look up */ 113 struct mutex ch_inuse_mutex; /* protect unused chid look up */
113 114
115 struct tsg_gk20a *tsg;
116 struct mutex tsg_inuse_mutex;
117
114 void (*remove_support)(struct fifo_gk20a *); 118 void (*remove_support)(struct fifo_gk20a *);
115 bool sw_ready; 119 bool sw_ready;
116 struct { 120 struct {
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c
index c1150bac..4c6566a6 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.c
@@ -69,7 +69,7 @@
69/* TODO: Change to e.g. "nvidia-gpu%s" once we have symlinks in place. */ 69/* TODO: Change to e.g. "nvidia-gpu%s" once we have symlinks in place. */
70#define INTERFACE_NAME "nvhost%s-gpu" 70#define INTERFACE_NAME "nvhost%s-gpu"
71 71
72#define GK20A_NUM_CDEVS 5 72#define GK20A_NUM_CDEVS 6
73 73
74#if defined(GK20A_DEBUG) 74#if defined(GK20A_DEBUG)
75u32 gk20a_dbg_mask = GK20A_DEFAULT_DBG_MASK; 75u32 gk20a_dbg_mask = GK20A_DEFAULT_DBG_MASK;
@@ -144,6 +144,16 @@ static const struct file_operations gk20a_prof_ops = {
144#endif 144#endif
145}; 145};
146 146
147static const struct file_operations gk20a_tsg_ops = {
148 .owner = THIS_MODULE,
149 .release = gk20a_tsg_dev_release,
150 .open = gk20a_tsg_dev_open,
151#ifdef CONFIG_COMPAT
152 .compat_ioctl = gk20a_tsg_dev_ioctl,
153#endif
154 .unlocked_ioctl = gk20a_tsg_dev_ioctl,
155};
156
147static inline void sim_writel(struct gk20a *g, u32 r, u32 v) 157static inline void sim_writel(struct gk20a *g, u32 r, u32 v)
148{ 158{
149 writel(v, g->sim.regs+r); 159 writel(v, g->sim.regs+r);
@@ -1061,6 +1071,11 @@ static void gk20a_user_deinit(struct platform_device *dev)
1061 cdev_del(&g->prof.cdev); 1071 cdev_del(&g->prof.cdev);
1062 } 1072 }
1063 1073
1074 if (g->tsg.node) {
1075 device_destroy(g->class, g->tsg.cdev.dev);
1076 cdev_del(&g->tsg.cdev);
1077 }
1078
1064 if (g->cdev_region) 1079 if (g->cdev_region)
1065 unregister_chrdev_region(g->cdev_region, GK20A_NUM_CDEVS); 1080 unregister_chrdev_region(g->cdev_region, GK20A_NUM_CDEVS);
1066 1081
@@ -1120,6 +1135,12 @@ static int gk20a_user_init(struct platform_device *dev)
1120 if (err) 1135 if (err)
1121 goto fail; 1136 goto fail;
1122 1137
1138 err = gk20a_create_device(dev, devno++, "-tsg",
1139 &g->tsg.cdev, &g->tsg.node,
1140 &gk20a_tsg_ops);
1141 if (err)
1142 goto fail;
1143
1123 return 0; 1144 return 0;
1124fail: 1145fail:
1125 gk20a_user_deinit(dev); 1146 gk20a_user_deinit(dev);
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index 9769ac99..60b9b80e 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -40,6 +40,7 @@ struct acr_gm20b;
40#include "as_gk20a.h" 40#include "as_gk20a.h"
41#include "clk_gk20a.h" 41#include "clk_gk20a.h"
42#include "fifo_gk20a.h" 42#include "fifo_gk20a.h"
43#include "tsg_gk20a.h"
43#include "gr_gk20a.h" 44#include "gr_gk20a.h"
44#include "sim_gk20a.h" 45#include "sim_gk20a.h"
45#include "pmu_gk20a.h" 46#include "pmu_gk20a.h"
@@ -308,6 +309,11 @@ struct gk20a {
308 struct device *node; 309 struct device *node;
309 } prof; 310 } prof;
310 311
312 struct {
313 struct cdev cdev;
314 struct device *node;
315 } tsg;
316
311 struct mutex client_lock; 317 struct mutex client_lock;
312 int client_refcount; /* open channels and ctrl nodes */ 318 int client_refcount; /* open channels and ctrl nodes */
313 319
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}
diff --git a/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h
new file mode 100644
index 00000000..2530a4bd
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/tsg_gk20a.h
@@ -0,0 +1,44 @@
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#ifndef __TSG_GK20A_H_
17#define __TSG_GK20A_H_
18
19#define NVGPU_INVALID_TSG_ID (-1)
20
21bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch);
22
23int gk20a_tsg_dev_release(struct inode *inode, struct file *filp);
24int gk20a_tsg_dev_open(struct inode *inode, struct file *filp);
25long gk20a_tsg_dev_ioctl(struct file *filp,
26 unsigned int cmd, unsigned long arg);
27
28int gk20a_init_tsg_support(struct gk20a *g, u32 tsgid);
29
30int gk20a_bind_runnable_channel_to_tsg(struct channel_gk20a *ch, int tsgid);
31int gk20a_unbind_channel_from_tsg(struct channel_gk20a *ch, int tsgid);
32
33struct tsg_gk20a {
34 struct gk20a *g;
35
36 bool in_use;
37 int tsgid;
38
39 struct list_head ch_runnable_list;
40 int num_runnable_channels;
41 struct mutex ch_list_lock;
42};
43
44#endif /* __TSG_GK20A_H_ */