280 lines · c
1/*2 * Copyright 2014 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Ben Skeggs <bskeggs@redhat.com>23 */24 25#include <nvif/object.h>26#include <nvif/client.h>27#include <nvif/driver.h>28#include <nvif/ioctl.h>29 30int31nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)32{33 struct nvif_client *client = object->client;34 union {35 struct nvif_ioctl_v0 v0;36 } *args = data;37 38 if (size >= sizeof(*args) && args->v0.version == 0) {39 if (object != &client->object)40 args->v0.object = nvif_handle(object);41 else42 args->v0.object = 0;43 } else44 return -ENOSYS;45 46 return client->driver->ioctl(client->object.priv, data, size, hack);47}48 49void50nvif_object_sclass_put(struct nvif_sclass **psclass)51{52 kfree(*psclass);53 *psclass = NULL;54}55 56int57nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass)58{59 struct {60 struct nvif_ioctl_v0 ioctl;61 struct nvif_ioctl_sclass_v0 sclass;62 } *args = NULL;63 int ret, cnt = 0, i;64 u32 size;65 66 while (1) {67 size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);68 if (!(args = kmalloc(size, GFP_KERNEL)))69 return -ENOMEM;70 args->ioctl.version = 0;71 args->ioctl.type = NVIF_IOCTL_V0_SCLASS;72 args->sclass.version = 0;73 args->sclass.count = cnt;74 75 ret = nvif_object_ioctl(object, args, size, NULL);76 if (ret == 0 && args->sclass.count <= cnt)77 break;78 cnt = args->sclass.count;79 kfree(args);80 if (ret != 0)81 return ret;82 }83 84 *psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL);85 if (*psclass) {86 for (i = 0; i < args->sclass.count; i++) {87 (*psclass)[i].oclass = args->sclass.oclass[i].oclass;88 (*psclass)[i].minver = args->sclass.oclass[i].minver;89 (*psclass)[i].maxver = args->sclass.oclass[i].maxver;90 }91 ret = args->sclass.count;92 } else {93 ret = -ENOMEM;94 }95 96 kfree(args);97 return ret;98}99 100int101nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)102{103 struct {104 struct nvif_ioctl_v0 ioctl;105 struct nvif_ioctl_mthd_v0 mthd;106 } *args;107 u32 args_size;108 u8 stack[128];109 int ret;110 111 if (check_add_overflow(sizeof(*args), size, &args_size))112 return -ENOMEM;113 114 if (args_size > sizeof(stack)) {115 args = kmalloc(args_size, GFP_KERNEL);116 if (!args)117 return -ENOMEM;118 } else {119 args = (void *)stack;120 }121 args->ioctl.version = 0;122 args->ioctl.type = NVIF_IOCTL_V0_MTHD;123 args->mthd.version = 0;124 args->mthd.method = mthd;125 126 memcpy(args->mthd.data, data, size);127 ret = nvif_object_ioctl(object, args, args_size, NULL);128 memcpy(data, args->mthd.data, size);129 if (args != (void *)stack)130 kfree(args);131 return ret;132}133 134void135nvif_object_unmap_handle(struct nvif_object *object)136{137 struct {138 struct nvif_ioctl_v0 ioctl;139 struct nvif_ioctl_unmap unmap;140 } args = {141 .ioctl.type = NVIF_IOCTL_V0_UNMAP,142 };143 144 nvif_object_ioctl(object, &args, sizeof(args), NULL);145}146 147int148nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc,149 u64 *handle, u64 *length)150{151 struct {152 struct nvif_ioctl_v0 ioctl;153 struct nvif_ioctl_map_v0 map;154 } *args;155 u32 argn = sizeof(*args) + argc;156 int ret, maptype;157 158 if (!(args = kzalloc(argn, GFP_KERNEL)))159 return -ENOMEM;160 args->ioctl.type = NVIF_IOCTL_V0_MAP;161 memcpy(args->map.data, argv, argc);162 163 ret = nvif_object_ioctl(object, args, argn, NULL);164 *handle = args->map.handle;165 *length = args->map.length;166 maptype = args->map.type;167 kfree(args);168 return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO);169}170 171void172nvif_object_unmap(struct nvif_object *object)173{174 struct nvif_client *client = object->client;175 if (object->map.ptr) {176 if (object->map.size) {177 client->driver->unmap(client, object->map.ptr,178 object->map.size);179 object->map.size = 0;180 }181 object->map.ptr = NULL;182 nvif_object_unmap_handle(object);183 }184}185 186int187nvif_object_map(struct nvif_object *object, void *argv, u32 argc)188{189 struct nvif_client *client = object->client;190 u64 handle, length;191 int ret = nvif_object_map_handle(object, argv, argc, &handle, &length);192 if (ret >= 0) {193 if (ret) {194 object->map.ptr = client->driver->map(client,195 handle,196 length);197 if (ret = -ENOMEM, object->map.ptr) {198 object->map.size = length;199 return 0;200 }201 } else {202 object->map.ptr = (void *)(unsigned long)handle;203 return 0;204 }205 nvif_object_unmap_handle(object);206 }207 return ret;208}209 210void211nvif_object_dtor(struct nvif_object *object)212{213 struct {214 struct nvif_ioctl_v0 ioctl;215 struct nvif_ioctl_del del;216 } args = {217 .ioctl.type = NVIF_IOCTL_V0_DEL,218 };219 220 if (!nvif_object_constructed(object))221 return;222 223 nvif_object_unmap(object);224 nvif_object_ioctl(object, &args, sizeof(args), NULL);225 object->client = NULL;226}227 228int229nvif_object_ctor(struct nvif_object *parent, const char *name, u32 handle,230 s32 oclass, void *data, u32 size, struct nvif_object *object)231{232 struct {233 struct nvif_ioctl_v0 ioctl;234 struct nvif_ioctl_new_v0 new;235 } *args;236 int ret = 0;237 238 object->client = NULL;239 object->name = name ? name : "nvifObject";240 object->handle = handle;241 object->oclass = oclass;242 object->map.ptr = NULL;243 object->map.size = 0;244 245 if (parent) {246 u32 args_size;247 248 if (check_add_overflow(sizeof(*args), size, &args_size)) {249 nvif_object_dtor(object);250 return -ENOMEM;251 }252 253 args = kmalloc(args_size, GFP_KERNEL);254 if (!args) {255 nvif_object_dtor(object);256 return -ENOMEM;257 }258 259 object->parent = parent->parent;260 261 args->ioctl.version = 0;262 args->ioctl.type = NVIF_IOCTL_V0_NEW;263 args->new.version = 0;264 args->new.object = nvif_handle(object);265 args->new.handle = handle;266 args->new.oclass = oclass;267 268 memcpy(args->new.data, data, size);269 ret = nvif_object_ioctl(parent, args, args_size, &object->priv);270 memcpy(data, args->new.data, size);271 kfree(args);272 if (ret == 0)273 object->client = parent->client;274 }275 276 if (ret)277 nvif_object_dtor(object);278 return ret;279}280