diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2014-06-11 07:15:54 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:10:16 -0400 |
commit | e6eb4b59f6e8753c64133a4b86c6278ceef98e93 (patch) | |
tree | 9c718a8a033e559daf4fc90cee2bc4429c788c32 /drivers/gpu | |
parent | 6f492c3834fe18fe3d00d0024b8178250bed7276 (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')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 3 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 3 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/fifo_gk20a.c | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/fifo_gk20a.h | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 23 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 6 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/tsg_gk20a.c | 261 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/tsg_gk20a.h | 44 |
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 | ||
37 | nvgpu-$(CONFIG_TEGRA_GK20A) += platform_gk20a_tegra.o | 38 | nvgpu-$(CONFIG_TEGRA_GK20A) += platform_gk20a_tegra.o |
38 | nvgpu-$(CONFIG_SYNC) += sync_gk20a.o | 39 | nvgpu-$(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) |
75 | u32 gk20a_dbg_mask = GK20A_DEFAULT_DBG_MASK; | 75 | u32 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 | ||
147 | static 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 | |||
147 | static inline void sim_writel(struct gk20a *g, u32 r, u32 v) | 157 | static 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; |
1124 | fail: | 1145 | fail: |
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 | |||
27 | bool 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 | */ | ||
38 | int 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 | |||
56 | int 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 | */ | ||
79 | static 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 | |||
98 | static 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 | |||
106 | int 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 | |||
124 | static 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 | |||
131 | static 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 | |||
149 | int 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 | |||
175 | int 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 | |||
195 | long 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 | |||
21 | bool gk20a_is_channel_marked_as_tsg(struct channel_gk20a *ch); | ||
22 | |||
23 | int gk20a_tsg_dev_release(struct inode *inode, struct file *filp); | ||
24 | int gk20a_tsg_dev_open(struct inode *inode, struct file *filp); | ||
25 | long gk20a_tsg_dev_ioctl(struct file *filp, | ||
26 | unsigned int cmd, unsigned long arg); | ||
27 | |||
28 | int gk20a_init_tsg_support(struct gk20a *g, u32 tsgid); | ||
29 | |||
30 | int gk20a_bind_runnable_channel_to_tsg(struct channel_gk20a *ch, int tsgid); | ||
31 | int gk20a_unbind_channel_from_tsg(struct channel_gk20a *ch, int tsgid); | ||
32 | |||
33 | struct 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_ */ | ||