brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · 0b87278 Raw
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