aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv50_graph.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-04 02:29:23 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-04 02:29:23 -0400
commit612a9aab56a93533e76e3ad91642db7033e03b69 (patch)
tree8402096973f67af941f9392f7da06cca03e0b58a /drivers/gpu/drm/nouveau/nv50_graph.c
parent3a494318b14b1bc0f59d2d6ce84c505c74d82d2a (diff)
parent268d28371cd326be4dfcd7eba5917bf4b9d30c8f (diff)
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm merge (part 1) from Dave Airlie: "So first of all my tree and uapi stuff has a conflict mess, its my fault as the nouveau stuff didn't hit -next as were trying to rebase regressions out of it before we merged. Highlights: - SH mobile modesetting driver and associated helpers - some DRM core documentation - i915 modesetting rework, haswell hdmi, haswell and vlv fixes, write combined pte writing, ilk rc6 support, - nouveau: major driver rework into a hw core driver, makes features like SLI a lot saner to implement, - psb: add eDP/DP support for Cedarview - radeon: 2 layer page tables, async VM pte updates, better PLL selection for > 2 screens, better ACPI interactions The rest is general grab bag of fixes. So why part 1? well I have the exynos pull req which came in a bit late but was waiting for me to do something they shouldn't have and it looks fairly safe, and David Howells has some more header cleanups he'd like me to pull, that seem like a good idea, but I'd like to get this merge out of the way so -next dosen't get blocked." Tons of conflicts mostly due to silly include line changes, but mostly mindless. A few other small semantic conflicts too, noted from Dave's pre-merged branch. * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (447 commits) drm/nv98/crypt: fix fuc build with latest envyas drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering drm/nv41/vm: fix and enable use of "real" pciegart drm/nv44/vm: fix and enable use of "real" pciegart drm/nv04/dmaobj: fixup vm target handling in preparation for nv4x pcie drm/nouveau: store supported dma mask in vmmgr drm/nvc0/ibus: initial implementation of subdev drm/nouveau/therm: add support for fan-control modes drm/nouveau/hwmon: rename pwm0* to pmw1* to follow hwmon's rules drm/nouveau/therm: calculate the pwm divisor on nv50+ drm/nouveau/fan: rewrite the fan tachometer driver to get more precision, faster drm/nouveau/therm: move thermal-related functions to the therm subdev drm/nouveau/bios: parse the pwm divisor from the perf table drm/nouveau/therm: use the EXTDEV table to detect i2c monitoring devices drm/nouveau/therm: rework thermal table parsing drm/nouveau/gpio: expose the PWM/TOGGLE parameter found in the gpio vbios table drm/nouveau: fix pm initialization order drm/nouveau/bios: check that fixed tvdac gpio data is valid before using it drm/nouveau: log channel debug/error messages from client object rather than drm client drm/nouveau: have drm debugging macros build on top of core macros ...
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_graph.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c867
1 files changed, 0 insertions, 867 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
deleted file mode 100644
index f8a9c8095297..000000000000
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ /dev/null
@@ -1,867 +0,0 @@
1/*
2 * Copyright (C) 2007 Ben Skeggs.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27#include <drm/drmP.h>
28#include "nouveau_drv.h"
29#include "nouveau_fifo.h"
30#include "nouveau_ramht.h"
31#include "nouveau_dma.h"
32#include "nouveau_vm.h"
33#include "nv50_evo.h"
34
35struct nv50_graph_engine {
36 struct nouveau_exec_engine base;
37 u32 ctxprog[512];
38 u32 ctxprog_size;
39 u32 grctx_size;
40};
41
42static int
43nv50_graph_init(struct drm_device *dev, int engine)
44{
45 struct drm_nouveau_private *dev_priv = dev->dev_private;
46 struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
47 u32 units = nv_rd32(dev, 0x001540);
48 int i;
49
50 NV_DEBUG(dev, "\n");
51
52 /* master reset */
53 nv_mask(dev, 0x000200, 0x00201000, 0x00000000);
54 nv_mask(dev, 0x000200, 0x00201000, 0x00201000);
55 nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
56
57 /* reset/enable traps and interrupts */
58 nv_wr32(dev, 0x400804, 0xc0000000);
59 nv_wr32(dev, 0x406800, 0xc0000000);
60 nv_wr32(dev, 0x400c04, 0xc0000000);
61 nv_wr32(dev, 0x401800, 0xc0000000);
62 nv_wr32(dev, 0x405018, 0xc0000000);
63 nv_wr32(dev, 0x402000, 0xc0000000);
64 for (i = 0; i < 16; i++) {
65 if (!(units & (1 << i)))
66 continue;
67
68 if (dev_priv->chipset < 0xa0) {
69 nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000);
70 nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000);
71 nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000);
72 } else {
73 nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000);
74 nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000);
75 nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000);
76 }
77 }
78
79 nv_wr32(dev, 0x400108, 0xffffffff);
80 nv_wr32(dev, 0x400138, 0xffffffff);
81 nv_wr32(dev, 0x400100, 0xffffffff);
82 nv_wr32(dev, 0x40013c, 0xffffffff);
83 nv_wr32(dev, 0x400500, 0x00010001);
84
85 /* upload context program, initialise ctxctl defaults */
86 nv_wr32(dev, 0x400324, 0x00000000);
87 for (i = 0; i < pgraph->ctxprog_size; i++)
88 nv_wr32(dev, 0x400328, pgraph->ctxprog[i]);
89 nv_wr32(dev, 0x400824, 0x00000000);
90 nv_wr32(dev, 0x400828, 0x00000000);
91 nv_wr32(dev, 0x40082c, 0x00000000);
92 nv_wr32(dev, 0x400830, 0x00000000);
93 nv_wr32(dev, 0x400724, 0x00000000);
94 nv_wr32(dev, 0x40032c, 0x00000000);
95 nv_wr32(dev, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */
96
97 /* some unknown zcull magic */
98 switch (dev_priv->chipset & 0xf0) {
99 case 0x50:
100 case 0x80:
101 case 0x90:
102 nv_wr32(dev, 0x402ca8, 0x00000800);
103 break;
104 case 0xa0:
105 default:
106 nv_wr32(dev, 0x402cc0, 0x00000000);
107 if (dev_priv->chipset == 0xa0 ||
108 dev_priv->chipset == 0xaa ||
109 dev_priv->chipset == 0xac) {
110 nv_wr32(dev, 0x402ca8, 0x00000802);
111 } else {
112 nv_wr32(dev, 0x402cc0, 0x00000000);
113 nv_wr32(dev, 0x402ca8, 0x00000002);
114 }
115
116 break;
117 }
118
119 /* zero out zcull regions */
120 for (i = 0; i < 8; i++) {
121 nv_wr32(dev, 0x402c20 + (i * 8), 0x00000000);
122 nv_wr32(dev, 0x402c24 + (i * 8), 0x00000000);
123 nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000);
124 nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000);
125 }
126
127 return 0;
128}
129
130static int
131nv50_graph_fini(struct drm_device *dev, int engine, bool suspend)
132{
133 nv_wr32(dev, 0x40013c, 0x00000000);
134 return 0;
135}
136
137static int
138nv50_graph_context_new(struct nouveau_channel *chan, int engine)
139{
140 struct drm_device *dev = chan->dev;
141 struct drm_nouveau_private *dev_priv = dev->dev_private;
142 struct nouveau_gpuobj *ramin = chan->ramin;
143 struct nouveau_gpuobj *grctx = NULL;
144 struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
145 int hdr, ret;
146
147 NV_DEBUG(dev, "ch%d\n", chan->id);
148
149 ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0,
150 NVOBJ_FLAG_ZERO_ALLOC |
151 NVOBJ_FLAG_ZERO_FREE, &grctx);
152 if (ret)
153 return ret;
154
155 hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
156 nv_wo32(ramin, hdr + 0x00, 0x00190002);
157 nv_wo32(ramin, hdr + 0x04, grctx->vinst + grctx->size - 1);
158 nv_wo32(ramin, hdr + 0x08, grctx->vinst);
159 nv_wo32(ramin, hdr + 0x0c, 0);
160 nv_wo32(ramin, hdr + 0x10, 0);
161 nv_wo32(ramin, hdr + 0x14, 0x00010000);
162
163 nv50_grctx_fill(dev, grctx);
164 nv_wo32(grctx, 0x00000, chan->ramin->vinst >> 12);
165
166 dev_priv->engine.instmem.flush(dev);
167
168 atomic_inc(&chan->vm->engref[NVOBJ_ENGINE_GR]);
169 chan->engctx[NVOBJ_ENGINE_GR] = grctx;
170 return 0;
171}
172
173static void
174nv50_graph_context_del(struct nouveau_channel *chan, int engine)
175{
176 struct nouveau_gpuobj *grctx = chan->engctx[engine];
177 struct drm_device *dev = chan->dev;
178 struct drm_nouveau_private *dev_priv = dev->dev_private;
179 int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
180
181 for (i = hdr; i < hdr + 24; i += 4)
182 nv_wo32(chan->ramin, i, 0);
183 dev_priv->engine.instmem.flush(dev);
184
185 atomic_dec(&chan->vm->engref[engine]);
186 nouveau_gpuobj_ref(NULL, &grctx);
187 chan->engctx[engine] = NULL;
188}
189
190static int
191nv50_graph_object_new(struct nouveau_channel *chan, int engine,
192 u32 handle, u16 class)
193{
194 struct drm_device *dev = chan->dev;
195 struct drm_nouveau_private *dev_priv = dev->dev_private;
196 struct nouveau_gpuobj *obj = NULL;
197 int ret;
198
199 ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
200 if (ret)
201 return ret;
202 obj->engine = 1;
203 obj->class = class;
204
205 nv_wo32(obj, 0x00, class);
206 nv_wo32(obj, 0x04, 0x00000000);
207 nv_wo32(obj, 0x08, 0x00000000);
208 nv_wo32(obj, 0x0c, 0x00000000);
209 dev_priv->engine.instmem.flush(dev);
210
211 ret = nouveau_ramht_insert(chan, handle, obj);
212 nouveau_gpuobj_ref(NULL, &obj);
213 return ret;
214}
215
216static void
217nv50_graph_tlb_flush(struct drm_device *dev, int engine)
218{
219 nv50_vm_flush_engine(dev, 0);
220}
221
222static void
223nv84_graph_tlb_flush(struct drm_device *dev, int engine)
224{
225 struct drm_nouveau_private *dev_priv = dev->dev_private;
226 struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
227 bool idle, timeout = false;
228 unsigned long flags;
229 u64 start;
230 u32 tmp;
231
232 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
233 nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
234
235 start = ptimer->read(dev);
236 do {
237 idle = true;
238
239 for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
240 if ((tmp & 7) == 1)
241 idle = false;
242 }
243
244 for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
245 if ((tmp & 7) == 1)
246 idle = false;
247 }
248
249 for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
250 if ((tmp & 7) == 1)
251 idle = false;
252 }
253 } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000));
254
255 if (timeout) {
256 NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
257 "0x%08x 0x%08x 0x%08x 0x%08x\n",
258 nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
259 nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
260 }
261
262 nv50_vm_flush_engine(dev, 0);
263
264 nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
265 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
266}
267
268static struct nouveau_enum nv50_mp_exec_error_names[] = {
269 { 3, "STACK_UNDERFLOW", NULL },
270 { 4, "QUADON_ACTIVE", NULL },
271 { 8, "TIMEOUT", NULL },
272 { 0x10, "INVALID_OPCODE", NULL },
273 { 0x40, "BREAKPOINT", NULL },
274 {}
275};
276
277static struct nouveau_bitfield nv50_graph_trap_m2mf[] = {
278 { 0x00000001, "NOTIFY" },
279 { 0x00000002, "IN" },
280 { 0x00000004, "OUT" },
281 {}
282};
283
284static struct nouveau_bitfield nv50_graph_trap_vfetch[] = {
285 { 0x00000001, "FAULT" },
286 {}
287};
288
289static struct nouveau_bitfield nv50_graph_trap_strmout[] = {
290 { 0x00000001, "FAULT" },
291 {}
292};
293
294static struct nouveau_bitfield nv50_graph_trap_ccache[] = {
295 { 0x00000001, "FAULT" },
296 {}
297};
298
299/* There must be a *lot* of these. Will take some time to gather them up. */
300struct nouveau_enum nv50_data_error_names[] = {
301 { 0x00000003, "INVALID_OPERATION", NULL },
302 { 0x00000004, "INVALID_VALUE", NULL },
303 { 0x00000005, "INVALID_ENUM", NULL },
304 { 0x00000008, "INVALID_OBJECT", NULL },
305 { 0x00000009, "READ_ONLY_OBJECT", NULL },
306 { 0x0000000a, "SUPERVISOR_OBJECT", NULL },
307 { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL },
308 { 0x0000000c, "INVALID_BITFIELD", NULL },
309 { 0x0000000d, "BEGIN_END_ACTIVE", NULL },
310 { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL },
311 { 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL },
312 { 0x00000010, "RT_DOUBLE_BIND", NULL },
313 { 0x00000011, "RT_TYPES_MISMATCH", NULL },
314 { 0x00000012, "RT_LINEAR_WITH_ZETA", NULL },
315 { 0x00000015, "FP_TOO_FEW_REGS", NULL },
316 { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL },
317 { 0x00000017, "RT_LINEAR_WITH_MSAA", NULL },
318 { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL },
319 { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL },
320 { 0x0000001a, "RT_INVALID_ALIGNMENT", NULL },
321 { 0x0000001b, "SAMPLER_OVER_LIMIT", NULL },
322 { 0x0000001c, "TEXTURE_OVER_LIMIT", NULL },
323 { 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL },
324 { 0x0000001f, "RT_BPP128_WITH_MS8", NULL },
325 { 0x00000021, "Z_OUT_OF_BOUNDS", NULL },
326 { 0x00000023, "XY_OUT_OF_BOUNDS", NULL },
327 { 0x00000024, "VP_ZERO_INPUTS", NULL },
328 { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL },
329 { 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL },
330 { 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL },
331 { 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL },
332 { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL },
333 { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL },
334 { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL },
335 { 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL },
336 { 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL },
337 { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL },
338 { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL },
339 { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL },
340 { 0x00000046, "LAYER_ID_NEEDS_GP", NULL },
341 { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL },
342 { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL },
343 {}
344};
345
346static struct nouveau_bitfield nv50_graph_intr[] = {
347 { 0x00000001, "NOTIFY" },
348 { 0x00000002, "COMPUTE_QUERY" },
349 { 0x00000010, "ILLEGAL_MTHD" },
350 { 0x00000020, "ILLEGAL_CLASS" },
351 { 0x00000040, "DOUBLE_NOTIFY" },
352 { 0x00001000, "CONTEXT_SWITCH" },
353 { 0x00010000, "BUFFER_NOTIFY" },
354 { 0x00100000, "DATA_ERROR" },
355 { 0x00200000, "TRAP" },
356 { 0x01000000, "SINGLE_STEP" },
357 {}
358};
359
360static void
361nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
362{
363 struct drm_nouveau_private *dev_priv = dev->dev_private;
364 uint32_t units = nv_rd32(dev, 0x1540);
365 uint32_t addr, mp10, status, pc, oplow, ophigh;
366 int i;
367 int mps = 0;
368 for (i = 0; i < 4; i++) {
369 if (!(units & 1 << (i+24)))
370 continue;
371 if (dev_priv->chipset < 0xa0)
372 addr = 0x408200 + (tpid << 12) + (i << 7);
373 else
374 addr = 0x408100 + (tpid << 11) + (i << 7);
375 mp10 = nv_rd32(dev, addr + 0x10);
376 status = nv_rd32(dev, addr + 0x14);
377 if (!status)
378 continue;
379 if (display) {
380 nv_rd32(dev, addr + 0x20);
381 pc = nv_rd32(dev, addr + 0x24);
382 oplow = nv_rd32(dev, addr + 0x70);
383 ophigh = nv_rd32(dev, addr + 0x74);
384 NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
385 "TP %d MP %d: ", tpid, i);
386 nouveau_enum_print(nv50_mp_exec_error_names, status);
387 printk(" at %06x warp %d, opcode %08x %08x\n",
388 pc&0xffffff, pc >> 24,
389 oplow, ophigh);
390 }
391 nv_wr32(dev, addr + 0x10, mp10);
392 nv_wr32(dev, addr + 0x14, 0);
393 mps++;
394 }
395 if (!mps && display)
396 NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: "
397 "No MPs claiming errors?\n", tpid);
398}
399
400static void
401nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
402 uint32_t ustatus_new, int display, const char *name)
403{
404 struct drm_nouveau_private *dev_priv = dev->dev_private;
405 int tps = 0;
406 uint32_t units = nv_rd32(dev, 0x1540);
407 int i, r;
408 uint32_t ustatus_addr, ustatus;
409 for (i = 0; i < 16; i++) {
410 if (!(units & (1 << i)))
411 continue;
412 if (dev_priv->chipset < 0xa0)
413 ustatus_addr = ustatus_old + (i << 12);
414 else
415 ustatus_addr = ustatus_new + (i << 11);
416 ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff;
417 if (!ustatus)
418 continue;
419 tps++;
420 switch (type) {
421 case 6: /* texture error... unknown for now */
422 if (display) {
423 NV_ERROR(dev, "magic set %d:\n", i);
424 for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
425 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
426 nv_rd32(dev, r));
427 }
428 break;
429 case 7: /* MP error */
430 if (ustatus & 0x04030000) {
431 nv50_pgraph_mp_trap(dev, i, display);
432 ustatus &= ~0x04030000;
433 }
434 break;
435 case 8: /* TPDMA error */
436 {
437 uint32_t e0c = nv_rd32(dev, ustatus_addr + 4);
438 uint32_t e10 = nv_rd32(dev, ustatus_addr + 8);
439 uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc);
440 uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10);
441 uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
442 uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
443 uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
444 /* 2d engine destination */
445 if (ustatus & 0x00000010) {
446 if (display) {
447 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
448 i, e14, e10);
449 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
450 i, e0c, e18, e1c, e20, e24);
451 }
452 ustatus &= ~0x00000010;
453 }
454 /* Render target */
455 if (ustatus & 0x00000040) {
456 if (display) {
457 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
458 i, e14, e10);
459 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
460 i, e0c, e18, e1c, e20, e24);
461 }
462 ustatus &= ~0x00000040;
463 }
464 /* CUDA memory: l[], g[] or stack. */
465 if (ustatus & 0x00000080) {
466 if (display) {
467 if (e18 & 0x80000000) {
468 /* g[] read fault? */
469 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
470 i, e14, e10 | ((e18 >> 24) & 0x1f));
471 e18 &= ~0x1f000000;
472 } else if (e18 & 0xc) {
473 /* g[] write fault? */
474 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
475 i, e14, e10 | ((e18 >> 7) & 0x1f));
476 e18 &= ~0x00000f80;
477 } else {
478 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
479 i, e14, e10);
480 }
481 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
482 i, e0c, e18, e1c, e20, e24);
483 }
484 ustatus &= ~0x00000080;
485 }
486 }
487 break;
488 }
489 if (ustatus) {
490 if (display)
491 NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
492 }
493 nv_wr32(dev, ustatus_addr, 0xc0000000);
494 }
495
496 if (!tps && display)
497 NV_INFO(dev, "%s - No TPs claiming errors?\n", name);
498}
499
500static int
501nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid)
502{
503 u32 status = nv_rd32(dev, 0x400108);
504 u32 ustatus;
505
506 if (!status && display) {
507 NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n");
508 return 1;
509 }
510
511 /* DISPATCH: Relays commands to other units and handles NOTIFY,
512 * COND, QUERY. If you get a trap from it, the command is still stuck
513 * in DISPATCH and you need to do something about it. */
514 if (status & 0x001) {
515 ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff;
516 if (!ustatus && display) {
517 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n");
518 }
519
520 nv_wr32(dev, 0x400500, 0x00000000);
521
522 /* Known to be triggered by screwed up NOTIFY and COND... */
523 if (ustatus & 0x00000001) {
524 u32 addr = nv_rd32(dev, 0x400808);
525 u32 subc = (addr & 0x00070000) >> 16;
526 u32 mthd = (addr & 0x00001ffc);
527 u32 datal = nv_rd32(dev, 0x40080c);
528 u32 datah = nv_rd32(dev, 0x400810);
529 u32 class = nv_rd32(dev, 0x400814);
530 u32 r848 = nv_rd32(dev, 0x400848);
531
532 NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n");
533 if (display && (addr & 0x80000000)) {
534 NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) "
535 "subc %d class 0x%04x mthd 0x%04x "
536 "data 0x%08x%08x "
537 "400808 0x%08x 400848 0x%08x\n",
538 chid, inst, subc, class, mthd, datah,
539 datal, addr, r848);
540 } else
541 if (display) {
542 NV_INFO(dev, "PGRAPH - no stuck command?\n");
543 }
544
545 nv_wr32(dev, 0x400808, 0);
546 nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3);
547 nv_wr32(dev, 0x400848, 0);
548 ustatus &= ~0x00000001;
549 }
550
551 if (ustatus & 0x00000002) {
552 u32 addr = nv_rd32(dev, 0x40084c);
553 u32 subc = (addr & 0x00070000) >> 16;
554 u32 mthd = (addr & 0x00001ffc);
555 u32 data = nv_rd32(dev, 0x40085c);
556 u32 class = nv_rd32(dev, 0x400814);
557
558 NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n");
559 if (display && (addr & 0x80000000)) {
560 NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) "
561 "subc %d class 0x%04x mthd 0x%04x "
562 "data 0x%08x 40084c 0x%08x\n",
563 chid, inst, subc, class, mthd,
564 data, addr);
565 } else
566 if (display) {
567 NV_INFO(dev, "PGRAPH - no stuck command?\n");
568 }
569
570 nv_wr32(dev, 0x40084c, 0);
571 ustatus &= ~0x00000002;
572 }
573
574 if (ustatus && display) {
575 NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown "
576 "0x%08x)\n", ustatus);
577 }
578
579 nv_wr32(dev, 0x400804, 0xc0000000);
580 nv_wr32(dev, 0x400108, 0x001);
581 status &= ~0x001;
582 if (!status)
583 return 0;
584 }
585
586 /* M2MF: Memory to memory copy engine. */
587 if (status & 0x002) {
588 u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff;
589 if (display) {
590 NV_INFO(dev, "PGRAPH - TRAP_M2MF");
591 nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus);
592 printk("\n");
593 NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n",
594 nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808),
595 nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810));
596
597 }
598
599 /* No sane way found yet -- just reset the bugger. */
600 nv_wr32(dev, 0x400040, 2);
601 nv_wr32(dev, 0x400040, 0);
602 nv_wr32(dev, 0x406800, 0xc0000000);
603 nv_wr32(dev, 0x400108, 0x002);
604 status &= ~0x002;
605 }
606
607 /* VFETCH: Fetches data from vertex buffers. */
608 if (status & 0x004) {
609 u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff;
610 if (display) {
611 NV_INFO(dev, "PGRAPH - TRAP_VFETCH");
612 nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus);
613 printk("\n");
614 NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n",
615 nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08),
616 nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10));
617 }
618
619 nv_wr32(dev, 0x400c04, 0xc0000000);
620 nv_wr32(dev, 0x400108, 0x004);
621 status &= ~0x004;
622 }
623
624 /* STRMOUT: DirectX streamout / OpenGL transform feedback. */
625 if (status & 0x008) {
626 ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff;
627 if (display) {
628 NV_INFO(dev, "PGRAPH - TRAP_STRMOUT");
629 nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus);
630 printk("\n");
631 NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n",
632 nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808),
633 nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810));
634
635 }
636
637 /* No sane way found yet -- just reset the bugger. */
638 nv_wr32(dev, 0x400040, 0x80);
639 nv_wr32(dev, 0x400040, 0);
640 nv_wr32(dev, 0x401800, 0xc0000000);
641 nv_wr32(dev, 0x400108, 0x008);
642 status &= ~0x008;
643 }
644
645 /* CCACHE: Handles code and c[] caches and fills them. */
646 if (status & 0x010) {
647 ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff;
648 if (display) {
649 NV_INFO(dev, "PGRAPH - TRAP_CCACHE");
650 nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus);
651 printk("\n");
652 NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x"
653 " %08x %08x %08x\n",
654 nv_rd32(dev, 0x405000), nv_rd32(dev, 0x405004),
655 nv_rd32(dev, 0x405008), nv_rd32(dev, 0x40500c),
656 nv_rd32(dev, 0x405010), nv_rd32(dev, 0x405014),
657 nv_rd32(dev, 0x40501c));
658
659 }
660
661 nv_wr32(dev, 0x405018, 0xc0000000);
662 nv_wr32(dev, 0x400108, 0x010);
663 status &= ~0x010;
664 }
665
666 /* Unknown, not seen yet... 0x402000 is the only trap status reg
667 * remaining, so try to handle it anyway. Perhaps related to that
668 * unknown DMA slot on tesla? */
669 if (status & 0x20) {
670 ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
671 if (display)
672 NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus);
673 nv_wr32(dev, 0x402000, 0xc0000000);
674 /* no status modifiction on purpose */
675 }
676
677 /* TEXTURE: CUDA texturing units */
678 if (status & 0x040) {
679 nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display,
680 "PGRAPH - TRAP_TEXTURE");
681 nv_wr32(dev, 0x400108, 0x040);
682 status &= ~0x040;
683 }
684
685 /* MP: CUDA execution engines. */
686 if (status & 0x080) {
687 nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display,
688 "PGRAPH - TRAP_MP");
689 nv_wr32(dev, 0x400108, 0x080);
690 status &= ~0x080;
691 }
692
693 /* TPDMA: Handles TP-initiated uncached memory accesses:
694 * l[], g[], stack, 2d surfaces, render targets. */
695 if (status & 0x100) {
696 nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display,
697 "PGRAPH - TRAP_TPDMA");
698 nv_wr32(dev, 0x400108, 0x100);
699 status &= ~0x100;
700 }
701
702 if (status) {
703 if (display)
704 NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status);
705 nv_wr32(dev, 0x400108, status);
706 }
707
708 return 1;
709}
710
711int
712nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
713{
714 struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
715 struct drm_nouveau_private *dev_priv = dev->dev_private;
716 struct nouveau_channel *chan;
717 unsigned long flags;
718 int i;
719
720 spin_lock_irqsave(&dev_priv->channels.lock, flags);
721 for (i = 0; i < pfifo->channels; i++) {
722 chan = dev_priv->channels.ptr[i];
723 if (!chan || !chan->ramin)
724 continue;
725
726 if (inst == chan->ramin->vinst)
727 break;
728 }
729 spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
730 return i;
731}
732
733static void
734nv50_graph_isr(struct drm_device *dev)
735{
736 u32 stat;
737
738 while ((stat = nv_rd32(dev, 0x400100))) {
739 u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12;
740 u32 chid = nv50_graph_isr_chid(dev, inst);
741 u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
742 u32 subc = (addr & 0x00070000) >> 16;
743 u32 mthd = (addr & 0x00001ffc);
744 u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
745 u32 class = nv_rd32(dev, 0x400814);
746 u32 show = stat;
747
748 if (stat & 0x00000010) {
749 if (!nouveau_gpuobj_mthd_call2(dev, chid, class,
750 mthd, data))
751 show &= ~0x00000010;
752 }
753
754 show = (show && nouveau_ratelimit()) ? show : 0;
755
756 if (show & 0x00100000) {
757 u32 ecode = nv_rd32(dev, 0x400110);
758 NV_INFO(dev, "PGRAPH - DATA_ERROR ");
759 nouveau_enum_print(nv50_data_error_names, ecode);
760 printk("\n");
761 }
762
763 if (stat & 0x00200000) {
764 if (!nv50_pgraph_trap_handler(dev, show, inst, chid))
765 show &= ~0x00200000;
766 }
767
768 nv_wr32(dev, 0x400100, stat);
769 nv_wr32(dev, 0x400500, 0x00010001);
770
771 if (show) {
772 NV_INFO(dev, "PGRAPH -");
773 nouveau_bitfield_print(nv50_graph_intr, show);
774 printk("\n");
775 NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d "
776 "class 0x%04x mthd 0x%04x data 0x%08x\n",
777 chid, inst, subc, class, mthd, data);
778 nv50_fb_vm_trap(dev, 1);
779 }
780 }
781
782 if (nv_rd32(dev, 0x400824) & (1 << 31))
783 nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
784}
785
786static void
787nv50_graph_destroy(struct drm_device *dev, int engine)
788{
789 struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
790
791 NVOBJ_ENGINE_DEL(dev, GR);
792
793 nouveau_irq_unregister(dev, 12);
794 kfree(pgraph);
795}
796
797int
798nv50_graph_create(struct drm_device *dev)
799{
800 struct drm_nouveau_private *dev_priv = dev->dev_private;
801 struct nv50_graph_engine *pgraph;
802 int ret;
803
804 pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
805 if (!pgraph)
806 return -ENOMEM;
807
808 ret = nv50_grctx_init(dev, pgraph->ctxprog, ARRAY_SIZE(pgraph->ctxprog),
809 &pgraph->ctxprog_size,
810 &pgraph->grctx_size);
811 if (ret) {
812 NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
813 kfree(pgraph);
814 return 0;
815 }
816
817 pgraph->base.destroy = nv50_graph_destroy;
818 pgraph->base.init = nv50_graph_init;
819 pgraph->base.fini = nv50_graph_fini;
820 pgraph->base.context_new = nv50_graph_context_new;
821 pgraph->base.context_del = nv50_graph_context_del;
822 pgraph->base.object_new = nv50_graph_object_new;
823 if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac)
824 pgraph->base.tlb_flush = nv50_graph_tlb_flush;
825 else
826 pgraph->base.tlb_flush = nv84_graph_tlb_flush;
827
828 nouveau_irq_register(dev, 12, nv50_graph_isr);
829
830 NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
831 NVOBJ_CLASS(dev, 0x0030, GR); /* null */
832 NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
833 NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
834
835 /* tesla */
836 if (dev_priv->chipset == 0x50)
837 NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
838 else
839 if (dev_priv->chipset < 0xa0)
840 NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
841 else {
842 switch (dev_priv->chipset) {
843 case 0xa0:
844 case 0xaa:
845 case 0xac:
846 NVOBJ_CLASS(dev, 0x8397, GR);
847 break;
848 case 0xa3:
849 case 0xa5:
850 case 0xa8:
851 NVOBJ_CLASS(dev, 0x8597, GR);
852 break;
853 case 0xaf:
854 NVOBJ_CLASS(dev, 0x8697, GR);
855 break;
856 }
857 }
858
859 /* compute */
860 NVOBJ_CLASS(dev, 0x50c0, GR);
861 if (dev_priv->chipset > 0xa0 &&
862 dev_priv->chipset != 0xaa &&
863 dev_priv->chipset != 0xac)
864 NVOBJ_CLASS(dev, 0x85c0, GR);
865
866 return 0;
867}