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>
27 #include <core/handle.h>
28 #include <core/namedb.h>
30 #include <nvif/unpack.h>
31 #include <nvif/ioctl.h>
34 nvkm_ioctl_nop(struct nvkm_handle
*handle
, void *data
, u32 size
)
36 struct nvkm_object
*object
= handle
->object
;
38 struct nvif_ioctl_nop none
;
42 nv_ioctl(object
, "nop size %d\n", size
);
43 if (nvif_unvers(args
->none
)) {
44 nv_ioctl(object
, "nop\n");
51 nvkm_ioctl_sclass(struct nvkm_handle
*handle
, void *data
, u32 size
)
53 struct nvkm_object
*object
= handle
->object
;
55 struct nvif_ioctl_sclass_v0 v0
;
59 if (!nv_iclass(object
, NV_PARENT_CLASS
)) {
60 nv_debug(object
, "cannot have children (sclass)\n");
64 nv_ioctl(object
, "sclass size %d\n", size
);
65 if (nvif_unpack(args
->v0
, 0, 0, true)) {
66 nv_ioctl(object
, "sclass vers %d count %d\n",
67 args
->v0
.version
, args
->v0
.count
);
68 if (size
== args
->v0
.count
* sizeof(args
->v0
.oclass
[0])) {
69 ret
= nvkm_parent_lclass(object
, args
->v0
.oclass
,
84 nvkm_ioctl_new(struct nvkm_handle
*handle
, void *data
, u32 size
)
87 struct nvif_ioctl_new_v0 v0
;
89 struct nvkm_client
*client
= nvkm_client(handle
->object
);
90 struct nvkm_object
*engctx
= NULL
;
91 struct nvkm_object
*object
= NULL
;
92 struct nvkm_parent
*parent
;
93 struct nvkm_object
*engine
;
94 struct nvkm_oclass
*oclass
;
98 nv_ioctl(client
, "new size %d\n", size
);
99 if (nvif_unpack(args
->v0
, 0, 0, true)) {
100 _handle
= args
->v0
.handle
;
101 _oclass
= args
->v0
.oclass
;
105 nv_ioctl(client
, "new vers %d handle %08x class %08x "
106 "route %02x token %llx\n",
107 args
->v0
.version
, _handle
, _oclass
,
108 args
->v0
.route
, args
->v0
.token
);
110 if (!nv_iclass(handle
->object
, NV_PARENT_CLASS
)) {
111 nv_debug(handle
->object
, "cannot have children (ctor)\n");
116 parent
= nv_parent(handle
->object
);
118 /* check that parent supports the requested subclass */
119 ret
= nvkm_parent_sclass(&parent
->object
, _oclass
, &engine
, &oclass
);
121 nv_debug(parent
, "illegal class 0x%04x\n", _oclass
);
125 /* make sure engine init has been completed *before* any objects
126 * it controls are created - the constructors may depend on
127 * state calculated at init (ie. default context construction)
130 ret
= nvkm_object_inc(engine
);
135 /* if engine requires it, create a context object to insert
136 * between the parent and its children (eg. PGRAPH context)
138 if (engine
&& nv_engine(engine
)->cclass
) {
139 ret
= nvkm_object_ctor(&parent
->object
, engine
,
140 nv_engine(engine
)->cclass
,
141 data
, size
, &engctx
);
145 nvkm_object_ref(&parent
->object
, &engctx
);
148 /* finally, create new object and bind it to its handle */
149 ret
= nvkm_object_ctor(engctx
, engine
, oclass
, data
, size
, &object
);
150 client
->data
= object
;
154 ret
= nvkm_object_inc(object
);
158 ret
= nvkm_handle_create(&parent
->object
, handle
->name
,
159 _handle
, object
, &handle
);
163 ret
= nvkm_handle_init(handle
);
164 handle
->route
= args
->v0
.route
;
165 handle
->token
= args
->v0
.token
;
167 nvkm_handle_destroy(handle
);
170 nvkm_object_dec(object
, false);
172 nvkm_object_ref(NULL
, &object
);
174 nvkm_object_ref(NULL
, &engctx
);
177 nvkm_object_dec(engine
, false);
183 nvkm_ioctl_del(struct nvkm_handle
*handle
, void *data
, u32 size
)
185 struct nvkm_object
*object
= handle
->object
;
187 struct nvif_ioctl_del none
;
191 nv_ioctl(object
, "delete size %d\n", size
);
192 if (nvif_unvers(args
->none
)) {
193 nv_ioctl(object
, "delete\n");
194 nvkm_handle_fini(handle
, false);
195 nvkm_handle_destroy(handle
);
202 nvkm_ioctl_mthd(struct nvkm_handle
*handle
, void *data
, u32 size
)
204 struct nvkm_object
*object
= handle
->object
;
205 struct nvkm_ofuncs
*ofuncs
= object
->oclass
->ofuncs
;
207 struct nvif_ioctl_mthd_v0 v0
;
211 nv_ioctl(object
, "mthd size %d\n", size
);
212 if (nvif_unpack(args
->v0
, 0, 0, true)) {
213 nv_ioctl(object
, "mthd vers %d mthd %02x\n",
214 args
->v0
.version
, args
->v0
.method
);
215 if (ret
= -ENODEV
, ofuncs
->mthd
)
216 ret
= ofuncs
->mthd(object
, args
->v0
.method
, data
, size
);
224 nvkm_ioctl_rd(struct nvkm_handle
*handle
, void *data
, u32 size
)
226 struct nvkm_object
*object
= handle
->object
;
227 struct nvkm_ofuncs
*ofuncs
= object
->oclass
->ofuncs
;
229 struct nvif_ioctl_rd_v0 v0
;
233 nv_ioctl(object
, "rd size %d\n", size
);
234 if (nvif_unpack(args
->v0
, 0, 0, false)) {
235 nv_ioctl(object
, "rd vers %d size %d addr %016llx\n",
236 args
->v0
.version
, args
->v0
.size
, args
->v0
.addr
);
237 switch (args
->v0
.size
) {
239 if (ret
= -ENODEV
, ofuncs
->rd08
) {
240 args
->v0
.data
= nv_ro08(object
, args
->v0
.addr
);
245 if (ret
= -ENODEV
, ofuncs
->rd16
) {
246 args
->v0
.data
= nv_ro16(object
, args
->v0
.addr
);
251 if (ret
= -ENODEV
, ofuncs
->rd32
) {
252 args
->v0
.data
= nv_ro32(object
, args
->v0
.addr
);
266 nvkm_ioctl_wr(struct nvkm_handle
*handle
, void *data
, u32 size
)
268 struct nvkm_object
*object
= handle
->object
;
269 struct nvkm_ofuncs
*ofuncs
= object
->oclass
->ofuncs
;
271 struct nvif_ioctl_wr_v0 v0
;
275 nv_ioctl(object
, "wr size %d\n", size
);
276 if (nvif_unpack(args
->v0
, 0, 0, false)) {
277 nv_ioctl(object
, "wr vers %d size %d addr %016llx data %08x\n",
278 args
->v0
.version
, args
->v0
.size
, args
->v0
.addr
,
280 switch (args
->v0
.size
) {
282 if (ret
= -ENODEV
, ofuncs
->wr08
) {
283 nv_wo08(object
, args
->v0
.addr
, args
->v0
.data
);
288 if (ret
= -ENODEV
, ofuncs
->wr16
) {
289 nv_wo16(object
, args
->v0
.addr
, args
->v0
.data
);
294 if (ret
= -ENODEV
, ofuncs
->wr32
) {
295 nv_wo32(object
, args
->v0
.addr
, args
->v0
.data
);
309 nvkm_ioctl_map(struct nvkm_handle
*handle
, void *data
, u32 size
)
311 struct nvkm_object
*object
= handle
->object
;
312 struct nvkm_ofuncs
*ofuncs
= object
->oclass
->ofuncs
;
314 struct nvif_ioctl_map_v0 v0
;
318 nv_ioctl(object
, "map size %d\n", size
);
319 if (nvif_unpack(args
->v0
, 0, 0, false)) {
320 nv_ioctl(object
, "map vers %d\n", args
->v0
.version
);
321 if (ret
= -ENODEV
, ofuncs
->map
) {
322 ret
= ofuncs
->map(object
, &args
->v0
.handle
,
331 nvkm_ioctl_unmap(struct nvkm_handle
*handle
, void *data
, u32 size
)
333 struct nvkm_object
*object
= handle
->object
;
335 struct nvif_ioctl_unmap none
;
339 nv_ioctl(object
, "unmap size %d\n", size
);
340 if (nvif_unvers(args
->none
)) {
341 nv_ioctl(object
, "unmap\n");
348 nvkm_ioctl_ntfy_new(struct nvkm_handle
*handle
, void *data
, u32 size
)
350 struct nvkm_object
*object
= handle
->object
;
351 struct nvkm_ofuncs
*ofuncs
= object
->oclass
->ofuncs
;
353 struct nvif_ioctl_ntfy_new_v0 v0
;
355 struct nvkm_event
*event
;
358 nv_ioctl(object
, "ntfy new size %d\n", size
);
359 if (nvif_unpack(args
->v0
, 0, 0, true)) {
360 nv_ioctl(object
, "ntfy new vers %d event %02x\n",
361 args
->v0
.version
, args
->v0
.event
);
362 if (ret
= -ENODEV
, ofuncs
->ntfy
)
363 ret
= ofuncs
->ntfy(object
, args
->v0
.event
, &event
);
365 ret
= nvkm_client_notify_new(object
, event
, data
, size
);
367 args
->v0
.index
= ret
;
377 nvkm_ioctl_ntfy_del(struct nvkm_handle
*handle
, void *data
, u32 size
)
379 struct nvkm_client
*client
= nvkm_client(handle
->object
);
380 struct nvkm_object
*object
= handle
->object
;
382 struct nvif_ioctl_ntfy_del_v0 v0
;
386 nv_ioctl(object
, "ntfy del size %d\n", size
);
387 if (nvif_unpack(args
->v0
, 0, 0, false)) {
388 nv_ioctl(object
, "ntfy del vers %d index %d\n",
389 args
->v0
.version
, args
->v0
.index
);
390 ret
= nvkm_client_notify_del(client
, args
->v0
.index
);
397 nvkm_ioctl_ntfy_get(struct nvkm_handle
*handle
, void *data
, u32 size
)
399 struct nvkm_client
*client
= nvkm_client(handle
->object
);
400 struct nvkm_object
*object
= handle
->object
;
402 struct nvif_ioctl_ntfy_get_v0 v0
;
406 nv_ioctl(object
, "ntfy get size %d\n", size
);
407 if (nvif_unpack(args
->v0
, 0, 0, false)) {
408 nv_ioctl(object
, "ntfy get vers %d index %d\n",
409 args
->v0
.version
, args
->v0
.index
);
410 ret
= nvkm_client_notify_get(client
, args
->v0
.index
);
417 nvkm_ioctl_ntfy_put(struct nvkm_handle
*handle
, void *data
, u32 size
)
419 struct nvkm_client
*client
= nvkm_client(handle
->object
);
420 struct nvkm_object
*object
= handle
->object
;
422 struct nvif_ioctl_ntfy_put_v0 v0
;
426 nv_ioctl(object
, "ntfy put size %d\n", size
);
427 if (nvif_unpack(args
->v0
, 0, 0, false)) {
428 nv_ioctl(object
, "ntfy put vers %d index %d\n",
429 args
->v0
.version
, args
->v0
.index
);
430 ret
= nvkm_client_notify_put(client
, args
->v0
.index
);
438 int (*func
)(struct nvkm_handle
*, void *, u32
);
441 { 0x00, nvkm_ioctl_nop
},
442 { 0x00, nvkm_ioctl_sclass
},
443 { 0x00, nvkm_ioctl_new
},
444 { 0x00, nvkm_ioctl_del
},
445 { 0x00, nvkm_ioctl_mthd
},
446 { 0x00, nvkm_ioctl_rd
},
447 { 0x00, nvkm_ioctl_wr
},
448 { 0x00, nvkm_ioctl_map
},
449 { 0x00, nvkm_ioctl_unmap
},
450 { 0x00, nvkm_ioctl_ntfy_new
},
451 { 0x00, nvkm_ioctl_ntfy_del
},
452 { 0x00, nvkm_ioctl_ntfy_get
},
453 { 0x00, nvkm_ioctl_ntfy_put
},
457 nvkm_ioctl_path(struct nvkm_handle
*parent
, u32 type
, u32 nr
, u32
*path
,
458 void *data
, u32 size
, u8 owner
, u8
*route
, u64
*token
)
460 struct nvkm_handle
*handle
= parent
;
461 struct nvkm_namedb
*namedb
;
462 struct nvkm_object
*object
;
465 while ((object
= parent
->object
), nr
--) {
466 nv_ioctl(object
, "path 0x%08x\n", path
[nr
]);
467 if (!nv_iclass(object
, NV_PARENT_CLASS
)) {
468 nv_debug(object
, "cannot have children (path)\n");
472 if (!(namedb
= (void *)nv_pclass(object
, NV_NAMEDB_CLASS
)) ||
473 !(handle
= nvkm_namedb_get(namedb
, path
[nr
]))) {
474 nv_debug(object
, "handle 0x%08x not found\n", path
[nr
]);
477 nvkm_namedb_put(handle
);
481 if (owner
!= NVIF_IOCTL_V0_OWNER_ANY
&& owner
!= handle
->route
) {
482 nv_ioctl(object
, "object route != owner\n");
485 *route
= handle
->route
;
486 *token
= handle
->token
;
488 if (ret
= -EINVAL
, type
< ARRAY_SIZE(nvkm_ioctl_v0
)) {
489 if (nvkm_ioctl_v0
[type
].version
== 0)
490 ret
= nvkm_ioctl_v0
[type
].func(handle
, data
, size
);
497 nvkm_ioctl(struct nvkm_client
*client
, bool supervisor
,
498 void *data
, u32 size
, void **hack
)
501 struct nvif_ioctl_v0 v0
;
505 client
->super
= supervisor
;
506 nv_ioctl(client
, "size %d\n", size
);
508 if (nvif_unpack(args
->v0
, 0, 0, true)) {
509 nv_ioctl(client
, "vers %d type %02x path %d owner %02x\n",
510 args
->v0
.version
, args
->v0
.type
, args
->v0
.path_nr
,
512 ret
= nvkm_ioctl_path(client
->root
, args
->v0
.type
,
513 args
->v0
.path_nr
, args
->v0
.path
,
514 data
, size
, args
->v0
.owner
,
515 &args
->v0
.route
, &args
->v0
.token
);
518 nv_ioctl(client
, "return %d\n", ret
);
520 *hack
= client
->data
;
524 client
->super
= false;