]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 30 Nov 2008 21:00:21 +0000 (13:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 30 Nov 2008 21:00:21 +0000 (13:00 -0800)
* 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/i915: Save/restore HWS_PGA on suspend/resume
  drm: move drm vblank initialization/cleanup to driver load/unload
  drm/i915: execbuffer pins objects, no need to ensure they're still in the GTT
  drm/i915: Always read pipestat in irq_handler
  drm/i915: Subtract total pinned bytes from available aperture size
  drm/i915: Avoid BUG_ONs on VT switch with a wedged chipset.
  drm/i915: Remove IMR masking during interrupt handler, and restart it if needed.
  drm/i915: Manage PIPESTAT to control vblank interrupts instead of IMR.

18 files changed:
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_opregion.c
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/mga/mga_dma.c
drivers/gpu/drm/mga/mga_irq.c
drivers/gpu/drm/r128/r128_drv.c
drivers/gpu/drm/r128/r128_drv.h
drivers/gpu/drm/r128/r128_irq.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_irq.c
drivers/gpu/drm/via/via_irq.c
drivers/gpu/drm/via/via_map.c
include/drm/drmP.h

index 3ab1e9cc4692fce873b925a7fb7816acc0173710..996097acb5e76b3c3d7698c0885f563ad9248522 100644 (file)
@@ -305,6 +305,8 @@ static void drm_cleanup(struct drm_device * dev)
                return;
        }
 
+       drm_vblank_cleanup(dev);
+
        drm_lastclose(dev);
 
        if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
index 15c8dabc3e97af6601448b32442df7fa803d71e5..1e787f894b3cf38f6c46eeda39c73cb8a49ad1c5 100644 (file)
@@ -94,7 +94,7 @@ static void vblank_disable_fn(unsigned long arg)
        }
 }
 
-static void drm_vblank_cleanup(struct drm_device *dev)
+void drm_vblank_cleanup(struct drm_device *dev)
 {
        /* Bail if the driver didn't call drm_vblank_init() */
        if (dev->num_crtcs == 0)
@@ -278,8 +278,6 @@ int drm_irq_uninstall(struct drm_device * dev)
 
        free_irq(dev->pdev->irq, dev);
 
-       drm_vblank_cleanup(dev);
-
        return 0;
 }
 EXPORT_SYMBOL(drm_irq_uninstall);
index 0d215e38606a32a053a620da3026139860e7fa5a..ba89b42f790abb693a0b355e9ee918f0f1339c81 100644 (file)
@@ -856,6 +856,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        spin_lock_init(&dev_priv->user_irq_lock);
 
+       ret = drm_vblank_init(dev, I915_NUM_PIPE);
+
+       if (ret) {
+               (void) i915_driver_unload(dev);
+               return ret;
+       }
+
        return ret;
 }
 
index ef1c0b8f8d07858422526f10e6f4fb63e428cf3d..0a4f39b9a0ec1623b79fa4073b8580efb203caa0 100644 (file)
@@ -47,6 +47,8 @@ enum pipe {
        PIPE_B,
 };
 
+#define I915_NUM_PIPE  2
+
 /* Interface history:
  *
  * 1.1: Original.
@@ -132,6 +134,7 @@ typedef struct drm_i915_private {
        int user_irq_refcount;
        /** Cached value of IMR to avoid reads in updating the bitfield */
        u32 irq_mask_reg;
+       u32 pipestat[2];
 
        int tex_lru_log_granularity;
        int allow_batchbuffer;
@@ -147,6 +150,7 @@ typedef struct drm_i915_private {
        u32 saveDSPBCNTR;
        u32 saveDSPARB;
        u32 saveRENDERSTANDBY;
+       u32 saveHWS;
        u32 savePIPEACONF;
        u32 savePIPEBCONF;
        u32 savePIPEASRC;
@@ -446,6 +450,13 @@ extern int i915_vblank_swap(struct drm_device *dev, void *data,
                            struct drm_file *file_priv);
 extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask);
 
+void
+i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
+
+void
+i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
+
+
 /* i915_mem.c */
 extern int i915_mem_alloc(struct drm_device *dev, void *data,
                          struct drm_file *file_priv);
index 6b4a2bd20640598f1e5407dc095ef3a9bed0d6b7..54bb0d0e49b86fe6ed3ab69cb27f49570394679c 100644 (file)
@@ -31,6 +31,8 @@
 #include "i915_drv.h"
 #include <linux/swap.h>
 
+#define I915_GEM_GPU_DOMAINS   (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
+
 static int
 i915_gem_object_set_domain(struct drm_gem_object *obj,
                            uint32_t read_domains,
@@ -83,20 +85,14 @@ int
 i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_get_aperture *args = data;
-       struct drm_i915_gem_object *obj_priv;
 
        if (!(dev->driver->driver_features & DRIVER_GEM))
                return -ENODEV;
 
        args->aper_size = dev->gtt_total;
-       args->aper_available_size = args->aper_size;
-
-       list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
-               if (obj_priv->pin_count > 0)
-                       args->aper_available_size -= obj_priv->obj->size;
-       }
+       args->aper_available_size = (args->aper_size -
+                                    atomic_read(&dev->pin_memory));
 
        return 0;
 }
@@ -1870,17 +1866,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
 
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
-               struct drm_i915_gem_object *obj_priv = obj->driver_private;
-
-               if (obj_priv->gtt_space == NULL) {
-                       /* We evicted the buffer in the process of validating
-                        * our set of buffers in.  We could try to recover by
-                        * kicking them everything out and trying again from
-                        * the start.
-                        */
-                       ret = -ENOMEM;
-                       goto err;
-               }
 
                /* make sure all previous memory operations have passed */
                ret = i915_gem_object_set_domain(obj,
@@ -2299,29 +2284,52 @@ i915_gem_idle(struct drm_device *dev)
 
        i915_gem_retire_requests(dev);
 
-       /* Active and flushing should now be empty as we've
-        * waited for a sequence higher than any pending execbuffer
-        */
-       BUG_ON(!list_empty(&dev_priv->mm.active_list));
-       BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+       if (!dev_priv->mm.wedged) {
+               /* Active and flushing should now be empty as we've
+                * waited for a sequence higher than any pending execbuffer
+                */
+               WARN_ON(!list_empty(&dev_priv->mm.active_list));
+               WARN_ON(!list_empty(&dev_priv->mm.flushing_list));
+               /* Request should now be empty as we've also waited
+                * for the last request in the list
+                */
+               WARN_ON(!list_empty(&dev_priv->mm.request_list));
+       }
 
-       /* Request should now be empty as we've also waited
-        * for the last request in the list
+       /* Empty the active and flushing lists to inactive.  If there's
+        * anything left at this point, it means that we're wedged and
+        * nothing good's going to happen by leaving them there.  So strip
+        * the GPU domains and just stuff them onto inactive.
         */
-       BUG_ON(!list_empty(&dev_priv->mm.request_list));
+       while (!list_empty(&dev_priv->mm.active_list)) {
+               struct drm_i915_gem_object *obj_priv;
 
-       /* Move all buffers out of the GTT. */
+               obj_priv = list_first_entry(&dev_priv->mm.active_list,
+                                           struct drm_i915_gem_object,
+                                           list);
+               obj_priv->obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
+               i915_gem_object_move_to_inactive(obj_priv->obj);
+       }
+
+       while (!list_empty(&dev_priv->mm.flushing_list)) {
+               struct drm_i915_gem_object *obj_priv;
+
+               obj_priv = list_first_entry(&dev_priv->mm.active_list,
+                                           struct drm_i915_gem_object,
+                                           list);
+               obj_priv->obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
+               i915_gem_object_move_to_inactive(obj_priv->obj);
+       }
+
+
+       /* Move all inactive buffers out of the GTT. */
        ret = i915_gem_evict_from_list(dev, &dev_priv->mm.inactive_list);
+       WARN_ON(!list_empty(&dev_priv->mm.inactive_list));
        if (ret) {
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
-       BUG_ON(!list_empty(&dev_priv->mm.active_list));
-       BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
-       BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
-       BUG_ON(!list_empty(&dev_priv->mm.request_list));
-
        i915_gem_cleanup_ringbuffer(dev);
        mutex_unlock(&dev->struct_mutex);
 
index 82752d6177a4949d406ec383b53cc31e6bcf9474..fe3d9cc72bf510403c797398c2cafa00eeecf8c2 100644 (file)
 
 #define MAX_NOPID ((u32)~0)
 
-/** These are the interrupts used by the driver */
-#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT |              \
-                                   I915_ASLE_INTERRUPT |               \
-                                   I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
-                                   I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+/**
+ * Interrupts that are always left unmasked.
+ *
+ * Since pipe events are edge-triggered from the PIPESTAT register to IIR,
+ * we leave them always unmasked in IMR and then control enabling them through
+ * PIPESTAT alone.
+ */
+#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
+                                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |  \
+                                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+
+/** Interrupts that we mask and unmask at runtime. */
+#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
+
+/** These are all of the interrupts used by the driver */
+#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \
+                                   I915_INTERRUPT_ENABLE_VAR)
 
 void
 i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -59,6 +71,41 @@ i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
        }
 }
 
+static inline u32
+i915_pipestat(int pipe)
+{
+       if (pipe == 0)
+               return PIPEASTAT;
+       if (pipe == 1)
+               return PIPEBSTAT;
+       BUG_ON(1);
+}
+
+void
+i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
+{
+       if ((dev_priv->pipestat[pipe] & mask) != mask) {
+               u32 reg = i915_pipestat(pipe);
+
+               dev_priv->pipestat[pipe] |= mask;
+               /* Enable the interrupt, clear any pending status */
+               I915_WRITE(reg, dev_priv->pipestat[pipe] | (mask >> 16));
+               (void) I915_READ(reg);
+       }
+}
+
+void
+i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
+{
+       if ((dev_priv->pipestat[pipe] & mask) != 0) {
+               u32 reg = i915_pipestat(pipe);
+
+               dev_priv->pipestat[pipe] &= ~mask;
+               I915_WRITE(reg, dev_priv->pipestat[pipe]);
+               (void) I915_READ(reg);
+       }
+}
+
 /**
  * i915_pipe_enabled - check if a pipe is enabled
  * @dev: DRM device
@@ -121,80 +168,102 @@ 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;
-       u32 iir;
+       u32 iir, new_iir;
        u32 pipea_stats, pipeb_stats;
+       u32 vblank_status;
+       u32 vblank_enable;
        int vblank = 0;
+       unsigned long irqflags;
+       int irq_received;
+       int ret = IRQ_NONE;
 
        atomic_inc(&dev_priv->irq_received);
 
-       if (dev->pdev->msi_enabled)
-               I915_WRITE(IMR, ~0);
        iir = I915_READ(IIR);
 
-       if (iir == 0) {
-               if (dev->pdev->msi_enabled) {
-                       I915_WRITE(IMR, dev_priv->irq_mask_reg);
-                       (void) I915_READ(IMR);
-               }
-               return IRQ_NONE;
+       if (IS_I965G(dev)) {
+               vblank_status = I915_START_VBLANK_INTERRUPT_STATUS;
+               vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE;
+       } else {
+               vblank_status = I915_VBLANK_INTERRUPT_STATUS;
+               vblank_enable = I915_VBLANK_INTERRUPT_ENABLE;
        }
 
-       /*
-        * Clear the PIPE(A|B)STAT regs before the IIR otherwise
-        * we may get extra interrupts.
-        */
-       if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
+       for (;;) {
+               irq_received = iir != 0;
+
+               /* Can't rely on pipestat interrupt bit in iir as it might
+                * have been cleared after the pipestat interrupt was received.
+                * It doesn't set the bit in iir again, but it still produces
+                * interrupts (for non-MSI).
+                */
+               spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
                pipea_stats = I915_READ(PIPEASTAT);
-               if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A))
-                       pipea_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
-                                        PIPE_VBLANK_INTERRUPT_ENABLE);
-               else if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
-                                       PIPE_VBLANK_INTERRUPT_STATUS)) {
+               pipeb_stats = I915_READ(PIPEBSTAT);
+               /*
+                * Clear the PIPE(A|B)STAT regs before the IIR
+                */
+               if (pipea_stats & 0x8000ffff) {
+                       I915_WRITE(PIPEASTAT, pipea_stats);
+                       irq_received = 1;
+               }
+
+               if (pipeb_stats & 0x8000ffff) {
+                       I915_WRITE(PIPEBSTAT, pipeb_stats);
+                       irq_received = 1;
+               }
+               spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+
+               if (!irq_received)
+                       break;
+
+               ret = IRQ_HANDLED;
+
+               I915_WRITE(IIR, iir);
+               new_iir = I915_READ(IIR); /* Flush posted writes */
+
+               if (dev_priv->sarea_priv)
+                       dev_priv->sarea_priv->last_dispatch =
+                               READ_BREADCRUMB(dev_priv);
+
+               if (iir & I915_USER_INTERRUPT) {
+                       dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
+                       DRM_WAKEUP(&dev_priv->irq_queue);
+               }
+
+               if (pipea_stats & vblank_status) {
                        vblank++;
                        drm_handle_vblank(dev, 0);
                }
 
-               I915_WRITE(PIPEASTAT, pipea_stats);
-       }
-       if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
-               pipeb_stats = I915_READ(PIPEBSTAT);
-               /* Ack the event */
-               I915_WRITE(PIPEBSTAT, pipeb_stats);
-
-               /* The vblank interrupt gets enabled even if we didn't ask for
-                  it, so make sure it's shut down again */
-               if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B))
-                       pipeb_stats &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
-                                        PIPE_VBLANK_INTERRUPT_ENABLE);
-               else if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS|
-                                       PIPE_VBLANK_INTERRUPT_STATUS)) {
+               if (pipeb_stats & vblank_status) {
                        vblank++;
                        drm_handle_vblank(dev, 1);
                }
 
-               if (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS)
+               if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
+                   (iir & I915_ASLE_INTERRUPT))
                        opregion_asle_intr(dev);
-               I915_WRITE(PIPEBSTAT, pipeb_stats);
-       }
-
-       I915_WRITE(IIR, iir);
-       if (dev->pdev->msi_enabled)
-               I915_WRITE(IMR, dev_priv->irq_mask_reg);
-       (void) I915_READ(IIR); /* Flush posted writes */
-
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->last_dispatch =
-                       READ_BREADCRUMB(dev_priv);
 
-       if (iir & I915_USER_INTERRUPT) {
-               dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
-               DRM_WAKEUP(&dev_priv->irq_queue);
+               /* With MSI, interrupts are only generated when iir
+                * transitions from zero to nonzero.  If another bit got
+                * set while we were handling the existing iir bits, then
+                * we would never get another interrupt.
+                *
+                * This is fine on non-MSI as well, as if we hit this path
+                * we avoid exiting the interrupt handler only to generate
+                * another one.
+                *
+                * Note that for MSI this could cause a stray interrupt report
+                * if an interrupt landed in the time between writing IIR and
+                * the posting read.  This should be rare enough to never
+                * trigger the 99% of 100,000 interrupts test for disabling
+                * stray interrupts.
+                */
+               iir = new_iir;
        }
 
-       if (iir & I915_ASLE_INTERRUPT)
-               opregion_asle_intr(dev);
-
-       return IRQ_HANDLED;
+       return ret;
 }
 
 static int i915_emit_irq(struct drm_device * dev)
@@ -330,48 +399,16 @@ int i915_irq_wait(struct drm_device *dev, void *data,
 int i915_enable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32     pipestat_reg = 0;
-       u32     pipestat;
-       u32     interrupt = 0;
        unsigned long irqflags;
 
-       switch (pipe) {
-       case 0:
-               pipestat_reg = PIPEASTAT;
-               interrupt = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
-               break;
-       case 1:
-               pipestat_reg = PIPEBSTAT;
-               interrupt = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
-               break;
-       default:
-               DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
-                         pipe);
-               return 0;
-       }
-
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-       /* Enabling vblank events in IMR comes before PIPESTAT write, or
-        * there's a race where the PIPESTAT vblank bit gets set to 1, so
-        * the OR of enabled PIPESTAT bits goes to 1, so the PIPExEVENT in
-        * ISR flashes to 1, but the IIR bit doesn't get set to 1 because
-        * IMR masks it.  It doesn't ever get set after we clear the masking
-        * in IMR because the ISR bit is edge, not level-triggered, on the
-        * OR of PIPESTAT bits.
-        */
-       i915_enable_irq(dev_priv, interrupt);
-       pipestat = I915_READ(pipestat_reg);
        if (IS_I965G(dev))
-               pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE;
+               i915_enable_pipestat(dev_priv, pipe,
+                                    PIPE_START_VBLANK_INTERRUPT_ENABLE);
        else
-               pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE;
-       /* Clear any stale interrupt status */
-       pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
-                    PIPE_VBLANK_INTERRUPT_STATUS);
-       I915_WRITE(pipestat_reg, pipestat);
-       (void) I915_READ(pipestat_reg); /* Posting read */
+               i915_enable_pipestat(dev_priv, pipe,
+                                    PIPE_VBLANK_INTERRUPT_ENABLE);
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
-
        return 0;
 }
 
@@ -381,37 +418,12 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
 void i915_disable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32     pipestat_reg = 0;
-       u32     pipestat;
-       u32     interrupt = 0;
        unsigned long irqflags;
 
-       switch (pipe) {
-       case 0:
-               pipestat_reg = PIPEASTAT;
-               interrupt = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
-               break;
-       case 1:
-               pipestat_reg = PIPEBSTAT;
-               interrupt = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
-               break;
-       default:
-               DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
-                         pipe);
-               return;
-               break;
-       }
-
        spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-       i915_disable_irq(dev_priv, interrupt);
-       pipestat = I915_READ(pipestat_reg);
-       pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE |
-                     PIPE_VBLANK_INTERRUPT_ENABLE);
-       /* Clear any stale interrupt status */
-       pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS |
-                    PIPE_VBLANK_INTERRUPT_STATUS);
-       I915_WRITE(pipestat_reg, pipestat);
-       (void) I915_READ(pipestat_reg); /* Posting read */
+       i915_disable_pipestat(dev_priv, pipe,
+                             PIPE_VBLANK_INTERRUPT_ENABLE |
+                             PIPE_START_VBLANK_INTERRUPT_ENABLE);
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
@@ -476,32 +488,35 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
        I915_WRITE(HWSTAM, 0xeffe);
+       I915_WRITE(PIPEASTAT, 0);
+       I915_WRITE(PIPEBSTAT, 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
+       (void) I915_READ(IER);
 }
 
 int i915_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       int ret, num_pipes = 2;
-
-       /* Set initial unmasked IRQs to just the selected vblank pipes. */
-       dev_priv->irq_mask_reg = ~0;
-
-       ret = drm_vblank_init(dev, num_pipes);
-       if (ret)
-               return ret;
 
        dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
-       dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
-       dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
 
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 
-       dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK;
+       /* Unmask the interrupts that we always want on. */
+       dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
+
+       dev_priv->pipestat[0] = 0;
+       dev_priv->pipestat[1] = 0;
+
+       /* Disable pipe interrupt enables, clear pending pipe status */
+       I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
+       I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
+       /* Clear pending interrupt status */
+       I915_WRITE(IIR, I915_READ(IIR));
 
-       I915_WRITE(IMR, dev_priv->irq_mask_reg);
        I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
+       I915_WRITE(IMR, dev_priv->irq_mask_reg);
        (void) I915_READ(IER);
 
        opregion_enable_asle(dev);
@@ -513,7 +528,6 @@ 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;
-       u32 temp;
 
        if (!dev_priv)
                return;
@@ -521,13 +535,12 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
        dev_priv->vblank_pipe = 0;
 
        I915_WRITE(HWSTAM, 0xffffffff);
+       I915_WRITE(PIPEASTAT, 0);
+       I915_WRITE(PIPEBSTAT, 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
 
-       temp = I915_READ(PIPEASTAT);
-       I915_WRITE(PIPEASTAT, temp);
-       temp = I915_READ(PIPEBSTAT);
-       I915_WRITE(PIPEBSTAT, temp);
-       temp = I915_READ(IIR);
-       I915_WRITE(IIR, temp);
+       I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
+       I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
+       I915_WRITE(IIR, I915_READ(IIR));
 }
index 1787a0c7e3abf09acc363b87495190ce362db6ce..13ae731a33dba577b9a7326a9fe22daf8c1baf1c 100644 (file)
@@ -235,17 +235,15 @@ void opregion_enable_asle(struct drm_device *dev)
        struct opregion_asle *asle = dev_priv->opregion.asle;
 
        if (asle) {
-               u32 pipeb_stats = I915_READ(PIPEBSTAT);
                if (IS_MOBILE(dev)) {
-                       /* Many devices trigger events with a write to the
-                          legacy backlight controller, so we need to ensure
-                          that it's able to generate interrupts */
-                       I915_WRITE(PIPEBSTAT, pipeb_stats |=
-                                  I915_LEGACY_BLC_EVENT_ENABLE);
-                       i915_enable_irq(dev_priv, I915_ASLE_INTERRUPT |
-                                       I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
-               } else
-                       i915_enable_irq(dev_priv, I915_ASLE_INTERRUPT);
+                       unsigned long irqflags;
+
+                       spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+                       i915_enable_pipestat(dev_priv, 1,
+                                            I915_LEGACY_BLC_EVENT_ENABLE);
+                       spin_unlock_irqrestore(&dev_priv->user_irq_lock,
+                                              irqflags);
+               }
 
                asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
                        ASLE_PFMB_EN;
index 5ddc6e595c0cef6b12ca729570505fd136f5d07d..5d84027ee8f39608076220513c71ed097cb751e4 100644 (file)
@@ -244,6 +244,9 @@ int i915_save_state(struct drm_device *dev)
        if (IS_I965G(dev) && IS_MOBILE(dev))
                dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY);
 
+       /* Hardware status page */
+       dev_priv->saveHWS = I915_READ(HWS_PGA);
+
        /* Display arbitration control */
        dev_priv->saveDSPARB = I915_READ(DSPARB);
 
@@ -373,6 +376,9 @@ int i915_restore_state(struct drm_device *dev)
        if (IS_I965G(dev) && IS_MOBILE(dev))
                I915_WRITE(MCHBAR_RENDER_STANDBY, dev_priv->saveRENDERSTANDBY);
 
+       /* Hardware status page */
+       I915_WRITE(HWS_PGA, dev_priv->saveHWS);
+
        /* Display arbitration */
        I915_WRITE(DSPARB, dev_priv->saveDSPARB);
 
index c1d12dbfa8d8dec82e47c7821561e06da9744417..b49c5ff29585d3533b9b915b6c65cc5f9904c68f 100644 (file)
@@ -396,6 +396,7 @@ int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf)
 int mga_driver_load(struct drm_device * dev, unsigned long flags)
 {
        drm_mga_private_t *dev_priv;
+       int ret;
 
        dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
        if (!dev_priv)
@@ -415,6 +416,13 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags)
        dev->types[7] = _DRM_STAT_PRIMARY;
        dev->types[8] = _DRM_STAT_SECONDARY;
 
+       ret = drm_vblank_init(dev, 1);
+
+       if (ret) {
+               (void) mga_driver_unload(dev);
+               return ret;
+       }
+
        return 0;
 }
 
index bab42f41188b0238356b4ef1ce80caeb87e6a6db..daa6041a483ad8be9f608b72f4c3f79db7f63e01 100644 (file)
@@ -152,11 +152,6 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
 int mga_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
-       int ret;
-
-       ret = drm_vblank_init(dev, 1);
-       if (ret)
-               return ret;
 
        DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
 
index 3265d53ba91f0d966fb4aadbe0645cab227cd0ef..601f4c0e5da57accd3e81ea1938f72bcf1c61c2e 100644 (file)
@@ -45,6 +45,7 @@ static struct drm_driver driver = {
            DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
            DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
        .dev_priv_size = sizeof(drm_r128_buf_priv_t),
+       .load = r128_driver_load,
        .preclose = r128_driver_preclose,
        .lastclose = r128_driver_lastclose,
        .get_vblank_counter = r128_get_vblank_counter,
@@ -84,6 +85,11 @@ static struct drm_driver driver = {
        .patchlevel = DRIVER_PATCHLEVEL,
 };
 
+int r128_driver_load(struct drm_device * dev, unsigned long flags)
+{
+       return drm_vblank_init(dev, 1);
+}
+
 static int __init r128_init(void)
 {
        driver.num_ioctls = r128_max_ioctl;
index 5898b274279d216cf0630fed63af2480a7a0ebb4..797a26c42dababf8c12193271aaf336849271424 100644 (file)
@@ -159,6 +159,7 @@ extern void r128_driver_irq_preinstall(struct drm_device * dev);
 extern int r128_driver_irq_postinstall(struct drm_device *dev);
 extern void r128_driver_irq_uninstall(struct drm_device * dev);
 extern void r128_driver_lastclose(struct drm_device * dev);
+extern int r128_driver_load(struct drm_device * dev, unsigned long flags);
 extern void r128_driver_preclose(struct drm_device * dev,
                                 struct drm_file *file_priv);
 
index d7349012a680b35a0b50091e2e6e5f3bf70d6004..69810fb8ac49101a36645061adc93ca265e19cd8 100644 (file)
@@ -102,7 +102,7 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
 
 int r128_driver_irq_postinstall(struct drm_device *dev)
 {
-       return drm_vblank_init(dev, 1);
+       return 0;
 }
 
 void r128_driver_irq_uninstall(struct drm_device * dev)
index abdc1ae384674def8810a122ecc1ae3c11a47ae2..dcebb4bee7aaf9e0e845db50296798f76686d1a6 100644 (file)
@@ -1757,6 +1757,12 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
        if (ret != 0)
                return ret;
 
+       ret = drm_vblank_init(dev, 2);
+       if (ret) {
+               radeon_driver_unload(dev);
+               return ret;
+       }
+
        DRM_DEBUG("%s card detected\n",
                  ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));
        return ret;
index 5079f7054a2f67aa712bcf6c89fa4e98cb1835b9..97c0599fdb1e2c49898c14c0ba097101978f8dc2 100644 (file)
@@ -337,15 +337,10 @@ int radeon_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_radeon_private_t *dev_priv =
            (drm_radeon_private_t *) dev->dev_private;
-       int ret;
 
        atomic_set(&dev_priv->swi_emitted, 0);
        DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
 
-       ret = drm_vblank_init(dev, 2);
-       if (ret)
-               return ret;
-
        dev->max_vblank_count = 0x001fffff;
 
        radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
index 665d319b927b2d3a07cc25a65ebccbc33b1160aa..c248c1d37268ac64cfed64e8b6bfba43b3d80332 100644 (file)
@@ -314,7 +314,6 @@ int via_driver_irq_postinstall(struct drm_device *dev)
        if (!dev_priv)
                return -EINVAL;
 
-       drm_vblank_init(dev, 1);
        status = VIA_READ(VIA_REG_INTERRUPT);
        VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
                  | dev_priv->irq_enable_mask);
index a967556be014612f731125e8b9f77437a334921b..2c4f0b48579207dd74ead54b1833c03e86e92cea 100644 (file)
@@ -107,8 +107,17 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset)
        ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
        if (ret) {
                drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+               return ret;
        }
-       return ret;
+
+       ret = drm_vblank_init(dev, 1);
+       if (ret) {
+               drm_sman_takedown(&dev_priv->sman);
+               drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
+               return ret;
+       }
+
+       return 0;
 }
 
 int via_driver_unload(struct drm_device *dev)
index 28c7f1679d496f6981d0e14418ef29af448b5a0d..d5e8e5c8954825baaf69564e07716dd041ed0593 100644 (file)
@@ -1151,6 +1151,7 @@ extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
 extern void drm_handle_vblank(struct drm_device *dev, int crtc);
 extern int drm_vblank_get(struct drm_device *dev, int crtc);
 extern void drm_vblank_put(struct drm_device *dev, int crtc);
+extern void drm_vblank_cleanup(struct drm_device *dev);
 /* Modesetting support */
 extern int drm_modeset_ctl(struct drm_device *dev, void *data,
                           struct drm_file *file_priv);