127111a23SBen Skeggs /*
227111a23SBen Skeggs * Copyright 2014 Red Hat Inc.
327111a23SBen Skeggs *
427111a23SBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
527111a23SBen Skeggs * copy of this software and associated documentation files (the "Software"),
627111a23SBen Skeggs * to deal in the Software without restriction, including without limitation
727111a23SBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
827111a23SBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
927111a23SBen Skeggs * Software is furnished to do so, subject to the following conditions:
1027111a23SBen Skeggs *
1127111a23SBen Skeggs * The above copyright notice and this permission notice shall be included in
1227111a23SBen Skeggs * all copies or substantial portions of the Software.
1327111a23SBen Skeggs *
1427111a23SBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1527111a23SBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1627111a23SBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1727111a23SBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1827111a23SBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1927111a23SBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2027111a23SBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
2127111a23SBen Skeggs *
2227111a23SBen Skeggs * Authors: Ben Skeggs <bskeggs@redhat.com>
2327111a23SBen Skeggs */
2427111a23SBen Skeggs
254dc28134SBen Skeggs #include "nouveau_drv.h"
2627111a23SBen Skeggs #include "nouveau_usif.h"
272621a416SBen Skeggs #include "nouveau_abi16.h"
2827111a23SBen Skeggs
2927111a23SBen Skeggs #include <nvif/unpack.h>
3027111a23SBen Skeggs #include <nvif/client.h>
3127111a23SBen Skeggs #include <nvif/ioctl.h>
3227111a23SBen Skeggs
33*148a8653SBen Skeggs #include <nvif/class.h>
34*148a8653SBen Skeggs #include <nvif/cl0080.h>
35*148a8653SBen Skeggs
3627111a23SBen Skeggs struct usif_object {
3727111a23SBen Skeggs struct list_head head;
3827111a23SBen Skeggs u8 route;
3927111a23SBen Skeggs u64 token;
4027111a23SBen Skeggs };
4127111a23SBen Skeggs
4227111a23SBen Skeggs static void
usif_object_dtor(struct usif_object * object)4327111a23SBen Skeggs usif_object_dtor(struct usif_object *object)
4427111a23SBen Skeggs {
4527111a23SBen Skeggs list_del(&object->head);
4627111a23SBen Skeggs kfree(object);
4727111a23SBen Skeggs }
4827111a23SBen Skeggs
4927111a23SBen Skeggs static int
usif_object_new(struct drm_file * f,void * data,u32 size,void * argv,u32 argc,bool parent_abi16)50*148a8653SBen Skeggs usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc, bool parent_abi16)
5127111a23SBen Skeggs {
5227111a23SBen Skeggs struct nouveau_cli *cli = nouveau_cli(f);
5327111a23SBen Skeggs struct nvif_client *client = &cli->base;
5427111a23SBen Skeggs union {
5527111a23SBen Skeggs struct nvif_ioctl_new_v0 v0;
5627111a23SBen Skeggs } *args = data;
5727111a23SBen Skeggs struct usif_object *object;
58f01c4e68SBen Skeggs int ret = -ENOSYS;
5927111a23SBen Skeggs
60*148a8653SBen Skeggs if ((ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true)))
61*148a8653SBen Skeggs return ret;
62*148a8653SBen Skeggs
63*148a8653SBen Skeggs switch (args->v0.oclass) {
64*148a8653SBen Skeggs case NV_DMA_FROM_MEMORY:
65*148a8653SBen Skeggs case NV_DMA_TO_MEMORY:
66*148a8653SBen Skeggs case NV_DMA_IN_MEMORY:
67*148a8653SBen Skeggs return -EINVAL;
68*148a8653SBen Skeggs case NV_DEVICE: {
69*148a8653SBen Skeggs union {
70*148a8653SBen Skeggs struct nv_device_v0 v0;
71*148a8653SBen Skeggs } *args = data;
72*148a8653SBen Skeggs
73*148a8653SBen Skeggs if ((ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false)))
74*148a8653SBen Skeggs return ret;
75*148a8653SBen Skeggs
76*148a8653SBen Skeggs args->v0.priv = false;
77*148a8653SBen Skeggs break;
78*148a8653SBen Skeggs }
79*148a8653SBen Skeggs default:
80*148a8653SBen Skeggs if (!parent_abi16)
81*148a8653SBen Skeggs return -EINVAL;
82*148a8653SBen Skeggs break;
83*148a8653SBen Skeggs }
84*148a8653SBen Skeggs
8527111a23SBen Skeggs if (!(object = kmalloc(sizeof(*object), GFP_KERNEL)))
8627111a23SBen Skeggs return -ENOMEM;
8727111a23SBen Skeggs list_add(&object->head, &cli->objects);
8827111a23SBen Skeggs
8927111a23SBen Skeggs object->route = args->v0.route;
9027111a23SBen Skeggs object->token = args->v0.token;
9127111a23SBen Skeggs args->v0.route = NVDRM_OBJECT_USIF;
9227111a23SBen Skeggs args->v0.token = (unsigned long)(void *)object;
9327111a23SBen Skeggs ret = nvif_client_ioctl(client, argv, argc);
94*148a8653SBen Skeggs if (ret) {
9527111a23SBen Skeggs usif_object_dtor(object);
9627111a23SBen Skeggs return ret;
9727111a23SBen Skeggs }
9827111a23SBen Skeggs
99*148a8653SBen Skeggs args->v0.token = object->token;
100*148a8653SBen Skeggs args->v0.route = object->route;
101*148a8653SBen Skeggs return 0;
102*148a8653SBen Skeggs }
103*148a8653SBen Skeggs
10427111a23SBen Skeggs int
usif_ioctl(struct drm_file * filp,void __user * user,u32 argc)10527111a23SBen Skeggs usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
10627111a23SBen Skeggs {
10727111a23SBen Skeggs struct nouveau_cli *cli = nouveau_cli(filp);
10827111a23SBen Skeggs struct nvif_client *client = &cli->base;
10927111a23SBen Skeggs void *data = kmalloc(argc, GFP_KERNEL);
11027111a23SBen Skeggs u32 size = argc;
11127111a23SBen Skeggs union {
11227111a23SBen Skeggs struct nvif_ioctl_v0 v0;
11327111a23SBen Skeggs } *argv = data;
11427111a23SBen Skeggs struct usif_object *object;
115*148a8653SBen Skeggs bool abi16 = false;
11627111a23SBen Skeggs u8 owner;
11727111a23SBen Skeggs int ret;
11827111a23SBen Skeggs
11927111a23SBen Skeggs if (ret = -ENOMEM, !argv)
12027111a23SBen Skeggs goto done;
12127111a23SBen Skeggs if (ret = -EFAULT, copy_from_user(argv, user, size))
12227111a23SBen Skeggs goto done;
12327111a23SBen Skeggs
124f01c4e68SBen Skeggs if (!(ret = nvif_unpack(-ENOSYS, &data, &size, argv->v0, 0, 0, true))) {
12527111a23SBen Skeggs /* block access to objects not created via this interface */
12627111a23SBen Skeggs owner = argv->v0.owner;
127c966b627SBen Skeggs if (argv->v0.object == 0ULL &&
128c966b627SBen Skeggs argv->v0.type != NVIF_IOCTL_V0_DEL)
129f5e55187SBen Skeggs argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */
130f5e55187SBen Skeggs else
13127111a23SBen Skeggs argv->v0.owner = NVDRM_OBJECT_USIF;
13227111a23SBen Skeggs } else
13327111a23SBen Skeggs goto done;
13427111a23SBen Skeggs
1352621a416SBen Skeggs /* USIF slightly abuses some return-only ioctl members in order
1362621a416SBen Skeggs * to provide interoperability with the older ABI16 objects
1372621a416SBen Skeggs */
13827111a23SBen Skeggs mutex_lock(&cli->mutex);
1392621a416SBen Skeggs if (argv->v0.route) {
1402621a416SBen Skeggs if (ret = -EINVAL, argv->v0.route == 0xff)
1412621a416SBen Skeggs ret = nouveau_abi16_usif(filp, argv, argc);
1422621a416SBen Skeggs if (ret) {
1432621a416SBen Skeggs mutex_unlock(&cli->mutex);
1442621a416SBen Skeggs goto done;
1452621a416SBen Skeggs }
146*148a8653SBen Skeggs
147*148a8653SBen Skeggs abi16 = true;
1482621a416SBen Skeggs }
1492621a416SBen Skeggs
15027111a23SBen Skeggs switch (argv->v0.type) {
15127111a23SBen Skeggs case NVIF_IOCTL_V0_NEW:
152*148a8653SBen Skeggs ret = usif_object_new(filp, data, size, argv, argc, abi16);
15327111a23SBen Skeggs break;
15427111a23SBen Skeggs default:
15527111a23SBen Skeggs ret = nvif_client_ioctl(client, argv, argc);
15627111a23SBen Skeggs break;
15727111a23SBen Skeggs }
15827111a23SBen Skeggs if (argv->v0.route == NVDRM_OBJECT_USIF) {
15927111a23SBen Skeggs object = (void *)(unsigned long)argv->v0.token;
16027111a23SBen Skeggs argv->v0.route = object->route;
16127111a23SBen Skeggs argv->v0.token = object->token;
16227111a23SBen Skeggs if (ret == 0 && argv->v0.type == NVIF_IOCTL_V0_DEL) {
16327111a23SBen Skeggs list_del(&object->head);
16427111a23SBen Skeggs kfree(object);
16527111a23SBen Skeggs }
16627111a23SBen Skeggs } else {
16727111a23SBen Skeggs argv->v0.route = NVIF_IOCTL_V0_ROUTE_HIDDEN;
16827111a23SBen Skeggs argv->v0.token = 0;
16927111a23SBen Skeggs }
17027111a23SBen Skeggs argv->v0.owner = owner;
17127111a23SBen Skeggs mutex_unlock(&cli->mutex);
17227111a23SBen Skeggs
17327111a23SBen Skeggs if (copy_to_user(user, argv, argc))
17427111a23SBen Skeggs ret = -EFAULT;
17527111a23SBen Skeggs done:
17627111a23SBen Skeggs kfree(argv);
17727111a23SBen Skeggs return ret;
17827111a23SBen Skeggs }
17927111a23SBen Skeggs
18027111a23SBen Skeggs void
usif_client_fini(struct nouveau_cli * cli)18127111a23SBen Skeggs usif_client_fini(struct nouveau_cli *cli)
18227111a23SBen Skeggs {
18327111a23SBen Skeggs struct usif_object *object, *otemp;
18427111a23SBen Skeggs
18527111a23SBen Skeggs list_for_each_entry_safe(object, otemp, &cli->objects, head) {
18627111a23SBen Skeggs usif_object_dtor(object);
18727111a23SBen Skeggs }
18827111a23SBen Skeggs }
18927111a23SBen Skeggs
19027111a23SBen Skeggs void
usif_client_init(struct nouveau_cli * cli)19127111a23SBen Skeggs usif_client_init(struct nouveau_cli *cli)
19227111a23SBen Skeggs {
19327111a23SBen Skeggs INIT_LIST_HEAD(&cli->objects);
19427111a23SBen Skeggs }
195