All of lore.kernel.org
 help / color / mirror / Atom feed
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.

  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.