Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2014 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs <bskeggs@redhat.com>
0023  */
0024 
0025 #include "nouveau_drv.h"
0026 #include "nouveau_usif.h"
0027 #include "nouveau_abi16.h"
0028 
0029 #include <nvif/unpack.h>
0030 #include <nvif/client.h>
0031 #include <nvif/ioctl.h>
0032 
0033 #include <nvif/class.h>
0034 #include <nvif/cl0080.h>
0035 
0036 struct usif_object {
0037     struct list_head head;
0038     u8  route;
0039     u64 token;
0040 };
0041 
0042 static void
0043 usif_object_dtor(struct usif_object *object)
0044 {
0045     list_del(&object->head);
0046     kfree(object);
0047 }
0048 
0049 static int
0050 usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc, bool parent_abi16)
0051 {
0052     struct nouveau_cli *cli = nouveau_cli(f);
0053     struct nvif_client *client = &cli->base;
0054     union {
0055         struct nvif_ioctl_new_v0 v0;
0056     } *args = data;
0057     struct usif_object *object;
0058     int ret = -ENOSYS;
0059 
0060     if ((ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true)))
0061         return ret;
0062 
0063     switch (args->v0.oclass) {
0064     case NV_DMA_FROM_MEMORY:
0065     case NV_DMA_TO_MEMORY:
0066     case NV_DMA_IN_MEMORY:
0067         return -EINVAL;
0068     case NV_DEVICE: {
0069         union {
0070             struct nv_device_v0 v0;
0071         } *args = data;
0072 
0073         if ((ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false)))
0074             return ret;
0075 
0076         args->v0.priv = false;
0077         break;
0078     }
0079     default:
0080         if (!parent_abi16)
0081             return -EINVAL;
0082         break;
0083     }
0084 
0085     if (!(object = kmalloc(sizeof(*object), GFP_KERNEL)))
0086         return -ENOMEM;
0087     list_add(&object->head, &cli->objects);
0088 
0089     object->route = args->v0.route;
0090     object->token = args->v0.token;
0091     args->v0.route = NVDRM_OBJECT_USIF;
0092     args->v0.token = (unsigned long)(void *)object;
0093     ret = nvif_client_ioctl(client, argv, argc);
0094     if (ret) {
0095         usif_object_dtor(object);
0096         return ret;
0097     }
0098 
0099     args->v0.token = object->token;
0100     args->v0.route = object->route;
0101     return 0;
0102 }
0103 
0104 int
0105 usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
0106 {
0107     struct nouveau_cli *cli = nouveau_cli(filp);
0108     struct nvif_client *client = &cli->base;
0109     void *data = kmalloc(argc, GFP_KERNEL);
0110     u32   size = argc;
0111     union {
0112         struct nvif_ioctl_v0 v0;
0113     } *argv = data;
0114     struct usif_object *object;
0115     bool abi16 = false;
0116     u8 owner;
0117     int ret;
0118 
0119     if (ret = -ENOMEM, !argv)
0120         goto done;
0121     if (ret = -EFAULT, copy_from_user(argv, user, size))
0122         goto done;
0123 
0124     if (!(ret = nvif_unpack(-ENOSYS, &data, &size, argv->v0, 0, 0, true))) {
0125         /* block access to objects not created via this interface */
0126         owner = argv->v0.owner;
0127         if (argv->v0.object == 0ULL &&
0128             argv->v0.type != NVIF_IOCTL_V0_DEL)
0129             argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */
0130         else
0131             argv->v0.owner = NVDRM_OBJECT_USIF;
0132     } else
0133         goto done;
0134 
0135     /* USIF slightly abuses some return-only ioctl members in order
0136      * to provide interoperability with the older ABI16 objects
0137      */
0138     mutex_lock(&cli->mutex);
0139     if (argv->v0.route) {
0140         if (ret = -EINVAL, argv->v0.route == 0xff)
0141             ret = nouveau_abi16_usif(filp, argv, argc);
0142         if (ret) {
0143             mutex_unlock(&cli->mutex);
0144             goto done;
0145         }
0146 
0147         abi16 = true;
0148     }
0149 
0150     switch (argv->v0.type) {
0151     case NVIF_IOCTL_V0_NEW:
0152         ret = usif_object_new(filp, data, size, argv, argc, abi16);
0153         break;
0154     case NVIF_IOCTL_V0_NTFY_NEW:
0155     case NVIF_IOCTL_V0_NTFY_DEL:
0156     case NVIF_IOCTL_V0_NTFY_GET:
0157     case NVIF_IOCTL_V0_NTFY_PUT:
0158         ret = -ENOSYS;
0159         break;
0160     default:
0161         ret = nvif_client_ioctl(client, argv, argc);
0162         break;
0163     }
0164     if (argv->v0.route == NVDRM_OBJECT_USIF) {
0165         object = (void *)(unsigned long)argv->v0.token;
0166         argv->v0.route = object->route;
0167         argv->v0.token = object->token;
0168         if (ret == 0 && argv->v0.type == NVIF_IOCTL_V0_DEL) {
0169             list_del(&object->head);
0170             kfree(object);
0171         }
0172     } else {
0173         argv->v0.route = NVIF_IOCTL_V0_ROUTE_HIDDEN;
0174         argv->v0.token = 0;
0175     }
0176     argv->v0.owner = owner;
0177     mutex_unlock(&cli->mutex);
0178 
0179     if (copy_to_user(user, argv, argc))
0180         ret = -EFAULT;
0181 done:
0182     kfree(argv);
0183     return ret;
0184 }
0185 
0186 void
0187 usif_client_fini(struct nouveau_cli *cli)
0188 {
0189     struct usif_object *object, *otemp;
0190 
0191     list_for_each_entry_safe(object, otemp, &cli->objects, head) {
0192         usif_object_dtor(object);
0193     }
0194 }
0195 
0196 void
0197 usif_client_init(struct nouveau_cli *cli)
0198 {
0199     INIT_LIST_HEAD(&cli->objects);
0200 }