#ifndef __NVKM_ENGINE_H__
#define __NVKM_ENGINE_H__
#include <core/subdev.h>
+struct nvkm_device_oclass; /*XXX: DEV!ENG */
+struct nvkm_fifo_chan;
#define NV_ENGINE_(eng,var) (((var) << 8) | (eng))
#define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var))
struct nvkm_engine {
struct nvkm_subdev subdev;
+ const struct nvkm_engine_func *func;
+
+ int usecount;
+
struct nvkm_oclass *cclass;
struct nvkm_oclass *sclass;
int (*tlb_flush)(struct nvkm_engine *);
};
+struct nvkm_engine_func {
+ void *(*dtor)(struct nvkm_engine *);
+ int (*oneinit)(struct nvkm_engine *);
+ int (*init)(struct nvkm_engine *);
+ int (*fini)(struct nvkm_engine *, bool suspend);
+ void (*intr)(struct nvkm_engine *);
+
+ struct {
+ int (*sclass)(struct nvkm_oclass *, int index,
+ const struct nvkm_device_oclass **);
+ } base;
+
+ struct {
+ int (*cclass)(struct nvkm_fifo_chan *,
+ const struct nvkm_oclass *,
+ struct nvkm_object **);
+ int (*sclass)(struct nvkm_oclass *, int index);
+ } fifo;
+
+ struct nvkm_sclass sclass[];
+};
+
+int nvkm_engine_ctor(const struct nvkm_engine_func *, struct nvkm_device *,
+ int index, u32 pmc_enable, bool enable,
+ struct nvkm_engine *);
+int nvkm_engine_new_(const struct nvkm_engine_func *, struct nvkm_device *,
+ int index, u32 pmc_enable, bool enable,
+ struct nvkm_engine **);
+struct nvkm_engine *nvkm_engine_ref(struct nvkm_engine *);
+void nvkm_engine_unref(struct nvkm_engine **);
+
static inline struct nvkm_engine *
nv_engine(void *obj)
{
#include <core/device.h>
#include <core/option.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_ref(struct nvkm_engine *engine)
+{
+ 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;
+}
+
+static void
+nvkm_engine_intr(struct nvkm_subdev *obj)
+{
+ struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev);
+ if (engine->func->intr)
+ engine->func->intr(engine);
+}
+
+static int
+nvkm_engine_fini(struct nvkm_subdev *obj, bool suspend)
+{
+ struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev);
+ if (engine->func->fini)
+ return engine->func->fini(engine, suspend);
+ return 0;
+}
+
+static int
+nvkm_engine_init(struct nvkm_subdev *obj)
+{
+ struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev);
+ struct nvkm_subdev *subdev = &engine->subdev;
+ int ret = 0;
+ s64 time;
+
+ if (!engine->usecount) {
+ nvkm_trace(subdev, "init skipped, engine has no users\n");
+ return ret;
+ }
+
+ 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);
+
+ return ret;
+}
+
+static void *
+nvkm_engine_dtor(struct nvkm_subdev *obj)
+{
+ struct nvkm_engine *engine = container_of(obj, typeof(*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;
+ }
+
+ 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);
+}
+
struct nvkm_engine *
nvkm_engine(void *obj, int idx)
{