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; \