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_client
*client
,
33 struct nvkm_object
*object
, void *data
, u32 size
)
36 struct nvif_ioctl_nop_v0 v0
;
40 nvif_ioctl(object
, "nop size %d\n", size
);
41 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
42 nvif_ioctl(object
, "nop vers %lld\n", args
->v0
.version
);
43 args
->v0
.version
= NVIF_VERSION_LATEST
;
50 nvkm_ioctl_sclass(struct nvkm_client
*client
,
51 struct nvkm_object
*object
, void *data
, u32 size
)
54 struct nvif_ioctl_sclass_v0 v0
;
56 struct nvkm_oclass oclass
= { .client
= client
};
57 int ret
= -ENOSYS
, i
= 0;
59 nvif_ioctl(object
, "sclass size %d\n", size
);
60 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
61 nvif_ioctl(object
, "sclass vers %d count %d\n",
62 args
->v0
.version
, args
->v0
.count
);
63 if (size
!= args
->v0
.count
* sizeof(args
->v0
.oclass
[0]))
66 while (object
->func
->sclass
&&
67 object
->func
->sclass(object
, i
, &oclass
) >= 0) {
68 if (i
< args
->v0
.count
) {
69 args
->v0
.oclass
[i
].oclass
= oclass
.base
.oclass
;
70 args
->v0
.oclass
[i
].minver
= oclass
.base
.minver
;
71 args
->v0
.oclass
[i
].maxver
= oclass
.base
.maxver
;
83 nvkm_ioctl_new(struct nvkm_client
*client
,
84 struct nvkm_object
*parent
, void *data
, u32 size
)
87 struct nvif_ioctl_new_v0 v0
;
89 struct nvkm_object
*object
= NULL
;
90 struct nvkm_oclass oclass
;
91 int ret
= -ENOSYS
, i
= 0;
93 nvif_ioctl(parent
, "new size %d\n", size
);
94 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
95 nvif_ioctl(parent
, "new vers %d handle %08x class %08x "
96 "route %02x token %llx object %016llx\n",
97 args
->v0
.version
, args
->v0
.handle
, args
->v0
.oclass
,
98 args
->v0
.route
, args
->v0
.token
, args
->v0
.object
);
102 if (!parent
->func
->sclass
) {
103 nvif_ioctl(parent
, "cannot have children\n");
108 memset(&oclass
, 0x00, sizeof(oclass
));
109 oclass
.handle
= args
->v0
.handle
;
110 oclass
.route
= args
->v0
.route
;
111 oclass
.token
= args
->v0
.token
;
112 oclass
.object
= args
->v0
.object
;
113 oclass
.client
= client
;
114 oclass
.parent
= parent
;
115 ret
= parent
->func
->sclass(parent
, i
++, &oclass
);
118 } while (oclass
.base
.oclass
!= args
->v0
.oclass
);
121 oclass
.engine
= nvkm_engine_ref(oclass
.engine
);
122 if (IS_ERR(oclass
.engine
))
123 return PTR_ERR(oclass
.engine
);
126 ret
= oclass
.ctor(&oclass
, data
, size
, &object
);
127 nvkm_engine_unref(&oclass
.engine
);
129 ret
= nvkm_object_init(object
);
131 list_add(&object
->head
, &parent
->tree
);
132 if (nvkm_object_insert(object
)) {
133 client
->data
= object
;
138 nvkm_object_fini(object
, false);
141 nvkm_object_del(&object
);
146 nvkm_ioctl_del(struct nvkm_client
*client
,
147 struct nvkm_object
*object
, void *data
, u32 size
)
150 struct nvif_ioctl_del none
;
154 nvif_ioctl(object
, "delete size %d\n", size
);
155 if (!(ret
= nvif_unvers(ret
, &data
, &size
, args
->none
))) {
156 nvif_ioctl(object
, "delete\n");
157 nvkm_object_fini(object
, false);
158 nvkm_object_del(&object
);
161 return ret
? ret
: 1;
165 nvkm_ioctl_mthd(struct nvkm_client
*client
,
166 struct nvkm_object
*object
, void *data
, u32 size
)
169 struct nvif_ioctl_mthd_v0 v0
;
173 nvif_ioctl(object
, "mthd size %d\n", size
);
174 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
175 nvif_ioctl(object
, "mthd vers %d mthd %02x\n",
176 args
->v0
.version
, args
->v0
.method
);
177 ret
= nvkm_object_mthd(object
, args
->v0
.method
, data
, size
);
185 nvkm_ioctl_rd(struct nvkm_client
*client
,
186 struct nvkm_object
*object
, void *data
, u32 size
)
189 struct nvif_ioctl_rd_v0 v0
;
198 nvif_ioctl(object
, "rd size %d\n", size
);
199 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
200 nvif_ioctl(object
, "rd vers %d size %d addr %016llx\n",
201 args
->v0
.version
, args
->v0
.size
, args
->v0
.addr
);
202 switch (args
->v0
.size
) {
204 ret
= nvkm_object_rd08(object
, args
->v0
.addr
, &v
.b08
);
205 args
->v0
.data
= v
.b08
;
208 ret
= nvkm_object_rd16(object
, args
->v0
.addr
, &v
.b16
);
209 args
->v0
.data
= v
.b16
;
212 ret
= nvkm_object_rd32(object
, args
->v0
.addr
, &v
.b32
);
213 args
->v0
.data
= v
.b32
;
225 nvkm_ioctl_wr(struct nvkm_client
*client
,
226 struct nvkm_object
*object
, void *data
, u32 size
)
229 struct nvif_ioctl_wr_v0 v0
;
233 nvif_ioctl(object
, "wr size %d\n", size
);
234 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
236 "wr vers %d size %d addr %016llx data %08x\n",
237 args
->v0
.version
, args
->v0
.size
, args
->v0
.addr
,
242 switch (args
->v0
.size
) {
243 case 1: return nvkm_object_wr08(object
, args
->v0
.addr
, args
->v0
.data
);
244 case 2: return nvkm_object_wr16(object
, args
->v0
.addr
, args
->v0
.data
);
245 case 4: return nvkm_object_wr32(object
, args
->v0
.addr
, args
->v0
.data
);
254 nvkm_ioctl_map(struct nvkm_client
*client
,
255 struct nvkm_object
*object
, void *data
, u32 size
)
258 struct nvif_ioctl_map_v0 v0
;
260 enum nvkm_object_map type
;
263 nvif_ioctl(object
, "map size %d\n", size
);
264 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
265 nvif_ioctl(object
, "map vers %d\n", args
->v0
.version
);
266 ret
= nvkm_object_map(object
, data
, size
, &type
,
269 if (type
== NVKM_OBJECT_MAP_IO
)
270 args
->v0
.type
= NVIF_IOCTL_MAP_V0_IO
;
272 args
->v0
.type
= NVIF_IOCTL_MAP_V0_VA
;
279 nvkm_ioctl_unmap(struct nvkm_client
*client
,
280 struct nvkm_object
*object
, void *data
, u32 size
)
283 struct nvif_ioctl_unmap none
;
287 nvif_ioctl(object
, "unmap size %d\n", size
);
288 if (!(ret
= nvif_unvers(ret
, &data
, &size
, args
->none
))) {
289 nvif_ioctl(object
, "unmap\n");
290 ret
= nvkm_object_unmap(object
);
297 nvkm_ioctl_ntfy_new(struct nvkm_client
*client
,
298 struct nvkm_object
*object
, void *data
, u32 size
)
301 struct nvif_ioctl_ntfy_new_v0 v0
;
303 struct nvkm_event
*event
;
306 nvif_ioctl(object
, "ntfy new size %d\n", size
);
307 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
308 nvif_ioctl(object
, "ntfy new vers %d event %02x\n",
309 args
->v0
.version
, args
->v0
.event
);
310 ret
= nvkm_object_ntfy(object
, args
->v0
.event
, &event
);
312 ret
= nvkm_client_notify_new(object
, event
, data
, size
);
314 args
->v0
.index
= ret
;
324 nvkm_ioctl_ntfy_del(struct nvkm_client
*client
,
325 struct nvkm_object
*object
, void *data
, u32 size
)
328 struct nvif_ioctl_ntfy_del_v0 v0
;
332 nvif_ioctl(object
, "ntfy del size %d\n", size
);
333 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
334 nvif_ioctl(object
, "ntfy del vers %d index %d\n",
335 args
->v0
.version
, args
->v0
.index
);
336 ret
= nvkm_client_notify_del(client
, args
->v0
.index
);
343 nvkm_ioctl_ntfy_get(struct nvkm_client
*client
,
344 struct nvkm_object
*object
, void *data
, u32 size
)
347 struct nvif_ioctl_ntfy_get_v0 v0
;
351 nvif_ioctl(object
, "ntfy get size %d\n", size
);
352 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
353 nvif_ioctl(object
, "ntfy get vers %d index %d\n",
354 args
->v0
.version
, args
->v0
.index
);
355 ret
= nvkm_client_notify_get(client
, args
->v0
.index
);
362 nvkm_ioctl_ntfy_put(struct nvkm_client
*client
,
363 struct nvkm_object
*object
, void *data
, u32 size
)
366 struct nvif_ioctl_ntfy_put_v0 v0
;
370 nvif_ioctl(object
, "ntfy put size %d\n", size
);
371 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
372 nvif_ioctl(object
, "ntfy put vers %d index %d\n",
373 args
->v0
.version
, args
->v0
.index
);
374 ret
= nvkm_client_notify_put(client
, args
->v0
.index
);
382 int (*func
)(struct nvkm_client
*, struct nvkm_object
*, void *, u32
);
385 { 0x00, nvkm_ioctl_nop
},
386 { 0x00, nvkm_ioctl_sclass
},
387 { 0x00, nvkm_ioctl_new
},
388 { 0x00, nvkm_ioctl_del
},
389 { 0x00, nvkm_ioctl_mthd
},
390 { 0x00, nvkm_ioctl_rd
},
391 { 0x00, nvkm_ioctl_wr
},
392 { 0x00, nvkm_ioctl_map
},
393 { 0x00, nvkm_ioctl_unmap
},
394 { 0x00, nvkm_ioctl_ntfy_new
},
395 { 0x00, nvkm_ioctl_ntfy_del
},
396 { 0x00, nvkm_ioctl_ntfy_get
},
397 { 0x00, nvkm_ioctl_ntfy_put
},
401 nvkm_ioctl_path(struct nvkm_client
*client
, u64 handle
, u32 type
,
402 void *data
, u32 size
, u8 owner
, u8
*route
, u64
*token
)
404 struct nvkm_object
*object
;
407 object
= nvkm_object_search(client
, handle
, NULL
);
408 if (IS_ERR(object
)) {
409 nvif_ioctl(&client
->object
, "object not found\n");
410 return PTR_ERR(object
);
413 if (owner
!= NVIF_IOCTL_V0_OWNER_ANY
&& owner
!= object
->route
) {
414 nvif_ioctl(&client
->object
, "route != owner\n");
417 *route
= object
->route
;
418 *token
= object
->token
;
420 if (ret
= -EINVAL
, type
< ARRAY_SIZE(nvkm_ioctl_v0
)) {
421 if (nvkm_ioctl_v0
[type
].version
== 0)
422 ret
= nvkm_ioctl_v0
[type
].func(client
, object
, data
, size
);
429 nvkm_ioctl(struct nvkm_client
*client
, bool supervisor
,
430 void *data
, u32 size
, void **hack
)
432 struct nvkm_object
*object
= &client
->object
;
434 struct nvif_ioctl_v0 v0
;
438 client
->super
= supervisor
;
439 nvif_ioctl(object
, "size %d\n", size
);
441 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, true))) {
443 "vers %d type %02x object %016llx owner %02x\n",
444 args
->v0
.version
, args
->v0
.type
, args
->v0
.object
,
446 ret
= nvkm_ioctl_path(client
, args
->v0
.object
, args
->v0
.type
,
447 data
, size
, args
->v0
.owner
,
448 &args
->v0
.route
, &args
->v0
.token
);
452 nvif_ioctl(object
, "return %d\n", ret
);
454 *hack
= client
->data
;