Home | History | Annotate | Line # | Download | only in core
      1 /*	$NetBSD: nouveau_nvkm_core_engine.c,v 1.5 2021/12/19 11:34:44 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012 Red Hat Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: Ben Skeggs
     25  */
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_core_engine.c,v 1.5 2021/12/19 11:34:44 riastradh Exp $");
     28 
     29 #include <core/engine.h>
     30 #include <core/device.h>
     31 #include <core/option.h>
     32 
     33 #include <subdev/fb.h>
     34 
     35 bool
     36 nvkm_engine_chsw_load(struct nvkm_engine *engine)
     37 {
     38 	if (engine->func->chsw_load)
     39 		return engine->func->chsw_load(engine);
     40 	return false;
     41 }
     42 
     43 void
     44 nvkm_engine_unref(struct nvkm_engine **pengine)
     45 {
     46 	struct nvkm_engine *engine = *pengine;
     47 	if (engine) {
     48 		mutex_lock(&engine->subdev.mutex);
     49 		if (--engine->usecount == 0)
     50 			nvkm_subdev_fini(&engine->subdev, false);
     51 		mutex_unlock(&engine->subdev.mutex);
     52 		*pengine = NULL;
     53 	}
     54 }
     55 
     56 struct nvkm_engine *
     57 nvkm_engine_ref(struct nvkm_engine *engine)
     58 {
     59 	if (engine) {
     60 		mutex_lock(&engine->subdev.mutex);
     61 		if (++engine->usecount == 1) {
     62 			int ret = nvkm_subdev_init(&engine->subdev);
     63 			if (ret) {
     64 				engine->usecount--;
     65 				mutex_unlock(&engine->subdev.mutex);
     66 				return ERR_PTR(ret);
     67 			}
     68 		}
     69 		mutex_unlock(&engine->subdev.mutex);
     70 	}
     71 	return engine;
     72 }
     73 
     74 void
     75 nvkm_engine_tile(struct nvkm_engine *engine, int region)
     76 {
     77 	struct nvkm_fb *fb = engine->subdev.device->fb;
     78 	if (engine->func->tile)
     79 		engine->func->tile(engine, region, &fb->tile.region[region]);
     80 }
     81 
     82 static void
     83 nvkm_engine_intr(struct nvkm_subdev *subdev)
     84 {
     85 	struct nvkm_engine *engine = nvkm_engine(subdev);
     86 	if (engine->func->intr)
     87 		engine->func->intr(engine);
     88 }
     89 
     90 static int
     91 nvkm_engine_info(struct nvkm_subdev *subdev, u64 mthd, u64 *data)
     92 {
     93 	struct nvkm_engine *engine = nvkm_engine(subdev);
     94 	if (engine->func->info) {
     95 		if (!IS_ERR((engine = nvkm_engine_ref(engine)))) {
     96 			int ret = engine->func->info(engine, mthd, data);
     97 			nvkm_engine_unref(&engine);
     98 			return ret;
     99 		}
    100 		return PTR_ERR(engine);
    101 	}
    102 	return -ENOSYS;
    103 }
    104 
    105 static int
    106 nvkm_engine_fini(struct nvkm_subdev *subdev, bool suspend)
    107 {
    108 	struct nvkm_engine *engine = nvkm_engine(subdev);
    109 	if (engine->func->fini)
    110 		return engine->func->fini(engine, suspend);
    111 	return 0;
    112 }
    113 
    114 static int
    115 nvkm_engine_init(struct nvkm_subdev *subdev)
    116 {
    117 	struct nvkm_engine *engine = nvkm_engine(subdev);
    118 	struct nvkm_fb *fb = subdev->device->fb;
    119 	int ret = 0, i;
    120 	s64 time;
    121 
    122 	if (!engine->usecount) {
    123 		nvkm_trace(subdev, "init skipped, engine has no users\n");
    124 		return ret;
    125 	}
    126 
    127 	if (engine->func->oneinit && !engine->subdev.oneinit) {
    128 		nvkm_trace(subdev, "one-time init running...\n");
    129 		time = ktime_to_us(ktime_get());
    130 		ret = engine->func->oneinit(engine);
    131 		if (ret) {
    132 			nvkm_trace(subdev, "one-time init failed, %d\n", ret);
    133 			return ret;
    134 		}
    135 
    136 		engine->subdev.oneinit = true;
    137 		time = ktime_to_us(ktime_get()) - time;
    138 		nvkm_trace(subdev, "one-time init completed in %"PRId64"us\n", time);
    139 	}
    140 
    141 	if (engine->func->init)
    142 		ret = engine->func->init(engine);
    143 
    144 	for (i = 0; fb && i < fb->tile.regions; i++)
    145 		nvkm_engine_tile(engine, i);
    146 	return ret;
    147 }
    148 
    149 static int
    150 nvkm_engine_preinit(struct nvkm_subdev *subdev)
    151 {
    152 	struct nvkm_engine *engine = nvkm_engine(subdev);
    153 	if (engine->func->preinit)
    154 		engine->func->preinit(engine);
    155 	return 0;
    156 }
    157 
    158 static void *
    159 nvkm_engine_dtor(struct nvkm_subdev *subdev)
    160 {
    161 	struct nvkm_engine *engine = nvkm_engine(subdev);
    162 	spin_lock_destroy(&engine->lock);
    163 	if (engine->func->dtor)
    164 		return engine->func->dtor(engine);
    165 	return engine;
    166 }
    167 
    168 static const struct nvkm_subdev_func
    169 nvkm_engine_func = {
    170 	.dtor = nvkm_engine_dtor,
    171 	.preinit = nvkm_engine_preinit,
    172 	.init = nvkm_engine_init,
    173 	.fini = nvkm_engine_fini,
    174 	.info = nvkm_engine_info,
    175 	.intr = nvkm_engine_intr,
    176 };
    177 
    178 int
    179 nvkm_engine_ctor(const struct nvkm_engine_func *func,
    180 		 struct nvkm_device *device, int index, bool enable,
    181 		 struct nvkm_engine *engine)
    182 {
    183 	nvkm_subdev_ctor(&nvkm_engine_func, device, index, &engine->subdev);
    184 	engine->func = func;
    185 
    186 	if (!nvkm_boolopt(device->cfgopt, nvkm_subdev_name[index], enable)) {
    187 		nvkm_debug(&engine->subdev, "disabled\n");
    188 		return -ENODEV;
    189 	}
    190 
    191 	spin_lock_init(&engine->lock);
    192 	return 0;
    193 }
    194 
    195 int
    196 nvkm_engine_new_(const struct nvkm_engine_func *func,
    197 		 struct nvkm_device *device, int index, bool enable,
    198 		 struct nvkm_engine **pengine)
    199 {
    200 	if (!(*pengine = kzalloc(sizeof(**pengine), GFP_KERNEL)))
    201 		return -ENOMEM;
    202 	return nvkm_engine_ctor(func, device, index, enable, *pengine);
    203 }
    204