summaryrefslogtreecommitdiff
path: root/drm/nouveau/nvkm/core/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'drm/nouveau/nvkm/core/object.c')
-rw-r--r--drm/nouveau/nvkm/core/object.c213
1 files changed, 98 insertions, 115 deletions
diff --git a/drm/nouveau/nvkm/core/object.c b/drm/nouveau/nvkm/core/object.c
index 8976526b1..67aa7223d 100644
--- a/drm/nouveau/nvkm/core/object.c
+++ b/drm/nouveau/nvkm/core/object.c
@@ -22,6 +22,7 @@
* Authors: Ben Skeggs
*/
#include <core/object.h>
+#include <core/client.h>
#include <core/engine.h>
int
@@ -109,28 +110,112 @@ nvkm_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *gpuobj,
int
nvkm_object_fini(struct nvkm_object *object, bool suspend)
{
- if (object->func->fini)
- return object->func->fini(object, suspend);
+ const char *action = suspend ? "suspend" : "fini";
+ struct nvkm_object *child;
+ s64 time;
+ int ret;
+
+ nvif_debug(object, "%s children...\n", action);
+ time = ktime_to_us(ktime_get());
+ list_for_each_entry(child, &object->tree, head) {
+ ret = nvkm_object_fini(child, suspend);
+ if (ret && suspend)
+ goto fail_child;
+ }
+
+ nvif_debug(object, "%s running...\n", action);
+ if (object->func->fini) {
+ ret = object->func->fini(object, suspend);
+ if (ret) {
+ nvif_error(object, "%s failed with %d\n", action, ret);
+ if (suspend)
+ goto fail;
+ }
+ }
+
+ time = ktime_to_us(ktime_get()) - time;
+ nvif_debug(object, "%s completed in %lldus\n", action, time);
return 0;
+
+fail:
+ if (object->func->init) {
+ int rret = object->func->init(object);
+ if (rret)
+ nvif_fatal(object, "failed to restart, %d\n", rret);
+ }
+fail_child:
+ list_for_each_entry_continue_reverse(child, &object->tree, head) {
+ nvkm_object_init(child);
+ }
+ return ret;
}
int
nvkm_object_init(struct nvkm_object *object)
{
- if (object->func->init)
- return object->func->init(object);
+ struct nvkm_object *child;
+ s64 time;
+ int ret;
+
+ nvif_debug(object, "init running...\n");
+ time = ktime_to_us(ktime_get());
+ if (object->func->init) {
+ ret = object->func->init(object);
+ if (ret)
+ goto fail;
+ }
+
+ nvif_debug(object, "init children...\n");
+ list_for_each_entry(child, &object->tree, head) {
+ ret = nvkm_object_init(child);
+ if (ret)
+ goto fail_child;
+ }
+
+ time = ktime_to_us(ktime_get()) - time;
+ nvif_debug(object, "init completed in %lldus\n", time);
return 0;
+
+fail_child:
+ list_for_each_entry_continue_reverse(child, &object->tree, head)
+ nvkm_object_fini(child, false);
+fail:
+ nvif_error(object, "init failed with %d\n", ret);
+ if (object->func->fini)
+ object->func->fini(object, false);
+ return ret;
}
-static void
+void *
+nvkm_object_dtor(struct nvkm_object *object)
+{
+ struct nvkm_object *child, *ctemp;
+ void *data = object;
+ s64 time;
+
+ nvif_debug(object, "destroy children...\n");
+ time = ktime_to_us(ktime_get());
+ list_for_each_entry_safe(child, ctemp, &object->tree, head) {
+ nvkm_object_del(&child);
+ }
+
+ nvif_debug(object, "destroy running...\n");
+ if (object->func->dtor)
+ data = object->func->dtor(object);
+ nvkm_engine_unref(&object->engine);
+ time = ktime_to_us(ktime_get()) - time;
+ nvif_debug(object, "destroy completed in %lldus...\n", time);
+ return data;
+}
+
+void
nvkm_object_del(struct nvkm_object **pobject)
{
struct nvkm_object *object = *pobject;
-
if (object && !WARN_ON(!object->func)) {
- if (object->func->dtor)
- *pobject = object->func->dtor(object);
- nvkm_engine_unref(&object->engine);
+ *pobject = nvkm_object_dtor(object);
+ nvkm_client_remove(object->client, object);
+ list_del(&object->head);
kfree(*pobject);
*pobject = NULL;
}
@@ -145,9 +230,10 @@ nvkm_object_ctor(const struct nvkm_object_func *func,
object->engine = nvkm_engine_ref(oclass->engine);
object->oclass = oclass->base.oclass;
object->handle = oclass->handle;
- object->parent = oclass->parent;
- atomic_set(&object->refcount, 1);
- atomic_set(&object->usecount, 0);
+ INIT_LIST_HEAD(&object->head);
+ INIT_LIST_HEAD(&object->tree);
+ RB_CLEAR_NODE(&object->node);
+ WARN_ON(oclass->engine && !object->engine);
}
int
@@ -176,106 +262,3 @@ nvkm_object_new(const struct nvkm_oclass *oclass, void *data, u32 size,
oclass->base.func ? oclass->base.func : &nvkm_object_func;
return nvkm_object_new_(func, oclass, data, size, pobject);
}
-
-void
-nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref)
-{
- if (obj) {
- atomic_inc(&obj->refcount);
- }
-
- if (*ref) {
- int dead = atomic_dec_and_test(&(*ref)->refcount);
- if (dead)
- nvkm_object_del(ref);
- }
-
- *ref = obj;
-}
-
-int
-nvkm_object_inc(struct nvkm_object *object)
-{
- int ref = atomic_add_return(1, &object->usecount);
- int ret;
-
- if (ref != 1)
- return 0;
-
- if (object->parent) {
- ret = nvkm_object_inc(object->parent);
- if (ret)
- goto fail_parent;
- }
-
- ret = nvkm_object_init(object);
- atomic_set(&object->usecount, 1);
- if (ret)
- goto fail_self;
-
- return 0;
-
-fail_self:
- if (object->parent)
- nvkm_object_dec(object->parent, false);
-fail_parent:
- atomic_dec(&object->usecount);
- return ret;
-}
-
-static int
-nvkm_object_decf(struct nvkm_object *object)
-{
- nvkm_object_fini(object, false);
- atomic_set(&object->usecount, 0);
-
- if (object->parent)
- nvkm_object_dec(object->parent, false);
-
- return 0;
-}
-
-static int
-nvkm_object_decs(struct nvkm_object *object)
-{
- int ret;
-
- ret = nvkm_object_fini(object, true);
- atomic_set(&object->usecount, 0);
- if (ret)
- return ret;
-
- if (object->parent) {
- ret = nvkm_object_dec(object->parent, true);
- if (ret)
- goto fail_parent;
- }
-
- return 0;
-
-fail_parent:
- nvkm_object_init(object);
-
- return ret;
-}
-
-int
-nvkm_object_dec(struct nvkm_object *object, bool suspend)
-{
- int ref = atomic_add_return(-1, &object->usecount);
- int ret;
-
- if (ref == 0) {
- if (suspend)
- ret = nvkm_object_decs(object);
- else
- ret = nvkm_object_decf(object);
-
- if (ret) {
- atomic_inc(&object->usecount);
- return ret;
- }
- }
-
- return 0;
-}