aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_irq.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2009-12-11 04:24:15 -0500
committerDave Airlie <airlied@redhat.com>2009-12-11 06:29:34 -0500
commit6ee738610f41b59733f63718f0bdbcba7d3a3f12 (patch)
treeeccb9f07671998c50a1bc606a54cd6f82ba43e0a /drivers/gpu/drm/nouveau/nouveau_irq.c
parentd1ede145cea25c5b6d2ebb19b167af14e374bb45 (diff)
drm/nouveau: Add DRM driver for NVIDIA GPUs
This adds a drm/kms staging non-API stable driver for GPUs from NVIDIA. This driver is a KMS-based driver and requires a compatible nouveau userspace libdrm and nouveau X.org driver. This driver requires firmware files not available in this kernel tree, interested parties can find them via the nouveau project git archive. This driver is reverse engineered, and is in no way supported by nVidia. Support for nearly the complete range of nvidia hw from nv04->g80 (nv50) is available, and the kms driver should support driving nearly all output types (displayport is under development still) along with supporting suspend/resume. This work is all from the upstream nouveau project found at nouveau.freedesktop.org. The original authors list from nouveau git tree is: Anssi Hannula <anssi.hannula@iki.fi> Ben Skeggs <bskeggs@redhat.com> Francisco Jerez <currojerez@riseup.net> Maarten Maathuis <madman2003@gmail.com> Marcin Koƛcielnicki <koriakin@0x04.net> Matthew Garrett <mjg@redhat.com> Matt Parnell <mparnell@gmail.com> Patrice Mandin <patmandin@gmail.com> Pekka Paalanen <pq@iki.fi> Xavier Chantry <shiningxc@gmail.com> along with project founder Stephane Marchesin <marchesin@icps.u-strasbg.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_irq.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c702
1 files changed, 702 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
new file mode 100644
index 00000000000..370c72c968d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -0,0 +1,702 @@
1/*
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"
38#include <linux/ratelimit.h>
39
40/* needed for hotplug irq */
41#include "nouveau_connector.h"
42#include "nv50_display.h"
43
44void
45nouveau_irq_preinstall(struct drm_device *dev)
46{
47 struct drm_nouveau_private *dev_priv = dev->dev_private;
48
49 /* Master disable */
50 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
51
52 if (dev_priv->card_type == NV_50) {
53 INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
54 INIT_LIST_HEAD(&dev_priv->vbl_waiting);
55 }
56}
57
58int
59nouveau_irq_postinstall(struct drm_device *dev)
60{
61 /* Master enable */
62 nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE);
63 return 0;
64}
65
66void
67nouveau_irq_uninstall(struct drm_device *dev)
68{
69 /* Master disable */
70 nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
71}
72
73static int
74nouveau_call_method(struct nouveau_channel *chan, int class, int mthd, int data)
75{
76 struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
77 struct nouveau_pgraph_object_method *grm;
78 struct nouveau_pgraph_object_class *grc;
79
80 grc = dev_priv->engine.graph.grclass;
81 while (grc->id) {
82 if (grc->id == class)
83 break;
84 grc++;
85 }
86
87 if (grc->id != class || !grc->methods)
88 return -ENOENT;
89
90 grm = grc->methods;
91 while (grm->id) {
92 if (grm->id == mthd)
93 return grm->exec(chan, class, mthd, data);
94 grm++;
95 }
96
97 return -ENOENT;
98}
99
100static bool
101nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data)
102{
103 struct drm_device *dev = chan->dev;
104 const int subc = (addr >> 13) & 0x7;
105 const int mthd = addr & 0x1ffc;
106
107 if (mthd == 0x0000) {
108 struct nouveau_gpuobj_ref *ref = NULL;
109
110 if (nouveau_gpuobj_ref_find(chan, data, &ref))
111 return false;
112
113 if (ref->gpuobj->engine != NVOBJ_ENGINE_SW)
114 return false;
115
116 chan->sw_subchannel[subc] = ref->gpuobj->class;
117 nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev,
118 NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4));
119 return true;
120 }
121
122 /* hw object */
123 if (nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE) & (1 << (subc*4)))
124 return false;
125
126 if (nouveau_call_method(chan, chan->sw_subchannel[subc], mthd, data))
127 return false;
128
129 return true;
130}
131
132static void
133nouveau_fifo_irq_handler(struct drm_device *dev)
134{
135 struct drm_nouveau_private *dev_priv = dev->dev_private;
136 struct nouveau_engine *engine = &dev_priv->engine;
137 uint32_t status, reassign;
138 int cnt = 0;
139
140 reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1;
141 while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
142 struct nouveau_channel *chan = NULL;
143 uint32_t chid, get;
144
145 nv_wr32(dev, NV03_PFIFO_CACHES, 0);
146
147 chid = engine->fifo.channel_id(dev);
148 if (chid >= 0 && chid < engine->fifo.channels)
149 chan = dev_priv->fifos[chid];
150 get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET);
151
152 if (status & NV_PFIFO_INTR_CACHE_ERROR) {
153 uint32_t mthd, data;
154 int ptr;
155
156 /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before
157 * wrapping on my G80 chips, but CACHE1 isn't big
158 * enough for this much data.. Tests show that it
159 * wraps around to the start at GET=0x800.. No clue
160 * as to why..
161 */
162 ptr = (get & 0x7ff) >> 2;
163
164 if (dev_priv->card_type < NV_40) {
165 mthd = nv_rd32(dev,
166 NV04_PFIFO_CACHE1_METHOD(ptr));
167 data = nv_rd32(dev,
168 NV04_PFIFO_CACHE1_DATA(ptr));
169 } else {
170 mthd = nv_rd32(dev,
171 NV40_PFIFO_CACHE1_METHOD(ptr));
172 data = nv_rd32(dev,
173 NV40_PFIFO_CACHE1_DATA(ptr));
174 }
175
176 if (!chan || !nouveau_fifo_swmthd(chan, mthd, data)) {
177 NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d "
178 "Mthd 0x%04x Data 0x%08x\n",
179 chid, (mthd >> 13) & 7, mthd & 0x1ffc,
180 data);
181 }
182
183 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
184 nv_wr32(dev, NV03_PFIFO_INTR_0,
185 NV_PFIFO_INTR_CACHE_ERROR);
186
187 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
188 nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1);
189 nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4);
190 nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0,
191 nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1);
192 nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
193
194 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH,
195 nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
196 nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
197
198 status &= ~NV_PFIFO_INTR_CACHE_ERROR;
199 }
200
201 if (status & NV_PFIFO_INTR_DMA_PUSHER) {
202 NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d\n", chid);
203
204 status &= ~NV_PFIFO_INTR_DMA_PUSHER;
205 nv_wr32(dev, NV03_PFIFO_INTR_0,
206 NV_PFIFO_INTR_DMA_PUSHER);
207
208 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000);
209 if (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT) != get)
210 nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET,
211 get + 4);
212 }
213
214 if (status) {
215 NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
216 status, chid);
217 nv_wr32(dev, NV03_PFIFO_INTR_0, status);
218 status = 0;
219 }
220
221 nv_wr32(dev, NV03_PFIFO_CACHES, reassign);
222 }
223
224 if (status) {
225 NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt);
226 nv_wr32(dev, 0x2140, 0);
227 nv_wr32(dev, 0x140, 0);
228 }
229
230 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
231}
232
233struct nouveau_bitfield_names {
234 uint32_t mask;
235 const char *name;
236};
237
238static struct nouveau_bitfield_names nstatus_names[] =
239{
240 { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
241 { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
242 { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
243 { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }
244};
245
246static struct nouveau_bitfield_names nstatus_names_nv10[] =
247{
248 { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
249 { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
250 { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
251 { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }
252};
253
254static struct nouveau_bitfield_names nsource_names[] =
255{
256 { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
257 { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
258 { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
259 { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
260 { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
261 { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
262 { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
263 { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
264 { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
265 { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
266 { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
267 { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
268 { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
269 { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
270 { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
271 { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
272 { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
273 { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
274 { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
275};
276
277static void
278nouveau_print_bitfield_names_(uint32_t value,
279 const struct nouveau_bitfield_names *namelist,
280 const int namelist_len)
281{
282 /*
283 * Caller must have already printed the KERN_* log level for us.
284 * Also the caller is responsible for adding the newline.
285 */
286 int i;
287 for (i = 0; i < namelist_len; ++i) {
288 uint32_t mask = namelist[i].mask;
289 if (value & mask) {
290 printk(" %s", namelist[i].name);
291 value &= ~mask;
292 }
293 }
294 if (value)
295 printk(" (unknown bits 0x%08x)", value);
296}
297#define nouveau_print_bitfield_names(val, namelist) \
298 nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist))
299
300
301static int
302nouveau_graph_chid_from_grctx(struct drm_device *dev)
303{
304 struct drm_nouveau_private *dev_priv = dev->dev_private;
305 uint32_t inst;
306 int i;
307
308 if (dev_priv->card_type < NV_40)
309 return dev_priv->engine.fifo.channels;
310 else
311 if (dev_priv->card_type < NV_50) {
312 inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 4;
313
314 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
315 struct nouveau_channel *chan = dev_priv->fifos[i];
316
317 if (!chan || !chan->ramin_grctx)
318 continue;
319
320 if (inst == chan->ramin_grctx->instance)
321 break;
322 }
323 } else {
324 inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 12;
325
326 for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
327 struct nouveau_channel *chan = dev_priv->fifos[i];
328
329 if (!chan || !chan->ramin)
330 continue;
331
332 if (inst == chan->ramin->instance)
333 break;
334 }
335 }
336
337
338 return i;
339}
340
341static int
342nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret)
343{
344 struct drm_nouveau_private *dev_priv = dev->dev_private;
345 struct nouveau_engine *engine = &dev_priv->engine;
346 int channel;
347
348 if (dev_priv->card_type < NV_10)
349 channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0xf;
350 else
351 if (dev_priv->card_type < NV_40)
352 channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
353 else
354 channel = nouveau_graph_chid_from_grctx(dev);
355
356 if (channel >= engine->fifo.channels || !dev_priv->fifos[channel]) {
357 NV_ERROR(dev, "AIII, invalid/inactive channel id %d\n", channel);
358 return -EINVAL;
359 }
360
361 *channel_ret = channel;
362 return 0;
363}
364
365struct nouveau_pgraph_trap {
366 int channel;
367 int class;
368 int subc, mthd, size;
369 uint32_t data, data2;
370 uint32_t nsource, nstatus;
371};
372
373static void
374nouveau_graph_trap_info(struct drm_device *dev,
375 struct nouveau_pgraph_trap *trap)
376{
377 struct drm_nouveau_private *dev_priv = dev->dev_private;
378 uint32_t address;
379
380 trap->nsource = trap->nstatus = 0;
381 if (dev_priv->card_type < NV_50) {
382 trap->nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
383 trap->nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
384 }
385
386 if (nouveau_graph_trapped_channel(dev, &trap->channel))
387 trap->channel = -1;
388 address = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
389
390 trap->mthd = address & 0x1FFC;
391 trap->data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
392 if (dev_priv->card_type < NV_10) {
393 trap->subc = (address >> 13) & 0x7;
394 } else {
395 trap->subc = (address >> 16) & 0x7;
396 trap->data2 = nv_rd32(dev, NV10_PGRAPH_TRAPPED_DATA_HIGH);
397 }
398
399 if (dev_priv->card_type < NV_10)
400 trap->class = nv_rd32(dev, 0x400180 + trap->subc*4) & 0xFF;
401 else if (dev_priv->card_type < NV_40)
402 trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFF;
403 else if (dev_priv->card_type < NV_50)
404 trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFFF;
405 else
406 trap->class = nv_rd32(dev, 0x400814);
407}
408
409static void
410nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id,
411 struct nouveau_pgraph_trap *trap)
412{
413 struct drm_nouveau_private *dev_priv = dev->dev_private;
414 uint32_t nsource = trap->nsource, nstatus = trap->nstatus;
415
416 NV_INFO(dev, "%s - nSource:", id);
417 nouveau_print_bitfield_names(nsource, nsource_names);
418 printk(", nStatus:");
419 if (dev_priv->card_type < NV_10)
420 nouveau_print_bitfield_names(nstatus, nstatus_names);
421 else
422 nouveau_print_bitfield_names(nstatus, nstatus_names_nv10);
423 printk("\n");
424
425 NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x "
426 "Data 0x%08x:0x%08x\n",
427 id, trap->channel, trap->subc,
428 trap->class, trap->mthd,
429 trap->data2, trap->data);
430}
431
432static int
433nouveau_pgraph_intr_swmthd(struct drm_device *dev,
434 struct nouveau_pgraph_trap *trap)
435{
436 struct drm_nouveau_private *dev_priv = dev->dev_private;
437
438 if (trap->channel < 0 ||
439 trap->channel >= dev_priv->engine.fifo.channels ||
440 !dev_priv->fifos[trap->channel])
441 return -ENODEV;
442
443 return nouveau_call_method(dev_priv->fifos[trap->channel],
444 trap->class, trap->mthd, trap->data);
445}
446
447static inline void
448nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource)
449{
450 struct nouveau_pgraph_trap trap;
451 int unhandled = 0;
452
453 nouveau_graph_trap_info(dev, &trap);
454
455 if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
456 if (nouveau_pgraph_intr_swmthd(dev, &trap))
457 unhandled = 1;
458 } else {
459 unhandled = 1;
460 }
461
462 if (unhandled)
463 nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap);
464}
465
466static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
467
468static int nouveau_ratelimit(void)
469{
470 return __ratelimit(&nouveau_ratelimit_state);
471}
472
473
474static inline void
475nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
476{
477 struct nouveau_pgraph_trap trap;
478 int unhandled = 0;
479
480 nouveau_graph_trap_info(dev, &trap);
481 trap.nsource = nsource;
482
483 if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
484 if (nouveau_pgraph_intr_swmthd(dev, &trap))
485 unhandled = 1;
486 } else {
487 unhandled = 1;
488 }
489
490 if (unhandled && nouveau_ratelimit())
491 nouveau_graph_dump_trap_info(dev, "PGRAPH_ERROR", &trap);
492}
493
494static inline void
495nouveau_pgraph_intr_context_switch(struct drm_device *dev)
496{
497 struct drm_nouveau_private *dev_priv = dev->dev_private;
498 struct nouveau_engine *engine = &dev_priv->engine;
499 uint32_t chid;
500
501 chid = engine->fifo.channel_id(dev);
502 NV_DEBUG(dev, "PGRAPH context switch interrupt channel %x\n", chid);
503
504 switch (dev_priv->card_type) {
505 case NV_04:
506 nv04_graph_context_switch(dev);
507 break;
508 case NV_10:
509 nv10_graph_context_switch(dev);
510 break;
511 default:
512 NV_ERROR(dev, "Context switch not implemented\n");
513 break;
514 }
515}
516
517static void
518nouveau_pgraph_irq_handler(struct drm_device *dev)
519{
520 uint32_t status;
521
522 while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) {
523 uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
524
525 if (status & NV_PGRAPH_INTR_NOTIFY) {
526 nouveau_pgraph_intr_notify(dev, nsource);
527
528 status &= ~NV_PGRAPH_INTR_NOTIFY;
529 nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY);
530 }
531
532 if (status & NV_PGRAPH_INTR_ERROR) {
533 nouveau_pgraph_intr_error(dev, nsource);
534
535 status &= ~NV_PGRAPH_INTR_ERROR;
536 nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_ERROR);
537 }
538
539 if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
540 nouveau_pgraph_intr_context_switch(dev);
541
542 status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
543 nv_wr32(dev, NV03_PGRAPH_INTR,
544 NV_PGRAPH_INTR_CONTEXT_SWITCH);
545 }
546
547 if (status) {
548 NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status);
549 nv_wr32(dev, NV03_PGRAPH_INTR, status);
550 }
551
552 if ((nv_rd32(dev, NV04_PGRAPH_FIFO) & (1 << 0)) == 0)
553 nv_wr32(dev, NV04_PGRAPH_FIFO, 1);
554 }
555
556 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
557}
558
559static void
560nv50_pgraph_irq_handler(struct drm_device *dev)
561{
562 uint32_t status, nsource;
563
564 status = nv_rd32(dev, NV03_PGRAPH_INTR);
565 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
566
567 if (status & 0x00000001) {
568 nouveau_pgraph_intr_notify(dev, nsource);
569 status &= ~0x00000001;
570 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001);
571 }
572
573 if (status & 0x00000010) {
574 nouveau_pgraph_intr_error(dev, nsource |
575 NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD);
576
577 status &= ~0x00000010;
578 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010);
579 }
580
581 if (status & 0x00001000) {
582 nv_wr32(dev, 0x400500, 0x00000000);
583 nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
584 nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev,
585 NV40_PGRAPH_INTR_EN) & ~NV_PGRAPH_INTR_CONTEXT_SWITCH);
586 nv_wr32(dev, 0x400500, 0x00010001);
587
588 nv50_graph_context_switch(dev);
589
590 status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
591 }
592
593 if (status & 0x00100000) {
594 nouveau_pgraph_intr_error(dev, nsource |
595 NV03_PGRAPH_NSOURCE_DATA_ERROR);
596
597 status &= ~0x00100000;
598 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000);
599 }
600
601 if (status & 0x00200000) {
602 int r;
603
604 nouveau_pgraph_intr_error(dev, nsource |
605 NV03_PGRAPH_NSOURCE_PROTECTION_ERROR);
606
607 NV_ERROR(dev, "magic set 1:\n");
608 for (r = 0x408900; r <= 0x408910; r += 4)
609 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r));
610 nv_wr32(dev, 0x408900, nv_rd32(dev, 0x408904) | 0xc0000000);
611 for (r = 0x408e08; r <= 0x408e24; r += 4)
612 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r));
613 nv_wr32(dev, 0x408e08, nv_rd32(dev, 0x408e08) | 0xc0000000);
614
615 NV_ERROR(dev, "magic set 2:\n");
616 for (r = 0x409900; r <= 0x409910; r += 4)
617 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r));
618 nv_wr32(dev, 0x409900, nv_rd32(dev, 0x409904) | 0xc0000000);
619 for (r = 0x409e08; r <= 0x409e24; r += 4)
620 NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, nv_rd32(dev, r));
621 nv_wr32(dev, 0x409e08, nv_rd32(dev, 0x409e08) | 0xc0000000);
622
623 status &= ~0x00200000;
624 nv_wr32(dev, NV03_PGRAPH_NSOURCE, nsource);
625 nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000);
626 }
627
628 if (status) {
629 NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status);
630 nv_wr32(dev, NV03_PGRAPH_INTR, status);
631 }
632
633 {
634 const int isb = (1 << 16) | (1 << 0);
635
636 if ((nv_rd32(dev, 0x400500) & isb) != isb)
637 nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | isb);
638 }
639
640 nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
641}
642
643static void
644nouveau_crtc_irq_handler(struct drm_device *dev, int crtc)
645{
646 if (crtc & 1)
647 nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
648
649 if (crtc & 2)
650 nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
651}
652
653irqreturn_t
654nouveau_irq_handler(DRM_IRQ_ARGS)
655{
656 struct drm_device *dev = (struct drm_device *)arg;
657 struct drm_nouveau_private *dev_priv = dev->dev_private;
658 uint32_t status, fbdev_flags = 0;
659
660 status = nv_rd32(dev, NV03_PMC_INTR_0);
661 if (!status)
662 return IRQ_NONE;
663
664 if (dev_priv->fbdev_info) {
665 fbdev_flags = dev_priv->fbdev_info->flags;
666 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
667 }
668
669 if (status & NV_PMC_INTR_0_PFIFO_PENDING) {
670 nouveau_fifo_irq_handler(dev);
671 status &= ~NV_PMC_INTR_0_PFIFO_PENDING;
672 }
673
674 if (status & NV_PMC_INTR_0_PGRAPH_PENDING) {
675 if (dev_priv->card_type >= NV_50)
676 nv50_pgraph_irq_handler(dev);
677 else
678 nouveau_pgraph_irq_handler(dev);
679
680 status &= ~NV_PMC_INTR_0_PGRAPH_PENDING;
681 }
682
683 if (status & NV_PMC_INTR_0_CRTCn_PENDING) {
684 nouveau_crtc_irq_handler(dev, (status>>24)&3);
685 status &= ~NV_PMC_INTR_0_CRTCn_PENDING;
686 }
687
688 if (status & (NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
689 NV_PMC_INTR_0_NV50_I2C_PENDING)) {
690 nv50_display_irq_handler(dev);
691 status &= ~(NV_PMC_INTR_0_NV50_DISPLAY_PENDING |
692 NV_PMC_INTR_0_NV50_I2C_PENDING);
693 }
694
695 if (status)
696 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status);
697
698 if (dev_priv->fbdev_info)
699 dev_priv->fbdev_info->flags = fbdev_flags;
700
701 return IRQ_HANDLED;
702}