From: "Christian König" <deathsimple@vodafone.de>
To: Alex Deucher <alexdeucher@gmail.com>
Cc: Christian Koenig <christian.koenig@amd.com>,
dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 07/10] drm/radeon: apply Murphy's law to the kms irq code
Date: Thu, 31 May 2012 22:15:31 +0200 [thread overview]
Message-ID: <4FC7D163.9050300@vodafone.de> (raw)
In-Reply-To: <CADnq5_OqLWHEMtFhz9O9JnVHb9TAmbibi56Q-JYizYhzf_pFZw@mail.gmail.com>
On 31.05.2012 20:15, Alex Deucher wrote:
> On Thu, May 24, 2012 at 11:35 AM, Alex Deucher<alexdeucher@gmail.com> wrote:
>> On Thu, May 24, 2012 at 3:49 AM, Christian König
>> <deathsimple@vodafone.de> wrote:
>>> From: Christian Koenig<christian.koenig@amd.com>
>>>
>>> 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@amd.com>
>>> ---
>>> 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.
The version I pushed into my repo includes nearly the same
implementation in the v2 version of the patch. I just haven't had time
to send it to the list yet.
There also is a V2 of the IH patch. After removing the spinlock (and
with it the disabling of IRQs) in the interrupt handler we seem to hit a
race condition in the vblank code. Actually I think we can hit the same
problem when the IH is currently running on one CPU and X modifying
vblank properties on another CPU, but that is really really really unlikely.
Whatever it is I modified the IH patch to keep the spinlock for now, put
I think I should look into it more closely.
Anyway going to send out the patches in a minute,
Christian.
next prev parent reply other threads:[~2012-05-31 20:15 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-05-24 7:49 [PATCH 01/10] drm/radeon: remove radeon_fence_create Christian König
2012-05-24 7:49 ` [PATCH 02/10] drm/radeon: add infrastructure for advanced ring synchronization Christian König
2012-05-24 15:56 ` j.glisse
2012-05-24 7:49 ` [PATCH 03/10] drm/radeon: rework ring syncing code Christian König
2012-05-24 15:57 ` j.glisse
2012-05-24 7:49 ` [PATCH 04/10] drm/radeon: replace vmram_mutex with mclk_lock v2 Christian König
2012-05-24 15:57 ` j.glisse
2012-05-24 7:49 ` [PATCH 05/10] drm/radeon: remove some unneeded structure members Christian König
2012-05-24 15:58 ` j.glisse
2012-05-24 7:49 ` [PATCH 06/10] drm/radeon: fix & improve ih ring handling Christian König
2012-05-24 15:59 ` j.glisse
2012-05-24 7:49 ` [PATCH 07/10] drm/radeon: apply Murphy's law to the kms irq code Christian König
2012-05-24 15:35 ` Alex Deucher
2012-05-24 15:53 ` j.glisse
2012-05-31 18:15 ` Alex Deucher
2012-05-31 18:39 ` Jerome Glisse
2012-05-31 20:15 ` Christian König [this message]
2012-05-24 7:49 ` [PATCH 08/10] drm/radeon: replace pflip and sw_int counters with atomics Christian König
2012-05-24 11:59 ` Sylvain BERTRAND
2012-05-24 12:29 ` Koenig, Christian
2012-05-24 12:46 ` Sylvain BERTRAND
2012-05-24 12:53 ` Dave Airlie
2012-05-24 12:54 ` Dave Airlie
2012-05-24 14:23 ` Sylvain BERTRAND
2012-05-24 7:49 ` [PATCH 09/10] drm/radeon: replace cs_mutex with vm_mutex Christian König
2012-05-24 7:49 ` [PATCH 10/10] drm/radeon: work around bugs in caymans compute rings Christian König
2012-05-24 15:54 ` [PATCH 01/10] drm/radeon: remove radeon_fence_create j.glisse
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4FC7D163.9050300@vodafone.de \
--to=deathsimple@vodafone.de \
--cc=alexdeucher@gmail.com \
--cc=christian.koenig@amd.com \
--cc=dri-devel@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.