Home | History | Annotate | Line # | Download | only in core
      1 /*	$NetBSD: nouveau_nvkm_core_object.c,v 1.11 2021/12/19 11:07:11 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012 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
     25  */
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_core_object.c,v 1.11 2021/12/19 11:07:11 riastradh Exp $");
     28 
     29 #include <core/object.h>
     30 #include <core/client.h>
     31 #include <core/engine.h>
     32 
     33 struct nvkm_object *
     34 nvkm_object_search(struct nvkm_client *client, u64 handle,
     35 		   const struct nvkm_object_func *func)
     36 {
     37 	struct nvkm_object *object;
     38 
     39 	if (handle) {
     40 #ifdef __NetBSD__
     41 		object = rb_tree_find_node(&client->objtree, &handle);
     42 		if (object)
     43 			goto done;
     44 #else
     45 		struct rb_node *node = client->objroot.rb_node;
     46 		while (node) {
     47 			object = rb_entry(node, typeof(*object), node);
     48 			if (handle < object->object)
     49 				node = node->rb_left;
     50 			else
     51 			if (handle > object->object)
     52 				node = node->rb_right;
     53 			else
     54 				goto done;
     55 		}
     56 #endif
     57 		return ERR_PTR(-ENOENT);
     58 	} else {
     59 		object = &client->object;
     60 	}
     61 
     62 done:
     63 	if (unlikely(func && object->func != func))
     64 		return ERR_PTR(-EINVAL);
     65 	return object;
     66 }
     67 
     68 void
     69 nvkm_object_remove(struct nvkm_object *object)
     70 {
     71 #ifdef __NetBSD__
     72 	if (object->on_tree) {
     73 		rb_tree_remove_node(&object->client->objtree, object);
     74 		object->on_tree = false;
     75 	}
     76 #else
     77 	if (!RB_EMPTY_NODE(&object->node))
     78 		rb_erase(&object->node, &object->client->objroot);
     79 #endif
     80 }
     81 
     82 bool
     83 nvkm_object_insert(struct nvkm_object *object)
     84 {
     85 #ifdef __NetBSD__
     86 	struct nvkm_object *collision =
     87 	    rb_tree_insert_node(&object->client->objtree, object);
     88 
     89 	if (collision != object)
     90 		return false;	/* EEXIST */
     91 
     92 	object->on_tree = true;
     93 	return true;
     94 #else
     95 	struct rb_node **ptr = &object->client->objroot.rb_node;
     96 	struct rb_node *parent = NULL;
     97 
     98 	while (*ptr) {
     99 		struct nvkm_object *this = rb_entry(*ptr, typeof(*this), node);
    100 		parent = *ptr;
    101 		if (object->object < this->object)
    102 			ptr = &parent->rb_left;
    103 		else
    104 		if (object->object > this->object)
    105 			ptr = &parent->rb_right;
    106 		else
    107 			return false;
    108 	}
    109 
    110 	rb_link_node(&object->node, parent, ptr);
    111 	rb_insert_color(&object->node, &object->client->objroot);
    112 	return true;
    113 #endif
    114 }
    115 
    116 int
    117 nvkm_object_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
    118 {
    119 	if (likely(object->func->mthd))
    120 		return object->func->mthd(object, mthd, data, size);
    121 	return -ENODEV;
    122 }
    123 
    124 int
    125 nvkm_object_ntfy(struct nvkm_object *object, u32 mthd,
    126 		 struct nvkm_event **pevent)
    127 {
    128 	if (likely(object->func->ntfy))
    129 		return object->func->ntfy(object, mthd, pevent);
    130 	return -ENODEV;
    131 }
    132 
    133 #ifdef __NetBSD__
    134 int
    135 nvkm_object_map(struct nvkm_object *object, void *argv, u32 argc,
    136     enum nvkm_object_map *type, bus_space_tag_t *tagp, u64 *addr, u64 *size)
    137 {
    138 	if (likely(object->func->map))
    139 		return object->func->map(object, argv, argc, type, tagp, addr,
    140 		    size);
    141 	return -ENODEV;
    142 }
    143 #else
    144 int
    145 nvkm_object_map(struct nvkm_object *object, void *argv, u32 argc,
    146 		enum nvkm_object_map *type, u64 *addr, u64 *size)
    147 {
    148 	if (likely(object->func->map))
    149 		return object->func->map(object, argv, argc, type, addr, size);
    150 	return -ENODEV;
    151 }
    152 #endif
    153 
    154 int
    155 nvkm_object_unmap(struct nvkm_object *object)
    156 {
    157 	if (likely(object->func->unmap))
    158 		return object->func->unmap(object);
    159 	return -ENODEV;
    160 }
    161 
    162 int
    163 nvkm_object_rd08(struct nvkm_object *object, u64 addr, u8 *data)
    164 {
    165 	if (likely(object->func->rd08))
    166 		return object->func->rd08(object, addr, data);
    167 	return -ENODEV;
    168 }
    169 
    170 int
    171 nvkm_object_rd16(struct nvkm_object *object, u64 addr, u16 *data)
    172 {
    173 	if (likely(object->func->rd16))
    174 		return object->func->rd16(object, addr, data);
    175 	return -ENODEV;
    176 }
    177 
    178 int
    179 nvkm_object_rd32(struct nvkm_object *object, u64 addr, u32 *data)
    180 {
    181 	if (likely(object->func->rd32))
    182 		return object->func->rd32(object, addr, data);
    183 	return -ENODEV;
    184 }
    185 
    186 int
    187 nvkm_object_wr08(struct nvkm_object *object, u64 addr, u8 data)
    188 {
    189 	if (likely(object->func->wr08))
    190 		return object->func->wr08(object, addr, data);
    191 	return -ENODEV;
    192 }
    193 
    194 int
    195 nvkm_object_wr16(struct nvkm_object *object, u64 addr, u16 data)
    196 {
    197 	if (likely(object->func->wr16))
    198 		return object->func->wr16(object, addr, data);
    199 	return -ENODEV;
    200 }
    201 
    202 int
    203 nvkm_object_wr32(struct nvkm_object *object, u64 addr, u32 data)
    204 {
    205 	if (likely(object->func->wr32))
    206 		return object->func->wr32(object, addr, data);
    207 	return -ENODEV;
    208 }
    209 
    210 int
    211 nvkm_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *gpuobj,
    212 		 int align, struct nvkm_gpuobj **pgpuobj)
    213 {
    214 	if (object->func->bind)
    215 		return object->func->bind(object, gpuobj, align, pgpuobj);
    216 	return -ENODEV;
    217 }
    218 
    219 int
    220 nvkm_object_fini(struct nvkm_object *object, bool suspend)
    221 {
    222 	const char *action = suspend ? "suspend" : "fini";
    223 	struct nvkm_object *child;
    224 	s64 time;
    225 	int ret;
    226 
    227 	nvif_debug(object, "%s children...\n", action);
    228 	time = ktime_to_us(ktime_get());
    229 	list_for_each_entry(child, &object->tree, head) {
    230 		ret = nvkm_object_fini(child, suspend);
    231 		if (ret && suspend)
    232 			goto fail_child;
    233 	}
    234 
    235 	nvif_debug(object, "%s running...\n", action);
    236 	if (object->func->fini) {
    237 		ret = object->func->fini(object, suspend);
    238 		if (ret) {
    239 			nvif_error(object, "%s failed with %d\n", action, ret);
    240 			if (suspend)
    241 				goto fail;
    242 		}
    243 	}
    244 
    245 	time = ktime_to_us(ktime_get()) - time;
    246 	nvif_debug(object, "%s completed in %"PRId64"us\n", action, time);
    247 	return 0;
    248 
    249 fail:
    250 	if (object->func->init) {
    251 		int rret = object->func->init(object);
    252 		if (rret)
    253 			nvif_fatal(object, "failed to restart, %d\n", rret);
    254 	}
    255 fail_child:
    256 	list_for_each_entry_continue_reverse(child, &object->tree, head) {
    257 		nvkm_object_init(child);
    258 	}
    259 	return ret;
    260 }
    261 
    262 int
    263 nvkm_object_init(struct nvkm_object *object)
    264 {
    265 	struct nvkm_object *child;
    266 	s64 time;
    267 	int ret;
    268 
    269 	nvif_debug(object, "init running...\n");
    270 	time = ktime_to_us(ktime_get());
    271 	if (object->func->init) {
    272 		ret = object->func->init(object);
    273 		if (ret)
    274 			goto fail;
    275 	}
    276 
    277 	nvif_debug(object, "init children...\n");
    278 	list_for_each_entry(child, &object->tree, head) {
    279 		ret = nvkm_object_init(child);
    280 		if (ret)
    281 			goto fail_child;
    282 	}
    283 
    284 	time = ktime_to_us(ktime_get()) - time;
    285 	nvif_debug(object, "init completed in %"PRId64"us\n", time);
    286 	return 0;
    287 
    288 fail_child:
    289 	list_for_each_entry_continue_reverse(child, &object->tree, head)
    290 		nvkm_object_fini(child, false);
    291 fail:
    292 	nvif_error(object, "init failed with %d\n", ret);
    293 	if (object->func->fini)
    294 		object->func->fini(object, false);
    295 	return ret;
    296 }
    297 
    298 void *
    299 nvkm_object_dtor(struct nvkm_object *object)
    300 {
    301 	struct nvkm_object *child, *ctemp;
    302 	void *data = object;
    303 	s64 time;
    304 
    305 	nvif_debug(object, "destroy children...\n");
    306 	time = ktime_to_us(ktime_get());
    307 	list_for_each_entry_safe(child, ctemp, &object->tree, head) {
    308 		nvkm_object_del(&child);
    309 	}
    310 
    311 	nvif_debug(object, "destroy running...\n");
    312 	nvkm_object_unmap(object);
    313 	if (object->func->dtor)
    314 		data = object->func->dtor(object);
    315 	nvkm_engine_unref(&object->engine);
    316 	time = ktime_to_us(ktime_get()) - time;
    317 	nvif_debug(object, "destroy completed in %"PRId64"us...\n", time);
    318 	return data;
    319 }
    320 
    321 void
    322 nvkm_object_del(struct nvkm_object **pobject)
    323 {
    324 	struct nvkm_object *object = *pobject;
    325 	if (object && !WARN_ON(!object->func)) {
    326 		*pobject = nvkm_object_dtor(object);
    327 		nvkm_object_remove(object);
    328 		list_del(&object->head);
    329 		kfree(*pobject);
    330 		*pobject = NULL;
    331 	}
    332 }
    333 
    334 void
    335 nvkm_object_ctor(const struct nvkm_object_func *func,
    336 		 const struct nvkm_oclass *oclass, struct nvkm_object *object)
    337 {
    338 	object->func = func;
    339 	object->client = oclass->client;
    340 	object->engine = nvkm_engine_ref(oclass->engine);
    341 	object->oclass = oclass->base.oclass;
    342 	object->handle = oclass->handle;
    343 	object->route  = oclass->route;
    344 	object->token  = oclass->token;
    345 	object->object = oclass->object;
    346 	INIT_LIST_HEAD(&object->head);
    347 	INIT_LIST_HEAD(&object->tree);
    348 #ifdef __NetBSD__
    349 	object->on_tree = false;
    350 #else
    351 	RB_CLEAR_NODE(&object->node);
    352 #endif
    353 	WARN_ON(IS_ERR(object->engine));
    354 }
    355 
    356 int
    357 nvkm_object_new_(const struct nvkm_object_func *func,
    358 		 const struct nvkm_oclass *oclass, void *data, u32 size,
    359 		 struct nvkm_object **pobject)
    360 {
    361 	if (size == 0) {
    362 		if (!(*pobject = kzalloc(sizeof(**pobject), GFP_KERNEL)))
    363 			return -ENOMEM;
    364 		nvkm_object_ctor(func, oclass, *pobject);
    365 		return 0;
    366 	}
    367 	return -ENOSYS;
    368 }
    369 
    370 static const struct nvkm_object_func
    371 nvkm_object_func = {
    372 };
    373 
    374 int
    375 nvkm_object_new(const struct nvkm_oclass *oclass, void *data, u32 size,
    376 		struct nvkm_object **pobject)
    377 {
    378 	const struct nvkm_object_func *func =
    379 		oclass->base.func ? oclass->base.func : &nvkm_object_func;
    380 	return nvkm_object_new_(func, oclass, data, size, pobject);
    381 }
    382