Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/drm2 New macro DRM_SPIN_WAIT_ON better refl...



details:   https://anonhg.NetBSD.org/src/rev/940bf003bc1f
branches:  trunk
changeset: 806554:940bf003bc1f
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sat Feb 28 18:25:39 2015 +0000

description:
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.

diffstat:

 sys/external/bsd/drm2/dist/drm/drm_irq.c            |   12 +-
 sys/external/bsd/drm2/dist/drm/i915/i915_dma.c      |    9 +-
 sys/external/bsd/drm2/dist/drm/via/via_dmablit.c    |   19 +---
 sys/external/bsd/drm2/dist/drm/via/via_drv.h        |    2 +-
 sys/external/bsd/drm2/dist/drm/via/via_irq.c        |   14 +--
 sys/external/bsd/drm2/dist/drm/via/via_video.c      |   22 +--
 sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h |  100 +++++++++++++------
 7 files changed, 88 insertions(+), 90 deletions(-)

diffs (truncated from 314 to 300 lines):

diff -r cf4c5e813ff4 -r 940bf003bc1f sys/external/bsd/drm2/dist/drm/drm_irq.c
--- a/sys/external/bsd/drm2/dist/drm/drm_irq.c  Sat Feb 28 15:45:12 2015 +0000
+++ b/sys/external/bsd/drm2/dist/drm/drm_irq.c  Sat Feb 28 18:25:39 2015 +0000
@@ -1293,20 +1293,14 @@
 #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,
diff -r cf4c5e813ff4 -r 940bf003bc1f sys/external/bsd/drm2/dist/drm/i915/i915_dma.c
--- a/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c    Sat Feb 28 15:45:12 2015 +0000
+++ b/sys/external/bsd/drm2/dist/drm/i915/i915_dma.c    Sat Feb 28 18:25:39 2015 +0000
@@ -812,16 +812,9 @@
 #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,
diff -r cf4c5e813ff4 -r 940bf003bc1f sys/external/bsd/drm2/dist/drm/via/via_dmablit.c
--- a/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c  Sat Feb 28 15:45:12 2015 +0000
+++ b/sys/external/bsd/drm2/dist/drm/via/via_dmablit.c  Sat Feb 28 18:25:39 2015 +0000
@@ -597,15 +597,8 @@
 #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 @@
        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;
diff -r cf4c5e813ff4 -r 940bf003bc1f sys/external/bsd/drm2/dist/drm/via/via_drv.h
--- a/sys/external/bsd/drm2/dist/drm/via/via_drv.h      Sat Feb 28 15:45:12 2015 +0000
+++ b/sys/external/bsd/drm2/dist/drm/via/via_drv.h      Sat Feb 28 18:25:39 2015 +0000
@@ -73,7 +73,7 @@
        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];
diff -r cf4c5e813ff4 -r 940bf003bc1f sys/external/bsd/drm2/dist/drm/via/via_irq.c
--- a/sys/external/bsd/drm2/dist/drm/via/via_irq.c      Sat Feb 28 15:45:12 2015 +0000
+++ b/sys/external/bsd/drm2/dist/drm/via/via_irq.c      Sat Feb 28 18:25:39 2015 +0000
@@ -249,23 +249,17 @@
 #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) {
diff -r cf4c5e813ff4 -r 940bf003bc1f sys/external/bsd/drm2/dist/drm/via/via_video.c
--- a/sys/external/bsd/drm2/dist/drm/via/via_video.c    Sat Feb 28 15:45:12 2015 +0000
+++ b/sys/external/bsd/drm2/dist/drm/via/via_video.c    Sat Feb 28 18:25:39 2015 +0000
@@ -37,7 +37,7 @@
 
        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 @@
 
        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 @@
                        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 @@
        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);
diff -r cf4c5e813ff4 -r 940bf003bc1f sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h
--- a/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h       Sat Feb 28 15:45:12 2015 +0000
+++ b/sys/external/bsd/drm2/include/drm/drm_wait_netbsd.h       Sat Feb 28 18:25:39 2015 +0000
@@ -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 @@
 }
 
 /*
- * 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 @@
 #define        DRM_WAIT_UNTIL(RET, Q, I, C)                            \
        _DRM_WAIT_UNTIL(RET, cv_wait_sig, Q, I, C)
 
-/*
- * Timed wait.  Return:



Home | Main Index | Thread Index | Old Index