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>
24 #include <core/ioctl.h>
25 #include <core/client.h>
26 #include <core/engine.h>
28 #include <nvif/unpack.h>
29 #include <nvif/ioctl.h>
32 nvkm_ioctl_nop(struct nvkm_object
*object
, void *data
, u32 size
)
35 struct nvif_ioctl_nop_v0 v0
;
39 nvif_ioctl(object
, "nop size %d\n", size
);
40 if (nvif_unpack(args
->v0
, 0, 0, false)) {
41 nvif_ioctl(object
, "nop vers %lld\n", args
->v0
.version
);
42 args
->v0
.version
= NVIF_VERSION_LATEST
;
49 nvkm_ioctl_sclass(struct nvkm_object
*object
, void *data
, u32 size
)
52 struct nvif_ioctl_sclass_v0 v0
;
54 struct nvkm_oclass oclass
;
57 nvif_ioctl(object
, "sclass size %d\n", size
);
58 if (nvif_unpack(args
->v0
, 0, 0, true)) {
59 nvif_ioctl(object
, "sclass vers %d count %d\n",
60 args
->v0
.version
, args
->v0
.count
);
61 if (size
!= args
->v0
.count
* sizeof(args
->v0
.oclass
[0]))
64 while (object
->func
->sclass
&&
65 object
->func
->sclass(object
, i
, &oclass
) >= 0) {
66 if (i
< args
->v0
.count
) {
67 args
->v0
.oclass
[i
].oclass
= oclass
.base
.oclass
;
68 args
->v0
.oclass
[i
].minver
= oclass
.base
.minver
;
69 args
->v0
.oclass
[i
].maxver
= oclass
.base
.maxver
;
81 nvkm_ioctl_new(struct nvkm_object
*parent
, void *data
, u32 size
)
84 struct nvif_ioctl_new_v0 v0
;
86 struct nvkm_client
*client
= parent
->client
;
87 struct nvkm_object
*object
= NULL
;
88 struct nvkm_oclass oclass
;
91 nvif_ioctl(parent
, "new size %d\n", size
);
92 if (nvif_unpack(args
->v0
, 0, 0, true)) {
93 nvif_ioctl(parent
, "new vers %d handle %08x class %08x "
94 "route %02x token %llx object %016llx\n",
95 args
->v0
.version
, args
->v0
.handle
, args
->v0
.oclass
,
96 args
->v0
.route
, args
->v0
.token
, args
->v0
.object
);
100 if (!parent
->func
->sclass
) {
101 nvif_ioctl(parent
, "cannot have children\n");
106 memset(&oclass
, 0x00, sizeof(oclass
));
107 oclass
.client
= client
;
108 oclass
.handle
= args
->v0
.handle
;
109 oclass
.object
= args
->v0
.object
;
110 oclass
.parent
= parent
;
111 ret
= parent
->func
->sclass(parent
, i
++, &oclass
);
114 } while (oclass
.base
.oclass
!= args
->v0
.oclass
);
117 oclass
.engine
= nvkm_engine_ref(oclass
.engine
);
118 if (IS_ERR(oclass
.engine
))
119 return PTR_ERR(oclass
.engine
);
122 ret
= oclass
.ctor(&oclass
, data
, size
, &object
);
123 nvkm_engine_unref(&oclass
.engine
);
125 ret
= nvkm_object_init(object
);
127 list_add(&object
->head
, &parent
->tree
);
128 object
->route
= args
->v0
.route
;
129 object
->token
= args
->v0
.token
;
130 object
->object
= args
->v0
.object
;
131 if (nvkm_client_insert(client
, object
)) {
132 client
->data
= object
;
137 nvkm_object_fini(object
, false);
140 nvkm_object_del(&object
);
145 nvkm_ioctl_del(struct nvkm_object
*object
, void *data
, u32 size
)
148 struct nvif_ioctl_del none
;
152 nvif_ioctl(object
, "delete size %d\n", size
);
153 if (nvif_unvers(args
->none
)) {
154 nvif_ioctl(object
, "delete\n");
155 nvkm_object_fini(object
, false);
156 nvkm_object_del(&object
);
163 nvkm_ioctl_mthd(struct nvkm_object
*object
, void *data
, u32 size
)
166 struct nvif_ioctl_mthd_v0 v0
;
170 nvif_ioctl(object
, "mthd size %d\n", size
);
171 if (nvif_unpack(args
->v0
, 0, 0, true)) {
172 nvif_ioctl(object
, "mthd vers %d mthd %02x\n",
173 args
->v0
.version
, args
->v0
.method
);
174 ret
= nvkm_object_mthd(object
, args
->v0
.method
, data
, size
);
182 nvkm_ioctl_rd(struct nvkm_object
*object
, void *data
, u32 size
)
185 struct nvif_ioctl_rd_v0 v0
;
194 nvif_ioctl(object
, "rd size %d\n", size
);
195 if (nvif_unpack(args
->v0
, 0, 0, false)) {
196 nvif_ioctl(object
, "rd vers %d size %d addr %016llx\n",
197 args
->v0
.version
, args
->v0
.size
, args
->v0
.addr
);
198 switch (args
->v0
.size
) {
200 ret
= nvkm_object_rd08(object
, args
->v0
.addr
, &v
.b08
);
201 args
->v0
.data
= v
.b08
;
204 ret
= nvkm_object_rd16(object
, args
->v0
.addr
, &v
.b16
);
205 args
->v0
.data
= v
.b16
;
208 ret
= nvkm_object_rd32(object
, args
->v0
.addr
, &v
.b32
);
209 args
->v0
.data
= v
.b32
;
221 nvkm_ioctl_wr(struct nvkm_object
*object
, void *data
, u32 size
)
224 struct nvif_ioctl_wr_v0 v0
;
228 nvif_ioctl(object
, "wr size %d\n", size
);
229 if (nvif_unpack(args
->v0
, 0, 0, false)) {
231 "wr vers %d size %d addr %016llx data %08x\n",
232 args
->v0
.version
, args
->v0
.size
, args
->v0
.addr
,
237 switch (args
->v0
.size
) {
238 case 1: return nvkm_object_wr08(object
, args
->v0
.addr
, args
->v0
.data
);
239 case 2: return nvkm_object_wr16(object
, args
->v0
.addr
, args
->v0
.data
);
240 case 4: return nvkm_object_wr32(object
, args
->v0
.addr
, args
->v0
.data
);
249 nvkm_ioctl_map(struct nvkm_object
*object
, void *data
, u32 size
)
252 struct nvif_ioctl_map_v0 v0
;
256 nvif_ioctl(object
, "map size %d\n", size
);
257 if (nvif_unpack(args
->v0
, 0, 0, false)) {
258 nvif_ioctl(object
, "map vers %d\n", args
->v0
.version
);
259 ret
= nvkm_object_map(object
, &args
->v0
.handle
,
267 nvkm_ioctl_unmap(struct nvkm_object
*object
, void *data
, u32 size
)
270 struct nvif_ioctl_unmap none
;
274 nvif_ioctl(object
, "unmap size %d\n", size
);
275 if (nvif_unvers(args
->none
)) {
276 nvif_ioctl(object
, "unmap\n");
283 nvkm_ioctl_ntfy_new(struct nvkm_object
*object
, void *data
, u32 size
)
286 struct nvif_ioctl_ntfy_new_v0 v0
;
288 struct nvkm_event
*event
;
291 nvif_ioctl(object
, "ntfy new size %d\n", size
);
292 if (nvif_unpack(args
->v0
, 0, 0, true)) {
293 nvif_ioctl(object
, "ntfy new vers %d event %02x\n",
294 args
->v0
.version
, args
->v0
.event
);
295 ret
= nvkm_object_ntfy(object
, args
->v0
.event
, &event
);
297 ret
= nvkm_client_notify_new(object
, event
, data
, size
);
299 args
->v0
.index
= ret
;
309 nvkm_ioctl_ntfy_del(struct nvkm_object
*object
, void *data
, u32 size
)
311 struct nvkm_client
*client
= object
->client
;
313 struct nvif_ioctl_ntfy_del_v0 v0
;
317 nvif_ioctl(object
, "ntfy del size %d\n", size
);
318 if (nvif_unpack(args
->v0
, 0, 0, false)) {
319 nvif_ioctl(object
, "ntfy del vers %d index %d\n",
320 args
->v0
.version
, args
->v0
.index
);
321 ret
= nvkm_client_notify_del(client
, args
->v0
.index
);
328 nvkm_ioctl_ntfy_get(struct nvkm_object
*object
, void *data
, u32 size
)
330 struct nvkm_client
*client
= object
->client
;
332 struct nvif_ioctl_ntfy_get_v0 v0
;
336 nvif_ioctl(object
, "ntfy get size %d\n", size
);
337 if (nvif_unpack(args
->v0
, 0, 0, false)) {
338 nvif_ioctl(object
, "ntfy get vers %d index %d\n",
339 args
->v0
.version
, args
->v0
.index
);
340 ret
= nvkm_client_notify_get(client
, args
->v0
.index
);
347 nvkm_ioctl_ntfy_put(struct nvkm_object
*object
, void *data
, u32 size
)
349 struct nvkm_client
*client
= object
->client
;
351 struct nvif_ioctl_ntfy_put_v0 v0
;
355 nvif_ioctl(object
, "ntfy put size %d\n", size
);
356 if (nvif_unpack(args
->v0
, 0, 0, false)) {
357 nvif_ioctl(object
, "ntfy put vers %d index %d\n",
358 args
->v0
.version
, args
->v0
.index
);
359 ret
= nvkm_client_notify_put(client
, args
->v0
.index
);
367 int (*func
)(struct nvkm_object
*, void *, u32
);
370 { 0x00, nvkm_ioctl_nop
},
371 { 0x00, nvkm_ioctl_sclass
},
372 { 0x00, nvkm_ioctl_new
},
373 { 0x00, nvkm_ioctl_del
},
374 { 0x00, nvkm_ioctl_mthd
},
375 { 0x00, nvkm_ioctl_rd
},
376 { 0x00, nvkm_ioctl_wr
},
377 { 0x00, nvkm_ioctl_map
},
378 { 0x00, nvkm_ioctl_unmap
},
379 { 0x00, nvkm_ioctl_ntfy_new
},
380 { 0x00, nvkm_ioctl_ntfy_del
},
381 { 0x00, nvkm_ioctl_ntfy_get
},
382 { 0x00, nvkm_ioctl_ntfy_put
},
386 nvkm_ioctl_path(struct nvkm_client
*client
, u64 handle
, u32 type
,
387 void *data
, u32 size
, u8 owner
, u8
*route
, u64
*token
)
389 struct nvkm_object
*object
;
393 object
= nvkm_client_search(client
, handle
);
395 object
= &client
->object
;
396 if (unlikely(!object
)) {
397 nvif_ioctl(&client
->object
, "object not found\n");
401 if (owner
!= NVIF_IOCTL_V0_OWNER_ANY
&& owner
!= object
->route
) {
402 nvif_ioctl(&client
->object
, "route != owner\n");
405 *route
= object
->route
;
406 *token
= object
->token
;
408 if (ret
= -EINVAL
, type
< ARRAY_SIZE(nvkm_ioctl_v0
)) {
409 if (nvkm_ioctl_v0
[type
].version
== 0)
410 ret
= nvkm_ioctl_v0
[type
].func(object
, data
, size
);
417 nvkm_ioctl(struct nvkm_client
*client
, bool supervisor
,
418 void *data
, u32 size
, void **hack
)
420 struct nvkm_object
*object
= &client
->object
;
422 struct nvif_ioctl_v0 v0
;
426 client
->super
= supervisor
;
427 nvif_ioctl(object
, "size %d\n", size
);
429 if (nvif_unpack(args
->v0
, 0, 0, true)) {
431 "vers %d type %02x object %016llx owner %02x\n",
432 args
->v0
.version
, args
->v0
.type
, args
->v0
.object
,
434 ret
= nvkm_ioctl_path(client
, args
->v0
.object
, args
->v0
.type
,
435 data
, size
, args
->v0
.owner
,
436 &args
->v0
.route
, &args
->v0
.token
);
439 nvif_ioctl(object
, "return %d\n", ret
);
441 *hack
= client
->data
;
445 client
->super
= false;