diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_nvif.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_usif.c | 384 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_usif.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/client.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/driver.h | 1 | ||||
-rw-r--r-- | include/uapi/drm/nouveau_drm.h | 3 |
9 files changed, 427 insertions, 10 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 1a44d952cc3a..f5d7f7ce4bc6 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile | |||
@@ -340,7 +340,7 @@ nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o | |||
340 | nouveau-y += nouveau_vga.o nouveau_agp.o | 340 | nouveau-y += nouveau_vga.o nouveau_agp.o |
341 | nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o | 341 | nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o |
342 | nouveau-y += nouveau_prime.o nouveau_abi16.o | 342 | nouveau-y += nouveau_prime.o nouveau_abi16.o |
343 | nouveau-y += nouveau_nvif.o | 343 | nouveau-y += nouveau_nvif.o nouveau_usif.o |
344 | nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o | 344 | nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o |
345 | nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o | 345 | nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o |
346 | 346 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 14fb8e86f5bc..606cc6b4922f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include "nouveau_fbcon.h" | 50 | #include "nouveau_fbcon.h" |
51 | #include "nouveau_fence.h" | 51 | #include "nouveau_fence.h" |
52 | #include "nouveau_debugfs.h" | 52 | #include "nouveau_debugfs.h" |
53 | #include "nouveau_usif.h" | ||
53 | 54 | ||
54 | MODULE_PARM_DESC(config, "option string to pass to driver core"); | 55 | MODULE_PARM_DESC(config, "option string to pass to driver core"); |
55 | static char *nouveau_config; | 56 | static char *nouveau_config; |
@@ -107,8 +108,10 @@ nouveau_cli_create(u64 name, const char *sname, | |||
107 | int ret = nvif_client_init(NULL, NULL, sname, name, | 108 | int ret = nvif_client_init(NULL, NULL, sname, name, |
108 | nouveau_config, nouveau_debug, | 109 | nouveau_config, nouveau_debug, |
109 | &cli->base); | 110 | &cli->base); |
110 | if (ret == 0) | 111 | if (ret == 0) { |
111 | mutex_init(&cli->mutex); | 112 | mutex_init(&cli->mutex); |
113 | usif_client_init(cli); | ||
114 | } | ||
112 | return ret; | 115 | return ret; |
113 | } | 116 | } |
114 | return -ENOMEM; | 117 | return -ENOMEM; |
@@ -119,6 +122,7 @@ nouveau_cli_destroy(struct nouveau_cli *cli) | |||
119 | { | 122 | { |
120 | nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL); | 123 | nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL); |
121 | nvif_client_fini(&cli->base); | 124 | nvif_client_fini(&cli->base); |
125 | usif_client_fini(cli); | ||
122 | } | 126 | } |
123 | 127 | ||
124 | static void | 128 | static void |
@@ -810,24 +814,31 @@ nouveau_ioctls[] = { | |||
810 | DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), | 814 | DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), |
811 | }; | 815 | }; |
812 | 816 | ||
813 | long nouveau_drm_ioctl(struct file *filp, | 817 | long |
814 | unsigned int cmd, unsigned long arg) | 818 | nouveau_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
815 | { | 819 | { |
816 | struct drm_file *file_priv = filp->private_data; | 820 | struct drm_file *filp = file->private_data; |
817 | struct drm_device *dev; | 821 | struct drm_device *dev = filp->minor->dev; |
818 | long ret; | 822 | long ret; |
819 | dev = file_priv->minor->dev; | ||
820 | 823 | ||
821 | ret = pm_runtime_get_sync(dev->dev); | 824 | ret = pm_runtime_get_sync(dev->dev); |
822 | if (ret < 0 && ret != -EACCES) | 825 | if (ret < 0 && ret != -EACCES) |
823 | return ret; | 826 | return ret; |
824 | 827 | ||
825 | ret = drm_ioctl(filp, cmd, arg); | 828 | switch (_IOC_NR(cmd) - DRM_COMMAND_BASE) { |
829 | case DRM_NOUVEAU_NVIF: | ||
830 | ret = usif_ioctl(filp, (void __user *)arg, _IOC_SIZE(cmd)); | ||
831 | break; | ||
832 | default: | ||
833 | ret = drm_ioctl(file, cmd, arg); | ||
834 | break; | ||
835 | } | ||
826 | 836 | ||
827 | pm_runtime_mark_last_busy(dev->dev); | 837 | pm_runtime_mark_last_busy(dev->dev); |
828 | pm_runtime_put_autosuspend(dev->dev); | 838 | pm_runtime_put_autosuspend(dev->dev); |
829 | return ret; | 839 | return ret; |
830 | } | 840 | } |
841 | |||
831 | static const struct file_operations | 842 | static const struct file_operations |
832 | nouveau_driver_fops = { | 843 | nouveau_driver_fops = { |
833 | .owner = THIS_MODULE, | 844 | .owner = THIS_MODULE, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 3a6ef5018f52..b02b02452c85 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h | |||
@@ -9,8 +9,8 @@ | |||
9 | #define DRIVER_DATE "20120801" | 9 | #define DRIVER_DATE "20120801" |
10 | 10 | ||
11 | #define DRIVER_MAJOR 1 | 11 | #define DRIVER_MAJOR 1 |
12 | #define DRIVER_MINOR 1 | 12 | #define DRIVER_MINOR 2 |
13 | #define DRIVER_PATCHLEVEL 2 | 13 | #define DRIVER_PATCHLEVEL 0 |
14 | 14 | ||
15 | /* | 15 | /* |
16 | * 1.1.1: | 16 | * 1.1.1: |
@@ -23,6 +23,9 @@ | |||
23 | * bounds access to local memory to be silently ignored / return 0). | 23 | * bounds access to local memory to be silently ignored / return 0). |
24 | * 1.1.2: | 24 | * 1.1.2: |
25 | * - fixes multiple bugs in flip completion events and timestamping | 25 | * - fixes multiple bugs in flip completion events and timestamping |
26 | * 1.2.0: | ||
27 | * - object api exposed to userspace | ||
28 | * - fermi,kepler,maxwell zbc | ||
26 | */ | 29 | */ |
27 | 30 | ||
28 | #include <nvif/client.h> | 31 | #include <nvif/client.h> |
@@ -79,6 +82,8 @@ struct nouveau_cli { | |||
79 | struct list_head head; | 82 | struct list_head head; |
80 | struct mutex mutex; | 83 | struct mutex mutex; |
81 | void *abi16; | 84 | void *abi16; |
85 | struct list_head objects; | ||
86 | struct list_head notifys; | ||
82 | }; | 87 | }; |
83 | 88 | ||
84 | static inline struct nouveau_cli * | 89 | static inline struct nouveau_cli * |
diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c index c3838bffe24f..47ca88623753 100644 --- a/drivers/gpu/drm/nouveau/nouveau_nvif.c +++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <nvif/ioctl.h> | 37 | #include <nvif/ioctl.h> |
38 | 38 | ||
39 | #include "nouveau_drm.h" | 39 | #include "nouveau_drm.h" |
40 | #include "nouveau_usif.h" | ||
40 | 41 | ||
41 | static void | 42 | static void |
42 | nvkm_client_unmap(void *priv, void *ptr, u32 size) | 43 | nvkm_client_unmap(void *priv, void *ptr, u32 size) |
@@ -95,6 +96,8 @@ nvkm_client_ntfy(const void *header, u32 length, const void *data, u32 size) | |||
95 | switch (route) { | 96 | switch (route) { |
96 | case NVDRM_NOTIFY_NVIF: | 97 | case NVDRM_NOTIFY_NVIF: |
97 | return nvif_notify(header, length, data, size); | 98 | return nvif_notify(header, length, data, size); |
99 | case NVDRM_NOTIFY_USIF: | ||
100 | return usif_notify(header, length, data, size); | ||
98 | default: | 101 | default: |
99 | WARN_ON(1); | 102 | WARN_ON(1); |
100 | break; | 103 | break; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c new file mode 100644 index 000000000000..cb1182d7e80e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_usif.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * Copyright 2014 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs <bskeggs@redhat.com> | ||
23 | */ | ||
24 | |||
25 | #include "nouveau_drm.h" | ||
26 | #include "nouveau_usif.h" | ||
27 | |||
28 | #include <nvif/notify.h> | ||
29 | #include <nvif/unpack.h> | ||
30 | #include <nvif/client.h> | ||
31 | #include <nvif/event.h> | ||
32 | #include <nvif/ioctl.h> | ||
33 | |||
34 | struct usif_notify_p { | ||
35 | struct drm_pending_event base; | ||
36 | struct { | ||
37 | struct drm_event base; | ||
38 | u8 data[]; | ||
39 | } e; | ||
40 | }; | ||
41 | |||
42 | struct usif_notify { | ||
43 | struct list_head head; | ||
44 | atomic_t enabled; | ||
45 | u32 handle; | ||
46 | u16 reply; | ||
47 | u8 route; | ||
48 | u64 token; | ||
49 | struct usif_notify_p *p; | ||
50 | }; | ||
51 | |||
52 | static inline struct usif_notify * | ||
53 | usif_notify_find(struct drm_file *filp, u32 handle) | ||
54 | { | ||
55 | struct nouveau_cli *cli = nouveau_cli(filp); | ||
56 | struct usif_notify *ntfy; | ||
57 | list_for_each_entry(ntfy, &cli->notifys, head) { | ||
58 | if (ntfy->handle == handle) | ||
59 | return ntfy; | ||
60 | } | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | static inline void | ||
65 | usif_notify_dtor(struct usif_notify *ntfy) | ||
66 | { | ||
67 | list_del(&ntfy->head); | ||
68 | kfree(ntfy); | ||
69 | } | ||
70 | |||
71 | int | ||
72 | usif_notify(const void *header, u32 length, const void *data, u32 size) | ||
73 | { | ||
74 | struct usif_notify *ntfy = NULL; | ||
75 | const union { | ||
76 | struct nvif_notify_rep_v0 v0; | ||
77 | } *rep = header; | ||
78 | struct drm_device *dev; | ||
79 | struct drm_file *filp; | ||
80 | unsigned long flags; | ||
81 | |||
82 | if (length == sizeof(rep->v0) && rep->v0.version == 0) { | ||
83 | if (WARN_ON(!(ntfy = (void *)(unsigned long)rep->v0.token))) | ||
84 | return NVIF_NOTIFY_DROP; | ||
85 | BUG_ON(rep->v0.route != NVDRM_NOTIFY_USIF); | ||
86 | } else | ||
87 | if (WARN_ON(1)) | ||
88 | return NVIF_NOTIFY_DROP; | ||
89 | |||
90 | if (WARN_ON(!ntfy->p || ntfy->reply != (length + size))) | ||
91 | return NVIF_NOTIFY_DROP; | ||
92 | filp = ntfy->p->base.file_priv; | ||
93 | dev = filp->minor->dev; | ||
94 | |||
95 | memcpy(&ntfy->p->e.data[0], header, length); | ||
96 | memcpy(&ntfy->p->e.data[length], data, size); | ||
97 | switch (rep->v0.version) { | ||
98 | case 0: { | ||
99 | struct nvif_notify_rep_v0 *rep = (void *)ntfy->p->e.data; | ||
100 | rep->route = ntfy->route; | ||
101 | rep->token = ntfy->token; | ||
102 | } | ||
103 | break; | ||
104 | default: | ||
105 | BUG_ON(1); | ||
106 | break; | ||
107 | } | ||
108 | |||
109 | spin_lock_irqsave(&dev->event_lock, flags); | ||
110 | if (!WARN_ON(filp->event_space < ntfy->p->e.base.length)) { | ||
111 | list_add_tail(&ntfy->p->base.link, &filp->event_list); | ||
112 | filp->event_space -= ntfy->p->e.base.length; | ||
113 | } | ||
114 | wake_up_interruptible(&filp->event_wait); | ||
115 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
116 | atomic_set(&ntfy->enabled, 0); | ||
117 | return NVIF_NOTIFY_DROP; | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | usif_notify_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) | ||
122 | { | ||
123 | struct nouveau_cli *cli = nouveau_cli(f); | ||
124 | struct nvif_client *client = &cli->base; | ||
125 | union { | ||
126 | struct nvif_ioctl_ntfy_new_v0 v0; | ||
127 | } *args = data; | ||
128 | union { | ||
129 | struct nvif_notify_req_v0 v0; | ||
130 | } *req; | ||
131 | struct usif_notify *ntfy; | ||
132 | int ret; | ||
133 | |||
134 | if (nvif_unpack(args->v0, 0, 0, true)) { | ||
135 | if (usif_notify_find(f, args->v0.index)) | ||
136 | return -EEXIST; | ||
137 | } else | ||
138 | return ret; | ||
139 | req = data; | ||
140 | |||
141 | if (!(ntfy = kmalloc(sizeof(*ntfy), GFP_KERNEL))) | ||
142 | return -ENOMEM; | ||
143 | atomic_set(&ntfy->enabled, 0); | ||
144 | |||
145 | if (nvif_unpack(req->v0, 0, 0, true)) { | ||
146 | ntfy->reply = sizeof(struct nvif_notify_rep_v0) + req->v0.reply; | ||
147 | ntfy->route = req->v0.route; | ||
148 | ntfy->token = req->v0.token; | ||
149 | req->v0.route = NVDRM_NOTIFY_USIF; | ||
150 | req->v0.token = (unsigned long)(void *)ntfy; | ||
151 | ret = nvif_client_ioctl(client, argv, argc); | ||
152 | req->v0.token = ntfy->token; | ||
153 | req->v0.route = ntfy->route; | ||
154 | ntfy->handle = args->v0.index; | ||
155 | } | ||
156 | |||
157 | if (ret == 0) | ||
158 | list_add(&ntfy->head, &cli->notifys); | ||
159 | if (ret) | ||
160 | kfree(ntfy); | ||
161 | return ret; | ||
162 | } | ||
163 | |||
164 | static int | ||
165 | usif_notify_del(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) | ||
166 | { | ||
167 | struct nouveau_cli *cli = nouveau_cli(f); | ||
168 | struct nvif_client *client = &cli->base; | ||
169 | union { | ||
170 | struct nvif_ioctl_ntfy_del_v0 v0; | ||
171 | } *args = data; | ||
172 | struct usif_notify *ntfy; | ||
173 | int ret; | ||
174 | |||
175 | if (nvif_unpack(args->v0, 0, 0, true)) { | ||
176 | if (!(ntfy = usif_notify_find(f, args->v0.index))) | ||
177 | return -ENOENT; | ||
178 | } else | ||
179 | return ret; | ||
180 | |||
181 | ret = nvif_client_ioctl(client, argv, argc); | ||
182 | if (ret == 0) | ||
183 | usif_notify_dtor(ntfy); | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | static int | ||
188 | usif_notify_get(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) | ||
189 | { | ||
190 | struct nouveau_cli *cli = nouveau_cli(f); | ||
191 | struct nvif_client *client = &cli->base; | ||
192 | union { | ||
193 | struct nvif_ioctl_ntfy_del_v0 v0; | ||
194 | } *args = data; | ||
195 | struct usif_notify *ntfy; | ||
196 | int ret; | ||
197 | |||
198 | if (nvif_unpack(args->v0, 0, 0, true)) { | ||
199 | if (!(ntfy = usif_notify_find(f, args->v0.index))) | ||
200 | return -ENOENT; | ||
201 | } else | ||
202 | return ret; | ||
203 | |||
204 | if (atomic_xchg(&ntfy->enabled, 1)) | ||
205 | return 0; | ||
206 | |||
207 | ntfy->p = kmalloc(sizeof(*ntfy->p) + ntfy->reply, GFP_KERNEL); | ||
208 | if (ret = -ENOMEM, !ntfy->p) | ||
209 | goto done; | ||
210 | ntfy->p->base.event = &ntfy->p->e.base; | ||
211 | ntfy->p->base.file_priv = f; | ||
212 | ntfy->p->base.pid = current->pid; | ||
213 | ntfy->p->base.destroy =(void(*)(struct drm_pending_event *))kfree; | ||
214 | ntfy->p->e.base.type = DRM_NOUVEAU_EVENT_NVIF; | ||
215 | ntfy->p->e.base.length = sizeof(ntfy->p->e.base) + ntfy->reply; | ||
216 | |||
217 | ret = nvif_client_ioctl(client, argv, argc); | ||
218 | done: | ||
219 | if (ret) { | ||
220 | atomic_set(&ntfy->enabled, 0); | ||
221 | kfree(ntfy->p); | ||
222 | } | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static int | ||
227 | usif_notify_put(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) | ||
228 | { | ||
229 | struct nouveau_cli *cli = nouveau_cli(f); | ||
230 | struct nvif_client *client = &cli->base; | ||
231 | union { | ||
232 | struct nvif_ioctl_ntfy_put_v0 v0; | ||
233 | } *args = data; | ||
234 | struct usif_notify *ntfy; | ||
235 | int ret; | ||
236 | |||
237 | if (nvif_unpack(args->v0, 0, 0, true)) { | ||
238 | if (!(ntfy = usif_notify_find(f, args->v0.index))) | ||
239 | return -ENOENT; | ||
240 | } else | ||
241 | return ret; | ||
242 | |||
243 | ret = nvif_client_ioctl(client, argv, argc); | ||
244 | if (ret == 0 && atomic_xchg(&ntfy->enabled, 0)) | ||
245 | kfree(ntfy->p); | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | struct usif_object { | ||
250 | struct list_head head; | ||
251 | struct list_head ntfy; | ||
252 | u8 route; | ||
253 | u64 token; | ||
254 | }; | ||
255 | |||
256 | static void | ||
257 | usif_object_dtor(struct usif_object *object) | ||
258 | { | ||
259 | list_del(&object->head); | ||
260 | kfree(object); | ||
261 | } | ||
262 | |||
263 | static int | ||
264 | usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) | ||
265 | { | ||
266 | struct nouveau_cli *cli = nouveau_cli(f); | ||
267 | struct nvif_client *client = &cli->base; | ||
268 | union { | ||
269 | struct nvif_ioctl_new_v0 v0; | ||
270 | } *args = data; | ||
271 | struct usif_object *object; | ||
272 | int ret; | ||
273 | |||
274 | if (!(object = kmalloc(sizeof(*object), GFP_KERNEL))) | ||
275 | return -ENOMEM; | ||
276 | list_add(&object->head, &cli->objects); | ||
277 | |||
278 | if (nvif_unpack(args->v0, 0, 0, true)) { | ||
279 | object->route = args->v0.route; | ||
280 | object->token = args->v0.token; | ||
281 | args->v0.route = NVDRM_OBJECT_USIF; | ||
282 | args->v0.token = (unsigned long)(void *)object; | ||
283 | ret = nvif_client_ioctl(client, argv, argc); | ||
284 | args->v0.token = object->token; | ||
285 | args->v0.route = object->route; | ||
286 | } | ||
287 | |||
288 | if (ret) | ||
289 | usif_object_dtor(object); | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | int | ||
294 | usif_ioctl(struct drm_file *filp, void __user *user, u32 argc) | ||
295 | { | ||
296 | struct nouveau_cli *cli = nouveau_cli(filp); | ||
297 | struct nvif_client *client = &cli->base; | ||
298 | void *data = kmalloc(argc, GFP_KERNEL); | ||
299 | u32 size = argc; | ||
300 | union { | ||
301 | struct nvif_ioctl_v0 v0; | ||
302 | } *argv = data; | ||
303 | struct usif_object *object; | ||
304 | u8 owner; | ||
305 | int ret; | ||
306 | |||
307 | if (ret = -ENOMEM, !argv) | ||
308 | goto done; | ||
309 | if (ret = -EFAULT, copy_from_user(argv, user, size)) | ||
310 | goto done; | ||
311 | |||
312 | if (nvif_unpack(argv->v0, 0, 0, true)) { | ||
313 | /* block access to objects not created via this interface */ | ||
314 | owner = argv->v0.owner; | ||
315 | argv->v0.owner = NVDRM_OBJECT_USIF; | ||
316 | } else | ||
317 | goto done; | ||
318 | |||
319 | mutex_lock(&cli->mutex); | ||
320 | switch (argv->v0.type) { | ||
321 | case NVIF_IOCTL_V0_NEW: | ||
322 | /* ... except if we're creating children */ | ||
323 | argv->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; | ||
324 | ret = usif_object_new(filp, data, size, argv, argc); | ||
325 | break; | ||
326 | case NVIF_IOCTL_V0_NTFY_NEW: | ||
327 | ret = usif_notify_new(filp, data, size, argv, argc); | ||
328 | break; | ||
329 | case NVIF_IOCTL_V0_NTFY_DEL: | ||
330 | ret = usif_notify_del(filp, data, size, argv, argc); | ||
331 | break; | ||
332 | case NVIF_IOCTL_V0_NTFY_GET: | ||
333 | ret = usif_notify_get(filp, data, size, argv, argc); | ||
334 | break; | ||
335 | case NVIF_IOCTL_V0_NTFY_PUT: | ||
336 | ret = usif_notify_put(filp, data, size, argv, argc); | ||
337 | break; | ||
338 | default: | ||
339 | ret = nvif_client_ioctl(client, argv, argc); | ||
340 | break; | ||
341 | } | ||
342 | if (argv->v0.route == NVDRM_OBJECT_USIF) { | ||
343 | object = (void *)(unsigned long)argv->v0.token; | ||
344 | argv->v0.route = object->route; | ||
345 | argv->v0.token = object->token; | ||
346 | if (ret == 0 && argv->v0.type == NVIF_IOCTL_V0_DEL) { | ||
347 | list_del(&object->head); | ||
348 | kfree(object); | ||
349 | } | ||
350 | } else { | ||
351 | argv->v0.route = NVIF_IOCTL_V0_ROUTE_HIDDEN; | ||
352 | argv->v0.token = 0; | ||
353 | } | ||
354 | argv->v0.owner = owner; | ||
355 | mutex_unlock(&cli->mutex); | ||
356 | |||
357 | if (copy_to_user(user, argv, argc)) | ||
358 | ret = -EFAULT; | ||
359 | done: | ||
360 | kfree(argv); | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | void | ||
365 | usif_client_fini(struct nouveau_cli *cli) | ||
366 | { | ||
367 | struct usif_object *object, *otemp; | ||
368 | struct usif_notify *notify, *ntemp; | ||
369 | |||
370 | list_for_each_entry_safe(notify, ntemp, &cli->notifys, head) { | ||
371 | usif_notify_dtor(notify); | ||
372 | } | ||
373 | |||
374 | list_for_each_entry_safe(object, otemp, &cli->objects, head) { | ||
375 | usif_object_dtor(object); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | void | ||
380 | usif_client_init(struct nouveau_cli *cli) | ||
381 | { | ||
382 | INIT_LIST_HEAD(&cli->objects); | ||
383 | INIT_LIST_HEAD(&cli->notifys); | ||
384 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.h b/drivers/gpu/drm/nouveau/nouveau_usif.h new file mode 100644 index 000000000000..c037e3ae8c70 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_usif.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef __NOUVEAU_USIF_H__ | ||
2 | #define __NOUVEAU_USIF_H__ | ||
3 | |||
4 | void usif_client_init(struct nouveau_cli *); | ||
5 | void usif_client_fini(struct nouveau_cli *); | ||
6 | int usif_ioctl(struct drm_file *, void __user *, u32); | ||
7 | int usif_notify(const void *, u32, const void *, u32); | ||
8 | |||
9 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c index 20fb38688b93..3c4df1fc26dc 100644 --- a/drivers/gpu/drm/nouveau/nvif/client.c +++ b/drivers/gpu/drm/nouveau/nvif/client.c | |||
@@ -60,6 +60,7 @@ nvif_drivers[] = { | |||
60 | #ifdef __KERNEL__ | 60 | #ifdef __KERNEL__ |
61 | &nvif_driver_nvkm, | 61 | &nvif_driver_nvkm, |
62 | #else | 62 | #else |
63 | &nvif_driver_drm, | ||
63 | &nvif_driver_lib, | 64 | &nvif_driver_lib, |
64 | #endif | 65 | #endif |
65 | NULL | 66 | NULL |
diff --git a/drivers/gpu/drm/nouveau/nvif/driver.h b/drivers/gpu/drm/nouveau/nvif/driver.h index ea5b1b880fb6..b72a8f0c2758 100644 --- a/drivers/gpu/drm/nouveau/nvif/driver.h +++ b/drivers/gpu/drm/nouveau/nvif/driver.h | |||
@@ -15,6 +15,7 @@ struct nvif_driver { | |||
15 | }; | 15 | }; |
16 | 16 | ||
17 | extern const struct nvif_driver nvif_driver_nvkm; | 17 | extern const struct nvif_driver nvif_driver_nvkm; |
18 | extern const struct nvif_driver nvif_driver_drm; | ||
18 | extern const struct nvif_driver nvif_driver_lib; | 19 | extern const struct nvif_driver nvif_driver_lib; |
19 | 20 | ||
20 | #endif | 21 | #endif |
diff --git a/include/uapi/drm/nouveau_drm.h b/include/uapi/drm/nouveau_drm.h index ed0b7bd4b473..0d7608dc1a34 100644 --- a/include/uapi/drm/nouveau_drm.h +++ b/include/uapi/drm/nouveau_drm.h | |||
@@ -25,6 +25,8 @@ | |||
25 | #ifndef __NOUVEAU_DRM_H__ | 25 | #ifndef __NOUVEAU_DRM_H__ |
26 | #define __NOUVEAU_DRM_H__ | 26 | #define __NOUVEAU_DRM_H__ |
27 | 27 | ||
28 | #define DRM_NOUVEAU_EVENT_NVIF 0x80000000 | ||
29 | |||
28 | /* reserved object handles when using deprecated object APIs - these | 30 | /* reserved object handles when using deprecated object APIs - these |
29 | * are here so that libdrm can allow interoperability with the new | 31 | * are here so that libdrm can allow interoperability with the new |
30 | * object APIs | 32 | * object APIs |
@@ -131,6 +133,7 @@ struct drm_nouveau_gem_cpu_fini { | |||
131 | #define DRM_NOUVEAU_GROBJ_ALLOC 0x04 /* deprecated */ | 133 | #define DRM_NOUVEAU_GROBJ_ALLOC 0x04 /* deprecated */ |
132 | #define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC 0x05 /* deprecated */ | 134 | #define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC 0x05 /* deprecated */ |
133 | #define DRM_NOUVEAU_GPUOBJ_FREE 0x06 /* deprecated */ | 135 | #define DRM_NOUVEAU_GPUOBJ_FREE 0x06 /* deprecated */ |
136 | #define DRM_NOUVEAU_NVIF 0x07 | ||
134 | #define DRM_NOUVEAU_GEM_NEW 0x40 | 137 | #define DRM_NOUVEAU_GEM_NEW 0x40 |
135 | #define DRM_NOUVEAU_GEM_PUSHBUF 0x41 | 138 | #define DRM_NOUVEAU_GEM_PUSHBUF 0x41 |
136 | #define DRM_NOUVEAU_GEM_CPU_PREP 0x42 | 139 | #define DRM_NOUVEAU_GEM_CPU_PREP 0x42 |