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 #include <core/ioctl.h>
0025 #include <core/client.h>
0026 #include <core/engine.h>
0027 #include <core/event.h>
0028 
0029 #include <nvif/unpack.h>
0030 #include <nvif/ioctl.h>
0031 
0032 static int
0033 nvkm_ioctl_nop(struct nvkm_client *client,
0034            struct nvkm_object *object, void *data, u32 size)
0035 {
0036     union {
0037         struct nvif_ioctl_nop_v0 v0;
0038     } *args = data;
0039     int ret = -ENOSYS;
0040 
0041     nvif_ioctl(object, "nop size %d\n", size);
0042     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0043         nvif_ioctl(object, "nop vers %lld\n", args->v0.version);
0044         args->v0.version = NVIF_VERSION_LATEST;
0045     }
0046 
0047     return ret;
0048 }
0049 
0050 static int
0051 nvkm_ioctl_sclass(struct nvkm_client *client,
0052           struct nvkm_object *object, void *data, u32 size)
0053 {
0054     union {
0055         struct nvif_ioctl_sclass_v0 v0;
0056     } *args = data;
0057     struct nvkm_oclass oclass = { .client = client };
0058     int ret = -ENOSYS, i = 0;
0059 
0060     nvif_ioctl(object, "sclass size %d\n", size);
0061     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0062         nvif_ioctl(object, "sclass vers %d count %d\n",
0063                args->v0.version, args->v0.count);
0064         if (size != args->v0.count * sizeof(args->v0.oclass[0]))
0065             return -EINVAL;
0066 
0067         while (object->func->sclass &&
0068                object->func->sclass(object, i, &oclass) >= 0) {
0069             if (i < args->v0.count) {
0070                 args->v0.oclass[i].oclass = oclass.base.oclass;
0071                 args->v0.oclass[i].minver = oclass.base.minver;
0072                 args->v0.oclass[i].maxver = oclass.base.maxver;
0073             }
0074             i++;
0075         }
0076 
0077         args->v0.count = i;
0078     }
0079 
0080     return ret;
0081 }
0082 
0083 static int
0084 nvkm_ioctl_new(struct nvkm_client *client,
0085            struct nvkm_object *parent, void *data, u32 size)
0086 {
0087     union {
0088         struct nvif_ioctl_new_v0 v0;
0089     } *args = data;
0090     struct nvkm_object *object = NULL;
0091     struct nvkm_oclass oclass;
0092     int ret = -ENOSYS, i = 0;
0093 
0094     nvif_ioctl(parent, "new size %d\n", size);
0095     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0096         nvif_ioctl(parent, "new vers %d handle %08x class %08x "
0097                    "route %02x token %llx object %016llx\n",
0098                args->v0.version, args->v0.handle, args->v0.oclass,
0099                args->v0.route, args->v0.token, args->v0.object);
0100     } else
0101         return ret;
0102 
0103     if (!parent->func->sclass) {
0104         nvif_ioctl(parent, "cannot have children\n");
0105         return -EINVAL;
0106     }
0107 
0108     do {
0109         memset(&oclass, 0x00, sizeof(oclass));
0110         oclass.handle = args->v0.handle;
0111         oclass.route  = args->v0.route;
0112         oclass.token  = args->v0.token;
0113         oclass.object = args->v0.object;
0114         oclass.client = client;
0115         oclass.parent = parent;
0116         ret = parent->func->sclass(parent, i++, &oclass);
0117         if (ret)
0118             return ret;
0119     } while (oclass.base.oclass != args->v0.oclass);
0120 
0121     if (oclass.engine) {
0122         oclass.engine = nvkm_engine_ref(oclass.engine);
0123         if (IS_ERR(oclass.engine))
0124             return PTR_ERR(oclass.engine);
0125     }
0126 
0127     ret = oclass.ctor(&oclass, data, size, &object);
0128     nvkm_engine_unref(&oclass.engine);
0129     if (ret == 0) {
0130         ret = nvkm_object_init(object);
0131         if (ret == 0) {
0132             list_add_tail(&object->head, &parent->tree);
0133             if (nvkm_object_insert(object)) {
0134                 client->data = object;
0135                 return 0;
0136             }
0137             ret = -EEXIST;
0138         }
0139         nvkm_object_fini(object, false);
0140     }
0141 
0142     nvkm_object_del(&object);
0143     return ret;
0144 }
0145 
0146 static int
0147 nvkm_ioctl_del(struct nvkm_client *client,
0148            struct nvkm_object *object, void *data, u32 size)
0149 {
0150     union {
0151         struct nvif_ioctl_del none;
0152     } *args = data;
0153     int ret = -ENOSYS;
0154 
0155     nvif_ioctl(object, "delete size %d\n", size);
0156     if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
0157         nvif_ioctl(object, "delete\n");
0158         nvkm_object_fini(object, false);
0159         nvkm_object_del(&object);
0160     }
0161 
0162     return ret ? ret : 1;
0163 }
0164 
0165 static int
0166 nvkm_ioctl_mthd(struct nvkm_client *client,
0167         struct nvkm_object *object, void *data, u32 size)
0168 {
0169     union {
0170         struct nvif_ioctl_mthd_v0 v0;
0171     } *args = data;
0172     int ret = -ENOSYS;
0173 
0174     nvif_ioctl(object, "mthd size %d\n", size);
0175     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0176         nvif_ioctl(object, "mthd vers %d mthd %02x\n",
0177                args->v0.version, args->v0.method);
0178         ret = nvkm_object_mthd(object, args->v0.method, data, size);
0179     }
0180 
0181     return ret;
0182 }
0183 
0184 
0185 static int
0186 nvkm_ioctl_rd(struct nvkm_client *client,
0187           struct nvkm_object *object, void *data, u32 size)
0188 {
0189     union {
0190         struct nvif_ioctl_rd_v0 v0;
0191     } *args = data;
0192     union {
0193         u8  b08;
0194         u16 b16;
0195         u32 b32;
0196     } v;
0197     int ret = -ENOSYS;
0198 
0199     nvif_ioctl(object, "rd size %d\n", size);
0200     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0201         nvif_ioctl(object, "rd vers %d size %d addr %016llx\n",
0202                args->v0.version, args->v0.size, args->v0.addr);
0203         switch (args->v0.size) {
0204         case 1:
0205             ret = nvkm_object_rd08(object, args->v0.addr, &v.b08);
0206             args->v0.data = v.b08;
0207             break;
0208         case 2:
0209             ret = nvkm_object_rd16(object, args->v0.addr, &v.b16);
0210             args->v0.data = v.b16;
0211             break;
0212         case 4:
0213             ret = nvkm_object_rd32(object, args->v0.addr, &v.b32);
0214             args->v0.data = v.b32;
0215             break;
0216         default:
0217             ret = -EINVAL;
0218             break;
0219         }
0220     }
0221 
0222     return ret;
0223 }
0224 
0225 static int
0226 nvkm_ioctl_wr(struct nvkm_client *client,
0227           struct nvkm_object *object, void *data, u32 size)
0228 {
0229     union {
0230         struct nvif_ioctl_wr_v0 v0;
0231     } *args = data;
0232     int ret = -ENOSYS;
0233 
0234     nvif_ioctl(object, "wr size %d\n", size);
0235     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0236         nvif_ioctl(object,
0237                "wr vers %d size %d addr %016llx data %08x\n",
0238                args->v0.version, args->v0.size, args->v0.addr,
0239                args->v0.data);
0240     } else
0241         return ret;
0242 
0243     switch (args->v0.size) {
0244     case 1: return nvkm_object_wr08(object, args->v0.addr, args->v0.data);
0245     case 2: return nvkm_object_wr16(object, args->v0.addr, args->v0.data);
0246     case 4: return nvkm_object_wr32(object, args->v0.addr, args->v0.data);
0247     default:
0248         break;
0249     }
0250 
0251     return -EINVAL;
0252 }
0253 
0254 static int
0255 nvkm_ioctl_map(struct nvkm_client *client,
0256            struct nvkm_object *object, void *data, u32 size)
0257 {
0258     union {
0259         struct nvif_ioctl_map_v0 v0;
0260     } *args = data;
0261     enum nvkm_object_map type;
0262     int ret = -ENOSYS;
0263 
0264     nvif_ioctl(object, "map size %d\n", size);
0265     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0266         nvif_ioctl(object, "map vers %d\n", args->v0.version);
0267         ret = nvkm_object_map(object, data, size, &type,
0268                       &args->v0.handle,
0269                       &args->v0.length);
0270         if (type == NVKM_OBJECT_MAP_IO)
0271             args->v0.type = NVIF_IOCTL_MAP_V0_IO;
0272         else
0273             args->v0.type = NVIF_IOCTL_MAP_V0_VA;
0274     }
0275 
0276     return ret;
0277 }
0278 
0279 static int
0280 nvkm_ioctl_unmap(struct nvkm_client *client,
0281          struct nvkm_object *object, void *data, u32 size)
0282 {
0283     union {
0284         struct nvif_ioctl_unmap none;
0285     } *args = data;
0286     int ret = -ENOSYS;
0287 
0288     nvif_ioctl(object, "unmap size %d\n", size);
0289     if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
0290         nvif_ioctl(object, "unmap\n");
0291         ret = nvkm_object_unmap(object);
0292     }
0293 
0294     return ret;
0295 }
0296 
0297 static int
0298 nvkm_ioctl_ntfy_new(struct nvkm_client *client,
0299             struct nvkm_object *object, void *data, u32 size)
0300 {
0301     union {
0302         struct nvif_ioctl_ntfy_new_v0 v0;
0303     } *args = data;
0304     struct nvkm_event *event;
0305     int ret = -ENOSYS;
0306 
0307     nvif_ioctl(object, "ntfy new size %d\n", size);
0308     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0309         nvif_ioctl(object, "ntfy new vers %d event %02x\n",
0310                args->v0.version, args->v0.event);
0311         ret = nvkm_object_ntfy(object, args->v0.event, &event);
0312         if (ret == 0) {
0313             ret = nvkm_client_notify_new(object, event, data, size);
0314             if (ret >= 0) {
0315                 args->v0.index = ret;
0316                 ret = 0;
0317             }
0318         }
0319     }
0320 
0321     return ret;
0322 }
0323 
0324 static int
0325 nvkm_ioctl_ntfy_del(struct nvkm_client *client,
0326             struct nvkm_object *object, void *data, u32 size)
0327 {
0328     union {
0329         struct nvif_ioctl_ntfy_del_v0 v0;
0330     } *args = data;
0331     int ret = -ENOSYS;
0332 
0333     nvif_ioctl(object, "ntfy del size %d\n", size);
0334     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0335         nvif_ioctl(object, "ntfy del vers %d index %d\n",
0336                args->v0.version, args->v0.index);
0337         ret = nvkm_client_notify_del(client, args->v0.index);
0338     }
0339 
0340     return ret;
0341 }
0342 
0343 static int
0344 nvkm_ioctl_ntfy_get(struct nvkm_client *client,
0345             struct nvkm_object *object, void *data, u32 size)
0346 {
0347     union {
0348         struct nvif_ioctl_ntfy_get_v0 v0;
0349     } *args = data;
0350     int ret = -ENOSYS;
0351 
0352     nvif_ioctl(object, "ntfy get size %d\n", size);
0353     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0354         nvif_ioctl(object, "ntfy get vers %d index %d\n",
0355                args->v0.version, args->v0.index);
0356         ret = nvkm_client_notify_get(client, args->v0.index);
0357     }
0358 
0359     return ret;
0360 }
0361 
0362 static int
0363 nvkm_ioctl_ntfy_put(struct nvkm_client *client,
0364             struct nvkm_object *object, void *data, u32 size)
0365 {
0366     union {
0367         struct nvif_ioctl_ntfy_put_v0 v0;
0368     } *args = data;
0369     int ret = -ENOSYS;
0370 
0371     nvif_ioctl(object, "ntfy put size %d\n", size);
0372     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
0373         nvif_ioctl(object, "ntfy put vers %d index %d\n",
0374                args->v0.version, args->v0.index);
0375         ret = nvkm_client_notify_put(client, args->v0.index);
0376     }
0377 
0378     return ret;
0379 }
0380 
0381 static struct {
0382     int version;
0383     int (*func)(struct nvkm_client *, struct nvkm_object *, void *, u32);
0384 }
0385 nvkm_ioctl_v0[] = {
0386     { 0x00, nvkm_ioctl_nop },
0387     { 0x00, nvkm_ioctl_sclass },
0388     { 0x00, nvkm_ioctl_new },
0389     { 0x00, nvkm_ioctl_del },
0390     { 0x00, nvkm_ioctl_mthd },
0391     { 0x00, nvkm_ioctl_rd },
0392     { 0x00, nvkm_ioctl_wr },
0393     { 0x00, nvkm_ioctl_map },
0394     { 0x00, nvkm_ioctl_unmap },
0395     { 0x00, nvkm_ioctl_ntfy_new },
0396     { 0x00, nvkm_ioctl_ntfy_del },
0397     { 0x00, nvkm_ioctl_ntfy_get },
0398     { 0x00, nvkm_ioctl_ntfy_put },
0399 };
0400 
0401 static int
0402 nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type,
0403         void *data, u32 size, u8 owner, u8 *route, u64 *token)
0404 {
0405     struct nvkm_object *object;
0406     int ret;
0407 
0408     object = nvkm_object_search(client, handle, NULL);
0409     if (IS_ERR(object)) {
0410         nvif_ioctl(&client->object, "object not found\n");
0411         return PTR_ERR(object);
0412     }
0413 
0414     if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != object->route) {
0415         nvif_ioctl(&client->object, "route != owner\n");
0416         return -EACCES;
0417     }
0418     *route = object->route;
0419     *token = object->token;
0420 
0421     if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
0422         if (nvkm_ioctl_v0[type].version == 0)
0423             ret = nvkm_ioctl_v0[type].func(client, object, data, size);
0424     }
0425 
0426     return ret;
0427 }
0428 
0429 int
0430 nvkm_ioctl(struct nvkm_client *client, void *data, u32 size, void **hack)
0431 {
0432     struct nvkm_object *object = &client->object;
0433     union {
0434         struct nvif_ioctl_v0 v0;
0435     } *args = data;
0436     int ret = -ENOSYS;
0437 
0438     nvif_ioctl(object, "size %d\n", size);
0439 
0440     if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
0441         nvif_ioctl(object,
0442                "vers %d type %02x object %016llx owner %02x\n",
0443                args->v0.version, args->v0.type, args->v0.object,
0444                args->v0.owner);
0445         ret = nvkm_ioctl_path(client, args->v0.object, args->v0.type,
0446                       data, size, args->v0.owner,
0447                       &args->v0.route, &args->v0.token);
0448     }
0449 
0450     if (ret != 1) {
0451         nvif_ioctl(object, "return %d\n", ret);
0452         if (hack) {
0453             *hack = client->data;
0454             client->data = NULL;
0455         }
0456     }
0457 
0458     return ret;
0459 }