I was seeing sticky interrupts happening on my 965gm -- none of the
interrupt status bits would be set, and yet the interrupt handler was
getting constantly invoked. Eventually, the kernel would give up and
disable the interrupt, making my chip stop working.

I patched the driver so that it used the PIPE_EVENT interrupt instead of
the (presumably old) PIPE_VBLANK interrupt. This fixed the problem for
me. See the included patch.

(this patch also includes #defines for the remaining bits in the
pipestat and interrupt definition bits)

commit e6db078052fd9a36fe392d758627f0f2d0fd6b27
Author: Keith Packard <[EMAIL PROTECTED]>
Date:   Thu Jan 24 11:46:45 2008 -0800

    Switch from PIPE_VBLANK to PIPE_EVENT interrupts.
    
    My 965GM gets interrupts stuck when using the old PIPE_VBLANK interrupt.
    Switch to the PIPE_EVENT interrupt mechanism, and set the PIPE*STAT
    registers to use START_VBLANK on 965 and VBLANK on previous chips.

diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 7a0c0ea..bd83384 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -460,10 +460,23 @@ extern int i915_wait_ring(struct drm_device * dev, int n, 
const char *caller);
 
 /* Interrupt bits:
  */
-#define USER_INT_FLAG    (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
-#define HWB_OOM_FLAG     (1<<13) /* binner out of memory */
+#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT             (1<<18)
+#define I915_DISPLAY_PORT_INTERRUPT                    (1<<17)
+#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT     (1<<15)
+#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT       (1<<14)
+#define I915_HWB_OOM_INTERRUPT                         (1<<13) /* binner out 
of memory */
+#define I915_SYNC_STATUS_INTERRUPT                     (1<<12)
+#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT    (1<<11)
+#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT    (1<<10)
+#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT      (1<<9)
+#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT    (1<<8)
+#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT           (1<<7)
+#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT            (1<<6)
+#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT           (1<<5)
+#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT            (1<<4)
+#define I915_DEBUG_INTERRUPT                           (1<<2)
+#define I915_USER_INTERRUPT                            (1<<1)
+
 
 #define I915REG_HWSTAM         0x02098
 #define I915REG_INT_IDENTITY_R 0x020a4
@@ -507,8 +520,31 @@ extern int i915_wait_ring(struct drm_device * dev, int n, 
const char *caller);
 #define PIPE_PIXEL_MASK         0x00ffffff
 #define PIPE_PIXEL_SHIFT        0
 
-#define I915_VBLANK_INTERRUPT_ENABLE   (1UL<<17)
-#define I915_VBLANK_CLEAR              (1UL<<1)
+#define I915_FIFO_UNDERRUN_STATUS              (1UL<<31)
+#define I915_CRC_ERROR_ENABLE                  (1UL<<29)
+#define I915_CRC_DONE_ENABLE                   (1UL<<28)
+#define I915_GMBUS_EVENT_ENABLE                        (1UL<<27)
+#define I915_VSYNC_INTERRUPT_ENABLE            (1UL<<25)
+#define I915_DISPLAY_LINE_COMPARE_ENABLE       (1UL<<24)
+#define I915_DPST_EVENT_ENABLE                 (1UL<<23)
+#define I915_LEGACY_BLC_EVENT_ENABLE           (1UL<<22)
+#define I915_ODD_FIELD_INTERRUPT_ENABLE                (1UL<<21)
+#define I915_EVEN_FIELD_INTERRUPT_ENABLE       (1UL<<20)
+#define I915_START_VBLANK_INTERRUPT_ENABLE     (1UL<<18)       /* 965 or later 
*/
+#define I915_VBLANK_INTERRUPT_ENABLE           (1UL<<17)
+#define I915_OVERLAY_UPDATED_ENABLE            (1UL<<16)
+#define I915_CRC_ERROR_INTERRUPT_STATUS                (1UL<<13)
+#define I915_CRC_DONE_INTERRUPT_STATUS         (1UL<<12)
+#define I915_GMBUS_INTERRUPT_STATUS            (1UL<<11)
+#define I915_VSYNC_INTERRUPT_STATUS            (1UL<<9)
+#define I915_DISPLAY_LINE_COMPARE_STATUS       (1UL<<8)
+#define I915_DPST_EVENT_STATUS                 (1UL<<7)
+#define I915_LEGACY_BLC_EVENT_STATUS           (1UL<<6)
+#define I915_ODD_FIELD_INTERRUPT_STATUS                (1UL<<5)
+#define I915_EVEN_FIELD_INTERRUPT_STATUS       (1UL<<4)
+#define I915_START_VBLANK_INTERRUPT_STATUS     (1UL<<2)        /* 965 or later 
*/
+#define I915_VBLANK_INTERRUPT_STATUS           (1UL<<1)
+#define I915_OVERLAY_UPDATED_STATUS            (1UL<<0)
 
 #define SRX_INDEX              0x3c4
 #define SRX_DATA               0x3c5
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 56bcac9..a31eec6 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -31,10 +31,6 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#define USER_INT_FLAG (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
-
 #define MAX_NOPID ((u32)~0)
 
 /**
@@ -396,53 +392,62 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u16 temp;
+       u32 iir;
        u32 pipea_stats, pipeb_stats;
+       int vblank = 0;
 
-       pipea_stats = I915_READ(I915REG_PIPEASTAT);
-       pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
-
-       temp = I915_READ16(I915REG_INT_IDENTITY_R);
-
+       iir = I915_READ(I915REG_INT_IDENTITY_R);
 #if 0
-       DRM_DEBUG("flag=%08x\n", temp);
+       DRM_DEBUG("flag=%08x\n", iir);
 #endif
-       if (temp == 0)
+       if (iir == 0) {
+               DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 
0x%08x\n",
+                          iir,
+                          I915_READ(I915REG_INT_MASK_R),
+                          I915_READ(I915REG_INT_ENABLE_R),
+                          I915_READ(I915REG_PIPEASTAT),
+                          I915_READ(I915REG_PIPEBSTAT));
                return IRQ_NONE;
+       }
 
        /*
         * Clear the PIPE(A|B)STAT regs before the IIR otherwise
         * we may get extra interrupts.
         */
-       if (temp & VSYNC_PIPEA_FLAG) {
-               drm_handle_vblank(dev, i915_get_plane(dev, 0));
-               I915_WRITE(I915REG_PIPEASTAT,
-                          pipea_stats | I915_VBLANK_INTERRUPT_ENABLE |
-                          I915_VBLANK_CLEAR);
-       }
-       if (temp & VSYNC_PIPEB_FLAG) {
-               drm_handle_vblank(dev, i915_get_plane(dev, 1));
-               I915_WRITE(I915REG_PIPEBSTAT,
-                          pipeb_stats | I915_VBLANK_INTERRUPT_ENABLE |
-                          I915_VBLANK_CLEAR);
+       if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
+               pipea_stats = I915_READ(I915REG_PIPEASTAT);
+               if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
+                                  I915_VBLANK_INTERRUPT_STATUS))
+               {
+                       vblank++;
+                       drm_handle_vblank(dev, i915_get_plane(dev, 0));
+               }
+               I915_WRITE(I915REG_PIPEASTAT, pipea_stats);
+       }
+       if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
+               pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
+               if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
+                                  I915_VBLANK_INTERRUPT_STATUS))
+               {
+                       vblank++;
+                       drm_handle_vblank(dev, i915_get_plane(dev, 1));
+               }
+               I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats);
        }
 
-       I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
-       (void) I915_READ16(I915REG_INT_IDENTITY_R); /* Flush posted write */
-
-       temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | VSYNC_PIPEA_FLAG |
-                VSYNC_PIPEB_FLAG);
-
        dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
 
-       if (temp & USER_INT_FLAG) {
+       I915_WRITE(I915REG_INT_IDENTITY_R, iir);
+       (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */
+
+       if (iir & I915_USER_INTERRUPT) {
                DRM_WAKEUP(&dev_priv->irq_queue);
 #ifdef I915_HAVE_FENCE
                i915_fence_handler(dev);
 #endif
        }
 
-       if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
+       if (vblank) {
                if (dev_priv->swaps_pending > 0)
                        drm_locked_tasklet(dev, i915_vblank_tasklet);
        }
@@ -473,8 +478,8 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv)
 {
        DRM_SPINLOCK(&dev_priv->user_irq_lock);
        if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
-               dev_priv->irq_enable_reg |= USER_INT_FLAG;
-               I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+               dev_priv->irq_enable_reg |= I915_USER_INTERRUPT;
+               I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
        }
        DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
 
@@ -485,7 +490,7 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv)
        DRM_SPINLOCK(&dev_priv->user_irq_lock);
        if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
                //              dev_priv->irq_enable_reg &= ~USER_INT_FLAG;
-               //              I915_WRITE16(I915REG_INT_ENABLE_R, 
dev_priv->irq_enable_reg);
+               //              I915_WRITE(I915REG_INT_ENABLE_R, 
dev_priv->irq_enable_reg);
        }
        DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
 }
@@ -562,13 +567,17 @@ int i915_enable_vblank(struct drm_device *dev, int plane)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe = i915_get_pipe(dev, plane);
+       u32     pipestat_reg = 0;
+       u32     pipestat;
 
        switch (pipe) {
        case 0:
-               dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
+               pipestat_reg = I915REG_PIPEASTAT;
+               dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
                break;
        case 1:
-               dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG;
+               pipestat_reg = I915REG_PIPEBSTAT;
+               dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
                break;
        default:
                DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
@@ -576,7 +585,25 @@ int i915_enable_vblank(struct drm_device *dev, int plane)
                break;
        }
 
-       I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+       if (pipestat_reg)
+       {
+               pipestat = I915_READ (pipestat_reg);
+               /*
+                * Older chips didn't have the start vblank interrupt,
+                * but 
+                */
+               if (IS_I965G (dev))
+                       pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE;
+               else
+                       pipestat |= I915_VBLANK_INTERRUPT_ENABLE;
+               /*
+                * Clear any pending status
+                */
+               pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS |
+                            I915_VBLANK_INTERRUPT_STATUS);
+               I915_WRITE(pipestat_reg, pipestat);
+       }
+       I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
 
        return 0;
 }
@@ -585,13 +612,17 @@ void i915_disable_vblank(struct drm_device *dev, int 
plane)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe = i915_get_pipe(dev, plane);
+       u32     pipestat_reg = 0;
+       u32     pipestat;
 
        switch (pipe) {
        case 0:
-               dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG;
+               pipestat_reg = I915REG_PIPEASTAT;
+               dev_priv->irq_enable_reg &= 
~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
                break;
        case 1:
-               dev_priv->irq_enable_reg &= ~VSYNC_PIPEB_FLAG;
+               pipestat_reg = I915REG_PIPEBSTAT;
+               dev_priv->irq_enable_reg &= 
~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
                break;
        default:
                DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
@@ -599,16 +630,28 @@ void i915_disable_vblank(struct drm_device *dev, int 
plane)
                break;
        }
 
-       I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+       I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+       if (pipestat_reg)
+       {
+               pipestat = I915_READ (pipestat_reg);
+               pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE |
+                             I915_VBLANK_INTERRUPT_ENABLE);
+               /*
+                * Clear any pending status
+                */
+               pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS |
+                            I915_VBLANK_INTERRUPT_STATUS);
+               I915_WRITE(pipestat_reg, pipestat);
+       }
 }
 
 static void i915_enable_interrupt (struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        
-       dev_priv->irq_enable_reg |= USER_INT_FLAG;
+       dev_priv->irq_enable_reg |= I915_USER_INTERRUPT;
 
-       I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+       I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
        dev_priv->irq_enabled = 1;
 }
 
@@ -649,9 +692,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
 
        flag = I915_READ(I915REG_INT_ENABLE_R);
        pipe->pipe = 0;
-       if (flag & VSYNC_PIPEA_FLAG)
+       if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)
                pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
-       if (flag & VSYNC_PIPEB_FLAG)
+       if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
                pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
 
        return 0;
@@ -855,16 +898,20 @@ int i915_driver_irq_postinstall(struct drm_device * dev)
 void i915_driver_irq_uninstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u16 temp;
+       u32 temp;
 
        if (!dev_priv)
                return;
 
        dev_priv->irq_enabled = 0;
-       I915_WRITE16(I915REG_HWSTAM, 0xffff);
-       I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
-       I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
-
-       temp = I915_READ16(I915REG_INT_IDENTITY_R);
-       I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+       I915_WRITE(I915REG_HWSTAM, 0xffffffff);
+       I915_WRITE(I915REG_INT_MASK_R, 0xffffffff);
+       I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
+
+       temp = I915_READ(I915REG_PIPEASTAT);
+       I915_WRITE(I915REG_PIPEASTAT, temp);
+       temp = I915_READ(I915REG_PIPEBSTAT);
+       I915_WRITE(I915REG_PIPEBSTAT, temp);
+       temp = I915_READ(I915REG_INT_IDENTITY_R);
+       I915_WRITE(I915REG_INT_IDENTITY_R, temp);
 }

-- 
[EMAIL PROTECTED]

Attachment: signature.asc
Description: This is a digitally signed message part

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to