diff options
Diffstat (limited to 'shared-core/mga_irq.c')
| -rw-r--r-- | shared-core/mga_irq.c | 50 | 
1 files changed, 48 insertions, 2 deletions
diff --git a/shared-core/mga_irq.c b/shared-core/mga_irq.c index 99a23fe1..16dfd44b 100644 --- a/shared-core/mga_irq.c +++ b/shared-core/mga_irq.c @@ -40,6 +40,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)  	drm_device_t *dev = (drm_device_t *) arg;  	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;  	int status; +	int handled = 0;  	status = MGA_READ(MGA_STATUS); @@ -49,6 +50,30 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)  		atomic_inc(&dev->vbl_received);  		DRM_WAKEUP(&dev->vbl_queue);  		drm_vbl_send_signals(dev); +		handled = 1; +	} + +	/* SOFTRAP interrupt */ +	if (status & MGA_SOFTRAPEN) { +		const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); +		const u32 prim_end   = MGA_READ(MGA_PRIMEND); + + +		MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); + +		/* In addition to clearing the interrupt-pending bit, we +		 * have to write to MGA_PRIMEND to re-start the DMA operation. +		 */ +		if ( (prim_start & ~0x03) != (prim_end & ~0x03) ) { +			MGA_WRITE(MGA_PRIMEND, prim_end); +		} + +		atomic_inc(&dev_priv->last_fence_retired); +		DRM_WAKEUP(&dev_priv->fence_queue); +		handled = 1; +	} + +	if ( handled ) {  		return IRQ_HANDLED;  	}  	return IRQ_NONE; @@ -72,6 +97,25 @@ int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)  	return ret;  } +int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence) +{ +	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; +	unsigned int cur_fence; +	int ret = 0; + +	/* Assume that the user has missed the current sequence number +	 * by about a day rather than she wants to wait for years +	 * using fences. +	 */ +	DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ, +		    (((cur_fence = atomic_read(&dev_priv->last_fence_retired)) +		      - *sequence) <= (1 << 23))); + +	*sequence = cur_fence; + +	return ret; +} +  void mga_driver_irq_preinstall(drm_device_t * dev)  {  	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -86,8 +130,10 @@ void mga_driver_irq_postinstall(drm_device_t * dev)  {  	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; -	/* Turn on VBL interrupt */ -	MGA_WRITE(MGA_IEN, MGA_VLINEIEN); +	DRM_INIT_WAITQUEUE( &dev_priv->fence_queue ); + +	/* Turn on vertical blank interrupt and soft trap interrupt. */ +	MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);  }  void mga_driver_irq_uninstall(drm_device_t * dev)  | 
