19274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs/*
29274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * Copyright 2012 Red Hat Inc.
39274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs *
49274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
59274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * copy of this software and associated documentation files (the "Software"),
69274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * to deal in the Software without restriction, including without limitation
79274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
89274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * and/or sell copies of the Software, and to permit persons to whom the
99274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * Software is furnished to do so, subject to the following conditions:
109274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs *
119274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * The above copyright notice and this permission notice shall be included in
129274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * all copies or substantial portions of the Software.
139274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs *
149274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
159274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
169274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
179274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
189274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
199274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
209274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * OTHER DEALINGS IN THE SOFTWARE.
219274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs *
229274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs * Authors: Ben Skeggs
239274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs */
249274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
259274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#include <core/object.h>
269274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#include <core/engine.h>
279274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
289274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#ifdef NOUVEAU_OBJECT_MAGIC
299274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsstatic struct list_head _objlist = LIST_HEAD_INIT(_objlist);
309274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsstatic DEFINE_SPINLOCK(_objlist_lock);
319274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#endif
329274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
339274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsint
349274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_create_(struct nouveau_object *parent,
359274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		       struct nouveau_object *engine,
369274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		       struct nouveau_oclass *oclass, u32 pclass,
379274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		       int size, void **pobject)
389274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
399274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	struct nouveau_object *object;
409274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
419274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	object = *pobject = kzalloc(size, GFP_KERNEL);
429274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (!object)
439274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		return -ENOMEM;
449274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
459274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nouveau_object_ref(parent, &object->parent);
469274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nouveau_object_ref(engine, &object->engine);
479274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	object->oclass = oclass;
489274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	object->oclass->handle |= pclass;
499274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	atomic_set(&object->refcount, 1);
509274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	atomic_set(&object->usecount, 0);
519274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
529274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#ifdef NOUVEAU_OBJECT_MAGIC
539274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	object->_magic = NOUVEAU_OBJECT_MAGIC;
549274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	spin_lock(&_objlist_lock);
559274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	list_add(&object->list, &_objlist);
569274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	spin_unlock(&_objlist_lock);
579274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#endif
589274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return 0;
599274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
609274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
61a532da976f17234375d3b34633ff5d48f71f62bcBen Skeggsint
629274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs_nouveau_object_ctor(struct nouveau_object *parent,
639274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		     struct nouveau_object *engine,
649274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		     struct nouveau_oclass *oclass, void *data, u32 size,
659274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		     struct nouveau_object **pobject)
669274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
67f5ee92f085376859d5c31743262350f8e344689aBen Skeggs	if (size != 0)
68f5ee92f085376859d5c31743262350f8e344689aBen Skeggs		return -ENOSYS;
69f5ee92f085376859d5c31743262350f8e344689aBen Skeggs	return nouveau_object_create(parent, engine, oclass, 0, pobject);
709274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
719274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
729274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsvoid
739274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_destroy(struct nouveau_object *object)
749274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
759274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#ifdef NOUVEAU_OBJECT_MAGIC
769274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	spin_lock(&_objlist_lock);
779274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	list_del(&object->list);
789274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	spin_unlock(&_objlist_lock);
799274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#endif
809274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nouveau_object_ref(NULL, &object->engine);
819274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nouveau_object_ref(NULL, &object->parent);
829274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	kfree(object);
839274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
849274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
859274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsint
869274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_init(struct nouveau_object *object)
879274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
889274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return 0;
899274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
909274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
919274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsint
929274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_fini(struct nouveau_object *object, bool suspend)
939274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
949274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return 0;
959274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
969274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
979274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsstruct nouveau_ofuncs
989274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_ofuncs = {
999274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	.ctor = _nouveau_object_ctor,
100f5ee92f085376859d5c31743262350f8e344689aBen Skeggs	.dtor = nouveau_object_destroy,
101f5ee92f085376859d5c31743262350f8e344689aBen Skeggs	.init = nouveau_object_init,
102f5ee92f085376859d5c31743262350f8e344689aBen Skeggs	.fini = nouveau_object_fini,
1039274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs};
1049274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1059274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsint
1069274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_ctor(struct nouveau_object *parent,
1079274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		    struct nouveau_object *engine,
1089274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		    struct nouveau_oclass *oclass, void *data, u32 size,
1099274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		    struct nouveau_object **pobject)
1109274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
1119274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
112db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs	struct nouveau_object *object = NULL;
1139274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	int ret;
1149274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
115db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs	ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
116db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs	*pobject = object;
1179274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (ret < 0) {
1189274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (ret != -ENODEV) {
1199274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			nv_error(parent, "failed to create 0x%08x, %d\n",
1209274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs				 oclass->handle, ret);
1219274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		}
1229274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
123db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs		if (object) {
124db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs			ofuncs->dtor(object);
1259274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			*pobject = NULL;
1269274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		}
1279274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1289274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		return ret;
1299274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
1309274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
131db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs	if (ret == 0) {
132964f85ec51c860c813858a9950c5eda9311410d5Ben Skeggs		nv_trace(object, "created\n");
133db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs		atomic_set(&object->refcount, 1);
134db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs	}
135db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs
1369274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return 0;
1379274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
1389274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1399274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsstatic void
1409274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_dtor(struct nouveau_object *object)
1419274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
142964f85ec51c860c813858a9950c5eda9311410d5Ben Skeggs	nv_trace(object, "destroying\n");
1439274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nv_ofuncs(object)->dtor(object);
1449274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
1459274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1469274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsvoid
1479274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
1489274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
1499274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (obj) {
1509274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		atomic_inc(&obj->refcount);
1519274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
1529274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
1539274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1549274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (*ref) {
1559274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		int dead = atomic_dec_and_test(&(*ref)->refcount);
1569274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
1579274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (dead)
1589274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			nouveau_object_dtor(*ref);
1599274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
1609274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1619274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	*ref = obj;
1629274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
1639274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1649274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsint
1659274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_inc(struct nouveau_object *object)
1669274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
1679274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	int ref = atomic_add_return(1, &object->usecount);
1689274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	int ret;
1699274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1709274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
1719274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (ref != 1)
1729274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		return 0;
1739274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1749274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nv_trace(object, "initialising...\n");
1759274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->parent) {
1769274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		ret = nouveau_object_inc(object->parent);
1779274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (ret) {
1789274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			nv_error(object, "parent failed, %d\n", ret);
1799274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			goto fail_parent;
1809274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		}
1819274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
1829274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1839274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->engine) {
1849274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_lock(&nv_subdev(object->engine)->mutex);
1859274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		ret = nouveau_object_inc(object->engine);
1869274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_unlock(&nv_subdev(object->engine)->mutex);
1879274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (ret) {
1889274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			nv_error(object, "engine failed, %d\n", ret);
1899274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			goto fail_engine;
1909274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		}
1919274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
1929274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
1939274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	ret = nv_ofuncs(object)->init(object);
194db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs	atomic_set(&object->usecount, 1);
1959274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (ret) {
1969274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_error(object, "init failed, %d\n", ret);
1979274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		goto fail_self;
1989274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
1999274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
200964f85ec51c860c813858a9950c5eda9311410d5Ben Skeggs	nv_trace(object, "initialised\n");
2019274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return 0;
2029274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2039274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsfail_self:
2049274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->engine) {
2059274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_lock(&nv_subdev(object->engine)->mutex);
2069274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nouveau_object_dec(object->engine, false);
2079274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_unlock(&nv_subdev(object->engine)->mutex);
2089274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
2099274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsfail_engine:
2109274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->parent)
2119274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		 nouveau_object_dec(object->parent, false);
2129274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsfail_parent:
2139274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	atomic_dec(&object->usecount);
2149274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return ret;
2159274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
2169274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2179274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsstatic int
2189274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_decf(struct nouveau_object *object)
2199274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
2209274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	int ret;
2219274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2229274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nv_trace(object, "stopping...\n");
2239274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2249274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	ret = nv_ofuncs(object)->fini(object, false);
225db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs	atomic_set(&object->usecount, 0);
2269274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (ret)
2279274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_warn(object, "failed fini, %d\n", ret);
2289274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2299274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->engine) {
2309274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_lock(&nv_subdev(object->engine)->mutex);
2319274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nouveau_object_dec(object->engine, false);
2329274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_unlock(&nv_subdev(object->engine)->mutex);
2339274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
2349274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2359274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->parent)
2369274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nouveau_object_dec(object->parent, false);
2379274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
238964f85ec51c860c813858a9950c5eda9311410d5Ben Skeggs	nv_trace(object, "stopped\n");
2399274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return 0;
2409274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
2419274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2429274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsstatic int
2439274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_decs(struct nouveau_object *object)
2449274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
2459274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	int ret, rret;
2469274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2479274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nv_trace(object, "suspending...\n");
2489274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2499274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	ret = nv_ofuncs(object)->fini(object, true);
250db91d68c9b5ca22e1fa25569bbde4895ade9dac0Ben Skeggs	atomic_set(&object->usecount, 0);
2519274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (ret) {
2529274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_error(object, "failed suspend, %d\n", ret);
2539274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		return ret;
2549274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
2559274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2569274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->engine) {
2579274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_lock(&nv_subdev(object->engine)->mutex);
2589274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		ret = nouveau_object_dec(object->engine, true);
2599274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_unlock(&nv_subdev(object->engine)->mutex);
2609274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (ret) {
2619274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			nv_warn(object, "engine failed suspend, %d\n", ret);
2629274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			goto fail_engine;
2639274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		}
2649274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
2659274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2669274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->parent) {
2679274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		ret = nouveau_object_dec(object->parent, true);
2689274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (ret) {
2699274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			nv_warn(object, "parent failed suspend, %d\n", ret);
2709274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			goto fail_parent;
2719274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		}
2729274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
2739274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
274964f85ec51c860c813858a9950c5eda9311410d5Ben Skeggs	nv_trace(object, "suspended\n");
2759274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return 0;
2769274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2779274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsfail_parent:
2789274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (object->engine) {
2799274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_lock(&nv_subdev(object->engine)->mutex);
2809274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		rret = nouveau_object_inc(object->engine);
2819274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		mutex_unlock(&nv_subdev(object->engine)->mutex);
2829274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (rret)
2839274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			nv_fatal(object, "engine failed to reinit, %d\n", rret);
2849274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
2859274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2869274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsfail_engine:
2879274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	rret = nv_ofuncs(object)->init(object);
2889274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (rret)
2899274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_fatal(object, "failed to reinit, %d\n", rret);
2909274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2919274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return ret;
2929274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
2939274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
2949274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsint
2959274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_dec(struct nouveau_object *object, bool suspend)
2969274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
2979274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	int ref = atomic_add_return(-1, &object->usecount);
2989274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	int ret;
2999274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
3009274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
3019274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
3029274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (ref == 0) {
3039274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (suspend)
3049274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			ret = nouveau_object_decs(object);
3059274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		else
3069274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			ret = nouveau_object_decf(object);
3079274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
3089274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		if (ret) {
3099274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			atomic_inc(&object->usecount);
3109274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			return ret;
3119274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		}
3129274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
3139274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
3149274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	return 0;
3159274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
3169274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs
3179274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsvoid
3189274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggsnouveau_object_debug(void)
3199274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs{
3209274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#ifdef NOUVEAU_OBJECT_MAGIC
3219274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	struct nouveau_object *object;
3229274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	if (!list_empty(&_objlist)) {
3239274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_fatal(NULL, "*******************************************\n");
3249274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
3259274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		nv_fatal(NULL, "*******************************************\n");
3269274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		list_for_each_entry(object, &_objlist, list) {
3279274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs			nv_fatal(object, "%p/%p/%d/%d\n",
3289274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs				 object->parent, object->engine,
3299274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs				 atomic_read(&object->refcount),
3309274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs				 atomic_read(&object->usecount));
3319274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs		}
3329274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs	}
3339274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs#endif
3349274f4a9ba7e70d1770e237fca16d52f27f0c728Ben Skeggs}
335