gf100.c 17.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 25
#include "gf100.h"
#include "changf100.h"
26

27 28
#include <core/client.h>
#include <core/enum.h>
29
#include <core/gpuobj.h>
30
#include <subdev/bar.h>
31
#include <engine/sw.h>
32

33
#include <nvif/class.h>
34

35
static void
36
gf100_fifo_uevent_init(struct nvkm_fifo *fifo)
37 38 39 40
{
	struct nvkm_device *device = fifo->engine.subdev.device;
	nvkm_mask(device, 0x002140, 0x80000000, 0x80000000);
}
41

42
static void
43
gf100_fifo_uevent_fini(struct nvkm_fifo *fifo)
44 45 46 47
{
	struct nvkm_device *device = fifo->engine.subdev.device;
	nvkm_mask(device, 0x002140, 0x80000000, 0x00000000);
}
48

49
void
50
gf100_fifo_runlist_commit(struct gf100_fifo *fifo)
51
{
52
	struct gf100_fifo_chan *chan;
53 54
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
55
	struct nvkm_memory *cur;
56
	int nr = 0;
57

58
	mutex_lock(&subdev->mutex);
B
Ben Skeggs 已提交
59 60
	cur = fifo->runlist.mem[fifo->runlist.active];
	fifo->runlist.active = !fifo->runlist.active;
61

62
	nvkm_kmap(cur);
63 64 65 66
	list_for_each_entry(chan, &fifo->chan, head) {
		nvkm_wo32(cur, (nr * 8) + 0, chan->base.chid);
		nvkm_wo32(cur, (nr * 8) + 4, 0x00000004);
		nr++;
67
	}
68
	nvkm_done(cur);
69

70
	nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12);
71
	nvkm_wr32(device, 0x002274, 0x01f00000 | nr);
72

B
Ben Skeggs 已提交
73
	if (wait_event_timeout(fifo->runlist.wait,
74
			       !(nvkm_rd32(device, 0x00227c) & 0x00100000),
75
			       msecs_to_jiffies(2000)) == 0)
76
		nvkm_error(subdev, "runlist update timeout\n");
77
	mutex_unlock(&subdev->mutex);
78
}
79

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
void
gf100_fifo_runlist_remove(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan)
{
	mutex_lock(&fifo->base.engine.subdev.mutex);
	list_del_init(&chan->head);
	mutex_unlock(&fifo->base.engine.subdev.mutex);
}

void
gf100_fifo_runlist_insert(struct gf100_fifo *fifo, struct gf100_fifo_chan *chan)
{
	mutex_lock(&fifo->base.engine.subdev.mutex);
	list_add_tail(&chan->head, &fifo->chan);
	mutex_unlock(&fifo->base.engine.subdev.mutex);
}

96
static inline int
B
Ben Skeggs 已提交
97
gf100_fifo_engidx(struct gf100_fifo *fifo, u32 engn)
98 99
{
	switch (engn) {
100 101 102 103 104 105
	case NVKM_ENGINE_GR    : engn = 0; break;
	case NVKM_ENGINE_MSVLD : engn = 1; break;
	case NVKM_ENGINE_MSPPP : engn = 2; break;
	case NVKM_ENGINE_MSPDEC: engn = 3; break;
	case NVKM_ENGINE_CE0   : engn = 4; break;
	case NVKM_ENGINE_CE1   : engn = 5; break;
106 107 108 109 110 111 112
	default:
		return -1;
	}

	return engn;
}

113
static inline struct nvkm_engine *
B
Ben Skeggs 已提交
114
gf100_fifo_engine(struct gf100_fifo *fifo, u32 engn)
115
{
116 117
	struct nvkm_device *device = fifo->base.engine.subdev.device;

118
	switch (engn) {
119 120 121 122 123 124
	case 0: engn = NVKM_ENGINE_GR; break;
	case 1: engn = NVKM_ENGINE_MSVLD; break;
	case 2: engn = NVKM_ENGINE_MSPPP; break;
	case 3: engn = NVKM_ENGINE_MSPDEC; break;
	case 4: engn = NVKM_ENGINE_CE0; break;
	case 5: engn = NVKM_ENGINE_CE1; break;
125 126 127 128
	default:
		return NULL;
	}

129
	return nvkm_device_engine(device, engn);
130 131 132
}

static void
133
gf100_fifo_recover_work(struct work_struct *work)
134
{
B
Ben Skeggs 已提交
135
	struct gf100_fifo *fifo = container_of(work, typeof(*fifo), fault);
136
	struct nvkm_device *device = fifo->base.engine.subdev.device;
137
	struct nvkm_engine *engine;
138 139 140 141
	unsigned long flags;
	u32 engn, engm = 0;
	u64 mask, todo;

B
Ben Skeggs 已提交
142 143 144 145
	spin_lock_irqsave(&fifo->base.lock, flags);
	mask = fifo->mask;
	fifo->mask = 0ULL;
	spin_unlock_irqrestore(&fifo->base.lock, flags);
146 147

	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
B
Ben Skeggs 已提交
148
		engm |= 1 << gf100_fifo_engidx(fifo, engn);
149
	nvkm_mask(device, 0x002630, engm, engm);
150 151

	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
152 153 154
		if ((engine = nvkm_device_engine(device, engn))) {
			nvkm_subdev_fini(&engine->subdev, false);
			WARN_ON(nvkm_subdev_init(&engine->subdev));
155 156 157
		}
	}

158
	gf100_fifo_runlist_commit(fifo);
159 160
	nvkm_wr32(device, 0x00262c, engm);
	nvkm_mask(device, 0x002630, engm, 0x00000000);
161 162 163
}

static void
B
Ben Skeggs 已提交
164
gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine,
165
		   struct gf100_fifo_chan *chan)
166
{
167 168
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
169 170
	u32 chid = chan->base.chid;

171
	nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n",
172
		   nvkm_subdev_name[engine->subdev.index], chid);
173
	assert_spin_locked(&fifo->base.lock);
174

175
	nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000);
176 177
	list_del_init(&chan->head);
	chan->killed = true;
178

179
	fifo->mask |= 1ULL << engine->subdev.index;
B
Ben Skeggs 已提交
180
	schedule_work(&fifo->fault);
181 182
}

183 184
static const struct nvkm_enum
gf100_fifo_sched_reason[] = {
B
Ben Skeggs 已提交
185 186 187 188
	{ 0x0a, "CTXSW_TIMEOUT" },
	{}
};

189
static void
B
Ben Skeggs 已提交
190
gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo)
191
{
192
	struct nvkm_device *device = fifo->base.engine.subdev.device;
193 194
	struct nvkm_engine *engine;
	struct gf100_fifo_chan *chan;
195
	unsigned long flags;
196 197
	u32 engn;

198
	spin_lock_irqsave(&fifo->base.lock, flags);
199
	for (engn = 0; engn < 6; engn++) {
200
		u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04));
201 202 203 204 205 206 207 208
		u32 busy = (stat & 0x80000000);
		u32 save = (stat & 0x00100000); /* maybe? */
		u32 unk0 = (stat & 0x00040000);
		u32 unk1 = (stat & 0x00001000);
		u32 chid = (stat & 0x0000007f);
		(void)save;

		if (busy && unk0 && unk1) {
209 210 211 212 213 214 215 216 217
			list_for_each_entry(chan, &fifo->chan, head) {
				if (chan->base.chid == chid) {
					engine = gf100_fifo_engine(fifo, engn);
					if (!engine)
						break;
					gf100_fifo_recover(fifo, engine, chan);
					break;
				}
			}
218 219
		}
	}
220
	spin_unlock_irqrestore(&fifo->base.lock, flags);
221 222
}

B
Ben Skeggs 已提交
223
static void
B
Ben Skeggs 已提交
224
gf100_fifo_intr_sched(struct gf100_fifo *fifo)
B
Ben Skeggs 已提交
225
{
226 227
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
228
	u32 intr = nvkm_rd32(device, 0x00254c);
B
Ben Skeggs 已提交
229
	u32 code = intr & 0x000000ff;
230
	const struct nvkm_enum *en;
B
Ben Skeggs 已提交
231

232
	en = nvkm_enum_find(gf100_fifo_sched_reason, code);
B
Ben Skeggs 已提交
233

234
	nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : "");
235 236 237

	switch (code) {
	case 0x0a:
B
Ben Skeggs 已提交
238
		gf100_fifo_intr_sched_ctxsw(fifo);
239 240 241 242
		break;
	default:
		break;
	}
B
Ben Skeggs 已提交
243 244
}

245 246
static const struct nvkm_enum
gf100_fifo_fault_engine[] = {
247 248 249 250 251 252 253
	{ 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR },
	{ 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB },
	{ 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
	{ 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM },
	{ 0x07, "PFIFO", NULL, NVKM_ENGINE_FIFO },
	{ 0x10, "PMSVLD", NULL, NVKM_ENGINE_MSVLD },
	{ 0x11, "PMSPPP", NULL, NVKM_ENGINE_MSPPP },
B
Ben Skeggs 已提交
254
	{ 0x13, "PCOUNTER" },
255 256 257
	{ 0x14, "PMSPDEC", NULL, NVKM_ENGINE_MSPDEC },
	{ 0x15, "PCE0", NULL, NVKM_ENGINE_CE0 },
	{ 0x16, "PCE1", NULL, NVKM_ENGINE_CE1 },
B
Ben Skeggs 已提交
258
	{ 0x17, "PDAEMON" },
259 260 261
	{}
};

262 263
static const struct nvkm_enum
gf100_fifo_fault_reason[] = {
B
Ben Skeggs 已提交
264 265 266 267 268 269 270 271 272
	{ 0x00, "PT_NOT_PRESENT" },
	{ 0x01, "PT_TOO_SHORT" },
	{ 0x02, "PAGE_NOT_PRESENT" },
	{ 0x03, "VM_LIMIT_EXCEEDED" },
	{ 0x04, "NO_CHANNEL" },
	{ 0x05, "PAGE_SYSTEM_ONLY" },
	{ 0x06, "PAGE_READ_ONLY" },
	{ 0x0a, "COMPRESSED_SYSRAM" },
	{ 0x0c, "INVALID_STORAGE_TYPE" },
273 274 275
	{}
};

276 277
static const struct nvkm_enum
gf100_fifo_fault_hubclient[] = {
278 279 280 281 282 283 284 285
	{ 0x01, "PCOPY0" },
	{ 0x02, "PCOPY1" },
	{ 0x04, "DISPATCH" },
	{ 0x05, "CTXCTL" },
	{ 0x06, "PFIFO" },
	{ 0x07, "BAR_READ" },
	{ 0x08, "BAR_WRITE" },
	{ 0x0b, "PVP" },
286
	{ 0x0c, "PMSPPP" },
287
	{ 0x0d, "PMSVLD" },
288 289 290 291 292 293 294
	{ 0x11, "PCOUNTER" },
	{ 0x12, "PDAEMON" },
	{ 0x14, "CCACHE" },
	{ 0x15, "CCACHE_POST" },
	{}
};

295 296
static const struct nvkm_enum
gf100_fifo_fault_gpcclient[] = {
297 298 299 300 301 302 303
	{ 0x01, "TEX" },
	{ 0x0c, "ESETUP" },
	{ 0x0e, "CTXCTL" },
	{ 0x0f, "PROP" },
	{}
};

304
static void
B
Ben Skeggs 已提交
305
gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit)
306
{
307 308
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
309 310 311 312
	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));
313
	u32 gpc    = (stat & 0x1f000000) >> 24;
314
	u32 client = (stat & 0x00001f00) >> 8;
315 316 317
	u32 write  = (stat & 0x00000080);
	u32 hub    = (stat & 0x00000040);
	u32 reason = (stat & 0x0000000f);
318
	const struct nvkm_enum *er, *eu, *ec;
319 320 321
	struct nvkm_engine *engine = NULL;
	struct nvkm_fifo_chan *chan;
	unsigned long flags;
322
	char gpcid[8] = "";
323

324 325
	er = nvkm_enum_find(gf100_fifo_fault_reason, reason);
	eu = nvkm_enum_find(gf100_fifo_fault_engine, unit);
326 327 328 329 330 331 332
	if (hub) {
		ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client);
	} else {
		ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client);
		snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc);
	}

333
	if (eu) {
334
		switch (eu->data2) {
335
		case NVKM_SUBDEV_BAR:
336
			nvkm_mask(device, 0x001704, 0x00000000, 0x00000000);
337
			break;
338
		case NVKM_SUBDEV_INSTMEM:
339
			nvkm_mask(device, 0x001714, 0x00000000, 0x00000000);
340
			break;
341
		case NVKM_ENGINE_IFB:
342
			nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
343 344
			break;
		default:
345
			engine = nvkm_device_engine(device, eu->data2);
346
			break;
347
		}
348
	}
349

350 351
	chan = nvkm_fifo_chan_inst(&fifo->base, (u64)inst << 12, &flags);

352 353 354 355 356
	nvkm_error(subdev,
		   "%s fault at %010llx engine %02x [%s] client %02x [%s%s] "
		   "reason %02x [%s] on channel %d [%010llx %s]\n",
		   write ? "write" : "read", (u64)vahi << 32 | valo,
		   unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "",
357
		   reason, er ? er->name : "", chan ? chan->chid : -1,
358 359
		   (u64)inst << 12,
		   chan ? chan->object.client->name : "unknown");
360

361 362 363
	if (engine && chan)
		gf100_fifo_recover(fifo, engine, (void *)chan);
	nvkm_fifo_chan_put(&fifo->base, flags, &chan);
364 365
}

366 367
static const struct nvkm_bitfield
gf100_fifo_pbdma_intr[] = {
368 369 370 371 372
/*	{ 0x00008000, "" }	seen with null ib push */
	{ 0x00200000, "ILLEGAL_MTHD" },
	{ 0x00800000, "EMPTY_SUBC" },
	{}
};
373

374
static void
B
Ben Skeggs 已提交
375
gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit)
376
{
377 378
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
379 380 381 382
	u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000));
	u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000));
	u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000));
	u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0x7f;
383
	u32 subc = (addr & 0x00070000) >> 16;
384
	u32 mthd = (addr & 0x00003ffc);
385 386
	struct nvkm_fifo_chan *chan;
	unsigned long flags;
387 388
	u32 show= stat;
	char msg[128];
389

390
	if (stat & 0x00800000) {
391 392 393 394
		if (device->sw) {
			if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data))
				show &= ~0x00800000;
		}
395 396
	}

397
	if (show) {
398
		nvkm_snprintbf(msg, sizeof(msg), gf100_fifo_pbdma_intr, show);
399 400 401 402 403
		chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags);
		nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] "
				   "subc %d mthd %04x data %08x\n",
			   unit, show, msg, chid, chan ? chan->inst->addr : 0,
			   chan ? chan->object.client->name : "unknown",
404
			   subc, mthd, data);
405
		nvkm_fifo_chan_put(&fifo->base, flags, &chan);
406
	}
407

408 409
	nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008);
	nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat);
410 411
}

B
Ben Skeggs 已提交
412
static void
B
Ben Skeggs 已提交
413
gf100_fifo_intr_runlist(struct gf100_fifo *fifo)
B
Ben Skeggs 已提交
414
{
415 416
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
417
	u32 intr = nvkm_rd32(device, 0x002a00);
B
Ben Skeggs 已提交
418 419

	if (intr & 0x10000000) {
B
Ben Skeggs 已提交
420
		wake_up(&fifo->runlist.wait);
421
		nvkm_wr32(device, 0x002a00, 0x10000000);
B
Ben Skeggs 已提交
422 423 424 425
		intr &= ~0x10000000;
	}

	if (intr) {
426
		nvkm_error(subdev, "RUNLIST %08x\n", intr);
427
		nvkm_wr32(device, 0x002a00, intr);
B
Ben Skeggs 已提交
428 429 430
	}
}

B
Ben Skeggs 已提交
431
static void
B
Ben Skeggs 已提交
432
gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn)
B
Ben Skeggs 已提交
433
{
434 435
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
436 437
	u32 intr = nvkm_rd32(device, 0x0025a8 + (engn * 0x04));
	u32 inte = nvkm_rd32(device, 0x002628);
B
Ben Skeggs 已提交
438 439
	u32 unkn;

440
	nvkm_wr32(device, 0x0025a8 + (engn * 0x04), intr);
441

B
Ben Skeggs 已提交
442 443 444
	for (unkn = 0; unkn < 8; unkn++) {
		u32 ints = (intr >> (unkn * 0x04)) & inte;
		if (ints & 0x1) {
B
Ben Skeggs 已提交
445
			nvkm_fifo_uevent(&fifo->base);
B
Ben Skeggs 已提交
446 447 448
			ints &= ~1;
		}
		if (ints) {
449 450
			nvkm_error(subdev, "ENGINE %d %d %01x",
				   engn, unkn, ints);
451
			nvkm_mask(device, 0x002628, ints, 0);
B
Ben Skeggs 已提交
452 453 454 455
		}
	}
}

456
void
B
Ben Skeggs 已提交
457
gf100_fifo_intr_engine(struct gf100_fifo *fifo)
B
Ben Skeggs 已提交
458
{
459 460
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	u32 mask = nvkm_rd32(device, 0x0025a4);
B
Ben Skeggs 已提交
461 462
	while (mask) {
		u32 unit = __ffs(mask);
B
Ben Skeggs 已提交
463
		gf100_fifo_intr_engine_unit(fifo, unit);
B
Ben Skeggs 已提交
464 465 466 467
		mask &= ~(1 << unit);
	}
}

468
static void
469
gf100_fifo_intr(struct nvkm_fifo *base)
470
{
471 472 473
	struct gf100_fifo *fifo = gf100_fifo(base);
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
474 475
	u32 mask = nvkm_rd32(device, 0x002140);
	u32 stat = nvkm_rd32(device, 0x002100) & mask;
476

477
	if (stat & 0x00000001) {
478
		u32 intr = nvkm_rd32(device, 0x00252c);
479
		nvkm_warn(subdev, "INTR 00000001: %08x\n", intr);
480
		nvkm_wr32(device, 0x002100, 0x00000001);
481 482 483
		stat &= ~0x00000001;
	}

484
	if (stat & 0x00000100) {
B
Ben Skeggs 已提交
485
		gf100_fifo_intr_sched(fifo);
486
		nvkm_wr32(device, 0x002100, 0x00000100);
487 488 489
		stat &= ~0x00000100;
	}

490
	if (stat & 0x00010000) {
491
		u32 intr = nvkm_rd32(device, 0x00256c);
492
		nvkm_warn(subdev, "INTR 00010000: %08x\n", intr);
493
		nvkm_wr32(device, 0x002100, 0x00010000);
494 495 496 497
		stat &= ~0x00010000;
	}

	if (stat & 0x01000000) {
498
		u32 intr = nvkm_rd32(device, 0x00258c);
499
		nvkm_warn(subdev, "INTR 01000000: %08x\n", intr);
500
		nvkm_wr32(device, 0x002100, 0x01000000);
501 502 503
		stat &= ~0x01000000;
	}

504
	if (stat & 0x10000000) {
505
		u32 mask = nvkm_rd32(device, 0x00259c);
506 507
		while (mask) {
			u32 unit = __ffs(mask);
B
Ben Skeggs 已提交
508
			gf100_fifo_intr_fault(fifo, unit);
509
			nvkm_wr32(device, 0x00259c, (1 << unit));
510
			mask &= ~(1 << unit);
511 512 513 514 515
		}
		stat &= ~0x10000000;
	}

	if (stat & 0x20000000) {
516
		u32 mask = nvkm_rd32(device, 0x0025a0);
517 518
		while (mask) {
			u32 unit = __ffs(mask);
B
Ben Skeggs 已提交
519
			gf100_fifo_intr_pbdma(fifo, unit);
520
			nvkm_wr32(device, 0x0025a0, (1 << unit));
521
			mask &= ~(1 << unit);
522 523 524 525
		}
		stat &= ~0x20000000;
	}

526
	if (stat & 0x40000000) {
B
Ben Skeggs 已提交
527
		gf100_fifo_intr_runlist(fifo);
528 529 530
		stat &= ~0x40000000;
	}

531
	if (stat & 0x80000000) {
B
Ben Skeggs 已提交
532
		gf100_fifo_intr_engine(fifo);
533 534 535
		stat &= ~0x80000000;
	}

536
	if (stat) {
537
		nvkm_error(subdev, "INTR %08x\n", stat);
538 539
		nvkm_mask(device, 0x002140, stat, 0x00000000);
		nvkm_wr32(device, 0x002100, stat);
540 541
	}
}
542

543
static int
544
gf100_fifo_oneinit(struct nvkm_fifo *base)
545
{
546 547 548
	struct gf100_fifo *fifo = gf100_fifo(base);
	struct nvkm_device *device = fifo->base.engine.subdev.device;
	int ret;
549

550 551 552 553 554 555 556
	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000,
			      false, &fifo->runlist.mem[0]);
	if (ret)
		return ret;

	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000,
			      false, &fifo->runlist.mem[1]);
557 558 559
	if (ret)
		return ret;

560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
	init_waitqueue_head(&fifo->runlist.wait);

	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 0x1000,
			      0x1000, false, &fifo->user.mem);
	if (ret)
		return ret;

	ret = nvkm_bar_umap(device->bar, 128 * 0x1000, 12, &fifo->user.bar);
	if (ret)
		return ret;

	nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0);
	return 0;
}

static void
gf100_fifo_fini(struct nvkm_fifo *base)
{
	struct gf100_fifo *fifo = gf100_fifo(base);
	flush_work(&fifo->fault);
}

static void
gf100_fifo_init(struct nvkm_fifo *base)
{
	struct gf100_fifo *fifo = gf100_fifo(base);
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
	int i;

590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
	nvkm_wr32(device, 0x000204, 0xffffffff);
	nvkm_wr32(device, 0x002204, 0xffffffff);

	fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x002204));
	nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr);

	/* assign engines to PBDMAs */
	if (fifo->spoon_nr >= 3) {
		nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */
		nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */
		nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */
		nvkm_wr32(device, 0x002214, ~(1 << 1)); /* PMSVLD */
		nvkm_wr32(device, 0x002218, ~(1 << 2)); /* PCE0 */
		nvkm_wr32(device, 0x00221c, ~(1 << 1)); /* PCE1 */
	}

	/* PBDMA[n] */
	for (i = 0; i < fifo->spoon_nr; i++) {
		nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
		nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
		nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
	}

	nvkm_mask(device, 0x002200, 0x00000001, 0x00000001);
	nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12);

	nvkm_wr32(device, 0x002100, 0xffffffff);
	nvkm_wr32(device, 0x002140, 0x7fffffff);
	nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
619 620
}

621 622
static void *
gf100_fifo_dtor(struct nvkm_fifo *base)
623
{
624
	struct gf100_fifo *fifo = gf100_fifo(base);
625 626 627 628
	nvkm_vm_put(&fifo->user.bar);
	nvkm_memory_del(&fifo->user.mem);
	nvkm_memory_del(&fifo->runlist.mem[0]);
	nvkm_memory_del(&fifo->runlist.mem[1]);
629
	return fifo;
630
}
631

632
static const struct nvkm_fifo_func
633 634 635 636 637 638 639 640
gf100_fifo = {
	.dtor = gf100_fifo_dtor,
	.oneinit = gf100_fifo_oneinit,
	.init = gf100_fifo_init,
	.fini = gf100_fifo_fini,
	.intr = gf100_fifo_intr,
	.uevent_init = gf100_fifo_uevent_init,
	.uevent_fini = gf100_fifo_uevent_fini,
641 642 643 644 645 646
	.chan = {
		&gf100_fifo_gpfifo_oclass,
		NULL
	},
};

647 648
int
gf100_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo)
649
{
B
Ben Skeggs 已提交
650
	struct gf100_fifo *fifo;
651

652 653
	if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
		return -ENOMEM;
654
	INIT_LIST_HEAD(&fifo->chan);
B
Ben Skeggs 已提交
655
	INIT_WORK(&fifo->fault, gf100_fifo_recover_work);
656
	*pfifo = &fifo->base;
657

658
	return nvkm_fifo_ctor(&gf100_fifo, device, index, 128, &fifo->base);
659
}