These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / nouveau / nvkm / core / engine.c
index 6082017..8a7bae7 100644 (file)
 #include <core/device.h>
 #include <core/option.h>
 
+#include <subdev/fb.h>
+
+void
+nvkm_engine_unref(struct nvkm_engine **pengine)
+{
+       struct nvkm_engine *engine = *pengine;
+       if (engine) {
+               mutex_lock(&engine->subdev.mutex);
+               if (--engine->usecount == 0)
+                       nvkm_subdev_fini(&engine->subdev, false);
+               mutex_unlock(&engine->subdev.mutex);
+               *pengine = NULL;
+       }
+}
+
 struct nvkm_engine *
-nvkm_engine(void *obj, int idx)
+nvkm_engine_ref(struct nvkm_engine *engine)
 {
-       obj = nvkm_subdev(obj, idx);
-       if (obj && nv_iclass(obj, NV_ENGINE_CLASS))
-               return nv_engine(obj);
-       return NULL;
+       if (engine) {
+               mutex_lock(&engine->subdev.mutex);
+               if (++engine->usecount == 1) {
+                       int ret = nvkm_subdev_init(&engine->subdev);
+                       if (ret) {
+                               engine->usecount--;
+                               mutex_unlock(&engine->subdev.mutex);
+                               return ERR_PTR(ret);
+                       }
+               }
+               mutex_unlock(&engine->subdev.mutex);
+       }
+       return engine;
 }
 
-int
-nvkm_engine_create_(struct nvkm_object *parent, struct nvkm_object *engobj,
-                   struct nvkm_oclass *oclass, bool enable,
-                   const char *iname, const char *fname,
-                   int length, void **pobject)
+void
+nvkm_engine_tile(struct nvkm_engine *engine, int region)
 {
-       struct nvkm_engine *engine;
-       int ret;
+       struct nvkm_fb *fb = engine->subdev.device->fb;
+       if (engine->func->tile)
+               engine->func->tile(engine, region, &fb->tile.region[region]);
+}
 
-       ret = nvkm_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS,
-                                 iname, fname, length, pobject);
-       engine = *pobject;
-       if (ret)
-               return ret;
+static void
+nvkm_engine_intr(struct nvkm_subdev *subdev)
+{
+       struct nvkm_engine *engine = nvkm_engine(subdev);
+       if (engine->func->intr)
+               engine->func->intr(engine);
+}
 
-       if (parent) {
-               struct nvkm_device *device = nv_device(parent);
-               int engidx = nv_engidx(engine);
+static int
+nvkm_engine_fini(struct nvkm_subdev *subdev, bool suspend)
+{
+       struct nvkm_engine *engine = nvkm_engine(subdev);
+       if (engine->func->fini)
+               return engine->func->fini(engine, suspend);
+       return 0;
+}
 
-               if (device->disable_mask & (1ULL << engidx)) {
-                       if (!nvkm_boolopt(device->cfgopt, iname, false)) {
-                               nv_debug(engine, "engine disabled by hw/fw\n");
-                               return -ENODEV;
-                       }
+static int
+nvkm_engine_init(struct nvkm_subdev *subdev)
+{
+       struct nvkm_engine *engine = nvkm_engine(subdev);
+       struct nvkm_fb *fb = subdev->device->fb;
+       int ret = 0, i;
+       s64 time;
 
-                       nv_warn(engine, "ignoring hw/fw engine disable\n");
-               }
+       if (!engine->usecount) {
+               nvkm_trace(subdev, "init skipped, engine has no users\n");
+               return ret;
+       }
 
-               if (!nvkm_boolopt(device->cfgopt, iname, enable)) {
-                       if (!enable)
-                               nv_warn(engine, "disabled, %s=1 to enable\n", iname);
-                       return -ENODEV;
+       if (engine->func->oneinit && !engine->subdev.oneinit) {
+               nvkm_trace(subdev, "one-time init running...\n");
+               time = ktime_to_us(ktime_get());
+               ret = engine->func->oneinit(engine);
+               if (ret) {
+                       nvkm_trace(subdev, "one-time init failed, %d\n", ret);
+                       return ret;
                }
+
+               engine->subdev.oneinit = true;
+               time = ktime_to_us(ktime_get()) - time;
+               nvkm_trace(subdev, "one-time init completed in %lldus\n", time);
+       }
+
+       if (engine->func->init)
+               ret = engine->func->init(engine);
+
+       for (i = 0; fb && i < fb->tile.regions; i++)
+               nvkm_engine_tile(engine, i);
+       return ret;
+}
+
+static void *
+nvkm_engine_dtor(struct nvkm_subdev *subdev)
+{
+       struct nvkm_engine *engine = nvkm_engine(subdev);
+       if (engine->func->dtor)
+               return engine->func->dtor(engine);
+       return engine;
+}
+
+static const struct nvkm_subdev_func
+nvkm_engine_func = {
+       .dtor = nvkm_engine_dtor,
+       .init = nvkm_engine_init,
+       .fini = nvkm_engine_fini,
+       .intr = nvkm_engine_intr,
+};
+
+int
+nvkm_engine_ctor(const struct nvkm_engine_func *func,
+                struct nvkm_device *device, int index, u32 pmc_enable,
+                bool enable, struct nvkm_engine *engine)
+{
+       nvkm_subdev_ctor(&nvkm_engine_func, device, index,
+                        pmc_enable, &engine->subdev);
+       engine->func = func;
+
+       if (!nvkm_boolopt(device->cfgopt, nvkm_subdev_name[index], enable)) {
+               nvkm_debug(&engine->subdev, "disabled\n");
+               return -ENODEV;
        }
 
-       INIT_LIST_HEAD(&engine->contexts);
        spin_lock_init(&engine->lock);
        return 0;
 }
+
+int
+nvkm_engine_new_(const struct nvkm_engine_func *func,
+                struct nvkm_device *device, int index, u32 pmc_enable,
+                bool enable, struct nvkm_engine **pengine)
+{
+       if (!(*pengine = kzalloc(sizeof(**pengine), GFP_KERNEL)))
+               return -ENOMEM;
+       return nvkm_engine_ctor(func, device, index, pmc_enable,
+                               enable, *pengine);
+}