aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2014-02-19 14:29:49 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-05-20 15:13:35 -0400
commitf2752282f7f7b566b07113dd5aa130725aa95ac4 (patch)
treed80fa96d1fafc4a3d916d99aa6f4d664aaa49046
parent3212a22ff7b1adad9c8bda6655dd483a6a91bdba (diff)
drm: Add drm_vblank_on()
drm_vblank_off() will turn off vblank interrupts, but as long as the refcount is elevated drm_vblank_get() will not re-enable them. This is a problem is someone is holding a vblank reference while a modeset is happening, and the driver requires vblank interrupt to work during that time. Add drm_vblank_on() as a counterpart to drm_vblank_off() which will re-enabled vblank interrupts if the refcount is already elevated. This will allow drivers to choose the specific places in the modeset sequence at which vblank interrupts get disabled and enabled. Testcase: igt/kms_flip/*-vs-suspend Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> [danvet: Add Testcase tag for the igt I've written.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/drm_irq.c72
-rw-r--r--drivers/gpu/drm/i915/intel_display.c8
-rw-r--r--include/drm/drmP.h1
3 files changed, 62 insertions, 19 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 13d671ed3421..dd786d84daab 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -840,6 +840,41 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
840} 840}
841 841
842/** 842/**
843 * drm_vblank_enable - enable the vblank interrupt on a CRTC
844 * @dev: DRM device
845 * @crtc: CRTC in question
846 */
847static int drm_vblank_enable(struct drm_device *dev, int crtc)
848{
849 int ret = 0;
850
851 assert_spin_locked(&dev->vbl_lock);
852
853 spin_lock(&dev->vblank_time_lock);
854
855 if (!dev->vblank[crtc].enabled) {
856 /* Enable vblank irqs under vblank_time_lock protection.
857 * All vblank count & timestamp updates are held off
858 * until we are done reinitializing master counter and
859 * timestamps. Filtercode in drm_handle_vblank() will
860 * prevent double-accounting of same vblank interval.
861 */
862 ret = dev->driver->enable_vblank(dev, crtc);
863 DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
864 if (ret)
865 atomic_dec(&dev->vblank[crtc].refcount);
866 else {
867 dev->vblank[crtc].enabled = true;
868 drm_update_vblank_count(dev, crtc);
869 }
870 }
871
872 spin_unlock(&dev->vblank_time_lock);
873
874 return ret;
875}
876
877/**
843 * drm_vblank_get - get a reference count on vblank events 878 * drm_vblank_get - get a reference count on vblank events
844 * @dev: DRM device 879 * @dev: DRM device
845 * @crtc: which CRTC to own 880 * @crtc: which CRTC to own
@@ -858,25 +893,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
858 spin_lock_irqsave(&dev->vbl_lock, irqflags); 893 spin_lock_irqsave(&dev->vbl_lock, irqflags);
859 /* Going from 0->1 means we have to enable interrupts again */ 894 /* Going from 0->1 means we have to enable interrupts again */
860 if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { 895 if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
861 spin_lock(&dev->vblank_time_lock); 896 ret = drm_vblank_enable(dev, crtc);
862 if (!dev->vblank[crtc].enabled) {
863 /* Enable vblank irqs under vblank_time_lock protection.
864 * All vblank count & timestamp updates are held off
865 * until we are done reinitializing master counter and
866 * timestamps. Filtercode in drm_handle_vblank() will
867 * prevent double-accounting of same vblank interval.
868 */
869 ret = dev->driver->enable_vblank(dev, crtc);
870 DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",
871 crtc, ret);
872 if (ret)
873 atomic_dec(&dev->vblank[crtc].refcount);
874 else {
875 dev->vblank[crtc].enabled = true;
876 drm_update_vblank_count(dev, crtc);
877 }
878 }
879 spin_unlock(&dev->vblank_time_lock);
880 } else { 897 } else {
881 if (!dev->vblank[crtc].enabled) { 898 if (!dev->vblank[crtc].enabled) {
882 atomic_dec(&dev->vblank[crtc].refcount); 899 atomic_dec(&dev->vblank[crtc].refcount);
@@ -946,6 +963,23 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
946EXPORT_SYMBOL(drm_vblank_off); 963EXPORT_SYMBOL(drm_vblank_off);
947 964
948/** 965/**
966 * drm_vblank_on - enable vblank events on a CRTC
967 * @dev: DRM device
968 * @crtc: CRTC in question
969 */
970void drm_vblank_on(struct drm_device *dev, int crtc)
971{
972 unsigned long irqflags;
973
974 spin_lock_irqsave(&dev->vbl_lock, irqflags);
975 /* re-enable interrupts if there's are users left */
976 if (atomic_read(&dev->vblank[crtc].refcount) != 0)
977 WARN_ON(drm_vblank_enable(dev, crtc));
978 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
979}
980EXPORT_SYMBOL(drm_vblank_on);
981
982/**
949 * drm_vblank_pre_modeset - account for vblanks across mode sets 983 * drm_vblank_pre_modeset - account for vblanks across mode sets
950 * @dev: DRM device 984 * @dev: DRM device
951 * @crtc: CRTC in question 985 * @crtc: CRTC in question
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 72b5c34d8ce7..313f29d1aae2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3737,6 +3737,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
3737 * happening. 3737 * happening.
3738 */ 3738 */
3739 intel_wait_for_vblank(dev, intel_crtc->pipe); 3739 intel_wait_for_vblank(dev, intel_crtc->pipe);
3740
3741 drm_vblank_on(dev, pipe);
3740} 3742}
3741 3743
3742/* IPS only exists on ULT machines and is tied to pipe A. */ 3744/* IPS only exists on ULT machines and is tied to pipe A. */
@@ -3828,6 +3830,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
3828 * to change the workaround. */ 3830 * to change the workaround. */
3829 haswell_mode_set_planes_workaround(intel_crtc); 3831 haswell_mode_set_planes_workaround(intel_crtc);
3830 ilk_crtc_enable_planes(crtc); 3832 ilk_crtc_enable_planes(crtc);
3833
3834 drm_vblank_on(dev, pipe);
3831} 3835}
3832 3836
3833static void ironlake_pfit_disable(struct intel_crtc *crtc) 3837static void ironlake_pfit_disable(struct intel_crtc *crtc)
@@ -4351,6 +4355,8 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
4351 4355
4352 for_each_encoder_on_crtc(dev, crtc, encoder) 4356 for_each_encoder_on_crtc(dev, crtc, encoder)
4353 encoder->enable(encoder); 4357 encoder->enable(encoder);
4358
4359 drm_vblank_on(dev, pipe);
4354} 4360}
4355 4361
4356static void i9xx_crtc_enable(struct drm_crtc *crtc) 4362static void i9xx_crtc_enable(struct drm_crtc *crtc)
@@ -4398,6 +4404,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
4398 4404
4399 for_each_encoder_on_crtc(dev, crtc, encoder) 4405 for_each_encoder_on_crtc(dev, crtc, encoder)
4400 encoder->enable(encoder); 4406 encoder->enable(encoder);
4407
4408 drm_vblank_on(dev, pipe);
4401} 4409}
4402 4410
4403static void i9xx_pfit_disable(struct intel_crtc *crtc) 4411static void i9xx_pfit_disable(struct intel_crtc *crtc)
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 9d982d483f12..7339b2b00724 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1360,6 +1360,7 @@ extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
1360extern int drm_vblank_get(struct drm_device *dev, int crtc); 1360extern int drm_vblank_get(struct drm_device *dev, int crtc);
1361extern void drm_vblank_put(struct drm_device *dev, int crtc); 1361extern void drm_vblank_put(struct drm_device *dev, int crtc);
1362extern void drm_vblank_off(struct drm_device *dev, int crtc); 1362extern void drm_vblank_off(struct drm_device *dev, int crtc);
1363extern void drm_vblank_on(struct drm_device *dev, int crtc);
1363extern void drm_vblank_cleanup(struct drm_device *dev); 1364extern void drm_vblank_cleanup(struct drm_device *dev);
1364extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, 1365extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
1365 struct timeval *tvblank, unsigned flags); 1366 struct timeval *tvblank, unsigned flags);