summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_irq.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-08-26 03:04:03 +0400
committerDave Airlie <airlied@redhat.com>2014-08-26 03:04:03 +0400
commitc0ee755fc57319a623e0d9ef839cf8fb26ce8d60 (patch)
tree727fe78a158757f75b54d7e037b383ad6a39843c /drivers/gpu/drm/drm_irq.c
parent52addcf9d6669fa439387610bc65c92fa0980cef (diff)
parent14f476fa24e81d0beea1aa14d763102958518d60 (diff)
downloadlinux-c0ee755fc57319a623e0d9ef839cf8fb26ce8d60.tar.xz
Merge tag 'topic/core-stuff-2014-08-15' of git://anongit.freedesktop.org/drm-intel into drm-next
So small drm stuff all over for 3.18. Biggest one is the cmdline parsing from Chris with a few fixes from me to make it work for stupid kernel configs. Plus the atomic prep series. Tested for more than a week in -nightly and Ville/Imre indeed discovered some fun which is now fixed (and i915 vblank patches postponed since the fixups need this branch plus drm-intel-next merged together). * tag 'topic/core-stuff-2014-08-15' of git://anongit.freedesktop.org/drm-intel: drm: Use the type of the array element when reallocating drm: Don't return 0 for a value used as a denominator drm: Docbook fixes drm/irq: Implement a generic vblank_wait function drm: Add a plane->reset hook drm: trylock modest locking for fbdev panics drm: Move ->old_fb from crtc to plane drm: Handle legacy per-crtc locking with full acquire ctx drm: Move modeset_lock_all helpers to drm_modeset_lock.[hc] drm: Add drm_plane/connector_index drm: idiot-proof vblank drm: Warn when leaking flip events on close drm: Perform cmdline mode parsing during connector initialisation video/fbdev: Always built-in video= cmdline parsing drm: Don't grab an fb reference for the idr
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r--drivers/gpu/drm/drm_irq.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 08ba1209228e..5708c056fa1b 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -720,6 +720,8 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp);
*/
u32 drm_vblank_count(struct drm_device *dev, int crtc)
{
+ if (WARN_ON(crtc >= dev->num_crtcs))
+ return 0;
return atomic_read(&dev->vblank[crtc].count);
}
EXPORT_SYMBOL(drm_vblank_count);
@@ -742,6 +744,9 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
{
u32 cur_vblank;
+ if (WARN_ON(crtc >= dev->num_crtcs))
+ return 0;
+
/* Read timestamp from slot of _vblank_time ringbuffer
* that corresponds to current vblank count. Retry if
* count has incremented during readout. This works like
@@ -917,6 +922,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
unsigned long irqflags;
int ret = 0;
+ if (WARN_ON(crtc >= dev->num_crtcs))
+ return -EINVAL;
+
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Going from 0->1 means we have to enable interrupts again */
if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
@@ -965,6 +973,9 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
{
BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);
+ if (WARN_ON(crtc >= dev->num_crtcs))
+ return;
+
/* Last user schedules interrupt disable */
if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
(drm_vblank_offdelay > 0))
@@ -989,6 +1000,50 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc)
EXPORT_SYMBOL(drm_crtc_vblank_put);
/**
+ * drm_wait_one_vblank - wait for one vblank
+ * @dev: DRM device
+ * @crtc: crtc index
+ *
+ * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
+ * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
+ * due to lack of driver support or because the crtc is off.
+ */
+void drm_wait_one_vblank(struct drm_device *dev, int crtc)
+{
+ int ret;
+ u32 last;
+
+ ret = drm_vblank_get(dev, crtc);
+ if (WARN_ON(ret))
+ return;
+
+ last = drm_vblank_count(dev, crtc);
+
+ ret = wait_event_timeout(dev->vblank[crtc].queue,
+ last != drm_vblank_count(dev, crtc),
+ msecs_to_jiffies(100));
+
+ WARN_ON(ret == 0);
+
+ drm_vblank_put(dev, crtc);
+}
+EXPORT_SYMBOL(drm_wait_one_vblank);
+
+/**
+ * drm_crtc_wait_one_vblank - wait for one vblank
+ * @crtc: DRM crtc
+ *
+ * This waits for one vblank to pass on @crtc, using the irq driver interfaces.
+ * It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
+ * due to lack of driver support or because the crtc is off.
+ */
+void drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
+{
+ drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc));
+}
+EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
+
+/**
* drm_vblank_off - disable vblank events on a CRTC
* @dev: DRM device
* @crtc: CRTC in question
@@ -1009,6 +1064,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
unsigned long irqflags;
unsigned int seq;
+ if (WARN_ON(crtc >= dev->num_crtcs))
+ return;
+
spin_lock_irqsave(&dev->vbl_lock, irqflags);
vblank_disable_and_save(dev, crtc);
wake_up(&dev->vblank[crtc].queue);
@@ -1068,6 +1126,9 @@ void drm_vblank_on(struct drm_device *dev, int crtc)
{
unsigned long irqflags;
+ if (WARN_ON(crtc >= dev->num_crtcs))
+ return;
+
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* re-enable interrupts if there's are users left */
if (atomic_read(&dev->vblank[crtc].refcount) != 0)
@@ -1121,6 +1182,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
/* vblank is not initialized (IRQ not installed ?), or has been freed */
if (!dev->num_crtcs)
return;
+
+ if (WARN_ON(crtc >= dev->num_crtcs))
+ return;
+
/*
* To avoid all the problems that might happen if interrupts
* were enabled/disabled around or between these calls, we just
@@ -1429,6 +1494,9 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
if (!dev->num_crtcs)
return false;
+ if (WARN_ON(crtc >= dev->num_crtcs))
+ return false;
+
/* Need timestamp lock to prevent concurrent execution with
* vblank enable/disable, as this would cause inconsistent
* or corrupted timestamps and vblank counts.