Module Name:    src
Committed By:   riastradh
Date:           Sat Feb 28 18:25:39 UTC 2015

Modified Files:
        src/sys/external/bsd/drm2/dist/drm: drm_irq.c
        src/sys/external/bsd/drm2/dist/drm/i915: i915_dma.c
        src/sys/external/bsd/drm2/dist/drm/via: via_dmablit.c via_drv.h
            via_irq.c via_video.c
        src/sys/external/bsd/drm2/include/drm: drm_wait_netbsd.h

Log Message:
New macro DRM_SPIN_WAIT_ON better reflects DRM_WAIT_ON.

We still need to adapt all waits from upstream to use an interlock,
so we can't implement DRM_WAIT_ON verbatim, but this more closely
reflects the API of DRM_WAIT_ON than DRM_*WAIT*_UNTIL do.

Major difference is that this polls every tick, like DRM_WAIT_ON,
unlike DRM_*WAIT*_UNTIL.  So it will mask missing wakeups, but it
wouldn't surprise me if there were such things upstream.


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/sys/external/bsd/drm2/dist/drm/drm_irq.c
cvs rdiff -u -r1.14 -r1.15 src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c \
    src/sys/external/bsd/drm2/dist/drm/via/via_irq.c \
    src/sys/external/bsd/drm2/dist/drm/via/via_video.c
cvs rdiff -u -r1.2 -r1.3 src/sys/external/bsd/drm2/dist/drm/via/via_drv.h
cvs rdiff -u -r1.8 -r1.9 \
    src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.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.7 src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.8
--- src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.7	Sat Feb 28 03:05:09 2015
+++ src/sys/external/bsd/drm2/dist/drm/drm_irq.c	Sat Feb 28 18:25:39 2015
@@ -1293,20 +1293,14 @@ int drm_wait_vblank(struct drm_device *d
 #ifdef __NetBSD__
     {
 	unsigned long irqflags;
+
 	spin_lock_irqsave(&dev->vbl_lock, irqflags);
-	DRM_SPIN_TIMED_WAIT_UNTIL(ret, &dev->vblank[crtc].queue,
-	    &dev->vbl_lock,
-	    (3 * HZ),
+	DRM_SPIN_WAIT_ON(ret, &dev->vblank[crtc].queue, &dev->vbl_lock,
+	    3 * HZ,
 	    (((drm_vblank_count(dev, crtc) -
 		    vblwait->request.sequence) <= (1 << 23)) ||
 		!dev->irq_enabled));
 	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-	if (ret < 0)		/* Failed: return negative error as is.  */
-		;
-	else if (ret == 0)	/* Timed out: return -EBUSY like Linux.  */
-		ret = -EBUSY;
-	else			/* Succeeded (ret > 0): return 0.  */
-		ret = 0;
     }
 #else
 	DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ,

Index: src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c
diff -u src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.14 src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.15
--- src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c:1.14	Sat Feb 28 03:06:46 2015
+++ src/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c	Sat Feb 28 18:25:39 2015
@@ -812,16 +812,9 @@ static int i915_wait_irq(struct drm_devi
 #ifdef __NetBSD__
 		unsigned long flags;
 		spin_lock_irqsave(&dev_priv->irq_lock, flags);
-		DRM_SPIN_TIMED_WAIT_UNTIL(ret, &ring->irq_queue,
-		    &dev_priv->irq_lock,
+		DRM_SPIN_WAIT_ON(ret, &ring->irq_queue, &dev_priv->irq_lock,
 		    3 * DRM_HZ,
 		    READ_BREADCRUMB(dev_priv) >= irq_nr);
-		if (ret < 0)	/* Failure: return negative error as is.  */
-			;
-		else if (ret == 0) /* Timed out: return -EBUSY like Linux.  */
-			ret = -EBUSY;
-		else		/* Succeeded (ret > 0): return 0.  */
-			ret = 0;
 		spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 #else
 		DRM_WAIT_ON(ret, ring->irq_queue, 3 * HZ,

Index: src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c
diff -u src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c:1.3 src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c:1.4
--- src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c:1.3	Sat Feb 28 03:23:32 2015
+++ src/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c	Sat Feb 28 18:25:39 2015
@@ -597,15 +597,8 @@ via_dmablit_sync(struct drm_device *dev,
 #ifdef __NetBSD__
 	spin_lock(&blitq->blit_lock);
 	if (via_dmablit_active(blitq, engine, handle, &queue)) {
-		DRM_SPIN_TIMED_WAIT_UNTIL(ret, queue, &blitq->blit_lock,
-		    3*DRM_HZ,
+		DRM_SPIN_WAIT_ON(ret, queue, &blitq->blit_lock, 3*DRM_HZ,
 		    !via_dmablit_active(blitq, engine, handle, NULL));
-		if (ret < 0)	/* Failure: return negative error as is.  */
-			;
-		else if (ret == 0) /* Timed out: return -EBUSY like Linux.  */
-			ret = -EBUSY;
-		else		/* Succeeded (ret > 0): return 0.  */
-			ret = 0;
 	}
 	spin_unlock(&blitq->blit_lock);
 #else
@@ -881,15 +874,9 @@ via_dmablit_grab_slot(drm_via_blitq_t *b
 	spin_lock_irqsave(&blitq->blit_lock, irqsave);
 	while (blitq->num_free == 0) {
 #ifdef __NetBSD__
-		DRM_SPIN_TIMED_WAIT_UNTIL(ret, &blitq->busy_queue,
-		    &blitq->blit_lock, DRM_HZ,
+		DRM_SPIN_WAIT_ON(ret, &blitq->busy_queue, &blitq->blit_lock,
+		    DRM_HZ,
 		    blitq->num_free > 0);
-		if (ret < 0)	/* Failure: return negative error as is.  */
-			;
-		else if (ret == 0) /* Timed out: return -EBUSY like Linux.  */
-			ret = -EBUSY;
-		else		/* Success (ret > 0): return 0.  */
-			ret = 0;
 		/* Map -EINTR to -EAGAIN.  */
 		if (ret == -EINTR)
 			ret = -EAGAIN;
Index: src/sys/external/bsd/drm2/dist/drm/via/via_irq.c
diff -u src/sys/external/bsd/drm2/dist/drm/via/via_irq.c:1.3 src/sys/external/bsd/drm2/dist/drm/via/via_irq.c:1.4
--- src/sys/external/bsd/drm2/dist/drm/via/via_irq.c:1.3	Sat Feb 28 03:23:32 2015
+++ src/sys/external/bsd/drm2/dist/drm/via/via_irq.c	Sat Feb 28 18:25:39 2015
@@ -249,23 +249,17 @@ via_driver_irq_wait(struct drm_device *d
 #ifdef __NetBSD__
 	spin_lock(&cur_irq->irq_lock);
 	if (masks[real_irq][2] && !force_sequence) {
-		DRM_SPIN_TIMED_WAIT_UNTIL(ret, &cur_irq->irq_queue,
-		    &cur_irq->irq_lock, 3 * DRM_HZ,
+		DRM_SPIN_WAIT_ON(ret, &cur_irq->irq_queue, &cur_irq->irq_lock,
+		    3 * DRM_HZ,
 		    ((VIA_READ(masks[irq][2]) & masks[irq][3]) ==
 			masks[irq][4]));
 		cur_irq_sequence = cur_irq->irq_received;
 	} else {
-		DRM_SPIN_TIMED_WAIT_UNTIL(ret, &cur_irq->irq_queue,
-		    &cur_irq->irq_lock, 3 * DRM_HZ,
+		DRM_SPIN_WAIT_ON(ret, &cur_irq->irq_queue, &cur_irq->irq_lock,
+		    3 * DRM_HZ,
 		    (((cur_irq_sequence = cur_irq->irq_received) -
 			*sequence) <= (1 << 23)));
 	}
-	if (ret < 0)		/* Failure: return negative error as is.  */
-		;
-	else if (ret == 0)	/* Timed out: return -EBUSY like Linux.  */
-		ret = -EBUSY;
-	else			/* Success (ret > 0): return 0.  */
-		ret = 0;
 	spin_unlock(&cur_irq->irq_lock);
 #else
 	if (masks[real_irq][2] && !force_sequence) {
Index: src/sys/external/bsd/drm2/dist/drm/via/via_video.c
diff -u src/sys/external/bsd/drm2/dist/drm/via/via_video.c:1.3 src/sys/external/bsd/drm2/dist/drm/via/via_video.c:1.4
--- src/sys/external/bsd/drm2/dist/drm/via/via_video.c:1.3	Sat Feb 28 03:23:32 2015
+++ src/sys/external/bsd/drm2/dist/drm/via/via_video.c	Sat Feb 28 18:25:39 2015
@@ -37,7 +37,7 @@ void via_init_futex(drm_via_private_t *d
 
 	for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
 #ifdef __NetBSD__
-		linux_mutex_init(&dev_priv->decoder_lock[i]);
+		spin_lock_init(&dev_priv->decoder_lock[i]);
 		DRM_INIT_WAITQUEUE(&dev_priv->decoder_queue[i], "viadec");
 #else
 		init_waitqueue_head(&(dev_priv->decoder_queue[i]));
@@ -53,7 +53,7 @@ void via_cleanup_futex(drm_via_private_t
 
 	for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
 		DRM_DESTROY_WAITQUEUE(&dev_priv->decoder_queue[i]);
-		linux_mutex_destroy(&dev_priv->decoder_lock[i]);
+		spin_lock_destroy(&dev_priv->decoder_lock[i]);
 	}
 #endif
 }
@@ -72,10 +72,10 @@ void via_release_futex(drm_via_private_t
 			if (_DRM_LOCK_IS_HELD(*lock)
 			    && (*lock & _DRM_LOCK_CONT)) {
 #ifdef __NetBSD__
-				mutex_lock(&dev_priv->decoder_lock[i]);
-				DRM_WAKEUP_ALL(&dev_priv->decoder_queue[i],
+				spin_lock(&dev_priv->decoder_lock[i]);
+				DRM_SPIN_WAKEUP_ALL(&dev_priv->decoder_queue[i],
 				    &dev_priv->decoder_lock[i]);
-				mutex_unlock(&dev_priv->decoder_lock[i]);
+				spin_unlock(&dev_priv->decoder_lock[i]);
 #else
 				wake_up(&(dev_priv->decoder_queue[i]));
 #endif
@@ -103,18 +103,12 @@ int via_decoder_futex(struct drm_device 
 	switch (fx->func) {
 	case VIA_FUTEX_WAIT:
 #ifdef __NetBSD__
-		mutex_lock(&dev_priv->decoder_lock[fx->lock]);
-		DRM_TIMED_WAIT_UNTIL(ret, &dev_priv->decoder_queue[fx->lock],
+		spin_lock(&dev_priv->decoder_lock[fx->lock]);
+		DRM_SPIN_WAIT_ON(ret, &dev_priv->decoder_queue[fx->lock],
 		    &dev_priv->decoder_lock[fx->lock],
 		    (fx->ms / 10) * (DRM_HZ / 100),
 		    *lock != fx->val);
-		if (ret < 0)	/* Failure: return negative error as is.  */
-			;
-		else if (ret == 0) /* Timed out: return -EBUSY like Linux.  */
-			ret = -EBUSY;
-		else		/* Success (ret > 0): return 0.  */
-			ret = 0;
-		mutex_unlock(&dev_priv->decoder_lock[fx->lock]);
+		spin_unlock(&dev_priv->decoder_lock[fx->lock]);
 #else
 		DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock],
 			    (fx->ms / 10) * (HZ / 100), *lock != fx->val);

Index: src/sys/external/bsd/drm2/dist/drm/via/via_drv.h
diff -u src/sys/external/bsd/drm2/dist/drm/via/via_drv.h:1.2 src/sys/external/bsd/drm2/dist/drm/via/via_drv.h:1.3
--- src/sys/external/bsd/drm2/dist/drm/via/via_drv.h:1.2	Tue Aug 26 17:28:14 2014
+++ src/sys/external/bsd/drm2/dist/drm/via/via_drv.h	Sat Feb 28 18:25:39 2015
@@ -73,7 +73,7 @@ typedef struct drm_via_private {
 	drm_local_map_t *mmio;
 	unsigned long agpAddr;
 #ifdef __NetBSD__
-	struct mutex decoder_lock[VIA_NR_XVMC_LOCKS];
+	spinlock_t decoder_lock[VIA_NR_XVMC_LOCKS];
 	drm_waitqueue_t decoder_queue[VIA_NR_XVMC_LOCKS];
 #else
 	wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];

Index: src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h
diff -u src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.8 src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.9
--- src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h:1.8	Sat Feb 28 04:57:12 2015
+++ src/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h	Sat Feb 28 18:25:39 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_wait_netbsd.h,v 1.8 2015/02/28 04:57:12 riastradh Exp $	*/
+/*	$NetBSD: drm_wait_netbsd.h,v 1.9 2015/02/28 18:25:39 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -105,31 +105,80 @@ DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, 
 }
 
 /*
- * WARNING: These DRM_*WAIT*_UNTIL macros are designed to replace the
- * Linux wait_event* macros.  They have a different return value
- * convention from the legacy portability DRM_WAIT_ON macro and a
+ * DRM_SPIN_WAIT_ON is a replacement for the legacy DRM_WAIT_ON
+ * portability macro.  It requires a spin interlock, which may require
+ * changes to the surrounding code so that the waits actually are
+ * interlocked by a spin lock.  It also polls the condition at every
+ * tick, which masks missing wakeups.  Since DRM_WAIT_ON is going away,
+ * in favour of Linux's native wait_event* API, waits in new code
+ * should be written to use the DRM_*WAIT*_UNTIL macros below.
+ *
+ * Like the legacy DRM_WAIT_ON, DRM_SPIN_WAIT_ON returns
+ *
+ * . -EBUSY if timed out (yes, -EBUSY, not -ETIMEDOUT or -EWOULDBLOCK),
+ * . -EINTR/-ERESTART if interrupted by a signal, or
+ * . 0 if the condition was true before or just after the timeout.
+ *
+ * Note that cv_timedwait* return -EWOULDBLOCK, not -EBUSY, on timeout.
+ */
+
+#define	DRM_SPIN_WAIT_ON(RET, Q, INTERLOCK, TICKS, CONDITION)	do	      \
+{									      \
+	extern int hardclock_ticks;					      \
+	const int _dswo_start = hardclock_ticks;			      \
+	const int _dswo_end = _dswo_start + (TICKS);			      \
+									      \
+	KASSERT(spin_is_locked((INTERLOCK)));				      \
+	KASSERT(!cpu_intr_p());						      \
+	KASSERT(!cpu_softintr_p());					      \
+	KASSERT(!cold);							      \
+									      \
+	for (;;) {							      \
+		if (CONDITION) {					      \
+			(RET) = 0;					      \
+			break;						      \
+		}							      \
+		const int _dswo_now = hardclock_ticks;			      \
+		if (_dswo_end < _dswo_now) {				      \
+			(RET) = -EBUSY;		/* Match Linux...  */	      \
+			break;						      \
+		}							      \
+		/* XXX errno NetBSD->Linux */				      \
+		(RET) = -cv_timedwait_sig((Q), &(INTERLOCK)->sl_lock,	      \
+		    (_dswo_end - _dswo_now));				      \
+		if (RET) {						      \
+			if ((RET) == -EWOULDBLOCK)			      \
+				(RET) = (CONDITION) ? 0 : -EBUSY;	      \
+									      \
+			break;						      \
+		}							      \
+	}								      \
+} while (0)
+
+/*
+ * The DRM_*WAIT*_UNTIL macros are replacements for the Linux
+ * wait_event* macros.  Like DRM_SPIN_WAIT_ON, they add an interlock,
+ * and so may require some changes to the surrounding code.  They have
+ * a different return value convention from DRM_SPIN_WAIT_ON and a
  * different return value convention from cv_*wait*.
  *
- * Specifically, the untimed macros
+ * The untimed DRM_*WAIT*_UNTIL macros return
  *
- * - return negative error code on failure (interruption), and
- * - return zero on sucess.
+ * . -EINTR/-ERESTART if interrupted by a signal, or
+ * . zero if the condition evaluated
  *
- * The timed macros
+ * The timed DRM_*TIMED_WAIT*_UNTIL macros return
  *
- * - return negative error code on failure (interruption),
- * - return zero on timeout, and
- * - return one on success.
+ * . -EINTR/-ERESTART if interrupted by a signal,
+ * . 0 if the condition was false after the timeout,
+ * . 1 if the condition was true just after the timeout, or
+ * . the number of ticks remaining if the condition was true before the
+ * timeout.
  *
- * Contrast DRM_WAIT_ON which returns -EINTR/-ERESTART on interruption,
+ * Contrast DRM_SPIN_WAIT_ON which returns -EINTR/-ERESTART on signal,
  * -EBUSY on timeout, and zero on success; and cv_*wait*, which return
- * -EINTR/-ERESTART on interruption, -EWOULDBLOCK on timeout, and zero
- * on success.
- *
- * We don't simply implement DRM_WAIT_ON because, like Linux
- * wait_event*, it lacks an interlock, whereas we require an interlock
- * for any waits in order to avoid the standard race conditions
- * associated with non-interlocked waits that plague Linux drivers.
+ * -EINTR/-ERESTART on signal, -EWOULDBLOCK on timeout, and zero on
+ * success.
  *
  * XXX In retrospect, giving the timed and untimed macros a different
  * return convention from one another to match Linux may have been a
@@ -162,19 +211,6 @@ DRM_SPIN_WAKEUP_ALL(drm_waitqueue_t *q, 
 #define	DRM_WAIT_UNTIL(RET, Q, I, C)				\
 	_DRM_WAIT_UNTIL(RET, cv_wait_sig, Q, I, C)
 
-/*
- * Timed wait.  Return:
- *
- * - 0 if condition is false after timeout,
- * - 1 if condition is true after timeout or one tick before timeout,
- * - number of ticks left if condition evaluated to true before timeout, or
- * - negative error if failure (e.g., interrupted).
- *
- * XXX Comments in Linux say it returns -ERESTARTSYS if interrupted.
- * What if by a signal without SA_RESTART?  Shouldn't it be -EINTR
- * then?  I'm going to leave it as what cv_timedwait returned, which is
- * ERESTART for signals with SA_RESTART and EINTR otherwise.
- */
 #define	_DRM_TIMED_WAIT_UNTIL(RET, WAIT, Q, INTERLOCK, TICKS, CONDITION) do \
 {									\
 	extern int hardclock_ticks;					\

Reply via email to