blob: 17e2fa86cde7916a88ac576f614b2b3f62be1bdb [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);
Andy Lutomirskiab838332010-11-16 18:40:52 -050063 spin_lock_init(&dev_priv->hpd_state.lock);
Ben Skeggs6ee73862009-12-11 19:24:15 +100064 INIT_LIST_HEAD(&dev_priv->vbl_waiting);
65 }
66}
67
68int
69nouveau_irq_postinstall(struct drm_device *dev)
70{
Ben Skeggs35fa2f22010-10-21 14:07:03 +100071 struct drm_nouveau_private *dev_priv = dev->dev_private;
72
Ben Skeggs6ee73862009-12-11 19:24:15 +100073 /* Master enable */
74 nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE);
Ben Skeggs35fa2f22010-10-21 14:07:03 +100075 if (dev_priv->msi_enabled)
76 nv_wr08(dev, 0x00088068, 0xff);
77
Ben Skeggs6ee73862009-12-11 19:24:15 +100078 return 0;
79}
80
81void
82nouveau_irq_uninstall(struct drm_device *dev)
83{
84 /* Master disable */
85 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
86}
87
Ben Skeggs6ee73862009-12-11 19:24:15 +100088static bool
Ben Skeggs7c74cbd2010-09-23 11:03:01 +100089nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
Ben Skeggs6ee73862009-12-11 19:24:15 +100090{
Ben Skeggs7c74cbd2010-09-23 11:03:01 +100091 struct drm_nouveau_private *dev_priv = dev->dev_private;
92 struct nouveau_channel *chan = NULL;
93 struct nouveau_gpuobj *obj;
Ben Skeggscff5c132010-10-06 16:16:59 +100094 unsigned long flags;
Ben Skeggs6ee73862009-12-11 19:24:15 +100095 const int subc = (addr >> 13) & 0x7;
96 const int mthd = addr & 0x1ffc;
Ben Skeggs7c74cbd2010-09-23 11:03:01 +100097 bool handled = false;
98 u32 engine;
Ben Skeggs6ee73862009-12-11 19:24:15 +100099
Ben Skeggscff5c132010-10-06 16:16:59 +1000100 spin_lock_irqsave(&dev_priv->channels.lock, flags);
Ben Skeggs7c74cbd2010-09-23 11:03:01 +1000101 if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels))
Ben Skeggscff5c132010-10-06 16:16:59 +1000102 chan = dev_priv->channels.ptr[chid];
Ben Skeggs7c74cbd2010-09-23 11:03:01 +1000103 if (unlikely(!chan))
Ben Skeggscff5c132010-10-06 16:16:59 +1000104 goto out;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000105
Ben Skeggs7c74cbd2010-09-23 11:03:01 +1000106 switch (mthd) {
107 case 0x0000: /* bind object to subchannel */
108 obj = nouveau_ramht_find(chan, data);
109 if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW))
110 break;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000111
Ben Skeggs7c74cbd2010-09-23 11:03:01 +1000112 chan->sw_subchannel[subc] = obj->class;
113 engine = 0x0000000f << (subc * 4);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000114
Ben Skeggs7c74cbd2010-09-23 11:03:01 +1000115 nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000);
116 handled = true;
117 break;
118 default:
119 engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE);
120 if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
121 break;
122
Ben Skeggsb8c157d2010-10-20 10:39:35 +1000123 if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc],
124 mthd, data))
Ben Skeggs7c74cbd2010-09-23 11:03:01 +1000125 handled = true;
126 break;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000127 }
128
Ben Skeggscff5c132010-10-06 16:16:59 +1000129out:
130 spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
Ben Skeggs7c74cbd2010-09-23 11:03:01 +1000131 return handled;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000132}
133
134static void
135nouveau_fifo_irq_handler(struct drm_device *dev)
136{
137 struct drm_nouveau_private *dev_priv = dev->dev_private;
138 struct nouveau_engine *engine = &dev_priv->engine;
139 uint32_t status, reassign;
140 int cnt = 0;
141
142 reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1;
143 while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000144 uint32_t chid, get;
145
146 nv_wr32(dev, NV03_PFIFO_CACHES, 0);
147
148 chid = engine->fifo.channel_id(dev);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000149 get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET);
150
151 if (status & NV_PFIFO_INTR_CACHE_ERROR) {
152 uint32_t mthd, data;
153 int ptr;
154
155 /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before
156 * wrapping on my G80 chips, but CACHE1 isn't big
157 * enough for this much data.. Tests show that it
158 * wraps around to the start at GET=0x800.. No clue
159 * as to why..
160 */
161 ptr = (get & 0x7ff) >> 2;
162
163 if (dev_priv->card_type < NV_40) {
164 mthd = nv_rd32(dev,
165 NV04_PFIFO_CACHE1_METHOD(ptr));
166 data = nv_rd32(dev,
167 NV04_PFIFO_CACHE1_DATA(ptr));
168 } else {
169 mthd = nv_rd32(dev,
170 NV40_PFIFO_CACHE1_METHOD(ptr));
171 data = nv_rd32(dev,
172 NV40_PFIFO_CACHE1_DATA(ptr));
173 }
174
Ben Skeggs7c74cbd2010-09-23 11:03:01 +1000175 if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000176 NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d "
177 "Mthd 0x%04x Data 0x%08x\n",
178 chid, (mthd >> 13) & 7, mthd & 0x1ffc,
179 data);
180 }
181
182 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
183 nv_wr32(dev, NV03_PFIFO_INTR_0,
184 NV_PFIFO_INTR_CACHE_ERROR);
185
186 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
187 nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1);
188 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
189 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
190 nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1);
191 nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
192
193 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH,
194 nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
195 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
196
197 status &= ~NV_PFIFO_INTR_CACHE_ERROR;
198 }
199
200 if (status & NV_PFIFO_INTR_DMA_PUSHER) {
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200201 u32 dma_get = nv_rd32(dev, 0x003244);
202 u32 dma_put = nv_rd32(dev, 0x003240);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000203 u32 push = nv_rd32(dev, 0x003220);
204 u32 state = nv_rd32(dev, 0x003228);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000205
Ben Skeggse071f8c2010-09-08 15:40:30 +1000206 if (dev_priv->card_type == NV_50) {
207 u32 ho_get = nv_rd32(dev, 0x003328);
208 u32 ho_put = nv_rd32(dev, 0x003320);
209 u32 ib_get = nv_rd32(dev, 0x003334);
210 u32 ib_put = nv_rd32(dev, 0x003330);
211
Jiri Slabyda3bd822010-10-05 15:07:33 +0200212 if (nouveau_ratelimit())
213 NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
Ben Skeggse071f8c2010-09-08 15:40:30 +1000214 "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
215 "State 0x%08x Push 0x%08x\n",
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200216 chid, ho_get, dma_get, ho_put,
217 dma_put, ib_get, ib_put, state,
218 push);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000219
220 /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
221 nv_wr32(dev, 0x003364, 0x00000000);
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200222 if (dma_get != dma_put || ho_get != ho_put) {
223 nv_wr32(dev, 0x003244, dma_put);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000224 nv_wr32(dev, 0x003328, ho_put);
225 } else
226 if (ib_get != ib_put) {
227 nv_wr32(dev, 0x003334, ib_put);
228 }
229 } else {
230 NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
231 "Put 0x%08x State 0x%08x Push 0x%08x\n",
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200232 chid, dma_get, dma_put, state, push);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000233
Francisco Jerezcbab95db2010-10-11 03:43:58 +0200234 if (dma_get != dma_put)
235 nv_wr32(dev, 0x003244, dma_put);
Ben Skeggse071f8c2010-09-08 15:40:30 +1000236 }
237
238 nv_wr32(dev, 0x003228, 0x00000000);
239 nv_wr32(dev, 0x003220, 0x00000001);
240 nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000241 status &= ~NV_PFIFO_INTR_DMA_PUSHER;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000242 }
243
Francisco Jerez139295b2010-01-30 18:28:00 +0100244 if (status & NV_PFIFO_INTR_SEMAPHORE) {
245 uint32_t sem;
246
247 status &= ~NV_PFIFO_INTR_SEMAPHORE;
248 nv_wr32(dev, NV03_PFIFO_INTR_0,
249 NV_PFIFO_INTR_SEMAPHORE);
250
251 sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE);
252 nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
253
254 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
255 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
256 }
257
Ben Skeggs1da26562010-09-03 15:56:12 +1000258 if (dev_priv->card_type == NV_50) {
259 if (status & 0x00000010) {
260 nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT");
261 status &= ~0x00000010;
262 nv_wr32(dev, 0x002100, 0x00000010);
263 }
264 }
265
Ben Skeggs6ee73862009-12-11 19:24:15 +1000266 if (status) {
Jiri Slabyda3bd822010-10-05 15:07:33 +0200267 if (nouveau_ratelimit())
268 NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
269 status, chid);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000270 nv_wr32(dev, NV03_PFIFO_INTR_0, status);
271 status = 0;
272 }
273
274 nv_wr32(dev, NV03_PFIFO_CACHES, reassign);
275 }
276
277 if (status) {
278 NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt);
279 nv_wr32(dev, 0x2140, 0);
280 nv_wr32(dev, 0x140, 0);
281 }
282
283 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
284}
285
286struct nouveau_bitfield_names {
287 uint32_t mask;
288 const char *name;
289};
290
291static struct nouveau_bitfield_names nstatus_names[] =
292{
293 { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
294 { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
295 { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
296 { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }
297};
298
299static struct nouveau_bitfield_names nstatus_names_nv10[] =
300{
301 { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
302 { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
303 { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
304 { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }
305};
306
307static struct nouveau_bitfield_names nsource_names[] =
308{
309 { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
310 { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
311 { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
312 { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
313 { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
314 { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
315 { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
316 { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
317 { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
318 { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
319 { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
320 { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
321 { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
322 { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
323 { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
324 { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
325 { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
326 { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
327 { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
328};
329
330static void
331nouveau_print_bitfield_names_(uint32_t value,
332 const struct nouveau_bitfield_names *namelist,
333 const int namelist_len)
334{
335 /*
336 * Caller must have already printed the KERN_* log level for us.
337 * Also the caller is responsible for adding the newline.
338 */
339 int i;
340 for (i = 0; i < namelist_len; ++i) {
341 uint32_t mask = namelist[i].mask;
342 if (value & mask) {
343 printk(" %s", namelist[i].name);
344 value &= ~mask;
345 }
346 }
347 if (value)
348 printk(" (unknown bits 0x%08x)", value);
349}
350#define nouveau_print_bitfield_names(val, namelist) \
351 nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist))
352
Marcin Koƛcielnicki304424e2010-03-01 00:18:39 +0000353struct nouveau_enum_names {
354 uint32_t value;
355 const char *name;
356};
357
358static void
359nouveau_print_enum_names_(uint32_t value,
360 const struct nouveau_enum_names *namelist,
361 const int namelist_len)
362{
363 /*
364 * Caller must have already printed the KERN_* log level for us.
365 * Also the caller is responsible for adding the newline.
366 */
367 int i;
368 for (i = 0; i < namelist_len; ++i) {
369 if (value == namelist[i].value) {
370 printk("%s", namelist[i].name);
371 return;
372 }
373 }
374 printk("unknown value 0x%08x", value);
375}
376#define nouveau_print_enum_names(val, namelist) \
377 nouveau_print_enum_names_((val), (namelist), ARRAY_SIZE(namelist))
Ben Skeggs6ee73862009-12-11 19:24:15 +1000378
379static int
380nouveau_graph_chid_from_grctx(struct drm_device *dev)
381{
382 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggscff5c132010-10-06 16:16:59 +1000383 struct nouveau_channel *chan;
384 unsigned long flags;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000385 uint32_t inst;
386 int i;
387
388 if (dev_priv->card_type < NV_40)
389 return dev_priv->engine.fifo.channels;
390 else
391 if (dev_priv->card_type < NV_50) {
392 inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 4;
393
Ben Skeggscff5c132010-10-06 16:16:59 +1000394 spin_lock_irqsave(&dev_priv->channels.lock, flags);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000395 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
Ben Skeggscff5c132010-10-06 16:16:59 +1000396 chan = dev_priv->channels.ptr[i];
Ben Skeggs6ee73862009-12-11 19:24:15 +1000397 if (!chan || !chan->ramin_grctx)
398 continue;
399
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000400 if (inst == chan->ramin_grctx->pinst)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000401 break;
402 }
Ben Skeggscff5c132010-10-06 16:16:59 +1000403 spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000404 } else {
405 inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 12;
406
Ben Skeggscff5c132010-10-06 16:16:59 +1000407 spin_lock_irqsave(&dev_priv->channels.lock, flags);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000408 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
Ben Skeggscff5c132010-10-06 16:16:59 +1000409 chan = dev_priv->channels.ptr[i];
Ben Skeggs6ee73862009-12-11 19:24:15 +1000410 if (!chan || !chan->ramin)
411 continue;
412
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000413 if (inst == chan->ramin->vinst)
Ben Skeggs6ee73862009-12-11 19:24:15 +1000414 break;
415 }
Ben Skeggscff5c132010-10-06 16:16:59 +1000416 spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000417 }
418
419
420 return i;
421}
422
423static int
424nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret)
425{
426 struct drm_nouveau_private *dev_priv = dev->dev_private;
427 struct nouveau_engine *engine = &dev_priv->engine;
428 int channel;
429
430 if (dev_priv->card_type < NV_10)
431 channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0xf;
432 else
433 if (dev_priv->card_type < NV_40)
434 channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
435 else
436 channel = nouveau_graph_chid_from_grctx(dev);
437
Ben Skeggscff5c132010-10-06 16:16:59 +1000438 if (channel >= engine->fifo.channels ||
439 !dev_priv->channels.ptr[channel]) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000440 NV_ERROR(dev, "AIII, invalid/inactive channel id %d\n", channel);
441 return -EINVAL;
442 }
443
444 *channel_ret = channel;
445 return 0;
446}
447
448struct nouveau_pgraph_trap {
449 int channel;
450 int class;
451 int subc, mthd, size;
452 uint32_t data, data2;
453 uint32_t nsource, nstatus;
454};
455
456static void
457nouveau_graph_trap_info(struct drm_device *dev,
458 struct nouveau_pgraph_trap *trap)
459{
460 struct drm_nouveau_private *dev_priv = dev->dev_private;
461 uint32_t address;
462
463 trap->nsource = trap->nstatus = 0;
464 if (dev_priv->card_type < NV_50) {
465 trap->nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
466 trap->nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
467 }
468
469 if (nouveau_graph_trapped_channel(dev, &trap->channel))
470 trap->channel = -1;
471 address = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
472
473 trap->mthd = address & 0x1FFC;
474 trap->data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
475 if (dev_priv->card_type < NV_10) {
476 trap->subc = (address >> 13) & 0x7;
477 } else {
478 trap->subc = (address >> 16) & 0x7;
479 trap->data2 = nv_rd32(dev, NV10_PGRAPH_TRAPPED_DATA_HIGH);
480 }
481
482 if (dev_priv->card_type < NV_10)
483 trap->class = nv_rd32(dev, 0x400180 + trap->subc*4) & 0xFF;
484 else if (dev_priv->card_type < NV_40)
485 trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFF;
486 else if (dev_priv->card_type < NV_50)
487 trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFFF;
488 else
489 trap->class = nv_rd32(dev, 0x400814);
490}
491
492static void
493nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id,
494 struct nouveau_pgraph_trap *trap)
495{
496 struct drm_nouveau_private *dev_priv = dev->dev_private;
497 uint32_t nsource = trap->nsource, nstatus = trap->nstatus;
498
Marcin Koƛcielnicki304424e2010-03-01 00:18:39 +0000499 if (dev_priv->card_type < NV_50) {
500 NV_INFO(dev, "%s - nSource:", id);
501 nouveau_print_bitfield_names(nsource, nsource_names);
502 printk(", nStatus:");
503 if (dev_priv->card_type < NV_10)
504 nouveau_print_bitfield_names(nstatus, nstatus_names);
505 else
506 nouveau_print_bitfield_names(nstatus, nstatus_names_nv10);
507 printk("\n");
508 }
Ben Skeggs6ee73862009-12-11 19:24:15 +1000509
510 NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x "
511 "Data 0x%08x:0x%08x\n",
512 id, trap->channel, trap->subc,
513 trap->class, trap->mthd,
514 trap->data2, trap->data);
515}
516
517static int
518nouveau_pgraph_intr_swmthd(struct drm_device *dev,
519 struct nouveau_pgraph_trap *trap)
520{
521 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggsb8c157d2010-10-20 10:39:35 +1000522 struct nouveau_channel *chan;
Ben Skeggscff5c132010-10-06 16:16:59 +1000523 unsigned long flags;
524 int ret = -EINVAL;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000525
Ben Skeggscff5c132010-10-06 16:16:59 +1000526 spin_lock_irqsave(&dev_priv->channels.lock, flags);
527 if (trap->channel > 0 &&
528 trap->channel < dev_priv->engine.fifo.channels &&
529 dev_priv->channels.ptr[trap->channel]) {
Ben Skeggsb8c157d2010-10-20 10:39:35 +1000530 chan = dev_priv->channels.ptr[trap->channel];
531 ret = nouveau_gpuobj_mthd_call(chan, trap->class, trap->mthd, trap->data);
Ben Skeggscff5c132010-10-06 16:16:59 +1000532 }
533 spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000534
Ben Skeggscff5c132010-10-06 16:16:59 +1000535 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000536}
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
Ben Skeggsbd2e5972010-10-19 20:06:01 +10001238 if (status & 0x00004000) {
1239 u32 stat = nv_rd32(dev, 0x102130);
1240 u32 mthd = nv_rd32(dev, 0x102190);
1241 u32 data = nv_rd32(dev, 0x102194);
1242 u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff;
1243
1244 NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n",
1245 stat, mthd, data, inst);
1246 nv_wr32(dev, 0x102130, stat);
1247 nv_wr32(dev, 0x10200c, 0x10);
1248
1249 nv50_fb_vm_trap(dev, nouveau_ratelimit(), "PCRYPT");
1250 status &= ~0x00004000;
1251
1252 }
1253
Ben Skeggs6ee73862009-12-11 19:24:15 +10001254 if (status & NV_PMC_INTR_0_CRTCn_PENDING) {
1255 nouveau_crtc_irq_handler(dev, (status>>24)&3);
1256 status &= ~NV_PMC_INTR_0_CRTCn_PENDING;
1257 }
1258
1259 if (status & (NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
1260 NV_PMC_INTR_0_NV50_I2C_PENDING)) {
1261 nv50_display_irq_handler(dev);
1262 status &= ~(NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
1263 NV_PMC_INTR_0_NV50_I2C_PENDING);
1264 }
1265
1266 if (status)
1267 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status);
1268
Maarten Maathuisff9e5272010-02-01 20:58:27 +01001269 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
1270
Ben Skeggs35fa2f22010-10-21 14:07:03 +10001271 if (dev_priv->msi_enabled)
1272 nv_wr08(dev, 0x00088068, 0xff);
1273
Ben Skeggs6ee73862009-12-11 19:24:15 +10001274 return IRQ_HANDLED;
1275}
Ben Skeggs35fa2f22010-10-21 14:07:03 +10001276
1277int
1278nouveau_irq_init(struct drm_device *dev)
1279{
1280 struct drm_nouveau_private *dev_priv = dev->dev_private;
1281 int ret;
1282
1283 if (nouveau_msi != 0 && dev_priv->card_type >= NV_50) {
1284 ret = pci_enable_msi(dev->pdev);
1285 if (ret == 0) {
1286 NV_INFO(dev, "enabled MSI\n");
1287 dev_priv->msi_enabled = true;
1288 }
1289 }
1290
1291 return drm_irq_install(dev);
1292}
1293
1294void
1295nouveau_irq_fini(struct drm_device *dev)
1296{
1297 struct drm_nouveau_private *dev_priv = dev->dev_private;
1298
1299 drm_irq_uninstall(dev);
1300 if (dev_priv->msi_enabled)
1301 pci_disable_msi(dev->pdev);
1302}