* [PATCH 1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock
@ 2017-03-16 23:47 Chris Wilson
2017-03-16 23:47 ` [PATCH 2/2] drm: Peek at the current counter/timestamp for vblank queries Chris Wilson
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Chris Wilson @ 2017-03-16 23:47 UTC (permalink / raw)
To: dri-devel; +Cc: Daniel Vetter, intel-gfx
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)) {
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);
}
}
@@ -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;
+
spin_lock_irqsave(&dev->event_lock, irqflags);
/* Need timestamp lock to prevent concurrent execution with
--
2.11.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] drm: Peek at the current counter/timestamp for vblank queries
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 ` Chris Wilson
2017-03-17 9:49 ` Ville Syrjälä
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 ` [PATCH 1/2] " Ville Syrjälä
2 siblings, 1 reply; 8+ messages in thread
From: Chris Wilson @ 2017-03-16 23:47 UTC (permalink / raw)
To: dri-devel; +Cc: Michel Dänzer, Laurent Pinchart, Dave Airlie, intel-gfx
Bypass all the spinlocks and return the last timestamp and counter from
the last vblank if the driver delcares that it is accurate (and stable
across on/off), and the vblank is currently enabled.
This is dependent upon the both the hardware and driver to provide the
proper barriers to facilitate reading our bookkeeping outside of the
vblank interrupt and outside of the explicit vblank locks.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Michel Dänzer <michel@daenzer.net>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Dave Airlie <airlied@redhat.com>,
Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
---
drivers/gpu/drm/drm_irq.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 4cc9352ab6a8..b4bd361a2bcc 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -1562,6 +1562,17 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
return ret;
}
+static bool drm_wait_vblank_is_query(union drm_wait_vblank *vblwait)
+{
+ if (vblwait->request.sequence)
+ return false;
+
+ return _DRM_VBLANK_RELATIVE ==
+ (vblwait->request.type & (_DRM_VBLANK_TYPES_MASK |
+ _DRM_VBLANK_EVENT |
+ _DRM_VBLANK_NEXTONMISS));
+}
+
/*
* Wait for VBLANK.
*
@@ -1611,6 +1622,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
vblank = &dev->vblank[pipe];
+ /* If the counter is currently enabled and accurate, short-circuit queries
+ * to return the cached timestamp of the last vblank.
+ */
+ if (dev->vblank_disable_immediate &&
+ drm_wait_vblank_is_query(vblwait) &&
+ vblank->enabled) {
+ struct timeval now;
+
+ vblwait->reply.sequence =
+ drm_vblank_count_and_time(dev, pipe, &now);
+ vblwait->reply.tval_sec = now.tv_sec;
+ vblwait->reply.tval_usec = now.tv_usec;
+ return 0;
+ }
+
ret = drm_vblank_get(dev, pipe);
if (ret) {
DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret);
--
2.11.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 8+ messages in thread
* ✗ Fi.CI.BAT: failure for series starting with [1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock
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 0:06 ` Patchwork
2017-03-17 9:47 ` [PATCH 1/2] " Ville Syrjälä
2 siblings, 0 replies; 8+ messages in thread
From: Patchwork @ 2017-03-17 0:06 UTC (permalink / raw)
To: Chris Wilson; +Cc: intel-gfx
== Series Details ==
Series: series starting with [1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock
URL : https://patchwork.freedesktop.org/series/21410/
State : failure
== Summary ==
Series 21410v1 Series without cover letter
https://patchwork.freedesktop.org/api/1.0/series/21410/revisions/1/mbox/
Test gem_exec_flush:
Subgroup basic-batch-kernel-default-uc:
pass -> FAIL (fi-snb-2600) fdo#100007
Test gem_exec_suspend:
Subgroup basic-s4-devices:
pass -> DMESG-WARN (fi-bxt-t5700) fdo#100125
Test pm_rpm:
Subgroup basic-rte:
pass -> DMESG-WARN (fi-skl-6770hq)
Test pm_rps:
Subgroup basic-api:
pass -> INCOMPLETE (fi-skl-6770hq)
fdo#100007 https://bugs.freedesktop.org/show_bug.cgi?id=100007
fdo#100125 https://bugs.freedesktop.org/show_bug.cgi?id=100125
fi-bdw-5557u total:278 pass:267 dwarn:0 dfail:0 fail:0 skip:11 time: 456s
fi-bsw-n3050 total:278 pass:239 dwarn:0 dfail:0 fail:0 skip:39 time: 573s
fi-bxt-j4205 total:278 pass:259 dwarn:0 dfail:0 fail:0 skip:19 time: 533s
fi-bxt-t5700 total:278 pass:257 dwarn:1 dfail:0 fail:0 skip:20 time: 552s
fi-byt-j1900 total:278 pass:251 dwarn:0 dfail:0 fail:0 skip:27 time: 498s
fi-byt-n2820 total:278 pass:247 dwarn:0 dfail:0 fail:0 skip:31 time: 505s
fi-hsw-4770 total:278 pass:262 dwarn:0 dfail:0 fail:0 skip:16 time: 435s
fi-hsw-4770r total:278 pass:262 dwarn:0 dfail:0 fail:0 skip:16 time: 432s
fi-ilk-650 total:278 pass:228 dwarn:0 dfail:0 fail:0 skip:50 time: 444s
fi-ivb-3520m total:278 pass:260 dwarn:0 dfail:0 fail:0 skip:18 time: 505s
fi-ivb-3770 total:278 pass:260 dwarn:0 dfail:0 fail:0 skip:18 time: 476s
fi-kbl-7500u total:278 pass:260 dwarn:0 dfail:0 fail:0 skip:18 time: 466s
fi-skl-6260u total:278 pass:268 dwarn:0 dfail:0 fail:0 skip:10 time: 488s
fi-skl-6700hq total:278 pass:261 dwarn:0 dfail:0 fail:0 skip:17 time: 596s
fi-skl-6700k total:278 pass:256 dwarn:4 dfail:0 fail:0 skip:18 time: 480s
fi-skl-6770hq total:243 pass:232 dwarn:1 dfail:0 fail:0 skip:9 time: 0s
fi-snb-2520m total:278 pass:250 dwarn:0 dfail:0 fail:0 skip:28 time: 547s
fi-snb-2600 total:278 pass:248 dwarn:0 dfail:0 fail:1 skip:29 time: 421s
99bd31bdd4d2c4c07a9eef33c9c68611a315c5b0 drm-tip: 2017y-03m-16d-22h-22m-27s UTC integration manifest
38f5f83 drm: Peek at the current counter/timestamp for vblank queries
1d381f8 drm: Mark up accesses of vblank->enabled outside of its spinlock
== Logs ==
For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_4211/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock
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 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ä
2017-03-17 10:19 ` Chris Wilson
2 siblings, 1 reply; 8+ messages in thread
From: Ville Syrjälä @ 2017-03-17 9:47 UTC (permalink / raw)
To: Chris Wilson; +Cc: Daniel Vetter, intel-gfx, dri-devel
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
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] drm: Peek at the current counter/timestamp for vblank queries
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
0 siblings, 1 reply; 8+ messages in thread
From: Ville Syrjälä @ 2017-03-17 9:49 UTC (permalink / raw)
To: Chris Wilson
Cc: Michel Dänzer, dri-devel, Laurent Pinchart, Dave Airlie, intel-gfx
On Thu, Mar 16, 2017 at 11:47:49PM +0000, Chris Wilson wrote:
> Bypass all the spinlocks and return the last timestamp and counter from
> the last vblank if the driver delcares that it is accurate (and stable
> across on/off), and the vblank is currently enabled.
>
> This is dependent upon the both the hardware and driver to provide the
> proper barriers to facilitate reading our bookkeeping outside of the
> vblank interrupt and outside of the explicit vblank locks.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Michel Dänzer <michel@daenzer.net>
> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Dave Airlie <airlied@redhat.com>,
> Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
> ---
> drivers/gpu/drm/drm_irq.c | 26 ++++++++++++++++++++++++++
> 1 file changed, 26 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> index 4cc9352ab6a8..b4bd361a2bcc 100644
> --- a/drivers/gpu/drm/drm_irq.c
> +++ b/drivers/gpu/drm/drm_irq.c
> @@ -1562,6 +1562,17 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
> return ret;
> }
>
> +static bool drm_wait_vblank_is_query(union drm_wait_vblank *vblwait)
> +{
> + if (vblwait->request.sequence)
> + return false;
> +
> + return _DRM_VBLANK_RELATIVE ==
> + (vblwait->request.type & (_DRM_VBLANK_TYPES_MASK |
> + _DRM_VBLANK_EVENT |
> + _DRM_VBLANK_NEXTONMISS));
> +}
> +
> /*
> * Wait for VBLANK.
> *
> @@ -1611,6 +1622,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
>
> vblank = &dev->vblank[pipe];
>
> + /* If the counter is currently enabled and accurate, short-circuit queries
> + * to return the cached timestamp of the last vblank.
> + */
> + if (dev->vblank_disable_immediate &&
> + drm_wait_vblank_is_query(vblwait) &&
> + vblank->enabled) {
> + struct timeval now;
> +
Do we want a comment here as well stating that the seqlock
already has the rmb?
> + vblwait->reply.sequence =
> + drm_vblank_count_and_time(dev, pipe, &now);
> + vblwait->reply.tval_sec = now.tv_sec;
> + vblwait->reply.tval_usec = now.tv_usec;
> + return 0;
> + }
> +
> ret = drm_vblank_get(dev, pipe);
> if (ret) {
> DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret);
> --
> 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
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock
2017-03-17 9:47 ` [PATCH 1/2] " Ville Syrjälä
@ 2017-03-17 10:19 ` Chris Wilson
2017-03-17 11:25 ` Ville Syrjälä
0 siblings, 1 reply; 8+ messages in thread
From: Chris Wilson @ 2017-03-17 10:19 UTC (permalink / raw)
To: Ville Syrjälä; +Cc: Daniel Vetter, intel-gfx, dri-devel
On Fri, Mar 17, 2017 at 11:47:51AM +0200, Ville Syrjälä wrote:
> On Thu, Mar 16, 2017 at 11:47:48PM +0000, Chris Wilson wrote:
> > @@ -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()?
There's like 3 different locks here. Afaict, the correct one for
serialising vblank->enabled was dev->vblank_time_lock. Every access
outside of that lock, I marked up as READ_ONCE.
Oh, you are using vbl_lock as the barrier? That's not as clear for
disable:
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 53a526c7b24d..f447ed07ef95 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -325,6 +325,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
unsigned long irqflags;
+ assert_spin_locked(&dev->vbl_lock);
+
/* Prevent vblank irq processing while disabling vblank irqs,
* so no updates of timestamps or count can happen after we've
* disabled. Needed to prevent races in case of delayed irq's.
> > @@ -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
Sure. There's a danger you miss the irq anyway, and so the last action
after enabling the interrupt should be to process any completed events -
that's implicitly handled by enabling the interrupt in advance of adding
the first event. In the scenario above, there should be nothing to do.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] drm: Mark up accesses of vblank->enabled outside of its spinlock
2017-03-17 10:19 ` Chris Wilson
@ 2017-03-17 11:25 ` Ville Syrjälä
0 siblings, 0 replies; 8+ messages in thread
From: Ville Syrjälä @ 2017-03-17 11:25 UTC (permalink / raw)
To: Chris Wilson, dri-devel, intel-gfx, Daniel Vetter
On Fri, Mar 17, 2017 at 10:19:51AM +0000, Chris Wilson wrote:
> On Fri, Mar 17, 2017 at 11:47:51AM +0200, Ville Syrjälä wrote:
> > On Thu, Mar 16, 2017 at 11:47:48PM +0000, Chris Wilson wrote:
> > > @@ -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()?
>
> There's like 3 different locks here. Afaict, the correct one for
> serialising vblank->enabled was dev->vblank_time_lock. Every access
> outside of that lock, I marked up as READ_ONCE.
>
> Oh, you are using vbl_lock as the barrier? That's not as clear for
> disable:
>
> diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> index 53a526c7b24d..f447ed07ef95 100644
> --- a/drivers/gpu/drm/drm_irq.c
> +++ b/drivers/gpu/drm/drm_irq.c
> @@ -325,6 +325,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
> struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> unsigned long irqflags;
>
> + assert_spin_locked(&dev->vbl_lock);
> +
> /* Prevent vblank irq processing while disabling vblank irqs,
> * so no updates of timestamps or count can happen after we've
> * disabled. Needed to prevent races in case of delayed irq's.
>
>
> > > @@ -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
>
> Sure. There's a danger you miss the irq anyway, and so the last action
> after enabling the interrupt should be to process any completed events -
> that's implicitly handled by enabling the interrupt in advance of adding
> the first event. In the scenario above, there should be nothing to do.
That's a slightly different scenario since you're only thinking about
actually enabling the interrupt vs. calling drm_update_vblank_count().
That is fine as is. But with the extra 'enabled' check in the interrupt
handler you're effectively reversing that order to enable the interrupt
after drm_update_vblank_count(). Hence we can lose an interrupt now.
Of course we would eventually get another interrupt, and thanks to the
hw frame counter and whatnot we wouldn't actually lose our place entirely,
but we would see the counter jump by two frames when we actually handle
the interrupt.
--
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] drm: Peek at the current counter/timestamp for vblank queries
2017-03-17 9:49 ` Ville Syrjälä
@ 2017-03-17 19:59 ` Chris Wilson
0 siblings, 0 replies; 8+ messages in thread
From: Chris Wilson @ 2017-03-17 19:59 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Michel Dänzer, dri-devel, Laurent Pinchart, Dave Airlie, intel-gfx
On Fri, Mar 17, 2017 at 11:49:32AM +0200, Ville Syrjälä wrote:
> On Thu, Mar 16, 2017 at 11:47:49PM +0000, Chris Wilson wrote:
> > Bypass all the spinlocks and return the last timestamp and counter from
> > the last vblank if the driver delcares that it is accurate (and stable
> > across on/off), and the vblank is currently enabled.
> >
> > This is dependent upon the both the hardware and driver to provide the
> > proper barriers to facilitate reading our bookkeeping outside of the
> > vblank interrupt and outside of the explicit vblank locks.
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: Michel Dänzer <michel@daenzer.net>
> > Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Cc: Dave Airlie <airlied@redhat.com>,
> > Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
> > ---
> > drivers/gpu/drm/drm_irq.c | 26 ++++++++++++++++++++++++++
> > 1 file changed, 26 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> > index 4cc9352ab6a8..b4bd361a2bcc 100644
> > --- a/drivers/gpu/drm/drm_irq.c
> > +++ b/drivers/gpu/drm/drm_irq.c
> > @@ -1562,6 +1562,17 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
> > return ret;
> > }
> >
> > +static bool drm_wait_vblank_is_query(union drm_wait_vblank *vblwait)
> > +{
> > + if (vblwait->request.sequence)
> > + return false;
> > +
> > + return _DRM_VBLANK_RELATIVE ==
> > + (vblwait->request.type & (_DRM_VBLANK_TYPES_MASK |
> > + _DRM_VBLANK_EVENT |
> > + _DRM_VBLANK_NEXTONMISS));
> > +}
> > +
> > /*
> > * Wait for VBLANK.
> > *
> > @@ -1611,6 +1622,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
> >
> > vblank = &dev->vblank[pipe];
> >
> > + /* If the counter is currently enabled and accurate, short-circuit queries
> > + * to return the cached timestamp of the last vblank.
> > + */
> > + if (dev->vblank_disable_immediate &&
> > + drm_wait_vblank_is_query(vblwait) &&
> > + vblank->enabled) {
> > + struct timeval now;
> > +
>
> Do we want a comment here as well stating that the seqlock
> already has the rmb?
I didn't find it enlightening. Added READ_ONCE(vblank->enabled).
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2017-03-17 19:59 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH 1/2] " Ville Syrjälä
2017-03-17 10:19 ` Chris Wilson
2017-03-17 11:25 ` Ville Syrjälä
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.