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