/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- */ /************************************************************************** * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * **************************************************************************/ #define __NO_VERSION__ #include "i915.h" #include "drmP.h" #include "drm.h" #include "i915_drm.h" #include "i915_drv.h" #define USER_INT_FLAG 0x2 #define MAX_NOPID ((u32)~0) #define READ_BREADCRUMB(dev_priv) (((u32*)(dev_priv->hw_status_page))[5]) irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *)arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private; u16 temp; temp = I915_READ16(I915REG_INT_IDENTITY_R); temp &= USER_INT_FLAG; DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); if (temp == 0) return IRQ_NONE; I915_WRITE16(I915REG_INT_IDENTITY_R, temp); DRM_WAKEUP( &dev_priv->irq_queue ); return IRQ_HANDLED; } int i915_emit_irq(drm_device_t *dev) { drm_i915_private_t *dev_priv = dev->dev_private; u32 ret; RING_LOCALS; i915_kernel_lost_context(dev); DRM_DEBUG("%s\n", __FUNCTION__); ret = dev_priv->counter; BEGIN_LP_RING(2); OUT_RING( 0 ); OUT_RING( GFX_OP_USER_INTERRUPT ); ADVANCE_LP_RING(); return ret; } int i915_wait_irq(drm_device_t *dev, int irq_nr) { drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private; int ret = 0; DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr, READ_BREADCRUMB(dev_priv)); if (READ_BREADCRUMB(dev_priv) >= irq_nr) return 0; dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; DRM_WAIT_ON( ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr ); if (ret == DRM_ERR(EBUSY)) { DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", __FUNCTION__, READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); } dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); return ret; } /* Needs the lock as it touches the ring. */ int i915_irq_emit( DRM_IOCTL_ARGS ) { DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_irq_emit_t emit; int result; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i915_irq_emit called without lock held\n"); return DRM_ERR(EINVAL); } if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( emit, (drm_i915_irq_emit_t __user *)data, sizeof(emit) ); result = i915_emit_irq( dev ); if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) { DRM_ERROR( "copy_to_user\n" ); return DRM_ERR(EFAULT); } return 0; } /* Doesn't need the hardware lock. */ int i915_irq_wait( DRM_IOCTL_ARGS ) { DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_irq_wait_t irqwait; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_i915_irq_wait_t __user *)data, sizeof(irqwait) ); return i915_wait_irq( dev, irqwait.irq_seq ); } /* drm_dma.h hooks */ void DRM(driver_irq_preinstall)( drm_device_t *dev ) { drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private; I915_WRITE16( I915REG_HWSTAM, 0xfffe ); I915_WRITE16( I915REG_INT_MASK_R, 0x0 ); I915_WRITE16( I915REG_INT_ENABLE_R, 0x0 ); } void DRM(driver_irq_postinstall)( drm_device_t *dev ) { drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private; I915_WRITE16( I915REG_INT_ENABLE_R, USER_INT_FLAG ); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); } void DRM(driver_irq_uninstall)( drm_device_t *dev ) { drm_i915_private_t *dev_priv = (drm_i915_private_t *)dev->dev_private; if (!dev_priv) return; I915_WRITE16( I915REG_HWSTAM, 0xffff ); I915_WRITE16( I915REG_INT_MASK_R, 0xffff ); I915_WRITE16( I915REG_INT_ENABLE_R, 0x0 ); }