These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / nouveau / nvkm / core / object.c
index 979f362..67aa722 100644 (file)
  * Authors: Ben Skeggs
  */
 #include <core/object.h>
+#include <core/client.h>
 #include <core/engine.h>
 
-#ifdef NVKM_OBJECT_MAGIC
-static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
-static DEFINE_SPINLOCK(_objlist_lock);
-#endif
-
 int
-nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine,
-                   struct nvkm_oclass *oclass, u32 pclass,
-                   int size, void **pobject)
+nvkm_object_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
 {
-       struct nvkm_object *object;
-
-       object = *pobject = kzalloc(size, GFP_KERNEL);
-       if (!object)
-               return -ENOMEM;
-
-       nvkm_object_ref(parent, &object->parent);
-       nvkm_object_ref(engine, (struct nvkm_object **)&object->engine);
-       object->oclass = oclass;
-       object->oclass->handle |= pclass;
-       atomic_set(&object->refcount, 1);
-       atomic_set(&object->usecount, 0);
-
-#ifdef NVKM_OBJECT_MAGIC
-       object->_magic = NVKM_OBJECT_MAGIC;
-       spin_lock(&_objlist_lock);
-       list_add(&object->list, &_objlist);
-       spin_unlock(&_objlist_lock);
-#endif
-       return 0;
+       if (likely(object->func->mthd))
+               return object->func->mthd(object, mthd, data, size);
+       return -ENODEV;
 }
 
 int
-_nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-                 struct nvkm_oclass *oclass, void *data, u32 size,
-                 struct nvkm_object **pobject)
+nvkm_object_ntfy(struct nvkm_object *object, u32 mthd,
+                struct nvkm_event **pevent)
 {
-       if (size != 0)
-               return -ENOSYS;
-       return nvkm_object_create(parent, engine, oclass, 0, pobject);
+       if (likely(object->func->ntfy))
+               return object->func->ntfy(object, mthd, pevent);
+       return -ENODEV;
 }
 
-void
-nvkm_object_destroy(struct nvkm_object *object)
+int
+nvkm_object_map(struct nvkm_object *object, u64 *addr, u32 *size)
 {
-#ifdef NVKM_OBJECT_MAGIC
-       spin_lock(&_objlist_lock);
-       list_del(&object->list);
-       spin_unlock(&_objlist_lock);
-#endif
-       nvkm_object_ref(NULL, (struct nvkm_object **)&object->engine);
-       nvkm_object_ref(NULL, &object->parent);
-       kfree(object);
+       if (likely(object->func->map))
+               return object->func->map(object, addr, size);
+       return -ENODEV;
 }
 
 int
-nvkm_object_init(struct nvkm_object *object)
+nvkm_object_rd08(struct nvkm_object *object, u64 addr, u8 *data)
 {
-       return 0;
+       if (likely(object->func->rd08))
+               return object->func->rd08(object, addr, data);
+       return -ENODEV;
 }
 
 int
-nvkm_object_fini(struct nvkm_object *object, bool suspend)
+nvkm_object_rd16(struct nvkm_object *object, u64 addr, u16 *data)
 {
-       return 0;
+       if (likely(object->func->rd16))
+               return object->func->rd16(object, addr, data);
+       return -ENODEV;
 }
 
-struct nvkm_ofuncs
-nvkm_object_ofuncs = {
-       .ctor = _nvkm_object_ctor,
-       .dtor = nvkm_object_destroy,
-       .init = nvkm_object_init,
-       .fini = nvkm_object_fini,
-};
-
 int
-nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-                struct nvkm_oclass *oclass, void *data, u32 size,
-                struct nvkm_object **pobject)
+nvkm_object_rd32(struct nvkm_object *object, u64 addr, u32 *data)
 {
-       struct nvkm_ofuncs *ofuncs = oclass->ofuncs;
-       struct nvkm_object *object = NULL;
-       int ret;
-
-       ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
-       *pobject = object;
-       if (ret < 0) {
-               if (ret != -ENODEV) {
-                       nv_error(parent, "failed to create 0x%08x, %d\n",
-                                oclass->handle, ret);
-               }
-
-               if (object) {
-                       ofuncs->dtor(object);
-                       *pobject = NULL;
-               }
-
-               return ret;
-       }
-
-       if (ret == 0) {
-               nv_trace(object, "created\n");
-               atomic_set(&object->refcount, 1);
-       }
-
-       return 0;
+       if (likely(object->func->rd32))
+               return object->func->rd32(object, addr, data);
+       return -ENODEV;
 }
 
-static void
-nvkm_object_dtor(struct nvkm_object *object)
+int
+nvkm_object_wr08(struct nvkm_object *object, u64 addr, u8 data)
 {
-       nv_trace(object, "destroying\n");
-       nv_ofuncs(object)->dtor(object);
+       if (likely(object->func->wr08))
+               return object->func->wr08(object, addr, data);
+       return -ENODEV;
 }
 
-void
-nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref)
+int
+nvkm_object_wr16(struct nvkm_object *object, u64 addr, u16 data)
 {
-       if (obj) {
-               atomic_inc(&obj->refcount);
-               nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
-       }
+       if (likely(object->func->wr16))
+               return object->func->wr16(object, addr, data);
+       return -ENODEV;
+}
 
-       if (*ref) {
-               int dead = atomic_dec_and_test(&(*ref)->refcount);
-               nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
-               if (dead)
-                       nvkm_object_dtor(*ref);
-       }
+int
+nvkm_object_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+       if (likely(object->func->wr32))
+               return object->func->wr32(object, addr, data);
+       return -ENODEV;
+}
 
-       *ref = obj;
+int
+nvkm_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *gpuobj,
+                int align, struct nvkm_gpuobj **pgpuobj)
+{
+       if (object->func->bind)
+               return object->func->bind(object, gpuobj, align, pgpuobj);
+       return -ENODEV;
 }
 
 int
-nvkm_object_inc(struct nvkm_object *object)
+nvkm_object_fini(struct nvkm_object *object, bool suspend)
 {
-       int ref = atomic_add_return(1, &object->usecount);
+       const char *action = suspend ? "suspend" : "fini";
+       struct nvkm_object *child;
+       s64 time;
        int ret;
 
-       nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
-       if (ref != 1)
-               return 0;
-
-       nv_trace(object, "initialising...\n");
-       if (object->parent) {
-               ret = nvkm_object_inc(object->parent);
-               if (ret) {
-                       nv_error(object, "parent failed, %d\n", ret);
-                       goto fail_parent;
-               }
+       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;
        }
 
-       if (object->engine) {
-               mutex_lock(&nv_subdev(object->engine)->mutex);
-               ret = nvkm_object_inc(&object->engine->subdev.object);
-               mutex_unlock(&nv_subdev(object->engine)->mutex);
+       nvif_debug(object, "%s running...\n", action);
+       if (object->func->fini) {
+               ret = object->func->fini(object, suspend);
                if (ret) {
-                       nv_error(object, "engine failed, %d\n", ret);
-                       goto fail_engine;
+                       nvif_error(object, "%s failed with %d\n", action, ret);
+                       if (suspend)
+                               goto fail;
                }
        }
 
-       ret = nv_ofuncs(object)->init(object);
-       atomic_set(&object->usecount, 1);
-       if (ret) {
-               nv_error(object, "init failed, %d\n", ret);
-               goto fail_self;
-       }
-
-       nv_trace(object, "initialised\n");
+       time = ktime_to_us(ktime_get()) - time;
+       nvif_debug(object, "%s completed in %lldus\n", action, time);
        return 0;
 
-fail_self:
-       if (object->engine) {
-               mutex_lock(&nv_subdev(object->engine)->mutex);
-               nvkm_object_dec(&object->engine->subdev.object, false);
-               mutex_unlock(&nv_subdev(object->engine)->mutex);
+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);
        }
-fail_engine:
-       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)
+int
+nvkm_object_init(struct nvkm_object *object)
 {
+       struct nvkm_object *child;
+       s64 time;
        int ret;
 
-       nv_trace(object, "stopping...\n");
-
-       ret = nv_ofuncs(object)->fini(object, false);
-       atomic_set(&object->usecount, 0);
-       if (ret)
-               nv_warn(object, "failed fini, %d\n", ret);
-
-       if (object->engine) {
-               mutex_lock(&nv_subdev(object->engine)->mutex);
-               nvkm_object_dec(&object->engine->subdev.object, false);
-               mutex_unlock(&nv_subdev(object->engine)->mutex);
+       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;
        }
 
-       if (object->parent)
-               nvkm_object_dec(object->parent, false);
+       nvif_debug(object, "init children...\n");
+       list_for_each_entry(child, &object->tree, head) {
+               ret = nvkm_object_init(child);
+               if (ret)
+                       goto fail_child;
+       }
 
-       nv_trace(object, "stopped\n");
+       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 int
-nvkm_object_decs(struct nvkm_object *object)
+void *
+nvkm_object_dtor(struct nvkm_object *object)
 {
-       int ret, rret;
-
-       nv_trace(object, "suspending...\n");
-
-       ret = nv_ofuncs(object)->fini(object, true);
-       atomic_set(&object->usecount, 0);
-       if (ret) {
-               nv_error(object, "failed suspend, %d\n", ret);
-               return ret;
+       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);
        }
 
-       if (object->engine) {
-               mutex_lock(&nv_subdev(object->engine)->mutex);
-               ret = nvkm_object_dec(&object->engine->subdev.object, true);
-               mutex_unlock(&nv_subdev(object->engine)->mutex);
-               if (ret) {
-                       nv_warn(object, "engine failed suspend, %d\n", ret);
-                       goto fail_engine;
-               }
-       }
-
-       if (object->parent) {
-               ret = nvkm_object_dec(object->parent, true);
-               if (ret) {
-                       nv_warn(object, "parent failed suspend, %d\n", ret);
-                       goto fail_parent;
-               }
-       }
-
-       nv_trace(object, "suspended\n");
-       return 0;
+       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;
+}
 
-fail_parent:
-       if (object->engine) {
-               mutex_lock(&nv_subdev(object->engine)->mutex);
-               rret = nvkm_object_inc(&object->engine->subdev.object);
-               mutex_unlock(&nv_subdev(object->engine)->mutex);
-               if (rret)
-                       nv_fatal(object, "engine failed to reinit, %d\n", rret);
+void
+nvkm_object_del(struct nvkm_object **pobject)
+{
+       struct nvkm_object *object = *pobject;
+       if (object && !WARN_ON(!object->func)) {
+               *pobject = nvkm_object_dtor(object);
+               nvkm_client_remove(object->client, object);
+               list_del(&object->head);
+               kfree(*pobject);
+               *pobject = NULL;
        }
+}
 
-fail_engine:
-       rret = nv_ofuncs(object)->init(object);
-       if (rret)
-               nv_fatal(object, "failed to reinit, %d\n", rret);
-
-       return ret;
+void
+nvkm_object_ctor(const struct nvkm_object_func *func,
+                const struct nvkm_oclass *oclass, struct nvkm_object *object)
+{
+       object->func = func;
+       object->client = oclass->client;
+       object->engine = nvkm_engine_ref(oclass->engine);
+       object->oclass = oclass->base.oclass;
+       object->handle = oclass->handle;
+       INIT_LIST_HEAD(&object->head);
+       INIT_LIST_HEAD(&object->tree);
+       RB_CLEAR_NODE(&object->node);
+       WARN_ON(oclass->engine && !object->engine);
 }
 
 int
-nvkm_object_dec(struct nvkm_object *object, bool suspend)
+nvkm_object_new_(const struct nvkm_object_func *func,
+                const struct nvkm_oclass *oclass, void *data, u32 size,
+                struct nvkm_object **pobject)
 {
-       int ref = atomic_add_return(-1, &object->usecount);
-       int ret;
-
-       nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
-
-       if (ref == 0) {
-               if (suspend)
-                       ret = nvkm_object_decs(object);
-               else
-                       ret = nvkm_object_decf(object);
-
-               if (ret) {
-                       atomic_inc(&object->usecount);
-                       return ret;
-               }
+       if (size == 0) {
+               if (!(*pobject = kzalloc(sizeof(**pobject), GFP_KERNEL)))
+                       return -ENOMEM;
+               nvkm_object_ctor(func, oclass, *pobject);
+               return 0;
        }
-
-       return 0;
+       return -ENOSYS;
 }
 
-void
-nvkm_object_debug(void)
+static const struct nvkm_object_func
+nvkm_object_func = {
+};
+
+int
+nvkm_object_new(const struct nvkm_oclass *oclass, void *data, u32 size,
+               struct nvkm_object **pobject)
 {
-#ifdef NVKM_OBJECT_MAGIC
-       struct nvkm_object *object;
-       if (!list_empty(&_objlist)) {
-               nv_fatal(NULL, "*******************************************\n");
-               nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
-               nv_fatal(NULL, "*******************************************\n");
-               list_for_each_entry(object, &_objlist, list) {
-                       nv_fatal(object, "%p/%p/%d/%d\n",
-                                object->parent, object->engine,
-                                atomic_read(&object->refcount),
-                                atomic_read(&object->usecount));
-               }
-       }
-#endif
+       const struct nvkm_object_func *func =
+               oclass->base.func ? oclass->base.func : &nvkm_object_func;
+       return nvkm_object_new_(func, oclass, data, size, pobject);
 }