diff --git a/linux-core/drmP.h b/linux-core/drmP.h index cf1c0fd..0ab69fe 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -832,6 +832,7 @@ typedef struct drm_device { /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ u32 *vblank_premodeset; /* were lost during modeset */ + struct timer_list vblank_disable_timer; unsigned long max_vblank_count; /**< size of vblank counter register */ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index c9d1c0d..5520fcc 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -77,10 +77,19 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp, return 0; } +static void vblank_disable_fn(unsigned long arg) +{ + drm_device_t *dev = (drm_device_t *)arg; + + dev->driver->disable_vblank(dev, 0); + dev->driver->disable_vblank(dev, 1); +} + int drm_vblank_init(drm_device_t *dev, int num_crtcs) { int i, ret = -ENOMEM; + setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, dev); spin_lock_init(&dev->vbl_lock); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; @@ -339,6 +348,7 @@ void drm_update_vblank_count(drm_device_t *dev, int crtc) } EXPORT_SYMBOL(drm_update_vblank_count); + /** * drm_vblank_get - get a reference count on vblank events * @dev: DRM device @@ -377,9 +387,10 @@ EXPORT_SYMBOL(drm_vblank_get); */ void drm_vblank_put(drm_device_t *dev, int crtc) { - /* Last user can disable interrupts */ + /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) - dev->driver->disable_vblank(dev, crtc); + mod_timer(&dev->vblank_disable_timer, + round_jiffies_relative(DRM_HZ)); } EXPORT_SYMBOL(drm_vblank_put); @@ -472,7 +483,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) } flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; - crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; + crtc = (flags & _DRM_VBLANK_SECONDARY) ? 1 : 0; if (crtc >= dev->num_crtcs) return -EINVAL; diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index ebb184c..b239889 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -31,17 +31,6 @@ #include "i915_drm.h" #include "i915_drv.h" -#define IS_I965G(dev) (dev->pci_device == 0x2972 || \ - dev->pci_device == 0x2982 || \ - dev->pci_device == 0x2992 || \ - dev->pci_device == 0x29A2 || \ - dev->pci_device == 0x2A02 || \ - dev->pci_device == 0x2A12) - -#define IS_G33(dev) (dev->pci_device == 0x29C2 || \ - dev->pci_device == 0x29B2 || \ - dev->pci_device == 0x29D2) - /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time * the head pointer changes, so that EBUSY only happens if the ring diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 213759a..c8961c0 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -396,4 +396,17 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) #define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) + +#define IS_I965G(dev) (dev->pci_device == 0x2972 || \ + dev->pci_device == 0x2982 || \ + dev->pci_device == 0x2992 || \ + dev->pci_device == 0x29A2 || \ + dev->pci_device == 0x2A02 || \ + dev->pci_device == 0x2A12) + +#define IS_G33(dev) (dev->pci_device == 0x29C2 || \ + dev->pci_device == 0x29B2 || \ + dev->pci_device == 0x29D2) + + #endif diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 713ec65..bb3321f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -285,6 +285,9 @@ u32 i915_get_vblank_counter(drm_device_t *dev, int crtc) unsigned long low_frame = crtc ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; u32 high1, high2, low, count; + if (!IS_I965G(dev)) + return 0; + /* * High & low register fields aren't synchronized, so make sure * we get a low value that's stable across two reads of the high @@ -315,7 +318,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) pipeb_stats = I915_READ(I915REG_PIPEBSTAT); temp = I915_READ16(I915REG_INT_IDENTITY_R); - temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG); #if 0 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); @@ -326,6 +328,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_WRITE16(I915REG_INT_IDENTITY_R, temp); (void) I915_READ16(I915REG_INT_IDENTITY_R); + 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) { @@ -335,6 +340,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) #endif } + if (!IS_I965G(dev)) { + if (temp & VSYNC_PIPEA_FLAG) + atomic_inc(&dev->_vblank_count[0]); + if (temp & VSYNC_PIPEB_FLAG) + atomic_inc(&dev->_vblank_count[1]); + } + /* * Use drm_update_vblank_counter here to deal with potential lost * interrupts @@ -482,6 +494,9 @@ int i915_enable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (!IS_I965G(dev)) + return 0; + switch (crtc) { case 0: dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; @@ -504,6 +519,9 @@ void i915_disable_vblank(drm_device_t *dev, int crtc) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (!IS_I965G(dev)) + return; + switch (crtc) { case 0: dev_priv->irq_enable_reg &= ~VSYNC_PIPEA_FLAG; @@ -763,6 +781,11 @@ int i915_driver_irq_postinstall(drm_device_t * dev) dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + if (!IS_I965G(dev)) { + dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG; + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } + i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);