Home | History | Annotate | Line # | Download | only in nvif
      1 /*	$NetBSD: nouveau_nvif_object.c,v 1.8 2021/12/19 11:07:35 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2014 Red Hat Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: Ben Skeggs <bskeggs (at) redhat.com>
     25  */
     26 
     27 #include <sys/cdefs.h>
     28 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvif_object.c,v 1.8 2021/12/19 11:07:35 riastradh Exp $");
     29 
     30 #include <nvif/object.h>
     31 #include <nvif/client.h>
     32 #include <nvif/driver.h>
     33 #include <nvif/ioctl.h>
     34 
     35 int
     36 nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
     37 {
     38 	struct nvif_client *client = object->client;
     39 	union {
     40 		struct nvif_ioctl_v0 v0;
     41 	} *args = data;
     42 
     43 	if (size >= sizeof(*args) && args->v0.version == 0) {
     44 		if (object != &client->object)
     45 			args->v0.object = nvif_handle(object);
     46 		else
     47 			args->v0.object = 0;
     48 		args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
     49 	} else
     50 		return -ENOSYS;
     51 
     52 	return client->driver->ioctl(client->object.priv, client->super,
     53 				     data, size, hack);
     54 }
     55 
     56 void
     57 nvif_object_sclass_put(struct nvif_sclass **psclass)
     58 {
     59 	kfree(*psclass);
     60 	*psclass = NULL;
     61 }
     62 
     63 int
     64 nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass)
     65 {
     66 	struct {
     67 		struct nvif_ioctl_v0 ioctl;
     68 		struct nvif_ioctl_sclass_v0 sclass;
     69 	} *args = NULL;
     70 	int ret, cnt = 0, i;
     71 	u32 size;
     72 
     73 	while (1) {
     74 		size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
     75 		if (!(args = kmalloc(size, GFP_KERNEL)))
     76 			return -ENOMEM;
     77 		args->ioctl.version = 0;
     78 		args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
     79 		args->sclass.version = 0;
     80 		args->sclass.count = cnt;
     81 
     82 		ret = nvif_object_ioctl(object, args, size, NULL);
     83 		if (ret == 0 && args->sclass.count <= cnt)
     84 			break;
     85 		cnt = args->sclass.count;
     86 		kfree(args);
     87 		if (ret != 0)
     88 			return ret;
     89 	}
     90 
     91 	*psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL);
     92 	if (*psclass) {
     93 		for (i = 0; i < args->sclass.count; i++) {
     94 			(*psclass)[i].oclass = args->sclass.oclass[i].oclass;
     95 			(*psclass)[i].minver = args->sclass.oclass[i].minver;
     96 			(*psclass)[i].maxver = args->sclass.oclass[i].maxver;
     97 		}
     98 		ret = args->sclass.count;
     99 	} else {
    100 		ret = -ENOMEM;
    101 	}
    102 
    103 	kfree(args);
    104 	return ret;
    105 }
    106 
    107 u32
    108 nvif_object_rd(struct nvif_object *object, int size, u64 addr)
    109 {
    110 	struct {
    111 		struct nvif_ioctl_v0 ioctl;
    112 		struct nvif_ioctl_rd_v0 rd;
    113 	} args = {
    114 		.ioctl.type = NVIF_IOCTL_V0_RD,
    115 		.rd.size = size,
    116 		.rd.addr = addr,
    117 	};
    118 	int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
    119 	if (ret) {
    120 		/*XXX: warn? */
    121 		return 0;
    122 	}
    123 	return args.rd.data;
    124 }
    125 
    126 void
    127 nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data)
    128 {
    129 	struct {
    130 		struct nvif_ioctl_v0 ioctl;
    131 		struct nvif_ioctl_wr_v0 wr;
    132 	} args = {
    133 		.ioctl.type = NVIF_IOCTL_V0_WR,
    134 		.wr.size = size,
    135 		.wr.addr = addr,
    136 		.wr.data = data,
    137 	};
    138 	int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
    139 	if (ret) {
    140 		/*XXX: warn? */
    141 	}
    142 }
    143 
    144 int
    145 nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
    146 {
    147 	struct {
    148 		struct nvif_ioctl_v0 ioctl;
    149 		struct nvif_ioctl_mthd_v0 mthd;
    150 	} *args;
    151 	u8 stack[128];
    152 	int ret;
    153 
    154 	if (sizeof(*args) + size > sizeof(stack)) {
    155 		if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
    156 			return -ENOMEM;
    157 	} else {
    158 		args = (void *)stack;
    159 	}
    160 	args->ioctl.version = 0;
    161 	args->ioctl.type = NVIF_IOCTL_V0_MTHD;
    162 	args->mthd.version = 0;
    163 	args->mthd.method = mthd;
    164 
    165 	memcpy(args->mthd.data, data, size);
    166 	ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
    167 	memcpy(data, args->mthd.data, size);
    168 	if (args != (void *)stack)
    169 		kfree(args);
    170 	return ret;
    171 }
    172 
    173 void
    174 nvif_object_unmap_handle(struct nvif_object *object)
    175 {
    176 	struct {
    177 		struct nvif_ioctl_v0 ioctl;
    178 		struct nvif_ioctl_unmap unmap;
    179 	} args = {
    180 		.ioctl.type = NVIF_IOCTL_V0_UNMAP,
    181 	};
    182 
    183 	nvif_object_ioctl(object, &args, sizeof(args), NULL);
    184 }
    185 
    186 int
    187 nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc,
    188 #ifdef __NetBSD__
    189 		       bus_space_tag_t *tag,
    190 #endif
    191 		       u64 *handle, u64 *length)
    192 {
    193 	struct {
    194 		struct nvif_ioctl_v0 ioctl;
    195 #ifdef __NetBSD__
    196 		struct nvif_ioctl_map_netbsd_v0 map;
    197 #else
    198 		struct nvif_ioctl_map_v0 map;
    199 #endif
    200 	} *args;
    201 	u32 argn = sizeof(*args) + argc;
    202 	int ret, maptype;
    203 
    204 	if (!(args = kzalloc(argn, GFP_KERNEL)))
    205 		return -ENOMEM;
    206 #ifdef __NetBSD__
    207 	args->ioctl.type = NVIF_IOCTL_V0_MAP_NETBSD;
    208 #else
    209 	args->ioctl.type = NVIF_IOCTL_V0_MAP;
    210 #endif
    211 	memcpy(args->map.data, argv, argc);
    212 
    213 	ret = nvif_object_ioctl(object, args, argn, NULL);
    214 #ifdef __NetBSD__
    215 	if (tag)
    216 		*tag = args->map.tag;
    217 #endif
    218 	*handle = args->map.handle;
    219 	*length = args->map.length;
    220 	maptype = args->map.type;
    221 	kfree(args);
    222 	return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO);
    223 }
    224 
    225 void
    226 nvif_object_unmap(struct nvif_object *object)
    227 {
    228 	struct nvif_client *client = object->client;
    229 	if (object->map.ptr) {
    230 		if (object->map.size) {
    231 #ifdef __NetBSD__
    232 			client->driver->unmap(client, object->map.tag,
    233 						      object->map.handle,
    234 						      object->map.addr,
    235 						      object->map.ptr,
    236 						      object->map.size);
    237 #else
    238 			client->driver->unmap(client, object->map.ptr,
    239 						      object->map.size);
    240 #endif
    241 			object->map.size = 0;
    242 		}
    243 		object->map.ptr = NULL;
    244 		nvif_object_unmap_handle(object);
    245 	}
    246 }
    247 
    248 int
    249 nvif_object_map(struct nvif_object *object, void *argv, u32 argc)
    250 {
    251 	struct nvif_client *client = object->client;
    252 	u64 handle, length;
    253 #ifdef __NetBSD__
    254 	bus_space_tag_t tag;
    255 	int ret = nvif_object_map_handle(object, argv, argc, &tag, &handle, &length);
    256 #else
    257 	int ret = nvif_object_map_handle(object, argv, argc, &handle, &length);
    258 #endif
    259 	if (ret >= 0) {
    260 		if (ret) {
    261 #ifdef __NetBSD__
    262 			/*
    263 			 * Note: handle is the bus address;
    264 			 * object->map.handle is the
    265 			 * bus_space_handle_t, which is typically a
    266 			 * virtual address mapped in kva.
    267 			 */
    268 			object->map.tag = tag;
    269 			object->map.addr = handle;
    270 			ret = client->driver->map(client, tag, handle, length,
    271 			    &object->map.handle, &object->map.ptr);
    272 			if (ret == 0) {
    273 				object->map.size = length;
    274 				return 0;
    275 			}
    276 #else
    277 			object->map.ptr = client->driver->map(client,
    278 							      handle,
    279 							      length);
    280 			if (ret = -ENOMEM, object->map.ptr) {
    281 				object->map.size = length;
    282 				return 0;
    283 			}
    284 #endif
    285 		} else {
    286 			object->map.ptr = (void *)(unsigned long)handle;
    287 			return 0;
    288 		}
    289 		nvif_object_unmap_handle(object);
    290 	}
    291 	return ret;
    292 }
    293 
    294 void
    295 nvif_object_fini(struct nvif_object *object)
    296 {
    297 	struct {
    298 		struct nvif_ioctl_v0 ioctl;
    299 		struct nvif_ioctl_del del;
    300 	} args = {
    301 		.ioctl.type = NVIF_IOCTL_V0_DEL,
    302 	};
    303 
    304 	if (!object->client)
    305 		return;
    306 
    307 	nvif_object_unmap(object);
    308 	nvif_object_ioctl(object, &args, sizeof(args), NULL);
    309 	object->client = NULL;
    310 }
    311 
    312 int
    313 nvif_object_init(struct nvif_object *parent, u32 handle, s32 oclass,
    314 		 void *data, u32 size, struct nvif_object *object)
    315 {
    316 	struct {
    317 		struct nvif_ioctl_v0 ioctl;
    318 		struct nvif_ioctl_new_v0 new;
    319 	} *args;
    320 	int ret = 0;
    321 
    322 	object->client = NULL;
    323 	object->handle = handle;
    324 	object->oclass = oclass;
    325 	object->map.ptr = NULL;
    326 	object->map.size = 0;
    327 
    328 	if (parent) {
    329 		if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) {
    330 			nvif_object_fini(object);
    331 			return -ENOMEM;
    332 		}
    333 
    334 		args->ioctl.version = 0;
    335 		args->ioctl.type = NVIF_IOCTL_V0_NEW;
    336 		args->new.version = 0;
    337 		args->new.route = parent->client->route;
    338 		args->new.token = nvif_handle(object);
    339 		args->new.object = nvif_handle(object);
    340 		args->new.handle = handle;
    341 		args->new.oclass = oclass;
    342 
    343 		memcpy(args->new.data, data, size);
    344 		ret = nvif_object_ioctl(parent, args, sizeof(*args) + size,
    345 					&object->priv);
    346 		memcpy(data, args->new.data, size);
    347 		kfree(args);
    348 		if (ret == 0)
    349 			object->client = parent->client;
    350 	}
    351 
    352 	if (ret)
    353 		nvif_object_fini(object);
    354 	return ret;
    355 }
    356