1 /*	$NetBSD: nouveau_core_object.c,v 1.3 2015/10/18 14:49:24 jmcneill 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 
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: nouveau_core_object.c,v 1.3 2015/10/18 14:49:24 jmcneill Exp $");
29 
30 #include <core/object.h>
31 #include <core/parent.h>
32 #include <core/namedb.h>
33 #include <core/handle.h>
34 #include <core/engine.h>
35 
36 #ifdef NOUVEAU_OBJECT_MAGIC
37 static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
38 #ifdef __NetBSD__
39 static spinlock_t _objlist_lock;
40 #else
41 static DEFINE_SPINLOCK(_objlist_lock);
42 #endif
43 #endif
44 
45 #ifdef __NetBSD__
46 void
nouveau_objects_init(void)47 nouveau_objects_init(void)
48 {
49 
50 #ifdef NOUVEAU_OBJECT_MAGIC
51 	spin_lock_init(&_objlist_lock);
52 #endif
53 }
54 
55 void
nouveau_objects_fini(void)56 nouveau_objects_fini(void)
57 {
58 
59 #ifdef NOUVEAU_OBJECT_MAGIC
60 	spin_lock_destroy(&_objlist_lock);
61 #endif
62 }
63 #endif
64 
65 int
nouveau_object_create_(struct nouveau_object * parent,struct nouveau_object * engine,struct nouveau_oclass * oclass,u32 pclass,int size,void ** pobject)66 nouveau_object_create_(struct nouveau_object *parent,
67 		       struct nouveau_object *engine,
68 		       struct nouveau_oclass *oclass, u32 pclass,
69 		       int size, void **pobject)
70 {
71 	struct nouveau_object *object;
72 
73 	object = *pobject = kzalloc(size, GFP_KERNEL);
74 	if (!object)
75 		return -ENOMEM;
76 
77 	nouveau_object_ref(parent, &object->parent);
78 	nouveau_object_ref(engine, &object->engine);
79 	object->oclass = oclass;
80 	object->oclass->handle |= pclass;
81 	atomic_set(&object->refcount, 1);
82 	atomic_set(&object->usecount, 0);
83 
84 #ifdef NOUVEAU_OBJECT_MAGIC
85 	object->_magic = NOUVEAU_OBJECT_MAGIC;
86 	spin_lock(&_objlist_lock);
87 	list_add(&object->list, &_objlist);
88 	spin_unlock(&_objlist_lock);
89 #endif
90 	return 0;
91 }
92 
93 static int
_nouveau_object_ctor(struct nouveau_object * parent,struct nouveau_object * engine,struct nouveau_oclass * oclass,void * data,u32 size,struct nouveau_object ** pobject)94 _nouveau_object_ctor(struct nouveau_object *parent,
95 		     struct nouveau_object *engine,
96 		     struct nouveau_oclass *oclass, void *data, u32 size,
97 		     struct nouveau_object **pobject)
98 {
99 	struct nouveau_object *object;
100 	int ret;
101 
102 	ret = nouveau_object_create(parent, engine, oclass, 0, &object);
103 	*pobject = nv_object(object);
104 	if (ret)
105 		return ret;
106 
107 	return 0;
108 }
109 
110 void
nouveau_object_destroy(struct nouveau_object * object)111 nouveau_object_destroy(struct nouveau_object *object)
112 {
113 #ifdef NOUVEAU_OBJECT_MAGIC
114 	spin_lock(&_objlist_lock);
115 	list_del(&object->list);
116 	spin_unlock(&_objlist_lock);
117 #endif
118 	nouveau_object_ref(NULL, &object->engine);
119 	nouveau_object_ref(NULL, &object->parent);
120 	kfree(object);
121 }
122 
123 static void
_nouveau_object_dtor(struct nouveau_object * object)124 _nouveau_object_dtor(struct nouveau_object *object)
125 {
126 	nouveau_object_destroy(object);
127 }
128 
129 int
nouveau_object_init(struct nouveau_object * object)130 nouveau_object_init(struct nouveau_object *object)
131 {
132 	return 0;
133 }
134 
135 static int
_nouveau_object_init(struct nouveau_object * object)136 _nouveau_object_init(struct nouveau_object *object)
137 {
138 	return nouveau_object_init(object);
139 }
140 
141 int
nouveau_object_fini(struct nouveau_object * object,bool suspend)142 nouveau_object_fini(struct nouveau_object *object, bool suspend)
143 {
144 	return 0;
145 }
146 
147 static int
_nouveau_object_fini(struct nouveau_object * object,bool suspend)148 _nouveau_object_fini(struct nouveau_object *object, bool suspend)
149 {
150 	return nouveau_object_fini(object, suspend);
151 }
152 
153 struct nouveau_ofuncs
154 nouveau_object_ofuncs = {
155 	.ctor = _nouveau_object_ctor,
156 	.dtor = _nouveau_object_dtor,
157 	.init = _nouveau_object_init,
158 	.fini = _nouveau_object_fini,
159 };
160 
161 int
nouveau_object_ctor(struct nouveau_object * parent,struct nouveau_object * engine,struct nouveau_oclass * oclass,void * data,u32 size,struct nouveau_object ** pobject)162 nouveau_object_ctor(struct nouveau_object *parent,
163 		    struct nouveau_object *engine,
164 		    struct nouveau_oclass *oclass, void *data, u32 size,
165 		    struct nouveau_object **pobject)
166 {
167 	struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
168 	struct nouveau_object *object = NULL;
169 	int ret;
170 
171 	ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
172 	*pobject = object;
173 	if (ret < 0) {
174 		if (ret != -ENODEV) {
175 			nv_error(parent, "failed to create 0x%08x, %d\n",
176 				 oclass->handle, ret);
177 		}
178 
179 		if (object) {
180 			ofuncs->dtor(object);
181 			*pobject = NULL;
182 		}
183 
184 		return ret;
185 	}
186 
187 	if (ret == 0) {
188 		nv_debug(object, "created\n");
189 		atomic_set(&object->refcount, 1);
190 	}
191 
192 	return 0;
193 }
194 
195 static void
nouveau_object_dtor(struct nouveau_object * object)196 nouveau_object_dtor(struct nouveau_object *object)
197 {
198 	nv_debug(object, "destroying\n");
199 	nv_ofuncs(object)->dtor(object);
200 }
201 
202 void
nouveau_object_ref(struct nouveau_object * obj,struct nouveau_object ** ref)203 nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
204 {
205 	if (obj) {
206 		atomic_inc(&obj->refcount);
207 		nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
208 	}
209 
210 	if (*ref) {
211 		int dead = atomic_dec_and_test(&(*ref)->refcount);
212 		nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
213 		if (dead)
214 			nouveau_object_dtor(*ref);
215 	}
216 
217 	*ref = obj;
218 }
219 
220 int
nouveau_object_new(struct nouveau_object * client,u32 _parent,u32 _handle,u16 _oclass,void * data,u32 size,struct nouveau_object ** pobject)221 nouveau_object_new(struct nouveau_object *client, u32 _parent, u32 _handle,
222 		   u16 _oclass, void *data, u32 size,
223 		   struct nouveau_object **pobject)
224 {
225 	struct nouveau_object *parent = NULL;
226 	struct nouveau_object *engctx = NULL;
227 	struct nouveau_object *object = NULL;
228 	struct nouveau_object *engine;
229 	struct nouveau_oclass *oclass;
230 	struct nouveau_handle *handle;
231 	int ret;
232 
233 	/* lookup parent object and ensure it *is* a parent */
234 	parent = nouveau_handle_ref(client, _parent);
235 	if (!parent) {
236 		nv_error(client, "parent 0x%08x not found\n", _parent);
237 		return -ENOENT;
238 	}
239 
240 	if (!nv_iclass(parent, NV_PARENT_CLASS)) {
241 		nv_error(parent, "cannot have children\n");
242 		ret = -EINVAL;
243 		goto fail_class;
244 	}
245 
246 	/* check that parent supports the requested subclass */
247 	ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass);
248 	if (ret) {
249 		nv_debug(parent, "illegal class 0x%04x\n", _oclass);
250 		goto fail_class;
251 	}
252 
253 	/* make sure engine init has been completed *before* any objects
254 	 * it controls are created - the constructors may depend on
255 	 * state calculated at init (ie. default context construction)
256 	 */
257 	if (engine) {
258 		ret = nouveau_object_inc(engine);
259 		if (ret)
260 			goto fail_class;
261 	}
262 
263 	/* if engine requires it, create a context object to insert
264 	 * between the parent and its children (eg. PGRAPH context)
265 	 */
266 	if (engine && nv_engine(engine)->cclass) {
267 		ret = nouveau_object_ctor(parent, engine,
268 					  nv_engine(engine)->cclass,
269 					  data, size, &engctx);
270 		if (ret)
271 			goto fail_engctx;
272 	} else {
273 		nouveau_object_ref(parent, &engctx);
274 	}
275 
276 	/* finally, create new object and bind it to its handle */
277 	ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
278 	*pobject = object;
279 	if (ret)
280 		goto fail_ctor;
281 
282 	ret = nouveau_object_inc(object);
283 	if (ret)
284 		goto fail_init;
285 
286 	ret = nouveau_handle_create(parent, _parent, _handle, object, &handle);
287 	if (ret)
288 		goto fail_handle;
289 
290 	ret = nouveau_handle_init(handle);
291 	if (ret)
292 		nouveau_handle_destroy(handle);
293 
294 fail_handle:
295 	nouveau_object_dec(object, false);
296 fail_init:
297 	nouveau_object_ref(NULL, &object);
298 fail_ctor:
299 	nouveau_object_ref(NULL, &engctx);
300 fail_engctx:
301 	if (engine)
302 		nouveau_object_dec(engine, false);
303 fail_class:
304 	nouveau_object_ref(NULL, &parent);
305 	return ret;
306 }
307 
308 int
nouveau_object_del(struct nouveau_object * client,u32 _parent,u32 _handle)309 nouveau_object_del(struct nouveau_object *client, u32 _parent, u32 _handle)
310 {
311 	struct nouveau_object *parent = NULL;
312 	struct nouveau_object *namedb = NULL;
313 	struct nouveau_handle *handle = NULL;
314 
315 	parent = nouveau_handle_ref(client, _parent);
316 	if (!parent)
317 		return -ENOENT;
318 
319 	namedb = nv_pclass(parent, NV_NAMEDB_CLASS);
320 	if (namedb) {
321 		handle = nouveau_namedb_get(nv_namedb(namedb), _handle);
322 		if (handle) {
323 			nouveau_namedb_put(handle);
324 			nouveau_handle_fini(handle, false);
325 			nouveau_handle_destroy(handle);
326 		}
327 	}
328 
329 	nouveau_object_ref(NULL, &parent);
330 	return handle ? 0 : -EINVAL;
331 }
332 
333 int
nouveau_object_inc(struct nouveau_object * object)334 nouveau_object_inc(struct nouveau_object *object)
335 {
336 	int ref = atomic_add_return(1, &object->usecount);
337 	int ret;
338 
339 	nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
340 	if (ref != 1)
341 		return 0;
342 
343 	nv_trace(object, "initialising...\n");
344 	if (object->parent) {
345 		ret = nouveau_object_inc(object->parent);
346 		if (ret) {
347 			nv_error(object, "parent failed, %d\n", ret);
348 			goto fail_parent;
349 		}
350 	}
351 
352 	if (object->engine) {
353 		mutex_lock(&nv_subdev(object->engine)->mutex);
354 		ret = nouveau_object_inc(object->engine);
355 		mutex_unlock(&nv_subdev(object->engine)->mutex);
356 		if (ret) {
357 			nv_error(object, "engine failed, %d\n", ret);
358 			goto fail_engine;
359 		}
360 	}
361 
362 	ret = nv_ofuncs(object)->init(object);
363 	atomic_set(&object->usecount, 1);
364 	if (ret) {
365 		nv_error(object, "init failed, %d\n", ret);
366 		goto fail_self;
367 	}
368 
369 	nv_debug(object, "initialised\n");
370 	return 0;
371 
372 fail_self:
373 	if (object->engine) {
374 		mutex_lock(&nv_subdev(object->engine)->mutex);
375 		nouveau_object_dec(object->engine, false);
376 		mutex_unlock(&nv_subdev(object->engine)->mutex);
377 	}
378 fail_engine:
379 	if (object->parent)
380 		 nouveau_object_dec(object->parent, false);
381 fail_parent:
382 	atomic_dec(&object->usecount);
383 	return ret;
384 }
385 
386 static int
nouveau_object_decf(struct nouveau_object * object)387 nouveau_object_decf(struct nouveau_object *object)
388 {
389 	int ret;
390 
391 	nv_trace(object, "stopping...\n");
392 
393 	ret = nv_ofuncs(object)->fini(object, false);
394 	atomic_set(&object->usecount, 0);
395 	if (ret)
396 		nv_warn(object, "failed fini, %d\n", ret);
397 
398 	if (object->engine) {
399 		mutex_lock(&nv_subdev(object->engine)->mutex);
400 		nouveau_object_dec(object->engine, false);
401 		mutex_unlock(&nv_subdev(object->engine)->mutex);
402 	}
403 
404 	if (object->parent)
405 		nouveau_object_dec(object->parent, false);
406 
407 	nv_debug(object, "stopped\n");
408 	return 0;
409 }
410 
411 static int
nouveau_object_decs(struct nouveau_object * object)412 nouveau_object_decs(struct nouveau_object *object)
413 {
414 	int ret, rret;
415 
416 	nv_trace(object, "suspending...\n");
417 
418 	ret = nv_ofuncs(object)->fini(object, true);
419 	atomic_set(&object->usecount, 0);
420 	if (ret) {
421 		nv_error(object, "failed suspend, %d\n", ret);
422 		return ret;
423 	}
424 
425 	if (object->engine) {
426 		mutex_lock(&nv_subdev(object->engine)->mutex);
427 		ret = nouveau_object_dec(object->engine, true);
428 		mutex_unlock(&nv_subdev(object->engine)->mutex);
429 		if (ret) {
430 			nv_warn(object, "engine failed suspend, %d\n", ret);
431 			goto fail_engine;
432 		}
433 	}
434 
435 	if (object->parent) {
436 		ret = nouveau_object_dec(object->parent, true);
437 		if (ret) {
438 			nv_warn(object, "parent failed suspend, %d\n", ret);
439 			goto fail_parent;
440 		}
441 	}
442 
443 	nv_debug(object, "suspended\n");
444 	return 0;
445 
446 fail_parent:
447 	if (object->engine) {
448 		mutex_lock(&nv_subdev(object->engine)->mutex);
449 		rret = nouveau_object_inc(object->engine);
450 		mutex_unlock(&nv_subdev(object->engine)->mutex);
451 		if (rret)
452 			nv_fatal(object, "engine failed to reinit, %d\n", rret);
453 	}
454 
455 fail_engine:
456 	rret = nv_ofuncs(object)->init(object);
457 	if (rret)
458 		nv_fatal(object, "failed to reinit, %d\n", rret);
459 
460 	return ret;
461 }
462 
463 int
nouveau_object_dec(struct nouveau_object * object,bool suspend)464 nouveau_object_dec(struct nouveau_object *object, bool suspend)
465 {
466 	int ref = atomic_add_return(-1, &object->usecount);
467 	int ret;
468 
469 	nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
470 
471 	if (ref == 0) {
472 		if (suspend)
473 			ret = nouveau_object_decs(object);
474 		else
475 			ret = nouveau_object_decf(object);
476 
477 		if (ret) {
478 			atomic_inc(&object->usecount);
479 			return ret;
480 		}
481 	}
482 
483 	return 0;
484 }
485 
486 void
nouveau_object_debug(void)487 nouveau_object_debug(void)
488 {
489 #ifdef NOUVEAU_OBJECT_MAGIC
490 	struct nouveau_object *object;
491 	if (!list_empty(&_objlist)) {
492 		nv_fatal(NULL, "*******************************************\n");
493 		nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
494 		nv_fatal(NULL, "*******************************************\n");
495 		list_for_each_entry(object, &_objlist, list) {
496 			nv_fatal(object, "%p/%p/%d/%d\n",
497 				 object->parent, object->engine,
498 				 atomic_read(&object->refcount),
499 				 atomic_read(&object->usecount));
500 		}
501 	}
502 #endif
503 }
504