From c4cc383915549cf14f027f374904e30c13653dac Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Mon, 21 Feb 2011 05:42:00 +0100 Subject: drm/vblank: Use abs64(diff_ns) for s64 diff_ns instead of abs(diff_ns) Use of abs() wrongly wrapped diff_ns to 32 bit, which gives a 1/4000 probability of a missed vblank increment at each vblank irq reenable if the kms driver doesn't support high precision vblank timestamping. Not a big deal in practice, but let's make it nice. Signed-off-by: Mario Kleiner Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/drm_irq.c') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 3dadfa2a852..6d2d4faf867 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -164,7 +164,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) * available. In that case we can't account for this and just * hope for the best. */ - if ((vblrc > 0) && (abs(diff_ns) > 1000000)) + if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) atomic_inc(&dev->_vblank_count[crtc]); /* Invalidate all timestamps while vblank irq's are off. */ @@ -1293,7 +1293,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) * e.g., due to spurious vblank interrupts. We need to * ignore those for accounting. */ - if (abs(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { + if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { /* Store new timestamp in ringbuffer. */ vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; smp_wmb(); -- cgit v1.2.3-18-g5258 From bc21512835a72bc1eab7abd7d8a1bff0435591d7 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Mon, 21 Feb 2011 05:42:01 +0100 Subject: drm/vblank: Use memory barriers optimized for atomic_t instead of generics. Documentation/atomic_ops.txt tells us that there are memory barriers optimized for atomic_inc and other atomic_t ops. Use these instead of smp_wmb(), and also to make the required memory barriers around vblank counter increments more explicit. Signed-off-by: Mario Kleiner Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_irq.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/drm_irq.c') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 6d2d4faf867..22f3bf5ecbd 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -164,8 +164,10 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) * available. In that case we can't account for this and just * hope for the best. */ - if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) + if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { atomic_inc(&dev->_vblank_count[crtc]); + smp_mb__after_atomic_inc(); + } /* Invalidate all timestamps while vblank irq's are off. */ clear_vblank_timestamps(dev, crtc); @@ -858,10 +860,11 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) if (rc) { tslot = atomic_read(&dev->_vblank_count[crtc]) + diff; vblanktimestamp(dev, crtc, tslot) = t_vblank; - smp_wmb(); } + smp_mb__before_atomic_inc(); atomic_add(diff, &dev->_vblank_count[crtc]); + smp_mb__after_atomic_inc(); } /** @@ -1296,12 +1299,13 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { /* Store new timestamp in ringbuffer. */ vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; - smp_wmb(); /* Increment cooked vblank count. This also atomically commits * the timestamp computed above. */ + smp_mb__before_atomic_inc(); atomic_inc(&dev->_vblank_count[crtc]); + smp_mb__after_atomic_inc(); } else { DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", crtc, (int) diff_ns); -- cgit v1.2.3-18-g5258 From 9be6f8a978bdcbab46474a125aa4212516b71fe7 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Mon, 21 Feb 2011 05:42:02 +0100 Subject: drm/vblank: Enable precise vblank timestamps for interlaced and doublescan modes. Testing showed the current code can already handle doublescan video modes just fine. A trivial tweak makes it work for interlaced scanout as well. Tested and shown to be precise on Radeon rv530, r600 and Intel 945-GME. Signed-off-by: Mario Kleiner Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_irq.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/drm_irq.c') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 22f3bf5ecbd..53120a72a48 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -493,6 +493,12 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc) /* Dot clock in Hz: */ dotclock = (u64) crtc->hwmode.clock * 1000; + /* Fields of interlaced scanout modes are only halve a frame duration. + * Double the dotclock to get halve the frame-/line-/pixelduration. + */ + if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE) + dotclock *= 2; + /* Valid dotclock? */ if (dotclock > 0) { /* Convert scanline length in pixels and video dot clock to @@ -605,14 +611,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, return -EAGAIN; } - /* Don't know yet how to handle interlaced or - * double scan modes. Just no-op for now. - */ - if (mode->flags & (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN)) { - DRM_DEBUG("crtc %d: Noop due to unsupported mode.\n", crtc); - return -ENOTSUPP; - } - /* Get current scanout position with system timestamp. * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times * if single query takes longer than max_error nanoseconds. -- cgit v1.2.3-18-g5258 From 1922756124ddd53846877416d92ba4a802bc658f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 24 Feb 2011 08:35:06 +1000 Subject: drm: fix unsigned vs signed comparison issue in modeset ctl ioctl. This fixes CVE-2011-1013. Reported-by: Matthiew Herrb (OpenBSD X.org team) Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/drm_irq.c') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 53120a72a48..28d1d3c24d6 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1012,7 +1012,8 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; - int crtc, ret = 0; + int ret = 0; + unsigned int crtc; /* If drm_vblank_init() hasn't been called yet, just no-op */ if (!dev->num_crtcs) -- cgit v1.2.3-18-g5258