gk104.c 31.2 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
	struct gk104_fifo_engn *engn = &fifo->engine[engine];
99 100
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	struct nvkm_bar *bar = device->bar;
101
	struct nvkm_gpuobj *cur;
102
	int i, p;
103

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

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

118 119
	nvkm_wr32(device, 0x002270, cur->addr >> 12);
	nvkm_wr32(device, 0x002274, (engine << 20) | (p >> 3));
120

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

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

	switch (nv_engidx(object->engine)) {
139
	case NVDEV_ENGINE_SW   :
140
		return 0;
141 142 143
	case NVDEV_ENGINE_CE0:
	case NVDEV_ENGINE_CE1:
	case NVDEV_ENGINE_CE2:
144
		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
145
		return 0;
146 147 148 149
	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;
150 151
	default:
		return -EINVAL;
152 153
	}

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

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

	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;
167 168
}

B
Ben Skeggs 已提交
169 170 171 172 173
static int
gk104_fifo_chan_kick(struct gk104_fifo_chan *chan)
{
	struct nvkm_object *obj = (void *)chan;
	struct gk104_fifo *fifo = (void *)obj->engine;
174
	struct nvkm_device *device = fifo->base.engine.subdev.device;
B
Ben Skeggs 已提交
175

176
	nvkm_wr32(device, 0x002634, chan->base.chid);
177 178 179 180
	if (nvkm_msec(device, 2000,
		if (!(nvkm_rd32(device, 0x002634) & 0x00100000))
			break;
	) < 0) {
B
Ben Skeggs 已提交
181 182 183 184 185 186 187 188
		nv_error(fifo, "channel %d [%s] kick timeout\n",
			 chan->base.chid, nvkm_client_name(chan));
		return -EBUSY;
	}

	return 0;
}

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

	switch (nv_engidx(object->engine)) {
200 201 202 203 204 205 206 207
	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;
208 209 210 211
	default:
		return -EINVAL;
	}

B
Ben Skeggs 已提交
212 213 214
	ret = gk104_fifo_chan_kick(chan);
	if (ret && suspend)
		return ret;
215

216 217 218 219 220 221
	if (addr) {
		nv_wo32(base, addr + 0x00, 0x00000000);
		nv_wo32(base, addr + 0x04, 0x00000000);
		bar->flush(bar);
	}

222
	return 0;
223 224 225
}

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

240 241 242 243 244 245 246 247
	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;
248

249
	for (i = 0; i < FIFO_ENGINE_NR; i++) {
250
		if (args->v0.engine & (1 << i)) {
251
			if (nvkm_engine(parent, fifo_engine[i].subdev)) {
252
				args->v0.engine = (1 << i);
253 254 255 256 257
				break;
			}
		}
	}

B
Ben Skeggs 已提交
258
	if (i == FIFO_ENGINE_NR) {
B
Ben Skeggs 已提交
259
		nv_error(fifo, "unsupported engines 0x%08x\n", args->v0.engine);
260
		return -ENODEV;
B
Ben Skeggs 已提交
261
	}
262

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

271 272
	args->v0.chid = chan->base.chid;

273 274
	nv_parent(chan)->context_attach = gk104_fifo_context_attach;
	nv_parent(chan)->context_detach = gk104_fifo_context_detach;
275
	chan->engine = i;
276 277

	usermem = chan->base.chid * 0x200;
278 279
	ioffset = args->v0.ioffset;
	ilength = order_base_2(args->v0.ilength / 8);
280 281

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

B
Ben Skeggs 已提交
284 285
	nv_wo32(base, 0x08, lower_32_bits(fifo->user.mem->addr + usermem));
	nv_wo32(base, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem));
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
	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;
}
301

302
static int
303
gk104_fifo_chan_init(struct nvkm_object *object)
304
{
305
	struct nvkm_gpuobj *base = nv_gpuobj(object->parent);
B
Ben Skeggs 已提交
306
	struct gk104_fifo *fifo = (void *)object->engine;
307
	struct gk104_fifo_chan *chan = (void *)object;
308
	struct nvkm_device *device = fifo->base.engine.subdev.device;
309 310
	u32 chid = chan->base.chid;
	int ret;
311

312
	ret = nvkm_fifo_channel_init(&chan->base);
313 314
	if (ret)
		return ret;
315

316 317
	nvkm_mask(device, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
	nvkm_wr32(device, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
318 319

	if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
320
		nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
B
Ben Skeggs 已提交
321
		gk104_fifo_runlist_update(fifo, chan->engine);
322
		nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
323 324
	}

325 326
	return 0;
}
327

328
static int
329
gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend)
330
{
B
Ben Skeggs 已提交
331
	struct gk104_fifo *fifo = (void *)object->engine;
332
	struct gk104_fifo_chan *chan = (void *)object;
333
	struct nvkm_device *device = fifo->base.engine.subdev.device;
334
	u32 chid = chan->base.chid;
335

336
	if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
337
		nvkm_mask(device, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
B
Ben Skeggs 已提交
338
		gk104_fifo_runlist_update(fifo, chan->engine);
339
	}
340

341
	nvkm_wr32(device, 0x800000 + (chid * 8), 0x00000000);
342
	return nvkm_fifo_channel_fini(&chan->base, suspend);
343
}
344

345 346
struct nvkm_ofuncs
gk104_fifo_chan_ofuncs = {
347 348 349 350 351 352 353 354
	.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
355
};
356

357 358
static struct nvkm_oclass
gk104_fifo_sclass[] = {
359
	{ KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs },
360 361 362 363 364 365
	{}
};

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

367
static int
368 369 370
gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
			struct nvkm_oclass *oclass, void *data, u32 size,
			struct nvkm_object **pobject)
371
{
372
	struct gk104_fifo_base *base;
373
	int ret;
374

375 376
	ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
				       0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
377 378 379
	*pobject = nv_object(base);
	if (ret)
		return ret;
380

381 382
	ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
			      &base->pgd);
383 384 385 386 387 388 389 390
	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);

391
	ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
392 393
	if (ret)
		return ret;
394 395 396 397

	return 0;
}

398
static void
399
gk104_fifo_context_dtor(struct nvkm_object *object)
400
{
401 402 403 404
	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);
405 406
}

407 408
static struct nvkm_oclass
gk104_fifo_cclass = {
409
	.handle = NV_ENGCTX(FIFO, 0xe0),
410 411 412 413 414 415 416
	.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,
417 418 419 420 421 422 423
	},
};

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

424
static inline int
B
Ben Skeggs 已提交
425
gk104_fifo_engidx(struct gk104_fifo *fifo, u32 engn)
426 427
{
	switch (engn) {
428 429 430 431 432 433 434 435
	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;
436 437 438 439 440 441 442
	default:
		return -1;
	}

	return engn;
}

443
static inline struct nvkm_engine *
B
Ben Skeggs 已提交
444
gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn)
445 446 447
{
	if (engn >= ARRAY_SIZE(fifo_engine))
		return NULL;
B
Ben Skeggs 已提交
448
	return nvkm_engine(fifo, fifo_engine[engn].subdev);
449 450
}

451
static void
452
gk104_fifo_recover_work(struct work_struct *work)
453
{
B
Ben Skeggs 已提交
454
	struct gk104_fifo *fifo = container_of(work, typeof(*fifo), fault);
455
	struct nvkm_device *device = fifo->base.engine.subdev.device;
456
	struct nvkm_object *engine;
457 458 459 460
	unsigned long flags;
	u32 engn, engm = 0;
	u64 mask, todo;

B
Ben Skeggs 已提交
461 462 463 464
	spin_lock_irqsave(&fifo->base.lock, flags);
	mask = fifo->mask;
	fifo->mask = 0ULL;
	spin_unlock_irqrestore(&fifo->base.lock, flags);
465 466

	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
B
Ben Skeggs 已提交
467
		engm |= 1 << gk104_fifo_engidx(fifo, engn);
468
	nvkm_mask(device, 0x002630, engm, engm);
469 470

	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
B
Ben Skeggs 已提交
471
		if ((engine = (void *)nvkm_engine(fifo, engn))) {
472 473 474
			nv_ofuncs(engine)->fini(engine, false);
			WARN_ON(nv_ofuncs(engine)->init(engine));
		}
B
Ben Skeggs 已提交
475
		gk104_fifo_runlist_update(fifo, gk104_fifo_engidx(fifo, engn));
476 477
	}

478 479
	nvkm_wr32(device, 0x00262c, engm);
	nvkm_mask(device, 0x002630, engm, 0x00000000);
480 481 482
}

static void
B
Ben Skeggs 已提交
483
gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine,
484
		  struct gk104_fifo_chan *chan)
485
{
486
	struct nvkm_device *device = fifo->base.engine.subdev.device;
487 488 489
	u32 chid = chan->base.chid;
	unsigned long flags;

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

493
	nvkm_mask(device, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800);
494 495
	chan->state = KILLED;

B
Ben Skeggs 已提交
496 497 498 499
	spin_lock_irqsave(&fifo->base.lock, flags);
	fifo->mask |= 1ULL << nv_engidx(engine);
	spin_unlock_irqrestore(&fifo->base.lock, flags);
	schedule_work(&fifo->fault);
500 501
}

502
static int
B
Ben Skeggs 已提交
503
gk104_fifo_swmthd(struct gk104_fifo *fifo, u32 chid, u32 mthd, u32 data)
504
{
505 506
	struct gk104_fifo_chan *chan = NULL;
	struct nvkm_handle *bind;
507 508 509
	unsigned long flags;
	int ret = -EINVAL;

B
Ben Skeggs 已提交
510 511 512
	spin_lock_irqsave(&fifo->base.lock, flags);
	if (likely(chid >= fifo->base.min && chid <= fifo->base.max))
		chan = (void *)fifo->base.channel[chid];
513 514 515
	if (unlikely(!chan))
		goto out;

516
	bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e);
517 518 519
	if (likely(bind)) {
		if (!mthd || !nv_call(bind->object, mthd, data))
			ret = 0;
520
		nvkm_namedb_put(bind);
521 522 523
	}

out:
B
Ben Skeggs 已提交
524
	spin_unlock_irqrestore(&fifo->base.lock, flags);
525 526 527
	return ret;
}

528 529
static const struct nvkm_enum
gk104_fifo_bind_reason[] = {
B
Ben Skeggs 已提交
530 531 532 533 534 535 536 537 538 539
	{ 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 已提交
540
gk104_fifo_intr_bind(struct gk104_fifo *fifo)
B
Ben Skeggs 已提交
541
{
542 543
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 intr = nvkm_rd32(device, 0x00252c);
B
Ben Skeggs 已提交
544
	u32 code = intr & 0x000000ff;
545
	const struct nvkm_enum *en;
B
Ben Skeggs 已提交
546 547
	char enunk[6] = "";

548
	en = nvkm_enum_find(gk104_fifo_bind_reason, code);
B
Ben Skeggs 已提交
549 550 551
	if (!en)
		snprintf(enunk, sizeof(enunk), "UNK%02x", code);

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

555 556
static const struct nvkm_enum
gk104_fifo_sched_reason[] = {
557 558 559 560
	{ 0x0a, "CTXSW_TIMEOUT" },
	{}
};

561
static void
B
Ben Skeggs 已提交
562
gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo)
563
{
564
	struct nvkm_device *device = fifo->base.engine.subdev.device;
565 566
	struct nvkm_engine *engine;
	struct gk104_fifo_chan *chan;
567 568 569
	u32 engn;

	for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) {
570
		u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04));
571 572 573 574 575 576 577 578 579 580
		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 已提交
581
			if (!(chan = (void *)fifo->base.channel[chid]))
582
				continue;
B
Ben Skeggs 已提交
583
			if (!(engine = gk104_fifo_engine(fifo, engn)))
584
				continue;
B
Ben Skeggs 已提交
585
			gk104_fifo_recover(fifo, engine, chan);
586 587 588 589
		}
	}
}

590
static void
B
Ben Skeggs 已提交
591
gk104_fifo_intr_sched(struct gk104_fifo *fifo)
592
{
593 594
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 intr = nvkm_rd32(device, 0x00254c);
595
	u32 code = intr & 0x000000ff;
596
	const struct nvkm_enum *en;
597 598
	char enunk[6] = "";

599
	en = nvkm_enum_find(gk104_fifo_sched_reason, code);
600 601 602
	if (!en)
		snprintf(enunk, sizeof(enunk), "UNK%02x", code);

B
Ben Skeggs 已提交
603
	nv_error(fifo, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
604 605 606

	switch (code) {
	case 0x0a:
B
Ben Skeggs 已提交
607
		gk104_fifo_intr_sched_ctxsw(fifo);
608 609 610 611
		break;
	default:
		break;
	}
612 613 614
}

static void
B
Ben Skeggs 已提交
615
gk104_fifo_intr_chsw(struct gk104_fifo *fifo)
616
{
617 618
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 stat = nvkm_rd32(device, 0x00256c);
B
Ben Skeggs 已提交
619
	nv_error(fifo, "CHSW_ERROR 0x%08x\n", stat);
620
	nvkm_wr32(device, 0x00256c, stat);
621 622 623
}

static void
B
Ben Skeggs 已提交
624
gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo)
625
{
626 627
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 stat = nvkm_rd32(device, 0x00259c);
B
Ben Skeggs 已提交
628
	nv_error(fifo, "DROPPED_MMU_FAULT 0x%08x\n", stat);
629 630
}

631 632
static const struct nvkm_enum
gk104_fifo_fault_engine[] = {
633
	{ 0x00, "GR", NULL, NVDEV_ENGINE_GR },
634
	{ 0x03, "IFB", NULL, NVDEV_ENGINE_IFB },
635 636
	{ 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
	{ 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
637 638 639
	{ 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO },
	{ 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO },
	{ 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO },
640
	{ 0x10, "MSVLD", NULL, NVDEV_ENGINE_MSVLD },
641
	{ 0x11, "MSPPP", NULL, NVDEV_ENGINE_MSPPP },
642
	{ 0x13, "PERF" },
643
	{ 0x14, "MSPDEC", NULL, NVDEV_ENGINE_MSPDEC },
644 645
	{ 0x15, "CE0", NULL, NVDEV_ENGINE_CE0 },
	{ 0x16, "CE1", NULL, NVDEV_ENGINE_CE1 },
646
	{ 0x17, "PMU" },
647
	{ 0x19, "MSENC", NULL, NVDEV_ENGINE_MSENC },
648
	{ 0x1b, "CE2", NULL, NVDEV_ENGINE_CE2 },
649 650 651
	{}
};

652 653
static const struct nvkm_enum
gk104_fifo_fault_reason[] = {
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
	{ 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" },
670 671 672
	{}
};

673 674
static const struct nvkm_enum
gk104_fifo_fault_hubclient[] = {
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
	{ 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" },
699
	{ 0x18, "GR_CE" },
700 701 702 703 704 705 706
	{ 0x19, "CE2" },
	{ 0x1a, "XV" },
	{ 0x1b, "MMU_NB" },
	{ 0x1c, "MSENC" },
	{ 0x1d, "DFALCON" },
	{ 0x1e, "SKED" },
	{ 0x1f, "AFALCON" },
707 708 709
	{}
};

710 711
static const struct nvkm_enum
gk104_fifo_fault_gpcclient[] = {
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
	{ 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" },
733 734 735
	{}
};

736
static void
B
Ben Skeggs 已提交
737
gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit)
738
{
739 740 741 742 743
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10));
	u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10));
	u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10));
	u32 stat = nvkm_rd32(device, 0x00280c + (unit * 0x10));
744
	u32 gpc    = (stat & 0x1f000000) >> 24;
745
	u32 client = (stat & 0x00001f00) >> 8;
746 747 748
	u32 write  = (stat & 0x00000080);
	u32 hub    = (stat & 0x00000040);
	u32 reason = (stat & 0x0000000f);
749 750 751
	struct nvkm_object *engctx = NULL, *object;
	struct nvkm_engine *engine = NULL;
	const struct nvkm_enum *er, *eu, *ec;
752 753 754 755 756
	char erunk[6] = "";
	char euunk[6] = "";
	char ecunk[6] = "";
	char gpcid[3] = "";

757
	er = nvkm_enum_find(gk104_fifo_fault_reason, reason);
758 759 760
	if (!er)
		snprintf(erunk, sizeof(erunk), "UNK%02X", reason);

761
	eu = nvkm_enum_find(gk104_fifo_fault_engine, unit);
762 763 764
	if (eu) {
		switch (eu->data2) {
		case NVDEV_SUBDEV_BAR:
765
			nvkm_mask(device, 0x001704, 0x00000000, 0x00000000);
766 767
			break;
		case NVDEV_SUBDEV_INSTMEM:
768
			nvkm_mask(device, 0x001714, 0x00000000, 0x00000000);
769 770
			break;
		case NVDEV_ENGINE_IFB:
771
			nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
772 773
			break;
		default:
B
Ben Skeggs 已提交
774
			engine = nvkm_engine(fifo, eu->data2);
775
			if (engine)
776
				engctx = nvkm_engctx_get(engine, inst);
777
			break;
778
		}
779 780
	} else {
		snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
781
	}
782 783

	if (hub) {
784
		ec = nvkm_enum_find(gk104_fifo_fault_hubclient, client);
785
	} else {
786
		ec = nvkm_enum_find(gk104_fifo_fault_gpcclient, client);
787 788 789 790 791 792
		snprintf(gpcid, sizeof(gpcid), "%d", gpc);
	}

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

B
Ben Skeggs 已提交
793
	nv_error(fifo, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
794 795 796 797
		       "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,
798
		 nvkm_client_name(engctx));
799

800 801 802
	object = engctx;
	while (object) {
		switch (nv_mclass(object)) {
803
		case KEPLER_CHANNEL_GPFIFO_A:
804
		case MAXWELL_CHANNEL_GPFIFO_A:
B
Ben Skeggs 已提交
805
			gk104_fifo_recover(fifo, engine, (void *)object);
806 807 808 809 810
			break;
		}
		object = object->parent;
	}

811
	nvkm_engctx_put(engctx);
812 813
}

814
static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = {
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
	{ 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" },
	{}
};
847

848
static void
B
Ben Skeggs 已提交
849
gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit)
850
{
851 852 853 854 855 856
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 mask = nvkm_rd32(device, 0x04010c + (unit * 0x2000));
	u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)) & mask;
	u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000));
	u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000));
	u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff;
857
	u32 subc = (addr & 0x00070000) >> 16;
858
	u32 mthd = (addr & 0x00003ffc);
859 860
	u32 show = stat;

861
	if (stat & 0x00800000) {
B
Ben Skeggs 已提交
862
		if (!gk104_fifo_swmthd(fifo, chid, mthd, data))
863
			show &= ~0x00800000;
864
		nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008);
865 866
	}

867
	if (show) {
B
Ben Skeggs 已提交
868
		nv_error(fifo, "PBDMA%d:", unit);
869
		nvkm_bitfield_print(gk104_fifo_pbdma_intr_0, show);
M
Marcin Slusarz 已提交
870
		pr_cont("\n");
B
Ben Skeggs 已提交
871
		nv_error(fifo,
B
Ben Skeggs 已提交
872
			 "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
873
			 unit, chid,
B
Ben Skeggs 已提交
874
			 nvkm_client_name_for_fifo_chid(&fifo->base, chid),
875
			 subc, mthd, data);
876
	}
877

878
	nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat);
879 880
}

881
static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = {
882 883 884 885 886 887 888 889 890
	{ 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 已提交
891
gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit)
892
{
893 894 895 896
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 mask = nvkm_rd32(device, 0x04014c + (unit * 0x2000));
	u32 stat = nvkm_rd32(device, 0x040148 + (unit * 0x2000)) & mask;
	u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff;
897 898

	if (stat) {
B
Ben Skeggs 已提交
899
		nv_error(fifo, "PBDMA%d:", unit);
900
		nvkm_bitfield_print(gk104_fifo_pbdma_intr_1, stat);
901
		pr_cont("\n");
B
Ben Skeggs 已提交
902
		nv_error(fifo, "PBDMA%d: ch %d %08x %08x\n", unit, chid,
903 904
			 nvkm_rd32(device, 0x040150 + (unit * 0x2000)),
			 nvkm_rd32(device, 0x040154 + (unit * 0x2000)));
905 906
	}

907
	nvkm_wr32(device, 0x040148 + (unit * 0x2000), stat);
908 909
}

B
Ben Skeggs 已提交
910
static void
B
Ben Skeggs 已提交
911
gk104_fifo_intr_runlist(struct gk104_fifo *fifo)
B
Ben Skeggs 已提交
912
{
913 914
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 mask = nvkm_rd32(device, 0x002a00);
B
Ben Skeggs 已提交
915 916
	while (mask) {
		u32 engn = __ffs(mask);
B
Ben Skeggs 已提交
917
		wake_up(&fifo->engine[engn].wait);
918
		nvkm_wr32(device, 0x002a00, 1 << engn);
B
Ben Skeggs 已提交
919 920 921 922
		mask &= ~(1 << engn);
	}
}

B
Ben Skeggs 已提交
923
static void
B
Ben Skeggs 已提交
924
gk104_fifo_intr_engine(struct gk104_fifo *fifo)
B
Ben Skeggs 已提交
925
{
B
Ben Skeggs 已提交
926
	nvkm_fifo_uevent(&fifo->base);
B
Ben Skeggs 已提交
927 928
}

929
static void
930
gk104_fifo_intr(struct nvkm_subdev *subdev)
931
{
B
Ben Skeggs 已提交
932
	struct gk104_fifo *fifo = (void *)subdev;
933 934 935
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 mask = nvkm_rd32(device, 0x002140);
	u32 stat = nvkm_rd32(device, 0x002100) & mask;
936

937
	if (stat & 0x00000001) {
B
Ben Skeggs 已提交
938
		gk104_fifo_intr_bind(fifo);
939
		nvkm_wr32(device, 0x002100, 0x00000001);
940 941 942 943
		stat &= ~0x00000001;
	}

	if (stat & 0x00000010) {
B
Ben Skeggs 已提交
944
		nv_error(fifo, "PIO_ERROR\n");
945
		nvkm_wr32(device, 0x002100, 0x00000010);
946 947 948
		stat &= ~0x00000010;
	}

949
	if (stat & 0x00000100) {
B
Ben Skeggs 已提交
950
		gk104_fifo_intr_sched(fifo);
951
		nvkm_wr32(device, 0x002100, 0x00000100);
952 953 954
		stat &= ~0x00000100;
	}

955
	if (stat & 0x00010000) {
B
Ben Skeggs 已提交
956
		gk104_fifo_intr_chsw(fifo);
957
		nvkm_wr32(device, 0x002100, 0x00010000);
958 959 960 961
		stat &= ~0x00010000;
	}

	if (stat & 0x00800000) {
B
Ben Skeggs 已提交
962
		nv_error(fifo, "FB_FLUSH_TIMEOUT\n");
963
		nvkm_wr32(device, 0x002100, 0x00800000);
964 965 966 967
		stat &= ~0x00800000;
	}

	if (stat & 0x01000000) {
B
Ben Skeggs 已提交
968
		nv_error(fifo, "LB_ERROR\n");
969
		nvkm_wr32(device, 0x002100, 0x01000000);
970 971 972 973
		stat &= ~0x01000000;
	}

	if (stat & 0x08000000) {
B
Ben Skeggs 已提交
974
		gk104_fifo_intr_dropped_fault(fifo);
975
		nvkm_wr32(device, 0x002100, 0x08000000);
976 977 978
		stat &= ~0x08000000;
	}

979
	if (stat & 0x10000000) {
980
		u32 mask = nvkm_rd32(device, 0x00259c);
981 982
		while (mask) {
			u32 unit = __ffs(mask);
B
Ben Skeggs 已提交
983
			gk104_fifo_intr_fault(fifo, unit);
984
			nvkm_wr32(device, 0x00259c, (1 << unit));
985
			mask &= ~(1 << unit);
986 987 988 989 990
		}
		stat &= ~0x10000000;
	}

	if (stat & 0x20000000) {
991
		u32 mask = nvkm_rd32(device, 0x0025a0);
992 993
		while (mask) {
			u32 unit = __ffs(mask);
B
Ben Skeggs 已提交
994 995
			gk104_fifo_intr_pbdma_0(fifo, unit);
			gk104_fifo_intr_pbdma_1(fifo, unit);
996
			nvkm_wr32(device, 0x0025a0, (1 << unit));
997
			mask &= ~(1 << unit);
998 999 1000 1001 1002
		}
		stat &= ~0x20000000;
	}

	if (stat & 0x40000000) {
B
Ben Skeggs 已提交
1003
		gk104_fifo_intr_runlist(fifo);
1004 1005 1006
		stat &= ~0x40000000;
	}

1007
	if (stat & 0x80000000) {
1008
		nvkm_wr32(device, 0x002100, 0x80000000);
B
Ben Skeggs 已提交
1009
		gk104_fifo_intr_engine(fifo);
1010 1011 1012
		stat &= ~0x80000000;
	}

1013
	if (stat) {
B
Ben Skeggs 已提交
1014
		nv_error(fifo, "INTR 0x%08x\n", stat);
1015 1016
		nvkm_mask(device, 0x002140, stat, 0x00000000);
		nvkm_wr32(device, 0x002100, stat);
1017 1018
	}
}
1019

1020
static void
1021
gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index)
1022
{
1023
	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
1024 1025
	struct nvkm_device *device = fifo->engine.subdev.device;
	nvkm_mask(device, 0x002140, 0x80000000, 0x80000000);
1026 1027 1028
}

static void
1029
gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
1030
{
1031
	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
1032 1033
	struct nvkm_device *device = fifo->engine.subdev.device;
	nvkm_mask(device, 0x002140, 0x80000000, 0x00000000);
1034 1035
}

1036
static const struct nvkm_event_func
1037 1038 1039 1040
gk104_fifo_uevent_func = {
	.ctor = nvkm_fifo_uevent_ctor,
	.init = gk104_fifo_uevent_init,
	.fini = gk104_fifo_uevent_fini,
1041 1042
};

1043
int
1044
gk104_fifo_fini(struct nvkm_object *object, bool suspend)
1045
{
B
Ben Skeggs 已提交
1046
	struct gk104_fifo *fifo = (void *)object;
1047
	struct nvkm_device *device = fifo->base.engine.subdev.device;
1048 1049
	int ret;

B
Ben Skeggs 已提交
1050
	ret = nvkm_fifo_fini(&fifo->base, suspend);
1051 1052 1053 1054
	if (ret)
		return ret;

	/* allow mmu fault interrupts, even when we're not using fifo */
1055
	nvkm_mask(device, 0x002140, 0x10000000, 0x10000000);
1056 1057 1058
	return 0;
}

B
Ben Skeggs 已提交
1059
int
1060
gk104_fifo_init(struct nvkm_object *object)
B
Ben Skeggs 已提交
1061
{
B
Ben Skeggs 已提交
1062
	struct gk104_fifo *fifo = (void *)object;
1063
	struct nvkm_device *device = fifo->base.engine.subdev.device;
B
Ben Skeggs 已提交
1064 1065
	int ret, i;

B
Ben Skeggs 已提交
1066
	ret = nvkm_fifo_init(&fifo->base);
B
Ben Skeggs 已提交
1067 1068 1069
	if (ret)
		return ret;

B
Ben Skeggs 已提交
1070
	/* enable all available PBDMA units */
1071 1072
	nvkm_wr32(device, 0x000204, 0xffffffff);
	fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x000204));
B
Ben Skeggs 已提交
1073
	nv_debug(fifo, "%d PBDMA unit(s)\n", fifo->spoon_nr);
B
Ben Skeggs 已提交
1074

B
Ben Skeggs 已提交
1075
	/* PBDMA[n] */
B
Ben Skeggs 已提交
1076
	for (i = 0; i < fifo->spoon_nr; i++) {
1077 1078 1079
		nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
		nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
		nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
B
Ben Skeggs 已提交
1080 1081
	}

1082
	/* PBDMA[n].HCE */
B
Ben Skeggs 已提交
1083
	for (i = 0; i < fifo->spoon_nr; i++) {
1084 1085
		nvkm_wr32(device, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
		nvkm_wr32(device, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
1086 1087
	}

1088
	nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12);
B
Ben Skeggs 已提交
1089

1090 1091
	nvkm_wr32(device, 0x002100, 0xffffffff);
	nvkm_wr32(device, 0x002140, 0x7fffffff);
B
Ben Skeggs 已提交
1092 1093 1094 1095
	return 0;
}

void
1096
gk104_fifo_dtor(struct nvkm_object *object)
B
Ben Skeggs 已提交
1097
{
B
Ben Skeggs 已提交
1098
	struct gk104_fifo *fifo = (void *)object;
B
Ben Skeggs 已提交
1099 1100
	int i;

B
Ben Skeggs 已提交
1101 1102
	nvkm_gpuobj_unmap(&fifo->user.bar);
	nvkm_gpuobj_ref(NULL, &fifo->user.mem);
B
Ben Skeggs 已提交
1103 1104

	for (i = 0; i < FIFO_ENGINE_NR; i++) {
B
Ben Skeggs 已提交
1105 1106
		nvkm_gpuobj_ref(NULL, &fifo->engine[i].runlist[1]);
		nvkm_gpuobj_ref(NULL, &fifo->engine[i].runlist[0]);
B
Ben Skeggs 已提交
1107 1108
	}

B
Ben Skeggs 已提交
1109
	nvkm_fifo_destroy(&fifo->base);
B
Ben Skeggs 已提交
1110 1111 1112
}

int
1113 1114 1115
gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
		struct nvkm_oclass *oclass, void *data, u32 size,
		struct nvkm_object **pobject)
1116
{
1117
	struct gk104_fifo_impl *impl = (void *)oclass;
B
Ben Skeggs 已提交
1118
	struct gk104_fifo *fifo;
1119
	int ret, i;
1120

1121
	ret = nvkm_fifo_create(parent, engine, oclass, 0,
B
Ben Skeggs 已提交
1122 1123
			       impl->channels - 1, &fifo);
	*pobject = nv_object(fifo);
1124 1125 1126
	if (ret)
		return ret;

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

1129
	for (i = 0; i < FIFO_ENGINE_NR; i++) {
B
Ben Skeggs 已提交
1130 1131
		ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x8000, 0x1000,
				      0, &fifo->engine[i].runlist[0]);
1132 1133 1134
		if (ret)
			return ret;

B
Ben Skeggs 已提交
1135 1136
		ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x8000, 0x1000,
				      0, &fifo->engine[i].runlist[1]);
1137 1138
		if (ret)
			return ret;
B
Ben Skeggs 已提交
1139

B
Ben Skeggs 已提交
1140
		init_waitqueue_head(&fifo->engine[i].wait);
1141 1142
	}

B
Ben Skeggs 已提交
1143 1144
	ret = nvkm_gpuobj_new(nv_object(fifo), NULL, impl->channels * 0x200,
			      0x1000, NVOBJ_FLAG_ZERO_ALLOC, &fifo->user.mem);
1145 1146 1147
	if (ret)
		return ret;

B
Ben Skeggs 已提交
1148 1149
	ret = nvkm_gpuobj_map(fifo->user.mem, NV_MEM_ACCESS_RW,
			      &fifo->user.bar);
1150 1151 1152
	if (ret)
		return ret;

B
Ben Skeggs 已提交
1153
	ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &fifo->base.uevent);
1154 1155
	if (ret)
		return ret;
1156

B
Ben Skeggs 已提交
1157 1158 1159 1160
	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;
1161 1162 1163
	return 0;
}

1164 1165
struct nvkm_oclass *
gk104_fifo_oclass = &(struct gk104_fifo_impl) {
B
Ben Skeggs 已提交
1166
	.base.handle = NV_ENGINE(FIFO, 0xe0),
1167 1168 1169 1170 1171
	.base.ofuncs = &(struct nvkm_ofuncs) {
		.ctor = gk104_fifo_ctor,
		.dtor = gk104_fifo_dtor,
		.init = gk104_fifo_init,
		.fini = gk104_fifo_fini,
1172
	},
B
Ben Skeggs 已提交
1173 1174
	.channels = 4096,
}.base;