drm/nv50: improve evo error handler when more than just channel 0 active
authorBen Skeggs <bskeggs@redhat.com>
Wed, 20 Oct 2010 04:23:29 +0000 (14:23 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 3 Dec 2010 05:10:58 +0000 (15:10 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_graph.c

index d0ce86c24ebff133b3ba242b2a08eef2ac7a2308..b6384d36d5d0c6ba021a29e219ec35747e450769 100644 (file)
 #define NV50_PDISPLAY_INTR_1_CLK_UNK10                               0x00000010
 #define NV50_PDISPLAY_INTR_1_CLK_UNK20                               0x00000020
 #define NV50_PDISPLAY_INTR_1_CLK_UNK40                               0x00000040
-#define NV50_PDISPLAY_INTR_EN                                        0x0061002c
-#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC                            0x0000000c
-#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(n)                   (1 << ((n) + 2))
-#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_0                          0x00000004
-#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_1                          0x00000008
-#define NV50_PDISPLAY_INTR_EN_CLK_UNK10                              0x00000010
-#define NV50_PDISPLAY_INTR_EN_CLK_UNK20                              0x00000020
-#define NV50_PDISPLAY_INTR_EN_CLK_UNK40                              0x00000040
+#define NV50_PDISPLAY_INTR_EN_0                                      0x00610028
+#define NV50_PDISPLAY_INTR_EN_1                                      0x0061002c
+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC                          0x0000000c
+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(n)                 (1 << ((n) + 2))
+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_0                        0x00000004
+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_1                        0x00000008
+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK10                            0x00000010
+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK20                            0x00000020
+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK40                            0x00000040
 #define NV50_PDISPLAY_UNK30_CTRL                                     0x00610030
 #define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0                        0x00000200
 #define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1                        0x00000400
 #define NV50_PDISPLAY_UNK30_CTRL_PENDING                             0x80000000
-#define NV50_PDISPLAY_TRAPPED_ADDR                                   0x00610080
-#define NV50_PDISPLAY_TRAPPED_DATA                                   0x00610084
+#define NV50_PDISPLAY_TRAPPED_ADDR(i)                  ((i) * 0x08 + 0x00610080)
+#define NV50_PDISPLAY_TRAPPED_DATA(i)                  ((i) * 0x08 + 0x00610084)
 #define NV50_PDISPLAY_EVO_CTRL(i)                      ((i) * 0x10 + 0x00610200)
 #define NV50_PDISPLAY_EVO_CTRL_DMA                                   0x00000010
 #define NV50_PDISPLAY_EVO_CTRL_DMA_DISABLED                          0x00000000
index db100a8f231e05dfa06fddd5ee74f0a032023ef2..99871e304d106c46b954388207e41e05cd9ed60b 100644 (file)
@@ -149,13 +149,13 @@ nv50_display_init(struct drm_device *dev)
        }
 
        nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000);
-       nv_wr32(dev, 0x610028, 0x00000000);
        nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000);
+       nv_wr32(dev, NV50_PDISPLAY_INTR_EN_0, 0x00000000);
        nv_mask(dev, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000);
-       nv_wr32(dev, NV50_PDISPLAY_INTR_EN,
-                    NV50_PDISPLAY_INTR_EN_CLK_UNK10 |
-                    NV50_PDISPLAY_INTR_EN_CLK_UNK20 |
-                    NV50_PDISPLAY_INTR_EN_CLK_UNK40);
+       nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1,
+                    NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 |
+                    NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 |
+                    NV50_PDISPLAY_INTR_EN_1_CLK_UNK40);
 
        /* enable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -248,7 +248,7 @@ static int nv50_display_disable(struct drm_device *dev)
        }
 
        /* disable interrupts. */
-       nv_wr32(dev, NV50_PDISPLAY_INTR_EN, 0x00000000);
+       nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, 0x00000000);
 
        /* disable hotplug interrupts */
        nv_wr32(dev, 0xe054, 0xffffffff);
@@ -451,8 +451,7 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
        if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1)
                nv50_display_vblank_crtc_handler(dev, 1);
 
-       nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev,
-                    NV50_PDISPLAY_INTR_EN) & ~intr);
+       nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, intr, 0x00000000);
        nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr);
 }
 
@@ -779,16 +778,23 @@ nv50_display_irq_handler_bh(struct work_struct *work)
 static void
 nv50_display_error_handler(struct drm_device *dev)
 {
-       uint32_t addr, data;
+       u32 channels = (nv_rd32(dev, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16;
+       u32 addr, data;
+       int chid;
 
-       nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000);
-       addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR);
-       data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA);
+       for (chid = 0; chid < 5; chid++) {
+               if (!(channels & (1 << chid)))
+                       continue;
 
-       NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x (0x%04x 0x%02x)\n",
-                0, addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf);
+               nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000 << chid);
+               addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid));
+               data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA(chid));
+               NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x "
+                             "(0x%04x 0x%02x)\n", chid,
+                        addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf);
 
-       nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000);
+               nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000);
+       }
 }
 
 void
@@ -891,9 +897,9 @@ nv50_display_irq_handler(struct drm_device *dev)
                if (!intr0 && !(intr1 & ~delayed))
                        break;
 
-               if (intr0 & 0x00010000) {
+               if (intr0 & 0x001f0000) {
                        nv50_display_error_handler(dev);
-                       intr0 &= ~0x00010000;
+                       intr0 &= ~0x001f0000;
                }
 
                if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) {
index a764af52a3ba34378e63e1156f07345845c39de3..d441308a09cf831b8302cbd5be8f1986ccdca0ae 100644 (file)
@@ -384,13 +384,12 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan,
        if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1)
                return -EINVAL;
 
-       if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN) &
-                     NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data))) {
+       if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN_1) &
+                          NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data))) {
                nv_wr32(dev, NV50_PDISPLAY_INTR_1,
-                       NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data));
-               nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev,
-                       NV50_PDISPLAY_INTR_EN) |
-                       NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data));
+                            NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data));
+               nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
+                            NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data));
        }
 
        list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting);