2 * Copyright 2014 Red Hat Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
22 * Authors: Ben Skeggs <bskeggs@redhat.com>
25 #include "nouveau_drm.h"
26 #include "nouveau_usif.h"
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>
34 struct usif_notify_p
{
35 struct drm_pending_event base
;
37 struct drm_event base
;
43 struct list_head head
;
49 struct usif_notify_p
*p
;
52 static inline struct usif_notify
*
53 usif_notify_find(struct drm_file
*filp
, u32 handle
)
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
)
65 usif_notify_dtor(struct usif_notify
*ntfy
)
67 list_del(&ntfy
->head
);
72 usif_notify(const void *header
, u32 length
, const void *data
, u32 size
)
74 struct usif_notify
*ntfy
= NULL
;
76 struct nvif_notify_rep_v0 v0
;
78 struct drm_device
*dev
;
79 struct drm_file
*filp
;
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
);
88 return NVIF_NOTIFY_DROP
;
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
;
95 memcpy(&ntfy
->p
->e
.data
[0], header
, length
);
96 memcpy(&ntfy
->p
->e
.data
[length
], data
, size
);
97 switch (rep
->v0
.version
) {
99 struct nvif_notify_rep_v0
*rep
= (void *)ntfy
->p
->e
.data
;
100 rep
->route
= ntfy
->route
;
101 rep
->token
= ntfy
->token
;
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
;
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
;
121 usif_notify_new(struct drm_file
*f
, void *data
, u32 size
, void *argv
, u32 argc
)
123 struct nouveau_cli
*cli
= nouveau_cli(f
);
124 struct nvif_client
*client
= &cli
->base
;
126 struct nvif_ioctl_ntfy_new_v0 v0
;
129 struct nvif_notify_req_v0 v0
;
131 struct usif_notify
*ntfy
;
134 if (nvif_unpack(args
->v0
, 0, 0, true)) {
135 if (usif_notify_find(f
, args
->v0
.index
))
141 if (!(ntfy
= kmalloc(sizeof(*ntfy
), GFP_KERNEL
)))
143 atomic_set(&ntfy
->enabled
, 0);
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
;
158 list_add(&ntfy
->head
, &cli
->notifys
);
165 usif_notify_del(struct drm_file
*f
, void *data
, u32 size
, void *argv
, u32 argc
)
167 struct nouveau_cli
*cli
= nouveau_cli(f
);
168 struct nvif_client
*client
= &cli
->base
;
170 struct nvif_ioctl_ntfy_del_v0 v0
;
172 struct usif_notify
*ntfy
;
175 if (nvif_unpack(args
->v0
, 0, 0, true)) {
176 if (!(ntfy
= usif_notify_find(f
, args
->v0
.index
)))
181 ret
= nvif_client_ioctl(client
, argv
, argc
);
183 usif_notify_dtor(ntfy
);
188 usif_notify_get(struct drm_file
*f
, void *data
, u32 size
, void *argv
, u32 argc
)
190 struct nouveau_cli
*cli
= nouveau_cli(f
);
191 struct nvif_client
*client
= &cli
->base
;
193 struct nvif_ioctl_ntfy_del_v0 v0
;
195 struct usif_notify
*ntfy
;
198 if (nvif_unpack(args
->v0
, 0, 0, true)) {
199 if (!(ntfy
= usif_notify_find(f
, args
->v0
.index
)))
204 if (atomic_xchg(&ntfy
->enabled
, 1))
207 ntfy
->p
= kmalloc(sizeof(*ntfy
->p
) + ntfy
->reply
, GFP_KERNEL
);
208 if (ret
= -ENOMEM
, !ntfy
->p
)
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
;
217 ret
= nvif_client_ioctl(client
, argv
, argc
);
220 atomic_set(&ntfy
->enabled
, 0);
227 usif_notify_put(struct drm_file
*f
, void *data
, u32 size
, void *argv
, u32 argc
)
229 struct nouveau_cli
*cli
= nouveau_cli(f
);
230 struct nvif_client
*client
= &cli
->base
;
232 struct nvif_ioctl_ntfy_put_v0 v0
;
234 struct usif_notify
*ntfy
;
237 if (nvif_unpack(args
->v0
, 0, 0, true)) {
238 if (!(ntfy
= usif_notify_find(f
, args
->v0
.index
)))
243 ret
= nvif_client_ioctl(client
, argv
, argc
);
244 if (ret
== 0 && atomic_xchg(&ntfy
->enabled
, 0))
250 struct list_head head
;
251 struct list_head ntfy
;
257 usif_object_dtor(struct usif_object
*object
)
259 list_del(&object
->head
);
264 usif_object_new(struct drm_file
*f
, void *data
, u32 size
, void *argv
, u32 argc
)
266 struct nouveau_cli
*cli
= nouveau_cli(f
);
267 struct nvif_client
*client
= &cli
->base
;
269 struct nvif_ioctl_new_v0 v0
;
271 struct usif_object
*object
;
274 if (!(object
= kmalloc(sizeof(*object
), GFP_KERNEL
)))
276 list_add(&object
->head
, &cli
->objects
);
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
;
289 usif_object_dtor(object
);
294 usif_ioctl(struct drm_file
*filp
, void __user
*user
, u32 argc
)
296 struct nouveau_cli
*cli
= nouveau_cli(filp
);
297 struct nvif_client
*client
= &cli
->base
;
298 void *data
= kmalloc(argc
, GFP_KERNEL
);
301 struct nvif_ioctl_v0 v0
;
303 struct usif_object
*object
;
307 if (ret
= -ENOMEM
, !argv
)
309 if (ret
= -EFAULT
, copy_from_user(argv
, user
, size
))
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
;
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
);
326 case NVIF_IOCTL_V0_NTFY_NEW
:
327 ret
= usif_notify_new(filp
, data
, size
, argv
, argc
);
329 case NVIF_IOCTL_V0_NTFY_DEL
:
330 ret
= usif_notify_del(filp
, data
, size
, argv
, argc
);
332 case NVIF_IOCTL_V0_NTFY_GET
:
333 ret
= usif_notify_get(filp
, data
, size
, argv
, argc
);
335 case NVIF_IOCTL_V0_NTFY_PUT
:
336 ret
= usif_notify_put(filp
, data
, size
, argv
, argc
);
339 ret
= nvif_client_ioctl(client
, argv
, argc
);
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
);
351 argv
->v0
.route
= NVIF_IOCTL_V0_ROUTE_HIDDEN
;
354 argv
->v0
.owner
= owner
;
355 mutex_unlock(&cli
->mutex
);
357 if (copy_to_user(user
, argv
, argc
))
365 usif_client_fini(struct nouveau_cli
*cli
)
367 struct usif_object
*object
, *otemp
;
368 struct usif_notify
*notify
, *ntemp
;
370 list_for_each_entry_safe(notify
, ntemp
, &cli
->notifys
, head
) {
371 usif_notify_dtor(notify
);
374 list_for_each_entry_safe(object
, otemp
, &cli
->objects
, head
) {
375 usif_object_dtor(object
);
380 usif_client_init(struct nouveau_cli
*cli
)
382 INIT_LIST_HEAD(&cli
->objects
);
383 INIT_LIST_HEAD(&cli
->notifys
);