OSDN Git Service

Merge branch 'ttm-vram-0-1-branch'
[android-x86/external-libdrm.git] / shared-core / mga_irq.c
index 99a23fe..490d1fb 100644 (file)
@@ -1,5 +1,6 @@
 /* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
- *
+ */
+/*
  * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
  *
  * The Weather Channel (TM) funded Tungsten Graphics to develop the
@@ -40,6 +41,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 +51,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 +98,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 +131,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)