i915: Add support for MSI and interrupt mitigation.
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_irq.c
index 089c015..61ed515 100644 (file)
@@ -63,7 +63,7 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
            p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
                return -EINVAL;
 
-       p->irq = dev->irq;
+       p->irq = dev->pdev->irq;
 
        DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
                  p->irq);
@@ -89,7 +89,7 @@ static int drm_irq_install(struct drm_device * dev)
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
 
-       if (dev->irq == 0)
+       if (dev->pdev->irq == 0)
                return -EINVAL;
 
        mutex_lock(&dev->struct_mutex);
@@ -107,7 +107,7 @@ static int drm_irq_install(struct drm_device * dev)
        dev->irq_enabled = 1;
        mutex_unlock(&dev->struct_mutex);
 
-       DRM_DEBUG("irq=%d\n", dev->irq);
+       DRM_DEBUG("irq=%d\n", dev->pdev->irq);
 
        if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
                init_waitqueue_head(&dev->vbl_queue);
@@ -127,8 +127,12 @@ static int drm_irq_install(struct drm_device * dev)
        if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
                sh_flags = IRQF_SHARED;
 
-       ret = request_irq(dev->irq, dev->driver->irq_handler,
+       ret = request_irq(dev->pdev->irq, dev->driver->irq_handler,
                          sh_flags, dev->devname, dev);
+       /* Expose the device irq number to drivers that want to export it for
+        * whatever reason.
+        */
+       dev->irq = dev->pdev->irq;
        if (ret < 0) {
                mutex_lock(&dev->struct_mutex);
                dev->irq_enabled = 0;
@@ -164,11 +168,11 @@ int drm_irq_uninstall(struct drm_device * dev)
        if (!irq_enabled)
                return -EINVAL;
 
-       DRM_DEBUG("irq=%d\n", dev->irq);
+       DRM_DEBUG("irq=%d\n", dev->pdev->irq);
 
        dev->driver->irq_uninstall(dev);
 
-       free_irq(dev->irq, dev);
+       free_irq(dev->pdev->irq, dev);
 
        dev->locked_tasklet_func = NULL;
 
@@ -201,7 +205,7 @@ int drm_control(struct drm_device *dev, void *data,
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
                if (dev->if_version < DRM_IF_VERSION(1, 2) &&
-                   ctl->irq != dev->irq)
+                   ctl->irq != dev->pdev->irq)
                        return -EINVAL;
                return drm_irq_install(dev);
        case DRM_UNINST_HANDLER:
@@ -239,7 +243,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
        int ret = 0;
        unsigned int flags, seq;
 
-       if ((!dev->irq) || (!dev->irq_enabled))
+       if ((!dev->pdev->irq) || (!dev->irq_enabled))
                return -EINVAL;
 
        if (vblwait->request.type &
@@ -400,27 +404,31 @@ static void drm_locked_tasklet_func(unsigned long data)
 {
        struct drm_device *dev = (struct drm_device *)data;
        unsigned long irqflags;
-
+       void (*tasklet_func)(struct drm_device *);
+       
        spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+       tasklet_func = dev->locked_tasklet_func;
+       spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
 
-       if (!dev->locked_tasklet_func ||
+       if (!tasklet_func ||
            !drm_lock_take(&dev->lock,
                           DRM_KERNEL_CONTEXT)) {
-               spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
                return;
        }
 
        dev->lock.lock_time = jiffies;
        atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
 
-       dev->locked_tasklet_func(dev);
+       spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+       tasklet_func = dev->locked_tasklet_func;
+       dev->locked_tasklet_func = NULL;
+       spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+       
+       if (tasklet_func != NULL)
+               tasklet_func(dev);
 
        drm_lock_free(&dev->lock,
                      DRM_KERNEL_CONTEXT);
-
-       dev->locked_tasklet_func = NULL;
-
-       spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
 }
 
 /**