gk104.c 29.7 KB
Newer Older
1
/*
2
 * Copyright 2012 Red Hat Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: Ben Skeggs
 */
24
#include "gk104.h"
25

26 27 28
#include <core/client.h>
#include <core/engctx.h>
#include <core/enum.h>
29
#include <core/handle.h>
30
#include <subdev/bar.h>
31
#include <subdev/fb.h>
32
#include <subdev/mmu.h>
33
#include <subdev/timer.h>
34

35 36
#include <nvif/class.h>
#include <nvif/unpack.h>
37

38
#define _(a,b) { (a), ((1ULL << (a)) | (b)) }
39
static const struct {
40 41
	u64 subdev;
	u64 mask;
42
} fifo_engine[] = {
43
	_(NVDEV_ENGINE_GR      , (1ULL << NVDEV_ENGINE_SW) |
44
				 (1ULL << NVDEV_ENGINE_CE2)),
45
	_(NVDEV_ENGINE_MSPDEC  , 0),
46
	_(NVDEV_ENGINE_MSPPP   , 0),
47
	_(NVDEV_ENGINE_MSVLD   , 0),
48 49
	_(NVDEV_ENGINE_CE0     , 0),
	_(NVDEV_ENGINE_CE1     , 0),
50
	_(NVDEV_ENGINE_MSENC   , 0),
51 52 53 54
};
#undef _
#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)

55 56
struct gk104_fifo_engn {
	struct nvkm_gpuobj *runlist[2];
B
Ben Skeggs 已提交
57
	int cur_runlist;
B
Ben Skeggs 已提交
58
	wait_queue_head_t wait;
59 60
};

B
Ben Skeggs 已提交
61
struct gk104_fifo {
62
	struct nvkm_fifo base;
63 64 65 66

	struct work_struct fault;
	u64 mask;

67
	struct gk104_fifo_engn engine[FIFO_ENGINE_NR];
68
	struct {
69 70
		struct nvkm_gpuobj *mem;
		struct nvkm_vma bar;
71 72 73 74
	} user;
	int spoon_nr;
};

75 76 77 78
struct gk104_fifo_base {
	struct nvkm_fifo_base base;
	struct nvkm_gpuobj *pgd;
	struct nvkm_vm *vm;
79 80
};

81 82
struct gk104_fifo_chan {
	struct nvkm_fifo_chan base;
83
	u32 engine;
84 85 86 87 88
	enum {
		STOPPED,
		RUNNING,
		KILLED
	} state;
89 90
};

91 92 93 94
/*******************************************************************************
 * FIFO channel objects
 ******************************************************************************/

95
static void
B
Ben Skeggs 已提交
96
gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine)
97
{
B
Ben Skeggs 已提交
98 99
	struct nvkm_bar *bar = nvkm_bar(fifo);
	struct gk104_fifo_engn *engn = &fifo->engine[engine];
100
	struct nvkm_gpuobj *cur;
101
	int i, p;
102

B
Ben Skeggs 已提交
103
	mutex_lock(&nv_subdev(fifo)->mutex);
B
Ben Skeggs 已提交
104 105
	cur = engn->runlist[engn->cur_runlist];
	engn->cur_runlist = !engn->cur_runlist;
106

B
Ben Skeggs 已提交
107 108
	for (i = 0, p = 0; i < fifo->base.max; i++) {
		struct gk104_fifo_chan *chan = (void *)fifo->base.channel[i];
109 110 111 112 113
		if (chan && chan->state == RUNNING && chan->engine == engine) {
			nv_wo32(cur, p + 0, i);
			nv_wo32(cur, p + 4, 0x00000000);
			p += 8;
		}
114
	}
115
	bar->flush(bar);
116

B
Ben Skeggs 已提交
117 118
	nv_wr32(fifo, 0x002270, cur->addr >> 12);
	nv_wr32(fifo, 0x002274, (engine << 20) | (p >> 3));
119

B
Ben Skeggs 已提交
120
	if (wait_event_timeout(engn->wait, !(nv_rd32(fifo, 0x002284 +
121 122
			       (engine * 0x08)) & 0x00100000),
				msecs_to_jiffies(2000)) == 0)
B
Ben Skeggs 已提交
123 124
		nv_error(fifo, "runlist %d update timeout\n", engine);
	mutex_unlock(&nv_subdev(fifo)->mutex);
125 126
}

127
static int
128 129
gk104_fifo_context_attach(struct nvkm_object *parent,
			  struct nvkm_object *object)
130
{
131 132 133
	struct nvkm_bar *bar = nvkm_bar(parent);
	struct gk104_fifo_base *base = (void *)parent->parent;
	struct nvkm_engctx *ectx = (void *)object;
134 135 136 137
	u32 addr;
	int ret;

	switch (nv_engidx(object->engine)) {
138
	case NVDEV_ENGINE_SW   :
139
		return 0;
140 141 142
	case NVDEV_ENGINE_CE0:
	case NVDEV_ENGINE_CE1:
	case NVDEV_ENGINE_CE2:
143
		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
144
		return 0;
145 146 147 148
	case NVDEV_ENGINE_GR    : addr = 0x0210; break;
	case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
	case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
	case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
149 150
	default:
		return -EINVAL;
151 152
	}

153
	if (!ectx->vma.node) {
154 155
		ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
					 NV_MEM_ACCESS_RW, &ectx->vma);
156 157
		if (ret)
			return ret;
158 159

		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
160 161 162 163 164 165
	}

	nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
	nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
	bar->flush(bar);
	return 0;
166 167
}

B
Ben Skeggs 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
static int
gk104_fifo_chan_kick(struct gk104_fifo_chan *chan)
{
	struct nvkm_object *obj = (void *)chan;
	struct gk104_fifo *fifo = (void *)obj->engine;

	nv_wr32(fifo, 0x002634, chan->base.chid);
	if (!nv_wait(fifo, 0x002634, 0x100000, 0x000000)) {
		nv_error(fifo, "channel %d [%s] kick timeout\n",
			 chan->base.chid, nvkm_client_name(chan));
		return -EBUSY;
	}

	return 0;
}

184
static int
185 186
gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
			  struct nvkm_object *object)
187
{
188 189 190
	struct nvkm_bar *bar = nvkm_bar(parent);
	struct gk104_fifo_base *base = (void *)parent->parent;
	struct gk104_fifo_chan *chan = (void *)parent;
191
	u32 addr;
B
Ben Skeggs 已提交
192
	int ret;
193 194

	switch (nv_engidx(object->engine)) {
195 196 197 198 199 200 201 202
	case NVDEV_ENGINE_SW    : return 0;
	case NVDEV_ENGINE_CE0   :
	case NVDEV_ENGINE_CE1   :
	case NVDEV_ENGINE_CE2   : addr = 0x0000; break;
	case NVDEV_ENGINE_GR    : addr = 0x0210; break;
	case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
	case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
	case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
203 204 205 206
	default:
		return -EINVAL;
	}

B
Ben Skeggs 已提交
207 208 209
	ret = gk104_fifo_chan_kick(chan);
	if (ret && suspend)
		return ret;
210

211 212 213 214 215 216
	if (addr) {
		nv_wo32(base, addr + 0x00, 0x00000000);
		nv_wo32(base, addr + 0x04, 0x00000000);
		bar->flush(bar);
	}

217
	return 0;
218 219 220
}

static int
221 222 223
gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
		     struct nvkm_oclass *oclass, void *data, u32 size,
		     struct nvkm_object **pobject)
224
{
225 226 227
	union {
		struct kepler_channel_gpfifo_a_v0 v0;
	} *args = data;
228
	struct nvkm_bar *bar = nvkm_bar(parent);
B
Ben Skeggs 已提交
229
	struct gk104_fifo *fifo = (void *)engine;
230 231
	struct gk104_fifo_base *base = (void *)parent;
	struct gk104_fifo_chan *chan;
232 233 234
	u64 usermem, ioffset, ilength;
	int ret, i;

235 236 237 238 239 240 241 242
	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
	if (nvif_unpack(args->v0, 0, 0, false)) {
		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
				 "ioffset %016llx ilength %08x engine %08x\n",
			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
			 args->v0.ilength, args->v0.engine);
	} else
		return ret;
243

244
	for (i = 0; i < FIFO_ENGINE_NR; i++) {
245
		if (args->v0.engine & (1 << i)) {
246
			if (nvkm_engine(parent, fifo_engine[i].subdev)) {
247
				args->v0.engine = (1 << i);
248 249 250 251 252
				break;
			}
		}
	}

B
Ben Skeggs 已提交
253
	if (i == FIFO_ENGINE_NR) {
B
Ben Skeggs 已提交
254
		nv_error(fifo, "unsupported engines 0x%08x\n", args->v0.engine);
255
		return -ENODEV;
B
Ben Skeggs 已提交
256
	}
257

258
	ret = nvkm_fifo_channel_create(parent, engine, oclass, 1,
B
Ben Skeggs 已提交
259
				       fifo->user.bar.offset, 0x200,
260 261
				       args->v0.pushbuf,
				       fifo_engine[i].mask, &chan);
262 263 264 265
	*pobject = nv_object(chan);
	if (ret)
		return ret;

266 267
	args->v0.chid = chan->base.chid;

268 269
	nv_parent(chan)->context_attach = gk104_fifo_context_attach;
	nv_parent(chan)->context_detach = gk104_fifo_context_detach;
270
	chan->engine = i;
271 272

	usermem = chan->base.chid * 0x200;
273 274
	ioffset = args->v0.ioffset;
	ilength = order_base_2(args->v0.ilength / 8);
275 276

	for (i = 0; i < 0x200; i += 4)
B
Ben Skeggs 已提交
277
		nv_wo32(fifo->user.mem, usermem + i, 0x00000000);
278

B
Ben Skeggs 已提交
279 280
	nv_wo32(base, 0x08, lower_32_bits(fifo->user.mem->addr + usermem));
	nv_wo32(base, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem));
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
	nv_wo32(base, 0x10, 0x0000face);
	nv_wo32(base, 0x30, 0xfffff902);
	nv_wo32(base, 0x48, lower_32_bits(ioffset));
	nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
	nv_wo32(base, 0x84, 0x20400000);
	nv_wo32(base, 0x94, 0x30000001);
	nv_wo32(base, 0x9c, 0x00000100);
	nv_wo32(base, 0xac, 0x0000001f);
	nv_wo32(base, 0xe8, chan->base.chid);
	nv_wo32(base, 0xb8, 0xf8000000);
	nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
	nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
	bar->flush(bar);
	return 0;
}
296

297
static int
298
gk104_fifo_chan_init(struct nvkm_object *object)
299
{
300
	struct nvkm_gpuobj *base = nv_gpuobj(object->parent);
B
Ben Skeggs 已提交
301
	struct gk104_fifo *fifo = (void *)object->engine;
302
	struct gk104_fifo_chan *chan = (void *)object;
303 304
	u32 chid = chan->base.chid;
	int ret;
305

306
	ret = nvkm_fifo_channel_init(&chan->base);
307 308
	if (ret)
		return ret;
309

B
Ben Skeggs 已提交
310 311
	nv_mask(fifo, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
	nv_wr32(fifo, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
312 313

	if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
B
Ben Skeggs 已提交
314 315 316
		nv_mask(fifo, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
		gk104_fifo_runlist_update(fifo, chan->engine);
		nv_mask(fifo, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
317 318
	}

319 320
	return 0;
}
321

322
static int
323
gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend)
324
{
B
Ben Skeggs 已提交
325
	struct gk104_fifo *fifo = (void *)object->engine;
326
	struct gk104_fifo_chan *chan = (void *)object;
327
	u32 chid = chan->base.chid;
328

329
	if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
B
Ben Skeggs 已提交
330 331
		nv_mask(fifo, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
		gk104_fifo_runlist_update(fifo, chan->engine);
332
	}
333

B
Ben Skeggs 已提交
334
	nv_wr32(fifo, 0x800000 + (chid * 8), 0x00000000);
335
	return nvkm_fifo_channel_fini(&chan->base, suspend);
336
}
337

338 339
struct nvkm_ofuncs
gk104_fifo_chan_ofuncs = {
340 341 342 343 344 345 346 347
	.ctor = gk104_fifo_chan_ctor,
	.dtor = _nvkm_fifo_channel_dtor,
	.init = gk104_fifo_chan_init,
	.fini = gk104_fifo_chan_fini,
	.map  = _nvkm_fifo_channel_map,
	.rd32 = _nvkm_fifo_channel_rd32,
	.wr32 = _nvkm_fifo_channel_wr32,
	.ntfy = _nvkm_fifo_channel_ntfy
348
};
349

350 351
static struct nvkm_oclass
gk104_fifo_sclass[] = {
352
	{ KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs },
353 354 355 356 357 358
	{}
};

/*******************************************************************************
 * FIFO context - instmem heap and vm setup
 ******************************************************************************/
359

360
static int
361 362 363
gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
			struct nvkm_oclass *oclass, void *data, u32 size,
			struct nvkm_object **pobject)
364
{
365
	struct gk104_fifo_base *base;
366
	int ret;
367

368 369
	ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
				       0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
370 371 372
	*pobject = nv_object(base);
	if (ret)
		return ret;
373

374 375
	ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
			      &base->pgd);
376 377 378 379 380 381 382 383
	if (ret)
		return ret;

	nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
	nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
	nv_wo32(base, 0x0208, 0xffffffff);
	nv_wo32(base, 0x020c, 0x000000ff);

384
	ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
385 386
	if (ret)
		return ret;
387 388 389 390

	return 0;
}

391
static void
392
gk104_fifo_context_dtor(struct nvkm_object *object)
393
{
394 395 396 397
	struct gk104_fifo_base *base = (void *)object;
	nvkm_vm_ref(NULL, &base->vm, base->pgd);
	nvkm_gpuobj_ref(NULL, &base->pgd);
	nvkm_fifo_context_destroy(&base->base);
398 399
}

400 401
static struct nvkm_oclass
gk104_fifo_cclass = {
402
	.handle = NV_ENGCTX(FIFO, 0xe0),
403 404 405 406 407 408 409
	.ofuncs = &(struct nvkm_ofuncs) {
		.ctor = gk104_fifo_context_ctor,
		.dtor = gk104_fifo_context_dtor,
		.init = _nvkm_fifo_context_init,
		.fini = _nvkm_fifo_context_fini,
		.rd32 = _nvkm_fifo_context_rd32,
		.wr32 = _nvkm_fifo_context_wr32,
410 411 412 413 414 415 416
	},
};

/*******************************************************************************
 * PFIFO engine
 ******************************************************************************/

417
static inline int
B
Ben Skeggs 已提交
418
gk104_fifo_engidx(struct gk104_fifo *fifo, u32 engn)
419 420
{
	switch (engn) {
421 422 423 424 425 426 427 428
	case NVDEV_ENGINE_GR    :
	case NVDEV_ENGINE_CE2   : engn = 0; break;
	case NVDEV_ENGINE_MSVLD : engn = 1; break;
	case NVDEV_ENGINE_MSPPP : engn = 2; break;
	case NVDEV_ENGINE_MSPDEC: engn = 3; break;
	case NVDEV_ENGINE_CE0   : engn = 4; break;
	case NVDEV_ENGINE_CE1   : engn = 5; break;
	case NVDEV_ENGINE_MSENC : engn = 6; break;
429 430 431 432 433 434 435
	default:
		return -1;
	}

	return engn;
}

436
static inline struct nvkm_engine *
B
Ben Skeggs 已提交
437
gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn)
438 439 440
{
	if (engn >= ARRAY_SIZE(fifo_engine))
		return NULL;
B
Ben Skeggs 已提交
441
	return nvkm_engine(fifo, fifo_engine[engn].subdev);
442 443
}

444
static void
445
gk104_fifo_recover_work(struct work_struct *work)
446
{
B
Ben Skeggs 已提交
447
	struct gk104_fifo *fifo = container_of(work, typeof(*fifo), fault);
448
	struct nvkm_object *engine;
449 450 451 452
	unsigned long flags;
	u32 engn, engm = 0;
	u64 mask, todo;

B
Ben Skeggs 已提交
453 454 455 456
	spin_lock_irqsave(&fifo->base.lock, flags);
	mask = fifo->mask;
	fifo->mask = 0ULL;
	spin_unlock_irqrestore(&fifo->base.lock, flags);
457 458

	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
B
Ben Skeggs 已提交
459 460
		engm |= 1 << gk104_fifo_engidx(fifo, engn);
	nv_mask(fifo, 0x002630, engm, engm);
461 462

	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
B
Ben Skeggs 已提交
463
		if ((engine = (void *)nvkm_engine(fifo, engn))) {
464 465 466
			nv_ofuncs(engine)->fini(engine, false);
			WARN_ON(nv_ofuncs(engine)->init(engine));
		}
B
Ben Skeggs 已提交
467
		gk104_fifo_runlist_update(fifo, gk104_fifo_engidx(fifo, engn));
468 469
	}

B
Ben Skeggs 已提交
470 471
	nv_wr32(fifo, 0x00262c, engm);
	nv_mask(fifo, 0x002630, engm, 0x00000000);
472 473 474
}

static void
B
Ben Skeggs 已提交
475
gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine,
476
		  struct gk104_fifo_chan *chan)
477 478 479 480
{
	u32 chid = chan->base.chid;
	unsigned long flags;

B
Ben Skeggs 已提交
481
	nv_error(fifo, "%s engine fault on channel %d, recovering...\n",
482 483
		       nv_subdev(engine)->name, chid);

B
Ben Skeggs 已提交
484
	nv_mask(fifo, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800);
485 486
	chan->state = KILLED;

B
Ben Skeggs 已提交
487 488 489 490
	spin_lock_irqsave(&fifo->base.lock, flags);
	fifo->mask |= 1ULL << nv_engidx(engine);
	spin_unlock_irqrestore(&fifo->base.lock, flags);
	schedule_work(&fifo->fault);
491 492
}

493
static int
B
Ben Skeggs 已提交
494
gk104_fifo_swmthd(struct gk104_fifo *fifo, u32 chid, u32 mthd, u32 data)
495
{
496 497
	struct gk104_fifo_chan *chan = NULL;
	struct nvkm_handle *bind;
498 499 500
	unsigned long flags;
	int ret = -EINVAL;

B
Ben Skeggs 已提交
501 502 503
	spin_lock_irqsave(&fifo->base.lock, flags);
	if (likely(chid >= fifo->base.min && chid <= fifo->base.max))
		chan = (void *)fifo->base.channel[chid];
504 505 506
	if (unlikely(!chan))
		goto out;

507
	bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e);
508 509 510
	if (likely(bind)) {
		if (!mthd || !nv_call(bind->object, mthd, data))
			ret = 0;
511
		nvkm_namedb_put(bind);
512 513 514
	}

out:
B
Ben Skeggs 已提交
515
	spin_unlock_irqrestore(&fifo->base.lock, flags);
516 517 518
	return ret;
}

519 520
static const struct nvkm_enum
gk104_fifo_bind_reason[] = {
B
Ben Skeggs 已提交
521 522 523 524 525 526 527 528 529 530
	{ 0x01, "BIND_NOT_UNBOUND" },
	{ 0x02, "SNOOP_WITHOUT_BAR1" },
	{ 0x03, "UNBIND_WHILE_RUNNING" },
	{ 0x05, "INVALID_RUNLIST" },
	{ 0x06, "INVALID_CTX_TGT" },
	{ 0x0b, "UNBIND_WHILE_PARKED" },
	{}
};

static void
B
Ben Skeggs 已提交
531
gk104_fifo_intr_bind(struct gk104_fifo *fifo)
B
Ben Skeggs 已提交
532
{
B
Ben Skeggs 已提交
533
	u32 intr = nv_rd32(fifo, 0x00252c);
B
Ben Skeggs 已提交
534
	u32 code = intr & 0x000000ff;
535
	const struct nvkm_enum *en;
B
Ben Skeggs 已提交
536 537
	char enunk[6] = "";

538
	en = nvkm_enum_find(gk104_fifo_bind_reason, code);
B
Ben Skeggs 已提交
539 540 541
	if (!en)
		snprintf(enunk, sizeof(enunk), "UNK%02x", code);

B
Ben Skeggs 已提交
542
	nv_error(fifo, "BIND_ERROR [ %s ]\n", en ? en->name : enunk);
B
Ben Skeggs 已提交
543 544
}

545 546
static const struct nvkm_enum
gk104_fifo_sched_reason[] = {
547 548 549 550
	{ 0x0a, "CTXSW_TIMEOUT" },
	{}
};

551
static void
B
Ben Skeggs 已提交
552
gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo)
553
{
554 555
	struct nvkm_engine *engine;
	struct gk104_fifo_chan *chan;
556 557 558
	u32 engn;

	for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) {
B
Ben Skeggs 已提交
559
		u32 stat = nv_rd32(fifo, 0x002640 + (engn * 0x04));
560 561 562 563 564 565 566 567 568 569
		u32 busy = (stat & 0x80000000);
		u32 next = (stat & 0x07ff0000) >> 16;
		u32 chsw = (stat & 0x00008000);
		u32 save = (stat & 0x00004000);
		u32 load = (stat & 0x00002000);
		u32 prev = (stat & 0x000007ff);
		u32 chid = load ? next : prev;
		(void)save;

		if (busy && chsw) {
B
Ben Skeggs 已提交
570
			if (!(chan = (void *)fifo->base.channel[chid]))
571
				continue;
B
Ben Skeggs 已提交
572
			if (!(engine = gk104_fifo_engine(fifo, engn)))
573
				continue;
B
Ben Skeggs 已提交
574
			gk104_fifo_recover(fifo, engine, chan);
575 576 577 578
		}
	}
}

579
static void
B
Ben Skeggs 已提交
580
gk104_fifo_intr_sched(struct gk104_fifo *fifo)
581
{
B
Ben Skeggs 已提交
582
	u32 intr = nv_rd32(fifo, 0x00254c);
583
	u32 code = intr & 0x000000ff;
584
	const struct nvkm_enum *en;
585 586
	char enunk[6] = "";

587
	en = nvkm_enum_find(gk104_fifo_sched_reason, code);
588 589 590
	if (!en)
		snprintf(enunk, sizeof(enunk), "UNK%02x", code);

B
Ben Skeggs 已提交
591
	nv_error(fifo, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
592 593 594

	switch (code) {
	case 0x0a:
B
Ben Skeggs 已提交
595
		gk104_fifo_intr_sched_ctxsw(fifo);
596 597 598 599
		break;
	default:
		break;
	}
600 601 602
}

static void
B
Ben Skeggs 已提交
603
gk104_fifo_intr_chsw(struct gk104_fifo *fifo)
604
{
B
Ben Skeggs 已提交
605 606 607
	u32 stat = nv_rd32(fifo, 0x00256c);
	nv_error(fifo, "CHSW_ERROR 0x%08x\n", stat);
	nv_wr32(fifo, 0x00256c, stat);
608 609 610
}

static void
B
Ben Skeggs 已提交
611
gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo)
612
{
B
Ben Skeggs 已提交
613 614
	u32 stat = nv_rd32(fifo, 0x00259c);
	nv_error(fifo, "DROPPED_MMU_FAULT 0x%08x\n", stat);
615 616
}

617 618
static const struct nvkm_enum
gk104_fifo_fault_engine[] = {
619
	{ 0x00, "GR", NULL, NVDEV_ENGINE_GR },
620
	{ 0x03, "IFB", NULL, NVDEV_ENGINE_IFB },
621 622
	{ 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
	{ 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
623 624 625
	{ 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO },
	{ 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO },
	{ 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO },
626
	{ 0x10, "MSVLD", NULL, NVDEV_ENGINE_MSVLD },
627
	{ 0x11, "MSPPP", NULL, NVDEV_ENGINE_MSPPP },
628
	{ 0x13, "PERF" },
629
	{ 0x14, "MSPDEC", NULL, NVDEV_ENGINE_MSPDEC },
630 631
	{ 0x15, "CE0", NULL, NVDEV_ENGINE_CE0 },
	{ 0x16, "CE1", NULL, NVDEV_ENGINE_CE1 },
632
	{ 0x17, "PMU" },
633
	{ 0x19, "MSENC", NULL, NVDEV_ENGINE_MSENC },
634
	{ 0x1b, "CE2", NULL, NVDEV_ENGINE_CE2 },
635 636 637
	{}
};

638 639
static const struct nvkm_enum
gk104_fifo_fault_reason[] = {
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
	{ 0x00, "PDE" },
	{ 0x01, "PDE_SIZE" },
	{ 0x02, "PTE" },
	{ 0x03, "VA_LIMIT_VIOLATION" },
	{ 0x04, "UNBOUND_INST_BLOCK" },
	{ 0x05, "PRIV_VIOLATION" },
	{ 0x06, "RO_VIOLATION" },
	{ 0x07, "WO_VIOLATION" },
	{ 0x08, "PITCH_MASK_VIOLATION" },
	{ 0x09, "WORK_CREATION" },
	{ 0x0a, "UNSUPPORTED_APERTURE" },
	{ 0x0b, "COMPRESSION_FAILURE" },
	{ 0x0c, "UNSUPPORTED_KIND" },
	{ 0x0d, "REGION_VIOLATION" },
	{ 0x0e, "BOTH_PTES_VALID" },
	{ 0x0f, "INFO_TYPE_POISONED" },
656 657 658
	{}
};

659 660
static const struct nvkm_enum
gk104_fifo_fault_hubclient[] = {
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
	{ 0x00, "VIP" },
	{ 0x01, "CE0" },
	{ 0x02, "CE1" },
	{ 0x03, "DNISO" },
	{ 0x04, "FE" },
	{ 0x05, "FECS" },
	{ 0x06, "HOST" },
	{ 0x07, "HOST_CPU" },
	{ 0x08, "HOST_CPU_NB" },
	{ 0x09, "ISO" },
	{ 0x0a, "MMU" },
	{ 0x0b, "MSPDEC" },
	{ 0x0c, "MSPPP" },
	{ 0x0d, "MSVLD" },
	{ 0x0e, "NISO" },
	{ 0x0f, "P2P" },
	{ 0x10, "PD" },
	{ 0x11, "PERF" },
	{ 0x12, "PMU" },
	{ 0x13, "RASTERTWOD" },
	{ 0x14, "SCC" },
	{ 0x15, "SCC_NB" },
	{ 0x16, "SEC" },
	{ 0x17, "SSYNC" },
685
	{ 0x18, "GR_CE" },
686 687 688 689 690 691 692
	{ 0x19, "CE2" },
	{ 0x1a, "XV" },
	{ 0x1b, "MMU_NB" },
	{ 0x1c, "MSENC" },
	{ 0x1d, "DFALCON" },
	{ 0x1e, "SKED" },
	{ 0x1f, "AFALCON" },
693 694 695
	{}
};

696 697
static const struct nvkm_enum
gk104_fifo_fault_gpcclient[] = {
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
	{ 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
	{ 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
	{ 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
	{ 0x09, "L1_3" }, { 0x0a, "T1_3" }, { 0x0b, "PE_3" },
	{ 0x0c, "RAST" },
	{ 0x0d, "GCC" },
	{ 0x0e, "GPCCS" },
	{ 0x0f, "PROP_0" },
	{ 0x10, "PROP_1" },
	{ 0x11, "PROP_2" },
	{ 0x12, "PROP_3" },
	{ 0x13, "L1_4" }, { 0x14, "T1_4" }, { 0x15, "PE_4" },
	{ 0x16, "L1_5" }, { 0x17, "T1_5" }, { 0x18, "PE_5" },
	{ 0x19, "L1_6" }, { 0x1a, "T1_6" }, { 0x1b, "PE_6" },
	{ 0x1c, "L1_7" }, { 0x1d, "T1_7" }, { 0x1e, "PE_7" },
	{ 0x1f, "GPM" },
	{ 0x20, "LTP_UTLB_0" },
	{ 0x21, "LTP_UTLB_1" },
	{ 0x22, "LTP_UTLB_2" },
	{ 0x23, "LTP_UTLB_3" },
	{ 0x24, "GPC_RGG_UTLB" },
719 720 721
	{}
};

722
static void
B
Ben Skeggs 已提交
723
gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit)
724
{
B
Ben Skeggs 已提交
725 726 727 728
	u32 inst = nv_rd32(fifo, 0x002800 + (unit * 0x10));
	u32 valo = nv_rd32(fifo, 0x002804 + (unit * 0x10));
	u32 vahi = nv_rd32(fifo, 0x002808 + (unit * 0x10));
	u32 stat = nv_rd32(fifo, 0x00280c + (unit * 0x10));
729
	u32 gpc    = (stat & 0x1f000000) >> 24;
730
	u32 client = (stat & 0x00001f00) >> 8;
731 732 733
	u32 write  = (stat & 0x00000080);
	u32 hub    = (stat & 0x00000040);
	u32 reason = (stat & 0x0000000f);
734 735 736
	struct nvkm_object *engctx = NULL, *object;
	struct nvkm_engine *engine = NULL;
	const struct nvkm_enum *er, *eu, *ec;
737 738 739 740 741
	char erunk[6] = "";
	char euunk[6] = "";
	char ecunk[6] = "";
	char gpcid[3] = "";

742
	er = nvkm_enum_find(gk104_fifo_fault_reason, reason);
743 744 745
	if (!er)
		snprintf(erunk, sizeof(erunk), "UNK%02X", reason);

746
	eu = nvkm_enum_find(gk104_fifo_fault_engine, unit);
747 748 749
	if (eu) {
		switch (eu->data2) {
		case NVDEV_SUBDEV_BAR:
B
Ben Skeggs 已提交
750
			nv_mask(fifo, 0x001704, 0x00000000, 0x00000000);
751 752
			break;
		case NVDEV_SUBDEV_INSTMEM:
B
Ben Skeggs 已提交
753
			nv_mask(fifo, 0x001714, 0x00000000, 0x00000000);
754 755
			break;
		case NVDEV_ENGINE_IFB:
B
Ben Skeggs 已提交
756
			nv_mask(fifo, 0x001718, 0x00000000, 0x00000000);
757 758
			break;
		default:
B
Ben Skeggs 已提交
759
			engine = nvkm_engine(fifo, eu->data2);
760
			if (engine)
761
				engctx = nvkm_engctx_get(engine, inst);
762
			break;
763
		}
764 765
	} else {
		snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
766
	}
767 768

	if (hub) {
769
		ec = nvkm_enum_find(gk104_fifo_fault_hubclient, client);
770
	} else {
771
		ec = nvkm_enum_find(gk104_fifo_fault_gpcclient, client);
772 773 774 775 776 777
		snprintf(gpcid, sizeof(gpcid), "%d", gpc);
	}

	if (!ec)
		snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);

B
Ben Skeggs 已提交
778
	nv_error(fifo, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
779 780 781 782
		       "channel 0x%010llx [%s]\n", write ? "write" : "read",
		 (u64)vahi << 32 | valo, er ? er->name : erunk,
		 eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
		 ec ? ec->name : ecunk, (u64)inst << 12,
783
		 nvkm_client_name(engctx));
784

785 786 787
	object = engctx;
	while (object) {
		switch (nv_mclass(object)) {
788
		case KEPLER_CHANNEL_GPFIFO_A:
789
		case MAXWELL_CHANNEL_GPFIFO_A:
B
Ben Skeggs 已提交
790
			gk104_fifo_recover(fifo, engine, (void *)object);
791 792 793 794 795
			break;
		}
		object = object->parent;
	}

796
	nvkm_engctx_put(engctx);
797 798
}

799
static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = {
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
	{ 0x00000001, "MEMREQ" },
	{ 0x00000002, "MEMACK_TIMEOUT" },
	{ 0x00000004, "MEMACK_EXTRA" },
	{ 0x00000008, "MEMDAT_TIMEOUT" },
	{ 0x00000010, "MEMDAT_EXTRA" },
	{ 0x00000020, "MEMFLUSH" },
	{ 0x00000040, "MEMOP" },
	{ 0x00000080, "LBCONNECT" },
	{ 0x00000100, "LBREQ" },
	{ 0x00000200, "LBACK_TIMEOUT" },
	{ 0x00000400, "LBACK_EXTRA" },
	{ 0x00000800, "LBDAT_TIMEOUT" },
	{ 0x00001000, "LBDAT_EXTRA" },
	{ 0x00002000, "GPFIFO" },
	{ 0x00004000, "GPPTR" },
	{ 0x00008000, "GPENTRY" },
	{ 0x00010000, "GPCRC" },
	{ 0x00020000, "PBPTR" },
	{ 0x00040000, "PBENTRY" },
	{ 0x00080000, "PBCRC" },
	{ 0x00100000, "XBARCONNECT" },
	{ 0x00200000, "METHOD" },
	{ 0x00400000, "METHODCRC" },
	{ 0x00800000, "DEVICE" },
	{ 0x02000000, "SEMAPHORE" },
	{ 0x04000000, "ACQUIRE" },
	{ 0x08000000, "PRI" },
	{ 0x20000000, "NO_CTXSW_SEG" },
	{ 0x40000000, "PBSEG" },
	{ 0x80000000, "SIGNATURE" },
	{}
};
832

833
static void
B
Ben Skeggs 已提交
834
gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit)
835
{
B
Ben Skeggs 已提交
836 837 838 839 840
	u32 mask = nv_rd32(fifo, 0x04010c + (unit * 0x2000));
	u32 stat = nv_rd32(fifo, 0x040108 + (unit * 0x2000)) & mask;
	u32 addr = nv_rd32(fifo, 0x0400c0 + (unit * 0x2000));
	u32 data = nv_rd32(fifo, 0x0400c4 + (unit * 0x2000));
	u32 chid = nv_rd32(fifo, 0x040120 + (unit * 0x2000)) & 0xfff;
841
	u32 subc = (addr & 0x00070000) >> 16;
842
	u32 mthd = (addr & 0x00003ffc);
843 844
	u32 show = stat;

845
	if (stat & 0x00800000) {
B
Ben Skeggs 已提交
846
		if (!gk104_fifo_swmthd(fifo, chid, mthd, data))
847
			show &= ~0x00800000;
B
Ben Skeggs 已提交
848
		nv_wr32(fifo, 0x0400c0 + (unit * 0x2000), 0x80600008);
849 850
	}

851
	if (show) {
B
Ben Skeggs 已提交
852
		nv_error(fifo, "PBDMA%d:", unit);
853
		nvkm_bitfield_print(gk104_fifo_pbdma_intr_0, show);
M
Marcin Slusarz 已提交
854
		pr_cont("\n");
B
Ben Skeggs 已提交
855
		nv_error(fifo,
B
Ben Skeggs 已提交
856
			 "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
857
			 unit, chid,
B
Ben Skeggs 已提交
858
			 nvkm_client_name_for_fifo_chid(&fifo->base, chid),
859
			 subc, mthd, data);
860
	}
861

B
Ben Skeggs 已提交
862
	nv_wr32(fifo, 0x040108 + (unit * 0x2000), stat);
863 864
}

865
static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = {
866 867 868 869 870 871 872 873 874
	{ 0x00000001, "HCE_RE_ILLEGAL_OP" },
	{ 0x00000002, "HCE_RE_ALIGNB" },
	{ 0x00000004, "HCE_PRIV" },
	{ 0x00000008, "HCE_ILLEGAL_MTHD" },
	{ 0x00000010, "HCE_ILLEGAL_CLASS" },
	{}
};

static void
B
Ben Skeggs 已提交
875
gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit)
876
{
B
Ben Skeggs 已提交
877 878 879
	u32 mask = nv_rd32(fifo, 0x04014c + (unit * 0x2000));
	u32 stat = nv_rd32(fifo, 0x040148 + (unit * 0x2000)) & mask;
	u32 chid = nv_rd32(fifo, 0x040120 + (unit * 0x2000)) & 0xfff;
880 881

	if (stat) {
B
Ben Skeggs 已提交
882
		nv_error(fifo, "PBDMA%d:", unit);
883
		nvkm_bitfield_print(gk104_fifo_pbdma_intr_1, stat);
884
		pr_cont("\n");
B
Ben Skeggs 已提交
885 886 887
		nv_error(fifo, "PBDMA%d: ch %d %08x %08x\n", unit, chid,
			 nv_rd32(fifo, 0x040150 + (unit * 0x2000)),
			 nv_rd32(fifo, 0x040154 + (unit * 0x2000)));
888 889
	}

B
Ben Skeggs 已提交
890
	nv_wr32(fifo, 0x040148 + (unit * 0x2000), stat);
891 892
}

B
Ben Skeggs 已提交
893
static void
B
Ben Skeggs 已提交
894
gk104_fifo_intr_runlist(struct gk104_fifo *fifo)
B
Ben Skeggs 已提交
895
{
B
Ben Skeggs 已提交
896
	u32 mask = nv_rd32(fifo, 0x002a00);
B
Ben Skeggs 已提交
897 898
	while (mask) {
		u32 engn = __ffs(mask);
B
Ben Skeggs 已提交
899 900
		wake_up(&fifo->engine[engn].wait);
		nv_wr32(fifo, 0x002a00, 1 << engn);
B
Ben Skeggs 已提交
901 902 903 904
		mask &= ~(1 << engn);
	}
}

B
Ben Skeggs 已提交
905
static void
B
Ben Skeggs 已提交
906
gk104_fifo_intr_engine(struct gk104_fifo *fifo)
B
Ben Skeggs 已提交
907
{
B
Ben Skeggs 已提交
908
	nvkm_fifo_uevent(&fifo->base);
B
Ben Skeggs 已提交
909 910
}

911
static void
912
gk104_fifo_intr(struct nvkm_subdev *subdev)
913
{
B
Ben Skeggs 已提交
914 915 916
	struct gk104_fifo *fifo = (void *)subdev;
	u32 mask = nv_rd32(fifo, 0x002140);
	u32 stat = nv_rd32(fifo, 0x002100) & mask;
917

918
	if (stat & 0x00000001) {
B
Ben Skeggs 已提交
919 920
		gk104_fifo_intr_bind(fifo);
		nv_wr32(fifo, 0x002100, 0x00000001);
921 922 923 924
		stat &= ~0x00000001;
	}

	if (stat & 0x00000010) {
B
Ben Skeggs 已提交
925 926
		nv_error(fifo, "PIO_ERROR\n");
		nv_wr32(fifo, 0x002100, 0x00000010);
927 928 929
		stat &= ~0x00000010;
	}

930
	if (stat & 0x00000100) {
B
Ben Skeggs 已提交
931 932
		gk104_fifo_intr_sched(fifo);
		nv_wr32(fifo, 0x002100, 0x00000100);
933 934 935
		stat &= ~0x00000100;
	}

936
	if (stat & 0x00010000) {
B
Ben Skeggs 已提交
937 938
		gk104_fifo_intr_chsw(fifo);
		nv_wr32(fifo, 0x002100, 0x00010000);
939 940 941 942
		stat &= ~0x00010000;
	}

	if (stat & 0x00800000) {
B
Ben Skeggs 已提交
943 944
		nv_error(fifo, "FB_FLUSH_TIMEOUT\n");
		nv_wr32(fifo, 0x002100, 0x00800000);
945 946 947 948
		stat &= ~0x00800000;
	}

	if (stat & 0x01000000) {
B
Ben Skeggs 已提交
949 950
		nv_error(fifo, "LB_ERROR\n");
		nv_wr32(fifo, 0x002100, 0x01000000);
951 952 953 954
		stat &= ~0x01000000;
	}

	if (stat & 0x08000000) {
B
Ben Skeggs 已提交
955 956
		gk104_fifo_intr_dropped_fault(fifo);
		nv_wr32(fifo, 0x002100, 0x08000000);
957 958 959
		stat &= ~0x08000000;
	}

960
	if (stat & 0x10000000) {
B
Ben Skeggs 已提交
961
		u32 mask = nv_rd32(fifo, 0x00259c);
962 963
		while (mask) {
			u32 unit = __ffs(mask);
B
Ben Skeggs 已提交
964 965
			gk104_fifo_intr_fault(fifo, unit);
			nv_wr32(fifo, 0x00259c, (1 << unit));
966
			mask &= ~(1 << unit);
967 968 969 970 971
		}
		stat &= ~0x10000000;
	}

	if (stat & 0x20000000) {
B
Ben Skeggs 已提交
972
		u32 mask = nv_rd32(fifo, 0x0025a0);
973 974
		while (mask) {
			u32 unit = __ffs(mask);
B
Ben Skeggs 已提交
975 976 977
			gk104_fifo_intr_pbdma_0(fifo, unit);
			gk104_fifo_intr_pbdma_1(fifo, unit);
			nv_wr32(fifo, 0x0025a0, (1 << unit));
978
			mask &= ~(1 << unit);
979 980 981 982 983
		}
		stat &= ~0x20000000;
	}

	if (stat & 0x40000000) {
B
Ben Skeggs 已提交
984
		gk104_fifo_intr_runlist(fifo);
985 986 987
		stat &= ~0x40000000;
	}

988
	if (stat & 0x80000000) {
B
Ben Skeggs 已提交
989 990
		nv_wr32(fifo, 0x002100, 0x80000000);
		gk104_fifo_intr_engine(fifo);
991 992 993
		stat &= ~0x80000000;
	}

994
	if (stat) {
B
Ben Skeggs 已提交
995 996 997
		nv_error(fifo, "INTR 0x%08x\n", stat);
		nv_mask(fifo, 0x002140, stat, 0x00000000);
		nv_wr32(fifo, 0x002100, stat);
998 999
	}
}
1000

1001
static void
1002
gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index)
1003
{
1004
	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
1005
	nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
1006 1007 1008
}

static void
1009
gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
1010
{
1011
	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
1012
	nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
1013 1014
}

1015
static const struct nvkm_event_func
1016 1017 1018 1019
gk104_fifo_uevent_func = {
	.ctor = nvkm_fifo_uevent_ctor,
	.init = gk104_fifo_uevent_init,
	.fini = gk104_fifo_uevent_fini,
1020 1021
};

1022
int
1023
gk104_fifo_fini(struct nvkm_object *object, bool suspend)
1024
{
B
Ben Skeggs 已提交
1025
	struct gk104_fifo *fifo = (void *)object;
1026 1027
	int ret;

B
Ben Skeggs 已提交
1028
	ret = nvkm_fifo_fini(&fifo->base, suspend);
1029 1030 1031 1032
	if (ret)
		return ret;

	/* allow mmu fault interrupts, even when we're not using fifo */
B
Ben Skeggs 已提交
1033
	nv_mask(fifo, 0x002140, 0x10000000, 0x10000000);
1034 1035 1036
	return 0;
}

B
Ben Skeggs 已提交
1037
int
1038
gk104_fifo_init(struct nvkm_object *object)
B
Ben Skeggs 已提交
1039
{
B
Ben Skeggs 已提交
1040
	struct gk104_fifo *fifo = (void *)object;
B
Ben Skeggs 已提交
1041 1042
	int ret, i;

B
Ben Skeggs 已提交
1043
	ret = nvkm_fifo_init(&fifo->base);
B
Ben Skeggs 已提交
1044 1045 1046
	if (ret)
		return ret;

B
Ben Skeggs 已提交
1047
	/* enable all available PBDMA units */
B
Ben Skeggs 已提交
1048 1049 1050
	nv_wr32(fifo, 0x000204, 0xffffffff);
	fifo->spoon_nr = hweight32(nv_rd32(fifo, 0x000204));
	nv_debug(fifo, "%d PBDMA unit(s)\n", fifo->spoon_nr);
B
Ben Skeggs 已提交
1051

B
Ben Skeggs 已提交
1052
	/* PBDMA[n] */
B
Ben Skeggs 已提交
1053 1054 1055 1056
	for (i = 0; i < fifo->spoon_nr; i++) {
		nv_mask(fifo, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
		nv_wr32(fifo, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
		nv_wr32(fifo, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
B
Ben Skeggs 已提交
1057 1058
	}

1059
	/* PBDMA[n].HCE */
B
Ben Skeggs 已提交
1060 1061 1062
	for (i = 0; i < fifo->spoon_nr; i++) {
		nv_wr32(fifo, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
		nv_wr32(fifo, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
1063 1064
	}

B
Ben Skeggs 已提交
1065
	nv_wr32(fifo, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12);
B
Ben Skeggs 已提交
1066

B
Ben Skeggs 已提交
1067 1068
	nv_wr32(fifo, 0x002100, 0xffffffff);
	nv_wr32(fifo, 0x002140, 0x7fffffff);
B
Ben Skeggs 已提交
1069 1070 1071 1072
	return 0;
}

void
1073
gk104_fifo_dtor(struct nvkm_object *object)
B
Ben Skeggs 已提交
1074
{
B
Ben Skeggs 已提交
1075
	struct gk104_fifo *fifo = (void *)object;
B
Ben Skeggs 已提交
1076 1077
	int i;

B
Ben Skeggs 已提交
1078 1079
	nvkm_gpuobj_unmap(&fifo->user.bar);
	nvkm_gpuobj_ref(NULL, &fifo->user.mem);
B
Ben Skeggs 已提交
1080 1081

	for (i = 0; i < FIFO_ENGINE_NR; i++) {
B
Ben Skeggs 已提交
1082 1083
		nvkm_gpuobj_ref(NULL, &fifo->engine[i].runlist[1]);
		nvkm_gpuobj_ref(NULL, &fifo->engine[i].runlist[0]);
B
Ben Skeggs 已提交
1084 1085
	}

B
Ben Skeggs 已提交
1086
	nvkm_fifo_destroy(&fifo->base);
B
Ben Skeggs 已提交
1087 1088 1089
}

int
1090 1091 1092
gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
		struct nvkm_oclass *oclass, void *data, u32 size,
		struct nvkm_object **pobject)
1093
{
1094
	struct gk104_fifo_impl *impl = (void *)oclass;
B
Ben Skeggs 已提交
1095
	struct gk104_fifo *fifo;
1096
	int ret, i;
1097

1098
	ret = nvkm_fifo_create(parent, engine, oclass, 0,
B
Ben Skeggs 已提交
1099 1100
			       impl->channels - 1, &fifo);
	*pobject = nv_object(fifo);
1101 1102 1103
	if (ret)
		return ret;

B
Ben Skeggs 已提交
1104
	INIT_WORK(&fifo->fault, gk104_fifo_recover_work);
1105

1106
	for (i = 0; i < FIFO_ENGINE_NR; i++) {
B
Ben Skeggs 已提交
1107 1108
		ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x8000, 0x1000,
				      0, &fifo->engine[i].runlist[0]);
1109 1110 1111
		if (ret)
			return ret;

B
Ben Skeggs 已提交
1112 1113
		ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x8000, 0x1000,
				      0, &fifo->engine[i].runlist[1]);
1114 1115
		if (ret)
			return ret;
B
Ben Skeggs 已提交
1116

B
Ben Skeggs 已提交
1117
		init_waitqueue_head(&fifo->engine[i].wait);
1118 1119
	}

B
Ben Skeggs 已提交
1120 1121
	ret = nvkm_gpuobj_new(nv_object(fifo), NULL, impl->channels * 0x200,
			      0x1000, NVOBJ_FLAG_ZERO_ALLOC, &fifo->user.mem);
1122 1123 1124
	if (ret)
		return ret;

B
Ben Skeggs 已提交
1125 1126
	ret = nvkm_gpuobj_map(fifo->user.mem, NV_MEM_ACCESS_RW,
			      &fifo->user.bar);
1127 1128 1129
	if (ret)
		return ret;

B
Ben Skeggs 已提交
1130
	ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &fifo->base.uevent);
1131 1132
	if (ret)
		return ret;
1133

B
Ben Skeggs 已提交
1134 1135 1136 1137
	nv_subdev(fifo)->unit = 0x00000100;
	nv_subdev(fifo)->intr = gk104_fifo_intr;
	nv_engine(fifo)->cclass = &gk104_fifo_cclass;
	nv_engine(fifo)->sclass = gk104_fifo_sclass;
1138 1139 1140
	return 0;
}

1141 1142
struct nvkm_oclass *
gk104_fifo_oclass = &(struct gk104_fifo_impl) {
B
Ben Skeggs 已提交
1143
	.base.handle = NV_ENGINE(FIFO, 0xe0),
1144 1145 1146 1147 1148
	.base.ofuncs = &(struct nvkm_ofuncs) {
		.ctor = gk104_fifo_ctor,
		.dtor = gk104_fifo_dtor,
		.init = gk104_fifo_init,
		.fini = gk104_fifo_fini,
1149
	},
B
Ben Skeggs 已提交
1150 1151
	.channels = 4096,
}.base;