Home | History | Annotate | Line # | Download | only in fifo
      1 /*	$NetBSD: nouveau_nvkm_engine_fifo_channv50.c,v 1.3 2021/12/18 23:45:35 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_channv50.c,v 1.3 2021/12/18 23:45:35 riastradh Exp $");
     28 
     29 #include "channv50.h"
     30 
     31 #include <core/client.h>
     32 #include <core/ramht.h>
     33 #include <subdev/mmu.h>
     34 #include <subdev/timer.h>
     35 
     36 static int
     37 nv50_fifo_chan_engine_addr(struct nvkm_engine *engine)
     38 {
     39 	switch (engine->subdev.index) {
     40 	case NVKM_ENGINE_DMAOBJ:
     41 	case NVKM_ENGINE_SW    : return -1;
     42 	case NVKM_ENGINE_GR    : return 0x0000;
     43 	case NVKM_ENGINE_MPEG  : return 0x0060;
     44 	default:
     45 		WARN_ON(1);
     46 		return -1;
     47 	}
     48 }
     49 
     50 static int
     51 nv50_fifo_chan_engine_fini(struct nvkm_fifo_chan *base,
     52 			   struct nvkm_engine *engine, bool suspend)
     53 {
     54 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
     55 	struct nv50_fifo *fifo = chan->fifo;
     56 	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
     57 	struct nvkm_device *device = subdev->device;
     58 	int offset, ret = 0;
     59 	u32 me;
     60 
     61 	offset = nv50_fifo_chan_engine_addr(engine);
     62 	if (offset < 0)
     63 		return 0;
     64 
     65 	/* HW bug workaround:
     66 	 *
     67 	 * PFIFO will hang forever if the connected engines don't report
     68 	 * that they've processed the context switch request.
     69 	 *
     70 	 * In order for the kickoff to work, we need to ensure all the
     71 	 * connected engines are in a state where they can answer.
     72 	 *
     73 	 * Newer chipsets don't seem to suffer from this issue, and well,
     74 	 * there's also a "ignore these engines" bitmask reg we can use
     75 	 * if we hit the issue there..
     76 	 */
     77 	me = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001);
     78 
     79 	/* do the kickoff... */
     80 	nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12);
     81 	if (nvkm_msec(device, 2000,
     82 		if (nvkm_rd32(device, 0x0032fc) != 0xffffffff)
     83 			break;
     84 	) < 0) {
     85 		nvkm_error(subdev, "channel %d [%s] unload timeout\n",
     86 			   chan->base.chid, chan->base.object.client->name);
     87 		if (suspend)
     88 			ret = -EBUSY;
     89 	}
     90 	nvkm_wr32(device, 0x00b860, me);
     91 
     92 	if (ret == 0) {
     93 		nvkm_kmap(chan->eng);
     94 		nvkm_wo32(chan->eng, offset + 0x00, 0x00000000);
     95 		nvkm_wo32(chan->eng, offset + 0x04, 0x00000000);
     96 		nvkm_wo32(chan->eng, offset + 0x08, 0x00000000);
     97 		nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000);
     98 		nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
     99 		nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
    100 		nvkm_done(chan->eng);
    101 	}
    102 
    103 	return ret;
    104 }
    105 
    106 static int
    107 nv50_fifo_chan_engine_init(struct nvkm_fifo_chan *base,
    108 			   struct nvkm_engine *engine)
    109 {
    110 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
    111 	struct nvkm_gpuobj *engn = chan->engn[engine->subdev.index];
    112 	u64 limit, start;
    113 	int offset;
    114 
    115 	offset = nv50_fifo_chan_engine_addr(engine);
    116 	if (offset < 0)
    117 		return 0;
    118 	limit = engn->addr + engn->size - 1;
    119 	start = engn->addr;
    120 
    121 	nvkm_kmap(chan->eng);
    122 	nvkm_wo32(chan->eng, offset + 0x00, 0x00190000);
    123 	nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit));
    124 	nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start));
    125 	nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 |
    126 					    upper_32_bits(start));
    127 	nvkm_wo32(chan->eng, offset + 0x10, 0x00000000);
    128 	nvkm_wo32(chan->eng, offset + 0x14, 0x00000000);
    129 	nvkm_done(chan->eng);
    130 	return 0;
    131 }
    132 
    133 void
    134 nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *base,
    135 			   struct nvkm_engine *engine)
    136 {
    137 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
    138 	nvkm_gpuobj_del(&chan->engn[engine->subdev.index]);
    139 }
    140 
    141 static int
    142 nv50_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base,
    143 			   struct nvkm_engine *engine,
    144 			   struct nvkm_object *object)
    145 {
    146 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
    147 	int engn = engine->subdev.index;
    148 
    149 	if (nv50_fifo_chan_engine_addr(engine) < 0)
    150 		return 0;
    151 
    152 	return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]);
    153 }
    154 
    155 void
    156 nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *base, int cookie)
    157 {
    158 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
    159 	nvkm_ramht_remove(chan->ramht, cookie);
    160 }
    161 
    162 static int
    163 nv50_fifo_chan_object_ctor(struct nvkm_fifo_chan *base,
    164 			   struct nvkm_object *object)
    165 {
    166 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
    167 	u32 handle = object->handle;
    168 	u32 context;
    169 
    170 	switch (object->engine->subdev.index) {
    171 	case NVKM_ENGINE_DMAOBJ:
    172 	case NVKM_ENGINE_SW    : context = 0x00000000; break;
    173 	case NVKM_ENGINE_GR    : context = 0x00100000; break;
    174 	case NVKM_ENGINE_MPEG  : context = 0x00200000; break;
    175 	default:
    176 		WARN_ON(1);
    177 		return -EINVAL;
    178 	}
    179 
    180 	return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context);
    181 }
    182 
    183 void
    184 nv50_fifo_chan_fini(struct nvkm_fifo_chan *base)
    185 {
    186 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
    187 	struct nv50_fifo *fifo = chan->fifo;
    188 	struct nvkm_device *device = fifo->base.engine.subdev.device;
    189 	u32 chid = chan->base.chid;
    190 
    191 	/* remove channel from runlist, fifo will unload context */
    192 	nvkm_mask(device, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
    193 	nv50_fifo_runlist_update(fifo);
    194 	nvkm_wr32(device, 0x002600 + (chid * 4), 0x00000000);
    195 }
    196 
    197 static void
    198 nv50_fifo_chan_init(struct nvkm_fifo_chan *base)
    199 {
    200 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
    201 	struct nv50_fifo *fifo = chan->fifo;
    202 	struct nvkm_device *device = fifo->base.engine.subdev.device;
    203 	u64 addr = chan->ramfc->addr >> 12;
    204 	u32 chid = chan->base.chid;
    205 
    206 	nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr);
    207 	nv50_fifo_runlist_update(fifo);
    208 }
    209 
    210 void *
    211 nv50_fifo_chan_dtor(struct nvkm_fifo_chan *base)
    212 {
    213 	struct nv50_fifo_chan *chan = nv50_fifo_chan(base);
    214 	nvkm_ramht_del(&chan->ramht);
    215 	nvkm_gpuobj_del(&chan->pgd);
    216 	nvkm_gpuobj_del(&chan->eng);
    217 	nvkm_gpuobj_del(&chan->cache);
    218 	nvkm_gpuobj_del(&chan->ramfc);
    219 	return chan;
    220 }
    221 
    222 static const struct nvkm_fifo_chan_func
    223 nv50_fifo_chan_func = {
    224 	.dtor = nv50_fifo_chan_dtor,
    225 	.init = nv50_fifo_chan_init,
    226 	.fini = nv50_fifo_chan_fini,
    227 	.engine_ctor = nv50_fifo_chan_engine_ctor,
    228 	.engine_dtor = nv50_fifo_chan_engine_dtor,
    229 	.engine_init = nv50_fifo_chan_engine_init,
    230 	.engine_fini = nv50_fifo_chan_engine_fini,
    231 	.object_ctor = nv50_fifo_chan_object_ctor,
    232 	.object_dtor = nv50_fifo_chan_object_dtor,
    233 };
    234 
    235 int
    236 nv50_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vmm, u64 push,
    237 		    const struct nvkm_oclass *oclass,
    238 		    struct nv50_fifo_chan *chan)
    239 {
    240 	struct nvkm_device *device = fifo->base.engine.subdev.device;
    241 	int ret;
    242 
    243 	if (!vmm)
    244 		return -EINVAL;
    245 
    246 	ret = nvkm_fifo_chan_ctor(&nv50_fifo_chan_func, &fifo->base,
    247 				  0x10000, 0x1000, false, vmm, push,
    248 				  (1ULL << NVKM_ENGINE_DMAOBJ) |
    249 				  (1ULL << NVKM_ENGINE_SW) |
    250 				  (1ULL << NVKM_ENGINE_GR) |
    251 				  (1ULL << NVKM_ENGINE_MPEG),
    252 				  0, 0xc00000, 0x2000, oclass, &chan->base);
    253 	chan->fifo = fifo;
    254 	if (ret)
    255 		return ret;
    256 
    257 	ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, chan->base.inst,
    258 			      &chan->ramfc);
    259 	if (ret)
    260 		return ret;
    261 
    262 	ret = nvkm_gpuobj_new(device, 0x1200, 0, true, chan->base.inst,
    263 			      &chan->eng);
    264 	if (ret)
    265 		return ret;
    266 
    267 	ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst,
    268 			      &chan->pgd);
    269 	if (ret)
    270 		return ret;
    271 
    272 	return nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht);
    273 }
    274