drm/radeon/kms: add irq mitigation code for sw interrupt.
Dave Airlie [Tue, 1 Dec 2009 06:04:56 +0000 (16:04 +1000)]
We really don't need to process every irq that comes in, we only
really want to do SW irq processing when we are actually waiting for
a fence to pass. I'm not 100% sure this is race free esp on non-MSI systems
so it needs some testing.

Signed-off-by: Dave Airlie <airlied@redhat.com>

13 files changed:
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c

index 0862fa4..04d4b4c 100644 (file)
@@ -3129,7 +3129,6 @@ static int r100_startup(struct radeon_device *rdev)
                        return r;
        }
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        r100_irq_set(rdev);
        /* 1M ring buffer */
        r = r100_cp_init(rdev, 1024 * 1024);
index 430fc2a..6be3acd 100644 (file)
@@ -1205,7 +1205,6 @@ static int r300_startup(struct radeon_device *rdev)
                        return r;
        }
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        r100_irq_set(rdev);
        /* 1M ring buffer */
        r = r100_cp_init(rdev, 1024 * 1024);
index e7c3477..885610f 100644 (file)
@@ -186,7 +186,6 @@ static int r420_startup(struct radeon_device *rdev)
        }
        r420_pipes_init(rdev);
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        r100_irq_set(rdev);
        /* 1M ring buffer */
        r = r100_cp_init(rdev, 1024 * 1024);
index 26c3779..92fbc98 100644 (file)
@@ -185,7 +185,6 @@ static int r520_startup(struct radeon_device *rdev)
                        return r;
        }
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        rs600_irq_set(rdev);
        /* 1M ring buffer */
        r = r100_cp_init(rdev, 1024 * 1024);
index 5067ab7..5966027 100644 (file)
@@ -1571,7 +1571,6 @@ int r600_startup(struct radeon_device *rdev)
        }
 
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        r = r600_irq_init(rdev);
        if (r) {
                DRM_ERROR("radeon: IH init failed (%d).\n", r);
index 0b8dad6..bdad153 100644 (file)
@@ -352,11 +352,14 @@ struct radeon_irq {
        bool            sw_int;
        /* FIXME: use a define max crtc rather than hardcode it */
        bool            crtc_vblank_int[2];
+       spinlock_t sw_lock;
+       int sw_refcount;
 };
 
 int radeon_irq_kms_init(struct radeon_device *rdev);
 void radeon_irq_kms_fini(struct radeon_device *rdev);
-
+void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev);
+void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev);
 
 /*
  * CP & ring.
index ab2a8b1..2ac3163 100644 (file)
@@ -193,14 +193,18 @@ retry:
        }
 
        if (intr) {
+               radeon_irq_kms_sw_irq_get(rdev);
                r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
                                radeon_fence_signaled(fence), timeout);
+               radeon_irq_kms_sw_irq_put(rdev);
                if (unlikely(r == -ERESTARTSYS)) {
                        return -EBUSY;
                }
        } else {
+               radeon_irq_kms_sw_irq_get(rdev);
                r = wait_event_timeout(rdev->fence_drv.queue,
                         radeon_fence_signaled(fence), timeout);
+               radeon_irq_kms_sw_irq_put(rdev);
        }
        if (unlikely(!radeon_fence_signaled(fence))) {
                if (unlikely(r == 0)) {
index 84f8a6f..2678997 100644 (file)
@@ -87,7 +87,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
 
        if (rdev->flags & RADEON_SINGLE_CRTC)
                num_crtc = 1;
-
+       spin_lock_init(&rdev->irq.sw_lock);
        r = drm_vblank_init(rdev->ddev, num_crtc);
        if (r) {
                return r;
@@ -122,3 +122,29 @@ void radeon_irq_kms_fini(struct radeon_device *rdev)
                        pci_disable_msi(rdev->pdev);
        }
 }
+
+void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&rdev->irq.sw_lock, irqflags);
+       if (rdev->ddev->irq_enabled && (++rdev->irq.sw_refcount == 1)) {
+               rdev->irq.sw_int = true;
+               radeon_irq_set(rdev);
+       }
+       spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
+}
+
+void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&rdev->irq.sw_lock, irqflags);
+       BUG_ON(rdev->ddev->irq_enabled && rdev->irq.sw_refcount <= 0);
+       if (rdev->ddev->irq_enabled && (--rdev->irq.sw_refcount == 0)) {
+               rdev->irq.sw_int = false;
+               radeon_irq_set(rdev);
+       }
+       spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
+}
+
index 2e5b945..50907f8 100644 (file)
@@ -394,7 +394,6 @@ static int rs400_startup(struct radeon_device *rdev)
        if (r)
                return r;
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        r100_irq_set(rdev);
        /* 1M ring buffer */
        r = r100_cp_init(rdev, 1024 * 1024);
index d2dac45..9b6303d 100644 (file)
@@ -388,7 +388,6 @@ static int rs600_startup(struct radeon_device *rdev)
        if (r)
                return r;
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        rs600_irq_set(rdev);
        /* 1M ring buffer */
        r = r100_cp_init(rdev, 1024 * 1024);
index 7ffd6db..4607025 100644 (file)
@@ -605,7 +605,6 @@ static int rs690_startup(struct radeon_device *rdev)
        if (r)
                return r;
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        rs600_irq_set(rdev);
        /* 1M ring buffer */
        r = r100_cp_init(rdev, 1024 * 1024);
index 93de4a9..0ecf5d9 100644 (file)
@@ -478,7 +478,6 @@ static int rv515_startup(struct radeon_device *rdev)
                        return r;
        }
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        rs600_irq_set(rdev);
        /* 1M ring buffer */
        r = r100_cp_init(rdev, 1024 * 1024);
index 479684b..a96be8b 100644 (file)
@@ -888,7 +888,6 @@ static int rv770_startup(struct radeon_device *rdev)
        }
 
        /* Enable IRQ */
-       rdev->irq.sw_int = true;
        r = r600_irq_init(rdev);
        if (r) {
                DRM_ERROR("radeon: IH init failed (%d).\n", r);