drm/radeon: apply Murphy's law to the kms irq code v3
authorChristian Koenig <christian.koenig@amd.com>
Wed, 16 May 2012 23:33:30 +0000 (01:33 +0200)
committerChristian König <deathsimple@vodafone.de>
Thu, 21 Jun 2012 07:38:50 +0000 (09:38 +0200)
1. It is really dangerous to have more than one
   spinlock protecting the same information.

2. radeon_irq_set sometimes wasn't called with lock
   protection, so it can happen that more than one
   CPU would tamper with the irq regs at the same
   time.

3. The pm.gui_idle variable was assuming that the 3D
   engine wasn't becoming idle between testing the
   register and setting the variable. So just remove
   it and test the register directly.

v2: Also handle the hpd irq code the same way.
v3: Rename hpd parameter for clarification.

Signed-off-by: Christian Koenig <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/si.c

index 765bd1f..bdc1f30 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 */
@@ -2984,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:
index 415b7d8..e8fe4ae 100644 (file)
@@ -567,43 +567,27 @@ void r100_hpd_init(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
        struct drm_connector *connector;
+       unsigned enable = 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:
-                       rdev->irq.hpd[0] = true;
-                       break;
-               case RADEON_HPD_2:
-                       rdev->irq.hpd[1] = true;
-                       break;
-               default:
-                       break;
-               }
+               enable |= 1 << radeon_connector->hpd.hpd;
                radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
        }
-       if (rdev->irq.installed)
-               r100_irq_set(rdev);
+       radeon_irq_kms_enable_hpd(rdev, enable);
 }
 
 void r100_hpd_fini(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
        struct drm_connector *connector;
+       unsigned disable = 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:
-                       rdev->irq.hpd[0] = false;
-                       break;
-               case RADEON_HPD_2:
-                       rdev->irq.hpd[1] = false;
-                       break;
-               default:
-                       break;
-               }
+               disable |= 1 << radeon_connector->hpd.hpd;
        }
+       radeon_irq_kms_disable_hpd(rdev, disable);
 }
 
 /*
@@ -782,7 +766,6 @@ int r100_irq_process(struct radeon_device *rdev)
                /* gui idle interrupt */
                if (status & RADEON_GUI_IDLE_STAT) {
                        rdev->irq.gui_idle_acked = true;
-                       rdev->pm.gui_idle = true;
                        wake_up(&rdev->irq.idle_queue);
                }
                /* Vertical blank interrupts */
index b487c69..9cd7728 100644 (file)
@@ -709,6 +709,7 @@ void r600_hpd_init(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
        struct drm_connector *connector;
+       unsigned enable = 0;
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -729,28 +730,22 @@ void r600_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;
                                /* DCE 3.2 */
                        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;
@@ -759,85 +754,73 @@ void r600_hpd_init(struct radeon_device *rdev)
                        switch (radeon_connector->hpd.hpd) {
                        case RADEON_HPD_1:
                                WREG32(DC_HOT_PLUG_DETECT1_CONTROL, DC_HOT_PLUG_DETECTx_EN);
-                               rdev->irq.hpd[0] = true;
                                break;
                        case RADEON_HPD_2:
                                WREG32(DC_HOT_PLUG_DETECT2_CONTROL, DC_HOT_PLUG_DETECTx_EN);
-                               rdev->irq.hpd[1] = true;
                                break;
                        case RADEON_HPD_3:
                                WREG32(DC_HOT_PLUG_DETECT3_CONTROL, DC_HOT_PLUG_DETECTx_EN);
-                               rdev->irq.hpd[2] = true;
                                break;
                        default:
                                break;
                        }
                }
+               enable |= 1 << radeon_connector->hpd.hpd;
                radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
        }
-       if (rdev->irq.installed)
-               r600_irq_set(rdev);
+       radeon_irq_kms_enable_hpd(rdev, enable);
 }
 
 void r600_hpd_fini(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
        struct drm_connector *connector;
+       unsigned disable = 0;
 
-       if (ASIC_IS_DCE3(rdev)) {
-               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-                       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               if (ASIC_IS_DCE3(rdev)) {
                        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;
                                /* DCE 3.2 */
                        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;
                        }
-               }
-       } else {
-               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-                       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               } else {
                        switch (radeon_connector->hpd.hpd) {
                        case RADEON_HPD_1:
                                WREG32(DC_HOT_PLUG_DETECT1_CONTROL, 0);
-                               rdev->irq.hpd[0] = false;
                                break;
                        case RADEON_HPD_2:
                                WREG32(DC_HOT_PLUG_DETECT2_CONTROL, 0);
-                               rdev->irq.hpd[1] = false;
                                break;
                        case RADEON_HPD_3:
                                WREG32(DC_HOT_PLUG_DETECT3_CONTROL, 0);
-                               rdev->irq.hpd[2] = false;
                                break;
                        default:
                                break;
                        }
                }
+               disable |= 1 << radeon_connector->hpd.hpd;
        }
+       radeon_irq_kms_disable_hpd(rdev, disable);
 }
 
 /*
@@ -3476,7 +3459,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:
index 82a0a4c..e3558c3 100644 (file)
@@ -519,8 +519,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
 
        if (rdev->irq.installed) {
                /* if irq is available use it */
-               rdev->irq.afmt[dig->afmt->id] = true;
-               radeon_irq_set(rdev);
+               radeon_irq_kms_enable_afmt(rdev, dig->afmt->id);
        }
 
        dig->afmt->enabled = true;
@@ -556,8 +555,7 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
                  offset, radeon_encoder->encoder_id);
 
        /* disable irq */
-       rdev->irq.afmt[dig->afmt->id] = false;
-       radeon_irq_set(rdev);
+       radeon_irq_kms_disable_afmt(rdev, dig->afmt->id);
 
        /* Older chipsets not handled by AtomBIOS */
        if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
index 5ddf895..353a183 100644 (file)
@@ -615,21 +615,20 @@ union radeon_irq_stat_regs {
 #define RADEON_MAX_AFMT_BLOCKS 6
 
 struct radeon_irq {
-       bool            installed;
-       bool            sw_int[RADEON_NUM_RINGS];
-       bool            crtc_vblank_int[RADEON_MAX_CRTCS];
-       bool            pflip[RADEON_MAX_CRTCS];
-       wait_queue_head_t       vblank_queue;
-       bool            hpd[RADEON_MAX_HPD_PINS];
-       bool            gui_idle;
-       bool            gui_idle_acked;
-       wait_queue_head_t       idle_queue;
-       bool            afmt[RADEON_MAX_AFMT_BLOCKS];
-       spinlock_t sw_lock;
-       int sw_refcount[RADEON_NUM_RINGS];
-       union radeon_irq_stat_regs stat_regs;
-       spinlock_t pflip_lock[RADEON_MAX_CRTCS];
-       int pflip_refcount[RADEON_MAX_CRTCS];
+       bool                            installed;
+       spinlock_t                      lock;
+       bool                            sw_int[RADEON_NUM_RINGS];
+       int                             sw_refcount[RADEON_NUM_RINGS];
+       bool                            crtc_vblank_int[RADEON_MAX_CRTCS];
+       bool                            pflip[RADEON_MAX_CRTCS];
+       int                             pflip_refcount[RADEON_MAX_CRTCS];
+       wait_queue_head_t               vblank_queue;
+       bool                            hpd[RADEON_MAX_HPD_PINS];
+       bool                            gui_idle;
+       bool                            gui_idle_acked;
+       wait_queue_head_t               idle_queue;
+       bool                            afmt[RADEON_MAX_AFMT_BLOCKS];
+       union radeon_irq_stat_regs      stat_regs;
 };
 
 int radeon_irq_kms_init(struct radeon_device *rdev);
@@ -638,6 +637,11 @@ void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring);
 void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring);
 void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc);
 void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc);
+void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block);
+void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block);
+void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, unsigned hpd_mask);
+void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask);
+int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev);
 
 /*
  * CP & rings.
@@ -1062,7 +1066,6 @@ struct radeon_pm {
        int                     active_crtc_count;
        int                     req_vblank;
        bool                    vblank_sync;
-       bool                    gui_idle;
        fixed20_12              max_bandwidth;
        fixed20_12              igp_sideport_mclk;
        fixed20_12              igp_system_mclk;
index 5df58d1..c5eb7a1 100644 (file)
@@ -32,6 +32,8 @@
 #include "radeon.h"
 #include "atom.h"
 
+#define RADEON_WAIT_IDLE_TIMEOUT 200
+
 irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
@@ -62,8 +64,10 @@ static void radeon_hotplug_work_func(struct work_struct *work)
 void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
 {
        struct radeon_device *rdev = dev->dev_private;
+       unsigned long irqflags;
        unsigned i;
 
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        /* Disable *all* interrupts */
        for (i = 0; i < RADEON_NUM_RINGS; i++)
                rdev->irq.sw_int[i] = false;
@@ -76,6 +80,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
                rdev->irq.afmt[i] = false;
        }
        radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
        /* Clear bits */
        radeon_irq_process(rdev);
 }
@@ -83,23 +88,28 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
 int radeon_driver_irq_postinstall_kms(struct drm_device *dev)
 {
        struct radeon_device *rdev = dev->dev_private;
+       unsigned long irqflags;
        unsigned i;
 
        dev->max_vblank_count = 0x001fffff;
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        for (i = 0; i < RADEON_NUM_RINGS; i++)
                rdev->irq.sw_int[i] = true;
        radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
        return 0;
 }
 
 void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
 {
        struct radeon_device *rdev = dev->dev_private;
+       unsigned long irqflags;
        unsigned i;
 
        if (rdev == NULL) {
                return;
        }
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        /* Disable *all* interrupts */
        for (i = 0; i < RADEON_NUM_RINGS; i++)
                rdev->irq.sw_int[i] = false;
@@ -112,6 +122,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
                rdev->irq.afmt[i] = false;
        }
        radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
 static bool radeon_msi_ok(struct radeon_device *rdev)
@@ -168,15 +179,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev)
 
 int radeon_irq_kms_init(struct radeon_device *rdev)
 {
-       int i;
        int r = 0;
 
        INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
        INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
 
-       spin_lock_init(&rdev->irq.sw_lock);
-       for (i = 0; i < rdev->num_crtc; i++)
-               spin_lock_init(&rdev->irq.pflip_lock[i]);
+       spin_lock_init(&rdev->irq.lock);
        r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
        if (r) {
                return r;
@@ -217,25 +225,25 @@ void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring)
 {
        unsigned long irqflags;
 
-       spin_lock_irqsave(&rdev->irq.sw_lock, irqflags);
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        if (rdev->ddev->irq_enabled && (++rdev->irq.sw_refcount[ring] == 1)) {
                rdev->irq.sw_int[ring] = true;
                radeon_irq_set(rdev);
        }
-       spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
 void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring)
 {
        unsigned long irqflags;
 
-       spin_lock_irqsave(&rdev->irq.sw_lock, irqflags);
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        BUG_ON(rdev->ddev->irq_enabled && rdev->irq.sw_refcount[ring] <= 0);
        if (rdev->ddev->irq_enabled && (--rdev->irq.sw_refcount[ring] == 0)) {
                rdev->irq.sw_int[ring] = false;
                radeon_irq_set(rdev);
        }
-       spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
 void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc)
@@ -245,12 +253,12 @@ void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc)
        if (crtc < 0 || crtc >= rdev->num_crtc)
                return;
 
-       spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags);
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        if (rdev->ddev->irq_enabled && (++rdev->irq.pflip_refcount[crtc] == 1)) {
                rdev->irq.pflip[crtc] = true;
                radeon_irq_set(rdev);
        }
-       spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
 void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc)
@@ -260,12 +268,76 @@ void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc)
        if (crtc < 0 || crtc >= rdev->num_crtc)
                return;
 
-       spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags);
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        BUG_ON(rdev->ddev->irq_enabled && rdev->irq.pflip_refcount[crtc] <= 0);
        if (rdev->ddev->irq_enabled && (--rdev->irq.pflip_refcount[crtc] == 0)) {
                rdev->irq.pflip[crtc] = false;
                radeon_irq_set(rdev);
        }
-       spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
+void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
+       rdev->irq.afmt[block] = true;
+       radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+
+}
+
+void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
+       rdev->irq.afmt[block] = false;
+       radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+}
+
+void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, unsigned hpd_mask)
+{
+       unsigned long irqflags;
+       int i;
+
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
+       for (i = 0; i < RADEON_MAX_HPD_PINS; ++i)
+               rdev->irq.hpd[i] |= !!(hpd_mask & (1 << i));
+       radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+}
+
+void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask)
+{
+       unsigned long irqflags;
+       int i;
+
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
+       for (i = 0; i < RADEON_MAX_HPD_PINS; ++i)
+               rdev->irq.hpd[i] &= !(hpd_mask & (1 << i));
+       radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+}
+
+int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev)
+{
+       unsigned long irqflags;
+       int r;
+
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
+       rdev->irq.gui_idle = true;
+       radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+
+       r = wait_event_timeout(rdev->irq.idle_queue, radeon_gui_idle(rdev),
+                              msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
+
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
+       rdev->irq.gui_idle = false;
+       radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+       return r;
+}
index 5c58d7d..18b81d6 100644 (file)
@@ -382,29 +382,35 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
 int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
 {
        struct radeon_device *rdev = dev->dev_private;
+       unsigned long irqflags;
+       int r;
 
        if (crtc < 0 || crtc >= rdev->num_crtc) {
                DRM_ERROR("Invalid crtc %d\n", crtc);
                return -EINVAL;
        }
 
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        rdev->irq.crtc_vblank_int[crtc] = true;
-
-       return radeon_irq_set(rdev);
+       r = radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+       return r;
 }
 
 void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
 {
        struct radeon_device *rdev = dev->dev_private;
+       unsigned long irqflags;
 
        if (crtc < 0 || crtc >= rdev->num_crtc) {
                DRM_ERROR("Invalid crtc %d\n", crtc);
                return;
        }
 
+       spin_lock_irqsave(&rdev->irq.lock, irqflags);
        rdev->irq.crtc_vblank_int[crtc] = false;
-
        radeon_irq_set(rdev);
+       spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
 int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
index 9dc0b54..7ae6066 100644 (file)
@@ -34,7 +34,6 @@
 #define RADEON_IDLE_LOOP_MS 100
 #define RADEON_RECLOCK_DELAY_MS 200
 #define RADEON_WAIT_VBLANK_TIMEOUT 200
-#define RADEON_WAIT_IDLE_TIMEOUT 200
 
 static const char *radeon_pm_state_type_name[5] = {
        "Default",
@@ -257,15 +256,8 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
        /* gui idle int has issues on older chips it seems */
        if (rdev->family >= CHIP_R600) {
                if (rdev->irq.installed) {
-                       /* wait for GPU idle */
-                       rdev->pm.gui_idle = false;
-                       rdev->irq.gui_idle = true;
-                       radeon_irq_set(rdev);
-                       wait_event_interruptible_timeout(
-                               rdev->irq.idle_queue, rdev->pm.gui_idle,
-                               msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
-                       rdev->irq.gui_idle = false;
-                       radeon_irq_set(rdev);
+                       /* wait for GPU to become idle */
+                       radeon_irq_kms_wait_gui_idle(rdev);
                }
        } else {
                struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
index e95c5e6..f9aee25 100644 (file)
@@ -294,6 +294,7 @@ void rs600_hpd_init(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
        struct drm_connector *connector;
+       unsigned enable = 0;
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -301,26 +302,25 @@ void rs600_hpd_init(struct radeon_device *rdev)
                case RADEON_HPD_1:
                        WREG32(R_007D00_DC_HOT_PLUG_DETECT1_CONTROL,
                               S_007D00_DC_HOT_PLUG_DETECT1_EN(1));
-                       rdev->irq.hpd[0] = true;
                        break;
                case RADEON_HPD_2:
                        WREG32(R_007D10_DC_HOT_PLUG_DETECT2_CONTROL,
                               S_007D10_DC_HOT_PLUG_DETECT2_EN(1));
-                       rdev->irq.hpd[1] = true;
                        break;
                default:
                        break;
                }
+               enable |= 1 << radeon_connector->hpd.hpd;
                radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
        }
-       if (rdev->irq.installed)
-               rs600_irq_set(rdev);
+       radeon_irq_kms_enable_hpd(rdev, enable);
 }
 
 void rs600_hpd_fini(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
        struct drm_connector *connector;
+       unsigned disable = 0;
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -328,17 +328,17 @@ void rs600_hpd_fini(struct radeon_device *rdev)
                case RADEON_HPD_1:
                        WREG32(R_007D00_DC_HOT_PLUG_DETECT1_CONTROL,
                               S_007D00_DC_HOT_PLUG_DETECT1_EN(0));
-                       rdev->irq.hpd[0] = false;
                        break;
                case RADEON_HPD_2:
                        WREG32(R_007D10_DC_HOT_PLUG_DETECT2_CONTROL,
                               S_007D10_DC_HOT_PLUG_DETECT2_EN(0));
-                       rdev->irq.hpd[1] = false;
                        break;
                default:
                        break;
                }
+               disable |= 1 << radeon_connector->hpd.hpd;
        }
+       radeon_irq_kms_disable_hpd(rdev, disable);
 }
 
 int rs600_asic_reset(struct radeon_device *rdev)
@@ -686,7 +686,6 @@ int rs600_irq_process(struct radeon_device *rdev)
                /* GUI idle */
                if (G_000040_GUI_IDLE(status)) {
                        rdev->irq.gui_idle_acked = true;
-                       rdev->pm.gui_idle = true;
                        wake_up(&rdev->irq.idle_queue);
                }
                /* Vertical blank interrupts */
index ecef972..a65045b 100644 (file)
@@ -3617,7 +3617,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: