nv50.c 26.5 KB
Newer Older
1
/*
2
 * Copyright 2012 Red Hat Inc.
3
 *
4 5 6 7 8 9
 * 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:
10
 *
11 12
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
13
 *
14 15 16 17 18 19 20
 * 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.
21
 *
22
 * Authors: Ben Skeggs
23
 */
24
#include "nv50.h"
25

26
#include <core/client.h>
27
#include <core/handle.h>
28
#include <engine/fifo.h>
29
#include <subdev/timer.h>
30

B
Ben Skeggs 已提交
31
struct nv50_gr {
32
	struct nvkm_gr base;
33 34 35
	spinlock_t lock;
	u32 size;
};
36

37
struct nv50_gr_chan {
38
	struct nvkm_gr_chan base;
39
};
40

41
static u64
42
nv50_gr_units(struct nvkm_gr *gr)
43
{
B
Ben Skeggs 已提交
44
	return nv_rd32(gr, 0x1540);
45 46
}

47 48 49
/*******************************************************************************
 * Graphics object classes
 ******************************************************************************/
50

51
static int
52 53 54
nv50_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
		    struct nvkm_oclass *oclass, void *data, u32 size,
		    struct nvkm_object **pobject)
55
{
56
	struct nvkm_gpuobj *obj;
57
	int ret;
58

59 60
	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
				 16, 16, 0, &obj);
61 62 63
	*pobject = nv_object(obj);
	if (ret)
		return ret;
64

65 66 67 68
	nv_wo32(obj, 0x00, nv_mclass(obj));
	nv_wo32(obj, 0x04, 0x00000000);
	nv_wo32(obj, 0x08, 0x00000000);
	nv_wo32(obj, 0x0c, 0x00000000);
69 70 71
	return 0;
}

72
static struct nvkm_ofuncs
73 74
nv50_gr_ofuncs = {
	.ctor = nv50_gr_object_ctor,
75 76 77 78 79
	.dtor = _nvkm_gpuobj_dtor,
	.init = _nvkm_gpuobj_init,
	.fini = _nvkm_gpuobj_fini,
	.rd32 = _nvkm_gpuobj_rd32,
	.wr32 = _nvkm_gpuobj_wr32,
80
};
81

82
static struct nvkm_oclass
83 84 85 86 87 88
nv50_gr_sclass[] = {
	{ 0x0030, &nv50_gr_ofuncs },
	{ 0x502d, &nv50_gr_ofuncs },
	{ 0x5039, &nv50_gr_ofuncs },
	{ 0x5097, &nv50_gr_ofuncs },
	{ 0x50c0, &nv50_gr_ofuncs },
89 90
	{}
};
91

92 93
static struct nvkm_oclass
g84_gr_sclass[] = {
94 95 96 97 98
	{ 0x0030, &nv50_gr_ofuncs },
	{ 0x502d, &nv50_gr_ofuncs },
	{ 0x5039, &nv50_gr_ofuncs },
	{ 0x50c0, &nv50_gr_ofuncs },
	{ 0x8297, &nv50_gr_ofuncs },
99 100
	{}
};
101

102 103
static struct nvkm_oclass
gt200_gr_sclass[] = {
104 105 106 107 108
	{ 0x0030, &nv50_gr_ofuncs },
	{ 0x502d, &nv50_gr_ofuncs },
	{ 0x5039, &nv50_gr_ofuncs },
	{ 0x50c0, &nv50_gr_ofuncs },
	{ 0x8397, &nv50_gr_ofuncs },
109 110
	{}
};
111

112 113
static struct nvkm_oclass
gt215_gr_sclass[] = {
114 115 116 117 118 119
	{ 0x0030, &nv50_gr_ofuncs },
	{ 0x502d, &nv50_gr_ofuncs },
	{ 0x5039, &nv50_gr_ofuncs },
	{ 0x50c0, &nv50_gr_ofuncs },
	{ 0x8597, &nv50_gr_ofuncs },
	{ 0x85c0, &nv50_gr_ofuncs },
120 121
	{}
};
122

123 124
static struct nvkm_oclass
mcp89_gr_sclass[] = {
125 126 127 128 129 130
	{ 0x0030, &nv50_gr_ofuncs },
	{ 0x502d, &nv50_gr_ofuncs },
	{ 0x5039, &nv50_gr_ofuncs },
	{ 0x50c0, &nv50_gr_ofuncs },
	{ 0x85c0, &nv50_gr_ofuncs },
	{ 0x8697, &nv50_gr_ofuncs },
131 132
	{}
};
133

134 135 136
/*******************************************************************************
 * PGRAPH context
 ******************************************************************************/
137 138

static int
139 140 141
nv50_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
		     struct nvkm_oclass *oclass, void *data, u32 size,
		     struct nvkm_object **pobject)
142
{
B
Ben Skeggs 已提交
143
	struct nv50_gr *gr = (void *)engine;
144
	struct nv50_gr_chan *chan;
145 146
	int ret;

B
Ben Skeggs 已提交
147
	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, gr->size,
148
				     0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
149
	*pobject = nv_object(chan);
150 151 152
	if (ret)
		return ret;

B
Ben Skeggs 已提交
153
	nv50_grctx_fill(nv_device(gr), nv_gpuobj(chan));
154
	return 0;
155 156
}

157
static struct nvkm_oclass
158
nv50_gr_cclass = {
159
	.handle = NV_ENGCTX(GR, 0x50),
160
	.ofuncs = &(struct nvkm_ofuncs) {
161
		.ctor = nv50_gr_context_ctor,
162 163 164 165 166
		.dtor = _nvkm_gr_context_dtor,
		.init = _nvkm_gr_context_init,
		.fini = _nvkm_gr_context_fini,
		.rd32 = _nvkm_gr_context_rd32,
		.wr32 = _nvkm_gr_context_wr32,
167 168 169 170 171 172 173
	},
};

/*******************************************************************************
 * PGRAPH engine/subdev functions
 ******************************************************************************/

B
Ben Skeggs 已提交
174
static const struct nvkm_bitfield nv50_gr_status[] = {
175 176 177 178 179 180 181 182 183 184
	{ 0x00000001, "BUSY" }, /* set when any bit is set */
	{ 0x00000002, "DISPATCH" },
	{ 0x00000004, "UNK2" },
	{ 0x00000008, "UNK3" },
	{ 0x00000010, "UNK4" },
	{ 0x00000020, "UNK5" },
	{ 0x00000040, "M2MF" },
	{ 0x00000080, "UNK7" },
	{ 0x00000100, "CTXPROG" },
	{ 0x00000200, "VFETCH" },
185 186 187 188 189
	{ 0x00000400, "CCACHE_PREGEOM" },
	{ 0x00000800, "STRMOUT_VATTR_POSTGEOM" },
	{ 0x00001000, "VCLIP" },
	{ 0x00002000, "RATTR_APLANE" },
	{ 0x00004000, "TRAST" },
190 191 192
	{ 0x00008000, "CLIPID" },
	{ 0x00010000, "ZCULL" },
	{ 0x00020000, "ENG2D" },
193 194 195 196 197 198
	{ 0x00040000, "RMASK" },
	{ 0x00080000, "TPC_RAST" },
	{ 0x00100000, "TPC_PROP" },
	{ 0x00200000, "TPC_TEX" },
	{ 0x00400000, "TPC_GEOM" },
	{ 0x00800000, "TPC_MP" },
199 200 201 202
	{ 0x01000000, "ROP" },
	{}
};

B
Ben Skeggs 已提交
203
static const char *const nv50_gr_vstatus_0[] = {
204 205
	"VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP",
	NULL
206 207
};

B
Ben Skeggs 已提交
208
static const char *const nv50_gr_vstatus_1[] = {
209
	"TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL
210 211
};

B
Ben Skeggs 已提交
212
static const char *const nv50_gr_vstatus_2[] = {
213
	"RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK",
214 215 216
	"ROP", NULL
};

217
static void
B
Ben Skeggs 已提交
218
nvkm_gr_vstatus_print(struct nv50_gr *gr, int r,
219
		       const char *const units[], u32 status)
220 221 222
{
	int i;

B
Ben Skeggs 已提交
223
	nv_error(gr, "PGRAPH_VSTATUS%d: 0x%08x", r, status);
224 225 226 227 228 229 230 231 232 233 234

	for (i = 0; units[i] && status; i++) {
		if ((status & 7) == 1)
			pr_cont(" %s", units[i]);
		status >>= 3;
	}
	if (status)
		pr_cont(" (invalid: 0x%x)", status);
	pr_cont("\n");
}

235
static int
236
g84_gr_tlb_flush(struct nvkm_engine *engine)
237
{
B
Ben Skeggs 已提交
238
	struct nvkm_timer *tmr = nvkm_timer(engine);
B
Ben Skeggs 已提交
239
	struct nv50_gr *gr = (void *)engine;
240 241 242 243 244
	bool idle, timeout = false;
	unsigned long flags;
	u64 start;
	u32 tmp;

B
Ben Skeggs 已提交
245 246
	spin_lock_irqsave(&gr->lock, flags);
	nv_mask(gr, 0x400500, 0x00000001, 0x00000000);
247

B
Ben Skeggs 已提交
248
	start = tmr->read(tmr);
249 250 251
	do {
		idle = true;

B
Ben Skeggs 已提交
252
		for (tmp = nv_rd32(gr, 0x400380); tmp && idle; tmp >>= 3) {
253 254 255 256
			if ((tmp & 7) == 1)
				idle = false;
		}

B
Ben Skeggs 已提交
257
		for (tmp = nv_rd32(gr, 0x400384); tmp && idle; tmp >>= 3) {
258 259 260 261
			if ((tmp & 7) == 1)
				idle = false;
		}

B
Ben Skeggs 已提交
262
		for (tmp = nv_rd32(gr, 0x400388); tmp && idle; tmp >>= 3) {
263 264 265
			if ((tmp & 7) == 1)
				idle = false;
		}
266
	} while (!idle &&
B
Ben Skeggs 已提交
267
		 !(timeout = tmr->read(tmr) - start > 2000000000));
268 269

	if (timeout) {
B
Ben Skeggs 已提交
270
		nv_error(gr, "PGRAPH TLB flush idle timeout fail\n");
271

B
Ben Skeggs 已提交
272 273 274
		tmp = nv_rd32(gr, 0x400700);
		nv_error(gr, "PGRAPH_STATUS  : 0x%08x", tmp);
		nvkm_bitfield_print(nv50_gr_status, tmp);
275 276
		pr_cont("\n");

B
Ben Skeggs 已提交
277 278 279 280 281 282
		nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0,
				       nv_rd32(gr, 0x400380));
		nvkm_gr_vstatus_print(gr, 1, nv50_gr_vstatus_1,
				       nv_rd32(gr, 0x400384));
		nvkm_gr_vstatus_print(gr, 2, nv50_gr_vstatus_2,
				       nv_rd32(gr, 0x400388));
283 284 285
	}


B
Ben Skeggs 已提交
286 287 288 289 290
	nv_wr32(gr, 0x100c80, 0x00000001);
	if (!nv_wait(gr, 0x100c80, 0x00000001, 0x00000000))
		nv_error(gr, "vm flush timeout\n");
	nv_mask(gr, 0x400500, 0x00000001, 0x00000001);
	spin_unlock_irqrestore(&gr->lock, flags);
291
	return timeout ? -EBUSY : 0;
292
}
293

294
static const struct nvkm_bitfield nv50_mp_exec_errors[] = {
295 296 297 298 299 300 301
	{ 0x01, "STACK_UNDERFLOW" },
	{ 0x02, "STACK_MISMATCH" },
	{ 0x04, "QUADON_ACTIVE" },
	{ 0x08, "TIMEOUT" },
	{ 0x10, "INVALID_OPCODE" },
	{ 0x20, "PM_OVERFLOW" },
	{ 0x40, "BREAKPOINT" },
302 303 304
	{}
};

305
static const struct nvkm_bitfield nv50_mpc_traps[] = {
306 307 308 309 310 311 312 313 314 315 316 317 318
	{ 0x0000001, "LOCAL_LIMIT_READ" },
	{ 0x0000010, "LOCAL_LIMIT_WRITE" },
	{ 0x0000040, "STACK_LIMIT" },
	{ 0x0000100, "GLOBAL_LIMIT_READ" },
	{ 0x0001000, "GLOBAL_LIMIT_WRITE" },
	{ 0x0010000, "MP0" },
	{ 0x0020000, "MP1" },
	{ 0x0040000, "GLOBAL_LIMIT_RED" },
	{ 0x0400000, "GLOBAL_LIMIT_ATOM" },
	{ 0x4000000, "MP2" },
	{}
};

319
static const struct nvkm_bitfield nv50_tex_traps[] = {
320 321 322 323 324 325 326 327
	{ 0x00000001, "" }, /* any bit set? */
	{ 0x00000002, "FAULT" },
	{ 0x00000004, "STORAGE_TYPE_MISMATCH" },
	{ 0x00000008, "LINEAR_MISMATCH" },
	{ 0x00000020, "WRONG_MEMTYPE" },
	{}
};

328
static const struct nvkm_bitfield nv50_gr_trap_m2mf[] = {
329 330 331 332 333 334
	{ 0x00000001, "NOTIFY" },
	{ 0x00000002, "IN" },
	{ 0x00000004, "OUT" },
	{}
};

335
static const struct nvkm_bitfield nv50_gr_trap_vfetch[] = {
336 337 338 339
	{ 0x00000001, "FAULT" },
	{}
};

340
static const struct nvkm_bitfield nv50_gr_trap_strmout[] = {
341 342 343 344
	{ 0x00000001, "FAULT" },
	{}
};

345
static const struct nvkm_bitfield nv50_gr_trap_ccache[] = {
346 347 348 349 350
	{ 0x00000001, "FAULT" },
	{}
};

/* There must be a *lot* of these. Will take some time to gather them up. */
351
const struct nvkm_enum nv50_data_error_names[] = {
352
	{ 0x00000003, "INVALID_OPERATION", NULL },
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
	{ 0x00000004, "INVALID_VALUE", NULL },
	{ 0x00000005, "INVALID_ENUM", NULL },
	{ 0x00000008, "INVALID_OBJECT", NULL },
	{ 0x00000009, "READ_ONLY_OBJECT", NULL },
	{ 0x0000000a, "SUPERVISOR_OBJECT", NULL },
	{ 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL },
	{ 0x0000000c, "INVALID_BITFIELD", NULL },
	{ 0x0000000d, "BEGIN_END_ACTIVE", NULL },
	{ 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL },
	{ 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL },
	{ 0x00000010, "RT_DOUBLE_BIND", NULL },
	{ 0x00000011, "RT_TYPES_MISMATCH", NULL },
	{ 0x00000012, "RT_LINEAR_WITH_ZETA", NULL },
	{ 0x00000015, "FP_TOO_FEW_REGS", NULL },
	{ 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL },
	{ 0x00000017, "RT_LINEAR_WITH_MSAA", NULL },
	{ 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL },
	{ 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL },
	{ 0x0000001a, "RT_INVALID_ALIGNMENT", NULL },
	{ 0x0000001b, "SAMPLER_OVER_LIMIT", NULL },
	{ 0x0000001c, "TEXTURE_OVER_LIMIT", NULL },
	{ 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL },
	{ 0x0000001f, "RT_BPP128_WITH_MS8", NULL },
	{ 0x00000021, "Z_OUT_OF_BOUNDS", NULL },
	{ 0x00000023, "XY_OUT_OF_BOUNDS", NULL },
378
	{ 0x00000024, "VP_ZERO_INPUTS", NULL },
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	{ 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL },
	{ 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL },
	{ 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL },
	{ 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL },
	{ 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL },
	{ 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL },
	{ 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL },
	{ 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL },
	{ 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL },
	{ 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL },
	{ 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL },
	{ 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL },
	{ 0x00000046, "LAYER_ID_NEEDS_GP", NULL },
	{ 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL },
	{ 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL },
394 395 396
	{}
};

397
static const struct nvkm_bitfield nv50_gr_intr_name[] = {
398 399 400 401 402 403 404 405 406 407 408 409 410
	{ 0x00000001, "NOTIFY" },
	{ 0x00000002, "COMPUTE_QUERY" },
	{ 0x00000010, "ILLEGAL_MTHD" },
	{ 0x00000020, "ILLEGAL_CLASS" },
	{ 0x00000040, "DOUBLE_NOTIFY" },
	{ 0x00001000, "CONTEXT_SWITCH" },
	{ 0x00010000, "BUFFER_NOTIFY" },
	{ 0x00100000, "DATA_ERROR" },
	{ 0x00200000, "TRAP" },
	{ 0x01000000, "SINGLE_STEP" },
	{}
};

411
static const struct nvkm_bitfield nv50_gr_trap_prop[] = {
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
	{ 0x00000004, "SURF_WIDTH_OVERRUN" },
	{ 0x00000008, "SURF_HEIGHT_OVERRUN" },
	{ 0x00000010, "DST2D_FAULT" },
	{ 0x00000020, "ZETA_FAULT" },
	{ 0x00000040, "RT_FAULT" },
	{ 0x00000080, "CUDA_FAULT" },
	{ 0x00000100, "DST2D_STORAGE_TYPE_MISMATCH" },
	{ 0x00000200, "ZETA_STORAGE_TYPE_MISMATCH" },
	{ 0x00000400, "RT_STORAGE_TYPE_MISMATCH" },
	{ 0x00000800, "DST2D_LINEAR_MISMATCH" },
	{ 0x00001000, "RT_LINEAR_MISMATCH" },
	{}
};

static void
B
Ben Skeggs 已提交
427
nv50_gr_prop_trap(struct nv50_gr *gr,
428 429
		    u32 ustatus_addr, u32 ustatus, u32 tp)
{
B
Ben Skeggs 已提交
430 431 432 433 434 435 436
	u32 e0c = nv_rd32(gr, ustatus_addr + 0x04);
	u32 e10 = nv_rd32(gr, ustatus_addr + 0x08);
	u32 e14 = nv_rd32(gr, ustatus_addr + 0x0c);
	u32 e18 = nv_rd32(gr, ustatus_addr + 0x10);
	u32 e1c = nv_rd32(gr, ustatus_addr + 0x14);
	u32 e20 = nv_rd32(gr, ustatus_addr + 0x18);
	u32 e24 = nv_rd32(gr, ustatus_addr + 0x1c);
437 438 439 440 441

	/* CUDA memory: l[], g[] or stack. */
	if (ustatus & 0x00000080) {
		if (e18 & 0x80000000) {
			/* g[] read fault? */
B
Ben Skeggs 已提交
442
			nv_error(gr, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n",
443 444 445 446
					 tp, e14, e10 | ((e18 >> 24) & 0x1f));
			e18 &= ~0x1f000000;
		} else if (e18 & 0xc) {
			/* g[] write fault? */
B
Ben Skeggs 已提交
447
			nv_error(gr, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n",
448 449 450
				 tp, e14, e10 | ((e18 >> 7) & 0x1f));
			e18 &= ~0x00000f80;
		} else {
B
Ben Skeggs 已提交
451
			nv_error(gr, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n",
452 453 454 455 456
				 tp, e14, e10);
		}
		ustatus &= ~0x00000080;
	}
	if (ustatus) {
B
Ben Skeggs 已提交
457
		nv_error(gr, "TRAP_PROP - TP %d -", tp);
458
		nvkm_bitfield_print(nv50_gr_trap_prop, ustatus);
459 460
		pr_cont(" - Address %02x%08x\n", e14, e10);
	}
B
Ben Skeggs 已提交
461
	nv_error(gr, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
462 463 464
		 tp, e0c, e18, e1c, e20, e24);
}

465
static void
B
Ben Skeggs 已提交
466
nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display)
467
{
B
Ben Skeggs 已提交
468
	u32 units = nv_rd32(gr, 0x1540);
469
	u32 addr, mp10, status, pc, oplow, ophigh;
470 471 472 473 474
	int i;
	int mps = 0;
	for (i = 0; i < 4; i++) {
		if (!(units & 1 << (i+24)))
			continue;
B
Ben Skeggs 已提交
475
		if (nv_device(gr)->chipset < 0xa0)
476 477 478
			addr = 0x408200 + (tpid << 12) + (i << 7);
		else
			addr = 0x408100 + (tpid << 11) + (i << 7);
B
Ben Skeggs 已提交
479 480
		mp10 = nv_rd32(gr, addr + 0x10);
		status = nv_rd32(gr, addr + 0x14);
481 482 483
		if (!status)
			continue;
		if (display) {
B
Ben Skeggs 已提交
484 485 486 487 488
			nv_rd32(gr, addr + 0x20);
			pc = nv_rd32(gr, addr + 0x24);
			oplow = nv_rd32(gr, addr + 0x70);
			ophigh = nv_rd32(gr, addr + 0x74);
			nv_error(gr, "TRAP_MP_EXEC - "
489
					"TP %d MP %d:", tpid, i);
490
			nvkm_bitfield_print(nv50_mp_exec_errors, status);
M
Marcin Slusarz 已提交
491
			pr_cont(" at %06x warp %d, opcode %08x %08x\n",
492 493 494
					pc&0xffffff, pc >> 24,
					oplow, ophigh);
		}
B
Ben Skeggs 已提交
495 496
		nv_wr32(gr, addr + 0x10, mp10);
		nv_wr32(gr, addr + 0x14, 0);
497 498 499
		mps++;
	}
	if (!mps && display)
B
Ben Skeggs 已提交
500
		nv_error(gr, "TRAP_MP_EXEC - TP %d: "
501 502 503 504
				"No MPs claiming errors?\n", tpid);
}

static void
B
Ben Skeggs 已提交
505
nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old,
506
		  u32 ustatus_new, int display, const char *name)
507 508
{
	int tps = 0;
B
Ben Skeggs 已提交
509
	u32 units = nv_rd32(gr, 0x1540);
510
	int i, r;
511
	u32 ustatus_addr, ustatus;
512 513 514
	for (i = 0; i < 16; i++) {
		if (!(units & (1 << i)))
			continue;
B
Ben Skeggs 已提交
515
		if (nv_device(gr)->chipset < 0xa0)
516 517 518
			ustatus_addr = ustatus_old + (i << 12);
		else
			ustatus_addr = ustatus_new + (i << 11);
B
Ben Skeggs 已提交
519
		ustatus = nv_rd32(gr, ustatus_addr) & 0x7fffffff;
520 521 522 523 524 525
		if (!ustatus)
			continue;
		tps++;
		switch (type) {
		case 6: /* texture error... unknown for now */
			if (display) {
B
Ben Skeggs 已提交
526
				nv_error(gr, "magic set %d:\n", i);
527
				for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
B
Ben Skeggs 已提交
528 529
					nv_error(gr, "\t0x%08x: 0x%08x\n", r,
						nv_rd32(gr, r));
530
				if (ustatus) {
B
Ben Skeggs 已提交
531
					nv_error(gr, "%s - TP%d:", name, i);
532
					nvkm_bitfield_print(nv50_tex_traps,
533 534 535 536
							       ustatus);
					pr_cont("\n");
					ustatus = 0;
				}
537 538 539
			}
			break;
		case 7: /* MP error */
540
			if (ustatus & 0x04030000) {
B
Ben Skeggs 已提交
541
				nv50_gr_mp_trap(gr, i, display);
542
				ustatus &= ~0x04030000;
543
			}
544
			if (ustatus && display) {
B
Ben Skeggs 已提交
545
				nv_error(gr, "%s - TP%d:", name, i);
546
				nvkm_bitfield_print(nv50_mpc_traps, ustatus);
547 548 549
				pr_cont("\n");
				ustatus = 0;
			}
550
			break;
551 552
		case 8: /* PROP error */
			if (display)
B
Ben Skeggs 已提交
553 554
				nv50_gr_prop_trap(
						gr, ustatus_addr, ustatus, i);
555
			ustatus = 0;
556 557 558 559
			break;
		}
		if (ustatus) {
			if (display)
B
Ben Skeggs 已提交
560
				nv_error(gr, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
561
		}
B
Ben Skeggs 已提交
562
		nv_wr32(gr, ustatus_addr, 0xc0000000);
563 564 565
	}

	if (!tps && display)
B
Ben Skeggs 已提交
566
		nv_warn(gr, "%s - No TPs claiming errors?\n", name);
567 568 569
}

static int
B
Ben Skeggs 已提交
570
nv50_gr_trap_handler(struct nv50_gr *gr, u32 display,
571
		     int chid, u64 inst, struct nvkm_object *engctx)
572
{
B
Ben Skeggs 已提交
573
	u32 status = nv_rd32(gr, 0x400108);
574 575 576
	u32 ustatus;

	if (!status && display) {
B
Ben Skeggs 已提交
577
		nv_error(gr, "TRAP: no units reporting traps?\n");
578 579 580 581 582 583 584
		return 1;
	}

	/* DISPATCH: Relays commands to other units and handles NOTIFY,
	 * COND, QUERY. If you get a trap from it, the command is still stuck
	 * in DISPATCH and you need to do something about it. */
	if (status & 0x001) {
B
Ben Skeggs 已提交
585
		ustatus = nv_rd32(gr, 0x400804) & 0x7fffffff;
586
		if (!ustatus && display) {
B
Ben Skeggs 已提交
587
			nv_error(gr, "TRAP_DISPATCH - no ustatus?\n");
588 589
		}

B
Ben Skeggs 已提交
590
		nv_wr32(gr, 0x400500, 0x00000000);
591 592 593

		/* Known to be triggered by screwed up NOTIFY and COND... */
		if (ustatus & 0x00000001) {
B
Ben Skeggs 已提交
594
			u32 addr = nv_rd32(gr, 0x400808);
595 596
			u32 subc = (addr & 0x00070000) >> 16;
			u32 mthd = (addr & 0x00001ffc);
B
Ben Skeggs 已提交
597 598 599 600
			u32 datal = nv_rd32(gr, 0x40080c);
			u32 datah = nv_rd32(gr, 0x400810);
			u32 class = nv_rd32(gr, 0x400814);
			u32 r848 = nv_rd32(gr, 0x400848);
601

B
Ben Skeggs 已提交
602
			nv_error(gr, "TRAP DISPATCH_FAULT\n");
603
			if (display && (addr & 0x80000000)) {
B
Ben Skeggs 已提交
604
				nv_error(gr,
605 606
					 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n",
					 chid, inst,
607
					 nvkm_client_name(engctx), subc,
608
					 class, mthd, datah, datal, addr, r848);
609 610
			} else
			if (display) {
B
Ben Skeggs 已提交
611
				nv_error(gr, "no stuck command?\n");
612 613
			}

B
Ben Skeggs 已提交
614 615 616
			nv_wr32(gr, 0x400808, 0);
			nv_wr32(gr, 0x4008e8, nv_rd32(gr, 0x4008e8) & 3);
			nv_wr32(gr, 0x400848, 0);
617 618 619 620
			ustatus &= ~0x00000001;
		}

		if (ustatus & 0x00000002) {
B
Ben Skeggs 已提交
621
			u32 addr = nv_rd32(gr, 0x40084c);
622 623
			u32 subc = (addr & 0x00070000) >> 16;
			u32 mthd = (addr & 0x00001ffc);
B
Ben Skeggs 已提交
624 625
			u32 data = nv_rd32(gr, 0x40085c);
			u32 class = nv_rd32(gr, 0x400814);
626

B
Ben Skeggs 已提交
627
			nv_error(gr, "TRAP DISPATCH_QUERY\n");
628
			if (display && (addr & 0x80000000)) {
B
Ben Skeggs 已提交
629
				nv_error(gr,
630 631
					 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n",
					 chid, inst,
632
					 nvkm_client_name(engctx), subc,
633
					 class, mthd, data, addr);
634 635
			} else
			if (display) {
B
Ben Skeggs 已提交
636
				nv_error(gr, "no stuck command?\n");
637 638
			}

B
Ben Skeggs 已提交
639
			nv_wr32(gr, 0x40084c, 0);
640 641 642 643
			ustatus &= ~0x00000002;
		}

		if (ustatus && display) {
B
Ben Skeggs 已提交
644
			nv_error(gr, "TRAP_DISPATCH (unknown "
645 646 647
				      "0x%08x)\n", ustatus);
		}

B
Ben Skeggs 已提交
648 649
		nv_wr32(gr, 0x400804, 0xc0000000);
		nv_wr32(gr, 0x400108, 0x001);
650 651 652 653 654 655 656
		status &= ~0x001;
		if (!status)
			return 0;
	}

	/* M2MF: Memory to memory copy engine. */
	if (status & 0x002) {
B
Ben Skeggs 已提交
657
		u32 ustatus = nv_rd32(gr, 0x406800) & 0x7fffffff;
658
		if (display) {
B
Ben Skeggs 已提交
659
			nv_error(gr, "TRAP_M2MF");
660
			nvkm_bitfield_print(nv50_gr_trap_m2mf, ustatus);
M
Marcin Slusarz 已提交
661
			pr_cont("\n");
B
Ben Skeggs 已提交
662 663 664
			nv_error(gr, "TRAP_M2MF %08x %08x %08x %08x\n",
				nv_rd32(gr, 0x406804), nv_rd32(gr, 0x406808),
				nv_rd32(gr, 0x40680c), nv_rd32(gr, 0x406810));
665 666 667 668

		}

		/* No sane way found yet -- just reset the bugger. */
B
Ben Skeggs 已提交
669 670 671 672
		nv_wr32(gr, 0x400040, 2);
		nv_wr32(gr, 0x400040, 0);
		nv_wr32(gr, 0x406800, 0xc0000000);
		nv_wr32(gr, 0x400108, 0x002);
673 674 675 676 677
		status &= ~0x002;
	}

	/* VFETCH: Fetches data from vertex buffers. */
	if (status & 0x004) {
B
Ben Skeggs 已提交
678
		u32 ustatus = nv_rd32(gr, 0x400c04) & 0x7fffffff;
679
		if (display) {
B
Ben Skeggs 已提交
680
			nv_error(gr, "TRAP_VFETCH");
681
			nvkm_bitfield_print(nv50_gr_trap_vfetch, ustatus);
M
Marcin Slusarz 已提交
682
			pr_cont("\n");
B
Ben Skeggs 已提交
683 684 685
			nv_error(gr, "TRAP_VFETCH %08x %08x %08x %08x\n",
				nv_rd32(gr, 0x400c00), nv_rd32(gr, 0x400c08),
				nv_rd32(gr, 0x400c0c), nv_rd32(gr, 0x400c10));
686 687
		}

B
Ben Skeggs 已提交
688 689
		nv_wr32(gr, 0x400c04, 0xc0000000);
		nv_wr32(gr, 0x400108, 0x004);
690 691 692 693 694
		status &= ~0x004;
	}

	/* STRMOUT: DirectX streamout / OpenGL transform feedback. */
	if (status & 0x008) {
B
Ben Skeggs 已提交
695
		ustatus = nv_rd32(gr, 0x401800) & 0x7fffffff;
696
		if (display) {
B
Ben Skeggs 已提交
697
			nv_error(gr, "TRAP_STRMOUT");
698
			nvkm_bitfield_print(nv50_gr_trap_strmout, ustatus);
M
Marcin Slusarz 已提交
699
			pr_cont("\n");
B
Ben Skeggs 已提交
700 701 702
			nv_error(gr, "TRAP_STRMOUT %08x %08x %08x %08x\n",
				nv_rd32(gr, 0x401804), nv_rd32(gr, 0x401808),
				nv_rd32(gr, 0x40180c), nv_rd32(gr, 0x401810));
703 704 705 706

		}

		/* No sane way found yet -- just reset the bugger. */
B
Ben Skeggs 已提交
707 708 709 710
		nv_wr32(gr, 0x400040, 0x80);
		nv_wr32(gr, 0x400040, 0);
		nv_wr32(gr, 0x401800, 0xc0000000);
		nv_wr32(gr, 0x400108, 0x008);
711 712 713 714 715
		status &= ~0x008;
	}

	/* CCACHE: Handles code and c[] caches and fills them. */
	if (status & 0x010) {
B
Ben Skeggs 已提交
716
		ustatus = nv_rd32(gr, 0x405018) & 0x7fffffff;
717
		if (display) {
B
Ben Skeggs 已提交
718
			nv_error(gr, "TRAP_CCACHE");
719
			nvkm_bitfield_print(nv50_gr_trap_ccache, ustatus);
M
Marcin Slusarz 已提交
720
			pr_cont("\n");
B
Ben Skeggs 已提交
721
			nv_error(gr, "TRAP_CCACHE %08x %08x %08x %08x"
722
				     " %08x %08x %08x\n",
B
Ben Skeggs 已提交
723 724 725 726
				nv_rd32(gr, 0x405000), nv_rd32(gr, 0x405004),
				nv_rd32(gr, 0x405008), nv_rd32(gr, 0x40500c),
				nv_rd32(gr, 0x405010), nv_rd32(gr, 0x405014),
				nv_rd32(gr, 0x40501c));
727 728 729

		}

B
Ben Skeggs 已提交
730 731
		nv_wr32(gr, 0x405018, 0xc0000000);
		nv_wr32(gr, 0x400108, 0x010);
732 733 734 735 736 737 738
		status &= ~0x010;
	}

	/* Unknown, not seen yet... 0x402000 is the only trap status reg
	 * remaining, so try to handle it anyway. Perhaps related to that
	 * unknown DMA slot on tesla? */
	if (status & 0x20) {
B
Ben Skeggs 已提交
739
		ustatus = nv_rd32(gr, 0x402000) & 0x7fffffff;
740
		if (display)
B
Ben Skeggs 已提交
741 742
			nv_error(gr, "TRAP_UNKC04 0x%08x\n", ustatus);
		nv_wr32(gr, 0x402000, 0xc0000000);
743 744 745 746 747
		/* no status modifiction on purpose */
	}

	/* TEXTURE: CUDA texturing units */
	if (status & 0x040) {
B
Ben Skeggs 已提交
748
		nv50_gr_tp_trap(gr, 6, 0x408900, 0x408600, display,
749
				    "TRAP_TEXTURE");
B
Ben Skeggs 已提交
750
		nv_wr32(gr, 0x400108, 0x040);
751 752 753 754 755
		status &= ~0x040;
	}

	/* MP: CUDA execution engines. */
	if (status & 0x080) {
B
Ben Skeggs 已提交
756
		nv50_gr_tp_trap(gr, 7, 0x408314, 0x40831c, display,
757
				    "TRAP_MP");
B
Ben Skeggs 已提交
758
		nv_wr32(gr, 0x400108, 0x080);
759 760 761
		status &= ~0x080;
	}

762
	/* PROP:  Handles TP-initiated uncached memory accesses:
763 764
	 * l[], g[], stack, 2d surfaces, render targets. */
	if (status & 0x100) {
B
Ben Skeggs 已提交
765
		nv50_gr_tp_trap(gr, 8, 0x408e08, 0x408708, display,
766
				    "TRAP_PROP");
B
Ben Skeggs 已提交
767
		nv_wr32(gr, 0x400108, 0x100);
768 769 770 771 772
		status &= ~0x100;
	}

	if (status) {
		if (display)
B
Ben Skeggs 已提交
773 774
			nv_error(gr, "TRAP: unknown 0x%08x\n", status);
		nv_wr32(gr, 0x400108, status);
775 776 777 778 779
	}

	return 1;
}

780
static void
781
nv50_gr_intr(struct nvkm_subdev *subdev)
782
{
B
Ben Skeggs 已提交
783
	struct nvkm_fifo *fifo = nvkm_fifo(subdev);
784 785 786
	struct nvkm_engine *engine = nv_engine(subdev);
	struct nvkm_object *engctx;
	struct nvkm_handle *handle = NULL;
B
Ben Skeggs 已提交
787 788 789 790
	struct nv50_gr *gr = (void *)subdev;
	u32 stat = nv_rd32(gr, 0x400100);
	u32 inst = nv_rd32(gr, 0x40032c) & 0x0fffffff;
	u32 addr = nv_rd32(gr, 0x400704);
791 792
	u32 subc = (addr & 0x00070000) >> 16;
	u32 mthd = (addr & 0x00001ffc);
B
Ben Skeggs 已提交
793 794
	u32 data = nv_rd32(gr, 0x400708);
	u32 class = nv_rd32(gr, 0x400814);
795
	u32 show = stat, show_bitfield = stat;
796 797
	int chid;

798
	engctx = nvkm_engctx_get(engine, inst);
B
Ben Skeggs 已提交
799
	chid   = fifo->chid(fifo, engctx);
800 801

	if (stat & 0x00000010) {
802
		handle = nvkm_handle_get_class(engctx, class);
803 804
		if (handle && !nv_call(handle->object, mthd, data))
			show &= ~0x00000010;
805
		nvkm_handle_put(handle);
806
	}
807

808
	if (show & 0x00100000) {
B
Ben Skeggs 已提交
809 810
		u32 ecode = nv_rd32(gr, 0x400110);
		nv_error(gr, "DATA_ERROR ");
811
		nvkm_enum_print(nv50_data_error_names, ecode);
M
Marcin Slusarz 已提交
812
		pr_cont("\n");
813
		show_bitfield &= ~0x00100000;
814
	}
815

816
	if (stat & 0x00200000) {
B
Ben Skeggs 已提交
817
		if (!nv50_gr_trap_handler(gr, show, chid, (u64)inst << 12,
818
					  engctx))
819
			show &= ~0x00200000;
820
		show_bitfield &= ~0x00200000;
821 822
	}

B
Ben Skeggs 已提交
823 824
	nv_wr32(gr, 0x400100, stat);
	nv_wr32(gr, 0x400500, 0x00010001);
825 826

	if (show) {
827 828
		show &= show_bitfield;
		if (show) {
B
Ben Skeggs 已提交
829
			nv_error(gr, "%s", "");
830
			nvkm_bitfield_print(nv50_gr_intr_name, show);
831 832
			pr_cont("\n");
		}
B
Ben Skeggs 已提交
833
		nv_error(gr,
834
			 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
835
			 chid, (u64)inst << 12, nvkm_client_name(engctx),
836
			 subc, class, mthd, data);
837
	}
838

B
Ben Skeggs 已提交
839 840
	if (nv_rd32(gr, 0x400824) & (1 << 31))
		nv_wr32(gr, 0x400824, nv_rd32(gr, 0x400824) & ~(1 << 31));
841

842
	nvkm_engctx_put(engctx);
843 844
}

845
static int
846 847 848
nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
	     struct nvkm_oclass *oclass, void *data, u32 size,
	     struct nvkm_object **pobject)
849
{
B
Ben Skeggs 已提交
850
	struct nv50_gr *gr;
851
	int ret;
852

B
Ben Skeggs 已提交
853 854
	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
	*pobject = nv_object(gr);
855 856
	if (ret)
		return ret;
857

B
Ben Skeggs 已提交
858 859 860
	nv_subdev(gr)->unit = 0x00201000;
	nv_subdev(gr)->intr = nv50_gr_intr;
	nv_engine(gr)->cclass = &nv50_gr_cclass;
861

B
Ben Skeggs 已提交
862
	gr->base.units = nv50_gr_units;
863

B
Ben Skeggs 已提交
864
	switch (nv_device(gr)->chipset) {
865
	case 0x50:
B
Ben Skeggs 已提交
866
		nv_engine(gr)->sclass = nv50_gr_sclass;
867 868 869 870 871 872 873
		break;
	case 0x84:
	case 0x86:
	case 0x92:
	case 0x94:
	case 0x96:
	case 0x98:
B
Ben Skeggs 已提交
874
		nv_engine(gr)->sclass = g84_gr_sclass;
875 876 877 878
		break;
	case 0xa0:
	case 0xaa:
	case 0xac:
B
Ben Skeggs 已提交
879
		nv_engine(gr)->sclass = gt200_gr_sclass;
880 881 882 883
		break;
	case 0xa3:
	case 0xa5:
	case 0xa8:
B
Ben Skeggs 已提交
884
		nv_engine(gr)->sclass = gt215_gr_sclass;
885 886
		break;
	case 0xaf:
B
Ben Skeggs 已提交
887
		nv_engine(gr)->sclass = mcp89_gr_sclass;
888
		break;
889

D
Damien Lespiau 已提交
890
	}
891

892
	/* unfortunate hw bug workaround... */
B
Ben Skeggs 已提交
893 894 895
	if (nv_device(gr)->chipset != 0x50 &&
	    nv_device(gr)->chipset != 0xac)
		nv_engine(gr)->tlb_flush = g84_gr_tlb_flush;
896

B
Ben Skeggs 已提交
897
	spin_lock_init(&gr->lock);
898
	return 0;
899
}
900

901
static int
902
nv50_gr_init(struct nvkm_object *object)
903
{
B
Ben Skeggs 已提交
904
	struct nv50_gr *gr = (void *)object;
905
	int ret, units, i;
906

B
Ben Skeggs 已提交
907
	ret = nvkm_gr_init(&gr->base);
908 909
	if (ret)
		return ret;
910

911
	/* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */
B
Ben Skeggs 已提交
912
	nv_wr32(gr, 0x40008c, 0x00000004);
913

914
	/* reset/enable traps and interrupts */
B
Ben Skeggs 已提交
915 916 917 918 919 920 921 922
	nv_wr32(gr, 0x400804, 0xc0000000);
	nv_wr32(gr, 0x406800, 0xc0000000);
	nv_wr32(gr, 0x400c04, 0xc0000000);
	nv_wr32(gr, 0x401800, 0xc0000000);
	nv_wr32(gr, 0x405018, 0xc0000000);
	nv_wr32(gr, 0x402000, 0xc0000000);

	units = nv_rd32(gr, 0x001540);
923 924 925
	for (i = 0; i < 16; i++) {
		if (!(units & (1 << i)))
			continue;
926

B
Ben Skeggs 已提交
927 928 929 930
		if (nv_device(gr)->chipset < 0xa0) {
			nv_wr32(gr, 0x408900 + (i << 12), 0xc0000000);
			nv_wr32(gr, 0x408e08 + (i << 12), 0xc0000000);
			nv_wr32(gr, 0x408314 + (i << 12), 0xc0000000);
931
		} else {
B
Ben Skeggs 已提交
932 933 934
			nv_wr32(gr, 0x408600 + (i << 11), 0xc0000000);
			nv_wr32(gr, 0x408708 + (i << 11), 0xc0000000);
			nv_wr32(gr, 0x40831c + (i << 11), 0xc0000000);
935
		}
936 937
	}

B
Ben Skeggs 已提交
938 939 940 941 942
	nv_wr32(gr, 0x400108, 0xffffffff);
	nv_wr32(gr, 0x400138, 0xffffffff);
	nv_wr32(gr, 0x400100, 0xffffffff);
	nv_wr32(gr, 0x40013c, 0xffffffff);
	nv_wr32(gr, 0x400500, 0x00010001);
943

944
	/* upload context program, initialise ctxctl defaults */
B
Ben Skeggs 已提交
945
	ret = nv50_grctx_init(nv_device(gr), &gr->size);
946 947
	if (ret)
		return ret;
948

B
Ben Skeggs 已提交
949 950 951 952 953 954
	nv_wr32(gr, 0x400824, 0x00000000);
	nv_wr32(gr, 0x400828, 0x00000000);
	nv_wr32(gr, 0x40082c, 0x00000000);
	nv_wr32(gr, 0x400830, 0x00000000);
	nv_wr32(gr, 0x40032c, 0x00000000);
	nv_wr32(gr, 0x400330, 0x00000000);
955

956
	/* some unknown zcull magic */
B
Ben Skeggs 已提交
957
	switch (nv_device(gr)->chipset & 0xf0) {
958 959 960
	case 0x50:
	case 0x80:
	case 0x90:
B
Ben Skeggs 已提交
961
		nv_wr32(gr, 0x402ca8, 0x00000800);
962 963 964
		break;
	case 0xa0:
	default:
B
Ben Skeggs 已提交
965 966 967 968
		if (nv_device(gr)->chipset == 0xa0 ||
		    nv_device(gr)->chipset == 0xaa ||
		    nv_device(gr)->chipset == 0xac) {
			nv_wr32(gr, 0x402ca8, 0x00000802);
969
		} else {
B
Ben Skeggs 已提交
970 971
			nv_wr32(gr, 0x402cc0, 0x00000000);
			nv_wr32(gr, 0x402ca8, 0x00000002);
972 973
		}

974 975
		break;
	}
976

977 978
	/* zero out zcull regions */
	for (i = 0; i < 8; i++) {
B
Ben Skeggs 已提交
979 980 981 982
		nv_wr32(gr, 0x402c20 + (i * 0x10), 0x00000000);
		nv_wr32(gr, 0x402c24 + (i * 0x10), 0x00000000);
		nv_wr32(gr, 0x402c28 + (i * 0x10), 0x00000000);
		nv_wr32(gr, 0x402c2c + (i * 0x10), 0x00000000);
983
	}
984 985
	return 0;
}
986

987
struct nvkm_oclass
988
nv50_gr_oclass = {
989
	.handle = NV_ENGINE(GR, 0x50),
990
	.ofuncs = &(struct nvkm_ofuncs) {
991
		.ctor = nv50_gr_ctor,
992
		.dtor = _nvkm_gr_dtor,
993
		.init = nv50_gr_init,
994
		.fini = _nvkm_gr_fini,
995 996
	},
};