Re: [PATCH 07/10] drm/radeon: apply Murphy's law to the kms irq code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, May 24, 2012 at 11:35 AM, Alex Deucher <alexdeucher@xxxxxxxxx> wrote:
> On Thu, May 24, 2012 at 3:49 AM, Christian König
> <deathsimple@xxxxxxxxxxx> wrote:
>> From: Christian Koenig <christian.koenig@xxxxxxx>
>>
>> 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.
>>
>> Signed-off-by: Christian Koenig <christian.koenig@xxxxxxx>
>> ---
>>  drivers/gpu/drm/radeon/evergreen.c      |    1 -
>>  drivers/gpu/drm/radeon/r100.c           |    1 -
>>  drivers/gpu/drm/radeon/r600.c           |    1 -
>>  drivers/gpu/drm/radeon/r600_hdmi.c      |    6 +--
>>  drivers/gpu/drm/radeon/radeon.h         |   33 +++++++-------
>>  drivers/gpu/drm/radeon/radeon_irq_kms.c |   72 +++++++++++++++++++++++++------
>>  drivers/gpu/drm/radeon/radeon_kms.c     |   12 ++++--
>>  drivers/gpu/drm/radeon/radeon_pm.c      |   12 +-----
>>  drivers/gpu/drm/radeon/rs600.c          |    1 -
>>  drivers/gpu/drm/radeon/si.c             |    1 -
>>  10 files changed, 90 insertions(+), 50 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
>> index bfcb39e..9e9b3bb 100644
>> --- a/drivers/gpu/drm/radeon/evergreen.c
>> +++ b/drivers/gpu/drm/radeon/evergreen.c
>> @@ -3254,7 +3254,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:
>> diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
>> index 415b7d8..2587426 100644
>> --- a/drivers/gpu/drm/radeon/r100.c
>> +++ b/drivers/gpu/drm/radeon/r100.c
>> @@ -782,7 +782,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 */
>> diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
>> index eadbb06..90c6639 100644
>> --- a/drivers/gpu/drm/radeon/r600.c
>> +++ b/drivers/gpu/drm/radeon/r600.c
>> @@ -3542,7 +3542,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:
>> diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
>> index 226379e..b76c0f2 100644
>> --- a/drivers/gpu/drm/radeon/r600_hdmi.c
>> +++ b/drivers/gpu/drm/radeon/r600_hdmi.c
>> @@ -523,8 +523,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;
>> @@ -560,8 +559,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)) {
>> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
>> index 8479096..23552b4 100644
>> --- a/drivers/gpu/drm/radeon/radeon.h
>> +++ b/drivers/gpu/drm/radeon/radeon.h
>> @@ -610,21 +610,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);
>> @@ -633,6 +632,9 @@ 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);
>> +int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev);
>>
>>  /*
>>  * CP & rings.
>> @@ -1058,7 +1060,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;
>> diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
>> index 5df58d1..11fc4f7 100644
>> --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
>> +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
>> @@ -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,52 @@ 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);
>>  }
>>
>
> Should probably also add radeon_irq_kms_[en|dis]able_hpd() function
> and call replaced the calls to *_irq_set() in the *_hpd_init() and
> *_hpd_fini() callbacks for display hotplug.

See attached follow on patch.

Alex
From 6d567f5f089a66e08432bb2098794ddc204dc0aa Mon Sep 17 00:00:00 2001
From: Alex Deucher <alexander.deucher@xxxxxxx>
Date: Thu, 31 May 2012 14:12:55 -0400
Subject: [PATCH] drm/radeon: apply Murphy's law to the kms hpd irq code

Follow on to Christian's:
drm/radeon: apply Murphy's law to the kms irq code

Signed-off-by: Alex Deucher <alexander.deucher@xxxxxxx>
---
 drivers/gpu/drm/radeon/evergreen.c      |   30 ++++++++++++---------
 drivers/gpu/drm/radeon/r100.c           |   14 ++++++---
 drivers/gpu/drm/radeon/r600.c           |   42 +++++++++++++++++--------------
 drivers/gpu/drm/radeon/radeon.h         |    2 +
 drivers/gpu/drm/radeon/radeon_irq_kms.c |   29 +++++++++++++++++++++
 drivers/gpu/drm/radeon/rs600.c          |   14 ++++++---
 6 files changed, 89 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 95fccbf..b78cb5e 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -430,33 +430,34 @@ void evergreen_hpd_init(struct radeon_device *rdev)
 	struct drm_connector *connector;
 	u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) |
 		DC_HPDx_RX_INT_TIMER(0xfa) | DC_HPDx_EN;
+	u32 hpd_mask = 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, tmp);
-			rdev->irq.hpd[0] = true;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
 			WREG32(DC_HPD2_CONTROL, tmp);
-			rdev->irq.hpd[1] = true;
+			hpd_mask |= (1 << 1);
 			break;
 		case RADEON_HPD_3:
 			WREG32(DC_HPD3_CONTROL, tmp);
-			rdev->irq.hpd[2] = true;
+			hpd_mask |= (1 << 2);
 			break;
 		case RADEON_HPD_4:
 			WREG32(DC_HPD4_CONTROL, tmp);
-			rdev->irq.hpd[3] = true;
+			hpd_mask |= (1 << 3);
 			break;
 		case RADEON_HPD_5:
 			WREG32(DC_HPD5_CONTROL, tmp);
-			rdev->irq.hpd[4] = true;
+			hpd_mask |= (1 << 4);
 			break;
 		case RADEON_HPD_6:
 			WREG32(DC_HPD6_CONTROL, tmp);
-			rdev->irq.hpd[5] = true;
+			hpd_mask |= (1 << 5);
 			break;
 		default:
 			break;
@@ -464,45 +465,48 @@ void evergreen_hpd_init(struct radeon_device *rdev)
 		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
-		evergreen_irq_set(rdev);
+		radeon_irq_kms_enable_hpd(rdev, hpd_mask);
 }
 
 void evergreen_hpd_fini(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 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;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
 			WREG32(DC_HPD2_CONTROL, 0);
-			rdev->irq.hpd[1] = false;
+			hpd_mask |= (1 << 1);
 			break;
 		case RADEON_HPD_3:
 			WREG32(DC_HPD3_CONTROL, 0);
-			rdev->irq.hpd[2] = false;
+			hpd_mask |= (1 << 2);
 			break;
 		case RADEON_HPD_4:
 			WREG32(DC_HPD4_CONTROL, 0);
-			rdev->irq.hpd[3] = false;
+			hpd_mask |= (1 << 3);
 			break;
 		case RADEON_HPD_5:
 			WREG32(DC_HPD5_CONTROL, 0);
-			rdev->irq.hpd[4] = false;
+			hpd_mask |= (1 << 4);
 			break;
 		case RADEON_HPD_6:
 			WREG32(DC_HPD6_CONTROL, 0);
-			rdev->irq.hpd[5] = false;
+			hpd_mask |= (1 << 5);
 			break;
 		default:
 			break;
 		}
 	}
+	if (rdev->irq.installed)
+		radeon_irq_kms_disable_hpd(rdev, hpd_mask);
 }
 
 /* watermark setup */
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 2587426..9b40363 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -567,15 +567,16 @@ void r100_hpd_init(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 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;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
-			rdev->irq.hpd[1] = true;
+			hpd_mask |= (1 << 1);
 			break;
 		default:
 			break;
@@ -583,27 +584,30 @@ void r100_hpd_init(struct radeon_device *rdev)
 		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
-		r100_irq_set(rdev);
+		radeon_irq_kms_enable_hpd(rdev, hpd_mask);
 }
 
 void r100_hpd_fini(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 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;
+			hpd_mask |= (1 << 0);
 			break;
 		case RADEON_HPD_2:
-			rdev->irq.hpd[1] = false;
+			hpd_mask |= (1 << 1);
 			break;
 		default:
 			break;
 		}
 	}
+	if (rdev->irq.installed)
+		radeon_irq_kms_disable_hpd(rdev, hpd_mask);
 }
 
 /*
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 90c6639..4f1ac83 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -709,6 +709,7 @@ void r600_hpd_init(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 0;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -729,28 +730,28 @@ 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;
+				hpd_mask |= (1 << 0);
 				break;
 			case RADEON_HPD_2:
 				WREG32(DC_HPD2_CONTROL, tmp);
-				rdev->irq.hpd[1] = true;
+				hpd_mask |= (1 << 1);
 				break;
 			case RADEON_HPD_3:
 				WREG32(DC_HPD3_CONTROL, tmp);
-				rdev->irq.hpd[2] = true;
+				hpd_mask |= (1 << 2);
 				break;
 			case RADEON_HPD_4:
 				WREG32(DC_HPD4_CONTROL, tmp);
-				rdev->irq.hpd[3] = true;
+				hpd_mask |= (1 << 3);
 				break;
 				/* DCE 3.2 */
 			case RADEON_HPD_5:
 				WREG32(DC_HPD5_CONTROL, tmp);
-				rdev->irq.hpd[4] = true;
+				hpd_mask |= (1 << 4);
 				break;
 			case RADEON_HPD_6:
 				WREG32(DC_HPD6_CONTROL, tmp);
-				rdev->irq.hpd[5] = true;
+				hpd_mask |= (1 << 5);
 				break;
 			default:
 				break;
@@ -759,15 +760,15 @@ 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;
+				hpd_mask |= (1 << 0);
 				break;
 			case RADEON_HPD_2:
 				WREG32(DC_HOT_PLUG_DETECT2_CONTROL, DC_HOT_PLUG_DETECTx_EN);
-				rdev->irq.hpd[1] = true;
+				hpd_mask |= (1 << 1);
 				break;
 			case RADEON_HPD_3:
 				WREG32(DC_HOT_PLUG_DETECT3_CONTROL, DC_HOT_PLUG_DETECTx_EN);
-				rdev->irq.hpd[2] = true;
+				hpd_mask |= (1 << 2);
 				break;
 			default:
 				break;
@@ -776,13 +777,14 @@ void r600_hpd_init(struct radeon_device *rdev)
 		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
-		r600_irq_set(rdev);
+		radeon_irq_kms_enable_hpd(rdev, hpd_mask);
 }
 
 void r600_hpd_fini(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 0;
 
 	if (ASIC_IS_DCE3(rdev)) {
 		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -790,28 +792,28 @@ void r600_hpd_fini(struct radeon_device *rdev)
 			switch (radeon_connector->hpd.hpd) {
 			case RADEON_HPD_1:
 				WREG32(DC_HPD1_CONTROL, 0);
-				rdev->irq.hpd[0] = false;
+				hpd_mask |= (1 << 0);
 				break;
 			case RADEON_HPD_2:
 				WREG32(DC_HPD2_CONTROL, 0);
-				rdev->irq.hpd[1] = false;
+				hpd_mask |= (1 << 1);
 				break;
 			case RADEON_HPD_3:
 				WREG32(DC_HPD3_CONTROL, 0);
-				rdev->irq.hpd[2] = false;
+				hpd_mask |= (1 << 2);
 				break;
 			case RADEON_HPD_4:
 				WREG32(DC_HPD4_CONTROL, 0);
-				rdev->irq.hpd[3] = false;
+				hpd_mask |= (1 << 3);
 				break;
 				/* DCE 3.2 */
 			case RADEON_HPD_5:
 				WREG32(DC_HPD5_CONTROL, 0);
-				rdev->irq.hpd[4] = false;
+				hpd_mask |= (1 << 4);
 				break;
 			case RADEON_HPD_6:
 				WREG32(DC_HPD6_CONTROL, 0);
-				rdev->irq.hpd[5] = false;
+				hpd_mask |= (1 << 5);
 				break;
 			default:
 				break;
@@ -823,21 +825,23 @@ void r600_hpd_fini(struct radeon_device *rdev)
 			switch (radeon_connector->hpd.hpd) {
 			case RADEON_HPD_1:
 				WREG32(DC_HOT_PLUG_DETECT1_CONTROL, 0);
-				rdev->irq.hpd[0] = false;
+				hpd_mask |= (1 << 0);
 				break;
 			case RADEON_HPD_2:
 				WREG32(DC_HOT_PLUG_DETECT2_CONTROL, 0);
-				rdev->irq.hpd[1] = false;
+				hpd_mask |= (1 << 1);
 				break;
 			case RADEON_HPD_3:
 				WREG32(DC_HOT_PLUG_DETECT3_CONTROL, 0);
-				rdev->irq.hpd[2] = false;
+				hpd_mask |= (1 << 2);
 				break;
 			default:
 				break;
 			}
 		}
 	}
+	if (rdev->irq.installed)
+		radeon_irq_kms_disable_hpd(rdev, hpd_mask);
 }
 
 /*
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 54eea81..3dd9b59 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -634,6 +634,8 @@ 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, u32 hpd_mask);
+void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, u32 hpd_mask);
 int radeon_irq_kms_wait_gui_idle(struct radeon_device *rdev);
 
 /*
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 11fc4f7..8f9ee4a 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -298,6 +298,35 @@ void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block)
 	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
 }
 
+void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, u32 hpd_mask)
+{
+	unsigned long irqflags;
+	int i;
+
+	spin_lock_irqsave(&rdev->irq.lock, irqflags);
+	for (i = 0; i < RADEON_MAX_HPD_PINS; i++) {
+		if (hpd_mask & (1 << i))
+			rdev->irq.hpd[i] = true;
+	}
+	radeon_irq_set(rdev);
+	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
+
+}
+
+void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, u32 hpd_mask)
+{
+	unsigned long irqflags;
+	int i;
+
+	spin_lock_irqsave(&rdev->irq.lock, irqflags);
+	for (i = 0; i < RADEON_MAX_HPD_PINS; i++) {
+		if (hpd_mask & (1 << i))
+			rdev->irq.hpd[i] = false;
+	}
+	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;
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 4e9c41a..3c8cd95 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -294,6 +294,7 @@ void rs600_hpd_init(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 0;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -301,12 +302,12 @@ 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;
+			hpd_mask |= (1 << 0);
 			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;
+			hpd_mask |= (1 << 0);
 			break;
 		default:
 			break;
@@ -314,13 +315,14 @@ void rs600_hpd_init(struct radeon_device *rdev)
 		radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 	}
 	if (rdev->irq.installed)
-		rs600_irq_set(rdev);
+		radeon_irq_kms_enable_hpd(rdev, hpd_mask);
 }
 
 void rs600_hpd_fini(struct radeon_device *rdev)
 {
 	struct drm_device *dev = rdev->ddev;
 	struct drm_connector *connector;
+	u32 hpd_mask = 0;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -328,17 +330,19 @@ 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;
+			hpd_mask |= (1 << 0);
 			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;
+			hpd_mask |= (1 << 1);
 			break;
 		default:
 			break;
 		}
 	}
+	if (rdev->irq.installed)
+		radeon_irq_kms_disable_hpd(rdev, hpd_mask);
 }
 
 int rs600_asic_reset(struct radeon_device *rdev)
-- 
1.7.7.5

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel

[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux