drm/radeon: apply Murphy's law to the kms irq code v3
[linux-2.6-block.git] / drivers / gpu / drm / radeon / evergreen.c
index 01550d05e2738d12d6e29fb191740ba8a5dc6637..bdc1f30d7474f9883fb449a3c2fef8e64f4e62ef 100644 (file)
@@ -428,6 +428,7 @@ void evergreen_hpd_init(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
        struct drm_connector *connector;
+       unsigned enabled = 0;
        u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) |
                DC_HPDx_RX_INT_TIMER(0xfa) | DC_HPDx_EN;
 
@@ -436,73 +437,64 @@ void evergreen_hpd_init(struct radeon_device *rdev)
                switch (radeon_connector->hpd.hpd) {
                case RADEON_HPD_1:
                        WREG32(DC_HPD1_CONTROL, tmp);
-                       rdev->irq.hpd[0] = true;
                        break;
                case RADEON_HPD_2:
                        WREG32(DC_HPD2_CONTROL, tmp);
-                       rdev->irq.hpd[1] = true;
                        break;
                case RADEON_HPD_3:
                        WREG32(DC_HPD3_CONTROL, tmp);
-                       rdev->irq.hpd[2] = true;
                        break;
                case RADEON_HPD_4:
                        WREG32(DC_HPD4_CONTROL, tmp);
-                       rdev->irq.hpd[3] = true;
                        break;
                case RADEON_HPD_5:
                        WREG32(DC_HPD5_CONTROL, tmp);
-                       rdev->irq.hpd[4] = true;
                        break;
                case RADEON_HPD_6:
                        WREG32(DC_HPD6_CONTROL, tmp);
-                       rdev->irq.hpd[5] = true;
                        break;
                default:
                        break;
                }
                radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
+               enabled |= 1 << radeon_connector->hpd.hpd;
        }
-       if (rdev->irq.installed)
-               evergreen_irq_set(rdev);
+       radeon_irq_kms_enable_hpd(rdev, enabled);
 }
 
 void evergreen_hpd_fini(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
        struct drm_connector *connector;
+       unsigned disabled = 0;
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                switch (radeon_connector->hpd.hpd) {
                case RADEON_HPD_1:
                        WREG32(DC_HPD1_CONTROL, 0);
-                       rdev->irq.hpd[0] = false;
                        break;
                case RADEON_HPD_2:
                        WREG32(DC_HPD2_CONTROL, 0);
-                       rdev->irq.hpd[1] = false;
                        break;
                case RADEON_HPD_3:
                        WREG32(DC_HPD3_CONTROL, 0);
-                       rdev->irq.hpd[2] = false;
                        break;
                case RADEON_HPD_4:
                        WREG32(DC_HPD4_CONTROL, 0);
-                       rdev->irq.hpd[3] = false;
                        break;
                case RADEON_HPD_5:
                        WREG32(DC_HPD5_CONTROL, 0);
-                       rdev->irq.hpd[4] = false;
                        break;
                case RADEON_HPD_6:
                        WREG32(DC_HPD6_CONTROL, 0);
-                       rdev->irq.hpd[5] = false;
                        break;
                default:
                        break;
                }
+               disabled |= 1 << radeon_connector->hpd.hpd;
        }
+       radeon_irq_kms_disable_hpd(rdev, disabled);
 }
 
 /* watermark setup */
@@ -1371,7 +1363,7 @@ void evergreen_mc_program(struct radeon_device *rdev)
  */
 void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 {
-       struct radeon_ring *ring = &rdev->ring[ib->fence->ring];
+       struct radeon_ring *ring = &rdev->ring[ib->ring];
 
        /* set to DX10/11 mode */
        radeon_ring_write(ring, PACKET3(PACKET3_MODE_CONTROL, 0));
@@ -1932,6 +1924,9 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.evergreen.sx_num_of_sets);
        WREG32(SMX_DC_CTL0, smx_dc_ctl0);
 
+       if (rdev->family <= CHIP_SUMO2)
+               WREG32(SMX_SAR_CTL0, 0x00010000);
+
        WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_size / 4) - 1) |
                                        POSITION_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_pos_size / 4) - 1) |
                                        SMX_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_smx_size / 4) - 1)));
@@ -2673,7 +2668,6 @@ int evergreen_irq_process(struct radeon_device *rdev)
        u32 rptr;
        u32 src_id, src_data;
        u32 ring_index;
-       unsigned long flags;
        bool queue_hotplug = false;
        bool queue_hdmi = false;
 
@@ -2681,22 +2675,21 @@ int evergreen_irq_process(struct radeon_device *rdev)
                return IRQ_NONE;
 
        wptr = evergreen_get_ih_wptr(rdev);
+
+restart_ih:
+       /* is somebody else already processing irqs? */
+       if (atomic_xchg(&rdev->ih.lock, 1))
+               return IRQ_NONE;
+
        rptr = rdev->ih.rptr;
        DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
 
-       spin_lock_irqsave(&rdev->ih.lock, flags);
-       if (rptr == wptr) {
-               spin_unlock_irqrestore(&rdev->ih.lock, flags);
-               return IRQ_NONE;
-       }
-restart_ih:
        /* Order reading of wptr vs. reading of IH ring data */
        rmb();
 
        /* display interrupts */
        evergreen_irq_ack(rdev);
 
-       rdev->ih.wptr = wptr;
        while (rptr != wptr) {
                /* wptr/rptr are in bytes! */
                ring_index = rptr / 4;
@@ -2983,7 +2976,6 @@ restart_ih:
                        break;
                case 233: /* GUI IDLE */
                        DRM_DEBUG("IH: GUI idle\n");
-                       rdev->pm.gui_idle = true;
                        wake_up(&rdev->irq.idle_queue);
                        break;
                default:
@@ -2995,17 +2987,19 @@ restart_ih:
                rptr += 16;
                rptr &= rdev->ih.ptr_mask;
        }
-       /* make sure wptr hasn't changed while processing */
-       wptr = evergreen_get_ih_wptr(rdev);
-       if (wptr != rdev->ih.wptr)
-               goto restart_ih;
        if (queue_hotplug)
                schedule_work(&rdev->hotplug_work);
        if (queue_hdmi)
                schedule_work(&rdev->audio_work);
        rdev->ih.rptr = rptr;
        WREG32(IH_RB_RPTR, rdev->ih.rptr);
-       spin_unlock_irqrestore(&rdev->ih.lock, flags);
+       atomic_set(&rdev->ih.lock, 0);
+
+       /* make sure wptr hasn't changed while processing */
+       wptr = evergreen_get_ih_wptr(rdev);
+       if (wptr != rptr)
+               goto restart_ih;
+
        return IRQ_HANDLED;
 }