blob: e2f2d59be3ead072fd9960d71add40746ce48d7a [file] [log] [blame]
Ben Skeggs6ee73862009-12-11 19:24:15 +10001/*
2 * Copyright (C) 2006 Ben Skeggs.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28/*
29 * Authors:
30 * Ben Skeggs <darktama@iinet.net.au>
31 */
32
33#include "drmP.h"
34#include "drm.h"
35#include "nouveau_drm.h"
36#include "nouveau_drv.h"
37#include "nouveau_reg.h"
Ben Skeggsa8eaebc2010-09-01 15:24:31 +100038#include "nouveau_ramht.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +100039#include <linux/ratelimit.h>
40
41/* needed for hotplug irq */
42#include "nouveau_connector.h"
43#include "nv50_display.h"
44
Jiri Slabyda3bd822010-10-05 15:07:33 +020045static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
46
47static int nouveau_ratelimit(void)
48{
49 return __ratelimit(&nouveau_ratelimit_state);
50}
51
Ben Skeggs6ee73862009-12-11 19:24:15 +100052void
53nouveau_irq_preinstall(struct drm_device *dev)
54{
55 struct drm_nouveau_private *dev_priv = dev->dev_private;
56
57 /* Master disable */
58 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
59
Ben Skeggs4b223ee2010-08-03 10:00:56 +100060 if (dev_priv->card_type >= NV_50) {
Ben Skeggs6ee73862009-12-11 19:24:15 +100061 INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
Ben Skeggsa5acac62010-03-30 15:14:41 +100062 INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
Ben Skeggs6ee73862009-12-11 19:24:15 +100063 INIT_LIST_HEAD(&dev_priv->vbl_waiting);
64 }
65}
66
67int
68nouveau_irq_postinstall(struct drm_device *dev)
69{
70 /* Master enable */
71 nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE);
72 return 0;
73}
74
75void
76nouveau_irq_uninstall(struct drm_device *dev)
77{
78 /* Master disable */
79 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
80}
81
82static int
83nouveau_call_method(struct nouveau_channel *chan, int class, int mthd, int data)
84{
85 struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
86 struct nouveau_pgraph_object_method *grm;
87 struct nouveau_pgraph_object_class *grc;
88
89 grc = dev_priv->engine.graph.grclass;
90 while (grc->id) {
91 if (grc->id == class)
92 break;
93 grc++;
94 }
95
96 if (grc->id != class || !grc->methods)
97 return -ENOENT;
98
99 grm = grc->methods;
100 while (grm->id) {
101 if (grm->id == mthd)
102 return grm->exec(chan, class, mthd, data);
103 grm++;
104 }
105
106 return -ENOENT;
107}
108
109static bool
110nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data)
111{
112 struct drm_device *dev = chan->dev;
113 const int subc = (addr >> 13) & 0x7;
114 const int mthd = addr & 0x1ffc;
115
116 if (mthd == 0x0000) {
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000117 struct nouveau_gpuobj *gpuobj;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000118
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000119 gpuobj = nouveau_ramht_find(chan, data);
120 if (!gpuobj)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000121 return false;
122
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000123 if (gpuobj->engine != NVOBJ_ENGINE_SW)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000124 return false;
125
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000126 chan->sw_subchannel[subc] = gpuobj->class;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000127 nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev,
128 NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4));
129 return true;
130 }
131
132 /* hw object */
133 if (nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE) & (1 << (subc*4)))
134 return false;
135
136 if (nouveau_call_method(chan, chan->sw_subchannel[subc], mthd, data))
137 return false;
138
139 return true;
140}
141
142static void
143nouveau_fifo_irq_handler(struct drm_device *dev)
144{
145 struct drm_nouveau_private *dev_priv = dev->dev_private;
146 struct nouveau_engine *engine = &dev_priv->engine;
147 uint32_t status, reassign;
148 int cnt = 0;
149
150 reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1;
151 while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
152 struct nouveau_channel *chan = NULL;
153 uint32_t chid, get;
154
155 nv_wr32(dev, NV03_PFIFO_CACHES, 0);
156
157 chid = engine->fifo.channel_id(dev);
158 if (chid >= 0 && chid < engine->fifo.channels)
159 chan = dev_priv->fifos[chid];
160 get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET);
161
162 if (status & NV_PFIFO_INTR_CACHE_ERROR) {
163 uint32_t mthd, data;
164 int ptr;
165
166 /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before
167 * wrapping on my G80 chips, but CACHE1 isn't big
168 * enough for this much data.. Tests show that it
169 * wraps around to the start at GET=0x800.. No clue
170 * as to why..
171 */
172 ptr = (get & 0x7ff) >> 2;
173
174 if (dev_priv->card_type < NV_40) {
175 mthd = nv_rd32(dev,
176 NV04_PFIFO_CACHE1_METHOD(ptr));
177 data = nv_rd32(dev,
178 NV04_PFIFO_CACHE1_DATA(ptr));
179 } else {
180 mthd = nv_rd32(dev,
181 NV40_PFIFO_CACHE1_METHOD(ptr));
182 data = nv_rd32(dev,
183 NV40_PFIFO_CACHE1_DATA(ptr));
184 }
185
186 if (!chan || !nouveau_fifo_swmthd(chan, mthd, data)) {
187 NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d "
188 "Mthd 0x%04x Data 0x%08x\n",
189 chid, (mthd >> 13) & 7, mthd & 0x1ffc,
190 data);
191 }
192
193 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
194 nv_wr32(dev, NV03_PFIFO_INTR_0,
195 NV_PFIFO_INTR_CACHE_ERROR);
196
197 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
198 nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1);
199 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
200 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
201 nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1);
202 nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
203
204 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH,
205 nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
206 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
207
208 status &= ~NV_PFIFO_INTR_CACHE_ERROR;
209 }
210
211 if (status & NV_PFIFO_INTR_DMA_PUSHER) {
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200212 u32 dma_get = nv_rd32(dev, 0x003244);
213 u32 dma_put = nv_rd32(dev, 0x003240);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000214 u32 push = nv_rd32(dev, 0x003220);
215 u32 state = nv_rd32(dev, 0x003228);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000216
Ben Skeggse071f8c2010-09-08 15:40:30 +1000217 if (dev_priv->card_type == NV_50) {
218 u32 ho_get = nv_rd32(dev, 0x003328);
219 u32 ho_put = nv_rd32(dev, 0x003320);
220 u32 ib_get = nv_rd32(dev, 0x003334);
221 u32 ib_put = nv_rd32(dev, 0x003330);
222
Jiri Slabyda3bd822010-10-05 15:07:33 +0200223 if (nouveau_ratelimit())
224 NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
Ben Skeggse071f8c2010-09-08 15:40:30 +1000225 "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
226 "State 0x%08x Push 0x%08x\n",
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200227 chid, ho_get, dma_get, ho_put,
228 dma_put, ib_get, ib_put, state,
229 push);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000230
231 /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
232 nv_wr32(dev, 0x003364, 0x00000000);
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200233 if (dma_get != dma_put || ho_get != ho_put) {
234 nv_wr32(dev, 0x003244, dma_put);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000235 nv_wr32(dev, 0x003328, ho_put);
236 } else
237 if (ib_get != ib_put) {
238 nv_wr32(dev, 0x003334, ib_put);
239 }
240 } else {
241 NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
242 "Put 0x%08x State 0x%08x Push 0x%08x\n",
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200243 chid, dma_get, dma_put, state, push);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000244
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200245 if (dma_get != dma_put)
246 nv_wr32(dev, 0x003244, dma_put);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000247 }
248
249 nv_wr32(dev, 0x003228, 0x00000000);
250 nv_wr32(dev, 0x003220, 0x00000001);
251 nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000252 status &= ~NV_PFIFO_INTR_DMA_PUSHER;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000253 }
254
Francisco Jerez139295b2010-01-30 18:28:00 +0100255 if (status & NV_PFIFO_INTR_SEMAPHORE) {
256 uint32_t sem;
257
258 status &= ~NV_PFIFO_INTR_SEMAPHORE;
259 nv_wr32(dev, NV03_PFIFO_INTR_0,
260 NV_PFIFO_INTR_SEMAPHORE);
261
262 sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE);
263 nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
264
265 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
266 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
267 }
268
Ben Skeggs1da26562010-09-03 15:56:12 +1000269 if (dev_priv->card_type == NV_50) {
270 if (status & 0x00000010) {
271 nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT");
272 status &= ~0x00000010;
273 nv_wr32(dev, 0x002100, 0x00000010);
274 }
275 }
276
Ben Skeggs6ee73862009-12-11 19:24:15 +1000277 if (status) {
Jiri Slabyda3bd822010-10-05 15:07:33 +0200278 if (nouveau_ratelimit())
279 NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
280 status, chid);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000281 nv_wr32(dev, NV03_PFIFO_INTR_0, status);
282 status = 0;
283 }
284
285 nv_wr32(dev, NV03_PFIFO_CACHES, reassign);
286 }
287
288 if (status) {
289 NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt);
290 nv_wr32(dev, 0x2140, 0);
291 nv_wr32(dev, 0x140, 0);
292 }
293
294 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
295}
296
297struct nouveau_bitfield_names {
298 uint32_t mask;
299 const char *name;
300};
301
302static struct nouveau_bitfield_names nstatus_names[] =
303{
304 { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
305 { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
306 { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
307 { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }
308};
309
310static struct nouveau_bitfield_names nstatus_names_nv10[] =
311{
312 { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
313 { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
314 { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
315 { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }
316};
317
318static struct nouveau_bitfield_names nsource_names[] =
319{
320 { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
321 { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
322 { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
323 { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
324 { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
325 { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
326 { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
327 { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
328 { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
329 { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
330 { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
331 { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
332 { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
333 { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
334 { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
335 { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
336 { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
337 { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
338 { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
339};
340
341static void
342nouveau_print_bitfield_names_(uint32_t value,
343 const struct nouveau_bitfield_names *namelist,
344 const int namelist_len)
345{
346 /*
347 * Caller must have already printed the KERN_* log level for us.
348 * Also the caller is responsible for adding the newline.
349 */
350 int i;
351 for (i = 0; i < namelist_len; ++i) {
352 uint32_t mask = namelist[i].mask;
353 if (value & mask) {
354 printk(" %s", namelist[i].name);
355 value &= ~mask;
356 }
357 }
358 if (value)
359 printk(" (unknown bits 0x%08x)", value);
360}
361#define nouveau_print_bitfield_names(val, namelist) \
362 nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist))
363
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000364struct nouveau_enum_names {
365 uint32_t value;
366 const char *name;
367};
368
369static void
370nouveau_print_enum_names_(uint32_t value,
371 const struct nouveau_enum_names *namelist,
372 const int namelist_len)
373{
374 /*
375 * Caller must have already printed the KERN_* log level for us.
376 * Also the caller is responsible for adding the newline.
377 */
378 int i;
379 for (i = 0; i < namelist_len; ++i) {
380 if (value == namelist[i].value) {
381 printk("%s", namelist[i].name);
382 return;
383 }
384 }
385 printk("unknown value 0x%08x", value);
386}
387#define nouveau_print_enum_names(val, namelist) \
388 nouveau_print_enum_names_((val), (namelist), ARRAY_SIZE(namelist))
Ben Skeggs6ee73862009-12-11 19:24:15 +1000389
390static int
391nouveau_graph_chid_from_grctx(struct drm_device *dev)
392{
393 struct drm_nouveau_private *dev_priv = dev->dev_private;
394 uint32_t inst;
395 int i;
396
397 if (dev_priv->card_type < NV_40)
398 return dev_priv->engine.fifo.channels;
399 else
400 if (dev_priv->card_type < NV_50) {
401 inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 4;
402
403 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
404 struct nouveau_channel *chan = dev_priv->fifos[i];
405
406 if (!chan || !chan->ramin_grctx)
407 continue;
408
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000409 if (inst == chan->ramin_grctx->pinst)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000410 break;
411 }
412 } else {
413 inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 12;
414
415 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
416 struct nouveau_channel *chan = dev_priv->fifos[i];
417
418 if (!chan || !chan->ramin)
419 continue;
420
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000421 if (inst == chan->ramin->vinst)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000422 break;
423 }
424 }
425
426
427 return i;
428}
429
430static int
431nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret)
432{
433 struct drm_nouveau_private *dev_priv = dev->dev_private;
434 struct nouveau_engine *engine = &dev_priv->engine;
435 int channel;
436
437 if (dev_priv->card_type < NV_10)
438 channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0xf;
439 else
440 if (dev_priv->card_type < NV_40)
441 channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
442 else
443 channel = nouveau_graph_chid_from_grctx(dev);
444
445 if (channel >= engine->fifo.channels || !dev_priv->fifos[channel]) {
446 NV_ERROR(dev, "AIII, invalid/inactive channel id %d\n", channel);
447 return -EINVAL;
448 }
449
450 *channel_ret = channel;
451 return 0;
452}
453
454struct nouveau_pgraph_trap {
455 int channel;
456 int class;
457 int subc, mthd, size;
458 uint32_t data, data2;
459 uint32_t nsource, nstatus;
460};
461
462static void
463nouveau_graph_trap_info(struct drm_device *dev,
464 struct nouveau_pgraph_trap *trap)
465{
466 struct drm_nouveau_private *dev_priv = dev->dev_private;
467 uint32_t address;
468
469 trap->nsource = trap->nstatus = 0;
470 if (dev_priv->card_type < NV_50) {
471 trap->nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
472 trap->nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
473 }
474
475 if (nouveau_graph_trapped_channel(dev, &trap->channel))
476 trap->channel = -1;
477 address = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
478
479 trap->mthd = address & 0x1FFC;
480 trap->data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
481 if (dev_priv->card_type < NV_10) {
482 trap->subc = (address >> 13) & 0x7;
483 } else {
484 trap->subc = (address >> 16) & 0x7;
485 trap->data2 = nv_rd32(dev, NV10_PGRAPH_TRAPPED_DATA_HIGH);
486 }
487
488 if (dev_priv->card_type < NV_10)
489 trap->class = nv_rd32(dev, 0x400180 + trap->subc*4) & 0xFF;
490 else if (dev_priv->card_type < NV_40)
491 trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFF;
492 else if (dev_priv->card_type < NV_50)
493 trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFFF;
494 else
495 trap->class = nv_rd32(dev, 0x400814);
496}
497
498static void
499nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id,
500 struct nouveau_pgraph_trap *trap)
501{
502 struct drm_nouveau_private *dev_priv = dev->dev_private;
503 uint32_t nsource = trap->nsource, nstatus = trap->nstatus;
504
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000505 if (dev_priv->card_type < NV_50) {
506 NV_INFO(dev, "%s - nSource:", id);
507 nouveau_print_bitfield_names(nsource, nsource_names);
508 printk(", nStatus:");
509 if (dev_priv->card_type < NV_10)
510 nouveau_print_bitfield_names(nstatus, nstatus_names);
511 else
512 nouveau_print_bitfield_names(nstatus, nstatus_names_nv10);
513 printk("\n");
514 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000515
516 NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x "
517 "Data 0x%08x:0x%08x\n",
518 id, trap->channel, trap->subc,
519 trap->class, trap->mthd,
520 trap->data2, trap->data);
521}
522
523static int
524nouveau_pgraph_intr_swmthd(struct drm_device *dev,
525 struct nouveau_pgraph_trap *trap)
526{
527 struct drm_nouveau_private *dev_priv = dev->dev_private;
528
529 if (trap->channel < 0 ||
530 trap->channel >= dev_priv->engine.fifo.channels ||
531 !dev_priv->fifos[trap->channel])
532 return -ENODEV;
533
534 return nouveau_call_method(dev_priv->fifos[trap->channel],
535 trap->class, trap->mthd, trap->data);
536}
537
538static inline void
539nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource)
540{
541 struct nouveau_pgraph_trap trap;
542 int unhandled = 0;
543
544 nouveau_graph_trap_info(dev, &trap);
545
546 if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
547 if (nouveau_pgraph_intr_swmthd(dev, &trap))
548 unhandled = 1;
549 } else {
550 unhandled = 1;
551 }
552
553 if (unhandled)
554 nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap);
555}
556
Ben Skeggs6ee73862009-12-11 19:24:15 +1000557
558static inline void
559nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
560{
561 struct nouveau_pgraph_trap trap;
562 int unhandled = 0;
563
564 nouveau_graph_trap_info(dev, &trap);
565 trap.nsource = nsource;
566
567 if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
568 if (nouveau_pgraph_intr_swmthd(dev, &trap))
569 unhandled = 1;
Luca Barbierid051bbb2010-01-16 15:27:51 +0100570 } else if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
571 uint32_t v = nv_rd32(dev, 0x402000);
572 nv_wr32(dev, 0x402000, v);
573
574 /* dump the error anyway for now: it's useful for
575 Gallium development */
576 unhandled = 1;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000577 } else {
578 unhandled = 1;
579 }
580
581 if (unhandled && nouveau_ratelimit())
582 nouveau_graph_dump_trap_info(dev, "PGRAPH_ERROR", &trap);
583}
584
585static inline void
586nouveau_pgraph_intr_context_switch(struct drm_device *dev)
587{
588 struct drm_nouveau_private *dev_priv = dev->dev_private;
589 struct nouveau_engine *engine = &dev_priv->engine;
590 uint32_t chid;
591
592 chid = engine->fifo.channel_id(dev);
593 NV_DEBUG(dev, "PGRAPH context switch interrupt channel %x\n", chid);
594
595 switch (dev_priv->card_type) {
596 case NV_04:
597 nv04_graph_context_switch(dev);
598 break;
599 case NV_10:
600 nv10_graph_context_switch(dev);
601 break;
602 default:
603 NV_ERROR(dev, "Context switch not implemented\n");
604 break;
605 }
606}
607
608static void
609nouveau_pgraph_irq_handler(struct drm_device *dev)
610{
611 uint32_t status;
612
613 while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) {
614 uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
615
616 if (status & NV_PGRAPH_INTR_NOTIFY) {
617 nouveau_pgraph_intr_notify(dev, nsource);
618
619 status &= ~NV_PGRAPH_INTR_NOTIFY;
620 nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY);
621 }
622
623 if (status & NV_PGRAPH_INTR_ERROR) {
624 nouveau_pgraph_intr_error(dev, nsource);
625
626 status &= ~NV_PGRAPH_INTR_ERROR;
627 nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_ERROR);
628 }
629
630 if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000631 status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
632 nv_wr32(dev, NV03_PGRAPH_INTR,
633 NV_PGRAPH_INTR_CONTEXT_SWITCH);
Francisco Jerez308dceb2010-08-04 04:41:55 +0200634
635 nouveau_pgraph_intr_context_switch(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000636 }
637
638 if (status) {
639 NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status);
640 nv_wr32(dev, NV03_PGRAPH_INTR, status);
641 }
642
643 if ((nv_rd32(dev, NV04_PGRAPH_FIFO) & (1 << 0)) == 0)
644 nv_wr32(dev, NV04_PGRAPH_FIFO, 1);
645 }
646
647 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
648}
649
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000650static struct nouveau_enum_names nv50_mp_exec_error_names[] =
651{
652 { 3, "STACK_UNDERFLOW" },
653 { 4, "QUADON_ACTIVE" },
654 { 8, "TIMEOUT" },
655 { 0x10, "INVALID_OPCODE" },
656 { 0x40, "BREAKPOINT" },
657};
658
659static void
660nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
661{
662 struct drm_nouveau_private *dev_priv = dev->dev_private;
663 uint32_t units = nv_rd32(dev, 0x1540);
664 uint32_t addr, mp10, status, pc, oplow, ophigh;
665 int i;
666 int mps = 0;
667 for (i = 0; i < 4; i++) {
668 if (!(units & 1 << (i+24)))
669 continue;
670 if (dev_priv->chipset < 0xa0)
671 addr = 0x408200 + (tpid << 12) + (i << 7);
672 else
673 addr = 0x408100 + (tpid << 11) + (i << 7);
674 mp10 = nv_rd32(dev, addr + 0x10);
675 status = nv_rd32(dev, addr + 0x14);
676 if (!status)
677 continue;
678 if (display) {
679 nv_rd32(dev, addr + 0x20);
680 pc = nv_rd32(dev, addr + 0x24);
681 oplow = nv_rd32(dev, addr + 0x70);
682 ophigh= nv_rd32(dev, addr + 0x74);
683 NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
684 "TP %d MP %d: ", tpid, i);
685 nouveau_print_enum_names(status,
686 nv50_mp_exec_error_names);
687 printk(" at %06x warp %d, opcode %08x %08x\n",
688 pc&0xffffff, pc >> 24,
689 oplow, ophigh);
690 }
691 nv_wr32(dev, addr + 0x10, mp10);
692 nv_wr32(dev, addr + 0x14, 0);
693 mps++;
694 }
695 if (!mps && display)
696 NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: "
697 "No MPs claiming errors?\n", tpid);
698}
699
700static void
701nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
702 uint32_t ustatus_new, int display, const char *name)
703{
704 struct drm_nouveau_private *dev_priv = dev->dev_private;
705 int tps = 0;
706 uint32_t units = nv_rd32(dev, 0x1540);
707 int i, r;
708 uint32_t ustatus_addr, ustatus;
709 for (i = 0; i < 16; i++) {
710 if (!(units & (1 << i)))
711 continue;
712 if (dev_priv->chipset < 0xa0)
713 ustatus_addr = ustatus_old + (i << 12);
714 else
715 ustatus_addr = ustatus_new + (i << 11);
716 ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff;
717 if (!ustatus)
718 continue;
719 tps++;
720 switch (type) {
721 case 6: /* texture error... unknown for now */
Ben Skeggsd96773e2010-09-03 15:46:58 +1000722 nv50_fb_vm_trap(dev, display, name);
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000723 if (display) {
724 NV_ERROR(dev, "magic set %d:\n", i);
725 for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
726 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
727 nv_rd32(dev, r));
728 }
729 break;
730 case 7: /* MP error */
731 if (ustatus & 0x00010000) {
732 nv50_pgraph_mp_trap(dev, i, display);
733 ustatus &= ~0x00010000;
734 }
735 break;
736 case 8: /* TPDMA error */
737 {
738 uint32_t e0c = nv_rd32(dev, ustatus_addr + 4);
739 uint32_t e10 = nv_rd32(dev, ustatus_addr + 8);
740 uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc);
741 uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10);
742 uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
743 uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
744 uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
Ben Skeggsd96773e2010-09-03 15:46:58 +1000745 nv50_fb_vm_trap(dev, display, name);
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000746 /* 2d engine destination */
747 if (ustatus & 0x00000010) {
748 if (display) {
749 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
750 i, e14, e10);
751 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
752 i, e0c, e18, e1c, e20, e24);
753 }
754 ustatus &= ~0x00000010;
755 }
756 /* Render target */
757 if (ustatus & 0x00000040) {
758 if (display) {
759 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
760 i, e14, e10);
761 NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
762 i, e0c, e18, e1c, e20, e24);
763 }
764 ustatus &= ~0x00000040;
765 }
766 /* CUDA memory: l[], g[] or stack. */
767 if (ustatus & 0x00000080) {
768 if (display) {
769 if (e18 & 0x80000000) {
770 /* g[] read fault? */
771 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
772 i, e14, e10 | ((e18 >> 24) & 0x1f));
773 e18 &= ~0x1f000000;
774 } else if (e18 & 0xc) {
775 /* g[] write fault? */
776 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
777 i, e14, e10 | ((e18 >> 7) & 0x1f));
778 e18 &= ~0x00000f80;
779 } else {
780 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
781 i, e14, e10);
782 }
783 NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
784 i, e0c, e18, e1c, e20, e24);
785 }
786 ustatus &= ~0x00000080;
787 }
788 }
789 break;
790 }
791 if (ustatus) {
792 if (display)
793 NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
794 }
795 nv_wr32(dev, ustatus_addr, 0xc0000000);
796 }
797
798 if (!tps && display)
799 NV_INFO(dev, "%s - No TPs claiming errors?\n", name);
800}
801
802static void
803nv50_pgraph_trap_handler(struct drm_device *dev)
804{
805 struct nouveau_pgraph_trap trap;
806 uint32_t status = nv_rd32(dev, 0x400108);
807 uint32_t ustatus;
808 int display = nouveau_ratelimit();
809
810
811 if (!status && display) {
812 nouveau_graph_trap_info(dev, &trap);
813 nouveau_graph_dump_trap_info(dev, "PGRAPH_TRAP", &trap);
814 NV_INFO(dev, "PGRAPH_TRAP - no units reporting traps?\n");
815 }
816
817 /* DISPATCH: Relays commands to other units and handles NOTIFY,
818 * COND, QUERY. If you get a trap from it, the command is still stuck
819 * in DISPATCH and you need to do something about it. */
820 if (status & 0x001) {
821 ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff;
822 if (!ustatus && display) {
823 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n");
824 }
825
826 /* Known to be triggered by screwed up NOTIFY and COND... */
827 if (ustatus & 0x00000001) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000828 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000829 nv_wr32(dev, 0x400500, 0);
830 if (nv_rd32(dev, 0x400808) & 0x80000000) {
831 if (display) {
832 if (nouveau_graph_trapped_channel(dev, &trap.channel))
833 trap.channel = -1;
834 trap.class = nv_rd32(dev, 0x400814);
835 trap.mthd = nv_rd32(dev, 0x400808) & 0x1ffc;
836 trap.subc = (nv_rd32(dev, 0x400808) >> 16) & 0x7;
837 trap.data = nv_rd32(dev, 0x40080c);
838 trap.data2 = nv_rd32(dev, 0x400810);
839 nouveau_graph_dump_trap_info(dev,
840 "PGRAPH_TRAP_DISPATCH_FAULT", &trap);
841 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400808: %08x\n", nv_rd32(dev, 0x400808));
842 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400848: %08x\n", nv_rd32(dev, 0x400848));
843 }
844 nv_wr32(dev, 0x400808, 0);
845 } else if (display) {
846 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - No stuck command?\n");
847 }
848 nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3);
849 nv_wr32(dev, 0x400848, 0);
850 ustatus &= ~0x00000001;
851 }
852 if (ustatus & 0x00000002) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000853 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000854 nv_wr32(dev, 0x400500, 0);
855 if (nv_rd32(dev, 0x40084c) & 0x80000000) {
856 if (display) {
857 if (nouveau_graph_trapped_channel(dev, &trap.channel))
858 trap.channel = -1;
859 trap.class = nv_rd32(dev, 0x400814);
860 trap.mthd = nv_rd32(dev, 0x40084c) & 0x1ffc;
861 trap.subc = (nv_rd32(dev, 0x40084c) >> 16) & 0x7;
862 trap.data = nv_rd32(dev, 0x40085c);
863 trap.data2 = 0;
864 nouveau_graph_dump_trap_info(dev,
865 "PGRAPH_TRAP_DISPATCH_QUERY", &trap);
866 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - 40084c: %08x\n", nv_rd32(dev, 0x40084c));
867 }
868 nv_wr32(dev, 0x40084c, 0);
869 } else if (display) {
870 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - No stuck command?\n");
871 }
872 ustatus &= ~0x00000002;
873 }
874 if (ustatus && display)
875 NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - Unhandled ustatus 0x%08x\n", ustatus);
876 nv_wr32(dev, 0x400804, 0xc0000000);
877 nv_wr32(dev, 0x400108, 0x001);
878 status &= ~0x001;
879 }
880
881 /* TRAPs other than dispatch use the "normal" trap regs. */
882 if (status && display) {
883 nouveau_graph_trap_info(dev, &trap);
884 nouveau_graph_dump_trap_info(dev,
885 "PGRAPH_TRAP", &trap);
886 }
887
888 /* M2MF: Memory to memory copy engine. */
889 if (status & 0x002) {
890 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff;
891 if (!ustatus && display) {
892 NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n");
893 }
894 if (ustatus & 0x00000001) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000895 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000896 ustatus &= ~0x00000001;
897 }
898 if (ustatus & 0x00000002) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000899 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000900 ustatus &= ~0x00000002;
901 }
902 if (ustatus & 0x00000004) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000903 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000904 ustatus &= ~0x00000004;
905 }
906 NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n",
907 nv_rd32(dev, 0x406804),
908 nv_rd32(dev, 0x406808),
909 nv_rd32(dev, 0x40680c),
910 nv_rd32(dev, 0x406810));
911 if (ustatus && display)
912 NV_INFO(dev, "PGRAPH_TRAP_M2MF - Unhandled ustatus 0x%08x\n", ustatus);
913 /* No sane way found yet -- just reset the bugger. */
914 nv_wr32(dev, 0x400040, 2);
915 nv_wr32(dev, 0x400040, 0);
916 nv_wr32(dev, 0x406800, 0xc0000000);
917 nv_wr32(dev, 0x400108, 0x002);
918 status &= ~0x002;
919 }
920
921 /* VFETCH: Fetches data from vertex buffers. */
922 if (status & 0x004) {
923 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff;
924 if (!ustatus && display) {
925 NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n");
926 }
927 if (ustatus & 0x00000001) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000928 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000929 NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n",
930 nv_rd32(dev, 0x400c00),
931 nv_rd32(dev, 0x400c08),
932 nv_rd32(dev, 0x400c0c),
933 nv_rd32(dev, 0x400c10));
934 ustatus &= ~0x00000001;
935 }
936 if (ustatus && display)
937 NV_INFO(dev, "PGRAPH_TRAP_VFETCH - Unhandled ustatus 0x%08x\n", ustatus);
938 nv_wr32(dev, 0x400c04, 0xc0000000);
939 nv_wr32(dev, 0x400108, 0x004);
940 status &= ~0x004;
941 }
942
943 /* STRMOUT: DirectX streamout / OpenGL transform feedback. */
944 if (status & 0x008) {
945 ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff;
946 if (!ustatus && display) {
947 NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n");
948 }
949 if (ustatus & 0x00000001) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000950 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000951 NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n",
952 nv_rd32(dev, 0x401804),
953 nv_rd32(dev, 0x401808),
954 nv_rd32(dev, 0x40180c),
955 nv_rd32(dev, 0x401810));
956 ustatus &= ~0x00000001;
957 }
958 if (ustatus && display)
959 NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - Unhandled ustatus 0x%08x\n", ustatus);
960 /* No sane way found yet -- just reset the bugger. */
961 nv_wr32(dev, 0x400040, 0x80);
962 nv_wr32(dev, 0x400040, 0);
963 nv_wr32(dev, 0x401800, 0xc0000000);
964 nv_wr32(dev, 0x400108, 0x008);
965 status &= ~0x008;
966 }
967
968 /* CCACHE: Handles code and c[] caches and fills them. */
969 if (status & 0x010) {
970 ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff;
971 if (!ustatus && display) {
972 NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n");
973 }
974 if (ustatus & 0x00000001) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000975 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000976 NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n",
977 nv_rd32(dev, 0x405800),
978 nv_rd32(dev, 0x405804),
979 nv_rd32(dev, 0x405808),
980 nv_rd32(dev, 0x40580c),
981 nv_rd32(dev, 0x405810),
982 nv_rd32(dev, 0x405814),
983 nv_rd32(dev, 0x40581c));
984 ustatus &= ~0x00000001;
985 }
986 if (ustatus && display)
987 NV_INFO(dev, "PGRAPH_TRAP_CCACHE - Unhandled ustatus 0x%08x\n", ustatus);
988 nv_wr32(dev, 0x405018, 0xc0000000);
989 nv_wr32(dev, 0x400108, 0x010);
990 status &= ~0x010;
991 }
992
993 /* Unknown, not seen yet... 0x402000 is the only trap status reg
994 * remaining, so try to handle it anyway. Perhaps related to that
995 * unknown DMA slot on tesla? */
996 if (status & 0x20) {
Ben Skeggsd96773e2010-09-03 15:46:58 +1000997 nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
Marcin Kościelnicki304424e2010-03-01 00:18:39 +0000998 ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
999 if (display)
1000 NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus);
1001 nv_wr32(dev, 0x402000, 0xc0000000);
1002 /* no status modifiction on purpose */
1003 }
1004
1005 /* TEXTURE: CUDA texturing units */
1006 if (status & 0x040) {
1007 nv50_pgraph_tp_trap (dev, 6, 0x408900, 0x408600, display,
1008 "PGRAPH_TRAP_TEXTURE");
1009 nv_wr32(dev, 0x400108, 0x040);
1010 status &= ~0x040;
1011 }
1012
1013 /* MP: CUDA execution engines. */
1014 if (status & 0x080) {
1015 nv50_pgraph_tp_trap (dev, 7, 0x408314, 0x40831c, display,
1016 "PGRAPH_TRAP_MP");
1017 nv_wr32(dev, 0x400108, 0x080);
1018 status &= ~0x080;
1019 }
1020
1021 /* TPDMA: Handles TP-initiated uncached memory accesses:
1022 * l[], g[], stack, 2d surfaces, render targets. */
1023 if (status & 0x100) {
1024 nv50_pgraph_tp_trap (dev, 8, 0x408e08, 0x408708, display,
1025 "PGRAPH_TRAP_TPDMA");
1026 nv_wr32(dev, 0x400108, 0x100);
1027 status &= ~0x100;
1028 }
1029
1030 if (status) {
1031 if (display)
1032 NV_INFO(dev, "PGRAPH_TRAP - Unknown trap 0x%08x\n",
1033 status);
1034 nv_wr32(dev, 0x400108, status);
1035 }
1036}
1037
1038/* There must be a *lot* of these. Will take some time to gather them up. */
1039static struct nouveau_enum_names nv50_data_error_names[] =
1040{
1041 { 4, "INVALID_VALUE" },
1042 { 5, "INVALID_ENUM" },
1043 { 8, "INVALID_OBJECT" },
1044 { 0xc, "INVALID_BITFIELD" },
1045 { 0x28, "MP_NO_REG_SPACE" },
1046 { 0x2b, "MP_BLOCK_SIZE_MISMATCH" },
1047};
1048
1049static void
Ben Skeggs6ee73862009-12-11 19:24:15 +10001050nv50_pgraph_irq_handler(struct drm_device *dev)
1051{
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001052 struct nouveau_pgraph_trap trap;
1053 int unhandled = 0;
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001054 uint32_t status;
Ben Skeggs6ee73862009-12-11 19:24:15 +10001055
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001056 while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) {
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001057 /* NOTIFY: You've set a NOTIFY an a command and it's done. */
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001058 if (status & 0x00000001) {
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001059 nouveau_graph_trap_info(dev, &trap);
1060 if (nouveau_ratelimit())
1061 nouveau_graph_dump_trap_info(dev,
1062 "PGRAPH_NOTIFY", &trap);
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001063 status &= ~0x00000001;
1064 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001);
1065 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001066
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001067 /* COMPUTE_QUERY: Purpose and exact cause unknown, happens
1068 * when you write 0x200 to 0x50c0 method 0x31c. */
1069 if (status & 0x00000002) {
1070 nouveau_graph_trap_info(dev, &trap);
1071 if (nouveau_ratelimit())
1072 nouveau_graph_dump_trap_info(dev,
1073 "PGRAPH_COMPUTE_QUERY", &trap);
1074 status &= ~0x00000002;
1075 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000002);
1076 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001077
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001078 /* Unknown, never seen: 0x4 */
1079
1080 /* ILLEGAL_MTHD: You used a wrong method for this class. */
1081 if (status & 0x00000010) {
1082 nouveau_graph_trap_info(dev, &trap);
1083 if (nouveau_pgraph_intr_swmthd(dev, &trap))
1084 unhandled = 1;
1085 if (unhandled && nouveau_ratelimit())
1086 nouveau_graph_dump_trap_info(dev,
1087 "PGRAPH_ILLEGAL_MTHD", &trap);
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001088 status &= ~0x00000010;
1089 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010);
1090 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001091
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001092 /* ILLEGAL_CLASS: You used a wrong class. */
1093 if (status & 0x00000020) {
1094 nouveau_graph_trap_info(dev, &trap);
1095 if (nouveau_ratelimit())
1096 nouveau_graph_dump_trap_info(dev,
1097 "PGRAPH_ILLEGAL_CLASS", &trap);
1098 status &= ~0x00000020;
1099 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000020);
1100 }
1101
1102 /* DOUBLE_NOTIFY: You tried to set a NOTIFY on another NOTIFY. */
1103 if (status & 0x00000040) {
1104 nouveau_graph_trap_info(dev, &trap);
1105 if (nouveau_ratelimit())
1106 nouveau_graph_dump_trap_info(dev,
1107 "PGRAPH_DOUBLE_NOTIFY", &trap);
1108 status &= ~0x00000040;
1109 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000040);
1110 }
1111
1112 /* CONTEXT_SWITCH: PGRAPH needs us to load a new context */
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001113 if (status & 0x00001000) {
1114 nv_wr32(dev, 0x400500, 0x00000000);
1115 nv_wr32(dev, NV03_PGRAPH_INTR,
1116 NV_PGRAPH_INTR_CONTEXT_SWITCH);
1117 nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev,
1118 NV40_PGRAPH_INTR_EN) &
1119 ~NV_PGRAPH_INTR_CONTEXT_SWITCH);
1120 nv_wr32(dev, 0x400500, 0x00010001);
Ben Skeggs6ee73862009-12-11 19:24:15 +10001121
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001122 nv50_graph_context_switch(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +10001123
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001124 status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
1125 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001126
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001127 /* BUFFER_NOTIFY: Your m2mf transfer finished */
1128 if (status & 0x00010000) {
1129 nouveau_graph_trap_info(dev, &trap);
1130 if (nouveau_ratelimit())
1131 nouveau_graph_dump_trap_info(dev,
1132 "PGRAPH_BUFFER_NOTIFY", &trap);
1133 status &= ~0x00010000;
1134 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00010000);
1135 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001136
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001137 /* DATA_ERROR: Invalid value for this method, or invalid
1138 * state in current PGRAPH context for this operation */
1139 if (status & 0x00100000) {
1140 nouveau_graph_trap_info(dev, &trap);
1141 if (nouveau_ratelimit()) {
1142 nouveau_graph_dump_trap_info(dev,
1143 "PGRAPH_DATA_ERROR", &trap);
1144 NV_INFO (dev, "PGRAPH_DATA_ERROR - ");
1145 nouveau_print_enum_names(nv_rd32(dev, 0x400110),
1146 nv50_data_error_names);
1147 printk("\n");
1148 }
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001149 status &= ~0x00100000;
1150 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000);
1151 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001152
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001153 /* TRAP: Something bad happened in the middle of command
1154 * execution. Has a billion types, subtypes, and even
1155 * subsubtypes. */
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001156 if (status & 0x00200000) {
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001157 nv50_pgraph_trap_handler(dev);
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001158 status &= ~0x00200000;
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001159 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000);
1160 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001161
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001162 /* Unknown, never seen: 0x00400000 */
1163
1164 /* SINGLE_STEP: Happens on every method if you turned on
1165 * single stepping in 40008c */
1166 if (status & 0x01000000) {
1167 nouveau_graph_trap_info(dev, &trap);
1168 if (nouveau_ratelimit())
1169 nouveau_graph_dump_trap_info(dev,
1170 "PGRAPH_SINGLE_STEP", &trap);
1171 status &= ~0x01000000;
1172 nv_wr32(dev, NV03_PGRAPH_INTR, 0x01000000);
1173 }
1174
1175 /* 0x02000000 happens when you pause a ctxprog...
1176 * but the only way this can happen that I know is by
1177 * poking the relevant MMIO register, and we don't
1178 * do that. */
1179
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001180 if (status) {
1181 NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n",
1182 status);
1183 nv_wr32(dev, NV03_PGRAPH_INTR, status);
1184 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001185
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001186 {
1187 const int isb = (1 << 16) | (1 << 0);
Ben Skeggs6ee73862009-12-11 19:24:15 +10001188
Maarten Maathuisb1d37aa2010-01-20 19:54:34 +01001189 if ((nv_rd32(dev, 0x400500) & isb) != isb)
1190 nv_wr32(dev, 0x400500,
1191 nv_rd32(dev, 0x400500) | isb);
1192 }
Ben Skeggs6ee73862009-12-11 19:24:15 +10001193 }
1194
1195 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
Marcin Kościelnicki304424e2010-03-01 00:18:39 +00001196 if (nv_rd32(dev, 0x400824) & (1 << 31))
1197 nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
Ben Skeggs6ee73862009-12-11 19:24:15 +10001198}
1199
1200static void
1201nouveau_crtc_irq_handler(struct drm_device *dev, int crtc)
1202{
1203 if (crtc & 1)
1204 nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
1205
1206 if (crtc & 2)
1207 nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
1208}
1209
1210irqreturn_t
1211nouveau_irq_handler(DRM_IRQ_ARGS)
1212{
1213 struct drm_device *dev = (struct drm_device *)arg;
1214 struct drm_nouveau_private *dev_priv = dev->dev_private;
Dave Airlie38651672010-03-30 05:34:13 +00001215 uint32_t status;
Maarten Maathuisff9e5272010-02-01 20:58:27 +01001216 unsigned long flags;
Ben Skeggs6ee73862009-12-11 19:24:15 +10001217
1218 status = nv_rd32(dev, NV03_PMC_INTR_0);
1219 if (!status)
1220 return IRQ_NONE;
1221
Maarten Maathuisff9e5272010-02-01 20:58:27 +01001222 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
1223
Ben Skeggs6ee73862009-12-11 19:24:15 +10001224 if (status & NV_PMC_INTR_0_PFIFO_PENDING) {
1225 nouveau_fifo_irq_handler(dev);
1226 status &= ~NV_PMC_INTR_0_PFIFO_PENDING;
1227 }
1228
1229 if (status & NV_PMC_INTR_0_PGRAPH_PENDING) {
1230 if (dev_priv->card_type >= NV_50)
1231 nv50_pgraph_irq_handler(dev);
1232 else
1233 nouveau_pgraph_irq_handler(dev);
1234
1235 status &= ~NV_PMC_INTR_0_PGRAPH_PENDING;
1236 }
1237
1238 if (status & NV_PMC_INTR_0_CRTCn_PENDING) {
1239 nouveau_crtc_irq_handler(dev, (status>>24)&3);
1240 status &= ~NV_PMC_INTR_0_CRTCn_PENDING;
1241 }
1242
1243 if (status & (NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
1244 NV_PMC_INTR_0_NV50_I2C_PENDING)) {
1245 nv50_display_irq_handler(dev);
1246 status &= ~(NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
1247 NV_PMC_INTR_0_NV50_I2C_PENDING);
1248 }
1249
1250 if (status)
1251 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status);
1252
Maarten Maathuisff9e5272010-02-01 20:58:27 +01001253 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
1254
Ben Skeggs6ee73862009-12-11 19:24:15 +10001255 return IRQ_HANDLED;
1256}