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 <nvif/client.h>
26 #include <nvif/driver.h>
27 #include <nvif/notify.h>
28 #include <nvif/object.h>
29 #include <nvif/ioctl.h>
30 #include <nvif/event.h>
33 nvif_notify_put_(struct nvif_notify
*notify
)
35 struct nvif_object
*object
= notify
->object
;
37 struct nvif_ioctl_v0 ioctl
;
38 struct nvif_ioctl_ntfy_put_v0 ntfy
;
40 .ioctl
.type
= NVIF_IOCTL_V0_NTFY_PUT
,
41 .ntfy
.index
= notify
->index
,
44 if (atomic_inc_return(¬ify
->putcnt
) != 1)
47 return nvif_object_ioctl(object
, &args
, sizeof(args
), NULL
);
51 nvif_notify_put(struct nvif_notify
*notify
)
53 if (likely(notify
->object
) &&
54 test_and_clear_bit(NVIF_NOTIFY_USER
, ¬ify
->flags
)) {
55 int ret
= nvif_notify_put_(notify
);
56 if (test_bit(NVIF_NOTIFY_WORK
, ¬ify
->flags
))
57 flush_work(¬ify
->work
);
64 nvif_notify_get_(struct nvif_notify
*notify
)
66 struct nvif_object
*object
= notify
->object
;
68 struct nvif_ioctl_v0 ioctl
;
69 struct nvif_ioctl_ntfy_get_v0 ntfy
;
71 .ioctl
.type
= NVIF_IOCTL_V0_NTFY_GET
,
72 .ntfy
.index
= notify
->index
,
75 if (atomic_dec_return(¬ify
->putcnt
) != 0)
78 return nvif_object_ioctl(object
, &args
, sizeof(args
), NULL
);
82 nvif_notify_get(struct nvif_notify
*notify
)
84 if (likely(notify
->object
) &&
85 !test_and_set_bit(NVIF_NOTIFY_USER
, ¬ify
->flags
))
86 return nvif_notify_get_(notify
);
91 nvif_notify_func(struct nvif_notify
*notify
, bool keep
)
93 int ret
= notify
->func(notify
);
94 if (ret
== NVIF_NOTIFY_KEEP
||
95 !test_and_clear_bit(NVIF_NOTIFY_USER
, ¬ify
->flags
)) {
97 atomic_dec(¬ify
->putcnt
);
99 nvif_notify_get_(notify
);
105 nvif_notify_work(struct work_struct
*work
)
107 struct nvif_notify
*notify
= container_of(work
, typeof(*notify
), work
);
108 nvif_notify_func(notify
, true);
112 nvif_notify(const void *header
, u32 length
, const void *data
, u32 size
)
114 struct nvif_notify
*notify
= NULL
;
116 struct nvif_notify_rep_v0 v0
;
118 int ret
= NVIF_NOTIFY_DROP
;
120 if (length
== sizeof(args
->v0
) && args
->v0
.version
== 0) {
121 if (WARN_ON(args
->v0
.route
))
122 return NVIF_NOTIFY_DROP
;
123 notify
= (void *)(unsigned long)args
->v0
.token
;
126 if (!WARN_ON(notify
== NULL
)) {
127 struct nvif_client
*client
= notify
->object
->client
;
128 if (!WARN_ON(notify
->size
!= size
)) {
129 atomic_inc(¬ify
->putcnt
);
130 if (test_bit(NVIF_NOTIFY_WORK
, ¬ify
->flags
)) {
131 memcpy((void *)notify
->data
, data
, size
);
132 schedule_work(¬ify
->work
);
133 return NVIF_NOTIFY_DROP
;
136 ret
= nvif_notify_func(notify
, client
->driver
->keep
);
145 nvif_notify_dtor(struct nvif_notify
*notify
)
147 struct nvif_object
*object
= notify
->object
;
149 struct nvif_ioctl_v0 ioctl
;
150 struct nvif_ioctl_ntfy_del_v0 ntfy
;
152 .ioctl
.type
= NVIF_IOCTL_V0_NTFY_DEL
,
153 .ntfy
.index
= notify
->index
,
155 int ret
= nvif_notify_put(notify
);
156 if (ret
>= 0 && object
) {
157 ret
= nvif_object_ioctl(object
, &args
, sizeof(args
), NULL
);
158 notify
->object
= NULL
;
159 kfree((void *)notify
->data
);
165 nvif_notify_ctor(struct nvif_object
*object
, const char *name
,
166 int (*func
)(struct nvif_notify
*), bool work
, u8 event
,
167 void *data
, u32 size
, u32 reply
, struct nvif_notify
*notify
)
170 struct nvif_ioctl_v0 ioctl
;
171 struct nvif_ioctl_ntfy_new_v0 ntfy
;
172 struct nvif_notify_req_v0 req
;
176 notify
->object
= object
;
177 notify
->name
= name
? name
: "nvifNotify";
179 atomic_set(¬ify
->putcnt
, 1);
182 notify
->size
= reply
;
184 INIT_WORK(¬ify
->work
, nvif_notify_work
);
185 set_bit(NVIF_NOTIFY_WORK
, ¬ify
->flags
);
186 notify
->data
= kmalloc(notify
->size
, GFP_KERNEL
);
191 if (!(args
= kmalloc(sizeof(*args
) + size
, GFP_KERNEL
)))
193 args
->ioctl
.version
= 0;
194 args
->ioctl
.type
= NVIF_IOCTL_V0_NTFY_NEW
;
195 args
->ntfy
.version
= 0;
196 args
->ntfy
.event
= event
;
197 args
->req
.version
= 0;
198 args
->req
.reply
= notify
->size
;
200 args
->req
.token
= (unsigned long)(void *)notify
;
202 memcpy(args
->req
.data
, data
, size
);
203 ret
= nvif_object_ioctl(object
, args
, sizeof(*args
) + size
, NULL
);
204 notify
->index
= args
->ntfy
.index
;
208 nvif_notify_dtor(notify
);