Module Name:    src
Committed By:   riastradh
Date:           Mon Aug 27 14:42:43 UTC 2018

Modified Files:
        src/sys/external/bsd/drm2/dist/drm: drm_irq.c
        src/sys/external/bsd/drm2/dist/include/drm: drmP.h

Log Message:
Rework vblank locking.  New drm_vblank_get/put_locked subroutines.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/external/bsd/drm2/dist/drm/drm_irq.c
cvs rdiff -u -r1.25 -r1.26 src/sys/external/bsd/drm2/dist/include/drm/drmP.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/dist/drm/drm_irq.c
diff -u src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.12 src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.13
--- src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.12	Mon Aug 27 07:03:39 2018
+++ src/sys/external/bsd/drm2/dist/drm/drm_irq.c	Mon Aug 27 14:42:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_irq.c,v 1.12 2018/08/27 07:03:39 riastradh Exp $	*/
+/*	$NetBSD: drm_irq.c,v 1.13 2018/08/27 14:42:43 riastradh Exp $	*/
 
 /*
  * drm_irq.c IRQ and vblank support
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_irq.c,v 1.12 2018/08/27 07:03:39 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_irq.c,v 1.13 2018/08/27 14:42:43 riastradh Exp $");
 
 #include <drm/drmP.h>
 #include "drm_trace.h"
@@ -62,6 +62,10 @@ __KERNEL_RCSID(0, "$NetBSD: drm_irq.c,v 
 #include <sys/select.h>
 #endif
 
+/*
+ * Lock order: dev->event_lock, then dev->vbl_lock, then dev->vblank_time_lock
+ */
+
 /* Access macro for slots in vblank timestamp ringbuffer. */
 #define vblanktimestamp(dev, pipe, count) \
 	((dev)->vblank[pipe].time[(count) % DRM_VBLANKTIME_RBSIZE])
@@ -144,6 +148,8 @@ static void drm_reset_vblank_timestamp(s
 	struct timeval t_vblank;
 	int count = DRM_TIMESTAMP_MAXRETRIES;
 
+	assert_spin_locked(&dev->vbl_lock);
+
 	spin_lock(&dev->vblank_time_lock);
 
 	/*
@@ -198,6 +204,8 @@ static void drm_update_vblank_count(stru
 	int count = DRM_TIMESTAMP_MAXRETRIES;
 	int framedur_ns = vblank->framedur_ns;
 
+	assert_spin_locked(&dev->vbl_lock);
+
 	/*
 	 * Interrupts were disabled prior to this call, so deal with counter
 	 * wrap if needed.
@@ -331,6 +339,8 @@ static void vblank_disable_and_save(stru
 	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.
@@ -358,6 +368,23 @@ static void vblank_disable_and_save(stru
 	spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
 }
 
+static void
+vblank_disable_locked(struct drm_vblank_crtc *vblank, struct drm_device *dev,
+    unsigned int pipe)
+{
+
+	BUG_ON(vblank != &dev->vblank[pipe]);
+	assert_spin_locked(&dev->vbl_lock);
+
+	if (!dev->vblank_disable_allowed)
+		return;
+
+	if (atomic_read(&vblank->refcount) == 0 && vblank->enabled) {
+		DRM_DEBUG("disabling vblank on crtc %u\n", pipe);
+		vblank_disable_and_save(dev, pipe);
+	}
+}
+
 static void vblank_disable_fn(unsigned long arg)
 {
 	struct drm_vblank_crtc *vblank = (void *)arg;
@@ -1269,31 +1296,24 @@ static int drm_vblank_enable(struct drm_
 }
 
 /**
- * drm_vblank_get - get a reference count on vblank events
+ * drm_vblank_get_locked - like drm_vblank_get but caller holds lock
  * @dev: DRM device
  * @pipe: index of CRTC to own
- *
- * Acquire a reference count on vblank events to avoid having them disabled
- * while in use.
- *
- * This is the legacy version of drm_crtc_vblank_get().
- *
- * Returns:
- * Zero on success or a negative error code on failure.
  */
-int drm_vblank_get(struct drm_device *dev, unsigned int pipe)
+int
+drm_vblank_get_locked(struct drm_device *dev, unsigned int pipe)
 {
 	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
-	unsigned long irqflags;
 	int ret = 0;
 
+	assert_spin_locked(&dev->vbl_lock);
+
 	if (!dev->num_crtcs)
 		return -EINVAL;
 
 	if (WARN_ON(pipe >= 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, &vblank->refcount) == 1) {
 		ret = drm_vblank_enable(dev, pipe);
@@ -1303,6 +1323,30 @@ int drm_vblank_get(struct drm_device *de
 			ret = -EINVAL;
 		}
 	}
+
+	return ret;
+}
+
+/**
+ * drm_vblank_get - get a reference count on vblank events
+ * @dev: DRM device
+ * @pipe: index of CRTC to own
+ *
+ * Acquire a reference count on vblank events to avoid having them disabled
+ * while in use.
+ *
+ * This is the legacy version of drm_crtc_vblank_get().
+ *
+ * Returns:
+ * Zero on success or a negative error code on failure.
+ */
+int drm_vblank_get(struct drm_device *dev, unsigned int pipe)
+{
+	unsigned long irqflags;
+	int ret;
+
+	spin_lock_irqsave(&dev->vbl_lock, irqflags);
+	ret = drm_vblank_get_locked(dev, pipe);
 	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
 	return ret;
@@ -1310,6 +1354,16 @@ int drm_vblank_get(struct drm_device *de
 EXPORT_SYMBOL(drm_vblank_get);
 
 /**
+ * drm_crtc_vblank_get_locked - like drm_crtc_vblank_get but caller holds lock
+ * @crtc: which CRTC to own
+ */
+int
+drm_crtc_vblank_get_locked(struct drm_crtc *crtc)
+{
+	return drm_vblank_get_locked(crtc->dev, drm_crtc_index(crtc));
+}
+
+/**
  * drm_crtc_vblank_get - get a reference count on vblank events
  * @crtc: which CRTC to own
  *
@@ -1328,6 +1382,36 @@ int drm_crtc_vblank_get(struct drm_crtc 
 EXPORT_SYMBOL(drm_crtc_vblank_get);
 
 /**
+ * drm_vblank_put_locked - like drm_vblank_put but caller holds lock
+ * @dev: DRM device
+ * @pipe: index of CRTC to release
+ */
+void
+drm_vblank_put_locked(struct drm_device *dev, unsigned int pipe)
+{
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+
+	assert_spin_locked(&dev->vbl_lock);
+
+	if (WARN_ON(pipe >= dev->num_crtcs))
+		return;
+
+	if (WARN_ON(atomic_read(&vblank->refcount) == 0))
+		return;
+
+	/* Last user schedules interrupt disable */
+	if (atomic_dec_and_test(&vblank->refcount)) {
+		if (drm_vblank_offdelay == 0)
+			return;
+		else if (drm_vblank_offdelay < 0)
+			vblank_disable_locked(vblank, dev, pipe);
+		else if (!dev->vblank_disable_immediate)
+			mod_timer(&vblank->disable_timer,
+				  jiffies + ((drm_vblank_offdelay * HZ)/1000));
+	}
+}
+
+/**
  * drm_vblank_put - release ownership of vblank events
  * @dev: DRM device
  * @pipe: index of CRTC to release
@@ -1361,6 +1445,16 @@ void drm_vblank_put(struct drm_device *d
 EXPORT_SYMBOL(drm_vblank_put);
 
 /**
+ * drm_crtc_vblank_put_locked - like drm_crtc_vblank_put but caller holds lock
+ * @crtc: which counter to give up
+ */
+void
+drm_crtc_vblank_put_locked(struct drm_crtc *crtc)
+{
+	drm_vblank_put_locked(crtc->dev, drm_crtc_index(crtc));
+}
+
+/**
  * drm_crtc_vblank_put - give up ownership of vblank events
  * @crtc: which counter to give up
  *
@@ -1990,9 +2084,6 @@ bool drm_handle_vblank(struct drm_device
 {
 	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
 	unsigned long irqflags;
-#ifdef __NetBSD__		/* XXX vblank locking */
-	unsigned long irqflags_vbl_lock;
-#endif
 
 	if (WARN_ON_ONCE(!dev->num_crtcs))
 		return false;
@@ -2001,9 +2092,6 @@ bool drm_handle_vblank(struct drm_device
 		return false;
 
 	spin_lock_irqsave(&dev->event_lock, irqflags);
-#ifdef __NetBSD__		/* XXX vblank locking */
-	spin_lock_irqsave(&dev->vbl_lock, irqflags_vbl_lock);
-#endif
 
 	/* Need timestamp lock to prevent concurrent execution with
 	 * vblank enable/disable, as this would cause inconsistent
@@ -2015,9 +2103,6 @@ bool drm_handle_vblank(struct drm_device
 	if (!vblank->enabled) {
 		spin_unlock(&dev->vblank_time_lock);
 		spin_unlock_irqrestore(&dev->event_lock, irqflags);
-#ifdef __NetBSD__		/* XXX vblank locking */
-		spin_unlock_irqrestore(&dev->vbl_lock, irqflags_vbl_lock);
-#endif
 		return false;
 	}
 
@@ -2026,7 +2111,9 @@ bool drm_handle_vblank(struct drm_device
 	spin_unlock(&dev->vblank_time_lock);
 
 #ifdef __NetBSD__
+	spin_lock(&dev->vbl_lock);
 	DRM_SPIN_WAKEUP_ONE(&vblank->queue, &dev->vbl_lock);
+	spin_unlock(&dev->vbl_lock);
 #else
 	wake_up(&vblank->queue);
 #endif
@@ -2043,9 +2130,6 @@ bool drm_handle_vblank(struct drm_device
 		vblank_disable_fn((unsigned long)vblank);
 
 	spin_unlock_irqrestore(&dev->event_lock, irqflags);
-#ifdef __NetBSD__		/* XXX vblank locking */
-	spin_unlock_irqrestore(&dev->vbl_lock, irqflags_vbl_lock);
-#endif
 
 	return true;
 }

Index: src/sys/external/bsd/drm2/dist/include/drm/drmP.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.25 src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.26
--- src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.25	Mon Aug 27 13:42:47 2018
+++ src/sys/external/bsd/drm2/dist/include/drm/drmP.h	Mon Aug 27 14:42:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: drmP.h,v 1.25 2018/08/27 13:42:47 riastradh Exp $	*/
+/*	$NetBSD: drmP.h,v 1.26 2018/08/27 14:42:43 riastradh Exp $	*/
 
 /*
  * Internal Header for the Direct Rendering Manager
@@ -1071,6 +1071,10 @@ extern int drm_vblank_get(struct drm_dev
 extern void drm_vblank_put(struct drm_device *dev, unsigned int pipe);
 extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_put(struct drm_crtc *crtc);
+extern int drm_vblank_get_locked(struct drm_device *dev, unsigned int pipe);
+extern void drm_vblank_put_locked(struct drm_device *dev, unsigned int pipe);
+extern int drm_crtc_vblank_get_locked(struct drm_crtc *crtc);
+extern void drm_crtc_vblank_put_locked(struct drm_crtc *crtc);
 extern void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe);
 extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
 extern void drm_vblank_off(struct drm_device *dev, unsigned int pipe);

Reply via email to