diff options
| -rw-r--r-- | linux-core/drmP.h | 1 | ||||
| -rw-r--r-- | linux-core/drm_irq.c | 17 | ||||
| -rw-r--r-- | shared-core/i915_dma.c | 11 | ||||
| -rw-r--r-- | shared-core/i915_drv.h | 13 | ||||
| -rw-r--r-- | shared-core/i915_irq.c | 27 | 
5 files changed, 54 insertions, 15 deletions
| diff --git a/linux-core/drmP.h b/linux-core/drmP.h index cf1c0fd7..0ab69feb 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 5d8d71be..eea00ac8 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -77,10 +77,22 @@ 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; +	int i; + +	for (i = 0; i < dev->num_crtcs; i++) +		if (atomic_read(&dev->vblank_refcount[i]) == 0) +			dev->driver->disable_vblank(dev, i); +} +  int drm_vblank_init(drm_device_t *dev, int num_crtcs)  {  	int i, ret = -ENOMEM; +	setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,\ +		    (unsigned long)dev);  	spin_lock_init(&dev->vbl_lock);  	atomic_set(&dev->vbl_signal_pending, 0);  	dev->num_crtcs = num_crtcs; @@ -374,9 +386,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); diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index ebb184cc..b2398896 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 213759a8..c8961c08 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 713ec654..c0c1bf9e 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); @@ -324,7 +326,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)  		return IRQ_NONE;  	I915_WRITE16(I915REG_INT_IDENTITY_R, temp); -	(void) I915_READ16(I915REG_INT_IDENTITY_R); +	(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); @@ -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); | 
