summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/as_gk20a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/as_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/as_gk20a.c293
1 files changed, 293 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/as_gk20a.c b/drivers/gpu/nvgpu/gk20a/as_gk20a.c
new file mode 100644
index 00000000..65c26938
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/as_gk20a.c
@@ -0,0 +1,293 @@
1/*
2 * drivers/video/tegra/host/gk20a/as_gk20a.c
3 *
4 * GK20A Address Spaces
5 *
6 * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 */
17
18#include <linux/slab.h>
19#include <linux/fs.h>
20#include <linux/cdev.h>
21#include <linux/uaccess.h>
22
23#include <trace/events/gk20a.h>
24
25#include "gk20a.h"
26
27/* dumb allocator... */
28static int generate_as_share_id(struct gk20a_as *as)
29{
30 gk20a_dbg_fn("");
31 return ++as->last_share_id;
32}
33/* still dumb */
34static void release_as_share_id(struct gk20a_as *as, int id)
35{
36 gk20a_dbg_fn("");
37 return;
38}
39
40static int gk20a_as_alloc_share(struct gk20a_as *as,
41 struct gk20a_as_share **out)
42{
43 struct gk20a_as_share *as_share;
44 int err = 0;
45
46 gk20a_dbg_fn("");
47
48 *out = 0;
49 as_share = kzalloc(sizeof(*as_share), GFP_KERNEL);
50 if (!as_share)
51 return -ENOMEM;
52
53 as_share->as = as;
54 as_share->id = generate_as_share_id(as_share->as);
55 as_share->ref_cnt.counter = 1;
56
57 /* this will set as_share->vm. */
58 err = gk20a_vm_alloc_share(as_share);
59 if (err)
60 goto failed;
61
62 *out = as_share;
63 return 0;
64
65 failed:
66 kfree(as_share);
67 return err;
68}
69
70/*
71 * channels and the device nodes call this to release.
72 * once the ref_cnt hits zero the share is deleted.
73 */
74int gk20a_as_release_share(struct gk20a_as_share *as_share)
75{
76 int err;
77
78 gk20a_dbg_fn("");
79
80 if (atomic_dec_return(&as_share->ref_cnt) > 0)
81 return 0;
82
83 err = gk20a_vm_release_share(as_share);
84 release_as_share_id(as_share->as, as_share->id);
85 kfree(as_share);
86 return err;
87}
88
89static int gk20a_as_ioctl_bind_channel(
90 struct gk20a_as_share *as_share,
91 struct nvhost_as_bind_channel_args *args)
92{
93 int err = 0;
94 struct channel_gk20a *ch;
95
96 gk20a_dbg_fn("");
97
98 ch = gk20a_get_channel_from_file(args->channel_fd);
99 if (!ch || gk20a_channel_as_bound(ch))
100 return -EINVAL;
101
102 atomic_inc(&as_share->ref_cnt);
103
104 /* this will set channel_gk20a->vm */
105 err = gk20a_vm_bind_channel(as_share, ch);
106 if (err) {
107 atomic_dec(&as_share->ref_cnt);
108 return err;
109 }
110
111 return err;
112}
113
114static int gk20a_as_ioctl_alloc_space(
115 struct gk20a_as_share *as_share,
116 struct nvhost_as_alloc_space_args *args)
117{
118 gk20a_dbg_fn("");
119 return gk20a_vm_alloc_space(as_share, args);
120}
121
122static int gk20a_as_ioctl_free_space(
123 struct gk20a_as_share *as_share,
124 struct nvhost_as_free_space_args *args)
125{
126 gk20a_dbg_fn("");
127 return gk20a_vm_free_space(as_share, args);
128}
129
130static int gk20a_as_ioctl_map_buffer_ex(
131 struct gk20a_as_share *as_share,
132 struct nvhost_as_map_buffer_ex_args *args)
133{
134 int i;
135
136 gk20a_dbg_fn("");
137
138 /* ensure that padding is not set. this is required for ensuring that
139 * we can safely use these fields later */
140 for (i = 0; i < ARRAY_SIZE(args->padding); i++)
141 if (args->padding[i])
142 return -EINVAL;
143
144 return gk20a_vm_map_buffer(as_share, args->dmabuf_fd,
145 &args->offset, args->flags,
146 args->kind);
147}
148
149static int gk20a_as_ioctl_map_buffer(
150 struct gk20a_as_share *as_share,
151 struct nvhost_as_map_buffer_args *args)
152{
153 gk20a_dbg_fn("");
154 return gk20a_vm_map_buffer(as_share, args->nvmap_handle,
155 &args->o_a.align,
156 args->flags, NV_KIND_DEFAULT);
157 /* args->o_a.offset will be set if !err */
158}
159
160static int gk20a_as_ioctl_unmap_buffer(
161 struct gk20a_as_share *as_share,
162 struct nvhost_as_unmap_buffer_args *args)
163{
164 gk20a_dbg_fn("");
165 return gk20a_vm_unmap_buffer(as_share, args->offset);
166}
167
168int gk20a_as_dev_open(struct inode *inode, struct file *filp)
169{
170 struct gk20a_as_share *as_share;
171 struct gk20a *g;
172 int err;
173
174 gk20a_dbg_fn("");
175
176 g = container_of(inode->i_cdev, struct gk20a, as.cdev);
177
178 err = gk20a_get_client(g);
179 if (err) {
180 gk20a_dbg_fn("fail to get channel!");
181 return err;
182 }
183
184 err = gk20a_as_alloc_share(&g->as, &as_share);
185 if (err) {
186 gk20a_dbg_fn("failed to alloc share");
187 gk20a_put_client(g);
188 return err;
189 }
190
191 filp->private_data = as_share;
192 return 0;
193}
194
195int gk20a_as_dev_release(struct inode *inode, struct file *filp)
196{
197 struct gk20a_as_share *as_share = filp->private_data;
198 int ret;
199 struct gk20a *g = gk20a_from_as(as_share->as);
200
201 gk20a_dbg_fn("");
202
203 ret = gk20a_as_release_share(as_share);
204
205 gk20a_put_client(g);
206
207 return ret;
208}
209
210long gk20a_as_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
211{
212 int err = 0;
213 struct gk20a_as_share *as_share = filp->private_data;
214 struct gk20a *g = gk20a_from_as(as_share->as);
215
216 u8 buf[NVHOST_AS_IOCTL_MAX_ARG_SIZE];
217
218 if ((_IOC_TYPE(cmd) != NVHOST_AS_IOCTL_MAGIC) ||
219 (_IOC_NR(cmd) == 0) ||
220 (_IOC_NR(cmd) > NVHOST_AS_IOCTL_LAST))
221 return -EFAULT;
222
223 BUG_ON(_IOC_SIZE(cmd) > NVHOST_AS_IOCTL_MAX_ARG_SIZE);
224
225 if (_IOC_DIR(cmd) & _IOC_WRITE) {
226 if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
227 return -EFAULT;
228 }
229
230 err = gk20a_channel_busy(g->dev);
231 if (err)
232 return err;
233
234 switch (cmd) {
235 case NVHOST_AS_IOCTL_BIND_CHANNEL:
236 trace_gk20a_as_ioctl_bind_channel(dev_name(dev_from_gk20a(g)));
237 err = gk20a_as_ioctl_bind_channel(as_share,
238 (struct nvhost_as_bind_channel_args *)buf);
239
240 break;
241 case NVHOST32_AS_IOCTL_ALLOC_SPACE:
242 {
243 struct nvhost32_as_alloc_space_args *args32 =
244 (struct nvhost32_as_alloc_space_args *)buf;
245 struct nvhost_as_alloc_space_args args;
246
247 args.pages = args32->pages;
248 args.page_size = args32->page_size;
249 args.flags = args32->flags;
250 args.o_a.offset = args32->o_a.offset;
251 trace_gk20a_as_ioctl_alloc_space(dev_name(dev_from_gk20a(g)));
252 err = gk20a_as_ioctl_alloc_space(as_share, &args);
253 args32->o_a.offset = args.o_a.offset;
254 break;
255 }
256 case NVHOST_AS_IOCTL_ALLOC_SPACE:
257 trace_gk20a_as_ioctl_alloc_space(dev_name(dev_from_gk20a(g)));
258 err = gk20a_as_ioctl_alloc_space(as_share,
259 (struct nvhost_as_alloc_space_args *)buf);
260 break;
261 case NVHOST_AS_IOCTL_FREE_SPACE:
262 trace_gk20a_as_ioctl_free_space(dev_name(dev_from_gk20a(g)));
263 err = gk20a_as_ioctl_free_space(as_share,
264 (struct nvhost_as_free_space_args *)buf);
265 break;
266 case NVHOST_AS_IOCTL_MAP_BUFFER:
267 trace_gk20a_as_ioctl_map_buffer(dev_name(dev_from_gk20a(g)));
268 err = gk20a_as_ioctl_map_buffer(as_share,
269 (struct nvhost_as_map_buffer_args *)buf);
270 break;
271 case NVHOST_AS_IOCTL_MAP_BUFFER_EX:
272 trace_gk20a_as_ioctl_map_buffer(dev_name(dev_from_gk20a(g)));
273 err = gk20a_as_ioctl_map_buffer_ex(as_share,
274 (struct nvhost_as_map_buffer_ex_args *)buf);
275 break;
276 case NVHOST_AS_IOCTL_UNMAP_BUFFER:
277 trace_gk20a_as_ioctl_unmap_buffer(dev_name(dev_from_gk20a(g)));
278 err = gk20a_as_ioctl_unmap_buffer(as_share,
279 (struct nvhost_as_unmap_buffer_args *)buf);
280 break;
281 default:
282 dev_err(dev_from_gk20a(g), "unrecognized as ioctl: 0x%x", cmd);
283 err = -ENOTTY;
284 break;
285 }
286
287 gk20a_channel_idle(g->dev);
288
289 if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
290 err = copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd));
291
292 return err;
293}