From: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
To: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>,
intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock
Date: Fri, 17 Mar 2017 11:47:51 +0200 [thread overview]
Message-ID: <20170317094751.GL31595@intel.com> (raw)
In-Reply-To: <20170316234749.1297-1-chris@chris-wilson.co.uk>
On Thu, Mar 16, 2017 at 11:47:48PM +0000, Chris Wilson wrote:
> Order the update to vblank->enabled after the timestamp is primed so
> that a concurrent unlocked reader will only see the vblank->enabled with
> the current timestamp.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
> drivers/gpu/drm/drm_irq.c | 30 ++++++++++++++++++------------
> 1 file changed, 18 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> index 53a526c7b24d..4cc9352ab6a8 100644
> --- a/drivers/gpu/drm/drm_irq.c
> +++ b/drivers/gpu/drm/drm_irq.c
> @@ -336,10 +336,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
> * calling the ->disable_vblank() operation in atomic context with the
> * hardware potentially runtime suspended.
> */
> - if (vblank->enabled) {
> + if (cmpxchg_relaxed(&vblank->enabled, true, false))
> __disable_vblank(dev, pipe);
> - vblank->enabled = false;
> - }
>
> /*
> * Always update the count and timestamp to maintain the
> @@ -360,7 +358,7 @@ static void vblank_disable_fn(unsigned long arg)
> unsigned long irqflags;
>
> spin_lock_irqsave(&dev->vbl_lock, irqflags);
> - if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) {
> + if (atomic_read(&vblank->refcount) == 0 && READ_ONCE(vblank->enabled)) {
Hmm. Aren't most of these accesses inside the lock? Looks like you're
marking everything READ/WRITE_ONCE()?
> DRM_DEBUG("disabling vblank on crtc %u\n", pipe);
> vblank_disable_and_save(dev, pipe);
> }
> @@ -384,7 +382,7 @@ void drm_vblank_cleanup(struct drm_device *dev)
> for (pipe = 0; pipe < dev->num_crtcs; pipe++) {
> struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
>
> - WARN_ON(vblank->enabled &&
> + WARN_ON(READ_ONCE(vblank->enabled) &&
> drm_core_check_feature(dev, DRIVER_MODESET));
>
> del_timer_sync(&vblank->disable_timer);
> @@ -564,7 +562,7 @@ int drm_irq_uninstall(struct drm_device *dev)
> for (i = 0; i < dev->num_crtcs; i++) {
> struct drm_vblank_crtc *vblank = &dev->vblank[i];
>
> - if (!vblank->enabled)
> + if (!READ_ONCE(vblank->enabled))
> continue;
>
> WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET));
> @@ -1105,11 +1103,16 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe)
> */
> ret = __enable_vblank(dev, pipe);
> DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret);
> - if (ret)
> + if (ret) {
> atomic_dec(&vblank->refcount);
> - else {
> - vblank->enabled = true;
> + } else {
> drm_update_vblank_count(dev, pipe, 0);
> + /* drm_update_vblank_count() includes a wmb so we just
> + * need to ensure that the compiler emits the write
> + * to mark the vblank as enabled after the call
> + * to drm_update_vblank_count().
> + */
> + WRITE_ONCE(vblank->enabled, true);
Ordering+barrier looks correct to me.
> }
> }
>
> @@ -1148,7 +1151,7 @@ static int drm_vblank_get(struct drm_device *dev, unsigned int pipe)
> if (atomic_add_return(1, &vblank->refcount) == 1) {
> ret = drm_vblank_enable(dev, pipe);
> } else {
> - if (!vblank->enabled) {
> + if (!READ_ONCE(vblank->enabled)) {
> atomic_dec(&vblank->refcount);
> ret = -EINVAL;
> }
> @@ -1517,7 +1520,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
> * vblank disable, so no need for further locking. The reference from
> * drm_vblank_get() protects against vblank disable from another source.
> */
> - if (!vblank->enabled) {
> + if (!READ_ONCE(vblank->enabled)) {
> ret = -EINVAL;
> goto err_unlock;
> }
> @@ -1644,7 +1647,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
> DRM_WAIT_ON(ret, vblank->queue, 3 * HZ,
> (((drm_vblank_count(dev, pipe) -
> vblwait->request.sequence) <= (1 << 23)) ||
> - !vblank->enabled ||
> + !READ_ONCE(vblank->enabled) ||
> !dev->irq_enabled));
> }
>
> @@ -1714,6 +1717,9 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe)
> if (WARN_ON(pipe >= dev->num_crtcs))
> return false;
>
> + if (!READ_ONCE(vblank->enabled))
> + return false;
This to me looks like it could theoretically cause us to
miss an interrupt.
1. enable_irq()
2. drm_update_vblank_count()
3. irq fires
4. drm_handle_vblank() doesn't do anything
5. enabled=true
> +
> spin_lock_irqsave(&dev->event_lock, irqflags);
>
> /* Need timestamp lock to prevent concurrent execution with
> --
> 2.11.0
--
Ville Syrjälä
Intel OTC
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2017-03-17 9:47 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-16 23:47 [PATCH 1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock Chris Wilson
2017-03-16 23:47 ` [PATCH 2/2] drm: Peek at the current counter/timestamp for vblank queries Chris Wilson
2017-03-17 9:49 ` Ville Syrjälä
2017-03-17 19:59 ` Chris Wilson
2017-03-17 0:06 ` ✗ Fi.CI.BAT: failure for series starting with [1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock Patchwork
2017-03-17 9:47 ` Ville Syrjälä [this message]
2017-03-17 10:19 ` [PATCH 1/2] " Chris Wilson
2017-03-17 11:25 ` Ville Syrjälä
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=20170317094751.GL31595@intel.com \
--to=ville.syrjala@linux.intel.com \
--cc=chris@chris-wilson.co.uk \
--cc=daniel.vetter@ffwll.ch \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@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.