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 <nvif/object.h>
0026 #include <nvif/client.h>
0027 #include <nvif/driver.h>
0028 #include <nvif/ioctl.h>
0029 
0030 int
0031 nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
0032 {
0033     struct nvif_client *client = object->client;
0034     union {
0035         struct nvif_ioctl_v0 v0;
0036     } *args = data;
0037 
0038     if (size >= sizeof(*args) && args->v0.version == 0) {
0039         if (object != &client->object)
0040             args->v0.object = nvif_handle(object);
0041         else
0042             args->v0.object = 0;
0043         args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
0044     } else
0045         return -ENOSYS;
0046 
0047     return client->driver->ioctl(client->object.priv, data, size, hack);
0048 }
0049 
0050 void
0051 nvif_object_sclass_put(struct nvif_sclass **psclass)
0052 {
0053     kfree(*psclass);
0054     *psclass = NULL;
0055 }
0056 
0057 int
0058 nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass)
0059 {
0060     struct {
0061         struct nvif_ioctl_v0 ioctl;
0062         struct nvif_ioctl_sclass_v0 sclass;
0063     } *args = NULL;
0064     int ret, cnt = 0, i;
0065     u32 size;
0066 
0067     while (1) {
0068         size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
0069         if (!(args = kmalloc(size, GFP_KERNEL)))
0070             return -ENOMEM;
0071         args->ioctl.version = 0;
0072         args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
0073         args->sclass.version = 0;
0074         args->sclass.count = cnt;
0075 
0076         ret = nvif_object_ioctl(object, args, size, NULL);
0077         if (ret == 0 && args->sclass.count <= cnt)
0078             break;
0079         cnt = args->sclass.count;
0080         kfree(args);
0081         if (ret != 0)
0082             return ret;
0083     }
0084 
0085     *psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL);
0086     if (*psclass) {
0087         for (i = 0; i < args->sclass.count; i++) {
0088             (*psclass)[i].oclass = args->sclass.oclass[i].oclass;
0089             (*psclass)[i].minver = args->sclass.oclass[i].minver;
0090             (*psclass)[i].maxver = args->sclass.oclass[i].maxver;
0091         }
0092         ret = args->sclass.count;
0093     } else {
0094         ret = -ENOMEM;
0095     }
0096 
0097     kfree(args);
0098     return ret;
0099 }
0100 
0101 u32
0102 nvif_object_rd(struct nvif_object *object, int size, u64 addr)
0103 {
0104     struct {
0105         struct nvif_ioctl_v0 ioctl;
0106         struct nvif_ioctl_rd_v0 rd;
0107     } args = {
0108         .ioctl.type = NVIF_IOCTL_V0_RD,
0109         .rd.size = size,
0110         .rd.addr = addr,
0111     };
0112     int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
0113     if (ret) {
0114         /*XXX: warn? */
0115         return 0;
0116     }
0117     return args.rd.data;
0118 }
0119 
0120 void
0121 nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data)
0122 {
0123     struct {
0124         struct nvif_ioctl_v0 ioctl;
0125         struct nvif_ioctl_wr_v0 wr;
0126     } args = {
0127         .ioctl.type = NVIF_IOCTL_V0_WR,
0128         .wr.size = size,
0129         .wr.addr = addr,
0130         .wr.data = data,
0131     };
0132     int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
0133     if (ret) {
0134         /*XXX: warn? */
0135     }
0136 }
0137 
0138 int
0139 nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
0140 {
0141     struct {
0142         struct nvif_ioctl_v0 ioctl;
0143         struct nvif_ioctl_mthd_v0 mthd;
0144     } *args;
0145     u8 stack[128];
0146     int ret;
0147 
0148     if (sizeof(*args) + size > sizeof(stack)) {
0149         if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
0150             return -ENOMEM;
0151     } else {
0152         args = (void *)stack;
0153     }
0154     args->ioctl.version = 0;
0155     args->ioctl.type = NVIF_IOCTL_V0_MTHD;
0156     args->mthd.version = 0;
0157     args->mthd.method = mthd;
0158 
0159     memcpy(args->mthd.data, data, size);
0160     ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
0161     memcpy(data, args->mthd.data, size);
0162     if (args != (void *)stack)
0163         kfree(args);
0164     return ret;
0165 }
0166 
0167 void
0168 nvif_object_unmap_handle(struct nvif_object *object)
0169 {
0170     struct {
0171         struct nvif_ioctl_v0 ioctl;
0172         struct nvif_ioctl_unmap unmap;
0173     } args = {
0174         .ioctl.type = NVIF_IOCTL_V0_UNMAP,
0175     };
0176 
0177     nvif_object_ioctl(object, &args, sizeof(args), NULL);
0178 }
0179 
0180 int
0181 nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc,
0182                u64 *handle, u64 *length)
0183 {
0184     struct {
0185         struct nvif_ioctl_v0 ioctl;
0186         struct nvif_ioctl_map_v0 map;
0187     } *args;
0188     u32 argn = sizeof(*args) + argc;
0189     int ret, maptype;
0190 
0191     if (!(args = kzalloc(argn, GFP_KERNEL)))
0192         return -ENOMEM;
0193     args->ioctl.type = NVIF_IOCTL_V0_MAP;
0194     memcpy(args->map.data, argv, argc);
0195 
0196     ret = nvif_object_ioctl(object, args, argn, NULL);
0197     *handle = args->map.handle;
0198     *length = args->map.length;
0199     maptype = args->map.type;
0200     kfree(args);
0201     return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO);
0202 }
0203 
0204 void
0205 nvif_object_unmap(struct nvif_object *object)
0206 {
0207     struct nvif_client *client = object->client;
0208     if (object->map.ptr) {
0209         if (object->map.size) {
0210             client->driver->unmap(client, object->map.ptr,
0211                               object->map.size);
0212             object->map.size = 0;
0213         }
0214         object->map.ptr = NULL;
0215         nvif_object_unmap_handle(object);
0216     }
0217 }
0218 
0219 int
0220 nvif_object_map(struct nvif_object *object, void *argv, u32 argc)
0221 {
0222     struct nvif_client *client = object->client;
0223     u64 handle, length;
0224     int ret = nvif_object_map_handle(object, argv, argc, &handle, &length);
0225     if (ret >= 0) {
0226         if (ret) {
0227             object->map.ptr = client->driver->map(client,
0228                                   handle,
0229                                   length);
0230             if (ret = -ENOMEM, object->map.ptr) {
0231                 object->map.size = length;
0232                 return 0;
0233             }
0234         } else {
0235             object->map.ptr = (void *)(unsigned long)handle;
0236             return 0;
0237         }
0238         nvif_object_unmap_handle(object);
0239     }
0240     return ret;
0241 }
0242 
0243 void
0244 nvif_object_dtor(struct nvif_object *object)
0245 {
0246     struct {
0247         struct nvif_ioctl_v0 ioctl;
0248         struct nvif_ioctl_del del;
0249     } args = {
0250         .ioctl.type = NVIF_IOCTL_V0_DEL,
0251     };
0252 
0253     if (!nvif_object_constructed(object))
0254         return;
0255 
0256     nvif_object_unmap(object);
0257     nvif_object_ioctl(object, &args, sizeof(args), NULL);
0258     object->client = NULL;
0259 }
0260 
0261 int
0262 nvif_object_ctor(struct nvif_object *parent, const char *name, u32 handle,
0263          s32 oclass, void *data, u32 size, struct nvif_object *object)
0264 {
0265     struct {
0266         struct nvif_ioctl_v0 ioctl;
0267         struct nvif_ioctl_new_v0 new;
0268     } *args;
0269     int ret = 0;
0270 
0271     object->client = NULL;
0272     object->name = name ? name : "nvifObject";
0273     object->handle = handle;
0274     object->oclass = oclass;
0275     object->map.ptr = NULL;
0276     object->map.size = 0;
0277 
0278     if (parent) {
0279         if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) {
0280             nvif_object_dtor(object);
0281             return -ENOMEM;
0282         }
0283 
0284         object->parent = parent->parent;
0285 
0286         args->ioctl.version = 0;
0287         args->ioctl.type = NVIF_IOCTL_V0_NEW;
0288         args->new.version = 0;
0289         args->new.route = parent->client->route;
0290         args->new.token = nvif_handle(object);
0291         args->new.object = nvif_handle(object);
0292         args->new.handle = handle;
0293         args->new.oclass = oclass;
0294 
0295         memcpy(args->new.data, data, size);
0296         ret = nvif_object_ioctl(parent, args, sizeof(*args) + size,
0297                     &object->priv);
0298         memcpy(data, args->new.data, size);
0299         kfree(args);
0300         if (ret == 0)
0301             object->client = parent->client;
0302     }
0303 
0304     if (ret)
0305         nvif_object_dtor(object);
0306     return ret;
0307 }