Home | History | Annotate | Line # | Download | only in fifo
      1 /*	$NetBSD: nouveau_nvkm_engine_fifo_base.c,v 1.4 2021/12/19 11:34:45 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_engine_fifo_base.c,v 1.4 2021/12/19 11:34:45 riastradh Exp $");
     28 
     29 #include "priv.h"
     30 #include "chan.h"
     31 
     32 #include <core/client.h>
     33 #include <core/gpuobj.h>
     34 #include <core/notify.h>
     35 #include <subdev/mc.h>
     36 
     37 #include <nvif/event.h>
     38 #include <nvif/cl0080.h>
     39 #include <nvif/unpack.h>
     40 
     41 void
     42 nvkm_fifo_recover_chan(struct nvkm_fifo *fifo, int chid)
     43 {
     44 	unsigned long flags;
     45 	if (WARN_ON(!fifo->func->recover_chan))
     46 		return;
     47 	spin_lock_irqsave(&fifo->lock, flags);
     48 	fifo->func->recover_chan(fifo, chid);
     49 	spin_unlock_irqrestore(&fifo->lock, flags);
     50 }
     51 
     52 void
     53 nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags)
     54 {
     55 	return fifo->func->pause(fifo, flags);
     56 }
     57 
     58 void
     59 nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags)
     60 {
     61 	return fifo->func->start(fifo, flags);
     62 }
     63 
     64 void
     65 nvkm_fifo_fault(struct nvkm_fifo *fifo, struct nvkm_fault_data *info)
     66 {
     67 	return fifo->func->fault(fifo, info);
     68 }
     69 
     70 void
     71 nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags,
     72 		   struct nvkm_fifo_chan **pchan)
     73 {
     74 	struct nvkm_fifo_chan *chan = *pchan;
     75 	if (likely(chan)) {
     76 		*pchan = NULL;
     77 		spin_unlock_irqrestore(&fifo->lock, flags);
     78 	}
     79 }
     80 
     81 struct nvkm_fifo_chan *
     82 nvkm_fifo_chan_inst_locked(struct nvkm_fifo *fifo, u64 inst)
     83 {
     84 	struct nvkm_fifo_chan *chan;
     85 	list_for_each_entry(chan, &fifo->chan, head) {
     86 		if (chan->inst->addr == inst) {
     87 			list_del(&chan->head);
     88 			list_add(&chan->head, &fifo->chan);
     89 			return chan;
     90 		}
     91 	}
     92 	return NULL;
     93 }
     94 
     95 struct nvkm_fifo_chan *
     96 nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags)
     97 {
     98 	struct nvkm_fifo_chan *chan;
     99 	unsigned long flags;
    100 	spin_lock_irqsave(&fifo->lock, flags);
    101 	if ((chan = nvkm_fifo_chan_inst_locked(fifo, inst))) {
    102 		*rflags = flags;
    103 		return chan;
    104 	}
    105 	spin_unlock_irqrestore(&fifo->lock, flags);
    106 	return NULL;
    107 }
    108 
    109 struct nvkm_fifo_chan *
    110 nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags)
    111 {
    112 	struct nvkm_fifo_chan *chan;
    113 	unsigned long flags;
    114 	spin_lock_irqsave(&fifo->lock, flags);
    115 	list_for_each_entry(chan, &fifo->chan, head) {
    116 		if (chan->chid == chid) {
    117 			list_del(&chan->head);
    118 			list_add(&chan->head, &fifo->chan);
    119 			*rflags = flags;
    120 			return chan;
    121 		}
    122 	}
    123 	spin_unlock_irqrestore(&fifo->lock, flags);
    124 	return NULL;
    125 }
    126 
    127 void
    128 nvkm_fifo_kevent(struct nvkm_fifo *fifo, int chid)
    129 {
    130 	nvkm_event_send(&fifo->kevent, 1, chid, NULL, 0);
    131 }
    132 
    133 static int
    134 nvkm_fifo_kevent_ctor(struct nvkm_object *object, void *data, u32 size,
    135 		      struct nvkm_notify *notify)
    136 {
    137 	struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object);
    138 	if (size == 0) {
    139 		notify->size  = 0;
    140 		notify->types = 1;
    141 		notify->index = chan->chid;
    142 		return 0;
    143 	}
    144 	return -ENOSYS;
    145 }
    146 
    147 static const struct nvkm_event_func
    148 nvkm_fifo_kevent_func = {
    149 	.ctor = nvkm_fifo_kevent_ctor,
    150 };
    151 
    152 static int
    153 nvkm_fifo_cevent_ctor(struct nvkm_object *object, void *data, u32 size,
    154 		      struct nvkm_notify *notify)
    155 {
    156 	if (size == 0) {
    157 		notify->size  = 0;
    158 		notify->types = 1;
    159 		notify->index = 0;
    160 		return 0;
    161 	}
    162 	return -ENOSYS;
    163 }
    164 
    165 static const struct nvkm_event_func
    166 nvkm_fifo_cevent_func = {
    167 	.ctor = nvkm_fifo_cevent_ctor,
    168 };
    169 
    170 void
    171 nvkm_fifo_cevent(struct nvkm_fifo *fifo)
    172 {
    173 	nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0);
    174 }
    175 
    176 static void
    177 nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
    178 {
    179 	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
    180 	fifo->func->uevent_fini(fifo);
    181 }
    182 
    183 static void
    184 nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index)
    185 {
    186 	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
    187 	fifo->func->uevent_init(fifo);
    188 }
    189 
    190 static int
    191 nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
    192 		      struct nvkm_notify *notify)
    193 {
    194 	union {
    195 		struct nvif_notify_uevent_req none;
    196 	} *req = data;
    197 	int ret = -ENOSYS;
    198 
    199 	if (!(ret = nvif_unvers(ret, &data, &size, req->none))) {
    200 		notify->size  = sizeof(struct nvif_notify_uevent_rep);
    201 		notify->types = 1;
    202 		notify->index = 0;
    203 	}
    204 
    205 	return ret;
    206 }
    207 
    208 static const struct nvkm_event_func
    209 nvkm_fifo_uevent_func = {
    210 	.ctor = nvkm_fifo_uevent_ctor,
    211 	.init = nvkm_fifo_uevent_init,
    212 	.fini = nvkm_fifo_uevent_fini,
    213 };
    214 
    215 void
    216 nvkm_fifo_uevent(struct nvkm_fifo *fifo)
    217 {
    218 	struct nvif_notify_uevent_rep rep = {
    219 	};
    220 	nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
    221 }
    222 
    223 static int
    224 nvkm_fifo_class_new_(struct nvkm_device *device,
    225 		     const struct nvkm_oclass *oclass, void *data, u32 size,
    226 		     struct nvkm_object **pobject)
    227 {
    228 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
    229 	return fifo->func->class_new(fifo, oclass, data, size, pobject);
    230 }
    231 
    232 static const struct nvkm_device_oclass
    233 nvkm_fifo_class_ = {
    234 	.ctor = nvkm_fifo_class_new_,
    235 };
    236 
    237 static int
    238 nvkm_fifo_class_new(struct nvkm_device *device,
    239 		    const struct nvkm_oclass *oclass, void *data, u32 size,
    240 		    struct nvkm_object **pobject)
    241 {
    242 	const struct nvkm_fifo_chan_oclass *sclass = oclass->engn;
    243 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
    244 	return sclass->ctor(fifo, oclass, data, size, pobject);
    245 }
    246 
    247 static const struct nvkm_device_oclass
    248 nvkm_fifo_class = {
    249 	.ctor = nvkm_fifo_class_new,
    250 };
    251 
    252 static int
    253 nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index,
    254 		    const struct nvkm_device_oclass **class)
    255 {
    256 	struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine);
    257 	const struct nvkm_fifo_chan_oclass *sclass;
    258 	int c = 0;
    259 
    260 	if (fifo->func->class_get) {
    261 		int ret = fifo->func->class_get(fifo, index, oclass);
    262 		if (ret == 0)
    263 			*class = &nvkm_fifo_class_;
    264 		return ret;
    265 	}
    266 
    267 	while ((sclass = fifo->func->chan[c])) {
    268 		if (c++ == index) {
    269 			oclass->base = sclass->base;
    270 			oclass->engn = sclass;
    271 			*class = &nvkm_fifo_class;
    272 			return 0;
    273 		}
    274 	}
    275 
    276 	return c;
    277 }
    278 
    279 static void
    280 nvkm_fifo_intr(struct nvkm_engine *engine)
    281 {
    282 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
    283 	fifo->func->intr(fifo);
    284 }
    285 
    286 static int
    287 nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend)
    288 {
    289 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
    290 	if (fifo->func->fini)
    291 		fifo->func->fini(fifo);
    292 	return 0;
    293 }
    294 
    295 static int
    296 nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
    297 {
    298 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
    299 	switch (mthd) {
    300 	case NV_DEVICE_FIFO_CHANNELS: *data = fifo->nr; return 0;
    301 	default:
    302 		if (fifo->func->info)
    303 			return fifo->func->info(fifo, mthd, data);
    304 		break;
    305 	}
    306 	return -ENOSYS;
    307 }
    308 
    309 static int
    310 nvkm_fifo_oneinit(struct nvkm_engine *engine)
    311 {
    312 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
    313 	if (fifo->func->oneinit)
    314 		return fifo->func->oneinit(fifo);
    315 	return 0;
    316 }
    317 
    318 static void
    319 nvkm_fifo_preinit(struct nvkm_engine *engine)
    320 {
    321 	nvkm_mc_reset(engine->subdev.device, NVKM_ENGINE_FIFO);
    322 }
    323 
    324 static int
    325 nvkm_fifo_init(struct nvkm_engine *engine)
    326 {
    327 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
    328 	fifo->func->init(fifo);
    329 	return 0;
    330 }
    331 
    332 static void *
    333 nvkm_fifo_dtor(struct nvkm_engine *engine)
    334 {
    335 	struct nvkm_fifo *fifo = nvkm_fifo(engine);
    336 	void *data = fifo;
    337 	if (fifo->func->dtor)
    338 		data = fifo->func->dtor(fifo);
    339 	nvkm_event_fini(&fifo->kevent);
    340 	nvkm_event_fini(&fifo->cevent);
    341 	nvkm_event_fini(&fifo->uevent);
    342 	spin_lock_destroy(&fifo->lock);
    343 	return data;
    344 }
    345 
    346 static const struct nvkm_engine_func
    347 nvkm_fifo = {
    348 	.dtor = nvkm_fifo_dtor,
    349 	.preinit = nvkm_fifo_preinit,
    350 	.oneinit = nvkm_fifo_oneinit,
    351 	.info = nvkm_fifo_info,
    352 	.init = nvkm_fifo_init,
    353 	.fini = nvkm_fifo_fini,
    354 	.intr = nvkm_fifo_intr,
    355 	.base.sclass = nvkm_fifo_class_get,
    356 };
    357 
    358 int
    359 nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device,
    360 	       int index, int nr, struct nvkm_fifo *fifo)
    361 {
    362 	int ret;
    363 
    364 	fifo->func = func;
    365 	INIT_LIST_HEAD(&fifo->chan);
    366 	spin_lock_init(&fifo->lock);
    367 
    368 	if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR))
    369 		fifo->nr = NVKM_FIFO_CHID_NR;
    370 	else
    371 		fifo->nr = nr;
    372 	bitmap_clear(fifo->mask, 0, fifo->nr);
    373 
    374 	ret = nvkm_engine_ctor(&nvkm_fifo, device, index, true, &fifo->engine);
    375 	if (ret)
    376 		return ret;
    377 
    378 	if (func->uevent_init) {
    379 		ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1,
    380 				      &fifo->uevent);
    381 		if (ret)
    382 			return ret;
    383 	}
    384 
    385 	ret = nvkm_event_init(&nvkm_fifo_cevent_func, 1, 1, &fifo->cevent);
    386 	if (ret)
    387 		return ret;
    388 
    389 	return nvkm_event_init(&nvkm_fifo_kevent_func, 1, nr, &fifo->kevent);
    390 }
    391